This round is dominated by NXP's i.MX clk drivers. We gained support for two or

three i.MX SoCs in here and that mostly means a lot of driver code and data.
 Beyond that platform, there are some new Mediatek, Amlogic, and Qualcomm clk
 drivers added in here, and then we get to the long tail of driver updates and
 non-critical fixes all around, including code for vendors such as Renesas,
 Rockchip, Nvidia, and Allwinner. Overall, the driver updates look normal.
 
 Beyond the usual driver updates we have an update to make registering OF based
 clk providers a little simpler when they're devices created as a child of a
 device backed by a node in DT. Drivers don't have to jump through hoops to
 unregister the provider upon driver removal anymore because the API does the
 right thing and uses the parent device DT node.
 
 Core:
  - Make devm_of_clk_add_hw_provider() use parent dt node if necessary
  - Various SPDX taggings
  - Mark clk_ops const when possible
 
 New Drivers:
  - NXP i.MX7ULP SoC clock support
  - NXP i.MX8QXP SoC clock support
  - NXP i.MX8MQ SoC clock support
  - NXP QorIQ T1023 SoC support
  - Qualcomm SDM845 audio subsystem clks
  - Qualcomm SDM845 GPU clck controllers
  - Qualcomm QCS404 RPM clk support
  - Mediatek MT7629 SoC clk controllers
  - Allwinner F1c100s SoC clocks
  - Allwinner H6 display engine clocks
  - Amlogic GX video clocks
  - Support for Amlogic meson8b CPU frequency scaling
  - Amlogic Meson8b CPU post-divider clocks
 
 Updates:
  - Proper suspend/resume on VersaClock5
  - Shrink code some with DEFINE_SHOW_ATTRIBUTE()
  - Register fixes for Rockchip rk3188 and rk3328
  - One new critical clock for Rockchip rk3188 and a fixed clock id (double used number)
  - New clock id for Rockchip rk3328
  - Amlogic Meson8/Meson8b video clock support
  - Amlogic got a clk-input helper and used it for the axg-audio clock driver
  - Sigma Delta modulation for the Allwinner A33 audio clocks
  - Support for CPEX (timer) clocks on various Renesas R-Car Gen3 and RZ/G2 SoCs
  - Support for SDHI HS400 clocks on early revisions of Renesas R-Car H3 and M3-W
  - Support for SDHI and USB clocks on Renesas RZ/A2
  - Support for RPC (SPI Multi I/O Bus Controller) clocks on Renesas R-Car V3M
  - Qualcomm MSM8998 GCC driver improvements (resets, drop unused clks, etc.)
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAlwZeqgRHHNib3lkQGtl
 cm5lbC5vcmcACgkQrQKIl8bklSU7qA/8C7p4EL36zkFFHhF6wh9+CiLIcTt1OKEu
 ePgTo0UP9Q94BzHy0SOZhwV6w6yqeOfTXCAYZWdV2UcNKyPDPlIMZPkxrNbH5twq
 kptjuBS1FqnnMgfusUP88bUrhQ5hUGEaKaC4iCDK7s0YI4nBfVB28G5ZMbFTSE5L
 hrIufRfZ0aQWQw6y8aGI4qDtUeg09s6cEwFw8cA+vArAJ+2hwv0zjFGMxQskNJ6N
 JubPopVCWuP+jsqMrGP48Rg4BphSQ97h4B65Uj0BNPQ4HTIMLVvXX6Pr8sRGvKiO
 IMsNQq+fS+ECmdcV7IUzSv14cX2mLCb9XWgfCnWEK67/Ny3deaurtzF0qloWnrtv
 kFSDE4df5cJkMkK2HZF8/e0/qn0FbGP6/wDSwfdhuVuJPmfdF5m552TtQuehNHey
 YNy/pIY4sCh0zCkeU212TFKvAaRLd8qVqh2nikn3Cs7ik0G5Bhv2GAqQmIGJEh6g
 f3n/WLTzVUqFksPC5KRZHu/1UIe4sz8i14AZXmxvCyH8buLSznhoniB0wwRrQdLL
 VcJ2ia4b4e4JBJg1A5b9IqfEliJBNUV0UZTakduXBnThBpXQeH0t6YesXNaPqKaM
 qJKvaQbNk0FNFsIO4GHxwrmujrf8SrHdhWuf/rh5O6mfOiXnNTzFcLZ59+nx86Bh
 3sUFruRiDx8=
 =iNvu
 -----END PGP SIGNATURE-----

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

Pull clk updates from Stephen Boyd:
 "This round is dominated by NXP's i.MX clk drivers. We gained support
  for two or three i.MX SoCs in here and that mostly means a lot of
  driver code and data.

  Beyond that platform, there are some new Mediatek, Amlogic, and
  Qualcomm clk drivers added in here, and then we get to the long tail
  of driver updates and non-critical fixes all around, including code
  for vendors such as Renesas, Rockchip, Nvidia, and Allwinner. Overall,
  the driver updates look normal.

  Apart from the usual driver updates we have an update to make
  registering OF based clk providers a little simpler when they're
  devices created as a child of a device backed by a node in DT. Drivers
  don't have to jump through hoops to unregister the provider upon
  driver removal anymore because the API does the right thing and uses
  the parent device DT node.

  Summary:

  Core:
   - Make devm_of_clk_add_hw_provider() use parent dt node if necessary
   - Various SPDX taggings
   - Mark clk_ops const when possible

  New Drivers:
   - NXP i.MX7ULP SoC clock support
   - NXP i.MX8QXP SoC clock support
   - NXP i.MX8MQ SoC clock support
   - NXP QorIQ T1023 SoC support
   - Qualcomm SDM845 audio subsystem clks
   - Qualcomm SDM845 GPU clck controllers
   - Qualcomm QCS404 RPM clk support
   - Mediatek MT7629 SoC clk controllers
   - Allwinner F1c100s SoC clocks
   - Allwinner H6 display engine clocks
   - Amlogic GX video clocks
   - Support for Amlogic meson8b CPU frequency scaling
   - Amlogic Meson8b CPU post-divider clocks

  Updates:
   - Proper suspend/resume on VersaClock5
   - Shrink code some with DEFINE_SHOW_ATTRIBUTE()
   - Register fixes for Rockchip rk3188 and rk3328
   - One new critical clock for Rockchip rk3188 and a fixed clock id
     (double used number)
   - New clock id for Rockchip rk3328
   - Amlogic Meson8/Meson8b video clock support
   - Amlogic got a clk-input helper and used it for the axg-audio clock
     driver
   - Sigma Delta modulation for the Allwinner A33 audio clocks
   - Support for CPEX (timer) clocks on various Renesas R-Car Gen3 and
     RZ/G2 SoCs
   - Support for SDHI HS400 clocks on early revisions of Renesas R-Car
     H3 and M3-W
   - Support for SDHI and USB clocks on Renesas RZ/A2
   - Support for RPC (SPI Multi I/O Bus Controller) clocks on Renesas
     R-Car V3M
   - Qualcomm MSM8998 GCC driver improvements (resets, drop unused clks,
     etc)"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (172 commits)
  clk: imx: imx7ulp: add arm hsrun mode clocks support
  dt-bindings: clock: imx7ulp: add HSRUN mode related clocks
  clk: Use of_node_name_eq for node name comparisons
  clk: vc5: Add suspend/resume support
  clk: qcom: Drop unused 8998 clock
  clk: qcom: Leave mmss noc on for 8998
  clk: tegra: Return the exact clock rate from clk_round_rate
  clk: tegra30: Use Tegra CPU powergate helper function
  soc/tegra: pmc: Drop SMP dependency from CPU APIs
  clk: tegra: Fix maximum audio sync clock for Tegra124/210
  clk: tegra: get rid of duplicate defines
  clk: imx: add imx8qxp lpcg driver
  clk: imx: add lpcg clock support
  clk: imx: add imx8qxp clk driver
  clk: imx: Make the i.MX8MQ CCM clock driver CLK_IMX8MQ dependant
  clk: imx: add scu clock common part
  clk: imx: add configuration option for mmio clks
  dt-bindings: clock: add imx8qxp lpcg clock binding
  dt-bindings: clock: imx8qxp: add SCU clock IDs
  clk: qcom: Add missing msm8998 resets
  ...
This commit is contained in:
Linus Torvalds 2018-12-25 14:57:37 -08:00
commit 1fbb2dc6f0
190 changed files with 10837 additions and 1189 deletions

View file

@ -58,19 +58,11 @@ This binding for the SCU power domain providers uses the generic power
domain binding[2].
Required properties:
- compatible: Should be "fsl,scu-pd".
- #address-cells: Should be 1.
- #size-cells: Should be 0.
Required properties for power domain sub nodes:
- #power-domain-cells: Must be 0.
Optional Properties:
- reg: Resource ID of this power domain.
No exist means uncontrollable by user.
- compatible: Should be "fsl,imx8qxp-scu-pd".
- #power-domain-cells: Must be 1. Contains the Resource ID used by
SCU commands.
See detailed Resource ID list from:
include/dt-bindings/power/imx-rsrc.h
- power-domains: phandle pointing to the parent power domain.
include/dt-bindings/firmware/imx/rsrc.h
Clock bindings based on SCU Message Protocol
------------------------------------------------------------
@ -152,22 +144,9 @@ firmware {
...
};
imx8qx-pm {
compatible = "fsl,scu-pd";
#address-cells = <1>;
#size-cells = <0>;
pd_dma: dma-power-domain {
#power-domain-cells = <0>;
pd_dma_lpuart0: dma-lpuart0@57 {
reg = <SC_R_UART_0>;
#power-domain-cells = <0>;
power-domains = <&pd_dma>;
};
...
};
...
pd: imx8qx-pd {
compatible = "fsl,imx8qxp-scu-pd";
#power-domain-cells = <1>;
};
};
};
@ -179,5 +158,5 @@ serial@5a060000 {
clocks = <&clk IMX8QXP_UART0_CLK>,
<&clk IMX8QXP_UART0_IPG_CLK>;
clock-names = "per", "ipg";
power-domains = <&pd_dma_lpuart0>;
power-domains = <&pd IMX_SC_R_UART_0>;
};

View file

@ -11,6 +11,7 @@ Required Properties:
- "mediatek,mt6797-apmixedsys"
- "mediatek,mt7622-apmixedsys"
- "mediatek,mt7623-apmixedsys", "mediatek,mt2701-apmixedsys"
- "mediatek,mt7629-apmixedsys"
- "mediatek,mt8135-apmixedsys"
- "mediatek,mt8173-apmixedsys"
- #clock-cells: Must be 1

View file

@ -9,6 +9,7 @@ Required Properties:
- "mediatek,mt2701-ethsys", "syscon"
- "mediatek,mt7622-ethsys", "syscon"
- "mediatek,mt7623-ethsys", "mediatek,mt2701-ethsys", "syscon"
- "mediatek,mt7629-ethsys", "syscon"
- #clock-cells: Must be 1
- #reset-cells: Must be 1

View file

@ -12,6 +12,7 @@ Required Properties:
- "mediatek,mt6797-infracfg", "syscon"
- "mediatek,mt7622-infracfg", "syscon"
- "mediatek,mt7623-infracfg", "mediatek,mt2701-infracfg", "syscon"
- "mediatek,mt7629-infracfg", "syscon"
- "mediatek,mt8135-infracfg", "syscon"
- "mediatek,mt8173-infracfg", "syscon"
- #clock-cells: Must be 1

View file

@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be:
- "mediatek,mt7622-pciesys", "syscon"
- "mediatek,mt7629-pciesys", "syscon"
- #clock-cells: Must be 1
- #reset-cells: Must be 1

View file

@ -11,6 +11,7 @@ Required Properties:
- "mediatek,mt2712-pericfg", "syscon"
- "mediatek,mt7622-pericfg", "syscon"
- "mediatek,mt7623-pericfg", "mediatek,mt2701-pericfg", "syscon"
- "mediatek,mt7629-pericfg", "syscon"
- "mediatek,mt8135-pericfg", "syscon"
- "mediatek,mt8173-pericfg", "syscon"
- #clock-cells: Must be 1

View file

@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be:
- "mediatek,mt7622-sgmiisys", "syscon"
- "mediatek,mt7629-sgmiisys", "syscon"
- #clock-cells: Must be 1
The SGMIISYS controller uses the common clk binding from

View file

@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be:
- "mediatek,mt7622-ssusbsys", "syscon"
- "mediatek,mt7629-ssusbsys", "syscon"
- #clock-cells: Must be 1
- #reset-cells: Must be 1

View file

@ -11,6 +11,7 @@ Required Properties:
- "mediatek,mt6797-topckgen"
- "mediatek,mt7622-topckgen"
- "mediatek,mt7623-topckgen", "mediatek,mt2701-topckgen"
- "mediatek,mt7629-topckgen"
- "mediatek,mt8135-topckgen"
- "mediatek,mt8173-topckgen"
- #clock-cells: Must be 1

View file

@ -9,15 +9,13 @@ Required Properties:
- "amlogic,meson8-clkc" for Meson8 (S802) SoCs
- "amlogic,meson8b-clkc" for Meson8 (S805) SoCs
- "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs
- reg: it must be composed by two tuples:
0) physical base address of the xtal register and length of memory
mapped region.
1) physical base address of the clock controller and length of memory
mapped region.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Parent node should have the following properties :
- compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon"
- reg: base address and size of the HHI system control register space.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/meson8b-clkc.h header and can be
@ -30,9 +28,8 @@ device tree sources).
Example: Clock controller node:
clkc: clock-controller@c1104000 {
clkc: clock-controller {
compatible = "amlogic,meson8b-clkc";
reg = <0xc1108000 0x4>, <0xc1104000 0x460>;
#clock-cells = <1>;
#reset-cells = <1>;
};

View file

@ -13,6 +13,9 @@ Optional properties:
management IC (PMIC) triggered via PMIC_STBY_REQ signal.
Boards that are designed to initiate poweroff on PMIC_ON_REQ signal should
be using "syscon-poweroff" driver instead.
- clocks: list of clock specifiers, must contain an entry for each entry
in clock-names
- clock-names: valid names are "osc", "ckil", "ckih1", "anaclk1" and "anaclk2"
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6qdl-clock.h

View file

@ -0,0 +1,104 @@
* Clock bindings for Freescale i.MX7ULP
i.MX7ULP Clock functions are under joint control of the System
Clock Generation (SCG) modules, Peripheral Clock Control (PCC)
modules, and Core Mode Controller (CMC)1 blocks
The clocking scheme provides clear separation between M4 domain
and A7 domain. Except for a few clock sources shared between two
domains, such as the System Oscillator clock, the Slow IRC (SIRC),
and and the Fast IRC clock (FIRCLK), clock sources and clock
management are separated and contained within each domain.
M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules.
A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules.
Note: this binding doc is only for A7 clock domain.
System Clock Generation (SCG) modules:
---------------------------------------------------------------------
The System Clock Generation (SCG) is responsible for clock generation
and distribution across this device. Functions performed by the SCG
include: clock reference selection, generation of clock used to derive
processor, system, peripheral bus and external memory interface clocks,
source selection for peripheral clocks and control of power saving
clock gating mode.
Required properties:
- compatible: Should be "fsl,imx7ulp-scg1".
- reg : Should contain registers location and length.
- #clock-cells: Should be <1>.
- clocks: Should contain the fixed input clocks.
- clock-names: Should contain the following clock names:
"rosc", "sosc", "sirc", "firc", "upll", "mpll".
Peripheral Clock Control (PCC) modules:
---------------------------------------------------------------------
The Peripheral Clock Control (PCC) is responsible for clock selection,
optional division and clock gating mode for peripherals in their
respected power domain
Required properties:
- compatible: Should be one of:
"fsl,imx7ulp-pcc2",
"fsl,imx7ulp-pcc3".
- reg : Should contain registers location and length.
- #clock-cells: Should be <1>.
- clocks: Should contain the fixed input clocks.
- clock-names: Should contain the following clock names:
"nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2",
"apll_pfd1", "apll_pfd0", "upll", "sosc_bus_clk",
"mpll", "firc_bus_clk", "rosc", "spll_bus_clk";
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell.
See include/dt-bindings/clock/imx7ulp-clock.h
for the full list of i.MX7ULP clock IDs of each module.
Examples:
#include <dt-bindings/clock/imx7ulp-clock.h>
scg1: scg1@403e0000 {
compatible = "fsl,imx7ulp-scg1;
reg = <0x403e0000 0x10000>;
clocks = <&rosc>, <&sosc>, <&sirc>,
<&firc>, <&upll>, <&mpll>;
clock-names = "rosc", "sosc", "sirc",
"firc", "upll", "mpll";
#clock-cells = <1>;
};
pcc2: pcc2@403f0000 {
compatible = "fsl,imx7ulp-pcc2";
reg = <0x403f0000 0x10000>;
#clock-cells = <1>;
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
<&scg1 IMX7ULP_CLK_DDR_DIV>,
<&scg1 IMX7ULP_CLK_APLL_PFD2>,
<&scg1 IMX7ULP_CLK_APLL_PFD1>,
<&scg1 IMX7ULP_CLK_APLL_PFD0>,
<&scg1 IMX7ULP_CLK_UPLL>,
<&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
<&scg1 IMX7ULP_CLK_MIPI_PLL>,
<&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
<&scg1 IMX7ULP_CLK_ROSC>,
<&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk",
"apll_pfd2", "apll_pfd1", "apll_pfd0",
"upll", "sosc_bus_clk", "mpll",
"firc_bus_clk", "rosc", "spll_bus_clk";
};
usdhc1: usdhc@40380000 {
compatible = "fsl,imx7ulp-usdhc";
reg = <0x40380000 0x10000>;
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
<&pcc2 IMX7ULP_CLK_USDHC1>;
clock-names ="ipg", "ahb", "per";
bus-width = <4>;
};

View file

@ -0,0 +1,20 @@
* Clock bindings for NXP i.MX8M Quad
Required properties:
- compatible: Should be "fsl,imx8mq-ccm"
- reg: Address and length of the register set
- #clock-cells: Should be <1>
- clocks: list of clock specifiers, must contain an entry for each required
entry in clock-names
- clock-names: should include the following entries:
- "ckil"
- "osc_25m"
- "osc_27m"
- "clk_ext1"
- "clk_ext2"
- "clk_ext3"
- "clk_ext4"
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h
for the full list of i.MX8M Quad clock IDs.

View file

@ -0,0 +1,51 @@
* NXP i.MX8QXP LPCG (Low-Power Clock Gating) Clock bindings
The Low-Power Clock Gate (LPCG) modules contain a local programming
model to control the clock gates for the peripherals. An LPCG module
is used to locally gate the clocks for the associated peripheral.
Note:
This level of clock gating is provided after the clocks are generated
by the SCU resources and clock controls. Thus even if the clock is
enabled by these control bits, it might still not be running based
on the base resource.
Required properties:
- compatible: Should be one of:
"fsl,imx8qxp-lpcg-adma",
"fsl,imx8qxp-lpcg-conn",
"fsl,imx8qxp-lpcg-dc",
"fsl,imx8qxp-lpcg-dsp",
"fsl,imx8qxp-lpcg-gpu",
"fsl,imx8qxp-lpcg-hsio",
"fsl,imx8qxp-lpcg-img",
"fsl,imx8qxp-lpcg-lsio",
"fsl,imx8qxp-lpcg-vpu"
- reg: Address and length of the register set
- #clock-cells: Should be <1>
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell.
See the full list of clock IDs from:
include/dt-bindings/clock/imx8qxp-clock.h
Examples:
#include <dt-bindings/clock/imx8qxp-clock.h>
conn_lpcg: clock-controller@5b200000 {
compatible = "fsl,imx8qxp-lpcg-conn";
reg = <0x5b200000 0xb0000>;
#clock-cells = <1>;
};
usdhc1: mmc@5b010000 {
compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc";
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 232 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x5b010000 0x10000>;
clocks = <&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_IPG_CLK>,
<&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_PER_CLK>,
<&conn_lpcg IMX8QXP_CONN_LPCG_SDHC0_HCLK>;
clock-names = "ipg", "per", "ahb";
};

View file

@ -35,6 +35,8 @@ be part of GCC and hence the TSENS properties can also be
part of the GCC/clock-controller node.
For more details on the TSENS properties please refer
Documentation/devicetree/bindings/thermal/qcom-tsens.txt
- protected-clocks : Protected clock specifier list as per common clock
binding.
Example:
clock-controller@900000 {
@ -55,3 +57,17 @@ Example of GCC with TSENS properties:
#reset-cells = <1>;
#thermal-sensor-cells = <1>;
};
Example of GCC with protected-clocks properties:
clock-controller@100000 {
compatible = "qcom,gcc-sdm845";
reg = <0x100000 0x1f0000>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
protected-clocks = <GCC_QSPI_CORE_CLK>,
<GCC_QSPI_CORE_CLK_SRC>,
<GCC_QSPI_CNOC_PERIPH_AHB_CLK>,
<GCC_LPASS_Q6_AXI_CLK>,
<GCC_LPASS_SWAY_CLK>;
};

View file

@ -0,0 +1,22 @@
Qualcomm Graphics Clock & Reset Controller Binding
--------------------------------------------------
Required properties :
- compatible : shall contain "qcom,sdm845-gpucc"
- 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
- clocks : shall contain the XO clock
- clock-names : shall be "xo"
Example:
gpucc: clock-controller@5090000 {
compatible = "qcom,sdm845-gpucc";
reg = <0x5090000 0x9000>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
clocks = <&rpmhcc RPMH_CXO_CLK>;
clock-names = "xo";
};

View file

@ -0,0 +1,26 @@
Qualcomm LPASS Clock Controller Binding
-----------------------------------------------
Required properties :
- compatible : shall contain "qcom,sdm845-lpasscc"
- #clock-cells : from common clock binding, shall contain 1.
- reg : shall contain base register address and size,
in the order
Index-0 maps to LPASS_CC register region
Index-1 maps to LPASS_QDSP6SS register region
Optional properties :
- reg-names : register names of LPASS domain
"cc", "qdsp6ss".
Example:
The below node has to be defined in the cases where the LPASS peripheral loader
would bring the subsystem out of reset.
lpasscc: clock-controller@17014000 {
compatible = "qcom,sdm845-lpasscc";
reg = <0x17014000 0x1f004>, <0x17300000 0x200>;
reg-names = "cc", "qdsp6ss";
#clock-cells = <1>;
};

View file

@ -16,6 +16,7 @@ Required properties :
"qcom,rpmcc-msm8974", "qcom,rpmcc"
"qcom,rpmcc-apq8064", "qcom,rpmcc"
"qcom,rpmcc-msm8996", "qcom,rpmcc"
"qcom,rpmcc-qcs404", "qcom,rpmcc"
- #clock-cells : shall contain 1

View file

@ -6,8 +6,6 @@ Required properties :
- reg : shall contain base register location and length
- #clock-cells : from common clock binding, shall contain 1.
- #power-domain-cells : from generic power domain binding, shall contain 1.
Optional properties :
- #reset-cells : from common reset binding, shall contain 1.
Example:
@ -16,4 +14,5 @@ Example:
reg = <0xab00000 0x10000>;
#clock-cells = <1>;
#power-domain-cells = <1>;
#reset-cells = <1>;
};

View file

@ -1,5 +1,5 @@
Allwinner Display Engine 2.0 Clock Control Binding
--------------------------------------------------
Allwinner Display Engine 2.0/3.0 Clock Control Binding
------------------------------------------------------
Required properties :
- compatible: must contain one of the following compatibles:
@ -8,6 +8,7 @@ Required properties :
- "allwinner,sun8i-v3s-de2-clk"
- "allwinner,sun50i-a64-de2-clk"
- "allwinner,sun50i-h5-de2-clk"
- "allwinner,sun50i-h6-de3-clk"
- reg: Must contain the registers base address and length
- clocks: phandle to the clocks feeding the display engine subsystem.

View file

@ -22,6 +22,7 @@ Required properties :
- "allwinner,sun50i-h5-ccu"
- "allwinner,sun50i-h6-ccu"
- "allwinner,sun50i-h6-r-ccu"
- "allwinner,suniv-f1c100s-ccu"
- "nextthing,gr8-ccu"
- reg: Must contain the registers base address and length

View file

@ -283,10 +283,19 @@ config COMMON_CLK_STM32H7
---help---
Support for stm32h7 SoC family clocks
config COMMON_CLK_BD718XX
tristate "Clock driver for ROHM BD718x7 PMIC"
depends on MFD_ROHM_BD718XX
help
This driver supports ROHM BD71837 and ROHM BD71847
PMICs clock gates.
source "drivers/clk/actions/Kconfig"
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imx/Kconfig"
source "drivers/clk/imgtec/Kconfig"
source "drivers/clk/imx/Kconfig"
source "drivers/clk/ingenic/Kconfig"
source "drivers/clk/keystone/Kconfig"
source "drivers/clk/mediatek/Kconfig"

View file

@ -21,6 +21,7 @@ endif
obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_COMMON_CLK_BD718XX) += clk-bd718x7.o
obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
@ -71,7 +72,7 @@ obj-$(CONFIG_ARCH_DAVINCI) += davinci/
obj-$(CONFIG_H8300) += h8300/
obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-y += imgtec/
obj-$(CONFIG_ARCH_MXC) += imx/
obj-y += imx/
obj-y += ingenic/
obj-$(CONFIG_ARCH_K3) += keystone/
obj-$(CONFIG_ARCH_KEYSTONE) += keystone/

View file

@ -1,15 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Broadcom
*
* 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.
*/
#include <linux/clk.h>
@ -79,4 +70,4 @@ builtin_platform_driver(bcm2835_aux_clk_driver);
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
MODULE_DESCRIPTION("BCM2835 auxiliary peripheral clock driver");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");

View file

@ -1,17 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2010,2015 Broadcom
* Copyright (C) 2012 Stephen Warren
*
* 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.
*
*/
/**
@ -2206,4 +2196,4 @@ builtin_platform_driver(bcm2835_clk_driver);
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
MODULE_DESCRIPTION("BCM2835 clock driver");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");

View file

@ -311,7 +311,6 @@ static struct axxia_divclk clk_per_div = {
"clk_sm1_pll"
},
.num_parents = 1,
.flags = CLK_IS_BASIC,
.ops = &axxia_divclk_ops,
},
.reg = 0x1000c,
@ -326,7 +325,6 @@ static struct axxia_divclk clk_mmc_div = {
"clk_sm1_pll"
},
.num_parents = 1,
.flags = CLK_IS_BASIC,
.ops = &axxia_divclk_ops,
},
.reg = 0x1000c,

123
drivers/clk/clk-bd718x7.c Normal file
View file

@ -0,0 +1,123 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 ROHM Semiconductors
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/rohm-bd718x7.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/regmap.h>
struct bd718xx_clk {
struct clk_hw hw;
u8 reg;
u8 mask;
struct platform_device *pdev;
struct bd718xx *mfd;
};
static int bd71837_clk_set(struct clk_hw *hw, int status)
{
struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
return regmap_update_bits(c->mfd->regmap, c->reg, c->mask, status);
}
static void bd71837_clk_disable(struct clk_hw *hw)
{
int rv;
struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
rv = bd71837_clk_set(hw, 0);
if (rv)
dev_dbg(&c->pdev->dev, "Failed to disable 32K clk (%d)\n", rv);
}
static int bd71837_clk_enable(struct clk_hw *hw)
{
return bd71837_clk_set(hw, 1);
}
static int bd71837_clk_is_enabled(struct clk_hw *hw)
{
int enabled;
int rval;
struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
rval = regmap_read(c->mfd->regmap, c->reg, &enabled);
if (rval)
return rval;
return enabled & c->mask;
}
static const struct clk_ops bd71837_clk_ops = {
.prepare = &bd71837_clk_enable,
.unprepare = &bd71837_clk_disable,
.is_prepared = &bd71837_clk_is_enabled,
};
static int bd71837_clk_probe(struct platform_device *pdev)
{
struct bd718xx_clk *c;
int rval = -ENOMEM;
const char *parent_clk;
struct device *parent = pdev->dev.parent;
struct bd718xx *mfd = dev_get_drvdata(parent);
struct clk_init_data init = {
.name = "bd718xx-32k-out",
.ops = &bd71837_clk_ops,
};
c = devm_kzalloc(&pdev->dev, sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;
init.num_parents = 1;
parent_clk = of_clk_get_parent_name(parent->of_node, 0);
init.parent_names = &parent_clk;
if (!parent_clk) {
dev_err(&pdev->dev, "No parent clk found\n");
return -EINVAL;
}
c->reg = BD718XX_REG_OUT32K;
c->mask = BD718XX_OUT32K_EN;
c->mfd = mfd;
c->pdev = pdev;
c->hw.init = &init;
of_property_read_string_index(parent->of_node,
"clock-output-names", 0, &init.name);
rval = devm_clk_hw_register(&pdev->dev, &c->hw);
if (rval) {
dev_err(&pdev->dev, "failed to register 32K clk");
return rval;
}
rval = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
&c->hw);
if (rval)
dev_err(&pdev->dev, "adding clk provider failed\n");
return rval;
}
static struct platform_driver bd71837_clk = {
.driver = {
.name = "bd718xx-clk",
},
.probe = bd71837_clk_probe,
};
module_platform_driver(bd71837_clk);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD71837 chip clk driver");
MODULE_LICENSE("GPL");

View file

@ -1,19 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2017 NXP
*
* Dong Aisheng <aisheng.dong@nxp.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>

View file

@ -1,17 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>

View file

@ -1,10 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2014 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>

View file

@ -1,9 +1,4 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/export.h>

View file

@ -1,12 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
* Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
* Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Adjustable divider clock implementation
*/

View file

@ -1,11 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Standard functionality for the common clock API.
*/
#include <linux/module.h>
#include <linux/clk-provider.h>

View file

@ -1,11 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
* Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Fixed rate clock implementation
*/

View file

@ -1,10 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2014 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Adjustable fractional divider clock implementation.
* Output rate = (m / n) * parent_rate.
* Uses rational best approximation algorithm.
@ -40,6 +37,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
m = (val & fd->mmask) >> fd->mshift;
n = (val & fd->nmask) >> fd->nshift;
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
m++;
n++;
}
if (!n || !m)
return parent_rate;
@ -103,6 +105,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
&m, &n);
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
m--;
n--;
}
if (fd->lock)
spin_lock_irqsave(fd->lock, flags);
else

View file

@ -1,11 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
* Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Gated clock implementation
*/

View file

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
*
@ -5,10 +6,6 @@
* Jyri Sarha <jsarha@ti.com>
* Sergej Sawazki <ce3a@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Gpio controlled clock implementation
*/

View file

@ -107,8 +107,8 @@ static int hi655x_clk_probe(struct platform_device *pdev)
if (ret)
return ret;
return of_clk_add_hw_provider(parent->of_node, of_clk_hw_simple_get,
&hi655x_clk->clk_hw);
return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
&hi655x_clk->clk_hw);
}
static struct platform_driver hi655x_clk_driver = {

View file

@ -137,7 +137,7 @@ static unsigned long max77686_recalc_rate(struct clk_hw *hw,
return 32768;
}
static struct clk_ops max77686_clk_ops = {
static const struct clk_ops max77686_clk_ops = {
.prepare = max77686_clk_prepare,
.unprepare = max77686_clk_unprepare,
.is_prepared = max77686_clk_is_prepared,

View file

@ -1,9 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/bitops.h>

View file

@ -1,12 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
* Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
* Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Simple multiplexer clock implementation
*/

View file

@ -455,7 +455,7 @@ static const char * const src_clk_names[] = {
"RNGCCLK ",
};
static int nomadik_src_clk_show(struct seq_file *s, void *what)
static int nomadik_src_clk_debugfs_show(struct seq_file *s, void *what)
{
int i;
u32 src_pcksr0 = readl(src_base + SRC_PCKSR0);
@ -479,17 +479,7 @@ static int nomadik_src_clk_show(struct seq_file *s, void *what)
return 0;
}
static int nomadik_src_clk_open(struct inode *inode, struct file *file)
{
return single_open(file, nomadik_src_clk_show, NULL);
}
static const struct file_operations nomadik_src_clk_debugfs_ops = {
.open = nomadik_src_clk_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(nomadik_src_clk_debugfs);
static int __init nomadik_src_clk_init_debugfs(void)
{
@ -499,7 +489,7 @@ static int __init nomadik_src_clk_init_debugfs(void)
src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
NULL, NULL, &nomadik_src_clk_debugfs_ops);
NULL, NULL, &nomadik_src_clk_debugfs_fops);
return 0;
}
device_initcall(nomadik_src_clk_init_debugfs);

View file

@ -115,7 +115,7 @@ static int palmas_clks_is_prepared(struct clk_hw *hw)
return !!(val & cinfo->clk_desc->enable_mask);
}
static struct clk_ops palmas_clks_ops = {
static const struct clk_ops palmas_clks_ops = {
.prepare = palmas_clks_prepare,
.unprepare = palmas_clks_unprepare,
.is_prepared = palmas_clks_is_prepared,

View file

@ -1418,12 +1418,23 @@ static void __init clockgen_init(struct device_node *np)
CLK_OF_DECLARE(qoriq_clockgen_1, "fsl,qoriq-clockgen-1.0", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_2, "fsl,qoriq-clockgen-2.0", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_b4420, "fsl,b4420-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_b4860, "fsl,b4860-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_p2041, "fsl,p2041-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_p3041, "fsl,p3041-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_p4080, "fsl,p4080-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_p5020, "fsl,p5020-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_p5040, "fsl,p5040-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_t1023, "fsl,t1023-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_t1040, "fsl,t1040-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_t2080, "fsl,t2080-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_t4240, "fsl,t4240-clockgen", clockgen_init);
/* Legacy nodes */
CLK_OF_DECLARE(qoriq_sysclk_1, "fsl,qoriq-sysclk-1.0", sysclk_init);

View file

@ -138,23 +138,12 @@ static int rk808_clkout_probe(struct platform_device *pdev)
if (ret)
return ret;
return of_clk_add_hw_provider(node, of_clk_rk808_get, rk808_clkout);
}
static int rk808_clkout_remove(struct platform_device *pdev)
{
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
struct i2c_client *client = rk808->i2c;
struct device_node *node = client->dev.of_node;
of_clk_del_provider(node);
return 0;
return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_rk808_get,
rk808_clkout);
}
static struct platform_driver rk808_clkout_driver = {
.probe = rk808_clkout_probe,
.remove = rk808_clkout_remove,
.driver = {
.name = "rk808-clkout",
},

View file

@ -71,7 +71,7 @@ static unsigned long s2mps11_clk_recalc_rate(struct clk_hw *hw,
return 32768;
}
static struct clk_ops s2mps11_clk_ops = {
static const struct clk_ops s2mps11_clk_ops = {
.prepare = s2mps11_clk_prepare,
.unprepare = s2mps11_clk_unprepare,
.is_prepared = s2mps11_clk_is_prepared,

View file

@ -2015,7 +2015,7 @@ static int stm32_register_hw_clk(struct device *dev,
void __iomem *base, spinlock_t *lock,
const struct clock_config *cfg)
{
static struct clk_hw **hws;
struct clk_hw **hws;
struct clk_hw *hw = ERR_PTR(-ENOENT);
hws = clk_data->hws;

View file

@ -108,9 +108,8 @@ static int twl6040_pdmclk_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, clkdata);
return of_clk_add_hw_provider(pdev->dev.parent->of_node,
of_clk_hw_simple_get,
&clkdata->pdmclk_hw);
return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
&clkdata->pdmclk_hw);
}
static struct platform_driver twl6040_pdmclk_driver = {

View file

@ -906,6 +906,28 @@ static int vc5_remove(struct i2c_client *client)
return 0;
}
static int __maybe_unused vc5_suspend(struct device *dev)
{
struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
regcache_cache_only(vc5->regmap, true);
regcache_mark_dirty(vc5->regmap);
return 0;
}
static int __maybe_unused vc5_resume(struct device *dev)
{
struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
int ret;
regcache_cache_only(vc5->regmap, false);
ret = regcache_sync(vc5->regmap);
if (ret)
dev_err(dev, "Failed to restore register map: %d\n", ret);
return ret;
}
static const struct vc5_chip_info idt_5p49v5923_info = {
.model = IDT_VC5_5P49V5923,
.clk_fod_cnt = 2,
@ -961,9 +983,12 @@ static const struct of_device_id clk_vc5_of_match[] = {
};
MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
static SIMPLE_DEV_PM_OPS(vc5_pm_ops, vc5_suspend, vc5_resume);
static struct i2c_driver vc5_driver = {
.driver = {
.name = "vc5",
.pm = &vc5_pm_ops,
.of_match_table = clk_vc5_of_match,
},
.probe = vc5_probe,

View file

@ -1,11 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
* Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Standard functionality for the common clock API. See Documentation/driver-api/clk.rst
*/
@ -3893,6 +3890,39 @@ static void devm_of_clk_release_provider(struct device *dev, void *res)
of_clk_del_provider(*(struct device_node **)res);
}
/*
* We allow a child device to use its parent device as the clock provider node
* for cases like MFD sub-devices where the child device driver wants to use
* devm_*() APIs but not list the device in DT as a sub-node.
*/
static struct device_node *get_clk_provider_node(struct device *dev)
{
struct device_node *np, *parent_np;
np = dev->of_node;
parent_np = dev->parent ? dev->parent->of_node : NULL;
if (!of_find_property(np, "#clock-cells", NULL))
if (of_find_property(parent_np, "#clock-cells", NULL))
np = parent_np;
return np;
}
/**
* devm_of_clk_add_hw_provider() - Managed clk provider node registration
* @dev: Device acting as the clock provider (used for DT node and lifetime)
* @get: callback for decoding clk_hw
* @data: context pointer for @get callback
*
* Registers clock provider for given device's node. If the device has no DT
* node or if the device node lacks of clock provider information (#clock-cells)
* then the parent device's node is scanned for this information. If parent node
* has the #clock-cells then it is used in registration. Provider is
* automatically released at device exit.
*
* Return: 0 on success or an errno on failure.
*/
int devm_of_clk_add_hw_provider(struct device *dev,
struct clk_hw *(*get)(struct of_phandle_args *clkspec,
void *data),
@ -3906,7 +3936,7 @@ int devm_of_clk_add_hw_provider(struct device *dev,
if (!ptr)
return -ENOMEM;
np = dev->of_node;
np = get_clk_provider_node(dev);
ret = of_clk_add_hw_provider(np, get, data);
if (!ret) {
*ptr = np;
@ -3950,12 +3980,17 @@ static int devm_clk_provider_match(struct device *dev, void *res, void *data)
return *np == data;
}
/**
* devm_of_clk_del_provider() - Remove clock provider registered using devm
* @dev: Device to whose lifetime the clock provider was bound
*/
void devm_of_clk_del_provider(struct device *dev)
{
int ret;
struct device_node *np = get_clk_provider_node(dev);
ret = devres_release(dev, devm_of_clk_release_provider,
devm_clk_provider_match, dev->of_node);
devm_clk_provider_match, np);
WARN_ON(ret);
}

View file

@ -1,12 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* linux/drivers/clk/clk.h
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
struct clk_hw;

View file

@ -117,7 +117,7 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node)
parent_name = of_clk_get_parent_name(node, 0);
init.name = clk_name;
init.ops = &pll_ops;
init.flags = CLK_IS_BASIC;
init.flags = 0;
init.parent_names = &parent_name;
init.num_parents = 1;
pll_clock->hw.init = &init;

View file

@ -435,7 +435,7 @@ static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk,
init.name = mmc_clk->name;
init.ops = &clk_mmc_ops;
init.flags = mmc_clk->flags | CLK_IS_BASIC;
init.flags = mmc_clk->flags;
init.parent_names = (mmc_clk->parent_name ? &mmc_clk->parent_name : NULL);
init.num_parents = (mmc_clk->parent_name ? 1 : 0);
mclk->hw.init = &init;

View file

@ -103,7 +103,7 @@ struct clk *clk_register_hisi_phase(struct device *dev,
init.name = clks->name;
init.ops = &clk_phase_ops;
init.flags = clks->flags | CLK_IS_BASIC;
init.flags = clks->flags;
init.parent_names = clks->parent_names ? &clks->parent_names : NULL;
init.num_parents = clks->parent_names ? 1 : 0;

View file

@ -274,7 +274,7 @@ hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, int nums,
else
init.ops = &clk_complex_ops;
init.flags = CLK_IS_BASIC;
init.flags = 0;
init.parent_names =
(clks[i].parent_name ? &clks[i].parent_name : NULL);
init.num_parents = (clks[i].parent_name ? 1 : 0);

View file

@ -110,7 +110,7 @@ struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name,
init.name = name;
init.ops = &clkgate_separated_ops;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);

View file

@ -73,27 +73,40 @@ static void __init clk_boston_setup(struct device_node *np)
hw = clk_hw_register_fixed_rate(NULL, "input", NULL, 0, in_freq);
if (IS_ERR(hw)) {
pr_err("failed to register input clock: %ld\n", PTR_ERR(hw));
return;
goto fail_input;
}
onecell->hws[BOSTON_CLK_INPUT] = hw;
hw = clk_hw_register_fixed_rate(NULL, "sys", "input", 0, sys_freq);
if (IS_ERR(hw)) {
pr_err("failed to register sys clock: %ld\n", PTR_ERR(hw));
return;
goto fail_sys;
}
onecell->hws[BOSTON_CLK_SYS] = hw;
hw = clk_hw_register_fixed_rate(NULL, "cpu", "input", 0, cpu_freq);
if (IS_ERR(hw)) {
pr_err("failed to register cpu clock: %ld\n", PTR_ERR(hw));
return;
goto fail_cpu;
}
onecell->hws[BOSTON_CLK_CPU] = hw;
err = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, onecell);
if (err)
if (err) {
pr_err("failed to add DT provider: %d\n", err);
goto fail_clk_add;
}
return;
fail_clk_add:
clk_hw_unregister_fixed_rate(onecell->hws[BOSTON_CLK_CPU]);
fail_cpu:
clk_hw_unregister_fixed_rate(onecell->hws[BOSTON_CLK_SYS]);
fail_sys:
clk_hw_unregister_fixed_rate(onecell->hws[BOSTON_CLK_INPUT]);
fail_input:
kfree(onecell);
}
/*

22
drivers/clk/imx/Kconfig Normal file
View file

@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0
# common clock support for NXP i.MX SoC family.
config MXC_CLK
bool
def_bool ARCH_MXC
config MXC_CLK_SCU
bool
depends on IMX_SCU
config CLK_IMX8MQ
bool "IMX8MQ CCM Clock Driver"
depends on ARCH_MXC && ARM64
help
Build the driver for i.MX8MQ CCM Clock Driver
config CLK_IMX8QXP
bool "IMX8QXP SCU Clock"
depends on ARCH_MXC && IMX_SCU && ARM64
select MXC_CLK_SCU
help
Build the driver for IMX8QXP SCU based clocks.

View file

@ -1,17 +1,31 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += \
obj-$(CONFIG_MXC_CLK) += \
clk.o \
clk-busy.o \
clk-composite-8m.o \
clk-cpu.o \
clk-composite-7ulp.o \
clk-divider-gate.o \
clk-fixup-div.o \
clk-fixup-mux.o \
clk-frac-pll.o \
clk-gate-exclusive.o \
clk-gate2.o \
clk-pfd.o \
clk-pfdv2.o \
clk-pllv1.o \
clk-pllv2.o \
clk-pllv3.o \
clk-pfd.o
clk-pllv4.o \
clk-sccg-pll.o
obj-$(CONFIG_MXC_CLK_SCU) += \
clk-scu.o \
clk-lpcg-scu.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o
obj-$(CONFIG_SOC_IMX1) += clk-imx1.o
obj-$(CONFIG_SOC_IMX21) += clk-imx21.o
@ -26,4 +40,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o
obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o
obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o
obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o
obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o
obj-$(CONFIG_SOC_VF610) += clk-vf610.o

View file

@ -154,7 +154,7 @@ static const struct clk_ops clk_busy_mux_ops = {
struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
u8 width, void __iomem *busy_reg, u8 busy_shift,
const char **parent_names, int num_parents)
const char * const *parent_names, int num_parents)
{
struct clk_busy_mux *busy;
struct clk *clk;

View file

@ -0,0 +1,87 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017~2018 NXP
*
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/slab.h>
#include "clk.h"
#define PCG_PCS_SHIFT 24
#define PCG_PCS_MASK 0x7
#define PCG_CGC_SHIFT 30
#define PCG_FRAC_SHIFT 3
#define PCG_FRAC_WIDTH 1
#define PCG_FRAC_MASK BIT(3)
#define PCG_PCD_SHIFT 0
#define PCG_PCD_WIDTH 3
#define PCG_PCD_MASK 0x7
struct clk_hw *imx7ulp_clk_composite(const char *name,
const char * const *parent_names,
int num_parents, bool mux_present,
bool rate_present, bool gate_present,
void __iomem *reg)
{
struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL;
struct clk_fractional_divider *fd = NULL;
struct clk_gate *gate = NULL;
struct clk_mux *mux = NULL;
struct clk_hw *hw;
if (mux_present) {
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
return ERR_PTR(-ENOMEM);
mux_hw = &mux->hw;
mux->reg = reg;
mux->shift = PCG_PCS_SHIFT;
mux->mask = PCG_PCS_MASK;
}
if (rate_present) {
fd = kzalloc(sizeof(*fd), GFP_KERNEL);
if (!fd) {
kfree(mux);
return ERR_PTR(-ENOMEM);
}
fd_hw = &fd->hw;
fd->reg = reg;
fd->mshift = PCG_FRAC_SHIFT;
fd->mwidth = PCG_FRAC_WIDTH;
fd->mmask = PCG_FRAC_MASK;
fd->nshift = PCG_PCD_SHIFT;
fd->nwidth = PCG_PCD_WIDTH;
fd->nmask = PCG_PCD_MASK;
fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
}
if (gate_present) {
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) {
kfree(mux);
kfree(fd);
return ERR_PTR(-ENOMEM);
}
gate_hw = &gate->hw;
gate->reg = reg;
gate->bit_idx = PCG_CGC_SHIFT;
}
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &clk_mux_ops, fd_hw,
&clk_fractional_divider_ops, gate_hw,
&clk_gate_ops, CLK_SET_RATE_GATE |
CLK_SET_PARENT_GATE);
if (IS_ERR(hw)) {
kfree(mux);
kfree(fd);
kfree(gate);
}
return hw;
}

View file

@ -0,0 +1,178 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2018 NXP
*/
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/clk-provider.h>
#include "clk.h"
#define PCG_PREDIV_SHIFT 16
#define PCG_PREDIV_WIDTH 3
#define PCG_PREDIV_MAX 8
#define PCG_DIV_SHIFT 0
#define PCG_DIV_WIDTH 6
#define PCG_DIV_MAX 64
#define PCG_PCS_SHIFT 24
#define PCG_PCS_MASK 0x7
#define PCG_CGC_SHIFT 28
static unsigned long imx8m_clk_composite_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
unsigned long prediv_rate;
unsigned int prediv_value;
unsigned int div_value;
prediv_value = readl(divider->reg) >> divider->shift;
prediv_value &= clk_div_mask(divider->width);
prediv_rate = divider_recalc_rate(hw, parent_rate, prediv_value,
NULL, divider->flags,
divider->width);
div_value = readl(divider->reg) >> PCG_DIV_SHIFT;
div_value &= clk_div_mask(PCG_DIV_WIDTH);
return divider_recalc_rate(hw, prediv_rate, div_value, NULL,
divider->flags, PCG_DIV_WIDTH);
}
static int imx8m_clk_composite_compute_dividers(unsigned long rate,
unsigned long parent_rate,
int *prediv, int *postdiv)
{
int div1, div2;
int error = INT_MAX;
int ret = -EINVAL;
*prediv = 1;
*postdiv = 1;
for (div1 = 1; div1 <= PCG_PREDIV_MAX; div1++) {
for (div2 = 1; div2 <= PCG_DIV_MAX; div2++) {
int new_error = ((parent_rate / div1) / div2) - rate;
if (abs(new_error) < abs(error)) {
*prediv = div1;
*postdiv = div2;
error = new_error;
ret = 0;
}
}
}
return ret;
}
static long imx8m_clk_composite_divider_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *prate)
{
int prediv_value;
int div_value;
imx8m_clk_composite_compute_dividers(rate, *prate,
&prediv_value, &div_value);
rate = DIV_ROUND_UP(*prate, prediv_value);
return DIV_ROUND_UP(rate, div_value);
}
static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct clk_divider *divider = to_clk_divider(hw);
unsigned long flags = 0;
int prediv_value;
int div_value;
int ret;
u32 val;
ret = imx8m_clk_composite_compute_dividers(rate, parent_rate,
&prediv_value, &div_value);
if (ret)
return -EINVAL;
spin_lock_irqsave(divider->lock, flags);
val = readl(divider->reg);
val &= ~((clk_div_mask(divider->width) << divider->shift) |
(clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT));
val |= (u32)(prediv_value - 1) << divider->shift;
val |= (u32)(div_value - 1) << PCG_DIV_SHIFT;
writel(val, divider->reg);
spin_unlock_irqrestore(divider->lock, flags);
return ret;
}
static const struct clk_ops imx8m_clk_composite_divider_ops = {
.recalc_rate = imx8m_clk_composite_divider_recalc_rate,
.round_rate = imx8m_clk_composite_divider_round_rate,
.set_rate = imx8m_clk_composite_divider_set_rate,
};
struct clk *imx8m_clk_composite_flags(const char *name,
const char **parent_names,
int num_parents, void __iomem *reg,
unsigned long flags)
{
struct clk_hw *hw = ERR_PTR(-ENOMEM), *mux_hw;
struct clk_hw *div_hw, *gate_hw;
struct clk_divider *div = NULL;
struct clk_gate *gate = NULL;
struct clk_mux *mux = NULL;
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
goto fail;
mux_hw = &mux->hw;
mux->reg = reg;
mux->shift = PCG_PCS_SHIFT;
mux->mask = PCG_PCS_MASK;
div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div)
goto fail;
div_hw = &div->hw;
div->reg = reg;
div->shift = PCG_PREDIV_SHIFT;
div->width = PCG_PREDIV_WIDTH;
div->lock = &imx_ccm_lock;
div->flags = CLK_DIVIDER_ROUND_CLOSEST;
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate)
goto fail;
gate_hw = &gate->hw;
gate->reg = reg;
gate->bit_idx = PCG_CGC_SHIFT;
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &clk_mux_ops, div_hw,
&imx8m_clk_composite_divider_ops,
gate_hw, &clk_gate_ops, flags);
if (IS_ERR(hw))
goto fail;
return hw->clk;
fail:
kfree(gate);
kfree(div);
kfree(mux);
return ERR_CAST(hw);
}

View file

@ -0,0 +1,221 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018 NXP.
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/slab.h>
#include "clk.h"
struct clk_divider_gate {
struct clk_divider divider;
u32 cached_val;
};
static inline struct clk_divider_gate *to_clk_divider_gate(struct clk_hw *hw)
{
struct clk_divider *div = to_clk_divider(hw);
return container_of(div, struct clk_divider_gate, divider);
}
static unsigned long clk_divider_gate_recalc_rate_ro(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_divider *div = to_clk_divider(hw);
unsigned int val;
val = clk_readl(div->reg) >> div->shift;
val &= clk_div_mask(div->width);
if (!val)
return 0;
return divider_recalc_rate(hw, parent_rate, val, div->table,
div->flags, div->width);
}
static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
struct clk_divider *div = to_clk_divider(hw);
unsigned long flags = 0;
unsigned int val;
spin_lock_irqsave(div->lock, flags);
if (!clk_hw_is_enabled(hw)) {
val = div_gate->cached_val;
} else {
val = clk_readl(div->reg) >> div->shift;
val &= clk_div_mask(div->width);
}
spin_unlock_irqrestore(div->lock, flags);
if (!val)
return 0;
return divider_recalc_rate(hw, parent_rate, val, div->table,
div->flags, div->width);
}
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_divider_ops.round_rate(hw, rate, prate);
}
static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
struct clk_divider *div = to_clk_divider(hw);
unsigned long flags = 0;
int value;
u32 val;
value = divider_get_val(rate, parent_rate, div->table,
div->width, div->flags);
if (value < 0)
return value;
spin_lock_irqsave(div->lock, flags);
if (clk_hw_is_enabled(hw)) {
val = clk_readl(div->reg);
val &= ~(clk_div_mask(div->width) << div->shift);
val |= (u32)value << div->shift;
clk_writel(val, div->reg);
} else {
div_gate->cached_val = value;
}
spin_unlock_irqrestore(div->lock, flags);
return 0;
}
static int clk_divider_enable(struct clk_hw *hw)
{
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
struct clk_divider *div = to_clk_divider(hw);
unsigned long flags = 0;
u32 val;
if (!div_gate->cached_val) {
pr_err("%s: no valid preset rate\n", clk_hw_get_name(hw));
return -EINVAL;
}
spin_lock_irqsave(div->lock, flags);
/* restore div val */
val = clk_readl(div->reg);
val |= div_gate->cached_val << div->shift;
clk_writel(val, div->reg);
spin_unlock_irqrestore(div->lock, flags);
return 0;
}
static void clk_divider_disable(struct clk_hw *hw)
{
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
struct clk_divider *div = to_clk_divider(hw);
unsigned long flags = 0;
u32 val;
spin_lock_irqsave(div->lock, flags);
/* store the current div val */
val = clk_readl(div->reg) >> div->shift;
val &= clk_div_mask(div->width);
div_gate->cached_val = val;
clk_writel(0, div->reg);
spin_unlock_irqrestore(div->lock, flags);
}
static int clk_divider_is_enabled(struct clk_hw *hw)
{
struct clk_divider *div = to_clk_divider(hw);
u32 val;
val = clk_readl(div->reg) >> div->shift;
val &= clk_div_mask(div->width);
return val ? 1 : 0;
}
static const struct clk_ops clk_divider_gate_ro_ops = {
.recalc_rate = clk_divider_gate_recalc_rate_ro,
.round_rate = clk_divider_round_rate,
};
static const struct clk_ops clk_divider_gate_ops = {
.recalc_rate = clk_divider_gate_recalc_rate,
.round_rate = clk_divider_round_rate,
.set_rate = clk_divider_gate_set_rate,
.enable = clk_divider_enable,
.disable = clk_divider_disable,
.is_enabled = clk_divider_is_enabled,
};
/*
* NOTE: In order to resue the most code from the common divider,
* we also design our divider following the way that provids an extra
* clk_divider_flags, however it's fixed to CLK_DIVIDER_ONE_BASED by
* default as our HW is. Besides that it supports only CLK_DIVIDER_READ_ONLY
* flag which can be specified by user flexibly.
*/
struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg,
u8 shift, u8 width, u8 clk_divider_flags,
const struct clk_div_table *table,
spinlock_t *lock)
{
struct clk_init_data init;
struct clk_divider_gate *div_gate;
struct clk_hw *hw;
u32 val;
int ret;
div_gate = kzalloc(sizeof(*div_gate), GFP_KERNEL);
if (!div_gate)
return ERR_PTR(-ENOMEM);
init.name = name;
if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
init.ops = &clk_divider_gate_ro_ops;
else
init.ops = &clk_divider_gate_ops;
init.flags = flags;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
div_gate->divider.reg = reg;
div_gate->divider.shift = shift;
div_gate->divider.width = width;
div_gate->divider.lock = lock;
div_gate->divider.table = table;
div_gate->divider.hw.init = &init;
div_gate->divider.flags = CLK_DIVIDER_ONE_BASED | clk_divider_flags;
/* cache gate status */
val = clk_readl(reg) >> shift;
val &= clk_div_mask(width);
div_gate->cached_val = val;
hw = &div_gate->divider.hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(div_gate);
hw = ERR_PTR(ret);
}
return hw;
}

View file

@ -70,7 +70,7 @@ static const struct clk_ops clk_fixup_mux_ops = {
};
struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents,
u8 shift, u8 width, const char * const *parents,
int num_parents, void (*fixup)(u32 *val))
{
struct clk_fixup_mux *fixup_mux;

View file

@ -0,0 +1,232 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2018 NXP.
*
* This driver supports the fractional plls found in the imx8m SOCs
*
* Documentation for this fractional pll can be found at:
* https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/bitfield.h>
#include "clk.h"
#define PLL_CFG0 0x0
#define PLL_CFG1 0x4
#define PLL_LOCK_STATUS BIT(31)
#define PLL_PD_MASK BIT(19)
#define PLL_BYPASS_MASK BIT(14)
#define PLL_NEWDIV_VAL BIT(12)
#define PLL_NEWDIV_ACK BIT(11)
#define PLL_FRAC_DIV_MASK GENMASK(30, 7)
#define PLL_INT_DIV_MASK GENMASK(6, 0)
#define PLL_OUTPUT_DIV_MASK GENMASK(4, 0)
#define PLL_FRAC_DENOM 0x1000000
#define PLL_FRAC_LOCK_TIMEOUT 10000
#define PLL_FRAC_ACK_TIMEOUT 500000
struct clk_frac_pll {
struct clk_hw hw;
void __iomem *base;
};
#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw)
static int clk_wait_lock(struct clk_frac_pll *pll)
{
u32 val;
return readl_poll_timeout(pll->base, val, val & PLL_LOCK_STATUS, 0,
PLL_FRAC_LOCK_TIMEOUT);
}
static int clk_wait_ack(struct clk_frac_pll *pll)
{
u32 val;
/* return directly if the pll is in powerdown or in bypass */
if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK))
return 0;
/* Wait for the pll's divfi and divff to be reloaded */
return readl_poll_timeout(pll->base, val, val & PLL_NEWDIV_ACK, 0,
PLL_FRAC_ACK_TIMEOUT);
}
static int clk_pll_prepare(struct clk_hw *hw)
{
struct clk_frac_pll *pll = to_clk_frac_pll(hw);
u32 val;
val = readl_relaxed(pll->base + PLL_CFG0);
val &= ~PLL_PD_MASK;
writel_relaxed(val, pll->base + PLL_CFG0);
return clk_wait_lock(pll);
}
static void clk_pll_unprepare(struct clk_hw *hw)
{
struct clk_frac_pll *pll = to_clk_frac_pll(hw);
u32 val;
val = readl_relaxed(pll->base + PLL_CFG0);
val |= PLL_PD_MASK;
writel_relaxed(val, pll->base + PLL_CFG0);
}
static int clk_pll_is_prepared(struct clk_hw *hw)
{
struct clk_frac_pll *pll = to_clk_frac_pll(hw);
u32 val;
val = readl_relaxed(pll->base + PLL_CFG0);
return (val & PLL_PD_MASK) ? 0 : 1;
}
static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_frac_pll *pll = to_clk_frac_pll(hw);
u32 val, divff, divfi, divq;
u64 temp64 = parent_rate;
u64 rate;
val = readl_relaxed(pll->base + PLL_CFG0);
divq = (FIELD_GET(PLL_OUTPUT_DIV_MASK, val) + 1) * 2;
val = readl_relaxed(pll->base + PLL_CFG1);
divff = FIELD_GET(PLL_FRAC_DIV_MASK, val);
divfi = FIELD_GET(PLL_INT_DIV_MASK, val);
temp64 *= 8;
temp64 *= divff;
do_div(temp64, PLL_FRAC_DENOM);
do_div(temp64, divq);
rate = parent_rate * 8 * (divfi + 1);
do_div(rate, divq);
rate += temp64;
return rate;
}
static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
u64 parent_rate = *prate;
u32 divff, divfi;
u64 temp64;
parent_rate *= 8;
rate *= 2;
temp64 = rate;
do_div(temp64, parent_rate);
divfi = temp64;
temp64 = rate - divfi * parent_rate;
temp64 *= PLL_FRAC_DENOM;
do_div(temp64, parent_rate);
divff = temp64;
temp64 = parent_rate;
temp64 *= divff;
do_div(temp64, PLL_FRAC_DENOM);
rate = parent_rate * divfi + temp64;
return rate / 2;
}
/*
* To simplify the clock calculation, we can keep the 'PLL_OUTPUT_VAL' at zero
* (means the PLL output will be divided by 2). So the PLL output can use
* the below formula:
* pllout = parent_rate * 8 / 2 * DIVF_VAL;
* where DIVF_VAL = 1 + DIVFI + DIVFF / 2^24.
*/
static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_frac_pll *pll = to_clk_frac_pll(hw);
u32 val, divfi, divff;
u64 temp64 = parent_rate;
int ret;
parent_rate *= 8;
rate *= 2;
divfi = rate / parent_rate;
temp64 *= rate - divfi;
temp64 *= PLL_FRAC_DENOM;
do_div(temp64, parent_rate);
divff = temp64;
val = readl_relaxed(pll->base + PLL_CFG1);
val &= ~(PLL_FRAC_DIV_MASK | PLL_INT_DIV_MASK);
val |= (divff << 7) | (divfi - 1);
writel_relaxed(val, pll->base + PLL_CFG1);
val = readl_relaxed(pll->base + PLL_CFG0);
val &= ~0x1f;
writel_relaxed(val, pll->base + PLL_CFG0);
/* Set the NEV_DIV_VAL to reload the DIVFI and DIVFF */
val = readl_relaxed(pll->base + PLL_CFG0);
val |= PLL_NEWDIV_VAL;
writel_relaxed(val, pll->base + PLL_CFG0);
ret = clk_wait_ack(pll);
/* clear the NEV_DIV_VAL */
val = readl_relaxed(pll->base + PLL_CFG0);
val &= ~PLL_NEWDIV_VAL;
writel_relaxed(val, pll->base + PLL_CFG0);
return ret;
}
static const struct clk_ops clk_frac_pll_ops = {
.prepare = clk_pll_prepare,
.unprepare = clk_pll_unprepare,
.is_prepared = clk_pll_is_prepared,
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_round_rate,
.set_rate = clk_pll_set_rate,
};
struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
void __iomem *base)
{
struct clk_init_data init;
struct clk_frac_pll *pll;
struct clk_hw *hw;
int ret;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &clk_frac_pll_ops;
init.flags = 0;
init.parent_names = &parent_name;
init.num_parents = 1;
pll->base = base;
pll->hw.init = &init;
hw = &pll->hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(pll);
return ERR_PTR(ret);
}
return hw->clk;
}

View file

@ -225,6 +225,41 @@ static void of_assigned_ldb_sels(struct device_node *node,
}
}
static bool pll6_bypassed(struct device_node *node)
{
int index, ret, num_clocks;
struct of_phandle_args clkspec;
num_clocks = of_count_phandle_with_args(node, "assigned-clocks",
"#clock-cells");
if (num_clocks < 0)
return false;
for (index = 0; index < num_clocks; index++) {
ret = of_parse_phandle_with_args(node, "assigned-clocks",
"#clock-cells", index,
&clkspec);
if (ret < 0)
return false;
if (clkspec.np == node &&
clkspec.args[0] == IMX6QDL_PLL6_BYPASS)
break;
}
/* PLL6 bypass is not part of the assigned clock list */
if (index == num_clocks)
return false;
ret = of_parse_phandle_with_args(node, "assigned-clock-parents",
"#clock-cells", index, &clkspec);
if (clkspec.args[0] != IMX6QDL_CLK_PLL6)
return true;
return false;
}
#define CCM_CCDR 0x04
#define CCM_CCSR 0x0c
#define CCM_CS2CDR 0x2c
@ -414,12 +449,24 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
int ret;
clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0);
clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
clk[IMX6QDL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
if (IS_ERR(clk[IMX6QDL_CLK_CKIL]))
clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
clk[IMX6QDL_CLK_CKIH] = of_clk_get_by_name(ccm_node, "ckih1");
if (IS_ERR(clk[IMX6QDL_CLK_CKIH]))
clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0);
clk[IMX6QDL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
if (IS_ERR(clk[IMX6QDL_CLK_OSC]))
clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
/* Clock source from external clock via CLK1/2 PADs */
clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
clk[IMX6QDL_CLK_ANACLK1] = of_clk_get_by_name(ccm_node, "anaclk1");
if (IS_ERR(clk[IMX6QDL_CLK_ANACLK1]))
clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
clk[IMX6QDL_CLK_ANACLK2] = of_clk_get_by_name(ccm_node, "anaclk2");
if (IS_ERR(clk[IMX6QDL_CLK_ANACLK2]))
clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
anatop_base = base = of_iomap(np, 0);
@ -491,16 +538,32 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
clk[IMX6QDL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
/*
* The ENET PLL is special in that is has multiple outputs with
* different post-dividers that are all affected by the single bypass
* bit, so a single mux bit affects 3 independent branches of the clock
* tree. There is no good way to model this in the clock framework and
* dynamically changing the bypass bit, will yield unexpected results.
* So we treat any configuration that bypasses the ENET PLL as
* essentially static with the divider ratios reflecting the bypass
* status.
*
*/
if (!pll6_bypassed(ccm_node)) {
clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5);
clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4);
clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
base + 0xe0, 0, 2, 0, clk_enet_ref_table,
&imx_ccm_lock);
} else {
clk[IMX6QDL_CLK_SATA_REF] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 1);
clk[IMX6QDL_CLK_PCIE_REF] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 1);
clk[IMX6QDL_CLK_ENET_REF] = imx_clk_fixed_factor("enet_ref", "pll6_enet", 1, 1);
}
clk[IMX6QDL_CLK_SATA_REF_100M] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20);
clk[IMX6QDL_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
clk[IMX6QDL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
base + 0xe0, 0, 2, 0, clk_enet_ref_table,
&imx_ccm_lock);
clk[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
clk[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
@ -508,8 +571,12 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
* lvds1_gate and lvds2_gate are pseudo-gates. Both can be
* independently configured as clock inputs or outputs. We treat
* the "output_enable" bit as a gate, even though it's really just
* enabling clock output.
* enabling clock output. Initially the gate bits are cleared, as
* otherwise the exclusive configuration gets locked in the setup done
* by software running before the clock driver, with no way to change
* it.
*/
writel(readl(base + 0x160) & ~0x3c00, base + 0x160);
clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
@ -737,6 +804,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16);
clk[IMX6QDL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
clk[IMX6QDL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20);
clk[IMX6QDL_CLK_DCIC1] = imx_clk_gate2("dcic1", "ipu1_podf", base + 0x68, 24);
clk[IMX6QDL_CLK_DCIC2] = imx_clk_gate2("dcic2", "ipu2_podf", base + 0x68, 26);
clk[IMX6QDL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
clk[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
clk[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);

View file

@ -17,6 +17,8 @@
#include "clk.h"
#define CCDR 0x4
#define BM_CCM_CCDR_MMDC_CH0_MASK (1 << 17)
#define CCSR 0xc
#define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
#define CACRR 0x10
@ -411,6 +413,10 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
clks[IMX6SL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
/* Ensure the MMDC CH0 handshake is bypassed */
writel_relaxed(readl_relaxed(base + CCDR) |
BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
imx_check_clocks(clks, ARRAY_SIZE(clks));
clk_data.clks = clks;

View file

@ -886,9 +886,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
/* set uart module clock's parent clock source that must be great then 80MHz */
clk_set_parent(clks[IMX7D_UART1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
/* Set clock rate for USBPHY, the USB_PLL at CCM is from USBOTG2 */
clks[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
clks[IMX7D_USB_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb_main_clk", "osc", 20, 1);

View file

@ -0,0 +1,249 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017~2018 NXP
*
* Author: Dong Aisheng <aisheng.dong@nxp.com>
*
*/
#include <dt-bindings/clock/imx7ulp-clock.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk.h"
static const char * const pll_pre_sels[] = { "sosc", "firc", };
static const char * const spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", };
static const char * const spll_sels[] = { "spll", "spll_pfd_sel", };
static const char * const apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", };
static const char * const apll_sels[] = { "apll", "apll_pfd_sel", };
static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", };
static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", };
static const char * const nic_sels[] = { "firc", "ddr_clk", };
static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", };
static const char * const periph_bus_sels[] = { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", };
static const char * const arm_sels[] = { "divcore", "dummy", "dummy", "hsrun_divcore", };
/* used by sosc/sirc/firc/ddr/spll/apll dividers */
static const struct clk_div_table ulp_div_table[] = {
{ .val = 1, .div = 1, },
{ .val = 2, .div = 2, },
{ .val = 3, .div = 4, },
{ .val = 4, .div = 8, },
{ .val = 5, .div = 16, },
{ .val = 6, .div = 32, },
{ .val = 7, .div = 64, },
};
static void __init imx7ulp_clk_scg1_init(struct device_node *np)
{
struct clk_hw_onecell_data *clk_data;
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_SCG1_END, GFP_KERNEL);
if (!clk_data)
return;
clk_data->num = IMX7ULP_CLK_SCG1_END;
clks = clk_data->hws;
clks[IMX7ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
clks[IMX7ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc");
clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc");
clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc");
clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc");
clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll");
clks[IMX7ULP_CLK_UPLL] = imx_obtain_fixed_clk_hw(np, "upll");
/* SCG1 */
base = of_iomap(np, 0);
WARN_ON(!base);
/* NOTE: xPLL config can't be changed when xPLL is enabled */
clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_hw_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
clks[IMX7ULP_CLK_SPLL_PRE_SEL] = imx_clk_hw_mux_flags("spll_pre_sel", base + 0x608, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
/* name parent_name reg shift width flags */
clks[IMX7ULP_CLK_APLL_PRE_DIV] = imx_clk_hw_divider_flags("apll_pre_div", "apll_pre_sel", base + 0x508, 8, 3, CLK_SET_RATE_GATE);
clks[IMX7ULP_CLK_SPLL_PRE_DIV] = imx_clk_hw_divider_flags("spll_pre_div", "spll_pre_sel", base + 0x608, 8, 3, CLK_SET_RATE_GATE);
/* name parent_name base */
clks[IMX7ULP_CLK_APLL] = imx_clk_pllv4("apll", "apll_pre_div", base + 0x500);
clks[IMX7ULP_CLK_SPLL] = imx_clk_pllv4("spll", "spll_pre_div", base + 0x600);
/* APLL PFDs */
clks[IMX7ULP_CLK_APLL_PFD0] = imx_clk_pfdv2("apll_pfd0", "apll", base + 0x50c, 0);
clks[IMX7ULP_CLK_APLL_PFD1] = imx_clk_pfdv2("apll_pfd1", "apll", base + 0x50c, 1);
clks[IMX7ULP_CLK_APLL_PFD2] = imx_clk_pfdv2("apll_pfd2", "apll", base + 0x50c, 2);
clks[IMX7ULP_CLK_APLL_PFD3] = imx_clk_pfdv2("apll_pfd3", "apll", base + 0x50c, 3);
/* SPLL PFDs */
clks[IMX7ULP_CLK_SPLL_PFD0] = imx_clk_pfdv2("spll_pfd0", "spll", base + 0x60C, 0);
clks[IMX7ULP_CLK_SPLL_PFD1] = imx_clk_pfdv2("spll_pfd1", "spll", base + 0x60C, 1);
clks[IMX7ULP_CLK_SPLL_PFD2] = imx_clk_pfdv2("spll_pfd2", "spll", base + 0x60C, 2);
clks[IMX7ULP_CLK_SPLL_PFD3] = imx_clk_pfdv2("spll_pfd3", "spll", base + 0x60C, 3);
/* PLL Mux */
clks[IMX7ULP_CLK_APLL_PFD_SEL] = imx_clk_hw_mux_flags("apll_pfd_sel", base + 0x508, 14, 2, apll_pfd_sels, ARRAY_SIZE(apll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
clks[IMX7ULP_CLK_SPLL_PFD_SEL] = imx_clk_hw_mux_flags("spll_pfd_sel", base + 0x608, 14, 2, spll_pfd_sels, ARRAY_SIZE(spll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
clks[IMX7ULP_CLK_APLL_SEL] = imx_clk_hw_mux_flags("apll_sel", base + 0x508, 1, 1, apll_sels, ARRAY_SIZE(apll_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
clks[IMX7ULP_CLK_SPLL_SEL] = imx_clk_hw_mux_flags("spll_sel", base + 0x608, 1, 1, spll_sels, ARRAY_SIZE(spll_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
clks[IMX7ULP_CLK_SPLL_BUS_CLK] = imx_clk_divider_gate("spll_bus_clk", "spll_sel", CLK_SET_RATE_GATE, base + 0x604, 8, 3, 0, ulp_div_table, &imx_ccm_lock);
/* scs/ddr/nic select different clock source requires that clock to be enabled first */
clks[IMX7ULP_CLK_SYS_SEL] = imx_clk_hw_mux2("scs_sel", base + 0x14, 24, 4, scs_sels, ARRAY_SIZE(scs_sels));
clks[IMX7ULP_CLK_HSRUN_SYS_SEL] = imx_clk_hw_mux2("hsrun_scs_sel", base + 0x1c, 24, 4, scs_sels, ARRAY_SIZE(scs_sels));
clks[IMX7ULP_CLK_NIC_SEL] = imx_clk_hw_mux2("nic_sel", base + 0x40, 28, 1, nic_sels, ARRAY_SIZE(nic_sels));
clks[IMX7ULP_CLK_DDR_SEL] = imx_clk_hw_mux_flags("ddr_sel", base + 0x30, 24, 1, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
clks[IMX7ULP_CLK_CORE_DIV] = imx_clk_hw_divider_flags("divcore", "scs_sel", base + 0x14, 16, 4, CLK_SET_RATE_PARENT);
clks[IMX7ULP_CLK_HSRUN_CORE_DIV] = imx_clk_hw_divider_flags("hsrun_divcore", "hsrun_scs_sel", base + 0x1c, 16, 4, CLK_SET_RATE_PARENT);
clks[IMX7ULP_CLK_DDR_DIV] = imx_clk_divider_gate("ddr_clk", "ddr_sel", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, base + 0x30, 0, 3,
0, ulp_div_table, &imx_ccm_lock);
clks[IMX7ULP_CLK_NIC0_DIV] = imx_clk_hw_divider_flags("nic0_clk", "nic_sel", base + 0x40, 24, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
clks[IMX7ULP_CLK_NIC1_DIV] = imx_clk_hw_divider_flags("nic1_clk", "nic0_clk", base + 0x40, 16, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
clks[IMX7ULP_CLK_NIC1_BUS_DIV] = imx_clk_hw_divider_flags("nic1_bus_clk", "nic1_clk", base + 0x40, 4, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
clks[IMX7ULP_CLK_GPU_DIV] = imx_clk_hw_divider("gpu_clk", "nic0_clk", base + 0x40, 20, 4);
clks[IMX7ULP_CLK_SOSC_BUS_CLK] = imx_clk_divider_gate("sosc_bus_clk", "sosc", 0, base + 0x104, 8, 3,
CLK_DIVIDER_READ_ONLY, ulp_div_table, &imx_ccm_lock);
clks[IMX7ULP_CLK_FIRC_BUS_CLK] = imx_clk_divider_gate("firc_bus_clk", "firc", 0, base + 0x304, 8, 3,
CLK_DIVIDER_READ_ONLY, ulp_div_table, &imx_ccm_lock);
imx_check_clk_hws(clks, clk_data->num);
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
}
CLK_OF_DECLARE(imx7ulp_clk_scg1, "fsl,imx7ulp-scg1", imx7ulp_clk_scg1_init);
static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
{
struct clk_hw_onecell_data *clk_data;
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_PCC2_END, GFP_KERNEL);
if (!clk_data)
return;
clk_data->num = IMX7ULP_CLK_PCC2_END;
clks = clk_data->hws;
/* PCC2 */
base = of_iomap(np, 0);
WARN_ON(!base);
clks[IMX7ULP_CLK_DMA1] = imx_clk_hw_gate("dma1", "nic1_clk", base + 0x20, 30);
clks[IMX7ULP_CLK_RGPIO2P1] = imx_clk_hw_gate("rgpio2p1", "nic1_bus_clk", base + 0x3c, 30);
clks[IMX7ULP_CLK_DMA_MUX1] = imx_clk_hw_gate("dma_mux1", "nic1_bus_clk", base + 0x84, 30);
clks[IMX7ULP_CLK_SNVS] = imx_clk_hw_gate("snvs", "nic1_bus_clk", base + 0x8c, 30);
clks[IMX7ULP_CLK_CAAM] = imx_clk_hw_gate("caam", "nic1_clk", base + 0x90, 30);
clks[IMX7ULP_CLK_LPTPM4] = imx7ulp_clk_composite("lptpm4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
clks[IMX7ULP_CLK_LPTPM5] = imx7ulp_clk_composite("lptpm5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
clks[IMX7ULP_CLK_LPIT1] = imx7ulp_clk_composite("lpit1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9c);
clks[IMX7ULP_CLK_LPSPI2] = imx7ulp_clk_composite("lpspi2", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xa4);
clks[IMX7ULP_CLK_LPSPI3] = imx7ulp_clk_composite("lpspi3", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xa8);
clks[IMX7ULP_CLK_LPI2C4] = imx7ulp_clk_composite("lpi2c4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xac);
clks[IMX7ULP_CLK_LPI2C5] = imx7ulp_clk_composite("lpi2c5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb0);
clks[IMX7ULP_CLK_LPUART4] = imx7ulp_clk_composite("lpuart4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb4);
clks[IMX7ULP_CLK_LPUART5] = imx7ulp_clk_composite("lpuart5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb8);
clks[IMX7ULP_CLK_FLEXIO1] = imx7ulp_clk_composite("flexio1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xc4);
clks[IMX7ULP_CLK_USB0] = imx7ulp_clk_composite("usb0", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xcc);
clks[IMX7ULP_CLK_USB1] = imx7ulp_clk_composite("usb1", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xd0);
clks[IMX7ULP_CLK_USB_PHY] = imx_clk_hw_gate("usb_phy", "nic1_bus_clk", base + 0xd4, 30);
clks[IMX7ULP_CLK_USDHC0] = imx7ulp_clk_composite("usdhc0", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xdc);
clks[IMX7ULP_CLK_USDHC1] = imx7ulp_clk_composite("usdhc1", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xe0);
clks[IMX7ULP_CLK_WDG1] = imx7ulp_clk_composite("wdg1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0xf4);
clks[IMX7ULP_CLK_WDG2] = imx7ulp_clk_composite("sdg2", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0x10c);
imx_check_clk_hws(clks, clk_data->num);
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
}
CLK_OF_DECLARE(imx7ulp_clk_pcc2, "fsl,imx7ulp-pcc2", imx7ulp_clk_pcc2_init);
static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
{
struct clk_hw_onecell_data *clk_data;
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_PCC3_END, GFP_KERNEL);
if (!clk_data)
return;
clk_data->num = IMX7ULP_CLK_PCC3_END;
clks = clk_data->hws;
/* PCC3 */
base = of_iomap(np, 0);
WARN_ON(!base);
clks[IMX7ULP_CLK_LPTPM6] = imx7ulp_clk_composite("lptpm6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x84);
clks[IMX7ULP_CLK_LPTPM7] = imx7ulp_clk_composite("lptpm7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x88);
clks[IMX7ULP_CLK_MMDC] = clk_hw_register_gate(NULL, "mmdc", "nic1_clk", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
base + 0xac, 30, 0, &imx_ccm_lock);
clks[IMX7ULP_CLK_LPI2C6] = imx7ulp_clk_composite("lpi2c6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x90);
clks[IMX7ULP_CLK_LPI2C7] = imx7ulp_clk_composite("lpi2c7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
clks[IMX7ULP_CLK_LPUART6] = imx7ulp_clk_composite("lpuart6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
clks[IMX7ULP_CLK_LPUART7] = imx7ulp_clk_composite("lpuart7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9c);
clks[IMX7ULP_CLK_DSI] = imx7ulp_clk_composite("dsi", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0xa4);
clks[IMX7ULP_CLK_LCDIF] = imx7ulp_clk_composite("lcdif", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xa8);
clks[IMX7ULP_CLK_VIU] = imx_clk_hw_gate("viu", "nic1_clk", base + 0xa0, 30);
clks[IMX7ULP_CLK_PCTLC] = imx_clk_hw_gate("pctlc", "nic1_bus_clk", base + 0xb8, 30);
clks[IMX7ULP_CLK_PCTLD] = imx_clk_hw_gate("pctld", "nic1_bus_clk", base + 0xbc, 30);
clks[IMX7ULP_CLK_PCTLE] = imx_clk_hw_gate("pctle", "nic1_bus_clk", base + 0xc0, 30);
clks[IMX7ULP_CLK_PCTLF] = imx_clk_hw_gate("pctlf", "nic1_bus_clk", base + 0xc4, 30);
clks[IMX7ULP_CLK_GPU3D] = imx7ulp_clk_composite("gpu3d", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x140);
clks[IMX7ULP_CLK_GPU2D] = imx7ulp_clk_composite("gpu2d", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x144);
imx_check_clk_hws(clks, clk_data->num);
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
}
CLK_OF_DECLARE(imx7ulp_clk_pcc3, "fsl,imx7ulp-pcc3", imx7ulp_clk_pcc3_init);
static void __init imx7ulp_clk_smc1_init(struct device_node *np)
{
struct clk_hw_onecell_data *clk_data;
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_SMC1_END, GFP_KERNEL);
if (!clk_data)
return;
clk_data->num = IMX7ULP_CLK_SMC1_END;
clks = clk_data->hws;
/* SMC1 */
base = of_iomap(np, 0);
WARN_ON(!base);
clks[IMX7ULP_CLK_ARM] = imx_clk_hw_mux_flags("arm", base + 0x10, 8, 2, arm_sels, ARRAY_SIZE(arm_sels), CLK_IS_CRITICAL);
imx_check_clk_hws(clks, clk_data->num);
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
}
CLK_OF_DECLARE(imx7ulp_clk_smc1, "fsl,imx7ulp-smc1", imx7ulp_clk_smc1_init);

View file

@ -0,0 +1,589 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2018 NXP.
* Copyright (C) 2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
*/
#include <dt-bindings/clock/imx8mq-clock.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include "clk.h"
static u32 share_count_sai1;
static u32 share_count_sai2;
static u32 share_count_sai3;
static u32 share_count_sai4;
static u32 share_count_sai5;
static u32 share_count_sai6;
static u32 share_count_dcss;
static u32 share_count_nand;
static struct clk *clks[IMX8MQ_CLK_END];
static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", };
static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", };
static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", };
static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", };
static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", };
static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", };
static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", };
static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", };
static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", };
/* CCM ROOT */
static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
"sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", };
static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
"sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", };
static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out",
"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out",
"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m",
"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",};
static const char *imx8mq_enet_axi_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m",
"sys2_pll_200m", "audio_pll1_out", "video_pll1_out", "sys3_pll2_out", };
static const char *imx8mq_nand_usdhc_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_200m",
"sys1_pll_133m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll1_out", };
static const char *imx8mq_vpu_bus_sels[] = {"osc_25m", "sys1_pll_800m", "vpu_pll_out", "audio_pll2_out", "sys3_pll2_out", "sys2_pll_1000m", "sys2_pll_200m", "sys1_pll_100m", };
static const char *imx8mq_disp_axi_sels[] = {"osc_25m", "sys2_pll_125m", "sys1_pll_800m", "sys3_pll2_out", "sys1_pll_400m", "audio_pll2_out", "clk_ext1", "clk_ext4", };
static const char *imx8mq_disp_apb_sels[] = {"osc_25m", "sys2_pll_125m", "sys1_pll_800m", "sys3_pll2_out",
"sys1_pll_40m", "audio_pll2_out", "clk_ext1", "clk_ext3", };
static const char *imx8mq_disp_rtrm_sels[] = {"osc_25m", "sys1_pll_800m", "sys2_pll_200m", "sys1_pll_400m",
"audio_pll1_out", "video_pll1_out", "clk_ext2", "clk_ext3", };
static const char *imx8mq_usb_bus_sels[] = {"osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_100m",
"sys2_pll_200m", "clk_ext2", "clk_ext4", "audio_pll2_out", };
static const char *imx8mq_gpu_axi_sels[] = {"osc_25m", "sys1_pll_800m", "gpu_pll_out", "sys3_pll2_out", "sys2_pll_1000m",
"audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
static const char *imx8mq_gpu_ahb_sels[] = {"osc_25m", "sys1_pll_800m", "gpu_pll_out", "sys3_pll2_out", "sys2_pll_1000m",
"audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
static const char *imx8mq_noc_sels[] = {"osc_25m", "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_1000m", "sys2_pll_500m",
"audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
static const char *imx8mq_noc_apb_sels[] = {"osc_25m", "sys1_pll_400m", "sys3_pll2_out", "sys2_pll_333m", "sys2_pll_200m",
"sys1_pll_800m", "audio_pll1_out", "video_pll1_out", };
static const char *imx8mq_ahb_sels[] = {"osc_25m", "sys1_pll_133m", "sys1_pll_800m", "sys1_pll_400m",
"sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", "video_pll1_out", };
static const char *imx8mq_audio_ahb_sels[] = {"osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_1000m",
"sys2_pll_166m", "sys3_pll2_out", "audio_pll1_out", "video_pll1_out", };
static const char *imx8mq_dsi_ahb_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out"};
static const char *imx8mq_dram_alt_sels[] = {"osc_25m", "sys1_pll_800m", "sys1_pll_100m", "sys2_pll_500m",
"sys2_pll_250m", "sys1_pll_400m", "audio_pll1_out", "sys1_pll_266m", };
static const char *imx8mq_dram_apb_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
"sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
static const char *imx8mq_vpu_g1_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_100m", "sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", };
static const char *imx8mq_vpu_g2_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_100m", "sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", };
static const char *imx8mq_disp_dtrc_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_160m", "sys2_pll_100m", "sys3_pll2_out", "audio_pll2_out", };
static const char *imx8mq_disp_dc8000_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_160m", "sys2_pll_100m", "sys3_pll2_out", "audio_pll2_out", };
static const char *imx8mq_pcie1_ctrl_sels[] = {"osc_25m", "sys2_pll_250m", "sys2_pll_200m", "sys1_pll_266m",
"sys1_pll_800m", "sys2_pll_500m", "sys2_pll_250m", "sys3_pll2_out", };
static const char *imx8mq_pcie1_phy_sels[] = {"osc_25m", "sys2_pll_100m", "sys2_pll_500m", "clk_ext1", "clk_ext2",
"clk_ext3", "clk_ext4", };
static const char *imx8mq_pcie1_aux_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_500m", "sys3_pll2_out",
"sys2_pll_100m", "sys1_pll_80m", "sys1_pll_160m", "sys1_pll_200m", };
static const char *imx8mq_dc_pixel_sels[] = {"osc_25m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll2_out", "clk_ext4", };
static const char *imx8mq_lcdif_pixel_sels[] = {"osc_25m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll2_out", "clk_ext4", };
static const char *imx8mq_sai1_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext1", "clk_ext2", };
static const char *imx8mq_sai2_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
static const char *imx8mq_sai3_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
static const char *imx8mq_sai4_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext1", "clk_ext2", };
static const char *imx8mq_sai5_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
static const char *imx8mq_sai6_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
static const char *imx8mq_spdif1_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
static const char *imx8mq_spdif2_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
static const char *imx8mq_enet_ref_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_500m", "sys2_pll_100m",
"sys1_pll_160m", "audio_pll1_out", "video_pll1_out", "clk_ext4", };
static const char *imx8mq_enet_timer_sels[] = {"osc_25m", "sys2_pll_100m", "audio_pll1_out", "clk_ext1", "clk_ext2",
"clk_ext3", "clk_ext4", "video_pll1_out", };
static const char *imx8mq_enet_phy_sels[] = {"osc_25m", "sys2_pll_50m", "sys2_pll_125m", "sys2_pll_500m",
"audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
static const char *imx8mq_nand_sels[] = {"osc_25m", "sys2_pll_500m", "audio_pll1_out", "sys1_pll_400m",
"audio_pll2_out", "sys3_pll2_out", "sys2_pll_250m", "video_pll1_out", };
static const char *imx8mq_qspi_sels[] = {"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m",
"audio_pll2_out", "sys1_pll_266m", "sys3_pll2_out", "sys1_pll_100m", };
static const char *imx8mq_usdhc1_sels[] = {"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m",
"audio_pll2_out", "sys1_pll_266m", "sys3_pll2_out", "sys1_pll_100m", };
static const char *imx8mq_usdhc2_sels[] = {"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m",
"audio_pll2_out", "sys1_pll_266m", "sys3_pll2_out", "sys1_pll_100m", };
static const char *imx8mq_i2c1_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll2_out", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
static const char *imx8mq_i2c2_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll2_out", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
static const char *imx8mq_i2c3_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll2_out", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
static const char *imx8mq_i2c4_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll2_out", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
static const char *imx8mq_uart1_sels[] = {"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m",
"sys3_pll2_out", "clk_ext2", "clk_ext4", "audio_pll2_out", };
static const char *imx8mq_uart2_sels[] = {"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m",
"sys3_pll2_out", "clk_ext2", "clk_ext3", "audio_pll2_out", };
static const char *imx8mq_uart3_sels[] = {"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m",
"sys3_pll2_out", "clk_ext2", "clk_ext4", "audio_pll2_out", };
static const char *imx8mq_uart4_sels[] = {"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m",
"sys3_pll2_out", "clk_ext2", "clk_ext3", "audio_pll2_out", };
static const char *imx8mq_usb_core_sels[] = {"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m",
"sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
static const char *imx8mq_usb_phy_sels[] = {"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m",
"sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
static const char *imx8mq_ecspi1_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
"sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
static const char *imx8mq_ecspi2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
"sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
static const char *imx8mq_pwm1_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_160m", "sys1_pll_40m",
"sys3_pll2_out", "clk_ext1", "sys1_pll_80m", "video_pll1_out", };
static const char *imx8mq_pwm2_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_160m", "sys1_pll_40m",
"sys3_pll2_out", "clk_ext1", "sys1_pll_80m", "video_pll1_out", };
static const char *imx8mq_pwm3_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_160m", "sys1_pll_40m",
"sys3_pll2_out", "clk_ext2", "sys1_pll_80m", "video_pll1_out", };
static const char *imx8mq_pwm4_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_160m", "sys1_pll_40m",
"sys3_pll2_out", "clk_ext2", "sys1_pll_80m", "video_pll1_out", };
static const char *imx8mq_gpt1_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_400m", "sys1_pll_40m",
"sys1_pll_80m", "audio_pll1_out", "clk_ext1", };
static const char *imx8mq_wdog_sels[] = {"osc_25m", "sys1_pll_133m", "sys1_pll_160m", "vpu_pll_out",
"sys2_pll_125m", "sys3_pll2_out", "sys1_pll_80m", "sys2_pll_166m", };
static const char *imx8mq_wrclk_sels[] = {"osc_25m", "sys1_pll_40m", "vpu_pll_out", "sys3_pll2_out", "sys2_pll_200m",
"sys1_pll_266m", "sys2_pll_500m", "sys1_pll_100m", };
static const char *imx8mq_dsi_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
static const char *imx8mq_dsi_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
"sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
static const char *imx8mq_dsi_dbi_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_100m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
static const char *imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
static const char *imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
static const char *imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
"sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
static const char *imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
static const char *imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
static const char *imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
"sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
static const char *imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
"sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
static const char *imx8mq_pcie2_ctrl_sels[] = {"osc_25m", "sys2_pll_250m", "sys2_pll_200m", "sys1_pll_266m",
"sys1_pll_800m", "sys2_pll_500m", "sys2_pll_333m", "sys3_pll2_out", };
static const char *imx8mq_pcie2_phy_sels[] = {"osc_25m", "sys2_pll_100m", "sys2_pll_500m", "clk_ext1",
"clk_ext2", "clk_ext3", "clk_ext4", "sys1_pll_400m", };
static const char *imx8mq_pcie2_aux_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_50m", "sys3_pll2_out",
"sys2_pll_100m", "sys1_pll_80m", "sys1_pll_160m", "sys1_pll_200m", };
static const char *imx8mq_ecspi3_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
"sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
static const char *imx8mq_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
static const char *imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_400m", "sys2_pll_166m", "audio_pll1_out",
"video_pll1_out", "ckil", };
static struct clk_onecell_data clk_data;
static int imx8mq_clocks_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
void __iomem *base;
int err;
int i;
clks[IMX8MQ_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clks[IMX8MQ_CLK_32K] = of_clk_get_by_name(np, "ckil");
clks[IMX8MQ_CLK_25M] = of_clk_get_by_name(np, "osc_25m");
clks[IMX8MQ_CLK_27M] = of_clk_get_by_name(np, "osc_27m");
clks[IMX8MQ_CLK_EXT1] = of_clk_get_by_name(np, "clk_ext1");
clks[IMX8MQ_CLK_EXT2] = of_clk_get_by_name(np, "clk_ext2");
clks[IMX8MQ_CLK_EXT3] = of_clk_get_by_name(np, "clk_ext3");
clks[IMX8MQ_CLK_EXT4] = of_clk_get_by_name(np, "clk_ext4");
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
base = of_iomap(np, 0);
if (WARN_ON(!base))
return -ENOMEM;
clks[IMX8MQ_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", base + 0x20, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", base + 0x8, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", base + 0x10, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_SYS1_PLL1_REF_SEL] = imx_clk_mux("sys1_pll1_ref_sel", base + 0x30, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_SYS2_PLL1_REF_SEL] = imx_clk_mux("sys2_pll1_ref_sel", base + 0x3c, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_SYS3_PLL1_REF_SEL] = imx_clk_mux("sys3_pll1_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_DRAM_PLL1_REF_SEL] = imx_clk_mux("dram_pll1_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
clks[IMX8MQ_ARM_PLL_REF_DIV] = imx_clk_divider("arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6);
clks[IMX8MQ_GPU_PLL_REF_DIV] = imx_clk_divider("gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6);
clks[IMX8MQ_VPU_PLL_REF_DIV] = imx_clk_divider("vpu_pll_ref_div", "vpu_pll_ref_sel", base + 0x20, 5, 6);
clks[IMX8MQ_AUDIO_PLL1_REF_DIV] = imx_clk_divider("audio_pll1_ref_div", "audio_pll1_ref_sel", base + 0x0, 5, 6);
clks[IMX8MQ_AUDIO_PLL2_REF_DIV] = imx_clk_divider("audio_pll2_ref_div", "audio_pll2_ref_sel", base + 0x8, 5, 6);
clks[IMX8MQ_VIDEO_PLL1_REF_DIV] = imx_clk_divider("video_pll1_ref_div", "video_pll1_ref_sel", base + 0x10, 5, 6);
clks[IMX8MQ_SYS1_PLL1_REF_DIV] = imx_clk_divider("sys1_pll1_ref_div", "sys1_pll1_ref_sel", base + 0x38, 25, 3);
clks[IMX8MQ_SYS2_PLL1_REF_DIV] = imx_clk_divider("sys2_pll1_ref_div", "sys2_pll1_ref_sel", base + 0x44, 25, 3);
clks[IMX8MQ_SYS3_PLL1_REF_DIV] = imx_clk_divider("sys3_pll1_ref_div", "sys3_pll1_ref_sel", base + 0x50, 25, 3);
clks[IMX8MQ_DRAM_PLL1_REF_DIV] = imx_clk_divider("dram_pll1_ref_div", "dram_pll1_ref_sel", base + 0x68, 25, 3);
clks[IMX8MQ_ARM_PLL] = imx_clk_frac_pll("arm_pll", "arm_pll_ref_div", base + 0x28);
clks[IMX8MQ_GPU_PLL] = imx_clk_frac_pll("gpu_pll", "gpu_pll_ref_div", base + 0x18);
clks[IMX8MQ_VPU_PLL] = imx_clk_frac_pll("vpu_pll", "vpu_pll_ref_div", base + 0x20);
clks[IMX8MQ_AUDIO_PLL1] = imx_clk_frac_pll("audio_pll1", "audio_pll1_ref_div", base + 0x0);
clks[IMX8MQ_AUDIO_PLL2] = imx_clk_frac_pll("audio_pll2", "audio_pll2_ref_div", base + 0x8);
clks[IMX8MQ_VIDEO_PLL1] = imx_clk_frac_pll("video_pll1", "video_pll1_ref_div", base + 0x10);
clks[IMX8MQ_SYS1_PLL1] = imx_clk_sccg_pll("sys1_pll1", "sys1_pll1_ref_div", base + 0x30, SCCG_PLL1);
clks[IMX8MQ_SYS2_PLL1] = imx_clk_sccg_pll("sys2_pll1", "sys2_pll1_ref_div", base + 0x3c, SCCG_PLL1);
clks[IMX8MQ_SYS3_PLL1] = imx_clk_sccg_pll("sys3_pll1", "sys3_pll1_ref_div", base + 0x48, SCCG_PLL1);
clks[IMX8MQ_DRAM_PLL1] = imx_clk_sccg_pll("dram_pll1", "dram_pll1_ref_div", base + 0x60, SCCG_PLL1);
clks[IMX8MQ_SYS1_PLL2] = imx_clk_sccg_pll("sys1_pll2", "sys1_pll1_out_div", base + 0x30, SCCG_PLL2);
clks[IMX8MQ_SYS2_PLL2] = imx_clk_sccg_pll("sys2_pll2", "sys2_pll1_out_div", base + 0x3c, SCCG_PLL2);
clks[IMX8MQ_SYS3_PLL2] = imx_clk_sccg_pll("sys3_pll2", "sys3_pll1_out_div", base + 0x48, SCCG_PLL2);
clks[IMX8MQ_DRAM_PLL2] = imx_clk_sccg_pll("dram_pll2", "dram_pll1_out_div", base + 0x60, SCCG_PLL2);
/* PLL divs */
clks[IMX8MQ_SYS1_PLL1_OUT_DIV] = imx_clk_divider("sys1_pll1_out_div", "sys1_pll1_out", base + 0x38, 19, 6);
clks[IMX8MQ_SYS2_PLL1_OUT_DIV] = imx_clk_divider("sys2_pll1_out_div", "sys2_pll1_out", base + 0x44, 19, 6);
clks[IMX8MQ_SYS3_PLL1_OUT_DIV] = imx_clk_divider("sys3_pll1_out_div", "sys3_pll1_out", base + 0x50, 19, 6);
clks[IMX8MQ_DRAM_PLL1_OUT_DIV] = imx_clk_divider("dram_pll1_out_div", "dram_pll1_out", base + 0x68, 19, 6);
clks[IMX8MQ_SYS1_PLL2_DIV] = imx_clk_divider("sys1_pll2_div", "sys1_pll2", base + 0x38, 1, 6);
clks[IMX8MQ_SYS2_PLL2_DIV] = imx_clk_divider("sys2_pll2_div", "sys2_pll2", base + 0x44, 1, 6);
clks[IMX8MQ_SYS3_PLL2_DIV] = imx_clk_divider("sys3_pll2_div", "sys3_pll2", base + 0x50, 1, 6);
clks[IMX8MQ_DRAM_PLL2_DIV] = imx_clk_divider("dram_pll2_div", "dram_pll2", base + 0x68, 1, 6);
/* PLL bypass out */
clks[IMX8MQ_ARM_PLL_BYPASS] = imx_clk_mux("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels));
clks[IMX8MQ_GPU_PLL_BYPASS] = imx_clk_mux("gpu_pll_bypass", base + 0x18, 14, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels));
clks[IMX8MQ_VPU_PLL_BYPASS] = imx_clk_mux("vpu_pll_bypass", base + 0x20, 14, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels));
clks[IMX8MQ_AUDIO_PLL1_BYPASS] = imx_clk_mux("audio_pll1_bypass", base + 0x0, 14, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels));
clks[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels));
clks[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels));
clks[IMX8MQ_SYS1_PLL1_OUT] = imx_clk_mux("sys1_pll1_out", base + 0x30, 5, 1, sys1_pll1_out_sels, ARRAY_SIZE(sys1_pll1_out_sels));
clks[IMX8MQ_SYS2_PLL1_OUT] = imx_clk_mux("sys2_pll1_out", base + 0x3c, 5, 1, sys2_pll1_out_sels, ARRAY_SIZE(sys2_pll1_out_sels));
clks[IMX8MQ_SYS3_PLL1_OUT] = imx_clk_mux("sys3_pll1_out", base + 0x48, 5, 1, sys3_pll1_out_sels, ARRAY_SIZE(sys3_pll1_out_sels));
clks[IMX8MQ_DRAM_PLL1_OUT] = imx_clk_mux("dram_pll1_out", base + 0x60, 5, 1, dram_pll1_out_sels, ARRAY_SIZE(dram_pll1_out_sels));
clks[IMX8MQ_SYS1_PLL2_OUT] = imx_clk_mux("sys1_pll2_out", base + 0x30, 4, 1, sys1_pll2_out_sels, ARRAY_SIZE(sys1_pll2_out_sels));
clks[IMX8MQ_SYS2_PLL2_OUT] = imx_clk_mux("sys2_pll2_out", base + 0x3c, 4, 1, sys2_pll2_out_sels, ARRAY_SIZE(sys2_pll2_out_sels));
clks[IMX8MQ_SYS3_PLL2_OUT] = imx_clk_mux("sys3_pll2_out", base + 0x48, 4, 1, sys3_pll2_out_sels, ARRAY_SIZE(sys3_pll2_out_sels));
clks[IMX8MQ_DRAM_PLL2_OUT] = imx_clk_mux("dram_pll2_out", base + 0x60, 4, 1, dram_pll2_out_sels, ARRAY_SIZE(dram_pll2_out_sels));
/* PLL OUT GATE */
clks[IMX8MQ_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21);
clks[IMX8MQ_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21);
clks[IMX8MQ_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x20, 21);
clks[IMX8MQ_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base + 0x0, 21);
clks[IMX8MQ_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x8, 21);
clks[IMX8MQ_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x10, 21);
clks[IMX8MQ_SYS1_PLL_OUT] = imx_clk_gate("sys1_pll_out", "sys1_pll2_out", base + 0x30, 9);
clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_gate("sys2_pll_out", "sys2_pll2_out", base + 0x3c, 9);
clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_gate("sys3_pll_out", "sys3_pll2_out", base + 0x48, 9);
clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll2_out", base + 0x60, 9);
/* SYS PLL fixed output */
clks[IMX8MQ_SYS1_PLL_40M] = imx_clk_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20);
clks[IMX8MQ_SYS1_PLL_80M] = imx_clk_fixed_factor("sys1_pll_80m", "sys1_pll_out", 1, 10);
clks[IMX8MQ_SYS1_PLL_100M] = imx_clk_fixed_factor("sys1_pll_100m", "sys1_pll_out", 1, 8);
clks[IMX8MQ_SYS1_PLL_133M] = imx_clk_fixed_factor("sys1_pll_133m", "sys1_pll_out", 1, 6);
clks[IMX8MQ_SYS1_PLL_160M] = imx_clk_fixed_factor("sys1_pll_160m", "sys1_pll_out", 1, 5);
clks[IMX8MQ_SYS1_PLL_200M] = imx_clk_fixed_factor("sys1_pll_200m", "sys1_pll_out", 1, 4);
clks[IMX8MQ_SYS1_PLL_266M] = imx_clk_fixed_factor("sys1_pll_266m", "sys1_pll_out", 1, 3);
clks[IMX8MQ_SYS1_PLL_400M] = imx_clk_fixed_factor("sys1_pll_400m", "sys1_pll_out", 1, 2);
clks[IMX8MQ_SYS1_PLL_800M] = imx_clk_fixed_factor("sys1_pll_800m", "sys1_pll_out", 1, 1);
clks[IMX8MQ_SYS2_PLL_50M] = imx_clk_fixed_factor("sys2_pll_50m", "sys2_pll_out", 1, 20);
clks[IMX8MQ_SYS2_PLL_100M] = imx_clk_fixed_factor("sys2_pll_100m", "sys2_pll_out", 1, 10);
clks[IMX8MQ_SYS2_PLL_125M] = imx_clk_fixed_factor("sys2_pll_125m", "sys2_pll_out", 1, 8);
clks[IMX8MQ_SYS2_PLL_166M] = imx_clk_fixed_factor("sys2_pll_166m", "sys2_pll_out", 1, 6);
clks[IMX8MQ_SYS2_PLL_200M] = imx_clk_fixed_factor("sys2_pll_200m", "sys2_pll_out", 1, 5);
clks[IMX8MQ_SYS2_PLL_250M] = imx_clk_fixed_factor("sys2_pll_250m", "sys2_pll_out", 1, 4);
clks[IMX8MQ_SYS2_PLL_333M] = imx_clk_fixed_factor("sys2_pll_333m", "sys2_pll_out", 1, 3);
clks[IMX8MQ_SYS2_PLL_500M] = imx_clk_fixed_factor("sys2_pll_500m", "sys2_pll_out", 1, 2);
clks[IMX8MQ_SYS2_PLL_1000M] = imx_clk_fixed_factor("sys2_pll_1000m", "sys2_pll_out", 1, 1);
np = dev->of_node;
base = of_iomap(np, 0);
if (WARN_ON(!base))
return -ENOMEM;
/* CORE */
clks[IMX8MQ_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
clks[IMX8MQ_CLK_VPU_SRC] = imx_clk_mux2("vpu_src", base + 0x8100, 24, 3, imx8mq_vpu_sels, ARRAY_SIZE(imx8mq_vpu_sels));
clks[IMX8MQ_CLK_GPU_CORE_SRC] = imx_clk_mux2("gpu_core_src", base + 0x8180, 24, 3, imx8mq_gpu_core_sels, ARRAY_SIZE(imx8mq_gpu_core_sels));
clks[IMX8MQ_CLK_GPU_SHADER_SRC] = imx_clk_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mq_gpu_shader_sels, ARRAY_SIZE(imx8mq_gpu_shader_sels));
clks[IMX8MQ_CLK_A53_CG] = imx_clk_gate3_flags("arm_a53_cg", "arm_a53_src", base + 0x8000, 28, CLK_IS_CRITICAL);
clks[IMX8MQ_CLK_VPU_CG] = imx_clk_gate3("vpu_cg", "vpu_src", base + 0x8100, 28);
clks[IMX8MQ_CLK_GPU_CORE_CG] = imx_clk_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28);
clks[IMX8MQ_CLK_GPU_SHADER_CG] = imx_clk_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28);
clks[IMX8MQ_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
clks[IMX8MQ_CLK_VPU_DIV] = imx_clk_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3);
clks[IMX8MQ_CLK_GPU_CORE_DIV] = imx_clk_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3);
clks[IMX8MQ_CLK_GPU_SHADER_DIV] = imx_clk_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3);
/* BUS */
clks[IMX8MQ_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mq_main_axi_sels, base + 0x8800);
clks[IMX8MQ_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mq_enet_axi_sels, base + 0x8880);
clks[IMX8MQ_CLK_NAND_USDHC_BUS] = imx8m_clk_composite("nand_usdhc_bus", imx8mq_nand_usdhc_sels, base + 0x8900);
clks[IMX8MQ_CLK_VPU_BUS] = imx8m_clk_composite("vpu_bus", imx8mq_vpu_bus_sels, base + 0x8980);
clks[IMX8MQ_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mq_disp_axi_sels, base + 0x8a00);
clks[IMX8MQ_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mq_disp_apb_sels, base + 0x8a80);
clks[IMX8MQ_CLK_DISP_RTRM] = imx8m_clk_composite("disp_rtrm", imx8mq_disp_rtrm_sels, base + 0x8b00);
clks[IMX8MQ_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mq_usb_bus_sels, base + 0x8b80);
clks[IMX8MQ_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mq_gpu_axi_sels, base + 0x8c00);
clks[IMX8MQ_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mq_gpu_ahb_sels, base + 0x8c80);
clks[IMX8MQ_CLK_NOC] = imx8m_clk_composite_critical("noc", imx8mq_noc_sels, base + 0x8d00);
clks[IMX8MQ_CLK_NOC_APB] = imx8m_clk_composite_critical("noc_apb", imx8mq_noc_apb_sels, base + 0x8d80);
/* AHB */
clks[IMX8MQ_CLK_AHB] = imx8m_clk_composite("ahb", imx8mq_ahb_sels, base + 0x9000);
clks[IMX8MQ_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mq_audio_ahb_sels, base + 0x9100);
/* IPG */
clks[IMX8MQ_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1);
clks[IMX8MQ_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1);
/* IP */
clks[IMX8MQ_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mq_dram_core_sels, ARRAY_SIZE(imx8mq_dram_core_sels), CLK_IS_CRITICAL);
clks[IMX8MQ_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mq_dram_alt_sels, base + 0xa000);
clks[IMX8MQ_CLK_DRAM_APB] = imx8m_clk_composite_critical("dram_apb", imx8mq_dram_apb_sels, base + 0xa080);
clks[IMX8MQ_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mq_vpu_g1_sels, base + 0xa100);
clks[IMX8MQ_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mq_vpu_g2_sels, base + 0xa180);
clks[IMX8MQ_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mq_disp_dtrc_sels, base + 0xa200);
clks[IMX8MQ_CLK_DISP_DC8000] = imx8m_clk_composite("disp_dc8000", imx8mq_disp_dc8000_sels, base + 0xa280);
clks[IMX8MQ_CLK_PCIE1_CTRL] = imx8m_clk_composite("pcie1_ctrl", imx8mq_pcie1_ctrl_sels, base + 0xa300);
clks[IMX8MQ_CLK_PCIE1_PHY] = imx8m_clk_composite("pcie1_phy", imx8mq_pcie1_phy_sels, base + 0xa380);
clks[IMX8MQ_CLK_PCIE1_AUX] = imx8m_clk_composite("pcie1_aux", imx8mq_pcie1_aux_sels, base + 0xa400);
clks[IMX8MQ_CLK_DC_PIXEL] = imx8m_clk_composite("dc_pixel", imx8mq_dc_pixel_sels, base + 0xa480);
clks[IMX8MQ_CLK_LCDIF_PIXEL] = imx8m_clk_composite("lcdif_pixel", imx8mq_lcdif_pixel_sels, base + 0xa500);
clks[IMX8MQ_CLK_SAI1] = imx8m_clk_composite("sai1", imx8mq_sai1_sels, base + 0xa580);
clks[IMX8MQ_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mq_sai2_sels, base + 0xa600);
clks[IMX8MQ_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mq_sai3_sels, base + 0xa680);
clks[IMX8MQ_CLK_SAI4] = imx8m_clk_composite("sai4", imx8mq_sai4_sels, base + 0xa700);
clks[IMX8MQ_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mq_sai5_sels, base + 0xa780);
clks[IMX8MQ_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mq_sai6_sels, base + 0xa800);
clks[IMX8MQ_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mq_spdif1_sels, base + 0xa880);
clks[IMX8MQ_CLK_SPDIF2] = imx8m_clk_composite("spdif2", imx8mq_spdif2_sels, base + 0xa900);
clks[IMX8MQ_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mq_enet_ref_sels, base + 0xa980);
clks[IMX8MQ_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mq_enet_timer_sels, base + 0xaa00);
clks[IMX8MQ_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mq_enet_phy_sels, base + 0xaa80);
clks[IMX8MQ_CLK_NAND] = imx8m_clk_composite("nand", imx8mq_nand_sels, base + 0xab00);
clks[IMX8MQ_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mq_qspi_sels, base + 0xab80);
clks[IMX8MQ_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mq_usdhc1_sels, base + 0xac00);
clks[IMX8MQ_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mq_usdhc2_sels, base + 0xac80);
clks[IMX8MQ_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mq_i2c1_sels, base + 0xad00);
clks[IMX8MQ_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mq_i2c2_sels, base + 0xad80);
clks[IMX8MQ_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mq_i2c3_sels, base + 0xae00);
clks[IMX8MQ_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mq_i2c4_sels, base + 0xae80);
clks[IMX8MQ_CLK_UART1] = imx8m_clk_composite("uart1", imx8mq_uart1_sels, base + 0xaf00);
clks[IMX8MQ_CLK_UART2] = imx8m_clk_composite("uart2", imx8mq_uart2_sels, base + 0xaf80);
clks[IMX8MQ_CLK_UART3] = imx8m_clk_composite("uart3", imx8mq_uart3_sels, base + 0xb000);
clks[IMX8MQ_CLK_UART4] = imx8m_clk_composite("uart4", imx8mq_uart4_sels, base + 0xb080);
clks[IMX8MQ_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100);
clks[IMX8MQ_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180);
clks[IMX8MQ_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280);
clks[IMX8MQ_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300);
clks[IMX8MQ_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mq_pwm1_sels, base + 0xb380);
clks[IMX8MQ_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mq_pwm2_sels, base + 0xb400);
clks[IMX8MQ_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mq_pwm3_sels, base + 0xb480);
clks[IMX8MQ_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mq_pwm4_sels, base + 0xb500);
clks[IMX8MQ_CLK_GPT1] = imx8m_clk_composite("gpt1", imx8mq_gpt1_sels, base + 0xb580);
clks[IMX8MQ_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mq_wdog_sels, base + 0xb900);
clks[IMX8MQ_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mq_wrclk_sels, base + 0xb980);
clks[IMX8MQ_CLK_CLKO2] = imx8m_clk_composite("clko2", imx8mq_clko2_sels, base + 0xba80);
clks[IMX8MQ_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mq_dsi_core_sels, base + 0xbb00);
clks[IMX8MQ_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mq_dsi_phy_sels, base + 0xbb80);
clks[IMX8MQ_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mq_dsi_dbi_sels, base + 0xbc00);
clks[IMX8MQ_CLK_DSI_ESC] = imx8m_clk_composite("dsi_esc", imx8mq_dsi_esc_sels, base + 0xbc80);
clks[IMX8MQ_CLK_DSI_AHB] = imx8m_clk_composite("dsi_ahb", imx8mq_dsi_ahb_sels, base + 0x9200);
clks[IMX8MQ_CLK_CSI1_CORE] = imx8m_clk_composite("csi1_core", imx8mq_csi1_core_sels, base + 0xbd00);
clks[IMX8MQ_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mq_csi1_phy_sels, base + 0xbd80);
clks[IMX8MQ_CLK_CSI1_ESC] = imx8m_clk_composite("csi1_esc", imx8mq_csi1_esc_sels, base + 0xbe00);
clks[IMX8MQ_CLK_CSI2_CORE] = imx8m_clk_composite("csi2_core", imx8mq_csi2_core_sels, base + 0xbe80);
clks[IMX8MQ_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mq_csi2_phy_sels, base + 0xbf00);
clks[IMX8MQ_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mq_csi2_esc_sels, base + 0xbf80);
clks[IMX8MQ_CLK_PCIE2_CTRL] = imx8m_clk_composite("pcie2_ctrl", imx8mq_pcie2_ctrl_sels, base + 0xc000);
clks[IMX8MQ_CLK_PCIE2_PHY] = imx8m_clk_composite("pcie2_phy", imx8mq_pcie2_phy_sels, base + 0xc080);
clks[IMX8MQ_CLK_PCIE2_AUX] = imx8m_clk_composite("pcie2_aux", imx8mq_pcie2_aux_sels, base + 0xc100);
clks[IMX8MQ_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mq_ecspi3_sels, base + 0xc180);
clks[IMX8MQ_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0);
clks[IMX8MQ_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0);
clks[IMX8MQ_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0);
clks[IMX8MQ_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0);
clks[IMX8MQ_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0);
clks[IMX8MQ_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0);
clks[IMX8MQ_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0);
clks[IMX8MQ_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0);
clks[IMX8MQ_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0);
clks[IMX8MQ_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
clks[IMX8MQ_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
clks[IMX8MQ_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0);
clks[IMX8MQ_CLK_PCIE2_ROOT] = imx_clk_gate4("pcie2_root_clk", "pcie2_ctrl", base + 0x4640, 0);
clks[IMX8MQ_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0);
clks[IMX8MQ_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0);
clks[IMX8MQ_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0);
clks[IMX8MQ_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0);
clks[IMX8MQ_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0);
clks[IMX8MQ_CLK_RAWNAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand);
clks[IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand);
clks[IMX8MQ_CLK_SAI1_ROOT] = imx_clk_gate2_shared2("sai1_root_clk", "sai1", base + 0x4330, 0, &share_count_sai1);
clks[IMX8MQ_CLK_SAI1_IPG] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0, &share_count_sai1);
clks[IMX8MQ_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2);
clks[IMX8MQ_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_root", base + 0x4340, 0, &share_count_sai2);
clks[IMX8MQ_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3);
clks[IMX8MQ_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root", base + 0x4350, 0, &share_count_sai3);
clks[IMX8MQ_CLK_SAI4_ROOT] = imx_clk_gate2_shared2("sai4_root_clk", "sai4", base + 0x4360, 0, &share_count_sai4);
clks[IMX8MQ_CLK_SAI4_IPG] = imx_clk_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0, &share_count_sai4);
clks[IMX8MQ_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5);
clks[IMX8MQ_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
clks[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6);
clks[IMX8MQ_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
clks[IMX8MQ_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0);
clks[IMX8MQ_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0);
clks[IMX8MQ_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0);
clks[IMX8MQ_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0);
clks[IMX8MQ_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_core_ref", base + 0x44d0, 0);
clks[IMX8MQ_CLK_USB2_CTRL_ROOT] = imx_clk_gate4("usb2_ctrl_root_clk", "usb_core_ref", base + 0x44e0, 0);
clks[IMX8MQ_CLK_USB1_PHY_ROOT] = imx_clk_gate4("usb1_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0);
clks[IMX8MQ_CLK_USB2_PHY_ROOT] = imx_clk_gate4("usb2_phy_root_clk", "usb_phy_ref", base + 0x4500, 0);
clks[IMX8MQ_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0);
clks[IMX8MQ_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0);
clks[IMX8MQ_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0);
clks[IMX8MQ_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0);
clks[IMX8MQ_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0);
clks[IMX8MQ_CLK_VPU_G1_ROOT] = imx_clk_gate2_flags("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
clks[IMX8MQ_CLK_GPU_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_core_div", base + 0x4570, 0);
clks[IMX8MQ_CLK_VPU_G2_ROOT] = imx_clk_gate2_flags("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
clks[IMX8MQ_CLK_DISP_ROOT] = imx_clk_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0, &share_count_dcss);
clks[IMX8MQ_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_dcss);
clks[IMX8MQ_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_dcss);
clks[IMX8MQ_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", base + 0x45d0, 0, &share_count_dcss);
clks[IMX8MQ_CLK_TMU_ROOT] = imx_clk_gate4_flags("tmu_root_clk", "ipg_root", base + 0x4620, 0, CLK_IS_CRITICAL);
clks[IMX8MQ_CLK_VPU_DEC_ROOT] = imx_clk_gate2_flags("vpu_dec_root_clk", "vpu_bus", base + 0x4630, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
clks[IMX8MQ_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0);
clks[IMX8MQ_CLK_CSI2_ROOT] = imx_clk_gate4("csi2_root_clk", "csi2_core", base + 0x4660, 0);
clks[IMX8MQ_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
clks[IMX8MQ_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
clks[IMX8MQ_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc_25m", 1, 8);
clks[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4);
for (i = 0; i < IMX8MQ_CLK_END; i++)
if (IS_ERR(clks[i]))
pr_err("i.MX8mq clk %u register failed with %ld\n",
i, PTR_ERR(clks[i]));
clk_data.clks = clks;
clk_data.clk_num = ARRAY_SIZE(clks);
err = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
WARN_ON(err);
return err;
}
static const struct of_device_id imx8mq_clk_of_match[] = {
{ .compatible = "fsl,imx8mq-ccm" },
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, imx8mq_clk_of_match);
static struct platform_driver imx8mq_clk_driver = {
.probe = imx8mq_clocks_probe,
.driver = {
.name = "imx8mq-ccm",
.of_match_table = of_match_ptr(imx8mq_clk_of_match),
},
};
module_platform_driver(imx8mq_clk_driver);

View file

@ -0,0 +1,216 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-scu.h"
#include "clk-imx8qxp-lpcg.h"
#include <dt-bindings/clock/imx8qxp-clock.h>
/*
* struct imx8qxp_lpcg_data - Description of one LPCG clock
* @id: clock ID
* @name: clock name
* @parent: parent clock name
* @flags: common clock flags
* @offset: offset of this LPCG clock
* @bit_idx: bit index of this LPCG clock
* @hw_gate: whether supports HW autogate
*
* This structure describes one LPCG clock
*/
struct imx8qxp_lpcg_data {
int id;
char *name;
char *parent;
unsigned long flags;
u32 offset;
u8 bit_idx;
bool hw_gate;
};
/*
* struct imx8qxp_ss_lpcg - Description of one subsystem LPCG clocks
* @lpcg: LPCG clocks array of one subsystem
* @num_lpcg: the number of LPCG clocks
* @num_max: the maximum number of LPCG clocks
*
* This structure describes each subsystem LPCG clocks information
* which then will be used to create respective LPCGs clocks
*/
struct imx8qxp_ss_lpcg {
const struct imx8qxp_lpcg_data *lpcg;
u8 num_lpcg;
u8 num_max;
};
static const struct imx8qxp_lpcg_data imx8qxp_lpcg_adma[] = {
{ IMX8QXP_ADMA_LPCG_UART0_IPG_CLK, "uart0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_0_LPCG, 16, 0, },
{ IMX8QXP_ADMA_LPCG_UART0_BAUD_CLK, "uart0_lpcg_baud_clk", "uart0_clk", 0, ADMA_LPUART_0_LPCG, 0, 0, },
{ IMX8QXP_ADMA_LPCG_UART1_IPG_CLK, "uart1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_1_LPCG, 16, 0, },
{ IMX8QXP_ADMA_LPCG_UART1_BAUD_CLK, "uart1_lpcg_baud_clk", "uart1_clk", 0, ADMA_LPUART_1_LPCG, 0, 0, },
{ IMX8QXP_ADMA_LPCG_UART2_IPG_CLK, "uart2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_2_LPCG, 16, 0, },
{ IMX8QXP_ADMA_LPCG_UART2_BAUD_CLK, "uart2_lpcg_baud_clk", "uart2_clk", 0, ADMA_LPUART_2_LPCG, 0, 0, },
{ IMX8QXP_ADMA_LPCG_UART3_IPG_CLK, "uart3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPUART_3_LPCG, 16, 0, },
{ IMX8QXP_ADMA_LPCG_UART3_BAUD_CLK, "uart3_lpcg_baud_clk", "uart3_clk", 0, ADMA_LPUART_3_LPCG, 0, 0, },
{ IMX8QXP_ADMA_LPCG_I2C0_IPG_CLK, "i2c0_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_0_LPCG, 16, 0, },
{ IMX8QXP_ADMA_LPCG_I2C0_CLK, "i2c0_lpcg_clk", "i2c0_clk", 0, ADMA_LPI2C_0_LPCG, 0, 0, },
{ IMX8QXP_ADMA_LPCG_I2C1_IPG_CLK, "i2c1_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_1_LPCG, 16, 0, },
{ IMX8QXP_ADMA_LPCG_I2C1_CLK, "i2c1_lpcg_clk", "i2c1_clk", 0, ADMA_LPI2C_1_LPCG, 0, 0, },
{ IMX8QXP_ADMA_LPCG_I2C2_IPG_CLK, "i2c2_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_2_LPCG, 16, 0, },
{ IMX8QXP_ADMA_LPCG_I2C2_CLK, "i2c2_lpcg_clk", "i2c2_clk", 0, ADMA_LPI2C_2_LPCG, 0, 0, },
{ IMX8QXP_ADMA_LPCG_I2C3_IPG_CLK, "i2c3_lpcg_ipg_clk", "dma_ipg_clk_root", 0, ADMA_LPI2C_3_LPCG, 16, 0, },
{ IMX8QXP_ADMA_LPCG_I2C3_CLK, "i2c3_lpcg_clk", "i2c3_clk", 0, ADMA_LPI2C_3_LPCG, 0, 0, },
};
static const struct imx8qxp_ss_lpcg imx8qxp_ss_adma = {
.lpcg = imx8qxp_lpcg_adma,
.num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_adma),
.num_max = IMX8QXP_ADMA_LPCG_CLK_END,
};
static const struct imx8qxp_lpcg_data imx8qxp_lpcg_conn[] = {
{ IMX8QXP_CONN_LPCG_SDHC0_PER_CLK, "sdhc0_lpcg_per_clk", "sdhc0_clk", 0, CONN_USDHC_0_LPCG, 0, 0, },
{ IMX8QXP_CONN_LPCG_SDHC0_IPG_CLK, "sdhc0_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_0_LPCG, 16, 0, },
{ IMX8QXP_CONN_LPCG_SDHC0_HCLK, "sdhc0_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_0_LPCG, 20, 0, },
{ IMX8QXP_CONN_LPCG_SDHC1_PER_CLK, "sdhc1_lpcg_per_clk", "sdhc1_clk", 0, CONN_USDHC_1_LPCG, 0, 0, },
{ IMX8QXP_CONN_LPCG_SDHC1_IPG_CLK, "sdhc1_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_1_LPCG, 16, 0, },
{ IMX8QXP_CONN_LPCG_SDHC1_HCLK, "sdhc1_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_1_LPCG, 20, 0, },
{ IMX8QXP_CONN_LPCG_SDHC2_PER_CLK, "sdhc2_lpcg_per_clk", "sdhc2_clk", 0, CONN_USDHC_2_LPCG, 0, 0, },
{ IMX8QXP_CONN_LPCG_SDHC2_IPG_CLK, "sdhc2_lpcg_ipg_clk", "conn_ipg_clk_root", 0, CONN_USDHC_2_LPCG, 16, 0, },
{ IMX8QXP_CONN_LPCG_SDHC2_HCLK, "sdhc2_lpcg_ahb_clk", "conn_axi_clk_root", 0, CONN_USDHC_2_LPCG, 20, 0, },
{ IMX8QXP_CONN_LPCG_ENET0_ROOT_CLK, "enet0_ipg_root_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 0, 0, },
{ IMX8QXP_CONN_LPCG_ENET0_TX_CLK, "enet0_tx_clk", "enet0_clk", 0, CONN_ENET_0_LPCG, 4, 0, },
{ IMX8QXP_CONN_LPCG_ENET0_AHB_CLK, "enet0_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_0_LPCG, 8, 0, },
{ IMX8QXP_CONN_LPCG_ENET0_IPG_S_CLK, "enet0_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_0_LPCG, 20, 0, },
{ IMX8QXP_CONN_LPCG_ENET0_IPG_CLK, "enet0_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_0_LPCG, 16, 0, },
{ IMX8QXP_CONN_LPCG_ENET1_ROOT_CLK, "enet1_ipg_root_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 0, 0, },
{ IMX8QXP_CONN_LPCG_ENET1_TX_CLK, "enet1_tx_clk", "enet1_clk", 0, CONN_ENET_1_LPCG, 4, 0, },
{ IMX8QXP_CONN_LPCG_ENET1_AHB_CLK, "enet1_ahb_clk", "conn_axi_clk_root", 0, CONN_ENET_1_LPCG, 8, 0, },
{ IMX8QXP_CONN_LPCG_ENET1_IPG_S_CLK, "enet1_ipg_s_clk", "conn_ipg_clk_root", 0, CONN_ENET_1_LPCG, 20, 0, },
{ IMX8QXP_CONN_LPCG_ENET1_IPG_CLK, "enet1_ipg_clk", "enet0_ipg_s_clk", 0, CONN_ENET_1_LPCG, 16, 0, },
};
static const struct imx8qxp_ss_lpcg imx8qxp_ss_conn = {
.lpcg = imx8qxp_lpcg_conn,
.num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_conn),
.num_max = IMX8QXP_CONN_LPCG_CLK_END,
};
static const struct imx8qxp_lpcg_data imx8qxp_lpcg_lsio[] = {
{ IMX8QXP_LSIO_LPCG_PWM0_IPG_CLK, "pwm0_lpcg_ipg_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 0, 0, },
{ IMX8QXP_LSIO_LPCG_PWM0_IPG_HF_CLK, "pwm0_lpcg_ipg_hf_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 4, 0, },
{ IMX8QXP_LSIO_LPCG_PWM0_IPG_S_CLK, "pwm0_lpcg_ipg_s_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 16, 0, },
{ IMX8QXP_LSIO_LPCG_PWM0_IPG_SLV_CLK, "pwm0_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_0_LPCG, 20, 0, },
{ IMX8QXP_LSIO_LPCG_PWM0_IPG_MSTR_CLK, "pwm0_lpcg_ipg_mstr_clk", "pwm0_clk", 0, LSIO_PWM_0_LPCG, 24, 0, },
{ IMX8QXP_LSIO_LPCG_PWM1_IPG_CLK, "pwm1_lpcg_ipg_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 0, 0, },
{ IMX8QXP_LSIO_LPCG_PWM1_IPG_HF_CLK, "pwm1_lpcg_ipg_hf_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 4, 0, },
{ IMX8QXP_LSIO_LPCG_PWM1_IPG_S_CLK, "pwm1_lpcg_ipg_s_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 16, 0, },
{ IMX8QXP_LSIO_LPCG_PWM1_IPG_SLV_CLK, "pwm1_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_1_LPCG, 20, 0, },
{ IMX8QXP_LSIO_LPCG_PWM1_IPG_MSTR_CLK, "pwm1_lpcg_ipg_mstr_clk", "pwm1_clk", 0, LSIO_PWM_1_LPCG, 24, 0, },
{ IMX8QXP_LSIO_LPCG_PWM2_IPG_CLK, "pwm2_lpcg_ipg_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 0, 0, },
{ IMX8QXP_LSIO_LPCG_PWM2_IPG_HF_CLK, "pwm2_lpcg_ipg_hf_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 4, 0, },
{ IMX8QXP_LSIO_LPCG_PWM2_IPG_S_CLK, "pwm2_lpcg_ipg_s_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 16, 0, },
{ IMX8QXP_LSIO_LPCG_PWM2_IPG_SLV_CLK, "pwm2_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_2_LPCG, 20, 0, },
{ IMX8QXP_LSIO_LPCG_PWM2_IPG_MSTR_CLK, "pwm2_lpcg_ipg_mstr_clk", "pwm2_clk", 0, LSIO_PWM_2_LPCG, 24, 0, },
{ IMX8QXP_LSIO_LPCG_PWM3_IPG_CLK, "pwm3_lpcg_ipg_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 0, 0, },
{ IMX8QXP_LSIO_LPCG_PWM3_IPG_HF_CLK, "pwm3_lpcg_ipg_hf_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 4, 0, },
{ IMX8QXP_LSIO_LPCG_PWM3_IPG_S_CLK, "pwm3_lpcg_ipg_s_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 16, 0, },
{ IMX8QXP_LSIO_LPCG_PWM3_IPG_SLV_CLK, "pwm3_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_3_LPCG, 20, 0, },
{ IMX8QXP_LSIO_LPCG_PWM3_IPG_MSTR_CLK, "pwm3_lpcg_ipg_mstr_clk", "pwm3_clk", 0, LSIO_PWM_3_LPCG, 24, 0, },
{ IMX8QXP_LSIO_LPCG_PWM4_IPG_CLK, "pwm4_lpcg_ipg_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 0, 0, },
{ IMX8QXP_LSIO_LPCG_PWM4_IPG_HF_CLK, "pwm4_lpcg_ipg_hf_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 4, 0, },
{ IMX8QXP_LSIO_LPCG_PWM4_IPG_S_CLK, "pwm4_lpcg_ipg_s_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 16, 0, },
{ IMX8QXP_LSIO_LPCG_PWM4_IPG_SLV_CLK, "pwm4_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_4_LPCG, 20, 0, },
{ IMX8QXP_LSIO_LPCG_PWM4_IPG_MSTR_CLK, "pwm4_lpcg_ipg_mstr_clk", "pwm4_clk", 0, LSIO_PWM_4_LPCG, 24, 0, },
{ IMX8QXP_LSIO_LPCG_PWM5_IPG_CLK, "pwm5_lpcg_ipg_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 0, 0, },
{ IMX8QXP_LSIO_LPCG_PWM5_IPG_HF_CLK, "pwm5_lpcg_ipg_hf_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 4, 0, },
{ IMX8QXP_LSIO_LPCG_PWM5_IPG_S_CLK, "pwm5_lpcg_ipg_s_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 16, 0, },
{ IMX8QXP_LSIO_LPCG_PWM5_IPG_SLV_CLK, "pwm5_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_5_LPCG, 20, 0, },
{ IMX8QXP_LSIO_LPCG_PWM5_IPG_MSTR_CLK, "pwm5_lpcg_ipg_mstr_clk", "pwm5_clk", 0, LSIO_PWM_5_LPCG, 24, 0, },
{ IMX8QXP_LSIO_LPCG_PWM6_IPG_CLK, "pwm6_lpcg_ipg_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 0, 0, },
{ IMX8QXP_LSIO_LPCG_PWM6_IPG_HF_CLK, "pwm6_lpcg_ipg_hf_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 4, 0, },
{ IMX8QXP_LSIO_LPCG_PWM6_IPG_S_CLK, "pwm6_lpcg_ipg_s_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 16, 0, },
{ IMX8QXP_LSIO_LPCG_PWM6_IPG_SLV_CLK, "pwm6_lpcg_ipg_slv_clk", "lsio_bus_clk_root", 0, LSIO_PWM_6_LPCG, 20, 0, },
{ IMX8QXP_LSIO_LPCG_PWM6_IPG_MSTR_CLK, "pwm6_lpcg_ipg_mstr_clk", "pwm6_clk", 0, LSIO_PWM_6_LPCG, 24, 0, },
};
static const struct imx8qxp_ss_lpcg imx8qxp_ss_lsio = {
.lpcg = imx8qxp_lpcg_lsio,
.num_lpcg = ARRAY_SIZE(imx8qxp_lpcg_lsio),
.num_max = IMX8QXP_LSIO_LPCG_CLK_END,
};
static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct clk_hw_onecell_data *clk_data;
const struct imx8qxp_ss_lpcg *ss_lpcg;
const struct imx8qxp_lpcg_data *lpcg;
struct resource *res;
struct clk_hw **clks;
void __iomem *base;
int i;
ss_lpcg = of_device_get_match_data(dev);
if (!ss_lpcg)
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap(dev, res->start, resource_size(res));
if (!base)
return -ENOMEM;
clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
ss_lpcg->num_max), GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
clk_data->num = ss_lpcg->num_max;
clks = clk_data->hws;
for (i = 0; i < ss_lpcg->num_lpcg; i++) {
lpcg = ss_lpcg->lpcg + i;
clks[lpcg->id] = imx_clk_lpcg_scu(lpcg->name, lpcg->parent,
lpcg->flags, base + lpcg->offset,
lpcg->bit_idx, lpcg->hw_gate);
}
for (i = 0; i < clk_data->num; i++) {
if (IS_ERR(clks[i]))
pr_warn("i.MX clk %u: register failed with %ld\n",
i, PTR_ERR(clks[i]));
}
return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
}
static const struct of_device_id imx8qxp_lpcg_match[] = {
{ .compatible = "fsl,imx8qxp-lpcg-adma", &imx8qxp_ss_adma, },
{ .compatible = "fsl,imx8qxp-lpcg-conn", &imx8qxp_ss_conn, },
{ .compatible = "fsl,imx8qxp-lpcg-lsio", &imx8qxp_ss_lsio, },
{ /* sentinel */ }
};
static struct platform_driver imx8qxp_lpcg_clk_driver = {
.driver = {
.name = "imx8qxp-lpcg-clk",
.of_match_table = imx8qxp_lpcg_match,
.suppress_bind_attrs = true,
},
.probe = imx8qxp_lpcg_clk_probe,
};
builtin_platform_driver(imx8qxp_lpcg_clk_driver);

View file

@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2018 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#ifndef _IMX8QXP_LPCG_H
#define _IMX8QXP_LPCG_H
/*LSIO SS */
#define LSIO_PWM_0_LPCG 0x00000
#define LSIO_PWM_1_LPCG 0x10000
#define LSIO_PWM_2_LPCG 0x20000
#define LSIO_PWM_3_LPCG 0x30000
#define LSIO_PWM_4_LPCG 0x40000
#define LSIO_PWM_5_LPCG 0x50000
#define LSIO_PWM_6_LPCG 0x60000
#define LSIO_PWM_7_LPCG 0x70000
#define LSIO_GPIO_0_LPCG 0x80000
#define LSIO_GPIO_1_LPCG 0x90000
#define LSIO_GPIO_2_LPCG 0xa0000
#define LSIO_GPIO_3_LPCG 0xb0000
#define LSIO_GPIO_4_LPCG 0xc0000
#define LSIO_GPIO_5_LPCG 0xd0000
#define LSIO_GPIO_6_LPCG 0xe0000
#define LSIO_GPIO_7_LPCG 0xf0000
#define LSIO_FSPI_0_LPCG 0x120000
#define LSIO_FSPI_1_LPCG 0x130000
#define LSIO_GPT_0_LPCG 0x140000
#define LSIO_GPT_1_LPCG 0x150000
#define LSIO_GPT_2_LPCG 0x160000
#define LSIO_GPT_3_LPCG 0x170000
#define LSIO_GPT_4_LPCG 0x180000
#define LSIO_OCRAM_LPCG 0x190000
#define LSIO_KPP_LPCG 0x1a0000
#define LSIO_ROMCP_LPCG 0x100000
/* Connectivity SS */
#define CONN_USDHC_0_LPCG 0x00000
#define CONN_USDHC_1_LPCG 0x10000
#define CONN_USDHC_2_LPCG 0x20000
#define CONN_ENET_0_LPCG 0x30000
#define CONN_ENET_1_LPCG 0x40000
#define CONN_DTCP_LPCG 0x50000
#define CONN_MLB_LPCG 0x60000
#define CONN_USB_2_LPCG 0x70000
#define CONN_USB_3_LPCG 0x80000
#define CONN_NAND_LPCG 0x90000
#define CONN_EDMA_LPCG 0xa0000
/* ADMA SS */
#define ADMA_ASRC_0_LPCG 0x400000
#define ADMA_ESAI_0_LPCG 0x410000
#define ADMA_SPDIF_0_LPCG 0x420000
#define ADMA_SAI_0_LPCG 0x440000
#define ADMA_SAI_1_LPCG 0x450000
#define ADMA_SAI_2_LPCG 0x460000
#define ADMA_SAI_3_LPCG 0x470000
#define ADMA_GPT_5_LPCG 0x4b0000
#define ADMA_GPT_6_LPCG 0x4c0000
#define ADMA_GPT_7_LPCG 0x4d0000
#define ADMA_GPT_8_LPCG 0x4e0000
#define ADMA_GPT_9_LPCG 0x4f0000
#define ADMA_GPT_10_LPCG 0x500000
#define ADMA_HIFI_LPCG 0x580000
#define ADMA_OCRAM_LPCG 0x590000
#define ADMA_EDMA_0_LPCG 0x5f0000
#define ADMA_ASRC_1_LPCG 0xc00000
#define ADMA_SAI_4_LPCG 0xc20000
#define ADMA_SAI_5_LPCG 0xc30000
#define ADMA_AMIX_LPCG 0xc40000
#define ADMA_MQS_LPCG 0xc50000
#define ADMA_ACM_LPCG 0xc60000
#define ADMA_REC_CLK0_LPCG 0xd00000
#define ADMA_REC_CLK1_LPCG 0xd10000
#define ADMA_PLL_CLK0_LPCG 0xd20000
#define ADMA_PLL_CLK1_LPCG 0xd30000
#define ADMA_MCLKOUT0_LPCG 0xd50000
#define ADMA_MCLKOUT1_LPCG 0xd60000
#define ADMA_EDMA_1_LPCG 0xdf0000
#define ADMA_LPSPI_0_LPCG 0x1400000
#define ADMA_LPSPI_1_LPCG 0x1410000
#define ADMA_LPSPI_2_LPCG 0x1420000
#define ADMA_LPSPI_3_LPCG 0x1430000
#define ADMA_LPUART_0_LPCG 0x1460000
#define ADMA_LPUART_1_LPCG 0x1470000
#define ADMA_LPUART_2_LPCG 0x1480000
#define ADMA_LPUART_3_LPCG 0x1490000
#define ADMA_LCD_LPCG 0x1580000
#define ADMA_PWM_LPCG 0x1590000
#define ADMA_LPI2C_0_LPCG 0x1c00000
#define ADMA_LPI2C_1_LPCG 0x1c10000
#define ADMA_LPI2C_2_LPCG 0x1c20000
#define ADMA_LPI2C_3_LPCG 0x1c30000
#define ADMA_ADC_0_LPCG 0x1c80000
#define ADMA_FTM_0_LPCG 0x1ca0000
#define ADMA_FTM_1_LPCG 0x1cb0000
#define ADMA_FLEXCAN_0_LPCG 0x1cd0000
#define ADMA_FLEXCAN_1_LPCG 0x1ce0000
#define ADMA_FLEXCAN_2_LPCG 0x1cf0000
#endif /* _IMX8QXP_LPCG_H */

View file

@ -0,0 +1,153 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-scu.h"
#include <dt-bindings/clock/imx8qxp-clock.h>
#include <dt-bindings/firmware/imx/rsrc.h>
static int imx8qxp_clk_probe(struct platform_device *pdev)
{
struct device_node *ccm_node = pdev->dev.of_node;
struct clk_hw_onecell_data *clk_data;
struct clk_hw **clks;
int ret, i;
ret = imx_clk_scu_init();
if (ret)
return ret;
clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws,
IMX8QXP_SCU_CLK_END), GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
clk_data->num = IMX8QXP_SCU_CLK_END;
clks = clk_data->hws;
/* Fixed clocks */
clks[IMX8QXP_CLK_DUMMY] = clk_hw_register_fixed_rate(NULL, "dummy", NULL, 0, 0);
clks[IMX8QXP_ADMA_IPG_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "dma_ipg_clk_root", NULL, 0, 120000000);
clks[IMX8QXP_CONN_AXI_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_axi_clk_root", NULL, 0, 333333333);
clks[IMX8QXP_CONN_AHB_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_ahb_clk_root", NULL, 0, 166666666);
clks[IMX8QXP_CONN_IPG_CLK_ROOT] = clk_hw_register_fixed_rate(NULL, "conn_ipg_clk_root", NULL, 0, 83333333);
clks[IMX8QXP_DC_AXI_EXT_CLK] = clk_hw_register_fixed_rate(NULL, "dc_axi_ext_clk_root", NULL, 0, 800000000);
clks[IMX8QXP_DC_AXI_INT_CLK] = clk_hw_register_fixed_rate(NULL, "dc_axi_int_clk_root", NULL, 0, 400000000);
clks[IMX8QXP_DC_CFG_CLK] = clk_hw_register_fixed_rate(NULL, "dc_cfg_clk_root", NULL, 0, 100000000);
clks[IMX8QXP_MIPI_IPG_CLK] = clk_hw_register_fixed_rate(NULL, "mipi_ipg_clk_root", NULL, 0, 120000000);
clks[IMX8QXP_IMG_AXI_CLK] = clk_hw_register_fixed_rate(NULL, "img_axi_clk_root", NULL, 0, 400000000);
clks[IMX8QXP_IMG_IPG_CLK] = clk_hw_register_fixed_rate(NULL, "img_ipg_clk_root", NULL, 0, 200000000);
clks[IMX8QXP_IMG_PXL_CLK] = clk_hw_register_fixed_rate(NULL, "img_pxl_clk_root", NULL, 0, 600000000);
clks[IMX8QXP_HSIO_AXI_CLK] = clk_hw_register_fixed_rate(NULL, "hsio_axi_clk_root", NULL, 0, 400000000);
clks[IMX8QXP_HSIO_PER_CLK] = clk_hw_register_fixed_rate(NULL, "hsio_per_clk_root", NULL, 0, 133333333);
clks[IMX8QXP_LSIO_MEM_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_mem_clk_root", NULL, 0, 200000000);
clks[IMX8QXP_LSIO_BUS_CLK] = clk_hw_register_fixed_rate(NULL, "lsio_bus_clk_root", NULL, 0, 100000000);
/* ARM core */
clks[IMX8QXP_A35_CLK] = imx_clk_scu("a35_clk", IMX_SC_R_A35, IMX_SC_PM_CLK_CPU);
/* LSIO SS */
clks[IMX8QXP_LSIO_PWM0_CLK] = imx_clk_scu("pwm0_clk", IMX_SC_R_PWM_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_PWM1_CLK] = imx_clk_scu("pwm1_clk", IMX_SC_R_PWM_1, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_PWM2_CLK] = imx_clk_scu("pwm2_clk", IMX_SC_R_PWM_2, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_PWM3_CLK] = imx_clk_scu("pwm3_clk", IMX_SC_R_PWM_3, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_PWM4_CLK] = imx_clk_scu("pwm4_clk", IMX_SC_R_PWM_4, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_PWM5_CLK] = imx_clk_scu("pwm5_clk", IMX_SC_R_PWM_5, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_PWM6_CLK] = imx_clk_scu("pwm6_clk", IMX_SC_R_PWM_6, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_PWM7_CLK] = imx_clk_scu("pwm7_clk", IMX_SC_R_PWM_7, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_GPT0_CLK] = imx_clk_scu("gpt0_clk", IMX_SC_R_GPT_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_GPT1_CLK] = imx_clk_scu("gpt1_clk", IMX_SC_R_GPT_1, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_GPT2_CLK] = imx_clk_scu("gpt2_clk", IMX_SC_R_GPT_2, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_GPT3_CLK] = imx_clk_scu("gpt3_clk", IMX_SC_R_GPT_3, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_GPT4_CLK] = imx_clk_scu("gpt4_clk", IMX_SC_R_GPT_4, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_FSPI0_CLK] = imx_clk_scu("fspi0_clk", IMX_SC_R_FSPI_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_LSIO_FSPI1_CLK] = imx_clk_scu("fspi1_clk", IMX_SC_R_FSPI_1, IMX_SC_PM_CLK_PER);
/* ADMA SS */
clks[IMX8QXP_ADMA_UART0_CLK] = imx_clk_scu("uart0_clk", IMX_SC_R_UART_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_UART1_CLK] = imx_clk_scu("uart1_clk", IMX_SC_R_UART_1, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_UART2_CLK] = imx_clk_scu("uart2_clk", IMX_SC_R_UART_2, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_UART3_CLK] = imx_clk_scu("uart3_clk", IMX_SC_R_UART_3, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_SPI0_CLK] = imx_clk_scu("spi0_clk", IMX_SC_R_SPI_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_SPI1_CLK] = imx_clk_scu("spi1_clk", IMX_SC_R_SPI_1, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_SPI2_CLK] = imx_clk_scu("spi2_clk", IMX_SC_R_SPI_2, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_SPI3_CLK] = imx_clk_scu("spi3_clk", IMX_SC_R_SPI_3, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_CAN0_CLK] = imx_clk_scu("can0_clk", IMX_SC_R_CAN_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_I2C0_CLK] = imx_clk_scu("i2c0_clk", IMX_SC_R_I2C_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_I2C1_CLK] = imx_clk_scu("i2c1_clk", IMX_SC_R_I2C_1, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_I2C2_CLK] = imx_clk_scu("i2c2_clk", IMX_SC_R_I2C_2, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_I2C3_CLK] = imx_clk_scu("i2c3_clk", IMX_SC_R_I2C_3, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_FTM0_CLK] = imx_clk_scu("ftm0_clk", IMX_SC_R_FTM_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_FTM1_CLK] = imx_clk_scu("ftm1_clk", IMX_SC_R_FTM_1, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_ADC0_CLK] = imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_PWM_CLK] = imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_ADMA_LCD_CLK] = imx_clk_scu("lcd_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
/* Connectivity */
clks[IMX8QXP_CONN_SDHC0_CLK] = imx_clk_scu("sdhc0_clk", IMX_SC_R_SDHC_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CONN_SDHC1_CLK] = imx_clk_scu("sdhc1_clk", IMX_SC_R_SDHC_1, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CONN_SDHC2_CLK] = imx_clk_scu("sdhc2_clk", IMX_SC_R_SDHC_2, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CONN_ENET0_ROOT_CLK] = imx_clk_scu("enet0_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CONN_ENET0_BYPASS_CLK] = imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
clks[IMX8QXP_CONN_ENET0_RGMII_CLK] = imx_clk_scu("enet0_rgmii_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
clks[IMX8QXP_CONN_ENET1_ROOT_CLK] = imx_clk_scu("enet1_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CONN_ENET1_BYPASS_CLK] = imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
clks[IMX8QXP_CONN_ENET1_RGMII_CLK] = imx_clk_scu("enet1_rgmii_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
clks[IMX8QXP_CONN_GPMI_BCH_IO_CLK] = imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
clks[IMX8QXP_CONN_GPMI_BCH_CLK] = imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CONN_USB2_ACLK] = imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CONN_USB2_BUS_CLK] = imx_clk_scu("usb3_bus_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MST_BUS);
clks[IMX8QXP_CONN_USB2_LPM_CLK] = imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC);
/* Display controller SS */
clks[IMX8QXP_DC0_DISP0_CLK] = imx_clk_scu("dc0_disp0_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0);
clks[IMX8QXP_DC0_DISP1_CLK] = imx_clk_scu("dc0_disp1_clk", IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1);
/* MIPI-LVDS SS */
clks[IMX8QXP_MIPI0_I2C0_CLK] = imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2);
clks[IMX8QXP_MIPI0_I2C1_CLK] = imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2);
/* MIPI CSI SS */
clks[IMX8QXP_CSI0_CORE_CLK] = imx_clk_scu("mipi_csi0_core_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CSI0_ESC_CLK] = imx_clk_scu("mipi_csi0_esc_clk", IMX_SC_R_CSI_0, IMX_SC_PM_CLK_MISC);
clks[IMX8QXP_CSI0_I2C0_CLK] = imx_clk_scu("mipi_csi0_i2c0_clk", IMX_SC_R_CSI_0_I2C_0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_CSI0_PWM0_CLK] = imx_clk_scu("mipi_csi0_pwm0_clk", IMX_SC_R_CSI_0_PWM_0, IMX_SC_PM_CLK_PER);
/* GPU SS */
clks[IMX8QXP_GPU0_CORE_CLK] = imx_clk_scu("gpu_core0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_PER);
clks[IMX8QXP_GPU0_SHADER_CLK] = imx_clk_scu("gpu_shader0_clk", IMX_SC_R_GPU_0_PID0, IMX_SC_PM_CLK_MISC);
for (i = 0; i < clk_data->num; i++) {
if (IS_ERR(clks[i]))
pr_warn("i.MX clk %u: register failed with %ld\n",
i, PTR_ERR(clks[i]));
}
return of_clk_add_hw_provider(ccm_node, of_clk_hw_onecell_get, clk_data);
}
static const struct of_device_id imx8qxp_match[] = {
{ .compatible = "fsl,imx8qxp-clk", },
{ /* sentinel */ }
};
static struct platform_driver imx8qxp_clk_driver = {
.driver = {
.name = "imx8qxp-clk",
.of_match_table = imx8qxp_match,
.suppress_bind_attrs = true,
},
.probe = imx8qxp_clk_probe,
};
builtin_platform_driver(imx8qxp_clk_driver);

View file

@ -0,0 +1,116 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "clk-scu.h"
static DEFINE_SPINLOCK(imx_lpcg_scu_lock);
#define CLK_GATE_SCU_LPCG_MASK 0x3
#define CLK_GATE_SCU_LPCG_HW_SEL BIT(0)
#define CLK_GATE_SCU_LPCG_SW_SEL BIT(1)
/*
* struct clk_lpcg_scu - Description of LPCG clock
*
* @hw: clk_hw of this LPCG
* @reg: register of this LPCG clock
* @bit_idx: bit index of this LPCG clock
* @hw_gate: HW auto gate enable
*
* This structure describes one LPCG clock
*/
struct clk_lpcg_scu {
struct clk_hw hw;
void __iomem *reg;
u8 bit_idx;
bool hw_gate;
};
#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
static int clk_lpcg_scu_enable(struct clk_hw *hw)
{
struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
unsigned long flags;
u32 reg, val;
spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
reg = readl_relaxed(clk->reg);
reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
val = CLK_GATE_SCU_LPCG_SW_SEL;
if (clk->hw_gate)
val |= CLK_GATE_SCU_LPCG_HW_SEL;
reg |= val << clk->bit_idx;
writel(reg, clk->reg);
spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
return 0;
}
static void clk_lpcg_scu_disable(struct clk_hw *hw)
{
struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
unsigned long flags;
u32 reg;
spin_lock_irqsave(&imx_lpcg_scu_lock, flags);
reg = readl_relaxed(clk->reg);
reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
writel(reg, clk->reg);
spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
}
static const struct clk_ops clk_lpcg_scu_ops = {
.enable = clk_lpcg_scu_enable,
.disable = clk_lpcg_scu_disable,
};
struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg,
u8 bit_idx, bool hw_gate)
{
struct clk_lpcg_scu *clk;
struct clk_init_data init;
struct clk_hw *hw;
int ret;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk)
return ERR_PTR(-ENOMEM);
clk->reg = reg;
clk->bit_idx = bit_idx;
clk->hw_gate = hw_gate;
init.name = name;
init.ops = &clk_lpcg_scu_ops;
init.flags = CLK_SET_RATE_PARENT | flags;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
clk->hw.init = &init;
hw = &clk->hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(clk);
hw = ERR_PTR(ret);
}
return hw;
}

203
drivers/clk/imx/clk-pfdv2.c Normal file
View file

@ -0,0 +1,203 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017~2018 NXP
*
* Author: Dong Aisheng <aisheng.dong@nxp.com>
*
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include "clk.h"
/**
* struct clk_pfdv2 - IMX PFD clock
* @clk_hw: clock source
* @reg: PFD register address
* @gate_bit: Gate bit offset
* @vld_bit: Valid bit offset
* @frac_off: PLL Fractional Divider offset
*/
struct clk_pfdv2 {
struct clk_hw hw;
void __iomem *reg;
u8 gate_bit;
u8 vld_bit;
u8 frac_off;
};
#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw)
#define CLK_PFDV2_FRAC_MASK 0x3f
#define LOCK_TIMEOUT_US USEC_PER_MSEC
static DEFINE_SPINLOCK(pfd_lock);
static int clk_pfdv2_wait(struct clk_pfdv2 *pfd)
{
u32 val;
return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit,
0, LOCK_TIMEOUT_US);
}
static int clk_pfdv2_enable(struct clk_hw *hw)
{
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
unsigned long flags;
u32 val;
spin_lock_irqsave(&pfd_lock, flags);
val = readl_relaxed(pfd->reg);
val &= ~pfd->gate_bit;
writel_relaxed(val, pfd->reg);
spin_unlock_irqrestore(&pfd_lock, flags);
return clk_pfdv2_wait(pfd);
}
static void clk_pfdv2_disable(struct clk_hw *hw)
{
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
unsigned long flags;
u32 val;
spin_lock_irqsave(&pfd_lock, flags);
val = readl_relaxed(pfd->reg);
val |= pfd->gate_bit;
writel_relaxed(val, pfd->reg);
spin_unlock_irqrestore(&pfd_lock, flags);
}
static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
u64 tmp = parent_rate;
u8 frac;
frac = (readl_relaxed(pfd->reg) >> pfd->frac_off)
& CLK_PFDV2_FRAC_MASK;
if (!frac) {
pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n",
clk_hw_get_name(hw));
return 0;
}
tmp *= 18;
do_div(tmp, frac);
return tmp;
}
static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
u64 tmp = *prate;
u8 frac;
tmp = tmp * 18 + rate / 2;
do_div(tmp, rate);
frac = tmp;
if (frac < 12)
frac = 12;
else if (frac > 35)
frac = 35;
tmp = *prate;
tmp *= 18;
do_div(tmp, frac);
return tmp;
}
static int clk_pfdv2_is_enabled(struct clk_hw *hw)
{
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
if (readl_relaxed(pfd->reg) & pfd->gate_bit)
return 0;
return 1;
}
static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
unsigned long flags;
u64 tmp = parent_rate;
u32 val;
u8 frac;
tmp = tmp * 18 + rate / 2;
do_div(tmp, rate);
frac = tmp;
if (frac < 12)
frac = 12;
else if (frac > 35)
frac = 35;
spin_lock_irqsave(&pfd_lock, flags);
val = readl_relaxed(pfd->reg);
val &= ~(CLK_PFDV2_FRAC_MASK << pfd->frac_off);
val |= frac << pfd->frac_off;
writel_relaxed(val, pfd->reg);
spin_unlock_irqrestore(&pfd_lock, flags);
return 0;
}
static const struct clk_ops clk_pfdv2_ops = {
.enable = clk_pfdv2_enable,
.disable = clk_pfdv2_disable,
.recalc_rate = clk_pfdv2_recalc_rate,
.round_rate = clk_pfdv2_round_rate,
.set_rate = clk_pfdv2_set_rate,
.is_enabled = clk_pfdv2_is_enabled,
};
struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
void __iomem *reg, u8 idx)
{
struct clk_init_data init;
struct clk_pfdv2 *pfd;
struct clk_hw *hw;
int ret;
WARN_ON(idx > 3);
pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
if (!pfd)
return ERR_PTR(-ENOMEM);
pfd->reg = reg;
pfd->gate_bit = 1 << ((idx + 1) * 8 - 1);
pfd->vld_bit = pfd->gate_bit - 1;
pfd->frac_off = idx * 8;
init.name = name;
init.ops = &clk_pfdv2_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE;
pfd->hw.init = &init;
hw = &pfd->hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(pfd);
hw = ERR_PTR(ret);
}
return hw;
}

184
drivers/clk/imx/clk-pllv4.c Normal file
View file

@ -0,0 +1,184 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Copyright 2017~2018 NXP
*
* Author: Dong Aisheng <aisheng.dong@nxp.com>
*
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include "clk.h"
/* PLL Control Status Register (xPLLCSR) */
#define PLL_CSR_OFFSET 0x0
#define PLL_VLD BIT(24)
#define PLL_EN BIT(0)
/* PLL Configuration Register (xPLLCFG) */
#define PLL_CFG_OFFSET 0x08
#define BP_PLL_MULT 16
#define BM_PLL_MULT (0x7f << 16)
/* PLL Numerator Register (xPLLNUM) */
#define PLL_NUM_OFFSET 0x10
/* PLL Denominator Register (xPLLDENOM) */
#define PLL_DENOM_OFFSET 0x14
struct clk_pllv4 {
struct clk_hw hw;
void __iomem *base;
};
/* Valid PLL MULT Table */
static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16};
#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw)
#define LOCK_TIMEOUT_US USEC_PER_MSEC
static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll)
{
u32 csr;
return readl_poll_timeout(pll->base + PLL_CSR_OFFSET,
csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US);
}
static int clk_pllv4_is_enabled(struct clk_hw *hw)
{
struct clk_pllv4 *pll = to_clk_pllv4(hw);
if (readl_relaxed(pll->base) & PLL_EN)
return 1;
return 0;
}
static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pllv4 *pll = to_clk_pllv4(hw);
u32 div;
div = readl_relaxed(pll->base + PLL_CFG_OFFSET);
div &= BM_PLL_MULT;
div >>= BP_PLL_MULT;
return parent_rate * div;
}
static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
unsigned long parent_rate = *prate;
unsigned long round_rate, i;
for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
round_rate = parent_rate * pllv4_mult_table[i];
if (rate >= round_rate)
return round_rate;
}
return round_rate;
}
static bool clk_pllv4_is_valid_mult(unsigned int mult)
{
int i;
/* check if mult is in valid MULT table */
for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
if (pllv4_mult_table[i] == mult)
return true;
}
return false;
}
static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_pllv4 *pll = to_clk_pllv4(hw);
u32 val, mult;
mult = rate / parent_rate;
if (!clk_pllv4_is_valid_mult(mult))
return -EINVAL;
val = readl_relaxed(pll->base + PLL_CFG_OFFSET);
val &= ~BM_PLL_MULT;
val |= mult << BP_PLL_MULT;
writel_relaxed(val, pll->base + PLL_CFG_OFFSET);
return 0;
}
static int clk_pllv4_enable(struct clk_hw *hw)
{
u32 val;
struct clk_pllv4 *pll = to_clk_pllv4(hw);
val = readl_relaxed(pll->base);
val |= PLL_EN;
writel_relaxed(val, pll->base);
return clk_pllv4_wait_lock(pll);
}
static void clk_pllv4_disable(struct clk_hw *hw)
{
u32 val;
struct clk_pllv4 *pll = to_clk_pllv4(hw);
val = readl_relaxed(pll->base);
val &= ~PLL_EN;
writel_relaxed(val, pll->base);
}
static const struct clk_ops clk_pllv4_ops = {
.recalc_rate = clk_pllv4_recalc_rate,
.round_rate = clk_pllv4_round_rate,
.set_rate = clk_pllv4_set_rate,
.enable = clk_pllv4_enable,
.disable = clk_pllv4_disable,
.is_enabled = clk_pllv4_is_enabled,
};
struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
void __iomem *base)
{
struct clk_pllv4 *pll;
struct clk_hw *hw;
struct clk_init_data init;
int ret;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
pll->base = base;
init.name = name;
init.ops = &clk_pllv4_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE;
pll->hw.init = &init;
hw = &pll->hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(pll);
hw = ERR_PTR(ret);
}
return hw;
}

View file

@ -0,0 +1,256 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright 2018 NXP.
*
* This driver supports the SCCG plls found in the imx8m SOCs
*
* Documentation for this SCCG pll can be found at:
* https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/bitfield.h>
#include "clk.h"
/* PLL CFGs */
#define PLL_CFG0 0x0
#define PLL_CFG1 0x4
#define PLL_CFG2 0x8
#define PLL_DIVF1_MASK GENMASK(18, 13)
#define PLL_DIVF2_MASK GENMASK(12, 7)
#define PLL_DIVR1_MASK GENMASK(27, 25)
#define PLL_DIVR2_MASK GENMASK(24, 19)
#define PLL_REF_MASK GENMASK(2, 0)
#define PLL_LOCK_MASK BIT(31)
#define PLL_PD_MASK BIT(7)
#define OSC_25M 25000000
#define OSC_27M 27000000
#define PLL_SCCG_LOCK_TIMEOUT 70
struct clk_sccg_pll {
struct clk_hw hw;
void __iomem *base;
};
#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw)
static int clk_pll_wait_lock(struct clk_sccg_pll *pll)
{
u32 val;
return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK, 0,
PLL_SCCG_LOCK_TIMEOUT);
}
static int clk_pll1_is_prepared(struct clk_hw *hw)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
val = readl_relaxed(pll->base + PLL_CFG0);
return (val & PLL_PD_MASK) ? 0 : 1;
}
static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val, divf;
val = readl_relaxed(pll->base + PLL_CFG2);
divf = FIELD_GET(PLL_DIVF1_MASK, val);
return parent_rate * 2 * (divf + 1);
}
static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
unsigned long parent_rate = *prate;
u32 div;
if (!parent_rate)
return 0;
div = rate / (parent_rate * 2);
return parent_rate * div * 2;
}
static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
u32 divf;
if (!parent_rate)
return -EINVAL;
divf = rate / (parent_rate * 2);
val = readl_relaxed(pll->base + PLL_CFG2);
val &= ~PLL_DIVF1_MASK;
val |= FIELD_PREP(PLL_DIVF1_MASK, divf - 1);
writel_relaxed(val, pll->base + PLL_CFG2);
return clk_pll_wait_lock(pll);
}
static int clk_pll1_prepare(struct clk_hw *hw)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
val = readl_relaxed(pll->base + PLL_CFG0);
val &= ~PLL_PD_MASK;
writel_relaxed(val, pll->base + PLL_CFG0);
return clk_pll_wait_lock(pll);
}
static void clk_pll1_unprepare(struct clk_hw *hw)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
val = readl_relaxed(pll->base + PLL_CFG0);
val |= PLL_PD_MASK;
writel_relaxed(val, pll->base + PLL_CFG0);
}
static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val, ref, divr1, divf1, divr2, divf2;
u64 temp64;
val = readl_relaxed(pll->base + PLL_CFG0);
switch (FIELD_GET(PLL_REF_MASK, val)) {
case 0:
ref = OSC_25M;
break;
case 1:
ref = OSC_27M;
break;
default:
ref = OSC_25M;
break;
}
val = readl_relaxed(pll->base + PLL_CFG2);
divr1 = FIELD_GET(PLL_DIVR1_MASK, val);
divr2 = FIELD_GET(PLL_DIVR2_MASK, val);
divf1 = FIELD_GET(PLL_DIVF1_MASK, val);
divf2 = FIELD_GET(PLL_DIVF2_MASK, val);
temp64 = ref * 2;
temp64 *= (divf1 + 1) * (divf2 + 1);
do_div(temp64, (divr1 + 1) * (divr2 + 1));
return temp64;
}
static long clk_pll2_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
u32 div;
unsigned long parent_rate = *prate;
if (!parent_rate)
return 0;
div = rate / parent_rate;
return parent_rate * div;
}
static int clk_pll2_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u32 val;
u32 divf;
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
if (!parent_rate)
return -EINVAL;
divf = rate / parent_rate;
val = readl_relaxed(pll->base + PLL_CFG2);
val &= ~PLL_DIVF2_MASK;
val |= FIELD_PREP(PLL_DIVF2_MASK, divf - 1);
writel_relaxed(val, pll->base + PLL_CFG2);
return clk_pll_wait_lock(pll);
}
static const struct clk_ops clk_sccg_pll1_ops = {
.is_prepared = clk_pll1_is_prepared,
.recalc_rate = clk_pll1_recalc_rate,
.round_rate = clk_pll1_round_rate,
.set_rate = clk_pll1_set_rate,
};
static const struct clk_ops clk_sccg_pll2_ops = {
.prepare = clk_pll1_prepare,
.unprepare = clk_pll1_unprepare,
.recalc_rate = clk_pll2_recalc_rate,
.round_rate = clk_pll2_round_rate,
.set_rate = clk_pll2_set_rate,
};
struct clk *imx_clk_sccg_pll(const char *name,
const char *parent_name,
void __iomem *base,
enum imx_sccg_pll_type pll_type)
{
struct clk_sccg_pll *pll;
struct clk_init_data init;
struct clk_hw *hw;
int ret;
switch (pll_type) {
case SCCG_PLL1:
init.ops = &clk_sccg_pll1_ops;
break;
case SCCG_PLL2:
init.ops = &clk_sccg_pll2_ops;
break;
default:
return ERR_PTR(-EINVAL);
}
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
init.name = name;
init.flags = 0;
init.parent_names = &parent_name;
init.num_parents = 1;
pll->base = base;
pll->hw.init = &init;
hw = &pll->hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(pll);
return ERR_PTR(ret);
}
return hw->clk;
}

270
drivers/clk/imx/clk-scu.c Normal file
View file

@ -0,0 +1,270 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2018 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/slab.h>
#include "clk-scu.h"
static struct imx_sc_ipc *ccm_ipc_handle;
/*
* struct clk_scu - Description of one SCU clock
* @hw: the common clk_hw
* @rsrc_id: resource ID of this SCU clock
* @clk_type: type of this clock resource
*/
struct clk_scu {
struct clk_hw hw;
u16 rsrc_id;
u8 clk_type;
};
/*
* struct imx_sc_msg_req_set_clock_rate - clock set rate protocol
* @hdr: SCU protocol header
* @rate: rate to set
* @resource: clock resource to set rate
* @clk: clk type of this resource
*
* This structure describes the SCU protocol of clock rate set
*/
struct imx_sc_msg_req_set_clock_rate {
struct imx_sc_rpc_msg hdr;
__le32 rate;
__le16 resource;
u8 clk;
} __packed;
struct req_get_clock_rate {
__le16 resource;
u8 clk;
} __packed;
struct resp_get_clock_rate {
__le32 rate;
};
/*
* struct imx_sc_msg_get_clock_rate - clock get rate protocol
* @hdr: SCU protocol header
* @req: get rate request protocol
* @resp: get rate response protocol
*
* This structure describes the SCU protocol of clock rate get
*/
struct imx_sc_msg_get_clock_rate {
struct imx_sc_rpc_msg hdr;
union {
struct req_get_clock_rate req;
struct resp_get_clock_rate resp;
} data;
};
/*
* struct imx_sc_msg_req_clock_enable - clock gate protocol
* @hdr: SCU protocol header
* @resource: clock resource to gate
* @clk: clk type of this resource
* @enable: whether gate off the clock
* @autog: HW auto gate enable
*
* This structure describes the SCU protocol of clock gate
*/
struct imx_sc_msg_req_clock_enable {
struct imx_sc_rpc_msg hdr;
__le16 resource;
u8 clk;
u8 enable;
u8 autog;
} __packed;
static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
{
return container_of(hw, struct clk_scu, hw);
}
int imx_clk_scu_init(void)
{
return imx_scu_get_handle(&ccm_ipc_handle);
}
/*
* clk_scu_recalc_rate - Get clock rate for a SCU clock
* @hw: clock to get rate for
* @parent_rate: parent rate provided by common clock framework, not used
*
* Gets the current clock rate of a SCU clock. Returns the current
* clock rate, or zero in failure.
*/
static unsigned long clk_scu_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_scu *clk = to_clk_scu(hw);
struct imx_sc_msg_get_clock_rate msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
int ret;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_RATE;
hdr->size = 2;
msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
msg.data.req.clk = clk->clk_type;
ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
if (ret) {
pr_err("%s: failed to get clock rate %d\n",
clk_hw_get_name(hw), ret);
return 0;
}
return le32_to_cpu(msg.data.resp.rate);
}
/*
* clk_scu_round_rate - Round clock rate for a SCU clock
* @hw: clock to round rate for
* @rate: rate to round
* @parent_rate: parent rate provided by common clock framework, not used
*
* Returns the current clock rate, or zero in failure.
*/
static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
/*
* Assume we support all the requested rate and let the SCU firmware
* to handle the left work
*/
return rate;
}
/*
* clk_scu_set_rate - Set rate for a SCU clock
* @hw: clock to change rate for
* @rate: target rate for the clock
* @parent_rate: rate of the clock parent, not used for SCU clocks
*
* Sets a clock frequency for a SCU clock. Returns the SCU
* protocol status.
*/
static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_scu *clk = to_clk_scu(hw);
struct imx_sc_msg_req_set_clock_rate msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_RATE;
hdr->size = 3;
msg.rate = cpu_to_le32(rate);
msg.resource = cpu_to_le16(clk->rsrc_id);
msg.clk = clk->clk_type;
return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
}
static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
u8 clk, bool enable, bool autog)
{
struct imx_sc_msg_req_clock_enable msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
hdr->func = IMX_SC_PM_FUNC_CLOCK_ENABLE;
hdr->size = 3;
msg.resource = cpu_to_le16(resource);
msg.clk = clk;
msg.enable = enable;
msg.autog = autog;
return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
}
/*
* clk_scu_prepare - Enable a SCU clock
* @hw: clock to enable
*
* Enable the clock at the DSC slice level
*/
static int clk_scu_prepare(struct clk_hw *hw)
{
struct clk_scu *clk = to_clk_scu(hw);
return sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
clk->clk_type, true, false);
}
/*
* clk_scu_unprepare - Disable a SCU clock
* @hw: clock to enable
*
* Disable the clock at the DSC slice level
*/
static void clk_scu_unprepare(struct clk_hw *hw)
{
struct clk_scu *clk = to_clk_scu(hw);
int ret;
ret = sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id,
clk->clk_type, false, false);
if (ret)
pr_warn("%s: clk unprepare failed %d\n", clk_hw_get_name(hw),
ret);
}
static const struct clk_ops clk_scu_ops = {
.recalc_rate = clk_scu_recalc_rate,
.round_rate = clk_scu_round_rate,
.set_rate = clk_scu_set_rate,
.prepare = clk_scu_prepare,
.unprepare = clk_scu_unprepare,
};
struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
{
struct clk_init_data init;
struct clk_scu *clk;
struct clk_hw *hw;
int ret;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk)
return ERR_PTR(-ENOMEM);
clk->rsrc_id = rsrc_id;
clk->clk_type = clk_type;
init.name = name;
init.ops = &clk_scu_ops;
init.num_parents = 0;
/*
* Note on MX8, the clocks are tightly coupled with power domain
* that once the power domain is off, the clock status may be
* lost. So we make it NOCACHE to let user to retrieve the real
* clock status from HW instead of using the possible invalid
* cached rate.
*/
init.flags = CLK_GET_RATE_NOCACHE;
clk->hw.init = &init;
hw = &clk->hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(clk);
hw = ERR_PTR(ret);
}
return hw;
}

18
drivers/clk/imx/clk-scu.h Normal file
View file

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2018 NXP
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#ifndef __IMX_CLK_SCU_H
#define __IMX_CLK_SCU_H
#include <linux/firmware/imx/sci.h>
int imx_clk_scu_init(void);
struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type);
struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg,
u8 bit_idx, bool hw_gate);
#endif

View file

@ -18,6 +18,16 @@ void __init imx_check_clocks(struct clk *clks[], unsigned int count)
i, PTR_ERR(clks[i]));
}
void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
{
unsigned int i;
for (i = 0; i < count; i++)
if (IS_ERR(clks[i]))
pr_err("i.MX clk %u: register failed with %ld\n",
i, PTR_ERR(clks[i]));
}
static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name)
{
struct of_phandle_args phandle;
@ -49,6 +59,18 @@ struct clk * __init imx_obtain_fixed_clock(
return clk;
}
struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np,
const char *name)
{
struct clk *clk;
clk = of_clk_get_by_name(np, name);
if (IS_ERR(clk))
return ERR_PTR(-ENOENT);
return __clk_get_hw(clk);
}
/*
* This fixups the register CCM_CSCMR1 write value.
* The write/read/divider values of the aclk_podf field

View file

@ -8,6 +8,7 @@
extern spinlock_t imx_ccm_lock;
void imx_check_clocks(struct clk *clks[], unsigned int count);
void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count);
void imx_register_uart_clocks(struct clk ** const clks[]);
extern void imx_cscmr1_fixup(u32 *val);
@ -21,12 +22,24 @@ enum imx_pllv1_type {
IMX_PLLV1_IMX35,
};
enum imx_sccg_pll_type {
SCCG_PLL1,
SCCG_PLL2,
};
struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
const char *parent, void __iomem *base);
struct clk *imx_clk_pllv2(const char *name, const char *parent,
void __iomem *base);
struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
void __iomem *base);
struct clk *imx_clk_sccg_pll(const char *name, const char *parent_name,
void __iomem *base,
enum imx_sccg_pll_type pll_type);
enum imx_pllv3_type {
IMX_PLLV3_GENERIC,
IMX_PLLV3_SYS,
@ -42,6 +55,9 @@ enum imx_pllv3_type {
struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent_name, void __iomem *base, u32 div_mask);
struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
void __iomem *base);
struct clk *clk_register_gate2(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx, u8 cgr_val,
@ -51,26 +67,38 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
struct clk * imx_obtain_fixed_clock(
const char *name, unsigned long rate);
struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np,
const char *name);
struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
void __iomem *reg, u8 shift, u32 exclusive_mask);
struct clk *imx_clk_pfd(const char *name, const char *parent_name,
void __iomem *reg, u8 idx);
struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
void __iomem *reg, u8 idx);
struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
void __iomem *reg, u8 shift, u8 width,
void __iomem *busy_reg, u8 busy_shift);
struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
u8 width, void __iomem *busy_reg, u8 busy_shift,
const char **parent_names, int num_parents);
const char * const *parent_names, int num_parents);
struct clk_hw *imx7ulp_clk_composite(const char *name,
const char * const *parent_names,
int num_parents, bool mux_present,
bool rate_present, bool gate_present,
void __iomem *reg);
struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width,
void (*fixup)(u32 *val));
struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents,
u8 shift, u8 width, const char * const *parents,
int num_parents, void (*fixup)(u32 *val));
static inline struct clk *imx_clk_fixed(const char *name, int rate)
@ -78,8 +106,19 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate)
return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
}
static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
{
return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
}
static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate)
{
return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
}
static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, int num_parents)
u8 shift, u8 width, const char * const *parents,
int num_parents)
{
return clk_register_mux(NULL, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg,
@ -100,6 +139,15 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_clk_hw_divider(const char *name,
const char *parent,
void __iomem *reg, u8 shift,
u8 width)
{
return clk_hw_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_divider_flags(const char *name,
const char *parent, void __iomem *reg, u8 shift, u8 width,
unsigned long flags)
@ -108,6 +156,15 @@ static inline struct clk *imx_clk_divider_flags(const char *name,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name,
const char *parent,
void __iomem *reg, u8 shift,
u8 width, unsigned long flags)
{
return clk_hw_register_divider(NULL, name, parent, flags,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width)
{
@ -116,6 +173,15 @@ static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_divider2_flags(const char *name,
const char *parent, void __iomem *reg, u8 shift, u8 width,
unsigned long flags)
{
return clk_register_divider(NULL, name, parent,
flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
@ -130,6 +196,13 @@ static inline struct clk *imx_clk_gate_flags(const char *name, const char *paren
shift, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
return clk_hw_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
@ -190,6 +263,15 @@ static inline struct clk *imx_clk_gate3(const char *name, const char *parent,
reg, shift, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate3_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 | CLK_OPS_PARENT_ENABLE,
reg, shift, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
@ -198,8 +280,18 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
}
static inline struct clk *imx_clk_gate4_flags(const char *name,
const char *parent, void __iomem *reg, u8 shift,
unsigned long flags)
{
return clk_register_gate2(NULL, name, parent,
flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
}
static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, int num_parents)
u8 shift, u8 width, const char * const *parents,
int num_parents)
{
return clk_register_mux(NULL, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT, reg, shift,
@ -207,24 +299,78 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
}
static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, int num_parents)
u8 shift, u8 width, const char * const *parents,
int num_parents)
{
return clk_register_mux(NULL, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_clk_hw_mux2(const char *name, void __iomem *reg,
u8 shift, u8 width,
const char * const *parents,
int num_parents)
{
return clk_hw_register_mux(NULL, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT |
CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_mux_flags(const char *name,
void __iomem *reg, u8 shift, u8 width, const char **parents,
int num_parents, unsigned long flags)
void __iomem *reg, u8 shift, u8 width,
const char * const *parents, int num_parents,
unsigned long flags)
{
return clk_register_mux(NULL, name, parents, num_parents,
flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0,
&imx_ccm_lock);
}
static inline struct clk *imx_clk_mux2_flags(const char *name,
void __iomem *reg, u8 shift, u8 width, const char **parents,
int num_parents, unsigned long flags)
{
return clk_register_mux(NULL, name, parents, num_parents,
flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk_hw *imx_clk_hw_mux_flags(const char *name,
void __iomem *reg, u8 shift,
u8 width,
const char * const *parents,
int num_parents,
unsigned long flags)
{
return clk_hw_register_mux(NULL, name, parents, num_parents,
flags | CLK_SET_RATE_NO_REPARENT,
reg, shift, width, 0, &imx_ccm_lock);
}
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step);
struct clk *imx8m_clk_composite_flags(const char *name,
const char **parent_names,
int num_parents, void __iomem *reg,
unsigned long flags);
#define __imx8m_clk_composite(name, parent_names, reg, flags) \
imx8m_clk_composite_flags(name, parent_names, \
ARRAY_SIZE(parent_names), reg, \
flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE)
#define imx8m_clk_composite(name, parent_names, reg) \
__imx8m_clk_composite(name, parent_names, reg, 0)
#define imx8m_clk_composite_critical(name, parent_names, reg) \
__imx8m_clk_composite(name, parent_names, reg, CLK_IS_CRITICAL)
struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock);
#endif

View file

@ -10,6 +10,8 @@
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include "clk.h"
struct clk_hw *__init clk_hw_register_pll(struct device *dev,
const char *name,
const char *parent_name,
@ -27,9 +29,9 @@ struct clk_hw *__init clk_hw_register_pll(struct device *dev,
init.name = name;
init.ops = ops;
init.flags = flags | CLK_IS_BASIC;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
init.flags = flags;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
hw->init = &init;
/* register the clock */

View file

@ -178,6 +178,29 @@ config COMMON_CLK_MT7622_AUDSYS
This driver supports MediaTek MT7622 AUDSYS clocks providing
to audio consumers such as I2S and TDM.
config COMMON_CLK_MT7629
bool "Clock driver for MediaTek MT7629"
depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
select COMMON_CLK_MEDIATEK
default ARCH_MEDIATEK && ARM
---help---
This driver supports MediaTek MT7629 basic clocks and clocks
required for various periperals found on MediaTek.
config COMMON_CLK_MT7629_ETHSYS
bool "Clock driver for MediaTek MT7629 ETHSYS"
depends on COMMON_CLK_MT7629
---help---
This driver add support for clocks for Ethernet and SGMII
required on MediaTek MT7629 SoC.
config COMMON_CLK_MT7629_HIFSYS
bool "Clock driver for MediaTek MT7629 HIFSYS"
depends on COMMON_CLK_MT7629
---help---
This driver supports MediaTek MT7629 HIFSYS clocks providing
to PCI-E and USB.
config COMMON_CLK_MT8135
bool "Clock driver for MediaTek MT8135"
depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST

View file

@ -26,5 +26,8 @@ obj-$(CONFIG_COMMON_CLK_MT7622) += clk-mt7622.o
obj-$(CONFIG_COMMON_CLK_MT7622_ETHSYS) += clk-mt7622-eth.o
obj-$(CONFIG_COMMON_CLK_MT7622_HIFSYS) += clk-mt7622-hif.o
obj-$(CONFIG_COMMON_CLK_MT7622_AUDSYS) += clk-mt7622-aud.o
obj-$(CONFIG_COMMON_CLK_MT7629) += clk-mt7629.o
obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o
obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o
obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o

View file

@ -53,7 +53,7 @@ static const struct clk_ops clk_cpumux_ops = {
.set_parent = clk_cpumux_set_parent,
};
static struct clk __init *
static struct clk *
mtk_clk_register_cpumux(const struct mtk_composite *mux,
struct regmap *regmap)
{
@ -84,9 +84,9 @@ mtk_clk_register_cpumux(const struct mtk_composite *mux,
return clk;
}
int __init mtk_clk_register_cpumuxes(struct device_node *node,
const struct mtk_composite *clks, int num,
struct clk_onecell_data *clk_data)
int mtk_clk_register_cpumuxes(struct device_node *node,
const struct mtk_composite *clks, int num,
struct clk_onecell_data *clk_data)
{
int i;
struct clk *clk;

View file

@ -513,7 +513,7 @@ static const struct mtk_gate peri_clks[] = {
GATE_PERI1(CLK_PERI_IRTX_PD, "peri_irtx_pd", "irtx_sel", 2),
};
static struct mtk_composite infra_muxes[] __initdata = {
static struct mtk_composite infra_muxes[] = {
MUX(CLK_INFRA_MUX1_SEL, "infra_mux1_sel", infra_mux1_parents,
0x000, 2, 2),
};
@ -652,7 +652,7 @@ static int mtk_topckgen_init(struct platform_device *pdev)
return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
}
static int __init mtk_infrasys_init(struct platform_device *pdev)
static int mtk_infrasys_init(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct clk_onecell_data *clk_data;

View file

@ -0,0 +1,159 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 MediaTek Inc.
* Author: Wenzhen Yu <Wenzhen Yu@mediatek.com>
* Ryder Lee <ryder.lee@mediatek.com>
*/
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include <dt-bindings/clock/mt7629-clk.h>
#define GATE_ETH(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &eth_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_no_setclr_inv, \
}
static const struct mtk_gate_regs eth_cg_regs = {
.set_ofs = 0x30,
.clr_ofs = 0x30,
.sta_ofs = 0x30,
};
static const struct mtk_gate eth_clks[] = {
GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "eth2pll", 6),
GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "txclk_src_pre", 7),
GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "txclk_src_pre", 8),
GATE_ETH(CLK_ETH_GP0_EN, "eth_gp0_en", "txclk_src_pre", 9),
GATE_ETH(CLK_ETH_ESW_EN, "eth_esw_en", "eth_500m", 16),
};
static const struct mtk_gate_regs sgmii_cg_regs = {
.set_ofs = 0xE4,
.clr_ofs = 0xE4,
.sta_ofs = 0xE4,
};
#define GATE_SGMII(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &sgmii_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_no_setclr_inv, \
}
static const struct mtk_gate sgmii_clks[2][4] = {
{
GATE_SGMII(CLK_SGMII_TX_EN, "sgmii_tx_en",
"ssusb_tx250m", 2),
GATE_SGMII(CLK_SGMII_RX_EN, "sgmii_rx_en",
"ssusb_eq_rx250m", 3),
GATE_SGMII(CLK_SGMII_CDR_REF, "sgmii_cdr_ref",
"ssusb_cdr_ref", 4),
GATE_SGMII(CLK_SGMII_CDR_FB, "sgmii_cdr_fb",
"ssusb_cdr_fb", 5),
}, {
GATE_SGMII(CLK_SGMII_TX_EN, "sgmii_tx_en1",
"ssusb_tx250m", 2),
GATE_SGMII(CLK_SGMII_RX_EN, "sgmii_rx_en1",
"ssusb_eq_rx250m", 3),
GATE_SGMII(CLK_SGMII_CDR_REF, "sgmii_cdr_ref1",
"ssusb_cdr_ref", 4),
GATE_SGMII(CLK_SGMII_CDR_FB, "sgmii_cdr_fb1",
"ssusb_cdr_fb", 5),
}
};
static int clk_mt7629_ethsys_init(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
int r;
clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);
mtk_clk_register_gates(node, eth_clks, CLK_ETH_NR_CLK, clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
mtk_register_reset_controller(node, 1, 0x34);
return r;
}
static int clk_mt7629_sgmiisys_init(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
static int id;
int r;
clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK);
mtk_clk_register_gates(node, sgmii_clks[id++], CLK_SGMII_NR_CLK,
clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static const struct of_device_id of_match_clk_mt7629_eth[] = {
{
.compatible = "mediatek,mt7629-ethsys",
.data = clk_mt7629_ethsys_init,
}, {
.compatible = "mediatek,mt7629-sgmiisys",
.data = clk_mt7629_sgmiisys_init,
}, {
/* sentinel */
}
};
static int clk_mt7629_eth_probe(struct platform_device *pdev)
{
int (*clk_init)(struct platform_device *);
int r;
clk_init = of_device_get_match_data(&pdev->dev);
if (!clk_init)
return -EINVAL;
r = clk_init(pdev);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static struct platform_driver clk_mt7629_eth_drv = {
.probe = clk_mt7629_eth_probe,
.driver = {
.name = "clk-mt7629-eth",
.of_match_table = of_match_clk_mt7629_eth,
},
};
builtin_platform_driver(clk_mt7629_eth_drv);

View file

@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 MediaTek Inc.
* Author: Wenzhen Yu <Wenzhen Yu@mediatek.com>
* Ryder Lee <ryder.lee@mediatek.com>
*/
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include <dt-bindings/clock/mt7629-clk.h>
#define GATE_PCIE(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &pcie_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_no_setclr_inv, \
}
#define GATE_SSUSB(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &ssusb_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_no_setclr_inv, \
}
static const struct mtk_gate_regs pcie_cg_regs = {
.set_ofs = 0x30,
.clr_ofs = 0x30,
.sta_ofs = 0x30,
};
static const struct mtk_gate_regs ssusb_cg_regs = {
.set_ofs = 0x30,
.clr_ofs = 0x30,
.sta_ofs = 0x30,
};
static const struct mtk_gate ssusb_clks[] = {
GATE_SSUSB(CLK_SSUSB_U2_PHY_1P_EN, "ssusb_u2_phy_1p",
"to_u2_phy_1p", 0),
GATE_SSUSB(CLK_SSUSB_U2_PHY_EN, "ssusb_u2_phy_en", "to_u2_phy", 1),
GATE_SSUSB(CLK_SSUSB_REF_EN, "ssusb_ref_en", "to_usb3_ref", 5),
GATE_SSUSB(CLK_SSUSB_SYS_EN, "ssusb_sys_en", "to_usb3_sys", 6),
GATE_SSUSB(CLK_SSUSB_MCU_EN, "ssusb_mcu_en", "to_usb3_mcu", 7),
GATE_SSUSB(CLK_SSUSB_DMA_EN, "ssusb_dma_en", "to_usb3_dma", 8),
};
static const struct mtk_gate pcie_clks[] = {
GATE_PCIE(CLK_PCIE_P1_AUX_EN, "pcie_p1_aux_en", "p1_1mhz", 12),
GATE_PCIE(CLK_PCIE_P1_OBFF_EN, "pcie_p1_obff_en", "free_run_4mhz", 13),
GATE_PCIE(CLK_PCIE_P1_AHB_EN, "pcie_p1_ahb_en", "from_top_ahb", 14),
GATE_PCIE(CLK_PCIE_P1_AXI_EN, "pcie_p1_axi_en", "from_top_axi", 15),
GATE_PCIE(CLK_PCIE_P1_MAC_EN, "pcie_p1_mac_en", "pcie1_mac_en", 16),
GATE_PCIE(CLK_PCIE_P1_PIPE_EN, "pcie_p1_pipe_en", "pcie1_pipe_en", 17),
GATE_PCIE(CLK_PCIE_P0_AUX_EN, "pcie_p0_aux_en", "p0_1mhz", 18),
GATE_PCIE(CLK_PCIE_P0_OBFF_EN, "pcie_p0_obff_en", "free_run_4mhz", 19),
GATE_PCIE(CLK_PCIE_P0_AHB_EN, "pcie_p0_ahb_en", "from_top_ahb", 20),
GATE_PCIE(CLK_PCIE_P0_AXI_EN, "pcie_p0_axi_en", "from_top_axi", 21),
GATE_PCIE(CLK_PCIE_P0_MAC_EN, "pcie_p0_mac_en", "pcie0_mac_en", 22),
GATE_PCIE(CLK_PCIE_P0_PIPE_EN, "pcie_p0_pipe_en", "pcie0_pipe_en", 23),
};
static int clk_mt7629_ssusbsys_init(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
int r;
clk_data = mtk_alloc_clk_data(CLK_SSUSB_NR_CLK);
mtk_clk_register_gates(node, ssusb_clks, ARRAY_SIZE(ssusb_clks),
clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
mtk_register_reset_controller(node, 1, 0x34);
return r;
}
static int clk_mt7629_pciesys_init(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
int r;
clk_data = mtk_alloc_clk_data(CLK_PCIE_NR_CLK);
mtk_clk_register_gates(node, pcie_clks, ARRAY_SIZE(pcie_clks),
clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
mtk_register_reset_controller(node, 1, 0x34);
return r;
}
static const struct of_device_id of_match_clk_mt7629_hif[] = {
{
.compatible = "mediatek,mt7629-pciesys",
.data = clk_mt7629_pciesys_init,
}, {
.compatible = "mediatek,mt7629-ssusbsys",
.data = clk_mt7629_ssusbsys_init,
}, {
/* sentinel */
}
};
static int clk_mt7629_hif_probe(struct platform_device *pdev)
{
int (*clk_init)(struct platform_device *);
int r;
clk_init = of_device_get_match_data(&pdev->dev);
if (!clk_init)
return -EINVAL;
r = clk_init(pdev);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static struct platform_driver clk_mt7629_hif_drv = {
.probe = clk_mt7629_hif_probe,
.driver = {
.name = "clk-mt7629-hif",
.of_match_table = of_match_clk_mt7629_hif,
},
};
builtin_platform_driver(clk_mt7629_hif_drv);

View file

@ -0,0 +1,723 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 MediaTek Inc.
* Author: Wenzhen Yu <Wenzhen Yu@mediatek.com>
* Ryder Lee <ryder.lee@mediatek.com>
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "clk-mtk.h"
#include "clk-gate.h"
#include "clk-cpumux.h"
#include <dt-bindings/clock/mt7629-clk.h>
#define MT7629_PLL_FMAX (2500UL * MHZ)
#define CON0_MT7629_RST_BAR BIT(24)
#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
_pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
_pcw_shift, _div_table, _parent_name) { \
.id = _id, \
.name = _name, \
.reg = _reg, \
.pwr_reg = _pwr_reg, \
.en_mask = _en_mask, \
.flags = _flags, \
.rst_bar_mask = CON0_MT7629_RST_BAR, \
.fmax = MT7629_PLL_FMAX, \
.pcwbits = _pcwbits, \
.pd_reg = _pd_reg, \
.pd_shift = _pd_shift, \
.tuner_reg = _tuner_reg, \
.pcw_reg = _pcw_reg, \
.pcw_shift = _pcw_shift, \
.div_table = _div_table, \
.parent_name = _parent_name, \
}
#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
_pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
_pcw_shift) \
PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
_pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \
NULL, "clk20m")
#define GATE_APMIXED(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &apmixed_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_no_setclr_inv, \
}
#define GATE_INFRA(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &infra_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr, \
}
#define GATE_PERI0(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &peri0_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr, \
}
#define GATE_PERI1(_id, _name, _parent, _shift) { \
.id = _id, \
.name = _name, \
.parent_name = _parent, \
.regs = &peri1_cg_regs, \
.shift = _shift, \
.ops = &mtk_clk_gate_ops_setclr, \
}
static DEFINE_SPINLOCK(mt7629_clk_lock);
static const char * const axi_parents[] = {
"clkxtal",
"syspll1_d2",
"syspll_d5",
"syspll1_d4",
"univpll_d5",
"univpll2_d2",
"univpll_d7",
"dmpll_ck"
};
static const char * const mem_parents[] = {
"clkxtal",
"dmpll_ck"
};
static const char * const ddrphycfg_parents[] = {
"clkxtal",
"syspll1_d8"
};
static const char * const eth_parents[] = {
"clkxtal",
"syspll1_d2",
"univpll1_d2",
"syspll1_d4",
"univpll_d5",
"sgmiipll_d2",
"univpll_d7",
"dmpll_ck"
};
static const char * const pwm_parents[] = {
"clkxtal",
"univpll2_d4"
};
static const char * const f10m_ref_parents[] = {
"clkxtal",
"sgmiipll_d2"
};
static const char * const nfi_infra_parents[] = {
"clkxtal",
"clkxtal",
"clkxtal",
"clkxtal",
"clkxtal",
"clkxtal",
"univpll2_d8",
"univpll3_d4",
"syspll1_d8",
"univpll1_d8",
"syspll4_d2",
"syspll2_d4",
"univpll2_d4",
"univpll3_d2",
"syspll1_d4",
"syspll_d7"
};
static const char * const flash_parents[] = {
"clkxtal",
"univpll_d80_d4",
"syspll2_d8",
"syspll3_d4",
"univpll3_d4",
"univpll1_d8",
"syspll2_d4",
"univpll2_d4"
};
static const char * const uart_parents[] = {
"clkxtal",
"univpll2_d8"
};
static const char * const spi0_parents[] = {
"clkxtal",
"syspll3_d2",
"clkxtal",
"syspll2_d4",
"syspll4_d2",
"univpll2_d4",
"univpll1_d8",
"clkxtal"
};
static const char * const spi1_parents[] = {
"clkxtal",
"syspll3_d2",
"clkxtal",
"syspll4_d4",
"syspll4_d2",
"univpll2_d4",
"univpll1_d8",
"clkxtal"
};
static const char * const msdc30_0_parents[] = {
"clkxtal",
"univpll2_d16",
"univ48m"
};
static const char * const msdc30_1_parents[] = {
"clkxtal",
"univpll2_d16",
"univ48m",
"syspll2_d4",
"univpll2_d4",
"syspll_d7",
"syspll2_d2",
"univpll2_d2"
};
static const char * const ap2wbmcu_parents[] = {
"clkxtal",
"syspll1_d2",
"univ48m",
"syspll1_d8",
"univpll2_d4",
"syspll_d7",
"syspll2_d2",
"univpll2_d2"
};
static const char * const audio_parents[] = {
"clkxtal",
"syspll3_d4",
"syspll4_d4",
"syspll1_d16"
};
static const char * const aud_intbus_parents[] = {
"clkxtal",
"syspll1_d4",
"syspll4_d2",
"dmpll_d4"
};
static const char * const pmicspi_parents[] = {
"clkxtal",
"syspll1_d8",
"syspll3_d4",
"syspll1_d16",
"univpll3_d4",
"clkxtal",
"univpll2_d4",
"dmpll_d8"
};
static const char * const scp_parents[] = {
"clkxtal",
"syspll1_d8",
"univpll2_d2",
"univpll2_d4"
};
static const char * const atb_parents[] = {
"clkxtal",
"syspll1_d2",
"syspll_d5"
};
static const char * const hif_parents[] = {
"clkxtal",
"syspll1_d2",
"univpll1_d2",
"syspll1_d4",
"univpll_d5",
"clk_null",
"univpll_d7"
};
static const char * const sata_parents[] = {
"clkxtal",
"univpll2_d4"
};
static const char * const usb20_parents[] = {
"clkxtal",
"univpll3_d4",
"syspll1_d8"
};
static const char * const aud1_parents[] = {
"clkxtal"
};
static const char * const irrx_parents[] = {
"clkxtal",
"syspll4_d16"
};
static const char * const crypto_parents[] = {
"clkxtal",
"univpll_d3",
"univpll1_d2",
"syspll1_d2",
"univpll_d5",
"syspll_d5",
"univpll2_d2",
"syspll_d2"
};
static const char * const gpt10m_parents[] = {
"clkxtal",
"clkxtal_d4"
};
static const char * const peribus_ck_parents[] = {
"syspll1_d8",
"syspll1_d4"
};
static const char * const infra_mux1_parents[] = {
"clkxtal",
"armpll",
"main_core_en",
"armpll"
};
static const struct mtk_gate_regs apmixed_cg_regs = {
.set_ofs = 0x8,
.clr_ofs = 0x8,
.sta_ofs = 0x8,
};
static const struct mtk_gate_regs infra_cg_regs = {
.set_ofs = 0x40,
.clr_ofs = 0x44,
.sta_ofs = 0x48,
};
static const struct mtk_gate_regs peri0_cg_regs = {
.set_ofs = 0x8,
.clr_ofs = 0x10,
.sta_ofs = 0x18,
};
static const struct mtk_gate_regs peri1_cg_regs = {
.set_ofs = 0xC,
.clr_ofs = 0x14,
.sta_ofs = 0x1C,
};
static const struct mtk_pll_data plls[] = {
PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x00000001,
0, 21, 0x0204, 24, 0, 0x0204, 0),
PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0210, 0x021C, 0x00000001,
HAVE_RST_BAR, 21, 0x0214, 24, 0, 0x0214, 0),
PLL(CLK_APMIXED_UNIV2PLL, "univ2pll", 0x0220, 0x022C, 0x00000001,
HAVE_RST_BAR, 7, 0x0224, 24, 0, 0x0224, 14),
PLL(CLK_APMIXED_ETH1PLL, "eth1pll", 0x0300, 0x0310, 0x00000001,
0, 21, 0x0300, 1, 0, 0x0304, 0),
PLL(CLK_APMIXED_ETH2PLL, "eth2pll", 0x0314, 0x0320, 0x00000001,
0, 21, 0x0314, 1, 0, 0x0318, 0),
PLL(CLK_APMIXED_SGMIPLL, "sgmipll", 0x0358, 0x0368, 0x00000001,
0, 21, 0x0358, 1, 0, 0x035C, 0),
};
static const struct mtk_gate apmixed_clks[] = {
GATE_APMIXED(CLK_APMIXED_MAIN_CORE_EN, "main_core_en", "mainpll", 5),
};
static const struct mtk_gate infra_clks[] = {
GATE_INFRA(CLK_INFRA_DBGCLK_PD, "infra_dbgclk_pd", "hd_faxi", 0),
GATE_INFRA(CLK_INFRA_TRNG_PD, "infra_trng_pd", "hd_faxi", 2),
GATE_INFRA(CLK_INFRA_DEVAPC_PD, "infra_devapc_pd", "hd_faxi", 4),
GATE_INFRA(CLK_INFRA_APXGPT_PD, "infra_apxgpt_pd", "infrao_10m", 18),
GATE_INFRA(CLK_INFRA_SEJ_PD, "infra_sej_pd", "infrao_10m", 19),
};
static const struct mtk_fixed_clk top_fixed_clks[] = {
FIXED_CLK(CLK_TOP_TO_U2_PHY, "to_u2_phy", "clkxtal",
31250000),
FIXED_CLK(CLK_TOP_TO_U2_PHY_1P, "to_u2_phy_1p", "clkxtal",
31250000),
FIXED_CLK(CLK_TOP_PCIE0_PIPE_EN, "pcie0_pipe_en", "clkxtal",
125000000),
FIXED_CLK(CLK_TOP_PCIE1_PIPE_EN, "pcie1_pipe_en", "clkxtal",
125000000),
FIXED_CLK(CLK_TOP_SSUSB_TX250M, "ssusb_tx250m", "clkxtal",
250000000),
FIXED_CLK(CLK_TOP_SSUSB_EQ_RX250M, "ssusb_eq_rx250m", "clkxtal",
250000000),
FIXED_CLK(CLK_TOP_SSUSB_CDR_REF, "ssusb_cdr_ref", "clkxtal",
33333333),
FIXED_CLK(CLK_TOP_SSUSB_CDR_FB, "ssusb_cdr_fb", "clkxtal",
50000000),
FIXED_CLK(CLK_TOP_SATA_ASIC, "sata_asic", "clkxtal",
50000000),
FIXED_CLK(CLK_TOP_SATA_RBC, "sata_rbc", "clkxtal",
50000000),
};
static const struct mtk_fixed_factor top_divs[] = {
FACTOR(CLK_TOP_TO_USB3_SYS, "to_usb3_sys", "eth1pll", 1, 4),
FACTOR(CLK_TOP_P1_1MHZ, "p1_1mhz", "eth1pll", 1, 500),
FACTOR(CLK_TOP_4MHZ, "free_run_4mhz", "eth1pll", 1, 125),
FACTOR(CLK_TOP_P0_1MHZ, "p0_1mhz", "eth1pll", 1, 500),
FACTOR(CLK_TOP_ETH_500M, "eth_500m", "eth1pll", 1, 1),
FACTOR(CLK_TOP_TXCLK_SRC_PRE, "txclk_src_pre", "sgmiipll_d2", 1, 1),
FACTOR(CLK_TOP_RTC, "rtc", "clkxtal", 1, 1024),
FACTOR(CLK_TOP_PWM_QTR_26M, "pwm_qtr_26m", "clkxtal", 1, 1),
FACTOR(CLK_TOP_CPUM_TCK_IN, "cpum_tck_in", "cpum_tck", 1, 1),
FACTOR(CLK_TOP_TO_USB3_DA_TOP, "to_usb3_da_top", "clkxtal", 1, 1),
FACTOR(CLK_TOP_MEMPLL, "mempll", "clkxtal", 32, 1),
FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "mempll", 1, 1),
FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "mempll", 1, 4),
FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "mempll", 1, 8),
FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2),
FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "mainpll", 1, 4),
FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "mainpll", 1, 8),
FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "mainpll", 1, 16),
FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "mainpll", 1, 32),
FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "mainpll", 1, 6),
FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "mainpll", 1, 12),
FACTOR(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "mainpll", 1, 24),
FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5),
FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "mainpll", 1, 10),
FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "mainpll", 1, 20),
FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "mainpll", 1, 7),
FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "mainpll", 1, 14),
FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "mainpll", 1, 28),
FACTOR(CLK_TOP_SYSPLL4_D16, "syspll4_d16", "mainpll", 1, 112),
FACTOR(CLK_TOP_UNIVPLL, "univpll", "univ2pll", 1, 2),
FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll", 1, 4),
FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll", 1, 8),
FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll", 1, 16),
FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3),
FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll", 1, 6),
FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll", 1, 12),
FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll", 1, 24),
FACTOR(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll", 1, 48),
FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll", 1, 10),
FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll", 1, 20),
FACTOR(CLK_TOP_UNIVPLL3_D16, "univpll3_d16", "univpll", 1, 80),
FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7),
FACTOR(CLK_TOP_UNIVPLL_D80_D4, "univpll_d80_d4", "univpll", 1, 320),
FACTOR(CLK_TOP_UNIV48M, "univ48m", "univpll", 1, 25),
FACTOR(CLK_TOP_SGMIIPLL_D2, "sgmiipll_d2", "sgmipll", 1, 2),
FACTOR(CLK_TOP_CLKXTAL_D4, "clkxtal_d4", "clkxtal", 1, 4),
FACTOR(CLK_TOP_HD_FAXI, "hd_faxi", "axi_sel", 1, 1),
FACTOR(CLK_TOP_FAXI, "faxi", "axi_sel", 1, 1),
FACTOR(CLK_TOP_F_FAUD_INTBUS, "f_faud_intbus", "aud_intbus_sel", 1, 1),
FACTOR(CLK_TOP_AP2WBHIF_HCLK, "ap2wbhif_hclk", "syspll1_d8", 1, 1),
FACTOR(CLK_TOP_10M_INFRAO, "infrao_10m", "gpt10m_sel", 1, 1),
FACTOR(CLK_TOP_MSDC30_1, "msdc30_1", "msdc30_1_sel", 1, 1),
FACTOR(CLK_TOP_SPI, "spi", "spi0_sel", 1, 1),
FACTOR(CLK_TOP_SF, "sf", "nfi_infra_sel", 1, 1),
FACTOR(CLK_TOP_FLASH, "flash", "flash_sel", 1, 1),
FACTOR(CLK_TOP_TO_USB3_REF, "to_usb3_ref", "sata_sel", 1, 4),
FACTOR(CLK_TOP_TO_USB3_MCU, "to_usb3_mcu", "axi_sel", 1, 1),
FACTOR(CLK_TOP_TO_USB3_DMA, "to_usb3_dma", "hif_sel", 1, 1),
FACTOR(CLK_TOP_FROM_TOP_AHB, "from_top_ahb", "axi_sel", 1, 1),
FACTOR(CLK_TOP_FROM_TOP_AXI, "from_top_axi", "hif_sel", 1, 1),
FACTOR(CLK_TOP_PCIE1_MAC_EN, "pcie1_mac_en", "sata_sel", 1, 1),
FACTOR(CLK_TOP_PCIE0_MAC_EN, "pcie0_mac_en", "sata_sel", 1, 1),
};
static const struct mtk_gate peri_clks[] = {
/* PERI0 */
GATE_PERI0(CLK_PERI_PWM1_PD, "peri_pwm1_pd", "pwm_qtr_26m", 2),
GATE_PERI0(CLK_PERI_PWM2_PD, "peri_pwm2_pd", "pwm_qtr_26m", 3),
GATE_PERI0(CLK_PERI_PWM3_PD, "peri_pwm3_pd", "pwm_qtr_26m", 4),
GATE_PERI0(CLK_PERI_PWM4_PD, "peri_pwm4_pd", "pwm_qtr_26m", 5),
GATE_PERI0(CLK_PERI_PWM5_PD, "peri_pwm5_pd", "pwm_qtr_26m", 6),
GATE_PERI0(CLK_PERI_PWM6_PD, "peri_pwm6_pd", "pwm_qtr_26m", 7),
GATE_PERI0(CLK_PERI_PWM7_PD, "peri_pwm7_pd", "pwm_qtr_26m", 8),
GATE_PERI0(CLK_PERI_PWM_PD, "peri_pwm_pd", "pwm_qtr_26m", 9),
GATE_PERI0(CLK_PERI_AP_DMA_PD, "peri_ap_dma_pd", "faxi", 12),
GATE_PERI0(CLK_PERI_MSDC30_1_PD, "peri_msdc30_1", "msdc30_1", 14),
GATE_PERI0(CLK_PERI_UART0_PD, "peri_uart0_pd", "faxi", 17),
GATE_PERI0(CLK_PERI_UART1_PD, "peri_uart1_pd", "faxi", 18),
GATE_PERI0(CLK_PERI_UART2_PD, "peri_uart2_pd", "faxi", 19),
GATE_PERI0(CLK_PERI_UART3_PD, "peri_uart3_pd", "faxi", 20),
GATE_PERI0(CLK_PERI_BTIF_PD, "peri_btif_pd", "faxi", 22),
GATE_PERI0(CLK_PERI_I2C0_PD, "peri_i2c0_pd", "faxi", 23),
GATE_PERI0(CLK_PERI_SPI0_PD, "peri_spi0_pd", "spi", 28),
GATE_PERI0(CLK_PERI_SNFI_PD, "peri_snfi_pd", "sf", 29),
GATE_PERI0(CLK_PERI_NFI_PD, "peri_nfi_pd", "faxi", 30),
GATE_PERI0(CLK_PERI_NFIECC_PD, "peri_nfiecc_pd", "faxi", 31),
/* PERI1 */
GATE_PERI1(CLK_PERI_FLASH_PD, "peri_flash_pd", "flash", 1),
};
static struct mtk_composite infra_muxes[] = {
/* INFRA_TOPCKGEN_CKMUXSEL */
MUX(CLK_INFRA_MUX1_SEL, "infra_mux1_sel", infra_mux1_parents, 0x000,
2, 2),
};
static struct mtk_composite top_muxes[] = {
/* CLK_CFG_0 */
MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
0x040, 0, 3, 7),
MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents,
0x040, 8, 1, 15),
MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents,
0x040, 16, 1, 23),
MUX_GATE(CLK_TOP_ETH_SEL, "eth_sel", eth_parents,
0x040, 24, 3, 31),
/* CLK_CFG_1 */
MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents,
0x050, 0, 2, 7),
MUX_GATE(CLK_TOP_F10M_REF_SEL, "f10m_ref_sel", f10m_ref_parents,
0x050, 8, 1, 15),
MUX_GATE(CLK_TOP_NFI_INFRA_SEL, "nfi_infra_sel", nfi_infra_parents,
0x050, 16, 4, 23),
MUX_GATE(CLK_TOP_FLASH_SEL, "flash_sel", flash_parents,
0x050, 24, 3, 31),
/* CLK_CFG_2 */
MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents,
0x060, 0, 1, 7),
MUX_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", spi0_parents,
0x060, 8, 3, 15),
MUX_GATE(CLK_TOP_SPI1_SEL, "spi1_sel", spi1_parents,
0x060, 16, 3, 23),
MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", uart_parents,
0x060, 24, 3, 31),
/* CLK_CFG_3 */
MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_0_parents,
0x070, 0, 3, 7),
MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_parents,
0x070, 8, 3, 15),
MUX_GATE(CLK_TOP_AP2WBMCU_SEL, "ap2wbmcu_sel", ap2wbmcu_parents,
0x070, 16, 3, 23),
MUX_GATE(CLK_TOP_AP2WBHIF_SEL, "ap2wbhif_sel", ap2wbmcu_parents,
0x070, 24, 3, 31),
/* CLK_CFG_4 */
MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents,
0x080, 0, 2, 7),
MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents,
0x080, 8, 2, 15),
MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents,
0x080, 16, 3, 23),
MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents,
0x080, 24, 2, 31),
/* CLK_CFG_5 */
MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents,
0x090, 0, 2, 7),
MUX_GATE(CLK_TOP_HIF_SEL, "hif_sel", hif_parents,
0x090, 8, 3, 15),
MUX_GATE(CLK_TOP_SATA_SEL, "sata_sel", sata_parents,
0x090, 16, 1, 23),
MUX_GATE(CLK_TOP_U2_SEL, "usb20_sel", usb20_parents,
0x090, 24, 2, 31),
/* CLK_CFG_6 */
MUX_GATE(CLK_TOP_AUD1_SEL, "aud1_sel", aud1_parents,
0x0A0, 0, 1, 7),
MUX_GATE(CLK_TOP_AUD2_SEL, "aud2_sel", aud1_parents,
0x0A0, 8, 1, 15),
MUX_GATE(CLK_TOP_IRRX_SEL, "irrx_sel", irrx_parents,
0x0A0, 16, 1, 23),
MUX_GATE(CLK_TOP_IRTX_SEL, "irtx_sel", irrx_parents,
0x0A0, 24, 1, 31),
/* CLK_CFG_7 */
MUX_GATE(CLK_TOP_SATA_MCU_SEL, "sata_mcu_sel", scp_parents,
0x0B0, 0, 2, 7),
MUX_GATE(CLK_TOP_PCIE0_MCU_SEL, "pcie0_mcu_sel", scp_parents,
0x0B0, 8, 2, 15),
MUX_GATE(CLK_TOP_PCIE1_MCU_SEL, "pcie1_mcu_sel", scp_parents,
0x0B0, 16, 2, 23),
MUX_GATE(CLK_TOP_SSUSB_MCU_SEL, "ssusb_mcu_sel", scp_parents,
0x0B0, 24, 2, 31),
/* CLK_CFG_8 */
MUX_GATE(CLK_TOP_CRYPTO_SEL, "crypto_sel", crypto_parents,
0x0C0, 0, 3, 7),
MUX_GATE(CLK_TOP_SGMII_REF_1_SEL, "sgmii_ref_1_sel", f10m_ref_parents,
0x0C0, 8, 1, 15),
MUX_GATE(CLK_TOP_10M_SEL, "gpt10m_sel", gpt10m_parents,
0x0C0, 16, 1, 23),
};
static struct mtk_composite peri_muxes[] = {
/* PERI_GLOBALCON_CKSEL */
MUX(CLK_PERIBUS_SEL, "peribus_ck_sel", peribus_ck_parents, 0x05C, 0, 1),
};
static int mtk_topckgen_init(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
void __iomem *base;
struct device_node *node = pdev->dev.of_node;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
clk_data);
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
clk_data);
mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
base, &mt7629_clk_lock, clk_data);
clk_prepare_enable(clk_data->clks[CLK_TOP_AXI_SEL]);
clk_prepare_enable(clk_data->clks[CLK_TOP_MEM_SEL]);
clk_prepare_enable(clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]);
return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
}
static int mtk_infrasys_init(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct clk_onecell_data *clk_data;
int r;
clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
clk_data);
mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes),
clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get,
clk_data);
if (r)
return r;
return 0;
}
static int mtk_pericfg_init(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
void __iomem *base;
int r;
struct device_node *node = pdev->dev.of_node;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
clk_data);
mtk_clk_register_composites(peri_muxes, ARRAY_SIZE(peri_muxes), base,
&mt7629_clk_lock, clk_data);
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
return r;
clk_prepare_enable(clk_data->clks[CLK_PERI_UART0_PD]);
return 0;
}
static int mtk_apmixedsys_init(struct platform_device *pdev)
{
struct clk_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
if (!clk_data)
return -ENOMEM;
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
clk_data);
mtk_clk_register_gates(node, apmixed_clks,
ARRAY_SIZE(apmixed_clks), clk_data);
clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMPLL]);
clk_prepare_enable(clk_data->clks[CLK_APMIXED_MAIN_CORE_EN]);
return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
}
static const struct of_device_id of_match_clk_mt7629[] = {
{
.compatible = "mediatek,mt7629-apmixedsys",
.data = mtk_apmixedsys_init,
}, {
.compatible = "mediatek,mt7629-infracfg",
.data = mtk_infrasys_init,
}, {
.compatible = "mediatek,mt7629-topckgen",
.data = mtk_topckgen_init,
}, {
.compatible = "mediatek,mt7629-pericfg",
.data = mtk_pericfg_init,
}, {
/* sentinel */
}
};
static int clk_mt7629_probe(struct platform_device *pdev)
{
int (*clk_init)(struct platform_device *);
int r;
clk_init = of_device_get_match_data(&pdev->dev);
if (!clk_init)
return -EINVAL;
r = clk_init(pdev);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static struct platform_driver clk_mt7629_drv = {
.probe = clk_mt7629_probe,
.driver = {
.name = "clk-mt7629",
.of_match_table = of_match_clk_mt7629,
},
};
static int clk_mt7629_init(void)
{
return platform_driver_register(&clk_mt7629_drv);
}
arch_initcall(clk_mt7629_init);

View file

@ -2,7 +2,8 @@
# Makefile for Meson specific clk
#
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o

View file

@ -631,22 +631,23 @@ static struct clk_regmap *const axg_audio_clk_regmaps[] = {
&axg_tdmout_c_lrclk,
};
static struct clk *devm_clk_get_enable(struct device *dev, char *id)
static int devm_clk_get_enable(struct device *dev, char *id)
{
struct clk *clk;
int ret;
clk = devm_clk_get(dev, id);
if (IS_ERR(clk)) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
ret = PTR_ERR(clk);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get %s", id);
return clk;
return ret;
}
ret = clk_prepare_enable(clk);
if (ret) {
dev_err(dev, "failed to enable %s", id);
return ERR_PTR(ret);
return ret;
}
ret = devm_add_action_or_reset(dev,
@ -654,74 +655,40 @@ static struct clk *devm_clk_get_enable(struct device *dev, char *id)
clk);
if (ret) {
dev_err(dev, "failed to add reset action on %s", id);
return ERR_PTR(ret);
return ret;
}
return clk;
}
static const struct clk_ops axg_clk_no_ops = {};
static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev,
const char *name,
const char *parent_name)
{
struct clk_hw *hw;
struct clk_init_data init;
char *clk_name;
int ret;
hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
if (!hw)
return ERR_PTR(-ENOMEM);
clk_name = kasprintf(GFP_KERNEL, "axg_%s", name);
if (!clk_name)
return ERR_PTR(-ENOMEM);
init.name = clk_name;
init.ops = &axg_clk_no_ops;
init.flags = 0;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
hw->init = &init;
ret = devm_clk_hw_register(dev, hw);
kfree(clk_name);
return ret ? ERR_PTR(ret) : hw;
return 0;
}
static int axg_register_clk_hw_input(struct device *dev,
const char *name,
unsigned int clkid)
{
struct clk *parent_clk = devm_clk_get(dev, name);
struct clk_hw *hw = NULL;
char *clk_name;
struct clk_hw *hw;
int err = 0;
if (IS_ERR(parent_clk)) {
int err = PTR_ERR(parent_clk);
clk_name = kasprintf(GFP_KERNEL, "axg_%s", name);
if (!clk_name)
return -ENOMEM;
hw = meson_clk_hw_register_input(dev, name, clk_name, 0);
if (IS_ERR(hw)) {
/* It is ok if an input clock is missing */
if (err == -ENOENT) {
if (PTR_ERR(hw) == -ENOENT) {
dev_dbg(dev, "%s not provided", name);
} else {
err = PTR_ERR(hw);
if (err != -EPROBE_DEFER)
dev_err(dev, "failed to get %s clock", name);
return err;
}
} else {
hw = axg_clk_hw_register_bypass(dev, name,
__clk_get_name(parent_clk));
axg_audio_hw_onecell_data.hws[clkid] = hw;
}
if (IS_ERR(hw)) {
dev_err(dev, "failed to register %s clock", name);
return PTR_ERR(hw);
}
axg_audio_hw_onecell_data.hws[clkid] = hw;
return 0;
kfree(clk_name);
return err;
}
static int axg_register_clk_hw_inputs(struct device *dev,
@ -759,7 +726,6 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
struct regmap *map;
struct resource *res;
void __iomem *regs;
struct clk *clk;
struct clk_hw *hw;
int ret, i;
@ -775,9 +741,9 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
}
/* Get the mandatory peripheral clock */
clk = devm_clk_get_enable(dev, "pclk");
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = devm_clk_get_enable(dev, "pclk");
if (ret)
return ret;
ret = device_reset(dev);
if (ret) {
@ -786,8 +752,7 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
}
/* Register the peripheral input clock */
hw = axg_clk_hw_register_bypass(dev, "audio_pclk",
__clk_get_name(clk));
hw = meson_clk_hw_register_input(dev, "pclk", "axg_audio_pclk", 0);
if (IS_ERR(hw))
return PTR_ERR(hw);

View file

@ -0,0 +1,44 @@
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright (c) 2018 BayLibre, SAS.
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include "clkc.h"
static const struct clk_ops meson_clk_no_ops = {};
struct clk_hw *meson_clk_hw_register_input(struct device *dev,
const char *of_name,
const char *clk_name,
unsigned long flags)
{
struct clk *parent_clk = devm_clk_get(dev, of_name);
struct clk_init_data init;
const char *parent_name;
struct clk_hw *hw;
int ret;
if (IS_ERR(parent_clk))
return (struct clk_hw *)parent_clk;
hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
if (!hw)
return ERR_PTR(-ENOMEM);
parent_name = __clk_get_name(parent_clk);
init.name = clk_name;
init.ops = &meson_clk_no_ops;
init.flags = flags;
init.parent_names = &parent_name;
init.num_parents = 1;
hw->init = &init;
ret = devm_clk_hw_register(dev, hw);
return ret ? ERR_PTR(ret) : hw;
}
EXPORT_SYMBOL_GPL(meson_clk_hw_register_input);

View file

@ -200,11 +200,28 @@ static void meson_clk_pll_init(struct clk_hw *hw)
}
}
static int meson_clk_pll_is_enabled(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
if (meson_parm_read(clk->map, &pll->rst) ||
!meson_parm_read(clk->map, &pll->en) ||
!meson_parm_read(clk->map, &pll->l))
return 0;
return 1;
}
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);
/* do nothing if the PLL is already enabled */
if (clk_hw_is_enabled(hw))
return 0;
/* Make sure the pll is in reset */
meson_parm_write(clk->map, &pll->rst, 1);
@ -288,10 +305,12 @@ 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,
.is_enabled = meson_clk_pll_is_enabled,
.enable = meson_clk_pll_enable,
.disable = meson_clk_pll_disable
};
const struct clk_ops meson_clk_pll_ro_ops = {
.recalc_rate = meson_clk_pll_recalc_rate,
.is_enabled = meson_clk_pll_is_enabled,
};

View file

@ -50,6 +50,11 @@ const struct clk_ops clk_regmap_gate_ops = {
};
EXPORT_SYMBOL_GPL(clk_regmap_gate_ops);
const struct clk_ops clk_regmap_gate_ro_ops = {
.is_enabled = clk_regmap_gate_is_enabled,
};
EXPORT_SYMBOL_GPL(clk_regmap_gate_ro_ops);
static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{

View file

@ -51,6 +51,7 @@ clk_get_regmap_gate_data(struct clk_regmap *clk)
}
extern const struct clk_ops clk_regmap_gate_ops;
extern const struct clk_ops clk_regmap_gate_ro_ops;
/**
* struct clk_regmap_div_data - regmap backed adjustable divider specific data

View file

@ -90,6 +90,11 @@ struct meson_clk_phase_data {
int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
struct meson_vid_pll_div_data {
struct parm val;
struct parm sel;
};
#define MESON_GATE(_name, _reg, _bit) \
struct clk_regmap _name = { \
.data = &(struct clk_regmap_gate_data){ \
@ -112,5 +117,11 @@ extern const struct clk_ops meson_clk_cpu_ops;
extern const struct clk_ops meson_clk_mpll_ro_ops;
extern const struct clk_ops meson_clk_mpll_ops;
extern const struct clk_ops meson_clk_phase_ops;
extern const struct clk_ops meson_vid_pll_div_ro_ops;
struct clk_hw *meson_clk_hw_register_input(struct device *dev,
const char *of_name,
const char *clk_name,
unsigned long flags);
#endif /* __CLKC_H */

View file

@ -199,6 +199,58 @@ static struct clk_regmap gxbb_hdmi_pll_dco = {
},
};
static struct clk_regmap gxl_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,
.width = 9,
},
.n = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 9,
.width = 5,
},
/*
* On gxl, there is a register shift due to
* HHI_HDMI_PLL_CNTL1 which does not exist on gxbb,
* so we use the HHI_HDMI_PLL_CNTL2 define from GXBB
* instead which is defined at the same offset.
*/
.frac = {
.reg_off = HHI_HDMI_PLL_CNTL2,
.shift = 0,
.width = 10,
},
.l = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 28,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.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,
@ -1524,6 +1576,616 @@ static struct clk_regmap gxbb_vapb = {
},
};
/* Video Clocks */
static struct clk_regmap gxbb_vid_pll_div = {
.data = &(struct meson_vid_pll_div_data){
.val = {
.reg_off = HHI_VID_PLL_CLK_DIV,
.shift = 0,
.width = 15,
},
.sel = {
.reg_off = HHI_VID_PLL_CLK_DIV,
.shift = 16,
.width = 2,
},
},
.hw.init = &(struct clk_init_data) {
.name = "vid_pll_div",
.ops = &meson_vid_pll_div_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
},
};
static const char * const gxbb_vid_pll_parent_names[] = { "vid_pll_div", "hdmi_pll" };
static struct clk_regmap gxbb_vid_pll_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VID_PLL_CLK_DIV,
.mask = 0x1,
.shift = 18,
},
.hw.init = &(struct clk_init_data){
.name = "vid_pll_sel",
.ops = &clk_regmap_mux_ops,
/*
* bit 18 selects from 2 possible parents:
* vid_pll_div or hdmi_pll
*/
.parent_names = gxbb_vid_pll_parent_names,
.num_parents = ARRAY_SIZE(gxbb_vid_pll_parent_names),
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_vid_pll = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_PLL_CLK_DIV,
.bit_idx = 19,
},
.hw.init = &(struct clk_init_data) {
.name = "vid_pll",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vid_pll_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static const char * const gxbb_vclk_parent_names[] = {
"vid_pll", "fclk_div4", "fclk_div3", "fclk_div5", "vid_pll",
"fclk_div7", "mpll1",
};
static struct clk_regmap gxbb_vclk_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VID_CLK_CNTL,
.mask = 0x7,
.shift = 16,
},
.hw.init = &(struct clk_init_data){
.name = "vclk_sel",
.ops = &clk_regmap_mux_ops,
/*
* bits 16:18 selects from 8 possible parents:
* vid_pll, fclk_div4, fclk_div3, fclk_div5,
* vid_pll, fclk_div7, mp1
*/
.parent_names = gxbb_vclk_parent_names,
.num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_vclk2_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VIID_CLK_CNTL,
.mask = 0x7,
.shift = 16,
},
.hw.init = &(struct clk_init_data){
.name = "vclk2_sel",
.ops = &clk_regmap_mux_ops,
/*
* bits 16:18 selects from 8 possible parents:
* vid_pll, fclk_div4, fclk_div3, fclk_div5,
* vid_pll, fclk_div7, mp1
*/
.parent_names = gxbb_vclk_parent_names,
.num_parents = ARRAY_SIZE(gxbb_vclk_parent_names),
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_vclk_input = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_DIV,
.bit_idx = 16,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk_input",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk2_input = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_DIV,
.bit_idx = 16,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk2_input",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk2_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_VID_CLK_DIV,
.shift = 0,
.width = 8,
},
.hw.init = &(struct clk_init_data){
.name = "vclk_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "vclk_input" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_vclk2_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_VIID_CLK_DIV,
.shift = 0,
.width = 8,
},
.hw.init = &(struct clk_init_data){
.name = "vclk2_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "vclk2_input" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_vclk = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 19,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk2 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_CNTL,
.bit_idx = 19,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk2",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk2_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk_div1 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 0,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk_div1",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk_div2_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 1,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk_div2_en",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk_div4_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 2,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk_div4_en",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk_div6_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 3,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk_div6_en",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk_div12_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 4,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk_div12_en",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk2_div1 = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_CNTL,
.bit_idx = 0,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk2_div1",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk2" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk2_div2_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_CNTL,
.bit_idx = 1,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk2_div2_en",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk2" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk2_div4_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_CNTL,
.bit_idx = 2,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk2_div4_en",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk2" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk2_div6_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_CNTL,
.bit_idx = 3,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk2_div6_en",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk2" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_vclk2_div12_en = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_CNTL,
.bit_idx = 4,
},
.hw.init = &(struct clk_init_data) {
.name = "vclk2_div12_en",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "vclk2" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_fixed_factor gxbb_vclk_div2 = {
.mult = 1,
.div = 2,
.hw.init = &(struct clk_init_data){
.name = "vclk_div2",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "vclk_div2_en" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_vclk_div4 = {
.mult = 1,
.div = 4,
.hw.init = &(struct clk_init_data){
.name = "vclk_div4",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "vclk_div4_en" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_vclk_div6 = {
.mult = 1,
.div = 6,
.hw.init = &(struct clk_init_data){
.name = "vclk_div6",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "vclk_div6_en" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_vclk_div12 = {
.mult = 1,
.div = 12,
.hw.init = &(struct clk_init_data){
.name = "vclk_div12",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "vclk_div12_en" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_vclk2_div2 = {
.mult = 1,
.div = 2,
.hw.init = &(struct clk_init_data){
.name = "vclk2_div2",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "vclk2_div2_en" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_vclk2_div4 = {
.mult = 1,
.div = 4,
.hw.init = &(struct clk_init_data){
.name = "vclk2_div4",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "vclk2_div4_en" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_vclk2_div6 = {
.mult = 1,
.div = 6,
.hw.init = &(struct clk_init_data){
.name = "vclk2_div6",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "vclk2_div6_en" },
.num_parents = 1,
},
};
static struct clk_fixed_factor gxbb_vclk2_div12 = {
.mult = 1,
.div = 12,
.hw.init = &(struct clk_init_data){
.name = "vclk2_div12",
.ops = &clk_fixed_factor_ops,
.parent_names = (const char *[]){ "vclk2_div12_en" },
.num_parents = 1,
},
};
static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
static const char * const gxbb_cts_parent_names[] = {
"vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
"vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
"vclk2_div6", "vclk2_div12"
};
static struct clk_regmap gxbb_cts_enci_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VID_CLK_DIV,
.mask = 0xf,
.shift = 28,
.table = mux_table_cts_sel,
},
.hw.init = &(struct clk_init_data){
.name = "cts_enci_sel",
.ops = &clk_regmap_mux_ops,
.parent_names = gxbb_cts_parent_names,
.num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_cts_encp_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VID_CLK_DIV,
.mask = 0xf,
.shift = 20,
.table = mux_table_cts_sel,
},
.hw.init = &(struct clk_init_data){
.name = "cts_encp_sel",
.ops = &clk_regmap_mux_ops,
.parent_names = gxbb_cts_parent_names,
.num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_cts_vdac_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VIID_CLK_DIV,
.mask = 0xf,
.shift = 28,
.table = mux_table_cts_sel,
},
.hw.init = &(struct clk_init_data){
.name = "cts_vdac_sel",
.ops = &clk_regmap_mux_ops,
.parent_names = gxbb_cts_parent_names,
.num_parents = ARRAY_SIZE(gxbb_cts_parent_names),
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
},
};
/* TOFIX: add support for cts_tcon */
static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
static const char * const gxbb_cts_hdmi_tx_parent_names[] = {
"vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
"vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
"vclk2_div6", "vclk2_div12"
};
static struct clk_regmap gxbb_hdmi_tx_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_HDMI_CLK_CNTL,
.mask = 0xf,
.shift = 16,
.table = mux_table_hdmi_tx_sel,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_tx_sel",
.ops = &clk_regmap_mux_ops,
/*
* bits 31:28 selects from 12 possible parents:
* vclk_div1, vclk_div2, vclk_div4, vclk_div6, vclk_div12
* vclk2_div1, vclk2_div2, vclk2_div4, vclk2_div6, vclk2_div12,
* cts_tcon
*/
.parent_names = gxbb_cts_hdmi_tx_parent_names,
.num_parents = ARRAY_SIZE(gxbb_cts_hdmi_tx_parent_names),
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_cts_enci = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 0,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_enci",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_enci_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_cts_encp = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 2,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_encp",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_encp_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_cts_vdac = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 4,
},
.hw.init = &(struct clk_init_data) {
.name = "cts_vdac",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "cts_vdac_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
static struct clk_regmap gxbb_hdmi_tx = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 5,
},
.hw.init = &(struct clk_init_data) {
.name = "hdmi_tx",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "hdmi_tx_sel" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
/* HDMI Clocks */
static const char * const gxbb_hdmi_parent_names[] = {
"xtal", "fclk_div4", "fclk_div3", "fclk_div5"
};
static struct clk_regmap gxbb_hdmi_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_HDMI_CLK_CNTL,
.mask = 0x3,
.shift = 9,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_sel",
.ops = &clk_regmap_mux_ops,
.parent_names = gxbb_hdmi_parent_names,
.num_parents = ARRAY_SIZE(gxbb_hdmi_parent_names),
.flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_hdmi_div = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_HDMI_CLK_CNTL,
.shift = 0,
.width = 7,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_div",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "hdmi_sel" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_hdmi = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_HDMI_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(struct clk_init_data) {
.name = "hdmi",
.ops = &clk_regmap_gate_ops,
.parent_names = (const char *[]){ "hdmi_div" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
},
};
/* VDEC clocks */
static const char * const gxbb_vdec_parent_names[] = {
@ -1935,6 +2597,46 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
[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,
[CLKID_VID_PLL_DIV] = &gxbb_vid_pll_div.hw,
[CLKID_VID_PLL_SEL] = &gxbb_vid_pll_sel.hw,
[CLKID_VID_PLL] = &gxbb_vid_pll.hw,
[CLKID_VCLK_SEL] = &gxbb_vclk_sel.hw,
[CLKID_VCLK2_SEL] = &gxbb_vclk2_sel.hw,
[CLKID_VCLK_INPUT] = &gxbb_vclk_input.hw,
[CLKID_VCLK2_INPUT] = &gxbb_vclk2_input.hw,
[CLKID_VCLK_DIV] = &gxbb_vclk_div.hw,
[CLKID_VCLK2_DIV] = &gxbb_vclk2_div.hw,
[CLKID_VCLK] = &gxbb_vclk.hw,
[CLKID_VCLK2] = &gxbb_vclk2.hw,
[CLKID_VCLK_DIV1] = &gxbb_vclk_div1.hw,
[CLKID_VCLK_DIV2_EN] = &gxbb_vclk_div2_en.hw,
[CLKID_VCLK_DIV2] = &gxbb_vclk_div2.hw,
[CLKID_VCLK_DIV4_EN] = &gxbb_vclk_div4_en.hw,
[CLKID_VCLK_DIV4] = &gxbb_vclk_div4.hw,
[CLKID_VCLK_DIV6_EN] = &gxbb_vclk_div6_en.hw,
[CLKID_VCLK_DIV6] = &gxbb_vclk_div6.hw,
[CLKID_VCLK_DIV12_EN] = &gxbb_vclk_div12_en.hw,
[CLKID_VCLK_DIV12] = &gxbb_vclk_div12.hw,
[CLKID_VCLK2_DIV1] = &gxbb_vclk2_div1.hw,
[CLKID_VCLK2_DIV2_EN] = &gxbb_vclk2_div2_en.hw,
[CLKID_VCLK2_DIV2] = &gxbb_vclk2_div2.hw,
[CLKID_VCLK2_DIV4_EN] = &gxbb_vclk2_div4_en.hw,
[CLKID_VCLK2_DIV4] = &gxbb_vclk2_div4.hw,
[CLKID_VCLK2_DIV6_EN] = &gxbb_vclk2_div6_en.hw,
[CLKID_VCLK2_DIV6] = &gxbb_vclk2_div6.hw,
[CLKID_VCLK2_DIV12_EN] = &gxbb_vclk2_div12_en.hw,
[CLKID_VCLK2_DIV12] = &gxbb_vclk2_div12.hw,
[CLKID_CTS_ENCI_SEL] = &gxbb_cts_enci_sel.hw,
[CLKID_CTS_ENCP_SEL] = &gxbb_cts_encp_sel.hw,
[CLKID_CTS_VDAC_SEL] = &gxbb_cts_vdac_sel.hw,
[CLKID_HDMI_TX_SEL] = &gxbb_hdmi_tx_sel.hw,
[CLKID_CTS_ENCI] = &gxbb_cts_enci.hw,
[CLKID_CTS_ENCP] = &gxbb_cts_encp.hw,
[CLKID_CTS_VDAC] = &gxbb_cts_vdac.hw,
[CLKID_HDMI_TX] = &gxbb_hdmi_tx.hw,
[CLKID_HDMI_SEL] = &gxbb_hdmi_sel.hw,
[CLKID_HDMI_DIV] = &gxbb_hdmi_div.hw,
[CLKID_HDMI] = &gxbb_hdmi.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -2101,11 +2803,51 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
[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_DCO] = &gxl_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,
[CLKID_VID_PLL_DIV] = &gxbb_vid_pll_div.hw,
[CLKID_VID_PLL_SEL] = &gxbb_vid_pll_sel.hw,
[CLKID_VID_PLL] = &gxbb_vid_pll.hw,
[CLKID_VCLK_SEL] = &gxbb_vclk_sel.hw,
[CLKID_VCLK2_SEL] = &gxbb_vclk2_sel.hw,
[CLKID_VCLK_INPUT] = &gxbb_vclk_input.hw,
[CLKID_VCLK2_INPUT] = &gxbb_vclk2_input.hw,
[CLKID_VCLK_DIV] = &gxbb_vclk_div.hw,
[CLKID_VCLK2_DIV] = &gxbb_vclk2_div.hw,
[CLKID_VCLK] = &gxbb_vclk.hw,
[CLKID_VCLK2] = &gxbb_vclk2.hw,
[CLKID_VCLK_DIV1] = &gxbb_vclk_div1.hw,
[CLKID_VCLK_DIV2_EN] = &gxbb_vclk_div2_en.hw,
[CLKID_VCLK_DIV2] = &gxbb_vclk_div2.hw,
[CLKID_VCLK_DIV4_EN] = &gxbb_vclk_div4_en.hw,
[CLKID_VCLK_DIV4] = &gxbb_vclk_div4.hw,
[CLKID_VCLK_DIV6_EN] = &gxbb_vclk_div6_en.hw,
[CLKID_VCLK_DIV6] = &gxbb_vclk_div6.hw,
[CLKID_VCLK_DIV12_EN] = &gxbb_vclk_div12_en.hw,
[CLKID_VCLK_DIV12] = &gxbb_vclk_div12.hw,
[CLKID_VCLK2_DIV1] = &gxbb_vclk2_div1.hw,
[CLKID_VCLK2_DIV2_EN] = &gxbb_vclk2_div2_en.hw,
[CLKID_VCLK2_DIV2] = &gxbb_vclk2_div2.hw,
[CLKID_VCLK2_DIV4_EN] = &gxbb_vclk2_div4_en.hw,
[CLKID_VCLK2_DIV4] = &gxbb_vclk2_div4.hw,
[CLKID_VCLK2_DIV6_EN] = &gxbb_vclk2_div6_en.hw,
[CLKID_VCLK2_DIV6] = &gxbb_vclk2_div6.hw,
[CLKID_VCLK2_DIV12_EN] = &gxbb_vclk2_div12_en.hw,
[CLKID_VCLK2_DIV12] = &gxbb_vclk2_div12.hw,
[CLKID_CTS_ENCI_SEL] = &gxbb_cts_enci_sel.hw,
[CLKID_CTS_ENCP_SEL] = &gxbb_cts_encp_sel.hw,
[CLKID_CTS_VDAC_SEL] = &gxbb_cts_vdac_sel.hw,
[CLKID_HDMI_TX_SEL] = &gxbb_hdmi_tx_sel.hw,
[CLKID_CTS_ENCI] = &gxbb_cts_enci.hw,
[CLKID_CTS_ENCP] = &gxbb_cts_encp.hw,
[CLKID_CTS_VDAC] = &gxbb_cts_vdac.hw,
[CLKID_HDMI_TX] = &gxbb_hdmi_tx.hw,
[CLKID_HDMI_SEL] = &gxbb_hdmi_sel.hw,
[CLKID_HDMI_DIV] = &gxbb_hdmi_div.hw,
[CLKID_HDMI] = &gxbb_hdmi.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@ -2116,6 +2858,7 @@ static struct clk_regmap *const gxbb_clk_regmaps[] = {
&gxbb_hdmi_pll,
&gxbb_hdmi_pll_od,
&gxbb_hdmi_pll_od2,
&gxbb_hdmi_pll_dco,
};
static struct clk_regmap *const gxl_clk_regmaps[] = {
@ -2123,6 +2866,7 @@ static struct clk_regmap *const gxl_clk_regmaps[] = {
&gxl_hdmi_pll,
&gxl_hdmi_pll_od,
&gxl_hdmi_pll_od2,
&gxl_hdmi_pll_dco,
};
static struct clk_regmap *const gx_clk_regmaps[] = {
@ -2278,9 +3022,40 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
&gxbb_gen_clk_div,
&gxbb_gen_clk,
&gxbb_fixed_pll_dco,
&gxbb_hdmi_pll_dco,
&gxbb_sys_pll_dco,
&gxbb_gp0_pll,
&gxbb_vid_pll,
&gxbb_vid_pll_sel,
&gxbb_vid_pll_div,
&gxbb_vclk,
&gxbb_vclk_sel,
&gxbb_vclk_div,
&gxbb_vclk_input,
&gxbb_vclk_div1,
&gxbb_vclk_div2_en,
&gxbb_vclk_div4_en,
&gxbb_vclk_div6_en,
&gxbb_vclk_div12_en,
&gxbb_vclk2,
&gxbb_vclk2_sel,
&gxbb_vclk2_div,
&gxbb_vclk2_input,
&gxbb_vclk2_div1,
&gxbb_vclk2_div2_en,
&gxbb_vclk2_div4_en,
&gxbb_vclk2_div6_en,
&gxbb_vclk2_div12_en,
&gxbb_cts_enci,
&gxbb_cts_enci_sel,
&gxbb_cts_encp,
&gxbb_cts_encp_sel,
&gxbb_cts_vdac,
&gxbb_cts_vdac_sel,
&gxbb_hdmi_tx,
&gxbb_hdmi_tx_sel,
&gxbb_hdmi_sel,
&gxbb_hdmi_div,
&gxbb_hdmi,
};
struct clkc_data {

View file

@ -165,8 +165,30 @@
#define CLKID_HDMI_PLL_OD2 163
#define CLKID_SYS_PLL_DCO 164
#define CLKID_GP0_PLL_DCO 165
#define CLKID_VID_PLL_SEL 167
#define CLKID_VID_PLL_DIV 168
#define CLKID_VCLK_SEL 169
#define CLKID_VCLK2_SEL 170
#define CLKID_VCLK_INPUT 171
#define CLKID_VCLK2_INPUT 172
#define CLKID_VCLK_DIV 173
#define CLKID_VCLK2_DIV 174
#define CLKID_VCLK_DIV2_EN 177
#define CLKID_VCLK_DIV4_EN 178
#define CLKID_VCLK_DIV6_EN 179
#define CLKID_VCLK_DIV12_EN 180
#define CLKID_VCLK2_DIV2_EN 181
#define CLKID_VCLK2_DIV4_EN 182
#define CLKID_VCLK2_DIV6_EN 183
#define CLKID_VCLK2_DIV12_EN 184
#define CLKID_CTS_ENCI_SEL 195
#define CLKID_CTS_ENCP_SEL 196
#define CLKID_CTS_VDAC_SEL 197
#define CLKID_HDMI_TX_SEL 198
#define CLKID_HDMI_SEL 203
#define CLKID_HDMI_DIV 204
#define NR_CLKS 166
#define NR_CLKS 206
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/gxbb-clkc.h>

File diff suppressed because it is too large Load diff

View file

@ -19,20 +19,26 @@
*
* [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf
*/
#define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */
#define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */
#define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in data sheet */
#define HHI_GCLK_MPEG1 0x144 /* 0x51 offset in data sheet */
#define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */
#define HHI_GCLK_OTHER 0x150 /* 0x54 offset in data sheet */
#define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */
#define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */
#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */
#define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */
#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */
#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */
#define HHI_VID_DIVIDER_CNTL 0x198 /* 0x66 offset in data sheet */
#define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */
#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */
#define HHI_NAND_CLK_CNTL 0x25c /* 0x97 offset in data sheet */
#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */
#define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */
#define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */
#define HHI_VID_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */
/*
* MPLL register offeset taken from the S905 datasheet. Vendor kernel source
@ -63,8 +69,8 @@
#define CLKID_MPLL1_DIV 97
#define CLKID_MPLL2_DIV 98
#define CLKID_CPU_IN_SEL 99
#define CLKID_CPU_DIV2 100
#define CLKID_CPU_DIV3 101
#define CLKID_CPU_IN_DIV2 100
#define CLKID_CPU_IN_DIV3 101
#define CLKID_CPU_SCALE_DIV 102
#define CLKID_CPU_SCALE_OUT_SEL 103
#define CLKID_MPLL_PREDIV 104
@ -76,10 +82,65 @@
#define CLKID_NAND_SEL 110
#define CLKID_NAND_DIV 111
#define CLKID_PLL_FIXED_DCO 113
#define CLKID_PLL_VID_DCO 114
#define CLKID_HDMI_PLL_DCO 114
#define CLKID_PLL_SYS_DCO 115
#define CLKID_CPU_CLK_DIV2 116
#define CLKID_CPU_CLK_DIV3 117
#define CLKID_CPU_CLK_DIV4 118
#define CLKID_CPU_CLK_DIV5 119
#define CLKID_CPU_CLK_DIV6 120
#define CLKID_CPU_CLK_DIV7 121
#define CLKID_CPU_CLK_DIV8 122
#define CLKID_ABP_SEL 123
#define CLKID_PERIPH_SEL 125
#define CLKID_AXI_SEL 127
#define CLKID_L2_DRAM_SEL 129
#define CLKID_HDMI_PLL_LVDS_OUT 131
#define CLKID_HDMI_PLL_HDMI_OUT 132
#define CLKID_VID_PLL_IN_SEL 133
#define CLKID_VID_PLL_IN_EN 134
#define CLKID_VID_PLL_PRE_DIV 135
#define CLKID_VID_PLL_POST_DIV 136
#define CLKID_VID_PLL_FINAL_DIV 137
#define CLKID_VCLK_IN_SEL 138
#define CLKID_VCLK_IN_EN 139
#define CLKID_VCLK_DIV1 140
#define CLKID_VCLK_DIV2_DIV 141
#define CLKID_VCLK_DIV2 142
#define CLKID_VCLK_DIV4_DIV 143
#define CLKID_VCLK_DIV4 144
#define CLKID_VCLK_DIV6_DIV 145
#define CLKID_VCLK_DIV6 146
#define CLKID_VCLK_DIV12_DIV 147
#define CLKID_VCLK_DIV12 148
#define CLKID_VCLK2_IN_SEL 149
#define CLKID_VCLK2_IN_EN 150
#define CLKID_VCLK2_DIV1 151
#define CLKID_VCLK2_DIV2_DIV 152
#define CLKID_VCLK2_DIV2 153
#define CLKID_VCLK2_DIV4_DIV 154
#define CLKID_VCLK2_DIV4 155
#define CLKID_VCLK2_DIV6_DIV 156
#define CLKID_VCLK2_DIV6 157
#define CLKID_VCLK2_DIV12_DIV 158
#define CLKID_VCLK2_DIV12 159
#define CLKID_CTS_ENCT_SEL 160
#define CLKID_CTS_ENCT 161
#define CLKID_CTS_ENCP_SEL 162
#define CLKID_CTS_ENCP 163
#define CLKID_CTS_ENCI_SEL 164
#define CLKID_CTS_ENCI 165
#define CLKID_HDMI_TX_PIXEL_SEL 166
#define CLKID_HDMI_TX_PIXEL 167
#define CLKID_CTS_ENCL_SEL 168
#define CLKID_CTS_ENCL 169
#define CLKID_CTS_VDAC0_SEL 170
#define CLKID_CTS_VDAC0 171
#define CLKID_HDMI_SYS_SEL 172
#define CLKID_HDMI_SYS_DIV 173
#define CLKID_HDMI_SYS 174
#define CLK_NR_CLKS 116
#define CLK_NR_CLKS 175
/*
* include the CLKID and RESETID that have

Some files were not shown because too many files have changed in this diff Show more