From 5eb8ba90958de1285120dae5d3a5d2b1a360b3b4 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:10:01 -0500 Subject: clk: highbank: fix refcount leak in hb_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 26cae166cff9 ("ARM: highbank: remove custom .init_time hook") Signed-off-by: Stephen Boyd --- drivers/clk/clk-highbank.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c index 727ed8e1bb72..8e4581004695 100644 --- a/drivers/clk/clk-highbank.c +++ b/drivers/clk/clk-highbank.c @@ -293,6 +293,7 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk /* Map system registers */ srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); hb_clk->reg = of_iomap(srnp, 0); + of_node_put(srnp); BUG_ON(!hb_clk->reg); hb_clk->reg += reg; -- cgit v1.2.3 From 70af6c5b5270e8101f318c4b69cc98a726edfab9 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:14:42 -0500 Subject: clk: qoriq: fix refcount leak in clockgen_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") Signed-off-by: Stephen Boyd --- drivers/clk/clk-qoriq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 4c30b6e799ed..97a0029a1cca 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -1389,6 +1389,7 @@ static void __init clockgen_init(struct device_node *np) pr_err("%s: Couldn't map %pOF regs\n", __func__, guts); } + of_node_put(guts); } } -- cgit v1.2.3 From 2274d8001fbb5e1942fbcab5ad2eb15553b09ed2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:21:31 -0500 Subject: clk: ti: fix refcount leak in ti_dt_clocks_register() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 5b385a45e001 ("clk: ti: add support for clkctrl aliases") Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index d0cd58534781..5174f9a91679 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -191,9 +191,13 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) clkdev_add(&c->lk); } else { if (num_args && !has_clkctrl_data) { - if (of_find_compatible_node(NULL, NULL, - "ti,clkctrl")) { + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, + "ti,clkctrl"); + if (np) { has_clkctrl_data = true; + of_node_put(np); } else { clkctrl_nodes_missing = true; -- cgit v1.2.3 From 7f9705beeb3759e69165e7aff588f6488ff6c1ac Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:29:02 -0500 Subject: clk: socfpga: fix refcount leak The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 5343325ff3dd ("clk: socfpga: add a clock driver for the Arria 10 platform") Fixes: a30d27ed739b ("clk: socfpga: fix clock driver for 3.15") Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-pll-a10.c | 1 + drivers/clk/socfpga/clk-pll.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index 35fabe1a32c3..269467e8e07e 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -95,6 +95,7 @@ static struct clk * __init __socfpga_pll_init(struct device_node *node, clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_a10_base_addr = of_iomap(clkmgr_np, 0); + of_node_put(clkmgr_np); BUG_ON(!clk_mgr_a10_base_addr); pll_clk->hw.reg = clk_mgr_a10_base_addr + reg; diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index c7f463172e4b..b4b44e9b5901 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -100,6 +100,7 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_base_addr = of_iomap(clkmgr_np, 0); + of_node_put(clkmgr_np); BUG_ON(!clk_mgr_base_addr); pll_clk->hw.reg = clk_mgr_base_addr + reg; -- cgit v1.2.3 From cee82eb9532090cd1dc953e845d71f9b1445c84e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:32:15 -0500 Subject: clk: samsung: exynos4: fix refcount leak in exynos4_get_xom() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: e062b571777f ("clk: exynos4: register clocks using common clock framework") Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-exynos4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 59d4d46667ce..54066e6508d3 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1028,6 +1028,7 @@ static unsigned long __init exynos4_get_xom(void) xom = readl(chipid_base + 8); iounmap(chipid_base); + of_node_put(np); } return xom; -- cgit v1.2.3 From c9ec1d8fef31b5fc9e90e99f9bd685db5caa7c5e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:53:00 -0500 Subject: clk: imx6q: fix refcount leak in imx6q_clocks_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 2acd1b6f889c ("ARM: i.MX6: implement clocks using common clock framework") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6q.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index bbe0c60f4d09..53617e0632a9 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -424,6 +424,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); anatop_base = base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); /* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { -- cgit v1.2.3 From 1731e14fb30212dd8c1e9f8fc1af061e56498c55 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:55:10 -0500 Subject: clk: imx6sx: fix refcount leak in imx6sx_clocks_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: d55135689019 ("ARM: imx: add clock driver for imx6sx") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx6sx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index 18527a335ace..91558b09bf9e 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -151,6 +151,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); -- cgit v1.2.3 From 5f8c183a996b76bb09748073c856e4246fd4ce95 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:57:16 -0500 Subject: clk: imx7d: fix refcount leak in imx7d_clocks_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 8f6d8094b215 ("ARM: imx: add imx7d clk tree support") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx7d.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index adb08f64c691..12e2e85bbe1c 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -404,6 +404,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); clks[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel)); clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel)); -- cgit v1.2.3 From 567177024e0313e4f0dcba7ba10c0732e50e655d Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:59:36 -0500 Subject: clk: vf610: fix refcount leak in vf610_clocks_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 1f2c5fd5f048 ("ARM: imx: add VF610 clock support") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-vf610.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 6dae54325a91..a334667c450a 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -203,6 +203,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop"); anatop_base = of_iomap(np, 0); BUG_ON(!anatop_base); + of_node_put(np); np = ccm_node; ccm_base = of_iomap(np, 0); -- cgit v1.2.3 From a3c24050bdf70c958a8d98c2823b66ea761e6a31 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:36:58 -0500 Subject: clk: armada-370: fix refcount leak in a370_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 07ad6836fa21 ("clk: mvebu: armada-370: maintain clock init order") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-370.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c index 7dedfaa6e152..5c6bbee396b3 100644 --- a/drivers/clk/mvebu/armada-370.c +++ b/drivers/clk/mvebu/armada-370.c @@ -175,8 +175,10 @@ static void __init a370_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &a370_coreclks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, a370_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init); -- cgit v1.2.3 From e7beeab9c61591cd0e690d8733d534c3f4278ff8 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:40:19 -0500 Subject: clk: kirkwood: fix refcount leak in kirkwood_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 58d516ae95cb ("clk: mvebu: kirkwood: maintain clock init order") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/kirkwood.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index 6f784167bda4..35af3aa18f1c 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c @@ -331,6 +331,8 @@ static void __init kirkwood_clk_init(struct device_node *np) if (cgnp) { mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc); + + of_node_put(cgnp); } } CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", -- cgit v1.2.3 From db20a90a4b6745dad62753f8bd2f66afdd5abc84 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:42:26 -0500 Subject: clk: armada-xp: fix refcount leak in axp_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 0a11a6ae9437 ("clk: mvebu: armada-xp: maintain clock init order") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/armada-xp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c index e8f03293ec83..fa1568279c23 100644 --- a/drivers/clk/mvebu/armada-xp.c +++ b/drivers/clk/mvebu/armada-xp.c @@ -226,7 +226,9 @@ static void __init axp_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &axp_coreclks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, axp_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init); -- cgit v1.2.3 From 9b4eedf627045ae5ddcff60a484200cdd554c413 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:48:05 -0500 Subject: clk: mv98dx3236: fix refcount leak in mv98dx3236_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 337072604224 ("clk: mvebu: Expand mv98dx3236-core-clock support") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/mv98dx3236.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mvebu/mv98dx3236.c b/drivers/clk/mvebu/mv98dx3236.c index 0a74cf7a7725..1c8ab4f834ba 100644 --- a/drivers/clk/mvebu/mv98dx3236.c +++ b/drivers/clk/mvebu/mv98dx3236.c @@ -172,7 +172,9 @@ static void __init mv98dx3236_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &mv98dx3236_core_clocks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init); -- cgit v1.2.3 From 8d726c5128298386b907963033be93407b0c4275 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:50:13 -0500 Subject: clk: dove: fix refcount leak in dove_clk_init() The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 8f7fc5450b64 ("clk: mvebu: dove: maintain clock init order") Fixes: 63b8d92c793f ("clk: add Dove PLL divider support for GPU, VMeta and AXI clocks") Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/dove.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c index e0dd99f36bf4..0bd09d33f9cf 100644 --- a/drivers/clk/mvebu/dove.c +++ b/drivers/clk/mvebu/dove.c @@ -188,10 +188,14 @@ static void __init dove_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &dove_coreclks); - if (ddnp) + if (ddnp) { dove_divider_clk_init(ddnp); + of_node_put(ddnp); + } - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, dove_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init); -- cgit v1.2.3 From a0e447b0c50240a90ab84b7126b3c06b0bab4adc Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Sun, 23 Dec 2018 01:42:49 +0900 Subject: clk: rockchip: fix frac settings of GPLL clock for rk3328 This patch fixes settings of GPLL frequency in fractional mode for rk3328. In this mode, FOUTVCO is calcurated by following formula: FOUTVCO = FREF * FBDIV / REFDIV + ((FREF * FRAC / REFDIV) >> 24) The problem is in FREF * FRAC >> 24 term. This result always lacks one from target value is specified by rate member. For example first itme of rk3328_pll_frac_rate originally has - rate : 1016064000 - refdiv: 3 - fbdiv : 127 - frac : 134217 - FREF * FBDIV / REFDIV = 1016000000 - (FREF * FRAC / REFDIV) >> 24 = 63999 Thus calculated rate is 1016063999. It seems wrong. If frac has 134218 (it is increased 1 from original value), second term is 64000. All other items have same situation. So this patch adds 1 to frac member in all items of rk3328_pll_frac_rate. Signed-off-by: Katsuhiro Suzuki Acked-by: Elaine Zhang Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index faa94adb2a37..65ab5c2f48b0 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -78,17 +78,17 @@ static struct rockchip_pll_rate_table rk3328_pll_rates[] = { static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = { /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ - RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217), + RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134218), /* vco = 1016064000 */ - RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088), + RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671089), /* vco = 983040000 */ - RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088), + RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671089), /* vco = 983040000 */ - RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088), + RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671089), /* vco = 860156000 */ - RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894), + RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797895), /* vco = 903168000 */ - RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329), + RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066330), /* vco = 819200000 */ { /* sentinel */ }, }; -- cgit v1.2.3 From 491b00ff699356a8dab10eb517a1b44205514c9e Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Sat, 29 Dec 2018 14:33:13 +0100 Subject: clk: rockchip: add CLK_SET_RATE_PARENT for rk3066 lcdc dclks Add CLK_SET_RATE_PARENT for both rk3066 lcdc dclk. Signed-off-by: Finley Xiao Signed-off-by: Johan Jonker Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3188.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 7ea20341e870..5ecf28854876 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -586,12 +586,12 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { COMPOSITE(0, "dclk_lcdc0_src", mux_pll_src_cpll_gpll_p, 0, RK2928_CLKSEL_CON(27), 0, 1, MFLAGS, 8, 8, DFLAGS, RK2928_CLKGATE_CON(3), 1, GFLAGS), - MUX(DCLK_LCDC0, "dclk_lcdc0", mux_rk3066_lcdc0_p, 0, + MUX(DCLK_LCDC0, "dclk_lcdc0", mux_rk3066_lcdc0_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(27), 4, 1, MFLAGS), COMPOSITE(0, "dclk_lcdc1_src", mux_pll_src_cpll_gpll_p, 0, RK2928_CLKSEL_CON(28), 0, 1, MFLAGS, 8, 8, DFLAGS, RK2928_CLKGATE_CON(3), 2, GFLAGS), - MUX(DCLK_LCDC1, "dclk_lcdc1", mux_rk3066_lcdc1_p, 0, + MUX(DCLK_LCDC1, "dclk_lcdc1", mux_rk3066_lcdc1_p, CLK_SET_RATE_PARENT, RK2928_CLKSEL_CON(28), 4, 1, MFLAGS), COMPOSITE_NOMUX(0, "cif1_pre", "cif_src", 0, -- cgit v1.2.3 From 83d0ea237bac5fb6a7509c69a8939e999693d311 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:35 +0100 Subject: dt-bindings: clk: meson: add ao slow clock path ids Add the CLKIDs for the slow clock generation path Reviewed-by: Rob Herring Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-2-jbrunet@baylibre.com --- include/dt-bindings/clock/axg-aoclkc.h | 7 ++++++- include/dt-bindings/clock/gxbb-aoclkc.h | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/axg-aoclkc.h b/include/dt-bindings/clock/axg-aoclkc.h index 61955016a55b..8ec4a269c7a6 100644 --- a/include/dt-bindings/clock/axg-aoclkc.h +++ b/include/dt-bindings/clock/axg-aoclkc.h @@ -21,6 +21,11 @@ #define CLKID_AO_SAR_ADC_SEL 8 #define CLKID_AO_SAR_ADC_DIV 9 #define CLKID_AO_SAR_ADC_CLK 10 -#define CLKID_AO_ALT_XTAL 11 +#define CLKID_AO_CTS_OSCIN 11 +#define CLKID_AO_32K_PRE 12 +#define CLKID_AO_32K_DIV 13 +#define CLKID_AO_32K_SEL 14 +#define CLKID_AO_32K 15 +#define CLKID_AO_CTS_RTC_OSCIN 16 #endif diff --git a/include/dt-bindings/clock/gxbb-aoclkc.h b/include/dt-bindings/clock/gxbb-aoclkc.h index 9d15e2221fdb..ec3b26319fc4 100644 --- a/include/dt-bindings/clock/gxbb-aoclkc.h +++ b/include/dt-bindings/clock/gxbb-aoclkc.h @@ -63,5 +63,12 @@ #define CLKID_AO_UART2 4 #define CLKID_AO_IR_BLASTER 5 #define CLKID_AO_CEC_32K 6 +#define CLKID_AO_CTS_OSCIN 7 +#define CLKID_AO_32K_PRE 8 +#define CLKID_AO_32K_DIV 9 +#define CLKID_AO_32K_SEL 10 +#define CLKID_AO_32K 11 +#define CLKID_AO_CTS_RTC_OSCIN 12 +#define CLKID_AO_CLK81 13 #endif -- cgit v1.2.3 From 8d9981efbcab066d17af4d3c85c169200f6f78df Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:36 +0100 Subject: clk: meson: clean-up clock registration Order, ids and size between the table of regmap clocks and the onecell data table could be different. Set regmap pointer in all the regmap clocks before starting the registration using the onecell data, to make sure we don't get into an incoherent situation. Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-3-jbrunet@baylibre.com --- drivers/clk/meson/meson-aoclk.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index f965845917e3..258c8d259ea1 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -65,15 +65,20 @@ int meson_aoclkc_probe(struct platform_device *pdev) return ret; } - /* - * Populate regmap and register all clks - */ - for (clkid = 0; clkid < data->num_clks; clkid++) { + /* Populate regmap */ + for (clkid = 0; clkid < data->num_clks; clkid++) data->clks[clkid]->map = regmap; + /* Register all clks */ + for (clkid = 0; clkid < data->hw_data->num; clkid++) { + if (!data->hw_data->hws[clkid]) + continue; + ret = devm_clk_hw_register(dev, data->hw_data->hws[clkid]); - if (ret) + if (ret) { + dev_err(dev, "Clock registration failed\n"); return ret; + } } return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, -- cgit v1.2.3 From a8d552a63857c73c6f0ea28dc8a70df10764b820 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:37 +0100 Subject: clk: meson: add dual divider clock driver Add the dual divider driver. This special divider make a weighted average between 2 dividers to reach fractional divider values. Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-4-jbrunet@baylibre.com --- drivers/clk/meson/Makefile | 2 +- drivers/clk/meson/clk-dualdiv.c | 130 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/clkc.h | 19 ++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/meson/clk-dualdiv.c diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index a849aa809825..f1fcafc046d5 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -3,7 +3,7 @@ # 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) += clk-input.o clk-dualdiv.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 diff --git a/drivers/clk/meson/clk-dualdiv.c b/drivers/clk/meson/clk-dualdiv.c new file mode 100644 index 000000000000..4d9e161de627 --- /dev/null +++ b/drivers/clk/meson/clk-dualdiv.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017 BayLibre, SAS + * Author: Neil Armstrong + * Author: Jerome Brunet + */ + +/* + * The AO Domain embeds a dual/divider to generate a more precise + * 32,768KHz clock for low-power suspend mode and CEC. + * ______ ______ + * | | | | + * | Div1 |-| Cnt1 | + * /|______| |______|\ + * -| ______ ______ X--> Out + * \| | | |/ + * | Div2 |-| Cnt2 | + * |______| |______| + * + * The dividing can be switched to single or dual, with a counter + * for each divider to set when the switching is done. + */ + +#include +#include "clkc.h" + +static inline struct meson_clk_dualdiv_data * +meson_clk_dualdiv_data(struct clk_regmap *clk) +{ + return (struct meson_clk_dualdiv_data *)clk->data; +} + +static unsigned long +__dualdiv_param_to_rate(unsigned long parent_rate, + const struct meson_clk_dualdiv_param *p) +{ + if (!p->dual) + return DIV_ROUND_CLOSEST(parent_rate, p->n1); + + return DIV_ROUND_CLOSEST(parent_rate * (p->m1 + p->m2), + p->n1 * p->m1 + p->n2 * p->m2); +} + +static unsigned long meson_clk_dualdiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + struct meson_clk_dualdiv_param setting; + + setting.dual = meson_parm_read(clk->map, &dualdiv->dual); + setting.n1 = meson_parm_read(clk->map, &dualdiv->n1) + 1; + setting.m1 = meson_parm_read(clk->map, &dualdiv->m1) + 1; + setting.n2 = meson_parm_read(clk->map, &dualdiv->n2) + 1; + setting.m2 = meson_parm_read(clk->map, &dualdiv->m2) + 1; + + return __dualdiv_param_to_rate(parent_rate, &setting); +} + +static const struct meson_clk_dualdiv_param * +__dualdiv_get_setting(unsigned long rate, unsigned long parent_rate, + struct meson_clk_dualdiv_data *dualdiv) +{ + const struct meson_clk_dualdiv_param *table = dualdiv->table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; + + if (!table) + return NULL; + + for (i = 0; table[i].n1; i++) { + now = __dualdiv_param_to_rate(parent_rate, &table[i]); + + /* If we get an exact match, don't bother any further */ + if (now == rate) { + return &table[i]; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + return (struct meson_clk_dualdiv_param *)&table[best_i]; +} + +static long meson_clk_dualdiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + const struct meson_clk_dualdiv_param *setting = + __dualdiv_get_setting(rate, *parent_rate, dualdiv); + + if (!setting) + return meson_clk_dualdiv_recalc_rate(hw, *parent_rate); + + return __dualdiv_param_to_rate(*parent_rate, setting); +} + +static int meson_clk_dualdiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk); + const struct meson_clk_dualdiv_param *setting = + __dualdiv_get_setting(rate, parent_rate, dualdiv); + + if (!setting) + return -EINVAL; + + meson_parm_write(clk->map, &dualdiv->dual, setting->dual); + meson_parm_write(clk->map, &dualdiv->n1, setting->n1 - 1); + meson_parm_write(clk->map, &dualdiv->m1, setting->m1 - 1); + meson_parm_write(clk->map, &dualdiv->n2, setting->n2 - 1); + meson_parm_write(clk->map, &dualdiv->m2, setting->m2 - 1); + + return 0; +} + +const struct clk_ops meson_clk_dualdiv_ops = { + .recalc_rate = meson_clk_dualdiv_recalc_rate, + .round_rate = meson_clk_dualdiv_round_rate, + .set_rate = meson_clk_dualdiv_set_rate, +}; +EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ops); + +const struct clk_ops meson_clk_dualdiv_ro_ops = { + .recalc_rate = meson_clk_dualdiv_recalc_rate, +}; +EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ro_ops); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 6183b22c4bf2..e3cd442db739 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -110,6 +110,23 @@ struct clk_regmap _name = { \ }, \ }; +struct meson_clk_dualdiv_param { + unsigned int n1; + unsigned int n2; + unsigned int m1; + unsigned int m2; + unsigned int dual; +}; + +struct meson_clk_dualdiv_data { + struct parm n1; + struct parm n2; + struct parm m1; + struct parm m2; + struct parm dual; + const struct meson_clk_dualdiv_param *table; +}; + /* clk_ops */ extern const struct clk_ops meson_clk_pll_ro_ops; extern const struct clk_ops meson_clk_pll_ops; @@ -118,6 +135,8 @@ 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; +extern const struct clk_ops meson_clk_dualdiv_ops; +extern const struct clk_ops meson_clk_dualdiv_ro_ops; struct clk_hw *meson_clk_hw_register_input(struct device *dev, const char *of_name, -- cgit v1.2.3 From b249623fd1472225232e8784864af55aec1fd81b Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:38 +0100 Subject: clk: meson: gxbb-ao: replace cec-32k with the dual divider Replace the cec-32k clock of gxbb-ao with the simpler dual divider driver. The dual divider implements only the dividing part. All the other bits are now exposed using simple elements, such as gates and muxes Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-5-jbrunet@baylibre.com --- drivers/clk/meson/Makefile | 2 +- drivers/clk/meson/gxbb-aoclk-32k.c | 193 ---------------------------- drivers/clk/meson/gxbb-aoclk.c | 251 +++++++++++++++++++++++++++++-------- drivers/clk/meson/gxbb-aoclk.h | 20 +-- 4 files changed, 204 insertions(+), 262 deletions(-) delete mode 100644 drivers/clk/meson/gxbb-aoclk-32k.c diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index f1fcafc046d5..8234e92eea38 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o clk-dualdiv.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 -obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o diff --git a/drivers/clk/meson/gxbb-aoclk-32k.c b/drivers/clk/meson/gxbb-aoclk-32k.c deleted file mode 100644 index 680467141a1d..000000000000 --- a/drivers/clk/meson/gxbb-aoclk-32k.c +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2017 BayLibre, SAS. - * Author: Neil Armstrong - */ - -#include -#include -#include -#include "gxbb-aoclk.h" - -/* - * The AO Domain embeds a dual/divider to generate a more precise - * 32,768KHz clock for low-power suspend mode and CEC. - * ______ ______ - * | | | | - * ______ | Div1 |-| Cnt1 | ______ - * | | /|______| |______|\ | | - * Xtal-->| Gate |---| ______ ______ X-X--| Gate |--> - * |______| | \| | | |/ | |______| - * | | Div2 |-| Cnt2 | | - * | |______| |______| | - * |_______________________| - * - * The dividing can be switched to single or dual, with a counter - * for each divider to set when the switching is done. - * The entire dividing mechanism can be also bypassed. - */ - -#define CLK_CNTL0_N1_MASK GENMASK(11, 0) -#define CLK_CNTL0_N2_MASK GENMASK(23, 12) -#define CLK_CNTL0_DUALDIV_EN BIT(28) -#define CLK_CNTL0_OUT_GATE_EN BIT(30) -#define CLK_CNTL0_IN_GATE_EN BIT(31) - -#define CLK_CNTL1_M1_MASK GENMASK(11, 0) -#define CLK_CNTL1_M2_MASK GENMASK(23, 12) -#define CLK_CNTL1_BYPASS_EN BIT(24) -#define CLK_CNTL1_SELECT_OSC BIT(27) - -#define PWR_CNTL_ALT_32K_SEL GENMASK(13, 10) - -struct cec_32k_freq_table { - unsigned long parent_rate; - unsigned long target_rate; - bool dualdiv; - unsigned int n1; - unsigned int n2; - unsigned int m1; - unsigned int m2; -}; - -static const struct cec_32k_freq_table aoclk_cec_32k_table[] = { - [0] = { - .parent_rate = 24000000, - .target_rate = 32768, - .dualdiv = true, - .n1 = 733, - .n2 = 732, - .m1 = 8, - .m2 = 11, - }, -}; - -/* - * If CLK_CNTL0_DUALDIV_EN == 0 - * - will use N1 divider only - * If CLK_CNTL0_DUALDIV_EN == 1 - * - hold M1 cycles of N1 divider then changes to N2 - * - hold M2 cycles of N2 divider then changes to N1 - * Then we can get more accurate division. - */ -static unsigned long aoclk_cec_32k_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw); - unsigned long n1; - u32 reg0, reg1; - - regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, ®0); - regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, ®1); - - if (reg1 & CLK_CNTL1_BYPASS_EN) - return parent_rate; - - if (reg0 & CLK_CNTL0_DUALDIV_EN) { - unsigned long n2, m1, m2, f1, f2, p1, p2; - - n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1; - n2 = FIELD_GET(CLK_CNTL0_N2_MASK, reg0) + 1; - - m1 = FIELD_GET(CLK_CNTL1_M1_MASK, reg1) + 1; - m2 = FIELD_GET(CLK_CNTL1_M2_MASK, reg1) + 1; - - f1 = DIV_ROUND_CLOSEST(parent_rate, n1); - f2 = DIV_ROUND_CLOSEST(parent_rate, n2); - - p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2)); - p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2)); - - return DIV_ROUND_UP(100000000, p1 + p2); - } - - n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1; - - return DIV_ROUND_CLOSEST(parent_rate, n1); -} - -static const struct cec_32k_freq_table *find_cec_32k_freq(unsigned long rate, - unsigned long prate) -{ - int i; - - for (i = 0 ; i < ARRAY_SIZE(aoclk_cec_32k_table) ; ++i) - if (aoclk_cec_32k_table[i].parent_rate == prate && - aoclk_cec_32k_table[i].target_rate == rate) - return &aoclk_cec_32k_table[i]; - - return NULL; -} - -static long aoclk_cec_32k_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate, - *prate); - - /* If invalid return first one */ - if (!freq) - return aoclk_cec_32k_table[0].target_rate; - - return freq->target_rate; -} - -/* - * From the Amlogic init procedure, the IN and OUT gates needs to be handled - * in the init procedure to avoid any glitches. - */ - -static int aoclk_cec_32k_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate, - parent_rate); - struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw); - u32 reg = 0; - - if (!freq) - return -EINVAL; - - /* Disable clock */ - regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, - CLK_CNTL0_IN_GATE_EN | CLK_CNTL0_OUT_GATE_EN, 0); - - reg = FIELD_PREP(CLK_CNTL0_N1_MASK, freq->n1 - 1); - if (freq->dualdiv) - reg |= CLK_CNTL0_DUALDIV_EN | - FIELD_PREP(CLK_CNTL0_N2_MASK, freq->n2 - 1); - - regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, reg); - - reg = FIELD_PREP(CLK_CNTL1_M1_MASK, freq->m1 - 1); - if (freq->dualdiv) - reg |= FIELD_PREP(CLK_CNTL1_M2_MASK, freq->m2 - 1); - - regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, reg); - - /* Enable clock */ - regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, - CLK_CNTL0_IN_GATE_EN, CLK_CNTL0_IN_GATE_EN); - - udelay(200); - - regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, - CLK_CNTL0_OUT_GATE_EN, CLK_CNTL0_OUT_GATE_EN); - - regmap_update_bits(cec_32k->regmap, AO_CRT_CLK_CNTL1, - CLK_CNTL1_SELECT_OSC, CLK_CNTL1_SELECT_OSC); - - /* Select 32k from XTAL */ - regmap_update_bits(cec_32k->regmap, - AO_RTI_PWR_CNTL_REG0, - PWR_CNTL_ALT_32K_SEL, - FIELD_PREP(PWR_CNTL_ALT_32K_SEL, 4)); - - return 0; -} - -const struct clk_ops meson_aoclk_cec_32k_ops = { - .recalc_rate = aoclk_cec_32k_recalc_rate, - .round_rate = aoclk_cec_32k_round_rate, - .set_rate = aoclk_cec_32k_set_rate, -}; diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 42ed61d3c3fb..5fa57b623b8f 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -5,10 +5,19 @@ */ #include #include -#include "clk-regmap.h" +#include "clkc.h" #include "meson-aoclk.h" #include "gxbb-aoclk.h" +/* AO Configuration Clock registers offsets */ +#define AO_RTI_PWR_CNTL_REG1 0x0c +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_OSCIN_CNTL 0x58 +#define AO_CRT_CLK_CNTL1 0x68 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + #define GXBB_AO_GATE(_name, _bit) \ static struct clk_regmap _name##_ao = { \ .data = &(struct clk_regmap_gate_data) { \ @@ -31,13 +40,174 @@ GXBB_AO_GATE(uart1, 3); GXBB_AO_GATE(uart2, 5); GXBB_AO_GATE(ir_blaster, 6); -static struct aoclk_cec_32k cec_32k_ao = { - .hw.init = &(struct clk_init_data) { - .name = "cec_32k_ao", - .ops = &meson_aoclk_cec_32k_ops, +static struct clk_regmap ao_cts_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTI_PWR_CNTL_REG0, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_oscin", + .ops = &clk_regmap_gate_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, - .flags = CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap ao_32k_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_pre", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "ao_cts_oscin" }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param gxbb_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, {} +}; + +static struct clk_regmap ao_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 28, + .width = 1, + }, + .table = gxbb_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_names = (const char *[]){ "ao_32k_pre" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap ao_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_ALT_CLK_CNTL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "ao_32k_div", + "ao_32k_pre" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap ao_32k = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_32k", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "ao_32k_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap ao_cts_rtc_oscin = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x7, + .shift = 10, + .table = (u32[]){ 1, 2, 3, 4 }, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "ext_32k_0", + "ext_32k_1", + "ext_32k_2", + "ao_32k" }, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap ao_clk81 = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 0, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_clk81", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "clk81", + "ao_cts_rtc_oscin" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap ao_cts_cec = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_CRT_CLK_CNTL1, + .mask = 0x1, + .shift = 27, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ao_cts_cec", + .ops = &clk_regmap_mux_ops, + /* + * FIXME: The 'fixme' parent obviously does not exist. + * + * ATM, CCF won't call get_parent() if num_parents is 1. It + * does not allow NULL as a parent name either. + * + * On this particular mux, we only know the input #1 parent + * but, on boot, unknown input #0 is set, so it is critical + * to call .get_parent() on it + * + * Until CCF gets fixed, adding this fake parent that won't + * ever be registered should work around the problem + */ + .parent_names = (const char *[]){ "fixme", + "ao_cts_rtc_oscin" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -50,13 +220,21 @@ static const unsigned int gxbb_aoclk_reset[] = { [RESET_AO_IR_BLASTER] = 23, }; -static struct clk_regmap *gxbb_aoclk_gate[] = { - [CLKID_AO_REMOTE] = &remote_ao, - [CLKID_AO_I2C_MASTER] = &i2c_master_ao, - [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, - [CLKID_AO_UART1] = &uart1_ao, - [CLKID_AO_UART2] = &uart2_ao, - [CLKID_AO_IR_BLASTER] = &ir_blaster_ao, +static struct clk_regmap *gxbb_aoclk[] = { + &remote_ao, + &i2c_master_ao, + &i2c_slave_ao, + &uart1_ao, + &uart2_ao, + &ir_blaster_ao, + &ao_cts_oscin, + &ao_32k_pre, + &ao_32k_div, + &ao_32k_sel, + &ao_32k, + &ao_cts_rtc_oscin, + &ao_clk81, + &ao_cts_cec, }; static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { @@ -67,52 +245,27 @@ static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { [CLKID_AO_UART1] = &uart1_ao.hw, [CLKID_AO_UART2] = &uart2_ao.hw, [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw, - [CLKID_AO_CEC_32K] = &cec_32k_ao.hw, + [CLKID_AO_CEC_32K] = &ao_cts_cec.hw, + [CLKID_AO_CTS_OSCIN] = &ao_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &ao_32k_pre.hw, + [CLKID_AO_32K_DIV] = &ao_32k_div.hw, + [CLKID_AO_32K_SEL] = &ao_32k_sel.hw, + [CLKID_AO_32K] = &ao_32k.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &ao_cts_rtc_oscin.hw, + [CLKID_AO_CLK81] = &ao_clk81.hw, }, .num = NR_CLKS, }; -static int gxbb_register_cec_ao_32k(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct regmap *regmap; - int ret; - - regmap = syscon_node_to_regmap(of_get_parent(dev->of_node)); - if (IS_ERR(regmap)) { - dev_err(dev, "failed to get regmap\n"); - return PTR_ERR(regmap); - } - - /* Specific clocks */ - cec_32k_ao.regmap = regmap; - ret = devm_clk_hw_register(dev, &cec_32k_ao.hw); - if (ret) { - dev_err(&pdev->dev, "clk cec_32k_ao register failed.\n"); - return ret; - } - - return 0; -} - static const struct meson_aoclk_data gxbb_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(gxbb_aoclk_reset), .reset = gxbb_aoclk_reset, - .num_clks = ARRAY_SIZE(gxbb_aoclk_gate), - .clks = gxbb_aoclk_gate, + .num_clks = ARRAY_SIZE(gxbb_aoclk), + .clks = gxbb_aoclk, .hw_data = &gxbb_aoclk_onecell_data, }; -static int gxbb_aoclkc_probe(struct platform_device *pdev) -{ - int ret = gxbb_register_cec_ao_32k(pdev); - if (ret) - return ret; - - return meson_aoclkc_probe(pdev); -} - static const struct of_device_id gxbb_aoclkc_match_table[] = { { .compatible = "amlogic,meson-gx-aoclkc", @@ -122,7 +275,7 @@ static const struct of_device_id gxbb_aoclkc_match_table[] = { }; static struct platform_driver gxbb_aoclkc_driver = { - .probe = gxbb_aoclkc_probe, + .probe = meson_aoclkc_probe, .driver = { .name = "gxbb-aoclkc", .of_match_table = gxbb_aoclkc_match_table, diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h index c514493d989a..1db16f9b37d4 100644 --- a/drivers/clk/meson/gxbb-aoclk.h +++ b/drivers/clk/meson/gxbb-aoclk.h @@ -7,25 +7,7 @@ #ifndef __GXBB_AOCLKC_H #define __GXBB_AOCLKC_H -#define NR_CLKS 7 - -/* AO Configuration Clock registers offsets */ -#define AO_RTI_PWR_CNTL_REG1 0x0c -#define AO_RTI_PWR_CNTL_REG0 0x10 -#define AO_RTI_GEN_CNTL_REG0 0x40 -#define AO_OSCIN_CNTL 0x58 -#define AO_CRT_CLK_CNTL1 0x68 -#define AO_RTC_ALT_CLK_CNTL0 0x94 -#define AO_RTC_ALT_CLK_CNTL1 0x98 - -struct aoclk_cec_32k { - struct clk_hw hw; - struct regmap *regmap; -}; - -#define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw) - -extern const struct clk_ops meson_aoclk_cec_32k_ops; +#define NR_CLKS 14 #include #include -- cgit v1.2.3 From 172e95346d5e3b364d71e3980c966cf323e0fdd7 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 21 Dec 2018 17:02:39 +0100 Subject: clk: meson: axg-ao: add 32k generation subtree Add the clock subtree generating the 32k clock in amlogic axg ao block. Signed-off-by: Jerome Brunet Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181221160239.26265-6-jbrunet@baylibre.com --- drivers/clk/meson/axg-aoclk.c | 175 ++++++++++++++++++++++++++++++++++++++---- drivers/clk/meson/axg-aoclk.h | 13 +--- 2 files changed, 163 insertions(+), 25 deletions(-) diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index 29e088542387..5f518be144ce 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -12,10 +12,23 @@ #include #include #include -#include "clk-regmap.h" +#include "clkc.h" #include "meson-aoclk.h" #include "axg-aoclk.h" +/* + * AO Configuration Clock registers offsets + * Register offsets from the data sheet must be multiplied by 4. + */ +#define AO_RTI_PWR_CNTL_REG1 0x0C +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_OSCIN_CNTL 0x58 +#define AO_CRT_CLK_CNTL1 0x68 +#define AO_SAR_CLK 0x90 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + #define AXG_AO_GATE(_name, _bit) \ static struct clk_regmap axg_aoclk_##_name = { \ .data = &(struct clk_regmap_gate_data) { \ @@ -39,17 +52,141 @@ AXG_AO_GATE(uart2, 5); AXG_AO_GATE(ir_blaster, 6); AXG_AO_GATE(saradc, 7); +static struct clk_regmap axg_aoclk_cts_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTI_PWR_CNTL_REG0, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_oscin", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_aoclk_32k_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_pre", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "cts_oscin" }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param axg_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, {} +}; + +static struct clk_regmap axg_aoclk_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 28, + .width = 1, + }, + .table = axg_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_names = (const char *[]){ "axg_ao_32k_pre" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap axg_aoclk_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_ALT_CLK_CNTL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "axg_ao_32k_div", + "axg_ao_32k_pre" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_aoclk_32k = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_32k", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "axg_ao_32k_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_aoclk_cts_rtc_oscin = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 10, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "axg_ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "axg_ao_32k", + "axg_ext_32k" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap axg_aoclk_clk81 = { .data = &(struct clk_regmap_mux_data) { .offset = AO_RTI_PWR_CNTL_REG0, .mask = 0x1, .shift = 8, + .flags = CLK_MUX_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ .name = "axg_ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "clk81", "ao_alt_xtal"}, + .parent_names = (const char *[]){ "clk81", + "axg_ao_cts_rtc_oscin"}, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -106,17 +243,23 @@ static const unsigned int axg_aoclk_reset[] = { }; static struct clk_regmap *axg_aoclk_regmap[] = { - [CLKID_AO_REMOTE] = &axg_aoclk_remote, - [CLKID_AO_I2C_MASTER] = &axg_aoclk_i2c_master, - [CLKID_AO_I2C_SLAVE] = &axg_aoclk_i2c_slave, - [CLKID_AO_UART1] = &axg_aoclk_uart1, - [CLKID_AO_UART2] = &axg_aoclk_uart2, - [CLKID_AO_IR_BLASTER] = &axg_aoclk_ir_blaster, - [CLKID_AO_SAR_ADC] = &axg_aoclk_saradc, - [CLKID_AO_CLK81] = &axg_aoclk_clk81, - [CLKID_AO_SAR_ADC_SEL] = &axg_aoclk_saradc_mux, - [CLKID_AO_SAR_ADC_DIV] = &axg_aoclk_saradc_div, - [CLKID_AO_SAR_ADC_CLK] = &axg_aoclk_saradc_gate, + &axg_aoclk_remote, + &axg_aoclk_i2c_master, + &axg_aoclk_i2c_slave, + &axg_aoclk_uart1, + &axg_aoclk_uart2, + &axg_aoclk_ir_blaster, + &axg_aoclk_saradc, + &axg_aoclk_cts_oscin, + &axg_aoclk_32k_pre, + &axg_aoclk_32k_div, + &axg_aoclk_32k_sel, + &axg_aoclk_32k, + &axg_aoclk_cts_rtc_oscin, + &axg_aoclk_clk81, + &axg_aoclk_saradc_mux, + &axg_aoclk_saradc_div, + &axg_aoclk_saradc_gate, }; static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { @@ -132,6 +275,12 @@ static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { [CLKID_AO_SAR_ADC_SEL] = &axg_aoclk_saradc_mux.hw, [CLKID_AO_SAR_ADC_DIV] = &axg_aoclk_saradc_div.hw, [CLKID_AO_SAR_ADC_CLK] = &axg_aoclk_saradc_gate.hw, + [CLKID_AO_CTS_OSCIN] = &axg_aoclk_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &axg_aoclk_32k_pre.hw, + [CLKID_AO_32K_DIV] = &axg_aoclk_32k_div.hw, + [CLKID_AO_32K_SEL] = &axg_aoclk_32k_sel.hw, + [CLKID_AO_32K] = &axg_aoclk_32k.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &axg_aoclk_cts_rtc_oscin.hw, }, .num = NR_CLKS, }; diff --git a/drivers/clk/meson/axg-aoclk.h b/drivers/clk/meson/axg-aoclk.h index 91384d8dd844..3cc27e85170f 100644 --- a/drivers/clk/meson/axg-aoclk.h +++ b/drivers/clk/meson/axg-aoclk.h @@ -10,18 +10,7 @@ #ifndef __AXG_AOCLKC_H #define __AXG_AOCLKC_H -#define NR_CLKS 11 -/* AO Configuration Clock registers offsets - * Register offsets from the data sheet must be multiplied by 4. - */ -#define AO_RTI_PWR_CNTL_REG1 0x0C -#define AO_RTI_PWR_CNTL_REG0 0x10 -#define AO_RTI_GEN_CNTL_REG0 0x40 -#define AO_OSCIN_CNTL 0x58 -#define AO_CRT_CLK_CNTL1 0x68 -#define AO_SAR_CLK 0x90 -#define AO_RTC_ALT_CLK_CNTL0 0x94 -#define AO_RTC_ALT_CLK_CNTL1 0x98 +#define NR_CLKS 17 #include #include -- cgit v1.2.3 From cce433e6bc53b3984274c61c78d0dadb87483646 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 8 Dec 2018 18:12:44 +0100 Subject: clk: meson: meson8b: use a separate clock table for Meson8 The Meson8 SoC is slightly different compared to Meson8b and Meson8m2 because it does not have the glitch-free Mali GPU clock mux. For Meson8b and Meson8m2 there are currently no known differences. Add a separate clk_hw_onecell_data table for Meson8 so these differences can be implemented. For now meson8_hw_onecell_data is a clone of our existing meson8b_hw_onecell_data. Signed-off-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181208171247.22238-3-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 203 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 197 insertions(+), 6 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 950d0e548c75..0b9353d8d4fd 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1659,6 +1659,185 @@ static MESON_GATE(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1); static MESON_GATE(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2); static MESON_GATE(meson8b_ao_iface, HHI_GCLK_AO, 3); +static struct clk_hw_onecell_data meson8_hw_onecell_data = { + .hws = { + [CLKID_XTAL] = &meson8b_xtal.hw, + [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, + [CLKID_PLL_VID] = &meson8b_vid_pll.hw, + [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, + [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, + [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, + [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, + [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, + [CLKID_CLK81] = &meson8b_clk81.hw, + [CLKID_DDR] = &meson8b_ddr.hw, + [CLKID_DOS] = &meson8b_dos.hw, + [CLKID_ISA] = &meson8b_isa.hw, + [CLKID_PL301] = &meson8b_pl301.hw, + [CLKID_PERIPHS] = &meson8b_periphs.hw, + [CLKID_SPICC] = &meson8b_spicc.hw, + [CLKID_I2C] = &meson8b_i2c.hw, + [CLKID_SAR_ADC] = &meson8b_sar_adc.hw, + [CLKID_SMART_CARD] = &meson8b_smart_card.hw, + [CLKID_RNG0] = &meson8b_rng0.hw, + [CLKID_UART0] = &meson8b_uart0.hw, + [CLKID_SDHC] = &meson8b_sdhc.hw, + [CLKID_STREAM] = &meson8b_stream.hw, + [CLKID_ASYNC_FIFO] = &meson8b_async_fifo.hw, + [CLKID_SDIO] = &meson8b_sdio.hw, + [CLKID_ABUF] = &meson8b_abuf.hw, + [CLKID_HIU_IFACE] = &meson8b_hiu_iface.hw, + [CLKID_ASSIST_MISC] = &meson8b_assist_misc.hw, + [CLKID_SPI] = &meson8b_spi.hw, + [CLKID_I2S_SPDIF] = &meson8b_i2s_spdif.hw, + [CLKID_ETH] = &meson8b_eth.hw, + [CLKID_DEMUX] = &meson8b_demux.hw, + [CLKID_AIU_GLUE] = &meson8b_aiu_glue.hw, + [CLKID_IEC958] = &meson8b_iec958.hw, + [CLKID_I2S_OUT] = &meson8b_i2s_out.hw, + [CLKID_AMCLK] = &meson8b_amclk.hw, + [CLKID_AIFIFO2] = &meson8b_aififo2.hw, + [CLKID_MIXER] = &meson8b_mixer.hw, + [CLKID_MIXER_IFACE] = &meson8b_mixer_iface.hw, + [CLKID_ADC] = &meson8b_adc.hw, + [CLKID_BLKMV] = &meson8b_blkmv.hw, + [CLKID_AIU] = &meson8b_aiu.hw, + [CLKID_UART1] = &meson8b_uart1.hw, + [CLKID_G2D] = &meson8b_g2d.hw, + [CLKID_USB0] = &meson8b_usb0.hw, + [CLKID_USB1] = &meson8b_usb1.hw, + [CLKID_RESET] = &meson8b_reset.hw, + [CLKID_NAND] = &meson8b_nand.hw, + [CLKID_DOS_PARSER] = &meson8b_dos_parser.hw, + [CLKID_USB] = &meson8b_usb.hw, + [CLKID_VDIN1] = &meson8b_vdin1.hw, + [CLKID_AHB_ARB0] = &meson8b_ahb_arb0.hw, + [CLKID_EFUSE] = &meson8b_efuse.hw, + [CLKID_BOOT_ROM] = &meson8b_boot_rom.hw, + [CLKID_AHB_DATA_BUS] = &meson8b_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &meson8b_ahb_ctrl_bus.hw, + [CLKID_HDMI_INTR_SYNC] = &meson8b_hdmi_intr_sync.hw, + [CLKID_HDMI_PCLK] = &meson8b_hdmi_pclk.hw, + [CLKID_USB1_DDR_BRIDGE] = &meson8b_usb1_ddr_bridge.hw, + [CLKID_USB0_DDR_BRIDGE] = &meson8b_usb0_ddr_bridge.hw, + [CLKID_MMC_PCLK] = &meson8b_mmc_pclk.hw, + [CLKID_DVIN] = &meson8b_dvin.hw, + [CLKID_UART2] = &meson8b_uart2.hw, + [CLKID_SANA] = &meson8b_sana.hw, + [CLKID_VPU_INTR] = &meson8b_vpu_intr.hw, + [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw, + [CLKID_CLK81_A9] = &meson8b_clk81_a9.hw, + [CLKID_VCLK2_VENCI0] = &meson8b_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &meson8b_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &meson8b_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &meson8b_vclk2_vencp1.hw, + [CLKID_GCLK_VENCI_INT] = &meson8b_gclk_venci_int.hw, + [CLKID_GCLK_VENCP_INT] = &meson8b_gclk_vencp_int.hw, + [CLKID_DAC_CLK] = &meson8b_dac_clk.hw, + [CLKID_AOCLK_GATE] = &meson8b_aoclk_gate.hw, + [CLKID_IEC958_GATE] = &meson8b_iec958_gate.hw, + [CLKID_ENC480P] = &meson8b_enc480p.hw, + [CLKID_RNG1] = &meson8b_rng1.hw, + [CLKID_GCLK_VENCL_INT] = &meson8b_gclk_vencl_int.hw, + [CLKID_VCLK2_VENCLMCC] = &meson8b_vclk2_venclmcc.hw, + [CLKID_VCLK2_VENCL] = &meson8b_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER] = &meson8b_vclk2_other.hw, + [CLKID_EDP] = &meson8b_edp.hw, + [CLKID_AO_MEDIA_CPU] = &meson8b_ao_media_cpu.hw, + [CLKID_AO_AHB_SRAM] = &meson8b_ao_ahb_sram.hw, + [CLKID_AO_AHB_BUS] = &meson8b_ao_ahb_bus.hw, + [CLKID_AO_IFACE] = &meson8b_ao_iface.hw, + [CLKID_MPLL0] = &meson8b_mpll0.hw, + [CLKID_MPLL1] = &meson8b_mpll1.hw, + [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, + [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, + [CLKID_CPU_IN_DIV2] = &meson8b_cpu_in_div2.hw, + [CLKID_CPU_IN_DIV3] = &meson8b_cpu_in_div3.hw, + [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, + [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, + [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, + [CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw, + [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, + [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, + [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, + [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, + [CLKID_CPU_CLK_DIV2] = &meson8b_cpu_clk_div2.hw, + [CLKID_CPU_CLK_DIV3] = &meson8b_cpu_clk_div3.hw, + [CLKID_CPU_CLK_DIV4] = &meson8b_cpu_clk_div4.hw, + [CLKID_CPU_CLK_DIV5] = &meson8b_cpu_clk_div5.hw, + [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, + [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, + [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, + [CLKID_ABP_SEL] = &meson8b_abp_clk_sel.hw, + [CLKID_ABP] = &meson8b_abp_clk_gate.hw, + [CLKID_PERIPH_SEL] = &meson8b_periph_clk_sel.hw, + [CLKID_PERIPH] = &meson8b_periph_clk_gate.hw, + [CLKID_AXI_SEL] = &meson8b_axi_clk_sel.hw, + [CLKID_AXI] = &meson8b_axi_clk_gate.hw, + [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_clk_sel.hw, + [CLKID_L2_DRAM] = &meson8b_l2_dram_clk_gate.hw, + [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, + [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, + [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, + [CLKID_VID_PLL_IN_EN] = &meson8b_vid_pll_in_en.hw, + [CLKID_VID_PLL_PRE_DIV] = &meson8b_vid_pll_pre_div.hw, + [CLKID_VID_PLL_POST_DIV] = &meson8b_vid_pll_post_div.hw, + [CLKID_VID_PLL_FINAL_DIV] = &meson8b_vid_pll_final_div.hw, + [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, + [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1_gate.hw, + [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2_div_gate.hw, + [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4_div_gate.hw, + [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6_div_gate.hw, + [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12_div_gate.hw, + [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_clk_in_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1_gate.hw, + [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2_div_gate.hw, + [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4_div_gate.hw, + [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6_div_gate.hw, + [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12_div_gate.hw, + [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, + [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, + [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, + [CLKID_CTS_ENCP] = &meson8b_cts_encp.hw, + [CLKID_CTS_ENCI_SEL] = &meson8b_cts_enci_sel.hw, + [CLKID_CTS_ENCI] = &meson8b_cts_enci.hw, + [CLKID_HDMI_TX_PIXEL_SEL] = &meson8b_hdmi_tx_pixel_sel.hw, + [CLKID_HDMI_TX_PIXEL] = &meson8b_hdmi_tx_pixel.hw, + [CLKID_CTS_ENCL_SEL] = &meson8b_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &meson8b_cts_encl.hw, + [CLKID_CTS_VDAC0_SEL] = &meson8b_cts_vdac0_sel.hw, + [CLKID_CTS_VDAC0] = &meson8b_cts_vdac0.hw, + [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, + [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, + [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLK_NR_CLKS] = NULL, + }, + .num = CLK_NR_CLKS, +}; + static struct clk_hw_onecell_data meson8b_hw_onecell_data = { .hws = { [CLKID_XTAL] = &meson8b_xtal.hw, @@ -2132,7 +2311,6 @@ static int meson8b_cpu_clk_notifier_cb(struct notifier_block *nb, static struct meson8b_nb_data meson8b_cpu_nb_data = { .nb.notifier_call = meson8b_cpu_clk_notifier_cb, - .onecell_data = &meson8b_hw_onecell_data, }; static const struct regmap_config clkc_regmap_config = { @@ -2141,7 +2319,8 @@ static const struct regmap_config clkc_regmap_config = { .reg_stride = 4, }; -static void __init meson8b_clkc_init(struct device_node *np) +static void __init meson8b_clkc_init_common(struct device_node *np, + struct clk_hw_onecell_data *clk_hw_onecell_data) { struct meson8b_clk_reset *rstc; const char *notifier_clk_name; @@ -2192,14 +2371,16 @@ static void __init meson8b_clkc_init(struct device_node *np) */ for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { /* array might be sparse */ - if (!meson8b_hw_onecell_data.hws[i]) + if (!clk_hw_onecell_data->hws[i]) continue; - ret = clk_hw_register(NULL, meson8b_hw_onecell_data.hws[i]); + ret = clk_hw_register(NULL, clk_hw_onecell_data->hws[i]); if (ret) return; } + meson8b_cpu_nb_data.onecell_data = clk_hw_onecell_data; + /* * FIXME we shouldn't program the muxes in notifier handlers. The * tricky programming sequence will be handled by the forthcoming @@ -2215,13 +2396,23 @@ static void __init meson8b_clkc_init(struct device_node *np) } ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, - &meson8b_hw_onecell_data); + clk_hw_onecell_data); if (ret) pr_err("%s: failed to register clock provider\n", __func__); } +static void __init meson8_clkc_init(struct device_node *np) +{ + return meson8b_clkc_init_common(np, &meson8_hw_onecell_data); +} + +static void __init meson8b_clkc_init(struct device_node *np) +{ + return meson8b_clkc_init_common(np, &meson8b_hw_onecell_data); +} + CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc", - meson8b_clkc_init); + meson8_clkc_init); CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc", meson8b_clkc_init); CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc", -- cgit v1.2.3 From 74e1f2521f16ffe38f1e49681a96588082f4406b Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 8 Dec 2018 18:12:45 +0100 Subject: clk: meson: meson8b: add the GPU clock tree Add the GPU clock tree on Meson8, Meson8b and Meson8m2. The GPU clock tree on Meson8b and Meson8m2 is almost identical to the one one GXBB: - there's a glitch-free mux at HHI_MALI_CLK_CNTL[31] - there are two identical parents for this mux: mali_0 and mali_1, each with a gate, divider and mux - the parents of mali_0_sel and mali_1_sel are identical to GXBB except there's no GP0_PLL on these 32-bit SoCs Meson8 is different because it does not have the glitch-free mux. Instead if only has the mali_0 clock tree. The parents of mali_0_sel are identical to the ones on Meson8b and Meson8m2. Signed-off-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20181208171247.22238-4-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/meson8b.h | 9 ++- 2 files changed, 154 insertions(+), 1 deletion(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 0b9353d8d4fd..748552c5f6c8 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1573,6 +1573,135 @@ static struct clk_regmap meson8b_hdmi_sys = { }, }; +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch on Meson8b and Meson8m2. Meson8 only + * has mali_0 and no glitch-free mux. + */ +static const char * const meson8b_mali_0_1_parent_names[] = { + "xtal", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", + "fclk_div5" +}; + +static u32 meson8b_mali_0_1_mux_table[] = { 0, 2, 3, 4, 5, 6, 7 }; + +static struct clk_regmap meson8b_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .table = meson8b_mali_0_1_mux_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = meson8b_mali_0_1_parent_names, + .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names), + /* + * Don't propagate rate changes up because the only changeable + * parents are mpll1 and mpll2 but we need those for audio and + * RGMII (Ethernet). We don't want to change the audio or + * Ethernet clocks when setting the GPU frequency. + */ + .flags = 0, + }, +}; + +static struct clk_regmap meson8b_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "mali_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mali_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .table = meson8b_mali_0_1_mux_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = meson8b_mali_0_1_parent_names, + .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names), + /* + * Don't propagate rate changes up because the only changeable + * parents are mpll1 and mpll2 but we need those for audio and + * RGMII (Ethernet). We don't want to change the audio or + * Ethernet clocks when setting the GPU frequency. + */ + .flags = 0, + }, +}; + +static struct clk_regmap meson8b_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "mali_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mali_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "mali_0", "mali_1" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); @@ -1833,6 +1962,9 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = { [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, + [CLKID_MALI] = &meson8b_mali_0.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -2012,6 +2144,13 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, + [CLKID_MALI_0_SEL] = &meson8b_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &meson8b_mali_0_div.hw, + [CLKID_MALI_0] = &meson8b_mali_0.hw, + [CLKID_MALI_1_SEL] = &meson8b_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &meson8b_mali_1_div.hw, + [CLKID_MALI_1] = &meson8b_mali_1.hw, + [CLKID_MALI] = &meson8b_mali.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -2167,6 +2306,13 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_hdmi_sys_sel, &meson8b_hdmi_sys_div, &meson8b_hdmi_sys, + &meson8b_mali_0_sel, + &meson8b_mali_0_div, + &meson8b_mali_0, + &meson8b_mali_1_sel, + &meson8b_mali_1_div, + &meson8b_mali_1, + &meson8b_mali, }; static const struct meson8b_clk_reset_line { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 87fba739af81..f212e2304ff5 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -33,6 +33,7 @@ #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_MALI_CLK_CNTL 0x1b0 /* 0x6c 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 */ @@ -139,8 +140,14 @@ #define CLKID_HDMI_SYS_SEL 172 #define CLKID_HDMI_SYS_DIV 173 #define CLKID_HDMI_SYS 174 +#define CLKID_MALI_0_SEL 175 +#define CLKID_MALI_0_DIV 176 +#define CLKID_MALI_0 177 +#define CLKID_MALI_1_SEL 178 +#define CLKID_MALI_1_DIV 179 +#define CLKID_MALI_1 180 -#define CLK_NR_CLKS 175 +#define CLK_NR_CLKS 181 /* * include the CLKID and RESETID that have -- cgit v1.2.3 From 26fe27d9201bb0a5568325f053326671dad4412c Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Mon, 17 Dec 2018 19:12:14 -0700 Subject: clk: qcom: Add CLK_SET_RATE_PARENT for 8998 branch clocks A branch clock is basically a clock that can be gated for power savings, but is also what devices/drivers consume. Configuring a branch clock's rate needs to be done at the source, so for all branch clocks which have a defined parent, set CLK_SET_RATE_PARENT so that clk_set_rate() calls on branch clocks can do what is expected. This is important as most drivers do not check the resulting clock rate after a successful clk_set_rate() call, thus the driver may get out of sync with the actual hardware state and weird issues might crop up. This has been observed with issues getting SDHCI to reliably support "fast" cards such as SDR104. Fixes: 4807c71cc688 (arm64: dts: Add msm8998 SoC and MTP board support) Signed-off-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-msm8998.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index 1b779396e04f..b618bbfa9a7f 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -1189,6 +1189,7 @@ static struct clk_branch gcc_aggre1_ufs_axi_clk = { "ufs_axi_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1206,6 +1207,7 @@ static struct clk_branch gcc_aggre1_usb3_axi_clk = { "usb30_master_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1288,6 +1290,7 @@ static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { "blsp1_qup1_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1305,6 +1308,7 @@ static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { "blsp1_qup1_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1322,6 +1326,7 @@ static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { "blsp1_qup2_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1339,6 +1344,7 @@ static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { "blsp1_qup2_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1356,6 +1362,7 @@ static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { "blsp1_qup3_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1373,6 +1380,7 @@ static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { "blsp1_qup3_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1390,6 +1398,7 @@ static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { "blsp1_qup4_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1407,6 +1416,7 @@ static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { "blsp1_qup4_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1424,6 +1434,7 @@ static struct clk_branch gcc_blsp1_qup5_i2c_apps_clk = { "blsp1_qup5_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1441,6 +1452,7 @@ static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = { "blsp1_qup5_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1458,6 +1470,7 @@ static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = { "blsp1_qup6_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1475,6 +1488,7 @@ static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = { "blsp1_qup6_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1505,6 +1519,7 @@ static struct clk_branch gcc_blsp1_uart1_apps_clk = { "blsp1_uart1_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1522,6 +1537,7 @@ static struct clk_branch gcc_blsp1_uart2_apps_clk = { "blsp1_uart2_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1539,6 +1555,7 @@ static struct clk_branch gcc_blsp1_uart3_apps_clk = { "blsp1_uart3_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1569,6 +1586,7 @@ static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = { "blsp2_qup1_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1586,6 +1604,7 @@ static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = { "blsp2_qup1_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1603,6 +1622,7 @@ static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = { "blsp2_qup2_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1620,6 +1640,7 @@ static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = { "blsp2_qup2_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1637,6 +1658,7 @@ static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = { "blsp2_qup3_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1654,6 +1676,7 @@ static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = { "blsp2_qup3_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1671,6 +1694,7 @@ static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = { "blsp2_qup4_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1688,6 +1712,7 @@ static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = { "blsp2_qup4_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1705,6 +1730,7 @@ static struct clk_branch gcc_blsp2_qup5_i2c_apps_clk = { "blsp2_qup5_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1722,6 +1748,7 @@ static struct clk_branch gcc_blsp2_qup5_spi_apps_clk = { "blsp2_qup5_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1739,6 +1766,7 @@ static struct clk_branch gcc_blsp2_qup6_i2c_apps_clk = { "blsp2_qup6_i2c_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1756,6 +1784,7 @@ static struct clk_branch gcc_blsp2_qup6_spi_apps_clk = { "blsp2_qup6_spi_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1786,6 +1815,7 @@ static struct clk_branch gcc_blsp2_uart1_apps_clk = { "blsp2_uart1_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1803,6 +1833,7 @@ static struct clk_branch gcc_blsp2_uart2_apps_clk = { "blsp2_uart2_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1820,6 +1851,7 @@ static struct clk_branch gcc_blsp2_uart3_apps_clk = { "blsp2_uart3_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1837,6 +1869,7 @@ static struct clk_branch gcc_cfg_noc_usb3_axi_clk = { "usb30_master_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1854,6 +1887,7 @@ static struct clk_branch gcc_gp1_clk = { "gp1_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1871,6 +1905,7 @@ static struct clk_branch gcc_gp2_clk = { "gp2_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1888,6 +1923,7 @@ static struct clk_branch gcc_gp3_clk = { "gp3_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1957,6 +1993,7 @@ static struct clk_branch gcc_hmss_ahb_clk = { "hmss_ahb_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1987,6 +2024,7 @@ static struct clk_branch gcc_hmss_rbcpr_clk = { "hmss_rbcpr_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2088,6 +2126,7 @@ static struct clk_branch gcc_pcie_0_aux_clk = { "pcie_aux_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2157,6 +2196,7 @@ static struct clk_branch gcc_pcie_phy_aux_clk = { "pcie_aux_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2174,6 +2214,7 @@ static struct clk_branch gcc_pdm2_clk = { "pdm2_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2243,6 +2284,7 @@ static struct clk_branch gcc_sdcc2_apps_clk = { "sdcc2_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2273,6 +2315,7 @@ static struct clk_branch gcc_sdcc4_apps_clk = { "sdcc4_apps_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2316,6 +2359,7 @@ static struct clk_branch gcc_tsif_ref_clk = { "tsif_ref_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2346,6 +2390,7 @@ static struct clk_branch gcc_ufs_axi_clk = { "ufs_axi_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2441,6 +2486,7 @@ static struct clk_branch gcc_usb30_master_clk = { "usb30_master_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2458,6 +2504,7 @@ static struct clk_branch gcc_usb30_mock_utmi_clk = { "usb30_mock_utmi_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2488,6 +2535,7 @@ static struct clk_branch gcc_usb3_phy_aux_clk = { "usb3_phy_aux_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, -- cgit v1.2.3 From 0c8ff62504e3a667387e87889a259632c3199a86 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 4 Jan 2019 09:49:46 -0700 Subject: clk: qcom: Add missing freq for usb30_master_clk on 8998 The usb30_master_clk supports a 60Mhz frequency, but that is missing from the table of supported frequencies. Add it. Fixes: b5f5f525c547 (clk: qcom: Add MSM8998 Global Clock Control (GCC) driver) Signed-off-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-msm8998.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index b618bbfa9a7f..96cf00c425a8 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -1112,6 +1112,7 @@ static struct clk_rcg2 ufs_axi_clk_src = { static const struct freq_tbl ftbl_usb30_master_clk_src[] = { F(19200000, P_XO, 1, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), F(120000000, P_GPLL0_OUT_MAIN, 5, 0, 0), F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), { } -- cgit v1.2.3 From 5f2420ed218981f037910bd029c19ff35ad1839c Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 4 Jan 2019 09:50:15 -0700 Subject: clk: qcom: Skip halt checks on gcc_usb3_phy_pipe_clk for 8998 The gcc_usb3_phy_pipe_clk is generated by the phy, but is also used by the phy during init. The clock needs to be enabled during the init sequence, but may not be fully active until after the init sequence is complete. This causes a catch-22 if the clock status is checked during enable. As a result, skip the checks to avoid the troubling situation. Signed-off-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-msm8998.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index 96cf00c425a8..3cbabbb8bd9a 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -2544,7 +2544,7 @@ static struct clk_branch gcc_usb3_phy_aux_clk = { static struct clk_branch gcc_usb3_phy_pipe_clk = { .halt_reg = 0x50004, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x50004, .enable_mask = BIT(0), -- cgit v1.2.3 From 5b42aac8904bfe8fcd65179c0fe71a6a1109ee53 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 13 Dec 2018 12:49:28 +0000 Subject: dt-bindings: clk: Add bindings for Fixed MMIO clock This patch adds a DT binding documentation for Fixed Memory Mapped IO clocks. Signed-off-by: Jan Kotas Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/fixed-mmio-clock.txt | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/fixed-mmio-clock.txt diff --git a/Documentation/devicetree/bindings/clock/fixed-mmio-clock.txt b/Documentation/devicetree/bindings/clock/fixed-mmio-clock.txt new file mode 100644 index 000000000000..c359367fd1a9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/fixed-mmio-clock.txt @@ -0,0 +1,24 @@ +Binding for simple memory mapped io fixed-rate clock sources. +The driver reads a clock frequency value from a single 32-bit memory mapped +I/O register and registers it as a fixed rate clock. + +It was designed for test systems, like FPGA, not for complete, finished SoCs. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "fixed-mmio-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- reg : Address and length of the clock value register set. + +Optional properties: +- clock-output-names : From common clock binding. + +Example: +sysclock: sysclock@fd020004 { + #clock-cells = <0>; + compatible = "fixed-mmio-clock"; + reg = <0xfd020004 0x4>; +}; -- cgit v1.2.3 From 50cc4caf531abb2075c6973451fccdaba9f02715 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 13 Dec 2018 12:49:29 +0000 Subject: clk: Add Fixed MMIO clock driver This patch adds a driver for Fixed MMIO clock. The driver reads a clock frequency value from a single 32-bit memory mapped register and registers it as a fixed rate clock. It can be enabled with COMMON_CLK_FIXED_MMIO Kconfig option. Signed-off-by: Jan Kotas [sboyd@kernel.org: Make of_fixed_mmio_clk_setup() static, use clk_hw based APIs] Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 6 +++ drivers/clk/Makefile | 1 + drivers/clk/clk-fixed-mmio.c | 101 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 drivers/clk/clk-fixed-mmio.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e5b2fe80eab4..296972518db4 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -290,6 +290,12 @@ config COMMON_CLK_BD718XX This driver supports ROHM BD71837 and ROHM BD71847 PMICs clock gates. +config COMMON_CLK_FIXED_MMIO + bool "Clock driver for Memory Mapped Fixed values" + depends on COMMON_CLK && OF + help + Support for Memory Mapped IO Fixed clocks + source "drivers/clk/actions/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 8a9440a97500..d6cd32bda771 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o +obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o diff --git a/drivers/clk/clk-fixed-mmio.c b/drivers/clk/clk-fixed-mmio.c new file mode 100644 index 000000000000..d1a97d971183 --- /dev/null +++ b/drivers/clk/clk-fixed-mmio.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Memory Mapped IO Fixed clock driver + * + * Copyright (C) 2018 Cadence Design Systems, Inc. + * + * Authors: + * Jan Kotas + */ + +#include +#include +#include +#include + +static struct clk_hw *fixed_mmio_clk_setup(struct device_node *node) +{ + struct clk_hw *clk; + const char *clk_name = node->name; + void __iomem *base; + u32 freq; + int ret; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%pOFn: failed to map address\n", node); + return ERR_PTR(-EIO); + } + + freq = readl(base); + iounmap(base); + of_property_read_string(node, "clock-output-names", &clk_name); + + clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0, freq); + if (IS_ERR(clk)) { + pr_err("%pOFn: failed to register fixed rate clock\n", node); + return clk; + } + + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, clk); + if (ret) { + pr_err("%pOFn: failed to add clock provider\n", node); + clk_hw_unregister(clk); + clk = ERR_PTR(ret); + } + + return clk; +} + +static void __init of_fixed_mmio_clk_setup(struct device_node *node) +{ + fixed_mmio_clk_setup(node); +} +CLK_OF_DECLARE(fixed_mmio_clk, "fixed-mmio-clock", of_fixed_mmio_clk_setup); + +/** + * This is not executed when of_fixed_mmio_clk_setup succeeded. + */ +static int of_fixed_mmio_clk_probe(struct platform_device *pdev) +{ + struct clk_hw *clk; + + clk = fixed_mmio_clk_setup(pdev->dev.of_node); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + platform_set_drvdata(pdev, clk); + + return 0; +} + +static int of_fixed_mmio_clk_remove(struct platform_device *pdev) +{ + struct clk_hw *clk = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + clk_hw_unregister_fixed_rate(clk); + + return 0; +} + +static const struct of_device_id of_fixed_mmio_clk_ids[] = { + { .compatible = "fixed-mmio-clock" }, + { } +}; +MODULE_DEVICE_TABLE(of, of_fixed_mmio_clk_ids); + +static struct platform_driver of_fixed_mmio_clk_driver = { + .driver = { + .name = "of_fixed_mmio_clk", + .of_match_table = of_fixed_mmio_clk_ids, + }, + .probe = of_fixed_mmio_clk_probe, + .remove = of_fixed_mmio_clk_remove, +}; +module_platform_driver(of_fixed_mmio_clk_driver); + +MODULE_AUTHOR("Jan Kotas "); +MODULE_DESCRIPTION("Memory Mapped IO Fixed clock driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6131dc81211cfcd8b7bd210665fbe0b6ba2e5fc5 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Mon, 17 Dec 2018 19:15:36 -0700 Subject: clk: qcom: smd: Add support for MSM8998 rpm clocks Add rpm smd clocks, PMIC and bus clocks which are required on MSM8998 for clients to vote on. Signed-off-by: Jeffrey Hugo Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/qcom,rpmcc.txt | 1 + drivers/clk/qcom/clk-smd-rpm.c | 63 ++++++++++++++++++++++ include/dt-bindings/clock/qcom,rpmcc.h | 10 ++++ 3 files changed, 74 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt index 87b4949e9bc8..944719bd586f 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt @@ -16,6 +16,7 @@ Required properties : "qcom,rpmcc-msm8974", "qcom,rpmcc" "qcom,rpmcc-apq8064", "qcom,rpmcc" "qcom,rpmcc-msm8996", "qcom,rpmcc" + "qcom,rpmcc-msm8998", "qcom,rpmcc" "qcom,rpmcc-qcs404", "qcom,rpmcc" - #clock-cells : shall contain 1 diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index d3aadaeb2903..22dd42ad9223 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -655,10 +655,73 @@ static const struct rpm_smd_clk_desc rpm_clk_qcs404 = { .num_clks = ARRAY_SIZE(qcs404_clks), }; +/* msm8998 */ +DEFINE_CLK_SMD_RPM(msm8998, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8998, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2); +DEFINE_CLK_SMD_RPM(msm8998, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, div_clk1, div_clk1_a, 0xb); +DEFINE_CLK_SMD_RPM(msm8998, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk1, ln_bb_clk1_a, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk2, ln_bb_clk2_a, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, ln_bb_clk3_pin, ln_bb_clk3_a_pin, + 3); +DEFINE_CLK_SMD_RPM(msm8998, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk, + QCOM_SMD_RPM_MMAXI_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8998, aggre1_noc_clk, aggre1_noc_a_clk, + QCOM_SMD_RPM_AGGR_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8998, aggre2_noc_clk, aggre2_noc_a_clk, + QCOM_SMD_RPM_AGGR_CLK, 2); +DEFINE_CLK_SMD_RPM_QDSS(msm8998, qdss_clk, qdss_a_clk, + QCOM_SMD_RPM_MISC_CLK, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk1, rf_clk1_a, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk2_pin, rf_clk2_a_pin, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk3, rf_clk3_a, 6); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk3_pin, rf_clk3_a_pin, 6); +static struct clk_smd_rpm *msm8998_clks[] = { + [RPM_SMD_SNOC_CLK] = &msm8998_snoc_clk, + [RPM_SMD_SNOC_A_CLK] = &msm8998_snoc_a_clk, + [RPM_SMD_CNOC_CLK] = &msm8998_cnoc_clk, + [RPM_SMD_CNOC_A_CLK] = &msm8998_cnoc_a_clk, + [RPM_SMD_CE1_CLK] = &msm8998_ce1_clk, + [RPM_SMD_CE1_A_CLK] = &msm8998_ce1_a_clk, + [RPM_SMD_DIV_CLK1] = &msm8998_div_clk1, + [RPM_SMD_DIV_A_CLK1] = &msm8998_div_clk1_a, + [RPM_SMD_IPA_CLK] = &msm8998_ipa_clk, + [RPM_SMD_IPA_A_CLK] = &msm8998_ipa_a_clk, + [RPM_SMD_LN_BB_CLK1] = &msm8998_ln_bb_clk1, + [RPM_SMD_LN_BB_CLK1_A] = &msm8998_ln_bb_clk1_a, + [RPM_SMD_LN_BB_CLK2] = &msm8998_ln_bb_clk2, + [RPM_SMD_LN_BB_CLK2_A] = &msm8998_ln_bb_clk2_a, + [RPM_SMD_LN_BB_CLK3_PIN] = &msm8998_ln_bb_clk3_pin, + [RPM_SMD_LN_BB_CLK3_A_PIN] = &msm8998_ln_bb_clk3_a_pin, + [RPM_SMD_MMAXI_CLK] = &msm8998_mmssnoc_axi_rpm_clk, + [RPM_SMD_MMAXI_A_CLK] = &msm8998_mmssnoc_axi_rpm_a_clk, + [RPM_SMD_AGGR1_NOC_CLK] = &msm8998_aggre1_noc_clk, + [RPM_SMD_AGGR1_NOC_A_CLK] = &msm8998_aggre1_noc_a_clk, + [RPM_SMD_AGGR2_NOC_CLK] = &msm8998_aggre2_noc_clk, + [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8998_aggre2_noc_a_clk, + [RPM_SMD_QDSS_CLK] = &msm8998_qdss_clk, + [RPM_SMD_QDSS_A_CLK] = &msm8998_qdss_a_clk, + [RPM_SMD_RF_CLK1] = &msm8998_rf_clk1, + [RPM_SMD_RF_CLK1_A] = &msm8998_rf_clk1_a, + [RPM_SMD_RF_CLK2_PIN] = &msm8998_rf_clk2_pin, + [RPM_SMD_RF_CLK2_A_PIN] = &msm8998_rf_clk2_a_pin, + [RPM_SMD_RF_CLK3] = &msm8998_rf_clk3, + [RPM_SMD_RF_CLK3_A] = &msm8998_rf_clk3_a, + [RPM_SMD_RF_CLK3_PIN] = &msm8998_rf_clk3_pin, + [RPM_SMD_RF_CLK3_A_PIN] = &msm8998_rf_clk3_a_pin, +}; + +static const struct rpm_smd_clk_desc rpm_clk_msm8998 = { + .clks = msm8998_clks, + .num_clks = ARRAY_SIZE(msm8998_clks), +}; + static const struct of_device_id rpm_smd_clk_match_table[] = { { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 }, { .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 }, + { .compatible = "qcom,rpmcc-msm8998", .data = &rpm_clk_msm8998 }, { .compatible = "qcom,rpmcc-qcs404", .data = &rpm_clk_qcs404 }, { } }; diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index 3658b0c14966..ede93a0ca156 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -127,5 +127,15 @@ #define RPM_SMD_BIMC_GPU_A_CLK 77 #define RPM_SMD_QPIC_CLK 78 #define RPM_SMD_QPIC_CLK_A 79 +#define RPM_SMD_LN_BB_CLK1 80 +#define RPM_SMD_LN_BB_CLK1_A 81 +#define RPM_SMD_LN_BB_CLK2 82 +#define RPM_SMD_LN_BB_CLK2_A 83 +#define RPM_SMD_LN_BB_CLK3_PIN 84 +#define RPM_SMD_LN_BB_CLK3_A_PIN 85 +#define RPM_SMD_RF_CLK3 86 +#define RPM_SMD_RF_CLK3_A 87 +#define RPM_SMD_RF_CLK3_PIN 88 +#define RPM_SMD_RF_CLK3_A_PIN 89 #endif -- cgit v1.2.3 From 77977b800451ea7f438bf0398c76e56ef92379fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 18 Dec 2018 12:20:48 +0100 Subject: clk: at91: enable AUDIOPLL as source for PCKx on SAMA5D2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Datasheet for SAMA5D2x mentions 6 sources for PCKx, the last being AUDIOPLL. Signed-off-by: MichaÅ‚ MirosÅ‚aw Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sama5d2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c index d69ad96fe988..ade063622531 100644 --- a/drivers/clk/at91/sama5d2.c +++ b/drivers/clk/at91/sama5d2.c @@ -241,13 +241,14 @@ static void __init sama5d2_pmc_setup(struct device_node *np) parent_names[2] = "plladivck"; parent_names[3] = "utmick"; parent_names[4] = "mck"; + parent_names[5] = "audiopll_pmcck"; for (i = 0; i < 3; i++) { char name[6]; snprintf(name, sizeof(name), "prog%d", i); hw = at91_clk_register_programmable(regmap, name, - parent_names, 5, i, + parent_names, 6, i, &at91sam9x5_programmable_layout); if (IS_ERR(hw)) goto err_free; -- cgit v1.2.3 From 31cc9e09688c77b2e87e5770802ebb1fd8ac9011 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 20 Dec 2018 11:54:33 +0300 Subject: clk: clps711x: Remove board support Since board support for the CLPS711X platform was removed, remove the board support from the clk-clps711x driver. Signed-off-by: Alexander Shiyan Acked-by: Arnd Bergmann Signed-off-by: Stephen Boyd --- drivers/clk/clk-clps711x.c | 61 +++++++++------------------------------------- 1 file changed, 11 insertions(+), 50 deletions(-) diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index 2c04396402ab..c36c47bdba02 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -44,21 +44,21 @@ struct clps711x_clk { struct clk_hw_onecell_data clk_data; }; -static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, - u32 fref) +static void __init clps711x_clk_init_dt(struct device_node *np) { - u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi; + u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi, fref = 0; struct clps711x_clk *clps711x_clk; - unsigned i; + void __iomem *base; + + WARN_ON(of_property_read_u32(np, "startup-frequency", &fref)); - if (!base) - return ERR_PTR(-ENOMEM); + base = of_iomap(np, 0); + BUG_ON(!base); clps711x_clk = kzalloc(struct_size(clps711x_clk, clk_data.hws, CLPS711X_CLK_MAX), GFP_KERNEL); - if (!clps711x_clk) - return ERR_PTR(-ENOMEM); + BUG_ON(!clps711x_clk); spin_lock_init(&clps711x_clk->lock); @@ -137,52 +137,13 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, clk_hw_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); clps711x_clk->clk_data.hws[CLPS711X_CLK_TICK] = clk_hw_register_fixed_rate(NULL, "tick", NULL, 0, 64); - for (i = 0; i < CLPS711X_CLK_MAX; i++) - if (IS_ERR(clps711x_clk->clk_data.hws[i])) + for (tmp = 0; tmp < CLPS711X_CLK_MAX; tmp++) + if (IS_ERR(clps711x_clk->clk_data.hws[tmp])) pr_err("clk %i: register failed with %ld\n", - i, PTR_ERR(clps711x_clk->clk_data.hws[i])); - - return clps711x_clk; -} - -void __init clps711x_clk_init(void __iomem *base) -{ - struct clps711x_clk *clps711x_clk; - - clps711x_clk = _clps711x_clk_init(base, 73728000); - - BUG_ON(IS_ERR(clps711x_clk)); - - /* Clocksource */ - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1], - NULL, "clps711x-timer.0"); - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2], - NULL, "clps711x-timer.1"); - - /* Drivers */ - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM], - NULL, "clps711x-pwm"); - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART], - NULL, "clps711x-uart.0"); - clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART], - NULL, "clps711x-uart.1"); -} - -#ifdef CONFIG_OF -static void __init clps711x_clk_init_dt(struct device_node *np) -{ - void __iomem *base = of_iomap(np, 0); - struct clps711x_clk *clps711x_clk; - u32 fref = 0; - - WARN_ON(of_property_read_u32(np, "startup-frequency", &fref)); - - clps711x_clk = _clps711x_clk_init(base, fref); - BUG_ON(IS_ERR(clps711x_clk)); + tmp, PTR_ERR(clps711x_clk->clk_data.hws[tmp])); clps711x_clk->clk_data.num = CLPS711X_CLK_MAX; of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clps711x_clk->clk_data); } CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt); -#endif -- cgit v1.2.3 From c0e6f5bf7676677af48abb8de706b2fb10191a27 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 16 Jan 2019 18:54:33 +0100 Subject: clk: meson: gxbb: claim clock controller input clock from DT Instead of relying on a fixed name for the xtal clock, claim the controller input clock trough DT. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190116175435.4990-2-jbrunet@baylibre.com --- drivers/clk/meson/gxbb.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 65f2599e5243..ecf9a8f6281c 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -16,6 +16,8 @@ #include "gxbb.h" #include "clk-regmap.h" +#define IN_PREFIX "ee-in-" + static DEFINE_SPINLOCK(meson_clk_lock); static const struct pll_params_table gxbb_gp0_pll_params_table[] = { @@ -118,7 +120,7 @@ static struct clk_regmap gxbb_fixed_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -148,7 +150,7 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_pre_mult", .ops = &clk_fixed_factor_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -241,7 +243,7 @@ static struct clk_regmap gxl_hdmi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, /* * Display directly handle hdmi pll registers ATM, we need @@ -378,7 +380,7 @@ static struct clk_regmap gxbb_sys_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -439,7 +441,7 @@ static struct clk_regmap gxbb_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -491,7 +493,7 @@ static struct clk_regmap gxl_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -789,7 +791,7 @@ static struct clk_regmap gxbb_mpll2 = { static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { - "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", + IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", "fclk_div3", "fclk_div5" }; @@ -852,7 +854,7 @@ static struct clk_regmap gxbb_sar_adc_clk_sel = { .name = "sar_adc_clk_sel", .ops = &clk_regmap_mux_ops, /* NOTE: The datasheet doesn't list the parents for bit 10 */ - .parent_names = (const char *[]){ "xtal", "clk81", }, + .parent_names = (const char *[]){ IN_PREFIX "xtal", "clk81", }, .num_parents = 2, }, }; @@ -891,7 +893,7 @@ static struct clk_regmap gxbb_sar_adc_clk = { */ static const char * const gxbb_mali_0_1_parent_names[] = { - "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", + IN_PREFIX "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", "fclk_div5" }; @@ -1153,7 +1155,7 @@ static struct clk_regmap gxbb_32k_clk = { }; static const char * const gxbb_32k_clk_parent_names[] = { - "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" + IN_PREFIX "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" }; static struct clk_regmap gxbb_32k_clk_sel = { @@ -1172,7 +1174,7 @@ static struct clk_regmap gxbb_32k_clk_sel = { }; static const char * const gxbb_sd_emmc_clk0_parent_names[] = { - "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", + IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", /* * Following these parent clocks, we should also have had mpll2, mpll3 @@ -2138,7 +2140,7 @@ static struct clk_regmap gxbb_hdmi_tx = { /* HDMI Clocks */ static const char * const gxbb_hdmi_parent_names[] = { - "xtal", "fclk_div4", "fclk_div3", "fclk_div5" + IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5" }; static struct clk_regmap gxbb_hdmi_sel = { @@ -2285,7 +2287,7 @@ static struct clk_regmap gxbb_vdec_hevc = { static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; static const char * const gen_clk_parent_names[] = { - "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2", + IN_PREFIX "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2", "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", }; @@ -3085,6 +3087,7 @@ static const struct of_device_id clkc_match_table[] = { static int gxbb_clkc_probe(struct platform_device *pdev) { const struct clkc_data *clkc_data; + struct clk_hw *input; struct regmap *map; int ret, i; struct device *dev = &pdev->dev; @@ -3100,6 +3103,14 @@ static int gxbb_clkc_probe(struct platform_device *pdev) return PTR_ERR(map); } + input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); + if (IS_ERR(input)) { + ret = PTR_ERR(input); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get input clock"); + return ret; + } + /* Populate regmap for the common regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) gx_clk_regmaps[i]->map = map; -- cgit v1.2.3 From 6e73dac7078f13d7fd2ee0d59941c5425bcf8ed8 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 16 Jan 2019 18:54:34 +0100 Subject: clk: meson: axg: claim clock controller input clock from DT Instead of relying on a fixed name for the xtal clock, claim the controller input clock trough DT. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190116175435.4990-3-jbrunet@baylibre.com --- drivers/clk/meson/axg.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 792735d7e46e..1c6539eeee7c 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -20,6 +20,8 @@ #include "clkc.h" #include "axg.h" +#define IN_PREFIX "ee-in-" + static DEFINE_SPINLOCK(meson_clk_lock); static struct clk_regmap axg_fixed_pll_dco = { @@ -58,7 +60,7 @@ static struct clk_regmap axg_fixed_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "fixed_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -113,7 +115,7 @@ static struct clk_regmap axg_sys_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "sys_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -214,7 +216,7 @@ static struct clk_regmap axg_gp0_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -283,7 +285,7 @@ static struct clk_regmap axg_hifi_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "hifi_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -701,7 +703,7 @@ static struct clk_regmap axg_pcie_pll_dco = { .hw.init = &(struct clk_init_data){ .name = "pcie_pll_dco", .ops = &meson_clk_pll_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -803,7 +805,7 @@ static struct clk_regmap axg_pcie_cml_en1 = { static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { - "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", + IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", "fclk_div3", "fclk_div5" }; @@ -852,7 +854,7 @@ static struct clk_regmap axg_clk81 = { }; static const char * const axg_sd_emmc_clk0_parent_names[] = { - "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", + IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", /* * Following these parent clocks, we should also have had mpll2, mpll3 @@ -957,7 +959,7 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, }; static const char * const gen_clk_parent_names[] = { - "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3", + IN_PREFIX "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3", "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", }; @@ -1263,6 +1265,7 @@ static const struct of_device_id clkc_match_table[] = { static int axg_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct clk_hw *input; struct regmap *map; int ret, i; @@ -1273,6 +1276,14 @@ static int axg_clkc_probe(struct platform_device *pdev) return PTR_ERR(map); } + input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); + if (IS_ERR(input)) { + ret = PTR_ERR(input); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get input clock"); + return ret; + } + /* Populate regmap for the regmap backed clocks */ for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) axg_clk_regmaps[i]->map = map; -- cgit v1.2.3 From 439a6bb5bfe775f9aa18f267a54878e0ac7f3d49 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 16 Jan 2019 18:54:35 +0100 Subject: clk: meson: ao-clkc: claim clock controller input clocks from DT Instead of relying on a fixed names for the differents input clocks of the controller, get them through DT. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190116175435.4990-4-jbrunet@baylibre.com --- drivers/clk/meson/axg-aoclk.c | 22 +++++++++++++++++----- drivers/clk/meson/gxbb-aoclk.c | 25 +++++++++++++++++++------ drivers/clk/meson/meson-aoclk.c | 37 ++++++++++++++++++++++++++++++++++++- drivers/clk/meson/meson-aoclk.h | 12 ++++++++++-- 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index 5f518be144ce..5701f5840b75 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -16,6 +16,8 @@ #include "meson-aoclk.h" #include "axg-aoclk.h" +#define IN_PREFIX "ao-in-" + /* * AO Configuration Clock registers offsets * Register offsets from the data sheet must be multiplied by 4. @@ -38,7 +40,7 @@ static struct clk_regmap axg_aoclk_##_name = { \ .hw.init = &(struct clk_init_data) { \ .name = "axg_ao_" #_name, \ .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ "clk81" }, \ + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ .num_parents = 1, \ .flags = CLK_IGNORE_UNUSED, \ }, \ @@ -60,7 +62,7 @@ static struct clk_regmap axg_aoclk_cts_oscin = { .hw.init = &(struct clk_init_data){ .name = "cts_oscin", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -167,7 +169,7 @@ static struct clk_regmap axg_aoclk_cts_rtc_oscin = { .name = "axg_ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "axg_ao_32k", - "axg_ext_32k" }, + IN_PREFIX "ext_32k-0" }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, }, @@ -183,7 +185,7 @@ static struct clk_regmap axg_aoclk_clk81 = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "clk81", + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", "axg_ao_cts_rtc_oscin"}, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, @@ -199,7 +201,8 @@ static struct clk_regmap axg_aoclk_saradc_mux = { .hw.init = &(struct clk_init_data){ .name = "axg_ao_saradc_mux", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "xtal", "axg_ao_clk81" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal", + "axg_ao_clk81" }, .num_parents = 2, }, }; @@ -285,6 +288,12 @@ static const struct clk_hw_onecell_data axg_aoclk_onecell_data = { .num = NR_CLKS, }; +static const struct meson_aoclk_input axg_aoclk_inputs[] = { + { .name = "xtal", .required = true }, + { .name = "mpeg-clk", .required = true }, + { .name = "ext-32k-0", .required = false }, +}; + static const struct meson_aoclk_data axg_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(axg_aoclk_reset), @@ -292,6 +301,9 @@ static const struct meson_aoclk_data axg_aoclkc_data = { .num_clks = ARRAY_SIZE(axg_aoclk_regmap), .clks = axg_aoclk_regmap, .hw_data = &axg_aoclk_onecell_data, + .inputs = axg_aoclk_inputs, + .num_inputs = ARRAY_SIZE(axg_aoclk_inputs), + .input_prefix = IN_PREFIX, }; static const struct of_device_id axg_aoclkc_match_table[] = { diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 5fa57b623b8f..510b6a7d2f18 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -9,6 +9,8 @@ #include "meson-aoclk.h" #include "gxbb-aoclk.h" +#define IN_PREFIX "ao-in-" + /* AO Configuration Clock registers offsets */ #define AO_RTI_PWR_CNTL_REG1 0x0c #define AO_RTI_PWR_CNTL_REG0 0x10 @@ -27,7 +29,7 @@ static struct clk_regmap _name##_ao = { \ .hw.init = &(struct clk_init_data) { \ .name = #_name "_ao", \ .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ "clk81" }, \ + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ .num_parents = 1, \ .flags = CLK_IGNORE_UNUSED, \ }, \ @@ -48,7 +50,7 @@ static struct clk_regmap ao_cts_oscin = { .hw.init = &(struct clk_init_data){ .name = "ao_cts_oscin", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "xtal" }, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, .num_parents = 1, }, }; @@ -155,9 +157,9 @@ static struct clk_regmap ao_cts_rtc_oscin = { .hw.init = &(struct clk_init_data){ .name = "ao_cts_rtc_oscin", .ops = &clk_regmap_mux_ops, - .parent_names = (const char *[]){ "ext_32k_0", - "ext_32k_1", - "ext_32k_2", + .parent_names = (const char *[]){ IN_PREFIX "ext-32k-0", + IN_PREFIX "ext-32k-1", + IN_PREFIX "ext-32k-2", "ao_32k" }, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, @@ -174,7 +176,7 @@ static struct clk_regmap ao_clk81 = { .hw.init = &(struct clk_init_data){ .name = "ao_clk81", .ops = &clk_regmap_mux_ro_ops, - .parent_names = (const char *[]){ "clk81", + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", "ao_cts_rtc_oscin" }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT, @@ -257,6 +259,14 @@ static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = { .num = NR_CLKS, }; +static const struct meson_aoclk_input gxbb_aoclk_inputs[] = { + { .name = "xtal", .required = true, }, + { .name = "mpeg-clk", .required = true, }, + {. name = "ext-32k-0", .required = false, }, + {. name = "ext-32k-1", .required = false, }, + {. name = "ext-32k-2", .required = false, }, +}; + static const struct meson_aoclk_data gxbb_aoclkc_data = { .reset_reg = AO_RTI_GEN_CNTL_REG0, .num_reset = ARRAY_SIZE(gxbb_aoclk_reset), @@ -264,6 +274,9 @@ static const struct meson_aoclk_data gxbb_aoclkc_data = { .num_clks = ARRAY_SIZE(gxbb_aoclk), .clks = gxbb_aoclk, .hw_data = &gxbb_aoclk_onecell_data, + .inputs = gxbb_aoclk_inputs, + .num_inputs = ARRAY_SIZE(gxbb_aoclk_inputs), + .input_prefix = IN_PREFIX, }; static const struct of_device_id gxbb_aoclkc_match_table[] = { diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index 258c8d259ea1..7b9d194ccc3b 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -14,7 +14,7 @@ #include #include #include -#include "clk-regmap.h" +#include #include "meson-aoclk.h" static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev, @@ -31,6 +31,37 @@ static const struct reset_control_ops meson_aoclk_reset_ops = { .reset = meson_aoclk_do_reset, }; +static int meson_aoclkc_register_inputs(struct device *dev, + struct meson_aoclk_data *data) +{ + struct clk_hw *hw; + char *str; + int i; + + for (i = 0; i < data->num_inputs; i++) { + const struct meson_aoclk_input *in = &data->inputs[i]; + + str = kasprintf(GFP_KERNEL, "%s%s", data->input_prefix, + in->name); + if (!str) + return -ENOMEM; + + hw = meson_clk_hw_register_input(dev, in->name, str, 0); + kfree(str); + + if (IS_ERR(hw)) { + if (!in->required && PTR_ERR(hw) == -ENOENT) + continue; + else if (PTR_ERR(hw) != -EPROBE_DEFER) + dev_err(dev, "failed to register input %s\n", + in->name); + return PTR_ERR(hw); + } + } + + return 0; +} + int meson_aoclkc_probe(struct platform_device *pdev) { struct meson_aoclk_reset_controller *rstc; @@ -53,6 +84,10 @@ int meson_aoclkc_probe(struct platform_device *pdev) return PTR_ERR(regmap); } + ret = meson_aoclkc_register_inputs(dev, data); + if (ret) + return ret; + /* Reset Controller */ rstc->data = data; rstc->regmap = regmap; diff --git a/drivers/clk/meson/meson-aoclk.h b/drivers/clk/meson/meson-aoclk.h index ab2819e88922..0758b35d4427 100644 --- a/drivers/clk/meson/meson-aoclk.h +++ b/drivers/clk/meson/meson-aoclk.h @@ -13,14 +13,22 @@ #include #include -#include "clk-regmap.h" +#include "clkc.h" + +struct meson_aoclk_input { + const char *name; + bool required; +}; struct meson_aoclk_data { const unsigned int reset_reg; const int num_reset; const unsigned int *reset; - int num_clks; + const int num_clks; struct clk_regmap **clks; + const int num_inputs; + const struct meson_aoclk_input *inputs; + const char *input_prefix; const struct clk_hw_onecell_data *hw_data; }; -- cgit v1.2.3 From 2a6efbc6da5d248c4fbe7fdb7de7f3eff1de95a4 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Wed, 16 Jan 2019 19:45:45 +0000 Subject: clk: renesas: r8a774c0: Add missing CANFD clock This patch adds the missing CANFD clock to the r8a774c0 specific clock driver. Signed-off-by: Fabrizio Castro Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a774c0-cpg-mssr.c | 4 ++++ include/dt-bindings/clock/r8a774c0-cpg-mssr.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c index 10b96895d452..28bcc8105d57 100644 --- a/drivers/clk/renesas/r8a774c0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774c0-cpg-mssr.c @@ -33,6 +33,7 @@ enum clk_ids { CLK_PLL1, CLK_PLL3, CLK_PLL0D4, + CLK_PLL0D6, CLK_PLL0D8, CLK_PLL0D20, CLK_PLL0D24, @@ -61,6 +62,7 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = { DEF_FIXED(".pll0", CLK_PLL0, CLK_MAIN, 1, 100), DEF_FIXED(".pll0d4", CLK_PLL0D4, CLK_PLL0, 4, 1), + DEF_FIXED(".pll0d6", CLK_PLL0D6, CLK_PLL0, 6, 1), DEF_FIXED(".pll0d8", CLK_PLL0D8, CLK_PLL0, 8, 1), DEF_FIXED(".pll0d20", CLK_PLL0D20, CLK_PLL0, 20, 1), DEF_FIXED(".pll0d24", CLK_PLL0D24, CLK_PLL0, 24, 1), @@ -112,6 +114,7 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = { DEF_GEN3_PE("s3d2c", R8A774C0_CLK_S3D2C, CLK_S3, 2, CLK_PE, 2), DEF_GEN3_PE("s3d4c", R8A774C0_CLK_S3D4C, CLK_S3, 4, CLK_PE, 4), + DEF_DIV6P1("canfd", R8A774C0_CLK_CANFD, CLK_PLL0D6, 0x244), DEF_DIV6P1("csi0", R8A774C0_CLK_CSI0, CLK_PLL1D2, 0x00c), DEF_DIV6P1("mso", R8A774C0_CLK_MSO, CLK_PLL1D2, 0x014), @@ -187,6 +190,7 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = { DEF_MOD("gpio2", 910, R8A774C0_CLK_S3D4), DEF_MOD("gpio1", 911, R8A774C0_CLK_S3D4), DEF_MOD("gpio0", 912, R8A774C0_CLK_S3D4), + DEF_MOD("can-fd", 914, R8A774C0_CLK_S3D2), DEF_MOD("can-if1", 915, R8A774C0_CLK_S3D4), DEF_MOD("can-if0", 916, R8A774C0_CLK_S3D4), DEF_MOD("i2c6", 918, R8A774C0_CLK_S3D2), diff --git a/include/dt-bindings/clock/r8a774c0-cpg-mssr.h b/include/dt-bindings/clock/r8a774c0-cpg-mssr.h index 8fe51b6aca28..8ad9cd6be8e9 100644 --- a/include/dt-bindings/clock/r8a774c0-cpg-mssr.h +++ b/include/dt-bindings/clock/r8a774c0-cpg-mssr.h @@ -56,5 +56,6 @@ #define R8A774C0_CLK_CSI0 45 #define R8A774C0_CLK_CP 46 #define R8A774C0_CLK_CPEX 47 +#define R8A774C0_CLK_CANFD 48 #endif /* __DT_BINDINGS_CLOCK_R8A774C0_CPG_MSSR_H__ */ -- cgit v1.2.3 From 9d034e151b407cbd2c66bc4c48b423f814533374 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Thu, 17 Jan 2019 14:54:14 +0000 Subject: clk: renesas: r8a774a1: Add missing CANFD clock This patch adds the missing CANFD clock to the r8a774a1 specific clock driver. Signed-off-by: Fabrizio Castro Reviewed-by: Chris Paterson Reviewed-by: Simon Horman Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a774a1-cpg-mssr.c | 2 ++ include/dt-bindings/clock/r8a774a1-cpg-mssr.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c index 10e852518870..e10374119a91 100644 --- a/drivers/clk/renesas/r8a774a1-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c @@ -102,6 +102,7 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = { DEF_FIXED("cp", R8A774A1_CLK_CP, CLK_EXTAL, 2, 1), DEF_FIXED("cpex", R8A774A1_CLK_CPEX, CLK_EXTAL, 2, 1), + DEF_DIV6P1("canfd", R8A774A1_CLK_CANFD, CLK_PLL1_DIV4, 0x244), DEF_DIV6P1("csi0", R8A774A1_CLK_CSI0, CLK_PLL1_DIV4, 0x00c), DEF_DIV6P1("mso", R8A774A1_CLK_MSO, CLK_PLL1_DIV4, 0x014), DEF_DIV6P1("hdmi", R8A774A1_CLK_HDMI, CLK_PLL1_DIV4, 0x250), @@ -191,6 +192,7 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = { DEF_MOD("gpio2", 910, R8A774A1_CLK_S3D4), DEF_MOD("gpio1", 911, R8A774A1_CLK_S3D4), DEF_MOD("gpio0", 912, R8A774A1_CLK_S3D4), + DEF_MOD("can-fd", 914, R8A774A1_CLK_S3D2), DEF_MOD("can-if1", 915, R8A774A1_CLK_S3D4), DEF_MOD("can-if0", 916, R8A774A1_CLK_S3D4), DEF_MOD("i2c6", 918, R8A774A1_CLK_S0D6), diff --git a/include/dt-bindings/clock/r8a774a1-cpg-mssr.h b/include/dt-bindings/clock/r8a774a1-cpg-mssr.h index 9bc5d45ff4b5..e355363f40c2 100644 --- a/include/dt-bindings/clock/r8a774a1-cpg-mssr.h +++ b/include/dt-bindings/clock/r8a774a1-cpg-mssr.h @@ -54,5 +54,6 @@ #define R8A774A1_CLK_CPEX 43 #define R8A774A1_CLK_R 44 #define R8A774A1_CLK_OSC 45 +#define R8A774A1_CLK_CANFD 46 #endif /* __DT_BINDINGS_CLOCK_R8A774A1_CPG_MSSR_H__ */ -- cgit v1.2.3 From d9286d9743b6e8cfbf1a13f8db84e9c65c0b09c7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Jan 2019 14:07:39 +0100 Subject: clk: renesas: r8a774c0: Correct parent clock of DU According to the RZ/G Series, 2nd Generation Hardware Manual Rev 0.61, the parent clock of the DU module clocks on RZ/G2E is S1D1. Fixes: 906e0a4a6d1ef2d3 ("clk: renesas: cpg-mssr: Add r8a774c0 support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Chris Paterson Reviewed-by: Simon Horman --- drivers/clk/renesas/r8a774c0-cpg-mssr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c index 28bcc8105d57..4f3111b3113e 100644 --- a/drivers/clk/renesas/r8a774c0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774c0-cpg-mssr.c @@ -175,8 +175,8 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = { DEF_MOD("ehci0", 703, R8A774C0_CLK_S3D4), DEF_MOD("hsusb", 704, R8A774C0_CLK_S3D4), DEF_MOD("csi40", 716, R8A774C0_CLK_CSI0), - DEF_MOD("du1", 723, R8A774C0_CLK_S2D1), - DEF_MOD("du0", 724, R8A774C0_CLK_S2D1), + DEF_MOD("du1", 723, R8A774C0_CLK_S1D1), + DEF_MOD("du0", 724, R8A774C0_CLK_S1D1), DEF_MOD("lvds", 727, R8A774C0_CLK_S2D1), DEF_MOD("vin5", 806, R8A774C0_CLK_S1D2), -- cgit v1.2.3 From a30a67be7b6e1117e0c0f5bcf84328ccdb8d6205 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 4 Dec 2018 11:14:02 -0800 Subject: clk: socfpga: Don't have get_parent for single parent ops This driver creates a gate clk with the possibility to have multiple parents. That can cause problems if the common clk framework tries to call the get_parent() op and gets back a number that's larger than the number of parents the clk says it supports in clk_init_data::num_parents. Let's duplicate the clk_ops structure each time this function is called and drop the get/set parent ops when there is only one parent. This allows the framework to consider a number larger than clk_init_data::num_parents as an error condition of the get_parent() clk op, clearing the way for proper code. Cc: Jerome Brunet Cc: Masahiro Yamada Cc: Dinh Nguyen Tested-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-gate.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c index aa7a6e6a15b6..73e03328d5c5 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -176,8 +176,7 @@ static struct clk_ops gateclk_ops = { .set_parent = socfpga_clk_set_parent, }; -static void __init __socfpga_gate_init(struct device_node *node, - const struct clk_ops *ops) +void __init socfpga_gate_init(struct device_node *node) { u32 clk_gate[2]; u32 div_reg[3]; @@ -188,12 +187,17 @@ static void __init __socfpga_gate_init(struct device_node *node, const char *clk_name = node->name; const char *parent_name[SOCFPGA_MAX_PARENTS]; struct clk_init_data init; + struct clk_ops *ops; int rc; socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL); if (WARN_ON(!socfpga_clk)) return; + ops = kmemdup(&gateclk_ops, sizeof(gateclk_ops), GFP_KERNEL); + if (WARN_ON(!ops)) + return; + rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2); if (rc) clk_gate[0] = 0; @@ -202,8 +206,8 @@ static void __init __socfpga_gate_init(struct device_node *node, socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0]; socfpga_clk->hw.bit_idx = clk_gate[1]; - gateclk_ops.enable = clk_gate_ops.enable; - gateclk_ops.disable = clk_gate_ops.disable; + ops->enable = clk_gate_ops.enable; + ops->disable = clk_gate_ops.disable; } rc = of_property_read_u32(node, "fixed-divider", &fixed_div); @@ -234,6 +238,11 @@ static void __init __socfpga_gate_init(struct device_node *node, init.flags = 0; init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS); + if (init.num_parents < 2) { + ops->get_parent = NULL; + ops->set_parent = NULL; + } + init.parent_names = parent_name; socfpga_clk->hw.hw.init = &init; @@ -246,8 +255,3 @@ static void __init __socfpga_gate_init(struct device_node *node, if (WARN_ON(rc)) return; } - -void __init socfpga_gate_init(struct device_node *node) -{ - __socfpga_gate_init(node, &gateclk_ops); -} -- cgit v1.2.3 From 921e88a4f9649cbd44b4995ebe9a52b384e2fef4 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 24 Dec 2018 00:40:25 -0600 Subject: clk: imx: imx7ulp: use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Reviewed-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx7ulp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c index 4e18f629f823..ce306631e844 100644 --- a/drivers/clk/imx/clk-imx7ulp.c +++ b/drivers/clk/imx/clk-imx7ulp.c @@ -48,8 +48,8 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np) struct clk_hw **clks; void __iomem *base; - clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * - IMX7ULP_CLK_SCG1_END, GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_SCG1_END), + GFP_KERNEL); if (!clk_data) return; @@ -136,8 +136,8 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np) struct clk_hw **clks; void __iomem *base; - clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * - IMX7ULP_CLK_PCC2_END, GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC2_END), + GFP_KERNEL); if (!clk_data) return; @@ -183,8 +183,8 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np) struct clk_hw **clks; void __iomem *base; - clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * - IMX7ULP_CLK_PCC3_END, GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC3_END), + GFP_KERNEL); if (!clk_data) return; @@ -228,8 +228,8 @@ static void __init imx7ulp_clk_smc1_init(struct device_node *np) struct clk_hw **clks; void __iomem *base; - clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) * - IMX7ULP_CLK_SMC1_END, GFP_KERNEL); + clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_SMC1_END), + GFP_KERNEL); if (!clk_data) return; -- cgit v1.2.3 From 463a554baa9feb31eb31281ff18f08d139f58acb Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Fri, 4 Jan 2019 22:48:26 +0100 Subject: clk: samsung: fix typo Fix spelling mistake: "lenght" -> "length" Signed-off-by: Matteo Croce Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index c3f309d7100d..9cfaca5fbcdb 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -26,7 +26,7 @@ struct samsung_clk_provider { void __iomem *reg_base; struct device *dev; spinlock_t lock; - /* clk_data must be the last entry due to variable lenght 'hws' array */ + /* clk_data must be the last entry due to variable length 'hws' array */ struct clk_hw_onecell_data clk_data; }; -- cgit v1.2.3 From 420601d25c0c8dd0749ccfb9bd59526c64b4cc35 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 10 Jan 2019 16:19:01 -0600 Subject: dt-bindings: clock: Convert fixed-clock binding to json-schema Convert the fixed-clock binding to DT schema format using json-schema. Cc: Michael Turquette Cc: Stephen Boyd Cc: linux-clk@vger.kernel.org Signed-off-by: Rob Herring [sboyd@kernel.org: Drop full stop on title] Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/fixed-clock.txt | 23 ----------- .../devicetree/bindings/clock/fixed-clock.yaml | 44 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/fixed-clock.txt create mode 100644 Documentation/devicetree/bindings/clock/fixed-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/fixed-clock.txt b/Documentation/devicetree/bindings/clock/fixed-clock.txt deleted file mode 100644 index 0641a663ad69..000000000000 --- a/Documentation/devicetree/bindings/clock/fixed-clock.txt +++ /dev/null @@ -1,23 +0,0 @@ -Binding for simple fixed-rate clock sources. - -This binding uses the common clock binding[1]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: -- compatible : shall be "fixed-clock". -- #clock-cells : from common clock binding; shall be set to 0. -- clock-frequency : frequency of clock in Hz. Should be a single cell. - -Optional properties: -- clock-accuracy : accuracy of clock in ppb (parts per billion). - Should be a single cell. -- clock-output-names : From common clock binding. - -Example: - clock { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <1000000000>; - clock-accuracy = <100>; - }; diff --git a/Documentation/devicetree/bindings/clock/fixed-clock.yaml b/Documentation/devicetree/bindings/clock/fixed-clock.yaml new file mode 100644 index 000000000000..b657ecd0ef1c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/fixed-clock.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/fixed-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Binding for simple fixed-rate clock sources + +maintainers: + - Michael Turquette + - Stephen Boyd + +properties: + compatible: + const: fixed-clock + + "#clock-cells": + const: 0 + + clock-frequency: true + + clock-accuracy: + description: accuracy of clock in ppb (parts per billion). + $ref: /schemas/types.yaml#/definitions/uint32 + + clock-output-names: + maxItems: 1 + +required: + - compatible + - "#clock-cells" + - clock-frequency + +additionalProperties: false + +examples: + - | + clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000000>; + clock-accuracy = <100>; + }; +... -- cgit v1.2.3 From f79bae1666f8af6ce0c2da0b2057675ba6185a25 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 10 Jan 2019 16:19:02 -0600 Subject: dt-bindings: clock: Convert fixed-factor-clock to json-schema Convert the fixed-factor-clock binding to DT schema format using json-schema. Cc: Michael Turquette Cc: Stephen Boyd Cc: linux-clk@vger.kernel.org Signed-off-by: Rob Herring [sboyd@kernel.org: Drop full stop on title] Signed-off-by: Stephen Boyd --- .../bindings/clock/fixed-factor-clock.txt | 28 ----------- .../bindings/clock/fixed-factor-clock.yaml | 56 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 28 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/fixed-factor-clock.txt create mode 100644 Documentation/devicetree/bindings/clock/fixed-factor-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt b/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt deleted file mode 100644 index 189467a7188a..000000000000 --- a/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt +++ /dev/null @@ -1,28 +0,0 @@ -Binding for simple fixed factor rate clock sources. - -This binding uses the common clock binding[1]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: -- compatible : shall be "fixed-factor-clock". -- #clock-cells : from common clock binding; shall be set to 0. -- clock-div: fixed divider. -- clock-mult: fixed multiplier. -- clocks: parent clock. - -Optional properties: -- clock-output-names : From common clock binding. - -Some clocks that require special treatments are also handled by that -driver, with the compatibles: - - allwinner,sun4i-a10-pll3-2x-clk - -Example: - clock { - compatible = "fixed-factor-clock"; - clocks = <&parentclk>; - #clock-cells = <0>; - clock-div = <2>; - clock-mult = <1>; - }; diff --git a/Documentation/devicetree/bindings/clock/fixed-factor-clock.yaml b/Documentation/devicetree/bindings/clock/fixed-factor-clock.yaml new file mode 100644 index 000000000000..b567f8092f8c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/fixed-factor-clock.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/fixed-factor-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Binding for simple fixed factor rate clock sources + +maintainers: + - Michael Turquette + - Stephen Boyd + +properties: + compatible: + enum: + - allwinner,sun4i-a10-pll3-2x-clk + - fixed-factor-clock + + "#clock-cells": + const: 0 + + clocks: + maxItems: 1 + + clock-div: + description: Fixed divider + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 1 + + clock-mult: + description: Fixed multiplier + $ref: /schemas/types.yaml#/definitions/uint32 + + clock-output-names: + maxItems: 1 + +required: + - compatible + - clocks + - "#clock-cells" + - clock-div + - clock-mult + +additionalProperties: false + +examples: + - | + clock { + compatible = "fixed-factor-clock"; + clocks = <&parentclk>; + #clock-cells = <0>; + clock-div = <2>; + clock-mult = <1>; + }; +... -- cgit v1.2.3 From 108a459ef4cd17a28711d81092044e597b5c7618 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 25 Jan 2019 11:23:04 +0800 Subject: clk: sunxi-ng: sun8i-a23: Enable PLL-MIPI LDOs when ungating it The PLL-MIPI clock is somewhat special as it has its own LDOs which need to be turned on for this PLL to actually work and output a clock signal. Add the 2 LDO enable bits to the gate bits. Fixes: 5690879d93e8 ("clk: sunxi-ng: Add A23 CCU") Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/clk/sunxi-ng/ccu-sun8i-a23.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index a4fa2945f230..4b5f8f4e4ab8 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -144,7 +144,7 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_mipi_clk, "pll-mipi", 8, 4, /* N */ 4, 2, /* K */ 0, 4, /* M */ - BIT(31), /* gate */ + BIT(31) | BIT(23) | BIT(22), /* gate */ BIT(28), /* lock */ CLK_SET_RATE_UNGATE); -- cgit v1.2.3 From 8cb8f16c62e5ea9c77ca7d25af761f4eaea670ba Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 22 Jan 2019 22:57:38 +0300 Subject: clk: renesas: rcar-gen3: Factor out cpg_reg_modify() There's quite often repeated sequence of a CPG register read-modify-write, so it seems worth factoring it out into a function -- this saves 68 bytes of the object code (AArch64 gcc 4.8.5) and simplifies protecting all such sequences with a spinlock in the next patch... Signed-off-by: Sergei Shtylyov Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-gen3-cpg.c | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index be2ccbd6d623..80d0808a7fe8 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -30,6 +30,16 @@ #define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */ +static void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set) +{ + u32 val; + + val = readl(reg); + val &= ~clear; + val |= set; + writel(val, reg); +}; + struct cpg_simple_notifier { struct notifier_block nb; void __iomem *reg; @@ -118,7 +128,6 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, struct cpg_z_clk *zclk = to_z_clk(hw); unsigned int mult; unsigned int i; - u32 val, kick; /* Factor of 2 is for fixed divider */ mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL * 2, parent_rate); @@ -127,17 +136,14 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) return -EBUSY; - val = readl(zclk->reg) & ~zclk->mask; - val |= ((32 - mult) << __ffs(zclk->mask)) & zclk->mask; - writel(val, zclk->reg); + cpg_reg_modify(zclk->reg, zclk->mask, + ((32 - mult) << __ffs(zclk->mask)) & zclk->mask); /* * Set KICK bit in FRQCRB to update hardware setting and wait for * clock change completion. */ - kick = readl(zclk->kick_reg); - kick |= CPG_FRQCRB_KICK; - writel(kick, zclk->kick_reg); + cpg_reg_modify(zclk->kick_reg, 0, CPG_FRQCRB_KICK); /* * Note: There is no HW information about the worst case latency. @@ -266,12 +272,10 @@ static const struct sd_div_table cpg_sd_div_table[] = { static int cpg_sd_clock_enable(struct clk_hw *hw) { struct sd_clock *clock = to_sd_clock(hw); - u32 val = readl(clock->csn.reg); - val &= ~(CPG_SD_STP_MASK); - val |= clock->div_table[clock->cur_div_idx].val & CPG_SD_STP_MASK; - - writel(val, clock->csn.reg); + cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK, + clock->div_table[clock->cur_div_idx].val & + CPG_SD_STP_MASK); return 0; } @@ -280,7 +284,7 @@ static void cpg_sd_clock_disable(struct clk_hw *hw) { struct sd_clock *clock = to_sd_clock(hw); - writel(readl(clock->csn.reg) | CPG_SD_STP_MASK, clock->csn.reg); + cpg_reg_modify(clock->csn.reg, 0, CPG_SD_STP_MASK); } static int cpg_sd_clock_is_enabled(struct clk_hw *hw) @@ -327,7 +331,6 @@ static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, { struct sd_clock *clock = to_sd_clock(hw); unsigned int div = cpg_sd_clock_calc_div(clock, rate, parent_rate); - u32 val; unsigned int i; for (i = 0; i < clock->div_num; i++) @@ -339,10 +342,9 @@ static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, clock->cur_div_idx = i; - val = readl(clock->csn.reg); - val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK); - val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK); - writel(val, clock->csn.reg); + cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK | CPG_SD_FC_MASK, + clock->div_table[i].val & + (CPG_SD_STP_MASK | CPG_SD_FC_MASK)); return 0; } -- cgit v1.2.3 From 875e8f6b0156c0ad56fd0c29c78e3f2f67ec0b16 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 22 Jan 2019 22:58:38 +0300 Subject: clk: renesas: rcar-gen3: Add spinlock Protect the CPG register read-modify-write sequence with a spinlock. Signed-off-by: Sergei Shtylyov Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-gen3-cpg.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 80d0808a7fe8..0818691253af 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -30,14 +30,19 @@ #define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */ +static spinlock_t cpg_lock; + static void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set) { + unsigned long flags; u32 val; + spin_lock_irqsave(&cpg_lock, flags); val = readl(reg); val &= ~clear; val |= set; writel(val, reg); + spin_unlock_irqrestore(&cpg_lock, flags); }; struct cpg_simple_notifier { @@ -615,5 +620,8 @@ int __init rcar_gen3_cpg_init(const struct rcar_gen3_cpg_pll_config *config, if (attr) cpg_quirks = (uintptr_t)attr->data; pr_debug("%s: mode = 0x%x quirks = 0x%x\n", __func__, mode, cpg_quirks); + + spin_lock_init(&cpg_lock); + return 0; } -- cgit v1.2.3 From 7403e48d7abd9a0114e9056e7615cfbbb5123b15 Mon Sep 17 00:00:00 2001 From: Kamil Konieczny Date: Tue, 22 Jan 2019 10:02:31 +0100 Subject: clk: samsung: dt-bindings: Add Exynos5433 IMEM CMU clock IDs Add DT bindings to describe the IMEM CMU clocks for the SlimSSS (Slim Security SubSystem). Signed-off-by: Kamil Konieczny Reviewed-by: Rob Herring Acked-by: Chanwoo Choi [s.nawrocki@samsung.com: edited commit description] Signed-off-by: Sylwester Nawrocki --- include/dt-bindings/clock/exynos5433.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 98bd85ce1e45..7cfce3a62050 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -1406,4 +1406,10 @@ #define CAM1_NR_CLK 113 +/* CMU_IMEM */ +#define CLK_ACLK_SLIMSSS 2 +#define CLK_PCLK_SLIMSSS 35 + +#define IMEM_NR_CLK 36 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS5433_H */ -- cgit v1.2.3 From 4e16c9ef2a0be931ed63448187d9f5ab0e872f3c Mon Sep 17 00:00:00 2001 From: Kamil Konieczny Date: Tue, 22 Jan 2019 10:02:28 +0100 Subject: clk: samsung: exynos5433: Fix definition of CLK_ACLK_IMEM_{200, 266} clocks This fixes typos in CLK_ACLK_IMEM_200 and CLK_ACLK_IMEM_266 clock definition, leading to incorrect parent clock assignment. Reviewed-by: Chanwoo Choi Signed-off-by: Kamil Konieczny [s.nawrocki@samsung.com: edited commit description] Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 751e2c4fb65b..ea47f49abc7f 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -568,10 +568,10 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = { GATE(CLK_ACLK_BUS1_400, "aclk_bus1_400", "div_aclk_bus1_400", ENABLE_ACLK_TOP, 25, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0), - GATE(CLK_ACLK_IMEM_200, "aclk_imem_200", "div_aclk_imem_266", + GATE(CLK_ACLK_IMEM_200, "aclk_imem_200", "div_aclk_imem_200", ENABLE_ACLK_TOP, 24, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0), - GATE(CLK_ACLK_IMEM_266, "aclk_imem_266", "div_aclk_imem_200", + GATE(CLK_ACLK_IMEM_266, "aclk_imem_266", "div_aclk_imem_266", ENABLE_ACLK_TOP, 23, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0), GATE(CLK_ACLK_PERIC_66, "aclk_peric_66", "div_aclk_peric_66_b", -- cgit v1.2.3 From b80a40c659ba38e1295ab7e55b2c781abee64739 Mon Sep 17 00:00:00 2001 From: Kamil Konieczny Date: Tue, 22 Jan 2019 10:02:29 +0100 Subject: clk: samsung: exynos5433: Fix name typo in sssx Fix typo in sssx name, there should be three letters 's'. Acked-by: Rob Herring Reviewed-by: Chanwoo Choi Signed-off-by: Kamil Konieczny Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 2 +- include/dt-bindings/clock/exynos5433.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index ea47f49abc7f..24c3360db65b 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -559,7 +559,7 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = { /* ENABLE_ACLK_TOP */ GATE(CLK_ACLK_G3D_400, "aclk_g3d_400", "div_aclk_g3d_400", ENABLE_ACLK_TOP, 30, CLK_IS_CRITICAL, 0), - GATE(CLK_ACLK_IMEM_SSX_266, "aclk_imem_ssx_266", + GATE(CLK_ACLK_IMEM_SSSX_266, "aclk_imem_sssx_266", "div_aclk_imem_sssx_266", ENABLE_ACLK_TOP, 29, CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK_BUS0_400, "aclk_bus0_400", "div_aclk_bus0_400", diff --git a/include/dt-bindings/clock/exynos5433.h b/include/dt-bindings/clock/exynos5433.h index 7cfce3a62050..25ffa53573a5 100644 --- a/include/dt-bindings/clock/exynos5433.h +++ b/include/dt-bindings/clock/exynos5433.h @@ -156,7 +156,7 @@ #define CLK_ACLK_G2D_266 220 #define CLK_ACLK_G2D_400 221 #define CLK_ACLK_G3D_400 222 -#define CLK_ACLK_IMEM_SSX_266 223 +#define CLK_ACLK_IMEM_SSSX_266 223 #define CLK_ACLK_BUS0_400 224 #define CLK_ACLK_BUS1_400 225 #define CLK_ACLK_IMEM_200 226 -- cgit v1.2.3 From 5af01ab3b6d7e0279bb6b90b54ecd921afc83bb2 Mon Sep 17 00:00:00 2001 From: Kamil Konieczny Date: Tue, 22 Jan 2019 10:02:30 +0100 Subject: clk: samsung: dt-bindings: Document Exynos5433 IMEM CMU Document DT bindings of the IMEM CMU providing clocks for the Exynos5433 Security SubSystem (SSS) and SlimSSS IPs. Acked-by: Chanwoo Choi Reviewed-by: Rob Herring Acked-by: Stephen Boyd Signed-off-by: Kamil Konieczny [s.nawrocki@samsung.com: edited commit description] Signed-off-by: Sylwester Nawrocki --- .../devicetree/bindings/clock/exynos5433-clock.txt | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt index 50d5897c9849..183c327a7d6b 100644 --- a/Documentation/devicetree/bindings/clock/exynos5433-clock.txt +++ b/Documentation/devicetree/bindings/clock/exynos5433-clock.txt @@ -50,6 +50,8 @@ Required Properties: IPs. - "samsung,exynos5433-cmu-cam1" - clock controller compatible for CMU_CAM1 which generates clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs. + - "samsung,exynos5433-cmu-imem" - clock controller compatible for CMU_IMEM + which generates clocks for SSS (Security SubSystem) and SlimSSS IPs. - reg: physical base address of the controller and length of memory mapped region. @@ -168,6 +170,12 @@ Required Properties: - aclk_cam1_400 - aclk_cam1_552 + Input clocks for imem clock controller: + - oscclk + - aclk_imem_sssx_266 + - aclk_imem_266 + - aclk_imem_200 + Optional properties: - power-domains: a phandle to respective power domain node as described by generic PM domain bindings (see power/power_domain.txt for more @@ -469,6 +477,21 @@ Example 2: Examples of clock controller nodes are listed below. power-domains = <&pd_cam1>; }; + cmu_imem: clock-controller@11060000 { + compatible = "samsung,exynos5433-cmu-imem"; + reg = <0x11060000 0x1000>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_imem_sssx_266", + "aclk_imem_266", + "aclk_imem_200"; + clocks = <&xxti>, + <&cmu_top CLK_DIV_ACLK_IMEM_SSSX_266>, + <&cmu_top CLK_DIV_ACLK_IMEM_266>, + <&cmu_top CLK_DIV_ACLK_IMEM_200>; + }; + Example 3: UART controller node that consumes the clock generated by the clock controller. -- cgit v1.2.3 From 81faa30df9b6e9088ea5ca488860616192e7b763 Mon Sep 17 00:00:00 2001 From: Kamil Konieczny Date: Tue, 22 Jan 2019 10:02:32 +0100 Subject: clk: samsung: exynos5433: Add selected IMEM clocks This patch adds clocks required for the Exynos5433 SoC Slim Security SubSystem (SlimSSS) IP block. Acked-by: Chanwoo Choi Signed-off-by: Kamil Konieczny [s.nawrocki@samsung.com: edited commit description] Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 24c3360db65b..dae1c96de933 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -5467,6 +5467,35 @@ static const struct samsung_cmu_info cam1_cmu_info __initconst = { .clk_name = "aclk_cam1_400", }; +/* + * Register offset definitions for CMU_IMEM + */ +#define ENABLE_ACLK_IMEM_SLIMSSS 0x080c +#define ENABLE_PCLK_IMEM_SLIMSSS 0x0908 + +static const unsigned long imem_clk_regs[] __initconst = { + ENABLE_ACLK_IMEM_SLIMSSS, + ENABLE_PCLK_IMEM_SLIMSSS, +}; + +static const struct samsung_gate_clock imem_gate_clks[] __initconst = { + /* ENABLE_ACLK_IMEM_SLIMSSS */ + GATE(CLK_ACLK_SLIMSSS, "aclk_slimsss", "aclk_imem_sssx_266", + ENABLE_ACLK_IMEM_SLIMSSS, 0, CLK_IGNORE_UNUSED, 0), + + /* ENABLE_PCLK_IMEM_SLIMSSS */ + GATE(CLK_PCLK_SLIMSSS, "pclk_slimsss", "aclk_imem_200", + ENABLE_PCLK_IMEM_SLIMSSS, 0, CLK_IGNORE_UNUSED, 0), +}; + +static const struct samsung_cmu_info imem_cmu_info __initconst = { + .gate_clks = imem_gate_clks, + .nr_gate_clks = ARRAY_SIZE(imem_gate_clks), + .nr_clk_ids = IMEM_NR_CLK, + .clk_regs = imem_clk_regs, + .nr_clk_regs = ARRAY_SIZE(imem_clk_regs), + .clk_name = "aclk_imem_200", +}; struct exynos5433_cmu_data { struct samsung_clk_reg_dump *clk_save; @@ -5654,6 +5683,9 @@ static const struct of_device_id exynos5433_cmu_of_match[] = { }, { .compatible = "samsung,exynos5433-cmu-mscl", .data = &mscl_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-imem", + .data = &imem_cmu_info, }, { }, }; -- cgit v1.2.3 From 12aa377bf80cb3a38053dba70eaa7e39975849b2 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 1 Feb 2019 13:58:38 +0100 Subject: clk: export some clk_hw function symbols for module drivers clk-provider.h provides clk_hw_is_prepared(), clk_hw_is_enabled() and clk_hw_is_prepared() but these symbols are not exported for the modules which prevents a clock driver using them to be compiled as a module. Export them to fix the problem. Acked-by: Stephen Boyd Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190201125841.26785-2-jbrunet@baylibre.com --- drivers/clk/clk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 75d13c0eff12..5558af12f9db 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -394,16 +394,19 @@ bool clk_hw_is_prepared(const struct clk_hw *hw) { return clk_core_is_prepared(hw->core); } +EXPORT_SYMBOL_GPL(clk_hw_is_prepared); bool clk_hw_rate_is_protected(const struct clk_hw *hw) { return clk_core_rate_is_protected(hw->core); } +EXPORT_SYMBOL_GPL(clk_hw_rate_is_protected); bool clk_hw_is_enabled(const struct clk_hw *hw) { return clk_core_is_enabled(hw->core); } +EXPORT_SYMBOL_GPL(clk_hw_is_enabled); bool __clk_is_enabled(struct clk *clk) { -- cgit v1.2.3 From 6e47b5307308d9d48d4990406e8322332634591c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 1 Feb 2019 13:58:39 +0100 Subject: clk: meson: use CONFIG_ARCH_MESON to enter meson clk directory Use CONFIG_ARCH_MESON to let make enter the meson clock directory. As part of a rework, CONFIG_COMMON_CLK_AMLOGIC is about to be removed. Acked-by: Stephen Boyd Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190201125841.26785-3-jbrunet@baylibre.com --- drivers/clk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 8a9440a97500..8d780c4390f1 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_ARCH_K3) += keystone/ obj-$(CONFIG_ARCH_KEYSTONE) += keystone/ obj-$(CONFIG_MACH_LOONGSON32) += loongson1/ obj-y += mediatek/ -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/ +obj-$(CONFIG_ARCH_MESON) += meson/ obj-$(CONFIG_MACH_PIC32) += microchip/ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_ARCH_MMP) += mmp/ -- cgit v1.2.3 From cb78ba76296efd145c50d943017d76a36544bb76 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 1 Feb 2019 13:58:40 +0100 Subject: clk: meson: axg-audio does not require syscon The axg audio clock controller uses regmap mmio, not syscon. Fixes: 1cd50181750f ("clk: meson: axg: add the audio clock controller driver") Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190201125841.26785-4-jbrunet@baylibre.com --- drivers/clk/meson/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index efaa70f682b4..2479dab09d70 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -50,7 +50,7 @@ config COMMON_CLK_AXG_AUDIO tristate "Meson AXG Audio Clock Controller Driver" depends on COMMON_CLK_AXG select COMMON_CLK_AMLOGIC_AUDIO - select MFD_SYSCON + select REGMAP_MMIO help Support for the audio clock controller on AmLogic A113D devices, aka axg, Say Y if you want audio subsystem to work. -- cgit v1.2.3 From 889c2b7ec42b8d14d421541f0a3ae1238e34891e Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 1 Feb 2019 13:58:41 +0100 Subject: clk: meson: rework and clean drivers dependencies Initially, the meson clock directory only hosted 2 controllers drivers, for meson8 and gxbb. At the time, both used the same set of clock drivers so managing the dependencies was not a big concern. Since this ancient time, entropy did its job, controllers with different requirement and specific clock drivers have been added. Unfortunately, we did not do a great job at managing the dependencies between the controllers and the different clock drivers. Some drivers, such as clk-phase or vid-pll-div, are compiled even if they are useless on the target (meson8). As we are adding new controllers, we need to be able to pick a driver w/o pulling the whole thing. The patch aims to clean things up by: * providing a dedicated CONFIG_ for each clock drivers * allowing clock drivers to be compiled as a modules, if possible * stating explicitly which drivers are required by each controller. Signed-off-by: Jerome Brunet Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190201125841.26785-5-jbrunet@baylibre.com --- drivers/clk/meson/Kconfig | 82 +++++++++++++++------- drivers/clk/meson/Makefile | 27 +++++--- drivers/clk/meson/axg-aoclk.c | 4 +- drivers/clk/meson/axg-audio.c | 5 +- drivers/clk/meson/axg.c | 5 +- drivers/clk/meson/clk-dualdiv.c | 10 ++- drivers/clk/meson/clk-dualdiv.h | 33 +++++++++ drivers/clk/meson/clk-input.c | 7 +- drivers/clk/meson/clk-input.h | 19 +++++ drivers/clk/meson/clk-mpll.c | 12 +++- drivers/clk/meson/clk-mpll.h | 30 ++++++++ drivers/clk/meson/clk-phase.c | 75 ++++++++++++++++++-- drivers/clk/meson/clk-phase.h | 26 +++++++ drivers/clk/meson/clk-pll.c | 13 ++-- drivers/clk/meson/clk-pll.h | 43 ++++++++++++ drivers/clk/meson/clk-regmap.c | 5 ++ drivers/clk/meson/clk-regmap.h | 15 ++++ drivers/clk/meson/clk-triphase.c | 68 ------------------ drivers/clk/meson/clkc-audio.h | 28 -------- drivers/clk/meson/clkc.h | 146 --------------------------------------- drivers/clk/meson/gxbb-aoclk.c | 4 +- drivers/clk/meson/gxbb.c | 5 +- drivers/clk/meson/meson-aoclk.c | 2 + drivers/clk/meson/meson-aoclk.h | 5 +- drivers/clk/meson/meson8b.c | 3 +- drivers/clk/meson/parm.h | 46 ++++++++++++ drivers/clk/meson/sclk-div.c | 10 ++- drivers/clk/meson/sclk-div.h | 22 ++++++ drivers/clk/meson/vid-pll-div.c | 10 ++- drivers/clk/meson/vid-pll-div.h | 20 ++++++ 30 files changed, 482 insertions(+), 298 deletions(-) create mode 100644 drivers/clk/meson/clk-dualdiv.h create mode 100644 drivers/clk/meson/clk-input.h create mode 100644 drivers/clk/meson/clk-mpll.h create mode 100644 drivers/clk/meson/clk-phase.h create mode 100644 drivers/clk/meson/clk-pll.h delete mode 100644 drivers/clk/meson/clk-triphase.c delete mode 100644 drivers/clk/meson/clkc-audio.h delete mode 100644 drivers/clk/meson/clkc.h create mode 100644 drivers/clk/meson/parm.h create mode 100644 drivers/clk/meson/sclk-div.h create mode 100644 drivers/clk/meson/vid-pll-div.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 2479dab09d70..f2e757aea4f1 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -1,27 +1,47 @@ -config COMMON_CLK_AMLOGIC - bool - depends on ARCH_MESON || COMPILE_TEST - select COMMON_CLK_REGMAP_MESON +config COMMON_CLK_MESON_INPUT + tristate -config COMMON_CLK_AMLOGIC_AUDIO - bool - depends on ARCH_MESON || COMPILE_TEST - select COMMON_CLK_AMLOGIC +config COMMON_CLK_MESON_REGMAP + tristate + select REGMAP -config COMMON_CLK_MESON_AO - bool - depends on OF - depends on ARCH_MESON || COMPILE_TEST - select COMMON_CLK_REGMAP_MESON - select RESET_CONTROLLER +config COMMON_CLK_MESON_DUALDIV + tristate + select COMMON_CLK_MESON_REGMAP -config COMMON_CLK_REGMAP_MESON - bool - select REGMAP +config COMMON_CLK_MESON_MPLL + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_PHASE + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_PLL + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_SCLK_DIV + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_VID_PLL_DIV + tristate + select COMMON_CLK_MESON_REGMAP + +config COMMON_CLK_MESON_AO_CLKC + tristate + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_INPUT + select RESET_CONTROLLER config COMMON_CLK_MESON8B bool - select COMMON_CLK_AMLOGIC + depends on ARCH_MESON + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select MFD_SYSCON select RESET_CONTROLLER help Support for the clock controller on AmLogic S802 (Meson8), @@ -30,8 +50,14 @@ config COMMON_CLK_MESON8B config COMMON_CLK_GXBB bool - select COMMON_CLK_AMLOGIC - select COMMON_CLK_MESON_AO + depends on ARCH_MESON + select COMMON_CLK_MESON_INPUT + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_VID_PLL_DIV + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_AO_CLKC select MFD_SYSCON help Support for the clock controller on AmLogic S905 devices, aka gxbb. @@ -39,8 +65,13 @@ config COMMON_CLK_GXBB config COMMON_CLK_AXG bool - select COMMON_CLK_AMLOGIC - select COMMON_CLK_MESON_AO + depends on ARCH_MESON + select COMMON_CLK_MESON_INPUT + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_AO_CLKC select MFD_SYSCON help Support for the clock controller on AmLogic A113D devices, aka axg. @@ -48,8 +79,11 @@ config COMMON_CLK_AXG config COMMON_CLK_AXG_AUDIO tristate "Meson AXG Audio Clock Controller Driver" - depends on COMMON_CLK_AXG - select COMMON_CLK_AMLOGIC_AUDIO + depends on ARCH_MESON + select COMMON_CLK_MESON_INPUT + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_PHASE + select COMMON_CLK_MESON_SCLK_DIV select REGMAP_MMIO help Support for the audio clock controller on AmLogic A113D devices, diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 8234e92eea38..e339d8f58488 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -1,13 +1,18 @@ -# -# Makefile for Meson specific clk -# +# Amlogic clock drivers -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 clk-dualdiv.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_MESON_AO_CLKC) += meson-aoclk.o +obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o +obj-$(CONFIG_COMMON_CLK_MESON_INPUT) += clk-input.o +obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o +obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o +obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o +obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o +obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o +obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o + +# Amlogic Clock controllers + +obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o +obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o -obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o -obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o -obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o -obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index 5701f5840b75..0086f31288eb 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -12,10 +12,12 @@ #include #include #include -#include "clkc.h" #include "meson-aoclk.h" #include "axg-aoclk.h" +#include "clk-regmap.h" +#include "clk-dualdiv.h" + #define IN_PREFIX "ao-in-" /* diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index 8ac3a2295473..7ab200b6c3bf 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -14,8 +14,11 @@ #include #include -#include "clkc-audio.h" #include "axg-audio.h" +#include "clk-input.h" +#include "clk-regmap.h" +#include "clk-phase.h" +#include "sclk-div.h" #define AXG_MST_IN_COUNT 8 #define AXG_SLV_SCLK_COUNT 10 diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 1c6539eeee7c..cbbdd93b175d 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -17,7 +17,10 @@ #include #include -#include "clkc.h" +#include "clk-input.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-mpll.h" #include "axg.h" #define IN_PREFIX "ee-in-" diff --git a/drivers/clk/meson/clk-dualdiv.c b/drivers/clk/meson/clk-dualdiv.c index 4d9e161de627..c5ca23a5e3e8 100644 --- a/drivers/clk/meson/clk-dualdiv.c +++ b/drivers/clk/meson/clk-dualdiv.c @@ -22,7 +22,10 @@ */ #include -#include "clkc.h" +#include + +#include "clk-regmap.h" +#include "clk-dualdiv.h" static inline struct meson_clk_dualdiv_data * meson_clk_dualdiv_data(struct clk_regmap *clk) @@ -128,3 +131,8 @@ const struct clk_ops meson_clk_dualdiv_ro_ops = { .recalc_rate = meson_clk_dualdiv_recalc_rate, }; EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ro_ops); + +MODULE_DESCRIPTION("Amlogic dual divider driver"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-dualdiv.h b/drivers/clk/meson/clk-dualdiv.h new file mode 100644 index 000000000000..4aa939018012 --- /dev/null +++ b/drivers/clk/meson/clk-dualdiv.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_DUALDIV_H +#define __MESON_CLK_DUALDIV_H + +#include +#include "parm.h" + +struct meson_clk_dualdiv_param { + unsigned int n1; + unsigned int n2; + unsigned int m1; + unsigned int m2; + unsigned int dual; +}; + +struct meson_clk_dualdiv_data { + struct parm n1; + struct parm n2; + struct parm m1; + struct parm m2; + struct parm dual; + const struct meson_clk_dualdiv_param *table; +}; + +extern const struct clk_ops meson_clk_dualdiv_ops; +extern const struct clk_ops meson_clk_dualdiv_ro_ops; + +#endif /* __MESON_CLK_DUALDIV_H */ diff --git a/drivers/clk/meson/clk-input.c b/drivers/clk/meson/clk-input.c index 06b3e3bb6a66..086226e9dba6 100644 --- a/drivers/clk/meson/clk-input.c +++ b/drivers/clk/meson/clk-input.c @@ -7,7 +7,8 @@ #include #include #include -#include "clkc.h" +#include +#include "clk-input.h" static const struct clk_ops meson_clk_no_ops = {}; @@ -42,3 +43,7 @@ struct clk_hw *meson_clk_hw_register_input(struct device *dev, return ret ? ERR_PTR(ret) : hw; } EXPORT_SYMBOL_GPL(meson_clk_hw_register_input); + +MODULE_DESCRIPTION("Amlogic clock input helper"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-input.h b/drivers/clk/meson/clk-input.h new file mode 100644 index 000000000000..4a541b9685a6 --- /dev/null +++ b/drivers/clk/meson/clk-input.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_INPUT_H +#define __MESON_CLK_INPUT_H + +#include + +struct device; + +struct clk_hw *meson_clk_hw_register_input(struct device *dev, + const char *of_name, + const char *clk_name, + unsigned long flags); + +#endif /* __MESON_CLK_INPUT_H */ diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 650f75cc15a9..f76850d99e59 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -12,7 +12,11 @@ */ #include -#include "clkc.h" +#include +#include + +#include "clk-regmap.h" +#include "clk-mpll.h" #define SDM_DEN 16384 #define N2_MIN 4 @@ -138,9 +142,15 @@ const struct clk_ops meson_clk_mpll_ro_ops = { .recalc_rate = mpll_recalc_rate, .round_rate = mpll_round_rate, }; +EXPORT_SYMBOL_GPL(meson_clk_mpll_ro_ops); const struct clk_ops meson_clk_mpll_ops = { .recalc_rate = mpll_recalc_rate, .round_rate = mpll_round_rate, .set_rate = mpll_set_rate, }; +EXPORT_SYMBOL_GPL(meson_clk_mpll_ops); + +MODULE_DESCRIPTION("Amlogic MPLL driver"); +MODULE_AUTHOR("Michael Turquette "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h new file mode 100644 index 000000000000..cf79340006dd --- /dev/null +++ b/drivers/clk/meson/clk-mpll.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_MPLL_H +#define __MESON_CLK_MPLL_H + +#include +#include + +#include "parm.h" + +struct meson_clk_mpll_data { + struct parm sdm; + struct parm sdm_en; + struct parm n2; + struct parm ssen; + struct parm misc; + spinlock_t *lock; + u8 flags; +}; + +#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0) + +extern const struct clk_ops meson_clk_mpll_ro_ops; +extern const struct clk_ops meson_clk_mpll_ops; + +#endif /* __MESON_CLK_MPLL_H */ diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c index cba43748ce3d..80c3ada193a4 100644 --- a/drivers/clk/meson/clk-phase.c +++ b/drivers/clk/meson/clk-phase.c @@ -5,7 +5,10 @@ */ #include -#include "clkc.h" +#include + +#include "clk-regmap.h" +#include "clk-phase.h" #define phase_step(_width) (360 / (1 << (_width))) @@ -15,13 +18,12 @@ meson_clk_phase_data(struct clk_regmap *clk) return (struct meson_clk_phase_data *)clk->data; } -int meson_clk_degrees_from_val(unsigned int val, unsigned int width) +static int meson_clk_degrees_from_val(unsigned int val, unsigned int width) { return phase_step(width) * val; } -EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val); -unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width) +static unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width) { unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width)); @@ -31,7 +33,6 @@ unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width) */ return val % (1 << width); } -EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val); static int meson_clk_phase_get_phase(struct clk_hw *hw) { @@ -61,3 +62,67 @@ const struct clk_ops meson_clk_phase_ops = { .set_phase = meson_clk_phase_set_phase, }; EXPORT_SYMBOL_GPL(meson_clk_phase_ops); + +/* + * This is a special clock for the audio controller. + * The phase of mst_sclk clock output can be controlled independently + * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2). + * Controlling these 3 phases as just one makes things simpler and + * give the same clock view to all the element on the i2s bus. + * If necessary, we can still control the phase in the tdm block + * which makes these independent control redundant. + */ +static inline struct meson_clk_triphase_data * +meson_clk_triphase_data(struct clk_regmap *clk) +{ + return (struct meson_clk_triphase_data *)clk->data; +} + +static void meson_clk_triphase_sync(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + + /* Get phase 0 and sync it to phase 1 and 2 */ + val = meson_parm_read(clk->map, &tph->ph0); + meson_parm_write(clk->map, &tph->ph1, val); + meson_parm_write(clk->map, &tph->ph2, val); +} + +static int meson_clk_triphase_get_phase(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + + /* Phase are in sync, reading phase 0 is enough */ + val = meson_parm_read(clk->map, &tph->ph0); + + return meson_clk_degrees_from_val(val, tph->ph0.width); +} + +static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); + unsigned int val; + + val = meson_clk_degrees_to_val(degrees, tph->ph0.width); + meson_parm_write(clk->map, &tph->ph0, val); + meson_parm_write(clk->map, &tph->ph1, val); + meson_parm_write(clk->map, &tph->ph2, val); + + return 0; +} + +const struct clk_ops meson_clk_triphase_ops = { + .init = meson_clk_triphase_sync, + .get_phase = meson_clk_triphase_get_phase, + .set_phase = meson_clk_triphase_set_phase, +}; +EXPORT_SYMBOL_GPL(meson_clk_triphase_ops); + +MODULE_DESCRIPTION("Amlogic phase driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-phase.h b/drivers/clk/meson/clk-phase.h new file mode 100644 index 000000000000..5579f9ced142 --- /dev/null +++ b/drivers/clk/meson/clk-phase.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_PHASE_H +#define __MESON_CLK_PHASE_H + +#include +#include "parm.h" + +struct meson_clk_phase_data { + struct parm ph; +}; + +struct meson_clk_triphase_data { + struct parm ph0; + struct parm ph1; + struct parm ph2; +}; + +extern const struct clk_ops meson_clk_phase_ops; +extern const struct clk_ops meson_clk_triphase_ops; + +#endif /* __MESON_CLK_PHASE_H */ diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index afffc1547e20..4a8c68ae8801 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -32,11 +32,9 @@ #include #include #include -#include -#include -#include -#include "clkc.h" +#include "clk-regmap.h" +#include "clk-pll.h" static inline struct meson_clk_pll_data * meson_clk_pll_data(struct clk_regmap *clk) @@ -309,8 +307,15 @@ const struct clk_ops meson_clk_pll_ops = { .enable = meson_clk_pll_enable, .disable = meson_clk_pll_disable }; +EXPORT_SYMBOL_GPL(meson_clk_pll_ops); const struct clk_ops meson_clk_pll_ro_ops = { .recalc_rate = meson_clk_pll_recalc_rate, .is_enabled = meson_clk_pll_is_enabled, }; +EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops); + +MODULE_DESCRIPTION("Amlogic PLL driver"); +MODULE_AUTHOR("Carlo Caione "); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h new file mode 100644 index 000000000000..5ccf0854d932 --- /dev/null +++ b/drivers/clk/meson/clk-pll.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_PLL_H +#define __MESON_CLK_PLL_H + +#include +#include +#include "parm.h" + +struct pll_params_table { + u16 m; + u16 n; +}; + +#define PLL_PARAMS(_m, _n) \ + { \ + .m = (_m), \ + .n = (_n), \ + } + +#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) + +struct meson_clk_pll_data { + struct parm en; + struct parm m; + struct parm n; + struct parm frac; + struct parm l; + struct parm rst; + const struct reg_sequence *init_regs; + unsigned int init_count; + const struct pll_params_table *table; + u8 flags; +}; + +extern const struct clk_ops meson_clk_pll_ro_ops; +extern const struct clk_ops meson_clk_pll_ops; + +#endif /* __MESON_CLK_PLL_H */ diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c index c515f67322a3..dcd1757cc5df 100644 --- a/drivers/clk/meson/clk-regmap.c +++ b/drivers/clk/meson/clk-regmap.c @@ -4,6 +4,7 @@ * Author: Jerome Brunet */ +#include #include "clk-regmap.h" static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) @@ -180,3 +181,7 @@ const struct clk_ops clk_regmap_mux_ro_ops = { .get_parent = clk_regmap_mux_get_parent, }; EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops); + +MODULE_DESCRIPTION("Amlogic regmap backed clock driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h index e9c5728d40eb..b7a085bbf072 100644 --- a/drivers/clk/meson/clk-regmap.h +++ b/drivers/clk/meson/clk-regmap.h @@ -111,4 +111,19 @@ clk_get_regmap_mux_data(struct clk_regmap *clk) extern const struct clk_ops clk_regmap_mux_ops; extern const struct clk_ops clk_regmap_mux_ro_ops; +#define MESON_GATE(_name, _reg, _bit) \ +struct clk_regmap _name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_names = (const char *[]){ "clk81" }, \ + .num_parents = 1, \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + }, \ +} + #endif /* __CLK_REGMAP_H */ diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c deleted file mode 100644 index 4a59936251e5..000000000000 --- a/drivers/clk/meson/clk-triphase.c +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MIT) -/* - * Copyright (c) 2018 BayLibre, SAS. - * Author: Jerome Brunet - */ - -#include -#include "clkc-audio.h" - -/* - * This is a special clock for the audio controller. - * The phase of mst_sclk clock output can be controlled independently - * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2). - * Controlling these 3 phases as just one makes things simpler and - * give the same clock view to all the element on the i2s bus. - * If necessary, we can still control the phase in the tdm block - * which makes these independent control redundant. - */ -static inline struct meson_clk_triphase_data * -meson_clk_triphase_data(struct clk_regmap *clk) -{ - return (struct meson_clk_triphase_data *)clk->data; -} - -static void meson_clk_triphase_sync(struct clk_hw *hw) -{ - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); - unsigned int val; - - /* Get phase 0 and sync it to phase 1 and 2 */ - val = meson_parm_read(clk->map, &tph->ph0); - meson_parm_write(clk->map, &tph->ph1, val); - meson_parm_write(clk->map, &tph->ph2, val); -} - -static int meson_clk_triphase_get_phase(struct clk_hw *hw) -{ - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); - unsigned int val; - - /* Phase are in sync, reading phase 0 is enough */ - val = meson_parm_read(clk->map, &tph->ph0); - - return meson_clk_degrees_from_val(val, tph->ph0.width); -} - -static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees) -{ - struct clk_regmap *clk = to_clk_regmap(hw); - struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); - unsigned int val; - - val = meson_clk_degrees_to_val(degrees, tph->ph0.width); - meson_parm_write(clk->map, &tph->ph0, val); - meson_parm_write(clk->map, &tph->ph1, val); - meson_parm_write(clk->map, &tph->ph2, val); - - return 0; -} - -const struct clk_ops meson_clk_triphase_ops = { - .init = meson_clk_triphase_sync, - .get_phase = meson_clk_triphase_get_phase, - .set_phase = meson_clk_triphase_set_phase, -}; -EXPORT_SYMBOL_GPL(meson_clk_triphase_ops); diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h deleted file mode 100644 index 0a7c157ebf81..000000000000 --- a/drivers/clk/meson/clkc-audio.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2018 BayLibre, SAS. - * Author: Jerome Brunet - */ - -#ifndef __MESON_CLKC_AUDIO_H -#define __MESON_CLKC_AUDIO_H - -#include "clkc.h" - -struct meson_clk_triphase_data { - struct parm ph0; - struct parm ph1; - struct parm ph2; -}; - -struct meson_sclk_div_data { - struct parm div; - struct parm hi; - unsigned int cached_div; - struct clk_duty cached_duty; -}; - -extern const struct clk_ops meson_clk_triphase_ops; -extern const struct clk_ops meson_sclk_div_ops; - -#endif /* __MESON_CLKC_AUDIO_H */ diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h deleted file mode 100644 index e3cd442db739..000000000000 --- a/drivers/clk/meson/clkc.h +++ /dev/null @@ -1,146 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2015 Endless Mobile, Inc. - * Author: Carlo Caione - */ - -#ifndef __CLKC_H -#define __CLKC_H - -#include -#include "clk-regmap.h" - -#define PMASK(width) GENMASK(width - 1, 0) -#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) -#define CLRPMASK(width, shift) (~SETPMASK(width, shift)) - -#define PARM_GET(width, shift, reg) \ - (((reg) & SETPMASK(width, shift)) >> (shift)) -#define PARM_SET(width, shift, reg, val) \ - (((reg) & CLRPMASK(width, shift)) | ((val) << (shift))) - -#define MESON_PARM_APPLICABLE(p) (!!((p)->width)) - -struct parm { - u16 reg_off; - u8 shift; - u8 width; -}; - -static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p) -{ - unsigned int val; - - regmap_read(map, p->reg_off, &val); - return PARM_GET(p->width, p->shift, val); -} - -static inline void meson_parm_write(struct regmap *map, struct parm *p, - unsigned int val) -{ - regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift), - val << p->shift); -} - - -struct pll_params_table { - u16 m; - u16 n; -}; - -#define PLL_PARAMS(_m, _n) \ - { \ - .m = (_m), \ - .n = (_n), \ - } - -#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) - -struct meson_clk_pll_data { - struct parm en; - struct parm m; - struct parm n; - struct parm frac; - struct parm l; - struct parm rst; - const struct reg_sequence *init_regs; - unsigned int init_count; - const struct pll_params_table *table; - u8 flags; -}; - -#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) - -struct meson_clk_mpll_data { - struct parm sdm; - struct parm sdm_en; - struct parm n2; - struct parm ssen; - struct parm misc; - spinlock_t *lock; - u8 flags; -}; - -#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0) - -struct meson_clk_phase_data { - struct parm ph; -}; - -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){ \ - .offset = (_reg), \ - .bit_idx = (_bit), \ - }, \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name, \ - .ops = &clk_regmap_gate_ops, \ - .parent_names = (const char *[]){ "clk81" }, \ - .num_parents = 1, \ - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ - }, \ -}; - -struct meson_clk_dualdiv_param { - unsigned int n1; - unsigned int n2; - unsigned int m1; - unsigned int m2; - unsigned int dual; -}; - -struct meson_clk_dualdiv_data { - struct parm n1; - struct parm n2; - struct parm m1; - struct parm m2; - struct parm dual; - const struct meson_clk_dualdiv_param *table; -}; - -/* clk_ops */ -extern const struct clk_ops meson_clk_pll_ro_ops; -extern const struct clk_ops meson_clk_pll_ops; -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; -extern const struct clk_ops meson_clk_dualdiv_ops; -extern const struct clk_ops meson_clk_dualdiv_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 */ diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 510b6a7d2f18..449f6ac189d8 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -5,10 +5,12 @@ */ #include #include -#include "clkc.h" #include "meson-aoclk.h" #include "gxbb-aoclk.h" +#include "clk-regmap.h" +#include "clk-dualdiv.h" + #define IN_PREFIX "ao-in-" /* AO Configuration Clock registers offsets */ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index ecf9a8f6281c..3741db9a9fe1 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -12,9 +12,12 @@ #include #include -#include "clkc.h" #include "gxbb.h" +#include "clk-input.h" #include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-mpll.h" +#include "vid-pll-div.h" #define IN_PREFIX "ee-in-" diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index 7b9d194ccc3b..b67951909e04 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -17,6 +17,8 @@ #include #include "meson-aoclk.h" +#include "clk-input.h" + static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev, unsigned long id) { diff --git a/drivers/clk/meson/meson-aoclk.h b/drivers/clk/meson/meson-aoclk.h index 0758b35d4427..999cde3868f7 100644 --- a/drivers/clk/meson/meson-aoclk.h +++ b/drivers/clk/meson/meson-aoclk.h @@ -11,9 +11,12 @@ #ifndef __MESON_AOCLK_H__ #define __MESON_AOCLK_H__ +#include #include +#include #include -#include "clkc.h" + +#include "clk-regmap.h" struct meson_aoclk_input { const char *name; diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 748552c5f6c8..23b1e355a849 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -16,9 +16,10 @@ #include #include -#include "clkc.h" #include "meson8b.h" #include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-mpll.h" static DEFINE_SPINLOCK(meson_clk_lock); diff --git a/drivers/clk/meson/parm.h b/drivers/clk/meson/parm.h new file mode 100644 index 000000000000..3c9ef1b505ce --- /dev/null +++ b/drivers/clk/meson/parm.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2015 Endless Mobile, Inc. + * Author: Carlo Caione + */ + +#ifndef __MESON_PARM_H +#define __MESON_PARM_H + +#include +#include + +#define PMASK(width) GENMASK(width - 1, 0) +#define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) +#define CLRPMASK(width, shift) (~SETPMASK(width, shift)) + +#define PARM_GET(width, shift, reg) \ + (((reg) & SETPMASK(width, shift)) >> (shift)) +#define PARM_SET(width, shift, reg, val) \ + (((reg) & CLRPMASK(width, shift)) | ((val) << (shift))) + +#define MESON_PARM_APPLICABLE(p) (!!((p)->width)) + +struct parm { + u16 reg_off; + u8 shift; + u8 width; +}; + +static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p) +{ + unsigned int val; + + regmap_read(map, p->reg_off, &val); + return PARM_GET(p->width, p->shift, val); +} + +static inline void meson_parm_write(struct regmap *map, struct parm *p, + unsigned int val) +{ + regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift), + val << p->shift); +} + +#endif /* __MESON_PARM_H */ + diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c index bc64019b8eeb..3acf03780221 100644 --- a/drivers/clk/meson/sclk-div.c +++ b/drivers/clk/meson/sclk-div.c @@ -16,7 +16,11 @@ * duty_cycle = (1 + hi) / (1 + val) */ -#include "clkc-audio.h" +#include +#include + +#include "clk-regmap.h" +#include "sclk-div.h" static inline struct meson_sclk_div_data * meson_sclk_div_data(struct clk_regmap *clk) @@ -241,3 +245,7 @@ const struct clk_ops meson_sclk_div_ops = { .init = sclk_div_init, }; EXPORT_SYMBOL_GPL(meson_sclk_div_ops); + +MODULE_DESCRIPTION("Amlogic Sample divider driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/sclk-div.h b/drivers/clk/meson/sclk-div.h new file mode 100644 index 000000000000..b64b2a32005f --- /dev/null +++ b/drivers/clk/meson/sclk-div.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_SCLK_DIV_H +#define __MESON_SCLK_DIV_H + +#include +#include "parm.h" + +struct meson_sclk_div_data { + struct parm div; + struct parm hi; + unsigned int cached_div; + struct clk_duty cached_duty; +}; + +extern const struct clk_ops meson_sclk_div_ops; + +#endif /* __MESON_SCLK_DIV_H */ diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c index 88af0e282ea0..08bcc01c0923 100644 --- a/drivers/clk/meson/vid-pll-div.c +++ b/drivers/clk/meson/vid-pll-div.c @@ -5,7 +5,10 @@ */ #include -#include "clkc.h" +#include + +#include "clk-regmap.h" +#include "vid-pll-div.h" static inline struct meson_vid_pll_div_data * meson_vid_pll_div_data(struct clk_regmap *clk) @@ -89,3 +92,8 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw, const struct clk_ops meson_vid_pll_div_ro_ops = { .recalc_rate = meson_vid_pll_div_recalc_rate, }; +EXPORT_SYMBOL_GPL(meson_vid_pll_div_ro_ops); + +MODULE_DESCRIPTION("Amlogic video pll divider driver"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/meson/vid-pll-div.h b/drivers/clk/meson/vid-pll-div.h new file mode 100644 index 000000000000..c0128e33ccf9 --- /dev/null +++ b/drivers/clk/meson/vid-pll-div.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_VID_PLL_DIV_H +#define __MESON_VID_PLL_DIV_H + +#include +#include "parm.h" + +struct meson_vid_pll_div_data { + struct parm val; + struct parm sel; +}; + +extern const struct clk_ops meson_vid_pll_div_ro_ops; + +#endif /* __MESON_VID_PLL_DIV_H */ -- cgit v1.2.3 From 8eed1db1adec6a26cef4acc7e0b2615049e8bd6d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 1 Feb 2019 15:53:42 +0100 Subject: clk: meson: pll: update driver for the g12a The g12a use fractional parameter of 17 useful bits. At the moment, this parameter in encoded using u16 value. Use this opportunity to switch all the pll to parameter to unsigned int. This should save us some annoying trouble shooting when and m and n field eventually grow as well. This patch also introduce pll multiplier range. On the g12a, the hifi and gp0 plls are able to lock as long as the following condition is met: 55 <= m/n <= 255. The param table describing this would be huge which is a waste of memory. Using ranges, we can save memory. Ranges also help find the best pll parameter significantly faster since we don't have to try all the possible settings. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong [jbrunet: fixed fix pll settings calculation with arm32] Link: https://lkml.kernel.org/r/20190201145345.6795-2-jbrunet@baylibre.com --- drivers/clk/meson/clk-pll.c | 203 +++++++++++++++++++++++++++++++------------- drivers/clk/meson/clk-pll.h | 10 ++- 2 files changed, 154 insertions(+), 59 deletions(-) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 4a8c68ae8801..41e16dd7272a 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "clk-regmap.h" #include "clk-pll.h" @@ -42,12 +43,21 @@ meson_clk_pll_data(struct clk_regmap *clk) return (struct meson_clk_pll_data *)clk->data; } +static int __pll_round_closest_mult(struct meson_clk_pll_data *pll) +{ + if ((pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) && + !MESON_PARM_APPLICABLE(&pll->frac)) + return 1; + + return 0; +} + static unsigned long __pll_params_to_rate(unsigned long parent_rate, - const struct pll_params_table *pllt, - u16 frac, + unsigned int m, unsigned int n, + unsigned int frac, struct meson_clk_pll_data *pll) { - u64 rate = (u64)parent_rate * pllt->m; + u64 rate = (u64)parent_rate * m; if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { u64 frac_rate = (u64)parent_rate * frac; @@ -56,7 +66,7 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate, (1 << pll->frac.width)); } - return DIV_ROUND_UP_ULL(rate, pllt->n); + return DIV_ROUND_UP_ULL(rate, n); } static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, @@ -64,35 +74,39 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - struct pll_params_table pllt; - u16 frac; + unsigned int m, n, frac; - pllt.n = meson_parm_read(clk->map, &pll->n); - pllt.m = meson_parm_read(clk->map, &pll->m); + n = meson_parm_read(clk->map, &pll->n); + m = meson_parm_read(clk->map, &pll->m); frac = MESON_PARM_APPLICABLE(&pll->frac) ? meson_parm_read(clk->map, &pll->frac) : 0; - return __pll_params_to_rate(parent_rate, &pllt, frac, pll); + return __pll_params_to_rate(parent_rate, m, n, frac, pll); } -static u16 __pll_params_with_frac(unsigned long rate, - unsigned long parent_rate, - const struct pll_params_table *pllt, - struct meson_clk_pll_data *pll) +static unsigned int __pll_params_with_frac(unsigned long rate, + unsigned long parent_rate, + unsigned int m, + unsigned int n, + struct meson_clk_pll_data *pll) { - u16 frac_max = (1 << pll->frac.width); - u64 val = (u64)rate * pllt->n; + unsigned int frac_max = (1 << pll->frac.width); + u64 val = (u64)rate * n; + + /* Bail out if we are already over the requested rate */ + if (rate < parent_rate * m / n) + return 0; if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); else val = div_u64(val * frac_max, parent_rate); - val -= pllt->m * frac_max; + val -= m * frac_max; - return min((u16)val, (u16)(frac_max - 1)); + return min((unsigned int)val, (frac_max - 1)); } static bool meson_clk_pll_is_better(unsigned long rate, @@ -100,45 +114,123 @@ static bool meson_clk_pll_is_better(unsigned long rate, unsigned long now, struct meson_clk_pll_data *pll) { - if (!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || - MESON_PARM_APPLICABLE(&pll->frac)) { - /* Round down */ - if (now < rate && best < now) - return true; - } else { + if (__pll_round_closest_mult(pll)) { /* Round Closest */ if (abs(now - rate) < abs(best - rate)) return true; + } else { + /* Round down */ + if (now < rate && best < now) + return true; } return false; } -static const struct pll_params_table * -meson_clk_get_pll_settings(unsigned long rate, - unsigned long parent_rate, - struct meson_clk_pll_data *pll) +static int meson_clk_get_pll_table_index(unsigned int index, + unsigned int *m, + unsigned int *n, + struct meson_clk_pll_data *pll) { - const struct pll_params_table *table = pll->table; - unsigned long best = 0, now = 0; - unsigned int i, best_i = 0; + if (!pll->table[index].n) + return -EINVAL; + + *m = pll->table[index].m; + *n = pll->table[index].n; + + return 0; +} + +static unsigned int meson_clk_get_pll_range_m(unsigned long rate, + unsigned long parent_rate, + unsigned int n, + struct meson_clk_pll_data *pll) +{ + u64 val = (u64)rate * n; + + if (__pll_round_closest_mult(pll)) + return DIV_ROUND_CLOSEST_ULL(val, parent_rate); - if (!table) - return NULL; + return div_u64(val, parent_rate); +} + +static int meson_clk_get_pll_range_index(unsigned long rate, + unsigned long parent_rate, + unsigned int index, + unsigned int *m, + unsigned int *n, + struct meson_clk_pll_data *pll) +{ + *n = index + 1; + + /* Check the predivider range */ + if (*n >= (1 << pll->n.width)) + return -EINVAL; + + if (*n == 1) { + /* Get the boundaries out the way */ + if (rate <= pll->range->min * parent_rate) { + *m = pll->range->min; + return -ENODATA; + } else if (rate >= pll->range->max * parent_rate) { + *m = pll->range->max; + return -ENODATA; + } + } + + *m = meson_clk_get_pll_range_m(rate, parent_rate, *n, pll); + + /* the pre-divider gives a multiplier too big - stop */ + if (*m >= (1 << pll->m.width)) + return -EINVAL; + + return 0; +} + +static int meson_clk_get_pll_get_index(unsigned long rate, + unsigned long parent_rate, + unsigned int index, + unsigned int *m, + unsigned int *n, + struct meson_clk_pll_data *pll) +{ + if (pll->range) + return meson_clk_get_pll_range_index(rate, parent_rate, + index, m, n, pll); + else if (pll->table) + return meson_clk_get_pll_table_index(index, m, n, pll); + + return -EINVAL; +} - for (i = 0; table[i].n; i++) { - now = __pll_params_to_rate(parent_rate, &table[i], 0, pll); +static int meson_clk_get_pll_settings(unsigned long rate, + unsigned long parent_rate, + unsigned int *best_m, + unsigned int *best_n, + struct meson_clk_pll_data *pll) +{ + unsigned long best = 0, now = 0; + unsigned int i, m, n; + int ret; + + for (i = 0, ret = 0; !ret; i++) { + ret = meson_clk_get_pll_get_index(rate, parent_rate, + i, &m, &n, pll); + if (ret == -EINVAL) + break; - /* If we get an exact match, don't bother any further */ - if (now == rate) { - return &table[i]; - } else if (meson_clk_pll_is_better(rate, best, now, pll)) { + now = __pll_params_to_rate(parent_rate, m, n, 0, pll); + if (meson_clk_pll_is_better(rate, best, now, pll)) { best = now; - best_i = i; + *best_m = m; + *best_n = n; + + if (now == rate) + break; } } - return (struct pll_params_table *)&table[best_i]; + return best ? 0 : -EINVAL; } static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, @@ -146,15 +238,15 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - const struct pll_params_table *pllt = - meson_clk_get_pll_settings(rate, *parent_rate, pll); + unsigned int m, n, frac; unsigned long round; - u16 frac; + int ret; - if (!pllt) + ret = meson_clk_get_pll_settings(rate, *parent_rate, &m, &n, pll); + if (ret) return meson_clk_pll_recalc_rate(hw, *parent_rate); - round = __pll_params_to_rate(*parent_rate, pllt, 0, pll); + round = __pll_params_to_rate(*parent_rate, m, n, 0, pll); if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round) return round; @@ -163,9 +255,9 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, * The rate provided by the setting is not an exact match, let's * try to improve the result using the fractional parameter */ - frac = __pll_params_with_frac(rate, *parent_rate, pllt, pll); + frac = __pll_params_with_frac(rate, *parent_rate, m, n, pll); - return __pll_params_to_rate(*parent_rate, pllt, frac, pll); + return __pll_params_to_rate(*parent_rate, m, n, frac, pll); } static int meson_clk_pll_wait_lock(struct clk_hw *hw) @@ -252,30 +344,27 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); - const struct pll_params_table *pllt; - unsigned int enabled; + unsigned int enabled, m, n, frac = 0, ret; unsigned long old_rate; - u16 frac = 0; if (parent_rate == 0 || rate == 0) return -EINVAL; old_rate = rate; - pllt = meson_clk_get_pll_settings(rate, parent_rate, pll); - if (!pllt) - return -EINVAL; + ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll); + if (ret) + return ret; enabled = meson_parm_read(clk->map, &pll->en); if (enabled) meson_clk_pll_disable(hw); - meson_parm_write(clk->map, &pll->n, pllt->n); - meson_parm_write(clk->map, &pll->m, pllt->m); - + meson_parm_write(clk->map, &pll->n, n); + meson_parm_write(clk->map, &pll->m, m); if (MESON_PARM_APPLICABLE(&pll->frac)) { - frac = __pll_params_with_frac(rate, parent_rate, pllt, pll); + frac = __pll_params_with_frac(rate, parent_rate, m, n, pll); meson_parm_write(clk->map, &pll->frac, frac); } diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h index 5ccf0854d932..55af2e285b1b 100644 --- a/drivers/clk/meson/clk-pll.h +++ b/drivers/clk/meson/clk-pll.h @@ -12,8 +12,13 @@ #include "parm.h" struct pll_params_table { - u16 m; - u16 n; + unsigned int m; + unsigned int n; +}; + +struct pll_mult_range { + unsigned int min; + unsigned int max; }; #define PLL_PARAMS(_m, _n) \ @@ -34,6 +39,7 @@ struct meson_clk_pll_data { const struct reg_sequence *init_regs; unsigned int init_count; const struct pll_params_table *table; + const struct pll_mult_range *range; u8 flags; }; -- cgit v1.2.3 From 25db146aa7262bc95c314b2df35db107f5eadd55 Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Fri, 1 Feb 2019 15:53:43 +0100 Subject: dt-bindings: clk: meson: add g12a periph clock controller bindings Add new clock controller compatible and dt-bindings header for the Everything-Else domain of the g12a SoC Reviewed-by: Rob Herring Signed-off-by: Jian Hu Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190201145345.6795-3-jbrunet@baylibre.com --- .../bindings/clock/amlogic,gxbb-clkc.txt | 1 + include/dt-bindings/clock/g12a-clkc.h | 135 +++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 include/dt-bindings/clock/g12a-clkc.h diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt index a6871953bf04..5c8b105be4d6 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt @@ -9,6 +9,7 @@ Required Properties: "amlogic,gxbb-clkc" for GXBB SoC, "amlogic,gxl-clkc" for GXL and GXM SoC, "amlogic,axg-clkc" for AXG SoC. + "amlogic,g12a-clkc" for G12A SoC. - clocks : list of clock phandle, one for each entry clock-names. - clock-names : should contain the following: * "xtal": the platform xtal diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h new file mode 100644 index 000000000000..83b657038d1e --- /dev/null +++ b/include/dt-bindings/clock/g12a-clkc.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR MIT */ +/* + * Meson-G12A clock tree IDs + * + * Copyright (c) 2018 Amlogic, Inc. All rights reserved. + */ + +#ifndef __G12A_CLKC_H +#define __G12A_CLKC_H + +#define CLKID_SYS_PLL 0 +#define CLKID_FIXED_PLL 1 +#define CLKID_FCLK_DIV2 2 +#define CLKID_FCLK_DIV3 3 +#define CLKID_FCLK_DIV4 4 +#define CLKID_FCLK_DIV5 5 +#define CLKID_FCLK_DIV7 6 +#define CLKID_GP0_PLL 7 +#define CLKID_CLK81 10 +#define CLKID_MPLL0 11 +#define CLKID_MPLL1 12 +#define CLKID_MPLL2 13 +#define CLKID_MPLL3 14 +#define CLKID_DDR 15 +#define CLKID_DOS 16 +#define CLKID_AUDIO_LOCKER 17 +#define CLKID_MIPI_DSI_HOST 18 +#define CLKID_ETH_PHY 19 +#define CLKID_ISA 20 +#define CLKID_PL301 21 +#define CLKID_PERIPHS 22 +#define CLKID_SPICC0 23 +#define CLKID_I2C 24 +#define CLKID_SANA 25 +#define CLKID_SD 26 +#define CLKID_RNG0 27 +#define CLKID_UART0 28 +#define CLKID_SPICC1 29 +#define CLKID_HIU_IFACE 30 +#define CLKID_MIPI_DSI_PHY 31 +#define CLKID_ASSIST_MISC 32 +#define CLKID_SD_EMMC_A 33 +#define CLKID_SD_EMMC_B 34 +#define CLKID_SD_EMMC_C 35 +#define CLKID_AUDIO_CODEC 36 +#define CLKID_AUDIO 37 +#define CLKID_ETH 38 +#define CLKID_DEMUX 39 +#define CLKID_AUDIO_IFIFO 40 +#define CLKID_ADC 41 +#define CLKID_UART1 42 +#define CLKID_G2D 43 +#define CLKID_RESET 44 +#define CLKID_PCIE_COMB 45 +#define CLKID_PARSER 46 +#define CLKID_USB 47 +#define CLKID_PCIE_PHY 48 +#define CLKID_AHB_ARB0 49 +#define CLKID_AHB_DATA_BUS 50 +#define CLKID_AHB_CTRL_BUS 51 +#define CLKID_HTX_HDCP22 52 +#define CLKID_HTX_PCLK 53 +#define CLKID_BT656 54 +#define CLKID_USB1_DDR_BRIDGE 55 +#define CLKID_MMC_PCLK 56 +#define CLKID_UART2 57 +#define CLKID_VPU_INTR 58 +#define CLKID_GIC 59 +#define CLKID_SD_EMMC_A_CLK0 60 +#define CLKID_SD_EMMC_B_CLK0 61 +#define CLKID_SD_EMMC_C_CLK0 62 +#define CLKID_HIFI_PLL 74 +#define CLKID_VCLK2_VENCI0 80 +#define CLKID_VCLK2_VENCI1 81 +#define CLKID_VCLK2_VENCP0 82 +#define CLKID_VCLK2_VENCP1 83 +#define CLKID_VCLK2_VENCT0 84 +#define CLKID_VCLK2_VENCT1 85 +#define CLKID_VCLK2_OTHER 86 +#define CLKID_VCLK2_ENCI 87 +#define CLKID_VCLK2_ENCP 88 +#define CLKID_DAC_CLK 89 +#define CLKID_AOCLK 90 +#define CLKID_IEC958 91 +#define CLKID_ENC480P 92 +#define CLKID_RNG1 93 +#define CLKID_VCLK2_ENCT 94 +#define CLKID_VCLK2_ENCL 95 +#define CLKID_VCLK2_VENCLMMC 96 +#define CLKID_VCLK2_VENCL 97 +#define CLKID_VCLK2_OTHER1 98 +#define CLKID_FCLK_DIV2P5 99 +#define CLKID_DMA 105 +#define CLKID_EFUSE 106 +#define CLKID_ROM_BOOT 107 +#define CLKID_RESET_SEC 108 +#define CLKID_SEC_AHB_APB3 109 +#define CLKID_VPU_0_SEL 110 +#define CLKID_VPU_0 112 +#define CLKID_VPU_1_SEL 113 +#define CLKID_VPU_1 115 +#define CLKID_VPU 116 +#define CLKID_VAPB_0_SEL 117 +#define CLKID_VAPB_0 119 +#define CLKID_VAPB_1_SEL 120 +#define CLKID_VAPB_1 122 +#define CLKID_VAPB_SEL 123 +#define CLKID_VAPB 124 +#define CLKID_HDMI_PLL 128 +#define CLKID_VID_PLL 129 +#define CLKID_VCLK 138 +#define CLKID_VCLK2 139 +#define CLKID_VCLK_DIV1 148 +#define CLKID_VCLK_DIV2 149 +#define CLKID_VCLK_DIV4 150 +#define CLKID_VCLK_DIV6 151 +#define CLKID_VCLK_DIV12 152 +#define CLKID_VCLK2_DIV1 153 +#define CLKID_VCLK2_DIV2 154 +#define CLKID_VCLK2_DIV4 155 +#define CLKID_VCLK2_DIV6 156 +#define CLKID_VCLK2_DIV12 157 +#define CLKID_CTS_ENCI 162 +#define CLKID_CTS_ENCP 163 +#define CLKID_CTS_VDAC 164 +#define CLKID_HDMI_TX 165 +#define CLKID_HDMI 168 +#define CLKID_MALI_0_SEL 169 +#define CLKID_MALI_0 171 +#define CLKID_MALI_1_SEL 172 +#define CLKID_MALI_1 174 +#define CLKID_MALI 175 +#define CLKID_MPLL_5OM 177 + +#endif /* __G12A_CLKC_H */ -- cgit v1.2.3 From 085a4ea93d5491b9e5274272b528a1fccf9b2546 Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Fri, 1 Feb 2019 15:53:44 +0100 Subject: clk: meson: g12a: add peripheral clock controller Add the peripheral clock controller found in the g12a SoC family Signed-off-by: Jian Hu Signed-off-by: Neil Armstrong Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190201145345.6795-4-jbrunet@baylibre.com --- drivers/clk/meson/Kconfig | 12 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/clk-regmap.h | 9 +- drivers/clk/meson/g12a.c | 2399 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/g12a.h | 175 +++ 5 files changed, 2594 insertions(+), 2 deletions(-) create mode 100644 drivers/clk/meson/g12a.c create mode 100644 drivers/clk/meson/g12a.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index f2e757aea4f1..4f61dd71f26d 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -88,3 +88,15 @@ config COMMON_CLK_AXG_AUDIO help Support for the audio clock controller on AmLogic A113D devices, aka axg, Say Y if you want audio subsystem to work. + +config COMMON_CLK_G12A + bool + depends on ARCH_MESON + select COMMON_CLK_MESON_INPUT + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select MFD_SYSCON + help + Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 + devices, aka g12a. Say Y if you want peripherals to work. diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index e339d8f58488..c3dd3901afe3 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -15,4 +15,5 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o +obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h index b7a085bbf072..1dd0abe3ba91 100644 --- a/drivers/clk/meson/clk-regmap.h +++ b/drivers/clk/meson/clk-regmap.h @@ -111,7 +111,7 @@ clk_get_regmap_mux_data(struct clk_regmap *clk) extern const struct clk_ops clk_regmap_mux_ops; extern const struct clk_ops clk_regmap_mux_ro_ops; -#define MESON_GATE(_name, _reg, _bit) \ +#define __MESON_GATE(_name, _reg, _bit, _ops) \ struct clk_regmap _name = { \ .data = &(struct clk_regmap_gate_data){ \ .offset = (_reg), \ @@ -119,11 +119,16 @@ struct clk_regmap _name = { \ }, \ .hw.init = &(struct clk_init_data) { \ .name = #_name, \ - .ops = &clk_regmap_gate_ops, \ + .ops = _ops, \ .parent_names = (const char *[]){ "clk81" }, \ .num_parents = 1, \ .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ }, \ } +#define MESON_GATE(_name, _reg, _bit) \ + __MESON_GATE(_name, _reg, _bit, &clk_regmap_gate_ops) + +#define MESON_GATE_RO(_name, _reg, _bit) \ + __MESON_GATE(_name, _reg, _bit, &clk_regmap_gate_ro_ops) #endif /* __CLK_REGMAP_H */ diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c new file mode 100644 index 000000000000..4d9ec6026ef6 --- /dev/null +++ b/drivers/clk/meson/g12a.c @@ -0,0 +1,2399 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson-G12A Clock Controller Driver + * + * Copyright (c) 2016 Baylibre SAS. + * Author: Michael Turquette + * + * Copyright (c) 2018 Amlogic, inc. + * Author: Qiufang Dai + * Author: Jian Hu + */ + +#include +#include +#include +#include +#include +#include + +#include "clk-input.h" +#include "clk-mpll.h" +#include "clk-pll.h" +#include "clk-regmap.h" +#include "vid-pll-div.h" +#include "g12a.h" + +#define IN_PREFIX "ee-in-" + +static DEFINE_SPINLOCK(meson_clk_lock); + +static struct clk_regmap g12a_fixed_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_FIX_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_FIX_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_FIX_PLL_CNTL0, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +/* + * Internal sys pll emulation configuration parameters + */ +static const struct reg_sequence g12a_sys_init_regs[] = { + { .reg = HHI_SYS_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_SYS_PLL_CNTL2, .def = 0x00000000 }, + { .reg = HHI_SYS_PLL_CNTL3, .def = 0x48681c00 }, + { .reg = HHI_SYS_PLL_CNTL4, .def = 0x88770290 }, + { .reg = HHI_SYS_PLL_CNTL5, .def = 0x39272000 }, + { .reg = HHI_SYS_PLL_CNTL6, .def = 0x56540000 }, +}; + +static struct clk_regmap g12a_sys_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .init_regs = g12a_sys_init_regs, + .init_count = ARRAY_SIZE(g12a_sys_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_sys_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_PLL_CNTL0, + .shift = 16, + .width = 3, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "sys_pll_dco" }, + .num_parents = 1, + }, +}; + +static const struct pll_mult_range g12a_gp0_pll_mult_range = { + .min = 55, + .max = 255, +}; + +/* + * Internal gp0 pll emulation configuration parameters + */ +static const struct reg_sequence g12a_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0x00000000 }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x48681c00 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0x33771290 }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x39272000 }, + { .reg = HHI_GP0_PLL_CNTL6, .def = 0x56540000 }, +}; + +static struct clk_regmap g12a_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .range = &g12a_gp0_pll_mult_range, + .init_regs = g12a_gp0_init_regs, + .init_count = ARRAY_SIZE(g12a_gp0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_GP0_PLL_CNTL0, + .shift = 16, + .width = 3, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "gp0_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * Internal hifi pll emulation configuration parameters + */ +static const struct reg_sequence g12a_hifi_init_regs[] = { + { .reg = HHI_HIFI_PLL_CNTL1, .def = 0x00000000 }, + { .reg = HHI_HIFI_PLL_CNTL2, .def = 0x00000000 }, + { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x6a285c00 }, + { .reg = HHI_HIFI_PLL_CNTL4, .def = 0x65771290 }, + { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x39272000 }, + { .reg = HHI_HIFI_PLL_CNTL6, .def = 0x56540000 }, +}; + +static struct clk_regmap g12a_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_HIFI_PLL_CNTL1, + .shift = 0, + .width = 17, + }, + .l = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HIFI_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + .range = &g12a_gp0_pll_mult_range, + .init_regs = g12a_hifi_init_regs, + .init_count = ARRAY_SIZE(g12a_hifi_init_regs), + .flags = CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HIFI_PLL_CNTL0, + .shift = 16, + .width = 2, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "hifi_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 10, + .width = 5, + }, + .frac = { + .reg_off = HHI_HDMI_PLL_CNTL1, + .shift = 0, + .width = 16, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 30, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ IN_PREFIX "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 g12a_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll_od2 = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 18, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od2", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_PLL_CNTL0, + .shift = 20, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_od2" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div2_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div3_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 21, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div4_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div5_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_fclk_div2p5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5_div", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_fclk_div2p5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_FIX_PLL_CNTL1, + .bit_idx = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div2p5_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor g12a_mpll_50m_div = { + .mult = 1, + .div = 80, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m_div", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll_50m = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_FIX_PLL_CNTL3, + .mask = 0x1, + .shift = 5, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal", + "mpll_50m_div" }, + .num_parents = 2, + }, +}; + +static struct clk_fixed_factor g12a_mpll_prediv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "fixed_pll_dco" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL1, + .shift = 29, + .width = 1, + }, + .lock = &meson_clk_lock, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "mpll_prediv" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL1, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL3, + .shift = 29, + .width = 1, + }, + .lock = &meson_clk_lock, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "mpll_prediv" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL3, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL5, + .shift = 29, + .width = 1, + }, + .lock = &meson_clk_lock, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "mpll_prediv" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL5, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll2_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 29, + .width = 1, + }, + .lock = &meson_clk_lock, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "mpll_prediv" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll3_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; +static const char * const clk81_parent_names[] = { + IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", + "fclk_div3", "fclk_div5" +}; + +static struct clk_regmap g12a_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = clk81_parent_names, + .num_parents = ARRAY_SIZE(clk81_parent_names), + }, +}; + +static struct clk_regmap g12a_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpeg_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "mpeg_clk_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "clk81", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpeg_clk_div" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + }, +}; + +static const char * const g12a_sd_emmc_clk0_parent_names[] = { + IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7", + + /* + * Following these parent clocks, we should also have had mpll2, mpll3 + * and gp0_pll but these clocks are too precious to be used here. All + * the necessary rates for MMC and NAND operation can be acheived using + * g12a_ee_core or fclk_div clocks + */ +}; + +/* SDIO clock */ +static struct clk_regmap g12a_sd_emmc_a_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_sd_emmc_clk0_parent_names, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_a_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_a_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_a_clk0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* SDcard clock */ +static struct clk_regmap g12a_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_sd_emmc_clk0_parent_names, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* EMMC/NAND clock */ +static struct clk_regmap g12a_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_sd_emmc_clk0_parent_names, + .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VPU Clock */ + +static const char * const g12a_vpu_parent_names[] = { + "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", + "mpll1", "vid_pll", "hifi_pll", "gp0_pll", +}; + +static struct clk_regmap g12a_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_vpu_parent_names, + .num_parents = ARRAY_SIZE(g12a_vpu_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vpu_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vpu_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_vpu_parent_names, + .num_parents = ARRAY_SIZE(g12a_vpu_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vpu_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vpu_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + /* + * bit 31 selects from 2 possible parents: + * vpu_0 or vpu_1 + */ + .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* VAPB Clock */ + +static const char * const g12a_vapb_parent_names[] = { + "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", + "mpll1", "vid_pll", "mpll2", "fclk_div2p5", +}; + +static struct clk_regmap g12a_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_vapb_parent_names, + .num_parents = ARRAY_SIZE(g12a_vapb_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vapb_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vapb_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_vapb_parent_names, + .num_parents = ARRAY_SIZE(g12a_vapb_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "vapb_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vapb_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_regmap g12a_vapb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_sel", + .ops = &clk_regmap_mux_ops, + /* + * bit 31 selects from 2 possible parents: + * vapb_0 or vapb_1 + */ + .parent_names = (const char *[]){ "vapb_0", "vapb_1" }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_vapb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "vapb_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +/* Video Clocks */ + +static struct clk_regmap g12a_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 g12a_vid_pll_parent_names[] = { "vid_pll_div", + "hdmi_pll" }; + +static struct clk_regmap g12a_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 = g12a_vid_pll_parent_names, + .num_parents = ARRAY_SIZE(g12a_vid_pll_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_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 g12a_vclk_parent_names[] = { + "vid_pll", "gp0_pll", "hifi_pll", "mpll1", "fclk_div3", "fclk_div4", + "fclk_div5", "fclk_div7" +}; + +static struct clk_regmap g12a_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, + .parent_names = g12a_vclk_parent_names, + .num_parents = ARRAY_SIZE(g12a_vclk_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_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, + .parent_names = g12a_vclk_parent_names, + .num_parents = ARRAY_SIZE(g12a_vclk_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 g12a_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 = g12a_cts_parent_names, + .num_parents = ARRAY_SIZE(g12a_cts_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_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 = g12a_cts_parent_names, + .num_parents = ARRAY_SIZE(g12a_cts_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_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 = g12a_cts_parent_names, + .num_parents = ARRAY_SIZE(g12a_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 g12a_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 g12a_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, + .parent_names = g12a_cts_hdmi_tx_parent_names, + .num_parents = ARRAY_SIZE(g12a_cts_hdmi_tx_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_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 g12a_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 g12a_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 g12a_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 g12a_hdmi_parent_names[] = { + IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5" +}; + +static struct clk_regmap g12a_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 = g12a_hdmi_parent_names, + .num_parents = ARRAY_SIZE(g12a_hdmi_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap g12a_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 g12a_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, + }, +}; + +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch. + */ + +static const char * const g12a_mali_0_1_parent_names[] = { + IN_PREFIX "xtal", "gp0_pll", "hihi_pll", "fclk_div2p5", + "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7" +}; + +static struct clk_regmap g12a_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_mali_0_1_parent_names, + .num_parents = 8, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "mali_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mali_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_mali_0_1_parent_names, + .num_parents = 8, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "mali_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mali_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const char * const g12a_mali_parent_names[] = { + "mali_0", "mali_1" +}; + +static struct clk_regmap g12a_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_names = g12a_mali_parent_names, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* Everything Else (EE) domain gates */ +static MESON_GATE(g12a_ddr, HHI_GCLK_MPEG0, 0); +static MESON_GATE(g12a_dos, HHI_GCLK_MPEG0, 1); +static MESON_GATE(g12a_audio_locker, HHI_GCLK_MPEG0, 2); +static MESON_GATE(g12a_mipi_dsi_host, HHI_GCLK_MPEG0, 3); +static MESON_GATE(g12a_eth_phy, HHI_GCLK_MPEG0, 4); +static MESON_GATE(g12a_isa, HHI_GCLK_MPEG0, 5); +static MESON_GATE(g12a_pl301, HHI_GCLK_MPEG0, 6); +static MESON_GATE(g12a_periphs, HHI_GCLK_MPEG0, 7); +static MESON_GATE(g12a_spicc_0, HHI_GCLK_MPEG0, 8); +static MESON_GATE(g12a_i2c, HHI_GCLK_MPEG0, 9); +static MESON_GATE(g12a_sana, HHI_GCLK_MPEG0, 10); +static MESON_GATE(g12a_sd, HHI_GCLK_MPEG0, 11); +static MESON_GATE(g12a_rng0, HHI_GCLK_MPEG0, 12); +static MESON_GATE(g12a_uart0, HHI_GCLK_MPEG0, 13); +static MESON_GATE(g12a_spicc_1, HHI_GCLK_MPEG0, 14); +static MESON_GATE(g12a_hiu_reg, HHI_GCLK_MPEG0, 19); +static MESON_GATE(g12a_mipi_dsi_phy, HHI_GCLK_MPEG0, 20); +static MESON_GATE(g12a_assist_misc, HHI_GCLK_MPEG0, 23); +static MESON_GATE(g12a_emmc_a, HHI_GCLK_MPEG0, 4); +static MESON_GATE(g12a_emmc_b, HHI_GCLK_MPEG0, 25); +static MESON_GATE(g12a_emmc_c, HHI_GCLK_MPEG0, 26); +static MESON_GATE(g12a_audio_codec, HHI_GCLK_MPEG0, 28); + +static MESON_GATE(g12a_audio, HHI_GCLK_MPEG1, 0); +static MESON_GATE(g12a_eth_core, HHI_GCLK_MPEG1, 3); +static MESON_GATE(g12a_demux, HHI_GCLK_MPEG1, 4); +static MESON_GATE(g12a_audio_ififo, HHI_GCLK_MPEG1, 11); +static MESON_GATE(g12a_adc, HHI_GCLK_MPEG1, 13); +static MESON_GATE(g12a_uart1, HHI_GCLK_MPEG1, 16); +static MESON_GATE(g12a_g2d, HHI_GCLK_MPEG1, 20); +static MESON_GATE(g12a_reset, HHI_GCLK_MPEG1, 23); +static MESON_GATE(g12a_pcie_comb, HHI_GCLK_MPEG1, 24); +static MESON_GATE(g12a_parser, HHI_GCLK_MPEG1, 25); +static MESON_GATE(g12a_usb_general, HHI_GCLK_MPEG1, 26); +static MESON_GATE(g12a_pcie_phy, HHI_GCLK_MPEG1, 27); +static MESON_GATE(g12a_ahb_arb0, HHI_GCLK_MPEG1, 29); + +static MESON_GATE(g12a_ahb_data_bus, HHI_GCLK_MPEG2, 1); +static MESON_GATE(g12a_ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); +static MESON_GATE(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3); +static MESON_GATE(g12a_htx_pclk, HHI_GCLK_MPEG2, 4); +static MESON_GATE(g12a_bt656, HHI_GCLK_MPEG2, 6); +static MESON_GATE(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8); +static MESON_GATE(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11); +static MESON_GATE(g12a_uart2, HHI_GCLK_MPEG2, 15); +static MESON_GATE(g12a_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON_GATE(g12a_gic, HHI_GCLK_MPEG2, 30); + +static MESON_GATE(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1); +static MESON_GATE(g12a_vclk2_venci1, HHI_GCLK_OTHER, 2); +static MESON_GATE(g12a_vclk2_vencp0, HHI_GCLK_OTHER, 3); +static MESON_GATE(g12a_vclk2_vencp1, HHI_GCLK_OTHER, 4); +static MESON_GATE(g12a_vclk2_venct0, HHI_GCLK_OTHER, 5); +static MESON_GATE(g12a_vclk2_venct1, HHI_GCLK_OTHER, 6); +static MESON_GATE(g12a_vclk2_other, HHI_GCLK_OTHER, 7); +static MESON_GATE(g12a_vclk2_enci, HHI_GCLK_OTHER, 8); +static MESON_GATE(g12a_vclk2_encp, HHI_GCLK_OTHER, 9); +static MESON_GATE(g12a_dac_clk, HHI_GCLK_OTHER, 10); +static MESON_GATE(g12a_aoclk_gate, HHI_GCLK_OTHER, 14); +static MESON_GATE(g12a_iec958_gate, HHI_GCLK_OTHER, 16); +static MESON_GATE(g12a_enc480p, HHI_GCLK_OTHER, 20); +static MESON_GATE(g12a_rng1, HHI_GCLK_OTHER, 21); +static MESON_GATE(g12a_vclk2_enct, HHI_GCLK_OTHER, 22); +static MESON_GATE(g12a_vclk2_encl, HHI_GCLK_OTHER, 23); +static MESON_GATE(g12a_vclk2_venclmmc, HHI_GCLK_OTHER, 24); +static MESON_GATE(g12a_vclk2_vencl, HHI_GCLK_OTHER, 25); +static MESON_GATE(g12a_vclk2_other1, HHI_GCLK_OTHER, 26); + +static MESON_GATE_RO(g12a_dma, HHI_GCLK_OTHER2, 0); +static MESON_GATE_RO(g12a_efuse, HHI_GCLK_OTHER2, 1); +static MESON_GATE_RO(g12a_rom_boot, HHI_GCLK_OTHER2, 2); +static MESON_GATE_RO(g12a_reset_sec, HHI_GCLK_OTHER2, 3); +static MESON_GATE_RO(g12a_sec_ahb_apb3, HHI_GCLK_OTHER2, 4); + +/* Array of all clocks provided by this provider */ +static struct clk_hw_onecell_data g12a_hw_onecell_data = { + .hws = { + [CLKID_SYS_PLL] = &g12a_sys_pll.hw, + [CLKID_FIXED_PLL] = &g12a_fixed_pll.hw, + [CLKID_FCLK_DIV2] = &g12a_fclk_div2.hw, + [CLKID_FCLK_DIV3] = &g12a_fclk_div3.hw, + [CLKID_FCLK_DIV4] = &g12a_fclk_div4.hw, + [CLKID_FCLK_DIV5] = &g12a_fclk_div5.hw, + [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, + [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, + [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, + [CLKID_MPEG_SEL] = &g12a_mpeg_clk_sel.hw, + [CLKID_MPEG_DIV] = &g12a_mpeg_clk_div.hw, + [CLKID_CLK81] = &g12a_clk81.hw, + [CLKID_MPLL0] = &g12a_mpll0.hw, + [CLKID_MPLL1] = &g12a_mpll1.hw, + [CLKID_MPLL2] = &g12a_mpll2.hw, + [CLKID_MPLL3] = &g12a_mpll3.hw, + [CLKID_DDR] = &g12a_ddr.hw, + [CLKID_DOS] = &g12a_dos.hw, + [CLKID_AUDIO_LOCKER] = &g12a_audio_locker.hw, + [CLKID_MIPI_DSI_HOST] = &g12a_mipi_dsi_host.hw, + [CLKID_ETH_PHY] = &g12a_eth_phy.hw, + [CLKID_ISA] = &g12a_isa.hw, + [CLKID_PL301] = &g12a_pl301.hw, + [CLKID_PERIPHS] = &g12a_periphs.hw, + [CLKID_SPICC0] = &g12a_spicc_0.hw, + [CLKID_I2C] = &g12a_i2c.hw, + [CLKID_SANA] = &g12a_sana.hw, + [CLKID_SD] = &g12a_sd.hw, + [CLKID_RNG0] = &g12a_rng0.hw, + [CLKID_UART0] = &g12a_uart0.hw, + [CLKID_SPICC1] = &g12a_spicc_1.hw, + [CLKID_HIU_IFACE] = &g12a_hiu_reg.hw, + [CLKID_MIPI_DSI_PHY] = &g12a_mipi_dsi_phy.hw, + [CLKID_ASSIST_MISC] = &g12a_assist_misc.hw, + [CLKID_SD_EMMC_A] = &g12a_emmc_a.hw, + [CLKID_SD_EMMC_B] = &g12a_emmc_b.hw, + [CLKID_SD_EMMC_C] = &g12a_emmc_c.hw, + [CLKID_AUDIO_CODEC] = &g12a_audio_codec.hw, + [CLKID_AUDIO] = &g12a_audio.hw, + [CLKID_ETH] = &g12a_eth_core.hw, + [CLKID_DEMUX] = &g12a_demux.hw, + [CLKID_AUDIO_IFIFO] = &g12a_audio_ififo.hw, + [CLKID_ADC] = &g12a_adc.hw, + [CLKID_UART1] = &g12a_uart1.hw, + [CLKID_G2D] = &g12a_g2d.hw, + [CLKID_RESET] = &g12a_reset.hw, + [CLKID_PCIE_COMB] = &g12a_pcie_comb.hw, + [CLKID_PARSER] = &g12a_parser.hw, + [CLKID_USB] = &g12a_usb_general.hw, + [CLKID_PCIE_PHY] = &g12a_pcie_phy.hw, + [CLKID_AHB_ARB0] = &g12a_ahb_arb0.hw, + [CLKID_AHB_DATA_BUS] = &g12a_ahb_data_bus.hw, + [CLKID_AHB_CTRL_BUS] = &g12a_ahb_ctrl_bus.hw, + [CLKID_HTX_HDCP22] = &g12a_htx_hdcp22.hw, + [CLKID_HTX_PCLK] = &g12a_htx_pclk.hw, + [CLKID_BT656] = &g12a_bt656.hw, + [CLKID_USB1_DDR_BRIDGE] = &g12a_usb1_to_ddr.hw, + [CLKID_MMC_PCLK] = &g12a_mmc_pclk.hw, + [CLKID_UART2] = &g12a_uart2.hw, + [CLKID_VPU_INTR] = &g12a_vpu_intr.hw, + [CLKID_GIC] = &g12a_gic.hw, + [CLKID_SD_EMMC_A_CLK0_SEL] = &g12a_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK0_DIV] = &g12a_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A_CLK0] = &g12a_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK0_SEL] = &g12a_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK0_DIV] = &g12a_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B_CLK0] = &g12a_sd_emmc_b_clk0.hw, + [CLKID_SD_EMMC_C_CLK0_SEL] = &g12a_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK0_DIV] = &g12a_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C_CLK0] = &g12a_sd_emmc_c_clk0.hw, + [CLKID_MPLL0_DIV] = &g12a_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &g12a_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &g12a_mpll2_div.hw, + [CLKID_MPLL3_DIV] = &g12a_mpll3_div.hw, + [CLKID_FCLK_DIV2_DIV] = &g12a_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &g12a_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &g12a_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &g12a_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &g12a_fclk_div7_div.hw, + [CLKID_FCLK_DIV2P5_DIV] = &g12a_fclk_div2p5_div.hw, + [CLKID_HIFI_PLL] = &g12a_hifi_pll.hw, + [CLKID_VCLK2_VENCI0] = &g12a_vclk2_venci0.hw, + [CLKID_VCLK2_VENCI1] = &g12a_vclk2_venci1.hw, + [CLKID_VCLK2_VENCP0] = &g12a_vclk2_vencp0.hw, + [CLKID_VCLK2_VENCP1] = &g12a_vclk2_vencp1.hw, + [CLKID_VCLK2_VENCT0] = &g12a_vclk2_venct0.hw, + [CLKID_VCLK2_VENCT1] = &g12a_vclk2_venct1.hw, + [CLKID_VCLK2_OTHER] = &g12a_vclk2_other.hw, + [CLKID_VCLK2_ENCI] = &g12a_vclk2_enci.hw, + [CLKID_VCLK2_ENCP] = &g12a_vclk2_encp.hw, + [CLKID_DAC_CLK] = &g12a_dac_clk.hw, + [CLKID_AOCLK] = &g12a_aoclk_gate.hw, + [CLKID_IEC958] = &g12a_iec958_gate.hw, + [CLKID_ENC480P] = &g12a_enc480p.hw, + [CLKID_RNG1] = &g12a_rng1.hw, + [CLKID_VCLK2_ENCT] = &g12a_vclk2_enct.hw, + [CLKID_VCLK2_ENCL] = &g12a_vclk2_encl.hw, + [CLKID_VCLK2_VENCLMMC] = &g12a_vclk2_venclmmc.hw, + [CLKID_VCLK2_VENCL] = &g12a_vclk2_vencl.hw, + [CLKID_VCLK2_OTHER1] = &g12a_vclk2_other1.hw, + [CLKID_FIXED_PLL_DCO] = &g12a_fixed_pll_dco.hw, + [CLKID_SYS_PLL_DCO] = &g12a_sys_pll_dco.hw, + [CLKID_GP0_PLL_DCO] = &g12a_gp0_pll_dco.hw, + [CLKID_HIFI_PLL_DCO] = &g12a_hifi_pll_dco.hw, + [CLKID_DMA] = &g12a_dma.hw, + [CLKID_EFUSE] = &g12a_efuse.hw, + [CLKID_ROM_BOOT] = &g12a_rom_boot.hw, + [CLKID_RESET_SEC] = &g12a_reset_sec.hw, + [CLKID_SEC_AHB_APB3] = &g12a_sec_ahb_apb3.hw, + [CLKID_MPLL_PREDIV] = &g12a_mpll_prediv.hw, + [CLKID_VPU_0_SEL] = &g12a_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &g12a_vpu_0_div.hw, + [CLKID_VPU_0] = &g12a_vpu_0.hw, + [CLKID_VPU_1_SEL] = &g12a_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &g12a_vpu_1_div.hw, + [CLKID_VPU_1] = &g12a_vpu_1.hw, + [CLKID_VPU] = &g12a_vpu.hw, + [CLKID_VAPB_0_SEL] = &g12a_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &g12a_vapb_0_div.hw, + [CLKID_VAPB_0] = &g12a_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &g12a_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &g12a_vapb_1_div.hw, + [CLKID_VAPB_1] = &g12a_vapb_1.hw, + [CLKID_VAPB_SEL] = &g12a_vapb_sel.hw, + [CLKID_VAPB] = &g12a_vapb.hw, + [CLKID_HDMI_PLL_DCO] = &g12a_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &g12a_hdmi_pll_od.hw, + [CLKID_HDMI_PLL_OD2] = &g12a_hdmi_pll_od2.hw, + [CLKID_HDMI_PLL] = &g12a_hdmi_pll.hw, + [CLKID_VID_PLL] = &g12a_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &g12a_vid_pll_sel.hw, + [CLKID_VID_PLL_DIV] = &g12a_vid_pll.hw, + [CLKID_VCLK_SEL] = &g12a_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &g12a_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &g12a_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &g12a_vclk2_input.hw, + [CLKID_VCLK_DIV] = &g12a_vclk_div.hw, + [CLKID_VCLK2_DIV] = &g12a_vclk2_div.hw, + [CLKID_VCLK] = &g12a_vclk.hw, + [CLKID_VCLK2] = &g12a_vclk2.hw, + [CLKID_VCLK_DIV1] = &g12a_vclk_div1.hw, + [CLKID_VCLK_DIV2_EN] = &g12a_vclk_div2_en.hw, + [CLKID_VCLK_DIV4_EN] = &g12a_vclk_div4_en.hw, + [CLKID_VCLK_DIV6_EN] = &g12a_vclk_div6_en.hw, + [CLKID_VCLK_DIV12_EN] = &g12a_vclk_div12_en.hw, + [CLKID_VCLK2_DIV1] = &g12a_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_EN] = &g12a_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV4_EN] = &g12a_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV6_EN] = &g12a_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV12_EN] = &g12a_vclk2_div12_en.hw, + [CLKID_VCLK_DIV2] = &g12a_vclk_div2.hw, + [CLKID_VCLK_DIV4] = &g12a_vclk_div4.hw, + [CLKID_VCLK_DIV6] = &g12a_vclk_div6.hw, + [CLKID_VCLK_DIV12] = &g12a_vclk_div12.hw, + [CLKID_VCLK2_DIV2] = &g12a_vclk2_div2.hw, + [CLKID_VCLK2_DIV4] = &g12a_vclk2_div4.hw, + [CLKID_VCLK2_DIV6] = &g12a_vclk2_div6.hw, + [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, + [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, + [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, + [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, + [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, + [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, + [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, + [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, + [CLKID_HDMI_DIV] = &g12a_hdmi_div.hw, + [CLKID_HDMI] = &g12a_hdmi.hw, + [CLKID_MALI_0_SEL] = &g12a_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &g12a_mali_0_div.hw, + [CLKID_MALI_0] = &g12a_mali_0.hw, + [CLKID_MALI_1_SEL] = &g12a_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, + [CLKID_MALI_1] = &g12a_mali_1.hw, + [CLKID_MALI] = &g12a_mali.hw, + [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw, + [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, +}; + +/* Convenience table to populate regmap in .probe */ +static struct clk_regmap *const g12a_clk_regmaps[] = { + &g12a_clk81, + &g12a_dos, + &g12a_ddr, + &g12a_audio_locker, + &g12a_mipi_dsi_host, + &g12a_eth_phy, + &g12a_isa, + &g12a_pl301, + &g12a_periphs, + &g12a_spicc_0, + &g12a_i2c, + &g12a_sana, + &g12a_sd, + &g12a_rng0, + &g12a_uart0, + &g12a_spicc_1, + &g12a_hiu_reg, + &g12a_mipi_dsi_phy, + &g12a_assist_misc, + &g12a_emmc_a, + &g12a_emmc_b, + &g12a_emmc_c, + &g12a_audio_codec, + &g12a_audio, + &g12a_eth_core, + &g12a_demux, + &g12a_audio_ififo, + &g12a_adc, + &g12a_uart1, + &g12a_g2d, + &g12a_reset, + &g12a_pcie_comb, + &g12a_parser, + &g12a_usb_general, + &g12a_pcie_phy, + &g12a_ahb_arb0, + &g12a_ahb_data_bus, + &g12a_ahb_ctrl_bus, + &g12a_htx_hdcp22, + &g12a_htx_pclk, + &g12a_bt656, + &g12a_usb1_to_ddr, + &g12a_mmc_pclk, + &g12a_vpu_intr, + &g12a_gic, + &g12a_sd_emmc_a_clk0, + &g12a_sd_emmc_b_clk0, + &g12a_sd_emmc_c_clk0, + &g12a_mpeg_clk_div, + &g12a_sd_emmc_a_clk0_div, + &g12a_sd_emmc_b_clk0_div, + &g12a_sd_emmc_c_clk0_div, + &g12a_mpeg_clk_sel, + &g12a_sd_emmc_a_clk0_sel, + &g12a_sd_emmc_b_clk0_sel, + &g12a_sd_emmc_c_clk0_sel, + &g12a_mpll0, + &g12a_mpll1, + &g12a_mpll2, + &g12a_mpll3, + &g12a_mpll0_div, + &g12a_mpll1_div, + &g12a_mpll2_div, + &g12a_mpll3_div, + &g12a_fixed_pll, + &g12a_sys_pll, + &g12a_gp0_pll, + &g12a_hifi_pll, + &g12a_vclk2_venci0, + &g12a_vclk2_venci1, + &g12a_vclk2_vencp0, + &g12a_vclk2_vencp1, + &g12a_vclk2_venct0, + &g12a_vclk2_venct1, + &g12a_vclk2_other, + &g12a_vclk2_enci, + &g12a_vclk2_encp, + &g12a_dac_clk, + &g12a_aoclk_gate, + &g12a_iec958_gate, + &g12a_enc480p, + &g12a_rng1, + &g12a_vclk2_enct, + &g12a_vclk2_encl, + &g12a_vclk2_venclmmc, + &g12a_vclk2_vencl, + &g12a_vclk2_other1, + &g12a_fixed_pll_dco, + &g12a_sys_pll_dco, + &g12a_gp0_pll_dco, + &g12a_hifi_pll_dco, + &g12a_fclk_div2, + &g12a_fclk_div3, + &g12a_fclk_div4, + &g12a_fclk_div5, + &g12a_fclk_div7, + &g12a_fclk_div2p5, + &g12a_dma, + &g12a_efuse, + &g12a_rom_boot, + &g12a_reset_sec, + &g12a_sec_ahb_apb3, + &g12a_vpu_0_sel, + &g12a_vpu_0_div, + &g12a_vpu_0, + &g12a_vpu_1_sel, + &g12a_vpu_1_div, + &g12a_vpu_1, + &g12a_vpu, + &g12a_vapb_0_sel, + &g12a_vapb_0_div, + &g12a_vapb_0, + &g12a_vapb_1_sel, + &g12a_vapb_1_div, + &g12a_vapb_1, + &g12a_vapb_sel, + &g12a_vapb, + &g12a_hdmi_pll_dco, + &g12a_hdmi_pll_od, + &g12a_hdmi_pll_od2, + &g12a_hdmi_pll, + &g12a_vid_pll_div, + &g12a_vid_pll_sel, + &g12a_vid_pll, + &g12a_vclk_sel, + &g12a_vclk2_sel, + &g12a_vclk_input, + &g12a_vclk2_input, + &g12a_vclk_div, + &g12a_vclk2_div, + &g12a_vclk, + &g12a_vclk2, + &g12a_vclk_div1, + &g12a_vclk_div2_en, + &g12a_vclk_div4_en, + &g12a_vclk_div6_en, + &g12a_vclk_div12_en, + &g12a_vclk2_div1, + &g12a_vclk2_div2_en, + &g12a_vclk2_div4_en, + &g12a_vclk2_div6_en, + &g12a_vclk2_div12_en, + &g12a_cts_enci_sel, + &g12a_cts_encp_sel, + &g12a_cts_vdac_sel, + &g12a_hdmi_tx_sel, + &g12a_cts_enci, + &g12a_cts_encp, + &g12a_cts_vdac, + &g12a_hdmi_tx, + &g12a_hdmi_sel, + &g12a_hdmi_div, + &g12a_hdmi, + &g12a_mali_0_sel, + &g12a_mali_0_div, + &g12a_mali_0, + &g12a_mali_1_sel, + &g12a_mali_1_div, + &g12a_mali_1, + &g12a_mali, + &g12a_mpll_50m, +}; + +static const struct of_device_id clkc_match_table[] = { + { .compatible = "amlogic,g12a-clkc" }, + {} +}; + +static int g12a_clkc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct clk_hw *input; + struct regmap *map; + int ret, i; + + /* Get the hhi system controller node */ + map = syscon_node_to_regmap(of_get_parent(dev->of_node)); + if (IS_ERR(map)) { + dev_err(dev, + "failed to get HHI regmap\n"); + return PTR_ERR(map); + } + + input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); + if (IS_ERR(input)) { + ret = PTR_ERR(input); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get input clock"); + return ret; + } + + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(g12a_clk_regmaps); i++) + g12a_clk_regmaps[i]->map = map; + + for (i = 0; i < g12a_hw_onecell_data.num; i++) { + /* array might be sparse */ + if (!g12a_hw_onecell_data.hws[i]) + continue; + + ret = devm_clk_hw_register(dev, g12a_hw_onecell_data.hws[i]); + if (ret) { + dev_err(dev, "Clock registration failed\n"); + return ret; + } + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &g12a_hw_onecell_data); +} + +static struct platform_driver g12a_driver = { + .probe = g12a_clkc_probe, + .driver = { + .name = "g12a-clkc", + .of_match_table = clkc_match_table, + }, +}; + +builtin_platform_driver(g12a_driver); diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h new file mode 100644 index 000000000000..f399dfe1401c --- /dev/null +++ b/drivers/clk/meson/g12a.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2016 Amlogic, Inc. + * Author: Michael Turquette + * + * Copyright (c) 2018 Amlogic, inc. + * Author: Qiufang Dai + * Author: Jian Hu + * + */ +#ifndef __G12A_H +#define __G12A_H + +/* + * Clock controller register offsets + * + * Register offsets from the data sheet must be multiplied by 4 before + * adding them to the base address to get the right value. + */ +#define HHI_MIPI_CNTL0 0x000 +#define HHI_MIPI_CNTL1 0x004 +#define HHI_MIPI_CNTL2 0x008 +#define HHI_MIPI_STS 0x00C +#define HHI_GP0_PLL_CNTL0 0x040 +#define HHI_GP0_PLL_CNTL1 0x044 +#define HHI_GP0_PLL_CNTL2 0x048 +#define HHI_GP0_PLL_CNTL3 0x04C +#define HHI_GP0_PLL_CNTL4 0x050 +#define HHI_GP0_PLL_CNTL5 0x054 +#define HHI_GP0_PLL_CNTL6 0x058 +#define HHI_GP0_PLL_STS 0x05C +#define HHI_PCIE_PLL_CNTL0 0x098 +#define HHI_PCIE_PLL_CNTL1 0x09C +#define HHI_PCIE_PLL_CNTL2 0x0A0 +#define HHI_PCIE_PLL_CNTL3 0x0A4 +#define HHI_PCIE_PLL_CNTL4 0x0A8 +#define HHI_PCIE_PLL_CNTL5 0x0AC +#define HHI_PCIE_PLL_STS 0x0B8 +#define HHI_HIFI_PLL_CNTL0 0x0D8 +#define HHI_HIFI_PLL_CNTL1 0x0DC +#define HHI_HIFI_PLL_CNTL2 0x0E0 +#define HHI_HIFI_PLL_CNTL3 0x0E4 +#define HHI_HIFI_PLL_CNTL4 0x0E8 +#define HHI_HIFI_PLL_CNTL5 0x0EC +#define HHI_HIFI_PLL_CNTL6 0x0F0 +#define HHI_VIID_CLK_DIV 0x128 +#define HHI_VIID_CLK_CNTL 0x12C +#define HHI_GCLK_MPEG0 0x140 +#define HHI_GCLK_MPEG1 0x144 +#define HHI_GCLK_MPEG2 0x148 +#define HHI_GCLK_OTHER 0x150 +#define HHI_GCLK_OTHER2 0x154 +#define HHI_VID_CLK_DIV 0x164 +#define HHI_MPEG_CLK_CNTL 0x174 +#define HHI_AUD_CLK_CNTL 0x178 +#define HHI_VID_CLK_CNTL 0x17c +#define HHI_TS_CLK_CNTL 0x190 +#define HHI_VID_CLK_CNTL2 0x194 +#define HHI_SYS_CPU_CLK_CNTL0 0x19c +#define HHI_VID_PLL_CLK_DIV 0x1A0 +#define HHI_MALI_CLK_CNTL 0x1b0 +#define HHI_VPU_CLKC_CNTL 0x1b4 +#define HHI_VPU_CLK_CNTL 0x1bC +#define HHI_HDMI_CLK_CNTL 0x1CC +#define HHI_VDEC_CLK_CNTL 0x1E0 +#define HHI_VDEC2_CLK_CNTL 0x1E4 +#define HHI_VDEC3_CLK_CNTL 0x1E8 +#define HHI_VDEC4_CLK_CNTL 0x1EC +#define HHI_HDCP22_CLK_CNTL 0x1F0 +#define HHI_VAPBCLK_CNTL 0x1F4 +#define HHI_VPU_CLKB_CNTL 0x20C +#define HHI_GEN_CLK_CNTL 0x228 +#define HHI_VDIN_MEAS_CLK_CNTL 0x250 +#define HHI_MIPIDSI_PHY_CLK_CNTL 0x254 +#define HHI_NAND_CLK_CNTL 0x25C +#define HHI_SD_EMMC_CLK_CNTL 0x264 +#define HHI_MPLL_CNTL0 0x278 +#define HHI_MPLL_CNTL1 0x27C +#define HHI_MPLL_CNTL2 0x280 +#define HHI_MPLL_CNTL3 0x284 +#define HHI_MPLL_CNTL4 0x288 +#define HHI_MPLL_CNTL5 0x28c +#define HHI_MPLL_CNTL6 0x290 +#define HHI_MPLL_CNTL7 0x294 +#define HHI_MPLL_CNTL8 0x298 +#define HHI_FIX_PLL_CNTL0 0x2A0 +#define HHI_FIX_PLL_CNTL1 0x2A4 +#define HHI_FIX_PLL_CNTL3 0x2AC +#define HHI_SYS_PLL_CNTL0 0x2f4 +#define HHI_SYS_PLL_CNTL1 0x2f8 +#define HHI_SYS_PLL_CNTL2 0x2fc +#define HHI_SYS_PLL_CNTL3 0x300 +#define HHI_SYS_PLL_CNTL4 0x304 +#define HHI_SYS_PLL_CNTL5 0x308 +#define HHI_SYS_PLL_CNTL6 0x30c +#define HHI_HDMI_PLL_CNTL0 0x320 +#define HHI_HDMI_PLL_CNTL1 0x324 +#define HHI_HDMI_PLL_CNTL2 0x328 +#define HHI_HDMI_PLL_CNTL3 0x32c +#define HHI_HDMI_PLL_CNTL4 0x330 +#define HHI_HDMI_PLL_CNTL5 0x334 +#define HHI_HDMI_PLL_CNTL6 0x338 +#define HHI_SPICC_CLK_CNTL 0x3dc + +/* + * CLKID index values + * + * These indices are entirely contrived and do not map onto the hardware. + * It has now been decided to expose everything by default in the DT header: + * include/dt-bindings/clock/g12a-clkc.h. Only the clocks ids we don't want + * to expose, such as the internal muxes and dividers of composite clocks, + * will remain defined here. + */ +#define CLKID_MPEG_SEL 8 +#define CLKID_MPEG_DIV 9 +#define CLKID_SD_EMMC_A_CLK0_SEL 63 +#define CLKID_SD_EMMC_A_CLK0_DIV 64 +#define CLKID_SD_EMMC_B_CLK0_SEL 65 +#define CLKID_SD_EMMC_B_CLK0_DIV 66 +#define CLKID_SD_EMMC_C_CLK0_SEL 67 +#define CLKID_SD_EMMC_C_CLK0_DIV 68 +#define CLKID_MPLL0_DIV 69 +#define CLKID_MPLL1_DIV 70 +#define CLKID_MPLL2_DIV 71 +#define CLKID_MPLL3_DIV 72 +#define CLKID_MPLL_PREDIV 73 +#define CLKID_FCLK_DIV2_DIV 75 +#define CLKID_FCLK_DIV3_DIV 76 +#define CLKID_FCLK_DIV4_DIV 77 +#define CLKID_FCLK_DIV5_DIV 78 +#define CLKID_FCLK_DIV7_DIV 79 +#define CLKID_FCLK_DIV2P5_DIV 100 +#define CLKID_FIXED_PLL_DCO 101 +#define CLKID_SYS_PLL_DCO 102 +#define CLKID_GP0_PLL_DCO 103 +#define CLKID_HIFI_PLL_DCO 104 +#define CLKID_VPU_0_DIV 111 +#define CLKID_VPU_1_DIV 114 +#define CLKID_VAPB_0_DIV 118 +#define CLKID_VAPB_1_DIV 121 +#define CLKID_HDMI_PLL_DCO 125 +#define CLKID_HDMI_PLL_OD 126 +#define CLKID_HDMI_PLL_OD2 127 +#define CLKID_VID_PLL_SEL 130 +#define CLKID_VID_PLL_DIV 131 +#define CLKID_VCLK_SEL 132 +#define CLKID_VCLK2_SEL 133 +#define CLKID_VCLK_INPUT 134 +#define CLKID_VCLK2_INPUT 135 +#define CLKID_VCLK_DIV 136 +#define CLKID_VCLK2_DIV 137 +#define CLKID_VCLK_DIV2_EN 140 +#define CLKID_VCLK_DIV4_EN 141 +#define CLKID_VCLK_DIV6_EN 142 +#define CLKID_VCLK_DIV12_EN 143 +#define CLKID_VCLK2_DIV2_EN 144 +#define CLKID_VCLK2_DIV4_EN 145 +#define CLKID_VCLK2_DIV6_EN 146 +#define CLKID_VCLK2_DIV12_EN 147 +#define CLKID_CTS_ENCI_SEL 158 +#define CLKID_CTS_ENCP_SEL 159 +#define CLKID_CTS_VDAC_SEL 160 +#define CLKID_HDMI_TX_SEL 161 +#define CLKID_HDMI_SEL 166 +#define CLKID_HDMI_DIV 167 +#define CLKID_MALI_0_DIV 170 +#define CLKID_MALI_1_DIV 173 +#define CLKID_MPLL_5OM_DIV 176 + +#define NR_CLKS 178 + +/* include the CLKIDs that have been made part of the DT binding */ +#include + +#endif /* __G12A_H */ -- cgit v1.2.3 From 6682bd4d443fad802e11a0a39332025cdfbf5108 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 1 Feb 2019 15:53:45 +0100 Subject: clk: meson: factorise meson64 peripheral clock controller drivers The function used to probe the peripheral clock controller of the arm64 amlogic SoCs is mostly the same. We now have 3 of those controllers so it is time to factorize things a bit. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lkml.kernel.org/r/20190201145345.6795-5-jbrunet@baylibre.com --- drivers/clk/meson/Kconfig | 11 +- drivers/clk/meson/Makefile | 1 + drivers/clk/meson/axg.c | 59 ++------- drivers/clk/meson/g12a.c | 58 ++------- drivers/clk/meson/gxbb.c | 272 +++++++++++++++++++++++++++++----------- drivers/clk/meson/meson-eeclk.c | 63 ++++++++++ drivers/clk/meson/meson-eeclk.h | 25 ++++ 7 files changed, 313 insertions(+), 176 deletions(-) create mode 100644 drivers/clk/meson/meson-eeclk.c create mode 100644 drivers/clk/meson/meson-eeclk.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 4f61dd71f26d..b72439315340 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -35,6 +35,11 @@ config COMMON_CLK_MESON_AO_CLKC select COMMON_CLK_MESON_INPUT select RESET_CONTROLLER +config COMMON_CLK_MESON_EE_CLKC + tristate + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_INPUT + config COMMON_CLK_MESON8B bool depends on ARCH_MESON @@ -51,13 +56,13 @@ config COMMON_CLK_MESON8B config COMMON_CLK_GXBB bool depends on ARCH_MESON - select COMMON_CLK_MESON_INPUT select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_VID_PLL_DIV select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL select COMMON_CLK_MESON_AO_CLKC + select COMMON_CLK_MESON_EE_CLKC select MFD_SYSCON help Support for the clock controller on AmLogic S905 devices, aka gxbb. @@ -66,12 +71,12 @@ config COMMON_CLK_GXBB config COMMON_CLK_AXG bool depends on ARCH_MESON - select COMMON_CLK_MESON_INPUT select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL select COMMON_CLK_MESON_AO_CLKC + select COMMON_CLK_MESON_EE_CLKC select MFD_SYSCON help Support for the clock controller on AmLogic A113D devices, aka axg. @@ -92,10 +97,10 @@ config COMMON_CLK_AXG_AUDIO config COMMON_CLK_G12A bool depends on ARCH_MESON - select COMMON_CLK_MESON_INPUT select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_EE_CLKC select MFD_SYSCON help Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index c3dd3901afe3..32d17f18541e 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o +obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o obj-$(CONFIG_COMMON_CLK_MESON_INPUT) += clk-input.o obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index cbbdd93b175d..7a8ef80e5f2c 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -9,21 +9,17 @@ * Author: Qiufang Dai */ -#include #include #include #include -#include #include -#include #include "clk-input.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-mpll.h" #include "axg.h" - -#define IN_PREFIX "ee-in-" +#include "meson-eeclk.h" static DEFINE_SPINLOCK(meson_clk_lock); @@ -1260,55 +1256,20 @@ static struct clk_regmap *const axg_clk_regmaps[] = { &axg_pcie_pll_od, }; +static const struct meson_eeclkc_data axg_clkc_data = { + .regmap_clks = axg_clk_regmaps, + .regmap_clk_num = ARRAY_SIZE(axg_clk_regmaps), + .hw_onecell_data = &axg_hw_onecell_data, +}; + + static const struct of_device_id clkc_match_table[] = { - { .compatible = "amlogic,axg-clkc" }, + { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, {} }; -static int axg_clkc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct clk_hw *input; - struct regmap *map; - int ret, i; - - /* Get the hhi system controller node if available */ - map = syscon_node_to_regmap(of_get_parent(dev->of_node)); - if (IS_ERR(map)) { - dev_err(dev, "failed to get HHI regmap\n"); - return PTR_ERR(map); - } - - input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); - if (IS_ERR(input)) { - ret = PTR_ERR(input); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get input clock"); - return ret; - } - - /* Populate regmap for the regmap backed clocks */ - for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) - axg_clk_regmaps[i]->map = map; - - for (i = 0; i < axg_hw_onecell_data.num; i++) { - /* array might be sparse */ - if (!axg_hw_onecell_data.hws[i]) - continue; - - ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]); - if (ret) { - dev_err(dev, "Clock registration failed\n"); - return ret; - } - } - - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, - &axg_hw_onecell_data); -} - static struct platform_driver axg_driver = { - .probe = axg_clkc_probe, + .probe = meson_eeclkc_probe, .driver = { .name = "axg-clkc", .of_match_table = clkc_match_table, diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 4d9ec6026ef6..0e1ce8c03259 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -13,19 +13,16 @@ #include #include #include -#include #include -#include #include "clk-input.h" #include "clk-mpll.h" #include "clk-pll.h" #include "clk-regmap.h" #include "vid-pll-div.h" +#include "meson-eeclk.h" #include "g12a.h" -#define IN_PREFIX "ee-in-" - static DEFINE_SPINLOCK(meson_clk_lock); static struct clk_regmap g12a_fixed_pll_dco = { @@ -2340,56 +2337,19 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &g12a_mpll_50m, }; +static const struct meson_eeclkc_data g12a_clkc_data = { + .regmap_clks = g12a_clk_regmaps, + .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), + .hw_onecell_data = &g12a_hw_onecell_data +}; + static const struct of_device_id clkc_match_table[] = { - { .compatible = "amlogic,g12a-clkc" }, + { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data }, {} }; -static int g12a_clkc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct clk_hw *input; - struct regmap *map; - int ret, i; - - /* Get the hhi system controller node */ - map = syscon_node_to_regmap(of_get_parent(dev->of_node)); - if (IS_ERR(map)) { - dev_err(dev, - "failed to get HHI regmap\n"); - return PTR_ERR(map); - } - - input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); - if (IS_ERR(input)) { - ret = PTR_ERR(input); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get input clock"); - return ret; - } - - /* Populate regmap for the regmap backed clocks */ - for (i = 0; i < ARRAY_SIZE(g12a_clk_regmaps); i++) - g12a_clk_regmaps[i]->map = map; - - for (i = 0; i < g12a_hw_onecell_data.num; i++) { - /* array might be sparse */ - if (!g12a_hw_onecell_data.hws[i]) - continue; - - ret = devm_clk_hw_register(dev, g12a_hw_onecell_data.hws[i]); - if (ret) { - dev_err(dev, "Clock registration failed\n"); - return ret; - } - } - - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, - &g12a_hw_onecell_data); -} - static struct platform_driver g12a_driver = { - .probe = g12a_clkc_probe, + .probe = meson_eeclkc_probe, .driver = { .name = "g12a-clkc", .of_match_table = clkc_match_table, diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 3741db9a9fe1..04df2e208ed6 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -4,19 +4,17 @@ * Michael Turquette */ -#include #include #include #include -#include #include -#include #include "gxbb.h" #include "clk-input.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-mpll.h" +#include "meson-eeclk.h" #include "vid-pll-div.h" #define IN_PREFIX "ee-in-" @@ -2859,6 +2857,192 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { }; static struct clk_regmap *const gxbb_clk_regmaps[] = { + &gxbb_clk81, + &gxbb_ddr, + &gxbb_dos, + &gxbb_isa, + &gxbb_pl301, + &gxbb_periphs, + &gxbb_spicc, + &gxbb_i2c, + &gxbb_sar_adc, + &gxbb_smart_card, + &gxbb_rng0, + &gxbb_uart0, + &gxbb_sdhc, + &gxbb_stream, + &gxbb_async_fifo, + &gxbb_sdio, + &gxbb_abuf, + &gxbb_hiu_iface, + &gxbb_assist_misc, + &gxbb_spi, + &gxbb_i2s_spdif, + &gxbb_eth, + &gxbb_demux, + &gxbb_aiu_glue, + &gxbb_iec958, + &gxbb_i2s_out, + &gxbb_amclk, + &gxbb_aififo2, + &gxbb_mixer, + &gxbb_mixer_iface, + &gxbb_adc, + &gxbb_blkmv, + &gxbb_aiu, + &gxbb_uart1, + &gxbb_g2d, + &gxbb_usb0, + &gxbb_usb1, + &gxbb_reset, + &gxbb_nand, + &gxbb_dos_parser, + &gxbb_usb, + &gxbb_vdin1, + &gxbb_ahb_arb0, + &gxbb_efuse, + &gxbb_boot_rom, + &gxbb_ahb_data_bus, + &gxbb_ahb_ctrl_bus, + &gxbb_hdmi_intr_sync, + &gxbb_hdmi_pclk, + &gxbb_usb1_ddr_bridge, + &gxbb_usb0_ddr_bridge, + &gxbb_mmc_pclk, + &gxbb_dvin, + &gxbb_uart2, + &gxbb_sana, + &gxbb_vpu_intr, + &gxbb_sec_ahb_ahb3_bridge, + &gxbb_clk81_a53, + &gxbb_vclk2_venci0, + &gxbb_vclk2_venci1, + &gxbb_vclk2_vencp0, + &gxbb_vclk2_vencp1, + &gxbb_gclk_venci_int0, + &gxbb_gclk_vencp_int, + &gxbb_dac_clk, + &gxbb_aoclk_gate, + &gxbb_iec958_gate, + &gxbb_enc480p, + &gxbb_rng1, + &gxbb_gclk_venci_int1, + &gxbb_vclk2_venclmcc, + &gxbb_vclk2_vencl, + &gxbb_vclk_other, + &gxbb_edp, + &gxbb_ao_media_cpu, + &gxbb_ao_ahb_sram, + &gxbb_ao_ahb_bus, + &gxbb_ao_iface, + &gxbb_ao_i2c, + &gxbb_emmc_a, + &gxbb_emmc_b, + &gxbb_emmc_c, + &gxbb_sar_adc_clk, + &gxbb_mali_0, + &gxbb_mali_1, + &gxbb_cts_amclk, + &gxbb_cts_mclk_i958, + &gxbb_32k_clk, + &gxbb_sd_emmc_a_clk0, + &gxbb_sd_emmc_b_clk0, + &gxbb_sd_emmc_c_clk0, + &gxbb_vpu_0, + &gxbb_vpu_1, + &gxbb_vapb_0, + &gxbb_vapb_1, + &gxbb_vapb, + &gxbb_mpeg_clk_div, + &gxbb_sar_adc_clk_div, + &gxbb_mali_0_div, + &gxbb_mali_1_div, + &gxbb_cts_mclk_i958_div, + &gxbb_32k_clk_div, + &gxbb_sd_emmc_a_clk0_div, + &gxbb_sd_emmc_b_clk0_div, + &gxbb_sd_emmc_c_clk0_div, + &gxbb_vpu_0_div, + &gxbb_vpu_1_div, + &gxbb_vapb_0_div, + &gxbb_vapb_1_div, + &gxbb_mpeg_clk_sel, + &gxbb_sar_adc_clk_sel, + &gxbb_mali_0_sel, + &gxbb_mali_1_sel, + &gxbb_mali, + &gxbb_cts_amclk_sel, + &gxbb_cts_mclk_i958_sel, + &gxbb_cts_i958, + &gxbb_32k_clk_sel, + &gxbb_sd_emmc_a_clk0_sel, + &gxbb_sd_emmc_b_clk0_sel, + &gxbb_sd_emmc_c_clk0_sel, + &gxbb_vpu_0_sel, + &gxbb_vpu_1_sel, + &gxbb_vpu, + &gxbb_vapb_0_sel, + &gxbb_vapb_1_sel, + &gxbb_vapb_sel, + &gxbb_mpll0, + &gxbb_mpll1, + &gxbb_mpll2, + &gxbb_mpll0_div, + &gxbb_mpll1_div, + &gxbb_mpll2_div, + &gxbb_cts_amclk_div, + &gxbb_fixed_pll, + &gxbb_sys_pll, + &gxbb_mpll_prediv, + &gxbb_fclk_div2, + &gxbb_fclk_div3, + &gxbb_fclk_div4, + &gxbb_fclk_div5, + &gxbb_fclk_div7, + &gxbb_vdec_1_sel, + &gxbb_vdec_1_div, + &gxbb_vdec_1, + &gxbb_vdec_hevc_sel, + &gxbb_vdec_hevc_div, + &gxbb_vdec_hevc, + &gxbb_gen_clk_sel, + &gxbb_gen_clk_div, + &gxbb_gen_clk, + &gxbb_fixed_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, &gxbb_gp0_pll_dco, &gxbb_hdmi_pll, &gxbb_hdmi_pll_od, @@ -2867,14 +3051,6 @@ static struct clk_regmap *const gxbb_clk_regmaps[] = { }; static struct clk_regmap *const gxl_clk_regmaps[] = { - &gxl_gp0_pll_dco, - &gxl_hdmi_pll, - &gxl_hdmi_pll_od, - &gxl_hdmi_pll_od2, - &gxl_hdmi_pll_dco, -}; - -static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_clk81, &gxbb_ddr, &gxbb_dos, @@ -3061,23 +3237,22 @@ static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_hdmi_sel, &gxbb_hdmi_div, &gxbb_hdmi, + &gxl_gp0_pll_dco, + &gxl_hdmi_pll, + &gxl_hdmi_pll_od, + &gxl_hdmi_pll_od2, + &gxl_hdmi_pll_dco, }; -struct clkc_data { - struct clk_regmap *const *regmap_clks; - unsigned int regmap_clks_count; - struct clk_hw_onecell_data *hw_onecell_data; -}; - -static const struct clkc_data gxbb_clkc_data = { +static const struct meson_eeclkc_data gxbb_clkc_data = { .regmap_clks = gxbb_clk_regmaps, - .regmap_clks_count = ARRAY_SIZE(gxbb_clk_regmaps), + .regmap_clk_num = ARRAY_SIZE(gxbb_clk_regmaps), .hw_onecell_data = &gxbb_hw_onecell_data, }; -static const struct clkc_data gxl_clkc_data = { +static const struct meson_eeclkc_data gxl_clkc_data = { .regmap_clks = gxl_clk_regmaps, - .regmap_clks_count = ARRAY_SIZE(gxl_clk_regmaps), + .regmap_clk_num = ARRAY_SIZE(gxl_clk_regmaps), .hw_onecell_data = &gxl_hw_onecell_data, }; @@ -3087,61 +3262,8 @@ static const struct of_device_id clkc_match_table[] = { {}, }; -static int gxbb_clkc_probe(struct platform_device *pdev) -{ - const struct clkc_data *clkc_data; - struct clk_hw *input; - struct regmap *map; - int ret, i; - struct device *dev = &pdev->dev; - - clkc_data = of_device_get_match_data(dev); - if (!clkc_data) - return -EINVAL; - - /* Get the hhi system controller node if available */ - map = syscon_node_to_regmap(of_get_parent(dev->of_node)); - if (IS_ERR(map)) { - dev_err(dev, "failed to get HHI regmap\n"); - return PTR_ERR(map); - } - - input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); - if (IS_ERR(input)) { - ret = PTR_ERR(input); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get input clock"); - return ret; - } - - /* Populate regmap for the common regmap backed clocks */ - for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) - gx_clk_regmaps[i]->map = map; - - /* Populate regmap for soc specific clocks */ - for (i = 0; i < clkc_data->regmap_clks_count; i++) - clkc_data->regmap_clks[i]->map = map; - - /* Register all clks */ - for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { - /* array might be sparse */ - if (!clkc_data->hw_onecell_data->hws[i]) - continue; - - ret = devm_clk_hw_register(dev, - clkc_data->hw_onecell_data->hws[i]); - if (ret) { - dev_err(dev, "Clock registration failed\n"); - return ret; - } - } - - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, - clkc_data->hw_onecell_data); -} - static struct platform_driver gxbb_driver = { - .probe = gxbb_clkc_probe, + .probe = meson_eeclkc_probe, .driver = { .name = "gxbb-clkc", .of_match_table = clkc_match_table, diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c new file mode 100644 index 000000000000..37a34c9c3885 --- /dev/null +++ b/drivers/clk/meson/meson-eeclk.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include +#include +#include +#include + +#include "clk-input.h" +#include "clk-regmap.h" +#include "meson-eeclk.h" + +int meson_eeclkc_probe(struct platform_device *pdev) +{ + const struct meson_eeclkc_data *data; + struct device *dev = &pdev->dev; + struct clk_hw *input; + struct regmap *map; + int ret, i; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + /* Get the hhi system controller node */ + map = syscon_node_to_regmap(of_get_parent(dev->of_node)); + if (IS_ERR(map)) { + dev_err(dev, + "failed to get HHI regmap\n"); + return PTR_ERR(map); + } + + input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); + if (IS_ERR(input)) { + ret = PTR_ERR(input); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get input clock"); + return ret; + } + + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < data->regmap_clk_num; i++) + data->regmap_clks[i]->map = map; + + for (i = 0; i < data->hw_onecell_data->num; i++) { + /* array might be sparse */ + if (!data->hw_onecell_data->hws[i]) + continue; + + ret = devm_clk_hw_register(dev, data->hw_onecell_data->hws[i]); + if (ret) { + dev_err(dev, "Clock registration failed\n"); + return ret; + } + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + data->hw_onecell_data); +} diff --git a/drivers/clk/meson/meson-eeclk.h b/drivers/clk/meson/meson-eeclk.h new file mode 100644 index 000000000000..1b809b1419fe --- /dev/null +++ b/drivers/clk/meson/meson-eeclk.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLKC_H +#define __MESON_CLKC_H + +#include +#include "clk-regmap.h" + +#define IN_PREFIX "ee-in-" + +struct platform_device; + +struct meson_eeclkc_data { + struct clk_regmap *const *regmap_clks; + unsigned int regmap_clk_num; + struct clk_hw_onecell_data *hw_onecell_data; +}; + +int meson_eeclkc_probe(struct platform_device *pdev); + +#endif /* __MESON_CLKC_H */ -- cgit v1.2.3 From db4a0073cc82a95d8d1a9b05fde82355fcce77d8 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 22 Jan 2019 22:59:35 +0300 Subject: clk: renesas: rcar-gen3: Add RPC clocks The RPCSRC internal clock is controlled by the RPCCKCR.DIV[4:3] on all the R-Car gen3 SoCs except V3M (R8A77970) but the encoding of this field is different between SoCs; it makes sense to support the most common case of this encoding in the R-Car gen3 CPG driver... After adding the RPCSRC clock, we can add the RPC[D2] clocks derived from it and controlled by the RPCCKCR register on all the R-Car gen3 SoCs except V3M (R8A77970); the composite clock driver seems handy for this task, using the spinlock added in the previous patch... Signed-off-by: Sergei Shtylyov Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-gen3-cpg.c | 101 ++++++++++++++++++++++++++++++++++++ drivers/clk/renesas/rcar-gen3-cpg.h | 4 ++ 2 files changed, 105 insertions(+) diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 0818691253af..9a8071a8114d 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -422,6 +422,92 @@ free_clock: return clk; } +struct rpc_clock { + struct clk_divider div; + struct clk_gate gate; + /* + * One notifier covers both RPC and RPCD2 clocks as they are both + * controlled by the same RPCCKCR register... + */ + struct cpg_simple_notifier csn; +}; + +static const struct clk_div_table cpg_rpcsrc_div_table[] = { + { 2, 5 }, { 3, 6 }, { 0, 0 }, +}; + +static const struct clk_div_table cpg_rpc_div_table[] = { + { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 }, +}; + +static struct clk * __init cpg_rpc_clk_register(const char *name, + void __iomem *base, const char *parent_name, + struct raw_notifier_head *notifiers) +{ + struct rpc_clock *rpc; + struct clk *clk; + + rpc = kzalloc(sizeof(*rpc), GFP_KERNEL); + if (!rpc) + return ERR_PTR(-ENOMEM); + + rpc->div.reg = base + CPG_RPCCKCR; + rpc->div.width = 3; + rpc->div.table = cpg_rpc_div_table; + rpc->div.lock = &cpg_lock; + + rpc->gate.reg = base + CPG_RPCCKCR; + rpc->gate.bit_idx = 8; + rpc->gate.flags = CLK_GATE_SET_TO_DISABLE; + rpc->gate.lock = &cpg_lock; + + rpc->csn.reg = base + CPG_RPCCKCR; + + clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, + &rpc->div.hw, &clk_divider_ops, + &rpc->gate.hw, &clk_gate_ops, 0); + if (IS_ERR(clk)) { + kfree(rpc); + return clk; + } + + cpg_simple_notifier_register(notifiers, &rpc->csn); + return clk; +} + +struct rpcd2_clock { + struct clk_fixed_factor fixed; + struct clk_gate gate; +}; + +static struct clk * __init cpg_rpcd2_clk_register(const char *name, + void __iomem *base, + const char *parent_name) +{ + struct rpcd2_clock *rpcd2; + struct clk *clk; + + rpcd2 = kzalloc(sizeof(*rpcd2), GFP_KERNEL); + if (!rpcd2) + return ERR_PTR(-ENOMEM); + + rpcd2->fixed.mult = 1; + rpcd2->fixed.div = 2; + + rpcd2->gate.reg = base + CPG_RPCCKCR; + rpcd2->gate.bit_idx = 9; + rpcd2->gate.flags = CLK_GATE_SET_TO_DISABLE; + rpcd2->gate.lock = &cpg_lock; + + clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, + &rpcd2->fixed.hw, &clk_fixed_factor_ops, + &rpcd2->gate.hw, &clk_gate_ops, 0); + if (IS_ERR(clk)) + kfree(rpcd2); + + return clk; +} + static const struct rcar_gen3_cpg_pll_config *cpg_pll_config __initdata; static unsigned int cpg_clk_extalr __initdata; @@ -600,6 +686,21 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, } break; + case CLK_TYPE_GEN3_RPCSRC: + return clk_register_divider_table(NULL, core->name, + __clk_get_name(parent), 0, + base + CPG_RPCCKCR, 3, 2, 0, + cpg_rpcsrc_div_table, + &cpg_lock); + + case CLK_TYPE_GEN3_RPC: + return cpg_rpc_clk_register(core->name, base, + __clk_get_name(parent), notifiers); + + case CLK_TYPE_GEN3_RPCD2: + return cpg_rpcd2_clk_register(core->name, base, + __clk_get_name(parent)); + default: return ERR_PTR(-EINVAL); } diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index f4fb6cf16688..eac1b057455a 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -23,6 +23,9 @@ enum rcar_gen3_clk_types { CLK_TYPE_GEN3_Z2, CLK_TYPE_GEN3_OSC, /* OSC EXTAL predivider and fixed divider */ CLK_TYPE_GEN3_RCKSEL, /* Select parent/divider using RCKCR.CKSEL */ + CLK_TYPE_GEN3_RPCSRC, + CLK_TYPE_GEN3_RPC, + CLK_TYPE_GEN3_RPCD2, /* SoC specific definitions start here */ CLK_TYPE_GEN3_SOC_BASE, @@ -57,6 +60,7 @@ struct rcar_gen3_cpg_pll_config { u8 osc_prediv; }; +#define CPG_RPCCKCR 0x238 #define CPG_RCKCR 0x240 struct clk *rcar_gen3_cpg_clk_register(struct device *dev, -- cgit v1.2.3 From 94e3935b5756a790396b57c7a5116460db511b29 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 22 Jan 2019 23:01:07 +0300 Subject: clk: renesas: r8a77980: Add RPC clocks Describe the RPCSRC internal clock and the RPC[D2] clocks derived from it, as well as the RPC-IF module clock, in the R-Car V3H (R8A77980) CPG/MSSR driver. Signed-off-by: Sergei Shtylyov Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a77980-cpg-mssr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/renesas/r8a77980-cpg-mssr.c b/drivers/clk/renesas/r8a77980-cpg-mssr.c index 25a3083b6764..f9e07fcc0d96 100644 --- a/drivers/clk/renesas/r8a77980-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77980-cpg-mssr.c @@ -41,6 +41,7 @@ enum clk_ids { CLK_S2, CLK_S3, CLK_SDSRC, + CLK_RPCSRC, CLK_OCO, /* Module Clocks */ @@ -65,8 +66,14 @@ static const struct cpg_core_clk r8a77980_core_clks[] __initconst = { DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1), DEF_RATE(".oco", CLK_OCO, 32768), + DEF_BASE("rpc", R8A77980_CLK_RPC, CLK_TYPE_GEN3_RPC, + CLK_RPCSRC), + DEF_BASE("rpcd2", R8A77980_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2, + R8A77980_CLK_RPC), + /* Core Clock Outputs */ DEF_FIXED("ztr", R8A77980_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), DEF_FIXED("ztrd2", R8A77980_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), @@ -164,6 +171,7 @@ static const struct mssr_mod_clk r8a77980_mod_clks[] __initconst = { DEF_MOD("gpio1", 911, R8A77980_CLK_CP), DEF_MOD("gpio0", 912, R8A77980_CLK_CP), DEF_MOD("can-fd", 914, R8A77980_CLK_S3D2), + DEF_MOD("rpc-if", 917, R8A77980_CLK_RPC), DEF_MOD("i2c4", 927, R8A77980_CLK_S0D6), DEF_MOD("i2c3", 928, R8A77980_CLK_S0D6), DEF_MOD("i2c2", 929, R8A77980_CLK_S3D2), -- cgit v1.2.3 From d1de227de8145e661e940377e050286098197eeb Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 4 Feb 2019 09:20:05 +0000 Subject: clk: renesas: r8a774c0: Add TMU clock This patch adds the TMU clocks to the R8A774C0 SoC. Signed-off-by: Biju Das Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a774c0-cpg-mssr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c index 4f3111b3113e..aeadb4d66f3e 100644 --- a/drivers/clk/renesas/r8a774c0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774c0-cpg-mssr.c @@ -122,6 +122,11 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = { + DEF_MOD("tmu4", 121, R8A774C0_CLK_S0D6C), + DEF_MOD("tmu3", 122, R8A774C0_CLK_S3D2C), + DEF_MOD("tmu2", 123, R8A774C0_CLK_S3D2C), + DEF_MOD("tmu1", 124, R8A774C0_CLK_S3D2C), + DEF_MOD("tmu0", 125, R8A774C0_CLK_CP), DEF_MOD("scif5", 202, R8A774C0_CLK_S3D4C), DEF_MOD("scif4", 203, R8A774C0_CLK_S3D4C), DEF_MOD("scif3", 204, R8A774C0_CLK_S3D4C), -- cgit v1.2.3 From c3424f59a0cb994a098c3701bf14617580a18290 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Fri, 14 Dec 2018 10:04:16 +0800 Subject: dt-bindings: clock: add clock for MT2712 Add new clock according to 3rd ECO design change. It's the parent clock of audio clock mux. Signed-off-by: Weiyi Lu Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/mt2712-clk.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/mt2712-clk.h b/include/dt-bindings/clock/mt2712-clk.h index 76265836a1e1..c3b29dff9c0e 100644 --- a/include/dt-bindings/clock/mt2712-clk.h +++ b/include/dt-bindings/clock/mt2712-clk.h @@ -228,7 +228,8 @@ #define CLK_TOP_NFI2X_EN 189 #define CLK_TOP_NFIECC_EN 190 #define CLK_TOP_NFI1X_CK_EN 191 -#define CLK_TOP_NR_CLK 192 +#define CLK_TOP_APLL2_D3 192 +#define CLK_TOP_NR_CLK 193 /* INFRACFG */ -- cgit v1.2.3 From 51ff86dd1069a9ea52672efb20b89dbaff6dffe1 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Fri, 14 Dec 2018 10:04:17 +0800 Subject: clk: mediatek: update clock driver of MT2712 According to 3rd ECO design change, 1. Add new fixed factor clock of audio. 2. Add the parent clocks for audio clock mux. Signed-off-by: Weiyi Lu Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt2712.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c index 991d4093726e..e36f4aab634d 100644 --- a/drivers/clk/mediatek/clk-mt2712.c +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -223,6 +223,8 @@ static const struct mtk_fixed_factor top_divs[] = { 4), FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1_ck", 1, 3), + FACTOR(CLK_TOP_APLL2_D3, "apll2_d3", "apll2_ck", 1, + 3), }; static const char * const axi_parents[] = { @@ -594,7 +596,8 @@ static const char * const a1sys_hp_parents[] = { "apll1_ck", "apll1_d2", "apll1_d4", - "apll1_d8" + "apll1_d8", + "apll1_d3" }; static const char * const a2sys_hp_parents[] = { @@ -602,7 +605,8 @@ static const char * const a2sys_hp_parents[] = { "apll2_ck", "apll2_d2", "apll2_d4", - "apll2_d8" + "apll2_d8", + "apll2_d3" }; static const char * const asm_l_parents[] = { -- cgit v1.2.3 From b7e29924a1a628aec60d18651b493fa1601bf944 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 25 Jan 2019 12:34:36 -0300 Subject: clk: ingenic: jz4740: Fix gating of UDC clock The UDC clock is gated when the bit is cleared, not when it is set. Signed-off-by: Paul Cercueil Tested-by: Artur Rojek Fixes: 2b555a4b9cae ("clk: ingenic: Add missing flag for UDC clock") Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/jz4740-cgu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c index 4479c102e899..b86edd328249 100644 --- a/drivers/clk/ingenic/jz4740-cgu.c +++ b/drivers/clk/ingenic/jz4740-cgu.c @@ -165,7 +165,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, .mux = { CGU_REG_CPCCR, 29, 1 }, .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, - .gate = { CGU_REG_SCR, 6 }, + .gate = { CGU_REG_SCR, 6, true }, }, /* Gate-only clocks */ -- cgit v1.2.3 From 5c56dfe63b6e7da3d9fd84a6c553ff4d2753dd1c Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 3 Dec 2018 11:13:08 +0000 Subject: clk: Add comment about __of_clk_get_by_name() error values It's not immediately obvious from the code that failure to get a clock provider can return either -ENOENT or -EINVAL. Therefore, add a comment to highlight this. Signed-off-by: Phil Edworthy Reviewed-by: Andy Shevchenko Cc: Russell King [sboyd@kernel.org: Fix comment to be proper C with ==] Signed-off-by: Stephen Boyd --- drivers/clk/clkdev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 9ab3db8b3988..5284fd191cca 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -52,6 +52,12 @@ struct clk *of_clk_get(struct device_node *np, int index) } EXPORT_SYMBOL(of_clk_get); +/* + * Beware the return values when np is valid, but no clock provider is found. + * If name == NULL, the function returns -ENOENT. + * If name != NULL, the function returns -EINVAL. This is because __of_clk_get() + * is called even if of_property_match_string() returns an error. + */ static struct clk *__of_clk_get_by_name(struct device_node *np, const char *dev_id, const char *name) -- cgit v1.2.3 From 60b8f0ddf1a927ef02141a6610fd52575134f821 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 3 Dec 2018 11:13:09 +0000 Subject: clk: Add (devm_)clk_get_optional() functions This adds clk_get_optional() and devm_clk_get_optional() functions to get optional clocks. They behave the same as (devm_)clk_get() except where there is no clock producer. In this case, instead of returning -ENOENT, the function returns NULL. This makes error checking simpler and allows clk_prepare_enable, etc to be called on the returned reference without additional checks. Signed-off-by: Phil Edworthy Reviewed-by: Andy Shevchenko Cc: Russell King [sboyd@kernel.org: Document in devres.txt] Signed-off-by: Stephen Boyd --- Documentation/driver-model/devres.txt | 1 + drivers/clk/clk-devres.c | 11 +++++++++++ include/linux/clk.h | 36 +++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index b277cafce71e..83f38c0439cd 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -242,6 +242,7 @@ certainly invest a bit more effort into libata core layer). CLOCK devm_clk_get() + devm_clk_get_optional() devm_clk_put() devm_clk_hw_register() devm_of_clk_add_hw_provider() diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index c9a86156ced8..daa1fc8fba53 100644 --- a/drivers/clk/clk-devres.c +++ b/drivers/clk/clk-devres.c @@ -29,6 +29,17 @@ struct clk *devm_clk_get(struct device *dev, const char *id) } EXPORT_SYMBOL(devm_clk_get); +struct clk *devm_clk_get_optional(struct device *dev, const char *id) +{ + struct clk *clk = devm_clk_get(dev, id); + + if (clk == ERR_PTR(-ENOENT)) + return NULL; + + return clk; +} +EXPORT_SYMBOL(devm_clk_get_optional); + struct clk_bulk_devres { struct clk_bulk_data *clks; int num_clks; diff --git a/include/linux/clk.h b/include/linux/clk.h index a7773b5c0b9f..d8bc1a856b39 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -383,6 +383,17 @@ int __must_check devm_clk_bulk_get_all(struct device *dev, */ struct clk *devm_clk_get(struct device *dev, const char *id); +/** + * devm_clk_get_optional - lookup and obtain a managed reference to an optional + * clock producer. + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Behaves the same as devm_clk_get() except where there is no clock producer. + * In this case, instead of returning -ENOENT, the function returns NULL. + */ +struct clk *devm_clk_get_optional(struct device *dev, const char *id); + /** * devm_get_clk_from_child - lookup and obtain a managed reference to a * clock producer from child node. @@ -718,6 +729,12 @@ static inline struct clk *devm_clk_get(struct device *dev, const char *id) return NULL; } +static inline struct clk *devm_clk_get_optional(struct device *dev, + const char *id) +{ + return NULL; +} + static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { @@ -862,6 +879,25 @@ static inline void clk_bulk_disable_unprepare(int num_clks, clk_bulk_unprepare(num_clks, clks); } +/** + * clk_get_optional - lookup and obtain a reference to an optional clock + * producer. + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Behaves the same as clk_get() except where there is no clock producer. In + * this case, instead of returning -ENOENT, the function returns NULL. + */ +static inline struct clk *clk_get_optional(struct device *dev, const char *id) +{ + struct clk *clk = clk_get(dev, id); + + if (clk == ERR_PTR(-ENOENT)) + return NULL; + + return clk; +} + #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) struct clk *of_clk_get(struct device_node *np, int index); struct clk *of_clk_get_by_name(struct device_node *np, const char *name); -- cgit v1.2.3 From 3eee6c7d119cd8563ad25898f94d6c1b514da548 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Fri, 7 Dec 2018 13:09:39 +0200 Subject: clkdev: add managed clkdev lookup registration Clkdev registration lacks of managed registration functions and it seems few drivers do not drop clkdev lookups at exit. Add devm_clk_hw_register_clkdev and devm_clk_release_clkdev to ease lookup releasing at exit. Signed-off-by: Matti Vaittinen Signed-off-by: Stephen Boyd --- Documentation/driver-model/devres.txt | 1 + drivers/clk/clkdev.c | 111 +++++++++++++++++++++++++++------- include/linux/clkdev.h | 4 ++ 3 files changed, 93 insertions(+), 23 deletions(-) diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index b277cafce71e..805b7bf5d98f 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -245,6 +245,7 @@ CLOCK devm_clk_put() devm_clk_hw_register() devm_of_clk_add_hw_provider() + devm_clk_hw_register_clkdev() DMA dmaenginem_async_device_register() diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 9ab3db8b3988..4621f8a91fc0 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -401,6 +401,23 @@ static struct clk_lookup *__clk_register_clkdev(struct clk_hw *hw, return cl; } +static int do_clk_register_clkdev(struct clk_hw *hw, + struct clk_lookup **cl, const char *con_id, const char *dev_id) +{ + if (IS_ERR(hw)) + return PTR_ERR(hw); + /* + * Since dev_id can be NULL, and NULL is handled specially, we must + * pass it as either a NULL format string, or with "%s". + */ + if (dev_id) + *cl = __clk_register_clkdev(hw, con_id, "%s", dev_id); + else + *cl = __clk_register_clkdev(hw, con_id, NULL); + + return *cl ? 0 : -ENOMEM; +} + /** * clk_register_clkdev - register one clock lookup for a struct clk * @clk: struct clk to associate with all clk_lookups @@ -423,17 +440,8 @@ int clk_register_clkdev(struct clk *clk, const char *con_id, if (IS_ERR(clk)) return PTR_ERR(clk); - /* - * Since dev_id can be NULL, and NULL is handled specially, we must - * pass it as either a NULL format string, or with "%s". - */ - if (dev_id) - cl = __clk_register_clkdev(__clk_get_hw(clk), con_id, "%s", - dev_id); - else - cl = __clk_register_clkdev(__clk_get_hw(clk), con_id, NULL); - - return cl ? 0 : -ENOMEM; + return do_clk_register_clkdev(__clk_get_hw(clk), &cl, con_id, + dev_id); } EXPORT_SYMBOL(clk_register_clkdev); @@ -456,18 +464,75 @@ int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id, { struct clk_lookup *cl; - if (IS_ERR(hw)) - return PTR_ERR(hw); + return do_clk_register_clkdev(hw, &cl, con_id, dev_id); +} +EXPORT_SYMBOL(clk_hw_register_clkdev); - /* - * Since dev_id can be NULL, and NULL is handled specially, we must - * pass it as either a NULL format string, or with "%s". - */ - if (dev_id) - cl = __clk_register_clkdev(hw, con_id, "%s", dev_id); - else - cl = __clk_register_clkdev(hw, con_id, NULL); +static void devm_clkdev_release(struct device *dev, void *res) +{ + clkdev_drop(*(struct clk_lookup **)res); +} - return cl ? 0 : -ENOMEM; +static int devm_clk_match_clkdev(struct device *dev, void *res, void *data) +{ + struct clk_lookup **l = res; + + return *l == data; } -EXPORT_SYMBOL(clk_hw_register_clkdev); + +/** + * devm_clk_release_clkdev - Resource managed clkdev lookup release + * @dev: device this lookup is bound + * @con_id: connection ID string on device + * @dev_id: format string describing device name + * + * Drop the clkdev lookup created with devm_clk_hw_register_clkdev. + * Normally this function will not need to be called and the resource + * management code will ensure that the resource is freed. + */ +void devm_clk_release_clkdev(struct device *dev, const char *con_id, + const char *dev_id) +{ + struct clk_lookup *cl; + int rval; + + cl = clk_find(dev_id, con_id); + WARN_ON(!cl); + rval = devres_release(dev, devm_clkdev_release, + devm_clk_match_clkdev, cl); + WARN_ON(rval); +} +EXPORT_SYMBOL(devm_clk_release_clkdev); + +/** + * devm_clk_hw_register_clkdev - managed clk lookup registration for clk_hw + * @dev: device this lookup is bound + * @hw: struct clk_hw to associate with all clk_lookups + * @con_id: connection ID string on device + * @dev_id: format string describing device name + * + * con_id or dev_id may be NULL as a wildcard, just as in the rest of + * clkdev. + * + * To make things easier for mass registration, we detect error clk_hws + * from a previous clk_hw_register_*() call, and return the error code for + * those. This is to permit this function to be called immediately + * after clk_hw_register_*(). + */ +int devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw, + const char *con_id, const char *dev_id) +{ + int rval = -ENOMEM; + struct clk_lookup **cl; + + cl = devres_alloc(devm_clkdev_release, sizeof(*cl), GFP_KERNEL); + if (cl) { + rval = do_clk_register_clkdev(hw, cl, con_id, dev_id); + if (!rval) + devres_add(dev, cl); + else + devres_free(cl); + } + return rval; +} +EXPORT_SYMBOL(devm_clk_hw_register_clkdev); diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index 4890ff033220..ccb32af5848b 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h @@ -52,4 +52,8 @@ int clk_add_alias(const char *, const char *, const char *, struct device *); int clk_register_clkdev(struct clk *, const char *, const char *); int clk_hw_register_clkdev(struct clk_hw *, const char *, const char *); +int devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw, + const char *con_id, const char *dev_id); +void devm_clk_release_clkdev(struct device *dev, const char *con_id, + const char *dev_id); #endif -- cgit v1.2.3 From 8144e1e8cacf30b74e331120edc368270b0ec1c0 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Fri, 7 Dec 2018 13:10:15 +0200 Subject: clk: clk-max77686: Clean clkdev lookup leak and use devm clk-max77686 never clean clkdev lookup at remove. This can cause oops if clk-max77686 is removed and inserted again. Fix leak by using new devm clkdev lookup registration. Simplify also error path by using new devm_of_clk_add_hw_provider. Signed-off-by: Matti Vaittinen Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- drivers/clk/clk-max77686.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 22c937644c93..3727d5472450 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -235,8 +235,9 @@ static int max77686_clk_probe(struct platform_device *pdev) return ret; } - ret = clk_hw_register_clkdev(&max_clk_data->hw, - max_clk_data->clk_idata.name, NULL); + ret = devm_clk_hw_register_clkdev(dev, &max_clk_data->hw, + max_clk_data->clk_idata.name, + NULL); if (ret < 0) { dev_err(dev, "Failed to clkdev register: %d\n", ret); return ret; @@ -244,8 +245,8 @@ static int max77686_clk_probe(struct platform_device *pdev) } if (parent->of_node) { - ret = of_clk_add_hw_provider(parent->of_node, of_clk_max77686_get, - drv_data); + ret = devm_of_clk_add_hw_provider(dev, of_clk_max77686_get, + drv_data); if (ret < 0) { dev_err(dev, "Failed to register OF clock provider: %d\n", @@ -261,27 +262,11 @@ static int max77686_clk_probe(struct platform_device *pdev) 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT); if (ret < 0) { dev_err(dev, "Failed to config low-jitter: %d\n", ret); - goto remove_of_clk_provider; + return ret; } } return 0; - -remove_of_clk_provider: - if (parent->of_node) - of_clk_del_provider(parent->of_node); - - return ret; -} - -static int max77686_clk_remove(struct platform_device *pdev) -{ - struct device *parent = pdev->dev.parent; - - if (parent->of_node) - of_clk_del_provider(parent->of_node); - - return 0; } static const struct platform_device_id max77686_clk_id[] = { @@ -297,7 +282,6 @@ static struct platform_driver max77686_clk_driver = { .name = "max77686-clk", }, .probe = max77686_clk_probe, - .remove = max77686_clk_remove, .id_table = max77686_clk_id, }; -- cgit v1.2.3 From d3236214e7dead87e7aefd32259aaf0bf41cf050 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Fri, 7 Dec 2018 13:10:51 +0200 Subject: clk: clk-st: avoid clkdev lookup leak at remove Use devm based clkdev lookup registration to avoid leaking lookup structures. Signed-off-by: Matti Vaittinen Signed-off-by: Stephen Boyd --- drivers/clk/x86/clk-st.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/x86/clk-st.c b/drivers/clk/x86/clk-st.c index 3a0996f2d556..25d4b97aff9b 100644 --- a/drivers/clk/x86/clk-st.c +++ b/drivers/clk/x86/clk-st.c @@ -52,7 +52,8 @@ static int st_clk_probe(struct platform_device *pdev) 0, st_data->base + MISCCLKCNTL1, OSCCLKENB, CLK_GATE_SET_TO_DISABLE, NULL); - clk_hw_register_clkdev(hws[ST_CLK_GATE], "oscout1", NULL); + devm_clk_hw_register_clkdev(&pdev->dev, hws[ST_CLK_GATE], "oscout1", + NULL); return 0; } -- cgit v1.2.3 From be3d960b0aeb97438a044d8d3ce75393d198c020 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 12 Feb 2019 17:28:58 +0100 Subject: dt-bindings: clk: add G12A AO Clock and Reset Bindings Add bindings for the Amlogic G12A AO Clock and Reset controllers. Signed-off-by: Neil Armstrong Acked-by: Jerome Brunet Link: https://lkml.kernel.org/r/20190212162859.20743-2-narmstrong@baylibre.com --- .../bindings/clock/amlogic,gxbb-aoclkc.txt | 1 + include/dt-bindings/clock/g12a-aoclkc.h | 34 ++++++++++++++++++++++ include/dt-bindings/reset/g12a-aoclkc.h | 18 ++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 include/dt-bindings/clock/g12a-aoclkc.h create mode 100644 include/dt-bindings/reset/g12a-aoclkc.h diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt index 79511d7bb321..c41f0be5d438 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt @@ -10,6 +10,7 @@ Required Properties: - GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc" - GXM (S912) : "amlogic,meson-gxm-aoclkc" - AXG (A113D, A113X) : "amlogic,meson-axg-aoclkc" + - G12A (S905X2, S905D2, S905Y2) : "amlogic,meson-g12a-aoclkc" followed by the common "amlogic,meson-gx-aoclkc" - clocks: list of clock phandle, one for each entry clock-names. - clock-names: should contain the following: diff --git a/include/dt-bindings/clock/g12a-aoclkc.h b/include/dt-bindings/clock/g12a-aoclkc.h new file mode 100644 index 000000000000..8db01ffbeb06 --- /dev/null +++ b/include/dt-bindings/clock/g12a-aoclkc.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (c) 2016 BayLibre, SAS + * Author: Neil Armstrong + * + * Copyright (c) 2018 Amlogic, inc. + * Author: Qiufang Dai + */ + +#ifndef DT_BINDINGS_CLOCK_AMLOGIC_MESON_G12A_AOCLK +#define DT_BINDINGS_CLOCK_AMLOGIC_MESON_G12A_AOCLK + +#define CLKID_AO_AHB 0 +#define CLKID_AO_IR_IN 1 +#define CLKID_AO_I2C_M0 2 +#define CLKID_AO_I2C_S0 3 +#define CLKID_AO_UART 4 +#define CLKID_AO_PROD_I2C 5 +#define CLKID_AO_UART2 6 +#define CLKID_AO_IR_OUT 7 +#define CLKID_AO_SAR_ADC 8 +#define CLKID_AO_MAILBOX 9 +#define CLKID_AO_M3 10 +#define CLKID_AO_AHB_SRAM 11 +#define CLKID_AO_RTI 12 +#define CLKID_AO_M4_FCLK 13 +#define CLKID_AO_M4_HCLK 14 +#define CLKID_AO_CLK81 15 +#define CLKID_AO_SAR_ADC_CLK 18 +#define CLKID_AO_32K 23 +#define CLKID_AO_CEC 27 +#define CLKID_AO_CTS_RTC_OSCIN 28 + +#endif diff --git a/include/dt-bindings/reset/g12a-aoclkc.h b/include/dt-bindings/reset/g12a-aoclkc.h new file mode 100644 index 000000000000..bd2e2337135c --- /dev/null +++ b/include/dt-bindings/reset/g12a-aoclkc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (c) 2016 BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef DT_BINDINGS_RESET_AMLOGIC_MESON_G12A_AOCLK +#define DT_BINDINGS_RESET_AMLOGIC_MESON_G12A_AOCLK + +#define RESET_AO_IR_IN 0 +#define RESET_AO_UART 1 +#define RESET_AO_I2C_M 2 +#define RESET_AO_I2C_S 3 +#define RESET_AO_SAR_ADC 4 +#define RESET_AO_UART2 5 +#define RESET_AO_IR_OUT 6 + +#endif -- cgit v1.2.3 From 042f01bb7f80012e19369b7f8a52fc5b74f4856b Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 12 Feb 2019 17:28:59 +0100 Subject: clk: meson: Add G12A AO Clock + Reset Controller Add the Amlogic G12A AO Clock and Reset controller driver handling generation of Always-On clocks : - AO Clocks and Reset for Always-On modules - 32K Generation for USB and CEC - SAR ADC controller clock Signed-off-by: Neil Armstrong Signed-off-by: Jerome Brunet Acked-by: Jerome Brunet Link: https://lkml.kernel.org/r/20190212162859.20743-3-narmstrong@baylibre.com --- drivers/clk/meson/Kconfig | 2 + drivers/clk/meson/Makefile | 2 +- drivers/clk/meson/g12a-aoclk.c | 454 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/meson/g12a-aoclk.h | 34 +++ 4 files changed, 491 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/meson/g12a-aoclk.c create mode 100644 drivers/clk/meson/g12a-aoclk.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index b72439315340..3858747f5438 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -98,8 +98,10 @@ config COMMON_CLK_G12A bool depends on ARCH_MESON select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_AO_CLKC select COMMON_CLK_MESON_EE_CLKC select MFD_SYSCON help diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 32d17f18541e..021fc290e749 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -16,5 +16,5 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o -obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o +obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c new file mode 100644 index 000000000000..1994e735396b --- /dev/null +++ b/drivers/clk/meson/g12a-aoclk.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson-AXG Clock Controller Driver + * + * Copyright (c) 2016 Baylibre SAS. + * Author: Michael Turquette + * + * Copyright (c) 2019 Baylibre SAS. + * Author: Neil Armstrong + */ +#include +#include +#include +#include +#include "meson-aoclk.h" +#include "g12a-aoclk.h" + +#include "clk-regmap.h" +#include "clk-dualdiv.h" + +#define IN_PREFIX "ao-in-" + +/* + * AO Configuration Clock registers offsets + * Register offsets from the data sheet must be multiplied by 4. + */ +#define AO_RTI_STATUS_REG3 0x0C +#define AO_RTI_PWR_CNTL_REG0 0x10 +#define AO_RTI_GEN_CNTL_REG0 0x40 +#define AO_CLK_GATE0 0x4c +#define AO_CLK_GATE0_SP 0x50 +#define AO_OSCIN_CNTL 0x58 +#define AO_CEC_CLK_CNTL_REG0 0x74 +#define AO_CEC_CLK_CNTL_REG1 0x78 +#define AO_SAR_CLK 0x90 +#define AO_RTC_ALT_CLK_CNTL0 0x94 +#define AO_RTC_ALT_CLK_CNTL1 0x98 + +/* + * Like every other peripheral clock gate in Amlogic Clock drivers, + * we are using CLK_IGNORE_UNUSED here, so we keep the state of the + * bootloader. The goal is to remove this flag at some point. + * Actually removing it will require some extensive test to be done safely. + */ +#define AXG_AO_GATE(_name, _reg, _bit) \ +static struct clk_regmap g12a_aoclk_##_name = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = "g12a_ao_" #_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \ + .num_parents = 1, \ + .flags = CLK_IGNORE_UNUSED, \ + }, \ +} + +AXG_AO_GATE(ahb, AO_CLK_GATE0, 0); +AXG_AO_GATE(ir_in, AO_CLK_GATE0, 1); +AXG_AO_GATE(i2c_m0, AO_CLK_GATE0, 2); +AXG_AO_GATE(i2c_s0, AO_CLK_GATE0, 3); +AXG_AO_GATE(uart, AO_CLK_GATE0, 4); +AXG_AO_GATE(prod_i2c, AO_CLK_GATE0, 5); +AXG_AO_GATE(uart2, AO_CLK_GATE0, 6); +AXG_AO_GATE(ir_out, AO_CLK_GATE0, 7); +AXG_AO_GATE(saradc, AO_CLK_GATE0, 8); +AXG_AO_GATE(mailbox, AO_CLK_GATE0_SP, 0); +AXG_AO_GATE(m3, AO_CLK_GATE0_SP, 1); +AXG_AO_GATE(ahb_sram, AO_CLK_GATE0_SP, 2); +AXG_AO_GATE(rti, AO_CLK_GATE0_SP, 3); +AXG_AO_GATE(m4_fclk, AO_CLK_GATE0_SP, 4); +AXG_AO_GATE(m4_hclk, AO_CLK_GATE0_SP, 5); + +static struct clk_regmap g12a_aoclk_cts_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTI_PWR_CNTL_REG0, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_oscin", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal" }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, {} +}; + +/* 32k_by_oscin clock */ + +static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_32k_by_oscin_pre", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "cts_oscin" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_aoclk_32k_by_oscin_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_RTC_ALT_CLK_CNTL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_RTC_ALT_CLK_CNTL0, + .shift = 28, + .width = 1, + }, + .table = g12a_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_32k_by_oscin_div", + .ops = &meson_clk_dualdiv_ops, + .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_pre" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTC_ALT_CLK_CNTL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_32k_by_oscin_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_div", + "g12a_ao_32k_by_oscin_pre" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_aoclk_32k_by_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_RTC_ALT_CLK_CNTL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_32k_by_oscin", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* cec clock */ + +static struct clk_regmap g12a_aoclk_cec_pre = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_CEC_CLK_CNTL_REG0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cec_pre", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "cts_oscin" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_aoclk_cec_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = AO_CEC_CLK_CNTL_REG0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = AO_CEC_CLK_CNTL_REG0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = AO_CEC_CLK_CNTL_REG1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = AO_CEC_CLK_CNTL_REG1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = AO_CEC_CLK_CNTL_REG0, + .shift = 28, + .width = 1, + }, + .table = g12a_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cec_div", + .ops = &meson_clk_dualdiv_ops, + .parent_names = (const char *[]){ "g12a_ao_cec_pre" }, + .num_parents = 1, + }, +}; + +static struct clk_regmap g12a_aoclk_cec_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_CEC_CLK_CNTL_REG1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cec_sel", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "g12a_ao_cec_div", + "g12a_ao_cec_pre" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_aoclk_cec = { + .data = &(struct clk_regmap_gate_data){ + .offset = AO_CEC_CLK_CNTL_REG0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cec", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "g12a_ao_cec_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_aoclk_cts_rtc_oscin = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 10, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_cts_rtc_oscin", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin", + IN_PREFIX "ext_32k-0" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_aoclk_clk81 = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_RTI_PWR_CNTL_REG0, + .mask = 0x1, + .shift = 8, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_clk81", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk", + "g12a_ao_cts_rtc_oscin"}, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_aoclk_saradc_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = AO_SAR_CLK, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_saradc_mux", + .ops = &clk_regmap_mux_ops, + .parent_names = (const char *[]){ IN_PREFIX "xtal", + "g12a_ao_clk81" }, + .num_parents = 2, + }, +}; + +static struct clk_regmap g12a_aoclk_saradc_div = { + .data = &(struct clk_regmap_div_data) { + .offset = AO_SAR_CLK, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_saradc_div", + .ops = &clk_regmap_divider_ops, + .parent_names = (const char *[]){ "g12a_ao_saradc_mux" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_aoclk_saradc_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = AO_SAR_CLK, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_ao_saradc_gate", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "g12a_ao_saradc_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const unsigned int g12a_aoclk_reset[] = { + [RESET_AO_IR_IN] = 16, + [RESET_AO_UART] = 17, + [RESET_AO_I2C_M] = 18, + [RESET_AO_I2C_S] = 19, + [RESET_AO_SAR_ADC] = 20, + [RESET_AO_UART2] = 22, + [RESET_AO_IR_OUT] = 23, +}; + +static struct clk_regmap *g12a_aoclk_regmap[] = { + &g12a_aoclk_ahb, + &g12a_aoclk_ir_in, + &g12a_aoclk_i2c_m0, + &g12a_aoclk_i2c_s0, + &g12a_aoclk_uart, + &g12a_aoclk_prod_i2c, + &g12a_aoclk_uart2, + &g12a_aoclk_ir_out, + &g12a_aoclk_saradc, + &g12a_aoclk_mailbox, + &g12a_aoclk_m3, + &g12a_aoclk_ahb_sram, + &g12a_aoclk_rti, + &g12a_aoclk_m4_fclk, + &g12a_aoclk_m4_hclk, + &g12a_aoclk_cts_oscin, + &g12a_aoclk_32k_by_oscin_pre, + &g12a_aoclk_32k_by_oscin_div, + &g12a_aoclk_32k_by_oscin_sel, + &g12a_aoclk_32k_by_oscin, + &g12a_aoclk_cec_pre, + &g12a_aoclk_cec_div, + &g12a_aoclk_cec_sel, + &g12a_aoclk_cec, + &g12a_aoclk_cts_rtc_oscin, + &g12a_aoclk_clk81, + &g12a_aoclk_saradc_mux, + &g12a_aoclk_saradc_div, + &g12a_aoclk_saradc_gate, +}; + +static const struct clk_hw_onecell_data g12a_aoclk_onecell_data = { + .hws = { + [CLKID_AO_AHB] = &g12a_aoclk_ahb.hw, + [CLKID_AO_IR_IN] = &g12a_aoclk_ir_in.hw, + [CLKID_AO_I2C_M0] = &g12a_aoclk_i2c_m0.hw, + [CLKID_AO_I2C_S0] = &g12a_aoclk_i2c_s0.hw, + [CLKID_AO_UART] = &g12a_aoclk_uart.hw, + [CLKID_AO_PROD_I2C] = &g12a_aoclk_prod_i2c.hw, + [CLKID_AO_UART2] = &g12a_aoclk_uart2.hw, + [CLKID_AO_IR_OUT] = &g12a_aoclk_ir_out.hw, + [CLKID_AO_SAR_ADC] = &g12a_aoclk_saradc.hw, + [CLKID_AO_MAILBOX] = &g12a_aoclk_mailbox.hw, + [CLKID_AO_M3] = &g12a_aoclk_m3.hw, + [CLKID_AO_AHB_SRAM] = &g12a_aoclk_ahb_sram.hw, + [CLKID_AO_RTI] = &g12a_aoclk_rti.hw, + [CLKID_AO_M4_FCLK] = &g12a_aoclk_m4_fclk.hw, + [CLKID_AO_M4_HCLK] = &g12a_aoclk_m4_hclk.hw, + [CLKID_AO_CLK81] = &g12a_aoclk_clk81.hw, + [CLKID_AO_SAR_ADC_SEL] = &g12a_aoclk_saradc_mux.hw, + [CLKID_AO_SAR_ADC_DIV] = &g12a_aoclk_saradc_div.hw, + [CLKID_AO_SAR_ADC_CLK] = &g12a_aoclk_saradc_gate.hw, + [CLKID_AO_CTS_OSCIN] = &g12a_aoclk_cts_oscin.hw, + [CLKID_AO_32K_PRE] = &g12a_aoclk_32k_by_oscin_pre.hw, + [CLKID_AO_32K_DIV] = &g12a_aoclk_32k_by_oscin_div.hw, + [CLKID_AO_32K_SEL] = &g12a_aoclk_32k_by_oscin_sel.hw, + [CLKID_AO_32K] = &g12a_aoclk_32k_by_oscin.hw, + [CLKID_AO_CEC_PRE] = &g12a_aoclk_cec_pre.hw, + [CLKID_AO_CEC_DIV] = &g12a_aoclk_cec_div.hw, + [CLKID_AO_CEC_SEL] = &g12a_aoclk_cec_sel.hw, + [CLKID_AO_CEC] = &g12a_aoclk_cec.hw, + [CLKID_AO_CTS_RTC_OSCIN] = &g12a_aoclk_cts_rtc_oscin.hw, + }, + .num = NR_CLKS, +}; + +static const struct meson_aoclk_input g12a_aoclk_inputs[] = { + { .name = "xtal", .required = true }, + { .name = "mpeg-clk", .required = true }, + { .name = "ext-32k-0", .required = false }, +}; + +static const struct meson_aoclk_data g12a_aoclkc_data = { + .reset_reg = AO_RTI_GEN_CNTL_REG0, + .num_reset = ARRAY_SIZE(g12a_aoclk_reset), + .reset = g12a_aoclk_reset, + .num_clks = ARRAY_SIZE(g12a_aoclk_regmap), + .clks = g12a_aoclk_regmap, + .hw_data = &g12a_aoclk_onecell_data, + .inputs = g12a_aoclk_inputs, + .num_inputs = ARRAY_SIZE(g12a_aoclk_inputs), + .input_prefix = IN_PREFIX, +}; + +static const struct of_device_id g12a_aoclkc_match_table[] = { + { + .compatible = "amlogic,meson-g12a-aoclkc", + .data = &g12a_aoclkc_data, + }, + { } +}; + +static struct platform_driver g12a_aoclkc_driver = { + .probe = meson_aoclkc_probe, + .driver = { + .name = "g12a-aoclkc", + .of_match_table = g12a_aoclkc_match_table, + }, +}; + +builtin_platform_driver(g12a_aoclkc_driver); diff --git a/drivers/clk/meson/g12a-aoclk.h b/drivers/clk/meson/g12a-aoclk.h new file mode 100644 index 000000000000..04b0d5506641 --- /dev/null +++ b/drivers/clk/meson/g12a-aoclk.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef __G12A_AOCLKC_H +#define __G12A_AOCLKC_H + +/* + * CLKID index values + * + * These indices are entirely contrived and do not map onto the hardware. + * It has now been decided to expose everything by default in the DT header: + * include/dt-bindings/clock/g12a-aoclkc.h. Only the clocks ids we don't want + * to expose, such as the internal muxes and dividers of composite clocks, + * will remain defined here. + */ +#define CLKID_AO_SAR_ADC_SEL 16 +#define CLKID_AO_SAR_ADC_DIV 17 +#define CLKID_AO_CTS_OSCIN 19 +#define CLKID_AO_32K_PRE 20 +#define CLKID_AO_32K_DIV 21 +#define CLKID_AO_32K_SEL 22 +#define CLKID_AO_CEC_PRE 24 +#define CLKID_AO_CEC_DIV 25 +#define CLKID_AO_CEC_SEL 26 + +#define NR_CLKS 29 + +#include +#include + +#endif /* __G12A_AOCLKC_H */ -- cgit v1.2.3 From 40d08f774c17add49c1db0083390b6a672030b7d Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sun, 10 Feb 2019 23:26:02 +0100 Subject: dt-bindings: clock: meson8b: add APB clock definition Commit 8e1dd17c8b0e3f ("dt-bindings: clock: meson8b: export the CPU post dividers") added a clock with the name "ABP". The actual name of this clock is "APB". Add a new #define with the same ID but the correct name. The old #define will be dropped in a follow-up patch because each commit in the tree must compile on it's own (the old #define is still used by the clock controller driver). Fixes: 8e1dd17c8b0e3f ("dt-bindings: clock: meson8b: export the CPU post dividers") Signed-off-by: Martin Blumenstingl Signed-off-by: Neil Armstrong Acked-by: Jerome Brunet Link: https://lkml.kernel.org/r/20190210222603.6404-2-martin.blumenstingl@googlemail.com --- include/dt-bindings/clock/meson8b-clkc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h index 5fe2923382d0..8067077a62ca 100644 --- a/include/dt-bindings/clock/meson8b-clkc.h +++ b/include/dt-bindings/clock/meson8b-clkc.h @@ -104,6 +104,7 @@ #define CLKID_MPLL2 95 #define CLKID_NAND_CLK 112 #define CLKID_ABP 124 +#define CLKID_APB 124 #define CLKID_PERIPH 126 #define CLKID_AXI 128 #define CLKID_L2_DRAM 130 -- cgit v1.2.3 From c5f09e6bd8a7537beef8ee53cd161a06b04de271 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sun, 10 Feb 2019 23:26:03 +0100 Subject: clk: meson: meson8b: fix the naming of the APB clocks Fix a typo in the APB clock names by renaming them from "abp" to "apb". No functional changes. Fixes: a7d19b05ce817d ("clk: meson: meson8b: add the CPU clock post divider clocks") Signed-off-by: Martin Blumenstingl Signed-off-by: Neil Armstrong Acked-by: Jerome Brunet Link: https://lkml.kernel.org/r/20190210222603.6404-2-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 26 +++++++++++++------------- drivers/clk/meson/meson8b.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 23b1e355a849..576ad42252d0 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -804,16 +804,16 @@ static struct clk_fixed_factor meson8b_cpu_clk_div8 = { }, }; -static u32 mux_table_abp[] = { 1, 2, 3, 4, 5, 6, 7 }; -static struct clk_regmap meson8b_abp_clk_sel = { +static u32 mux_table_apb[] = { 1, 2, 3, 4, 5, 6, 7 }; +static struct clk_regmap meson8b_apb_clk_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .mask = 0x7, .shift = 3, - .table = mux_table_abp, + .table = mux_table_apb, }, .hw.init = &(struct clk_init_data){ - .name = "abp_clk_sel", + .name = "apb_clk_sel", .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "cpu_clk_div2", "cpu_clk_div3", @@ -826,16 +826,16 @@ static struct clk_regmap meson8b_abp_clk_sel = { }, }; -static struct clk_regmap meson8b_abp_clk_gate = { +static struct clk_regmap meson8b_apb_clk_gate = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 16, .flags = CLK_GATE_SET_TO_DISABLE, }, .hw.init = &(struct clk_init_data){ - .name = "abp_clk_dis", + .name = "apb_clk_dis", .ops = &clk_regmap_gate_ro_ops, - .parent_names = (const char *[]){ "abp_clk_sel" }, + .parent_names = (const char *[]){ "apb_clk_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -1911,8 +1911,8 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = { [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, - [CLKID_ABP_SEL] = &meson8b_abp_clk_sel.hw, - [CLKID_ABP] = &meson8b_abp_clk_gate.hw, + [CLKID_APB_SEL] = &meson8b_apb_clk_sel.hw, + [CLKID_APB] = &meson8b_apb_clk_gate.hw, [CLKID_PERIPH_SEL] = &meson8b_periph_clk_sel.hw, [CLKID_PERIPH] = &meson8b_periph_clk_gate.hw, [CLKID_AXI_SEL] = &meson8b_axi_clk_sel.hw, @@ -2093,8 +2093,8 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_CPU_CLK_DIV6] = &meson8b_cpu_clk_div6.hw, [CLKID_CPU_CLK_DIV7] = &meson8b_cpu_clk_div7.hw, [CLKID_CPU_CLK_DIV8] = &meson8b_cpu_clk_div8.hw, - [CLKID_ABP_SEL] = &meson8b_abp_clk_sel.hw, - [CLKID_ABP] = &meson8b_abp_clk_gate.hw, + [CLKID_APB_SEL] = &meson8b_apb_clk_sel.hw, + [CLKID_APB] = &meson8b_apb_clk_gate.hw, [CLKID_PERIPH_SEL] = &meson8b_periph_clk_sel.hw, [CLKID_PERIPH] = &meson8b_periph_clk_gate.hw, [CLKID_AXI_SEL] = &meson8b_axi_clk_sel.hw, @@ -2262,8 +2262,8 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_fixed_pll_dco, &meson8b_hdmi_pll_dco, &meson8b_sys_pll_dco, - &meson8b_abp_clk_sel, - &meson8b_abp_clk_gate, + &meson8b_apb_clk_sel, + &meson8b_apb_clk_gate, &meson8b_periph_clk_sel, &meson8b_periph_clk_gate, &meson8b_axi_clk_sel, diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index f212e2304ff5..b8c58faeae52 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -92,7 +92,7 @@ #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_APB_SEL 123 #define CLKID_PERIPH_SEL 125 #define CLKID_AXI_SEL 127 #define CLKID_L2_DRAM_SEL 129 -- cgit v1.2.3 From 77b773aea5a8abccbd25101390e1ba4b33b3fca0 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 15 Jan 2019 11:15:12 +0200 Subject: clk: ti: move clk_hw_omap list handling under generic part of the driver Currently the clk_hw_omap list is handled under the autoidle code, but it should be accessible generically. Add a few APIs towards this, and update the autoidle code to use the generic implementations. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Tested-by: Keerthy --- drivers/clk/ti/autoidle.c | 65 +++++++++++++++++++---------------------------- drivers/clk/ti/clk.c | 42 ++++++++++++++++++++++++++++++ drivers/clk/ti/clock.h | 1 + 3 files changed, 69 insertions(+), 39 deletions(-) diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index 7bb9afbe4058..a129b4b36ea3 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -35,7 +35,20 @@ struct clk_ti_autoidle { #define AUTOIDLE_LOW 0x1 static LIST_HEAD(autoidle_clks); -static LIST_HEAD(clk_hw_omap_clocks); + +static int _omap2_clk_deny_idle(struct clk_hw_omap *clk) +{ + if (clk->ops && clk->ops->deny_idle) + clk->ops->deny_idle(clk); + return 0; +} + +static int _omap2_clk_allow_idle(struct clk_hw_omap *clk) +{ + if (clk->ops && clk->ops->allow_idle) + clk->ops->allow_idle(clk); + return 0; +} /** * omap2_clk_deny_idle - disable autoidle on an OMAP clock @@ -45,12 +58,9 @@ static LIST_HEAD(clk_hw_omap_clocks); */ int omap2_clk_deny_idle(struct clk *clk) { - struct clk_hw_omap *c; + struct clk_hw_omap *c = to_clk_hw_omap(__clk_get_hw(clk)); - c = to_clk_hw_omap(__clk_get_hw(clk)); - if (c->ops && c->ops->deny_idle) - c->ops->deny_idle(c); - return 0; + return _omap2_clk_deny_idle(c); } /** @@ -61,12 +71,9 @@ int omap2_clk_deny_idle(struct clk *clk) */ int omap2_clk_allow_idle(struct clk *clk) { - struct clk_hw_omap *c; + struct clk_hw_omap *c = to_clk_hw_omap(__clk_get_hw(clk)); - c = to_clk_hw_omap(__clk_get_hw(clk)); - if (c->ops && c->ops->allow_idle) - c->ops->allow_idle(c); - return 0; + return _omap2_clk_allow_idle(c); } static void _allow_autoidle(struct clk_ti_autoidle *clk) @@ -167,26 +174,6 @@ int __init of_ti_clk_autoidle_setup(struct device_node *node) return 0; } -/** - * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock - * @hw: struct clk_hw * to initialize - * - * Add an OMAP clock @clk to the internal list of OMAP clocks. Used - * temporarily for autoidle handling, until this support can be - * integrated into the common clock framework code in some way. No - * return value. - */ -void omap2_init_clk_hw_omap_clocks(struct clk_hw *hw) -{ - struct clk_hw_omap *c; - - if (clk_hw_get_flags(hw) & CLK_IS_BASIC) - return; - - c = to_clk_hw_omap(hw); - list_add(&c->node, &clk_hw_omap_clocks); -} - /** * omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that * support it @@ -198,11 +185,11 @@ void omap2_init_clk_hw_omap_clocks(struct clk_hw *hw) */ int omap2_clk_enable_autoidle_all(void) { - struct clk_hw_omap *c; + int ret; - list_for_each_entry(c, &clk_hw_omap_clocks, node) - if (c->ops && c->ops->allow_idle) - c->ops->allow_idle(c); + ret = omap2_clk_for_each(_omap2_clk_allow_idle); + if (ret) + return ret; _clk_generic_allow_autoidle_all(); @@ -220,11 +207,11 @@ int omap2_clk_enable_autoidle_all(void) */ int omap2_clk_disable_autoidle_all(void) { - struct clk_hw_omap *c; + int ret; - list_for_each_entry(c, &clk_hw_omap_clocks, node) - if (c->ops && c->ops->deny_idle) - c->ops->deny_idle(c); + ret = omap2_clk_for_each(_omap2_clk_deny_idle); + if (ret) + return ret; _clk_generic_deny_autoidle_all(); diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index d0cd58534781..817284324d41 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -31,6 +31,7 @@ #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ +static LIST_HEAD(clk_hw_omap_clocks); struct ti_clk_ll_ops *ti_clk_ll_ops; static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; @@ -517,3 +518,44 @@ struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, return clk; } + +/** + * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock + * @hw: struct clk_hw * to initialize + * + * Add an OMAP clock @clk to the internal list of OMAP clocks. Used + * temporarily for autoidle handling, until this support can be + * integrated into the common clock framework code in some way. No + * return value. + */ +void omap2_init_clk_hw_omap_clocks(struct clk_hw *hw) +{ + struct clk_hw_omap *c; + + c = to_clk_hw_omap(hw); + list_add(&c->node, &clk_hw_omap_clocks); +} + +/** + * omap2_clk_for_each - call function for each registered clk_hw_omap + * @fn: pointer to a callback function + * + * Call @fn for each registered clk_hw_omap, passing @hw to each + * function. @fn must return 0 for success or any other value for + * failure. If @fn returns non-zero, the iteration across clocks + * will stop and the non-zero return value will be passed to the + * caller of omap2_clk_for_each(). + */ +int omap2_clk_for_each(int (*fn)(struct clk_hw_omap *hw)) +{ + int ret; + struct clk_hw_omap *hw; + + list_for_each_entry(hw, &clk_hw_omap_clocks, node) { + ret = (*fn)(hw); + if (ret) + break; + } + + return ret; +} diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 9f312a219510..e5b8af38cfa0 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -301,6 +301,7 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, unsigned long *parent_rate); int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, struct clk_rate_request *req); +int omap2_clk_for_each(int (*fn)(struct clk_hw_omap *hw)); extern struct ti_clk_ll_ops *ti_clk_ll_ops; -- cgit v1.2.3 From 7fd79ee78a0318bd23f92c3cf3f4aba03a5dd6ad Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 15 Jan 2019 11:15:13 +0200 Subject: clk: ti: add new API for checking if a provided clock is an OMAP clock omap2_clk_is_hw_omap can now be used to verify if the provided clk_hw is an omap HW clock or not. This is done to replace the usage of CLK_IS_BASIC flag within the TI clock drivers. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Tested-by: Keerthy --- drivers/clk/ti/clk.c | 19 +++++++++++++++++++ drivers/clk/ti/clock.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 817284324d41..122af2680833 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -559,3 +559,22 @@ int omap2_clk_for_each(int (*fn)(struct clk_hw_omap *hw)) return ret; } + +/** + * omap2_clk_is_hw_omap - check if the provided clk_hw is OMAP clock + * @hw: clk_hw to check if it is an omap clock or not + * + * Checks if the provided clk_hw is OMAP clock or not. Returns true if + * it is, false otherwise. + */ +bool omap2_clk_is_hw_omap(struct clk_hw *hw) +{ + struct clk_hw_omap *oclk; + + list_for_each_entry(oclk, &clk_hw_omap_clocks, node) { + if (&oclk->hw == hw) + return true; + } + + return false; +} diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index e5b8af38cfa0..034ff6a2be07 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -302,6 +302,7 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, struct clk_rate_request *req); int omap2_clk_for_each(int (*fn)(struct clk_hw_omap *hw)); +bool omap2_clk_is_hw_omap(struct clk_hw *hw); extern struct ti_clk_ll_ops *ti_clk_ll_ops; -- cgit v1.2.3 From 8aa09cf322c196df95b52ed63c4cae605296f343 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 15 Jan 2019 11:15:14 +0200 Subject: clk: ti: remove usage of CLK_IS_BASIC Remove the usage of CLK_IS_BASIC flag completely from TI clock driver. In most cases, the use is completely redundant, but in some cases we need to use the new API to check if the clock is an OMAP clock or not. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Tested-by: Keerthy --- drivers/clk/ti/adpll.c | 2 +- drivers/clk/ti/clkctrl.c | 2 +- drivers/clk/ti/clockdomain.c | 2 +- drivers/clk/ti/divider.c | 2 +- drivers/clk/ti/dpll3xxx.c | 2 +- drivers/clk/ti/mux.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c index 688e403333b9..0c210984765a 100644 --- a/drivers/clk/ti/adpll.c +++ b/drivers/clk/ti/adpll.c @@ -614,7 +614,7 @@ static int ti_adpll_init_clkout(struct ti_adpll_data *d, init.name = child_name; init.ops = ops; - init.flags = CLK_IS_BASIC; + init.flags = 0; co->hw.init = &init; parent_names[0] = __clk_get_name(clk0); parent_names[1] = __clk_get_name(clk1); diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c index 40630eb950fc..bf32d996177f 100644 --- a/drivers/clk/ti/clkctrl.c +++ b/drivers/clk/ti/clkctrl.c @@ -276,7 +276,7 @@ _ti_clkctrl_clk_register(struct omap_clkctrl_provider *provider, init.parent_names = parents; init.num_parents = num_parents; init.ops = ops; - init.flags = CLK_IS_BASIC; + init.flags = 0; clk = ti_clk_register(NULL, clk_hw, init.name); if (IS_ERR_OR_NULL(clk)) { diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index 07a805125e98..423a99b9f10c 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -143,7 +143,7 @@ static void __init of_ti_clockdomain_setup(struct device_node *node) continue; } clk_hw = __clk_get_hw(clk); - if (clk_hw_get_flags(clk_hw) & CLK_IS_BASIC) { + if (!omap2_clk_is_hw_omap(clk_hw)) { pr_warn("can't setup clkdm for basic clk %s\n", __clk_get_name(clk)); continue; diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 8d77090ad94a..cb5a81963ba9 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -336,7 +336,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, init.name = name; init.ops = &ti_clk_divider_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); diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c index 44b6b6403753..3dde6c8c3354 100644 --- a/drivers/clk/ti/dpll3xxx.c +++ b/drivers/clk/ti/dpll3xxx.c @@ -731,7 +731,7 @@ static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw) do { do { hw = clk_hw_get_parent(hw); - } while (hw && (clk_hw_get_flags(hw) & CLK_IS_BASIC)); + } while (hw && (!omap2_clk_is_hw_omap(hw))); if (!hw) break; pclk = to_clk_hw_omap(hw); diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index 883bdde94d04..b7f9a4f068bf 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -143,7 +143,7 @@ static struct clk *_register_mux(struct device *dev, const char *name, init.name = name; init.ops = &ti_clk_mux_ops; - init.flags = flags | CLK_IS_BASIC; + init.flags = flags; init.parent_names = parent_names; init.num_parents = num_parents; -- cgit v1.2.3 From ead478250b950f1f082d4cb57bed3adeacfe53c3 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 15 Jan 2019 11:15:15 +0200 Subject: clk: ti: generalize the init sequence of clk_hw_omap clocks Add a generic API for initializing clocks of clk_hw_omap type clocks, and convert the whole TI clock driver suite to use this for registering the clocks. Also, get rid of the now redundant API for adding the clocks to the OMAP HW clocks list; instead this is used directly from the register API. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Tested-by: Keerthy --- drivers/clk/ti/apll.c | 4 ++-- drivers/clk/ti/clk.c | 31 +++++++++++++++++++++---------- drivers/clk/ti/clock.h | 3 ++- drivers/clk/ti/dpll.c | 11 ++++------- drivers/clk/ti/gate.c | 2 +- drivers/clk/ti/interface.c | 4 +--- 6 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index 222f68bc3f2a..015a657d3382 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -165,7 +165,7 @@ static void __init omap_clk_register_apll(void *user, ad->clk_bypass = __clk_get_hw(clk); - clk = ti_clk_register(NULL, &clk_hw->hw, node->name); + clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, node->name); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); kfree(clk_hw->hw.init->parent_names); @@ -402,7 +402,7 @@ static void __init of_omap2_apll_setup(struct device_node *node) if (ret) goto cleanup; - clk = clk_register(NULL, &clk_hw->hw); + clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, node->name); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); kfree(init); diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 122af2680833..d1f948163d6a 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -520,20 +520,31 @@ struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, } /** - * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock - * @hw: struct clk_hw * to initialize + * ti_clk_register_omap_hw - register a clk_hw_omap to the clock framework + * @dev: device for this clock + * @hw: hardware clock handle + * @con: connection ID for this clock * - * Add an OMAP clock @clk to the internal list of OMAP clocks. Used - * temporarily for autoidle handling, until this support can be - * integrated into the common clock framework code in some way. No - * return value. + * Registers a clk_hw_omap clock to the clock framewor, adds a clock alias + * for it, and adds the list to the available clk_hw_omap type clocks. + * Returns a handle to the registered clock if successful, ERR_PTR value + * in failure. */ -void omap2_init_clk_hw_omap_clocks(struct clk_hw *hw) +struct clk *ti_clk_register_omap_hw(struct device *dev, struct clk_hw *hw, + const char *con) { - struct clk_hw_omap *c; + struct clk *clk; + struct clk_hw_omap *oclk; - c = to_clk_hw_omap(hw); - list_add(&c->node, &clk_hw_omap_clocks); + clk = ti_clk_register(dev, hw, con); + if (IS_ERR(clk)) + return clk; + + oclk = to_clk_hw_omap(hw); + + list_add(&oclk->node, &clk_hw_omap_clocks); + + return clk; } /** diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 034ff6a2be07..1c0fac59d809 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -203,6 +203,8 @@ typedef void (*ti_of_clk_init_cb_t)(void *, struct device_node *); struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, const char *con); +struct clk *ti_clk_register_omap_hw(struct device *dev, struct clk_hw *hw, + const char *con); int ti_clk_add_alias(struct device *dev, struct clk *clk, const char *con); void ti_clk_add_aliases(void); @@ -221,7 +223,6 @@ int ti_clk_retry_init(struct device_node *node, void *user, ti_of_clk_init_cb_t func); int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); -void omap2_init_clk_hw_omap_clocks(struct clk_hw *hw); int of_ti_clk_autoidle_setup(struct device_node *node); void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 6c3329bc116f..659dadb23279 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -192,10 +192,9 @@ static void __init _register_dpll(void *user, dd->clk_bypass = __clk_get_hw(clk); /* register the clock */ - clk = ti_clk_register(NULL, &clk_hw->hw, node->name); + clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, node->name); if (!IS_ERR(clk)) { - omap2_init_clk_hw_omap_clocks(&clk_hw->hw); of_clk_add_provider(node, of_clk_src_simple_get, clk); kfree(clk_hw->hw.init->parent_names); kfree(clk_hw->hw.init); @@ -265,14 +264,12 @@ static void _register_dpll_x2(struct device_node *node, #endif /* register the clock */ - clk = ti_clk_register(NULL, &clk_hw->hw, name); + clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, name); - if (IS_ERR(clk)) { + if (IS_ERR(clk)) kfree(clk_hw); - } else { - omap2_init_clk_hw_omap_clocks(&clk_hw->hw); + else of_clk_add_provider(node, of_clk_src_simple_get, clk); - } } #endif diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c index 1c78fff5513c..504c0e91cdc7 100644 --- a/drivers/clk/ti/gate.c +++ b/drivers/clk/ti/gate.c @@ -123,7 +123,7 @@ static struct clk *_register_gate(struct device *dev, const char *name, init.flags = flags; - clk = ti_clk_register(NULL, &clk_hw->hw, name); + clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, name); if (IS_ERR(clk)) kfree(clk_hw); diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c index 87e00c2ee957..83e34429d3b1 100644 --- a/drivers/clk/ti/interface.c +++ b/drivers/clk/ti/interface.c @@ -57,12 +57,10 @@ static struct clk *_register_interface(struct device *dev, const char *name, init.num_parents = 1; init.parent_names = &parent_name; - clk = ti_clk_register(NULL, &clk_hw->hw, name); + clk = ti_clk_register_omap_hw(NULL, &clk_hw->hw, name); if (IS_ERR(clk)) kfree(clk_hw); - else - omap2_init_clk_hw_omap_clocks(&clk_hw->hw); return clk; } -- cgit v1.2.3 From d277ce2d3a75c6c116a6119c3745694f5941eff5 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 16 Jan 2019 23:04:27 +0100 Subject: clk: ti: add a usecount for autoidle Multiple users might deny autoidle on a clock. So we should have some counting here, also according to the comment in _setup_iclk_autoidle(). Also setting autoidle regs is not atomic, so there is another reason for locking. Signed-off-by: Andreas Kemnade Acked-by: Tony Lindgren Tested-by: Keerthy Signed-off-by: Tero Kristo --- drivers/clk/ti/autoidle.c | 32 ++++++++++++++++++++++++++++---- include/linux/clk/ti.h | 1 + 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index a129b4b36ea3..964e97b5478a 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -36,17 +36,41 @@ struct clk_ti_autoidle { static LIST_HEAD(autoidle_clks); +/* + * we have some non-atomic read/write + * operations behind it, so lets + * take one lock for handling autoidle + * of all clocks + */ +static DEFINE_SPINLOCK(autoidle_spinlock); + static int _omap2_clk_deny_idle(struct clk_hw_omap *clk) { - if (clk->ops && clk->ops->deny_idle) - clk->ops->deny_idle(clk); + if (clk->ops && clk->ops->deny_idle) { + unsigned long irqflags; + + spin_lock_irqsave(&autoidle_spinlock, irqflags); + clk->autoidle_count++; + if (clk->autoidle_count == 1) + clk->ops->deny_idle(clk); + + spin_unlock_irqrestore(&autoidle_spinlock, irqflags); + } return 0; } static int _omap2_clk_allow_idle(struct clk_hw_omap *clk) { - if (clk->ops && clk->ops->allow_idle) - clk->ops->allow_idle(clk); + if (clk->ops && clk->ops->allow_idle) { + unsigned long irqflags; + + spin_lock_irqsave(&autoidle_spinlock, irqflags); + clk->autoidle_count--; + if (clk->autoidle_count == 0) + clk->ops->allow_idle(clk); + + spin_unlock_irqrestore(&autoidle_spinlock, irqflags); + } return 0; } diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index eacc5df57b99..78872efc7be0 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -160,6 +160,7 @@ struct clk_hw_omap { struct clockdomain *clkdm; const struct clk_hw_omap_ops *ops; u32 context; + int autoidle_count; }; /* -- cgit v1.2.3 From fddf4e29a6ce97d693e2a2e759f495ddc4ac2474 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 16 Jan 2019 23:04:28 +0100 Subject: clk: ti: check clock type before doing autoidle ops Code might use autoidle api with clocks not being omap2 clocks, so check if clock type is really omap2. Signed-off-by: Andreas Kemnade Acked-by: Tony Lindgren Tested-by: Keerthy Signed-off-by: Tero Kristo --- drivers/clk/ti/autoidle.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index 964e97b5478a..1cae226759dd 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -82,9 +82,15 @@ static int _omap2_clk_allow_idle(struct clk_hw_omap *clk) */ int omap2_clk_deny_idle(struct clk *clk) { - struct clk_hw_omap *c = to_clk_hw_omap(__clk_get_hw(clk)); + struct clk_hw *hw = __clk_get_hw(clk); - return _omap2_clk_deny_idle(c); + if (omap2_clk_is_hw_omap(hw)) { + struct clk_hw_omap *c = to_clk_hw_omap(hw); + + return _omap2_clk_deny_idle(c); + } + + return -EINVAL; } /** @@ -95,9 +101,15 @@ int omap2_clk_deny_idle(struct clk *clk) */ int omap2_clk_allow_idle(struct clk *clk) { - struct clk_hw_omap *c = to_clk_hw_omap(__clk_get_hw(clk)); + struct clk_hw *hw = __clk_get_hw(clk); + + if (omap2_clk_is_hw_omap(hw)) { + struct clk_hw_omap *c = to_clk_hw_omap(hw); + + return _omap2_clk_allow_idle(c); + } - return _omap2_clk_allow_idle(c); + return -EINVAL; } static void _allow_autoidle(struct clk_ti_autoidle *clk) -- cgit v1.2.3 From 12af39cad78e9cb8172793ca5d7f369eb144578b Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 16 Jan 2019 23:04:29 +0100 Subject: ARM: OMAP2+: hwmod: disable ick autoidling when a hwmod requires that Deny autoidle for hwmods with the OCPIF_SWSUP_IDLE flag, that makes hwmods working properly which cannot handle autoidle properly in lower power states. Affected is e. g. the omap_hdq. Since an ick might have mulitple users, autoidle is disabled when an individual user requires that rather than in _setup_iclk_autoidle. dss_ick is an example for that. Signed-off-by: Andreas Kemnade Acked-by: Tony Lindgren Tested-by: Keerthy Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/omap_hwmod.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index b5531dd3ae9c..3a04c73ac03c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1002,8 +1002,10 @@ static int _enable_clocks(struct omap_hwmod *oh) clk_enable(oh->_clk); list_for_each_entry(os, &oh->slave_ports, node) { - if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) + if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) { + omap2_clk_deny_idle(os->_clk); clk_enable(os->_clk); + } } /* The opt clocks are controlled by the device driver. */ @@ -1055,8 +1057,10 @@ static int _disable_clocks(struct omap_hwmod *oh) clk_disable(oh->_clk); list_for_each_entry(os, &oh->slave_ports, node) { - if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) + if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) { clk_disable(os->_clk); + omap2_clk_allow_idle(os->_clk); + } } if (oh->flags & HWMOD_OPT_CLKS_NEEDED) @@ -2436,9 +2440,13 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh) continue; if (os->flags & OCPIF_SWSUP_IDLE) { - /* XXX omap_iclk_deny_idle(c); */ + /* + * we might have multiple users of one iclk with + * different requirements, disable autoidle when + * the module is enabled, e.g. dss iclk + */ } else { - /* XXX omap_iclk_allow_idle(c); */ + /* we are enabling autoidle afterwards anyways */ clk_enable(os->_clk); } } -- cgit v1.2.3 From 65a6b7c5f31c39a47da729021cb2a5ec1339affb Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 14 Dec 2018 15:30:09 +0000 Subject: clk: imx: Make parent_names const pointer in composite-8m The parent_names needs to be pointer to const pointer to const char. Signed-off-by: Abel Vesa Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-composite-8m.c | 2 +- drivers/clk/imx/clk.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c index 527ade1d6933..574fac1a169f 100644 --- a/drivers/clk/imx/clk-composite-8m.c +++ b/drivers/clk/imx/clk-composite-8m.c @@ -123,7 +123,7 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = { }; struct clk *imx8m_clk_composite_flags(const char *name, - const char **parent_names, + const char * const *parent_names, int num_parents, void __iomem *reg, unsigned long flags) { diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 028312de21b8..1363dbe65020 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -354,7 +354,7 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name, struct clk *step); struct clk *imx8m_clk_composite_flags(const char *name, - const char **parent_names, + const char * const *parent_names, int num_parents, void __iomem *reg, unsigned long flags); -- cgit v1.2.3 From 470663e0781c06234235a025a5455c0e15925f0c Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 14 Dec 2018 15:30:10 +0000 Subject: clk: imx: Make parents const pointer in mux wrappers The parents needs to be pointer to const pointer to const char. Signed-off-by: Abel Vesa Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 1363dbe65020..2e442d8389a5 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -329,7 +329,8 @@ static inline struct clk *imx_clk_mux_flags(const char *name, } static inline struct clk *imx_clk_mux2_flags(const char *name, - void __iomem *reg, u8 shift, u8 width, const char **parents, + 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, -- cgit v1.2.3 From 402564aee071a9d1139bbca47f5a25242f215deb Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 14 Dec 2018 15:30:11 +0000 Subject: clk: imx8mq: Make parent names arrays const pointers The arrays containing the mux selectors need to be of const pointer to const char. Signed-off-by: Abel Vesa Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mq.c | 194 +++++++++++++++++++++---------------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 26b57f43ccc3..398ab0bcd9de 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -26,245 +26,245 @@ 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", }; +static const char * const pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char * const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char * const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char * const sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char * const sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char * const sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char * const dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; + +static const char * const sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char * const sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char * const sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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 * const 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 * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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 * const 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 * const 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 * const 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 * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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", +static const char * const 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 * const 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", +static const char * const 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; -- cgit v1.2.3 From cd67d3272768aa3f44c0f7cc71b82a112dce01fa Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Thu, 24 Jan 2019 13:22:49 +0000 Subject: clk: imx: scu: add fallback compatible string support SCU clock can be used in a similar way by IMX8QXP and IMX8QM SoCs. Make the driver support "fsl,scu-clk" fallback compatible string to allow other SoCs to reuse the common part. Cc: Shawn Guo Cc: Sascha Hauer Cc: Fabio Estevam Cc: Stephen Boyd Cc: Michael Turquette Signed-off-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8qxp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index 83e2ef96d81d..5e2903efc488 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -138,6 +138,7 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) } static const struct of_device_id imx8qxp_match[] = { + { .compatible = "fsl,scu-clk", }, { .compatible = "fsl,imx8qxp-clk", }, { /* sentinel */ } }; -- cgit v1.2.3 From 666aed2d13ee58b4d1df00a9c112b3cc76f2d36a Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Wed, 30 Jan 2019 13:39:15 +0000 Subject: clk: imx: scu: add set parent support Add clk scu set parents support. Cc: Stephen Boyd Cc: Shawn Guo Cc: Sascha Hauer Cc: Fabio Estevam Cc: Michael Turquette Signed-off-by: Dong Aisheng [sboyd@kernel.org: Remove le32_to_cpu() on get_parent op] Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-scu.c | 87 +++++++++++++++++++++++++++++++++++++++++++++-- drivers/clk/imx/clk-scu.h | 16 ++++++++- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index 7ccf7edfe11c..f460526a7abb 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -65,6 +65,41 @@ struct imx_sc_msg_get_clock_rate { } data; }; +/* + * struct imx_sc_msg_get_clock_parent - clock get parent protocol + * @hdr: SCU protocol header + * @req: get parent request protocol + * @resp: get parent response protocol + * + * This structure describes the SCU protocol of clock get parent + */ +struct imx_sc_msg_get_clock_parent { + struct imx_sc_rpc_msg hdr; + union { + struct req_get_clock_parent { + __le16 resource; + u8 clk; + } __packed req; + struct resp_get_clock_parent { + u8 parent; + } resp; + } data; +}; + +/* + * struct imx_sc_msg_set_clock_parent - clock set parent protocol + * @hdr: SCU protocol header + * @req: set parent request protocol + * + * This structure describes the SCU protocol of clock set parent + */ +struct imx_sc_msg_set_clock_parent { + struct imx_sc_rpc_msg hdr; + __le16 resource; + u8 clk; + u8 parent; +} __packed; + /* * struct imx_sc_msg_req_clock_enable - clock gate protocol * @hdr: SCU protocol header @@ -173,6 +208,49 @@ static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate, return imx_scu_call_rpc(ccm_ipc_handle, &msg, true); } +static u8 clk_scu_get_parent(struct clk_hw *hw) +{ + struct clk_scu *clk = to_clk_scu(hw); + struct imx_sc_msg_get_clock_parent 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_PARENT; + 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 parent %d\n", + clk_hw_get_name(hw), ret); + return 0; + } + + return msg.data.resp.parent; +} + +static int clk_scu_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_scu *clk = to_clk_scu(hw); + struct imx_sc_msg_set_clock_parent 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_PARENT; + hdr->size = 2; + + msg.resource = cpu_to_le16(clk->rsrc_id); + msg.clk = clk->clk_type; + msg.parent = index; + + 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) { @@ -228,11 +306,14 @@ 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, + .get_parent = clk_scu_get_parent, + .set_parent = clk_scu_set_parent, .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_hw *__imx_clk_scu(const char *name, const char * const *parents, + int num_parents, u32 rsrc_id, u8 clk_type) { struct clk_init_data init; struct clk_scu *clk; @@ -248,7 +329,9 @@ struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type) init.name = name; init.ops = &clk_scu_ops; - init.num_parents = 0; + init.parent_names = parents; + init.num_parents = num_parents; + /* * Note on MX8, the clocks are tightly coupled with power domain * that once the power domain is off, the clock status may be diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h index 52c1746ec988..2bcfaf06a458 100644 --- a/drivers/clk/imx/clk-scu.h +++ b/drivers/clk/imx/clk-scu.h @@ -10,7 +10,21 @@ #include 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_scu(const char *name, const char * const *parents, + int num_parents, u32 rsrc_id, u8 clk_type); + +static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, + u8 clk_type) +{ + return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type); +} + +static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents, + int num_parents, u32 rsrc_id, u8 clk_type) +{ + return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type); +} struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, -- cgit v1.2.3 From 9b15cffbf21d3ac0a60618a3274b335532f33573 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Tue, 8 Jan 2019 17:21:15 +0100 Subject: clk: imx5: add imx5_SCC2_IPG_GATE This adds the missing clock for the SCC2 peripheral unit. Signed-off-by: Michael Grzeschik Signed-off-by: Lucas Stach Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx51-imx53.c | 1 + include/dt-bindings/clock/imx5-clock.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c index fc8e782d817b..e91c826bce70 100644 --- a/drivers/clk/imx/clk-imx51-imx53.c +++ b/drivers/clk/imx/clk-imx51-imx53.c @@ -428,6 +428,7 @@ static void __init mx51_clocks_init(struct device_node *np) clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14); clk[IMX5_CLK_USB_PHY_GATE] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0); clk[IMX5_CLK_HSI2C_GATE] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22); + clk[IMX5_CLK_SCC2_IPG_GATE] = imx_clk_gate2("scc2_gate", "ipg", MXC_CCM_CCGR1, 30); clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2_flags("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6, CLK_IS_CRITICAL); clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2_flags("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8, CLK_IS_CRITICAL); clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2_flags("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10, CLK_IS_CRITICAL); diff --git a/include/dt-bindings/clock/imx5-clock.h b/include/dt-bindings/clock/imx5-clock.h index d382fc71aa83..a81be5be6700 100644 --- a/include/dt-bindings/clock/imx5-clock.h +++ b/include/dt-bindings/clock/imx5-clock.h @@ -214,6 +214,7 @@ #define IMX5_CLK_IEEE1588_SEL 202 #define IMX5_CLK_IEEE1588_PODF 203 #define IMX5_CLK_IEEE1588_GATE 204 -#define IMX5_CLK_END 205 +#define IMX5_CLK_SCC2_IPG_GATE 205 +#define IMX5_CLK_END 206 #endif /* __DT_BINDINGS_CLOCK_IMX5_H */ -- cgit v1.2.3 From 8646d4dcc7fb2e6e771f8cee500950f3f69aa1ea Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Tue, 22 Jan 2019 09:31:41 +0000 Subject: clk: imx: Add PLLs driver for imx8mm soc New PLLs are introduced on i.MX8M Mini SOC. PLL1416X is Integer PLL, PLL1443X is a Frac PLL. Signed-off-by: Bai Ping Signed-off-by: Stephen Boyd --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-pll14xx.c | 392 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/imx/clk.h | 24 +++ 3 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-pll14xx.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 73119fbfa547..ff7428744222 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -18,7 +18,8 @@ obj-$(CONFIG_MXC_CLK) += \ clk-pllv2.o \ clk-pllv3.o \ clk-pllv4.o \ - clk-sccg-pll.o + clk-sccg-pll.o \ + clk-pll14xx.o obj-$(CONFIG_MXC_CLK_SCU) += \ clk-scu.o \ diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c new file mode 100644 index 000000000000..1acfa3e3cfb4 --- /dev/null +++ b/drivers/clk/imx/clk-pll14xx.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2017-2018 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define GNRL_CTL 0x0 +#define DIV_CTL 0x4 +#define LOCK_STATUS BIT(31) +#define LOCK_SEL_MASK BIT(29) +#define CLKE_MASK BIT(11) +#define RST_MASK BIT(9) +#define BYPASS_MASK BIT(4) +#define MDIV_SHIFT 12 +#define MDIV_MASK GENMASK(21, 12) +#define PDIV_SHIFT 4 +#define PDIV_MASK GENMASK(9, 4) +#define SDIV_SHIFT 0 +#define SDIV_MASK GENMASK(2, 0) +#define KDIV_SHIFT 0 +#define KDIV_MASK GENMASK(15, 0) + +#define LOCK_TIMEOUT_US 10000 + +struct clk_pll14xx { + struct clk_hw hw; + void __iomem *base; + enum imx_pll14xx_type type; + const struct imx_pll14xx_rate_table *rate_table; + int rate_count; +}; + +#define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw) + +static const struct imx_pll14xx_rate_table *imx_get_pll_settings( + struct clk_pll14xx *pll, unsigned long rate) +{ + const struct imx_pll14xx_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) + if (rate == rate_table[i].rate) + return &rate_table[i]; + + return NULL; +} + +static long clk_pll14xx_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + const struct imx_pll14xx_rate_table *rate_table = pll->rate_table; + int i; + + /* Assumming rate_table is in descending order */ + for (i = 0; i < pll->rate_count; i++) + if (rate >= rate_table[i].rate) + return rate_table[i].rate; + + /* return minimum supported value */ + return rate_table[i - 1].rate; +} + +static unsigned long clk_pll1416x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div; + u64 fvco = parent_rate; + + pll_gnrl = readl_relaxed(pll->base); + pll_div = readl_relaxed(pll->base + 4); + mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT; + pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT; + sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT; + + fvco *= mdiv; + do_div(fvco, pdiv << sdiv); + + return fvco; +} + +static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div_ctl0, pll_div_ctl1; + short int kdiv; + u64 fvco = parent_rate; + + pll_gnrl = readl_relaxed(pll->base); + pll_div_ctl0 = readl_relaxed(pll->base + 4); + pll_div_ctl1 = readl_relaxed(pll->base + 8); + mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT; + pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT; + sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT; + kdiv = pll_div_ctl1 & KDIV_MASK; + + /* fvco = (m * 65536 + k) * Fin / (p * 65536) */ + fvco *= (mdiv * 65536 + kdiv); + pdiv *= 65536; + + do_div(fvco, pdiv << sdiv); + + return fvco; +} + +static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div) +{ + u32 old_mdiv, old_pdiv; + + old_mdiv = (pll_div >> MDIV_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div >> PDIV_SHIFT) & PDIV_MASK; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv; +} + +static inline bool clk_pll1443x_mpk_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div_ctl0, u32 pll_div_ctl1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK; + old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || + rate->kdiv != old_kdiv; +} + +static inline bool clk_pll1443x_mp_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div_ctl0, u32 pll_div_ctl1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK; + old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK; + old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || + rate->kdiv != old_kdiv; +} + +static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & LOCK_TIMEOUT_US, 0, + LOCK_TIMEOUT_US); +} + +static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + const struct imx_pll14xx_rate_table *rate; + u32 tmp, div_val; + int ret; + + rate = imx_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + + tmp = readl_relaxed(pll->base + 4); + + if (!clk_pll1416x_mp_change(rate, tmp)) { + tmp &= ~(SDIV_MASK) << SDIV_SHIFT; + tmp |= rate->sdiv << SDIV_SHIFT; + writel_relaxed(tmp, pll->base + 4); + + return 0; + } + + /* Bypass clock and set lock to pll output lock */ + tmp = readl_relaxed(pll->base); + tmp |= LOCK_SEL_MASK; + writel_relaxed(tmp, pll->base); + + /* Enable RST */ + tmp &= ~RST_MASK; + writel_relaxed(tmp, pll->base); + + div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) | + (rate->sdiv << SDIV_SHIFT); + writel_relaxed(div_val, pll->base + 0x4); + + /* + * According to SPEC, t3 - t2 need to be greater than + * 1us and 1/FREF, respectively. + * FREF is FIN / Prediv, the prediv is [1, 63], so choose + * 3us. + */ + udelay(3); + + /* Disable RST */ + tmp |= RST_MASK; + writel_relaxed(tmp, pll->base); + + /* Wait Lock */ + ret = clk_pll14xx_wait_lock(pll); + if (ret) + return ret; + + /* Bypass */ + tmp &= ~BYPASS_MASK; + writel_relaxed(tmp, pll->base); + + return 0; +} + +static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + const struct imx_pll14xx_rate_table *rate; + u32 tmp, div_val; + int ret; + + rate = imx_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + + tmp = readl_relaxed(pll->base + 4); + div_val = readl_relaxed(pll->base + 8); + + if (!clk_pll1443x_mpk_change(rate, tmp, div_val)) { + tmp &= ~(SDIV_MASK) << SDIV_SHIFT; + tmp |= rate->sdiv << SDIV_SHIFT; + writel_relaxed(tmp, pll->base + 4); + + return 0; + } + + /* Enable RST */ + tmp = readl_relaxed(pll->base); + tmp &= ~RST_MASK; + writel_relaxed(tmp, pll->base); + + div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) | + (rate->sdiv << SDIV_SHIFT); + writel_relaxed(div_val, pll->base + 0x4); + writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + 0x8); + + /* + * According to SPEC, t3 - t2 need to be greater than + * 1us and 1/FREF, respectively. + * FREF is FIN / Prediv, the prediv is [1, 63], so choose + * 3us. + */ + udelay(3); + + /* Disable RST */ + tmp |= RST_MASK; + writel_relaxed(tmp, pll->base); + + /* Wait Lock*/ + ret = clk_pll14xx_wait_lock(pll); + if (ret) + return ret; + + /* Bypass */ + tmp &= ~BYPASS_MASK; + writel_relaxed(tmp, pll->base); + + return 0; +} + +static int clk_pll14xx_prepare(struct clk_hw *hw) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 val; + + /* + * RESETB = 1 from 0, PLL starts its normal + * operation after lock time + */ + val = readl_relaxed(pll->base + GNRL_CTL); + val |= RST_MASK; + writel_relaxed(val, pll->base + GNRL_CTL); + + return clk_pll14xx_wait_lock(pll); +} + +static int clk_pll14xx_is_prepared(struct clk_hw *hw) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 val; + + val = readl_relaxed(pll->base + GNRL_CTL); + + return (val & RST_MASK) ? 1 : 0; +} + +static void clk_pll14xx_unprepare(struct clk_hw *hw) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + u32 val; + + /* + * Set RST to 0, power down mode is enabled and + * every digital block is reset + */ + val = readl_relaxed(pll->base + GNRL_CTL); + val &= ~RST_MASK; + writel_relaxed(val, pll->base + GNRL_CTL); +} + +static const struct clk_ops clk_pll1416x_ops = { + .prepare = clk_pll14xx_prepare, + .unprepare = clk_pll14xx_unprepare, + .is_prepared = clk_pll14xx_is_prepared, + .recalc_rate = clk_pll1416x_recalc_rate, + .round_rate = clk_pll14xx_round_rate, + .set_rate = clk_pll1416x_set_rate, +}; + +static const struct clk_ops clk_pll1416x_min_ops = { + .recalc_rate = clk_pll1416x_recalc_rate, +}; + +static const struct clk_ops clk_pll1443x_ops = { + .prepare = clk_pll14xx_prepare, + .unprepare = clk_pll14xx_unprepare, + .is_prepared = clk_pll14xx_is_prepared, + .recalc_rate = clk_pll1443x_recalc_rate, + .round_rate = clk_pll14xx_round_rate, + .set_rate = clk_pll1443x_set_rate, +}; + +struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_pll14xx_clk *pll_clk) +{ + struct clk_pll14xx *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = pll_clk->flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + switch (pll_clk->type) { + case PLL_1416X: + if (!pll->rate_table) + init.ops = &clk_pll1416x_min_ops; + else + init.ops = &clk_pll1416x_ops; + break; + case PLL_1443X: + init.ops = &clk_pll1443x_ops; + break; + default: + pr_err("%s: Unknown pll type for pll clk %s\n", + __func__, name); + }; + + pll->base = base; + pll->hw.init = &init; + pll->type = pll_clk->type; + pll->rate_table = pll_clk->rate_table; + pll->rate_count = pll_clk->rate_count; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register pll %s %lu\n", + __func__, name, PTR_ERR(clk)); + kfree(pll); + } + + return clk; +} diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 2e442d8389a5..0aa48d3e3b95 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -27,6 +27,30 @@ enum imx_sccg_pll_type { SCCG_PLL2, }; +enum imx_pll14xx_type { + PLL_1416X, + PLL_1443X, +}; + +/* NOTE: Rate table should be kept sorted in descending order. */ +struct imx_pll14xx_rate_table { + unsigned int rate; + unsigned int pdiv; + unsigned int mdiv; + unsigned int sdiv; + unsigned int kdiv; +}; + +struct imx_pll14xx_clk { + enum imx_pll14xx_type type; + const struct imx_pll14xx_rate_table *rate_table; + int rate_count; + int flags; +}; + +struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, + void __iomem *base, const struct imx_pll14xx_clk *pll_clk); + struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name, const char *parent, void __iomem *base); -- cgit v1.2.3 From 037a474f6144544848da72bfda80776686084a13 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Tue, 22 Jan 2019 09:31:46 +0000 Subject: dt-bindings: imx: Add clock binding doc for imx8mm Add the clock binding doc for i.MX8MM. Signed-off-by: Bai Ping Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/imx8mm-clock.txt | 29 +++ include/dt-bindings/clock/imx8mm-clock.h | 244 +++++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mm-clock.txt create mode 100644 include/dt-bindings/clock/imx8mm-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mm-clock.txt b/Documentation/devicetree/bindings/clock/imx8mm-clock.txt new file mode 100644 index 000000000000..8e4ab9e619a1 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mm-clock.txt @@ -0,0 +1,29 @@ +* Clock bindings for NXP i.MX8M Mini + +Required properties: +- compatible: Should be "fsl,imx8mm-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: + - "osc_32k" + - "osc_24m" + - "clk_ext1" + - "clk_ext2" + - "clk_ext3" + - "clk_ext4" + +clk: clock-controller@30380000 { + compatible = "fsl,imx8mm-ccm"; + reg = <0x0 0x30380000 0x0 0x10000>; + #clock-cells = <1>; + clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, + <&clk_ext3>, <&clk_ext4>; + clock-names = "osc_32k", "osc_24m", "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/imx8mm-clock.h +for the full list of i.MX8M Mini clock IDs. diff --git a/include/dt-bindings/clock/imx8mm-clock.h b/include/dt-bindings/clock/imx8mm-clock.h new file mode 100644 index 000000000000..1b4353e7b486 --- /dev/null +++ b/include/dt-bindings/clock/imx8mm-clock.h @@ -0,0 +1,244 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017-2018 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MM_H +#define __DT_BINDINGS_CLOCK_IMX8MM_H + +#define IMX8MM_CLK_DUMMY 0 +#define IMX8MM_CLK_32K 1 +#define IMX8MM_CLK_24M 2 +#define IMX8MM_OSC_HDMI_CLK 3 +#define IMX8MM_CLK_EXT1 4 +#define IMX8MM_CLK_EXT2 5 +#define IMX8MM_CLK_EXT3 6 +#define IMX8MM_CLK_EXT4 7 +#define IMX8MM_AUDIO_PLL1_REF_SEL 8 +#define IMX8MM_AUDIO_PLL2_REF_SEL 9 +#define IMX8MM_VIDEO_PLL1_REF_SEL 10 +#define IMX8MM_DRAM_PLL_REF_SEL 11 +#define IMX8MM_GPU_PLL_REF_SEL 12 +#define IMX8MM_VPU_PLL_REF_SEL 13 +#define IMX8MM_ARM_PLL_REF_SEL 14 +#define IMX8MM_SYS_PLL1_REF_SEL 15 +#define IMX8MM_SYS_PLL2_REF_SEL 16 +#define IMX8MM_SYS_PLL3_REF_SEL 17 +#define IMX8MM_AUDIO_PLL1 18 +#define IMX8MM_AUDIO_PLL2 19 +#define IMX8MM_VIDEO_PLL1 20 +#define IMX8MM_DRAM_PLL 21 +#define IMX8MM_GPU_PLL 22 +#define IMX8MM_VPU_PLL 23 +#define IMX8MM_ARM_PLL 24 +#define IMX8MM_SYS_PLL1 25 +#define IMX8MM_SYS_PLL2 26 +#define IMX8MM_SYS_PLL3 27 +#define IMX8MM_AUDIO_PLL1_BYPASS 28 +#define IMX8MM_AUDIO_PLL2_BYPASS 29 +#define IMX8MM_VIDEO_PLL1_BYPASS 30 +#define IMX8MM_DRAM_PLL_BYPASS 31 +#define IMX8MM_GPU_PLL_BYPASS 32 +#define IMX8MM_VPU_PLL_BYPASS 33 +#define IMX8MM_ARM_PLL_BYPASS 34 +#define IMX8MM_SYS_PLL1_BYPASS 35 +#define IMX8MM_SYS_PLL2_BYPASS 36 +#define IMX8MM_SYS_PLL3_BYPASS 37 +#define IMX8MM_AUDIO_PLL1_OUT 38 +#define IMX8MM_AUDIO_PLL2_OUT 39 +#define IMX8MM_VIDEO_PLL1_OUT 40 +#define IMX8MM_DRAM_PLL_OUT 41 +#define IMX8MM_GPU_PLL_OUT 42 +#define IMX8MM_VPU_PLL_OUT 43 +#define IMX8MM_ARM_PLL_OUT 44 +#define IMX8MM_SYS_PLL1_OUT 45 +#define IMX8MM_SYS_PLL2_OUT 46 +#define IMX8MM_SYS_PLL3_OUT 47 +#define IMX8MM_SYS_PLL1_40M 48 +#define IMX8MM_SYS_PLL1_80M 49 +#define IMX8MM_SYS_PLL1_100M 50 +#define IMX8MM_SYS_PLL1_133M 51 +#define IMX8MM_SYS_PLL1_160M 52 +#define IMX8MM_SYS_PLL1_200M 53 +#define IMX8MM_SYS_PLL1_266M 54 +#define IMX8MM_SYS_PLL1_400M 55 +#define IMX8MM_SYS_PLL1_800M 56 +#define IMX8MM_SYS_PLL2_50M 57 +#define IMX8MM_SYS_PLL2_100M 58 +#define IMX8MM_SYS_PLL2_125M 59 +#define IMX8MM_SYS_PLL2_166M 60 +#define IMX8MM_SYS_PLL2_200M 61 +#define IMX8MM_SYS_PLL2_250M 62 +#define IMX8MM_SYS_PLL2_333M 63 +#define IMX8MM_SYS_PLL2_500M 64 +#define IMX8MM_SYS_PLL2_1000M 65 + +/* core */ +#define IMX8MM_CLK_A53_SRC 66 +#define IMX8MM_CLK_M4_SRC 67 +#define IMX8MM_CLK_VPU_SRC 68 +#define IMX8MM_CLK_GPU3D_SRC 69 +#define IMX8MM_CLK_GPU2D_SRC 70 +#define IMX8MM_CLK_A53_CG 71 +#define IMX8MM_CLK_M4_CG 72 +#define IMX8MM_CLK_VPU_CG 73 +#define IMX8MM_CLK_GPU3D_CG 74 +#define IMX8MM_CLK_GPU2D_CG 75 +#define IMX8MM_CLK_A53_DIV 76 +#define IMX8MM_CLK_M4_DIV 77 +#define IMX8MM_CLK_VPU_DIV 78 +#define IMX8MM_CLK_GPU3D_DIV 79 +#define IMX8MM_CLK_GPU2D_DIV 80 + +/* bus */ +#define IMX8MM_CLK_MAIN_AXI 81 +#define IMX8MM_CLK_ENET_AXI 82 +#define IMX8MM_CLK_NAND_USDHC_BUS 83 +#define IMX8MM_CLK_VPU_BUS 84 +#define IMX8MM_CLK_DISP_AXI 85 +#define IMX8MM_CLK_DISP_APB 86 +#define IMX8MM_CLK_DISP_RTRM 87 +#define IMX8MM_CLK_USB_BUS 88 +#define IMX8MM_CLK_GPU_AXI 89 +#define IMX8MM_CLK_GPU_AHB 90 +#define IMX8MM_CLK_NOC 91 +#define IMX8MM_CLK_NOC_APB 92 + +#define IMX8MM_CLK_AHB 93 +#define IMX8MM_CLK_AUDIO_AHB 94 +#define IMX8MM_CLK_IPG_ROOT 95 +#define IMX8MM_CLK_IPG_AUDIO_ROOT 96 + +#define IMX8MM_CLK_DRAM_ALT 97 +#define IMX8MM_CLK_DRAM_APB 98 +#define IMX8MM_CLK_VPU_G1 99 +#define IMX8MM_CLK_VPU_G2 100 +#define IMX8MM_CLK_DISP_DTRC 101 +#define IMX8MM_CLK_DISP_DC8000 102 +#define IMX8MM_CLK_PCIE1_CTRL 103 +#define IMX8MM_CLK_PCIE1_PHY 104 +#define IMX8MM_CLK_PCIE1_AUX 105 +#define IMX8MM_CLK_DC_PIXEL 106 +#define IMX8MM_CLK_LCDIF_PIXEL 107 +#define IMX8MM_CLK_SAI1 108 +#define IMX8MM_CLK_SAI2 109 +#define IMX8MM_CLK_SAI3 110 +#define IMX8MM_CLK_SAI4 111 +#define IMX8MM_CLK_SAI5 112 +#define IMX8MM_CLK_SAI6 113 +#define IMX8MM_CLK_SPDIF1 114 +#define IMX8MM_CLK_SPDIF2 115 +#define IMX8MM_CLK_ENET_REF 116 +#define IMX8MM_CLK_ENET_TIMER 117 +#define IMX8MM_CLK_ENET_PHY_REF 118 +#define IMX8MM_CLK_NAND 119 +#define IMX8MM_CLK_QSPI 120 +#define IMX8MM_CLK_USDHC1 121 +#define IMX8MM_CLK_USDHC2 122 +#define IMX8MM_CLK_I2C1 123 +#define IMX8MM_CLK_I2C2 124 +#define IMX8MM_CLK_I2C3 125 +#define IMX8MM_CLK_I2C4 126 +#define IMX8MM_CLK_UART1 127 +#define IMX8MM_CLK_UART2 128 +#define IMX8MM_CLK_UART3 129 +#define IMX8MM_CLK_UART4 130 +#define IMX8MM_CLK_USB_CORE_REF 131 +#define IMX8MM_CLK_USB_PHY_REF 132 +#define IMX8MM_CLK_ECSPI1 133 +#define IMX8MM_CLK_ECSPI2 134 +#define IMX8MM_CLK_PWM1 135 +#define IMX8MM_CLK_PWM2 136 +#define IMX8MM_CLK_PWM3 137 +#define IMX8MM_CLK_PWM4 138 +#define IMX8MM_CLK_GPT1 139 +#define IMX8MM_CLK_WDOG 140 +#define IMX8MM_CLK_WRCLK 141 +#define IMX8MM_CLK_DSI_CORE 142 +#define IMX8MM_CLK_DSI_PHY_REF 143 +#define IMX8MM_CLK_DSI_DBI 144 +#define IMX8MM_CLK_USDHC3 145 +#define IMX8MM_CLK_CSI1_CORE 146 +#define IMX8MM_CLK_CSI1_PHY_REF 147 +#define IMX8MM_CLK_CSI1_ESC 148 +#define IMX8MM_CLK_CSI2_CORE 149 +#define IMX8MM_CLK_CSI2_PHY_REF 150 +#define IMX8MM_CLK_CSI2_ESC 151 +#define IMX8MM_CLK_PCIE2_CTRL 152 +#define IMX8MM_CLK_PCIE2_PHY 153 +#define IMX8MM_CLK_PCIE2_AUX 154 +#define IMX8MM_CLK_ECSPI3 155 +#define IMX8MM_CLK_PDM 156 +#define IMX8MM_CLK_VPU_H1 157 +#define IMX8MM_CLK_CLKO1 158 + +#define IMX8MM_CLK_ECSPI1_ROOT 159 +#define IMX8MM_CLK_ECSPI2_ROOT 160 +#define IMX8MM_CLK_ECSPI3_ROOT 161 +#define IMX8MM_CLK_ENET1_ROOT 162 +#define IMX8MM_CLK_GPT1_ROOT 163 +#define IMX8MM_CLK_I2C1_ROOT 164 +#define IMX8MM_CLK_I2C2_ROOT 165 +#define IMX8MM_CLK_I2C3_ROOT 166 +#define IMX8MM_CLK_I2C4_ROOT 167 +#define IMX8MM_CLK_OCOTP_ROOT 168 +#define IMX8MM_CLK_PCIE1_ROOT 169 +#define IMX8MM_CLK_PWM1_ROOT 170 +#define IMX8MM_CLK_PWM2_ROOT 171 +#define IMX8MM_CLK_PWM3_ROOT 172 +#define IMX8MM_CLK_PWM4_ROOT 173 +#define IMX8MM_CLK_QSPI_ROOT 174 +#define IMX8MM_CLK_NAND_ROOT 175 +#define IMX8MM_CLK_SAI1_ROOT 176 +#define IMX8MM_CLK_SAI1_IPG 177 +#define IMX8MM_CLK_SAI2_ROOT 178 +#define IMX8MM_CLK_SAI2_IPG 179 +#define IMX8MM_CLK_SAI3_ROOT 180 +#define IMX8MM_CLK_SAI3_IPG 181 +#define IMX8MM_CLK_SAI4_ROOT 182 +#define IMX8MM_CLK_SAI4_IPG 183 +#define IMX8MM_CLK_SAI5_ROOT 184 +#define IMX8MM_CLK_SAI5_IPG 185 +#define IMX8MM_CLK_SAI6_ROOT 186 +#define IMX8MM_CLK_SAI6_IPG 187 +#define IMX8MM_CLK_UART1_ROOT 188 +#define IMX8MM_CLK_UART2_ROOT 189 +#define IMX8MM_CLK_UART3_ROOT 190 +#define IMX8MM_CLK_UART4_ROOT 191 +#define IMX8MM_CLK_USB1_CTRL_ROOT 192 +#define IMX8MM_CLK_GPU3D_ROOT 193 +#define IMX8MM_CLK_USDHC1_ROOT 194 +#define IMX8MM_CLK_USDHC2_ROOT 195 +#define IMX8MM_CLK_WDOG1_ROOT 196 +#define IMX8MM_CLK_WDOG2_ROOT 197 +#define IMX8MM_CLK_WDOG3_ROOT 198 +#define IMX8MM_CLK_VPU_G1_ROOT 199 +#define IMX8MM_CLK_GPU_BUS_ROOT 200 +#define IMX8MM_CLK_VPU_H1_ROOT 201 +#define IMX8MM_CLK_VPU_G2_ROOT 202 +#define IMX8MM_CLK_PDM_ROOT 203 +#define IMX8MM_CLK_DISP_ROOT 204 +#define IMX8MM_CLK_DISP_AXI_ROOT 205 +#define IMX8MM_CLK_DISP_APB_ROOT 206 +#define IMX8MM_CLK_DISP_RTRM_ROOT 207 +#define IMX8MM_CLK_USDHC3_ROOT 208 +#define IMX8MM_CLK_TMU_ROOT 209 +#define IMX8MM_CLK_VPU_DEC_ROOT 210 +#define IMX8MM_CLK_SDMA1_ROOT 211 +#define IMX8MM_CLK_SDMA2_ROOT 212 +#define IMX8MM_CLK_SDMA3_ROOT 213 +#define IMX8MM_CLK_GPT_3M 214 +#define IMX8MM_CLK_ARM 215 +#define IMX8MM_CLK_PDM_IPG 216 +#define IMX8MM_CLK_GPU2D_ROOT 217 +#define IMX8MM_CLK_MU_ROOT 218 +#define IMX8MM_CLK_CSI1_ROOT 219 + +#define IMX8MM_CLK_DRAM_CORE 220 +#define IMX8MM_CLK_DRAM_ALT_ROOT 221 + +#define IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK 222 + +#define IMX8MM_CLK_END 223 + +#endif -- cgit v1.2.3 From ba5625c3e272c77014687d44e12d2649eec4ddee Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Tue, 22 Jan 2019 09:31:51 +0000 Subject: clk: imx: Add clock driver support for imx8mm Add clock driver support for i.MX8MM SOC. Signed-off-by: Bai Ping Signed-off-by: Stephen Boyd --- drivers/clk/imx/Kconfig | 6 + drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mm.c | 675 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 682 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mm.c diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 4aae31a23449..0eaf41848280 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -8,6 +8,12 @@ config MXC_CLK_SCU bool depends on IMX_SCU +config CLK_IMX8MM + bool "IMX8MM CCM Clock Driver" + depends on ARCH_MXC && ARM64 + help + Build the driver for i.MX8MM CCM Clock Driver + config CLK_IMX8MQ bool "IMX8MQ CCM Clock Driver" depends on ARCH_MXC && ARM64 diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index ff7428744222..0d5180fbe988 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_MXC_CLK_SCU) += \ clk-scu.o \ clk-lpcg-scu.o +obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c new file mode 100644 index 000000000000..b7f3ac256856 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mm.c @@ -0,0 +1,675 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2017-2018 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_pdm; +static u32 share_count_nand; + +#define PLL_1416X_RATE(_rate, _m, _p, _s) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + } + +static const struct imx_pll14xx_rate_table imx8mm_pll1416x_tbl[] = { + PLL_1416X_RATE(1800000000U, 225, 3, 0), + PLL_1416X_RATE(1600000000U, 200, 3, 0), + PLL_1416X_RATE(1200000000U, 300, 3, 1), + PLL_1416X_RATE(1000000000U, 250, 3, 1), + PLL_1416X_RATE(800000000U, 200, 3, 1), + PLL_1416X_RATE(750000000U, 250, 2, 2), + PLL_1416X_RATE(700000000U, 350, 3, 2), + PLL_1416X_RATE(600000000U, 300, 3, 2), +}; + +static const struct imx_pll14xx_rate_table imx8mm_audiopll_tbl[] = { + PLL_1443X_RATE(786432000U, 655, 5, 2, 23593), + PLL_1443X_RATE(722534400U, 301, 5, 1, 3670), +}; + +static const struct imx_pll14xx_rate_table imx8mm_videopll_tbl[] = { + PLL_1443X_RATE(650000000U, 325, 3, 2, 0), + PLL_1443X_RATE(594000000U, 198, 2, 2, 0), +}; + +static const struct imx_pll14xx_rate_table imx8mm_drampll_tbl[] = { + PLL_1443X_RATE(650000000U, 325, 3, 2, 0), +}; + +static struct imx_pll14xx_clk imx8mm_audio_pll __initdata = { + .type = PLL_1443X, + .rate_table = imx8mm_audiopll_tbl, + .rate_count = ARRAY_SIZE(imx8mm_audiopll_tbl), +}; + +static struct imx_pll14xx_clk imx8mm_video_pll __initdata = { + .type = PLL_1443X, + .rate_table = imx8mm_videopll_tbl, + .rate_count = ARRAY_SIZE(imx8mm_videopll_tbl), +}; + +static struct imx_pll14xx_clk imx8mm_dram_pll __initdata = { + .type = PLL_1443X, + .rate_table = imx8mm_drampll_tbl, + .rate_count = ARRAY_SIZE(imx8mm_drampll_tbl), +}; + +static struct imx_pll14xx_clk imx8mm_arm_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mm_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl), +}; + +static struct imx_pll14xx_clk imx8mm_gpu_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mm_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl), +}; + +static struct imx_pll14xx_clk imx8mm_vpu_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mm_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl), +}; + +static struct imx_pll14xx_clk imx8mm_sys_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mm_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl), +}; + +static const char *pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", }; +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 *dram_pll_bypass_sels[] = {"dram_pll", "dram_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 *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", }; +static const char *sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", }; +static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mm_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m", + "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", }; + +static const char *imx8mm_m4_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m", "sys_pll1_266m", + "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", }; + +static const char *imx8mm_vpu_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m", + "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mm_gpu3d_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mm_gpu2d_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mm_main_axi_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll1_800m", "sys_pll2_250m", + "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "sys_pll1_100m",}; + +static const char *imx8mm_enet_axi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_250m", + "sys_pll2_200m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", }; + +static const char *imx8mm_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m", + "sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", }; + +static const char *imx8mm_vpu_bus_sels[] = {"osc_24m", "sys_pll1_800m", "vpu_pll_out", "audio_pll2_out", + "sys_pll3_out", "sys_pll2_1000m", "sys_pll2_200m", "sys_pll1_100m", }; + +static const char *imx8mm_disp_axi_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll1_40m", "audio_pll2_out", "clk_ext1", "clk_ext4", }; + +static const char *imx8mm_disp_apb_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll1_40m", "audio_pll2_out", "clk_ext1", "clk_ext3", }; + +static const char *imx8mm_disp_rtrm_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll2_200m", "sys_pll2_1000m", + "audio_pll1_out", "video_pll1_out", "clk_ext2", "clk_ext3", }; + +static const char *imx8mm_usb_bus_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m", "sys_pll2_100m", + "sys_pll2_200m", "clk_ext2", "clk_ext4", "audio_pll2_out", }; + +static const char *imx8mm_gpu_axi_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out", "sys_pll3_out", "sys_pll2_1000m", + "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mm_gpu_ahb_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out", "sys_pll3_out", "sys_pll2_1000m", + "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mm_noc_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out", "sys_pll2_1000m", "sys_pll2_500m", + "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mm_noc_apb_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll3_out", "sys_pll2_333m", "sys_pll2_200m", + "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", }; + +static const char *imx8mm_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m", "sys_pll1_400m", + "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", }; + +static const char *imx8mm_audio_ahb_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m", "sys_pll2_1000m", + "sys_pll2_166m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", }; + +static const char *imx8mm_dram_alt_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll1_100m", "sys_pll2_500m", + "sys_pll2_1000m", "sys_pll3_out", "audio_pll1_out", "sys_pll1_266m", }; + +static const char *imx8mm_dram_apb_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m", + "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", }; + +static const char *imx8mm_vpu_g1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m", + "sys_pll1_100m", "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", }; + +static const char *imx8mm_vpu_g2_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m", + "sys_pll1_100m", "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", }; + +static const char *imx8mm_disp_dtrc_sels[] = {"osc_24m", "video_pll2_out", "sys_pll1_800m", "sys_pll2_1000m", + "sys_pll1_160m", "video_pll1_out", "sys_pll3_out", "audio_pll2_out", }; + +static const char *imx8mm_disp_dc8000_sels[] = {"osc_24m", "video_pll2_out", "sys_pll1_800m", "sys_pll2_1000m", + "sys_pll1_160m", "video_pll1_out", "sys_pll3_out", "audio_pll2_out", }; + +static const char *imx8mm_pcie1_ctrl_sels[] = {"osc_24m", "sys_pll2_250m", "sys_pll2_200m", "sys_pll1_266m", + "sys_pll1_800m", "sys_pll2_500m", "sys_pll2_333m", "sys_pll3_out", }; + +static const char *imx8mm_pcie1_phy_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll2_500m", "clk_ext1", "clk_ext2", + "clk_ext3", "clk_ext4", "sys_pll1_400m", }; + +static const char *imx8mm_pcie1_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m", "sys_pll3_out", + "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_160m", "sys_pll1_200m", }; + +static const char *imx8mm_dc_pixel_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out", + "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", "clk_ext4", }; + +static const char *imx8mm_lcdif_pixel_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out", + "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", "clk_ext4", }; + +static const char *imx8mm_sai1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", + "sys_pll1_133m", "osc_hdmi", "clk_ext1", "clk_ext2", }; + +static const char *imx8mm_sai2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", + "sys_pll1_133m", "osc_hdmi", "clk_ext2", "clk_ext3", }; + +static const char *imx8mm_sai3_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", + "sys_pll1_133m", "osc_hdmi", "clk_ext3", "clk_ext4", }; + +static const char *imx8mm_sai4_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", + "sys_pll1_133m", "osc_hdmi", "clk_ext1", "clk_ext2", }; + +static const char *imx8mm_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", + "sys_pll1_133m", "osc_hdmi", "clk_ext2", "clk_ext3", }; + +static const char *imx8mm_sai6_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", + "sys_pll1_133m", "osc_hdmi", "clk_ext3", "clk_ext4", }; + +static const char *imx8mm_spdif1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", + "sys_pll1_133m", "osc_hdmi", "clk_ext2", "clk_ext3", }; + +static const char *imx8mm_spdif2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", + "sys_pll1_133m", "osc_hdmi", "clk_ext3", "clk_ext4", }; + +static const char *imx8mm_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m", "sys_pll2_100m", + "sys_pll1_160m", "audio_pll1_out", "video_pll1_out", "clk_ext4", }; + +static const char *imx8mm_enet_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out", "clk_ext1", "clk_ext2", + "clk_ext3", "clk_ext4", "video_pll1_out", }; + +static const char *imx8mm_enet_phy_sels[] = {"osc_24m", "sys_pll2_50m", "sys_pll2_125m", "sys_pll2_200m", + "sys_pll2_500m", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mm_nand_sels[] = {"osc_24m", "sys_pll2_500m", "audio_pll1_out", "sys_pll1_400m", + "audio_pll2_out", "sys_pll3_out", "sys_pll2_250m", "video_pll1_out", }; + +static const char *imx8mm_qspi_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", + "audio_pll2_out", "sys_pll1_266m", "sys_pll3_out", "sys_pll1_100m", }; + +static const char *imx8mm_usdhc1_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", + "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", }; + +static const char *imx8mm_usdhc2_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", + "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", }; + +static const char *imx8mm_i2c1_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mm_i2c2_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mm_i2c3_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mm_i2c4_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mm_uart1_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", "sys_pll2_100m", + "sys_pll3_out", "clk_ext2", "clk_ext4", "audio_pll2_out", }; + +static const char *imx8mm_uart2_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", "sys_pll2_100m", + "sys_pll3_out", "clk_ext2", "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mm_uart3_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", "sys_pll2_100m", + "sys_pll3_out", "clk_ext2", "clk_ext4", "audio_pll2_out", }; + +static const char *imx8mm_uart4_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", "sys_pll2_100m", + "sys_pll3_out", "clk_ext2", "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mm_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m", + "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mm_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m", + "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mm_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m", + "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", }; + +static const char *imx8mm_ecspi2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m", + "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", }; + +static const char *imx8mm_pwm1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", + "sys_pll3_out", "clk_ext1", "sys_pll1_80m", "video_pll1_out", }; + +static const char *imx8mm_pwm2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", + "sys_pll3_out", "clk_ext1", "sys_pll1_80m", "video_pll1_out", }; + +static const char *imx8mm_pwm3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", + "sys3_pll2_out", "clk_ext2", "sys_pll1_80m", "video_pll1_out", }; + +static const char *imx8mm_pwm4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", + "sys_pll3_out", "clk_ext2", "sys_pll1_80m", "video_pll1_out", }; + +static const char *imx8mm_gpt1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m", "sys_pll1_40m", + "video_pll1_out", "sys_pll1_800m", "audio_pll1_out", "clk_ext1" }; + +static const char *imx8mm_wdog_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_160m", "vpu_pll_out", + "sys_pll2_125m", "sys_pll3_out", "sys_pll1_80m", "sys_pll2_166m", }; + +static const char *imx8mm_wrclk_sels[] = {"osc_24m", "sys_pll1_40m", "vpu_pll_out", "sys_pll3_out", "sys_pll2_200m", + "sys_pll1_266m", "sys_pll2_500m", "sys_pll1_100m", }; + +static const char *imx8mm_dsi_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", }; + +static const char *imx8mm_dsi_phy_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_100m", "sys_pll1_800m", + "sys_pll2_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + +static const char *imx8mm_dsi_dbi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_100m", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", }; + +static const char *imx8mm_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", + "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", }; + +static const char *imx8mm_csi1_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", }; + +static const char *imx8mm_csi1_phy_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m", "sys_pll1_800m", + "sys_pll2_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + +static const char *imx8mm_csi1_esc_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mm_csi2_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", }; + +static const char *imx8mm_csi2_phy_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m", "sys_pll1_800m", + "sys_pll2_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + +static const char *imx8mm_csi2_esc_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mm_pcie2_ctrl_sels[] = {"osc_24m", "sys_pll2_250m", "sys_pll2_200m", "sys_pll1_266m", + "sys_pll1_800m", "sys_pll2_500m", "sys_pll2_333m", "sys_pll3_out", }; + +static const char *imx8mm_pcie2_phy_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll2_500m", "clk_ext1", + "clk_ext2", "clk_ext3", "clk_ext4", "sys_pll1_400m", }; + +static const char *imx8mm_pcie2_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m", "sys_pll3_out", + "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_160m", "sys_pll1_200m", }; + +static const char *imx8mm_ecspi3_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m", + "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", }; + +static const char *imx8mm_pdm_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mm_vpu_h1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m", + "audio_pll2_clk", "sys_pll2_125m", "sys_pll3_clk", "audio_pll1_out", }; + +static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; + +static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_clk", + "vpu_pll", "sys_pll1_80m", }; + +static struct clk *clks[IMX8MM_CLK_END]; +static struct clk_onecell_data clk_data; + +static struct clk ** const uart_clks[] __initconst = { + &clks[IMX8MM_CLK_UART1_ROOT], + &clks[IMX8MM_CLK_UART2_ROOT], + &clks[IMX8MM_CLK_UART3_ROOT], + &clks[IMX8MM_CLK_UART4_ROOT], + NULL +}; + +static int imx8mm_clocks_init(struct device_node *ccm_node) +{ + struct device_node *np; + void __iomem *base; + int ret; + + clks[IMX8MM_CLK_DUMMY] = imx_clk_fixed("dummy", 0); + clks[IMX8MM_CLK_24M] = of_clk_get_by_name(ccm_node, "osc_24m"); + clks[IMX8MM_CLK_32K] = of_clk_get_by_name(ccm_node, "osc_32k"); + clks[IMX8MM_CLK_EXT1] = of_clk_get_by_name(ccm_node, "clk_ext1"); + clks[IMX8MM_CLK_EXT2] = of_clk_get_by_name(ccm_node, "clk_ext2"); + clks[IMX8MM_CLK_EXT3] = of_clk_get_by_name(ccm_node, "clk_ext3"); + clks[IMX8MM_CLK_EXT4] = of_clk_get_by_name(ccm_node, "clk_ext4"); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop"); + base = of_iomap(np, 0); + if (WARN_ON(!base)) + return -ENOMEM; + + clks[IMX8MM_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", base + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_DRAM_PLL_REF_SEL] = imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", base + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_SYS_PLL1_REF_SEL] = imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_SYS_PLL2_REF_SEL] = imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + clks[IMX8MM_SYS_PLL3_REF_SEL] = imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); + + clks[IMX8MM_AUDIO_PLL1] = imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", base, &imx8mm_audio_pll); + clks[IMX8MM_AUDIO_PLL2] = imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx8mm_audio_pll); + clks[IMX8MM_VIDEO_PLL1] = imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx8mm_video_pll); + clks[IMX8MM_DRAM_PLL] = imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mm_dram_pll); + clks[IMX8MM_GPU_PLL] = imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx8mm_gpu_pll); + clks[IMX8MM_VPU_PLL] = imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx8mm_vpu_pll); + clks[IMX8MM_ARM_PLL] = imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mm_arm_pll); + clks[IMX8MM_SYS_PLL1] = imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mm_sys_pll); + clks[IMX8MM_SYS_PLL2] = imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mm_sys_pll); + clks[IMX8MM_SYS_PLL3] = imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mm_sys_pll); + + /* PLL bypass out */ + clks[IMX8MM_AUDIO_PLL1_BYPASS] = imx_clk_mux_flags("audio_pll1_bypass", base, 4, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_AUDIO_PLL2_BYPASS] = imx_clk_mux_flags("audio_pll2_bypass", base + 0x14, 4, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_VIDEO_PLL1_BYPASS] = imx_clk_mux_flags("video_pll1_bypass", base + 0x28, 4, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_DRAM_PLL_BYPASS] = imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_GPU_PLL_BYPASS] = imx_clk_mux_flags("gpu_pll_bypass", base + 0x64, 4, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_VPU_PLL_BYPASS] = imx_clk_mux_flags("vpu_pll_bypass", base + 0x74, 4, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_SYS_PLL1_BYPASS] = imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_SYS_PLL2_BYPASS] = imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX8MM_SYS_PLL3_BYPASS] = imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT); + + /* unbypass all the plls */ + clk_set_parent(clks[IMX8MM_AUDIO_PLL1_BYPASS], clks[IMX8MM_AUDIO_PLL1]); + clk_set_parent(clks[IMX8MM_AUDIO_PLL2_BYPASS], clks[IMX8MM_AUDIO_PLL2]); + clk_set_parent(clks[IMX8MM_VIDEO_PLL1_BYPASS], clks[IMX8MM_VIDEO_PLL1]); + clk_set_parent(clks[IMX8MM_DRAM_PLL_BYPASS], clks[IMX8MM_DRAM_PLL]); + clk_set_parent(clks[IMX8MM_GPU_PLL_BYPASS], clks[IMX8MM_GPU_PLL]); + clk_set_parent(clks[IMX8MM_VPU_PLL_BYPASS], clks[IMX8MM_VPU_PLL]); + clk_set_parent(clks[IMX8MM_ARM_PLL_BYPASS], clks[IMX8MM_ARM_PLL]); + clk_set_parent(clks[IMX8MM_SYS_PLL1_BYPASS], clks[IMX8MM_SYS_PLL1]); + clk_set_parent(clks[IMX8MM_SYS_PLL2_BYPASS], clks[IMX8MM_SYS_PLL2]); + clk_set_parent(clks[IMX8MM_SYS_PLL3_BYPASS], clks[IMX8MM_SYS_PLL3]); + + /* PLL out gate */ + clks[IMX8MM_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base, 13); + clks[IMX8MM_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x14, 13); + clks[IMX8MM_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x28, 13); + clks[IMX8MM_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13); + clks[IMX8MM_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x64, 13); + clks[IMX8MM_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x74, 13); + clks[IMX8MM_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 13); + clks[IMX8MM_SYS_PLL1_OUT] = imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", base + 0x94, 13); + clks[IMX8MM_SYS_PLL2_OUT] = imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", base + 0x104, 13); + clks[IMX8MM_SYS_PLL3_OUT] = imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 13); + + /* SYS PLL fixed output */ + clks[IMX8MM_SYS_PLL1_40M] = imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20); + clks[IMX8MM_SYS_PLL1_80M] = imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10); + clks[IMX8MM_SYS_PLL1_100M] = imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8); + clks[IMX8MM_SYS_PLL1_133M] = imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6); + clks[IMX8MM_SYS_PLL1_160M] = imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5); + clks[IMX8MM_SYS_PLL1_200M] = imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4); + clks[IMX8MM_SYS_PLL1_266M] = imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3); + clks[IMX8MM_SYS_PLL1_400M] = imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2); + clks[IMX8MM_SYS_PLL1_800M] = imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1); + + clks[IMX8MM_SYS_PLL2_50M] = imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20); + clks[IMX8MM_SYS_PLL2_100M] = imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10); + clks[IMX8MM_SYS_PLL2_125M] = imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8); + clks[IMX8MM_SYS_PLL2_166M] = imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6); + clks[IMX8MM_SYS_PLL2_200M] = imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5); + clks[IMX8MM_SYS_PLL2_250M] = imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4); + clks[IMX8MM_SYS_PLL2_333M] = imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3); + clks[IMX8MM_SYS_PLL2_500M] = imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2); + clks[IMX8MM_SYS_PLL2_1000M] = imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1); + + np = ccm_node; + base = of_iomap(np, 0); + if (WARN_ON(!base)) + return -ENOMEM; + + /* Core Slice */ + clks[IMX8MM_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels)); + clks[IMX8MM_CLK_M4_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mm_m4_sels, ARRAY_SIZE(imx8mm_m4_sels)); + clks[IMX8MM_CLK_VPU_SRC] = imx_clk_mux2("vpu_src", base + 0x8100, 24, 3, imx8mm_vpu_sels, ARRAY_SIZE(imx8mm_vpu_sels)); + clks[IMX8MM_CLK_GPU3D_SRC] = imx_clk_mux2("gpu3d_src", base + 0x8180, 24, 3, imx8mm_gpu3d_sels, ARRAY_SIZE(imx8mm_gpu3d_sels)); + clks[IMX8MM_CLK_GPU2D_SRC] = imx_clk_mux2("gpu2d_src", base + 0x8200, 24, 3, imx8mm_gpu2d_sels, ARRAY_SIZE(imx8mm_gpu2d_sels)); + clks[IMX8MM_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28); + clks[IMX8MM_CLK_M4_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28); + clks[IMX8MM_CLK_VPU_CG] = imx_clk_gate3("vpu_cg", "vpu_src", base + 0x8100, 28); + clks[IMX8MM_CLK_GPU3D_CG] = imx_clk_gate3("gpu3d_cg", "gpu3d_src", base + 0x8180, 28); + clks[IMX8MM_CLK_GPU2D_CG] = imx_clk_gate3("gpu2d_cg", "gpu2d_src", base + 0x8200, 28); + clks[IMX8MM_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3); + clks[IMX8MM_CLK_M4_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3); + clks[IMX8MM_CLK_VPU_DIV] = imx_clk_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3); + clks[IMX8MM_CLK_GPU3D_DIV] = imx_clk_divider2("gpu3d_div", "gpu3d_cg", base + 0x8180, 0, 3); + clks[IMX8MM_CLK_GPU2D_DIV] = imx_clk_divider2("gpu2d_div", "gpu2d_cg", base + 0x8200, 0, 3); + + /* BUS */ + clks[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_composite_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800); + clks[IMX8MM_CLK_ENET_AXI] = imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels, base + 0x8880); + clks[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_composite_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900); + clks[IMX8MM_CLK_VPU_BUS] = imx8m_clk_composite("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980); + clks[IMX8MM_CLK_DISP_AXI] = imx8m_clk_composite("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00); + clks[IMX8MM_CLK_DISP_APB] = imx8m_clk_composite("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80); + clks[IMX8MM_CLK_DISP_RTRM] = imx8m_clk_composite("disp_rtrm", imx8mm_disp_rtrm_sels, base + 0x8b00); + clks[IMX8MM_CLK_USB_BUS] = imx8m_clk_composite("usb_bus", imx8mm_usb_bus_sels, base + 0x8b80); + clks[IMX8MM_CLK_GPU_AXI] = imx8m_clk_composite("gpu_axi", imx8mm_gpu_axi_sels, base + 0x8c00); + clks[IMX8MM_CLK_GPU_AHB] = imx8m_clk_composite("gpu_ahb", imx8mm_gpu_ahb_sels, base + 0x8c80); + clks[IMX8MM_CLK_NOC] = imx8m_clk_composite_critical("noc", imx8mm_noc_sels, base + 0x8d00); + clks[IMX8MM_CLK_NOC_APB] = imx8m_clk_composite_critical("noc_apb", imx8mm_noc_apb_sels, base + 0x8d80); + + /* AHB */ + clks[IMX8MM_CLK_AHB] = imx8m_clk_composite_critical("ahb", imx8mm_ahb_sels, base + 0x9000); + clks[IMX8MM_CLK_AUDIO_AHB] = imx8m_clk_composite("audio_ahb", imx8mm_audio_ahb_sels, base + 0x9100); + + /* IPG */ + clks[IMX8MM_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1); + clks[IMX8MM_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb", base + 0x9180, 0, 1); + + /* IP */ + clks[IMX8MM_CLK_DRAM_ALT] = imx8m_clk_composite("dram_alt", imx8mm_dram_alt_sels, base + 0xa000); + clks[IMX8MM_CLK_DRAM_APB] = imx8m_clk_composite("dram_apb", imx8mm_dram_apb_sels, base + 0xa080); + clks[IMX8MM_CLK_VPU_G1] = imx8m_clk_composite("vpu_g1", imx8mm_vpu_g1_sels, base + 0xa100); + clks[IMX8MM_CLK_VPU_G2] = imx8m_clk_composite("vpu_g2", imx8mm_vpu_g2_sels, base + 0xa180); + clks[IMX8MM_CLK_DISP_DTRC] = imx8m_clk_composite("disp_dtrc", imx8mm_disp_dtrc_sels, base + 0xa200); + clks[IMX8MM_CLK_DISP_DC8000] = imx8m_clk_composite("disp_dc8000", imx8mm_disp_dc8000_sels, base + 0xa280); + clks[IMX8MM_CLK_PCIE1_CTRL] = imx8m_clk_composite("pcie1_ctrl", imx8mm_pcie1_ctrl_sels, base + 0xa300); + clks[IMX8MM_CLK_PCIE1_PHY] = imx8m_clk_composite("pcie1_phy", imx8mm_pcie1_phy_sels, base + 0xa380); + clks[IMX8MM_CLK_PCIE1_AUX] = imx8m_clk_composite("pcie1_aux", imx8mm_pcie1_aux_sels, base + 0xa400); + clks[IMX8MM_CLK_DC_PIXEL] = imx8m_clk_composite("dc_pixel", imx8mm_dc_pixel_sels, base + 0xa480); + clks[IMX8MM_CLK_LCDIF_PIXEL] = imx8m_clk_composite("lcdif_pixel", imx8mm_lcdif_pixel_sels, base + 0xa500); + clks[IMX8MM_CLK_SAI1] = imx8m_clk_composite("sai1", imx8mm_sai1_sels, base + 0xa580); + clks[IMX8MM_CLK_SAI2] = imx8m_clk_composite("sai2", imx8mm_sai2_sels, base + 0xa600); + clks[IMX8MM_CLK_SAI3] = imx8m_clk_composite("sai3", imx8mm_sai3_sels, base + 0xa680); + clks[IMX8MM_CLK_SAI4] = imx8m_clk_composite("sai4", imx8mm_sai4_sels, base + 0xa700); + clks[IMX8MM_CLK_SAI5] = imx8m_clk_composite("sai5", imx8mm_sai5_sels, base + 0xa780); + clks[IMX8MM_CLK_SAI6] = imx8m_clk_composite("sai6", imx8mm_sai6_sels, base + 0xa800); + clks[IMX8MM_CLK_SPDIF1] = imx8m_clk_composite("spdif1", imx8mm_spdif1_sels, base + 0xa880); + clks[IMX8MM_CLK_SPDIF2] = imx8m_clk_composite("spdif2", imx8mm_spdif2_sels, base + 0xa900); + clks[IMX8MM_CLK_ENET_REF] = imx8m_clk_composite("enet_ref", imx8mm_enet_ref_sels, base + 0xa980); + clks[IMX8MM_CLK_ENET_TIMER] = imx8m_clk_composite("enet_timer", imx8mm_enet_timer_sels, base + 0xaa00); + clks[IMX8MM_CLK_ENET_PHY_REF] = imx8m_clk_composite("enet_phy", imx8mm_enet_phy_sels, base + 0xaa80); + clks[IMX8MM_CLK_NAND] = imx8m_clk_composite("nand", imx8mm_nand_sels, base + 0xab00); + clks[IMX8MM_CLK_QSPI] = imx8m_clk_composite("qspi", imx8mm_qspi_sels, base + 0xab80); + clks[IMX8MM_CLK_USDHC1] = imx8m_clk_composite("usdhc1", imx8mm_usdhc1_sels, base + 0xac00); + clks[IMX8MM_CLK_USDHC2] = imx8m_clk_composite("usdhc2", imx8mm_usdhc2_sels, base + 0xac80); + clks[IMX8MM_CLK_I2C1] = imx8m_clk_composite("i2c1", imx8mm_i2c1_sels, base + 0xad00); + clks[IMX8MM_CLK_I2C2] = imx8m_clk_composite("i2c2", imx8mm_i2c2_sels, base + 0xad80); + clks[IMX8MM_CLK_I2C3] = imx8m_clk_composite("i2c3", imx8mm_i2c3_sels, base + 0xae00); + clks[IMX8MM_CLK_I2C4] = imx8m_clk_composite("i2c4", imx8mm_i2c4_sels, base + 0xae80); + clks[IMX8MM_CLK_UART1] = imx8m_clk_composite("uart1", imx8mm_uart1_sels, base + 0xaf00); + clks[IMX8MM_CLK_UART2] = imx8m_clk_composite("uart2", imx8mm_uart2_sels, base + 0xaf80); + clks[IMX8MM_CLK_UART3] = imx8m_clk_composite("uart3", imx8mm_uart3_sels, base + 0xb000); + clks[IMX8MM_CLK_UART4] = imx8m_clk_composite("uart4", imx8mm_uart4_sels, base + 0xb080); + clks[IMX8MM_CLK_USB_CORE_REF] = imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100); + clks[IMX8MM_CLK_USB_PHY_REF] = imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180); + clks[IMX8MM_CLK_ECSPI1] = imx8m_clk_composite("ecspi1", imx8mm_ecspi1_sels, base + 0xb280); + clks[IMX8MM_CLK_ECSPI2] = imx8m_clk_composite("ecspi2", imx8mm_ecspi2_sels, base + 0xb300); + clks[IMX8MM_CLK_PWM1] = imx8m_clk_composite("pwm1", imx8mm_pwm1_sels, base + 0xb380); + clks[IMX8MM_CLK_PWM2] = imx8m_clk_composite("pwm2", imx8mm_pwm2_sels, base + 0xb400); + clks[IMX8MM_CLK_PWM3] = imx8m_clk_composite("pwm3", imx8mm_pwm3_sels, base + 0xb480); + clks[IMX8MM_CLK_PWM4] = imx8m_clk_composite("pwm4", imx8mm_pwm4_sels, base + 0xb500); + clks[IMX8MM_CLK_GPT1] = imx8m_clk_composite("gpt1", imx8mm_gpt1_sels, base + 0xb580); + clks[IMX8MM_CLK_WDOG] = imx8m_clk_composite("wdog", imx8mm_wdog_sels, base + 0xb900); + clks[IMX8MM_CLK_WRCLK] = imx8m_clk_composite("wrclk", imx8mm_wrclk_sels, base + 0xb980); + clks[IMX8MM_CLK_CLKO1] = imx8m_clk_composite("clko1", imx8mm_clko1_sels, base + 0xba00); + clks[IMX8MM_CLK_DSI_CORE] = imx8m_clk_composite("dsi_core", imx8mm_dsi_core_sels, base + 0xbb00); + clks[IMX8MM_CLK_DSI_PHY_REF] = imx8m_clk_composite("dsi_phy_ref", imx8mm_dsi_phy_sels, base + 0xbb80); + clks[IMX8MM_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mm_dsi_dbi_sels, base + 0xbc00); + clks[IMX8MM_CLK_USDHC3] = imx8m_clk_composite("usdhc3", imx8mm_usdhc3_sels, base + 0xbc80); + clks[IMX8MM_CLK_CSI1_CORE] = imx8m_clk_composite("csi1_core", imx8mm_csi1_core_sels, base + 0xbd00); + clks[IMX8MM_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mm_csi1_phy_sels, base + 0xbd80); + clks[IMX8MM_CLK_CSI1_ESC] = imx8m_clk_composite("csi1_esc", imx8mm_csi1_esc_sels, base + 0xbe00); + clks[IMX8MM_CLK_CSI2_CORE] = imx8m_clk_composite("csi2_core", imx8mm_csi2_core_sels, base + 0xbe80); + clks[IMX8MM_CLK_CSI2_PHY_REF] = imx8m_clk_composite("csi2_phy_ref", imx8mm_csi2_phy_sels, base + 0xbf00); + clks[IMX8MM_CLK_CSI2_ESC] = imx8m_clk_composite("csi2_esc", imx8mm_csi2_esc_sels, base + 0xbf80); + clks[IMX8MM_CLK_PCIE2_CTRL] = imx8m_clk_composite("pcie2_ctrl", imx8mm_pcie2_ctrl_sels, base + 0xc000); + clks[IMX8MM_CLK_PCIE2_PHY] = imx8m_clk_composite("pcie2_phy", imx8mm_pcie2_phy_sels, base + 0xc080); + clks[IMX8MM_CLK_PCIE2_AUX] = imx8m_clk_composite("pcie2_aux", imx8mm_pcie2_aux_sels, base + 0xc100); + clks[IMX8MM_CLK_ECSPI3] = imx8m_clk_composite("ecspi3", imx8mm_ecspi3_sels, base + 0xc180); + clks[IMX8MM_CLK_PDM] = imx8m_clk_composite("pdm", imx8mm_pdm_sels, base + 0xc200); + clks[IMX8MM_CLK_VPU_H1] = imx8m_clk_composite("vpu_h1", imx8mm_vpu_h1_sels, base + 0xc280); + + /* CCGR */ + clks[IMX8MM_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0); + clks[IMX8MM_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0); + clks[IMX8MM_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0); + clks[IMX8MM_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0); + clks[IMX8MM_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1", base + 0x4100, 0); + clks[IMX8MM_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0); + clks[IMX8MM_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0); + clks[IMX8MM_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0); + clks[IMX8MM_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0); + clks[IMX8MM_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0); + clks[IMX8MM_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0); + clks[IMX8MM_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl", base + 0x4250, 0); + clks[IMX8MM_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0); + clks[IMX8MM_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0); + clks[IMX8MM_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0); + clks[IMX8MM_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0); + clks[IMX8MM_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0); + clks[IMX8MM_CLK_NAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand); + clks[IMX8MM_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus", base + 0x4300, 0, &share_count_nand); + clks[IMX8MM_CLK_SAI1_ROOT] = imx_clk_gate2_shared2("sai1_root_clk", "sai1", base + 0x4330, 0, &share_count_sai1); + clks[IMX8MM_CLK_SAI1_IPG] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0, &share_count_sai1); + clks[IMX8MM_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2", base + 0x4340, 0, &share_count_sai2); + clks[IMX8MM_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", base + 0x4340, 0, &share_count_sai2); + clks[IMX8MM_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3", base + 0x4350, 0, &share_count_sai3); + clks[IMX8MM_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", base + 0x4350, 0, &share_count_sai3); + clks[IMX8MM_CLK_SAI4_ROOT] = imx_clk_gate2_shared2("sai4_root_clk", "sai4", base + 0x4360, 0, &share_count_sai4); + clks[IMX8MM_CLK_SAI4_IPG] = imx_clk_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0, &share_count_sai4); + clks[IMX8MM_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5", base + 0x4370, 0, &share_count_sai5); + clks[IMX8MM_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5); + clks[IMX8MM_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6", base + 0x4380, 0, &share_count_sai6); + clks[IMX8MM_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6); + clks[IMX8MM_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0); + clks[IMX8MM_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0); + clks[IMX8MM_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0); + clks[IMX8MM_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0); + clks[IMX8MM_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_core_ref", base + 0x44d0, 0); + clks[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_gate4("gpu3d_root_clk", "gpu3d_div", base + 0x44f0, 0); + clks[IMX8MM_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0); + clks[IMX8MM_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0); + clks[IMX8MM_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0); + clks[IMX8MM_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0); + clks[IMX8MM_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0); + clks[IMX8MM_CLK_VPU_G1_ROOT] = imx_clk_gate4("vpu_g1_root_clk", "vpu_g1", base + 0x4560, 0); + clks[IMX8MM_CLK_GPU_BUS_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_axi", base + 0x4570, 0); + clks[IMX8MM_CLK_VPU_H1_ROOT] = imx_clk_gate4("vpu_h1_root_clk", "vpu_h1", base + 0x4590, 0); + clks[IMX8MM_CLK_VPU_G2_ROOT] = imx_clk_gate4("vpu_g2_root_clk", "vpu_g2", base + 0x45a0, 0); + clks[IMX8MM_CLK_PDM_ROOT] = imx_clk_gate2_shared2("pdm_root_clk", "pdm", base + 0x45b0, 0, &share_count_pdm); + clks[IMX8MM_CLK_PDM_IPG] = imx_clk_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", base + 0x45b0, 0, &share_count_pdm); + clks[IMX8MM_CLK_DISP_ROOT] = imx_clk_gate2_shared2("disp_root_clk", "disp_dc8000", base + 0x45d0, 0, &share_count_dcss); + clks[IMX8MM_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi", base + 0x45d0, 0, &share_count_dcss); + clks[IMX8MM_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb", base + 0x45d0, 0, &share_count_dcss); + clks[IMX8MM_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm", base + 0x45d0, 0, &share_count_dcss); + clks[IMX8MM_CLK_USDHC3_ROOT] = imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0); + clks[IMX8MM_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0); + clks[IMX8MM_CLK_VPU_DEC_ROOT] = imx_clk_gate4("vpu_dec_root_clk", "vpu_bus", base + 0x4630, 0); + clks[IMX8MM_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0); + clks[IMX8MM_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0); + clks[IMX8MM_CLK_SDMA3_ROOT] = imx_clk_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0); + clks[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_gate4("gpu2d_root_clk", "gpu2d_div", base + 0x4660, 0); + clks[IMX8MM_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core", base + 0x4650, 0); + + clks[IMX8MM_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc_24m", 1, 8); + + clks[IMX8MM_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4); + clks[IMX8MM_CLK_DRAM_CORE] = imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mm_dram_core_sels, ARRAY_SIZE(imx8mm_dram_core_sels), CLK_IS_CRITICAL); + + clks[IMX8MM_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_div", + clks[IMX8MM_CLK_A53_DIV], + clks[IMX8MM_CLK_A53_SRC], + clks[IMX8MM_ARM_PLL_OUT], + clks[IMX8MM_CLK_24M]); + + imx_check_clocks(clks, ARRAY_SIZE(clks)); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + if (ret < 0) { + pr_err("failed to register clks for i.MX8MM\n"); + return -EINVAL; + } + + imx_register_uart_clocks(uart_clks); + + return 0; +} +CLK_OF_DECLARE_DRIVER(imx8mm, "fsl,imx8mm-ccm", imx8mm_clocks_init); -- cgit v1.2.3 From 81bf81e7d3f14088f94f9d8a6cddc8186967fd6c Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 30 Jan 2019 20:17:25 +0000 Subject: clk: imx8mq: Add missing M4 clocks The clocks list is missing the clocks for the M4 core. Signed-off-by: Carlo Caione Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mq.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 398ab0bcd9de..c02c43fcb892 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -48,6 +48,9 @@ static const char * const dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_re static const char * const 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 * const imx8mq_arm_m4_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_250m", "sys1_pll_266m", + "sys1_pll_800m", "audio_pll1_out", "video_pll1_out", "sys3_pll2_out", }; + static const char * const 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", }; @@ -396,15 +399,19 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) /* 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_M4_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mq_arm_m4_sels, ARRAY_SIZE(imx8mq_arm_m4_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_M4_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28); 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_M4_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 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); -- cgit v1.2.3 From 0bfed63baf55fd490bff03af57943b6200ccc45f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 30 Jan 2019 17:21:02 -0200 Subject: clk: imx8mq: Fix the CLKO2 source select list The CLKO2 clock source select list is the following as per the i.MX8M Reference Manual: 000 - 25M_REF_CLK 001 - SYSTEM_PLL2_DIV5 010 - SYSTEM_PLL1_DIV2 011 - SYSTEM_PLL2_DIV6 100 - SYSTEM_PLL3_CLK 101 - AUDIO_PLL1_CLK 110 - VIDEO_PLL1_CLK 111 - 32K_REF_CLK However, in imx8mq_clko2_sels[] only the first four entries are correct. Fix it by adding the missing "sys3_pll2_out" entry in order to match the description from the manual. Fixes: b80522040cd3f ("clk: imx: Add clock driver for i.MX8MQ CCM") Reported-by: Rogerio Pimentel Signed-off-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index c02c43fcb892..cd904764212b 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -267,8 +267,8 @@ static const char * const imx8mq_ecspi3_sels[] = {"osc_25m", "sys2_pll_200m", "s "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", }; static const char * const imx8mq_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; -static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_400m", "sys2_pll_166m", "audio_pll1_out", - "video_pll1_out", "ckil", }; +static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_400m", "sys2_pll_166m", + "sys3_pll2_out", "audio_pll1_out", "video_pll1_out", "ckil", }; static struct clk_onecell_data clk_data; -- cgit v1.2.3 From 202ce5afe51e883f94736310997ea1c73219eb36 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 30 Jan 2019 22:20:56 -0200 Subject: clk: imx8mq: Add support for the CLKO1 clock Add the entry for the CLKO1 clock. Signed-off-by: Fabio Estevam Reviewed-by: Abel Vesa Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mq.c | 3 +++ include/dt-bindings/clock/imx8mq-clock.h | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index cd904764212b..897740f0a012 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -267,6 +267,8 @@ static const char * const imx8mq_ecspi3_sels[] = {"osc_25m", "sys2_pll_200m", "s "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", }; static const char * const imx8mq_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; +static const char * const imx8mq_clko1_sels[] = {"osc_25m", "sys1_pll_800m", "osc_27m", "sys1_pll_200m", + "audio_pll2_out", "sys2_pll_500m", "vpu_pll_out", "sys1_pll_80m", }; static const char * const imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_400m", "sys2_pll_166m", "sys3_pll2_out", "audio_pll1_out", "video_pll1_out", "ckil", }; @@ -486,6 +488,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) 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_CLKO1] = imx8m_clk_composite("clko1", imx8mq_clko1_sels, base + 0xba00); 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); diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h index 04f7ac345984..74f80b26f679 100644 --- a/include/dt-bindings/clock/imx8mq-clock.h +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -391,5 +391,7 @@ #define IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK 267 -#define IMX8MQ_CLK_END 268 +#define IMX8MQ_CLK_CLKO1 268 + +#define IMX8MQ_CLK_END 269 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */ -- cgit v1.2.3 From ad18bbf369a6a49633f50be4d1bcc9b5aad422fc Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 15 Feb 2019 17:48:43 +0000 Subject: clk: imx: imx8mq: Fix the rate propagation for arm pll The arm pll bypass needs to propagate the rate upwards in order for the cpufreq to work. Fixes: b80522040cd3f ("clk: imx: Add clock driver for i.MX8MQ CCM") Signed-off-by: Abel Vesa Reviewed-by: Lucas Stach Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 897740f0a012..90986ddc0f37 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -345,7 +345,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) 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_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT); 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)); -- cgit v1.2.3 From 45a359e80d9b81b0fc3d9612053a86fc52a5f4b9 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 15 Feb 2019 17:48:45 +0000 Subject: dt-bindings: imx8mq-clock: Add the missing ARM clock Add the missing ARM clock which will be used by cpufreq Signed-off-by: Abel Vesa Reviewed-by: Lucas Stach [sboyd@kernel.org: Fixed numbering in dt header] Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/imx8mq-clock.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h index 74f80b26f679..491e39c146be 100644 --- a/include/dt-bindings/clock/imx8mq-clock.h +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -392,6 +392,7 @@ #define IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK 267 #define IMX8MQ_CLK_CLKO1 268 +#define IMX8MQ_CLK_ARM 269 -#define IMX8MQ_CLK_END 269 +#define IMX8MQ_CLK_END 270 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */ -- cgit v1.2.3 From db27e40b27f18d66d9e01745211ac87bc03a14b7 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 15 Feb 2019 17:48:46 +0000 Subject: clk: imx8mq: Add the missing ARM clock Add the ARM clock as imx_clk_cpu type. Will be used by cpufreq. Signed-off-by: Abel Vesa Reviewed-by: Lucas Stach Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mq.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 90986ddc0f37..01c771f441cb 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -568,6 +568,12 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) 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); + clks[IMX8MQ_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_div", + clks[IMX8MQ_CLK_A53_DIV], + clks[IMX8MQ_CLK_A53_SRC], + clks[IMX8MQ_ARM_PLL_OUT], + clks[IMX8MQ_SYS1_PLL_800M]); + for (i = 0; i < IMX8MQ_CLK_END; i++) if (IS_ERR(clks[i])) pr_err("i.MX8mq clk %u register failed with %ld\n", -- cgit v1.2.3 From e61b30bb34b6206f76e623269a41b65cd3989fff Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Wed, 20 Feb 2019 16:09:20 +0000 Subject: clk: renesas: r8a774c0: Fix LAST_DT_CORE_CLK Enum LAST_DT_CORE_CLK needs updating as R8A774C0_CLK_CANFD was recently added and it's the core clock with the highest index. Signed-off-by: Fabrizio Castro Reviewed-by: Chris Paterson Fixes: 2a6efbc6da5d248c ("clk: renesas: r8a774c0: Add missing CANFD clock") Reviewed-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd --- drivers/clk/renesas/r8a774c0-cpg-mssr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r8a774c0-cpg-mssr.c b/drivers/clk/renesas/r8a774c0-cpg-mssr.c index aeadb4d66f3e..34e274f2a273 100644 --- a/drivers/clk/renesas/r8a774c0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774c0-cpg-mssr.c @@ -22,7 +22,7 @@ enum clk_ids { /* Core Clock Outputs exported to DT */ - LAST_DT_CORE_CLK = R8A774C0_CLK_CPEX, + LAST_DT_CORE_CLK = R8A774C0_CLK_CANFD, /* External Input Clocks */ CLK_EXTAL, -- cgit v1.2.3 From 5f0b6216ea381b43c0dff88702d6cc5673d63922 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 21 Feb 2019 12:45:51 +0100 Subject: clk: samsung: exynos5: Fix possible NULL pointer exception on platform_device_alloc() failure During initialization of subdevices if platform_device_alloc() failed, returned NULL pointer will be later dereferenced. Add proper error paths to exynos5_clk_register_subcmu(). The return value of this function is still ignored because at this stage of init there is nothing we can do. Fixes: b06a532bf1fa ("clk: samsung: Add Exynos5 sub-CMU clock driver") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-exynos5-subcmu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c index 93306283d764..d07ef26bd052 100644 --- a/drivers/clk/samsung/clk-exynos5-subcmu.c +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -136,15 +136,21 @@ static int __init exynos5_clk_register_subcmu(struct device *parent, { struct of_phandle_args genpdspec = { .np = pd_node }; struct platform_device *pdev; + int ret; pdev = platform_device_alloc(info->pd_name, -1); + if (!pdev) + return -ENOMEM; + pdev->dev.parent = parent; pdev->driver_override = "exynos5-subcmu"; platform_set_drvdata(pdev, (void *)info); of_genpd_add_device(&genpdspec, &pdev->dev); - platform_device_add(pdev); + ret = platform_device_add(pdev); + if (ret) + platform_device_put(pdev); - return 0; + return ret; } static int __init exynos5_clk_probe(struct platform_device *pdev) -- cgit v1.2.3 From 785c9f411eb2d9a6076d3511c631587d5e676bf3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 21 Feb 2019 12:45:52 +0100 Subject: clk: samsung: exynos5: Fix kfree() of const memory on setting driver_override Platform driver driver_override field should not be initialized from const memory because the core later kfree() it. If driver_override is manually set later through sysfs, kfree() of old value leads to: $ echo "new_value" > /sys/bus/platform/drivers/.../driver_override kernel BUG at ../mm/slub.c:3960! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM ... (kfree) from [] (platform_set_driver_override+0x84/0xac) (platform_set_driver_override) from [] (driver_override_store+0x20/0x34) (driver_override_store) from [] (kernfs_fop_write+0x100/0x1dc) (kernfs_fop_write) from [] (__vfs_write+0x2c/0x17c) (__vfs_write) from [] (vfs_write+0xa4/0x188) (vfs_write) from [] (ksys_write+0x4c/0xac) (ksys_write) from [] (ret_fast_syscall+0x0/0x28) The clk-exynos5-subcmu driver uses override only for the purpose of creating meaningful names for children devices (matching names of power domains, e.g. DISP, MFC). The driver_override was not developed for this purpose so just switch to default names of devices to fix the issue. Fixes: b06a532bf1fa ("clk: samsung: Add Exynos5 sub-CMU clock driver") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-exynos5-subcmu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c index d07ef26bd052..8ae44b5db4c2 100644 --- a/drivers/clk/samsung/clk-exynos5-subcmu.c +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -138,12 +138,11 @@ static int __init exynos5_clk_register_subcmu(struct device *parent, struct platform_device *pdev; int ret; - pdev = platform_device_alloc(info->pd_name, -1); + pdev = platform_device_alloc("exynos5-subcmu", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; pdev->dev.parent = parent; - pdev->driver_override = "exynos5-subcmu"; platform_set_drvdata(pdev, (void *)info); of_genpd_add_device(&genpdspec, &pdev->dev); ret = platform_device_add(pdev); -- cgit v1.2.3 From 0612fe604d862631da7f94224dd6ea633b722914 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 11 Feb 2019 12:15:31 -0600 Subject: clk: samsung: s3c2443: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warnings: drivers/clk/samsung/clk-s3c2443.c: In function ‘s3c2443_common_clk_init’: drivers/clk/samsung/clk-s3c2443.c:390:3: warning: this statement may fall through [-Wimplicit-fallthrough=] samsung_clk_register_alias(ctx, s3c2450_aliases, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ARRAY_SIZE(s3c2450_aliases)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/clk/samsung/clk-s3c2443.c:393:2: note: here case S3C2416: ^~~~ Warning level 3 was used: -Wimplicit-fallthrough=3 Notice that, in this particular case, the code comment is modified in accordance with what GCC is expecting to find. This patch is part of the ongoing efforts to enable -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-s3c2443.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index 884067e4f1a1..f38f0e24e3b6 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -389,7 +389,7 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, ARRAY_SIZE(s3c2450_gates)); samsung_clk_register_alias(ctx, s3c2450_aliases, ARRAY_SIZE(s3c2450_aliases)); - /* fall through, as s3c2450 extends the s3c2416 clocks */ + /* fall through - as s3c2450 extends the s3c2416 clocks */ case S3C2416: samsung_clk_register_div(ctx, s3c2416_dividers, ARRAY_SIZE(s3c2416_dividers)); -- cgit v1.2.3 From 521282237b9d78b9bff423ec818becd4c95841c2 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 8 Feb 2019 11:25:23 +0900 Subject: clk: uniphier: Fix update register for CPU-gear Need to set the update bit in UNIPHIER_CLK_CPUGEAR_UPD to update the CPU-gear value. Fixes: d08f1f0d596c ("clk: uniphier: add CPU-gear change (cpufreq) support") Cc: linux-stable@vger.kernel.org Signed-off-by: Kunihiko Hayashi Acked-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/uniphier/clk-uniphier-cpugear.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/uniphier/clk-uniphier-cpugear.c b/drivers/clk/uniphier/clk-uniphier-cpugear.c index ec11f55594ad..5d2d42b7e182 100644 --- a/drivers/clk/uniphier/clk-uniphier-cpugear.c +++ b/drivers/clk/uniphier/clk-uniphier-cpugear.c @@ -47,7 +47,7 @@ static int uniphier_clk_cpugear_set_parent(struct clk_hw *hw, u8 index) return ret; ret = regmap_write_bits(gear->regmap, - gear->regbase + UNIPHIER_CLK_CPUGEAR_SET, + gear->regbase + UNIPHIER_CLK_CPUGEAR_UPD, UNIPHIER_CLK_CPUGEAR_UPD_BIT, UNIPHIER_CLK_CPUGEAR_UPD_BIT); if (ret) -- cgit v1.2.3 From ed11aff3eef35440e23a7cf9692f84ab6233e527 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 21 Jan 2019 07:31:28 +0100 Subject: dt-bindings: marvell,mmp2: Add clock id for the LCDC clock The peripheral clock is required for access the the LCDC registers. It is in fact separate from the "AXI clock" that is optionally used to generate the pixel clock and as such requires a separate clock id. Link: https://lists.freedesktop.org/archives/dri-devel/2019-January/203975.html Signed-off-by: Lubomir Rintel Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/marvell,mmp2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/clock/marvell,mmp2.h b/include/dt-bindings/clock/marvell,mmp2.h index 228a5e234af0..e785c6eb3561 100644 --- a/include/dt-bindings/clock/marvell,mmp2.h +++ b/include/dt-bindings/clock/marvell,mmp2.h @@ -71,6 +71,7 @@ #define MMP2_CLK_CCIC1_MIX 117 #define MMP2_CLK_CCIC1_PHY 118 #define MMP2_CLK_CCIC1_SPHY 119 +#define MMP2_CLK_DISP0_LCDC 120 #define MMP2_NR_CLKS 200 #endif -- cgit v1.2.3 From 0ea8cbc15d802564e89ceab65ea4dedabf406fd2 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 21 Jan 2019 07:31:29 +0100 Subject: clk: mmp2: separate LCDC peripheral clk form the display clock These are in fact two clocks, they shouldn't be exposed as one. One is required for accessing LCD controller registers (peripheral clock), while other (AXI clock) can be optionally used as a pixel clock source for the panel. LCDC can alternatively use different clocks than the Display 1 AXI clock for generating the pixel clock: the second AXI clock (fixed in this commit too), the HDMI PLL, or the AXI bus clock. They should really be controlled independently. Link: https://lists.freedesktop.org/archives/dri-devel/2019-January/203975.html Signed-off-by: Lubomir Rintel Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-of-mmp2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index d083b860f083..a60a1be937ad 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -229,9 +229,10 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = { {MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP2_CLK_SDH2, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, {MMP2_CLK_SDH3, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, - {MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, + {MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x09, 0x09, 0x0, 0, &disp0_lock}, + {MMP2_CLK_DISP0_LCDC, "disp0_lcdc_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x12, 0x12, 0x0, 0, &disp0_lock}, {MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock}, - {MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock}, + {MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x09, 0x09, 0x0, 0, &disp1_lock}, {MMP2_CLK_CCIC_ARBITER, "ccic_arbiter", "vctcxo", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1800, 0x1800, 0x0, 0, &ccic0_lock}, {MMP2_CLK_CCIC0, "ccic0_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock}, {MMP2_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock}, -- cgit v1.2.3 From 04053f4d23a41b9383dcea4da302fd43f673afb3 Mon Sep 17 00:00:00 2001 From: David Dai Date: Thu, 24 Jan 2019 16:47:00 -0800 Subject: clk: qcom: clk-rpmh: Add IPA clock support The clk-rpmh driver only supports on and off RPMh clock resources. Let's extend the driver by adding support for clocks that are managed by a different type of RPMh resource known as Bus Clock Manager(BCM). The BCM is a configurable shared resource aggregator that scales performance based on a set of frequency points. The Qualcomm IP Accelerator (IPA) clock is an example of a resource that is managed by the BCM and this a requirement from the IPA driver in order to scale its core clock. Signed-off-by: David Dai Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rpmh.c | 146 ++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/qcom,rpmh.h | 1 + 2 files changed, 147 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 9f4fc7773fb2..c3fd632af119 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -18,6 +18,31 @@ #define CLK_RPMH_ARC_EN_OFFSET 0 #define CLK_RPMH_VRM_EN_OFFSET 4 +#define BCM_TCS_CMD_COMMIT_MASK 0x40000000 +#define BCM_TCS_CMD_VALID_SHIFT 29 +#define BCM_TCS_CMD_VOTE_MASK 0x3fff +#define BCM_TCS_CMD_VOTE_SHIFT 0 + +#define BCM_TCS_CMD(valid, vote) \ + (BCM_TCS_CMD_COMMIT_MASK | \ + ((valid) << BCM_TCS_CMD_VALID_SHIFT) | \ + ((vote & BCM_TCS_CMD_VOTE_MASK) \ + << BCM_TCS_CMD_VOTE_SHIFT)) + +/** + * struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager(BCM) + * @unit: divisor used to convert Hz value to an RPMh msg + * @width: multiplier used to convert Hz value to an RPMh msg + * @vcd: virtual clock domain that this bcm belongs to + * @reserved: reserved to pad the struct + */ +struct bcm_db { + __le32 unit; + __le16 width; + u8 vcd; + u8 reserved; +}; + /** * struct clk_rpmh - individual rpmh clock data structure * @hw: handle between common and hardware-specific interfaces @@ -29,6 +54,7 @@ * @aggr_state: rpmh clock aggregated state * @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh * @valid_state_mask: mask to determine the state of the rpmh clock + * @unit: divisor to convert rate to rpmh msg in magnitudes of Khz * @dev: device to which it is attached * @peer: pointer to the clock rpmh sibling */ @@ -42,6 +68,7 @@ struct clk_rpmh { u32 aggr_state; u32 last_sent_aggr_state; u32 valid_state_mask; + u32 unit; struct device *dev; struct clk_rpmh *peer; }; @@ -98,6 +125,17 @@ static DEFINE_MUTEX(rpmh_clk_lock); __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ CLK_RPMH_VRM_EN_OFFSET, 1, _div) +#define DEFINE_CLK_RPMH_BCM(_platform, _name, _res_name) \ + static struct clk_rpmh _platform##_##_name = { \ + .res_name = _res_name, \ + .valid_state_mask = BIT(RPMH_ACTIVE_ONLY_STATE), \ + .div = 1, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpmh_bcm_ops, \ + .name = #_name, \ + }, \ + } + static inline struct clk_rpmh *to_clk_rpmh(struct clk_hw *_hw) { return container_of(_hw, struct clk_rpmh, hw); @@ -210,6 +248,96 @@ static const struct clk_ops clk_rpmh_ops = { .recalc_rate = clk_rpmh_recalc_rate, }; +static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) +{ + struct tcs_cmd cmd = { 0 }; + u32 cmd_state; + int ret; + + mutex_lock(&rpmh_clk_lock); + + cmd_state = 0; + if (enable) { + cmd_state = 1; + if (c->aggr_state) + cmd_state = c->aggr_state; + } + + if (c->last_sent_aggr_state == cmd_state) { + mutex_unlock(&rpmh_clk_lock); + return 0; + } + + cmd.addr = c->res_addr; + cmd.data = BCM_TCS_CMD(enable, cmd_state); + + ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1); + if (ret) { + dev_err(c->dev, "set active state of %s failed: (%d)\n", + c->res_name, ret); + mutex_unlock(&rpmh_clk_lock); + return ret; + } + + c->last_sent_aggr_state = cmd_state; + + mutex_unlock(&rpmh_clk_lock); + + return 0; +} + +static int clk_rpmh_bcm_prepare(struct clk_hw *hw) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + return clk_rpmh_bcm_send_cmd(c, true); +}; + +static void clk_rpmh_bcm_unprepare(struct clk_hw *hw) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + clk_rpmh_bcm_send_cmd(c, false); +}; + +static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + c->aggr_state = rate / c->unit; + /* + * Since any non-zero value sent to hw would result in enabling the + * clock, only send the value if the clock has already been prepared. + */ + if (clk_hw_is_prepared(hw)) + clk_rpmh_bcm_send_cmd(c, true); + + return 0; +}; + +static long clk_rpmh_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return rate; +} + +static unsigned long clk_rpmh_bcm_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_rpmh *c = to_clk_rpmh(hw); + + return c->aggr_state * c->unit; +} + +static const struct clk_ops clk_rpmh_bcm_ops = { + .prepare = clk_rpmh_bcm_prepare, + .unprepare = clk_rpmh_bcm_unprepare, + .set_rate = clk_rpmh_bcm_set_rate, + .round_rate = clk_rpmh_round_rate, + .recalc_rate = clk_rpmh_bcm_recalc_rate, +}; + /* Resource name must match resource id present in cmd-db. */ DEFINE_CLK_RPMH_ARC(sdm845, bi_tcxo, bi_tcxo_ao, "xo.lvl", 0x3, 2); DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk2, ln_bb_clk2_ao, "lnbclka2", 2); @@ -217,6 +345,7 @@ DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk3, ln_bb_clk3_ao, "lnbclka3", 2); DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1); DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1); DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1); +DEFINE_CLK_RPMH_BCM(sdm845, ipa, "IP0"); static struct clk_hw *sdm845_rpmh_clocks[] = { [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, @@ -231,6 +360,7 @@ static struct clk_hw *sdm845_rpmh_clocks[] = { [RPMH_RF_CLK2_A] = &sdm845_rf_clk2_ao.hw, [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, + [RPMH_IPA_CLK] = &sdm845_ipa.hw, }; static const struct clk_rpmh_desc clk_rpmh_sdm845 = { @@ -267,6 +397,8 @@ static int clk_rpmh_probe(struct platform_device *pdev) for (i = 0; i < desc->num_clks; i++) { u32 res_addr; + size_t aux_data_len; + const struct bcm_db *data; rpmh_clk = to_clk_rpmh(hw_clks[i]); res_addr = cmd_db_read_addr(rpmh_clk->res_name); @@ -275,6 +407,20 @@ static int clk_rpmh_probe(struct platform_device *pdev) rpmh_clk->res_name); return -ENODEV; } + + data = cmd_db_read_aux_data(rpmh_clk->res_name, &aux_data_len); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + dev_err(&pdev->dev, + "error reading RPMh aux data for %s (%d)\n", + rpmh_clk->res_name, ret); + return ret; + } + + /* Convert unit from Khz to Hz */ + if (aux_data_len == sizeof(*data)) + rpmh_clk->unit = le32_to_cpu(data->unit) * 1000ULL; + rpmh_clk->res_addr += res_addr; rpmh_clk->dev = &pdev->dev; diff --git a/include/dt-bindings/clock/qcom,rpmh.h b/include/dt-bindings/clock/qcom,rpmh.h index f48fbd6f2095..edcab3f7b7d3 100644 --- a/include/dt-bindings/clock/qcom,rpmh.h +++ b/include/dt-bindings/clock/qcom,rpmh.h @@ -18,5 +18,6 @@ #define RPMH_RF_CLK2_A 9 #define RPMH_RF_CLK3 10 #define RPMH_RF_CLK3_A 11 +#define RPMH_IPA_CLK 12 #endif -- cgit v1.2.3 From c0189feeade0f02a6cdac3b27b5e9c52f9930fc2 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 11 Feb 2019 14:58:18 +0100 Subject: clk: clk-gpio: add support for sleeping GPIOs in gpio-gate-clk The current implementation of gpio-gate-clk enables/disables the clock using the GPIO in the ->enable() and ->disable() clock callbacks. This requires the GPIO to be configurable in atomic contexts. While it is the case for most memory-mapped GPIO controllers, it is not the case for GPIO expanders on I2C or SPI. This commit extends the gpio-gate-clk to check whether the GPIO calls require sleeping or not. If sleeping is not required, the current implementation based on ->enable()/->disable() is kept. However, if sleeping is needed, we instead implement the logic in the ->prepare() and ->unprepare() hooks. Thanks to this, a gate clock connected to a GPIO on a GPIO expander can be controlled with the existing driver. Signed-off-by: Thomas Petazzoni [sboyd@kernel.org: Mark clk ops static] Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 25eed3e0251f..c2f07f0d077c 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -58,6 +58,35 @@ const struct clk_ops clk_gpio_gate_ops = { }; EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); +static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value_cansleep(clk->gpiod, 1); + + return 0; +} + +static void clk_sleeping_gpio_gate_unprepare(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value_cansleep(clk->gpiod, 0); +} + +static int clk_sleeping_gpio_gate_is_prepared(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + return gpiod_get_value_cansleep(clk->gpiod); +} + +static const struct clk_ops clk_sleeping_gpio_gate_ops = { + .prepare = clk_sleeping_gpio_gate_prepare, + .unprepare = clk_sleeping_gpio_gate_unprepare, + .is_prepared = clk_sleeping_gpio_gate_is_prepared, +}; + /** * DOC: basic clock multiplexer which can be controlled with a gpio output * Traits of this clock: @@ -144,10 +173,16 @@ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name, const char *parent_name, struct gpio_desc *gpiod, unsigned long flags) { + const struct clk_ops *ops; + + if (gpiod_cansleep(gpiod)) + ops = &clk_sleeping_gpio_gate_ops; + else + ops = &clk_gpio_gate_ops; + return clk_register_gpio(dev, name, (parent_name ? &parent_name : NULL), - (parent_name ? 1 : 0), gpiod, flags, - &clk_gpio_gate_ops); + (parent_name ? 1 : 0), gpiod, flags, ops); } EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate); -- cgit v1.2.3 From 5ae51d67aec95f6f9386aa8dd5db424964895575 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 11 Feb 2019 14:59:07 -0800 Subject: clk: clk-twl6040: Fix imprecise external abort for pdmclk I noticed that modprobe clk-twl6040 can fail after a cold boot with: abe_cm:clk:0010:0: failed to enable ... Unhandled fault: imprecise external abort (0x1406) at 0xbe896b20 WARNING: CPU: 1 PID: 29 at drivers/clk/clk.c:828 clk_core_disable_lock+0x18/0x24 ... (clk_core_disable_lock) from [] (_disable_clocks+0x18/0x90) (_disable_clocks) from [] (_idle+0x17c/0x244) (_idle) from [] (omap_hwmod_idle+0x24/0x44) (omap_hwmod_idle) from [] (sysc_runtime_suspend+0x48/0x108) (sysc_runtime_suspend) from [] (__rpm_callback+0x144/0x1d8) (__rpm_callback) from [] (rpm_callback+0x20/0x80) (rpm_callback) from [] (rpm_suspend+0x120/0x694) (rpm_suspend) from [] (__pm_runtime_idle+0x60/0x84) (__pm_runtime_idle) from [] (sysc_probe+0x874/0xf2c) (sysc_probe) from [] (platform_drv_probe+0x48/0x98) After searching around for a similar issue, I came across an earlier fix that never got merged upstream in the Android tree for glass-omap-xrr02. There is patch "MFD: twl6040-codec: Implement PDMCLK cold temp errata" by Misael Lopez Cruz . Based on my observations, this fix is also needed when cold booting devices, and not just for deeper idle modes. Since we now have a clock driver for pdmclk, let's fix the issue in twl6040_pdmclk_prepare(). Cc: Misael Lopez Cruz Cc: Peter Ujfalusi Signed-off-by: Tony Lindgren Acked-by: Peter Ujfalusi Cc: Signed-off-by: Stephen Boyd --- drivers/clk/clk-twl6040.c | 53 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index ea846f77750b..0cad5748bf0e 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -41,6 +41,43 @@ static int twl6040_pdmclk_is_prepared(struct clk_hw *hw) return pdmclk->enabled; } +static int twl6040_pdmclk_reset_one_clock(struct twl6040_pdmclk *pdmclk, + unsigned int reg) +{ + const u8 reset_mask = TWL6040_HPLLRST; /* Same for HPPLL and LPPLL */ + int ret; + + ret = twl6040_set_bits(pdmclk->twl6040, reg, reset_mask); + if (ret < 0) + return ret; + + ret = twl6040_clear_bits(pdmclk->twl6040, reg, reset_mask); + if (ret < 0) + return ret; + + return 0; +} + +/* + * TWL6040A2 Phoenix Audio IC erratum #6: "PDM Clock Generation Issue At + * Cold Temperature". This affects cold boot and deeper idle states it + * seems. The workaround consists of resetting HPPLL and LPPLL. + */ +static int twl6040_pdmclk_quirk_reset_clocks(struct twl6040_pdmclk *pdmclk) +{ + int ret; + + ret = twl6040_pdmclk_reset_one_clock(pdmclk, TWL6040_REG_HPPLLCTL); + if (ret) + return ret; + + ret = twl6040_pdmclk_reset_one_clock(pdmclk, TWL6040_REG_LPPLLCTL); + if (ret) + return ret; + + return 0; +} + static int twl6040_pdmclk_prepare(struct clk_hw *hw) { struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk, @@ -48,8 +85,20 @@ static int twl6040_pdmclk_prepare(struct clk_hw *hw) int ret; ret = twl6040_power(pdmclk->twl6040, 1); - if (!ret) - pdmclk->enabled = 1; + if (ret) + return ret; + + ret = twl6040_pdmclk_quirk_reset_clocks(pdmclk); + if (ret) + goto out_err; + + pdmclk->enabled = 1; + + return 0; + +out_err: + dev_err(pdmclk->dev, "%s: error %i\n", __func__, ret); + twl6040_power(pdmclk->twl6040, 0); return ret; } -- cgit v1.2.3 From 749c9e553e1f063eb132a78d80225532cbfedb80 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:41 +0100 Subject: clk: stm32mp1: parent clocks update Fixes parent clock for axi, fdcan, sai and adc12 clocks. Fixes: e51d297e9a92 ("clk: stm32mp1: add Sub System clocks") Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 6a31f7f434ce..be2ed35977ca 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -121,7 +121,7 @@ static const char * const cpu_src[] = { }; static const char * const axi_src[] = { - "ck_hsi", "ck_hse", "pll2_p", "pll3_p" + "ck_hsi", "ck_hse", "pll2_p" }; static const char * const per_src[] = { @@ -225,19 +225,19 @@ static const char * const usart6_src[] = { }; static const char * const fdcan_src[] = { - "ck_hse", "pll3_q", "pll4_q" + "ck_hse", "pll3_q", "pll4_q", "pll4_r" }; static const char * const sai_src[] = { - "pll4_q", "pll3_q", "i2s_ckin", "ck_per" + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" }; static const char * const sai2_src[] = { - "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb" + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r" }; static const char * const adc12_src[] = { - "pll4_q", "ck_per" + "pll4_r", "ck_per", "pll3_q" }; static const char * const dsi_src[] = { -- cgit v1.2.3 From 72cfd1ad1057f16fc614861b3c271597995e57ba Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:42 +0100 Subject: clk: stm32mp1: add CLK_SET_RATE_NO_REPARENT to Kernel clocks STM32MP1 clock IP offers lots of Kernel clocks that are shared by multiple IP's at the same time. Then boot loader applies a clock tree that allows to use all IP's at same time and with the maximum of performance. Not change parents on a change rate on kernel clocks ensures the integrity of the system. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index be2ed35977ca..e72079de83f4 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1286,10 +1286,11 @@ _clk_stm32_register_composite(struct device *dev, MGATE_MP1(_id, _name, _parent, _flags, _mgate) #define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ - COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE | _flags,\ - _MGATE_MP1(_mgate),\ - _MMUX(_mmux),\ - _NO_DIV) + COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\ + CLK_SET_RATE_NO_REPARENT | _flags,\ + _MGATE_MP1(_mgate),\ + _MMUX(_mmux),\ + _NO_DIV) enum { G_SAI1, @@ -1952,7 +1953,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), - COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE, + COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, _NO_GATE, _MMUX(M_ETHCK), _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), -- cgit v1.2.3 From c488b24f862787dedbf2578e0bc622a74ac64f0f Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:43 +0100 Subject: clk: stm32mp1: set ck_csi as critical clock ck_csi is used for IO compensation so it should be considered as "always-on" and kept on. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index e72079de83f4..f9b7d5e9491d 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1661,7 +1661,9 @@ static const struct clock_config stm32mp1_clock_cfg[] = { /* External / Internal Oscillators */ GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), - GATE_MP1(CK_CSI, "ck_csi", "clk-csi", 0, RCC_OCENSETR, 4, 0), + /* ck_csi is used by IO compensation and should be critical */ + GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL, + RCC_OCENSETR, 4, 0), GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0), GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), -- cgit v1.2.3 From 140fc4e406fac420b978a0ef2ee1fe3c641a6ae4 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:44 +0100 Subject: clk: stm32mp1: fix mcu divider table index 8: ck_mcu is divided by 256 (not 512) Fixes: e51d297e9a92 ("clk: stm32mp1: add Sub System clocks") Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index f9b7d5e9491d..8b4e01af4848 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -269,7 +269,7 @@ static const struct clk_div_table axi_div_table[] = { static const struct clk_div_table mcu_div_table[] = { { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 }, - { 8, 512 }, { 9, 512 }, { 10, 512}, { 11, 512 }, + { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 }, { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, { 0 }, }; -- cgit v1.2.3 From d3f2e33c875de5052e032a9eefa64c897a930ed1 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:45 +0100 Subject: clk: stm32mp1: fix HSI divider flag The divider of HSI (clk-hsi-div) is power of two divider. Fixes: 9bee94e7b7da ("clk: stm32mp1: Introduce STM32MP1 clock driver") Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 8b4e01af4848..8958bc11ff05 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1656,8 +1656,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { static const struct clock_config stm32mp1_clock_cfg[] = { /* Oscillator divider */ - DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, - CLK_DIVIDER_READ_ONLY), + DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO, + RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), /* External / Internal Oscillators */ GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), -- cgit v1.2.3 From f9b76fd24d0a0cd7b3d9309b93c36c9c32526b00 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:46 +0100 Subject: clk: stm32mp1: remove unnecessary CLK_DIVIDER_ALLOW_ZERO flag The divisor of ethptp_k and ck_hse_rtc clocks is: 'value register plus one'. Then CLK_DIVIDER_ALLOW_ZERO flag has no effect and is useless here. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 8958bc11ff05..ca987632564e 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1959,11 +1959,10 @@ static const struct clock_config stm32mp1_clock_cfg[] = { CLK_SET_RATE_NO_REPARENT, _NO_GATE, _MMUX(M_ETHCK), - _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), + _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)), /* RTC clock */ - DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7, - CLK_DIVIDER_ALLOW_ZERO), + DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7, 0), COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT, -- cgit v1.2.3 From 97621d22df60d7348826d2e4b0c349673faeb4b8 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:40:47 +0100 Subject: clk: stm32mp1: fix bit width of hse_rtc divider Fix the bit width of the hse rtc divider because it's off by one. Fixes: 2c87c9d33117 ("clk: stm32mp1: add RTC clock") Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32mp1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index ca987632564e..a0ae8dc16909 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -1962,7 +1962,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)), /* RTC clock */ - DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7, 0), + DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0), COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT, -- cgit v1.2.3 From 585fc46bd47a143ee7433768e298a7f94008e5f5 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Thu, 14 Feb 2019 11:42:42 +0100 Subject: dt-bindings: clock: remove unused definition for stm32mp1 A copy of LTDC_PX and ETHCK_K (LTDC_K and ETHMAC_K) was introduced in stm32mp1 dt-bindings file by mistake. These bindings are not used and shouldn't be use to be conform with convention name of the stm32mp1 clock IP. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/stm32mp1-clks.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h index 90ec780bfc68..4cdaf135829c 100644 --- a/include/dt-bindings/clock/stm32mp1-clks.h +++ b/include/dt-bindings/clock/stm32mp1-clks.h @@ -248,7 +248,4 @@ #define STM32MP1_LAST_CLK 232 -#define LTDC_K LTDC_PX -#define ETHMAC_K ETHCK_K - #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ -- cgit v1.2.3 From fe6b580ec64cc8b32c4f5ee3db4a994471e1e4c1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 11 Feb 2019 13:09:26 +0530 Subject: clk: qcom: remove empty lines in clk-rcg.h Remove the redundant empty lines crept in. Signed-off-by: Vinod Koul Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rcg.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index e5eca8a1abe4..91336a030179 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -71,7 +71,6 @@ struct src_sel { * @freq_tbl: frequency table * @clkr: regmap clock handle * @lock: register lock - * */ struct clk_rcg { u32 ns_reg; @@ -107,7 +106,6 @@ extern const struct clk_ops clk_rcg_lcc_ops; * @freq_tbl: frequency table * @clkr: regmap clock handle * @lock: register lock - * */ struct clk_dyn_rcg { u32 ns_reg[2]; @@ -140,7 +138,6 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table * @clkr: regmap clock handle - * */ struct clk_rcg2 { u32 cmd_rcgr; -- cgit v1.2.3 From 96dc791d0b9e12f6374a80f00ad9304b9df2efee Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 11 Feb 2019 13:09:27 +0530 Subject: clk: qcom: clk-rcg2: Introduce a cfg offset for RCGs The RCG CFG/M/N/D register base could be at a different offset than the CMD register, so introduce a cfg_offset to identify the offset with respect to the CMD RCGR register. Signed-off-by: Taniya Das Signed-off-by: Anu Ramanathan Signed-off-by: Shawn Guo Signed-off-by: Vinod Koul Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-rcg.h | 2 ++ drivers/clk/qcom/clk-rcg2.c | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 91336a030179..c25b57c3cbc8 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -138,6 +138,7 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table * @clkr: regmap clock handle + * @cfg_off: defines the cfg register offset from the CMD_RCGR + CFG_REG */ struct clk_rcg2 { u32 cmd_rcgr; @@ -147,6 +148,7 @@ struct clk_rcg2 { const struct parent_map *parent_map; const struct freq_tbl *freq_tbl; struct clk_regmap clkr; + u8 cfg_off; }; #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 6e3bd195d012..8c02bffe50df 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -41,6 +41,11 @@ #define N_REG 0xc #define D_REG 0x10 +#define RCG_CFG_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + CFG_REG) +#define RCG_M_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + M_REG) +#define RCG_N_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + N_REG) +#define RCG_D_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + D_REG) + /* Dynamic Frequency Scaling */ #define MAX_PERF_LEVEL 8 #define SE_CMD_DFSR_OFFSET 0x14 @@ -74,7 +79,7 @@ static u8 clk_rcg2_get_parent(struct clk_hw *hw) u32 cfg; int i, ret; - ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); if (ret) goto err; @@ -123,7 +128,7 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) int ret; u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT; - ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, + ret = regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), CFG_SRC_SEL_MASK, cfg); if (ret) return ret; @@ -162,13 +167,13 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_rcg2 *rcg = to_clk_rcg2(hw); u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); if (rcg->mnd_width) { mask = BIT(rcg->mnd_width) - 1; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m); + regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m); m &= mask; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n); + regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), &n); n = ~n; n &= mask; n += m; @@ -263,17 +268,17 @@ static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) if (rcg->mnd_width && f->n) { mask = BIT(rcg->mnd_width) - 1; ret = regmap_update_bits(rcg->clkr.regmap, - rcg->cmd_rcgr + M_REG, mask, f->m); + RCG_M_OFFSET(rcg), mask, f->m); if (ret) return ret; ret = regmap_update_bits(rcg->clkr.regmap, - rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m)); + RCG_N_OFFSET(rcg), mask, ~(f->n - f->m)); if (ret) return ret; ret = regmap_update_bits(rcg->clkr.regmap, - rcg->cmd_rcgr + D_REG, mask, ~f->n); + RCG_D_OFFSET(rcg), mask, ~f->n); if (ret) return ret; } @@ -284,8 +289,7 @@ static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT; if (rcg->mnd_width && f->n && (f->m != f->n)) cfg |= CFG_MODE_DUAL_EDGE; - - return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, + return regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), mask, cfg); } -- cgit v1.2.3 From 9d575719ca9b8e177391addb2855be3911dc0d93 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 11 Feb 2019 13:09:28 +0530 Subject: clk: qcom: gcc-qcs404: Add cfg_offset for blsp1_uart3 clock The CFG/M/N/D registers are at an offset of 0x20 from the CMD register only for blsp1_uart3 clock, so add it for uart3 only. Signed-off-by: Taniya Das Signed-off-by: Anu Ramanathan Signed-off-by: Shawn Guo Signed-off-by: Vinod Koul Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-qcs404.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c index 64da032bb9ed..493e055299b4 100644 --- a/drivers/clk/qcom/gcc-qcs404.c +++ b/drivers/clk/qcom/gcc-qcs404.c @@ -678,6 +678,7 @@ static struct clk_rcg2 blsp1_uart3_apps_clk_src = { .cmd_rcgr = 0x4014, .mnd_width = 16, .hid_width = 5, + .cfg_off = 0x20, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_blsp1_uart0_apps_clk_src, .clkr.hw.init = &(struct clk_init_data){ -- cgit v1.2.3 From 341fdf2602113a3fd8e05046e2b7a75b5c0f308e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 21 Feb 2019 15:27:55 -0800 Subject: clk: imx: imx8mm: Mark init function __init It calls another __init marked function and thus causes a section mismatch if we don't mark it this way. Fixes: ba5625c3e272 ("clk: imx: Add clock driver support for imx8mm") Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index b7f3ac256856..1ef8438e3d6d 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -379,7 +379,7 @@ static struct clk ** const uart_clks[] __initconst = { NULL }; -static int imx8mm_clocks_init(struct device_node *ccm_node) +static int __init imx8mm_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; -- cgit v1.2.3 From 9831289f6f629b6aac4bd4491bc54dcebdc0b6ba Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 15 Jan 2019 09:03:35 +0530 Subject: clk: actions: Add configurable PLL delay S500 SoC requires configurable delay for different PLLs. Hence, add a separate macro for declaring a PLL with configurable delay and also modify the existing OWL_PLL_NO_PARENT macro to use default delay so that no need to modify the existing S700/S900 drivers. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Stephen Boyd --- drivers/clk/actions/owl-pll.c | 2 +- drivers/clk/actions/owl-pll.h | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/clk/actions/owl-pll.c b/drivers/clk/actions/owl-pll.c index 058e06d7099f..02437bdedf4d 100644 --- a/drivers/clk/actions/owl-pll.c +++ b/drivers/clk/actions/owl-pll.c @@ -179,7 +179,7 @@ static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate, regmap_write(common->regmap, pll_hw->reg, reg); - udelay(PLL_STABILITY_WAIT_US); + udelay(pll_hw->delay); return 0; } diff --git a/drivers/clk/actions/owl-pll.h b/drivers/clk/actions/owl-pll.h index 0aae30abd5dc..6fb0d45bb088 100644 --- a/drivers/clk/actions/owl-pll.h +++ b/drivers/clk/actions/owl-pll.h @@ -13,6 +13,8 @@ #include "owl-common.h" +#define OWL_PLL_DEF_DELAY 50 + /* last entry should have rate = 0 */ struct clk_pll_table { unsigned int val; @@ -27,6 +29,7 @@ struct owl_pll_hw { u8 width; u8 min_mul; u8 max_mul; + u8 delay; const struct clk_pll_table *table; }; @@ -36,7 +39,7 @@ struct owl_pll { }; #define OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \ - _width, _min_mul, _max_mul, _table) \ + _width, _min_mul, _max_mul, _delay, _table) \ { \ .reg = _reg, \ .bfreq = _bfreq, \ @@ -45,6 +48,7 @@ struct owl_pll { .width = _width, \ .min_mul = _min_mul, \ .max_mul = _max_mul, \ + .delay = _delay, \ .table = _table, \ } @@ -52,8 +56,8 @@ struct owl_pll { _shift, _width, _min_mul, _max_mul, _table, _flags) \ struct owl_pll _struct = { \ .pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \ - _width, _min_mul, \ - _max_mul, _table), \ + _width, _min_mul, _max_mul, \ + OWL_PLL_DEF_DELAY, _table), \ .common = { \ .regmap = NULL, \ .hw.init = CLK_HW_INIT(_name, \ @@ -67,8 +71,23 @@ struct owl_pll { _shift, _width, _min_mul, _max_mul, _table, _flags) \ struct owl_pll _struct = { \ .pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \ - _width, _min_mul, \ - _max_mul, _table), \ + _width, _min_mul, _max_mul, \ + OWL_PLL_DEF_DELAY, _table), \ + .common = { \ + .regmap = NULL, \ + .hw.init = CLK_HW_INIT_NO_PARENT(_name, \ + &owl_pll_ops, \ + _flags), \ + }, \ + } + +#define OWL_PLL_NO_PARENT_DELAY(_struct, _name, _reg, _bfreq, _bit_idx, \ + _shift, _width, _min_mul, _max_mul, _delay, _table, \ + _flags) \ + struct owl_pll _struct = { \ + .pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \ + _width, _min_mul, _max_mul, \ + _delay, _table), \ .common = { \ .regmap = NULL, \ .hw.init = CLK_HW_INIT_NO_PARENT(_name, \ @@ -78,7 +97,6 @@ struct owl_pll { } #define mul_mask(m) ((1 << ((m)->width)) - 1) -#define PLL_STABILITY_WAIT_US (50) static inline struct owl_pll *hw_to_owl_pll(const struct clk_hw *hw) { -- cgit v1.2.3 From 0c8c53e033d278cad09a81ec1c46a401a6a6b1af Mon Sep 17 00:00:00 2001 From: Edgar Bernardi Righi Date: Tue, 15 Jan 2019 09:03:36 +0530 Subject: dt-bindings: clock: Add DT bindings for Actions Semi S500 CMU Add devicetree bindings for Actions Semi S500 Clock Management Unit. Signed-off-by: Edgar Bernardi Righi [Mani: Documented S500 CMU compatible] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring [sboyd@kernel.org: Fix SPDX comment style in header file] Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/actions,owl-cmu.txt | 7 +- include/dt-bindings/clock/actions,s500-cmu.h | 78 ++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 include/dt-bindings/clock/actions,s500-cmu.h diff --git a/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt b/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt index 2ef86ae96df8..d19885b7c73f 100644 --- a/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt +++ b/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt @@ -2,13 +2,14 @@ The Actions Semi Owl Clock Management Unit generates and supplies clock to various controllers within the SoC. The clock binding described here is -applicable to S900 and S700 SoC's. +applicable to S900, S700 and S500 SoC's. Required Properties: - compatible: should be one of the following, "actions,s900-cmu" "actions,s700-cmu" + "actions,s500-cmu" - reg: physical base address of the controller and length of memory mapped region. - clocks: Reference to the parent clocks ("hosc", "losc") @@ -19,8 +20,8 @@ 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 corresponding -dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h header and can be -used in device tree sources. +dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h or +actions,s500-cmu.h header and can be used in device tree sources. External clocks: diff --git a/include/dt-bindings/clock/actions,s500-cmu.h b/include/dt-bindings/clock/actions,s500-cmu.h new file mode 100644 index 000000000000..030981cd2d56 --- /dev/null +++ b/include/dt-bindings/clock/actions,s500-cmu.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Device Tree binding constants for Actions Semi S500 Clock Management Unit + * + * Copyright (c) 2014 Actions Semi Inc. + * Copyright (c) 2018 LSI-TEC - Caninos Loucos + */ + +#ifndef __DT_BINDINGS_CLOCK_S500_CMU_H +#define __DT_BINDINGS_CLOCK_S500_CMU_H + +#define CLK_NONE 0 + +/* fixed rate clocks */ +#define CLK_LOSC 1 +#define CLK_HOSC 2 + +/* pll clocks */ +#define CLK_CORE_PLL 3 +#define CLK_DEV_PLL 4 +#define CLK_DDR_PLL 5 +#define CLK_NAND_PLL 6 +#define CLK_DISPLAY_PLL 7 +#define CLK_ETHERNET_PLL 8 +#define CLK_AUDIO_PLL 9 + +/* system clock */ +#define CLK_DEV 10 +#define CLK_H 11 +#define CLK_AHBPREDIV 12 +#define CLK_AHB 13 +#define CLK_DE 14 +#define CLK_BISP 15 +#define CLK_VCE 16 +#define CLK_VDE 17 + +/* peripheral device clock */ +#define CLK_TIMER 18 +#define CLK_I2C0 19 +#define CLK_I2C1 20 +#define CLK_I2C2 21 +#define CLK_I2C3 22 +#define CLK_PWM0 23 +#define CLK_PWM1 24 +#define CLK_PWM2 25 +#define CLK_PWM3 26 +#define CLK_PWM4 27 +#define CLK_PWM5 28 +#define CLK_SD0 29 +#define CLK_SD1 30 +#define CLK_SD2 31 +#define CLK_SENSOR0 32 +#define CLK_SENSOR1 33 +#define CLK_SPI0 34 +#define CLK_SPI1 35 +#define CLK_SPI2 36 +#define CLK_SPI3 37 +#define CLK_UART0 38 +#define CLK_UART1 39 +#define CLK_UART2 40 +#define CLK_UART3 41 +#define CLK_UART4 42 +#define CLK_UART5 43 +#define CLK_UART6 44 +#define CLK_DE1 45 +#define CLK_DE2 46 +#define CLK_I2SRX 47 +#define CLK_I2STX 48 +#define CLK_HDMI_AUDIO 49 +#define CLK_HDMI 50 +#define CLK_SPDIF 51 +#define CLK_NAND 52 +#define CLK_ECC 53 +#define CLK_RMII_REF 54 + +#define CLK_NR_CLKS (CLK_RMII_REF + 1) + +#endif /* __DT_BINDINGS_CLOCK_S500_CMU_H */ -- cgit v1.2.3 From ed6b4795ece45e43856f6a42571d477695173742 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 15 Jan 2019 09:03:39 +0530 Subject: clk: actions: Add clock driver for S500 SoC Add common clock driver for Actions Semi S500 SoC. Signed-off-by: Edgar Bernardi Righi [Mani: cleaned up the driver] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Stephen Boyd --- drivers/clk/actions/Kconfig | 5 + drivers/clk/actions/Makefile | 1 + drivers/clk/actions/owl-s500.c | 525 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 531 insertions(+) create mode 100644 drivers/clk/actions/owl-s500.c diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig index 04f0a6355726..5b45ca35757e 100644 --- a/drivers/clk/actions/Kconfig +++ b/drivers/clk/actions/Kconfig @@ -9,6 +9,11 @@ if CLK_ACTIONS # SoC Drivers +config CLK_OWL_S500 + bool "Support for the Actions Semi OWL S500 clocks" + depends on ARCH_ACTIONS || COMPILE_TEST + default ARCH_ACTIONS + config CLK_OWL_S700 bool "Support for the Actions Semi OWL S700 clocks" depends on (ARM64 && ARCH_ACTIONS) || COMPILE_TEST diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile index ccfdf9781cef..a2588e55c790 100644 --- a/drivers/clk/actions/Makefile +++ b/drivers/clk/actions/Makefile @@ -10,5 +10,6 @@ clk-owl-y += owl-pll.o clk-owl-y += owl-reset.o # SoC support +obj-$(CONFIG_CLK_OWL_S500) += owl-s500.o obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o obj-$(CONFIG_CLK_OWL_S900) += owl-s900.o diff --git a/drivers/clk/actions/owl-s500.c b/drivers/clk/actions/owl-s500.c new file mode 100644 index 000000000000..e2007ac4d235 --- /dev/null +++ b/drivers/clk/actions/owl-s500.c @@ -0,0 +1,525 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Actions Semi Owl S500 SoC clock driver + * + * Copyright (c) 2014 Actions Semi Inc. + * Author: David Liu + * + * Copyright (c) 2018 Linaro Ltd. + * Author: Manivannan Sadhasivam + * + * Copyright (c) 2018 LSI-TEC - Caninos Loucos + * Author: Edgar Bernardi Righi + */ + +#include +#include + +#include "owl-common.h" +#include "owl-composite.h" +#include "owl-divider.h" +#include "owl-factor.h" +#include "owl-fixed-factor.h" +#include "owl-gate.h" +#include "owl-mux.h" +#include "owl-pll.h" + +#include + +#define CMU_COREPLL (0x0000) +#define CMU_DEVPLL (0x0004) +#define CMU_DDRPLL (0x0008) +#define CMU_NANDPLL (0x000C) +#define CMU_DISPLAYPLL (0x0010) +#define CMU_AUDIOPLL (0x0014) +#define CMU_TVOUTPLL (0x0018) +#define CMU_BUSCLK (0x001C) +#define CMU_SENSORCLK (0x0020) +#define CMU_LCDCLK (0x0024) +#define CMU_DSICLK (0x0028) +#define CMU_CSICLK (0x002C) +#define CMU_DECLK (0x0030) +#define CMU_BISPCLK (0x0034) +#define CMU_BUSCLK1 (0x0038) +#define CMU_VDECLK (0x0040) +#define CMU_VCECLK (0x0044) +#define CMU_NANDCCLK (0x004C) +#define CMU_SD0CLK (0x0050) +#define CMU_SD1CLK (0x0054) +#define CMU_SD2CLK (0x0058) +#define CMU_UART0CLK (0x005C) +#define CMU_UART1CLK (0x0060) +#define CMU_UART2CLK (0x0064) +#define CMU_PWM4CLK (0x0068) +#define CMU_PWM5CLK (0x006C) +#define CMU_PWM0CLK (0x0070) +#define CMU_PWM1CLK (0x0074) +#define CMU_PWM2CLK (0x0078) +#define CMU_PWM3CLK (0x007C) +#define CMU_USBPLL (0x0080) +#define CMU_ETHERNETPLL (0x0084) +#define CMU_CVBSPLL (0x0088) +#define CMU_LENSCLK (0x008C) +#define CMU_GPU3DCLK (0x0090) +#define CMU_CORECTL (0x009C) +#define CMU_DEVCLKEN0 (0x00A0) +#define CMU_DEVCLKEN1 (0x00A4) +#define CMU_DEVRST0 (0x00A8) +#define CMU_DEVRST1 (0x00AC) +#define CMU_UART3CLK (0x00B0) +#define CMU_UART4CLK (0x00B4) +#define CMU_UART5CLK (0x00B8) +#define CMU_UART6CLK (0x00BC) +#define CMU_SSCLK (0x00C0) +#define CMU_DIGITALDEBUG (0x00D0) +#define CMU_ANALOGDEBUG (0x00D4) +#define CMU_COREPLLDEBUG (0x00D8) +#define CMU_DEVPLLDEBUG (0x00DC) +#define CMU_DDRPLLDEBUG (0x00E0) +#define CMU_NANDPLLDEBUG (0x00E4) +#define CMU_DISPLAYPLLDEBUG (0x00E8) +#define CMU_TVOUTPLLDEBUG (0x00EC) +#define CMU_DEEPCOLORPLLDEBUG (0x00F4) +#define CMU_AUDIOPLL_ETHPLLDEBUG (0x00F8) +#define CMU_CVBSPLLDEBUG (0x00FC) + +#define OWL_S500_COREPLL_DELAY (150) +#define OWL_S500_DDRPLL_DELAY (63) +#define OWL_S500_DEVPLL_DELAY (28) +#define OWL_S500_NANDPLL_DELAY (44) +#define OWL_S500_DISPLAYPLL_DELAY (57) +#define OWL_S500_ETHERNETPLL_DELAY (25) +#define OWL_S500_AUDIOPLL_DELAY (100) + +static const struct clk_pll_table clk_audio_pll_table[] = { + { 0, 45158400 }, { 1, 49152000 }, + { 0, 0 }, +}; + +/* pll clocks */ +static OWL_PLL_NO_PARENT_DELAY(ethernet_pll_clk, "ethernet_pll_clk", CMU_ETHERNETPLL, 500000000, 0, 0, 0, 0, 0, OWL_S500_ETHERNETPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(core_pll_clk, "core_pll_clk", CMU_COREPLL, 12000000, 9, 0, 8, 4, 134, OWL_S500_COREPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(ddr_pll_clk, "ddr_pll_clk", CMU_DDRPLL, 12000000, 8, 0, 8, 1, 67, OWL_S500_DDRPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(nand_pll_clk, "nand_pll_clk", CMU_NANDPLL, 6000000, 8, 0, 7, 2, 86, OWL_S500_NANDPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(display_pll_clk, "display_pll_clk", CMU_DISPLAYPLL, 6000000, 8, 0, 8, 2, 126, OWL_S500_DISPLAYPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(dev_pll_clk, "dev_pll_clk", CMU_DEVPLL, 6000000, 8, 0, 7, 8, 126, OWL_S500_DEVPLL_DELAY, NULL, CLK_IGNORE_UNUSED); +static OWL_PLL_NO_PARENT_DELAY(audio_pll_clk, "audio_pll_clk", CMU_AUDIOPLL, 0, 4, 0, 1, 0, 0, OWL_S500_AUDIOPLL_DELAY, clk_audio_pll_table, CLK_IGNORE_UNUSED); + +static const char * const dev_clk_mux_p[] = { "hosc", "dev_pll_clk" }; +static const char * const bisp_clk_mux_p[] = { "display_pll_clk", "dev_clk" }; +static const char * const sensor_clk_mux_p[] = { "hosc", "bisp_clk" }; +static const char * const sd_clk_mux_p[] = { "dev_clk", "nand_pll_clk" }; +static const char * const pwm_clk_mux_p[] = { "losc", "hosc" }; +static const char * const ahbprediv_clk_mux_p[] = { "dev_clk", "display_pll_clk", "nand_pll_clk", "ddr_pll_clk" }; +static const char * const uart_clk_mux_p[] = { "hosc", "dev_pll_clk" }; +static const char * const de_clk_mux_p[] = { "display_pll_clk", "dev_clk" }; +static const char * const i2s_clk_mux_p[] = { "audio_pll_clk" }; +static const char * const hde_clk_mux_p[] = { "dev_clk", "display_pll_clk", "nand_pll_clk", "ddr_pll_clk" }; +static const char * const nand_clk_mux_p[] = { "nand_pll_clk", "display_pll_clk", "dev_clk", "ddr_pll_clk" }; + +static struct clk_factor_table sd_factor_table[] = { + /* bit0 ~ 4 */ + { 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 }, + { 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 }, + { 8, 1, 9 }, { 9, 1, 10 }, { 10, 1, 11 }, { 11, 1, 12 }, + { 12, 1, 13 }, { 13, 1, 14 }, { 14, 1, 15 }, { 15, 1, 16 }, + { 16, 1, 17 }, { 17, 1, 18 }, { 18, 1, 19 }, { 19, 1, 20 }, + { 20, 1, 21 }, { 21, 1, 22 }, { 22, 1, 23 }, { 23, 1, 24 }, + { 24, 1, 25 }, { 25, 1, 26 }, { 26, 1, 27 }, { 27, 1, 28 }, + { 28, 1, 29 }, { 29, 1, 30 }, { 30, 1, 31 }, { 31, 1, 32 }, + + /* bit8: /128 */ + { 256, 1, 1 * 128 }, { 257, 1, 2 * 128 }, { 258, 1, 3 * 128 }, { 259, 1, 4 * 128 }, + { 260, 1, 5 * 128 }, { 261, 1, 6 * 128 }, { 262, 1, 7 * 128 }, { 263, 1, 8 * 128 }, + { 264, 1, 9 * 128 }, { 265, 1, 10 * 128 }, { 266, 1, 11 * 128 }, { 267, 1, 12 * 128 }, + { 268, 1, 13 * 128 }, { 269, 1, 14 * 128 }, { 270, 1, 15 * 128 }, { 271, 1, 16 * 128 }, + { 272, 1, 17 * 128 }, { 273, 1, 18 * 128 }, { 274, 1, 19 * 128 }, { 275, 1, 20 * 128 }, + { 276, 1, 21 * 128 }, { 277, 1, 22 * 128 }, { 278, 1, 23 * 128 }, { 279, 1, 24 * 128 }, + { 280, 1, 25 * 128 }, { 281, 1, 26 * 128 }, { 282, 1, 27 * 128 }, { 283, 1, 28 * 128 }, + { 284, 1, 29 * 128 }, { 285, 1, 30 * 128 }, { 286, 1, 31 * 128 }, { 287, 1, 32 * 128 }, + { 0, 0, 0 }, +}; + +static struct clk_factor_table bisp_factor_table[] = { + { 0, 1, 1 }, { 1, 1, 2 }, { 2, 1, 3 }, { 3, 1, 4 }, + { 4, 1, 5 }, { 5, 1, 6 }, { 6, 1, 7 }, { 7, 1, 8 }, + { 0, 0, 0 }, +}; + +static struct clk_factor_table ahb_factor_table[] = { + { 1, 1, 2 }, { 2, 1, 3 }, + { 0, 0, 0 }, +}; + +static struct clk_div_table rmii_ref_div_table[] = { + { 0, 4 }, { 1, 10 }, + { 0, 0 }, +}; + +static struct clk_div_table i2s_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, + { 4, 6 }, { 5, 8 }, { 6, 12 }, { 7, 16 }, + { 8, 24 }, + { 0, 0 }, +}; + +static struct clk_div_table nand_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 6 }, + { 4, 8 }, { 5, 10 }, { 6, 12 }, { 7, 14 }, + { 8, 16 }, { 9, 18 }, { 10, 20 }, { 11, 22 }, + { 0, 0 }, +}; + +/* mux clock */ +static OWL_MUX(dev_clk, "dev_clk", dev_clk_mux_p, CMU_DEVPLL, 12, 1, CLK_SET_RATE_PARENT); +static OWL_MUX(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT); + +/* gate clocks */ +static OWL_GATE(spi0_clk, "spi0_clk", "ahb_clk", CMU_DEVCLKEN1, 10, 0, CLK_IGNORE_UNUSED); +static OWL_GATE(spi1_clk, "spi1_clk", "ahb_clk", CMU_DEVCLKEN1, 11, 0, CLK_IGNORE_UNUSED); +static OWL_GATE(spi2_clk, "spi2_clk", "ahb_clk", CMU_DEVCLKEN1, 12, 0, CLK_IGNORE_UNUSED); +static OWL_GATE(spi3_clk, "spi3_clk", "ahb_clk", CMU_DEVCLKEN1, 13, 0, CLK_IGNORE_UNUSED); +static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0); +static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0); + +/* divider clocks */ +static OWL_DIVIDER(h_clk, "h_clk", "ahbprevdiv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0); +static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0); + +/* factor clocks */ +static OWL_FACTOR(ahb_clk, "ahb_clk", "h_clk", CMU_BUSCLK1, 2, 2, ahb_factor_table, 0, 0); +static OWL_FACTOR(de1_clk, "de_clk1", "de_clk", CMU_DECLK, 0, 3, bisp_factor_table, 0, 0); +static OWL_FACTOR(de2_clk, "de_clk2", "de_clk", CMU_DECLK, 4, 3, bisp_factor_table, 0, 0); + +/* composite clocks */ +static OWL_COMP_FACTOR(vce_clk, "vce_clk", hde_clk_mux_p, + OWL_MUX_HW(CMU_VCECLK, 4, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 26, 0), + OWL_FACTOR_HW(CMU_VCECLK, 0, 3, 0, bisp_factor_table), + 0); + +static OWL_COMP_FACTOR(vde_clk, "vde_clk", hde_clk_mux_p, + OWL_MUX_HW(CMU_VDECLK, 4, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 25, 0), + OWL_FACTOR_HW(CMU_VDECLK, 0, 3, 0, bisp_factor_table), + 0); + +static OWL_COMP_FACTOR(bisp_clk, "bisp_clk", bisp_clk_mux_p, + OWL_MUX_HW(CMU_BISPCLK, 4, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0), + OWL_FACTOR_HW(CMU_BISPCLK, 0, 3, 0, bisp_factor_table), + 0); + +static OWL_COMP_FACTOR(sensor0_clk, "sensor0_clk", sensor_clk_mux_p, + OWL_MUX_HW(CMU_SENSORCLK, 4, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0), + OWL_FACTOR_HW(CMU_SENSORCLK, 0, 3, 0, bisp_factor_table), + CLK_IGNORE_UNUSED); + +static OWL_COMP_FACTOR(sensor1_clk, "sensor1_clk", sensor_clk_mux_p, + OWL_MUX_HW(CMU_SENSORCLK, 4, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 14, 0), + OWL_FACTOR_HW(CMU_SENSORCLK, 8, 3, 0, bisp_factor_table), + CLK_IGNORE_UNUSED); + +static OWL_COMP_FACTOR(sd0_clk, "sd0_clk", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD0CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 5, 0), + OWL_FACTOR_HW(CMU_SD0CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_FACTOR(sd1_clk, "sd1_clk", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD1CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 6, 0), + OWL_FACTOR_HW(CMU_SD1CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_FACTOR(sd2_clk, "sd2_clk", sd_clk_mux_p, + OWL_MUX_HW(CMU_SD2CLK, 9, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 7, 0), + OWL_FACTOR_HW(CMU_SD2CLK, 0, 9, 0, sd_factor_table), + 0); + +static OWL_COMP_DIV(pwm0_clk, "pwm0_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM0CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 23, 0), + OWL_DIVIDER_HW(CMU_PWM0CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm1_clk, "pwm1_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM1CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 24, 0), + OWL_DIVIDER_HW(CMU_PWM1CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm2_clk, "pwm2_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM2CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 25, 0), + OWL_DIVIDER_HW(CMU_PWM2CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm3_clk, "pwm3_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM3CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 26, 0), + OWL_DIVIDER_HW(CMU_PWM3CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm4_clk, "pwm4_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM4CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 11, 0), + OWL_DIVIDER_HW(CMU_PWM4CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_DIV(pwm5_clk, "pwm5_clk", pwm_clk_mux_p, + OWL_MUX_HW(CMU_PWM5CLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 0, 0), + OWL_DIVIDER_HW(CMU_PWM5CLK, 0, 10, 0, NULL), + 0); + +static OWL_COMP_PASS(de_clk, "de_clk", de_clk_mux_p, + OWL_MUX_HW(CMU_DECLK, 12, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 8, 0), + 0); + +static OWL_COMP_FIXED_FACTOR(i2c0_clk, "i2c0_clk", "ethernet_pll_clk", + OWL_GATE_HW(CMU_DEVCLKEN1, 14, 0), + 1, 5, 0); + +static OWL_COMP_FIXED_FACTOR(i2c1_clk, "i2c1_clk", "ethernet_pll_clk", + OWL_GATE_HW(CMU_DEVCLKEN1, 15, 0), + 1, 5, 0); + +static OWL_COMP_FIXED_FACTOR(i2c2_clk, "i2c2_clk", "ethernet_pll_clk", + OWL_GATE_HW(CMU_DEVCLKEN1, 30, 0), + 1, 5, 0); + +static OWL_COMP_FIXED_FACTOR(i2c3_clk, "i2c3_clk", "ethernet_pll_clk", + OWL_GATE_HW(CMU_DEVCLKEN1, 31, 0), + 1, 5, 0); + +static OWL_COMP_DIV(uart0_clk, "uart0_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART0CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 6, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart1_clk, "uart1_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART1CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 7, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart2_clk, "uart2_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART2CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 8, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart3_clk, "uart3_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART3CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 19, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart4_clk, "uart4_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART4CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 20, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart5_clk, "uart5_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART5CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 21, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(uart6_clk, "uart6_clk", uart_clk_mux_p, + OWL_MUX_HW(CMU_UART6CLK, 16, 1), + OWL_GATE_HW(CMU_DEVCLKEN1, 18, 0), + OWL_DIVIDER_HW(CMU_UART1CLK, 0, 8, CLK_DIVIDER_ROUND_CLOSEST, NULL), + CLK_IGNORE_UNUSED); + +static OWL_COMP_DIV(i2srx_clk, "i2srx_clk", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 21, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 20, 4, 0, i2s_div_table), + 0); + +static OWL_COMP_DIV(i2stx_clk, "i2stx_clk", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 20, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 16, 4, 0, i2s_div_table), + 0); + +static OWL_COMP_DIV(hdmia_clk, "hdmia_clk", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 22, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 24, 4, 0, i2s_div_table), + 0); + +static OWL_COMP_DIV(spdif_clk, "spdif_clk", i2s_clk_mux_p, + OWL_MUX_HW(CMU_AUDIOPLL, 24, 1), + OWL_GATE_HW(CMU_DEVCLKEN0, 23, 0), + OWL_DIVIDER_HW(CMU_AUDIOPLL, 28, 4, 0, i2s_div_table), + 0); + +static OWL_COMP_DIV(nand_clk, "nand_clk", nand_clk_mux_p, + OWL_MUX_HW(CMU_NANDCCLK, 8, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 4, 0), + OWL_DIVIDER_HW(CMU_NANDCCLK, 0, 3, 0, nand_div_table), + CLK_SET_RATE_PARENT); + +static OWL_COMP_DIV(ecc_clk, "ecc_clk", nand_clk_mux_p, + OWL_MUX_HW(CMU_NANDCCLK, 8, 2), + OWL_GATE_HW(CMU_DEVCLKEN0, 4, 0), + OWL_DIVIDER_HW(CMU_NANDCCLK, 4, 3, 0, nand_div_table), + CLK_SET_RATE_PARENT); + +static struct owl_clk_common *s500_clks[] = { + ðernet_pll_clk.common, + &core_pll_clk.common, + &ddr_pll_clk.common, + &dev_pll_clk.common, + &nand_pll_clk.common, + &audio_pll_clk.common, + &display_pll_clk.common, + &dev_clk.common, + &timer_clk.common, + &i2c0_clk.common, + &i2c1_clk.common, + &i2c2_clk.common, + &i2c3_clk.common, + &uart0_clk.common, + &uart1_clk.common, + &uart2_clk.common, + &uart3_clk.common, + &uart4_clk.common, + &uart5_clk.common, + &uart6_clk.common, + &pwm0_clk.common, + &pwm1_clk.common, + &pwm2_clk.common, + &pwm3_clk.common, + &pwm4_clk.common, + &pwm5_clk.common, + &sensor0_clk.common, + &sensor1_clk.common, + &sd0_clk.common, + &sd1_clk.common, + &sd2_clk.common, + &bisp_clk.common, + &ahb_clk.common, + &ahbprediv_clk.common, + &h_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &spi2_clk.common, + &spi3_clk.common, + &rmii_ref_clk.common, + &de_clk.common, + &de1_clk.common, + &de2_clk.common, + &i2srx_clk.common, + &i2stx_clk.common, + &hdmia_clk.common, + &hdmi_clk.common, + &vce_clk.common, + &vde_clk.common, + &spdif_clk.common, + &nand_clk.common, + &ecc_clk.common, +}; + +static struct clk_hw_onecell_data s500_hw_clks = { + .hws = { + [CLK_ETHERNET_PLL] = ðernet_pll_clk.common.hw, + [CLK_CORE_PLL] = &core_pll_clk.common.hw, + [CLK_DDR_PLL] = &ddr_pll_clk.common.hw, + [CLK_NAND_PLL] = &nand_pll_clk.common.hw, + [CLK_DISPLAY_PLL] = &display_pll_clk.common.hw, + [CLK_DEV_PLL] = &dev_pll_clk.common.hw, + [CLK_AUDIO_PLL] = &audio_pll_clk.common.hw, + [CLK_TIMER] = &timer_clk.common.hw, + [CLK_DEV] = &dev_clk.common.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_DE1] = &de1_clk.common.hw, + [CLK_DE2] = &de2_clk.common.hw, + [CLK_I2C0] = &i2c0_clk.common.hw, + [CLK_I2C1] = &i2c1_clk.common.hw, + [CLK_I2C2] = &i2c2_clk.common.hw, + [CLK_I2C3] = &i2c3_clk.common.hw, + [CLK_I2SRX] = &i2srx_clk.common.hw, + [CLK_I2STX] = &i2stx_clk.common.hw, + [CLK_UART0] = &uart0_clk.common.hw, + [CLK_UART1] = &uart1_clk.common.hw, + [CLK_UART2] = &uart2_clk.common.hw, + [CLK_UART3] = &uart3_clk.common.hw, + [CLK_UART4] = &uart4_clk.common.hw, + [CLK_UART5] = &uart5_clk.common.hw, + [CLK_UART6] = &uart6_clk.common.hw, + [CLK_PWM0] = &pwm0_clk.common.hw, + [CLK_PWM1] = &pwm1_clk.common.hw, + [CLK_PWM2] = &pwm2_clk.common.hw, + [CLK_PWM3] = &pwm3_clk.common.hw, + [CLK_PWM4] = &pwm4_clk.common.hw, + [CLK_PWM5] = &pwm5_clk.common.hw, + [CLK_SENSOR0] = &sensor0_clk.common.hw, + [CLK_SENSOR1] = &sensor1_clk.common.hw, + [CLK_SD0] = &sd0_clk.common.hw, + [CLK_SD1] = &sd1_clk.common.hw, + [CLK_SD2] = &sd2_clk.common.hw, + [CLK_BISP] = &bisp_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_SPI2] = &spi2_clk.common.hw, + [CLK_SPI3] = &spi3_clk.common.hw, + [CLK_AHB] = &ahb_clk.common.hw, + [CLK_H] = &h_clk.common.hw, + [CLK_AHBPREDIV] = &ahbprediv_clk.common.hw, + [CLK_RMII_REF] = &rmii_ref_clk.common.hw, + [CLK_HDMI_AUDIO] = &hdmia_clk.common.hw, + [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_VDE] = &vde_clk.common.hw, + [CLK_VCE] = &vce_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_NAND] = &nand_clk.common.hw, + [CLK_ECC] = &ecc_clk.common.hw, + }, + .num = CLK_NR_CLKS, +}; + +static struct owl_clk_desc s500_clk_desc = { + .clks = s500_clks, + .num_clks = ARRAY_SIZE(s500_clks), + + .hw_clks = &s500_hw_clks, +}; + +static int s500_clk_probe(struct platform_device *pdev) +{ + struct owl_clk_desc *desc; + + desc = &s500_clk_desc; + owl_clk_regmap_init(pdev, desc); + + return owl_clk_probe(&pdev->dev, desc->hw_clks); +} + +static const struct of_device_id s500_clk_of_match[] = { + { .compatible = "actions,s500-cmu", }, + { /* sentinel */ } +}; + +static struct platform_driver s500_clk_driver = { + .probe = s500_clk_probe, + .driver = { + .name = "s500-cmu", + .of_match_table = s500_clk_of_match, + }, +}; + +static int __init s500_clk_init(void) +{ + return platform_driver_register(&s500_clk_driver); +} +core_initcall(s500_clk_init); -- cgit v1.2.3 From 760be6586fbcc0a5a3b7892e3fe664a3f0530631 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Sun, 10 Feb 2019 13:14:05 -0700 Subject: clk: qcom: Make common clk_hw registrations Several clock controller drivers define a list of clk_hw devices, and then register those devices in probe() before using common code to process the rest of initialization. Extend the common code to accept a list of clk_hw devices to process, thus eliminating many duplicate implementations. Signed-off-by: Jeffrey Hugo Suggested-by: Stephen Boyd Reviewed-by: Vinod Koul Tested-by: Vinod Koul Signed-off-by: Stephen Boyd --- drivers/clk/qcom/common.c | 8 ++++++++ drivers/clk/qcom/common.h | 2 ++ drivers/clk/qcom/gcc-ipq8074.c | 10 ++-------- drivers/clk/qcom/gcc-mdm9615.c | 11 ++--------- drivers/clk/qcom/gcc-msm8996.c | 10 ++-------- drivers/clk/qcom/gcc-msm8998.c | 10 ++++++---- drivers/clk/qcom/gcc-qcs404.c | 9 ++------- drivers/clk/qcom/gcc-sdm660.c | 11 +++-------- drivers/clk/qcom/mmcc-msm8996.c | 10 ++-------- 9 files changed, 29 insertions(+), 52 deletions(-) diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 0a48ed56833b..a6b2f86112d8 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -231,6 +231,8 @@ int qcom_cc_really_probe(struct platform_device *pdev, struct gdsc_desc *scd; size_t num_clks = desc->num_clks; struct clk_regmap **rclks = desc->clks; + size_t num_clk_hws = desc->num_clk_hws; + struct clk_hw **clk_hws = desc->clk_hws; cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL); if (!cc) @@ -269,6 +271,12 @@ int qcom_cc_really_probe(struct platform_device *pdev, qcom_cc_drop_protected(dev, cc); + for (i = 0; i < num_clk_hws; i++) { + ret = devm_clk_hw_register(dev, clk_hws[i]); + if (ret) + return ret; + } + for (i = 0; i < num_clks; i++) { if (!rclks[i]) continue; diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 4aa33ee70bae..1e2a8bdac55a 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -27,6 +27,8 @@ struct qcom_cc_desc { size_t num_resets; struct gdsc **gdscs; size_t num_gdscs; + struct clk_hw **clk_hws; + size_t num_clk_hws; }; /** diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c index 505c6263141d..0e32892b438c 100644 --- a/drivers/clk/qcom/gcc-ipq8074.c +++ b/drivers/clk/qcom/gcc-ipq8074.c @@ -4715,18 +4715,12 @@ static const struct qcom_cc_desc gcc_ipq8074_desc = { .num_clks = ARRAY_SIZE(gcc_ipq8074_clks), .resets = gcc_ipq8074_resets, .num_resets = ARRAY_SIZE(gcc_ipq8074_resets), + .clk_hws = gcc_ipq8074_hws, + .num_clk_hws = ARRAY_SIZE(gcc_ipq8074_hws), }; static int gcc_ipq8074_probe(struct platform_device *pdev) { - int ret, i; - - for (i = 0; i < ARRAY_SIZE(gcc_ipq8074_hws); i++) { - ret = devm_clk_hw_register(&pdev->dev, gcc_ipq8074_hws[i]); - if (ret) - return ret; - } - return qcom_cc_probe(pdev, &gcc_ipq8074_desc); } diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c index 849046fbed6d..8c6d93144b9c 100644 --- a/drivers/clk/qcom/gcc-mdm9615.c +++ b/drivers/clk/qcom/gcc-mdm9615.c @@ -1702,6 +1702,8 @@ static const struct qcom_cc_desc gcc_mdm9615_desc = { .num_clks = ARRAY_SIZE(gcc_mdm9615_clks), .resets = gcc_mdm9615_resets, .num_resets = ARRAY_SIZE(gcc_mdm9615_resets), + .clk_hws = gcc_mdm9615_hws, + .num_clk_hws = ARRAY_SIZE(gcc_mdm9615_hws), }; static const struct of_device_id gcc_mdm9615_match_table[] = { @@ -1712,21 +1714,12 @@ MODULE_DEVICE_TABLE(of, gcc_mdm9615_match_table); static int gcc_mdm9615_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; struct regmap *regmap; - int ret; - int i; regmap = qcom_cc_map(pdev, &gcc_mdm9615_desc); if (IS_ERR(regmap)) return PTR_ERR(regmap); - for (i = 0; i < ARRAY_SIZE(gcc_mdm9615_hws); i++) { - ret = devm_clk_hw_register(dev, gcc_mdm9615_hws[i]); - if (ret) - return ret; - } - return qcom_cc_really_probe(pdev, &gcc_mdm9615_desc, regmap); } diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 9d136172c27c..4632b9272b7f 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -3656,6 +3656,8 @@ static const struct qcom_cc_desc gcc_msm8996_desc = { .num_resets = ARRAY_SIZE(gcc_msm8996_resets), .gdscs = gcc_msm8996_gdscs, .num_gdscs = ARRAY_SIZE(gcc_msm8996_gdscs), + .clk_hws = gcc_msm8996_hws, + .num_clk_hws = ARRAY_SIZE(gcc_msm8996_hws), }; static const struct of_device_id gcc_msm8996_match_table[] = { @@ -3666,8 +3668,6 @@ MODULE_DEVICE_TABLE(of, gcc_msm8996_match_table); static int gcc_msm8996_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - int i, ret; struct regmap *regmap; regmap = qcom_cc_map(pdev, &gcc_msm8996_desc); @@ -3680,12 +3680,6 @@ static int gcc_msm8996_probe(struct platform_device *pdev) */ regmap_update_bits(regmap, 0x52008, BIT(21), BIT(21)); - for (i = 0; i < ARRAY_SIZE(gcc_msm8996_hws); i++) { - ret = devm_clk_hw_register(dev, gcc_msm8996_hws[i]); - if (ret) - return ret; - } - return qcom_cc_really_probe(pdev, &gcc_msm8996_desc, regmap); } diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index 3cbabbb8bd9a..c240fba794c7 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -2959,6 +2959,10 @@ static const struct regmap_config gcc_msm8998_regmap_config = { .fast_io = true, }; +static struct clk_hw *gcc_msm8998_hws[] = { + &xo.hw, +}; + static const struct qcom_cc_desc gcc_msm8998_desc = { .config = &gcc_msm8998_regmap_config, .clks = gcc_msm8998_clocks, @@ -2967,6 +2971,8 @@ static const struct qcom_cc_desc gcc_msm8998_desc = { .num_resets = ARRAY_SIZE(gcc_msm8998_resets), .gdscs = gcc_msm8998_gdscs, .num_gdscs = ARRAY_SIZE(gcc_msm8998_gdscs), + .clk_hws = gcc_msm8998_hws, + .num_clk_hws = ARRAY_SIZE(gcc_msm8998_hws), }; static int gcc_msm8998_probe(struct platform_device *pdev) @@ -2986,10 +2992,6 @@ static int gcc_msm8998_probe(struct platform_device *pdev) if (ret) return ret; - ret = devm_clk_hw_register(&pdev->dev, &xo.hw); - if (ret) - return ret; - return qcom_cc_really_probe(pdev, &gcc_msm8998_desc, regmap); } diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c index 64da032bb9ed..a7b2fe0fe505 100644 --- a/drivers/clk/qcom/gcc-qcs404.c +++ b/drivers/clk/qcom/gcc-qcs404.c @@ -2692,6 +2692,8 @@ static const struct qcom_cc_desc gcc_qcs404_desc = { .num_clks = ARRAY_SIZE(gcc_qcs404_clocks), .resets = gcc_qcs404_resets, .num_resets = ARRAY_SIZE(gcc_qcs404_resets), + .clk_hws = gcc_qcs404_hws, + .num_clk_hws = ARRAY_SIZE(gcc_qcs404_hws), }; static const struct of_device_id gcc_qcs404_match_table[] = { @@ -2703,7 +2705,6 @@ MODULE_DEVICE_TABLE(of, gcc_qcs404_match_table); static int gcc_qcs404_probe(struct platform_device *pdev) { struct regmap *regmap; - int ret, i; regmap = qcom_cc_map(pdev, &gcc_qcs404_desc); if (IS_ERR(regmap)) @@ -2711,12 +2712,6 @@ static int gcc_qcs404_probe(struct platform_device *pdev) clk_alpha_pll_configure(&gpll3_out_main, regmap, &gpll3_config); - for (i = 0; i < ARRAY_SIZE(gcc_qcs404_hws); i++) { - ret = devm_clk_hw_register(&pdev->dev, gcc_qcs404_hws[i]); - if (ret) - return ret; - } - return qcom_cc_really_probe(pdev, &gcc_qcs404_desc, regmap); } diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index ba239ea4c842..8827db23066f 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -2420,6 +2420,8 @@ static const struct qcom_cc_desc gcc_sdm660_desc = { .num_resets = ARRAY_SIZE(gcc_sdm660_resets), .gdscs = gcc_sdm660_gdscs, .num_gdscs = ARRAY_SIZE(gcc_sdm660_gdscs), + .clk_hws = gcc_sdm660_hws, + .num_clk_hws = ARRAY_SIZE(gcc_sdm660_hws), }; static const struct of_device_id gcc_sdm660_match_table[] = { @@ -2431,7 +2433,7 @@ MODULE_DEVICE_TABLE(of, gcc_sdm660_match_table); static int gcc_sdm660_probe(struct platform_device *pdev) { - int i, ret; + int ret; struct regmap *regmap; regmap = qcom_cc_map(pdev, &gcc_sdm660_desc); @@ -2446,13 +2448,6 @@ static int gcc_sdm660_probe(struct platform_device *pdev) if (ret) return ret; - /* Register the hws */ - for (i = 0; i < ARRAY_SIZE(gcc_sdm660_hws); i++) { - ret = devm_clk_hw_register(&pdev->dev, gcc_sdm660_hws[i]); - if (ret) - return ret; - } - return qcom_cc_really_probe(pdev, &gcc_sdm660_desc, regmap); } diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 7d4ee109435c..7235510eac94 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -3347,6 +3347,8 @@ static const struct qcom_cc_desc mmcc_msm8996_desc = { .num_resets = ARRAY_SIZE(mmcc_msm8996_resets), .gdscs = mmcc_msm8996_gdscs, .num_gdscs = ARRAY_SIZE(mmcc_msm8996_gdscs), + .clk_hws = mmcc_msm8996_hws, + .num_clk_hws = ARRAY_SIZE(mmcc_msm8996_hws), }; static const struct of_device_id mmcc_msm8996_match_table[] = { @@ -3357,8 +3359,6 @@ MODULE_DEVICE_TABLE(of, mmcc_msm8996_match_table); static int mmcc_msm8996_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - int i, ret; struct regmap *regmap; regmap = qcom_cc_map(pdev, &mmcc_msm8996_desc); @@ -3370,12 +3370,6 @@ static int mmcc_msm8996_probe(struct platform_device *pdev) /* Disable the NoC FSM for mmss_mmagic_cfg_ahb_clk */ regmap_update_bits(regmap, 0x5054, BIT(15), 0); - for (i = 0; i < ARRAY_SIZE(mmcc_msm8996_hws); i++) { - ret = devm_clk_hw_register(dev, mmcc_msm8996_hws[i]); - if (ret) - return ret; - } - return qcom_cc_really_probe(pdev, &mmcc_msm8996_desc, regmap); } -- cgit v1.2.3 From d13501a2bedfbea0983cc868d3f1dc692627f60d Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Mon, 11 Feb 2019 00:38:06 +0900 Subject: clk: fractional-divider: check parent rate only if flag is set Custom approximation of fractional-divider may not need parent clock rate checking. For example Rockchip SoCs work fine using grand parent clock rate even if target rate is greater than parent. This patch checks parent clock rate only if CLK_SET_RATE_PARENT flag is set. For detailed example, clock tree of Rockchip I2S audio hardware. - Clock rate of CPLL is 1.2GHz, GPLL is 491.52MHz. - i2s1_div is integer divider can divide N (N is 1~128). Input clock is CPLL or GPLL. Initial divider value is N = 1. Ex) PLL = CPLL, N = 10, i2s1_div output rate is CPLL / 10 = 1.2GHz / 10 = 120MHz - i2s1_frac is fractional divider can divide input to x/y, x and y are 16bit integer. CPLL --> | selector | ---> i2s1_div -+--> | selector | --> I2S1 MCLK GPLL --> | | ,--------------' | | `--> i2s1_frac ---> | | Clock mux system try to choose suitable one from i2s1_div and i2s1_frac for master clock (MCLK) of I2S1. Bad scenario as follows: - Try to set MCLK to 8.192MHz (32kHz audio replay) Candidate setting is - i2s1_div: GPLL / 60 = 8.192MHz i2s1_div candidate is exactly same as target clock rate, so mux choose this clock source. i2s1_div output rate is changed 491.52MHz -> 8.192MHz - After that try to set to 11.2896MHz (44.1kHz audio replay) Candidate settings are - i2s1_div : CPLL / 107 = 11.214945MHz - i2s1_frac: i2s1_div = 8.192MHz This is because clk_fd_round_rate() thinks target rate (11.2896MHz) is higher than parent rate (i2s1_div = 8.192MHz) and returns parent clock rate. Above is current upstreamed behavior. Clock mux system choose i2s1_div, but this clock rate is not acceptable for I2S driver, so users cannot replay audio. Expected behavior is: - Try to set master clock to 11.2896MHz (44.1kHz audio replay) Candidate settings are - i2s1_div : CPLL / 107 = 11.214945MHz - i2s1_frac: i2s1_div * 147/6400 = 11.2896MHz Change i2s1_div to GPLL / 1 = 491.52MHz at same time. If apply this commit, clk_fd_round_rate() calls custom approximate function of Rockchip even if target rate is higher than parent. Custom function changes both grand parent (i2s1_div) and parent (i2s_frac) settings at same time. Clock mux system can choose i2s1_frac and audio works fine. Signed-off-by: Katsuhiro Suzuki Reviewed-by: Heiko Stuebner [sboyd@kernel.org: Make function into a macro instead] Signed-off-by: Stephen Boyd --- drivers/clk/clk-fractional-divider.c | 2 +- include/linux/clk-provider.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 545dceec0bbf..fdfe2e423d15 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -79,7 +79,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long m, n; u64 ret; - if (!rate || rate >= *parent_rate) + if (!rate || (!clk_hw_can_set_rate_parent(hw) && rate >= *parent_rate)) return *parent_rate; if (fd->approximation) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index e443fa9fa859..b7cf80a71293 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -792,6 +792,9 @@ unsigned int __clk_get_enable_count(struct clk *clk); unsigned long clk_hw_get_rate(const struct clk_hw *hw); unsigned long __clk_get_flags(struct clk *clk); unsigned long clk_hw_get_flags(const struct clk_hw *hw); +#define clk_hw_can_set_rate_parent(hw) \ + (clk_hw_get_flags((hw)) & CLK_SET_RATE_PARENT) + bool clk_hw_is_prepared(const struct clk_hw *hw); bool clk_hw_rate_is_protected(const struct clk_hw *hw); bool clk_hw_is_enabled(const struct clk_hw *hw); -- cgit v1.2.3 From a9443a63283ae7eb78f735341da22bc3a69a464d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 18 Feb 2019 22:34:15 +0300 Subject: clk: x86: Move clk-lpss.h to platform_data/x86 clk-lpss.h is solely x86 related header. Move it to correct folder. Signed-off-by: Andy Shevchenko Acked-by: Rafael J. Wysocki Signed-off-by: Stephen Boyd --- drivers/acpi/acpi_lpss.c | 2 +- drivers/clk/x86/clk-lpt.c | 2 +- include/linux/platform_data/clk-lpss.h | 23 ----------------------- include/linux/platform_data/x86/clk-lpss.h | 23 +++++++++++++++++++++++ 4 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 include/linux/platform_data/clk-lpss.h create mode 100644 include/linux/platform_data/x86/clk-lpss.h diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 5f94c35d165f..1e2a10a06b9d 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c index 6b40eb89ae19..68bd3abaef2c 100644 --- a/drivers/clk/x86/clk-lpt.c +++ b/drivers/clk/x86/clk-lpt.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include static int lpt_clk_probe(struct platform_device *pdev) diff --git a/include/linux/platform_data/clk-lpss.h b/include/linux/platform_data/clk-lpss.h deleted file mode 100644 index 23901992b9dd..000000000000 --- a/include/linux/platform_data/clk-lpss.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Intel Low Power Subsystem clocks. - * - * Copyright (C) 2013, Intel Corporation - * Authors: Mika Westerberg - * Rafael J. Wysocki - * - * 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. - */ - -#ifndef __CLK_LPSS_H -#define __CLK_LPSS_H - -struct lpss_clk_data { - const char *name; - struct clk *clk; -}; - -extern int lpt_clk_init(void); - -#endif /* __CLK_LPSS_H */ diff --git a/include/linux/platform_data/x86/clk-lpss.h b/include/linux/platform_data/x86/clk-lpss.h new file mode 100644 index 000000000000..23901992b9dd --- /dev/null +++ b/include/linux/platform_data/x86/clk-lpss.h @@ -0,0 +1,23 @@ +/* + * Intel Low Power Subsystem clocks. + * + * Copyright (C) 2013, Intel Corporation + * Authors: Mika Westerberg + * Rafael J. Wysocki + * + * 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. + */ + +#ifndef __CLK_LPSS_H +#define __CLK_LPSS_H + +struct lpss_clk_data { + const char *name; + struct clk *clk; +}; + +extern int lpt_clk_init(void); + +#endif /* __CLK_LPSS_H */ -- cgit v1.2.3 From bb631af3d55fa89a612a5f09f3a3dda76121385a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 18 Dec 2018 12:20:48 +0100 Subject: clk: at91: optimize clk_round_rate() for AUDIO_PLL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop the search for parent rate when exact match is found. This makes for 3 clk_round_rate() calls instead of 64 of them on SAMA5D2-based board when searching for 12.288MHz clock. Signed-off-by: MichaÅ‚ MirosÅ‚aw Reviewed-by: Nicolas Ferre Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-audio-pll.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c index 36d77146a3bd..3cc4a82f4e9f 100644 --- a/drivers/clk/at91/clk-audio-pll.c +++ b/drivers/clk/at91/clk-audio-pll.c @@ -340,7 +340,12 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate, pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__, rate, *parent_rate); - for (div = 1; div <= AUDIO_PLL_QDPMC_MAX; div++) { + if (!rate) + return 0; + + best_parent_rate = clk_round_rate(pclk->clk, 1); + div = max(best_parent_rate / rate, 1UL); + for (; div <= AUDIO_PLL_QDPMC_MAX; div++) { best_parent_rate = clk_round_rate(pclk->clk, rate * div); tmp_rate = best_parent_rate / div; tmp_diff = abs(rate - tmp_rate); @@ -350,6 +355,8 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate, best_rate = tmp_rate; best_diff = tmp_diff; tmp_qd = div; + if (!best_diff) + break; /* got exact match */ } } -- cgit v1.2.3 From 8f99f5eab06cc837e196f87d4b1e1d14e5f1efe3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 18 Feb 2019 12:19:06 +0300 Subject: clk: qoriq: Improve an error message We intended to print "ret" but there is a copy and paste bug from the previous error message. Signed-off-by: Dan Carpenter Signed-off-by: Stephen Boyd --- drivers/clk/clk-qoriq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 5baa9e051110..a81995c262ac 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -1148,8 +1148,8 @@ static void __init create_one_pll(struct clockgen *cg, int idx) pll->div[i].clk = clk; ret = clk_register_clkdev(clk, pll->div[i].name, NULL); if (ret != 0) - pr_err("%s: %s: register to lookup table failed %ld\n", - __func__, pll->div[i].name, PTR_ERR(clk)); + pr_err("%s: %s: register to lookup table failed %d\n", + __func__, pll->div[i].name, ret); } } -- cgit v1.2.3 From e7e6198c60566eda97655d495087fa73e1d7a1fd Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 9 Jan 2019 12:50:21 +0000 Subject: clk: tegra: dfll: Fix debugfs_simple_attr.cocci warnings Use DEFINE_DEBUGFS_ATTRIBUTE rather than DEFINE_SIMPLE_ATTRIBUTE for debugfs files. Semantic patch information: Rationale: DEFINE_SIMPLE_ATTRIBUTE + debugfs_create_file() imposes some significant overhead as compared to DEFINE_DEBUGFS_ATTRIBUTE + debugfs_create_file_unsafe(). Generated by: scripts/coccinelle/api/debugfs/debugfs_simple_attr.cocci Signed-off-by: YueHaibing Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-dfll.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 609e363dabf8..7ec752ed3499 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -1112,8 +1112,8 @@ static int attr_enable_set(void *data, u64 val) return val ? dfll_enable(td) : dfll_disable(td); } -DEFINE_SIMPLE_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, - "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, + "%llu\n"); static int attr_lock_get(void *data, u64 *val) { @@ -1129,8 +1129,7 @@ static int attr_lock_set(void *data, u64 val) return val ? dfll_lock(td) : dfll_unlock(td); } -DEFINE_SIMPLE_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set, - "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set, "%llu\n"); static int attr_rate_get(void *data, u64 *val) { @@ -1147,7 +1146,7 @@ static int attr_rate_set(void *data, u64 val) return dfll_request_rate(td, val); } -DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n"); static int attr_registers_show(struct seq_file *s, void *data) { @@ -1196,10 +1195,11 @@ static void dfll_debug_init(struct tegra_dfll *td) root = debugfs_create_dir("tegra_dfll_fcpu", NULL); td->debugfs_dir = root; - debugfs_create_file("enable", S_IRUGO | S_IWUSR, root, td, &enable_fops); - debugfs_create_file("lock", S_IRUGO, root, td, &lock_fops); - debugfs_create_file("rate", S_IRUGO, root, td, &rate_fops); - debugfs_create_file("registers", S_IRUGO, root, td, &attr_registers_fops); + debugfs_create_file_unsafe("enable", 0644, root, td, + &enable_fops); + debugfs_create_file_unsafe("lock", 0444, root, td, &lock_fops); + debugfs_create_file_unsafe("rate", 0444, root, td, &rate_fops); + debugfs_create_file("registers", 0444, root, td, &attr_registers_fops); } #else -- cgit v1.2.3 From 812296631816d31eef001078c1b14ce865f8378a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 14 Feb 2019 01:56:16 +0000 Subject: clk: mediatek: fix platform_no_drv_owner.cocci warnings Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: YueHaibing Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt2712.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c index 991d4093726e..2895a5ae814d 100644 --- a/drivers/clk/mediatek/clk-mt2712.c +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -1463,7 +1463,6 @@ static struct platform_driver clk_mt2712_drv = { .probe = clk_mt2712_probe, .driver = { .name = "clk-mt2712", - .owner = THIS_MODULE, .of_match_table = of_match_clk_mt2712, }, }; -- cgit v1.2.3 From bc5d922c93491878c44c9216e9d227c7eeb81d7f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 27 Jan 2019 23:09:20 -0300 Subject: clk: ingenic: Fix round_rate misbehaving with non-integer dividers Take a parent rate of 180 MHz, and a requested rate of 4.285715 MHz. This results in a theorical divider of 41.999993 which is then rounded up to 42. The .round_rate function would then return (180 MHz / 42) as the clock, rounded down, so 4.285714 MHz. Calling clk_set_rate on 4.285714 MHz would round the rate again, and give a theorical divider of 42,0000028, now rounded up to 43, and the rate returned would be (180 MHz / 43) which is 4.186046 MHz, aka. not what we requested. Fix this by rounding up the divisions. Signed-off-by: Paul Cercueil Tested-by: Maarten ter Huurne Cc: Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/cgu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index 5ef7d9ba2195..b40160eb3372 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -426,16 +426,16 @@ ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate, struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw); struct ingenic_cgu *cgu = ingenic_clk->cgu; const struct ingenic_cgu_clk_info *clk_info; - long rate = *parent_rate; + unsigned int div = 1; clk_info = &cgu->clock_info[ingenic_clk->idx]; if (clk_info->type & CGU_CLK_DIV) - rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate); + div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate); else if (clk_info->type & CGU_CLK_FIXDIV) - rate /= clk_info->fixdiv.div; + div = clk_info->fixdiv.div; - return rate; + return DIV_ROUND_UP(*parent_rate, div); } static int @@ -455,7 +455,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate, if (clk_info->type & CGU_CLK_DIV) { div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate); - rate = parent_rate / div; + rate = DIV_ROUND_UP(parent_rate, div); if (rate != req_rate) return -EINVAL; -- cgit v1.2.3 From 7ca4c922aad2e3c46767a12f80d01c6b25337b59 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 27 Jan 2019 23:09:21 -0300 Subject: clk: ingenic: Fix doc of ingenic_cgu_div_info The 'div' field does not represent a number of bits used to divide (understand: right-shift) the divider, but a number itself used to divide the divider. Signed-off-by: Paul Cercueil Signed-off-by: Maarten ter Huurne Cc: Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/cgu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h index 502bcbb61b04..e12716d8ce3c 100644 --- a/drivers/clk/ingenic/cgu.h +++ b/drivers/clk/ingenic/cgu.h @@ -80,7 +80,7 @@ struct ingenic_cgu_mux_info { * @reg: offset of the divider control register within the CGU * @shift: number of bits to left shift the divide value by (ie. the index of * the lowest bit of the divide value within its control register) - * @div: number of bits to divide the divider value by (i.e. if the + * @div: number to divide the divider value by (i.e. if the * effective divider value is the value written to the register * multiplied by some constant) * @bits: the size of the divide value in bits -- cgit v1.2.3 From df446f7e6ec0ed474dab2e6f19e4618116907f29 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 22 Feb 2019 11:59:39 +0000 Subject: clk: renesas: r8a774a1: Fix LAST_DT_CORE_CLK Enum LAST_DT_CORE_CLK needs updating as R8A774A1_CLK_CANFD was recently added and it's the core clock with the highest index. Signed-off-by: Fabrizio Castro Reviewed-by: Chris Paterson Fixes: 9d034e151b40 ("clk: renesas: r8a774a1: Add missing CANFD clock") Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd --- drivers/clk/renesas/r8a774a1-cpg-mssr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c index e10374119a91..4d92b27a6153 100644 --- a/drivers/clk/renesas/r8a774a1-cpg-mssr.c +++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c @@ -21,7 +21,7 @@ enum clk_ids { /* Core Clock Outputs exported to DT */ - LAST_DT_CORE_CLK = R8A774A1_CLK_OSC, + LAST_DT_CORE_CLK = R8A774A1_CLK_CANFD, /* External Input Clocks */ CLK_EXTAL, -- cgit v1.2.3 From b026a7eca1a7b1254017835f91438b569bfc4e54 Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Mon, 25 Feb 2019 10:09:09 +0800 Subject: clk: mediatek: add MUX_GATE_FLAGS_2 Add MUX_GATE_FLAGS_2 for the clock which needs to set two falgs. Such as some mux need to set the flags of "CLK_MUX_ROUND_CLOSEST". Signed-off-by: chunhui dai Signed-off-by: wangyan wang Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mtk.c | 2 +- drivers/clk/mediatek/clk-mtk.h | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 9c0ae4278a94..2ed996404804 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -167,7 +167,7 @@ struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, mux->mask = BIT(mc->mux_width) - 1; mux->shift = mc->mux_shift; mux->lock = lock; - + mux->flags = mc->mux_flags; mux_hw = &mux->hw; mux_ops = &clk_mux_ops; diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index f83c2bbb677e..5f0b18bc5ef5 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -81,15 +81,13 @@ struct mtk_composite { signed char divider_shift; signed char divider_width; + u8 mux_flags; + signed char num_parents; }; -/* - * In case the rate change propagation to parent clocks is undesirable, - * this macro allows to specify the clock flags manually. - */ -#define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ - _gate, _flags) { \ +#define MUX_GATE_FLAGS_2(_id, _name, _parents, _reg, _shift, \ + _width, _gate, _flags, _muxflags) { \ .id = _id, \ .name = _name, \ .mux_reg = _reg, \ @@ -101,8 +99,18 @@ struct mtk_composite { .parent_names = _parents, \ .num_parents = ARRAY_SIZE(_parents), \ .flags = _flags, \ + .mux_flags = _muxflags, \ } +/* + * In case the rate change propagation to parent clocks is undesirable, + * this macro allows to specify the clock flags manually. + */ +#define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ + _gate, _flags) \ + MUX_GATE_FLAGS_2(_id, _name, _parents, _reg, \ + _shift, _width, _gate, _flags, 0) + /* * Unless necessary, all MUX_GATE clocks propagate rate changes to their * parent clock by default. -- cgit v1.2.3 From d3174bc836d5aadc871f74ed496694c5ea27b104 Mon Sep 17 00:00:00 2001 From: chunhui dai Date: Mon, 25 Feb 2019 10:09:10 +0800 Subject: clk: mediatek: using CLK_MUX_ROUND_CLOSEST for the clock of dpi1_sel The MUX clock of dpi1_sel should select the closet clock for itself. We could add this flag to enable this function of MUX in CCF. Signed-off-by: chunhui dai Signed-off-by: wangyan wang Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt2701.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index ab6ab07f53e6..905a2316f6a7 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -535,8 +535,8 @@ static const struct mtk_composite top_muxes[] = { 0x0080, 8, 2, 15), MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x0080, 16, 3, 23), - MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, - 0x0080, 24, 2, 31), + MUX_GATE_FLAGS_2(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, + 0x0080, 24, 2, 31, 0, CLK_MUX_ROUND_CLOSEST), MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents, 0x0090, 0, 3, 7), -- cgit v1.2.3 From 97d010dc420469fbdfcf0b335578f19a0b25e17b Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Sat, 23 Feb 2019 01:08:58 +0100 Subject: clk: at91: programmable: remove unneeded register read This register read is a leftover of a previous read/modify/write. We now use regmap_update_bits(), so we don't need it anymore. Signed-off-by: Nicolas Ferre Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-programmable.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 5bc68b9c5498..89d6f3736dbf 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -132,11 +132,8 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_programmable *prog = to_clk_programmable(hw); const struct clk_programmable_layout *layout = prog->layout; unsigned long div = parent_rate / rate; - unsigned int pckr; int shift = 0; - regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr); - if (!div) return -EINVAL; -- cgit v1.2.3 From 635bd69bbe92acfeddcc6f3d7e7eb1a9049f361b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 26 Feb 2019 01:57:32 +0000 Subject: clk: ingenic: Remove set but not used variable 'enable' Fixes gcc '-Wunused-but-set-variable' warning: drivers/clk/ingenic/cgu.c: In function 'ingenic_pll_recalc_rate': drivers/clk/ingenic/cgu.c:86:15: warning: variable 'enable' set but not used [-Wunused-but-set-variable] It's not used after commit ab27eb4bc365 ("clk: ingenic: Add code to enable/disable PLLs") Signed-off-by: YueHaibing Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/cgu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index b40160eb3372..510b685212d3 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -83,7 +83,7 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) const struct ingenic_cgu_clk_info *clk_info; const struct ingenic_cgu_pll_info *pll_info; unsigned m, n, od_enc, od; - bool bypass, enable; + bool bypass; unsigned long flags; u32 ctl; @@ -103,7 +103,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) od_enc &= GENMASK(pll_info->od_bits - 1, 0); bypass = !pll_info->no_bypass_bit && !!(ctl & BIT(pll_info->bypass_bit)); - enable = !!(ctl & BIT(pll_info->enable_bit)); if (bypass) return parent_rate; -- cgit v1.2.3 From 4b5a59a265f05a41df6bb3449d8c6db50577dca5 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 25 Feb 2019 23:02:21 -0800 Subject: clk: qcom: gcc-sdm845: Define parent of PCIe PIPE clocks The PCIe PIPE clock in the GCC is fed by the PIPE clock coming from the PHY, describe this relationship. Signed-off-by: Bjorn Andersson Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-sdm845.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index c782e62dd98b..83843896177d 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -1697,6 +1697,9 @@ static struct clk_branch gcc_pcie_0_pipe_clk = { .enable_mask = BIT(4), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_0_pipe_clk", + .parent_names = (const char *[]){ "pcie_0_pipe_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1796,6 +1799,8 @@ static struct clk_branch gcc_pcie_1_pipe_clk = { .enable_mask = BIT(30), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_1_pipe_clk", + .parent_names = (const char *[]){ "pcie_1_pipe_clk" }, + .num_parents = 1, .ops = &clk_branch2_ops, }, }, -- cgit v1.2.3 From 03c4fda603fb48d5bb58cc72906dd592a54e464f Mon Sep 17 00:00:00 2001 From: Jasper Mattsson Date: Thu, 14 Feb 2019 17:32:18 +0100 Subject: clk: mediatek: Add MUX_FLAGS macro This is required to mark outputs of certain MUXes as CLK_IS_CRITICAL. Signed-off-by: Jasper Mattsson Acked-by: Mars Cheng Signed-off-by: Matthias Brugger Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mtk.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index f83c2bbb677e..daab6ee94788 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -111,7 +111,11 @@ struct mtk_composite { MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ _gate, CLK_SET_RATE_PARENT) -#define MUX(_id, _name, _parents, _reg, _shift, _width) { \ +#define MUX(_id, _name, _parents, _reg, _shift, _width) \ + MUX_FLAGS(_id, _name, _parents, _reg, \ + _shift, _width, CLK_SET_RATE_PARENT) + +#define MUX_FLAGS(_id, _name, _parents, _reg, _shift, _width, _flags) { \ .id = _id, \ .name = _name, \ .mux_reg = _reg, \ @@ -121,7 +125,7 @@ struct mtk_composite { .divider_shift = -1, \ .parent_names = _parents, \ .num_parents = ARRAY_SIZE(_parents), \ - .flags = CLK_SET_RATE_PARENT, \ + .flags = _flags, \ } #define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, \ -- cgit v1.2.3 From 5a1cc4c27ad2aa3f988e2d69ce281fd3e8292ce3 Mon Sep 17 00:00:00 2001 From: Jasper Mattsson Date: Thu, 14 Feb 2019 17:32:30 +0100 Subject: clk: mediatek: Add flags to mtk_gate This is required to mark gates as CLK_IS_CRITICAL. Signed-off-by: Jasper Mattsson Acked-by: Mars Cheng Signed-off-by: Matthias Brugger Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-gate.c | 4 +++- drivers/clk/mediatek/clk-gate.h | 3 ++- drivers/clk/mediatek/clk-mtk.c | 2 +- drivers/clk/mediatek/clk-mtk.h | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index 934bf0e45e26..9628d4e7690b 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -157,7 +157,8 @@ struct clk *mtk_clk_register_gate( int clr_ofs, int sta_ofs, u8 bit, - const struct clk_ops *ops) + const struct clk_ops *ops, + unsigned long flags) { struct mtk_clk_gate *cg; struct clk *clk; @@ -172,6 +173,7 @@ struct clk *mtk_clk_register_gate( init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; init.ops = ops; + init.flags = flags; cg->regmap = regmap; cg->set_ofs = set_ofs; diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h index 72ef89b3ad7b..9f766dfe1d57 100644 --- a/drivers/clk/mediatek/clk-gate.h +++ b/drivers/clk/mediatek/clk-gate.h @@ -47,6 +47,7 @@ struct clk *mtk_clk_register_gate( int clr_ofs, int sta_ofs, u8 bit, - const struct clk_ops *ops); + const struct clk_ops *ops, + unsigned long flags); #endif /* __DRV_CLK_GATE_H */ diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 9c0ae4278a94..ef410413bb0b 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -130,7 +130,7 @@ int mtk_clk_register_gates(struct device_node *node, gate->regs->set_ofs, gate->regs->clr_ofs, gate->regs->sta_ofs, - gate->shift, gate->ops); + gate->shift, gate->ops, gate->flags); if (IS_ERR(clk)) { pr_err("Failed to register clk %s: %ld\n", diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index daab6ee94788..987ff2855249 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -162,6 +162,7 @@ struct mtk_gate { const struct mtk_gate_regs *regs; int shift; const struct clk_ops *ops; + unsigned long flags; }; int mtk_clk_register_gates(struct device_node *node, -- cgit v1.2.3 From b35656de2a13298512a558506fa8d97a9eda5494 Mon Sep 17 00:00:00 2001 From: Jasper Mattsson Date: Thu, 14 Feb 2019 17:32:42 +0100 Subject: clk: mediatek: Mark bus and DRAM related clocks as critical Currently, DRAM-related clocks are not marked with CLK_IS_CRITICAL for MT6797. This causes memory corruption when the system is booted without clk_ignore_unused. This patch marks MUX ddrphycfg_sel as well as gates infra_dramc_f26m and infra_dramc_b_f26m as CLK_IS_CRITICAL. Signed-off-by: Jasper Mattsson Signed-off-by: Matthias Brugger Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt6797.c | 68 +++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c index 5702bc974ed9..c2b46b184b9a 100644 --- a/drivers/clk/mediatek/clk-mt6797.c +++ b/drivers/clk/mediatek/clk-mt6797.c @@ -324,6 +324,10 @@ static const char * const anc_md32_parents[] = { "univpll_d5", }; +/* + * Clock mux ddrphycfg is needed by the DRAM controller. We mark it as + * critical as otherwise the system will hang after boot. + */ static const struct mtk_composite top_muxes[] = { MUX(CLK_TOP_MUX_ULPOSC_AXI_CK_MUX_PRE, "ulposc_axi_ck_mux_pre", ulposc_axi_ck_mux_pre_parents, 0x0040, 3, 1), @@ -331,8 +335,8 @@ static const struct mtk_composite top_muxes[] = { ulposc_axi_ck_mux_parents, 0x0040, 2, 1), MUX(CLK_TOP_MUX_AXI, "axi_sel", axi_parents, 0x0040, 0, 2), - MUX(CLK_TOP_MUX_DDRPHYCFG, "ddrphycfg_sel", ddrphycfg_parents, - 0x0040, 16, 2), + MUX_FLAGS(CLK_TOP_MUX_DDRPHYCFG, "ddrphycfg_sel", ddrphycfg_parents, + 0x0040, 16, 2, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), MUX(CLK_TOP_MUX_MM, "mm_sel", mm_parents, 0x0040, 24, 2), MUX_GATE(CLK_TOP_MUX_PWM, "pwm_sel", pwm_parents, 0x0050, 0, 3, 7), @@ -424,33 +428,45 @@ static const struct mtk_gate_regs infra2_cg_regs = { .sta_ofs = 0x00b0, }; -#define GATE_ICG0(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra0_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ +#define GATE_ICG0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &infra0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ } -#define GATE_ICG1(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra1_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ +#define GATE_ICG1(_id, _name, _parent, _shift) \ + GATE_ICG1_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_ICG1_FLAGS(_id, _name, _parent, _shift, _flags) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &infra1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + .flags = _flags, \ } -#define GATE_ICG2(_id, _name, _parent, _shift) { \ - .id = _id, \ - .name = _name, \ - .parent_name = _parent, \ - .regs = &infra2_cg_regs, \ - .shift = _shift, \ - .ops = &mtk_clk_gate_ops_setclr, \ +#define GATE_ICG2(_id, _name, _parent, _shift) \ + GATE_ICG2_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_ICG2_FLAGS(_id, _name, _parent, _shift, _flags) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &infra2_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + .flags = _flags, \ } +/* + * Clock gates dramc and dramc_b are needed by the DRAM controller. + * We mark them as critical as otherwise the system will hang after boot. + */ static const struct mtk_gate infra_clks[] = { GATE_ICG0(CLK_INFRA_PMIC_TMR, "infra_pmic_tmr", "ulposc", 0), GATE_ICG0(CLK_INFRA_PMIC_AP, "infra_pmic_ap", "pmicspi_sel", 1), @@ -505,7 +521,8 @@ static const struct mtk_gate infra_clks[] = { GATE_ICG1(CLK_INFRA_CCIF_AP, "infra_ccif_ap", "axi_sel", 23), GATE_ICG1(CLK_INFRA_AUDIO, "infra_audio", "axi_sel", 25), GATE_ICG1(CLK_INFRA_CCIF_MD, "infra_ccif_md", "axi_sel", 26), - GATE_ICG1(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", "clk26m", 31), + GATE_ICG1_FLAGS(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", + "clk26m", 31, CLK_IS_CRITICAL), GATE_ICG2(CLK_INFRA_I2C4, "infra_i2c4", "axi_sel", 0), GATE_ICG2(CLK_INFRA_I2C_APPM, "infra_i2c_appm", "axi_sel", 1), GATE_ICG2(CLK_INFRA_I2C_GPUPM, "infra_i2c_gpupm", "axi_sel", 2), @@ -516,7 +533,8 @@ static const struct mtk_gate infra_clks[] = { GATE_ICG2(CLK_INFRA_I2C5, "infra_i2c5", "axi_sel", 7), GATE_ICG2(CLK_INFRA_SYS_CIRQ, "infra_sys_cirq", "axi_sel", 8), GATE_ICG2(CLK_INFRA_SPI1, "infra_spi1", "spi_sel", 10), - GATE_ICG2(CLK_INFRA_DRAMC_B_F26M, "infra_dramc_b_f26m", "clk26m", 11), + GATE_ICG2_FLAGS(CLK_INFRA_DRAMC_B_F26M, "infra_dramc_b_f26m", + "clk26m", 11, CLK_IS_CRITICAL), GATE_ICG2(CLK_INFRA_ANC_MD32, "infra_anc_md32", "anc_md32_sel", 12), GATE_ICG2(CLK_INFRA_ANC_MD32_32K, "infra_anc_md32_32k", "clk26m", 13), GATE_ICG2(CLK_INFRA_DVFS_SPM1, "infra_dvfs_spm1", "axi_sel", 15), -- cgit v1.2.3 From 3b9ea606cda533964985966ad5b30715da7ba097 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 26 Feb 2019 05:17:36 +0000 Subject: clk: imx: scu: add cpu frequency scaling support On NXP's i.MX SoCs with system controller inside, CPU frequency scaling can ONLY be done by system controller firmware, and it can ONLY be requested from secure mode, so Linux kernel has to call ARM SMC to trap to ARM-Trusted-Firmware to request system controller firmware to do CPU frequency scaling. This patch adds i.MX system controller CPU frequency scaling support, it reuses cpufreq-dt driver and implement the CPU frequency scaling inside SCU clock driver. Signed-off-by: Anson Huang Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-scu.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index f460526a7abb..fbef740704d0 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -4,12 +4,17 @@ * Dong Aisheng */ +#include +#include #include #include #include #include "clk-scu.h" +#define IMX_SIP_CPUFREQ 0xC2000001 +#define IMX_SIP_SET_CPUFREQ 0x00 + static struct imx_sc_ipc *ccm_ipc_handle; /* @@ -180,6 +185,25 @@ static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate, return rate; } +static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_scu *clk = to_clk_scu(hw); + struct arm_smccc_res res; + unsigned long cluster_id; + + if (clk->rsrc_id == IMX_SC_R_A35) + cluster_id = 0; + else + return -EINVAL; + + /* CPU frequency scaling can ONLY be done by ARM-Trusted-Firmware */ + arm_smccc_smc(IMX_SIP_CPUFREQ, IMX_SIP_SET_CPUFREQ, + cluster_id, rate, 0, 0, 0, 0, &res); + + return 0; +} + /* * clk_scu_set_rate - Set rate for a SCU clock * @hw: clock to change rate for @@ -312,6 +336,14 @@ static const struct clk_ops clk_scu_ops = { .unprepare = clk_scu_unprepare, }; +static const struct clk_ops clk_scu_cpu_ops = { + .recalc_rate = clk_scu_recalc_rate, + .round_rate = clk_scu_round_rate, + .set_rate = clk_scu_atf_set_cpu_rate, + .prepare = clk_scu_prepare, + .unprepare = clk_scu_unprepare, +}; + struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, int num_parents, u32 rsrc_id, u8 clk_type) { @@ -329,6 +361,10 @@ struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, init.name = name; init.ops = &clk_scu_ops; + if (rsrc_id == IMX_SC_R_A35) + init.ops = &clk_scu_cpu_ops; + else + init.ops = &clk_scu_ops; init.parent_names = parents; init.num_parents = num_parents; -- cgit v1.2.3 From e9dda4af685ff4c19cd9236e12c1ee0377696843 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 22 Feb 2019 17:07:32 +0000 Subject: clk: imx: Refactor entire sccg pll clk Make the entire combination of plls to be one single clock. The parents used for bypasses are specified each as an index in the parents list. The determine_rate does a lookup throughout all the possible combinations for all the divs and returns the best possible 'setup' which in turn is used by set_rate later to set up all the divs and bypasses. Signed-off-by: Abel Vesa Tested-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mq.c | 53 +---- drivers/clk/imx/clk-sccg-pll.c | 514 ++++++++++++++++++++++++++++++++--------- drivers/clk/imx/clk.h | 9 +- 3 files changed, 417 insertions(+), 159 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 01c771f441cb..081dc2d7c99c 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -34,15 +34,10 @@ static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; -static const char * const sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; -static const char * const sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; -static const char * const sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; -static const char * const dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; - -static const char * const sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; -static const char * const sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; -static const char * const sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; -static const char * const dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; +static const char * const sys1_pll_out_sels[] = {"sys1_pll1_ref_sel", }; +static const char * const sys2_pll_out_sels[] = {"sys1_pll1_ref_sel", "sys2_pll1_ref_sel", }; +static const char * const sys3_pll_out_sels[] = {"sys3_pll1_ref_sel", "sys2_pll1_ref_sel", }; +static const char * const dram_pll_out_sels[] = {"dram_pll1_ref_sel", }; /* CCM ROOT */ static const char * const imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", @@ -313,10 +308,6 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) 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); @@ -324,25 +315,6 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) 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_flags("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT); @@ -352,15 +324,6 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) 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); @@ -368,11 +331,11 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) 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); + clks[IMX8MQ_SYS1_PLL_OUT] = imx_clk_sccg_pll("sys1_pll_out", sys1_pll_out_sels, ARRAY_SIZE(sys1_pll_out_sels), 0, 0, 0, base + 0x30, CLK_IS_CRITICAL); + clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_sccg_pll("sys2_pll_out", sys2_pll_out_sels, ARRAY_SIZE(sys2_pll_out_sels), 0, 0, 1, base + 0x3c, CLK_IS_CRITICAL); + clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_sccg_pll("sys3_pll_out", sys3_pll_out_sels, ARRAY_SIZE(sys3_pll_out_sels), 0, 0, 1, base + 0x48, CLK_IS_CRITICAL); + clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_sccg_pll("dram_pll_out", dram_pll_out_sels, ARRAY_SIZE(dram_pll_out_sels), 0, 0, 0, base + 0x60, CLK_IS_CRITICAL); /* 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); diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c index ee7752bace89..9dfd03a95557 100644 --- a/drivers/clk/imx/clk-sccg-pll.c +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -25,87 +25,292 @@ #define PLL_DIVF2_MASK GENMASK(12, 7) #define PLL_DIVR1_MASK GENMASK(27, 25) #define PLL_DIVR2_MASK GENMASK(24, 19) +#define PLL_DIVQ_MASK GENMASK(6, 1) #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 +/* These are the specification limits for the SSCG PLL */ +#define PLL_REF_MIN_FREQ 25000000UL +#define PLL_REF_MAX_FREQ 235000000UL -#define PLL_SCCG_LOCK_TIMEOUT 70 +#define PLL_STAGE1_MIN_FREQ 1600000000UL +#define PLL_STAGE1_MAX_FREQ 2400000000UL + +#define PLL_STAGE1_REF_MIN_FREQ 25000000UL +#define PLL_STAGE1_REF_MAX_FREQ 54000000UL + +#define PLL_STAGE2_MIN_FREQ 1200000000UL +#define PLL_STAGE2_MAX_FREQ 2400000000UL + +#define PLL_STAGE2_REF_MIN_FREQ 54000000UL +#define PLL_STAGE2_REF_MAX_FREQ 75000000UL + +#define PLL_OUT_MIN_FREQ 20000000UL +#define PLL_OUT_MAX_FREQ 1200000000UL + +#define PLL_DIVR1_MAX 7 +#define PLL_DIVR2_MAX 63 +#define PLL_DIVF1_MAX 63 +#define PLL_DIVF2_MAX 63 +#define PLL_DIVQ_MAX 63 + +#define PLL_BYPASS_NONE 0x0 +#define PLL_BYPASS1 0x2 +#define PLL_BYPASS2 0x1 + +#define SSCG_PLL_BYPASS1_MASK BIT(5) +#define SSCG_PLL_BYPASS2_MASK BIT(4) +#define SSCG_PLL_BYPASS_MASK GENMASK(5, 4) + +#define PLL_SCCG_LOCK_TIMEOUT 70 + +struct clk_sccg_pll_setup { + int divr1, divf1; + int divr2, divf2; + int divq; + int bypass; + + uint64_t vco1; + uint64_t vco2; + uint64_t fout; + uint64_t ref; + uint64_t ref_div1; + uint64_t ref_div2; + uint64_t fout_request; + int fout_error; +}; struct clk_sccg_pll { struct clk_hw hw; - void __iomem *base; + const struct clk_ops ops; + + void __iomem *base; + + struct clk_sccg_pll_setup setup; + + u8 parent; + u8 bypass1; + u8 bypass2; }; #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) +static int clk_sccg_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); + val = readl_relaxed(pll->base + PLL_CFG0); + + /* don't wait for lock if all plls are bypassed */ + if (!(val & SSCG_PLL_BYPASS2_MASK)) + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK, + 0, PLL_SCCG_LOCK_TIMEOUT); + + return 0; } -static int clk_pll1_is_prepared(struct clk_hw *hw) +static int clk_sccg_pll2_check_match(struct clk_sccg_pll_setup *setup, + struct clk_sccg_pll_setup *temp_setup) { - struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); - u32 val; + int new_diff = temp_setup->fout - temp_setup->fout_request; + int diff = temp_setup->fout_error; - val = readl_relaxed(pll->base + PLL_CFG0); - return (val & PLL_PD_MASK) ? 0 : 1; + if (abs(diff) > abs(new_diff)) { + temp_setup->fout_error = new_diff; + memcpy(setup, temp_setup, sizeof(struct clk_sccg_pll_setup)); + + if (temp_setup->fout_request == temp_setup->fout) + return 0; + } + return -1; } -static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static int clk_sccg_divq_lookup(struct clk_sccg_pll_setup *setup, + struct clk_sccg_pll_setup *temp_setup) { - struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); - u32 val, divf; + int ret = -EINVAL; + + for (temp_setup->divq = 0; temp_setup->divq <= PLL_DIVQ_MAX; + temp_setup->divq++) { + temp_setup->vco2 = temp_setup->vco1; + do_div(temp_setup->vco2, temp_setup->divr2 + 1); + temp_setup->vco2 *= 2; + temp_setup->vco2 *= temp_setup->divf2 + 1; + if (temp_setup->vco2 >= PLL_STAGE2_MIN_FREQ && + temp_setup->vco2 <= PLL_STAGE2_MAX_FREQ) { + temp_setup->fout = temp_setup->vco2; + do_div(temp_setup->fout, 2 * (temp_setup->divq + 1)); + + ret = clk_sccg_pll2_check_match(setup, temp_setup); + if (!ret) { + temp_setup->bypass = PLL_BYPASS1; + return ret; + } + } + } - val = readl_relaxed(pll->base + PLL_CFG2); - divf = FIELD_GET(PLL_DIVF1_MASK, val); + return ret; +} + +static int clk_sccg_divf2_lookup(struct clk_sccg_pll_setup *setup, + struct clk_sccg_pll_setup *temp_setup) +{ + int ret = -EINVAL; + + for (temp_setup->divf2 = 0; temp_setup->divf2 <= PLL_DIVF2_MAX; + temp_setup->divf2++) { + ret = clk_sccg_divq_lookup(setup, temp_setup); + if (!ret) + return ret; + } - return parent_rate * 2 * (divf + 1); + return ret; } -static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_sccg_divr2_lookup(struct clk_sccg_pll_setup *setup, + struct clk_sccg_pll_setup *temp_setup) { - unsigned long parent_rate = *prate; - u32 div; + int ret = -EINVAL; + + for (temp_setup->divr2 = 0; temp_setup->divr2 <= PLL_DIVR2_MAX; + temp_setup->divr2++) { + temp_setup->ref_div2 = temp_setup->vco1; + do_div(temp_setup->ref_div2, temp_setup->divr2 + 1); + if (temp_setup->ref_div2 >= PLL_STAGE2_REF_MIN_FREQ && + temp_setup->ref_div2 <= PLL_STAGE2_REF_MAX_FREQ) { + ret = clk_sccg_divf2_lookup(setup, temp_setup); + if (!ret) + return ret; + } + } + + return ret; +} + +static int clk_sccg_pll2_find_setup(struct clk_sccg_pll_setup *setup, + struct clk_sccg_pll_setup *temp_setup, + uint64_t ref) +{ + + int ret = -EINVAL; - if (!parent_rate) - return 0; + if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ) + return ret; - div = rate / (parent_rate * 2); + temp_setup->vco1 = ref; - return parent_rate * div * 2; + ret = clk_sccg_divr2_lookup(setup, temp_setup); + return ret; } -static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static int clk_sccg_divf1_lookup(struct clk_sccg_pll_setup *setup, + struct clk_sccg_pll_setup *temp_setup) { - struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); - u32 val; - u32 divf; + int ret = -EINVAL; - if (!parent_rate) - return -EINVAL; + for (temp_setup->divf1 = 0; temp_setup->divf1 <= PLL_DIVF1_MAX; + temp_setup->divf1++) { + uint64_t vco1 = temp_setup->ref; - divf = rate / (parent_rate * 2); + do_div(vco1, temp_setup->divr1 + 1); + vco1 *= 2; + vco1 *= temp_setup->divf1 + 1; - 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); + ret = clk_sccg_pll2_find_setup(setup, temp_setup, vco1); + if (!ret) { + temp_setup->bypass = PLL_BYPASS_NONE; + return ret; + } + } + + return ret; +} + +static int clk_sccg_divr1_lookup(struct clk_sccg_pll_setup *setup, + struct clk_sccg_pll_setup *temp_setup) +{ + int ret = -EINVAL; + + for (temp_setup->divr1 = 0; temp_setup->divr1 <= PLL_DIVR1_MAX; + temp_setup->divr1++) { + temp_setup->ref_div1 = temp_setup->ref; + do_div(temp_setup->ref_div1, temp_setup->divr1 + 1); + if (temp_setup->ref_div1 >= PLL_STAGE1_REF_MIN_FREQ && + temp_setup->ref_div1 <= PLL_STAGE1_REF_MAX_FREQ) { + ret = clk_sccg_divf1_lookup(setup, temp_setup); + if (!ret) + return ret; + } + } + + return ret; +} + +static int clk_sccg_pll1_find_setup(struct clk_sccg_pll_setup *setup, + struct clk_sccg_pll_setup *temp_setup, + uint64_t ref) +{ + + int ret = -EINVAL; + + if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ) + return ret; + + temp_setup->ref = ref; + + ret = clk_sccg_divr1_lookup(setup, temp_setup); + + return ret; +} + +static int clk_sccg_pll_find_setup(struct clk_sccg_pll_setup *setup, + uint64_t prate, + uint64_t rate, int try_bypass) +{ + struct clk_sccg_pll_setup temp_setup; + int ret = -EINVAL; + + memset(&temp_setup, 0, sizeof(struct clk_sccg_pll_setup)); + memset(setup, 0, sizeof(struct clk_sccg_pll_setup)); + + temp_setup.fout_error = PLL_OUT_MAX_FREQ; + temp_setup.fout_request = rate; + + switch (try_bypass) { - return clk_pll_wait_lock(pll); + case PLL_BYPASS2: + if (prate == rate) { + setup->bypass = PLL_BYPASS2; + setup->fout = rate; + ret = 0; + } + break; + + case PLL_BYPASS1: + ret = clk_sccg_pll2_find_setup(setup, &temp_setup, prate); + break; + + case PLL_BYPASS_NONE: + ret = clk_sccg_pll1_find_setup(setup, &temp_setup, prate); + break; + } + + return ret; +} + + +static int clk_sccg_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + + u32 val = readl_relaxed(pll->base + PLL_CFG0); + + return (val & PLL_PD_MASK) ? 0 : 1; } -static int clk_pll1_prepare(struct clk_hw *hw) +static int clk_sccg_pll_prepare(struct clk_hw *hw) { struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); u32 val; @@ -114,10 +319,10 @@ static int clk_pll1_prepare(struct clk_hw *hw) val &= ~PLL_PD_MASK; writel_relaxed(val, pll->base + PLL_CFG0); - return clk_pll_wait_lock(pll); + return clk_sccg_pll_wait_lock(pll); } -static void clk_pll1_unprepare(struct clk_hw *hw) +static void clk_sccg_pll_unprepare(struct clk_hw *hw) { struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); u32 val; @@ -125,121 +330,208 @@ static void clk_pll1_unprepare(struct clk_hw *hw) 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, +static unsigned long clk_sccg_pll_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; + u32 val, divr1, divf1, divr2, divf2, divq; 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)); + divq = FIELD_GET(PLL_DIVQ_MASK, val); + + temp64 = parent_rate; + + val = clk_readl(pll->base + PLL_CFG0); + if (val & SSCG_PLL_BYPASS2_MASK) { + temp64 = parent_rate; + } else if (val & SSCG_PLL_BYPASS1_MASK) { + temp64 *= divf2; + do_div(temp64, (divr2 + 1) * (divq + 1)); + } else { + temp64 *= 2; + temp64 *= (divf1 + 1) * (divf2 + 1); + do_div(temp64, (divr1 + 1) * (divr2 + 1) * (divq + 1)); + } return temp64; } -static long clk_pll2_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_sccg_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { - u32 div; - unsigned long parent_rate = *prate; + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + struct clk_sccg_pll_setup *setup = &pll->setup; + u32 val; - if (!parent_rate) - return 0; + /* set bypass here too since the parent might be the same */ + val = clk_readl(pll->base + PLL_CFG0); + val &= ~SSCG_PLL_BYPASS_MASK; + val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass); + clk_writel(val, pll->base + PLL_CFG0); - div = rate / parent_rate; + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK); + val &= ~(PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK); + val |= FIELD_PREP(PLL_DIVF1_MASK, setup->divf1); + val |= FIELD_PREP(PLL_DIVF2_MASK, setup->divf2); + val |= FIELD_PREP(PLL_DIVR1_MASK, setup->divr1); + val |= FIELD_PREP(PLL_DIVR2_MASK, setup->divr2); + val |= FIELD_PREP(PLL_DIVQ_MASK, setup->divq); + writel_relaxed(val, pll->base + PLL_CFG2); - return parent_rate * div; + return clk_sccg_pll_wait_lock(pll); } -static int clk_pll2_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static u8 clk_sccg_pll_get_parent(struct clk_hw *hw) { + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); u32 val; - u32 divf; + u8 ret = pll->parent; + + val = clk_readl(pll->base + PLL_CFG0); + if (val & SSCG_PLL_BYPASS2_MASK) + ret = pll->bypass2; + else if (val & SSCG_PLL_BYPASS1_MASK) + ret = pll->bypass1; + return ret; +} + +static int clk_sccg_pll_set_parent(struct clk_hw *hw, u8 index) +{ struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; - if (!parent_rate) - return -EINVAL; + val = clk_readl(pll->base + PLL_CFG0); + val &= ~SSCG_PLL_BYPASS_MASK; + val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass); + clk_writel(val, pll->base + PLL_CFG0); - divf = rate / parent_rate; + return clk_sccg_pll_wait_lock(pll); +} - 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); +static int __clk_sccg_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req, + uint64_t min, + uint64_t max, + uint64_t rate, + int bypass) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + struct clk_sccg_pll_setup *setup = &pll->setup; + struct clk_hw *parent_hw = NULL; + int bypass_parent_index; + int ret = -EINVAL; + + req->max_rate = max; + req->min_rate = min; + + switch (bypass) { + case PLL_BYPASS2: + bypass_parent_index = pll->bypass2; + break; + case PLL_BYPASS1: + bypass_parent_index = pll->bypass1; + break; + default: + bypass_parent_index = pll->parent; + break; + } + + parent_hw = clk_hw_get_parent_by_index(hw, bypass_parent_index); + ret = __clk_determine_rate(parent_hw, req); + if (!ret) { + ret = clk_sccg_pll_find_setup(setup, req->rate, + rate, bypass); + } + + req->best_parent_hw = parent_hw; + req->best_parent_rate = req->rate; + req->rate = setup->fout; - return clk_pll_wait_lock(pll); + return ret; } -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 int clk_sccg_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + struct clk_sccg_pll_setup *setup = &pll->setup; + uint64_t rate = req->rate; + uint64_t min = req->min_rate; + uint64_t max = req->max_rate; + int ret = -EINVAL; + + if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ) + return ret; + + ret = __clk_sccg_pll_determine_rate(hw, req, req->rate, req->rate, + rate, PLL_BYPASS2); + if (!ret) + return ret; + + ret = __clk_sccg_pll_determine_rate(hw, req, PLL_STAGE1_REF_MIN_FREQ, + PLL_STAGE1_REF_MAX_FREQ, rate, + PLL_BYPASS1); + if (!ret) + return ret; + + ret = __clk_sccg_pll_determine_rate(hw, req, PLL_REF_MIN_FREQ, + PLL_REF_MAX_FREQ, rate, + PLL_BYPASS_NONE); + if (!ret) + return ret; + + if (setup->fout >= min && setup->fout <= max) + ret = 0; + + return ret; +} -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, +static const struct clk_ops clk_sccg_pll_ops = { + .prepare = clk_sccg_pll_prepare, + .unprepare = clk_sccg_pll_unprepare, + .is_prepared = clk_sccg_pll_is_prepared, + .recalc_rate = clk_sccg_pll_recalc_rate, + .set_rate = clk_sccg_pll_set_rate, + .set_parent = clk_sccg_pll_set_parent, + .get_parent = clk_sccg_pll_get_parent, + .determine_rate = clk_sccg_pll_determine_rate, }; struct clk *imx_clk_sccg_pll(const char *name, - const char *parent_name, + const char * const *parent_names, + u8 num_parents, + u8 parent, u8 bypass1, u8 bypass2, void __iomem *base, - enum imx_sccg_pll_type pll_type) + unsigned long flags) { 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); + pll->parent = parent; + pll->bypass1 = bypass1; + pll->bypass2 = bypass2; + + pll->base = base; init.name = name; - init.flags = 0; - init.parent_names = &parent_name; - init.num_parents = 1; + init.ops = &clk_sccg_pll_ops; + + init.flags = flags; + init.parent_names = parent_names; + init.num_parents = num_parents; pll->base = base; pll->hw.init = &init; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 0aa48d3e3b95..5748ec8673e4 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -60,9 +60,12 @@ struct clk *imx_clk_pllv2(const char *name, const char *parent, 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); +struct clk *imx_clk_sccg_pll(const char *name, + const char * const *parent_names, + u8 num_parents, + u8 parent, u8 bypass1, u8 bypass2, + void __iomem *base, + unsigned long flags); enum imx_pllv3_type { IMX_PLLV3_GENERIC, -- cgit v1.2.3 From 64f4466c887e2f16cb01467c8064ff1106c980a3 Mon Sep 17 00:00:00 2001 From: Seiya Wang Date: Mon, 25 Feb 2019 14:51:12 +0800 Subject: clk: mediatek: correct cpu clock name for MT8173 SoC Correct cpu clock name from ca57 to ca72 since MT8173 does use cortex-a72. Signed-off-by: Seiya Wang Reviewed-by: Matthias Brugger Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt8173.c | 4 ++-- include/dt-bindings/clock/mt8173-clk.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c index 96c292c3e440..deedeb3ea33b 100644 --- a/drivers/clk/mediatek/clk-mt8173.c +++ b/drivers/clk/mediatek/clk-mt8173.c @@ -533,7 +533,7 @@ static const char * const ca53_parents[] __initconst = { "univpll" }; -static const char * const ca57_parents[] __initconst = { +static const char * const ca72_parents[] __initconst = { "clk26m", "armca15pll", "mainpll", @@ -542,7 +542,7 @@ static const char * const ca57_parents[] __initconst = { static const struct mtk_composite cpu_muxes[] __initconst = { MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2), - MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2), + MUX(CLK_INFRA_CA72SEL, "infra_ca72_sel", ca72_parents, 0x0000, 2, 2), }; static const struct mtk_composite top_muxes[] __initconst = { diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h index 8aea623dd518..76e4e5b65353 100644 --- a/include/dt-bindings/clock/mt8173-clk.h +++ b/include/dt-bindings/clock/mt8173-clk.h @@ -194,7 +194,8 @@ #define CLK_INFRA_PMICWRAP 11 #define CLK_INFRA_CLK_13M 12 #define CLK_INFRA_CA53SEL 13 -#define CLK_INFRA_CA57SEL 14 +#define CLK_INFRA_CA57SEL 14 /* Deprecated. Don't use it. */ +#define CLK_INFRA_CA72SEL 14 #define CLK_INFRA_NR_CLK 15 /* PERI_SYS */ -- cgit v1.2.3 From 0c91c11c7d62de9fea6f5520edb143a7199f3307 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 27 Feb 2019 01:28:26 +0000 Subject: clk: imx8mq: add GPIO clocks to clock tree i.MX8MQ has clock gate for each GPIO bank, add them into clock tree for GPIO driver to manage. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8mq.c | 5 +++++ include/dt-bindings/clock/imx8mq-clock.h | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 081dc2d7c99c..a9b3888aef0c 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -473,6 +473,11 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) 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_GPIO1_ROOT] = imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0); + clks[IMX8MQ_CLK_GPIO2_ROOT] = imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0); + clks[IMX8MQ_CLK_GPIO3_ROOT] = imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0); + clks[IMX8MQ_CLK_GPIO4_ROOT] = imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0); + clks[IMX8MQ_CLK_GPIO5_ROOT] = imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 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); diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h index 491e39c146be..b58cc643c9c9 100644 --- a/include/dt-bindings/clock/imx8mq-clock.h +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -394,5 +394,11 @@ #define IMX8MQ_CLK_CLKO1 268 #define IMX8MQ_CLK_ARM 269 -#define IMX8MQ_CLK_END 270 +#define IMX8MQ_CLK_GPIO1_ROOT 270 +#define IMX8MQ_CLK_GPIO2_ROOT 271 +#define IMX8MQ_CLK_GPIO3_ROOT 272 +#define IMX8MQ_CLK_GPIO4_ROOT 273 +#define IMX8MQ_CLK_GPIO5_ROOT 274 + +#define IMX8MQ_CLK_END 275 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */ -- cgit v1.2.3 From 1df4046a93e086f77d244ea47c21591b4acad3e2 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 11 Dec 2018 08:32:04 -0800 Subject: clk: Combine __clk_get() and __clk_create_clk() The __clk_get() function is practically a private clk implementation detail now. No architecture defines it, and given that new code should be using the common clk framework there isn't a need for it to keep existing just to serve clkdev purposes. Let's fold it into the __clk_create_clk() function and make that a little more generic by renaming it to clk_hw_create_clk(). This will allow the framework to create a struct clk handle to a particular clk_hw pointer and link it up as a consumer wherever that's needed. Doing this also lets us get rid of the __clk_free_clk() API that had to be kept in sync with __clk_put(). Splitting that API up into the "link and unlink from consumer list" phase and "free the clk pointer" phase allows us to reuse that logic in a couple places, simplifying the code. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 140 ++++++++++++++++++++++++++++++++++----------------- drivers/clk/clk.h | 10 ++-- drivers/clk/clkdev.c | 9 +--- 3 files changed, 98 insertions(+), 61 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d2477a5058ac..fef937ea44f4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3209,42 +3209,103 @@ unlock: return ret; } -struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, +/** + * clk_core_link_consumer - Add a clk consumer to the list of consumers in a clk_core + * @core: clk to add consumer to + * @clk: consumer to link to a clk + */ +static void clk_core_link_consumer(struct clk_core *core, struct clk *clk) +{ + clk_prepare_lock(); + hlist_add_head(&clk->clks_node, &core->clks); + clk_prepare_unlock(); +} + +/** + * clk_core_unlink_consumer - Remove a clk consumer from the list of consumers in a clk_core + * @clk: consumer to unlink + */ +static void clk_core_unlink_consumer(struct clk *clk) +{ + lockdep_assert_held(&prepare_lock); + hlist_del(&clk->clks_node); +} + +/** + * alloc_clk - Allocate a clk consumer, but leave it unlinked to the clk_core + * @core: clk to allocate a consumer for + * @dev_id: string describing device name + * @con_id: connection ID string on device + * + * Returns: clk consumer left unlinked from the consumer list + */ +static struct clk *alloc_clk(struct clk_core *core, const char *dev_id, const char *con_id) { struct clk *clk; - /* This is to allow this function to be chained to others */ - if (IS_ERR_OR_NULL(hw)) - return ERR_CAST(hw); - clk = kzalloc(sizeof(*clk), GFP_KERNEL); if (!clk) return ERR_PTR(-ENOMEM); - clk->core = hw->core; + clk->core = core; clk->dev_id = dev_id; clk->con_id = kstrdup_const(con_id, GFP_KERNEL); clk->max_rate = ULONG_MAX; - clk_prepare_lock(); - hlist_add_head(&clk->clks_node, &hw->core->clks); - clk_prepare_unlock(); - return clk; } -/* keep in sync with __clk_put */ -void __clk_free_clk(struct clk *clk) +/** + * free_clk - Free a clk consumer + * @clk: clk consumer to free + * + * Note, this assumes the clk has been unlinked from the clk_core consumer + * list. + */ +static void free_clk(struct clk *clk) { - clk_prepare_lock(); - hlist_del(&clk->clks_node); - clk_prepare_unlock(); - kfree_const(clk->con_id); kfree(clk); } +/** + * clk_hw_create_clk: Allocate and link a clk consumer to a clk_core given + * a clk_hw + * @hw: clk_hw associated with the clk being consumed + * @dev_id: string describing device name + * @con_id: connection ID string on device + * + * This is the main function used to create a clk pointer for use by clk + * consumers. It connects a consumer to the clk_core and clk_hw structures + * used by the framework and clk provider respectively. + */ +struct clk *clk_hw_create_clk(struct clk_hw *hw, + const char *dev_id, const char *con_id) +{ + struct clk *clk; + struct clk_core *core; + + /* This is to allow this function to be chained to others */ + if (IS_ERR_OR_NULL(hw)) + return ERR_CAST(hw); + + core = hw->core; + clk = alloc_clk(core, dev_id, con_id); + if (IS_ERR(clk)) + return clk; + + if (!try_module_get(core->owner)) { + free_clk(clk); + return ERR_PTR(-ENOENT); + } + + kref_get(&core->ref); + clk_core_link_consumer(core, clk); + + return clk; +} + /** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock @@ -3320,17 +3381,27 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) INIT_HLIST_HEAD(&core->clks); - hw->clk = __clk_create_clk(hw, NULL, NULL); + /* + * Don't call clk_hw_create_clk() here because that would pin the + * provider module to itself and prevent it from ever being removed. + */ + hw->clk = alloc_clk(core, NULL, NULL); if (IS_ERR(hw->clk)) { ret = PTR_ERR(hw->clk); goto fail_parents; } + clk_core_link_consumer(hw->core, hw->clk); + ret = __clk_core_init(core); if (!ret) return hw->clk; - __clk_free_clk(hw->clk); + clk_prepare_lock(); + clk_core_unlink_consumer(hw->clk); + clk_prepare_unlock(); + + free_clk(hw->clk); hw->clk = NULL; fail_parents: @@ -3601,20 +3672,7 @@ EXPORT_SYMBOL_GPL(devm_clk_hw_unregister); /* * clkdev helpers */ -int __clk_get(struct clk *clk) -{ - struct clk_core *core = !clk ? NULL : clk->core; - - if (core) { - if (!try_module_get(core->owner)) - return 0; - - kref_get(&core->ref); - } - return 1; -} -/* keep in sync with __clk_free_clk */ void __clk_put(struct clk *clk) { struct module *owner; @@ -3648,8 +3706,7 @@ void __clk_put(struct clk *clk) module_put(owner); - kfree_const(clk->con_id); - kfree(clk); + free_clk(clk); } /*** clk rate change notifiers ***/ @@ -4025,8 +4082,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, const char *dev_id, const char *con_id) { struct of_clk_provider *provider; - struct clk *clk = ERR_PTR(-EPROBE_DEFER); - struct clk_hw *hw; + struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); if (!clkspec) return ERR_PTR(-EINVAL); @@ -4036,21 +4092,13 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, list_for_each_entry(provider, &of_clk_providers, link) { if (provider->node == clkspec->np) { hw = __of_clk_get_hw_from_provider(provider, clkspec); - clk = __clk_create_clk(hw, dev_id, con_id); - } - - if (!IS_ERR(clk)) { - if (!__clk_get(clk)) { - __clk_free_clk(clk); - clk = ERR_PTR(-ENOENT); - } - - break; + if (!IS_ERR(hw)) + break; } } mutex_unlock(&of_clk_mutex); - return clk; + return clk_hw_create_clk(hw, dev_id, con_id); } /** diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index b02f5e604e69..4cdf30b0008c 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -12,24 +12,20 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, #endif #ifdef CONFIG_COMMON_CLK -struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, - const char *con_id); -void __clk_free_clk(struct clk *clk); -int __clk_get(struct clk *clk); +struct clk *clk_hw_create_clk(struct clk_hw *hw, + const char *dev_id, const char *con_id); void __clk_put(struct clk *clk); #else /* All these casts to avoid ifdefs in clkdev... */ static inline struct clk * -__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id) +clk_hw_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id) { return (struct clk *)hw; } -static inline void __clk_free_clk(struct clk *clk) { } static struct clk_hw *__clk_get_hw(struct clk *clk) { return (struct clk_hw *)clk; } -static inline int __clk_get(struct clk *clk) { return 1; } static inline void __clk_put(struct clk *clk) { } #endif diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 9ab3db8b3988..bdeaffc950ae 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -174,16 +174,9 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id) if (!cl) goto out; - clk = __clk_create_clk(cl->clk_hw, dev_id, con_id); + clk = clk_hw_create_clk(cl->clk_hw, dev_id, con_id); if (IS_ERR(clk)) - goto out; - - if (!__clk_get(clk)) { - __clk_free_clk(clk); cl = NULL; - goto out; - } - out: mutex_unlock(&clocks_mutex); -- cgit v1.2.3 From 2447883934a03c80a85d92cd313ea1d10e330158 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 4 Dec 2018 20:24:37 +0100 Subject: clk: core: clarify the check for runtime PM Currently, the core->dev entry is populated only if runtime PM is enabled. Doing so prevents accessing the device structure in any case. Keep the same logic but instead of using the presence of core->dev as the only condition, also check the status of pm_runtime_enabled(). Then, we can set the core->dev pointer at any time as long as a device structure is available. This change will help supporting device links in the clock subsystem. Signed-off-by: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai [sboyd@kernel.org: Change to a boolean flag] Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fef937ea44f4..d46e8b9b9c9f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -57,6 +57,7 @@ struct clk_core { struct clk_core *new_child; unsigned long flags; bool orphan; + bool rpm_enabled; unsigned int enable_count; unsigned int prepare_count; unsigned int protect_count; @@ -92,9 +93,9 @@ struct clk { /*** runtime pm ***/ static int clk_pm_runtime_get(struct clk_core *core) { - int ret = 0; + int ret; - if (!core->dev) + if (!core->rpm_enabled) return 0; ret = pm_runtime_get_sync(core->dev); @@ -103,7 +104,7 @@ static int clk_pm_runtime_get(struct clk_core *core) static void clk_pm_runtime_put(struct clk_core *core) { - if (!core->dev) + if (!core->rpm_enabled) return; pm_runtime_put_sync(core->dev); @@ -223,7 +224,7 @@ static bool clk_core_is_enabled(struct clk_core *core) * taking enable spinlock, but the below check is needed if one tries * to call it from other places. */ - if (core->dev) { + if (core->rpm_enabled) { pm_runtime_get_noresume(core->dev); if (!pm_runtime_active(core->dev)) { ret = false; @@ -233,7 +234,7 @@ static bool clk_core_is_enabled(struct clk_core *core) ret = core->ops->is_enabled(core->hw); done: - if (core->dev) + if (core->rpm_enabled) pm_runtime_put(core->dev); return ret; @@ -3341,7 +3342,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) core->ops = hw->init->ops; if (dev && pm_runtime_enabled(dev)) - core->dev = dev; + core->rpm_enabled = true; + core->dev = dev; if (dev && dev->driver) core->owner = dev->driver->owner; core->hw = hw; -- cgit v1.2.3 From 4472287a3b2f52f4aa53f294ccb74392dde4e07d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 19 Dec 2018 10:59:55 -0800 Subject: clk: Introduce of_clk_get_hw_from_clkspec() We want to get struct clk_hw pointers from a DT clk specifier (i.e. a clocks property) so that we can find parent clks without searching for globally unique clk names. This should save time by avoiding the global string search for clks that are external to the clock controller providing the clk and let us move away from string comparisons in general. Introduce of_clk_get_hw_from_clkspec() which is largely the DT parsing part of finding clks implemented in clkdev.c and have that return a clk_hw pointer instead of converting that into a clk pointer. This lets us push up the clk pointer creation to the caller in clk_get() and avoids the need to push the dev_id and con_id throughout the DT parsing code. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 46 +++++++++++++++++++++++++---- drivers/clk/clk.h | 5 ++-- drivers/clk/clkdev.c | 83 ++++++++++++++++------------------------------------ 3 files changed, 69 insertions(+), 65 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d46e8b9b9c9f..04288063847b 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4065,6 +4065,42 @@ void devm_of_clk_del_provider(struct device *dev) } EXPORT_SYMBOL(devm_of_clk_del_provider); +int of_parse_clkspec(const struct device_node *np, int index, const char *name, + struct of_phandle_args *out_args) +{ + int ret = -ENOENT; + + /* Walk up the tree of devices looking for a clock property that matches */ + while (np) { + /* + * For named clocks, first look up the name in the + * "clock-names" property. If it cannot be found, then index + * will be an error code and of_parse_phandle_with_args() will + * return -EINVAL. + */ + if (name) + index = of_property_match_string(np, "clock-names", name); + ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", + index, out_args); + if (!ret) + break; + if (name && index >= 0) + break; + + /* + * No matching clock found on this node. If the parent node + * has a "clock-ranges" property, then we can try one of its + * clocks. + */ + np = np->parent; + if (np && !of_get_property(np, "clock-ranges", NULL)) + break; + index = 0; + } + + return ret; +} + static struct clk_hw * __of_clk_get_hw_from_provider(struct of_clk_provider *provider, struct of_phandle_args *clkspec) @@ -4080,8 +4116,7 @@ __of_clk_get_hw_from_provider(struct of_clk_provider *provider, return __clk_get_hw(clk); } -struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, - const char *dev_id, const char *con_id) +struct clk_hw *of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec) { struct of_clk_provider *provider; struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); @@ -4089,7 +4124,6 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, if (!clkspec) return ERR_PTR(-EINVAL); - /* Check if we have such a provider in our array */ mutex_lock(&of_clk_mutex); list_for_each_entry(provider, &of_clk_providers, link) { if (provider->node == clkspec->np) { @@ -4100,7 +4134,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, } mutex_unlock(&of_clk_mutex); - return clk_hw_create_clk(hw, dev_id, con_id); + return hw; } /** @@ -4113,7 +4147,9 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, */ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) { - return __of_clk_get_from_provider(clkspec, NULL, __func__); + struct clk_hw *hw = of_clk_get_hw_from_clkspec(clkspec); + + return clk_hw_create_clk(hw, NULL, __func__); } EXPORT_SYMBOL_GPL(of_clk_get_from_provider); diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 4cdf30b0008c..5a0ca0e3c1f1 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -7,8 +7,9 @@ struct clk_hw; #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) -struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, - const char *dev_id, const char *con_id); +int of_parse_clkspec(const struct device_node *np, int index, const char *name, + struct of_phandle_args *out_args); +struct clk_hw *of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec); #endif #ifdef CONFIG_COMMON_CLK diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index bdeaffc950ae..5ebb2119c0b9 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -28,69 +28,37 @@ static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) -static struct clk *__of_clk_get(struct device_node *np, int index, - const char *dev_id, const char *con_id) +static struct clk_hw *of_clk_get_hw(struct device_node *np, + int index, const char *con_id) { + int ret; + struct clk_hw *hw; struct of_phandle_args clkspec; - struct clk *clk; - int rc; - rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index, - &clkspec); - if (rc) - return ERR_PTR(rc); + ret = of_parse_clkspec(np, index, con_id, &clkspec); + if (ret) + return ERR_PTR(ret); - clk = __of_clk_get_from_provider(&clkspec, dev_id, con_id); + hw = of_clk_get_hw_from_clkspec(&clkspec); of_node_put(clkspec.np); - return clk; + return hw; } -struct clk *of_clk_get(struct device_node *np, int index) +static struct clk *__of_clk_get(struct device_node *np, + int index, const char *dev_id, + const char *con_id) { - return __of_clk_get(np, index, np->full_name, NULL); + struct clk_hw *hw = of_clk_get_hw(np, index, con_id); + + return clk_hw_create_clk(hw, dev_id, con_id); } -EXPORT_SYMBOL(of_clk_get); -static struct clk *__of_clk_get_by_name(struct device_node *np, - const char *dev_id, - const char *name) +struct clk *of_clk_get(struct device_node *np, int index) { - struct clk *clk = ERR_PTR(-ENOENT); - - /* Walk up the tree of devices looking for a clock that matches */ - while (np) { - int index = 0; - - /* - * For named clocks, first look up the name in the - * "clock-names" property. If it cannot be found, then - * index will be an error code, and of_clk_get() will fail. - */ - if (name) - index = of_property_match_string(np, "clock-names", name); - clk = __of_clk_get(np, index, dev_id, name); - if (!IS_ERR(clk)) { - break; - } else if (name && index >= 0) { - if (PTR_ERR(clk) != -EPROBE_DEFER) - pr_err("ERROR: could not get clock %pOF:%s(%i)\n", - np, name ? name : "", index); - return clk; - } - - /* - * No matching clock found on this node. If the parent node - * has a "clock-ranges" property, then we can try one of its - * clocks. - */ - np = np->parent; - if (np && !of_get_property(np, "clock-ranges", NULL)) - break; - } - - return clk; + return __of_clk_get(np, index, np->full_name, NULL); } +EXPORT_SYMBOL(of_clk_get); /** * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node @@ -106,15 +74,14 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name) if (!np) return ERR_PTR(-ENOENT); - return __of_clk_get_by_name(np, np->full_name, name); + return __of_clk_get(np, -1, np->full_name, name); } EXPORT_SYMBOL(of_clk_get_by_name); #else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */ -static struct clk *__of_clk_get_by_name(struct device_node *np, - const char *dev_id, - const char *name) +static struct clk_hw *of_clk_get_hw(struct device_node *np, + int index, const char *con_id) { return ERR_PTR(-ENOENT); } @@ -187,12 +154,12 @@ EXPORT_SYMBOL(clk_get_sys); struct clk *clk_get(struct device *dev, const char *con_id) { const char *dev_id = dev ? dev_name(dev) : NULL; - struct clk *clk; + struct clk_hw *hw; if (dev && dev->of_node) { - clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id); - if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER) - return clk; + hw = of_clk_get_hw(dev->of_node, 0, con_id); + if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER) + return clk_hw_create_clk(hw, dev_id, con_id); } return clk_get_sys(dev_id, con_id); -- cgit v1.2.3 From efa850487a6b6742699e3352d8562f5aba531ae7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 11 Dec 2018 08:34:16 -0800 Subject: clk: Inform the core about consumer devices We'd like to have a pointer to the device that's consuming a particular clk in the clk framework so we can link the consumer to the clk provider with a PM device link. Add a device argument to clk_hw_create_clk() for this so it can be used in subsequent patches to add and remove the link. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 7 +++++-- drivers/clk/clk.h | 7 +++++-- drivers/clk/clkdev.c | 16 +++++++++++----- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 04288063847b..8244ef2ba977 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -82,6 +82,7 @@ struct clk_core { struct clk { struct clk_core *core; + struct device *dev; const char *dev_id; const char *con_id; unsigned long min_rate; @@ -3273,6 +3274,7 @@ static void free_clk(struct clk *clk) /** * clk_hw_create_clk: Allocate and link a clk consumer to a clk_core given * a clk_hw + * @dev: clk consumer device * @hw: clk_hw associated with the clk being consumed * @dev_id: string describing device name * @con_id: connection ID string on device @@ -3281,7 +3283,7 @@ static void free_clk(struct clk *clk) * consumers. It connects a consumer to the clk_core and clk_hw structures * used by the framework and clk provider respectively. */ -struct clk *clk_hw_create_clk(struct clk_hw *hw, +struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id, const char *con_id) { struct clk *clk; @@ -3295,6 +3297,7 @@ struct clk *clk_hw_create_clk(struct clk_hw *hw, clk = alloc_clk(core, dev_id, con_id); if (IS_ERR(clk)) return clk; + clk->dev = dev; if (!try_module_get(core->owner)) { free_clk(clk); @@ -4149,7 +4152,7 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) { struct clk_hw *hw = of_clk_get_hw_from_clkspec(clkspec); - return clk_hw_create_clk(hw, NULL, __func__); + return clk_hw_create_clk(NULL, hw, NULL, __func__); } EXPORT_SYMBOL_GPL(of_clk_get_from_provider); diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 5a0ca0e3c1f1..5ea2185e57a1 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -5,6 +5,8 @@ */ struct clk_hw; +struct device; +struct of_phandle_args; #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) int of_parse_clkspec(const struct device_node *np, int index, const char *name, @@ -13,13 +15,14 @@ struct clk_hw *of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec); #endif #ifdef CONFIG_COMMON_CLK -struct clk *clk_hw_create_clk(struct clk_hw *hw, +struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id, const char *con_id); void __clk_put(struct clk *clk); #else /* All these casts to avoid ifdefs in clkdev... */ static inline struct clk * -clk_hw_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id) +clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id, + const char *con_id) { return (struct clk *)hw; } diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 5ebb2119c0b9..f2f4f2afd28c 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -51,7 +51,7 @@ static struct clk *__of_clk_get(struct device_node *np, { struct clk_hw *hw = of_clk_get_hw(np, index, con_id); - return clk_hw_create_clk(hw, dev_id, con_id); + return clk_hw_create_clk(NULL, hw, dev_id, con_id); } struct clk *of_clk_get(struct device_node *np, int index) @@ -130,7 +130,8 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) return cl; } -struct clk *clk_get_sys(const char *dev_id, const char *con_id) +static struct clk *__clk_get_sys(struct device *dev, const char *dev_id, + const char *con_id) { struct clk_lookup *cl; struct clk *clk = NULL; @@ -141,7 +142,7 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id) if (!cl) goto out; - clk = clk_hw_create_clk(cl->clk_hw, dev_id, con_id); + clk = clk_hw_create_clk(dev, cl->clk_hw, dev_id, con_id); if (IS_ERR(clk)) cl = NULL; out: @@ -149,6 +150,11 @@ out: return cl ? clk : ERR_PTR(-ENOENT); } + +struct clk *clk_get_sys(const char *dev_id, const char *con_id) +{ + return __clk_get_sys(NULL, dev_id, con_id); +} EXPORT_SYMBOL(clk_get_sys); struct clk *clk_get(struct device *dev, const char *con_id) @@ -159,10 +165,10 @@ struct clk *clk_get(struct device *dev, const char *con_id) if (dev && dev->of_node) { hw = of_clk_get_hw(dev->of_node, 0, con_id); if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER) - return clk_hw_create_clk(hw, dev_id, con_id); + return clk_hw_create_clk(dev, hw, dev_id, con_id); } - return clk_get_sys(dev_id, con_id); + return __clk_get_sys(dev, dev_id, con_id); } EXPORT_SYMBOL(clk_get); -- cgit v1.2.3 From cf13f2896807d516df79d118d1e82f9d2db3c336 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 19 Dec 2018 15:09:14 -0800 Subject: clk: Move of_clk_*() APIs into clk.c from clkdev.c The API between clk.c and clkdev.c is purely getting the clk_hw structure (or the struct clk if it's not CCF) and then turning that struct clk_hw pointer into a struct clk pointer via clk_hw_create_clk(). There's no need to complicate clkdev.c with these DT parsing details that are only relevant to the common clk framework. Move the DT parsing logic into the core framework and just expose the APIs to get a clk_hw pointer and convert it. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++--- drivers/clk/clk.h | 11 +++++++--- drivers/clk/clkdev.c | 60 ---------------------------------------------------- 3 files changed, 62 insertions(+), 66 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 8244ef2ba977..937b8d092d17 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4068,8 +4068,8 @@ void devm_of_clk_del_provider(struct device *dev) } EXPORT_SYMBOL(devm_of_clk_del_provider); -int of_parse_clkspec(const struct device_node *np, int index, const char *name, - struct of_phandle_args *out_args) +static int of_parse_clkspec(const struct device_node *np, int index, + const char *name, struct of_phandle_args *out_args) { int ret = -ENOENT; @@ -4119,7 +4119,8 @@ __of_clk_get_hw_from_provider(struct of_clk_provider *provider, return __clk_get_hw(clk); } -struct clk_hw *of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec) +static struct clk_hw * +of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec) { struct of_clk_provider *provider; struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); @@ -4156,6 +4157,56 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) } EXPORT_SYMBOL_GPL(of_clk_get_from_provider); +struct clk_hw *of_clk_get_hw(struct device_node *np, int index, + const char *con_id) +{ + int ret; + struct clk_hw *hw; + struct of_phandle_args clkspec; + + ret = of_parse_clkspec(np, index, con_id, &clkspec); + if (ret) + return ERR_PTR(ret); + + hw = of_clk_get_hw_from_clkspec(&clkspec); + of_node_put(clkspec.np); + + return hw; +} + +static struct clk *__of_clk_get(struct device_node *np, + int index, const char *dev_id, + const char *con_id) +{ + struct clk_hw *hw = of_clk_get_hw(np, index, con_id); + + return clk_hw_create_clk(NULL, hw, dev_id, con_id); +} + +struct clk *of_clk_get(struct device_node *np, int index) +{ + return __of_clk_get(np, index, np->full_name, NULL); +} +EXPORT_SYMBOL(of_clk_get); + +/** + * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node + * @np: pointer to clock consumer node + * @name: name of consumer's clock input, or NULL for the first clock reference + * + * This function parses the clocks and clock-names properties, + * and uses them to look up the struct clk from the registered list of clock + * providers. + */ +struct clk *of_clk_get_by_name(struct device_node *np, const char *name) +{ + if (!np) + return ERR_PTR(-ENOENT); + + return __of_clk_get(np, -1, np->full_name, name); +} +EXPORT_SYMBOL(of_clk_get_by_name); + /** * of_clk_get_parent_count() - Count the number of clocks a device node has * @np: device node to count diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 5ea2185e57a1..553f531cc232 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -9,9 +9,14 @@ struct device; struct of_phandle_args; #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) -int of_parse_clkspec(const struct device_node *np, int index, const char *name, - struct of_phandle_args *out_args); -struct clk_hw *of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec); +struct clk_hw *of_clk_get_hw(struct device_node *np, + int index, const char *con_id); +#else /* !CONFIG_COMMON_CLK || !CONFIG_OF */ +static inline struct clk_hw *of_clk_get_hw(struct device_node *np, + int index, const char *con_id) +{ + return ERR_PTR(-ENOENT); +} #endif #ifdef CONFIG_COMMON_CLK diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index f2f4f2afd28c..d3758bf4305c 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -27,66 +27,6 @@ static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); -#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) -static struct clk_hw *of_clk_get_hw(struct device_node *np, - int index, const char *con_id) -{ - int ret; - struct clk_hw *hw; - struct of_phandle_args clkspec; - - ret = of_parse_clkspec(np, index, con_id, &clkspec); - if (ret) - return ERR_PTR(ret); - - hw = of_clk_get_hw_from_clkspec(&clkspec); - of_node_put(clkspec.np); - - return hw; -} - -static struct clk *__of_clk_get(struct device_node *np, - int index, const char *dev_id, - const char *con_id) -{ - struct clk_hw *hw = of_clk_get_hw(np, index, con_id); - - return clk_hw_create_clk(NULL, hw, dev_id, con_id); -} - -struct clk *of_clk_get(struct device_node *np, int index) -{ - return __of_clk_get(np, index, np->full_name, NULL); -} -EXPORT_SYMBOL(of_clk_get); - -/** - * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node - * @np: pointer to clock consumer node - * @name: name of consumer's clock input, or NULL for the first clock reference - * - * This function parses the clocks and clock-names properties, - * and uses them to look up the struct clk from the registered list of clock - * providers. - */ -struct clk *of_clk_get_by_name(struct device_node *np, const char *name) -{ - if (!np) - return ERR_PTR(-ENOENT); - - return __of_clk_get(np, -1, np->full_name, name); -} -EXPORT_SYMBOL(of_clk_get_by_name); - -#else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */ - -static struct clk_hw *of_clk_get_hw(struct device_node *np, - int index, const char *con_id) -{ - return ERR_PTR(-ENOENT); -} -#endif - /* * Find the correct struct clk for the device and connection ID. * We do slightly fuzzy matching here: -- cgit v1.2.3 From 65cf20ad4f54d7feb87cda0369d6560e9789f0d5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 6 Mar 2019 16:18:28 +0900 Subject: clk: fixup default index for of_clk_get_by_name() of_clk_get_by_name() is using -1 for __of_clk_get() index. It will go to of_parse_clkspec(), and be used for of_parse_phandle_with_args(). Here, if user doesn't specify clock name (= of_clk_get_by_name(np, NULL)), this index is still -1, and of_parse_phandle_with_args() will return -EINVAL (This index will be updated if if it had clock name). clk_get_by_name(np, NULL) should work, then, default index should be 0 instead of -1. This patch fixes it. Fixes: 4472287a3b2f ("clk: Introduce of_clk_get_hw_from_clkspec()") Signed-off-by: Kuninori Morimoto Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 14cbf239d9b2..96053a96fe2f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4213,7 +4213,7 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name) if (!np) return ERR_PTR(-ENOENT); - return __of_clk_get(np, -1, np->full_name, name); + return __of_clk_get(np, 0, np->full_name, name); } EXPORT_SYMBOL(of_clk_get_by_name); -- cgit v1.2.3 From d17a718db40df2548e99a62dc3d7e5e2b38143cc Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 7 Mar 2019 12:10:56 -0800 Subject: clk: ti: clkctrl: Fix clkdm_name regression for TI_CLK_CLKCTRL_COMPAT Commit a72d785021cb ("clk: ti: Prepare for remove of OF node name") changed the code to use kasprintf() for provider->clkdm_name but also changed the offset used later on by three. We don't need to change the offset as we already have the extra three characters in the format for kasprintf with "%pOFnxxx". This caused the clocks with TI_CLK_CLKCTRL_COMPAT to have NULL clk->clkdm_name for omap4 and 5. And null clkdm_name can cause module reset, enable, and idle to fail. The issue can also be seen also when enabling DEBUG for clkctrl.c and then we start seeing "clock: could not associate" messages for omap4 and 5 as the generated name is something like "l4_wkclkdm" instead of "l4_wkup_clkdm" that's needed. Let's fix the issue with a partial revert of commit a72d785021cb ("clk: ti: Prepare for remove of OF node name"). ALso note that in general code should not depend on the dts node names. And the node names should be generic types like clock-domain in this case. This could be fixed later by using separate compatible properties for the clockdomains, or by adding soc_device_match() table with reg offsets to the driver. But let's fix the regression first. Fixes: a72d785021cb ("clk: ti: Prepare for remove of OF node name") Cc: Tero Kristo Signed-off-by: Tony Lindgren Signed-off-by: Stephen Boyd --- drivers/clk/ti/clkctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c index bf32d996177f..639f515e08f0 100644 --- a/drivers/clk/ti/clkctrl.c +++ b/drivers/clk/ti/clkctrl.c @@ -530,7 +530,7 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node) * Create default clkdm name, replace _cm from end of parent * node name with _clkdm */ - provider->clkdm_name[strlen(provider->clkdm_name) - 5] = 0; + provider->clkdm_name[strlen(provider->clkdm_name) - 2] = 0; } else { provider->clkdm_name = kasprintf(GFP_KERNEL, "%pOFn", node); if (!provider->clkdm_name) { -- cgit v1.2.3 From 010d5166bbe95523e8584f3caca9f1bbeac9ea6e Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Tue, 5 Mar 2019 09:49:16 +0000 Subject: dt-bindings: clock: imx8mq: Fix numbering overlaps and gaps IMX8MQ_CLK_USB_PHY_REF changes from 163 to 153, this way removing the gap. All the following clock ids are now decreased by 10 to keep the numbering right. Doing this, the IMX8MQ_CLK_CSI2_CORE is not overlapped with IMX8MQ_CLK_GPT1 anymore. IMX8MQ_CLK_GPT1_ROOT changes from 193 to 183 and all the following ids are updated accordingly. Reported-by: Patrick Wildt Fixes: 1cf3817b ("dt-bindings: Add binding for i.MX8MQ CCM") Signed-off-by: Abel Vesa Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/imx8mq-clock.h | 220 +++++++++++++++---------------- 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h index b58cc643c9c9..6677e920dc2d 100644 --- a/include/dt-bindings/clock/imx8mq-clock.h +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -245,160 +245,160 @@ /* USB_CORE_REF */ #define IMX8MQ_CLK_USB_CORE_REF 152 /* USB_PHY_REF */ -#define IMX8MQ_CLK_USB_PHY_REF 163 +#define IMX8MQ_CLK_USB_PHY_REF 153 /* ECSPI1 */ -#define IMX8MQ_CLK_ECSPI1 164 +#define IMX8MQ_CLK_ECSPI1 154 /* ECSPI2 */ -#define IMX8MQ_CLK_ECSPI2 165 +#define IMX8MQ_CLK_ECSPI2 155 /* PWM1 */ -#define IMX8MQ_CLK_PWM1 166 +#define IMX8MQ_CLK_PWM1 156 /* PWM2 */ -#define IMX8MQ_CLK_PWM2 167 +#define IMX8MQ_CLK_PWM2 157 /* PWM3 */ -#define IMX8MQ_CLK_PWM3 168 +#define IMX8MQ_CLK_PWM3 158 /* PWM4 */ -#define IMX8MQ_CLK_PWM4 169 +#define IMX8MQ_CLK_PWM4 159 /* GPT1 */ -#define IMX8MQ_CLK_GPT1 170 +#define IMX8MQ_CLK_GPT1 160 /* WDOG */ -#define IMX8MQ_CLK_WDOG 171 +#define IMX8MQ_CLK_WDOG 161 /* WRCLK */ -#define IMX8MQ_CLK_WRCLK 172 +#define IMX8MQ_CLK_WRCLK 162 /* DSI_CORE */ -#define IMX8MQ_CLK_DSI_CORE 173 +#define IMX8MQ_CLK_DSI_CORE 163 /* DSI_PHY */ -#define IMX8MQ_CLK_DSI_PHY_REF 174 +#define IMX8MQ_CLK_DSI_PHY_REF 164 /* DSI_DBI */ -#define IMX8MQ_CLK_DSI_DBI 175 +#define IMX8MQ_CLK_DSI_DBI 165 /*DSI_ESC */ -#define IMX8MQ_CLK_DSI_ESC 176 +#define IMX8MQ_CLK_DSI_ESC 166 /* CSI1_CORE */ -#define IMX8MQ_CLK_CSI1_CORE 177 +#define IMX8MQ_CLK_CSI1_CORE 167 /* CSI1_PHY */ -#define IMX8MQ_CLK_CSI1_PHY_REF 178 +#define IMX8MQ_CLK_CSI1_PHY_REF 168 /* CSI_ESC */ -#define IMX8MQ_CLK_CSI1_ESC 179 +#define IMX8MQ_CLK_CSI1_ESC 169 /* CSI2_CORE */ #define IMX8MQ_CLK_CSI2_CORE 170 /* CSI2_PHY */ -#define IMX8MQ_CLK_CSI2_PHY_REF 181 +#define IMX8MQ_CLK_CSI2_PHY_REF 171 /* CSI2_ESC */ -#define IMX8MQ_CLK_CSI2_ESC 182 +#define IMX8MQ_CLK_CSI2_ESC 172 /* PCIE2_CTRL */ -#define IMX8MQ_CLK_PCIE2_CTRL 183 +#define IMX8MQ_CLK_PCIE2_CTRL 173 /* PCIE2_PHY */ -#define IMX8MQ_CLK_PCIE2_PHY 184 +#define IMX8MQ_CLK_PCIE2_PHY 174 /* PCIE2_AUX */ -#define IMX8MQ_CLK_PCIE2_AUX 185 +#define IMX8MQ_CLK_PCIE2_AUX 175 /* ECSPI3 */ -#define IMX8MQ_CLK_ECSPI3 186 +#define IMX8MQ_CLK_ECSPI3 176 /* CCGR clocks */ -#define IMX8MQ_CLK_A53_ROOT 187 -#define IMX8MQ_CLK_DRAM_ROOT 188 -#define IMX8MQ_CLK_ECSPI1_ROOT 189 +#define IMX8MQ_CLK_A53_ROOT 177 +#define IMX8MQ_CLK_DRAM_ROOT 178 +#define IMX8MQ_CLK_ECSPI1_ROOT 179 #define IMX8MQ_CLK_ECSPI2_ROOT 180 #define IMX8MQ_CLK_ECSPI3_ROOT 181 #define IMX8MQ_CLK_ENET1_ROOT 182 -#define IMX8MQ_CLK_GPT1_ROOT 193 -#define IMX8MQ_CLK_I2C1_ROOT 194 -#define IMX8MQ_CLK_I2C2_ROOT 195 -#define IMX8MQ_CLK_I2C3_ROOT 196 -#define IMX8MQ_CLK_I2C4_ROOT 197 -#define IMX8MQ_CLK_M4_ROOT 198 -#define IMX8MQ_CLK_PCIE1_ROOT 199 -#define IMX8MQ_CLK_PCIE2_ROOT 200 -#define IMX8MQ_CLK_PWM1_ROOT 201 -#define IMX8MQ_CLK_PWM2_ROOT 202 -#define IMX8MQ_CLK_PWM3_ROOT 203 -#define IMX8MQ_CLK_PWM4_ROOT 204 -#define IMX8MQ_CLK_QSPI_ROOT 205 -#define IMX8MQ_CLK_SAI1_ROOT 206 -#define IMX8MQ_CLK_SAI2_ROOT 207 -#define IMX8MQ_CLK_SAI3_ROOT 208 -#define IMX8MQ_CLK_SAI4_ROOT 209 -#define IMX8MQ_CLK_SAI5_ROOT 210 -#define IMX8MQ_CLK_SAI6_ROOT 212 -#define IMX8MQ_CLK_UART1_ROOT 213 -#define IMX8MQ_CLK_UART2_ROOT 214 -#define IMX8MQ_CLK_UART3_ROOT 215 -#define IMX8MQ_CLK_UART4_ROOT 216 -#define IMX8MQ_CLK_USB1_CTRL_ROOT 217 -#define IMX8MQ_CLK_USB2_CTRL_ROOT 218 -#define IMX8MQ_CLK_USB1_PHY_ROOT 219 -#define IMX8MQ_CLK_USB2_PHY_ROOT 220 -#define IMX8MQ_CLK_USDHC1_ROOT 221 -#define IMX8MQ_CLK_USDHC2_ROOT 222 -#define IMX8MQ_CLK_WDOG1_ROOT 223 -#define IMX8MQ_CLK_WDOG2_ROOT 224 -#define IMX8MQ_CLK_WDOG3_ROOT 225 -#define IMX8MQ_CLK_GPU_ROOT 226 -#define IMX8MQ_CLK_HEVC_ROOT 227 -#define IMX8MQ_CLK_AVC_ROOT 228 -#define IMX8MQ_CLK_VP9_ROOT 229 -#define IMX8MQ_CLK_HEVC_INTER_ROOT 230 -#define IMX8MQ_CLK_DISP_ROOT 231 -#define IMX8MQ_CLK_HDMI_ROOT 232 -#define IMX8MQ_CLK_HDMI_PHY_ROOT 233 -#define IMX8MQ_CLK_VPU_DEC_ROOT 234 -#define IMX8MQ_CLK_CSI1_ROOT 235 -#define IMX8MQ_CLK_CSI2_ROOT 236 -#define IMX8MQ_CLK_RAWNAND_ROOT 237 -#define IMX8MQ_CLK_SDMA1_ROOT 238 -#define IMX8MQ_CLK_SDMA2_ROOT 239 -#define IMX8MQ_CLK_VPU_G1_ROOT 240 -#define IMX8MQ_CLK_VPU_G2_ROOT 241 +#define IMX8MQ_CLK_GPT1_ROOT 183 +#define IMX8MQ_CLK_I2C1_ROOT 184 +#define IMX8MQ_CLK_I2C2_ROOT 185 +#define IMX8MQ_CLK_I2C3_ROOT 186 +#define IMX8MQ_CLK_I2C4_ROOT 187 +#define IMX8MQ_CLK_M4_ROOT 188 +#define IMX8MQ_CLK_PCIE1_ROOT 189 +#define IMX8MQ_CLK_PCIE2_ROOT 190 +#define IMX8MQ_CLK_PWM1_ROOT 191 +#define IMX8MQ_CLK_PWM2_ROOT 192 +#define IMX8MQ_CLK_PWM3_ROOT 193 +#define IMX8MQ_CLK_PWM4_ROOT 194 +#define IMX8MQ_CLK_QSPI_ROOT 195 +#define IMX8MQ_CLK_SAI1_ROOT 196 +#define IMX8MQ_CLK_SAI2_ROOT 197 +#define IMX8MQ_CLK_SAI3_ROOT 198 +#define IMX8MQ_CLK_SAI4_ROOT 199 +#define IMX8MQ_CLK_SAI5_ROOT 200 +#define IMX8MQ_CLK_SAI6_ROOT 201 +#define IMX8MQ_CLK_UART1_ROOT 202 +#define IMX8MQ_CLK_UART2_ROOT 203 +#define IMX8MQ_CLK_UART3_ROOT 204 +#define IMX8MQ_CLK_UART4_ROOT 205 +#define IMX8MQ_CLK_USB1_CTRL_ROOT 206 +#define IMX8MQ_CLK_USB2_CTRL_ROOT 207 +#define IMX8MQ_CLK_USB1_PHY_ROOT 208 +#define IMX8MQ_CLK_USB2_PHY_ROOT 209 +#define IMX8MQ_CLK_USDHC1_ROOT 210 +#define IMX8MQ_CLK_USDHC2_ROOT 211 +#define IMX8MQ_CLK_WDOG1_ROOT 212 +#define IMX8MQ_CLK_WDOG2_ROOT 213 +#define IMX8MQ_CLK_WDOG3_ROOT 214 +#define IMX8MQ_CLK_GPU_ROOT 215 +#define IMX8MQ_CLK_HEVC_ROOT 216 +#define IMX8MQ_CLK_AVC_ROOT 217 +#define IMX8MQ_CLK_VP9_ROOT 218 +#define IMX8MQ_CLK_HEVC_INTER_ROOT 219 +#define IMX8MQ_CLK_DISP_ROOT 220 +#define IMX8MQ_CLK_HDMI_ROOT 221 +#define IMX8MQ_CLK_HDMI_PHY_ROOT 222 +#define IMX8MQ_CLK_VPU_DEC_ROOT 223 +#define IMX8MQ_CLK_CSI1_ROOT 224 +#define IMX8MQ_CLK_CSI2_ROOT 225 +#define IMX8MQ_CLK_RAWNAND_ROOT 226 +#define IMX8MQ_CLK_SDMA1_ROOT 227 +#define IMX8MQ_CLK_SDMA2_ROOT 228 +#define IMX8MQ_CLK_VPU_G1_ROOT 229 +#define IMX8MQ_CLK_VPU_G2_ROOT 230 /* SCCG PLL GATE */ -#define IMX8MQ_SYS1_PLL_OUT 242 -#define IMX8MQ_SYS2_PLL_OUT 243 -#define IMX8MQ_SYS3_PLL_OUT 244 -#define IMX8MQ_DRAM_PLL_OUT 245 - -#define IMX8MQ_GPT_3M_CLK 246 - -#define IMX8MQ_CLK_IPG_ROOT 247 -#define IMX8MQ_CLK_IPG_AUDIO_ROOT 248 -#define IMX8MQ_CLK_SAI1_IPG 249 -#define IMX8MQ_CLK_SAI2_IPG 250 -#define IMX8MQ_CLK_SAI3_IPG 251 -#define IMX8MQ_CLK_SAI4_IPG 252 -#define IMX8MQ_CLK_SAI5_IPG 253 -#define IMX8MQ_CLK_SAI6_IPG 254 +#define IMX8MQ_SYS1_PLL_OUT 231 +#define IMX8MQ_SYS2_PLL_OUT 232 +#define IMX8MQ_SYS3_PLL_OUT 233 +#define IMX8MQ_DRAM_PLL_OUT 234 + +#define IMX8MQ_GPT_3M_CLK 235 + +#define IMX8MQ_CLK_IPG_ROOT 236 +#define IMX8MQ_CLK_IPG_AUDIO_ROOT 237 +#define IMX8MQ_CLK_SAI1_IPG 238 +#define IMX8MQ_CLK_SAI2_IPG 239 +#define IMX8MQ_CLK_SAI3_IPG 240 +#define IMX8MQ_CLK_SAI4_IPG 241 +#define IMX8MQ_CLK_SAI5_IPG 242 +#define IMX8MQ_CLK_SAI6_IPG 243 /* DSI AHB/IPG clocks */ /* rxesc clock */ -#define IMX8MQ_CLK_DSI_AHB 255 +#define IMX8MQ_CLK_DSI_AHB 244 /* txesc clock */ -#define IMX8MQ_CLK_DSI_IPG_DIV 256 +#define IMX8MQ_CLK_DSI_IPG_DIV 245 -#define IMX8MQ_CLK_TMU_ROOT 257 +#define IMX8MQ_CLK_TMU_ROOT 246 /* Display root clocks */ -#define IMX8MQ_CLK_DISP_AXI_ROOT 258 -#define IMX8MQ_CLK_DISP_APB_ROOT 259 -#define IMX8MQ_CLK_DISP_RTRM_ROOT 260 +#define IMX8MQ_CLK_DISP_AXI_ROOT 247 +#define IMX8MQ_CLK_DISP_APB_ROOT 248 +#define IMX8MQ_CLK_DISP_RTRM_ROOT 249 -#define IMX8MQ_CLK_OCOTP_ROOT 261 +#define IMX8MQ_CLK_OCOTP_ROOT 250 -#define IMX8MQ_CLK_DRAM_ALT_ROOT 262 -#define IMX8MQ_CLK_DRAM_CORE 263 +#define IMX8MQ_CLK_DRAM_ALT_ROOT 251 +#define IMX8MQ_CLK_DRAM_CORE 252 -#define IMX8MQ_CLK_MU_ROOT 264 -#define IMX8MQ_VIDEO2_PLL_OUT 265 +#define IMX8MQ_CLK_MU_ROOT 253 +#define IMX8MQ_VIDEO2_PLL_OUT 254 -#define IMX8MQ_CLK_CLKO2 266 +#define IMX8MQ_CLK_CLKO2 255 -#define IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK 267 +#define IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK 256 -#define IMX8MQ_CLK_CLKO1 268 -#define IMX8MQ_CLK_ARM 269 +#define IMX8MQ_CLK_CLKO1 257 +#define IMX8MQ_CLK_ARM 258 -#define IMX8MQ_CLK_GPIO1_ROOT 270 -#define IMX8MQ_CLK_GPIO2_ROOT 271 -#define IMX8MQ_CLK_GPIO3_ROOT 272 -#define IMX8MQ_CLK_GPIO4_ROOT 273 -#define IMX8MQ_CLK_GPIO5_ROOT 274 +#define IMX8MQ_CLK_GPIO1_ROOT 259 +#define IMX8MQ_CLK_GPIO2_ROOT 260 +#define IMX8MQ_CLK_GPIO3_ROOT 261 +#define IMX8MQ_CLK_GPIO4_ROOT 262 +#define IMX8MQ_CLK_GPIO5_ROOT 263 -#define IMX8MQ_CLK_END 275 +#define IMX8MQ_CLK_END 264 #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */ -- cgit v1.2.3