whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

commit 519f64bf15dccb4f64af34b74ed186c32363ab59
parent 0c86e761b95131943c2b8af2ffb3c0554f9a71f5
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Wed, 31 Oct 2018 11:08:30 -0700

Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk updates from Stephen Boyd:
 "This time it looks like a quieter release cycle in the clk tree. I
  guess that's because of summer time holidays/vacations. The biggest
  change in the diffstat is in the Qualcomm clk driver, where they got
  support for CPUs and handful of SoCs. After that, the at91 driver got
  a major rewrite for newer DT bindings that should make things easier
  going forward and the TI code moved to a clockdomain based design.

  The long tail is mostly small driver updates for newer clks and some
  simpler SoC clock drivers such as the Hisilicon and imx support.

  In the core framework, we only have two small changes this time.

  One is a new clk API to get all clks for a device with the bulk clk
  APIs. This allows drivers that don't care about doing anything besides
  turning on all the clks to just clk_get() them all and turn them on.

  The other change is the beginning of a way to support save and restore
  of clk settings in the clk framework. TI is the only user right now,
  but we will want to expand upon this design in the future to support
  more save and restore of clk registers. At least this gets us started
  and works well enough for one SoC, but there's more work in the
  future.

  Core:
   - clk_bulk_get_all() API and friends to get all the clks for a device
   - Basic clk state save/restore hooks

  New Drivers:
   - Renesas RZ/A2 (R7S9210) SoC, including early clocks
   - Rensas RZ/G1N (R8A7744) and RZ/G2E (R8A774C0) SoCs
   - Rensas RZ/G2M (r8a774a1) SoC
   - Qualcomm Krait CPU clk support
   - Qualcomm QCS404 GCC support
   - Qualcomm SDM660 GCC support
   - Qualcomm SDM845 camera clock controller
   - Ingenic jz4725b CGU
   - Hisilicon 3670 SoC support
   - TI SCI clks on K3 SoCs
   - iMX6 MMDC clks
   - Reset Controller (RMU) support for Actions Semi Owl S900 and S700 SoCs

  Updates:
   - Rework at91 PMC clock driver for new DT bindings
   - Nvidia Tegra clk driver MBIST workaround fix
   - S2RAM support for Marvell mvebu periph clks
   - Use updated printk format for OF node names
   - Fix TI code to only search DT subnodes
   - Various static analysis finds
   - Tag various drivers with SPDX license tags
   - Support dynamic frequency switching (DFS) on qcom SDM845 GCC
   - Only use s2mps11 dt-binding defines instead of redefining them in the driver
   - Add some more missing clks to qcom MSM8996 GCC
   - Quad SPI clks on qcom SDM845
   - Add support for CMT timer clocks on R-Car V3H
   - Add support for SHDI and various timer clocks on R-Car V3M
   - Improve OSC and RCLK (watchdog) handling on R-Car Gen3 SoCs
   - Amlogic clk-pll driver improvements and updates
   - Amlogic axg audio controller system clocks
   - Register Amlogic meson8b clock controller early
   - Add support for SATA and Fine Display Processor (FDP) clocks on R-Car M3-N
   - Consolidation of system suspend related code in Exynos, S5P, S3C SoC clk drivers
   - Fixes for system suspend support on Exynos542x (Odroid boards) and Exynos5433 SoC
   - Remove obsoleted Exynos4212 ISP clock definitions
   - Migrated TI am3/4/5 and dra7 SoCs to clockdomain based design
   - TI RTC+DDR sleep mode support for clock save/restore
   - Allwinner A64 display engine support and fixes
   - Allwinner A83t display engine support and fixes"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (186 commits)
  clk: qcom: Remove unused arrays in SDM845 GCC
  clk: fixed-rate: fix of_node_get-put imbalance
  clk: s2mps11: Add used attribute to s2mps11_dt_match
  clk: qcom: gcc-sdm660: Add MODULE_LICENSE
  clk: qcom: Add safe switch hook for krait mux clocks
  dt-bindings: clock: Document qcom,krait-cc
  clk: qcom: Add Krait clock controller driver
  dt-bindings: arm: Document qcom,kpss-gcc
  clk: qcom: Add KPSS ACC/GCC driver
  clk: qcom: Add support for Krait clocks
  clk: qcom: Add IPQ806X's HFPLLs
  clk: qcom: Add MSM8960/APQ8064's HFPLLs
  dt-bindings: clock: Document qcom,hfpll
  clk: qcom: Add HFPLL driver
  clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
  ARM: Add Krait L2 register accessor functions
  clk: imx6q: add mmdc0 ipg clock
  clk: imx6sl: add mmdc ipg clocks
  clk: imx6sll: add mmdc1 ipg clock
  clk: imx6sx: add mmdc1 ipg clock
  ...

Diffstat:
MDocumentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt | 19+++++++++++++++++++
ADocumentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt | 44++++++++++++++++++++++++++++++++++++++++++++
MDocumentation/devicetree/bindings/clock/actions,owl-cmu.txt | 2++
MDocumentation/devicetree/bindings/clock/at91-clock.txt | 516++++---------------------------------------------------------------------------
ADocumentation/devicetree/bindings/clock/hi3670-clock.txt | 43+++++++++++++++++++++++++++++++++++++++++++
MDocumentation/devicetree/bindings/clock/ingenic,cgu.txt | 7+++++--
ADocumentation/devicetree/bindings/clock/qcom,camcc.txt | 18++++++++++++++++++
MDocumentation/devicetree/bindings/clock/qcom,gcc.txt | 3+++
ADocumentation/devicetree/bindings/clock/qcom,hfpll.txt | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ADocumentation/devicetree/bindings/clock/qcom,krait-cc.txt | 34++++++++++++++++++++++++++++++++++
MDocumentation/devicetree/bindings/clock/renesas,cpg-mssr.txt | 17+++++++++++------
March/arm/common/Kconfig | 3+++
March/arm/common/Makefile | 1+
Aarch/arm/common/krait-l2-accessors.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Aarch/arm/include/asm/krait-l2-accessors.h | 9+++++++++
Darch/arm/mach-davinci/include/mach/clock.h | 21---------------------
Mdrivers/clk/Kconfig | 1+
Mdrivers/clk/Makefile | 3++-
Mdrivers/clk/actions/Kconfig | 1+
Mdrivers/clk/actions/Makefile | 1+
Mdrivers/clk/actions/owl-common.c | 3++-
Mdrivers/clk/actions/owl-common.h | 5++++-
Adrivers/clk/actions/owl-reset.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/actions/owl-reset.h | 31+++++++++++++++++++++++++++++++
Mdrivers/clk/actions/owl-s700.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mdrivers/clk/actions/owl-s900.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mdrivers/clk/at91/Makefile | 5++++-
Adrivers/clk/at91/at91sam9260.c | 494+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/at91/at91sam9rl.c | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/at91/at91sam9x5.c | 309+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/at91/clk-audio-pll.c | 109+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mdrivers/clk/at91/clk-generated.c | 81+++----------------------------------------------------------------------------
Mdrivers/clk/at91/clk-h32mx.c | 22+++++++---------------
Mdrivers/clk/at91/clk-i2s-mux.c | 40++--------------------------------------
Mdrivers/clk/at91/clk-main.c | 112+++----------------------------------------------------------------------------
Mdrivers/clk/at91/clk-master.c | 99+++----------------------------------------------------------------------------
Mdrivers/clk/at91/clk-peripheral.c | 81++-----------------------------------------------------------------------------
Mdrivers/clk/at91/clk-pll.c | 190++++---------------------------------------------------------------------------
Mdrivers/clk/at91/clk-plldiv.c | 27+--------------------------
Mdrivers/clk/at91/clk-programmable.c | 81++++---------------------------------------------------------------------------
Mdrivers/clk/at91/clk-slow.c | 32+-------------------------------
Mdrivers/clk/at91/clk-smd.c | 34+---------------------------------
Mdrivers/clk/at91/clk-system.c | 39+--------------------------------------
Mdrivers/clk/at91/clk-usb.c | 94+++----------------------------------------------------------------------------
Mdrivers/clk/at91/clk-utmi.c | 45+--------------------------------------------
Adrivers/clk/at91/dt-compat.c | 961+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/at91/pmc.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/at91/pmc.h | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/at91/sama5d2.c | 336+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/at91/sama5d4.c | 264+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/axs10x/pll_clock.c | 4++--
Mdrivers/clk/bcm/clk-kona-setup.c | 22+++++++++++-----------
Mdrivers/clk/clk-asm9260.c | 4++--
Mdrivers/clk/clk-bulk.c | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/clk-cdce925.c | 11++++++-----
Mdrivers/clk/clk-devres.c | 24++++++++++++++++++++++++
Mdrivers/clk/clk-fixed-factor.c | 8++++----
Mdrivers/clk/clk-fixed-rate.c | 1+
Mdrivers/clk/clk-gpio.c | 8++++----
Mdrivers/clk/clk-hsdk-pll.c | 4++--
Mdrivers/clk/clk-max77686.c | 27++++++---------------------
Mdrivers/clk/clk-nomadik.c | 4++--
Mdrivers/clk/clk-npcm7xx.c | 2+-
Mdrivers/clk/clk-palmas.c | 4++--
Mdrivers/clk/clk-qoriq.c | 14+++++++-------
Mdrivers/clk/clk-s2mps11.c | 58++++++++++++++++++++++++++++++++++++----------------------
Mdrivers/clk/clk-scmi.c | 2+-
Mdrivers/clk/clk-scpi.c | 6+++---
Mdrivers/clk/clk-si5351.c | 4++--
Mdrivers/clk/clk-stm32f4.c | 2+-
Mdrivers/clk/clk-stm32h7.c | 2+-
Mdrivers/clk/clk-stm32mp1.c | 2+-
Mdrivers/clk/clk-tango4.c | 10+++++-----
Mdrivers/clk/clk.c | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/davinci/psc.c | 18------------------
Mdrivers/clk/hisilicon/Kconfig | 7+++++++
Mdrivers/clk/hisilicon/Makefile | 1+
Adrivers/clk/hisilicon/clk-hi3670.c | 1016+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/hisilicon/reset.c | 5++---
Mdrivers/clk/imx/clk-cpu.c | 2+-
Mdrivers/clk/imx/clk-imx6q.c | 1+
Mdrivers/clk/imx/clk-imx6sl.c | 2++
Mdrivers/clk/imx/clk-imx6sll.c | 1+
Mdrivers/clk/imx/clk-imx6sx.c | 1+
Mdrivers/clk/imx/clk-imx6ul.c | 1+
Mdrivers/clk/imx/clk-imx7d.c | 28++++++++--------------------
Mdrivers/clk/imx/clk.h | 7+++++++
Adrivers/clk/ingenic/Kconfig | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/ingenic/Makefile | 9+++++----
Adrivers/clk/ingenic/jz4725b-cgu.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/keystone/Kconfig | 2+-
Mdrivers/clk/keystone/gate.c | 7++++++-
Mdrivers/clk/keystone/pll.c | 7++++++-
Mdrivers/clk/mediatek/clk-mt2701.c | 5-----
Mdrivers/clk/meson/axg-audio.c | 34+++++++++++++++++++++++-----------
Mdrivers/clk/meson/axg.c | 332+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mdrivers/clk/meson/axg.h | 8+++++++-
Mdrivers/clk/meson/clk-pll.c | 156+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mdrivers/clk/meson/clkc.h | 16++++------------
Mdrivers/clk/meson/gxbb.c | 518++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mdrivers/clk/meson/gxbb.h | 10++++++++--
Mdrivers/clk/meson/meson8b.c | 280++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mdrivers/clk/meson/meson8b.h | 5++++-
Mdrivers/clk/mmp/clk-of-mmp2.c | 4++--
Mdrivers/clk/mvebu/ap806-system-controller.c | 5+----
Mdrivers/clk/mvebu/armada-370.c | 4+---
Mdrivers/clk/mvebu/armada-375.c | 4+---
Mdrivers/clk/mvebu/armada-37xx-periph.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mdrivers/clk/mvebu/armada-37xx-tbg.c | 8+++-----
Mdrivers/clk/mvebu/armada-37xx-xtal.c | 4+---
Mdrivers/clk/mvebu/armada-38x.c | 4+---
Mdrivers/clk/mvebu/armada-39x.c | 4+---
Mdrivers/clk/mvebu/armada-xp.c | 4+---
Mdrivers/clk/mvebu/clk-corediv.c | 4+---
Mdrivers/clk/mvebu/clk-cpu.c | 4+---
Mdrivers/clk/mvebu/common.c | 4+---
Mdrivers/clk/mvebu/common.h | 4+---
Mdrivers/clk/mvebu/cp110-system-controller.c | 4+---
Mdrivers/clk/mvebu/dove.c | 4+---
Mdrivers/clk/mvebu/kirkwood.c | 4+---
Mdrivers/clk/mvebu/mv98dx3236.c | 4+---
Mdrivers/clk/mvebu/orion.c | 4+---
Mdrivers/clk/qcom/Kconfig | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/qcom/Makefile | 8++++++++
Adrivers/clk/qcom/camcc-sdm845.c | 1745+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/qcom/clk-alpha-pll.c | 1+
Mdrivers/clk/qcom/clk-branch.c | 2+-
Adrivers/clk/qcom/clk-hfpll.c | 244+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/qcom/clk-hfpll.h | 44++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/qcom/clk-krait.c | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/qcom/clk-krait.h | 40++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/qcom/clk-rcg.h | 11+++++++++++
Mdrivers/clk/qcom/clk-rcg2.c | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/qcom/gcc-ipq806x.c | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/qcom/gcc-msm8960.c | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/qcom/gcc-msm8996.c | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/qcom/gcc-qcs404.c | 2744+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/qcom/gcc-sdm660.c | 2480+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/qcom/gcc-sdm845.c | 321+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Adrivers/clk/qcom/hfpll.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/qcom/kpss-xcc.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/qcom/krait-cc.c | 397+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/renesas/Kconfig | 19++++++++++++++++++-
Mdrivers/clk/renesas/Makefile | 3+++
Mdrivers/clk/renesas/clk-div6.c | 17+++++++----------
Mdrivers/clk/renesas/clk-emev2.c | 22+++++-----------------
Mdrivers/clk/renesas/clk-mstp.c | 13+++++--------
Mdrivers/clk/renesas/clk-r8a73a4.c | 9+++------
Mdrivers/clk/renesas/clk-r8a7740.c | 9+++------
Mdrivers/clk/renesas/clk-r8a7778.c | 9+++------
Mdrivers/clk/renesas/clk-r8a7779.c | 9+++------
Mdrivers/clk/renesas/clk-rcar-gen2.c | 9+++------
Mdrivers/clk/renesas/clk-rz.c | 9+++------
Mdrivers/clk/renesas/clk-sh73a0.c | 9+++------
Adrivers/clk/renesas/r7s9210-cpg-mssr.c | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/renesas/r8a7743-cpg-mssr.c | 18+++++++++++++-----
Mdrivers/clk/renesas/r8a7745-cpg-mssr.c | 5+----
Adrivers/clk/renesas/r8a774a1-cpg-mssr.c | 323+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adrivers/clk/renesas/r8a774c0-cpg-mssr.c | 286+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/renesas/r8a7790-cpg-mssr.c | 5+----
Mdrivers/clk/renesas/r8a7791-cpg-mssr.c | 5+----
Mdrivers/clk/renesas/r8a7792-cpg-mssr.c | 5+----
Mdrivers/clk/renesas/r8a7794-cpg-mssr.c | 5+----
Mdrivers/clk/renesas/r8a7795-cpg-mssr.c | 72+++++++++++++++++++++++++++++++++++-------------------------------------
Mdrivers/clk/renesas/r8a7796-cpg-mssr.c | 72+++++++++++++++++++++++++++++++++++-------------------------------------
Mdrivers/clk/renesas/r8a77965-cpg-mssr.c | 69++++++++++++++++++++++++++++++++++++---------------------------------
Mdrivers/clk/renesas/r8a77970-cpg-mssr.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mdrivers/clk/renesas/r8a77980-cpg-mssr.c | 32+++++++++++++++++++++-----------
Mdrivers/clk/renesas/r8a77990-cpg-mssr.c | 17+++++++++++++----
Mdrivers/clk/renesas/r8a77995-cpg-mssr.c | 17+++++++++++------
Mdrivers/clk/renesas/r9a06g032-clocks.c | 3++-
Mdrivers/clk/renesas/rcar-gen2-cpg.c | 5+----
Mdrivers/clk/renesas/rcar-gen2-cpg.h | 7++-----
Mdrivers/clk/renesas/rcar-gen3-cpg.c | 45++++++++++++++++++++++++++++++++-------------
Mdrivers/clk/renesas/rcar-gen3-cpg.h | 33++++++++++++++++++++++++---------
Mdrivers/clk/renesas/rcar-usb2-clock-sel.c | 5+----
Mdrivers/clk/renesas/renesas-cpg-mssr.c | 205++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mdrivers/clk/renesas/renesas-cpg-mssr.h | 38+++++++++++++++++++++++++++++++++-----
Mdrivers/clk/rockchip/clk-ddr.c | 4----
Mdrivers/clk/rockchip/clk-rk3188.c | 2+-
Mdrivers/clk/rockchip/clk-rk3288.c | 29+++++++++++++++++++++++++----
Mdrivers/clk/rockchip/clk-rk3328.c | 8++++----
Mdrivers/clk/samsung/clk-cpu.c | 6+++---
Mdrivers/clk/samsung/clk-cpu.h | 2+-
Mdrivers/clk/samsung/clk-exynos-audss.c | 1-
Mdrivers/clk/samsung/clk-exynos3250.c | 1-
Mdrivers/clk/samsung/clk-exynos4.c | 226+++++--------------------------------------------------------------------------
Mdrivers/clk/samsung/clk-exynos5250.c | 42++----------------------------------------
Mdrivers/clk/samsung/clk-exynos5420.c | 76++++++++--------------------------------------------------------------------
Mdrivers/clk/samsung/clk-exynos5433.c | 33++++++++++++++++++++++++++++++++-
Mdrivers/clk/samsung/clk-s3c2410.c | 43++-----------------------------------------
Mdrivers/clk/samsung/clk-s3c2412.c | 43++-----------------------------------------
Mdrivers/clk/samsung/clk-s3c2443.c | 43++-----------------------------------------
Mdrivers/clk/samsung/clk-s3c64xx.c | 66++++++------------------------------------------------------------
Mdrivers/clk/samsung/clk-s5pv210.c | 41++---------------------------------------
Mdrivers/clk/samsung/clk.c | 23+++++++++++++----------
Mdrivers/clk/samsung/clk.h | 18++++++++++++++++--
Mdrivers/clk/st/clkgen-fsyn.c | 2+-
Mdrivers/clk/sunxi-ng/ccu-sun50i-a64.c | 48++++++++++++++++++++++++++----------------------
Mdrivers/clk/sunxi-ng/ccu-sun50i-a64.h | 4+++-
Mdrivers/clk/sunxi-ng/ccu-sun50i-h6.c | 53++++++++++++++++++++++++++++-------------------------
Mdrivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 2++
Mdrivers/clk/sunxi-ng/ccu-sun8i-h3.c | 25+++++++++++++------------
Mdrivers/clk/sunxi-ng/ccu-sun8i-r40.c | 52++++++++++++++++++++++++++--------------------------
Mdrivers/clk/sunxi-ng/ccu_nkmp.c | 7+++++++
Mdrivers/clk/sunxi-ng/ccu_nkmp.h | 1+
Mdrivers/clk/sunxi-ng/ccu_nm.c | 7+++++++
Mdrivers/clk/sunxi-ng/ccu_nm.h | 30++++++++++++++++++++++++++++++
Mdrivers/clk/sunxi/clk-mod0.c | 6+++---
Mdrivers/clk/sunxi/clk-sun9i-core.c | 20++++++++++----------
Mdrivers/clk/sunxi/clk-sunxi.c | 4++--
Mdrivers/clk/tegra/clk-dfll.c | 8++++++--
Mdrivers/clk/tegra/clk-tegra210.c | 7++++---
Mdrivers/clk/ti/Makefile | 9++++++---
Mdrivers/clk/ti/apll.c | 18+++++++++---------
Adrivers/clk/ti/clk-33xx-compat.c | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/ti/clk-33xx.c | 232++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Adrivers/clk/ti/clk-43xx-compat.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/ti/clk-43xx.c | 249+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Adrivers/clk/ti/clk-7xx-compat.c | 823+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/ti/clk-7xx.c | 590++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mdrivers/clk/ti/clk-dra7-atl.c | 4++--
Mdrivers/clk/ti/clk.c | 28++++++++++++++++++----------
Mdrivers/clk/ti/clkctrl.c | 101++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mdrivers/clk/ti/clock.h | 11+++++++++++
Mdrivers/clk/ti/composite.c | 14+++++++-------
Mdrivers/clk/ti/divider.c | 40++++++++++++++++++++++++++++++++++++++--
Mdrivers/clk/ti/dpll.c | 18++++++++++++------
Mdrivers/clk/ti/dpll3xxx.c | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/clk/ti/fapll.c | 8++++----
Mdrivers/clk/ti/fixed-factor.c | 4++--
Mdrivers/clk/ti/gate.c | 5++++-
Mdrivers/clk/ti/interface.c | 2+-
Mdrivers/clk/ti/mux.c | 33+++++++++++++++++++++++++++++++--
Mdrivers/clk/zynq/clkc.c | 4++--
Minclude/dt-bindings/clock/am3.h | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/dt-bindings/clock/am4.h | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/dt-bindings/clock/at91.h | 15+++++++++++++++
Minclude/dt-bindings/clock/dra7.h | 326++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Minclude/dt-bindings/clock/exynos4.h | 30------------------------------
Ainclude/dt-bindings/clock/hi3670-clock.h | 348+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/dt-bindings/clock/imx6qdl-clock.h | 3++-
Minclude/dt-bindings/clock/imx6sl-clock.h | 4+++-
Minclude/dt-bindings/clock/imx6sll-clock.h | 3++-
Minclude/dt-bindings/clock/imx6sx-clock.h | 3++-
Minclude/dt-bindings/clock/imx6ul-clock.h | 3++-
Ainclude/dt-bindings/clock/jz4725b-cgu.h | 35+++++++++++++++++++++++++++++++++++
Minclude/dt-bindings/clock/maxim,max77686.h | 5+----
Minclude/dt-bindings/clock/maxim,max77802.h | 5+----
Ainclude/dt-bindings/clock/qcom,camcc-sdm845.h | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/dt-bindings/clock/qcom,gcc-msm8960.h | 2++
Minclude/dt-bindings/clock/qcom,gcc-msm8996.h | 9+++++++++
Ainclude/dt-bindings/clock/qcom,gcc-qcs404.h | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/dt-bindings/clock/qcom,gcc-sdm660.h | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/dt-bindings/clock/qcom,gcc-sdm845.h | 3+++
Minclude/dt-bindings/clock/r7s72100-clock.h | 7++-----
Ainclude/dt-bindings/clock/r7s9210-cpg-mssr.h | 20++++++++++++++++++++
Minclude/dt-bindings/clock/r8a7743-cpg-mssr.h | 8++------
Ainclude/dt-bindings/clock/r8a7744-cpg-mssr.h | 39+++++++++++++++++++++++++++++++++++++++
Minclude/dt-bindings/clock/r8a7745-cpg-mssr.h | 8++------
Ainclude/dt-bindings/clock/r8a774a1-cpg-mssr.h | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/dt-bindings/clock/r8a774c0-cpg-mssr.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/dt-bindings/clock/r8a7790-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/r8a7791-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/r8a7792-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/r8a7793-clock.h | 12++----------
Minclude/dt-bindings/clock/r8a7793-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/r8a7794-clock.h | 8++------
Minclude/dt-bindings/clock/r8a7794-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/r8a7795-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/r8a7796-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/r8a77970-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/r8a77995-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/renesas-cpg-mssr.h | 8++------
Minclude/dt-bindings/clock/rk3188-cru-common.h | 3++-
Minclude/dt-bindings/clock/samsung,s2mps11.h | 5+----
Minclude/dt-bindings/clock/samsung,s3c64xx-clock.h | 7++-----
Minclude/dt-bindings/clock/sun50i-a64-ccu.h | 1+
Ainclude/dt-bindings/reset/actions,s700-reset.h | 34++++++++++++++++++++++++++++++++++
Ainclude/dt-bindings/reset/actions,s900-reset.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/linux/clk-provider.h | 9+++++++++
Minclude/linux/clk.h | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Minclude/linux/clk/renesas.h | 8++------
Minclude/linux/clk/ti.h | 7+++++++
284 files changed, 20482 insertions(+), 4223 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt @@ -21,10 +21,29 @@ PROPERTIES the register region. An optional second element specifies the base address and size of the alias register region. +- clocks: + Usage: required + Value type: <prop-encoded-array> + Definition: reference to the pll parents. + +- clock-names: + Usage: required + Value type: <stringlist> + Definition: must be "pll8_vote", "pxo". + +- clock-output-names: + Usage: optional + Value type: <string> + Definition: Name of the output clock. Typically acpuX_aux where X is a + CPU number starting at 0. + Example: clock-controller@2088000 { compatible = "qcom,kpss-acc-v2"; reg = <0x02088000 0x1000>, <0x02008000 0x1000>; + clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>; + clock-names = "pll8_vote", "pxo"; + clock-output-names = "acpu0_aux"; }; diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt @@ -0,0 +1,44 @@ +Krait Processor Sub-system (KPSS) Global Clock Controller (GCC) + +PROPERTIES + +- compatible: + Usage: required + Value type: <string> + Definition: should be one of the following. The generic compatible + "qcom,kpss-gcc" should also be included. + "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc" + "qcom,kpss-gcc-apq8064", "qcom,kpss-gcc" + "qcom,kpss-gcc-msm8974", "qcom,kpss-gcc" + "qcom,kpss-gcc-msm8960", "qcom,kpss-gcc" + +- reg: + Usage: required + Value type: <prop-encoded-array> + Definition: base address and size of the register region + +- clocks: + Usage: required + Value type: <prop-encoded-array> + Definition: reference to the pll parents. + +- clock-names: + Usage: required + Value type: <stringlist> + Definition: must be "pll8_vote", "pxo". + +- clock-output-names: + Usage: required + Value type: <string> + Definition: Name of the output clock. Typically acpu_l2_aux indicating + an L2 cache auxiliary clock. + +Example: + + l2cc: clock-controller@2011000 { + compatible = "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc"; + reg = <0x2011000 0x1000>; + clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>; + clock-names = "pll8_vote", "pxo"; + clock-output-names = "acpu_l2_aux"; + }; diff --git a/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt b/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt @@ -13,6 +13,7 @@ Required Properties: region. - clocks: Reference to the parent clocks ("hosc", "losc") - #clock-cells: should be 1. +- #reset-cells: should be 1. Each clock is assigned an identifier, and client nodes can use this identifier to specify the clock which they consume. @@ -36,6 +37,7 @@ Example: Clock Management Unit node: reg = <0x0 0xe0160000 0x0 0x1000>; clocks = <&hosc>, <&losc>; #clock-cells = <1>; + #reset-cells = <1>; }; Example: UART controller node that consumes clock generated by the clock diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -4,6 +4,8 @@ This binding uses the common clock binding[1]. [1] Documentation/devicetree/bindings/clock/clock-bindings.txt +Slow Clock controller: + Required properties: - compatible : shall be one of the following: "atmel,at91sam9x5-sckc" or @@ -16,84 +18,6 @@ Required properties: "atmel,at91sam9x5-clk-slow-rc-osc": at91 internal slow RC oscillator - - "atmel,<chip>-pmc": - at91 PMC (Power Management Controller) - All at91 specific clocks (clocks defined below) must be child - node of the PMC node. - <chip> can be: at91rm9200, at91sam9260, at91sam9261, - at91sam9263, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9x5, - sama5d2, sama5d3 or sama5d4. - - "atmel,at91sam9x5-clk-slow" (under sckc node) - or - "atmel,at91sam9260-clk-slow" (under pmc node): - at91 slow clk - - "atmel,at91rm9200-clk-main-osc" - "atmel,at91sam9x5-clk-main-rc-osc" - at91 main clk sources - - "atmel,at91sam9x5-clk-main" - "atmel,at91rm9200-clk-main": - at91 main clock - - "atmel,at91rm9200-clk-master" or - "atmel,at91sam9x5-clk-master": - at91 master clock - - "atmel,at91sam9x5-clk-peripheral" or - "atmel,at91rm9200-clk-peripheral": - at91 peripheral clocks - - "atmel,at91rm9200-clk-pll" or - "atmel,at91sam9g45-clk-pll" or - "atmel,at91sam9g20-clk-pllb" or - "atmel,sama5d3-clk-pll": - at91 pll clocks - - "atmel,at91sam9x5-clk-plldiv": - at91 plla divisor - - "atmel,at91rm9200-clk-programmable" or - "atmel,at91sam9g45-clk-programmable" or - "atmel,at91sam9x5-clk-programmable": - at91 programmable clocks - - "atmel,at91sam9x5-clk-smd": - at91 SMD (Soft Modem) clock - - "atmel,at91rm9200-clk-system": - at91 system clocks - - "atmel,at91rm9200-clk-usb" or - "atmel,at91sam9x5-clk-usb" or - "atmel,at91sam9n12-clk-usb": - at91 usb clock - - "atmel,at91sam9x5-clk-utmi": - at91 utmi clock - - "atmel,sama5d4-clk-h32mx": - at91 h32mx clock - - "atmel,sama5d2-clk-generated": - at91 generated clock - - "atmel,sama5d2-clk-audio-pll-frac": - at91 audio fractional pll - - "atmel,sama5d2-clk-audio-pll-pad": - at91 audio pll CLK_AUDIO output pin - - "atmel,sama5d2-clk-audio-pll-pmc" - at91 audio pll output on AUDIOPLLCLK that feeds the PMC - and can be used by peripheral clock or generic clock - - "atmel,sama5d2-clk-i2s-mux" (under pmc node): - at91 I2S clock source selection - -Required properties for SCKC node: - reg : defines the IO memory reserved for the SCKC. - #size-cells : shall be 0 (reg is used to encode clk id). - #address-cells : shall be 1 (reg is used to encode clk id). @@ -109,428 +33,30 @@ For example: /* put at91 slow clocks here */ }; +Power Management Controller (PMC): -Required properties for internal slow RC oscillator: -- #clock-cells : from common clock binding; shall be set to 0. -- clock-frequency : define the internal RC oscillator frequency. - -Optional properties: -- clock-accuracy : define the internal RC oscillator accuracy. - -For example: - slow_rc_osc: slow_rc_osc { - compatible = "atmel,at91sam9x5-clk-slow-rc-osc"; - clock-frequency = <32768>; - clock-accuracy = <50000000>; - }; - -Required properties for slow oscillator: -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall encode the main osc source clk sources (see atmel datasheet). +Required properties: +- compatible : shall be "atmel,<chip>-pmc", "syscon": + <chip> can be: at91rm9200, at91sam9260, at91sam9261, + at91sam9263, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9g15, + at91sam9g25, at91sam9g35, at91sam9x25, at91sam9x35, at91sam9x5, + sama5d2, sama5d3 or sama5d4. +- #clock-cells : from common clock binding; shall be set to 2. The first entry + is the type of the clock (core, system, peripheral or generated) and the + second entry its index as provided by the datasheet +- clocks : Must contain an entry for each entry in clock-names. +- clock-names: Must include the following entries: "slow_clk", "main_xtal" Optional properties: - atmel,osc-bypass : boolean property. Set this when a clock signal is directly provided on XIN. For example: - slow_osc: slow_osc { - compatible = "atmel,at91rm9200-clk-slow-osc"; - #clock-cells = <0>; - clocks = <&slow_xtal>; - }; - -Required properties for slow clock: -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall encode the slow clk sources (see atmel datasheet). - -For example: - clk32k: slck { - compatible = "atmel,at91sam9x5-clk-slow"; - #clock-cells = <0>; - clocks = <&slow_rc_osc &slow_osc>; - }; - -Required properties for PMC node: -- reg : defines the IO memory reserved for the PMC. -- #size-cells : shall be 0 (reg is used to encode clk id). -- #address-cells : shall be 1 (reg is used to encode clk id). -- interrupts : shall be set to PMC interrupt line. -- interrupt-controller : tell that the PMC is an interrupt controller. -- #interrupt-cells : must be set to 1. The first cell encodes the interrupt id, - and reflect the bit position in the PMC_ER/DR/SR registers. - You can use the dt macros defined in dt-bindings/clock/at91.h. - 0 (AT91_PMC_MOSCS) -> main oscillator ready - 1 (AT91_PMC_LOCKA) -> PLL A ready - 2 (AT91_PMC_LOCKB) -> PLL B ready - 3 (AT91_PMC_MCKRDY) -> master clock ready - 6 (AT91_PMC_LOCKU) -> UTMI PLL clock ready - 8 .. 15 (AT91_PMC_PCKRDY(id)) -> programmable clock ready - 16 (AT91_PMC_MOSCSELS) -> main oscillator selected - 17 (AT91_PMC_MOSCRCS) -> RC main oscillator stabilized - 18 (AT91_PMC_CFDEV) -> clock failure detected - -For example: - pmc: pmc@fffffc00 { - compatible = "atmel,sama5d3-pmc"; - interrupts = <1 4 7>; - interrupt-controller; - #interrupt-cells = <2>; - #size-cells = <0>; - #address-cells = <1>; - - /* put at91 clocks here */ - }; - -Required properties for main clock internal RC oscillator: -- interrupts : shall be set to "<0>". -- clock-frequency : define the internal RC oscillator frequency. - -Optional properties: -- clock-accuracy : define the internal RC oscillator accuracy. - -For example: - main_rc_osc: main_rc_osc { - compatible = "atmel,at91sam9x5-clk-main-rc-osc"; - interrupt-parent = <&pmc>; - interrupts = <0>; - clock-frequency = <12000000>; - clock-accuracy = <50000000>; - }; - -Required properties for main clock oscillator: -- interrupts : shall be set to "<0>". -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall encode the main osc source clk sources (see atmel datasheet). - -Optional properties: -- atmel,osc-bypass : boolean property. Specified if a clock signal is provided - on XIN. - - clock signal is directly provided on XIN pin. - -For example: - main_osc: main_osc { - compatible = "atmel,at91rm9200-clk-main-osc"; - interrupt-parent = <&pmc>; - interrupts = <0>; - #clock-cells = <0>; - clocks = <&main_xtal>; - }; - -Required properties for main clock: -- interrupts : shall be set to "<0>". -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall encode the main clk sources (see atmel datasheet). - -For example: - main: mainck { - compatible = "atmel,at91sam9x5-clk-main"; - interrupt-parent = <&pmc>; - interrupts = <0>; - #clock-cells = <0>; - clocks = <&main_rc_osc &main_osc>; - }; - -Required properties for master clock: -- interrupts : shall be set to "<3>". -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall be the master clock sources (see atmel datasheet) phandles. - e.g. "<&ck32k>, <&main>, <&plla>, <&pllb>". -- atmel,clk-output-range : minimum and maximum clock frequency (two u32 - fields). - e.g. output = <0 133000000>; <=> 0 to 133MHz. -- atmel,clk-divisors : master clock divisors table (four u32 fields). - 0 <=> reserved value. - e.g. divisors = <1 2 4 6>; -- atmel,master-clk-have-div3-pres : some SoC use the reserved value 7 in the - PRES field as CLOCK_DIV3 (e.g sam9x5). - -For example: - mck: mck { - compatible = "atmel,at91rm9200-clk-master"; - interrupt-parent = <&pmc>; - interrupts = <3>; - #clock-cells = <0>; - atmel,clk-output-range = <0 133000000>; - atmel,clk-divisors = <1 2 4 0>; - }; - -Required properties for peripheral clocks: -- #size-cells : shall be 0 (reg is used to encode clk id). -- #address-cells : shall be 1 (reg is used to encode clk id). -- clocks : shall be the master clock phandle. - e.g. clocks = <&mck>; -- name: device tree node describing a specific peripheral clock. - * #clock-cells : from common clock binding; shall be set to 0. - * reg: peripheral id. See Atmel's datasheets to get a full - list of peripheral ids. - * atmel,clk-output-range : minimum and maximum clock frequency - (two u32 fields). Only valid on at91sam9x5-clk-peripheral - compatible IPs. - -For example: - periph: periphck { - compatible = "atmel,at91sam9x5-clk-peripheral"; - #size-cells = <0>; - #address-cells = <1>; - clocks = <&mck>; - - ssc0_clk { - #clock-cells = <0>; - reg = <2>; - atmel,clk-output-range = <0 133000000>; - }; - - usart0_clk { - #clock-cells = <0>; - reg = <3>; - atmel,clk-output-range = <0 66000000>; - }; - }; - - -Required properties for pll clocks: -- interrupts : shall be set to "<1>". -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall be the main clock phandle. -- reg : pll id. - 0 -> PLL A - 1 -> PLL B -- atmel,clk-input-range : minimum and maximum source clock frequency (two u32 - fields). - e.g. input = <1 32000000>; <=> 1 to 32MHz. -- #atmel,pll-clk-output-range-cells : number of cells reserved for pll output - range description. Sould be set to 2, 3 - or 4. - * 1st and 2nd cells represent the frequency range (min-max). - * 3rd cell is optional and represents the OUT field value for the given - range. - * 4th cell is optional and represents the ICPLL field (PLLICPR - register) -- atmel,pll-clk-output-ranges : pll output frequency ranges + optional parameter - depending on #atmel,pll-output-range-cells - property value. - -For example: - plla: pllack { - compatible = "atmel,at91sam9g45-clk-pll"; - interrupt-parent = <&pmc>; - interrupts = <1>; - #clock-cells = <0>; - clocks = <&main>; - reg = <0>; - atmel,clk-input-range = <2000000 32000000>; - #atmel,pll-clk-output-range-cells = <4>; - atmel,pll-clk-output-ranges = <74500000 800000000 0 0 - 69500000 750000000 1 0 - 64500000 700000000 2 0 - 59500000 650000000 3 0 - 54500000 600000000 0 1 - 49500000 550000000 1 1 - 44500000 500000000 2 1 - 40000000 450000000 3 1>; - }; - -Required properties for plldiv clocks (plldiv = pll / 2): -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall be the plla clock phandle. - -The pll divisor is equal to 2 and cannot be changed. - -For example: - plladiv: plladivck { - compatible = "atmel,at91sam9x5-clk-plldiv"; - #clock-cells = <0>; - clocks = <&plla>; - }; - -Required properties for programmable clocks: -- #size-cells : shall be 0 (reg is used to encode clk id). -- #address-cells : shall be 1 (reg is used to encode clk id). -- clocks : shall be the programmable clock source phandles. - e.g. clocks = <&clk32k>, <&main>, <&plla>, <&pllb>; -- name: device tree node describing a specific prog clock. - * #clock-cells : from common clock binding; shall be set to 0. - * reg : programmable clock id (register offset from PCKx - register). - * interrupts : shall be set to "<(8 + id)>". - -For example: - prog: progck { - compatible = "atmel,at91sam9g45-clk-programmable"; - #size-cells = <0>; - #address-cells = <1>; - interrupt-parent = <&pmc>; - clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>; - - prog0 { - #clock-cells = <0>; - reg = <0>; - interrupts = <8>; - }; - - prog1 { - #clock-cells = <0>; - reg = <1>; - interrupts = <9>; - }; - }; - - -Required properties for smd clock: -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall be the smd clock source phandles. - e.g. clocks = <&plladiv>, <&utmi>; - -For example: - smd: smdck { - compatible = "atmel,at91sam9x5-clk-smd"; - #clock-cells = <0>; - clocks = <&plladiv>, <&utmi>; - }; - -Required properties for system clocks: -- #size-cells : shall be 0 (reg is used to encode clk id). -- #address-cells : shall be 1 (reg is used to encode clk id). -- name: device tree node describing a specific system clock. - * #clock-cells : from common clock binding; shall be set to 0. - * reg: system clock id (bit position in SCER/SCDR/SCSR registers). - See Atmel's datasheet to get a full list of system clock ids. - -For example: - system: systemck { - compatible = "atmel,at91rm9200-clk-system"; - #address-cells = <1>; - #size-cells = <0>; - - ddrck { - #clock-cells = <0>; - reg = <2>; - clocks = <&mck>; - }; - - uhpck { - #clock-cells = <0>; - reg = <6>; - clocks = <&usb>; - }; - - udpck { - #clock-cells = <0>; - reg = <7>; - clocks = <&usb>; - }; - }; - - -Required properties for usb clock: -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall be the smd clock source phandles. - e.g. clocks = <&pllb>; -- atmel,clk-divisors (only available for "atmel,at91rm9200-clk-usb"): - usb clock divisor table. - e.g. divisors = <1 2 4 0>; - -For example: - usb: usbck { - compatible = "atmel,at91sam9x5-clk-usb"; - #clock-cells = <0>; - clocks = <&plladiv>, <&utmi>; - }; - - usb: usbck { - compatible = "atmel,at91rm9200-clk-usb"; - #clock-cells = <0>; - clocks = <&pllb>; - atmel,clk-divisors = <1 2 4 0>; - }; - - -Required properties for utmi clock: -- interrupts : shall be set to "<AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>". -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall be the main clock source phandle. - -For example: - utmi: utmick { - compatible = "atmel,at91sam9x5-clk-utmi"; - interrupt-parent = <&pmc>; - interrupts = <AT91_PMC_LOCKU IRQ_TYPE_LEVEL_HIGH>; - #clock-cells = <0>; - clocks = <&main>; - }; - -Required properties for 32 bits bus Matrix clock (h32mx clock): -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : shall be the master clock source phandle. - -For example: - h32ck: h32mxck { - #clock-cells = <0>; - compatible = "atmel,sama5d4-clk-h32mx"; - clocks = <&mck>; - }; - -Required properties for generated clocks: -- #size-cells : shall be 0 (reg is used to encode clk id). -- #address-cells : shall be 1 (reg is used to encode clk id). -- clocks : shall be the generated clock source phandles. - e.g. clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; -- name: device tree node describing a specific generated clock. - * #clock-cells : from common clock binding; shall be set to 0. - * reg: peripheral id. See Atmel's datasheets to get a full - list of peripheral ids. - * atmel,clk-output-range : minimum and maximum clock frequency - (two u32 fields). - -For example: - gck { - compatible = "atmel,sama5d2-clk-generated"; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; - - tcb0_gclk: tcb0_gclk { - #clock-cells = <0>; - reg = <35>; - atmel,clk-output-range = <0 83000000>; - }; - - pwm_gclk: pwm_gclk { - #clock-cells = <0>; - reg = <38>; - atmel,clk-output-range = <0 83000000>; - }; - }; - -Required properties for I2S mux clocks: -- #size-cells : shall be 0 (reg is used to encode I2S bus id). -- #address-cells : shall be 1 (reg is used to encode I2S bus id). -- name: device tree node describing a specific mux clock. - * #clock-cells : from common clock binding; shall be set to 0. - * clocks : shall be the mux clock parent phandles; shall be 2 phandles: - peripheral and generated clock; the first phandle shall belong to the - peripheral clock and the second one shall belong to the generated - clock; "clock-indices" property can be user to specify - the correct order. - * reg: I2S bus id of the corresponding mux clock. - e.g. reg = <0>; for i2s0, reg = <1>; for i2s1 - -For example: - i2s_clkmux { - compatible = "atmel,sama5d2-clk-i2s-mux"; - #address-cells = <1>; - #size-cells = <0>; - - i2s0muxck: i2s0_muxclk { - clocks = <&i2s0_clk>, <&i2s0_gclk>; - #clock-cells = <0>; - reg = <0>; - }; - - i2s1muxck: i2s1_muxclk { - clocks = <&i2s1_clk>, <&i2s1_gclk>; - #clock-cells = <0>; - reg = <1>; - }; + pmc: pmc@f0018000 { + compatible = "atmel,sama5d4-pmc", "syscon"; + reg = <0xf0018000 0x120>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + #clock-cells = <2>; + clocks = <&clk32k>, <&main_xtal>; + clock-names = "slow_clk", "main_xtal"; }; diff --git a/Documentation/devicetree/bindings/clock/hi3670-clock.txt b/Documentation/devicetree/bindings/clock/hi3670-clock.txt @@ -0,0 +1,43 @@ +* Hisilicon Hi3670 Clock Controller + +The Hi3670 clock controller generates and supplies clock to various +controllers within the Hi3670 SoC. + +Required Properties: + +- compatible: the compatible should be one of the following strings to + indicate the clock controller functionality. + + - "hisilicon,hi3670-crgctrl" + - "hisilicon,hi3670-pctrl" + - "hisilicon,hi3670-pmuctrl" + - "hisilicon,hi3670-sctrl" + - "hisilicon,hi3670-iomcu" + - "hisilicon,hi3670-media1-crg" + - "hisilicon,hi3670-media2-crg" + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in <dt-bindings/clock/hi3670-clock.h>. + +Examples: + crg_ctrl: clock-controller@fff35000 { + compatible = "hisilicon,hi3670-crgctrl", "syscon"; + reg = <0x0 0xfff35000 0x0 0x1000>; + #clock-cells = <1>; + }; + + uart0: serial@fdf02000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0xfdf02000 0x0 0x1000>; + interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg_ctrl HI3670_CLK_GATE_UART0>, + <&crg_ctrl HI3670_PCLK>; + clock-names = "uartclk", "apb_pclk"; + }; diff --git a/Documentation/devicetree/bindings/clock/ingenic,cgu.txt b/Documentation/devicetree/bindings/clock/ingenic,cgu.txt @@ -6,8 +6,11 @@ to provide many different clock signals derived from only 2 external source clocks. Required properties: -- compatible : Should be "ingenic,<soctype>-cgu". - For example "ingenic,jz4740-cgu" or "ingenic,jz4780-cgu". +- compatible : Should be one of: + * ingenic,jz4740-cgu + * ingenic,jz4725b-cgu + * ingenic,jz4770-cgu + * ingenic,jz4780-cgu - reg : The address & length of the CGU registers. - clocks : List of phandle & clock specifiers for clocks external to the CGU. Two such external clocks should be specified - first the external crystal diff --git a/Documentation/devicetree/bindings/clock/qcom,camcc.txt b/Documentation/devicetree/bindings/clock/qcom,camcc.txt @@ -0,0 +1,18 @@ +Qualcomm Camera Clock & Reset Controller Binding +------------------------------------------------ + +Required properties : +- compatible : shall contain "qcom,sdm845-camcc". +- reg : shall contain base register location and length. +- #clock-cells : from common clock binding, shall contain 1. +- #reset-cells : from common reset binding, shall contain 1. +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Example: + camcc: clock-controller@ad00000 { + compatible = "qcom,sdm845-camcc"; + reg = <0xad00000 0x10000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -19,6 +19,9 @@ Required properties : "qcom,gcc-msm8996" "qcom,gcc-msm8998" "qcom,gcc-mdm9615" + "qcom,gcc-qcs404" + "qcom,gcc-sdm630" + "qcom,gcc-sdm660" "qcom,gcc-sdm845" - reg : shall contain base register location and length diff --git a/Documentation/devicetree/bindings/clock/qcom,hfpll.txt b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt @@ -0,0 +1,60 @@ +High-Frequency PLL (HFPLL) + +PROPERTIES + +- compatible: + Usage: required + Value type: <string>: + shall contain only one of the following. The generic + compatible "qcom,hfpll" should be also included. + + "qcom,hfpll-ipq8064", "qcom,hfpll" + "qcom,hfpll-apq8064", "qcom,hfpll" + "qcom,hfpll-msm8974", "qcom,hfpll" + "qcom,hfpll-msm8960", "qcom,hfpll" + +- reg: + Usage: required + Value type: <prop-encoded-array> + Definition: address and size of HPLL registers. An optional second + element specifies the address and size of the alias + register region. + +- clocks: + Usage: required + Value type: <prop-encoded-array> + Definition: reference to the xo clock. + +- clock-names: + Usage: required + Value type: <stringlist> + Definition: must be "xo". + +- clock-output-names: + Usage: required + Value type: <string> + Definition: Name of the PLL. Typically hfpllX where X is a CPU number + starting at 0. Otherwise hfpll_Y where Y is more specific + such as "l2". + +Example: + +1) An HFPLL for the L2 cache. + + clock-controller@f9016000 { + compatible = "qcom,hfpll-ipq8064", "qcom,hfpll"; + reg = <0xf9016000 0x30>; + clocks = <&xo_board>; + clock-names = "xo"; + clock-output-names = "hfpll_l2"; + }; + +2) An HFPLL for CPU0. This HFPLL has the alias register region. + + clock-controller@f908a000 { + compatible = "qcom,hfpll-ipq8064", "qcom,hfpll"; + reg = <0xf908a000 0x30>, <0xf900a000 0x30>; + clocks = <&xo_board>; + clock-names = "xo"; + clock-output-names = "hfpll0"; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt @@ -0,0 +1,34 @@ +Krait Clock Controller + +PROPERTIES + +- compatible: + Usage: required + Value type: <string> + Definition: must be one of: + "qcom,krait-cc-v1" + "qcom,krait-cc-v2" + +- #clock-cells: + Usage: required + Value type: <u32> + Definition: must be 1 + +- clocks: + Usage: required + Value type: <prop-encoded-array> + Definition: reference to the clock parents of hfpll, secondary muxes. + +- clock-names: + Usage: required + Value type: <stringlist> + Definition: must be "hfpll0", "hfpll1", "acpu0_aux", "acpu1_aux", "qsb". + +Example: + + kraitcc: clock-controller { + compatible = "qcom,krait-cc-v1"; + clocks = <&hfpll0>, <&hfpll1>, <&acpu0_aux>, <&acpu1_aux>, <qsb>; + clock-names = "hfpll0", "hfpll1", "acpu0_aux", "acpu1_aux", "qsb"; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.txt @@ -13,9 +13,13 @@ They provide the following functionalities: Required Properties: - compatible: Must be one of: + - "renesas,r7s9210-cpg-mssr" for the r7s9210 SoC (RZ/A2) - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M) + - "renesas,r8a7744-cpg-mssr" for the r8a7744 SoC (RZ/G1N) - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E) - "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C) + - "renesas,r8a774a1-cpg-mssr" for the r8a774a1 SoC (RZ/G2M) + - "renesas,r8a774c0-cpg-mssr" for the r8a774c0 SoC (RZ/G2E) - "renesas,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2) - "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W) - "renesas,r8a7792-cpg-mssr" for the r8a7792 SoC (R-Car V2H) @@ -35,12 +39,13 @@ Required Properties: - clocks: References to external parent clocks, one entry for each entry in clock-names - clock-names: List of external parent clock names. Valid names are: - - "extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7792, - r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, r8a77970, - r8a77980, r8a77990, r8a77995) - - "extalr" (r8a7795, r8a7796, r8a77965, r8a77970, r8a77980) - - "usb_extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7793, - r8a7794) + - "extal" (r7s9210, r8a7743, r8a7744, r8a7745, r8a77470, r8a774a1, + r8a774c0, r8a7790, r8a7791, r8a7792, r8a7793, r8a7794, + r8a7795, r8a7796, r8a77965, r8a77970, r8a77980, r8a77990, + r8a77995) + - "extalr" (r8a774a1, r8a7795, r8a7796, r8a77965, r8a77970, r8a77980) + - "usb_extal" (r8a7743, r8a7744, r8a7745, r8a77470, r8a7790, r8a7791, + r8a7793, r8a7794) - #clock-cells: Must be 2 - For CPG core clocks, the two clock specifier cells must be "CPG_CORE" diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig @@ -7,6 +7,9 @@ config DMABOUNCE bool select ZONE_DMA +config KRAIT_L2_ACCESSORS + bool + config SHARP_LOCOMO bool diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile @@ -7,6 +7,7 @@ obj-y += firmware.o obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_DMABOUNCE) += dmabounce.o +obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o obj-$(CONFIG_SHARP_LOCOMO) += locomo.o obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o diff --git a/arch/arm/common/krait-l2-accessors.c b/arch/arm/common/krait-l2-accessors.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, The Linux Foundation. All rights reserved. + +#include <linux/spinlock.h> +#include <linux/export.h> + +#include <asm/barrier.h> +#include <asm/krait-l2-accessors.h> + +static DEFINE_RAW_SPINLOCK(krait_l2_lock); + +void krait_set_l2_indirect_reg(u32 addr, u32 val) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&krait_l2_lock, flags); + /* + * Select the L2 window by poking l2cpselr, then write to the window + * via l2cpdr. + */ + asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr)); + isb(); + asm volatile ("mcr p15, 3, %0, c15, c0, 7 @ l2cpdr" : : "r" (val)); + isb(); + + raw_spin_unlock_irqrestore(&krait_l2_lock, flags); +} +EXPORT_SYMBOL(krait_set_l2_indirect_reg); + +u32 krait_get_l2_indirect_reg(u32 addr) +{ + u32 val; + unsigned long flags; + + raw_spin_lock_irqsave(&krait_l2_lock, flags); + /* + * Select the L2 window by poking l2cpselr, then read from the window + * via l2cpdr. + */ + asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr)); + isb(); + asm volatile ("mrc p15, 3, %0, c15, c0, 7 @ l2cpdr" : "=r" (val)); + + raw_spin_unlock_irqrestore(&krait_l2_lock, flags); + + return val; +} +EXPORT_SYMBOL(krait_get_l2_indirect_reg); diff --git a/arch/arm/include/asm/krait-l2-accessors.h b/arch/arm/include/asm/krait-l2-accessors.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASMARM_KRAIT_L2_ACCESSORS_H +#define __ASMARM_KRAIT_L2_ACCESSORS_H + +extern void krait_set_l2_indirect_reg(u32 addr, u32 val); +extern u32 krait_get_l2_indirect_reg(u32 addr); + +#endif diff --git a/arch/arm/mach-davinci/include/mach/clock.h b/arch/arm/mach-davinci/include/mach/clock.h @@ -1,21 +0,0 @@ -/* - * arch/arm/mach-davinci/include/mach/clock.h - * - * Clock control driver for DaVinci - header file - * - * Authors: Vladimir Barinov <source@mvista.com> - * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#ifndef __ASM_ARCH_DAVINCI_CLOCK_H -#define __ASM_ARCH_DAVINCI_CLOCK_H - -struct clk; - -int davinci_clk_reset_assert(struct clk *c); -int davinci_clk_reset_deassert(struct clk *c); - -#endif diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig @@ -287,6 +287,7 @@ source "drivers/clk/actions/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/imgtec/Kconfig" +source "drivers/clk/ingenic/Kconfig" source "drivers/clk/keystone/Kconfig" source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile @@ -72,7 +72,8 @@ obj-$(CONFIG_H8300) += h8300/ obj-$(CONFIG_ARCH_HISI) += hisilicon/ obj-y += imgtec/ obj-$(CONFIG_ARCH_MXC) += imx/ -obj-$(CONFIG_MACH_INGENIC) += ingenic/ +obj-y += ingenic/ +obj-$(CONFIG_ARCH_K3) += keystone/ obj-$(CONFIG_ARCH_KEYSTONE) += keystone/ obj-$(CONFIG_MACH_LOONGSON32) += loongson1/ obj-y += mediatek/ diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig @@ -2,6 +2,7 @@ config CLK_ACTIONS bool "Clock driver for Actions Semi SoCs" depends on ARCH_ACTIONS || COMPILE_TEST select REGMAP_MMIO + select RESET_CONTROLLER default ARCH_ACTIONS if CLK_ACTIONS diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile @@ -7,6 +7,7 @@ clk-owl-y += owl-divider.o clk-owl-y += owl-factor.o clk-owl-y += owl-composite.o clk-owl-y += owl-pll.o +clk-owl-y += owl-reset.o # SoC support obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o diff --git a/drivers/clk/actions/owl-common.c b/drivers/clk/actions/owl-common.c @@ -39,7 +39,7 @@ static void owl_clk_set_regmap(const struct owl_clk_desc *desc, } int owl_clk_regmap_init(struct platform_device *pdev, - const struct owl_clk_desc *desc) + struct owl_clk_desc *desc) { void __iomem *base; struct regmap *regmap; @@ -57,6 +57,7 @@ int owl_clk_regmap_init(struct platform_device *pdev, } owl_clk_set_regmap(desc, regmap); + desc->regmap = regmap; return 0; } diff --git a/drivers/clk/actions/owl-common.h b/drivers/clk/actions/owl-common.h @@ -26,6 +26,9 @@ struct owl_clk_desc { struct owl_clk_common **clks; unsigned long num_clks; struct clk_hw_onecell_data *hw_clks; + const struct owl_reset_map *resets; + unsigned long num_resets; + struct regmap *regmap; }; static inline struct owl_clk_common * @@ -35,7 +38,7 @@ static inline struct owl_clk_common * } int owl_clk_regmap_init(struct platform_device *pdev, - const struct owl_clk_desc *desc); + struct owl_clk_desc *desc); int owl_clk_probe(struct device *dev, struct clk_hw_onecell_data *hw_clks); #endif /* _OWL_COMMON_H_ */ diff --git a/drivers/clk/actions/owl-reset.c b/drivers/clk/actions/owl-reset.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Actions Semi Owl SoCs Reset Management Unit driver +// +// Copyright (c) 2018 Linaro Ltd. +// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + +#include <linux/delay.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> + +#include "owl-reset.h" + +static int owl_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct owl_reset *reset = to_owl_reset(rcdev); + const struct owl_reset_map *map = &reset->reset_map[id]; + + return regmap_update_bits(reset->regmap, map->reg, map->bit, 0); +} + +static int owl_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct owl_reset *reset = to_owl_reset(rcdev); + const struct owl_reset_map *map = &reset->reset_map[id]; + + return regmap_update_bits(reset->regmap, map->reg, map->bit, map->bit); +} + +static int owl_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + owl_reset_assert(rcdev, id); + udelay(1); + owl_reset_deassert(rcdev, id); + + return 0; +} + +static int owl_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct owl_reset *reset = to_owl_reset(rcdev); + const struct owl_reset_map *map = &reset->reset_map[id]; + u32 reg; + int ret; + + ret = regmap_read(reset->regmap, map->reg, &reg); + if (ret) + return ret; + + /* + * The reset control API expects 0 if reset is not asserted, + * which is the opposite of what our hardware uses. + */ + return !(map->bit & reg); +} + +const struct reset_control_ops owl_reset_ops = { + .assert = owl_reset_assert, + .deassert = owl_reset_deassert, + .reset = owl_reset_reset, + .status = owl_reset_status, +}; diff --git a/drivers/clk/actions/owl-reset.h b/drivers/clk/actions/owl-reset.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Actions Semi Owl SoCs Reset Management Unit driver +// +// Copyright (c) 2018 Linaro Ltd. +// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + +#ifndef _OWL_RESET_H_ +#define _OWL_RESET_H_ + +#include <linux/reset-controller.h> + +struct owl_reset_map { + u32 reg; + u32 bit; +}; + +struct owl_reset { + struct reset_controller_dev rcdev; + const struct owl_reset_map *reset_map; + struct regmap *regmap; +}; + +static inline struct owl_reset *to_owl_reset(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct owl_reset, rcdev); +} + +extern const struct reset_control_ops owl_reset_ops; + +#endif /* _OWL_RESET_H_ */ diff --git a/drivers/clk/actions/owl-s700.c b/drivers/clk/actions/owl-s700.c @@ -20,8 +20,10 @@ #include "owl-gate.h" #include "owl-mux.h" #include "owl-pll.h" +#include "owl-reset.h" #include <dt-bindings/clock/actions,s700-cmu.h> +#include <dt-bindings/reset/actions,s700-reset.h> #define CMU_COREPLL (0x0000) #define CMU_DEVPLL (0x0004) @@ -569,20 +571,69 @@ static struct clk_hw_onecell_data s700_hw_clks = { .num = CLK_NR_CLKS, }; -static const struct owl_clk_desc s700_clk_desc = { +static const struct owl_reset_map s700_resets[] = { + [RESET_DE] = { CMU_DEVRST0, BIT(0) }, + [RESET_LCD0] = { CMU_DEVRST0, BIT(1) }, + [RESET_DSI] = { CMU_DEVRST0, BIT(2) }, + [RESET_CSI] = { CMU_DEVRST0, BIT(13) }, + [RESET_SI] = { CMU_DEVRST0, BIT(14) }, + [RESET_I2C0] = { CMU_DEVRST1, BIT(0) }, + [RESET_I2C1] = { CMU_DEVRST1, BIT(1) }, + [RESET_I2C2] = { CMU_DEVRST1, BIT(2) }, + [RESET_I2C3] = { CMU_DEVRST1, BIT(3) }, + [RESET_SPI0] = { CMU_DEVRST1, BIT(4) }, + [RESET_SPI1] = { CMU_DEVRST1, BIT(5) }, + [RESET_SPI2] = { CMU_DEVRST1, BIT(6) }, + [RESET_SPI3] = { CMU_DEVRST1, BIT(7) }, + [RESET_UART0] = { CMU_DEVRST1, BIT(8) }, + [RESET_UART1] = { CMU_DEVRST1, BIT(9) }, + [RESET_UART2] = { CMU_DEVRST1, BIT(10) }, + [RESET_UART3] = { CMU_DEVRST1, BIT(11) }, + [RESET_UART4] = { CMU_DEVRST1, BIT(12) }, + [RESET_UART5] = { CMU_DEVRST1, BIT(13) }, + [RESET_UART6] = { CMU_DEVRST1, BIT(14) }, + [RESET_KEY] = { CMU_DEVRST1, BIT(24) }, + [RESET_GPIO] = { CMU_DEVRST1, BIT(25) }, + [RESET_AUDIO] = { CMU_DEVRST1, BIT(29) }, +}; + +static struct owl_clk_desc s700_clk_desc = { .clks = s700_clks, .num_clks = ARRAY_SIZE(s700_clks), .hw_clks = &s700_hw_clks, + + .resets = s700_resets, + .num_resets = ARRAY_SIZE(s700_resets), }; static int s700_clk_probe(struct platform_device *pdev) { - const struct owl_clk_desc *desc; + struct owl_clk_desc *desc; + struct owl_reset *reset; + int ret; desc = &s700_clk_desc; owl_clk_regmap_init(pdev, desc); + /* + * FIXME: Reset controller registration should be moved to + * common code, once all SoCs of Owl family supports it. + */ + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + reset->rcdev.of_node = pdev->dev.of_node; + reset->rcdev.ops = &owl_reset_ops; + reset->rcdev.nr_resets = desc->num_resets; + reset->reset_map = desc->resets; + reset->regmap = desc->regmap; + + ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev); + if (ret) + dev_err(&pdev->dev, "Failed to register reset controller\n"); + return owl_clk_probe(&pdev->dev, desc->hw_clks); } diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c @@ -19,8 +19,10 @@ #include "owl-gate.h" #include "owl-mux.h" #include "owl-pll.h" +#include "owl-reset.h" #include <dt-bindings/clock/actions,s900-cmu.h> +#include <dt-bindings/reset/actions,s900-reset.h> #define CMU_COREPLL (0x0000) #define CMU_DEVPLL (0x0004) @@ -684,20 +686,100 @@ static struct clk_hw_onecell_data s900_hw_clks = { .num = CLK_NR_CLKS, }; -static const struct owl_clk_desc s900_clk_desc = { +static const struct owl_reset_map s900_resets[] = { + [RESET_DMAC] = { CMU_DEVRST0, BIT(0) }, + [RESET_SRAMI] = { CMU_DEVRST0, BIT(1) }, + [RESET_DDR_CTL_PHY] = { CMU_DEVRST0, BIT(2) }, + [RESET_NANDC0] = { CMU_DEVRST0, BIT(3) }, + [RESET_SD0] = { CMU_DEVRST0, BIT(4) }, + [RESET_SD1] = { CMU_DEVRST0, BIT(5) }, + [RESET_PCM1] = { CMU_DEVRST0, BIT(6) }, + [RESET_DE] = { CMU_DEVRST0, BIT(7) }, + [RESET_LVDS] = { CMU_DEVRST0, BIT(8) }, + [RESET_SD2] = { CMU_DEVRST0, BIT(9) }, + [RESET_DSI] = { CMU_DEVRST0, BIT(10) }, + [RESET_CSI0] = { CMU_DEVRST0, BIT(11) }, + [RESET_BISP_AXI] = { CMU_DEVRST0, BIT(12) }, + [RESET_CSI1] = { CMU_DEVRST0, BIT(13) }, + [RESET_GPIO] = { CMU_DEVRST0, BIT(15) }, + [RESET_EDP] = { CMU_DEVRST0, BIT(16) }, + [RESET_AUDIO] = { CMU_DEVRST0, BIT(17) }, + [RESET_PCM0] = { CMU_DEVRST0, BIT(18) }, + [RESET_HDE] = { CMU_DEVRST0, BIT(21) }, + [RESET_GPU3D_PA] = { CMU_DEVRST0, BIT(22) }, + [RESET_IMX] = { CMU_DEVRST0, BIT(23) }, + [RESET_SE] = { CMU_DEVRST0, BIT(24) }, + [RESET_NANDC1] = { CMU_DEVRST0, BIT(25) }, + [RESET_SD3] = { CMU_DEVRST0, BIT(26) }, + [RESET_GIC] = { CMU_DEVRST0, BIT(27) }, + [RESET_GPU3D_PB] = { CMU_DEVRST0, BIT(28) }, + [RESET_DDR_CTL_PHY_AXI] = { CMU_DEVRST0, BIT(29) }, + [RESET_CMU_DDR] = { CMU_DEVRST0, BIT(30) }, + [RESET_DMM] = { CMU_DEVRST0, BIT(31) }, + [RESET_USB2HUB] = { CMU_DEVRST1, BIT(0) }, + [RESET_USB2HSIC] = { CMU_DEVRST1, BIT(1) }, + [RESET_HDMI] = { CMU_DEVRST1, BIT(2) }, + [RESET_HDCP2TX] = { CMU_DEVRST1, BIT(3) }, + [RESET_UART6] = { CMU_DEVRST1, BIT(4) }, + [RESET_UART0] = { CMU_DEVRST1, BIT(5) }, + [RESET_UART1] = { CMU_DEVRST1, BIT(6) }, + [RESET_UART2] = { CMU_DEVRST1, BIT(7) }, + [RESET_SPI0] = { CMU_DEVRST1, BIT(8) }, + [RESET_SPI1] = { CMU_DEVRST1, BIT(9) }, + [RESET_SPI2] = { CMU_DEVRST1, BIT(10) }, + [RESET_SPI3] = { CMU_DEVRST1, BIT(11) }, + [RESET_I2C0] = { CMU_DEVRST1, BIT(12) }, + [RESET_I2C1] = { CMU_DEVRST1, BIT(13) }, + [RESET_USB3] = { CMU_DEVRST1, BIT(14) }, + [RESET_UART3] = { CMU_DEVRST1, BIT(15) }, + [RESET_UART4] = { CMU_DEVRST1, BIT(16) }, + [RESET_UART5] = { CMU_DEVRST1, BIT(17) }, + [RESET_I2C2] = { CMU_DEVRST1, BIT(18) }, + [RESET_I2C3] = { CMU_DEVRST1, BIT(19) }, + [RESET_ETHERNET] = { CMU_DEVRST1, BIT(20) }, + [RESET_CHIPID] = { CMU_DEVRST1, BIT(21) }, + [RESET_I2C4] = { CMU_DEVRST1, BIT(22) }, + [RESET_I2C5] = { CMU_DEVRST1, BIT(23) }, + [RESET_CPU_SCNT] = { CMU_DEVRST1, BIT(30) } +}; + +static struct owl_clk_desc s900_clk_desc = { .clks = s900_clks, .num_clks = ARRAY_SIZE(s900_clks), .hw_clks = &s900_hw_clks, + + .resets = s900_resets, + .num_resets = ARRAY_SIZE(s900_resets), }; static int s900_clk_probe(struct platform_device *pdev) { - const struct owl_clk_desc *desc; + struct owl_clk_desc *desc; + struct owl_reset *reset; + int ret; desc = &s900_clk_desc; owl_clk_regmap_init(pdev, desc); + /* + * FIXME: Reset controller registration should be moved to + * common code, once all SoCs of Owl family supports it. + */ + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + reset->rcdev.of_node = pdev->dev.of_node; + reset->rcdev.ops = &owl_reset_ops; + reset->rcdev.nr_resets = desc->num_resets; + reset->reset_map = desc->resets; + reset->regmap = desc->regmap; + + ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev); + if (ret) + dev_err(&pdev->dev, "Failed to register reset controller\n"); + return owl_clk_probe(&pdev->dev, desc->hw_clks); } diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile @@ -3,7 +3,7 @@ # Makefile for at91 specific clk # -obj-y += pmc.o sckc.o +obj-y += pmc.o sckc.o dt-compat.o obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o obj-y += clk-system.o clk-peripheral.o clk-programmable.o @@ -14,3 +14,6 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o +obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o +obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o +obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> +#include <linux/slab.h> + +#include <dt-bindings/clock/at91.h> + +#include "pmc.h" + +struct sck { + char *n; + char *p; + u8 id; +}; + +struct pck { + char *n; + u8 id; +}; + +struct at91sam926x_data { + const struct clk_pll_layout *plla_layout; + const struct clk_pll_characteristics *plla_characteristics; + const struct clk_pll_layout *pllb_layout; + const struct clk_pll_characteristics *pllb_characteristics; + const struct clk_master_characteristics *mck_characteristics; + const struct sck *sck; + const struct pck *pck; + u8 num_sck; + u8 num_pck; + u8 num_progck; + bool has_slck; +}; + +static const struct clk_master_characteristics sam9260_mck_characteristics = { + .output = { .min = 0, .max = 105000000 }, + .divisors = { 1, 2, 4, 0 }, +}; + +static u8 sam9260_plla_out[] = { 0, 2 }; + +static u16 sam9260_plla_icpll[] = { 1, 1 }; + +static struct clk_range sam9260_plla_outputs[] = { + { .min = 80000000, .max = 160000000 }, + { .min = 150000000, .max = 240000000 }, +}; + +static const struct clk_pll_characteristics sam9260_plla_characteristics = { + .input = { .min = 1000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(sam9260_plla_outputs), + .output = sam9260_plla_outputs, + .icpll = sam9260_plla_icpll, + .out = sam9260_plla_out, +}; + +static u8 sam9260_pllb_out[] = { 1 }; + +static u16 sam9260_pllb_icpll[] = { 1 }; + +static struct clk_range sam9260_pllb_outputs[] = { + { .min = 70000000, .max = 130000000 }, +}; + +static const struct clk_pll_characteristics sam9260_pllb_characteristics = { + .input = { .min = 1000000, .max = 5000000 }, + .num_output = ARRAY_SIZE(sam9260_pllb_outputs), + .output = sam9260_pllb_outputs, + .icpll = sam9260_pllb_icpll, + .out = sam9260_pllb_out, +}; + +static const struct sck at91sam9260_systemck[] = { + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, +}; + +static const struct pck at91sam9260_periphck[] = { + { .n = "pioA_clk", .id = 2 }, + { .n = "pioB_clk", .id = 3 }, + { .n = "pioC_clk", .id = 4 }, + { .n = "adc_clk", .id = 5 }, + { .n = "usart0_clk", .id = 6 }, + { .n = "usart1_clk", .id = 7 }, + { .n = "usart2_clk", .id = 8 }, + { .n = "mci0_clk", .id = 9 }, + { .n = "udc_clk", .id = 10 }, + { .n = "twi0_clk", .id = 11 }, + { .n = "spi0_clk", .id = 12 }, + { .n = "spi1_clk", .id = 13 }, + { .n = "ssc0_clk", .id = 14 }, + { .n = "tc0_clk", .id = 17 }, + { .n = "tc1_clk", .id = 18 }, + { .n = "tc2_clk", .id = 19 }, + { .n = "ohci_clk", .id = 20 }, + { .n = "macb0_clk", .id = 21 }, + { .n = "isi_clk", .id = 22 }, + { .n = "usart3_clk", .id = 23 }, + { .n = "uart0_clk", .id = 24 }, + { .n = "uart1_clk", .id = 25 }, + { .n = "tc3_clk", .id = 26 }, + { .n = "tc4_clk", .id = 27 }, + { .n = "tc5_clk", .id = 28 }, +}; + +static struct at91sam926x_data at91sam9260_data = { + .plla_layout = &at91rm9200_pll_layout, + .plla_characteristics = &sam9260_plla_characteristics, + .pllb_layout = &at91rm9200_pll_layout, + .pllb_characteristics = &sam9260_pllb_characteristics, + .mck_characteristics = &sam9260_mck_characteristics, + .sck = at91sam9260_systemck, + .num_sck = ARRAY_SIZE(at91sam9260_systemck), + .pck = at91sam9260_periphck, + .num_pck = ARRAY_SIZE(at91sam9260_periphck), + .num_progck = 2, + .has_slck = true, +}; + +static const struct clk_master_characteristics sam9g20_mck_characteristics = { + .output = { .min = 0, .max = 133000000 }, + .divisors = { 1, 2, 4, 6 }, +}; + +static u8 sam9g20_plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; + +static u16 sam9g20_plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 }; + +static struct clk_range sam9g20_plla_outputs[] = { + { .min = 745000000, .max = 800000000 }, + { .min = 695000000, .max = 750000000 }, + { .min = 645000000, .max = 700000000 }, + { .min = 595000000, .max = 650000000 }, + { .min = 545000000, .max = 600000000 }, + { .min = 495000000, .max = 550000000 }, + { .min = 445000000, .max = 500000000 }, + { .min = 400000000, .max = 450000000 }, +}; + +static const struct clk_pll_characteristics sam9g20_plla_characteristics = { + .input = { .min = 2000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(sam9g20_plla_outputs), + .output = sam9g20_plla_outputs, + .icpll = sam9g20_plla_icpll, + .out = sam9g20_plla_out, +}; + +static u8 sam9g20_pllb_out[] = { 0 }; + +static u16 sam9g20_pllb_icpll[] = { 0 }; + +static struct clk_range sam9g20_pllb_outputs[] = { + { .min = 30000000, .max = 100000000 }, +}; + +static const struct clk_pll_characteristics sam9g20_pllb_characteristics = { + .input = { .min = 2000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(sam9g20_pllb_outputs), + .output = sam9g20_pllb_outputs, + .icpll = sam9g20_pllb_icpll, + .out = sam9g20_pllb_out, +}; + +static struct at91sam926x_data at91sam9g20_data = { + .plla_layout = &at91sam9g45_pll_layout, + .plla_characteristics = &sam9g20_plla_characteristics, + .pllb_layout = &at91sam9g20_pllb_layout, + .pllb_characteristics = &sam9g20_pllb_characteristics, + .mck_characteristics = &sam9g20_mck_characteristics, + .sck = at91sam9260_systemck, + .num_sck = ARRAY_SIZE(at91sam9260_systemck), + .pck = at91sam9260_periphck, + .num_pck = ARRAY_SIZE(at91sam9260_periphck), + .num_progck = 2, + .has_slck = true, +}; + +static const struct clk_master_characteristics sam9261_mck_characteristics = { + .output = { .min = 0, .max = 94000000 }, + .divisors = { 1, 2, 4, 0 }, +}; + +static struct clk_range sam9261_plla_outputs[] = { + { .min = 80000000, .max = 200000000 }, + { .min = 190000000, .max = 240000000 }, +}; + +static const struct clk_pll_characteristics sam9261_plla_characteristics = { + .input = { .min = 1000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(sam9261_plla_outputs), + .output = sam9261_plla_outputs, + .icpll = sam9260_plla_icpll, + .out = sam9260_plla_out, +}; + +static u8 sam9261_pllb_out[] = { 1 }; + +static u16 sam9261_pllb_icpll[] = { 1 }; + +static struct clk_range sam9261_pllb_outputs[] = { + { .min = 70000000, .max = 130000000 }, +}; + +static const struct clk_pll_characteristics sam9261_pllb_characteristics = { + .input = { .min = 1000000, .max = 5000000 }, + .num_output = ARRAY_SIZE(sam9261_pllb_outputs), + .output = sam9261_pllb_outputs, + .icpll = sam9261_pllb_icpll, + .out = sam9261_pllb_out, +}; + +static const struct sck at91sam9261_systemck[] = { + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, + { .n = "pck3", .p = "prog3", .id = 11 }, + { .n = "hclk0", .p = "masterck", .id = 16 }, + { .n = "hclk1", .p = "masterck", .id = 17 }, +}; + +static const struct pck at91sam9261_periphck[] = { + { .n = "pioA_clk", .id = 2, }, + { .n = "pioB_clk", .id = 3, }, + { .n = "pioC_clk", .id = 4, }, + { .n = "usart0_clk", .id = 6, }, + { .n = "usart1_clk", .id = 7, }, + { .n = "usart2_clk", .id = 8, }, + { .n = "mci0_clk", .id = 9, }, + { .n = "udc_clk", .id = 10, }, + { .n = "twi0_clk", .id = 11, }, + { .n = "spi0_clk", .id = 12, }, + { .n = "spi1_clk", .id = 13, }, + { .n = "ssc0_clk", .id = 14, }, + { .n = "ssc1_clk", .id = 15, }, + { .n = "ssc2_clk", .id = 16, }, + { .n = "tc0_clk", .id = 17, }, + { .n = "tc1_clk", .id = 18, }, + { .n = "tc2_clk", .id = 19, }, + { .n = "ohci_clk", .id = 20, }, + { .n = "lcd_clk", .id = 21, }, +}; + +static struct at91sam926x_data at91sam9261_data = { + .plla_layout = &at91rm9200_pll_layout, + .plla_characteristics = &sam9261_plla_characteristics, + .pllb_layout = &at91rm9200_pll_layout, + .pllb_characteristics = &sam9261_pllb_characteristics, + .mck_characteristics = &sam9261_mck_characteristics, + .sck = at91sam9261_systemck, + .num_sck = ARRAY_SIZE(at91sam9261_systemck), + .pck = at91sam9261_periphck, + .num_pck = ARRAY_SIZE(at91sam9261_periphck), + .num_progck = 4, +}; + +static const struct clk_master_characteristics sam9263_mck_characteristics = { + .output = { .min = 0, .max = 120000000 }, + .divisors = { 1, 2, 4, 0 }, +}; + +static struct clk_range sam9263_pll_outputs[] = { + { .min = 80000000, .max = 200000000 }, + { .min = 190000000, .max = 240000000 }, +}; + +static const struct clk_pll_characteristics sam9263_pll_characteristics = { + .input = { .min = 1000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(sam9263_pll_outputs), + .output = sam9263_pll_outputs, + .icpll = sam9260_plla_icpll, + .out = sam9260_plla_out, +}; + +static const struct sck at91sam9263_systemck[] = { + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, + { .n = "pck3", .p = "prog3", .id = 11 }, +}; + +static const struct pck at91sam9263_periphck[] = { + { .n = "pioA_clk", .id = 2, }, + { .n = "pioB_clk", .id = 3, }, + { .n = "pioCDE_clk", .id = 4, }, + { .n = "usart0_clk", .id = 7, }, + { .n = "usart1_clk", .id = 8, }, + { .n = "usart2_clk", .id = 9, }, + { .n = "mci0_clk", .id = 10, }, + { .n = "mci1_clk", .id = 11, }, + { .n = "can_clk", .id = 12, }, + { .n = "twi0_clk", .id = 13, }, + { .n = "spi0_clk", .id = 14, }, + { .n = "spi1_clk", .id = 15, }, + { .n = "ssc0_clk", .id = 16, }, + { .n = "ssc1_clk", .id = 17, }, + { .n = "ac97_clk", .id = 18, }, + { .n = "tcb_clk", .id = 19, }, + { .n = "pwm_clk", .id = 20, }, + { .n = "macb0_clk", .id = 21, }, + { .n = "g2de_clk", .id = 23, }, + { .n = "udc_clk", .id = 24, }, + { .n = "isi_clk", .id = 25, }, + { .n = "lcd_clk", .id = 26, }, + { .n = "dma_clk", .id = 27, }, + { .n = "ohci_clk", .id = 29, }, +}; + +static struct at91sam926x_data at91sam9263_data = { + .plla_layout = &at91rm9200_pll_layout, + .plla_characteristics = &sam9263_pll_characteristics, + .pllb_layout = &at91rm9200_pll_layout, + .pllb_characteristics = &sam9263_pll_characteristics, + .mck_characteristics = &sam9263_mck_characteristics, + .sck = at91sam9263_systemck, + .num_sck = ARRAY_SIZE(at91sam9263_systemck), + .pck = at91sam9263_periphck, + .num_pck = ARRAY_SIZE(at91sam9263_periphck), + .num_progck = 4, +}; + +static void __init at91sam926x_pmc_setup(struct device_node *np, + struct at91sam926x_data *data) +{ + const char *slowxtal_name, *mainxtal_name; + struct pmc_data *at91sam9260_pmc; + u32 usb_div[] = { 1, 2, 4, 0 }; + const char *parent_names[6]; + const char *slck_name; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "slow_xtal"); + if (i < 0) + return; + + slowxtal_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + at91sam9260_pmc = pmc_data_allocate(PMC_MAIN + 1, + ndck(data->sck, data->num_sck), + ndck(data->pck, data->num_pck), 0); + if (!at91sam9260_pmc) + return; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_rm9200_main(regmap, "mainck", "main_osc"); + if (IS_ERR(hw)) + goto err_free; + + at91sam9260_pmc->chws[PMC_MAIN] = hw; + + if (data->has_slck) { + hw = clk_hw_register_fixed_rate_with_accuracy(NULL, + "slow_rc_osc", + NULL, 0, 32768, + 50000000); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "slow_rc_osc"; + parent_names[1] = "slow_xtal"; + hw = at91_clk_register_sam9260_slow(regmap, "slck", + parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + at91sam9260_pmc->chws[PMC_SLOW] = hw; + slck_name = "slck"; + } else { + slck_name = slowxtal_name; + } + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + data->plla_layout, + data->plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1, + data->pllb_layout, + data->pllb_characteristics); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + parent_names[3] = "pllbck"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91rm9200_master_layout, + data->mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91sam9260_pmc->chws[PMC_MCK] = hw; + + hw = at91rm9200_clk_register_usb(regmap, "usbck", "pllbck", usb_div); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + parent_names[3] = "pllbck"; + for (i = 0; i < data->num_progck; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 4, i, + &at91rm9200_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < data->num_sck; i++) { + hw = at91_clk_register_system(regmap, data->sck[i].n, + data->sck[i].p, + data->sck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9260_pmc->shws[data->sck[i].id] = hw; + } + + for (i = 0; i < data->num_pck; i++) { + hw = at91_clk_register_peripheral(regmap, + data->pck[i].n, + "masterck", + data->pck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9260_pmc->phws[data->pck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9260_pmc); + + return; + +err_free: + pmc_data_free(at91sam9260_pmc); +} + +static void __init at91sam9260_pmc_setup(struct device_node *np) +{ + at91sam926x_pmc_setup(np, &at91sam9260_data); +} +CLK_OF_DECLARE_DRIVER(at91sam9260_pmc, "atmel,at91sam9260-pmc", + at91sam9260_pmc_setup); + +static void __init at91sam9261_pmc_setup(struct device_node *np) +{ + at91sam926x_pmc_setup(np, &at91sam9261_data); +} +CLK_OF_DECLARE_DRIVER(at91sam9261_pmc, "atmel,at91sam9261-pmc", + at91sam9261_pmc_setup); + +static void __init at91sam9263_pmc_setup(struct device_node *np) +{ + at91sam926x_pmc_setup(np, &at91sam9263_data); +} +CLK_OF_DECLARE_DRIVER(at91sam9263_pmc, "atmel,at91sam9263-pmc", + at91sam9263_pmc_setup); + +static void __init at91sam9g20_pmc_setup(struct device_node *np) +{ + at91sam926x_pmc_setup(np, &at91sam9g20_data); +} +CLK_OF_DECLARE_DRIVER(at91sam9g20_pmc, "atmel,at91sam9g20-pmc", + at91sam9g20_pmc_setup); diff --git a/drivers/clk/at91/at91sam9rl.c b/drivers/clk/at91/at91sam9rl.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> +#include <linux/slab.h> + +#include <dt-bindings/clock/at91.h> + +#include "pmc.h" + +static const struct clk_master_characteristics sam9rl_mck_characteristics = { + .output = { .min = 0, .max = 94000000 }, + .divisors = { 1, 2, 4, 0 }, +}; + +static u8 sam9rl_plla_out[] = { 0, 2 }; + +static struct clk_range sam9rl_plla_outputs[] = { + { .min = 80000000, .max = 200000000 }, + { .min = 190000000, .max = 240000000 }, +}; + +static const struct clk_pll_characteristics sam9rl_plla_characteristics = { + .input = { .min = 1000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(sam9rl_plla_outputs), + .output = sam9rl_plla_outputs, + .out = sam9rl_plla_out, +}; + +static const struct { + char *n; + char *p; + u8 id; +} at91sam9rl_systemck[] = { + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, +}; + +static const struct { + char *n; + u8 id; +} at91sam9rl_periphck[] = { + { .n = "pioA_clk", .id = 2, }, + { .n = "pioB_clk", .id = 3, }, + { .n = "pioC_clk", .id = 4, }, + { .n = "pioD_clk", .id = 5, }, + { .n = "usart0_clk", .id = 6, }, + { .n = "usart1_clk", .id = 7, }, + { .n = "usart2_clk", .id = 8, }, + { .n = "usart3_clk", .id = 9, }, + { .n = "mci0_clk", .id = 10, }, + { .n = "twi0_clk", .id = 11, }, + { .n = "twi1_clk", .id = 12, }, + { .n = "spi0_clk", .id = 13, }, + { .n = "ssc0_clk", .id = 14, }, + { .n = "ssc1_clk", .id = 15, }, + { .n = "tc0_clk", .id = 16, }, + { .n = "tc1_clk", .id = 17, }, + { .n = "tc2_clk", .id = 18, }, + { .n = "pwm_clk", .id = 19, }, + { .n = "adc_clk", .id = 20, }, + { .n = "dma0_clk", .id = 21, }, + { .n = "udphs_clk", .id = 22, }, + { .n = "lcd_clk", .id = 23, }, +}; + +static void __init at91sam9rl_pmc_setup(struct device_node *np) +{ + const char *slck_name, *mainxtal_name; + struct pmc_data *at91sam9rl_pmc; + const char *parent_names[6]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + + i = of_property_match_string(np, "clock-names", "slow_clk"); + if (i < 0) + return; + + slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + at91sam9rl_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(at91sam9rl_systemck), + nck(at91sam9rl_periphck), 0); + if (!at91sam9rl_pmc) + return; + + hw = at91_clk_register_rm9200_main(regmap, "mainck", mainxtal_name); + if (IS_ERR(hw)) + goto err_free; + + at91sam9rl_pmc->chws[PMC_MAIN] = hw; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &at91rm9200_pll_layout, + &sam9rl_plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck"); + if (IS_ERR(hw)) + goto err_free; + + at91sam9rl_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + parent_names[3] = "utmick"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91rm9200_master_layout, + &sam9rl_mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91sam9rl_pmc->chws[PMC_MCK] = hw; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + parent_names[3] = "utmick"; + parent_names[4] = "masterck"; + for (i = 0; i < 2; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 5, i, + &at91rm9200_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9rl_systemck); i++) { + hw = at91_clk_register_system(regmap, at91sam9rl_systemck[i].n, + at91sam9rl_systemck[i].p, + at91sam9rl_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9rl_pmc->shws[at91sam9rl_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) { + hw = at91_clk_register_peripheral(regmap, + at91sam9rl_periphck[i].n, + "masterck", + at91sam9rl_periphck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9rl_pmc->phws[at91sam9rl_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9rl_pmc); + + return; + +err_free: + pmc_data_free(at91sam9rl_pmc); +} +CLK_OF_DECLARE_DRIVER(at91sam9rl_pmc, "atmel,at91sam9rl-pmc", at91sam9rl_pmc_setup); diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> +#include <linux/slab.h> + +#include <dt-bindings/clock/at91.h> + +#include "pmc.h" + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 0, .max = 133333333 }, + .divisors = { 1, 2, 4, 3 }, + .have_div3_pres = 1, +}; + +static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 }; + +static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 }; + +static struct clk_range plla_outputs[] = { + { .min = 745000000, .max = 800000000 }, + { .min = 695000000, .max = 750000000 }, + { .min = 645000000, .max = 700000000 }, + { .min = 595000000, .max = 650000000 }, + { .min = 545000000, .max = 600000000 }, + { .min = 495000000, .max = 555000000 }, + { .min = 445000000, .max = 500000000 }, + { .min = 400000000, .max = 450000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 2000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, + .icpll = plla_icpll, + .out = plla_out, +}; + +static const struct { + char *n; + char *p; + u8 id; +} at91sam9x5_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "smdck", .p = "smdclk", .id = 4 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, +}; + +struct pck { + char *n; + u8 id; +}; + +static const struct pck at91sam9x5_periphck[] = { + { .n = "pioAB_clk", .id = 2, }, + { .n = "pioCD_clk", .id = 3, }, + { .n = "smd_clk", .id = 4, }, + { .n = "usart0_clk", .id = 5, }, + { .n = "usart1_clk", .id = 6, }, + { .n = "usart2_clk", .id = 7, }, + { .n = "twi0_clk", .id = 9, }, + { .n = "twi1_clk", .id = 10, }, + { .n = "twi2_clk", .id = 11, }, + { .n = "mci0_clk", .id = 12, }, + { .n = "spi0_clk", .id = 13, }, + { .n = "spi1_clk", .id = 14, }, + { .n = "uart0_clk", .id = 15, }, + { .n = "uart1_clk", .id = 16, }, + { .n = "tcb0_clk", .id = 17, }, + { .n = "pwm_clk", .id = 18, }, + { .n = "adc_clk", .id = 19, }, + { .n = "dma0_clk", .id = 20, }, + { .n = "dma1_clk", .id = 21, }, + { .n = "uhphs_clk", .id = 22, }, + { .n = "udphs_clk", .id = 23, }, + { .n = "mci1_clk", .id = 26, }, + { .n = "ssc0_clk", .id = 28, }, +}; + +static const struct pck at91sam9g15_periphck[] = { + { .n = "lcdc_clk", .id = 25, }, + { /* sentinel */} +}; + +static const struct pck at91sam9g25_periphck[] = { + { .n = "usart3_clk", .id = 8, }, + { .n = "macb0_clk", .id = 24, }, + { .n = "isi_clk", .id = 25, }, + { /* sentinel */} +}; + +static const struct pck at91sam9g35_periphck[] = { + { .n = "macb0_clk", .id = 24, }, + { .n = "lcdc_clk", .id = 25, }, + { /* sentinel */} +}; + +static const struct pck at91sam9x25_periphck[] = { + { .n = "usart3_clk", .id = 8, }, + { .n = "macb0_clk", .id = 24, }, + { .n = "macb1_clk", .id = 27, }, + { .n = "can0_clk", .id = 29, }, + { .n = "can1_clk", .id = 30, }, + { /* sentinel */} +}; + +static const struct pck at91sam9x35_periphck[] = { + { .n = "macb0_clk", .id = 24, }, + { .n = "lcdc_clk", .id = 25, }, + { .n = "can0_clk", .id = 29, }, + { .n = "can1_clk", .id = 30, }, + { /* sentinel */} +}; + +static void __init at91sam9x5_pmc_setup(struct device_node *np, + const struct pck *extra_pcks, + bool has_lcdck) +{ + struct clk_range range = CLK_RANGE(0, 0); + const char *slck_name, *mainxtal_name; + struct pmc_data *at91sam9x5_pmc; + const char *parent_names[6]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "slow_clk"); + if (i < 0) + return; + + slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + at91sam9x5_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(at91sam9x5_systemck), + nck(at91sam9x35_periphck), 0); + if (!at91sam9x5_pmc) + return; + + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000, + 50000000); + if (IS_ERR(hw)) + goto err_free; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "main_rc_osc"; + parent_names[1] = "main_osc"; + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + at91sam9x5_pmc->chws[PMC_MAIN] = hw; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &at91rm9200_pll_layout, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack"); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck"); + if (IS_ERR(hw)) + goto err_free; + + at91sam9x5_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91sam9x5_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91sam9x5_pmc->chws[PMC_MCK] = hw; + + parent_names[0] = "plladivck"; + parent_names[1] = "utmick"; + hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + parent_names[4] = "mck"; + for (i = 0; i < 2; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 5, i, + &at91sam9x5_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9x5_systemck); i++) { + hw = at91_clk_register_system(regmap, at91sam9x5_systemck[i].n, + at91sam9x5_systemck[i].p, + at91sam9x5_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9x5_pmc->shws[at91sam9x5_systemck[i].id] = hw; + } + + if (has_lcdck) { + hw = at91_clk_register_system(regmap, "lcdck", "masterck", 3); + if (IS_ERR(hw)) + goto err_free; + + at91sam9x5_pmc->shws[3] = hw; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + at91sam9x5_periphck[i].n, + "masterck", + at91sam9x5_periphck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + at91sam9x5_pmc->phws[at91sam9x5_periphck[i].id] = hw; + } + + for (i = 0; extra_pcks[i].id; i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + extra_pcks[i].n, + "masterck", + extra_pcks[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + at91sam9x5_pmc->phws[extra_pcks[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9x5_pmc); + + return; + +err_free: + pmc_data_free(at91sam9x5_pmc); +} + +static void __init at91sam9g15_pmc_setup(struct device_node *np) +{ + at91sam9x5_pmc_setup(np, at91sam9g15_periphck, true); +} +CLK_OF_DECLARE_DRIVER(at91sam9g15_pmc, "atmel,at91sam9g15-pmc", + at91sam9g15_pmc_setup); + +static void __init at91sam9g25_pmc_setup(struct device_node *np) +{ + at91sam9x5_pmc_setup(np, at91sam9g25_periphck, false); +} +CLK_OF_DECLARE_DRIVER(at91sam9g25_pmc, "atmel,at91sam9g25-pmc", + at91sam9g25_pmc_setup); + +static void __init at91sam9g35_pmc_setup(struct device_node *np) +{ + at91sam9x5_pmc_setup(np, at91sam9g35_periphck, true); +} +CLK_OF_DECLARE_DRIVER(at91sam9g35_pmc, "atmel,at91sam9g35-pmc", + at91sam9g35_pmc_setup); + +static void __init at91sam9x25_pmc_setup(struct device_node *np) +{ + at91sam9x5_pmc_setup(np, at91sam9x25_periphck, false); +} +CLK_OF_DECLARE_DRIVER(at91sam9x25_pmc, "atmel,at91sam9x25-pmc", + at91sam9x25_pmc_setup); + +static void __init at91sam9x35_pmc_setup(struct device_node *np) +{ + at91sam9x5_pmc_setup(np, at91sam9x35_periphck, true); +} +CLK_OF_DECLARE_DRIVER(at91sam9x35_pmc, "atmel,at91sam9x35-pmc", + at91sam9x35_pmc_setup); diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c @@ -43,6 +43,8 @@ #include <linux/regmap.h> #include <linux/slab.h> +#include "pmc.h" + #define AUDIO_PLL_DIV_FRAC BIT(22) #define AUDIO_PLL_ND_MAX (AT91_PMC_AUDIO_PLL_ND_MASK >> \ AT91_PMC_AUDIO_PLL_ND_OFFSET) @@ -444,93 +446,94 @@ static const struct clk_ops audio_pll_pmc_ops = { .set_rate = clk_audio_pll_pmc_set_rate, }; -static int of_sama5d2_clk_audio_pll_setup(struct device_node *np, - struct clk_init_data *init, - struct clk_hw *hw, - struct regmap **clk_audio_regmap) -{ - struct regmap *regmap; - const char *parent_names[1]; - int ret; - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - init->name = np->name; - of_clk_parent_fill(np, parent_names, 1); - init->parent_names = parent_names; - init->num_parents = 1; - - hw->init = init; - *clk_audio_regmap = regmap; - - ret = clk_hw_register(NULL, hw); - if (ret) - return ret; - - return of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - -static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np) +struct clk_hw * __init +at91_clk_register_audio_pll_frac(struct regmap *regmap, const char *name, + const char *parent_name) { struct clk_audio_frac *frac_ck; struct clk_init_data init = {}; + int ret; frac_ck = kzalloc(sizeof(*frac_ck), GFP_KERNEL); if (!frac_ck) - return; + return ERR_PTR(-ENOMEM); + init.name = name; init.ops = &audio_pll_frac_ops; + init.parent_names = &parent_name; + init.num_parents = 1; init.flags = CLK_SET_RATE_GATE; - if (of_sama5d2_clk_audio_pll_setup(np, &init, &frac_ck->hw, - &frac_ck->regmap)) + frac_ck->hw.init = &init; + frac_ck->regmap = regmap; + + ret = clk_hw_register(NULL, &frac_ck->hw); + if (ret) { kfree(frac_ck); + return ERR_PTR(ret); + } + + return &frac_ck->hw; } -static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np) +struct clk_hw * __init +at91_clk_register_audio_pll_pad(struct regmap *regmap, const char *name, + const char *parent_name) { struct clk_audio_pad *apad_ck; - struct clk_init_data init = {}; + struct clk_init_data init; + int ret; apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL); if (!apad_ck) - return; + return ERR_PTR(-ENOMEM); + init.name = name; init.ops = &audio_pll_pad_ops; + init.parent_names = &parent_name; + init.num_parents = 1; init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT; - if (of_sama5d2_clk_audio_pll_setup(np, &init, &apad_ck->hw, - &apad_ck->regmap)) + apad_ck->hw.init = &init; + apad_ck->regmap = regmap; + + ret = clk_hw_register(NULL, &apad_ck->hw); + if (ret) { kfree(apad_ck); + return ERR_PTR(ret); + } + + return &apad_ck->hw; } -static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np) +struct clk_hw * __init +at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name, + const char *parent_name) { - struct clk_audio_pad *apmc_ck; - struct clk_init_data init = {}; + struct clk_audio_pmc *apmc_ck; + struct clk_init_data init; + int ret; apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL); if (!apmc_ck) - return; + return ERR_PTR(-ENOMEM); + init.name = name; init.ops = &audio_pll_pmc_ops; + init.parent_names = &parent_name; + init.num_parents = 1; init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT; - if (of_sama5d2_clk_audio_pll_setup(np, &init, &apmc_ck->hw, - &apmc_ck->regmap)) + apmc_ck->hw.init = &init; + apmc_ck->regmap = regmap; + + ret = clk_hw_register(NULL, &apmc_ck->hw); + if (ret) { kfree(apmc_ck); -} + return ERR_PTR(ret); + } -CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup, - "atmel,sama5d2-clk-audio-pll-frac", - of_sama5d2_clk_audio_pll_frac_setup); -CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup, - "atmel,sama5d2-clk-audio-pll-pad", - of_sama5d2_clk_audio_pll_pad_setup); -CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup, - "atmel,sama5d2-clk-audio-pll-pmc", - of_sama5d2_clk_audio_pll_pmc_setup); + return &apmc_ck->hw; +} diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c @@ -20,17 +20,8 @@ #include "pmc.h" -#define PERIPHERAL_MAX 64 -#define PERIPHERAL_ID_MIN 2 - -#define GENERATED_SOURCE_MAX 6 #define GENERATED_MAX_DIV 255 -#define GCK_ID_SSC0 43 -#define GCK_ID_SSC1 44 -#define GCK_ID_I2S0 54 -#define GCK_ID_I2S1 55 -#define GCK_ID_CLASSD 59 #define GCK_INDEX_DT_AUDIO_PLL 5 struct clk_generated { @@ -279,10 +270,10 @@ static void clk_generated_startup(struct clk_generated *gck) >> AT91_PMC_PCR_GCKDIV_OFFSET; } -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char *name, const char **parent_names, - u8 num_parents, u8 id, + u8 num_parents, u8 id, bool pll_audio, const struct clk_range *range) { struct clk_generated *gck; @@ -306,6 +297,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, gck->regmap = regmap; gck->lock = lock; gck->range = *range; + gck->audio_pll_allowed = pll_audio; clk_generated_startup(gck); hw = &gck->hw; @@ -319,70 +311,3 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, return hw; } - -static void __init of_sama5d2_clk_generated_setup(struct device_node *np) -{ - int num; - u32 id; - const char *name; - struct clk_hw *hw; - unsigned int num_parents; - const char *parent_names[GENERATED_SOURCE_MAX]; - struct device_node *gcknp; - struct clk_range range = CLK_RANGE(0, 0); - struct regmap *regmap; - struct clk_generated *gck; - - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - - num = of_get_child_count(np); - if (!num || num > PERIPHERAL_MAX) - return; - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - for_each_child_of_node(np, gcknp) { - if (of_property_read_u32(gcknp, "reg", &id)) - continue; - - if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX) - continue; - - if (of_property_read_string(np, "clock-output-names", &name)) - name = gcknp->name; - - of_at91_get_clk_range(gcknp, "atmel,clk-output-range", - &range); - - hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, - parent_names, num_parents, - id, &range); - - gck = to_clk_generated(hw); - - if (of_device_is_compatible(np, - "atmel,sama5d2-clk-generated")) { - if (gck->id == GCK_ID_SSC0 || gck->id == GCK_ID_SSC1 || - gck->id == GCK_ID_I2S0 || gck->id == GCK_ID_I2S1 || - gck->id == GCK_ID_CLASSD) - gck->audio_pll_allowed = true; - else - gck->audio_pll_allowed = false; - } else { - gck->audio_pll_allowed = false; - } - - if (IS_ERR(hw)) - continue; - - of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw); - } -} -CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated", - of_sama5d2_clk_generated_setup); diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c @@ -86,25 +86,19 @@ static const struct clk_ops h32mx_ops = { .set_rate = clk_sama5d4_h32mx_set_rate, }; -static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) +struct clk_hw * __init +at91_clk_register_h32mx(struct regmap *regmap, const char *name, + const char *parent_name) { struct clk_sama5d4_h32mx *h32mxclk; struct clk_init_data init; - const char *parent_name; - struct regmap *regmap; int ret; - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL); if (!h32mxclk) - return; - - parent_name = of_clk_get_parent_name(np, 0); + return ERR_PTR(-ENOMEM); - init.name = np->name; + init.name = name; init.ops = &h32mx_ops; init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; @@ -116,10 +110,8 @@ static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) ret = clk_hw_register(NULL, &h32mxclk->hw); if (ret) { kfree(h32mxclk); - return; + return ERR_PTR(ret); } - of_clk_add_hw_provider(np, of_clk_hw_simple_get, &h32mxclk->hw); + return &h32mxclk->hw; } -CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx", - of_sama5d4_clk_h32mx_setup); diff --git a/drivers/clk/at91/clk-i2s-mux.c b/drivers/clk/at91/clk-i2s-mux.c @@ -14,7 +14,7 @@ #include <soc/at91/atmel-sfr.h> -#define I2S_BUS_NR 2 +#include "pmc.h" struct clk_i2s_mux { struct clk_hw hw; @@ -48,7 +48,7 @@ static const struct clk_ops clk_i2s_mux_ops = { .determine_rate = __clk_mux_determine_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_i2s_mux_register(struct regmap *regmap, const char *name, const char * const *parent_names, unsigned int num_parents, u8 bus_id) @@ -78,39 +78,3 @@ at91_clk_i2s_mux_register(struct regmap *regmap, const char *name, return &i2s_ck->hw; } - -static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np) -{ - struct regmap *regmap_sfr; - u8 bus_id; - const char *parent_names[2]; - struct device_node *i2s_mux_np; - struct clk_hw *hw; - int ret; - - regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); - if (IS_ERR(regmap_sfr)) - return; - - for_each_child_of_node(np, i2s_mux_np) { - if (of_property_read_u8(i2s_mux_np, "reg", &bus_id)) - continue; - - if (bus_id > I2S_BUS_NR) - continue; - - ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2); - if (ret != 2) - continue; - - hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name, - parent_names, 2, bus_id); - if (IS_ERR(hw)) - continue; - - of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw); - } -} - -CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux", - of_sama5d2_clk_i2s_mux_setup); diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c @@ -12,7 +12,6 @@ #include <linux/clkdev.h> #include <linux/clk/at91_pmc.h> #include <linux/delay.h> -#include <linux/of.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> @@ -128,7 +127,7 @@ static const struct clk_ops main_osc_ops = { .is_prepared = clk_main_osc_is_prepared, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_main_osc(struct regmap *regmap, const char *name, const char *parent_name, @@ -171,31 +170,6 @@ at91_clk_register_main_osc(struct regmap *regmap, return hw; } -static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np) -{ - struct clk_hw *hw; - const char *name = np->name; - const char *parent_name; - struct regmap *regmap; - bool bypass; - - of_property_read_string(np, "clock-output-names", &name); - bypass = of_property_read_bool(np, "atmel,osc-bypass"); - parent_name = of_clk_get_parent_name(np, 0); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc", - of_at91rm9200_clk_main_osc_setup); - static bool clk_main_rc_osc_ready(struct regmap *regmap) { unsigned int status; @@ -275,7 +249,7 @@ static const struct clk_ops main_rc_osc_ops = { .recalc_accuracy = clk_main_rc_osc_recalc_accuracy, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_main_rc_osc(struct regmap *regmap, const char *name, u32 frequency, u32 accuracy) @@ -313,32 +287,6 @@ at91_clk_register_main_rc_osc(struct regmap *regmap, return hw; } -static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np) -{ - struct clk_hw *hw; - u32 frequency = 0; - u32 accuracy = 0; - const char *name = np->name; - struct regmap *regmap; - - of_property_read_string(np, "clock-output-names", &name); - of_property_read_u32(np, "clock-frequency", &frequency); - of_property_read_u32(np, "clock-accuracy", &accuracy); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc", - of_at91sam9x5_clk_main_rc_osc_setup); - - static int clk_main_probe_frequency(struct regmap *regmap) { unsigned long prep_time, timeout; @@ -403,7 +351,7 @@ static const struct clk_ops rm9200_main_ops = { .recalc_rate = clk_rm9200_main_recalc_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_rm9200_main(struct regmap *regmap, const char *name, const char *parent_name) @@ -442,29 +390,6 @@ at91_clk_register_rm9200_main(struct regmap *regmap, return hw; } -static void __init of_at91rm9200_clk_main_setup(struct device_node *np) -{ - struct clk_hw *hw; - const char *parent_name; - const char *name = np->name; - struct regmap *regmap; - - parent_name = of_clk_get_parent_name(np, 0); - of_property_read_string(np, "clock-output-names", &name); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - hw = at91_clk_register_rm9200_main(regmap, name, parent_name); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main", - of_at91rm9200_clk_main_setup); - static inline bool clk_sam9x5_main_ready(struct regmap *regmap) { unsigned int status; @@ -541,7 +466,7 @@ static const struct clk_ops sam9x5_main_ops = { .get_parent = clk_sam9x5_main_get_parent, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name, const char **parent_names, @@ -583,32 +508,3 @@ at91_clk_register_sam9x5_main(struct regmap *regmap, return hw; } - -static void __init of_at91sam9x5_clk_main_setup(struct device_node *np) -{ - struct clk_hw *hw; - const char *parent_names[2]; - unsigned int num_parents; - const char *name = np->name; - struct regmap *regmap; - - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > 2) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - of_property_read_string(np, "clock-output-names", &name); - - hw = at91_clk_register_sam9x5_main(regmap, name, parent_names, - num_parents); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main", - of_at91sam9x5_clk_main_setup); diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c @@ -17,24 +17,11 @@ #include "pmc.h" -#define MASTER_SOURCE_MAX 4 - #define MASTER_PRES_MASK 0x7 #define MASTER_PRES_MAX MASTER_PRES_MASK #define MASTER_DIV_SHIFT 8 #define MASTER_DIV_MASK 0x3 -struct clk_master_characteristics { - struct clk_range output; - u32 divisors[4]; - u8 have_div3_pres; -}; - -struct clk_master_layout { - u32 mask; - u8 pres_shift; -}; - #define to_clk_master(hw) container_of(hw, struct clk_master, hw) struct clk_master { @@ -120,7 +107,7 @@ static const struct clk_ops master_ops = { .get_parent = clk_master_get_parent, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_master(struct regmap *regmap, const char *name, int num_parents, const char **parent_names, @@ -161,92 +148,12 @@ at91_clk_register_master(struct regmap *regmap, } -static const struct clk_master_layout at91rm9200_master_layout = { +const struct clk_master_layout at91rm9200_master_layout = { .mask = 0x31F, .pres_shift = 2, }; -static const struct clk_master_layout at91sam9x5_master_layout = { +const struct clk_master_layout at91sam9x5_master_layout = { .mask = 0x373, .pres_shift = 4, }; - - -static struct clk_master_characteristics * __init -of_at91_clk_master_get_characteristics(struct device_node *np) -{ - struct clk_master_characteristics *characteristics; - - characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); - if (!characteristics) - return NULL; - - if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output)) - goto out_free_characteristics; - - of_property_read_u32_array(np, "atmel,clk-divisors", - characteristics->divisors, 4); - - characteristics->have_div3_pres = - of_property_read_bool(np, "atmel,master-clk-have-div3-pres"); - - return characteristics; - -out_free_characteristics: - kfree(characteristics); - return NULL; -} - -static void __init -of_at91_clk_master_setup(struct device_node *np, - const struct clk_master_layout *layout) -{ - struct clk_hw *hw; - unsigned int num_parents; - const char *parent_names[MASTER_SOURCE_MAX]; - const char *name = np->name; - struct clk_master_characteristics *characteristics; - struct regmap *regmap; - - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - - of_property_read_string(np, "clock-output-names", &name); - - characteristics = of_at91_clk_master_get_characteristics(np); - if (!characteristics) - return; - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - hw = at91_clk_register_master(regmap, name, num_parents, - parent_names, layout, - characteristics); - if (IS_ERR(hw)) - goto out_free_characteristics; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); - return; - -out_free_characteristics: - kfree(characteristics); -} - -static void __init of_at91rm9200_clk_master_setup(struct device_node *np) -{ - of_at91_clk_master_setup(np, &at91rm9200_master_layout); -} -CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master", - of_at91rm9200_clk_master_setup); - -static void __init of_at91sam9x5_clk_master_setup(struct device_node *np) -{ - of_at91_clk_master_setup(np, &at91sam9x5_master_layout); -} -CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master", - of_at91sam9x5_clk_master_setup); diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c @@ -19,11 +19,6 @@ DEFINE_SPINLOCK(pmc_pcr_lock); -#define PERIPHERAL_MAX 64 - -#define PERIPHERAL_AT91RM9200 0 -#define PERIPHERAL_AT91SAM9X5 1 - #define PERIPHERAL_ID_MIN 2 #define PERIPHERAL_ID_MAX 31 #define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) @@ -104,7 +99,7 @@ static const struct clk_ops peripheral_ops = { .is_enabled = clk_peripheral_is_enabled, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_peripheral(struct regmap *regmap, const char *name, const char *parent_name, u32 id) { @@ -331,7 +326,7 @@ static const struct clk_ops sam9x5_peripheral_ops = { .set_rate = clk_sam9x5_peripheral_set_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, const char *name, const char *parent_name, u32 id, const struct clk_range *range) @@ -374,75 +369,3 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, return hw; } - -static void __init -of_at91_clk_periph_setup(struct device_node *np, u8 type) -{ - int num; - u32 id; - struct clk_hw *hw; - const char *parent_name; - const char *name; - struct device_node *periphclknp; - struct regmap *regmap; - - parent_name = of_clk_get_parent_name(np, 0); - if (!parent_name) - return; - - num = of_get_child_count(np); - if (!num || num > PERIPHERAL_MAX) - return; - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - for_each_child_of_node(np, periphclknp) { - if (of_property_read_u32(periphclknp, "reg", &id)) - continue; - - if (id >= PERIPHERAL_MAX) - continue; - - if (of_property_read_string(np, "clock-output-names", &name)) - name = periphclknp->name; - - if (type == PERIPHERAL_AT91RM9200) { - hw = at91_clk_register_peripheral(regmap, name, - parent_name, id); - } else { - struct clk_range range = CLK_RANGE(0, 0); - - of_at91_get_clk_range(periphclknp, - "atmel,clk-output-range", - &range); - - hw = at91_clk_register_sam9x5_peripheral(regmap, - &pmc_pcr_lock, - name, - parent_name, - id, &range); - } - - if (IS_ERR(hw)) - continue; - - of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw); - } -} - -static void __init of_at91rm9200_clk_periph_setup(struct device_node *np) -{ - of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200); -} -CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral", - of_at91rm9200_clk_periph_setup); - -static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np) -{ - of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5); -} -CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral", - of_at91sam9x5_clk_periph_setup); - diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c @@ -34,20 +34,6 @@ #define PLL_OUT_SHIFT 14 #define PLL_MAX_ID 1 -struct clk_pll_characteristics { - struct clk_range input; - int num_output; - struct clk_range *output; - u16 *icpll; - u8 *out; -}; - -struct clk_pll_layout { - u32 pllr_mask; - u16 mul_mask; - u8 mul_shift; -}; - #define to_clk_pll(hw) container_of(hw, struct clk_pll, hw) struct clk_pll { @@ -133,6 +119,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, { struct clk_pll *pll = to_clk_pll(hw); + if (!pll->div || !pll->mul) + return 0; + return (parent_rate / pll->div) * (pll->mul + 1); } @@ -285,7 +274,7 @@ static const struct clk_ops pll_ops = { .set_rate = clk_pll_set_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_pll(struct regmap *regmap, const char *name, const char *parent_name, u8 id, const struct clk_pll_layout *layout, @@ -331,189 +320,26 @@ at91_clk_register_pll(struct regmap *regmap, const char *name, } -static const struct clk_pll_layout at91rm9200_pll_layout = { +const struct clk_pll_layout at91rm9200_pll_layout = { .pllr_mask = 0x7FFFFFF, .mul_shift = 16, .mul_mask = 0x7FF, }; -static const struct clk_pll_layout at91sam9g45_pll_layout = { +const struct clk_pll_layout at91sam9g45_pll_layout = { .pllr_mask = 0xFFFFFF, .mul_shift = 16, .mul_mask = 0xFF, }; -static const struct clk_pll_layout at91sam9g20_pllb_layout = { +const struct clk_pll_layout at91sam9g20_pllb_layout = { .pllr_mask = 0x3FFFFF, .mul_shift = 16, .mul_mask = 0x3F, }; -static const struct clk_pll_layout sama5d3_pll_layout = { +const struct clk_pll_layout sama5d3_pll_layout = { .pllr_mask = 0x1FFFFFF, .mul_shift = 18, .mul_mask = 0x7F, }; - - -static struct clk_pll_characteristics * __init -of_at91_clk_pll_get_characteristics(struct device_node *np) -{ - int i; - int offset; - u32 tmp; - int num_output; - u32 num_cells; - struct clk_range input; - struct clk_range *output; - u8 *out = NULL; - u16 *icpll = NULL; - struct clk_pll_characteristics *characteristics; - - if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input)) - return NULL; - - if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells", - &num_cells)) - return NULL; - - if (num_cells < 2 || num_cells > 4) - return NULL; - - if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp)) - return NULL; - num_output = tmp / (sizeof(u32) * num_cells); - - characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); - if (!characteristics) - return NULL; - - output = kcalloc(num_output, sizeof(*output), GFP_KERNEL); - if (!output) - goto out_free_characteristics; - - if (num_cells > 2) { - out = kcalloc(num_output, sizeof(*out), GFP_KERNEL); - if (!out) - goto out_free_output; - } - - if (num_cells > 3) { - icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL); - if (!icpll) - goto out_free_output; - } - - for (i = 0; i < num_output; i++) { - offset = i * num_cells; - if (of_property_read_u32_index(np, - "atmel,pll-clk-output-ranges", - offset, &tmp)) - goto out_free_output; - output[i].min = tmp; - if (of_property_read_u32_index(np, - "atmel,pll-clk-output-ranges", - offset + 1, &tmp)) - goto out_free_output; - output[i].max = tmp; - - if (num_cells == 2) - continue; - - if (of_property_read_u32_index(np, - "atmel,pll-clk-output-ranges", - offset + 2, &tmp)) - goto out_free_output; - out[i] = tmp; - - if (num_cells == 3) - continue; - - if (of_property_read_u32_index(np, - "atmel,pll-clk-output-ranges", - offset + 3, &tmp)) - goto out_free_output; - icpll[i] = tmp; - } - - characteristics->input = input; - characteristics->num_output = num_output; - characteristics->output = output; - characteristics->out = out; - characteristics->icpll = icpll; - return characteristics; - -out_free_output: - kfree(icpll); - kfree(out); - kfree(output); -out_free_characteristics: - kfree(characteristics); - return NULL; -} - -static void __init -of_at91_clk_pll_setup(struct device_node *np, - const struct clk_pll_layout *layout) -{ - u32 id; - struct clk_hw *hw; - struct regmap *regmap; - const char *parent_name; - const char *name = np->name; - struct clk_pll_characteristics *characteristics; - - if (of_property_read_u32(np, "reg", &id)) - return; - - parent_name = of_clk_get_parent_name(np, 0); - - of_property_read_string(np, "clock-output-names", &name); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - characteristics = of_at91_clk_pll_get_characteristics(np); - if (!characteristics) - return; - - hw = at91_clk_register_pll(regmap, name, parent_name, id, layout, - characteristics); - if (IS_ERR(hw)) - goto out_free_characteristics; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); - return; - -out_free_characteristics: - kfree(characteristics); -} - -static void __init of_at91rm9200_clk_pll_setup(struct device_node *np) -{ - of_at91_clk_pll_setup(np, &at91rm9200_pll_layout); -} -CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll", - of_at91rm9200_clk_pll_setup); - -static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np) -{ - of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout); -} -CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll", - of_at91sam9g45_clk_pll_setup); - -static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np) -{ - of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout); -} -CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb", - of_at91sam9g20_clk_pllb_setup); - -static void __init of_sama5d3_clk_pll_setup(struct device_node *np) -{ - of_at91_clk_pll_setup(np, &sama5d3_pll_layout); -} -CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll", - of_sama5d3_clk_pll_setup); diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c @@ -75,7 +75,7 @@ static const struct clk_ops plldiv_ops = { .set_rate = clk_plldiv_set_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_plldiv(struct regmap *regmap, const char *name, const char *parent_name) { @@ -106,28 +106,3 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name, return hw; } - -static void __init -of_at91sam9x5_clk_plldiv_setup(struct device_node *np) -{ - struct clk_hw *hw; - const char *parent_name; - const char *name = np->name; - struct regmap *regmap; - - parent_name = of_clk_get_parent_name(np, 0); - - of_property_read_string(np, "clock-output-names", &name); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - hw = at91_clk_register_plldiv(regmap, name, parent_name); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv", - of_at91sam9x5_clk_plldiv_setup); diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c @@ -17,7 +17,6 @@ #include "pmc.h" -#define PROG_SOURCE_MAX 5 #define PROG_ID_MAX 7 #define PROG_STATUS_MASK(id) (1 << ((id) + 8)) @@ -25,12 +24,6 @@ #define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK) #define PROG_MAX_RM9200_CSS 3 -struct clk_programmable_layout { - u8 pres_shift; - u8 css_mask; - u8 have_slck_mck; -}; - struct clk_programmable { struct clk_hw hw; struct regmap *regmap; @@ -170,7 +163,7 @@ static const struct clk_ops programmable_ops = { .set_rate = clk_programmable_set_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_programmable(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents, u8 id, @@ -211,86 +204,20 @@ at91_clk_register_programmable(struct regmap *regmap, return hw; } -static const struct clk_programmable_layout at91rm9200_programmable_layout = { +const struct clk_programmable_layout at91rm9200_programmable_layout = { .pres_shift = 2, .css_mask = 0x3, .have_slck_mck = 0, }; -static const struct clk_programmable_layout at91sam9g45_programmable_layout = { +const struct clk_programmable_layout at91sam9g45_programmable_layout = { .pres_shift = 2, .css_mask = 0x3, .have_slck_mck = 1, }; -static const struct clk_programmable_layout at91sam9x5_programmable_layout = { +const struct clk_programmable_layout at91sam9x5_programmable_layout = { .pres_shift = 4, .css_mask = 0x7, .have_slck_mck = 0, }; - -static void __init -of_at91_clk_prog_setup(struct device_node *np, - const struct clk_programmable_layout *layout) -{ - int num; - u32 id; - struct clk_hw *hw; - unsigned int num_parents; - const char *parent_names[PROG_SOURCE_MAX]; - const char *name; - struct device_node *progclknp; - struct regmap *regmap; - - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > PROG_SOURCE_MAX) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - - num = of_get_child_count(np); - if (!num || num > (PROG_ID_MAX + 1)) - return; - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - for_each_child_of_node(np, progclknp) { - if (of_property_read_u32(progclknp, "reg", &id)) - continue; - - if (of_property_read_string(np, "clock-output-names", &name)) - name = progclknp->name; - - hw = at91_clk_register_programmable(regmap, name, - parent_names, num_parents, - id, layout); - if (IS_ERR(hw)) - continue; - - of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw); - } -} - - -static void __init of_at91rm9200_clk_prog_setup(struct device_node *np) -{ - of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout); -} -CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable", - of_at91rm9200_clk_prog_setup); - -static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np) -{ - of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout); -} -CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable", - of_at91sam9g45_clk_prog_setup); - -static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np) -{ - of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout); -} -CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable", - of_at91sam9x5_clk_prog_setup); diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c @@ -40,7 +40,7 @@ static const struct clk_ops sam9260_slow_ops = { .get_parent = clk_sam9260_slow_get_parent, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_sam9260_slow(struct regmap *regmap, const char *name, const char **parent_names, @@ -79,33 +79,3 @@ at91_clk_register_sam9260_slow(struct regmap *regmap, return hw; } - -static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) -{ - struct clk_hw *hw; - const char *parent_names[2]; - unsigned int num_parents; - const char *name = np->name; - struct regmap *regmap; - - num_parents = of_clk_get_parent_count(np); - if (num_parents != 2) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - of_property_read_string(np, "clock-output-names", &name); - - hw = at91_clk_register_sam9260_slow(regmap, name, parent_names, - num_parents); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} - -CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow", - of_at91sam9260_clk_slow_setup); diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c @@ -17,8 +17,6 @@ #include "pmc.h" -#define SMD_SOURCE_MAX 2 - #define SMD_DIV_SHIFT 8 #define SMD_MAX_DIV 0xf @@ -111,7 +109,7 @@ static const struct clk_ops at91sam9x5_smd_ops = { .set_rate = at91sam9x5_clk_smd_set_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents) { @@ -142,33 +140,3 @@ at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name, return hw; } - -static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np) -{ - struct clk_hw *hw; - unsigned int num_parents; - const char *parent_names[SMD_SOURCE_MAX]; - const char *name = np->name; - struct regmap *regmap; - - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > SMD_SOURCE_MAX) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - - of_property_read_string(np, "clock-output-names", &name); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - hw = at91sam9x5_clk_register_smd(regmap, name, parent_names, - num_parents); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd", - of_at91sam9x5_clk_smd_setup); diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c @@ -88,7 +88,7 @@ static const struct clk_ops system_ops = { .is_prepared = clk_system_is_prepared, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_system(struct regmap *regmap, const char *name, const char *parent_name, u8 id) { @@ -123,40 +123,3 @@ at91_clk_register_system(struct regmap *regmap, const char *name, return hw; } - -static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) -{ - int num; - u32 id; - struct clk_hw *hw; - const char *name; - struct device_node *sysclknp; - const char *parent_name; - struct regmap *regmap; - - num = of_get_child_count(np); - if (num > (SYSTEM_MAX_ID + 1)) - return; - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - for_each_child_of_node(np, sysclknp) { - if (of_property_read_u32(sysclknp, "reg", &id)) - continue; - - if (of_property_read_string(np, "clock-output-names", &name)) - name = sysclknp->name; - - parent_name = of_clk_get_parent_name(sysclknp, 0); - - hw = at91_clk_register_system(regmap, name, parent_name, id); - if (IS_ERR(hw)) - continue; - - of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw); - } -} -CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system", - of_at91rm9200_clk_sys_setup); diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c @@ -17,8 +17,6 @@ #include "pmc.h" -#define USB_SOURCE_MAX 2 - #define SAM9X5_USB_DIV_SHIFT 8 #define SAM9X5_USB_MAX_DIV 0xf @@ -192,7 +190,7 @@ static const struct clk_ops at91sam9n12_usb_ops = { .set_rate = at91sam9x5_clk_usb_set_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents) { @@ -225,7 +223,7 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, return hw; } -static struct clk_hw * __init +struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name) { @@ -342,7 +340,7 @@ static const struct clk_ops at91rm9200_usb_ops = { .set_rate = at91rm9200_clk_usb_set_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name, const u32 *divisors) { @@ -374,89 +372,3 @@ at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, return hw; } - -static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np) -{ - struct clk_hw *hw; - unsigned int num_parents; - const char *parent_names[USB_SOURCE_MAX]; - const char *name = np->name; - struct regmap *regmap; - - num_parents = of_clk_get_parent_count(np); - if (num_parents == 0 || num_parents > USB_SOURCE_MAX) - return; - - of_clk_parent_fill(np, parent_names, num_parents); - - of_property_read_string(np, "clock-output-names", &name); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - hw = at91sam9x5_clk_register_usb(regmap, name, parent_names, - num_parents); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb", - of_at91sam9x5_clk_usb_setup); - -static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np) -{ - struct clk_hw *hw; - const char *parent_name; - const char *name = np->name; - struct regmap *regmap; - - parent_name = of_clk_get_parent_name(np, 0); - if (!parent_name) - return; - - of_property_read_string(np, "clock-output-names", &name); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - - hw = at91sam9n12_clk_register_usb(regmap, name, parent_name); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb", - of_at91sam9n12_clk_usb_setup); - -static void __init of_at91rm9200_clk_usb_setup(struct device_node *np) -{ - struct clk_hw *hw; - const char *parent_name; - const char *name = np->name; - u32 divisors[4] = {0, 0, 0, 0}; - struct regmap *regmap; - - parent_name = of_clk_get_parent_name(np, 0); - if (!parent_name) - return; - - of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4); - if (!divisors[0]) - return; - - of_property_read_string(np, "clock-output-names", &name); - - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) - return; - hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); -} -CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb", - of_at91rm9200_clk_usb_setup); diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c @@ -125,7 +125,7 @@ static const struct clk_ops utmi_ops = { .recalc_rate = clk_utmi_recalc_rate, }; -static struct clk_hw * __init +struct clk_hw * __init at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, const char *name, const char *parent_name) { @@ -157,46 +157,3 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, return hw; } - -static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) -{ - struct clk_hw *hw; - const char *parent_name; - const char *name = np->name; - struct regmap *regmap_pmc, *regmap_sfr; - - parent_name = of_clk_get_parent_name(np, 0); - - of_property_read_string(np, "clock-output-names", &name); - - regmap_pmc = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap_pmc)) - return; - - /* - * If the device supports different mainck rates, this value has to be - * set in the UTMI Clock Trimming register. - * - 9x5: mainck supports several rates but it is indicated that a - * 12 MHz is needed in case of USB. - * - sama5d3 and sama5d2: mainck supports several rates. Configuring - * the FREQ field of the UTMI Clock Trimming register is mandatory. - * - sama5d4: mainck is at 12 MHz. - * - * We only need to retrieve sama5d3 or sama5d2 sfr regmap. - */ - regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr"); - if (IS_ERR(regmap_sfr)) { - regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); - if (IS_ERR(regmap_sfr)) - regmap_sfr = NULL; - } - - hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name); - if (IS_ERR(hw)) - return; - - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); - return; -} -CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi", - of_at91sam9x5_clk_utmi_setup); diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c @@ -0,0 +1,961 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk-provider.h> +#include <linux/clk/at91_pmc.h> +#include <linux/of.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include "pmc.h" + +#define MASTER_SOURCE_MAX 4 + +#define PERIPHERAL_AT91RM9200 0 +#define PERIPHERAL_AT91SAM9X5 1 + +#define PERIPHERAL_MAX 64 + +#define PERIPHERAL_ID_MIN 2 + +#define PROG_SOURCE_MAX 5 +#define PROG_ID_MAX 7 + +#define SYSTEM_MAX_ID 31 + +#ifdef CONFIG_HAVE_AT91_AUDIO_PLL +static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *name = np->name; + const char *parent_name; + struct regmap *regmap; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + parent_name = of_clk_get_parent_name(np, 0); + + hw = at91_clk_register_audio_pll_frac(regmap, name, parent_name); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup, + "atmel,sama5d2-clk-audio-pll-frac", + of_sama5d2_clk_audio_pll_frac_setup); + +static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *name = np->name; + const char *parent_name; + struct regmap *regmap; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + parent_name = of_clk_get_parent_name(np, 0); + + hw = at91_clk_register_audio_pll_pad(regmap, name, parent_name); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup, + "atmel,sama5d2-clk-audio-pll-pad", + of_sama5d2_clk_audio_pll_pad_setup); + +static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *name = np->name; + const char *parent_name; + struct regmap *regmap; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + parent_name = of_clk_get_parent_name(np, 0); + + hw = at91_clk_register_audio_pll_pmc(regmap, name, parent_name); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup, + "atmel,sama5d2-clk-audio-pll-pmc", + of_sama5d2_clk_audio_pll_pmc_setup); +#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */ + +#ifdef CONFIG_HAVE_AT91_GENERATED_CLK +#define GENERATED_SOURCE_MAX 6 + +#define GCK_ID_I2S0 54 +#define GCK_ID_I2S1 55 +#define GCK_ID_CLASSD 59 + +static void __init of_sama5d2_clk_generated_setup(struct device_node *np) +{ + int num; + u32 id; + const char *name; + struct clk_hw *hw; + unsigned int num_parents; + const char *parent_names[GENERATED_SOURCE_MAX]; + struct device_node *gcknp; + struct clk_range range = CLK_RANGE(0, 0); + struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + + num = of_get_child_count(np); + if (!num || num > PERIPHERAL_MAX) + return; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + for_each_child_of_node(np, gcknp) { + bool pll_audio = false; + + if (of_property_read_u32(gcknp, "reg", &id)) + continue; + + if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX) + continue; + + if (of_property_read_string(np, "clock-output-names", &name)) + name = gcknp->name; + + of_at91_get_clk_range(gcknp, "atmel,clk-output-range", + &range); + + if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") && + (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 || + id == GCK_ID_CLASSD)) + pll_audio = true; + + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, + parent_names, num_parents, + id, pll_audio, &range); + if (IS_ERR(hw)) + continue; + + of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw); + } +} +CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated", + of_sama5d2_clk_generated_setup); +#endif /* CONFIG_HAVE_AT91_GENERATED_CLK */ + +#ifdef CONFIG_HAVE_AT91_H32MX +static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *name = np->name; + const char *parent_name; + struct regmap *regmap; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + parent_name = of_clk_get_parent_name(np, 0); + + hw = at91_clk_register_h32mx(regmap, name, parent_name); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx", + of_sama5d4_clk_h32mx_setup); +#endif /* CONFIG_HAVE_AT91_H32MX */ + +#ifdef CONFIG_HAVE_AT91_I2S_MUX_CLK +#define I2S_BUS_NR 2 + +static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np) +{ + struct regmap *regmap_sfr; + u8 bus_id; + const char *parent_names[2]; + struct device_node *i2s_mux_np; + struct clk_hw *hw; + int ret; + + regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(regmap_sfr)) + return; + + for_each_child_of_node(np, i2s_mux_np) { + if (of_property_read_u8(i2s_mux_np, "reg", &bus_id)) + continue; + + if (bus_id > I2S_BUS_NR) + continue; + + ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2); + if (ret != 2) + continue; + + hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name, + parent_names, 2, bus_id); + if (IS_ERR(hw)) + continue; + + of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw); + } +} +CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux", + of_sama5d2_clk_i2s_mux_setup); +#endif /* CONFIG_HAVE_AT91_I2S_MUX_CLK */ + +static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *name = np->name; + const char *parent_name; + struct regmap *regmap; + bool bypass; + + of_property_read_string(np, "clock-output-names", &name); + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + parent_name = of_clk_get_parent_name(np, 0); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc", + of_at91rm9200_clk_main_osc_setup); + +static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np) +{ + struct clk_hw *hw; + u32 frequency = 0; + u32 accuracy = 0; + const char *name = np->name; + struct regmap *regmap; + + of_property_read_string(np, "clock-output-names", &name); + of_property_read_u32(np, "clock-frequency", &frequency); + of_property_read_u32(np, "clock-accuracy", &accuracy); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc", + of_at91sam9x5_clk_main_rc_osc_setup); + +static void __init of_at91rm9200_clk_main_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *parent_name; + const char *name = np->name; + struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + of_property_read_string(np, "clock-output-names", &name); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + hw = at91_clk_register_rm9200_main(regmap, name, parent_name); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main", + of_at91rm9200_clk_main_setup); + +static void __init of_at91sam9x5_clk_main_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *parent_names[2]; + unsigned int num_parents; + const char *name = np->name; + struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents == 0 || num_parents > 2) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + of_property_read_string(np, "clock-output-names", &name); + + hw = at91_clk_register_sam9x5_main(regmap, name, parent_names, + num_parents); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main", + of_at91sam9x5_clk_main_setup); + +static struct clk_master_characteristics * __init +of_at91_clk_master_get_characteristics(struct device_node *np) +{ + struct clk_master_characteristics *characteristics; + + characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); + if (!characteristics) + return NULL; + + if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output)) + goto out_free_characteristics; + + of_property_read_u32_array(np, "atmel,clk-divisors", + characteristics->divisors, 4); + + characteristics->have_div3_pres = + of_property_read_bool(np, "atmel,master-clk-have-div3-pres"); + + return characteristics; + +out_free_characteristics: + kfree(characteristics); + return NULL; +} + +static void __init +of_at91_clk_master_setup(struct device_node *np, + const struct clk_master_layout *layout) +{ + struct clk_hw *hw; + unsigned int num_parents; + const char *parent_names[MASTER_SOURCE_MAX]; + const char *name = np->name; + struct clk_master_characteristics *characteristics; + struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + + of_property_read_string(np, "clock-output-names", &name); + + characteristics = of_at91_clk_master_get_characteristics(np); + if (!characteristics) + return; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + hw = at91_clk_register_master(regmap, name, num_parents, + parent_names, layout, + characteristics); + if (IS_ERR(hw)) + goto out_free_characteristics; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); + return; + +out_free_characteristics: + kfree(characteristics); +} + +static void __init of_at91rm9200_clk_master_setup(struct device_node *np) +{ + of_at91_clk_master_setup(np, &at91rm9200_master_layout); +} +CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master", + of_at91rm9200_clk_master_setup); + +static void __init of_at91sam9x5_clk_master_setup(struct device_node *np) +{ + of_at91_clk_master_setup(np, &at91sam9x5_master_layout); +} +CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master", + of_at91sam9x5_clk_master_setup); + +static void __init +of_at91_clk_periph_setup(struct device_node *np, u8 type) +{ + int num; + u32 id; + struct clk_hw *hw; + const char *parent_name; + const char *name; + struct device_node *periphclknp; + struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) + return; + + num = of_get_child_count(np); + if (!num || num > PERIPHERAL_MAX) + return; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + for_each_child_of_node(np, periphclknp) { + if (of_property_read_u32(periphclknp, "reg", &id)) + continue; + + if (id >= PERIPHERAL_MAX) + continue; + + if (of_property_read_string(np, "clock-output-names", &name)) + name = periphclknp->name; + + if (type == PERIPHERAL_AT91RM9200) { + hw = at91_clk_register_peripheral(regmap, name, + parent_name, id); + } else { + struct clk_range range = CLK_RANGE(0, 0); + + of_at91_get_clk_range(periphclknp, + "atmel,clk-output-range", + &range); + + hw = at91_clk_register_sam9x5_peripheral(regmap, + &pmc_pcr_lock, + name, + parent_name, + id, &range); + } + + if (IS_ERR(hw)) + continue; + + of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw); + } +} + +static void __init of_at91rm9200_clk_periph_setup(struct device_node *np) +{ + of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200); +} +CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral", + of_at91rm9200_clk_periph_setup); + +static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np) +{ + of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5); +} +CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral", + of_at91sam9x5_clk_periph_setup); + +static struct clk_pll_characteristics * __init +of_at91_clk_pll_get_characteristics(struct device_node *np) +{ + int i; + int offset; + u32 tmp; + int num_output; + u32 num_cells; + struct clk_range input; + struct clk_range *output; + u8 *out = NULL; + u16 *icpll = NULL; + struct clk_pll_characteristics *characteristics; + + if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input)) + return NULL; + + if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells", + &num_cells)) + return NULL; + + if (num_cells < 2 || num_cells > 4) + return NULL; + + if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp)) + return NULL; + num_output = tmp / (sizeof(u32) * num_cells); + + characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); + if (!characteristics) + return NULL; + + output = kcalloc(num_output, sizeof(*output), GFP_KERNEL); + if (!output) + goto out_free_characteristics; + + if (num_cells > 2) { + out = kcalloc(num_output, sizeof(*out), GFP_KERNEL); + if (!out) + goto out_free_output; + } + + if (num_cells > 3) { + icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL); + if (!icpll) + goto out_free_output; + } + + for (i = 0; i < num_output; i++) { + offset = i * num_cells; + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset, &tmp)) + goto out_free_output; + output[i].min = tmp; + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 1, &tmp)) + goto out_free_output; + output[i].max = tmp; + + if (num_cells == 2) + continue; + + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 2, &tmp)) + goto out_free_output; + out[i] = tmp; + + if (num_cells == 3) + continue; + + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 3, &tmp)) + goto out_free_output; + icpll[i] = tmp; + } + + characteristics->input = input; + characteristics->num_output = num_output; + characteristics->output = output; + characteristics->out = out; + characteristics->icpll = icpll; + return characteristics; + +out_free_output: + kfree(icpll); + kfree(out); + kfree(output); +out_free_characteristics: + kfree(characteristics); + return NULL; +} + +static void __init +of_at91_clk_pll_setup(struct device_node *np, + const struct clk_pll_layout *layout) +{ + u32 id; + struct clk_hw *hw; + struct regmap *regmap; + const char *parent_name; + const char *name = np->name; + struct clk_pll_characteristics *characteristics; + + if (of_property_read_u32(np, "reg", &id)) + return; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + characteristics = of_at91_clk_pll_get_characteristics(np); + if (!characteristics) + return; + + hw = at91_clk_register_pll(regmap, name, parent_name, id, layout, + characteristics); + if (IS_ERR(hw)) + goto out_free_characteristics; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); + return; + +out_free_characteristics: + kfree(characteristics); +} + +static void __init of_at91rm9200_clk_pll_setup(struct device_node *np) +{ + of_at91_clk_pll_setup(np, &at91rm9200_pll_layout); +} +CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll", + of_at91rm9200_clk_pll_setup); + +static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np) +{ + of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout); +} +CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll", + of_at91sam9g45_clk_pll_setup); + +static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np) +{ + of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout); +} +CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb", + of_at91sam9g20_clk_pllb_setup); + +static void __init of_sama5d3_clk_pll_setup(struct device_node *np) +{ + of_at91_clk_pll_setup(np, &sama5d3_pll_layout); +} +CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll", + of_sama5d3_clk_pll_setup); + +static void __init +of_at91sam9x5_clk_plldiv_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *parent_name; + const char *name = np->name; + struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + hw = at91_clk_register_plldiv(regmap, name, parent_name); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv", + of_at91sam9x5_clk_plldiv_setup); + +static void __init +of_at91_clk_prog_setup(struct device_node *np, + const struct clk_programmable_layout *layout) +{ + int num; + u32 id; + struct clk_hw *hw; + unsigned int num_parents; + const char *parent_names[PROG_SOURCE_MAX]; + const char *name; + struct device_node *progclknp; + struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents == 0 || num_parents > PROG_SOURCE_MAX) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + + num = of_get_child_count(np); + if (!num || num > (PROG_ID_MAX + 1)) + return; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + for_each_child_of_node(np, progclknp) { + if (of_property_read_u32(progclknp, "reg", &id)) + continue; + + if (of_property_read_string(np, "clock-output-names", &name)) + name = progclknp->name; + + hw = at91_clk_register_programmable(regmap, name, + parent_names, num_parents, + id, layout); + if (IS_ERR(hw)) + continue; + + of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw); + } +} + +static void __init of_at91rm9200_clk_prog_setup(struct device_node *np) +{ + of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout); +} +CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable", + of_at91rm9200_clk_prog_setup); + +static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np) +{ + of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout); +} +CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable", + of_at91sam9g45_clk_prog_setup); + +static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np) +{ + of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout); +} +CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable", + of_at91sam9x5_clk_prog_setup); + +static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *parent_names[2]; + unsigned int num_parents; + const char *name = np->name; + struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents != 2) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + of_property_read_string(np, "clock-output-names", &name); + + hw = at91_clk_register_sam9260_slow(regmap, name, parent_names, + num_parents); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow", + of_at91sam9260_clk_slow_setup); + +#ifdef CONFIG_HAVE_AT91_SMD +#define SMD_SOURCE_MAX 2 + +static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np) +{ + struct clk_hw *hw; + unsigned int num_parents; + const char *parent_names[SMD_SOURCE_MAX]; + const char *name = np->name; + struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents == 0 || num_parents > SMD_SOURCE_MAX) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + + of_property_read_string(np, "clock-output-names", &name); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + hw = at91sam9x5_clk_register_smd(regmap, name, parent_names, + num_parents); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd", + of_at91sam9x5_clk_smd_setup); +#endif /* CONFIG_HAVE_AT91_SMD */ + +static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) +{ + int num; + u32 id; + struct clk_hw *hw; + const char *name; + struct device_node *sysclknp; + const char *parent_name; + struct regmap *regmap; + + num = of_get_child_count(np); + if (num > (SYSTEM_MAX_ID + 1)) + return; + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + for_each_child_of_node(np, sysclknp) { + if (of_property_read_u32(sysclknp, "reg", &id)) + continue; + + if (of_property_read_string(np, "clock-output-names", &name)) + name = sysclknp->name; + + parent_name = of_clk_get_parent_name(sysclknp, 0); + + hw = at91_clk_register_system(regmap, name, parent_name, id); + if (IS_ERR(hw)) + continue; + + of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw); + } +} +CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system", + of_at91rm9200_clk_sys_setup); + +#ifdef CONFIG_HAVE_AT91_USB_CLK +#define USB_SOURCE_MAX 2 + +static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np) +{ + struct clk_hw *hw; + unsigned int num_parents; + const char *parent_names[USB_SOURCE_MAX]; + const char *name = np->name; + struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents == 0 || num_parents > USB_SOURCE_MAX) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + + of_property_read_string(np, "clock-output-names", &name); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + hw = at91sam9x5_clk_register_usb(regmap, name, parent_names, + num_parents); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb", + of_at91sam9x5_clk_usb_setup); + +static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *parent_name; + const char *name = np->name; + struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) + return; + + of_property_read_string(np, "clock-output-names", &name); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + + hw = at91sam9n12_clk_register_usb(regmap, name, parent_name); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb", + of_at91sam9n12_clk_usb_setup); + +static void __init of_at91rm9200_clk_usb_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *parent_name; + const char *name = np->name; + u32 divisors[4] = {0, 0, 0, 0}; + struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) + return; + + of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4); + if (!divisors[0]) + return; + + of_property_read_string(np, "clock-output-names", &name); + + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb", + of_at91rm9200_clk_usb_setup); +#endif /* CONFIG_HAVE_AT91_USB_CLK */ + +#ifdef CONFIG_HAVE_AT91_UTMI +static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) +{ + struct clk_hw *hw; + const char *parent_name; + const char *name = np->name; + struct regmap *regmap_pmc, *regmap_sfr; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + regmap_pmc = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap_pmc)) + return; + + /* + * If the device supports different mainck rates, this value has to be + * set in the UTMI Clock Trimming register. + * - 9x5: mainck supports several rates but it is indicated that a + * 12 MHz is needed in case of USB. + * - sama5d3 and sama5d2: mainck supports several rates. Configuring + * the FREQ field of the UTMI Clock Trimming register is mandatory. + * - sama5d4: mainck is at 12 MHz. + * + * We only need to retrieve sama5d3 or sama5d2 sfr regmap. + */ + regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr"); + if (IS_ERR(regmap_sfr)) { + regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(regmap_sfr)) + regmap_sfr = NULL; + } + + hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name); + if (IS_ERR(hw)) + return; + + of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); +} +CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi", + of_at91sam9x5_clk_utmi_setup); +#endif /* CONFIG_HAVE_AT91_UTMI */ diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c @@ -19,6 +19,8 @@ #include <asm/proc-fns.h> +#include <dt-bindings/clock/at91.h> + #include "pmc.h" #define PMC_MAX_IDS 128 @@ -47,6 +49,82 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname, } EXPORT_SYMBOL_GPL(of_at91_get_clk_range); +struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data) +{ + unsigned int type = clkspec->args[0]; + unsigned int idx = clkspec->args[1]; + struct pmc_data *pmc_data = data; + + switch (type) { + case PMC_TYPE_CORE: + if (idx < pmc_data->ncore) + return pmc_data->chws[idx]; + break; + case PMC_TYPE_SYSTEM: + if (idx < pmc_data->nsystem) + return pmc_data->shws[idx]; + break; + case PMC_TYPE_PERIPHERAL: + if (idx < pmc_data->nperiph) + return pmc_data->phws[idx]; + break; + case PMC_TYPE_GCK: + if (idx < pmc_data->ngck) + return pmc_data->ghws[idx]; + break; + default: + break; + } + + pr_err("%s: invalid type (%u) or index (%u)\n", __func__, type, idx); + + return ERR_PTR(-EINVAL); +} + +void pmc_data_free(struct pmc_data *pmc_data) +{ + kfree(pmc_data->chws); + kfree(pmc_data->shws); + kfree(pmc_data->phws); + kfree(pmc_data->ghws); +} + +struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, + unsigned int nperiph, unsigned int ngck) +{ + struct pmc_data *pmc_data = kzalloc(sizeof(*pmc_data), GFP_KERNEL); + + if (!pmc_data) + return NULL; + + pmc_data->ncore = ncore; + pmc_data->chws = kcalloc(ncore, sizeof(struct clk_hw *), GFP_KERNEL); + if (!pmc_data->chws) + goto err; + + pmc_data->nsystem = nsystem; + pmc_data->shws = kcalloc(nsystem, sizeof(struct clk_hw *), GFP_KERNEL); + if (!pmc_data->shws) + goto err; + + pmc_data->nperiph = nperiph; + pmc_data->phws = kcalloc(nperiph, sizeof(struct clk_hw *), GFP_KERNEL); + if (!pmc_data->phws) + goto err; + + pmc_data->ngck = ngck; + pmc_data->ghws = kcalloc(ngck, sizeof(struct clk_hw *), GFP_KERNEL); + if (!pmc_data->ghws) + goto err; + + return pmc_data; + +err: + pmc_data_free(pmc_data); + + return NULL; +} + #ifdef CONFIG_PM static struct regmap *pmcreg; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h @@ -19,6 +19,17 @@ extern spinlock_t pmc_pcr_lock; +struct pmc_data { + unsigned int ncore; + struct clk_hw **chws; + unsigned int nsystem; + struct clk_hw **shws; + unsigned int nperiph; + struct clk_hw **phws; + unsigned int ngck; + struct clk_hw **ghws; +}; + struct clk_range { unsigned long min; unsigned long max; @@ -26,9 +37,157 @@ struct clk_range { #define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,} +struct clk_master_layout { + u32 mask; + u8 pres_shift; +}; + +extern const struct clk_master_layout at91rm9200_master_layout; +extern const struct clk_master_layout at91sam9x5_master_layout; + +struct clk_master_characteristics { + struct clk_range output; + u32 divisors[4]; + u8 have_div3_pres; +}; + +struct clk_pll_layout { + u32 pllr_mask; + u16 mul_mask; + u8 mul_shift; +}; + +extern const struct clk_pll_layout at91rm9200_pll_layout; +extern const struct clk_pll_layout at91sam9g45_pll_layout; +extern const struct clk_pll_layout at91sam9g20_pllb_layout; +extern const struct clk_pll_layout sama5d3_pll_layout; + +struct clk_pll_characteristics { + struct clk_range input; + int num_output; + struct clk_range *output; + u16 *icpll; + u8 *out; +}; + +struct clk_programmable_layout { + u8 pres_shift; + u8 css_mask; + u8 have_slck_mck; +}; + +extern const struct clk_programmable_layout at91rm9200_programmable_layout; +extern const struct clk_programmable_layout at91sam9g45_programmable_layout; +extern const struct clk_programmable_layout at91sam9x5_programmable_layout; + +#define ndck(a, s) (a[s - 1].id + 1) +#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) +struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, + unsigned int nperiph, unsigned int ngck); +void pmc_data_free(struct pmc_data *pmc_data); + int of_at91_get_clk_range(struct device_node *np, const char *propname, struct clk_range *range); +struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data); + +struct clk_hw * __init +at91_clk_register_audio_pll_frac(struct regmap *regmap, const char *name, + const char *parent_name); + +struct clk_hw * __init +at91_clk_register_audio_pll_pad(struct regmap *regmap, const char *name, + const char *parent_name); + +struct clk_hw * __init +at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name, + const char *parent_name); + +struct clk_hw * __init +at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, + const char *name, const char **parent_names, + u8 num_parents, u8 id, bool pll_audio, + const struct clk_range *range); + +struct clk_hw * __init +at91_clk_register_h32mx(struct regmap *regmap, const char *name, + const char *parent_name); + +struct clk_hw * __init +at91_clk_i2s_mux_register(struct regmap *regmap, const char *name, + const char * const *parent_names, + unsigned int num_parents, u8 bus_id); + +struct clk_hw * __init +at91_clk_register_main_rc_osc(struct regmap *regmap, const char *name, + u32 frequency, u32 accuracy); +struct clk_hw * __init +at91_clk_register_main_osc(struct regmap *regmap, const char *name, + const char *parent_name, bool bypass); +struct clk_hw * __init +at91_clk_register_rm9200_main(struct regmap *regmap, + const char *name, + const char *parent_name); +struct clk_hw * __init +at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name, + const char **parent_names, int num_parents); + +struct clk_hw * __init +at91_clk_register_master(struct regmap *regmap, const char *name, + int num_parents, const char **parent_names, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics); + +struct clk_hw * __init +at91_clk_register_peripheral(struct regmap *regmap, const char *name, + const char *parent_name, u32 id); +struct clk_hw * __init +at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, + const char *name, const char *parent_name, + u32 id, const struct clk_range *range); + +struct clk_hw * __init +at91_clk_register_pll(struct regmap *regmap, const char *name, + const char *parent_name, u8 id, + const struct clk_pll_layout *layout, + const struct clk_pll_characteristics *characteristics); +struct clk_hw * __init +at91_clk_register_plldiv(struct regmap *regmap, const char *name, + const char *parent_name); + +struct clk_hw * __init +at91_clk_register_programmable(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents, u8 id, + const struct clk_programmable_layout *layout); + +struct clk_hw * __init +at91_clk_register_sam9260_slow(struct regmap *regmap, + const char *name, + const char **parent_names, + int num_parents); + +struct clk_hw * __init +at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents); + +struct clk_hw * __init +at91_clk_register_system(struct regmap *regmap, const char *name, + const char *parent_name, u8 id); + +struct clk_hw * __init +at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents); +struct clk_hw * __init +at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, + const char *parent_name); +struct clk_hw * __init +at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, + const char *parent_name, const u32 *divisors); + +struct clk_hw * __init +at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, + const char *name, const char *parent_name); + #ifdef CONFIG_PM void pmc_register_id(u8 id); void pmc_register_pck(u8 pck); diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> +#include <linux/slab.h> + +#include <dt-bindings/clock/at91.h> + +#include "pmc.h" + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 124000000, .max = 166000000 }, + .divisors = { 1, 2, 4, 3 }, +}; + +static u8 plla_out[] = { 0 }; + +static u16 plla_icpll[] = { 0 }; + +static struct clk_range plla_outputs[] = { + { .min = 600000000, .max = 1200000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 12000000, .max = 12000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, + .icpll = plla_icpll, + .out = plla_out, +}; + +static const struct { + char *n; + char *p; + u8 id; +} sama5d2_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "lcdck", .p = "masterck", .id = 3 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, + { .n = "iscck", .p = "masterck", .id = 18 }, +}; + +static const struct { + char *n; + u8 id; + struct clk_range r; +} sama5d2_periph32ck[] = { + { .n = "macb0_clk", .id = 5, .r = { .min = 0, .max = 83000000 }, }, + { .n = "tdes_clk", .id = 11, .r = { .min = 0, .max = 83000000 }, }, + { .n = "matrix1_clk", .id = 14, }, + { .n = "hsmc_clk", .id = 17, }, + { .n = "pioA_clk", .id = 18, .r = { .min = 0, .max = 83000000 }, }, + { .n = "flx0_clk", .id = 19, .r = { .min = 0, .max = 83000000 }, }, + { .n = "flx1_clk", .id = 20, .r = { .min = 0, .max = 83000000 }, }, + { .n = "flx2_clk", .id = 21, .r = { .min = 0, .max = 83000000 }, }, + { .n = "flx3_clk", .id = 22, .r = { .min = 0, .max = 83000000 }, }, + { .n = "flx4_clk", .id = 23, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart0_clk", .id = 24, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart1_clk", .id = 25, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart2_clk", .id = 26, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart3_clk", .id = 27, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart4_clk", .id = 28, .r = { .min = 0, .max = 83000000 }, }, + { .n = "twi0_clk", .id = 29, .r = { .min = 0, .max = 83000000 }, }, + { .n = "twi1_clk", .id = 30, .r = { .min = 0, .max = 83000000 }, }, + { .n = "spi0_clk", .id = 33, .r = { .min = 0, .max = 83000000 }, }, + { .n = "spi1_clk", .id = 34, .r = { .min = 0, .max = 83000000 }, }, + { .n = "tcb0_clk", .id = 35, .r = { .min = 0, .max = 83000000 }, }, + { .n = "tcb1_clk", .id = 36, .r = { .min = 0, .max = 83000000 }, }, + { .n = "pwm_clk", .id = 38, .r = { .min = 0, .max = 83000000 }, }, + { .n = "adc_clk", .id = 40, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uhphs_clk", .id = 41, .r = { .min = 0, .max = 83000000 }, }, + { .n = "udphs_clk", .id = 42, .r = { .min = 0, .max = 83000000 }, }, + { .n = "ssc0_clk", .id = 43, .r = { .min = 0, .max = 83000000 }, }, + { .n = "ssc1_clk", .id = 44, .r = { .min = 0, .max = 83000000 }, }, + { .n = "trng_clk", .id = 47, .r = { .min = 0, .max = 83000000 }, }, + { .n = "pdmic_clk", .id = 48, .r = { .min = 0, .max = 83000000 }, }, + { .n = "securam_clk", .id = 51, }, + { .n = "i2s0_clk", .id = 54, .r = { .min = 0, .max = 83000000 }, }, + { .n = "i2s1_clk", .id = 55, .r = { .min = 0, .max = 83000000 }, }, + { .n = "can0_clk", .id = 56, .r = { .min = 0, .max = 83000000 }, }, + { .n = "can1_clk", .id = 57, .r = { .min = 0, .max = 83000000 }, }, + { .n = "classd_clk", .id = 59, .r = { .min = 0, .max = 83000000 }, }, +}; + +static const struct { + char *n; + u8 id; +} sama5d2_periphck[] = { + { .n = "dma0_clk", .id = 6, }, + { .n = "dma1_clk", .id = 7, }, + { .n = "aes_clk", .id = 9, }, + { .n = "aesb_clk", .id = 10, }, + { .n = "sha_clk", .id = 12, }, + { .n = "mpddr_clk", .id = 13, }, + { .n = "matrix0_clk", .id = 15, }, + { .n = "sdmmc0_hclk", .id = 31, }, + { .n = "sdmmc1_hclk", .id = 32, }, + { .n = "lcdc_clk", .id = 45, }, + { .n = "isc_clk", .id = 46, }, + { .n = "qspi0_clk", .id = 52, }, + { .n = "qspi1_clk", .id = 53, }, +}; + +static const struct { + char *n; + u8 id; + struct clk_range r; + bool pll; +} sama5d2_gck[] = { + { .n = "sdmmc0_gclk", .id = 31, }, + { .n = "sdmmc1_gclk", .id = 32, }, + { .n = "tcb0_gclk", .id = 35, .r = { .min = 0, .max = 83000000 }, }, + { .n = "tcb1_gclk", .id = 36, .r = { .min = 0, .max = 83000000 }, }, + { .n = "pwm_gclk", .id = 38, .r = { .min = 0, .max = 83000000 }, }, + { .n = "isc_gclk", .id = 46, }, + { .n = "pdmic_gclk", .id = 48, }, + { .n = "i2s0_gclk", .id = 54, .pll = true }, + { .n = "i2s1_gclk", .id = 55, .pll = true }, + { .n = "can0_gclk", .id = 56, .r = { .min = 0, .max = 80000000 }, }, + { .n = "can1_gclk", .id = 57, .r = { .min = 0, .max = 80000000 }, }, + { .n = "classd_gclk", .id = 59, .r = { .min = 0, .max = 100000000 }, + .pll = true }, +}; + +static void __init sama5d2_pmc_setup(struct device_node *np) +{ + struct clk_range range = CLK_RANGE(0, 0); + const char *slck_name, *mainxtal_name; + struct pmc_data *sama5d2_pmc; + const char *parent_names[6]; + struct regmap *regmap, *regmap_sfr; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "slow_clk"); + if (i < 0) + return; + + slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + sama5d2_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1, + nck(sama5d2_systemck), + nck(sama5d2_periph32ck), + nck(sama5d2_gck)); + if (!sama5d2_pmc) + return; + + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000, + 100000000); + if (IS_ERR(hw)) + goto err_free; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "main_rc_osc"; + parent_names[1] = "main_osc"; + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->chws[PMC_MAIN] = hw; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &sama5d3_pll_layout, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack"); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_audio_pll_frac(regmap, "audiopll_fracck", + "mainck"); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_audio_pll_pad(regmap, "audiopll_padck", + "audiopll_fracck"); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_audio_pll_pmc(regmap, "audiopll_pmcck", + "audiopll_fracck"); + if (IS_ERR(hw)) + goto err_free; + + regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(regmap_sfr)) + regmap_sfr = NULL; + + hw = at91_clk_register_utmi(regmap, regmap_sfr, "utmick", "mainck"); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91sam9x5_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->chws[PMC_MCK] = hw; + + hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck"); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->chws[PMC_MCK2] = hw; + + parent_names[0] = "plladivck"; + parent_names[1] = "utmick"; + hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + parent_names[4] = "mck"; + for (i = 0; i < 3; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 5, i, + &at91sam9x5_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) { + hw = at91_clk_register_system(regmap, sama5d2_systemck[i].n, + sama5d2_systemck[i].p, + sama5d2_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->shws[sama5d2_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + sama5d2_periphck[i].n, + "masterck", + sama5d2_periphck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->phws[sama5d2_periphck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + sama5d2_periph32ck[i].n, + "h32mxck", + sama5d2_periph32ck[i].id, + &sama5d2_periph32ck[i].r); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->phws[sama5d2_periph32ck[i].id] = hw; + } + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + parent_names[4] = "mck"; + parent_names[5] = "audiopll_pmcck"; + for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) { + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, + sama5d2_gck[i].n, + parent_names, 6, + sama5d2_gck[i].id, + sama5d2_gck[i].pll, + &sama5d2_gck[i].r); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->ghws[sama5d2_gck[i].id] = hw; + } + + if (regmap_sfr) { + parent_names[0] = "i2s0_clk"; + parent_names[1] = "i2s0_gclk"; + hw = at91_clk_i2s_mux_register(regmap_sfr, "i2s0_muxclk", + parent_names, 2, 0); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->chws[PMC_I2S0_MUX] = hw; + + parent_names[0] = "i2s1_clk"; + parent_names[1] = "i2s1_gclk"; + hw = at91_clk_i2s_mux_register(regmap_sfr, "i2s1_muxclk", + parent_names, 2, 1); + if (IS_ERR(hw)) + goto err_free; + + sama5d2_pmc->chws[PMC_I2S1_MUX] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d2_pmc); + + return; + +err_free: + pmc_data_free(sama5d2_pmc); +} +CLK_OF_DECLARE_DRIVER(sama5d2_pmc, "atmel,sama5d2-pmc", sama5d2_pmc_setup); diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> +#include <linux/slab.h> + +#include <dt-bindings/clock/at91.h> + +#include "pmc.h" + +static const struct clk_master_characteristics mck_characteristics = { + .output = { .min = 125000000, .max = 200000000 }, + .divisors = { 1, 2, 4, 3 }, +}; + +static u8 plla_out[] = { 0 }; + +static u16 plla_icpll[] = { 0 }; + +static struct clk_range plla_outputs[] = { + { .min = 600000000, .max = 1200000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 12000000, .max = 12000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, + .icpll = plla_icpll, + .out = plla_out, +}; + +static const struct { + char *n; + char *p; + u8 id; +} sama5d4_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "lcdck", .p = "masterck", .id = 3 }, + { .n = "smdck", .p = "smdclk", .id = 4 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "udpck", .p = "usbck", .id = 7 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, + { .n = "pck2", .p = "prog2", .id = 10 }, +}; + +static const struct { + char *n; + u8 id; +} sama5d4_periph32ck[] = { + { .n = "pioD_clk", .id = 5 }, + { .n = "usart0_clk", .id = 6 }, + { .n = "usart1_clk", .id = 7 }, + { .n = "icm_clk", .id = 9 }, + { .n = "aes_clk", .id = 12 }, + { .n = "tdes_clk", .id = 14 }, + { .n = "sha_clk", .id = 15 }, + { .n = "matrix1_clk", .id = 17 }, + { .n = "hsmc_clk", .id = 22 }, + { .n = "pioA_clk", .id = 23 }, + { .n = "pioB_clk", .id = 24 }, + { .n = "pioC_clk", .id = 25 }, + { .n = "pioE_clk", .id = 26 }, + { .n = "uart0_clk", .id = 27 }, + { .n = "uart1_clk", .id = 28 }, + { .n = "usart2_clk", .id = 29 }, + { .n = "usart3_clk", .id = 30 }, + { .n = "usart4_clk", .id = 31 }, + { .n = "twi0_clk", .id = 32 }, + { .n = "twi1_clk", .id = 33 }, + { .n = "twi2_clk", .id = 34 }, + { .n = "mci0_clk", .id = 35 }, + { .n = "mci1_clk", .id = 36 }, + { .n = "spi0_clk", .id = 37 }, + { .n = "spi1_clk", .id = 38 }, + { .n = "spi2_clk", .id = 39 }, + { .n = "tcb0_clk", .id = 40 }, + { .n = "tcb1_clk", .id = 41 }, + { .n = "tcb2_clk", .id = 42 }, + { .n = "pwm_clk", .id = 43 }, + { .n = "adc_clk", .id = 44 }, + { .n = "dbgu_clk", .id = 45 }, + { .n = "uhphs_clk", .id = 46 }, + { .n = "udphs_clk", .id = 47 }, + { .n = "ssc0_clk", .id = 48 }, + { .n = "ssc1_clk", .id = 49 }, + { .n = "trng_clk", .id = 53 }, + { .n = "macb0_clk", .id = 54 }, + { .n = "macb1_clk", .id = 55 }, + { .n = "fuse_clk", .id = 57 }, + { .n = "securam_clk", .id = 59 }, + { .n = "smd_clk", .id = 61 }, + { .n = "twi3_clk", .id = 62 }, + { .n = "catb_clk", .id = 63 }, +}; + +static const struct { + char *n; + u8 id; +} sama5d4_periphck[] = { + { .n = "dma0_clk", .id = 8 }, + { .n = "cpkcc_clk", .id = 10 }, + { .n = "aesb_clk", .id = 13 }, + { .n = "mpddr_clk", .id = 16 }, + { .n = "matrix0_clk", .id = 18 }, + { .n = "vdec_clk", .id = 19 }, + { .n = "dma1_clk", .id = 50 }, + { .n = "lcdc_clk", .id = 51 }, + { .n = "isi_clk", .id = 52 }, +}; + +static void __init sama5d4_pmc_setup(struct device_node *np) +{ + struct clk_range range = CLK_RANGE(0, 0); + const char *slck_name, *mainxtal_name; + struct pmc_data *sama5d4_pmc; + const char *parent_names[5]; + struct regmap *regmap; + struct clk_hw *hw; + int i; + bool bypass; + + i = of_property_match_string(np, "clock-names", "slow_clk"); + if (i < 0) + return; + + slck_name = of_clk_get_parent_name(np, i); + + i = of_property_match_string(np, "clock-names", "main_xtal"); + if (i < 0) + return; + mainxtal_name = of_clk_get_parent_name(np, i); + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + sama5d4_pmc = pmc_data_allocate(PMC_MCK2 + 1, + nck(sama5d4_systemck), + nck(sama5d4_periph32ck), 0); + if (!sama5d4_pmc) + return; + + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000, + 100000000); + if (IS_ERR(hw)) + goto err_free; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, + bypass); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "main_rc_osc"; + parent_names[1] = "main_osc"; + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &sama5d3_pll_layout, &plla_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack"); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck"); + if (IS_ERR(hw)) + goto err_free; + + sama5d4_pmc->chws[PMC_UTMI] = hw; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91sam9x5_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + sama5d4_pmc->chws[PMC_MCK] = hw; + + hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck"); + if (IS_ERR(hw)) + goto err_free; + + sama5d4_pmc->chws[PMC_MCK2] = hw; + + parent_names[0] = "plladivck"; + parent_names[1] = "utmick"; + hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = "plladivck"; + parent_names[1] = "utmick"; + hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "utmick"; + parent_names[4] = "mck"; + for (i = 0; i < 3; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw = at91_clk_register_programmable(regmap, name, + parent_names, 5, i, + &at91sam9x5_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(sama5d4_systemck); i++) { + hw = at91_clk_register_system(regmap, sama5d4_systemck[i].n, + sama5d4_systemck[i].p, + sama5d4_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + sama5d4_pmc->shws[sama5d4_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + sama5d4_periphck[i].n, + "masterck", + sama5d4_periphck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + sama5d4_pmc->phws[sama5d4_periphck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + sama5d4_periph32ck[i].n, + "h32mxck", + sama5d4_periph32ck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + sama5d4_pmc->phws[sama5d4_periph32ck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d4_pmc); + + return; + +err_free: + pmc_data_free(sama5d4_pmc); +} +CLK_OF_DECLARE_DRIVER(sama5d4_pmc, "atmel,sama5d4-pmc", sama5d4_pmc_setup); diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c @@ -301,13 +301,13 @@ static void __init of_axs10x_pll_clk_setup(struct device_node *node) ret = clk_hw_register(NULL, &pll_clk->hw); if (ret) { - pr_err("failed to register %s clock\n", node->name); + pr_err("failed to register %pOFn clock\n", node); goto err_unmap_lock; } ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw); if (ret) { - pr_err("failed to add hw provider for %s clock\n", node->name); + pr_err("failed to add hw provider for %pOFn clock\n", node); goto err_unregister_clk; } diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c @@ -808,29 +808,29 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu, ret = of_address_to_resource(node, 0, &res); if (ret) { - pr_err("%s: no valid CCU registers found for %s\n", __func__, - node->name); + pr_err("%s: no valid CCU registers found for %pOFn\n", __func__, + node); goto out_err; } range = resource_size(&res); if (range > (resource_size_t)U32_MAX) { - pr_err("%s: address range too large for %s\n", __func__, - node->name); + pr_err("%s: address range too large for %pOFn\n", __func__, + node); goto out_err; } ccu->range = (u32)range; if (!ccu_data_valid(ccu)) { - pr_err("%s: ccu data not valid for %s\n", __func__, node->name); + pr_err("%s: ccu data not valid for %pOFn\n", __func__, node); goto out_err; } ccu->base = ioremap(res.start, ccu->range); if (!ccu->base) { - pr_err("%s: unable to map CCU registers for %s\n", __func__, - node->name); + pr_err("%s: unable to map CCU registers for %pOFn\n", __func__, + node); goto out_err; } ccu->node = of_node_get(node); @@ -848,16 +848,16 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu, ret = of_clk_add_hw_provider(node, of_clk_kona_onecell_get, ccu); if (ret) { - pr_err("%s: error adding ccu %s as provider (%d)\n", __func__, - node->name, ret); + pr_err("%s: error adding ccu %pOFn as provider (%d)\n", __func__, + node, ret); goto out_err; } if (!kona_ccu_init(ccu)) - pr_err("Broadcom %s initialization had errors\n", node->name); + pr_err("Broadcom %pOFn initialization had errors\n", node); return; out_err: kona_ccu_teardown(ccu); - pr_err("Broadcom %s setup aborted\n", node->name); + pr_err("Broadcom %pOFn setup aborted\n", node); } diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c @@ -281,7 +281,7 @@ static void __init asm9260_acc_init(struct device_node *np) base = of_io_request_and_map(np, 0, np->name); if (IS_ERR(base)) - panic("%s: unable to map resource", np->name); + panic("%pOFn: unable to map resource", np); /* register pll */ rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000; @@ -292,7 +292,7 @@ static void __init asm9260_acc_init(struct device_node *np) ref_clk, 0, rate, accuracy); if (IS_ERR(hw)) - panic("%s: can't register REFCLK. Check DT!", np->name); + panic("%pOFn: can't register REFCLK. Check DT!", np); for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) { const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n]; diff --git a/drivers/clk/clk-bulk.c b/drivers/clk/clk-bulk.c @@ -17,8 +17,65 @@ */ #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/device.h> #include <linux/export.h> +#include <linux/of.h> +#include <linux/slab.h> + +static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks, + struct clk_bulk_data *clks) +{ + int ret; + int i; + + for (i = 0; i < num_clks; i++) + clks[i].clk = NULL; + + for (i = 0; i < num_clks; i++) { + clks[i].clk = of_clk_get(np, i); + if (IS_ERR(clks[i].clk)) { + ret = PTR_ERR(clks[i].clk); + pr_err("%pOF: Failed to get clk index: %d ret: %d\n", + np, i, ret); + clks[i].clk = NULL; + goto err; + } + } + + return 0; + +err: + clk_bulk_put(i, clks); + + return ret; +} + +static int __must_check of_clk_bulk_get_all(struct device_node *np, + struct clk_bulk_data **clks) +{ + struct clk_bulk_data *clk_bulk; + int num_clks; + int ret; + + num_clks = of_clk_get_parent_count(np); + if (!num_clks) + return 0; + + clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL); + if (!clk_bulk) + return -ENOMEM; + + ret = of_clk_bulk_get(np, num_clks, clk_bulk); + if (ret) { + kfree(clk_bulk); + return ret; + } + + *clks = clk_bulk; + + return num_clks; +} void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) { @@ -59,6 +116,29 @@ err: } EXPORT_SYMBOL(clk_bulk_get); +void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks) +{ + if (IS_ERR_OR_NULL(clks)) + return; + + clk_bulk_put(num_clks, clks); + + kfree(clks); +} +EXPORT_SYMBOL(clk_bulk_put_all); + +int __must_check clk_bulk_get_all(struct device *dev, + struct clk_bulk_data **clks) +{ + struct device_node *np = dev_of_node(dev); + + if (!np) + return 0; + + return of_clk_bulk_get_all(np, clks); +} +EXPORT_SYMBOL(clk_bulk_get_all); + #ifdef CONFIG_HAVE_CLK_PREPARE /** diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c @@ -669,8 +669,8 @@ static int cdce925_probe(struct i2c_client *client, /* Register PLL clocks */ for (i = 0; i < data->chip_info->num_plls; ++i) { - pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d", - client->dev.of_node->name, i); + pll_clk_name[i] = kasprintf(GFP_KERNEL, "%pOFn.pll%d", + client->dev.of_node, i); init.name = pll_clk_name[i]; data->pll[i].chip = data; data->pll[i].hw.init = &init; @@ -703,6 +703,7 @@ static int cdce925_probe(struct i2c_client *client, 0x12 + (i*CDCE925_OFFSET_PLL), 0x07, value & 0x07); } + of_node_put(np_output); } /* Register output clock Y1 */ @@ -710,7 +711,7 @@ static int cdce925_probe(struct i2c_client *client, init.flags = 0; init.num_parents = 1; init.parent_names = &parent_name; /* Mux Y1 to input */ - init.name = kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node->name); + init.name = kasprintf(GFP_KERNEL, "%pOFn.Y1", client->dev.of_node); data->clk[0].chip = data; data->clk[0].hw.init = &init; data->clk[0].index = 0; @@ -727,8 +728,8 @@ static int cdce925_probe(struct i2c_client *client, init.flags = CLK_SET_RATE_PARENT; init.num_parents = 1; for (i = 1; i < data->chip_info->num_outputs; ++i) { - init.name = kasprintf(GFP_KERNEL, "%s.Y%d", - client->dev.of_node->name, i+1); + init.name = kasprintf(GFP_KERNEL, "%pOFn.Y%d", + client->dev.of_node, i+1); data->clk[i].chip = data; data->clk[i].hw.init = &init; data->clk[i].index = i; diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c @@ -70,6 +70,30 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, } EXPORT_SYMBOL_GPL(devm_clk_bulk_get); +int __must_check devm_clk_bulk_get_all(struct device *dev, + struct clk_bulk_data **clks) +{ + struct clk_bulk_devres *devres; + int ret; + + devres = devres_alloc(devm_clk_bulk_release, + sizeof(*devres), GFP_KERNEL); + if (!devres) + return -ENOMEM; + + ret = clk_bulk_get_all(dev, &devres->clks); + if (ret > 0) { + *clks = devres->clks; + devres->num_clks = ret; + devres_add(dev, devres); + } else { + devres_free(devres); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all); + static int devm_clk_match(struct device *dev, void *res, void *data) { struct clk **c = res; diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c @@ -158,14 +158,14 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) int ret; if (of_property_read_u32(node, "clock-div", &div)) { - pr_err("%s Fixed factor clock <%s> must have a clock-div property\n", - __func__, node->name); + pr_err("%s Fixed factor clock <%pOFn> must have a clock-div property\n", + __func__, node); return ERR_PTR(-EIO); } if (of_property_read_u32(node, "clock-mult", &mult)) { - pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n", - __func__, node->name); + pr_err("%s Fixed factor clock <%pOFn> must have a clock-mult property\n", + __func__, node); return ERR_PTR(-EIO); } diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c @@ -200,6 +200,7 @@ static int of_fixed_clk_remove(struct platform_device *pdev) { struct clk *clk = platform_get_drvdata(pdev); + of_clk_del_provider(pdev->dev.of_node); clk_unregister_fixed_rate(clk); return 0; diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c @@ -233,11 +233,11 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) if (IS_ERR(gpiod)) { ret = PTR_ERR(gpiod); if (ret == -EPROBE_DEFER) - pr_debug("%s: %s: GPIOs not yet available, retry later\n", - node->name, __func__); + pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n", + node, __func__); else - pr_err("%s: %s: Can't get '%s' named GPIO property\n", - node->name, __func__, + pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n", + node, __func__, gpio_name); return ret; } diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c @@ -390,13 +390,13 @@ static void __init of_hsdk_pll_clk_setup(struct device_node *node) ret = clk_hw_register(NULL, &pll_clk->hw); if (ret) { - pr_err("failed to register %s clock\n", node->name); + pr_err("failed to register %pOFn clock\n", node); goto err_unmap_spec_regs; } ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw); if (ret) { - pr_err("failed to add hw provider for %s clock\n", node->name); + pr_err("failed to add hw provider for %pOFn clock\n", node); goto err_unmap_spec_regs; } diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c @@ -1,24 +1,9 @@ -/* - * clk-max77686.c - Clock driver for Maxim 77686/MAX77802 - * - * Copyright (C) 2012 Samsung Electornics - * Jonghwa Lee <jonghwa3.lee@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// clk-max77686.c - Clock driver for Maxim 77686/MAX77802 +// +// Copyright (C) 2012 Samsung Electornics +// Jonghwa Lee <jonghwa3.lee@samsung.com> #include <linux/kernel.h> #include <linux/slab.h> diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c @@ -97,8 +97,8 @@ static void __init nomadik_src_init(void) } src_base = of_iomap(np, 0); if (!src_base) { - pr_err("%s: must have src parent node with REGS (%s)\n", - __func__, np->name); + pr_err("%s: must have src parent node with REGS (%pOFn)\n", + __func__, np); return; } diff --git a/drivers/clk/clk-npcm7xx.c b/drivers/clk/clk-npcm7xx.c @@ -549,7 +549,7 @@ static void __init npcm7xx_clk_init(struct device_node *clk_np) ret = of_address_to_resource(clk_np, 0, &res); if (ret) { - pr_err("%s: failed to get resource, ret %d\n", clk_np->name, + pr_err("%pOFn: failed to get resource, ret %d\n", clk_np, ret); return; } diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c @@ -195,8 +195,8 @@ static void palmas_clks_get_clk_data(struct platform_device *pdev, prop = PALMAS_EXT_CONTROL_NSLEEP; break; default: - dev_warn(&pdev->dev, "%s: Invalid ext control option: %u\n", - node->name, prop); + dev_warn(&pdev->dev, "%pOFn: Invalid ext control option: %u\n", + node, prop); prop = 0; break; } diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c @@ -945,8 +945,8 @@ static void __init core_mux_init(struct device_node *np) rc = of_clk_add_provider(np, of_clk_src_simple_get, clk); if (rc) { - pr_err("%s: Couldn't register clk provider for node %s: %d\n", - __func__, np->name, rc); + pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n", + __func__, np, rc); return; } } @@ -1199,8 +1199,8 @@ static void __init legacy_pll_init(struct device_node *np, int idx) rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data); if (rc) { - pr_err("%s: Couldn't register clk provider for node %s: %d\n", - __func__, np->name, rc); + pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n", + __func__, np, rc); goto err_cell; } @@ -1360,7 +1360,7 @@ static void __init clockgen_init(struct device_node *np) is_old_ls1021a = true; } if (!clockgen.regs) { - pr_err("%s(): %s: of_iomap() failed\n", __func__, np->name); + pr_err("%s(): %pOFn: of_iomap() failed\n", __func__, np); return; } @@ -1406,8 +1406,8 @@ static void __init clockgen_init(struct device_node *np) ret = of_clk_add_provider(np, clockgen_clk_get, &clockgen); if (ret) { - pr_err("%s: Couldn't register clk provider for node %s: %d\n", - __func__, np->name, ret); + pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n", + __func__, np, ret); } return; diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c @@ -1,19 +1,8 @@ -/* - * clk-s2mps11.c - Clock driver for S2MPS11. - * - * Copyright (C) 2013,2014 Samsung Electornics - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// clk-s2mps11.c - Clock driver for S2MPS11. +// +// Copyright (C) 2013,2014 Samsung Electornics #include <linux/module.h> #include <linux/err.h> @@ -28,12 +17,7 @@ #include <linux/mfd/samsung/s5m8767.h> #include <linux/mfd/samsung/core.h> -enum { - S2MPS11_CLK_AP = 0, - S2MPS11_CLK_CP, - S2MPS11_CLK_BT, - S2MPS11_CLKS_NUM, -}; +#include <dt-bindings/clock/samsung,s2mps11.h> struct s2mps11_clk { struct sec_pmic_dev *iodev; @@ -245,6 +229,36 @@ static const struct platform_device_id s2mps11_clk_id[] = { }; MODULE_DEVICE_TABLE(platform, s2mps11_clk_id); +#ifdef CONFIG_OF +/* + * Device is instantiated through parent MFD device and device matching is done + * through platform_device_id. + * + * However if device's DT node contains proper clock compatible and driver is + * built as a module, then the *module* matching will be done trough DT aliases. + * This requires of_device_id table. In the same time this will not change the + * actual *device* matching so do not add .of_match_table. + */ +static const struct of_device_id s2mps11_dt_match[] __used = { + { + .compatible = "samsung,s2mps11-clk", + .data = (void *)S2MPS11X, + }, { + .compatible = "samsung,s2mps13-clk", + .data = (void *)S2MPS13X, + }, { + .compatible = "samsung,s2mps14-clk", + .data = (void *)S2MPS14X, + }, { + .compatible = "samsung,s5m8767-clk", + .data = (void *)S5M8767X, + }, { + /* Sentinel */ + }, +}; +MODULE_DEVICE_TABLE(of, s2mps11_dt_match); +#endif + static struct platform_driver s2mps11_clk_driver = { .driver = { .name = "s2mps11-clk", diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c @@ -132,7 +132,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev) count = handle->clk_ops->count_get(handle); if (count < 0) { - dev_err(dev, "%s: invalid clock output count\n", np->name); + dev_err(dev, "%pOFn: invalid clock output count\n", np); return -EINVAL; } diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c @@ -207,7 +207,7 @@ static int scpi_clk_add(struct device *dev, struct device_node *np, count = of_property_count_strings(np, "clock-output-names"); if (count < 0) { - dev_err(dev, "%s: invalid clock output count\n", np->name); + dev_err(dev, "%pOFn: invalid clock output count\n", np); return -EINVAL; } @@ -232,13 +232,13 @@ static int scpi_clk_add(struct device *dev, struct device_node *np, if (of_property_read_string_index(np, "clock-output-names", idx, &name)) { - dev_err(dev, "invalid clock name @ %s\n", np->name); + dev_err(dev, "invalid clock name @ %pOFn\n", np); return -EINVAL; } if (of_property_read_u32_index(np, "clock-indices", idx, &val)) { - dev_err(dev, "invalid clock index @ %s\n", np->name); + dev_err(dev, "invalid clock index @ %pOFn\n", np); return -EINVAL; } diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c @@ -1215,8 +1215,8 @@ static int si5351_dt_parse(struct i2c_client *client, /* per clkout properties */ for_each_child_of_node(np, child) { if (of_property_read_u32(child, "reg", &num)) { - dev_err(&client->dev, "missing reg property of %s\n", - child->name); + dev_err(&client->dev, "missing reg property of %pOFn\n", + child); goto put_child; } diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c @@ -1433,7 +1433,7 @@ static void __init stm32f4_rcc_init(struct device_node *np) base = of_iomap(np, 0); if (!base) { - pr_err("%s: unable to map resource\n", np->name); + pr_err("%pOFn: unable to map resource\n", np); return; } diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c @@ -1216,7 +1216,7 @@ static void __init stm32h7_rcc_init(struct device_node *np) /* get RCC base @ from DT */ base = of_iomap(np, 0); if (!base) { - pr_err("%s: unable to map resource", np->name); + pr_err("%pOFn: unable to map resource", np); goto err_free_clks; } diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c @@ -2088,7 +2088,7 @@ static void stm32mp1_rcc_init(struct device_node *np) base = of_iomap(np, 0); if (!base) { - pr_err("%s: unable to map resource", np->name); + pr_err("%pOFn: unable to map resource", np); of_node_put(np); return; } diff --git a/drivers/clk/clk-tango4.c b/drivers/clk/clk-tango4.c @@ -54,13 +54,13 @@ static void __init tango4_clkgen_setup(struct device_node *np) const char *parent = of_clk_get_parent_name(np, 0); if (!base) - panic("%s: invalid address\n", np->name); + panic("%pOFn: invalid address\n", np); if (readl(base + CPUCLK_DIV) & DIV_BYPASS) - panic("%s: unsupported cpuclk setup\n", np->name); + panic("%pOFn: unsupported cpuclk setup\n", np); if (readl(base + SYSCLK_DIV) & DIV_BYPASS) - panic("%s: unsupported sysclk setup\n", np->name); + panic("%pOFn: unsupported sysclk setup\n", np); writel(0x100, base + CPUCLK_DIV); /* disable frequency ramping */ @@ -77,9 +77,9 @@ static void __init tango4_clkgen_setup(struct device_node *np) pp[3] = clk_register_fixed_factor(NULL, "sdio_clk", "cd6", 0, 1, 2); if (IS_ERR(pp[0]) || IS_ERR(pp[1]) || IS_ERR(pp[2]) || IS_ERR(pp[3])) - panic("%s: clk registration failed\n", np->name); + panic("%pOFn: clk registration failed\n", np); if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) - panic("%s: clk provider registration failed\n", np->name); + panic("%pOFn: clk provider registration failed\n", np); } CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c @@ -924,6 +924,101 @@ static int clk_core_enable_lock(struct clk_core *core) } /** + * clk_gate_restore_context - restore context for poweroff + * @hw: the clk_hw pointer of clock whose state is to be restored + * + * The clock gate restore context function enables or disables + * the gate clocks based on the enable_count. This is done in cases + * where the clock context is lost and based on the enable_count + * the clock either needs to be enabled/disabled. This + * helps restore the state of gate clocks. + */ +void clk_gate_restore_context(struct clk_hw *hw) +{ + struct clk_core *core = hw->core; + + if (core->enable_count) + core->ops->enable(hw); + else + core->ops->disable(hw); +} +EXPORT_SYMBOL_GPL(clk_gate_restore_context); + +static int clk_core_save_context(struct clk_core *core) +{ + struct clk_core *child; + int ret = 0; + + hlist_for_each_entry(child, &core->children, child_node) { + ret = clk_core_save_context(child); + if (ret < 0) + return ret; + } + + if (core->ops && core->ops->save_context) + ret = core->ops->save_context(core->hw); + + return ret; +} + +static void clk_core_restore_context(struct clk_core *core) +{ + struct clk_core *child; + + if (core->ops && core->ops->restore_context) + core->ops->restore_context(core->hw); + + hlist_for_each_entry(child, &core->children, child_node) + clk_core_restore_context(child); +} + +/** + * clk_save_context - save clock context for poweroff + * + * Saves the context of the clock register for powerstates in which the + * contents of the registers will be lost. Occurs deep within the suspend + * code. Returns 0 on success. + */ +int clk_save_context(void) +{ + struct clk_core *clk; + int ret; + + hlist_for_each_entry(clk, &clk_root_list, child_node) { + ret = clk_core_save_context(clk); + if (ret < 0) + return ret; + } + + hlist_for_each_entry(clk, &clk_orphan_list, child_node) { + ret = clk_core_save_context(clk); + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(clk_save_context); + +/** + * clk_restore_context - restore clock context after poweroff + * + * Restore the saved clock context upon resume. + * + */ +void clk_restore_context(void) +{ + struct clk_core *core; + + hlist_for_each_entry(core, &clk_root_list, child_node) + clk_core_restore_context(core); + + hlist_for_each_entry(core, &clk_orphan_list, child_node) + clk_core_restore_context(core); +} +EXPORT_SYMBOL_GPL(clk_restore_context); + +/** * clk_enable - ungate a clock * @clk: the clk being ungated * diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c @@ -303,24 +303,6 @@ static int davinci_lpsc_clk_reset(struct clk *clk, bool reset) return 0; } -/* - * REVISIT: These exported functions can be removed after a non-DT lookup is - * added to the reset controller framework and the davinci-rproc driver is - * updated to use the generic reset controller framework. - */ - -int davinci_clk_reset_assert(struct clk *clk) -{ - return davinci_lpsc_clk_reset(clk, true); -} -EXPORT_SYMBOL(davinci_clk_reset_assert); - -int davinci_clk_reset_deassert(struct clk *clk) -{ - return davinci_lpsc_clk_reset(clk, false); -} -EXPORT_SYMBOL(davinci_clk_reset_deassert); - static int davinci_psc_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig @@ -21,6 +21,13 @@ config COMMON_CLK_HI3660 help Build the clock driver for hi3660. +config COMMON_CLK_HI3670 + bool "Hi3670 Clock Driver" + depends on ARCH_HISI || COMPILE_TEST + default ARCH_HISI + help + Build the clock driver for hi3670. + config COMMON_CLK_HI3798CV200 tristate "Hi3798CV200 Clock Driver" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o obj-$(CONFIG_COMMON_CLK_HI3516CV300) += crg-hi3516cv300.o obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o obj-$(CONFIG_COMMON_CLK_HI3660) += clk-hi3660.o +obj-$(CONFIG_COMMON_CLK_HI3670) += clk-hi3670.o obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o obj-$(CONFIG_RESET_HISI) += reset.o diff --git a/drivers/clk/hisilicon/clk-hi3670.c b/drivers/clk/hisilicon/clk-hi3670.c @@ -0,0 +1,1016 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2001-2021, Huawei Tech. Co., Ltd. + * Author: chenjun <chenjun14@huawei.com> + * + * Copyright (c) 2018, Linaro Ltd. + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + */ + +#include <dt-bindings/clock/hi3670-clock.h> +#include <linux/clk-provider.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include "clk.h" + +static const struct hisi_fixed_rate_clock hi3670_fixed_rate_clks[] = { + { HI3670_CLKIN_SYS, "clkin_sys", NULL, 0, 19200000, }, + { HI3670_CLKIN_REF, "clkin_ref", NULL, 0, 32764, }, + { HI3670_CLK_FLL_SRC, "clk_fll_src", NULL, 0, 134400000, }, + { HI3670_CLK_PPLL0, "clk_ppll0", NULL, 0, 1660000000, }, + { HI3670_CLK_PPLL1, "clk_ppll1", NULL, 0, 1866000000, }, + { HI3670_CLK_PPLL2, "clk_ppll2", NULL, 0, 1920000000, }, + { HI3670_CLK_PPLL3, "clk_ppll3", NULL, 0, 1200000000, }, + { HI3670_CLK_PPLL4, "clk_ppll4", NULL, 0, 900000000, }, + { HI3670_CLK_PPLL6, "clk_ppll6", NULL, 0, 393216000, }, + { HI3670_CLK_PPLL7, "clk_ppll7", NULL, 0, 1008000000, }, + { HI3670_CLK_PPLL_PCIE, "clk_ppll_pcie", NULL, 0, 100000000, }, + { HI3670_CLK_PCIEPLL_REV, "clk_pciepll_rev", NULL, 0, 100000000, }, + { HI3670_CLK_SCPLL, "clk_scpll", NULL, 0, 245760000, }, + { HI3670_PCLK, "pclk", NULL, 0, 20000000, }, + { HI3670_CLK_UART0_DBG, "clk_uart0_dbg", NULL, 0, 19200000, }, + { HI3670_CLK_UART6, "clk_uart6", NULL, 0, 19200000, }, + { HI3670_OSC32K, "osc32k", NULL, 0, 32764, }, + { HI3670_OSC19M, "osc19m", NULL, 0, 19200000, }, + { HI3670_CLK_480M, "clk_480m", NULL, 0, 480000000, }, + { HI3670_CLK_INVALID, "clk_invalid", NULL, 0, 10000000, }, +}; + +/* crgctrl */ +static const struct hisi_fixed_factor_clock hi3670_crg_fixed_factor_clks[] = { + { HI3670_CLK_DIV_SYSBUS, "clk_div_sysbus", "clk_mux_sysbus", + 1, 7, 0, }, + { HI3670_CLK_FACTOR_MMC, "clk_factor_mmc", "clkin_sys", + 1, 6, 0, }, + { HI3670_CLK_SD_SYS, "clk_sd_sys", "clk_sd_sys_gt", + 1, 6, 0, }, + { HI3670_CLK_SDIO_SYS, "clk_sdio_sys", "clk_sdio_sys_gt", + 1, 6, 0, }, + { HI3670_CLK_DIV_A53HPM, "clk_div_a53hpm", "clk_a53hpm_andgt", + 1, 4, 0, }, + { HI3670_CLK_DIV_320M, "clk_div_320m", "clk_320m_pll_gt", + 1, 5, 0, }, + { HI3670_PCLK_GATE_UART0, "pclk_gate_uart0", "clk_mux_uartl", + 1, 1, 0, }, + { HI3670_CLK_FACTOR_UART0, "clk_factor_uart0", "clk_mux_uart0", + 1, 1, 0, }, + { HI3670_CLK_FACTOR_USB3PHY_PLL, "clk_factor_usb3phy_pll", "clk_ppll0", + 1, 60, 0, }, + { HI3670_CLK_GATE_ABB_USB, "clk_gate_abb_usb", "clk_gate_usb_tcxo_en", + 1, 1, 0, }, + { HI3670_CLK_GATE_UFSPHY_REF, "clk_gate_ufsphy_ref", "clkin_sys", + 1, 1, 0, }, + { HI3670_ICS_VOLT_HIGH, "ics_volt_high", "peri_volt_hold", + 1, 1, 0, }, + { HI3670_ICS_VOLT_MIDDLE, "ics_volt_middle", "peri_volt_middle", + 1, 1, 0, }, + { HI3670_VENC_VOLT_HOLD, "venc_volt_hold", "peri_volt_hold", + 1, 1, 0, }, + { HI3670_VDEC_VOLT_HOLD, "vdec_volt_hold", "peri_volt_hold", + 1, 1, 0, }, + { HI3670_EDC_VOLT_HOLD, "edc_volt_hold", "peri_volt_hold", + 1, 1, 0, }, + { HI3670_CLK_ISP_SNCLK_FAC, "clk_isp_snclk_fac", "clk_isp_snclk_angt", + 1, 10, 0, }, + { HI3670_CLK_FACTOR_RXDPHY, "clk_factor_rxdphy", "clk_andgt_rxdphy", + 1, 6, 0, }, +}; + +static const struct hisi_gate_clock hi3670_crgctrl_gate_sep_clks[] = { + { HI3670_PPLL1_EN_ACPU, "ppll1_en_acpu", "clk_ppll1", + CLK_SET_RATE_PARENT, 0x0, 0, 0, }, + { HI3670_PPLL2_EN_ACPU, "ppll2_en_acpu", "clk_ppll2", + CLK_SET_RATE_PARENT, 0x0, 3, 0, }, + { HI3670_PPLL3_EN_ACPU, "ppll3_en_acpu", "clk_ppll3", + CLK_SET_RATE_PARENT, 0x0, 27, 0, }, + { HI3670_PPLL1_GT_CPU, "ppll1_gt_cpu", "clk_ppll1", + CLK_SET_RATE_PARENT, 0x460, 16, 0, }, + { HI3670_PPLL2_GT_CPU, "ppll2_gt_cpu", "clk_ppll2", + CLK_SET_RATE_PARENT, 0x460, 18, 0, }, + { HI3670_PPLL3_GT_CPU, "ppll3_gt_cpu", "clk_ppll3", + CLK_SET_RATE_PARENT, 0x460, 20, 0, }, + { HI3670_CLK_GATE_PPLL2_MEDIA, "clk_gate_ppll2_media", "clk_ppll2", + CLK_SET_RATE_PARENT, 0x410, 27, 0, }, + { HI3670_CLK_GATE_PPLL3_MEDIA, "clk_gate_ppll3_media", "clk_ppll3", + CLK_SET_RATE_PARENT, 0x410, 28, 0, }, + { HI3670_CLK_GATE_PPLL4_MEDIA, "clk_gate_ppll4_media", "clk_ppll4", + CLK_SET_RATE_PARENT, 0x410, 26, 0, }, + { HI3670_CLK_GATE_PPLL6_MEDIA, "clk_gate_ppll6_media", "clk_ppll6", + CLK_SET_RATE_PARENT, 0x410, 30, 0, }, + { HI3670_CLK_GATE_PPLL7_MEDIA, "clk_gate_ppll7_media", "clk_ppll7", + CLK_SET_RATE_PARENT, 0x410, 29, 0, }, + { HI3670_PCLK_GPIO0, "pclk_gpio0", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 0, 0, }, + { HI3670_PCLK_GPIO1, "pclk_gpio1", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 1, 0, }, + { HI3670_PCLK_GPIO2, "pclk_gpio2", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 2, 0, }, + { HI3670_PCLK_GPIO3, "pclk_gpio3", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 3, 0, }, + { HI3670_PCLK_GPIO4, "pclk_gpio4", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 4, 0, }, + { HI3670_PCLK_GPIO5, "pclk_gpio5", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 5, 0, }, + { HI3670_PCLK_GPIO6, "pclk_gpio6", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 6, 0, }, + { HI3670_PCLK_GPIO7, "pclk_gpio7", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 7, 0, }, + { HI3670_PCLK_GPIO8, "pclk_gpio8", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 8, 0, }, + { HI3670_PCLK_GPIO9, "pclk_gpio9", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 9, 0, }, + { HI3670_PCLK_GPIO10, "pclk_gpio10", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 10, 0, }, + { HI3670_PCLK_GPIO11, "pclk_gpio11", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 11, 0, }, + { HI3670_PCLK_GPIO12, "pclk_gpio12", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 12, 0, }, + { HI3670_PCLK_GPIO13, "pclk_gpio13", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 13, 0, }, + { HI3670_PCLK_GPIO14, "pclk_gpio14", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 14, 0, }, + { HI3670_PCLK_GPIO15, "pclk_gpio15", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 15, 0, }, + { HI3670_PCLK_GPIO16, "pclk_gpio16", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 16, 0, }, + { HI3670_PCLK_GPIO17, "pclk_gpio17", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 17, 0, }, + { HI3670_PCLK_GPIO20, "pclk_gpio20", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 20, 0, }, + { HI3670_PCLK_GPIO21, "pclk_gpio21", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x10, 21, 0, }, + { HI3670_PCLK_GATE_DSI0, "pclk_gate_dsi0", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x50, 28, 0, }, + { HI3670_PCLK_GATE_DSI1, "pclk_gate_dsi1", "clk_div_cfgbus", + CLK_SET_RATE_PARENT, 0x50, 29, 0, }, + { HI3670_HCLK_GATE_USB3OTG, "hclk_gate_usb3otg", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x0, 25, 0, }, + { HI3670_ACLK_GATE_USB3DVFS, "aclk_gate_usb3dvfs", "autodiv_emmc0bus", + CLK_SET_RATE_PARENT, 0x40, 1, 0, }, + { HI3670_HCLK_GATE_SDIO, "hclk_gate_sdio", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x0, 21, 0, }, + { HI3670_PCLK_GATE_PCIE_SYS, "pclk_gate_pcie_sys", "clk_div_mmc1bus", + CLK_SET_RATE_PARENT, 0x420, 7, 0, }, + { HI3670_PCLK_GATE_PCIE_PHY, "pclk_gate_pcie_phy", "pclk_gate_mmc1_pcie", + CLK_SET_RATE_PARENT, 0x420, 9, 0, }, + { HI3670_PCLK_GATE_MMC1_PCIE, "pclk_gate_mmc1_pcie", "pclk_div_mmc1_pcie", + CLK_SET_RATE_PARENT, 0x30, 12, 0, }, + { HI3670_PCLK_GATE_MMC0_IOC, "pclk_gate_mmc0_ioc", "clk_div_mmc0bus", + CLK_SET_RATE_PARENT, 0x40, 13, 0, }, + { HI3670_PCLK_GATE_MMC1_IOC, "pclk_gate_mmc1_ioc", "clk_div_mmc1bus", + CLK_SET_RATE_PARENT, 0x420, 21, 0, }, + { HI3670_CLK_GATE_DMAC, "clk_gate_dmac", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x30, 1, 0, }, + { HI3670_CLK_GATE_VCODECBUS2DDR, "clk_gate_vcodecbus2ddr", "clk_div_vcodecbus", + CLK_SET_RATE_PARENT, 0x0, 5, 0, }, + { HI3670_CLK_CCI400_BYPASS, "clk_cci400_bypass", "clk_ddrc_freq", + CLK_SET_RATE_PARENT, 0x22C, 28, 0, }, + { HI3670_CLK_GATE_CCI400, "clk_gate_cci400", "clk_ddrc_freq", + CLK_SET_RATE_PARENT, 0x50, 14, 0, }, + { HI3670_CLK_GATE_SD, "clk_gate_sd", "clk_mux_sd_sys", + CLK_SET_RATE_PARENT, 0x40, 17, 0, }, + { HI3670_HCLK_GATE_SD, "hclk_gate_sd", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x0, 30, 0, }, + { HI3670_CLK_GATE_SDIO, "clk_gate_sdio", "clk_mux_sdio_sys", + CLK_SET_RATE_PARENT, 0x40, 19, 0, }, + { HI3670_CLK_GATE_A57HPM, "clk_gate_a57hpm", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x050, 9, 0, }, + { HI3670_CLK_GATE_A53HPM, "clk_gate_a53hpm", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x050, 13, 0, }, + { HI3670_CLK_GATE_PA_A53, "clk_gate_pa_a53", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x480, 10, 0, }, + { HI3670_CLK_GATE_PA_A57, "clk_gate_pa_a57", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x480, 9, 0, }, + { HI3670_CLK_GATE_PA_G3D, "clk_gate_pa_g3d", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x480, 15, 0, }, + { HI3670_CLK_GATE_GPUHPM, "clk_gate_gpuhpm", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x050, 15, 0, }, + { HI3670_CLK_GATE_PERIHPM, "clk_gate_perihpm", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x050, 12, 0, }, + { HI3670_CLK_GATE_AOHPM, "clk_gate_aohpm", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x050, 11, 0, }, + { HI3670_CLK_GATE_UART1, "clk_gate_uart1", "clk_mux_uarth", + CLK_SET_RATE_PARENT, 0x20, 11, 0, }, + { HI3670_CLK_GATE_UART4, "clk_gate_uart4", "clk_mux_uarth", + CLK_SET_RATE_PARENT, 0x20, 14, 0, }, + { HI3670_PCLK_GATE_UART1, "pclk_gate_uart1", "clk_mux_uarth", + CLK_SET_RATE_PARENT, 0x20, 11, 0, }, + { HI3670_PCLK_GATE_UART4, "pclk_gate_uart4", "clk_mux_uarth", + CLK_SET_RATE_PARENT, 0x20, 14, 0, }, + { HI3670_CLK_GATE_UART2, "clk_gate_uart2", "clk_mux_uartl", + CLK_SET_RATE_PARENT, 0x20, 12, 0, }, + { HI3670_CLK_GATE_UART5, "clk_gate_uart5", "clk_mux_uartl", + CLK_SET_RATE_PARENT, 0x20, 15, 0, }, + { HI3670_PCLK_GATE_UART2, "pclk_gate_uart2", "clk_mux_uartl", + CLK_SET_RATE_PARENT, 0x20, 12, 0, }, + { HI3670_PCLK_GATE_UART5, "pclk_gate_uart5", "clk_mux_uartl", + CLK_SET_RATE_PARENT, 0x20, 15, 0, }, + { HI3670_CLK_GATE_UART0, "clk_gate_uart0", "clk_mux_uart0", + CLK_SET_RATE_PARENT, 0x20, 10, 0, }, + { HI3670_CLK_GATE_I2C3, "clk_gate_i2c3", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x20, 7, 0, }, + { HI3670_CLK_GATE_I2C4, "clk_gate_i2c4", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x20, 27, 0, }, + { HI3670_CLK_GATE_I2C7, "clk_gate_i2c7", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x10, 31, 0, }, + { HI3670_PCLK_GATE_I2C3, "pclk_gate_i2c3", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x20, 7, 0, }, + { HI3670_PCLK_GATE_I2C4, "pclk_gate_i2c4", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x20, 27, 0, }, + { HI3670_PCLK_GATE_I2C7, "pclk_gate_i2c7", "clk_mux_i2c", + CLK_SET_RATE_PARENT, 0x10, 31, 0, }, + { HI3670_CLK_GATE_SPI1, "clk_gate_spi1", "clk_mux_spi", + CLK_SET_RATE_PARENT, 0x20, 9, 0, }, + { HI3670_CLK_GATE_SPI4, "clk_gate_spi4", "clk_mux_spi", + CLK_SET_RATE_PARENT, 0x40, 4, 0, }, + { HI3670_PCLK_GATE_SPI1, "pclk_gate_spi1", "clk_mux_spi", + CLK_SET_RATE_PARENT, 0x20, 9, 0, }, + { HI3670_PCLK_GATE_SPI4, "pclk_gate_spi4", "clk_mux_spi", + CLK_SET_RATE_PARENT, 0x40, 4, 0, }, + { HI3670_CLK_GATE_USB3OTG_REF, "clk_gate_usb3otg_ref", "clkin_sys", + CLK_SET_RATE_PARENT, 0x40, 0, 0, }, + { HI3670_CLK_GATE_USB2PHY_REF, "clk_gate_usb2phy_ref", "clkin_sys", + CLK_SET_RATE_PARENT, 0x410, 19, 0, }, + { HI3670_CLK_GATE_PCIEAUX, "clk_gate_pcieaux", "clkin_sys", + CLK_SET_RATE_PARENT, 0x420, 8, 0, }, + { HI3670_ACLK_GATE_PCIE, "aclk_gate_pcie", "clk_gate_mmc1_pcieaxi", + CLK_SET_RATE_PARENT, 0x420, 5, 0, }, + { HI3670_CLK_GATE_MMC1_PCIEAXI, "clk_gate_mmc1_pcieaxi", "clk_div_pcieaxi", + CLK_SET_RATE_PARENT, 0x050, 4, 0, }, + { HI3670_CLK_GATE_PCIEPHY_REF, "clk_gate_pciephy_ref", "clk_ppll_pcie", + CLK_SET_RATE_PARENT, 0x470, 14, 0, }, + { HI3670_CLK_GATE_PCIE_DEBOUNCE, "clk_gate_pcie_debounce", "clk_ppll_pcie", + CLK_SET_RATE_PARENT, 0x470, 12, 0, }, + { HI3670_CLK_GATE_PCIEIO, "clk_gate_pcieio", "clk_ppll_pcie", + CLK_SET_RATE_PARENT, 0x470, 13, 0, }, + { HI3670_CLK_GATE_PCIE_HP, "clk_gate_pcie_hp", "clk_ppll_pcie", + CLK_SET_RATE_PARENT, 0x470, 15, 0, }, + { HI3670_CLK_GATE_AO_ASP, "clk_gate_ao_asp", "clk_div_ao_asp", + CLK_SET_RATE_PARENT, 0x0, 26, 0, }, + { HI3670_PCLK_GATE_PCTRL, "pclk_gate_pctrl", "clk_div_ptp", + CLK_SET_RATE_PARENT, 0x20, 31, 0, }, + { HI3670_CLK_CSI_TRANS_GT, "clk_csi_trans_gt", "clk_div_csi_trans", + CLK_SET_RATE_PARENT, 0x30, 24, 0, }, + { HI3670_CLK_DSI_TRANS_GT, "clk_dsi_trans_gt", "clk_div_dsi_trans", + CLK_SET_RATE_PARENT, 0x30, 25, 0, }, + { HI3670_CLK_GATE_PWM, "clk_gate_pwm", "clk_div_ptp", + CLK_SET_RATE_PARENT, 0x20, 0, 0, }, + { HI3670_ABB_AUDIO_EN0, "abb_audio_en0", "clk_gate_abb_192", + CLK_SET_RATE_PARENT, 0x30, 8, 0, }, + { HI3670_ABB_AUDIO_EN1, "abb_audio_en1", "clk_gate_abb_192", + CLK_SET_RATE_PARENT, 0x30, 9, 0, }, + { HI3670_ABB_AUDIO_GT_EN0, "abb_audio_gt_en0", "abb_audio_en0", + CLK_SET_RATE_PARENT, 0x30, 19, 0, }, + { HI3670_ABB_AUDIO_GT_EN1, "abb_audio_gt_en1", "abb_audio_en1", + CLK_SET_RATE_PARENT, 0x40, 20, 0, }, + { HI3670_CLK_GATE_DP_AUDIO_PLL_AO, "clk_gate_dp_audio_pll_ao", "clkdiv_dp_audio_pll_ao", + CLK_SET_RATE_PARENT, 0x00, 13, 0, }, + { HI3670_PERI_VOLT_HOLD, "peri_volt_hold", "clkin_sys", + CLK_SET_RATE_PARENT, 0, 1, 0, }, + { HI3670_PERI_VOLT_MIDDLE, "peri_volt_middle", "clkin_sys", + CLK_SET_RATE_PARENT, 0, 1, 0, }, + { HI3670_CLK_GATE_ISP_SNCLK0, "clk_gate_isp_snclk0", "clk_isp_snclk_mux0", + CLK_SET_RATE_PARENT, 0x50, 16, 0, }, + { HI3670_CLK_GATE_ISP_SNCLK1, "clk_gate_isp_snclk1", "clk_isp_snclk_mux1", + CLK_SET_RATE_PARENT, 0x50, 17, 0, }, + { HI3670_CLK_GATE_ISP_SNCLK2, "clk_gate_isp_snclk2", "clk_isp_snclk_mux2", + CLK_SET_RATE_PARENT, 0x50, 18, 0, }, + { HI3670_CLK_GATE_RXDPHY0_CFG, "clk_gate_rxdphy0_cfg", "clk_mux_rxdphy_cfg", + CLK_SET_RATE_PARENT, 0x030, 20, 0, }, + { HI3670_CLK_GATE_RXDPHY1_CFG, "clk_gate_rxdphy1_cfg", "clk_mux_rxdphy_cfg", + CLK_SET_RATE_PARENT, 0x030, 21, 0, }, + { HI3670_CLK_GATE_RXDPHY2_CFG, "clk_gate_rxdphy2_cfg", "clk_mux_rxdphy_cfg", + CLK_SET_RATE_PARENT, 0x030, 22, 0, }, + { HI3670_CLK_GATE_TXDPHY0_CFG, "clk_gate_txdphy0_cfg", "clkin_sys", + CLK_SET_RATE_PARENT, 0x030, 28, 0, }, + { HI3670_CLK_GATE_TXDPHY0_REF, "clk_gate_txdphy0_ref", "clkin_sys", + CLK_SET_RATE_PARENT, 0x030, 29, 0, }, + { HI3670_CLK_GATE_TXDPHY1_CFG, "clk_gate_txdphy1_cfg", "clkin_sys", + CLK_SET_RATE_PARENT, 0x030, 30, 0, }, + { HI3670_CLK_GATE_TXDPHY1_REF, "clk_gate_txdphy1_ref", "clkin_sys", + CLK_SET_RATE_PARENT, 0x030, 31, 0, }, + { HI3670_CLK_GATE_MEDIA_TCXO, "clk_gate_media_tcxo", "clkin_sys", + CLK_SET_RATE_PARENT, 0x40, 6, 0, }, +}; + +static const struct hisi_gate_clock hi3670_crgctrl_gate_clks[] = { + { HI3670_AUTODIV_SYSBUS, "autodiv_sysbus", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x404, 5, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_AUTODIV_EMMC0BUS, "autodiv_emmc0bus", "autodiv_sysbus", + CLK_SET_RATE_PARENT, 0x404, 1, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_PCLK_ANDGT_MMC1_PCIE, "pclk_andgt_mmc1_pcie", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xf8, 13, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_GATE_VCODECBUS_GT, "clk_gate_vcodecbus_gt", "clk_mux_vcodecbus", + CLK_SET_RATE_PARENT, 0x0F0, 8, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_SD, "clk_andgt_sd", "clk_mux_sd_pll", + CLK_SET_RATE_PARENT, 0xF4, 3, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_SD_SYS_GT, "clk_sd_sys_gt", "clkin_sys", + CLK_SET_RATE_PARENT, 0xF4, 5, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_SDIO, "clk_andgt_sdio", "clk_mux_sdio_pll", + CLK_SET_RATE_PARENT, 0xF4, 8, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_SDIO_SYS_GT, "clk_sdio_sys_gt", "clkin_sys", + CLK_SET_RATE_PARENT, 0xF4, 6, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_A53HPM_ANDGT, "clk_a53hpm_andgt", "clk_mux_a53hpm", + CLK_SET_RATE_PARENT, 0x0F4, 7, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_320M_PLL_GT, "clk_320m_pll_gt", "clk_mux_320m", + CLK_SET_RATE_PARENT, 0xF8, 10, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_UARTH, "clk_andgt_uarth", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xF4, 11, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_UARTL, "clk_andgt_uartl", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xF4, 10, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_UART0, "clk_andgt_uart0", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xF4, 9, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_SPI, "clk_andgt_spi", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xF4, 13, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_PCIEAXI, "clk_andgt_pcieaxi", "clk_mux_pcieaxi", + CLK_SET_RATE_PARENT, 0xfc, 15, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_AO_ASP_GT, "clk_div_ao_asp_gt", "clk_mux_ao_asp", + CLK_SET_RATE_PARENT, 0xF4, 4, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_GATE_CSI_TRANS, "clk_gate_csi_trans", "clk_ppll2", + CLK_SET_RATE_PARENT, 0xF4, 14, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_GATE_DSI_TRANS, "clk_gate_dsi_trans", "clk_ppll2", + CLK_SET_RATE_PARENT, 0xF4, 1, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_PTP, "clk_andgt_ptp", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xF8, 5, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_OUT0, "clk_andgt_out0", "clk_ppll0", + CLK_SET_RATE_PARENT, 0xF0, 10, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_OUT1, "clk_andgt_out1", "clk_ppll0", + CLK_SET_RATE_PARENT, 0xF0, 11, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLKGT_DP_AUDIO_PLL_AO, "clkgt_dp_audio_pll_ao", "clk_ppll6", + CLK_SET_RATE_PARENT, 0xF8, 15, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_VDEC, "clk_andgt_vdec", "clk_mux_vdec", + CLK_SET_RATE_PARENT, 0xF0, 13, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_VENC, "clk_andgt_venc", "clk_mux_venc", + CLK_SET_RATE_PARENT, 0xF0, 9, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ISP_SNCLK_ANGT, "clk_isp_snclk_angt", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x108, 2, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_RXDPHY, "clk_andgt_rxdphy", "clk_div_a53hpm", + CLK_SET_RATE_PARENT, 0x0F0, 12, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_ICS, "clk_andgt_ics", "clk_mux_ics", + CLK_SET_RATE_PARENT, 0xf0, 14, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_AUTODIV_DMABUS, "autodiv_dmabus", "autodiv_sysbus", + CLK_SET_RATE_PARENT, 0x404, 3, CLK_GATE_HIWORD_MASK, 0, }, +}; + +static const char *const +clk_mux_sysbus_p[] = { "clk_ppll1", "clk_ppll0", }; +static const char *const +clk_mux_vcodecbus_p[] = { "clk_invalid", "clk_ppll4", "clk_ppll0", + "clk_invalid", "clk_ppll2", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_ppll3", + "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", }; +static const char *const +clk_mux_sd_sys_p[] = { "clk_sd_sys", "clk_div_sd", }; +static const char *const +clk_mux_sd_pll_p[] = { "clk_ppll0", "clk_ppll3", "clk_ppll2", "clk_ppll2", }; +static const char *const +clk_mux_sdio_sys_p[] = { "clk_sdio_sys", "clk_div_sdio", }; +static const char *const +clk_mux_sdio_pll_p[] = { "clk_ppll0", "clk_ppll3", "clk_ppll2", "clk_ppll2", }; +static const char *const +clk_mux_a53hpm_p[] = { "clk_ppll0", "clk_ppll2", }; +static const char *const +clk_mux_320m_p[] = { "clk_ppll2", "clk_ppll0", }; +static const char *const +clk_mux_uarth_p[] = { "clkin_sys", "clk_div_uarth", }; +static const char *const +clk_mux_uartl_p[] = { "clkin_sys", "clk_div_uartl", }; +static const char *const +clk_mux_uart0_p[] = { "clkin_sys", "clk_div_uart0", }; +static const char *const +clk_mux_i2c_p[] = { "clkin_sys", "clk_div_i2c", }; +static const char *const +clk_mux_spi_p[] = { "clkin_sys", "clk_div_spi", }; +static const char *const +clk_mux_pcieaxi_p[] = { "clkin_sys", "clk_ppll0", }; +static const char *const +clk_mux_ao_asp_p[] = { "clk_ppll2", "clk_ppll3", }; +static const char *const +clk_mux_vdec_p[] = { "clk_invalid", "clk_ppll4", "clk_ppll0", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", }; +static const char *const +clk_mux_venc_p[] = { "clk_invalid", "clk_ppll4", "clk_ppll0", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", }; +static const char *const +clk_isp_snclk_mux0_p[] = { "clkin_sys", "clk_isp_snclk_div0", }; +static const char *const +clk_isp_snclk_mux1_p[] = { "clkin_sys", "clk_isp_snclk_div1", }; +static const char *const +clk_isp_snclk_mux2_p[] = { "clkin_sys", "clk_isp_snclk_div2", }; +static const char *const +clk_mux_rxdphy_cfg_p[] = { "clk_factor_rxdphy", "clkin_sys", }; +static const char *const +clk_mux_ics_p[] = { "clk_invalid", "clk_ppll4", "clk_ppll0", "clk_invalid", + "clk_ppll2", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_ppll3", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", }; + +static const struct hisi_mux_clock hi3670_crgctrl_mux_clks[] = { + { HI3670_CLK_MUX_SYSBUS, "clk_mux_sysbus", clk_mux_sysbus_p, + ARRAY_SIZE(clk_mux_sysbus_p), CLK_SET_RATE_PARENT, + 0xAC, 0, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_VCODECBUS, "clk_mux_vcodecbus", clk_mux_vcodecbus_p, + ARRAY_SIZE(clk_mux_vcodecbus_p), CLK_SET_RATE_PARENT, + 0x0C8, 0, 4, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_SD_SYS, "clk_mux_sd_sys", clk_mux_sd_sys_p, + ARRAY_SIZE(clk_mux_sd_sys_p), CLK_SET_RATE_PARENT, + 0x0B8, 6, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_SD_PLL, "clk_mux_sd_pll", clk_mux_sd_pll_p, + ARRAY_SIZE(clk_mux_sd_pll_p), CLK_SET_RATE_PARENT, + 0x0B8, 4, 2, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_SDIO_SYS, "clk_mux_sdio_sys", clk_mux_sdio_sys_p, + ARRAY_SIZE(clk_mux_sdio_sys_p), CLK_SET_RATE_PARENT, + 0x0C0, 6, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_SDIO_PLL, "clk_mux_sdio_pll", clk_mux_sdio_pll_p, + ARRAY_SIZE(clk_mux_sdio_pll_p), CLK_SET_RATE_PARENT, + 0x0C0, 4, 2, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_A53HPM, "clk_mux_a53hpm", clk_mux_a53hpm_p, + ARRAY_SIZE(clk_mux_a53hpm_p), CLK_SET_RATE_PARENT, + 0x0D4, 9, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_320M, "clk_mux_320m", clk_mux_320m_p, + ARRAY_SIZE(clk_mux_320m_p), CLK_SET_RATE_PARENT, + 0x100, 0, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_UARTH, "clk_mux_uarth", clk_mux_uarth_p, + ARRAY_SIZE(clk_mux_uarth_p), CLK_SET_RATE_PARENT, + 0xAC, 4, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_UARTL, "clk_mux_uartl", clk_mux_uartl_p, + ARRAY_SIZE(clk_mux_uartl_p), CLK_SET_RATE_PARENT, + 0xAC, 3, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_UART0, "clk_mux_uart0", clk_mux_uart0_p, + ARRAY_SIZE(clk_mux_uart0_p), CLK_SET_RATE_PARENT, + 0xAC, 2, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_I2C, "clk_mux_i2c", clk_mux_i2c_p, + ARRAY_SIZE(clk_mux_i2c_p), CLK_SET_RATE_PARENT, + 0xAC, 13, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_SPI, "clk_mux_spi", clk_mux_spi_p, + ARRAY_SIZE(clk_mux_spi_p), CLK_SET_RATE_PARENT, + 0xAC, 8, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_PCIEAXI, "clk_mux_pcieaxi", clk_mux_pcieaxi_p, + ARRAY_SIZE(clk_mux_pcieaxi_p), CLK_SET_RATE_PARENT, + 0xb4, 5, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_AO_ASP, "clk_mux_ao_asp", clk_mux_ao_asp_p, + ARRAY_SIZE(clk_mux_ao_asp_p), CLK_SET_RATE_PARENT, + 0x100, 6, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_VDEC, "clk_mux_vdec", clk_mux_vdec_p, + ARRAY_SIZE(clk_mux_vdec_p), CLK_SET_RATE_PARENT, + 0xC8, 8, 4, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_VENC, "clk_mux_venc", clk_mux_venc_p, + ARRAY_SIZE(clk_mux_venc_p), CLK_SET_RATE_PARENT, + 0xC8, 4, 4, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_ISP_SNCLK_MUX0, "clk_isp_snclk_mux0", clk_isp_snclk_mux0_p, + ARRAY_SIZE(clk_isp_snclk_mux0_p), CLK_SET_RATE_PARENT, + 0x108, 3, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_ISP_SNCLK_MUX1, "clk_isp_snclk_mux1", clk_isp_snclk_mux1_p, + ARRAY_SIZE(clk_isp_snclk_mux1_p), CLK_SET_RATE_PARENT, + 0x10C, 13, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_ISP_SNCLK_MUX2, "clk_isp_snclk_mux2", clk_isp_snclk_mux2_p, + ARRAY_SIZE(clk_isp_snclk_mux2_p), CLK_SET_RATE_PARENT, + 0x10C, 10, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_RXDPHY_CFG, "clk_mux_rxdphy_cfg", clk_mux_rxdphy_cfg_p, + ARRAY_SIZE(clk_mux_rxdphy_cfg_p), CLK_SET_RATE_PARENT, + 0x0C4, 8, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_ICS, "clk_mux_ics", clk_mux_ics_p, + ARRAY_SIZE(clk_mux_ics_p), CLK_SET_RATE_PARENT, + 0xc8, 12, 4, CLK_MUX_HIWORD_MASK, }, +}; + +static const struct hisi_divider_clock hi3670_crgctrl_divider_clks[] = { + { HI3670_CLK_DIV_CFGBUS, "clk_div_cfgbus", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0xEC, 0, 2, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_MMC0BUS, "clk_div_mmc0bus", "autodiv_emmc0bus", + CLK_SET_RATE_PARENT, 0x0EC, 2, 1, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_MMC1BUS, "clk_div_mmc1bus", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x0EC, 3, 1, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_PCLK_DIV_MMC1_PCIE, "pclk_div_mmc1_pcie", "pclk_andgt_mmc1_pcie", + CLK_SET_RATE_PARENT, 0xb4, 6, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_VCODECBUS, "clk_div_vcodecbus", "clk_gate_vcodecbus_gt", + CLK_SET_RATE_PARENT, 0x0BC, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_SD, "clk_div_sd", "clk_andgt_sd", + CLK_SET_RATE_PARENT, 0xB8, 0, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_SDIO, "clk_div_sdio", "clk_andgt_sdio", + CLK_SET_RATE_PARENT, 0xC0, 0, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_UARTH, "clk_div_uarth", "clk_andgt_uarth", + CLK_SET_RATE_PARENT, 0xB0, 12, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_UARTL, "clk_div_uartl", "clk_andgt_uartl", + CLK_SET_RATE_PARENT, 0xB0, 8, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_UART0, "clk_div_uart0", "clk_andgt_uart0", + CLK_SET_RATE_PARENT, 0xB0, 4, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_I2C, "clk_div_i2c", "clk_div_320m", + CLK_SET_RATE_PARENT, 0xE8, 4, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_SPI, "clk_div_spi", "clk_andgt_spi", + CLK_SET_RATE_PARENT, 0xC4, 12, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_PCIEAXI, "clk_div_pcieaxi", "clk_andgt_pcieaxi", + CLK_SET_RATE_PARENT, 0xb4, 0, 5, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_AO_ASP, "clk_div_ao_asp", "clk_div_ao_asp_gt", + CLK_SET_RATE_PARENT, 0x108, 6, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_CSI_TRANS, "clk_div_csi_trans", "clk_gate_csi_trans", + CLK_SET_RATE_PARENT, 0xD4, 0, 5, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_DSI_TRANS, "clk_div_dsi_trans", "clk_gate_dsi_trans", + CLK_SET_RATE_PARENT, 0xD4, 10, 5, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_PTP, "clk_div_ptp", "clk_andgt_ptp", + CLK_SET_RATE_PARENT, 0xD8, 0, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_CLKOUT0_PLL, "clk_div_clkout0_pll", "clk_andgt_out0", + CLK_SET_RATE_PARENT, 0xe0, 4, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_CLKOUT1_PLL, "clk_div_clkout1_pll", "clk_andgt_out1", + CLK_SET_RATE_PARENT, 0xe0, 10, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLKDIV_DP_AUDIO_PLL_AO, "clkdiv_dp_audio_pll_ao", "clkgt_dp_audio_pll_ao", + CLK_SET_RATE_PARENT, 0xBC, 11, 4, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_VDEC, "clk_div_vdec", "clk_andgt_vdec", + CLK_SET_RATE_PARENT, 0xC4, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_VENC, "clk_div_venc", "clk_andgt_venc", + CLK_SET_RATE_PARENT, 0xC0, 8, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_ISP_SNCLK_DIV0, "clk_isp_snclk_div0", "clk_isp_snclk_fac", + CLK_SET_RATE_PARENT, 0x108, 0, 2, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_ISP_SNCLK_DIV1, "clk_isp_snclk_div1", "clk_isp_snclk_fac", + CLK_SET_RATE_PARENT, 0x10C, 14, 2, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_ISP_SNCLK_DIV2, "clk_isp_snclk_div2", "clk_isp_snclk_fac", + CLK_SET_RATE_PARENT, 0x10C, 11, 2, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_ICS, "clk_div_ics", "clk_andgt_ics", + CLK_SET_RATE_PARENT, 0xE4, 9, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, +}; + +/* clk_pmuctrl */ +static const struct hisi_gate_clock hi3670_pmu_gate_clks[] = { + { HI3670_GATE_ABB_192, "clk_gate_abb_192", "clkin_sys", + CLK_SET_RATE_PARENT, (0x037 << 2), 0, 0, }, +}; + +/* clk_pctrl */ +static const struct hisi_gate_clock hi3670_pctrl_gate_clks[] = { + { HI3670_GATE_UFS_TCXO_EN, "clk_gate_ufs_tcxo_en", "clk_gate_abb_192", + CLK_SET_RATE_PARENT, 0x10, 0, CLK_GATE_HIWORD_MASK, }, + { HI3670_GATE_USB_TCXO_EN, "clk_gate_usb_tcxo_en", "clk_gate_abb_192", + CLK_SET_RATE_PARENT, 0x10, 1, CLK_GATE_HIWORD_MASK, }, +}; + +/* clk_sctrl */ +static const struct hisi_gate_clock hi3670_sctrl_gate_sep_clks[] = { + { HI3670_PPLL0_EN_ACPU, "ppll0_en_acpu", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x190, 26, 0, }, + { HI3670_PPLL0_GT_CPU, "ppll0_gt_cpu", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x190, 15, 0, }, + { HI3670_CLK_GATE_PPLL0_MEDIA, "clk_gate_ppll0_media", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x1b0, 6, 0, }, + { HI3670_PCLK_GPIO18, "pclk_gpio18", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x1B0, 9, 0, }, + { HI3670_PCLK_GPIO19, "pclk_gpio19", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x1B0, 8, 0, }, + { HI3670_CLK_GATE_SPI, "clk_gate_spi", "clk_div_ioperi", + CLK_SET_RATE_PARENT, 0x1B0, 10, 0, }, + { HI3670_PCLK_GATE_SPI, "pclk_gate_spi", "clk_div_ioperi", + CLK_SET_RATE_PARENT, 0x1B0, 10, 0, }, + { HI3670_CLK_GATE_UFS_SUBSYS, "clk_gate_ufs_subsys", "clk_div_ufs_subsys", + CLK_SET_RATE_PARENT, 0x1B0, 14, 0, }, + { HI3670_CLK_GATE_UFSIO_REF, "clk_gate_ufsio_ref", "clkin_sys", + CLK_SET_RATE_PARENT, 0x1b0, 12, 0, }, + { HI3670_PCLK_AO_GPIO0, "pclk_ao_gpio0", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 11, 0, }, + { HI3670_PCLK_AO_GPIO1, "pclk_ao_gpio1", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 12, 0, }, + { HI3670_PCLK_AO_GPIO2, "pclk_ao_gpio2", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 13, 0, }, + { HI3670_PCLK_AO_GPIO3, "pclk_ao_gpio3", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 14, 0, }, + { HI3670_PCLK_AO_GPIO4, "pclk_ao_gpio4", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 21, 0, }, + { HI3670_PCLK_AO_GPIO5, "pclk_ao_gpio5", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 22, 0, }, + { HI3670_PCLK_AO_GPIO6, "pclk_ao_gpio6", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 25, 0, }, + { HI3670_CLK_GATE_OUT0, "clk_gate_out0", "clk_mux_clkout0", + CLK_SET_RATE_PARENT, 0x160, 16, 0, }, + { HI3670_CLK_GATE_OUT1, "clk_gate_out1", "clk_mux_clkout1", + CLK_SET_RATE_PARENT, 0x160, 17, 0, }, + { HI3670_PCLK_GATE_SYSCNT, "pclk_gate_syscnt", "clk_div_aobus", + CLK_SET_RATE_PARENT, 0x160, 19, 0, }, + { HI3670_CLK_GATE_SYSCNT, "clk_gate_syscnt", "clkin_sys", + CLK_SET_RATE_PARENT, 0x160, 20, 0, }, + { HI3670_CLK_GATE_ASP_SUBSYS_PERI, "clk_gate_asp_subsys_peri", + "clk_mux_asp_subsys_peri", + CLK_SET_RATE_PARENT, 0x170, 6, 0, }, + { HI3670_CLK_GATE_ASP_SUBSYS, "clk_gate_asp_subsys", "clk_mux_asp_pll", + CLK_SET_RATE_PARENT, 0x170, 4, 0, }, + { HI3670_CLK_GATE_ASP_TCXO, "clk_gate_asp_tcxo", "clkin_sys", + CLK_SET_RATE_PARENT, 0x160, 27, 0, }, + { HI3670_CLK_GATE_DP_AUDIO_PLL, "clk_gate_dp_audio_pll", + "clk_gate_dp_audio_pll_ao", + CLK_SET_RATE_PARENT, 0x1B0, 7, 0, }, +}; + +static const struct hisi_gate_clock hi3670_sctrl_gate_clks[] = { + { HI3670_CLK_ANDGT_IOPERI, "clk_andgt_ioperi", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x270, 6, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLKANDGT_ASP_SUBSYS_PERI, "clkandgt_asp_subsys_peri", + "clk_ppll0", + CLK_SET_RATE_PARENT, 0x268, 3, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANGT_ASP_SUBSYS, "clk_angt_asp_subsys", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x258, 0, CLK_GATE_HIWORD_MASK, 0, }, +}; + +static const char *const +clk_mux_ufs_subsys_p[] = { "clkin_sys", "clk_ppll0", }; +static const char *const +clk_mux_clkout0_p[] = { "clkin_ref", "clk_div_clkout0_tcxo", + "clk_div_clkout0_pll", "clk_div_clkout0_pll", }; +static const char *const +clk_mux_clkout1_p[] = { "clkin_ref", "clk_div_clkout1_tcxo", + "clk_div_clkout1_pll", "clk_div_clkout1_pll", }; +static const char *const +clk_mux_asp_subsys_peri_p[] = { "clk_ppll0", "clk_fll_src", }; +static const char *const +clk_mux_asp_pll_p[] = { "clk_ppll0", "clk_fll_src", "clk_gate_ao_asp", + "clk_pciepll_rev", }; + +static const struct hisi_mux_clock hi3670_sctrl_mux_clks[] = { + { HI3670_CLK_MUX_UFS_SUBSYS, "clk_mux_ufs_subsys", clk_mux_ufs_subsys_p, + ARRAY_SIZE(clk_mux_ufs_subsys_p), CLK_SET_RATE_PARENT, + 0x274, 8, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_CLKOUT0, "clk_mux_clkout0", clk_mux_clkout0_p, + ARRAY_SIZE(clk_mux_clkout0_p), CLK_SET_RATE_PARENT, + 0x254, 12, 2, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_CLKOUT1, "clk_mux_clkout1", clk_mux_clkout1_p, + ARRAY_SIZE(clk_mux_clkout1_p), CLK_SET_RATE_PARENT, + 0x254, 14, 2, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_ASP_SUBSYS_PERI, "clk_mux_asp_subsys_peri", + clk_mux_asp_subsys_peri_p, ARRAY_SIZE(clk_mux_asp_subsys_peri_p), + CLK_SET_RATE_PARENT, 0x268, 8, 1, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_ASP_PLL, "clk_mux_asp_pll", clk_mux_asp_pll_p, + ARRAY_SIZE(clk_mux_asp_pll_p), CLK_SET_RATE_PARENT, + 0x268, 9, 2, CLK_MUX_HIWORD_MASK, }, +}; + +static const struct hisi_divider_clock hi3670_sctrl_divider_clks[] = { + { HI3670_CLK_DIV_AOBUS, "clk_div_aobus", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x254, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_UFS_SUBSYS, "clk_div_ufs_subsys", "clk_mux_ufs_subsys", + CLK_SET_RATE_PARENT, 0x274, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_IOPERI, "clk_div_ioperi", "clk_andgt_ioperi", + CLK_SET_RATE_PARENT, 0x270, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_CLKOUT0_TCXO, "clk_div_clkout0_tcxo", "clkin_sys", + CLK_SET_RATE_PARENT, 0x254, 6, 3, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_CLKOUT1_TCXO, "clk_div_clkout1_tcxo", "clkin_sys", + CLK_SET_RATE_PARENT, 0x254, 9, 3, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_ASP_SUBSYS_PERI_DIV, "clk_asp_subsys_peri_div", "clkandgt_asp_subsys_peri", + CLK_SET_RATE_PARENT, 0x268, 0, 3, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_ASP_SUBSYS, "clk_div_asp_subsys", "clk_angt_asp_subsys", + CLK_SET_RATE_PARENT, 0x250, 0, 3, CLK_DIVIDER_HIWORD_MASK, 0, }, +}; + +/* clk_iomcu */ +static const struct hisi_fixed_factor_clock hi3670_iomcu_fixed_factor_clks[] = { + { HI3670_CLK_GATE_I2C0, "clk_gate_i2c0", "clk_i2c0_gate_iomcu", 1, 4, 0, }, + { HI3670_CLK_GATE_I2C1, "clk_gate_i2c1", "clk_i2c1_gate_iomcu", 1, 4, 0, }, + { HI3670_CLK_GATE_I2C2, "clk_gate_i2c2", "clk_i2c2_gate_iomcu", 1, 4, 0, }, + { HI3670_CLK_GATE_SPI0, "clk_gate_spi0", "clk_spi0_gate_iomcu", 1, 1, 0, }, + { HI3670_CLK_GATE_SPI2, "clk_gate_spi2", "clk_spi2_gate_iomcu", 1, 1, 0, }, + { HI3670_CLK_GATE_UART3, "clk_gate_uart3", "clk_uart3_gate_iomcu", 1, 16, 0, }, +}; + +static const struct hisi_gate_clock hi3670_iomcu_gate_sep_clks[] = { + { HI3670_CLK_I2C0_GATE_IOMCU, "clk_i2c0_gate_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 3, 0, }, + { HI3670_CLK_I2C1_GATE_IOMCU, "clk_i2c1_gate_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 4, 0, }, + { HI3670_CLK_I2C2_GATE_IOMCU, "clk_i2c2_gate_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 5, 0, }, + { HI3670_CLK_SPI0_GATE_IOMCU, "clk_spi0_gate_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 10, 0, }, + { HI3670_CLK_SPI2_GATE_IOMCU, "clk_spi2_gate_iomcu", "clk_fll_src", + CLK_SET_RATE_PARENT, 0x10, 30, 0, }, + { HI3670_CLK_UART3_GATE_IOMCU, "clk_uart3_gate_iomcu", "clk_gate_iomcu_peri0", + CLK_SET_RATE_PARENT, 0x10, 11, 0, }, + { HI3670_CLK_GATE_PERI0_IOMCU, "clk_gate_iomcu_peri0", "clk_ppll0", + CLK_SET_RATE_PARENT, 0x90, 0, 0, }, +}; + +/* clk_media1 */ +static const struct hisi_gate_clock hi3670_media1_gate_sep_clks[] = { + { HI3670_ACLK_GATE_NOC_DSS, "aclk_gate_noc_dss", "aclk_gate_disp_noc_subsys", + CLK_SET_RATE_PARENT, 0x10, 21, 0, }, + { HI3670_PCLK_GATE_NOC_DSS_CFG, "pclk_gate_noc_dss_cfg", "pclk_gate_disp_noc_subsys", + CLK_SET_RATE_PARENT, 0x10, 22, 0, }, + { HI3670_PCLK_GATE_MMBUF_CFG, "pclk_gate_mmbuf_cfg", "pclk_gate_disp_noc_subsys", + CLK_SET_RATE_PARENT, 0x20, 5, 0, }, + { HI3670_PCLK_GATE_DISP_NOC_SUBSYS, "pclk_gate_disp_noc_subsys", "clk_div_sysbus", + CLK_SET_RATE_PARENT, 0x10, 18, 0, }, + { HI3670_ACLK_GATE_DISP_NOC_SUBSYS, "aclk_gate_disp_noc_subsys", "clk_gate_vivobusfreq", + CLK_SET_RATE_PARENT, 0x10, 17, 0, }, + { HI3670_PCLK_GATE_DSS, "pclk_gate_dss", "pclk_gate_disp_noc_subsys", + CLK_SET_RATE_PARENT, 0x00, 14, 0, }, + { HI3670_ACLK_GATE_DSS, "aclk_gate_dss", "aclk_gate_disp_noc_subsys", + CLK_SET_RATE_PARENT, 0x00, 19, 0, }, + { HI3670_CLK_GATE_VIVOBUSFREQ, "clk_gate_vivobusfreq", "clk_div_vivobus", + CLK_SET_RATE_PARENT, 0x00, 18, 0, }, + { HI3670_CLK_GATE_EDC0, "clk_gate_edc0", "clk_div_edc0", + CLK_SET_RATE_PARENT, 0x00, 15, 0, }, + { HI3670_CLK_GATE_LDI0, "clk_gate_ldi0", "clk_div_ldi0", + CLK_SET_RATE_PARENT, 0x00, 16, 0, }, + { HI3670_CLK_GATE_LDI1FREQ, "clk_gate_ldi1freq", "clk_div_ldi1", + CLK_SET_RATE_PARENT, 0x00, 17, 0, }, + { HI3670_CLK_GATE_BRG, "clk_gate_brg", "clk_media_common_div", + CLK_SET_RATE_PARENT, 0x00, 29, 0, }, + { HI3670_ACLK_GATE_ASC, "aclk_gate_asc", "clk_gate_mmbuf", + CLK_SET_RATE_PARENT, 0x20, 3, 0, }, + { HI3670_CLK_GATE_DSS_AXI_MM, "clk_gate_dss_axi_mm", "clk_gate_mmbuf", + CLK_SET_RATE_PARENT, 0x20, 4, 0, }, + { HI3670_CLK_GATE_MMBUF, "clk_gate_mmbuf", "aclk_div_mmbuf", + CLK_SET_RATE_PARENT, 0x20, 0, 0, }, + { HI3670_PCLK_GATE_MMBUF, "pclk_gate_mmbuf", "pclk_div_mmbuf", + CLK_SET_RATE_PARENT, 0x20, 1, 0, }, + { HI3670_CLK_GATE_ATDIV_VIVO, "clk_gate_atdiv_vivo", "clk_div_vivobus", + CLK_SET_RATE_PARENT, 0x010, 1, 0, }, +}; + +static const struct hisi_gate_clock hi3670_media1_gate_clks[] = { + { HI3670_CLK_GATE_VIVOBUS_ANDGT, "clk_gate_vivobus_andgt", "clk_mux_vivobus", + CLK_SET_RATE_PARENT, 0x84, 3, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_EDC0, "clk_andgt_edc0", "clk_mux_edc0", + CLK_SET_RATE_PARENT, 0x84, 7, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_LDI0, "clk_andgt_ldi0", "clk_mux_ldi0", + CLK_SET_RATE_PARENT, 0x84, 9, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_ANDGT_LDI1, "clk_andgt_ldi1", "clk_mux_ldi1", + CLK_SET_RATE_PARENT, 0x84, 8, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_CLK_MMBUF_PLL_ANDGT, "clk_mmbuf_pll_andgt", "clk_sw_mmbuf", + CLK_SET_RATE_PARENT, 0x84, 14, CLK_GATE_HIWORD_MASK, 0, }, + { HI3670_PCLK_MMBUF_ANDGT, "pclk_mmbuf_andgt", "aclk_div_mmbuf", + CLK_SET_RATE_PARENT, 0x84, 15, CLK_GATE_HIWORD_MASK, 0, }, +}; + +static const char *const +clk_mux_vivobus_p[] = { "clk_invalid", "clk_invalid", "clk_gate_ppll0_media", + "clk_invalid", "clk_gate_ppll2_media", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_gate_ppll3_media", + "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", }; +static const char *const +clk_mux_edc0_p[] = { "clk_invalid", "clk_invalid", "clk_gate_ppll0_media", + "clk_invalid", "clk_gate_ppll2_media", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_gate_ppll3_media", + "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", }; +static const char *const +clk_mux_ldi0_p[] = { "clk_invalid", "clk_gate_ppll7_media", + "clk_gate_ppll0_media", "clk_invalid", + "clk_gate_ppll2_media", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_gate_ppll3_media", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", }; +static const char *const +clk_mux_ldi1_p[] = { "clk_invalid", "clk_gate_ppll7_media", + "clk_gate_ppll0_media", "clk_invalid", + "clk_gate_ppll2_media", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_gate_ppll3_media", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", }; +static const char *const +clk_sw_mmbuf_p[] = { "clk_invalid", "clk_invalid", "clk_gate_ppll0_media", + "clk_invalid", "clk_gate_ppll2_media", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_gate_ppll3_media", + "clk_invalid", "clk_invalid", "clk_invalid", "clk_invalid", + "clk_invalid", "clk_invalid", "clk_invalid", }; + +static const struct hisi_mux_clock hi3670_media1_mux_clks[] = { + { HI3670_CLK_MUX_VIVOBUS, "clk_mux_vivobus", clk_mux_vivobus_p, + ARRAY_SIZE(clk_mux_vivobus_p), CLK_SET_RATE_PARENT, + 0x74, 6, 4, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_EDC0, "clk_mux_edc0", clk_mux_edc0_p, + ARRAY_SIZE(clk_mux_edc0_p), CLK_SET_RATE_PARENT, + 0x68, 6, 4, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_LDI0, "clk_mux_ldi0", clk_mux_ldi0_p, + ARRAY_SIZE(clk_mux_ldi0_p), CLK_SET_RATE_PARENT, + 0x60, 6, 4, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_MUX_LDI1, "clk_mux_ldi1", clk_mux_ldi1_p, + ARRAY_SIZE(clk_mux_ldi1_p), CLK_SET_RATE_PARENT, + 0x64, 6, 4, CLK_MUX_HIWORD_MASK, }, + { HI3670_CLK_SW_MMBUF, "clk_sw_mmbuf", clk_sw_mmbuf_p, + ARRAY_SIZE(clk_sw_mmbuf_p), CLK_SET_RATE_PARENT, + 0x88, 0, 4, CLK_MUX_HIWORD_MASK, }, +}; + +static const struct hisi_divider_clock hi3670_media1_divider_clks[] = { + { HI3670_CLK_DIV_VIVOBUS, "clk_div_vivobus", "clk_gate_vivobus_andgt", + CLK_SET_RATE_PARENT, 0x74, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_EDC0, "clk_div_edc0", "clk_andgt_edc0", + CLK_SET_RATE_PARENT, 0x68, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_LDI0, "clk_div_ldi0", "clk_andgt_ldi0", + CLK_SET_RATE_PARENT, 0x60, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_CLK_DIV_LDI1, "clk_div_ldi1", "clk_andgt_ldi1", + CLK_SET_RATE_PARENT, 0x64, 0, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_ACLK_DIV_MMBUF, "aclk_div_mmbuf", "clk_mmbuf_pll_andgt", + CLK_SET_RATE_PARENT, 0x7C, 10, 6, CLK_DIVIDER_HIWORD_MASK, 0, }, + { HI3670_PCLK_DIV_MMBUF, "pclk_div_mmbuf", "pclk_mmbuf_andgt", + CLK_SET_RATE_PARENT, 0x78, 0, 2, CLK_DIVIDER_HIWORD_MASK, 0, }, +}; + +/* clk_media2 */ +static const struct hisi_gate_clock hi3670_media2_gate_sep_clks[] = { + { HI3670_CLK_GATE_VDECFREQ, "clk_gate_vdecfreq", "clk_div_vdec", + CLK_SET_RATE_PARENT, 0x00, 8, 0, }, + { HI3670_CLK_GATE_VENCFREQ, "clk_gate_vencfreq", "clk_div_venc", + CLK_SET_RATE_PARENT, 0x00, 5, 0, }, + { HI3670_CLK_GATE_ICSFREQ, "clk_gate_icsfreq", "clk_div_ics", + CLK_SET_RATE_PARENT, 0x00, 2, 0, }, +}; + +static void hi3670_clk_crgctrl_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + + int nr = ARRAY_SIZE(hi3670_fixed_rate_clks) + + ARRAY_SIZE(hi3670_crgctrl_gate_sep_clks) + + ARRAY_SIZE(hi3670_crgctrl_gate_clks) + + ARRAY_SIZE(hi3670_crgctrl_mux_clks) + + ARRAY_SIZE(hi3670_crg_fixed_factor_clks) + + ARRAY_SIZE(hi3670_crgctrl_divider_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_fixed_rate(hi3670_fixed_rate_clks, + ARRAY_SIZE(hi3670_fixed_rate_clks), + clk_data); + hisi_clk_register_gate_sep(hi3670_crgctrl_gate_sep_clks, + ARRAY_SIZE(hi3670_crgctrl_gate_sep_clks), + clk_data); + hisi_clk_register_gate(hi3670_crgctrl_gate_clks, + ARRAY_SIZE(hi3670_crgctrl_gate_clks), + clk_data); + hisi_clk_register_mux(hi3670_crgctrl_mux_clks, + ARRAY_SIZE(hi3670_crgctrl_mux_clks), + clk_data); + hisi_clk_register_fixed_factor(hi3670_crg_fixed_factor_clks, + ARRAY_SIZE(hi3670_crg_fixed_factor_clks), + clk_data); + hisi_clk_register_divider(hi3670_crgctrl_divider_clks, + ARRAY_SIZE(hi3670_crgctrl_divider_clks), + clk_data); +} + +static void hi3670_clk_pctrl_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3670_pctrl_gate_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + hisi_clk_register_gate(hi3670_pctrl_gate_clks, + ARRAY_SIZE(hi3670_pctrl_gate_clks), clk_data); +} + +static void hi3670_clk_pmuctrl_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3670_pmu_gate_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_gate(hi3670_pmu_gate_clks, + ARRAY_SIZE(hi3670_pmu_gate_clks), clk_data); +} + +static void hi3670_clk_sctrl_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3670_sctrl_gate_sep_clks) + + ARRAY_SIZE(hi3670_sctrl_gate_clks) + + ARRAY_SIZE(hi3670_sctrl_mux_clks) + + ARRAY_SIZE(hi3670_sctrl_divider_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_gate_sep(hi3670_sctrl_gate_sep_clks, + ARRAY_SIZE(hi3670_sctrl_gate_sep_clks), + clk_data); + hisi_clk_register_gate(hi3670_sctrl_gate_clks, + ARRAY_SIZE(hi3670_sctrl_gate_clks), + clk_data); + hisi_clk_register_mux(hi3670_sctrl_mux_clks, + ARRAY_SIZE(hi3670_sctrl_mux_clks), + clk_data); + hisi_clk_register_divider(hi3670_sctrl_divider_clks, + ARRAY_SIZE(hi3670_sctrl_divider_clks), + clk_data); +} + +static void hi3670_clk_iomcu_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + int nr = ARRAY_SIZE(hi3670_iomcu_gate_sep_clks) + + ARRAY_SIZE(hi3670_iomcu_fixed_factor_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_gate(hi3670_iomcu_gate_sep_clks, + ARRAY_SIZE(hi3670_iomcu_gate_sep_clks), clk_data); + + hisi_clk_register_fixed_factor(hi3670_iomcu_fixed_factor_clks, + ARRAY_SIZE(hi3670_iomcu_fixed_factor_clks), + clk_data); +} + +static void hi3670_clk_media1_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + + int nr = ARRAY_SIZE(hi3670_media1_gate_sep_clks) + + ARRAY_SIZE(hi3670_media1_gate_clks) + + ARRAY_SIZE(hi3670_media1_mux_clks) + + ARRAY_SIZE(hi3670_media1_divider_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_gate_sep(hi3670_media1_gate_sep_clks, + ARRAY_SIZE(hi3670_media1_gate_sep_clks), + clk_data); + hisi_clk_register_gate(hi3670_media1_gate_clks, + ARRAY_SIZE(hi3670_media1_gate_clks), + clk_data); + hisi_clk_register_mux(hi3670_media1_mux_clks, + ARRAY_SIZE(hi3670_media1_mux_clks), + clk_data); + hisi_clk_register_divider(hi3670_media1_divider_clks, + ARRAY_SIZE(hi3670_media1_divider_clks), + clk_data); +} + +static void hi3670_clk_media2_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + + int nr = ARRAY_SIZE(hi3670_media2_gate_sep_clks); + + clk_data = hisi_clk_init(np, nr); + if (!clk_data) + return; + + hisi_clk_register_gate_sep(hi3670_media2_gate_sep_clks, + ARRAY_SIZE(hi3670_media2_gate_sep_clks), + clk_data); +} + +static const struct of_device_id hi3670_clk_match_table[] = { + { .compatible = "hisilicon,hi3670-crgctrl", + .data = hi3670_clk_crgctrl_init }, + { .compatible = "hisilicon,hi3670-pctrl", + .data = hi3670_clk_pctrl_init }, + { .compatible = "hisilicon,hi3670-pmuctrl", + .data = hi3670_clk_pmuctrl_init }, + { .compatible = "hisilicon,hi3670-sctrl", + .data = hi3670_clk_sctrl_init }, + { .compatible = "hisilicon,hi3670-iomcu", + .data = hi3670_clk_iomcu_init }, + { .compatible = "hisilicon,hi3670-media1-crg", + .data = hi3670_clk_media1_init }, + { .compatible = "hisilicon,hi3670-media2-crg", + .data = hi3670_clk_media2_init }, + { } +}; + +static int hi3670_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + void (*init_func)(struct device_node *np); + + init_func = of_device_get_match_data(dev); + if (!init_func) + return -ENODEV; + + init_func(np); + + return 0; +} + +static struct platform_driver hi3670_clk_driver = { + .probe = hi3670_clk_probe, + .driver = { + .name = "hi3670-clk", + .of_match_table = hi3670_clk_match_table, + }, +}; + +static int __init hi3670_clk_init(void) +{ + return platform_driver_register(&hi3670_clk_driver); +} +core_initcall(hi3670_clk_init); diff --git a/drivers/clk/hisilicon/reset.c b/drivers/clk/hisilicon/reset.c @@ -109,9 +109,8 @@ struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev) return NULL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rstc->membase = devm_ioremap(&pdev->dev, - res->start, resource_size(res)); - if (!rstc->membase) + rstc->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rstc->membase)) return NULL; spin_lock_init(&rstc->lock); diff --git a/drivers/clk/imx/clk-cpu.c b/drivers/clk/imx/clk-cpu.c @@ -94,7 +94,7 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name, init.name = name; init.ops = &clk_cpu_ops; - init.flags = 0; + init.flags = CLK_IS_CRITICAL; init.parent_names = &parent_name; init.num_parents = 1; diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c @@ -789,6 +789,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18); clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL); clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22); + clk[IMX6QDL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); clk[IMX6QDL_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28); clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30); clk[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0); diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c @@ -386,6 +386,8 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) clks[IMX6SL_CLK_LCDIF_AXI] = imx_clk_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6); clks[IMX6SL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8); clks[IMX6SL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10); + clks[IMX6SL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6SL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26); clks[IMX6SL_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28); clks[IMX6SL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); clks[IMX6SL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c @@ -293,6 +293,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6SLL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26); clks[IMX6SLL_CLK_OCRAM] = imx_clk_gate_flags("ocram","ahb", base + 0x74, 28, CLK_IS_CRITICAL); /* CCGR4 */ diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c @@ -431,6 +431,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18); clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6SX_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26); clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL); /* CCGR4 */ diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c @@ -408,6 +408,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26); clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL); /* CCGR4 */ diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c @@ -379,14 +379,6 @@ static const char *pll_enet_bypass_sel[] = { "pll_enet_main", "pll_enet_main_src static const char *pll_audio_bypass_sel[] = { "pll_audio_main", "pll_audio_main_src", }; static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_src", }; -static int const clks_init_on[] __initconst = { - IMX7D_ARM_A7_ROOT_CLK, IMX7D_MAIN_AXI_ROOT_CLK, - IMX7D_PLL_SYS_MAIN_480M_CLK, IMX7D_NAND_USDHC_BUS_ROOT_CLK, - IMX7D_DRAM_PHYM_ROOT_CLK, IMX7D_DRAM_ROOT_CLK, - IMX7D_DRAM_PHYM_ALT_ROOT_CLK, IMX7D_DRAM_ALT_ROOT_CLK, - IMX7D_AHB_CHANNEL_ROOT_CLK, IMX7D_IPG_ROOT_CLK, -}; - static struct clk_onecell_data clk_data; static struct clk ** const uart_clks[] __initconst = { @@ -404,7 +396,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0); clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc"); @@ -467,7 +458,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4); clks[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2); - clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4); + clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL); clks[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5); clks[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6); clks[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12); @@ -720,7 +711,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6); clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6); clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6); - clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider2("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2); + clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT); clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3); clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3); clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3); @@ -784,17 +775,17 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_CLKO1_ROOT_DIV] = imx_clk_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6); clks[IMX7D_CLKO2_ROOT_DIV] = imx_clk_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6); - clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate4("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0); + clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE); clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0); - clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate4("main_axi_root_clk", "axi_post_div", base + 0x4040, 0); + clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE); clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0); clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0); clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0); clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0); - clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate4("dram_root_clk", "dram_post_div", base + 0x4130, 0); - clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate4("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0); - clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0); - clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0); + clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE); + clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE); + clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE); + clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE); clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0); clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0); clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0); @@ -883,9 +874,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clk_data.clk_num = ARRAY_SIZE(clks); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); - for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) - clk_prepare_enable(clks[clks_init_on[i]]); - clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]); clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]); clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]); diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h @@ -137,6 +137,13 @@ static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent, shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock); } +static inline struct clk *imx_clk_gate_dis_flags(const char *name, const char *parent, + void __iomem *reg, u8 shift, unsigned long flags) +{ + return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg, + shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock); +} + static inline struct clk *imx_clk_gate2(const char *name, const char *parent, void __iomem *reg, u8 shift) { diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig @@ -0,0 +1,47 @@ +menu "Ingenic JZ47xx CGU drivers" + depends on MIPS + +config INGENIC_CGU_COMMON + bool + +config INGENIC_CGU_JZ4740 + bool "Ingenic JZ4740 CGU driver" + default MACH_JZ4740 + select INGENIC_CGU_COMMON + help + Support the clocks provided by the CGU hardware on Ingenic JZ4740 + and compatible SoCs. + + If building for a JZ4740 SoC, you want to say Y here. + +config INGENIC_CGU_JZ4725B + bool "Ingenic JZ4725B CGU driver" + default MACH_JZ4725B + select INGENIC_CGU_COMMON + help + Support the clocks provided by the CGU hardware on Ingenic JZ4725B + and compatible SoCs. + + If building for a JZ4725B SoC, you want to say Y here. + +config INGENIC_CGU_JZ4770 + bool "Ingenic JZ4770 CGU driver" + default MACH_JZ4770 + select INGENIC_CGU_COMMON + help + Support the clocks provided by the CGU hardware on Ingenic JZ4770 + and compatible SoCs. + + If building for a JZ4770 SoC, you want to say Y here. + +config INGENIC_CGU_JZ4780 + bool "Ingenic JZ4780 CGU driver" + default MACH_JZ4780 + select INGENIC_CGU_COMMON + help + Support the clocks provided by the CGU hardware on Ingenic JZ4780 + and compatible SoCs. + + If building for a JZ4780 SoC, you want to say Y here. + +endmenu diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile @@ -1,4 +1,5 @@ -obj-y += cgu.o -obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o -obj-$(CONFIG_MACH_JZ4770) += jz4770-cgu.o -obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o +obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o +obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o +obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o +obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o +obj-$(CONFIG_INGENIC_CGU_JZ4780) += jz4780-cgu.o diff --git a/drivers/clk/ingenic/jz4725b-cgu.c b/drivers/clk/ingenic/jz4725b-cgu.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Ingenic JZ4725B SoC CGU driver + * + * Copyright (C) 2018 Paul Cercueil + * Author: Paul Cercueil <paul@crapouillou.net> + */ + +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <dt-bindings/clock/jz4725b-cgu.h> +#include "cgu.h" + +/* CGU register offsets */ +#define CGU_REG_CPCCR 0x00 +#define CGU_REG_LCR 0x04 +#define CGU_REG_CPPCR 0x10 +#define CGU_REG_CLKGR 0x20 +#define CGU_REG_OPCR 0x24 +#define CGU_REG_I2SCDR 0x60 +#define CGU_REG_LPCDR 0x64 +#define CGU_REG_MSCCDR 0x68 +#define CGU_REG_SSICDR 0x74 +#define CGU_REG_CIMCDR 0x78 + +/* bits within the LCR register */ +#define LCR_SLEEP BIT(0) + +static struct ingenic_cgu *cgu; + +static const s8 pll_od_encoding[4] = { + 0x0, 0x1, -1, 0x3, +}; + +static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = { + + /* External clocks */ + + [JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT }, + [JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT }, + + [JZ4725B_CLK_PLL] = { + "pll", CGU_CLK_PLL, + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, + .pll = { + .reg = CGU_REG_CPPCR, + .m_shift = 23, + .m_bits = 9, + .m_offset = 2, + .n_shift = 18, + .n_bits = 5, + .n_offset = 2, + .od_shift = 16, + .od_bits = 2, + .od_max = 4, + .od_encoding = pll_od_encoding, + .stable_bit = 10, + .bypass_bit = 9, + .enable_bit = 8, + }, + }, + + /* Muxes & dividers */ + + [JZ4725B_CLK_PLL_HALF] = { + "pll half", CGU_CLK_DIV, + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, + .div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 }, + }, + + [JZ4725B_CLK_CCLK] = { + "cclk", CGU_CLK_DIV, + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, + .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, + }, + + [JZ4725B_CLK_HCLK] = { + "hclk", CGU_CLK_DIV, + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, + .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, + }, + + [JZ4725B_CLK_PCLK] = { + "pclk", CGU_CLK_DIV, + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, + .div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 }, + }, + + [JZ4725B_CLK_MCLK] = { + "mclk", CGU_CLK_DIV, + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, + .div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 }, + }, + + [JZ4725B_CLK_IPU] = { + "ipu", CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4725B_CLK_PLL, -1, -1, -1 }, + .div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 }, + .gate = { CGU_REG_CLKGR, 13 }, + }, + + [JZ4725B_CLK_LCD] = { + "lcd", CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 }, + .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 9 }, + }, + + [JZ4725B_CLK_I2S] = { + "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 }, + .mux = { CGU_REG_CPCCR, 31, 1 }, + .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 6 }, + }, + + [JZ4725B_CLK_SPI] = { + "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 }, + .mux = { CGU_REG_SSICDR, 31, 1 }, + .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 4 }, + }, + + [JZ4725B_CLK_MMC_MUX] = { + "mmc_mux", CGU_CLK_DIV, + .parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 }, + .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 }, + }, + + [JZ4725B_CLK_UDC] = { + "udc", CGU_CLK_MUX | CGU_CLK_DIV, + .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 }, + .mux = { CGU_REG_CPCCR, 29, 1 }, + .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, + }, + + /* Gate-only clocks */ + + [JZ4725B_CLK_UART] = { + "uart", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 0 }, + }, + + [JZ4725B_CLK_DMA] = { + "dma", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_PCLK, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 12 }, + }, + + [JZ4725B_CLK_ADC] = { + "adc", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 7 }, + }, + + [JZ4725B_CLK_I2C] = { + "i2c", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 3 }, + }, + + [JZ4725B_CLK_AIC] = { + "aic", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_EXT, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 5 }, + }, + + [JZ4725B_CLK_MMC0] = { + "mmc0", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 6 }, + }, + + [JZ4725B_CLK_MMC1] = { + "mmc1", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 16 }, + }, + + [JZ4725B_CLK_BCH] = { + "bch", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 11 }, + }, + + [JZ4725B_CLK_TCU] = { + "tcu", CGU_CLK_GATE, + .parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 1 }, + }, + + [JZ4725B_CLK_EXT512] = { + "ext/512", CGU_CLK_FIXDIV, + .parents = { JZ4725B_CLK_EXT }, + + /* Doc calls it EXT512, but it seems to be /256... */ + .fixdiv = { 256 }, + }, + + [JZ4725B_CLK_RTC] = { + "rtc", CGU_CLK_MUX, + .parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 }, + .mux = { CGU_REG_OPCR, 2, 1}, + }, +}; + +static void __init jz4725b_cgu_init(struct device_node *np) +{ + int retval; + + cgu = ingenic_cgu_new(jz4725b_cgu_clocks, + ARRAY_SIZE(jz4725b_cgu_clocks), np); + if (!cgu) { + pr_err("%s: failed to initialise CGU\n", __func__); + return; + } + + retval = ingenic_cgu_register_clocks(cgu); + if (retval) + pr_err("%s: failed to register CGU Clocks\n", __func__); +} +CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init); diff --git a/drivers/clk/keystone/Kconfig b/drivers/clk/keystone/Kconfig @@ -7,7 +7,7 @@ config COMMON_CLK_KEYSTONE config TI_SCI_CLK tristate "TI System Control Interface clock drivers" - depends on (ARCH_KEYSTONE || COMPILE_TEST) && OF + depends on (ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST) && OF depends on TI_SCI_PROTOCOL default ARCH_KEYSTONE ---help--- diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c @@ -245,7 +245,7 @@ static void __init of_psc_clk_init(struct device_node *node, spinlock_t *lock) return; } - pr_err("%s: error registering clk %s\n", __func__, node->name); + pr_err("%s: error registering clk %pOFn\n", __func__, node); unmap_domain: iounmap(data->domain_base); @@ -266,3 +266,8 @@ static void __init of_keystone_psc_clk_init(struct device_node *node) } CLK_OF_DECLARE(keystone_gate_clk, "ti,keystone,psc-clock", of_keystone_psc_clk_init); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Clock driver for Keystone 2 based devices"); +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>"); +MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>"); diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c @@ -219,7 +219,7 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl) } out: - pr_err("%s: error initializing pll %s\n", __func__, node->name); + pr_err("%s: error initializing pll %pOFn\n", __func__, node); kfree(pll_data); } @@ -338,3 +338,8 @@ static void __init of_pll_mux_clk_init(struct device_node *node) pr_err("%s: error registering mux %s\n", __func__, clk_name); } CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PLL clock driver for Keystone devices"); +MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>"); +MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>"); diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c @@ -249,11 +249,6 @@ static const char * const msdc30_parents[] = { "univpll2_d4" }; -static const char * const audio_parents[] = { - "clk26m", - "syspll1_d16" -}; - static const char * const aud_intbus_parents[] = { "clk26m", "syspll1_d4", diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c @@ -101,10 +101,16 @@ static const char * const mst_mux_parent_names[] = { "axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7", }; -#define AXG_MST_MCLK_MUX(_name, _reg) \ - AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \ +#define AXG_MST_MUX(_name, _reg, _flag) \ + AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ mst_mux_parent_names, CLK_SET_RATE_PARENT) +#define AXG_MST_MCLK_MUX(_name, _reg) \ + AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) + +#define AXG_MST_SYS_MUX(_name, _reg) \ + AXG_MST_MUX(_name, _reg, 0) + static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); @@ -112,13 +118,19 @@ static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_MCLK_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AXG_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); + +#define AXG_MST_DIV(_name, _reg, _flag) \ + AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ + "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ + +#define AXG_MST_MCLK_DIV(_name, _reg) \ + AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) -#define AXG_MST_MCLK_DIV(_name, _reg) \ - AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \ - "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ +#define AXG_MST_SYS_DIV(_name, _reg) \ + AXG_MST_DIV(_name, _reg, 0) static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); @@ -127,12 +139,12 @@ static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); -static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); -static AXG_MST_MCLK_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +static AXG_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +static AXG_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); -#define AXG_MST_MCLK_GATE(_name, _reg) \ - AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ +#define AXG_MST_MCLK_GATE(_name, _reg) \ + AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ CLK_SET_RATE_PARENT) static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c @@ -22,8 +22,13 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static struct clk_regmap axg_fixed_pll = { +static struct clk_regmap axg_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -34,11 +39,6 @@ static struct clk_regmap axg_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -56,15 +56,39 @@ static struct clk_regmap axg_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; -static struct clk_regmap axg_sys_pll = { +static struct clk_regmap axg_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_regmap axg_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, @@ -75,11 +99,6 @@ static struct clk_regmap axg_sys_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, @@ -92,102 +111,59 @@ static struct clk_regmap axg_sys_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "sys_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; -static const struct pll_rate_table axg_gp0_pll_rate_table[] = { - PLL_RATE(240000000, 40, 1, 2), - PLL_RATE(246000000, 41, 1, 2), - PLL_RATE(252000000, 42, 1, 2), - PLL_RATE(258000000, 43, 1, 2), - PLL_RATE(264000000, 44, 1, 2), - PLL_RATE(270000000, 45, 1, 2), - PLL_RATE(276000000, 46, 1, 2), - PLL_RATE(282000000, 47, 1, 2), - PLL_RATE(288000000, 48, 1, 2), - PLL_RATE(294000000, 49, 1, 2), - PLL_RATE(300000000, 50, 1, 2), - PLL_RATE(306000000, 51, 1, 2), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(318000000, 53, 1, 2), - PLL_RATE(324000000, 54, 1, 2), - PLL_RATE(330000000, 55, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(342000000, 57, 1, 2), - PLL_RATE(348000000, 58, 1, 2), - PLL_RATE(354000000, 59, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(366000000, 61, 1, 2), - PLL_RATE(372000000, 62, 1, 2), - PLL_RATE(378000000, 63, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(390000000, 65, 1, 3), - PLL_RATE(396000000, 66, 1, 3), - PLL_RATE(402000000, 67, 1, 3), - PLL_RATE(408000000, 68, 1, 3), - PLL_RATE(480000000, 40, 1, 1), - PLL_RATE(492000000, 41, 1, 1), - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(756000000, 63, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(780000000, 65, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(804000000, 67, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(960000000, 40, 1, 0), - PLL_RATE(984000000, 41, 1, 0), - PLL_RATE(1008000000, 42, 1, 0), - PLL_RATE(1032000000, 43, 1, 0), - PLL_RATE(1056000000, 44, 1, 0), - PLL_RATE(1080000000, 45, 1, 0), - PLL_RATE(1104000000, 46, 1, 0), - PLL_RATE(1128000000, 47, 1, 0), - PLL_RATE(1152000000, 48, 1, 0), - PLL_RATE(1176000000, 49, 1, 0), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), - PLL_RATE(1560000000, 65, 1, 0), - PLL_RATE(1584000000, 66, 1, 0), - PLL_RATE(1608000000, 67, 1, 0), - PLL_RATE(1632000000, 68, 1, 0), +static struct clk_regmap axg_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct pll_params_table axg_gp0_pll_params_table[] = { + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), + PLL_PARAMS(67, 1), + PLL_PARAMS(68, 1), { /* sentinel */ }, }; @@ -197,11 +173,15 @@ static const struct reg_sequence axg_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, - { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, }; -static struct clk_regmap axg_gp0_pll = { +static struct clk_regmap axg_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, @@ -212,11 +192,6 @@ static struct clk_regmap axg_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_GP0_PLL_CNTL1, .shift = 0, @@ -232,29 +207,49 @@ static struct clk_regmap axg_gp0_pll = { .shift = 29, .width = 1, }, - .table = axg_gp0_pll_rate_table, + .table = axg_gp0_pll_params_table, .init_regs = axg_gp0_init_regs, .init_count = ARRAY_SIZE(axg_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gp0_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static const struct reg_sequence axg_hifi_init_regs[] = { { .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 }, { .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 }, { .reg = HHI_HIFI_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 }, - { .reg = HHI_HIFI_PLL_CNTL, .def = 0x40010250 }, }; -static struct clk_regmap axg_hifi_pll = { +static struct clk_regmap axg_hifi_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_HIFI_PLL_CNTL, .shift = 0, @@ -265,11 +260,6 @@ static struct clk_regmap axg_hifi_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_HIFI_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_HIFI_PLL_CNTL5, .shift = 0, @@ -285,19 +275,35 @@ static struct clk_regmap axg_hifi_pll = { .shift = 29, .width = 1, }, - .table = axg_gp0_pll_rate_table, + .table = axg_gp0_pll_params_table, .init_regs = axg_hifi_init_regs, .init_count = ARRAY_SIZE(axg_hifi_init_regs), .flags = CLK_MESON_PLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ - .name = "hifi_pll", + .name = "hifi_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HIFI_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "hifi_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_fixed_factor axg_fclk_div2_div = { .mult = 1, .div = 2, @@ -625,29 +631,31 @@ static struct clk_regmap axg_mpll3 = { }, }; -static const struct pll_rate_table axg_pcie_pll_rate_table[] = { +static const struct pll_params_table axg_pcie_pll_params_table[] = { { - .rate = 100000000, - .m = 200, - .n = 3, - .od = 1, - .od2 = 3, + .m = 200, + .n = 3, }, { /* sentinel */ }, }; static const struct reg_sequence axg_pcie_init_regs[] = { - { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa }, { .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be }, { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e }, { .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 }, { .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 }, + { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, }; -static struct clk_regmap axg_pcie_pll = { +static struct clk_regmap axg_pcie_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_PCIE_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_PCIE_PLL_CNTL, .shift = 0, @@ -658,16 +666,6 @@ static struct clk_regmap axg_pcie_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_PCIE_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .od2 = { - .reg_off = HHI_PCIE_PLL_CNTL6, - .shift = 6, - .width = 2, - }, .frac = { .reg_off = HHI_PCIE_PLL_CNTL1, .shift = 0, @@ -683,29 +681,63 @@ static struct clk_regmap axg_pcie_pll = { .shift = 29, .width = 1, }, - .table = axg_pcie_pll_rate_table, + .table = axg_pcie_pll_params_table, .init_regs = axg_pcie_init_regs, .init_count = ARRAY_SIZE(axg_pcie_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "pcie_pll", + .name = "pcie_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; +static struct clk_regmap axg_pcie_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "pcie_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_pcie_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_PCIE_PLL_CNTL6, + .shift = 6, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "pcie_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "pcie_pll_od" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap axg_pcie_mux = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_PCIE_PLL_CNTL6, .mask = 0x1, .shift = 2, + /* skip the parent mpll3, reserved for debug */ + .table = (u32[]){ 1 }, }, .hw.init = &(struct clk_init_data){ .name = "pcie_mux", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "mpll3", "pcie_pll" }, - .num_parents = 2, + .parent_names = (const char *[]){ "pcie_pll" }, + .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; @@ -1107,6 +1139,12 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw, [CLKID_GEN_CLK] = &axg_gen_clk.hw, + [CLKID_SYS_PLL_DCO] = &axg_sys_pll_dco.hw, + [CLKID_FIXED_PLL_DCO] = &axg_fixed_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &axg_gp0_pll_dco.hw, + [CLKID_HIFI_PLL_DCO] = &axg_hifi_pll_dco.hw, + [CLKID_PCIE_PLL_DCO] = &axg_pcie_pll_dco.hw, + [CLKID_PCIE_PLL_OD] = &axg_pcie_pll_od.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1185,6 +1223,8 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_fclk_div4, &axg_fclk_div5, &axg_fclk_div7, + &axg_pcie_pll_dco, + &axg_pcie_pll_od, &axg_pcie_pll, &axg_pcie_mux, &axg_pcie_ref, @@ -1194,6 +1234,12 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_gen_clk_sel, &axg_gen_clk_div, &axg_gen_clk, + &axg_fixed_pll_dco, + &axg_sys_pll_dco, + &axg_gp0_pll_dco, + &axg_hifi_pll_dco, + &axg_pcie_pll_dco, + &axg_pcie_pll_od, }; static const struct of_device_id clkc_match_table[] = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h @@ -133,8 +133,14 @@ #define CLKID_PCIE_REF 78 #define CLKID_GEN_CLK_SEL 82 #define CLKID_GEN_CLK_DIV 83 +#define CLKID_SYS_PLL_DCO 85 +#define CLKID_FIXED_PLL_DCO 86 +#define CLKID_GP0_PLL_DCO 87 +#define CLKID_HIFI_PLL_DCO 88 +#define CLKID_PCIE_PLL_DCO 89 +#define CLKID_PCIE_PLL_OD 90 -#define NR_CLKS 85 +#define NR_CLKS 91 /* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/axg-clkc.h> diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c @@ -11,15 +11,19 @@ * In the most basic form, a Meson PLL is composed as follows: * * PLL - * +------------------------------+ - * | | - * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out - * | ^ ^ | - * +------------------------------+ - * | | - * FREF VCO + * +--------------------------------+ + * | | + * | +--+ | + * in >>-----[ /N ]--->| | +-----+ | + * | | |------| DCO |---->> out + * | +--------->| | +--v--+ | + * | | +--+ | | + * | | | | + * | +--[ *(M + (F/Fmax) ]<--+ | + * | | + * +--------------------------------+ * - * out = in * (m + frac / frac_max) / (n << sum(ods)) + * out = in * (m + frac / frac_max) / n */ #include <linux/clk-provider.h> @@ -41,12 +45,11 @@ meson_clk_pll_data(struct clk_regmap *clk) } static unsigned long __pll_params_to_rate(unsigned long parent_rate, - const struct pll_rate_table *pllt, + const struct pll_params_table *pllt, u16 frac, struct meson_clk_pll_data *pll) { u64 rate = (u64)parent_rate * pllt->m; - unsigned int od = pllt->od + pllt->od2 + pllt->od3; if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { u64 frac_rate = (u64)parent_rate * frac; @@ -55,7 +58,7 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate, (1 << pll->frac.width)); } - return DIV_ROUND_UP_ULL(rate, pllt->n << od); + return DIV_ROUND_UP_ULL(rate, pllt->n); } static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, @@ -63,20 +66,11 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - struct pll_rate_table pllt; + struct pll_params_table pllt; u16 frac; pllt.n = meson_parm_read(clk->map, &pll->n); pllt.m = meson_parm_read(clk->map, &pll->m); - pllt.od = meson_parm_read(clk->map, &pll->od); - - pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ? - meson_parm_read(clk->map, &pll->od2) : - 0; - - pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ? - meson_parm_read(clk->map, &pll->od3) : - 0; frac = MESON_PARM_APPLICABLE(&pll->frac) ? meson_parm_read(clk->map, &pll->frac) : @@ -87,14 +81,12 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, static u16 __pll_params_with_frac(unsigned long rate, unsigned long parent_rate, - const struct pll_rate_table *pllt, + const struct pll_params_table *pllt, struct meson_clk_pll_data *pll) { u16 frac_max = (1 << pll->frac.width); u64 val = (u64)rate * pllt->n; - val <<= pllt->od + pllt->od2 + pllt->od3; - if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); else @@ -105,29 +97,50 @@ static u16 __pll_params_with_frac(unsigned long rate, return min((u16)val, (u16)(frac_max - 1)); } -static const struct pll_rate_table * +static bool meson_clk_pll_is_better(unsigned long rate, + unsigned long best, + unsigned long now, + struct meson_clk_pll_data *pll) +{ + if (!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || + MESON_PARM_APPLICABLE(&pll->frac)) { + /* Round down */ + if (now < rate && best < now) + return true; + } else { + /* Round Closest */ + if (abs(now - rate) < abs(best - rate)) + return true; + } + + return false; +} + +static const struct pll_params_table * meson_clk_get_pll_settings(unsigned long rate, + unsigned long parent_rate, struct meson_clk_pll_data *pll) { - const struct pll_rate_table *table = pll->table; - unsigned int i = 0; + const struct pll_params_table *table = pll->table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; if (!table) return NULL; - /* Find the first table element exceeding rate */ - while (table[i].rate && table[i].rate <= rate) - i++; + for (i = 0; table[i].n; i++) { + now = __pll_params_to_rate(parent_rate, &table[i], 0, pll); - if (i != 0) { - if (MESON_PARM_APPLICABLE(&pll->frac) || - !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || - (abs(rate - table[i - 1].rate) < - abs(rate - table[i].rate))) - i--; + /* If we get an exact match, don't bother any further */ + if (now == rate) { + return &table[i]; + } else if (meson_clk_pll_is_better(rate, best, now, pll)) { + best = now; + best_i = i; + } } - return (struct pll_rate_table *)&table[i]; + return (struct pll_params_table *)&table[best_i]; } static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -135,16 +148,18 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - const struct pll_rate_table *pllt = - meson_clk_get_pll_settings(rate, pll); + const struct pll_params_table *pllt = + meson_clk_get_pll_settings(rate, *parent_rate, pll); + unsigned long round; u16 frac; if (!pllt) return meson_clk_pll_recalc_rate(hw, *parent_rate); - if (!MESON_PARM_APPLICABLE(&pll->frac) - || rate == pllt->rate) - return pllt->rate; + round = __pll_params_to_rate(*parent_rate, pllt, 0, pll); + + if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round) + return round; /* * The rate provided by the setting is not an exact match, let's @@ -185,12 +200,45 @@ static void meson_clk_pll_init(struct clk_hw *hw) } } +static int meson_clk_pll_enable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + /* Make sure the pll is in reset */ + meson_parm_write(clk->map, &pll->rst, 1); + + /* Enable the pll */ + meson_parm_write(clk->map, &pll->en, 1); + + /* Take the pll out reset */ + meson_parm_write(clk->map, &pll->rst, 0); + + if (meson_clk_pll_wait_lock(hw)) + return -EIO; + + return 0; +} + +static void meson_clk_pll_disable(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + /* Put the pll is in reset */ + meson_parm_write(clk->map, &pll->rst, 1); + + /* Disable the pll */ + meson_parm_write(clk->map, &pll->en, 0); +} + static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - const struct pll_rate_table *pllt; + const struct pll_params_table *pllt; + unsigned int enabled; unsigned long old_rate; u16 frac = 0; @@ -199,32 +247,28 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, old_rate = rate; - pllt = meson_clk_get_pll_settings(rate, pll); + pllt = meson_clk_get_pll_settings(rate, parent_rate, pll); if (!pllt) return -EINVAL; - /* Put the pll in reset to write the params */ - meson_parm_write(clk->map, &pll->rst, 1); + enabled = meson_parm_read(clk->map, &pll->en); + if (enabled) + meson_clk_pll_disable(hw); meson_parm_write(clk->map, &pll->n, pllt->n); meson_parm_write(clk->map, &pll->m, pllt->m); - meson_parm_write(clk->map, &pll->od, pllt->od); - if (MESON_PARM_APPLICABLE(&pll->od2)) - meson_parm_write(clk->map, &pll->od2, pllt->od2); - - if (MESON_PARM_APPLICABLE(&pll->od3)) - meson_parm_write(clk->map, &pll->od3, pllt->od3); if (MESON_PARM_APPLICABLE(&pll->frac)) { frac = __pll_params_with_frac(rate, parent_rate, pllt, pll); meson_parm_write(clk->map, &pll->frac, frac); } - /* make sure the reset is cleared at this point */ - meson_parm_write(clk->map, &pll->rst, 0); + /* If the pll is stopped, bail out now */ + if (!enabled) + return 0; - if (meson_clk_pll_wait_lock(hw)) { + if (meson_clk_pll_enable(hw)) { pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", __func__, old_rate); /* @@ -244,6 +288,8 @@ const struct clk_ops meson_clk_pll_ops = { .recalc_rate = meson_clk_pll_recalc_rate, .round_rate = meson_clk_pll_round_rate, .set_rate = meson_clk_pll_set_rate, + .enable = meson_clk_pll_enable, + .disable = meson_clk_pll_disable }; const struct clk_ops meson_clk_pll_ro_ops = { diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h @@ -43,37 +43,29 @@ static inline void meson_parm_write(struct regmap *map, struct parm *p, } -struct pll_rate_table { - unsigned long rate; +struct pll_params_table { u16 m; u16 n; - u16 od; - u16 od2; - u16 od3; }; -#define PLL_RATE(_r, _m, _n, _od) \ +#define PLL_PARAMS(_m, _n) \ { \ - .rate = (_r), \ .m = (_m), \ .n = (_n), \ - .od = (_od), \ } #define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) struct meson_clk_pll_data { + struct parm en; struct parm m; struct parm n; struct parm frac; - struct parm od; - struct parm od2; - struct parm od3; struct parm l; struct parm rst; const struct reg_sequence *init_regs; unsigned int init_count; - const struct pll_rate_table *table; + const struct pll_params_table *table; u8 flags; }; diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c @@ -18,165 +18,77 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = { - PLL_RATE(96000000, 32, 1, 3), - PLL_RATE(99000000, 33, 1, 3), - PLL_RATE(102000000, 34, 1, 3), - PLL_RATE(105000000, 35, 1, 3), - PLL_RATE(108000000, 36, 1, 3), - PLL_RATE(111000000, 37, 1, 3), - PLL_RATE(114000000, 38, 1, 3), - PLL_RATE(117000000, 39, 1, 3), - PLL_RATE(120000000, 40, 1, 3), - PLL_RATE(123000000, 41, 1, 3), - PLL_RATE(126000000, 42, 1, 3), - PLL_RATE(129000000, 43, 1, 3), - PLL_RATE(132000000, 44, 1, 3), - PLL_RATE(135000000, 45, 1, 3), - PLL_RATE(138000000, 46, 1, 3), - PLL_RATE(141000000, 47, 1, 3), - PLL_RATE(144000000, 48, 1, 3), - PLL_RATE(147000000, 49, 1, 3), - PLL_RATE(150000000, 50, 1, 3), - PLL_RATE(153000000, 51, 1, 3), - PLL_RATE(156000000, 52, 1, 3), - PLL_RATE(159000000, 53, 1, 3), - PLL_RATE(162000000, 54, 1, 3), - PLL_RATE(165000000, 55, 1, 3), - PLL_RATE(168000000, 56, 1, 3), - PLL_RATE(171000000, 57, 1, 3), - PLL_RATE(174000000, 58, 1, 3), - PLL_RATE(177000000, 59, 1, 3), - PLL_RATE(180000000, 60, 1, 3), - PLL_RATE(183000000, 61, 1, 3), - PLL_RATE(186000000, 62, 1, 3), - PLL_RATE(192000000, 32, 1, 2), - PLL_RATE(198000000, 33, 1, 2), - PLL_RATE(204000000, 34, 1, 2), - PLL_RATE(210000000, 35, 1, 2), - PLL_RATE(216000000, 36, 1, 2), - PLL_RATE(222000000, 37, 1, 2), - PLL_RATE(228000000, 38, 1, 2), - PLL_RATE(234000000, 39, 1, 2), - PLL_RATE(240000000, 40, 1, 2), - PLL_RATE(246000000, 41, 1, 2), - PLL_RATE(252000000, 42, 1, 2), - PLL_RATE(258000000, 43, 1, 2), - PLL_RATE(264000000, 44, 1, 2), - PLL_RATE(270000000, 45, 1, 2), - PLL_RATE(276000000, 46, 1, 2), - PLL_RATE(282000000, 47, 1, 2), - PLL_RATE(288000000, 48, 1, 2), - PLL_RATE(294000000, 49, 1, 2), - PLL_RATE(300000000, 50, 1, 2), - PLL_RATE(306000000, 51, 1, 2), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(318000000, 53, 1, 2), - PLL_RATE(324000000, 54, 1, 2), - PLL_RATE(330000000, 55, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(342000000, 57, 1, 2), - PLL_RATE(348000000, 58, 1, 2), - PLL_RATE(354000000, 59, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(366000000, 61, 1, 2), - PLL_RATE(372000000, 62, 1, 2), - PLL_RATE(384000000, 32, 1, 1), - PLL_RATE(396000000, 33, 1, 1), - PLL_RATE(408000000, 34, 1, 1), - PLL_RATE(420000000, 35, 1, 1), - PLL_RATE(432000000, 36, 1, 1), - PLL_RATE(444000000, 37, 1, 1), - PLL_RATE(456000000, 38, 1, 1), - PLL_RATE(468000000, 39, 1, 1), - PLL_RATE(480000000, 40, 1, 1), - PLL_RATE(492000000, 41, 1, 1), - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 32, 1, 0), - PLL_RATE(792000000, 33, 1, 0), - PLL_RATE(816000000, 34, 1, 0), - PLL_RATE(840000000, 35, 1, 0), - PLL_RATE(864000000, 36, 1, 0), - PLL_RATE(888000000, 37, 1, 0), - PLL_RATE(912000000, 38, 1, 0), - PLL_RATE(936000000, 39, 1, 0), - PLL_RATE(960000000, 40, 1, 0), - PLL_RATE(984000000, 41, 1, 0), - PLL_RATE(1008000000, 42, 1, 0), - PLL_RATE(1032000000, 43, 1, 0), - PLL_RATE(1056000000, 44, 1, 0), - PLL_RATE(1080000000, 45, 1, 0), - PLL_RATE(1104000000, 46, 1, 0), - PLL_RATE(1128000000, 47, 1, 0), - PLL_RATE(1152000000, 48, 1, 0), - PLL_RATE(1176000000, 49, 1, 0), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), +static const struct pll_params_table gxbb_gp0_pll_params_table[] = { + PLL_PARAMS(32, 1), + PLL_PARAMS(33, 1), + PLL_PARAMS(34, 1), + PLL_PARAMS(35, 1), + PLL_PARAMS(36, 1), + PLL_PARAMS(37, 1), + PLL_PARAMS(38, 1), + PLL_PARAMS(39, 1), + PLL_PARAMS(40, 1), + PLL_PARAMS(41, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), { /* sentinel */ }, }; -static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { - PLL_RATE(504000000, 42, 1, 1), - PLL_RATE(516000000, 43, 1, 1), - PLL_RATE(528000000, 44, 1, 1), - PLL_RATE(540000000, 45, 1, 1), - PLL_RATE(552000000, 46, 1, 1), - PLL_RATE(564000000, 47, 1, 1), - PLL_RATE(576000000, 48, 1, 1), - PLL_RATE(588000000, 49, 1, 1), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(612000000, 51, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(636000000, 53, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(660000000, 55, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(684000000, 57, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(708000000, 59, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(732000000, 61, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(756000000, 63, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(780000000, 65, 1, 1), - PLL_RATE(792000000, 66, 1, 1), +static const struct pll_params_table gxl_gp0_pll_params_table[] = { + PLL_PARAMS(42, 1), + PLL_PARAMS(43, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(46, 1), + PLL_PARAMS(47, 1), + PLL_PARAMS(48, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(65, 1), + PLL_PARAMS(66, 1), { /* sentinel */ }, }; -static struct clk_regmap gxbb_fixed_pll = { +static struct clk_regmap gxbb_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -187,11 +99,6 @@ static struct clk_regmap gxbb_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -209,11 +116,29 @@ static struct clk_regmap gxbb_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ }, }; @@ -228,8 +153,13 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { }, }; -static struct clk_regmap gxbb_hdmi_pll = { +static struct clk_regmap gxbb_hdmi_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_HDMI_PLL_CNTL, .shift = 0, @@ -245,21 +175,6 @@ static struct clk_regmap gxbb_hdmi_pll = { .shift = 0, .width = 12, }, - .od = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 16, - .width = 2, - }, - .od2 = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 22, - .width = 2, - }, - .od3 = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 18, - .width = 2, - }, .l = { .reg_off = HHI_HDMI_PLL_CNTL, .shift = 31, @@ -272,74 +187,121 @@ static struct clk_regmap gxbb_hdmi_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "hdmi_pll", + .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "hdmi_pll_pre_mult" }, .num_parents = 1, + /* + * Display directly handle hdmi pll registers ATM, we need + * NOCACHE to keep our view of the clock as accurate as possible + */ .flags = CLK_GET_RATE_NOCACHE, }, }; +static struct clk_regmap gxbb_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 22, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxbb_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL2, + .shift = 18, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od2" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxl_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap gxl_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap gxl_hdmi_pll = { - .data = &(struct meson_clk_pll_data){ - .m = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .frac = { - /* - * On gxl, there is a register shift due to - * HHI_HDMI_PLL_CNTL1 which does not exist on gxbb, - * so we compute the register offset based on the PLL - * base to get it right - */ - .reg_off = HHI_HDMI_PLL_CNTL + 4, - .shift = 0, - .width = 12, - }, - .od = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 21, - .width = 2, - }, - .od2 = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 23, - .width = 2, - }, - .od3 = { - .reg_off = HHI_HDMI_PLL_CNTL + 8, - .shift = 19, - .width = 2, - }, - .l = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 31, - .width = 1, - }, - .rst = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 29, - .width = 1, - }, + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", - .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od2" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, }, }; -static struct clk_regmap gxbb_sys_pll = { +static struct clk_regmap gxbb_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, @@ -350,11 +312,6 @@ static struct clk_regmap gxbb_sys_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 10, - .width = 2, - }, .l = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, @@ -367,11 +324,26 @@ static struct clk_regmap gxbb_sys_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "sys_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 10, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -379,11 +351,15 @@ static const struct reg_sequence gxbb_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, - { .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 }, }; -static struct clk_regmap gxbb_gp0_pll = { +static struct clk_regmap gxbb_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, @@ -394,11 +370,6 @@ static struct clk_regmap gxbb_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 31, @@ -409,16 +380,15 @@ static struct clk_regmap gxbb_gp0_pll = { .shift = 29, .width = 1, }, - .table = gxbb_gp0_pll_rate_table, + .table = gxbb_gp0_pll_params_table, .init_regs = gxbb_gp0_init_regs, .init_count = ARRAY_SIZE(gxbb_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; @@ -428,11 +398,15 @@ static const struct reg_sequence gxl_gp0_init_regs[] = { { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, - { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, }; -static struct clk_regmap gxl_gp0_pll = { +static struct clk_regmap gxl_gp0_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_GP0_PLL_CNTL, .shift = 0, @@ -443,11 +417,6 @@ static struct clk_regmap gxl_gp0_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_GP0_PLL_CNTL1, .shift = 0, @@ -463,16 +432,31 @@ static struct clk_regmap gxl_gp0_pll = { .shift = 29, .width = 1, }, - .table = gxl_gp0_pll_rate_table, + .table = gxl_gp0_pll_params_table, .init_regs = gxl_gp0_init_regs, .init_count = ARRAY_SIZE(gxl_gp0_init_regs), }, .hw.init = &(struct clk_init_data){ - .name = "gp0_pll", + .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap gxbb_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gp0_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -1933,6 +1917,12 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, + [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &gxbb_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &gxbb_hdmi_pll_od2.hw, + [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &gxbb_gp0_pll_dco.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1948,7 +1938,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_FCLK_DIV4] = &gxbb_fclk_div4.hw, [CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw, [CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw, - [CLKID_GP0_PLL] = &gxl_gp0_pll.hw, + [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw, [CLKID_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw, [CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw, [CLKID_CLK81] = &gxbb_clk81.hw, @@ -2098,19 +2088,29 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, + [CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &gxl_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &gxl_hdmi_pll_od2.hw, + [CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &gxl_gp0_pll_dco.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, }; static struct clk_regmap *const gxbb_clk_regmaps[] = { - &gxbb_gp0_pll, + &gxbb_gp0_pll_dco, &gxbb_hdmi_pll, + &gxbb_hdmi_pll_od, + &gxbb_hdmi_pll_od2, }; static struct clk_regmap *const gxl_clk_regmaps[] = { - &gxl_gp0_pll, + &gxl_gp0_pll_dco, &gxl_hdmi_pll, + &gxl_hdmi_pll_od, + &gxl_hdmi_pll_od2, }; static struct clk_regmap *const gx_clk_regmaps[] = { @@ -2265,6 +2265,10 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_gen_clk_sel, &gxbb_gen_clk_div, &gxbb_gen_clk, + &gxbb_fixed_pll_dco, + &gxbb_hdmi_pll_dco, + &gxbb_sys_pll_dco, + &gxbb_gp0_pll, }; struct clkc_data { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h @@ -159,8 +159,14 @@ #define CLKID_VDEC_HEVC_DIV 155 #define CLKID_GEN_CLK_SEL 157 #define CLKID_GEN_CLK_DIV 158 - -#define NR_CLKS 160 +#define CLKID_FIXED_PLL_DCO 160 +#define CLKID_HDMI_PLL_DCO 161 +#define CLKID_HDMI_PLL_OD 162 +#define CLKID_HDMI_PLL_OD2 163 +#define CLKID_SYS_PLL_DCO 164 +#define CLKID_GP0_PLL_DCO 165 + +#define NR_CLKS 166 /* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/gxbb-clkc.h> diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c @@ -11,7 +11,6 @@ #include <linux/clk-provider.h> #include <linux/init.h> #include <linux/of_address.h> -#include <linux/platform_device.h> #include <linux/reset-controller.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -22,66 +21,27 @@ static DEFINE_SPINLOCK(meson_clk_lock); -static void __iomem *clk_base; - struct meson8b_clk_reset { struct reset_controller_dev reset; - void __iomem *base; + struct regmap *regmap; }; -static const struct pll_rate_table sys_pll_rate_table[] = { - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(408000000, 68, 1, 2), - PLL_RATE(432000000, 72, 1, 2), - PLL_RATE(456000000, 76, 1, 2), - PLL_RATE(480000000, 80, 1, 2), - PLL_RATE(504000000, 84, 1, 2), - PLL_RATE(528000000, 88, 1, 2), - PLL_RATE(552000000, 92, 1, 2), - PLL_RATE(576000000, 96, 1, 2), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(840000000, 70, 1, 1), - PLL_RATE(864000000, 72, 1, 1), - PLL_RATE(888000000, 74, 1, 1), - PLL_RATE(912000000, 76, 1, 1), - PLL_RATE(936000000, 78, 1, 1), - PLL_RATE(960000000, 80, 1, 1), - PLL_RATE(984000000, 82, 1, 1), - PLL_RATE(1008000000, 84, 1, 1), - PLL_RATE(1032000000, 86, 1, 1), - PLL_RATE(1056000000, 88, 1, 1), - PLL_RATE(1080000000, 90, 1, 1), - PLL_RATE(1104000000, 92, 1, 1), - PLL_RATE(1128000000, 94, 1, 1), - PLL_RATE(1152000000, 96, 1, 1), - PLL_RATE(1176000000, 98, 1, 1), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), +static const struct pll_params_table sys_pll_params_table[] = { + PLL_PARAMS(50, 1), + PLL_PARAMS(51, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(53, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(55, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(57, 1), + PLL_PARAMS(58, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(63, 1), + PLL_PARAMS(64, 1), { /* sentinel */ }, }; @@ -94,8 +54,13 @@ static struct clk_fixed_rate meson8b_xtal = { }, }; -static struct clk_regmap meson8b_fixed_pll = { +static struct clk_regmap meson8b_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_MPLL_CNTL, .shift = 0, @@ -106,11 +71,6 @@ static struct clk_regmap meson8b_fixed_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, .frac = { .reg_off = HHI_MPLL_CNTL2, .shift = 0, @@ -128,16 +88,39 @@ static struct clk_regmap meson8b_fixed_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "fixed_pll", + .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; -static struct clk_regmap meson8b_vid_pll = { +static struct clk_regmap meson8b_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_regmap meson8b_vid_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_VID_PLL_CNTL, .shift = 0, @@ -148,11 +131,6 @@ static struct clk_regmap meson8b_vid_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_VID_PLL_CNTL, .shift = 31, @@ -165,16 +143,36 @@ static struct clk_regmap meson8b_vid_pll = { }, }, .hw.init = &(struct clk_init_data){ - .name = "vid_pll", + .name = "vid_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, }, }; -static struct clk_regmap meson8b_sys_pll = { +static struct clk_regmap meson8b_vid_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "vid_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_sys_pll_dco = { .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 30, + .width = 1, + }, .m = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 0, @@ -185,11 +183,6 @@ static struct clk_regmap meson8b_sys_pll = { .shift = 9, .width = 5, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, .l = { .reg_off = HHI_SYS_PLL_CNTL, .shift = 31, @@ -200,14 +193,29 @@ static struct clk_regmap meson8b_sys_pll = { .shift = 29, .width = 1, }, - .table = sys_pll_rate_table, + .table = sys_pll_params_table, }, .hw.init = &(struct clk_init_data){ - .name = "sys_pll", + .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap meson8b_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -879,6 +887,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_PLL_VID_DCO] = &meson8b_vid_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -987,6 +998,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_nand_clk_sel, &meson8b_nand_clk_div, &meson8b_nand_clk_gate, + &meson8b_fixed_pll_dco, + &meson8b_vid_pll_dco, + &meson8b_sys_pll_dco, }; static const struct meson8b_clk_reset_line { @@ -1050,7 +1064,6 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, container_of(rcdev, struct meson8b_clk_reset, reset); unsigned long flags; const struct meson8b_clk_reset_line *reset; - u32 val; if (id >= ARRAY_SIZE(meson8b_clk_reset_bits)) return -EINVAL; @@ -1059,12 +1072,12 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, spin_lock_irqsave(&meson_clk_lock, flags); - val = readl(meson8b_clk_reset->base + reset->reg); if (assert) - val |= BIT(reset->bit_idx); + regmap_update_bits(meson8b_clk_reset->regmap, reset->reg, + BIT(reset->bit_idx), BIT(reset->bit_idx)); else - val &= ~BIT(reset->bit_idx); - writel(val, meson8b_clk_reset->base + reset->reg); + regmap_update_bits(meson8b_clk_reset->regmap, reset->reg, + BIT(reset->bit_idx), 0); spin_unlock_irqrestore(&meson_clk_lock, flags); @@ -1094,62 +1107,12 @@ static const struct regmap_config clkc_regmap_config = { .reg_stride = 4, }; -static int meson8b_clkc_probe(struct platform_device *pdev) -{ - int ret, i; - struct device *dev = &pdev->dev; - struct regmap *map; - - if (!clk_base) - return -ENXIO; - - map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); - if (IS_ERR(map)) - return PTR_ERR(map); - - /* Populate regmap for the regmap backed clocks */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) - meson8b_clk_regmaps[i]->map = map; - - /* - * register all clks - * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 - */ - for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { - /* array might be sparse */ - if (!meson8b_hw_onecell_data.hws[i]) - continue; - - ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]); - if (ret) - return ret; - } - - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, - &meson8b_hw_onecell_data); -} - -static const struct of_device_id meson8b_clkc_match_table[] = { - { .compatible = "amlogic,meson8-clkc" }, - { .compatible = "amlogic,meson8b-clkc" }, - { .compatible = "amlogic,meson8m2-clkc" }, - { } -}; - -static struct platform_driver meson8b_driver = { - .probe = meson8b_clkc_probe, - .driver = { - .name = "meson8b-clkc", - .of_match_table = meson8b_clkc_match_table, - }, -}; - -builtin_platform_driver(meson8b_driver); - -static void __init meson8b_clkc_reset_init(struct device_node *np) +static void __init meson8b_clkc_init(struct device_node *np) { struct meson8b_clk_reset *rstc; - int ret; + void __iomem *clk_base; + struct regmap *map; + int i, ret; /* Generic clocks, PLLs and some of the reset-bits */ clk_base = of_iomap(np, 1); @@ -1158,12 +1121,16 @@ static void __init meson8b_clkc_reset_init(struct device_node *np) return; } + map = regmap_init_mmio(NULL, clk_base, &clkc_regmap_config); + if (IS_ERR(map)) + return; + rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); if (!rstc) return; /* Reset Controller */ - rstc->base = clk_base; + rstc->regmap = map; rstc->reset.ops = &meson8b_clk_reset_ops; rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits); rstc->reset.of_node = np; @@ -1173,11 +1140,34 @@ static void __init meson8b_clkc_reset_init(struct device_node *np) __func__, ret); return; } + + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) + meson8b_clk_regmaps[i]->map = map; + + /* + * register all clks + * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 + */ + for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { + /* array might be sparse */ + if (!meson8b_hw_onecell_data.hws[i]) + continue; + + ret = clk_hw_register(NULL, meson8b_hw_onecell_data.hws[i]); + if (ret) + return; + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + &meson8b_hw_onecell_data); + if (ret) + pr_err("%s: failed to register clock provider\n", __func__); } CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc", - meson8b_clkc_reset_init); + meson8b_clkc_init); diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h @@ -75,8 +75,11 @@ #define CLKID_FCLK_DIV7_DIV 109 #define CLKID_NAND_SEL 110 #define CLKID_NAND_DIV 111 +#define CLKID_PLL_FIXED_DCO 113 +#define CLKID_PLL_VID_DCO 114 +#define CLKID_PLL_SYS_DCO 115 -#define CLK_NR_CLKS 113 +#define CLK_NR_CLKS 116 /* * include the CLKID and RESETID that have diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c @@ -227,8 +227,8 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = { /* The gate clocks has mux parent. */ {MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, - {MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, - {MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH2, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH3, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, {MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock}, {MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock}, diff --git a/drivers/clk/mvebu/ap806-system-controller.c b/drivers/clk/mvebu/ap806-system-controller.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Armada AP806 System Controller * @@ -5,9 +6,6 @@ * * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "ap806-system-controller: " fmt @@ -155,7 +153,6 @@ static int ap806_syscon_common_probe(struct platform_device *pdev, goto fail4; } - of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data); ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data); if (ret) goto fail_clk_add; diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Armada 370 SoC clocks * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/armada-375.c b/drivers/clk/mvebu/armada-375.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Armada 375 SoC clocks * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c @@ -56,6 +56,15 @@ struct clk_periph_driver_data { struct clk_hw_onecell_data *hw_data; spinlock_t lock; + void __iomem *reg; + + /* Storage registers for suspend/resume operations */ + u32 tbg_sel; + u32 div_sel0; + u32 div_sel1; + u32 div_sel2; + u32 clk_sel; + u32 clk_dis; }; struct clk_double_div { @@ -672,6 +681,40 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data, return PTR_ERR_OR_ZERO(*hw); } +static int __maybe_unused armada_3700_periph_clock_suspend(struct device *dev) +{ + struct clk_periph_driver_data *data = dev_get_drvdata(dev); + + data->tbg_sel = readl(data->reg + TBG_SEL); + data->div_sel0 = readl(data->reg + DIV_SEL0); + data->div_sel1 = readl(data->reg + DIV_SEL1); + data->div_sel2 = readl(data->reg + DIV_SEL2); + data->clk_sel = readl(data->reg + CLK_SEL); + data->clk_dis = readl(data->reg + CLK_DIS); + + return 0; +} + +static int __maybe_unused armada_3700_periph_clock_resume(struct device *dev) +{ + struct clk_periph_driver_data *data = dev_get_drvdata(dev); + + /* Follow the same order than what the Cortex-M3 does (ATF code) */ + writel(data->clk_dis, data->reg + CLK_DIS); + writel(data->div_sel0, data->reg + DIV_SEL0); + writel(data->div_sel1, data->reg + DIV_SEL1); + writel(data->div_sel2, data->reg + DIV_SEL2); + writel(data->tbg_sel, data->reg + TBG_SEL); + writel(data->clk_sel, data->reg + CLK_SEL); + + return 0; +} + +static const struct dev_pm_ops armada_3700_periph_clock_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(armada_3700_periph_clock_suspend, + armada_3700_periph_clock_resume) +}; + static int armada_3700_periph_clock_probe(struct platform_device *pdev) { struct clk_periph_driver_data *driver_data; @@ -680,7 +723,6 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int num_periph = 0, i, ret; struct resource *res; - void __iomem *reg; data = of_device_get_match_data(dev); if (!data) @@ -689,11 +731,6 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) while (data[num_periph].name) num_periph++; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(dev, res); - if (IS_ERR(reg)) - return PTR_ERR(reg); - driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL); if (!driver_data) return -ENOMEM; @@ -706,12 +743,16 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) return -ENOMEM; driver_data->hw_data->num = num_periph; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + driver_data->reg = devm_ioremap_resource(dev, res); + if (IS_ERR(driver_data->reg)) + return PTR_ERR(driver_data->reg); + spin_lock_init(&driver_data->lock); for (i = 0; i < num_periph; i++) { struct clk_hw **hw = &driver_data->hw_data->hws[i]; - - if (armada_3700_add_composite_clk(&data[i], reg, + if (armada_3700_add_composite_clk(&data[i], driver_data->reg, &driver_data->lock, dev, hw)) dev_err(dev, "Can't register periph clock %s\n", data[i].name); @@ -749,6 +790,7 @@ static struct platform_driver armada_3700_periph_clock_driver = { .driver = { .name = "marvell-armada-3700-periph-clock", .of_match_table = armada_3700_periph_clock_of_match, + .pm = &armada_3700_periph_clock_pm_ops, }, }; diff --git a/drivers/clk/mvebu/armada-37xx-tbg.c b/drivers/clk/mvebu/armada-37xx-tbg.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Marvell Armada 37xx SoC Time Base Generator clocks * * Copyright (C) 2016 Marvell * * Gregory CLEMENT <gregory.clement@free-electrons.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2 or later. This program is licensed "as is" - * without any warranty of any kind, whether express or implied. */ #include <linux/clk-provider.h> @@ -99,12 +96,13 @@ static int armada_3700_tbg_clock_probe(struct platform_device *pdev) hw_tbg_data->num = NUM_TBG; platform_set_drvdata(pdev, hw_tbg_data); - parent = devm_clk_get(dev, NULL); + parent = clk_get(dev, NULL); if (IS_ERR(parent)) { dev_err(dev, "Could get the clock parent\n"); return -EINVAL; } parent_name = __clk_get_name(parent); + clk_put(parent); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg = devm_ioremap_resource(dev, res); diff --git a/drivers/clk/mvebu/armada-37xx-xtal.c b/drivers/clk/mvebu/armada-37xx-xtal.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Armada 37xx SoC xtal clocks * @@ -5,9 +6,6 @@ * * Gregory CLEMENT <gregory.clement@free-electrons.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/clk-provider.h> diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Armada 380/385 SoC clocks * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/armada-39x.c b/drivers/clk/mvebu/armada-39x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Armada 39x SoC clocks * @@ -8,9 +9,6 @@ * Andrew Lunn <andrew@lunn.ch> * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Armada XP SoC clocks * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * MVEBU Core divider clock * @@ -5,9 +6,6 @@ * * Ezequiel Garcia <ezequiel.garcia@free-electrons.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell MVEBU CPU clock handling. * @@ -5,9 +6,6 @@ * * Gregory CLEMENT <gregory.clement@free-electrons.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> #include <linux/slab.h> diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell EBU SoC common clock handling * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/common.h b/drivers/clk/mvebu/common.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Marvell EBU SoC common clock handling * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __CLK_MVEBU_COMMON_H_ diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Armada CP110 System Controller * @@ -5,9 +6,6 @@ * * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ /* diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Dove SoC clocks * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Kirkwood SoC clocks * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/mv98dx3236.c b/drivers/clk/mvebu/mv98dx3236.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell MV98DX3236 SoC clocks * @@ -7,9 +8,6 @@ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> * Andrew Lunn <andrew@lunn.ch> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/mvebu/orion.c b/drivers/clk/mvebu/orion.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Marvell Orion SoC clocks * @@ -5,9 +6,6 @@ * * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig @@ -1,3 +1,7 @@ +config KRAIT_CLOCKS + bool + select KRAIT_L2_ACCESSORS + config QCOM_GDSC bool select PM_GENERIC_DOMAINS if PM @@ -235,6 +239,31 @@ config MSM_GCC_8998 Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, UFS, SD/eMMC, PCIe, etc. +config QCS_GCC_404 + tristate "QCS404 Global Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on QCS404 devices. + Say Y if you want to use multimedia devices or peripheral + devices such as UART, SPI, I2C, USB, SD/eMMC, PCIe etc. + +config SDM_CAMCC_845 + tristate "SDM845 Camera Clock Controller" + depends on COMMON_CLK_QCOM + select SDM_GCC_845 + help + Support for the camera clock controller on SDM845 devices. + Say Y if you want to support camera devices and camera functionality. + +config SDM_GCC_660 + tristate "SDM660 Global Clock Controller" + select QCOM_GDSC + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on SDM660 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2C, USB, UFS, SDDC, PCIe, etc. + config SDM_GCC_845 tristate "SDM845 Global Clock Controller" select QCOM_GDSC @@ -272,3 +301,27 @@ config SPMI_PMIC_CLKDIV Technologies, Inc. SPMI PMIC. It configures the frequency of clkdiv outputs of the PMIC. These clocks are typically wired through alternate functions on GPIO pins. + +config QCOM_HFPLL + tristate "High-Frequency PLL (HFPLL) Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the high-frequency PLLs present on Qualcomm devices. + Say Y if you want to support CPU frequency scaling on devices + such as MSM8974, APQ8084, etc. + +config KPSS_XCC + tristate "KPSS Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the Krait ACC and GCC clock controllers. Say Y + if you want to support CPU frequency scaling on devices such + as MSM8960, APQ8064, etc. + +config KRAITCC + tristate "Krait Clock Controller" + depends on COMMON_CLK_QCOM && ARM + select KRAIT_CLOCKS + help + Support for the Krait CPU clocks on Qualcomm devices. + Say Y if you want to support CPU frequency scaling. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile @@ -11,6 +11,8 @@ clk-qcom-y += clk-branch.o clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o clk-qcom-y += clk-regmap-mux-div.o +clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o +clk-qcom-y += clk-hfpll.o clk-qcom-y += reset.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o @@ -39,7 +41,13 @@ obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o +obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o +obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o +obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o +obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o +obj-$(CONFIG_QCOM_HFPLL) += hfpll.o +obj-$(CONFIG_KRAITCC) += krait-cc.o diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c @@ -0,0 +1,1745 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <dt-bindings/clock/qcom,camcc-sdm845.h> + +#include "common.h" +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "gdsc.h" + +enum { + P_BI_TCXO, + P_CAM_CC_PLL0_OUT_EVEN, + P_CAM_CC_PLL1_OUT_EVEN, + P_CAM_CC_PLL2_OUT_EVEN, + P_CAM_CC_PLL3_OUT_EVEN, + P_CORE_BI_PLL_TEST_SE, +}; + +static const struct parent_map cam_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL2_OUT_EVEN, 1 }, + { P_CAM_CC_PLL1_OUT_EVEN, 2 }, + { P_CAM_CC_PLL3_OUT_EVEN, 5 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const cam_cc_parent_names_0[] = { + "bi_tcxo", + "cam_cc_pll2_out_even", + "cam_cc_pll1_out_even", + "cam_cc_pll3_out_even", + "cam_cc_pll0_out_even", + "core_bi_pll_test_se", +}; + +static struct clk_alpha_pll cam_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll0_out_even", + .parent_names = (const char *[]){ "cam_cc_pll0" }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_fabia_ops, + }, +}; + +static struct clk_alpha_pll cam_cc_pll1 = { + .offset = 0x1000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = { + .offset = 0x1000, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll1_out_even", + .parent_names = (const char *[]){ "cam_cc_pll1" }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_fabia_ops, + }, +}; + +static struct clk_alpha_pll cam_cc_pll2 = { + .offset = 0x2000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll2", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll2_out_even = { + .offset = 0x2000, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll2_out_even", + .parent_names = (const char *[]){ "cam_cc_pll2" }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_fabia_ops, + }, +}; + +static struct clk_alpha_pll cam_cc_pll3 = { + .offset = 0x3000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll3", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = { + .offset = 0x3000, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll3_out_even", + .parent_names = (const char *[]){ "cam_cc_pll3" }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_fabia_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +/* + * As per HW design, some of the CAMCC RCGs needs to + * move to XO clock during their clock disable so using + * clk_rcg2_shared_ops for such RCGs. This is required + * to power down the camera memories gracefully. + * Also, use CLK_SET_RATE_PARENT flag for the RCGs which + * have CAM_CC_PLL2_OUT_EVEN PLL as parent in frequency + * table and requires reconfiguration of the PLL frequency. + */ +static struct clk_rcg2 cam_cc_bps_clk_src = { + .cmd_rcgr = 0x600c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_bps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cci_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0), + F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cci_clk_src = { + .cmd_rcgr = 0xb0d8, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_cci_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cphy_rx_clk_src = { + .cmd_rcgr = 0x9060, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_cphy_rx_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(240000000, P_CAM_CC_PLL2_OUT_EVEN, 2, 0, 0), + F(269333333, P_CAM_CC_PLL1_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = { + .cmd_rcgr = 0x5004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi0phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = { + .cmd_rcgr = 0x5028, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi1phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = { + .cmd_rcgr = 0x504c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi2phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = { + .cmd_rcgr = 0x5070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi3phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_fast_ahb_clk_src = { + .cmd_rcgr = 0x6038, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_fast_ahb_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_fd_core_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_fd_core_clk_src = { + .cmd_rcgr = 0xb0b0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_fd_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_fd_core_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_icp_clk_src = { + .cmd_rcgr = 0xb088, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_icp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), + F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_clk_src = { + .cmd_rcgr = 0x900c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_csid_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(75000000, P_CAM_CC_PLL0_OUT_EVEN, 8, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = { + .cmd_rcgr = 0x9038, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_csid_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_1_clk_src = { + .cmd_rcgr = 0xa00c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = { + .cmd_rcgr = 0xa030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_csid_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_clk_src = { + .cmd_rcgr = 0xb004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = { + .cmd_rcgr = 0xb024, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_csid_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ipe_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0), + F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ipe_0_clk_src = { + .cmd_rcgr = 0x700c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ipe_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ipe_1_clk_src = { + .cmd_rcgr = 0x800c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ipe_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_jpeg_clk_src = { + .cmd_rcgr = 0xb04c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_bps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_jpeg_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_lrme_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(269333333, P_CAM_CC_PLL1_OUT_EVEN, 3, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_lrme_clk_src = { + .cmd_rcgr = 0xb0f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_lrme_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_lrme_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_CAM_CC_PLL2_OUT_EVEN, 10, 1, 2), + F(33333333, P_CAM_CC_PLL0_OUT_EVEN, 2, 1, 9), + F(34285714, P_CAM_CC_PLL2_OUT_EVEN, 14, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_mclk0_clk_src = { + .cmd_rcgr = 0x4004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk0_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk1_clk_src = { + .cmd_rcgr = 0x4024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk1_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk2_clk_src = { + .cmd_rcgr = 0x4044, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk2_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk3_clk_src = { + .cmd_rcgr = 0x4064, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk3_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(60000000, P_CAM_CC_PLL0_OUT_EVEN, 10, 0, 0), + F(66666667, P_CAM_CC_PLL0_OUT_EVEN, 9, 0, 0), + F(73846154, P_CAM_CC_PLL2_OUT_EVEN, 6.5, 0, 0), + F(80000000, P_CAM_CC_PLL2_OUT_EVEN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_slow_ahb_clk_src = { + .cmd_rcgr = 0x6054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_slow_ahb_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch cam_cc_bps_ahb_clk = { + .halt_reg = 0x606c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x606c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_ahb_clk", + .parent_names = (const char *[]){ + "cam_cc_slow_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_areg_clk = { + .halt_reg = 0x6050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_areg_clk", + .parent_names = (const char *[]){ + "cam_cc_fast_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_axi_clk = { + .halt_reg = 0x6034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_clk = { + .halt_reg = 0x6024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_clk", + .parent_names = (const char *[]){ + "cam_cc_bps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_camnoc_atb_clk = { + .halt_reg = 0xb12c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb12c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_camnoc_atb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_camnoc_axi_clk = { + .halt_reg = 0xb124, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb124, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_camnoc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_clk = { + .halt_reg = 0xb0f0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0f0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_cci_clk", + .parent_names = (const char *[]){ + "cam_cc_cci_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ahb_clk = { + .halt_reg = 0xb11c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb11c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_cpas_ahb_clk", + .parent_names = (const char *[]){ + "cam_cc_slow_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi0phytimer_clk = { + .halt_reg = 0x501c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x501c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi0phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi0phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi1phytimer_clk = { + .halt_reg = 0x5040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi1phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi1phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi2phytimer_clk = { + .halt_reg = 0x5064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi2phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi2phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi3phytimer_clk = { + .halt_reg = 0x5088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi3phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi3phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy0_clk = { + .halt_reg = 0x5020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy0_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy1_clk = { + .halt_reg = 0x5044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy1_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy2_clk = { + .halt_reg = 0x5068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy2_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy3_clk = { + .halt_reg = 0x508c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x508c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy3_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_fd_core_clk = { + .halt_reg = 0xb0c8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_fd_core_clk", + .parent_names = (const char *[]){ + "cam_cc_fd_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_fd_core_uar_clk = { + .halt_reg = 0xb0d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0d0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_fd_core_uar_clk", + .parent_names = (const char *[]){ + "cam_cc_fd_core_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_apb_clk = { + .halt_reg = 0xb084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_atb_clk = { + .halt_reg = 0xb078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_atb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_clk = { + .halt_reg = 0xb0a0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0a0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_clk", + .parent_names = (const char *[]){ + "cam_cc_icp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_cti_clk = { + .halt_reg = 0xb07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_cti_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_ts_clk = { + .halt_reg = 0xb080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_ts_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_axi_clk = { + .halt_reg = 0x907c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x907c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_clk = { + .halt_reg = 0x9024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_cphy_rx_clk = { + .halt_reg = 0x9078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_cphy_rx_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_csid_clk = { + .halt_reg = 0x9050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_csid_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_0_csid_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_dsp_clk = { + .halt_reg = 0x9034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_dsp_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_0_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_axi_clk = { + .halt_reg = 0xa054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_clk = { + .halt_reg = 0xa024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_cphy_rx_clk = { + .halt_reg = 0xa050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_cphy_rx_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_csid_clk = { + .halt_reg = 0xa048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_csid_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_1_csid_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_dsp_clk = { + .halt_reg = 0xa02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa02c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_dsp_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_1_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_clk = { + .halt_reg = 0xb01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_lite_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = { + .halt_reg = 0xb044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_cphy_rx_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_csid_clk = { + .halt_reg = 0xb03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_csid_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_lite_csid_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_ahb_clk = { + .halt_reg = 0x703c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x703c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_ahb_clk", + .parent_names = (const char *[]){ + "cam_cc_slow_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_areg_clk = { + .halt_reg = 0x7038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_areg_clk", + .parent_names = (const char *[]){ + "cam_cc_fast_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_axi_clk = { + .halt_reg = 0x7034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_clk = { + .halt_reg = 0x7024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_clk", + .parent_names = (const char *[]){ + "cam_cc_ipe_0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_1_ahb_clk = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_ahb_clk", + .parent_names = (const char *[]){ + "cam_cc_slow_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_1_areg_clk = { + .halt_reg = 0x8038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_areg_clk", + .parent_names = (const char *[]){ + "cam_cc_fast_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_1_axi_clk = { + .halt_reg = 0x8034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_1_clk = { + .halt_reg = 0x8024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_clk", + .parent_names = (const char *[]){ + "cam_cc_ipe_1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_jpeg_clk = { + .halt_reg = 0xb064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_jpeg_clk", + .parent_names = (const char *[]){ + "cam_cc_jpeg_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_lrme_clk = { + .halt_reg = 0xb110, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb110, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_lrme_clk", + .parent_names = (const char *[]){ + "cam_cc_lrme_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk0_clk = { + .halt_reg = 0x401c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x401c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk0_clk", + .parent_names = (const char *[]){ + "cam_cc_mclk0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk1_clk = { + .halt_reg = 0x403c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x403c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk1_clk", + .parent_names = (const char *[]){ + "cam_cc_mclk1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk2_clk = { + .halt_reg = 0x405c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x405c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk2_clk", + .parent_names = (const char *[]){ + "cam_cc_mclk2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk3_clk = { + .halt_reg = 0x407c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x407c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk3_clk", + .parent_names = (const char *[]){ + "cam_cc_mclk3_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_soc_ahb_clk = { + .halt_reg = 0xb13c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb13c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_soc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sys_tmr_clk = { + .halt_reg = 0xb0a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_sys_tmr_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc bps_gdsc = { + .gdscr = 0x6004, + .pd = { + .name = "bps_gdsc", + }, + .flags = HW_CTRL | POLL_CFG_GDSCR, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ipe_0_gdsc = { + .gdscr = 0x7004, + .pd = { + .name = "ipe_0_gdsc", + }, + .flags = HW_CTRL | POLL_CFG_GDSCR, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ipe_1_gdsc = { + .gdscr = 0x8004, + .pd = { + .name = "ipe_1_gdsc", + }, + .flags = HW_CTRL | POLL_CFG_GDSCR, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_0_gdsc = { + .gdscr = 0x9004, + .pd = { + .name = "ife_0_gdsc", + }, + .flags = POLL_CFG_GDSCR, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_1_gdsc = { + .gdscr = 0xa004, + .pd = { + .name = "ife_1_gdsc", + }, + .flags = POLL_CFG_GDSCR, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc titan_top_gdsc = { + .gdscr = 0xb134, + .pd = { + .name = "titan_top_gdsc", + }, + .flags = POLL_CFG_GDSCR, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct clk_regmap *cam_cc_sdm845_clocks[] = { + [CAM_CC_BPS_AHB_CLK] = &cam_cc_bps_ahb_clk.clkr, + [CAM_CC_BPS_AREG_CLK] = &cam_cc_bps_areg_clk.clkr, + [CAM_CC_BPS_AXI_CLK] = &cam_cc_bps_axi_clk.clkr, + [CAM_CC_BPS_CLK] = &cam_cc_bps_clk.clkr, + [CAM_CC_BPS_CLK_SRC] = &cam_cc_bps_clk_src.clkr, + [CAM_CC_CAMNOC_ATB_CLK] = &cam_cc_camnoc_atb_clk.clkr, + [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr, + [CAM_CC_CCI_CLK] = &cam_cc_cci_clk.clkr, + [CAM_CC_CCI_CLK_SRC] = &cam_cc_cci_clk_src.clkr, + [CAM_CC_CPAS_AHB_CLK] = &cam_cc_cpas_ahb_clk.clkr, + [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr, + [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr, + [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr, + [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr, + [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr, + [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr, + [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr, + [CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr, + [CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr, + [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr, + [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr, + [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr, + [CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr, + [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr, + [CAM_CC_FD_CORE_CLK] = &cam_cc_fd_core_clk.clkr, + [CAM_CC_FD_CORE_CLK_SRC] = &cam_cc_fd_core_clk_src.clkr, + [CAM_CC_FD_CORE_UAR_CLK] = &cam_cc_fd_core_uar_clk.clkr, + [CAM_CC_ICP_APB_CLK] = &cam_cc_icp_apb_clk.clkr, + [CAM_CC_ICP_ATB_CLK] = &cam_cc_icp_atb_clk.clkr, + [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr, + [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr, + [CAM_CC_ICP_CTI_CLK] = &cam_cc_icp_cti_clk.clkr, + [CAM_CC_ICP_TS_CLK] = &cam_cc_icp_ts_clk.clkr, + [CAM_CC_IFE_0_AXI_CLK] = &cam_cc_ife_0_axi_clk.clkr, + [CAM_CC_IFE_0_CLK] = &cam_cc_ife_0_clk.clkr, + [CAM_CC_IFE_0_CLK_SRC] = &cam_cc_ife_0_clk_src.clkr, + [CAM_CC_IFE_0_CPHY_RX_CLK] = &cam_cc_ife_0_cphy_rx_clk.clkr, + [CAM_CC_IFE_0_CSID_CLK] = &cam_cc_ife_0_csid_clk.clkr, + [CAM_CC_IFE_0_CSID_CLK_SRC] = &cam_cc_ife_0_csid_clk_src.clkr, + [CAM_CC_IFE_0_DSP_CLK] = &cam_cc_ife_0_dsp_clk.clkr, + [CAM_CC_IFE_1_AXI_CLK] = &cam_cc_ife_1_axi_clk.clkr, + [CAM_CC_IFE_1_CLK] = &cam_cc_ife_1_clk.clkr, + [CAM_CC_IFE_1_CLK_SRC] = &cam_cc_ife_1_clk_src.clkr, + [CAM_CC_IFE_1_CPHY_RX_CLK] = &cam_cc_ife_1_cphy_rx_clk.clkr, + [CAM_CC_IFE_1_CSID_CLK] = &cam_cc_ife_1_csid_clk.clkr, + [CAM_CC_IFE_1_CSID_CLK_SRC] = &cam_cc_ife_1_csid_clk_src.clkr, + [CAM_CC_IFE_1_DSP_CLK] = &cam_cc_ife_1_dsp_clk.clkr, + [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr, + [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr, + [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr, + [CAM_CC_IPE_0_AHB_CLK] = &cam_cc_ipe_0_ahb_clk.clkr, + [CAM_CC_IPE_0_AREG_CLK] = &cam_cc_ipe_0_areg_clk.clkr, + [CAM_CC_IPE_0_AXI_CLK] = &cam_cc_ipe_0_axi_clk.clkr, + [CAM_CC_IPE_0_CLK] = &cam_cc_ipe_0_clk.clkr, + [CAM_CC_IPE_0_CLK_SRC] = &cam_cc_ipe_0_clk_src.clkr, + [CAM_CC_IPE_1_AHB_CLK] = &cam_cc_ipe_1_ahb_clk.clkr, + [CAM_CC_IPE_1_AREG_CLK] = &cam_cc_ipe_1_areg_clk.clkr, + [CAM_CC_IPE_1_AXI_CLK] = &cam_cc_ipe_1_axi_clk.clkr, + [CAM_CC_IPE_1_CLK] = &cam_cc_ipe_1_clk.clkr, + [CAM_CC_IPE_1_CLK_SRC] = &cam_cc_ipe_1_clk_src.clkr, + [CAM_CC_JPEG_CLK] = &cam_cc_jpeg_clk.clkr, + [CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr, + [CAM_CC_LRME_CLK] = &cam_cc_lrme_clk.clkr, + [CAM_CC_LRME_CLK_SRC] = &cam_cc_lrme_clk_src.clkr, + [CAM_CC_MCLK0_CLK] = &cam_cc_mclk0_clk.clkr, + [CAM_CC_MCLK0_CLK_SRC] = &cam_cc_mclk0_clk_src.clkr, + [CAM_CC_MCLK1_CLK] = &cam_cc_mclk1_clk.clkr, + [CAM_CC_MCLK1_CLK_SRC] = &cam_cc_mclk1_clk_src.clkr, + [CAM_CC_MCLK2_CLK] = &cam_cc_mclk2_clk.clkr, + [CAM_CC_MCLK2_CLK_SRC] = &cam_cc_mclk2_clk_src.clkr, + [CAM_CC_MCLK3_CLK] = &cam_cc_mclk3_clk.clkr, + [CAM_CC_MCLK3_CLK_SRC] = &cam_cc_mclk3_clk_src.clkr, + [CAM_CC_PLL0] = &cam_cc_pll0.clkr, + [CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.clkr, + [CAM_CC_PLL1] = &cam_cc_pll1.clkr, + [CAM_CC_PLL1_OUT_EVEN] = &cam_cc_pll1_out_even.clkr, + [CAM_CC_PLL2] = &cam_cc_pll2.clkr, + [CAM_CC_PLL2_OUT_EVEN] = &cam_cc_pll2_out_even.clkr, + [CAM_CC_PLL3] = &cam_cc_pll3.clkr, + [CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr, + [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr, + [CAM_CC_SOC_AHB_CLK] = &cam_cc_soc_ahb_clk.clkr, + [CAM_CC_SYS_TMR_CLK] = &cam_cc_sys_tmr_clk.clkr, +}; + +static struct gdsc *cam_cc_sdm845_gdscs[] = { + [BPS_GDSC] = &bps_gdsc, + [IPE_0_GDSC] = &ipe_0_gdsc, + [IPE_1_GDSC] = &ipe_1_gdsc, + [IFE_0_GDSC] = &ife_0_gdsc, + [IFE_1_GDSC] = &ife_1_gdsc, + [TITAN_TOP_GDSC] = &titan_top_gdsc, +}; + +static const struct regmap_config cam_cc_sdm845_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xd004, + .fast_io = true, +}; + +static const struct qcom_cc_desc cam_cc_sdm845_desc = { + .config = &cam_cc_sdm845_regmap_config, + .clks = cam_cc_sdm845_clocks, + .num_clks = ARRAY_SIZE(cam_cc_sdm845_clocks), + .gdscs = cam_cc_sdm845_gdscs, + .num_gdscs = ARRAY_SIZE(cam_cc_sdm845_gdscs), +}; + +static const struct of_device_id cam_cc_sdm845_match_table[] = { + { .compatible = "qcom,sdm845-camcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, cam_cc_sdm845_match_table); + +static int cam_cc_sdm845_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + struct alpha_pll_config cam_cc_pll_config = { }; + + regmap = qcom_cc_map(pdev, &cam_cc_sdm845_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + cam_cc_pll_config.l = 0x1f; + cam_cc_pll_config.alpha = 0x4000; + clk_fabia_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll_config); + + cam_cc_pll_config.l = 0x2a; + cam_cc_pll_config.alpha = 0x1556; + clk_fabia_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll_config); + + cam_cc_pll_config.l = 0x32; + cam_cc_pll_config.alpha = 0x0; + clk_fabia_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll_config); + + cam_cc_pll_config.l = 0x14; + clk_fabia_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll_config); + + return qcom_cc_really_probe(pdev, &cam_cc_sdm845_desc, regmap); +} + +static struct platform_driver cam_cc_sdm845_driver = { + .probe = cam_cc_sdm845_probe, + .driver = { + .name = "sdm845-camcc", + .of_match_table = cam_cc_sdm845_match_table, + }, +}; + +static int __init cam_cc_sdm845_init(void) +{ + return platform_driver_register(&cam_cc_sdm845_driver); +} +subsys_initcall(cam_cc_sdm845_init); + +static void __exit cam_cc_sdm845_exit(void) +{ + platform_driver_unregister(&cam_cc_sdm845_driver); +} +module_exit(cam_cc_sdm845_exit); + +MODULE_DESCRIPTION("QTI CAM_CC SDM845 Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c @@ -220,6 +220,7 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, if (pll->flags & SUPPORTS_FSM_MODE) qcom_pll_set_fsm_mode(regmap, PLL_MODE(pll), 6, 0); } +EXPORT_SYMBOL_GPL(clk_alpha_pll_configure); static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw) { diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c @@ -18,7 +18,7 @@ static bool clk_branch_in_hwcg_mode(const struct clk_branch *br) u32 val; if (!br->hwcg_reg) - return 0; + return false; regmap_read(br->clkr.regmap, br->hwcg_reg, &val); diff --git a/drivers/clk/qcom/clk-hfpll.c b/drivers/clk/qcom/clk-hfpll.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, The Linux Foundation. All rights reserved. + +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/regmap.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk-provider.h> +#include <linux/spinlock.h> + +#include "clk-regmap.h" +#include "clk-hfpll.h" + +#define PLL_OUTCTRL BIT(0) +#define PLL_BYPASSNL BIT(1) +#define PLL_RESET_N BIT(2) + +/* Initialize a HFPLL at a given rate and enable it. */ +static void __clk_hfpll_init_once(struct clk_hw *hw) +{ + struct clk_hfpll *h = to_clk_hfpll(hw); + struct hfpll_data const *hd = h->d; + struct regmap *regmap = h->clkr.regmap; + + if (likely(h->init_done)) + return; + + /* Configure PLL parameters for integer mode. */ + if (hd->config_val) + regmap_write(regmap, hd->config_reg, hd->config_val); + regmap_write(regmap, hd->m_reg, 0); + regmap_write(regmap, hd->n_reg, 1); + + if (hd->user_reg) { + u32 regval = hd->user_val; + unsigned long rate; + + rate = clk_hw_get_rate(hw); + + /* Pick the right VCO. */ + if (hd->user_vco_mask && rate > hd->low_vco_max_rate) + regval |= hd->user_vco_mask; + regmap_write(regmap, hd->user_reg, regval); + } + + if (hd->droop_reg) + regmap_write(regmap, hd->droop_reg, hd->droop_val); + + h->init_done = true; +} + +static void __clk_hfpll_enable(struct clk_hw *hw) +{ + struct clk_hfpll *h = to_clk_hfpll(hw); + struct hfpll_data const *hd = h->d; + struct regmap *regmap = h->clkr.regmap; + u32 val; + + __clk_hfpll_init_once(hw); + + /* Disable PLL bypass mode. */ + regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL); + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. Delay 10us just to be safe. + */ + udelay(10); + + /* De-assert active-low PLL reset. */ + regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N); + + /* Wait for PLL to lock. */ + if (hd->status_reg) { + do { + regmap_read(regmap, hd->status_reg, &val); + } while (!(val & BIT(hd->lock_bit))); + } else { + udelay(60); + } + + /* Enable PLL output. */ + regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL); +} + +/* Enable an already-configured HFPLL. */ +static int clk_hfpll_enable(struct clk_hw *hw) +{ + unsigned long flags; + struct clk_hfpll *h = to_clk_hfpll(hw); + struct hfpll_data const *hd = h->d; + struct regmap *regmap = h->clkr.regmap; + u32 mode; + + spin_lock_irqsave(&h->lock, flags); + regmap_read(regmap, hd->mode_reg, &mode); + if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL))) + __clk_hfpll_enable(hw); + spin_unlock_irqrestore(&h->lock, flags); + + return 0; +} + +static void __clk_hfpll_disable(struct clk_hfpll *h) +{ + struct hfpll_data const *hd = h->d; + struct regmap *regmap = h->clkr.regmap; + + /* + * Disable the PLL output, disable test mode, enable the bypass mode, + * and assert the reset. + */ + regmap_update_bits(regmap, hd->mode_reg, + PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0); +} + +static void clk_hfpll_disable(struct clk_hw *hw) +{ + struct clk_hfpll *h = to_clk_hfpll(hw); + unsigned long flags; + + spin_lock_irqsave(&h->lock, flags); + __clk_hfpll_disable(h); + spin_unlock_irqrestore(&h->lock, flags); +} + +static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_hfpll *h = to_clk_hfpll(hw); + struct hfpll_data const *hd = h->d; + unsigned long rrate; + + rate = clamp(rate, hd->min_rate, hd->max_rate); + + rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate; + if (rrate > hd->max_rate) + rrate -= *parent_rate; + + return rrate; +} + +/* + * For optimization reasons, assumes no downstream clocks are actively using + * it. + */ +static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hfpll *h = to_clk_hfpll(hw); + struct hfpll_data const *hd = h->d; + struct regmap *regmap = h->clkr.regmap; + unsigned long flags; + u32 l_val, val; + bool enabled; + + l_val = rate / parent_rate; + + spin_lock_irqsave(&h->lock, flags); + + enabled = __clk_is_enabled(hw->clk); + if (enabled) + __clk_hfpll_disable(h); + + /* Pick the right VCO. */ + if (hd->user_reg && hd->user_vco_mask) { + regmap_read(regmap, hd->user_reg, &val); + if (rate <= hd->low_vco_max_rate) + val &= ~hd->user_vco_mask; + else + val |= hd->user_vco_mask; + regmap_write(regmap, hd->user_reg, val); + } + + regmap_write(regmap, hd->l_reg, l_val); + + if (enabled) + __clk_hfpll_enable(hw); + + spin_unlock_irqrestore(&h->lock, flags); + + return 0; +} + +static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_hfpll *h = to_clk_hfpll(hw); + struct hfpll_data const *hd = h->d; + struct regmap *regmap = h->clkr.regmap; + u32 l_val; + + regmap_read(regmap, hd->l_reg, &l_val); + + return l_val * parent_rate; +} + +static void clk_hfpll_init(struct clk_hw *hw) +{ + struct clk_hfpll *h = to_clk_hfpll(hw); + struct hfpll_data const *hd = h->d; + struct regmap *regmap = h->clkr.regmap; + u32 mode, status; + + regmap_read(regmap, hd->mode_reg, &mode); + if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) { + __clk_hfpll_init_once(hw); + return; + } + + if (hd->status_reg) { + regmap_read(regmap, hd->status_reg, &status); + if (!(status & BIT(hd->lock_bit))) { + WARN(1, "HFPLL %s is ON, but not locked!\n", + __clk_get_name(hw->clk)); + clk_hfpll_disable(hw); + __clk_hfpll_init_once(hw); + } + } +} + +static int hfpll_is_enabled(struct clk_hw *hw) +{ + struct clk_hfpll *h = to_clk_hfpll(hw); + struct hfpll_data const *hd = h->d; + struct regmap *regmap = h->clkr.regmap; + u32 mode; + + regmap_read(regmap, hd->mode_reg, &mode); + mode &= 0x7; + return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL); +} + +const struct clk_ops clk_ops_hfpll = { + .enable = clk_hfpll_enable, + .disable = clk_hfpll_disable, + .is_enabled = hfpll_is_enabled, + .round_rate = clk_hfpll_round_rate, + .set_rate = clk_hfpll_set_rate, + .recalc_rate = clk_hfpll_recalc_rate, + .init = clk_hfpll_init, +}; +EXPORT_SYMBOL_GPL(clk_ops_hfpll); diff --git a/drivers/clk/qcom/clk-hfpll.h b/drivers/clk/qcom/clk-hfpll.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __QCOM_CLK_HFPLL_H__ +#define __QCOM_CLK_HFPLL_H__ + +#include <linux/clk-provider.h> +#include <linux/spinlock.h> +#include "clk-regmap.h" + +struct hfpll_data { + u32 mode_reg; + u32 l_reg; + u32 m_reg; + u32 n_reg; + u32 user_reg; + u32 droop_reg; + u32 config_reg; + u32 status_reg; + u8 lock_bit; + + u32 droop_val; + u32 config_val; + u32 user_val; + u32 user_vco_mask; + unsigned long low_vco_max_rate; + + unsigned long min_rate; + unsigned long max_rate; +}; + +struct clk_hfpll { + struct hfpll_data const *d; + int init_done; + + struct clk_regmap clkr; + spinlock_t lock; +}; + +#define to_clk_hfpll(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr) + +extern const struct clk_ops clk_ops_hfpll; + +#endif diff --git a/drivers/clk/qcom/clk-krait.c b/drivers/clk/qcom/clk-krait.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, The Linux Foundation. All rights reserved. + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk-provider.h> +#include <linux/spinlock.h> + +#include <asm/krait-l2-accessors.h> + +#include "clk-krait.h" + +/* Secondary and primary muxes share the same cp15 register */ +static DEFINE_SPINLOCK(krait_clock_reg_lock); + +#define LPL_SHIFT 8 +static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel) +{ + unsigned long flags; + u32 regval; + + spin_lock_irqsave(&krait_clock_reg_lock, flags); + regval = krait_get_l2_indirect_reg(mux->offset); + regval &= ~(mux->mask << mux->shift); + regval |= (sel & mux->mask) << mux->shift; + if (mux->lpl) { + regval &= ~(mux->mask << (mux->shift + LPL_SHIFT)); + regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT); + } + krait_set_l2_indirect_reg(mux->offset, regval); + spin_unlock_irqrestore(&krait_clock_reg_lock, flags); + + /* Wait for switch to complete. */ + mb(); + udelay(1); +} + +static int krait_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct krait_mux_clk *mux = to_krait_mux_clk(hw); + u32 sel; + + sel = clk_mux_index_to_val(mux->parent_map, 0, index); + mux->en_mask = sel; + /* Don't touch mux if CPU is off as it won't work */ + if (__clk_is_enabled(hw->clk)) + __krait_mux_set_sel(mux, sel); + + mux->reparent = true; + + return 0; +} + +static u8 krait_mux_get_parent(struct clk_hw *hw) +{ + struct krait_mux_clk *mux = to_krait_mux_clk(hw); + u32 sel; + + sel = krait_get_l2_indirect_reg(mux->offset); + sel >>= mux->shift; + sel &= mux->mask; + mux->en_mask = sel; + + return clk_mux_val_to_index(hw, mux->parent_map, 0, sel); +} + +const struct clk_ops krait_mux_clk_ops = { + .set_parent = krait_mux_set_parent, + .get_parent = krait_mux_get_parent, + .determine_rate = __clk_mux_determine_rate_closest, +}; +EXPORT_SYMBOL_GPL(krait_mux_clk_ops); + +/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */ +static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2); + return DIV_ROUND_UP(*parent_rate, 2); +} + +static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct krait_div2_clk *d = to_krait_div2_clk(hw); + unsigned long flags; + u32 val; + u32 mask = BIT(d->width) - 1; + + if (d->lpl) + mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift; + + spin_lock_irqsave(&krait_clock_reg_lock, flags); + val = krait_get_l2_indirect_reg(d->offset); + val &= ~mask; + krait_set_l2_indirect_reg(d->offset, val); + spin_unlock_irqrestore(&krait_clock_reg_lock, flags); + + return 0; +} + +static unsigned long +krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct krait_div2_clk *d = to_krait_div2_clk(hw); + u32 mask = BIT(d->width) - 1; + u32 div; + + div = krait_get_l2_indirect_reg(d->offset); + div >>= d->shift; + div &= mask; + div = (div + 1) * 2; + + return DIV_ROUND_UP(parent_rate, div); +} + +const struct clk_ops krait_div2_clk_ops = { + .round_rate = krait_div2_round_rate, + .set_rate = krait_div2_set_rate, + .recalc_rate = krait_div2_recalc_rate, +}; +EXPORT_SYMBOL_GPL(krait_div2_clk_ops); diff --git a/drivers/clk/qcom/clk-krait.h b/drivers/clk/qcom/clk-krait.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __QCOM_CLK_KRAIT_H +#define __QCOM_CLK_KRAIT_H + +#include <linux/clk-provider.h> + +struct krait_mux_clk { + unsigned int *parent_map; + u32 offset; + u32 mask; + u32 shift; + u32 en_mask; + bool lpl; + u8 safe_sel; + u8 old_index; + bool reparent; + + struct clk_hw hw; + struct notifier_block clk_nb; +}; + +#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw) + +extern const struct clk_ops krait_mux_clk_ops; + +struct krait_div2_clk { + u32 offset; + u8 width; + u32 shift; + bool lpl; + + struct clk_hw hw; +}; + +#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw) + +extern const struct clk_ops krait_div2_clk_ops; + +#endif diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h @@ -163,4 +163,15 @@ extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; +struct clk_rcg_dfs_data { + struct clk_rcg2 *rcg; + struct clk_init_data *init; +}; + +#define DEFINE_RCG_DFS(r) \ + { .rcg = &r##_src, .init = &r##_init } + +extern int qcom_cc_register_rcg_dfs(struct regmap *regmap, + const struct clk_rcg_dfs_data *rcgs, + size_t len); #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c @@ -12,6 +12,7 @@ #include <linux/delay.h> #include <linux/regmap.h> #include <linux/math64.h> +#include <linux/slab.h> #include <asm/div64.h> @@ -40,6 +41,14 @@ #define N_REG 0xc #define D_REG 0x10 +/* Dynamic Frequency Scaling */ +#define MAX_PERF_LEVEL 8 +#define SE_CMD_DFSR_OFFSET 0x14 +#define SE_CMD_DFS_EN BIT(0) +#define SE_PERF_DFSR(level) (0x1c + 0x4 * (level)) +#define SE_PERF_M_DFSR(level) (0x5c + 0x4 * (level)) +#define SE_PERF_N_DFSR(level) (0x9c + 0x4 * (level)) + enum freq_policy { FLOOR, CEIL, @@ -929,3 +938,189 @@ const struct clk_ops clk_rcg2_shared_ops = { .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, }; EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); + +/* Common APIs to be used for DFS based RCGR */ +static void clk_rcg2_dfs_populate_freq(struct clk_hw *hw, unsigned int l, + struct freq_tbl *f) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct clk_hw *p; + unsigned long prate = 0; + u32 val, mask, cfg, mode; + int i, num_parents; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(l), &cfg); + + mask = BIT(rcg->hid_width) - 1; + f->pre_div = 1; + if (cfg & mask) + f->pre_div = cfg & mask; + + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + num_parents = clk_hw_get_num_parents(hw); + for (i = 0; i < num_parents; i++) { + if (cfg == rcg->parent_map[i].cfg) { + f->src = rcg->parent_map[i].src; + p = clk_hw_get_parent_by_index(&rcg->clkr.hw, i); + prate = clk_hw_get_rate(p); + } + } + + mode = cfg & CFG_MODE_MASK; + mode >>= CFG_MODE_SHIFT; + if (mode) { + mask = BIT(rcg->mnd_width) - 1; + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_M_DFSR(l), + &val); + val &= mask; + f->m = val; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_N_DFSR(l), + &val); + val = ~val; + val &= mask; + val += f->m; + f->n = val; + } + + f->freq = calc_rate(prate, f->m, f->n, mode, f->pre_div); +} + +static int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg) +{ + struct freq_tbl *freq_tbl; + int i; + + /* Allocate space for 1 extra since table is NULL terminated */ + freq_tbl = kcalloc(MAX_PERF_LEVEL + 1, sizeof(*freq_tbl), GFP_KERNEL); + if (!freq_tbl) + return -ENOMEM; + rcg->freq_tbl = freq_tbl; + + for (i = 0; i < MAX_PERF_LEVEL; i++) + clk_rcg2_dfs_populate_freq(&rcg->clkr.hw, i, freq_tbl + i); + + return 0; +} + +static int clk_rcg2_dfs_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + int ret; + + if (!rcg->freq_tbl) { + ret = clk_rcg2_dfs_populate_freq_table(rcg); + if (ret) { + pr_err("Failed to update DFS tables for %s\n", + clk_hw_get_name(hw)); + return ret; + } + } + + return clk_rcg2_determine_rate(hw, req); +} + +static unsigned long +clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + u32 level, mask, cfg, m = 0, n = 0, mode, pre_div; + + regmap_read(rcg->clkr.regmap, + rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level); + level &= GENMASK(4, 1); + level >>= 1; + + if (rcg->freq_tbl) + return rcg->freq_tbl[level].freq; + + /* </