From 3188aa6af1d09492d60b1f80ce44cdbb616a591b Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 2 Sep 2021 18:03:36 -0500 Subject: [PATCH 01/39] clk: sunxi-ng: mux: Remove unused 'reg' field The driver uses 'reg' from 'struct ccu_common' everywhere, so this duplicate field is unused and unnecessary. Remove it. Signed-off-by: Samuel Holland Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210902230336.29745-1-samuel@sholland.org --- drivers/clk/sunxi-ng/ccu_mux.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index f165395effb5..e31efc509b3d 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -40,7 +40,6 @@ struct ccu_mux_internal { _SUNXI_CCU_MUX_TABLE(_shift, _width, NULL) struct ccu_mux { - u16 reg; u32 enable; struct ccu_mux_internal mux; From 4abfc297b6276310fcb28b14e2255265925cd581 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 2 Sep 2021 18:02:00 -0500 Subject: [PATCH 02/39] clk: sunxi-ng: Add machine dependency to A83T CCU The CCUs for all other 32-bit SoCs have a dependency on a specific MACH_SUNxI symbol. This effectively hides these drivers when building an ARCH=arm64 kernel. However, the A83T CCU still shows up because it is missing this dependency. Let's add it for consistency. Signed-off-by: Samuel Holland Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210902230200.29574-1-samuel@sholland.org --- drivers/clk/sunxi-ng/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index cd46d8853876..e76e1676f0f0 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -71,6 +71,7 @@ config SUN8I_A33_CCU config SUN8I_A83T_CCU bool "Support for the Allwinner A83T CCU" default MACH_SUN8I + depends on MACH_SUN8I || COMPILE_TEST config SUN8I_H3_CCU bool "Support for the Allwinner H3 CCU" From 9bec2b9c6134052994115d2d3374e96f2ccb9b9d Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 1 Sep 2021 00:05:19 -0500 Subject: [PATCH 03/39] clk: sunxi-ng: Unregister clocks/resets when unbinding Currently, unbinding a CCU driver unmaps the device's MMIO region, while leaving its clocks/resets and their providers registered. This can cause a page fault later when some clock operation tries to perform MMIO. Fix this by separating the CCU initialization from the memory allocation, and then using a devres callback to unregister the clocks and resets. This also fixes a memory leak of the `struct ccu_reset`, and uses the correct owner (the specific platform driver) for the clocks and resets. Early OF clock providers are never unregistered, and limited error handling is possible, so they are mostly unchanged. The error reporting is made more consistent by moving the message inside of_sunxi_ccu_probe. Signed-off-by: Samuel Holland Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210901050526.45673-2-samuel@sholland.org --- drivers/clk/sunxi-ng/ccu-sun4i-a10.c | 2 +- drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c | 2 +- drivers/clk/sunxi-ng/ccu-sun50i-a100.c | 2 +- drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 2 +- drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c | 2 +- drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 2 +- drivers/clk/sunxi-ng/ccu-sun50i-h616.c | 4 +- drivers/clk/sunxi-ng/ccu-sun5i.c | 2 +- drivers/clk/sunxi-ng/ccu-sun6i-a31.c | 2 +- drivers/clk/sunxi-ng/ccu-sun8i-a23.c | 2 +- drivers/clk/sunxi-ng/ccu-sun8i-a33.c | 2 +- drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 2 +- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 2 +- drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 2 +- drivers/clk/sunxi-ng/ccu-sun8i-r.c | 2 +- drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 2 +- drivers/clk/sunxi-ng/ccu-sun8i-v3s.c | 2 +- drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c | 3 +- drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c | 3 +- drivers/clk/sunxi-ng/ccu-sun9i-a80.c | 2 +- drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c | 2 +- drivers/clk/sunxi-ng/ccu_common.c | 89 ++++++++++++++++++++---- drivers/clk/sunxi-ng/ccu_common.h | 6 +- 23 files changed, 100 insertions(+), 41 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c index f32366d9336e..bd9a8782fec3 100644 --- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c +++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c @@ -1464,7 +1464,7 @@ static void __init sun4i_ccu_init(struct device_node *node, val &= ~GENMASK(7, 6); writel(val | (2 << 6), reg + SUN4I_AHB_REG); - sunxi_ccu_probe(node, reg, desc); + of_sunxi_ccu_probe(node, reg, desc); } static void __init sun4i_a10_ccu_setup(struct device_node *node) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c index a56142b90993..6f2a58970556 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c @@ -196,7 +196,7 @@ static int sun50i_a100_r_ccu_probe(struct platform_device *pdev) if (IS_ERR(reg)) return PTR_ERR(reg); - return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_r_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a100_r_ccu_desc); } static const struct of_device_id sun50i_a100_r_ccu_ids[] = { diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c index 81b48c73d389..913bb08e6dee 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c @@ -1247,7 +1247,7 @@ static int sun50i_a100_ccu_probe(struct platform_device *pdev) writel(val, reg + sun50i_a100_usb2_clk_regs[i]); } - ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_ccu_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a100_ccu_desc); if (ret) return ret; diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index 149cfde817cb..54f25c624f02 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -955,7 +955,7 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev) writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); - ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a64_ccu_desc); if (ret) return ret; diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c index f8909a7ed553..f30d7eb5424d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c @@ -232,7 +232,7 @@ static void __init sunxi_r_ccu_init(struct device_node *node, return; } - sunxi_ccu_probe(node, reg, desc); + of_sunxi_ccu_probe(node, reg, desc); } static void __init sun50i_h6_r_ccu_setup(struct device_node *node) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index bff446b78290..c0800da2fa3d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -1240,7 +1240,7 @@ static int sun50i_h6_ccu_probe(struct platform_device *pdev) val |= BIT(24); writel(val, reg + SUN50I_H6_HDMI_CEC_CLK_REG); - return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_h6_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h6_ccu_desc); } static const struct of_device_id sun50i_h6_ccu_ids[] = { diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c index 225307305880..22eb18079a15 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c @@ -1141,9 +1141,7 @@ static void __init sun50i_h616_ccu_setup(struct device_node *node) val |= BIT(24); writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); - i = sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc); - if (i) - pr_err("%pOF: probing clocks fails: %d\n", node, i); + of_sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc); } CLK_OF_DECLARE(sun50i_h616_ccu, "allwinner,sun50i-h616-ccu", diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c index b78e9b507c1c..1f4bc0e773a7 100644 --- a/drivers/clk/sunxi-ng/ccu-sun5i.c +++ b/drivers/clk/sunxi-ng/ccu-sun5i.c @@ -1012,7 +1012,7 @@ static void __init sun5i_ccu_init(struct device_node *node, val &= ~GENMASK(7, 6); writel(val | (2 << 6), reg + SUN5I_AHB_REG); - sunxi_ccu_probe(node, reg, desc); + of_sunxi_ccu_probe(node, reg, desc); } static void __init sun5i_a10s_ccu_setup(struct device_node *node) diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 9b40d53266a3..3df5c0b41580 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -1257,7 +1257,7 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node) val |= 0x3 << 12; writel(val, reg + SUN6I_A31_AHB1_REG); - sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc); + of_sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc); ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk, &sun6i_a31_cpu_nb); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index 103aa504f6c8..577bb235d658 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -745,7 +745,7 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node) val &= ~BIT(16); writel(val, reg + SUN8I_A23_PLL_MIPI_REG); - sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc); + of_sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc); } CLK_OF_DECLARE(sun8i_a23_ccu, "allwinner,sun8i-a23-ccu", sun8i_a23_ccu_setup); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c index 91838cd11037..8f65cd03f5ac 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c @@ -805,7 +805,7 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node) val &= ~BIT(16); writel(val, reg + SUN8I_A33_PLL_MIPI_REG); - sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc); + of_sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc); /* Gate then ungate PLL CPU after any rate changes */ ccu_pll_notifier_register(&sun8i_a33_pll_cpu_nb); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index 2b434521c5cc..c2ddcd2ddab4 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -906,7 +906,7 @@ static int sun8i_a83t_ccu_probe(struct platform_device *pdev) sun8i_a83t_cpu_pll_fixup(reg + SUN8I_A83T_PLL_C0CPUX_REG); sun8i_a83t_cpu_pll_fixup(reg + SUN8I_A83T_PLL_C1CPUX_REG); - return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_a83t_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a83t_ccu_desc); } static const struct of_device_id sun8i_a83t_ccu_ids[] = { diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 524f33275bc7..4b94b6041b27 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -342,7 +342,7 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev) goto err_disable_mod_clk; } - ret = sunxi_ccu_probe(pdev->dev.of_node, reg, ccu_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc); if (ret) goto err_assert_reset; diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 7e629a4493af..d2fc2903787d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -1154,7 +1154,7 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node, val &= ~GENMASK(19, 16); writel(val | (0 << 16), reg + SUN8I_H3_PLL_AUDIO_REG); - sunxi_ccu_probe(node, reg, desc); + of_sunxi_ccu_probe(node, reg, desc); /* Gate then ungate PLL CPU after any rate changes */ ccu_pll_notifier_register(&sun8i_h3_pll_cpu_nb); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c index 4c8c491b87c2..9e754d1f754a 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c @@ -265,7 +265,7 @@ static void __init sunxi_r_ccu_init(struct device_node *node, return; } - sunxi_ccu_probe(node, reg, desc); + of_sunxi_ccu_probe(node, reg, desc); } static void __init sun8i_a83t_r_ccu_setup(struct device_node *node) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index 84153418453f..002e0c3a04db 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -1346,7 +1346,7 @@ static int sun8i_r40_ccu_probe(struct platform_device *pdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); - ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_r40_ccu_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_r40_ccu_desc); if (ret) return ret; diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c index f49724a22540..ce150f83ab54 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c @@ -822,7 +822,7 @@ static void __init sun8i_v3_v3s_ccu_init(struct device_node *node, val &= ~GENMASK(19, 16); writel(val, reg + SUN8I_V3S_PLL_AUDIO_REG); - sunxi_ccu_probe(node, reg, ccu_desc); + of_sunxi_ccu_probe(node, reg, ccu_desc); } static void __init sun8i_v3s_ccu_setup(struct device_node *node) diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c index 6616e8114f62..261e64416f26 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c @@ -246,8 +246,7 @@ static int sun9i_a80_de_clk_probe(struct platform_device *pdev) goto err_disable_clk; } - ret = sunxi_ccu_probe(pdev->dev.of_node, reg, - &sun9i_a80_de_clk_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_de_clk_desc); if (ret) goto err_assert_reset; diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c index 4b4a507d04ed..596243b3e0fa 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c @@ -117,8 +117,7 @@ static int sun9i_a80_usb_clk_probe(struct platform_device *pdev) return ret; } - ret = sunxi_ccu_probe(pdev->dev.of_node, reg, - &sun9i_a80_usb_clk_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_usb_clk_desc); if (ret) goto err_disable_clk; diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c index ef29582676f6..97aaed0e6850 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c @@ -1231,7 +1231,7 @@ static int sun9i_a80_ccu_probe(struct platform_device *pdev) sun9i_a80_cpu_pll_fixup(reg + SUN9I_A80_PLL_C0CPUX_REG); sun9i_a80_cpu_pll_fixup(reg + SUN9I_A80_PLL_C1CPUX_REG); - return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun9i_a80_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_ccu_desc); } static const struct of_device_id sun9i_a80_ccu_ids[] = { diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c index 7ecc3a5a5b5e..61ad7ee91c11 100644 --- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c +++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c @@ -538,7 +538,7 @@ static void __init suniv_f1c100s_ccu_setup(struct device_node *node) val &= ~GENMASK(19, 16); writel(val | (3 << 16), reg + SUNIV_PLL_AUDIO_REG); - sunxi_ccu_probe(node, reg, &suniv_ccu_desc); + of_sunxi_ccu_probe(node, reg, &suniv_ccu_desc); /* Gate then ungate PLL CPU after any rate changes */ ccu_pll_notifier_register(&suniv_pll_cpu_nb); diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index 2e20e650b6c0..88cb569e5835 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -14,6 +15,11 @@ #include "ccu_gate.h" #include "ccu_reset.h" +struct sunxi_ccu { + const struct sunxi_ccu_desc *desc; + struct ccu_reset reset; +}; + static DEFINE_SPINLOCK(ccu_lock); void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) @@ -79,12 +85,15 @@ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb) &pll_nb->clk_nb); } -int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, - const struct sunxi_ccu_desc *desc) +static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev, + struct device_node *node, void __iomem *reg, + const struct sunxi_ccu_desc *desc) { struct ccu_reset *reset; int i, ret; + ccu->desc = desc; + for (i = 0; i < desc->num_ccu_clks; i++) { struct ccu_common *cclk = desc->ccu_clks[i]; @@ -103,7 +112,10 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, continue; name = hw->init->name; - ret = of_clk_hw_register(node, hw); + if (dev) + ret = clk_hw_register(dev, hw); + else + ret = of_clk_hw_register(node, hw); if (ret) { pr_err("Couldn't register clock %d - %s\n", i, name); goto err_clk_unreg; @@ -115,15 +127,10 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, if (ret) goto err_clk_unreg; - reset = kzalloc(sizeof(*reset), GFP_KERNEL); - if (!reset) { - ret = -ENOMEM; - goto err_alloc_reset; - } - + reset = &ccu->reset; reset->rcdev.of_node = node; reset->rcdev.ops = &ccu_reset_ops; - reset->rcdev.owner = THIS_MODULE; + reset->rcdev.owner = dev ? dev->driver->owner : THIS_MODULE; reset->rcdev.nr_resets = desc->num_resets; reset->base = reg; reset->lock = &ccu_lock; @@ -131,13 +138,11 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, ret = reset_controller_register(&reset->rcdev); if (ret) - goto err_of_clk_unreg; + goto err_del_provider; return 0; -err_of_clk_unreg: - kfree(reset); -err_alloc_reset: +err_del_provider: of_clk_del_provider(node); err_clk_unreg: while (--i >= 0) { @@ -149,3 +154,59 @@ err_clk_unreg: } return ret; } + +static void devm_sunxi_ccu_release(struct device *dev, void *res) +{ + struct sunxi_ccu *ccu = res; + const struct sunxi_ccu_desc *desc = ccu->desc; + int i; + + reset_controller_unregister(&ccu->reset.rcdev); + of_clk_del_provider(dev->of_node); + + for (i = 0; i < desc->hw_clks->num; i++) { + struct clk_hw *hw = desc->hw_clks->hws[i]; + + if (!hw) + continue; + clk_hw_unregister(hw); + } +} + +int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg, + const struct sunxi_ccu_desc *desc) +{ + struct sunxi_ccu *ccu; + int ret; + + ccu = devres_alloc(devm_sunxi_ccu_release, sizeof(*ccu), GFP_KERNEL); + if (!ccu) + return -ENOMEM; + + ret = sunxi_ccu_probe(ccu, dev, dev->of_node, reg, desc); + if (ret) { + devres_free(ccu); + return ret; + } + + devres_add(dev, ccu); + + return 0; +} + +void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg, + const struct sunxi_ccu_desc *desc) +{ + struct sunxi_ccu *ccu; + int ret; + + ccu = kzalloc(sizeof(*ccu), GFP_KERNEL); + if (!ccu) + return; + + ret = sunxi_ccu_probe(ccu, NULL, node, reg, desc); + if (ret) { + pr_err("%pOF: probing clocks failed: %d\n", node, ret); + kfree(ccu); + } +} diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h index 04e7a12200a2..98a1834b58bb 100644 --- a/drivers/clk/sunxi-ng/ccu_common.h +++ b/drivers/clk/sunxi-ng/ccu_common.h @@ -63,7 +63,9 @@ struct ccu_pll_nb { int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb); -int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, - const struct sunxi_ccu_desc *desc); +int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg, + const struct sunxi_ccu_desc *desc); +void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg, + const struct sunxi_ccu_desc *desc); #endif /* _COMMON_H_ */ From 66028ddb94c1717411eb7f84a9648e1a94d2a947 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 1 Sep 2021 00:05:20 -0500 Subject: [PATCH 04/39] clk: sunxi-ng: Prevent unbinding CCUs via sysfs The CCU drivers are not really designed to be unbound. Unbinding a SoC's main CCU is especially pointless, as very few of the peripherals on the SoC will work without it. Let's avoid any potential problems by removing the bind/unbind attributes from sysfs for these drivers. This change is not applied to the "secondary" CCUs (DE, USB) as those could reasonably be unbound without making the system useless. Signed-off-by: Samuel Holland Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210901050526.45673-3-samuel@sholland.org --- drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c | 1 + drivers/clk/sunxi-ng/ccu-sun50i-a100.c | 1 + drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 1 + drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 1 + drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 1 + drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 1 + drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c | 1 + drivers/clk/sunxi-ng/ccu-sun9i-a80.c | 1 + 8 files changed, 8 insertions(+) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c index 6f2a58970556..804729e0a208 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c @@ -208,6 +208,7 @@ static struct platform_driver sun50i_a100_r_ccu_driver = { .probe = sun50i_a100_r_ccu_probe, .driver = { .name = "sun50i-a100-r-ccu", + .suppress_bind_attrs = true, .of_match_table = sun50i_a100_r_ccu_ids, }, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c index 913bb08e6dee..1d475d5a3d91 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c @@ -1270,6 +1270,7 @@ static struct platform_driver sun50i_a100_ccu_driver = { .probe = sun50i_a100_ccu_probe, .driver = { .name = "sun50i-a100-ccu", + .suppress_bind_attrs = true, .of_match_table = sun50i_a100_ccu_ids, }, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index 54f25c624f02..fcbd914e84e0 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -978,6 +978,7 @@ static struct platform_driver sun50i_a64_ccu_driver = { .probe = sun50i_a64_ccu_probe, .driver = { .name = "sun50i-a64-ccu", + .suppress_bind_attrs = true, .of_match_table = sun50i_a64_ccu_ids, }, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index c0800da2fa3d..9a8902f702c5 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -1252,6 +1252,7 @@ static struct platform_driver sun50i_h6_ccu_driver = { .probe = sun50i_h6_ccu_probe, .driver = { .name = "sun50i-h6-ccu", + .suppress_bind_attrs = true, .of_match_table = sun50i_h6_ccu_ids, }, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index c2ddcd2ddab4..e663ab0c9935 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -918,6 +918,7 @@ static struct platform_driver sun8i_a83t_ccu_driver = { .probe = sun8i_a83t_ccu_probe, .driver = { .name = "sun8i-a83t-ccu", + .suppress_bind_attrs = true, .of_match_table = sun8i_a83t_ccu_ids, }, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index 002e0c3a04db..a2144ee728a0 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -1369,6 +1369,7 @@ static struct platform_driver sun8i_r40_ccu_driver = { .probe = sun8i_r40_ccu_probe, .driver = { .name = "sun8i-r40-ccu", + .suppress_bind_attrs = true, .of_match_table = sun8i_r40_ccu_ids, }, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c index 261e64416f26..d2072972b614 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c @@ -268,6 +268,7 @@ static struct platform_driver sun9i_a80_de_clk_driver = { .probe = sun9i_a80_de_clk_probe, .driver = { .name = "sun9i-a80-de-clks", + .suppress_bind_attrs = true, .of_match_table = sun9i_a80_de_clk_ids, }, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c index 97aaed0e6850..68b30fdc60fd 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c @@ -1243,6 +1243,7 @@ static struct platform_driver sun9i_a80_ccu_driver = { .probe = sun9i_a80_ccu_probe, .driver = { .name = "sun9i-a80-ccu", + .suppress_bind_attrs = true, .of_match_table = sun9i_a80_ccu_ids, }, }; From 8f8163215249cf47d754c550c2ac981a564df105 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 1 Sep 2021 00:05:21 -0500 Subject: [PATCH 05/39] clk: sunxi-ng: Use a separate lock for each CCU instance Some platforms have more than one CCU driver loaded: the main CCU, the PRCM, the display engine, and possibly others. All of these hardware blocks have separate MMIO spaces, so there is no need to synchronize between them. Signed-off-by: Samuel Holland Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210901050526.45673-4-samuel@sholland.org --- drivers/clk/sunxi-ng/ccu_common.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index 88cb569e5835..31af8b6b5286 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -17,11 +17,10 @@ struct sunxi_ccu { const struct sunxi_ccu_desc *desc; + spinlock_t lock; struct ccu_reset reset; }; -static DEFINE_SPINLOCK(ccu_lock); - void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) { void __iomem *addr; @@ -94,6 +93,8 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev, ccu->desc = desc; + spin_lock_init(&ccu->lock); + for (i = 0; i < desc->num_ccu_clks; i++) { struct ccu_common *cclk = desc->ccu_clks[i]; @@ -101,7 +102,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev, continue; cclk->base = reg; - cclk->lock = &ccu_lock; + cclk->lock = &ccu->lock; } for (i = 0; i < desc->hw_clks->num ; i++) { @@ -133,7 +134,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev, reset->rcdev.owner = dev ? dev->driver->owner : THIS_MODULE; reset->rcdev.nr_resets = desc->num_resets; reset->base = reg; - reset->lock = &ccu_lock; + reset->lock = &ccu->lock; reset->reset_map = desc->resets; ret = reset_controller_register(&reset->rcdev); From cea6d174e7016ed93ab1f893233b280f73e7a995 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 1 Sep 2021 11:18:09 +0200 Subject: [PATCH 06/39] dt-bindings: clocks: Fix typo in the H6 compatible Even though both the driver and the device trees all use the allwinner,sun50i-h6-de3-clk, we documented the compatible as allwinner,sun50i-h6-de2-clk in the binding. Let's fix this. Reviewed-by: Rob Herring Signed-off-by: Maxime Ripard Reviewed-by: Jernej Skrabec Link: https://lore.kernel.org/r/20210901091852.479202-10-maxime@cerno.tech --- .../devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml index 3f995d2b30eb..e79eeac5f086 100644 --- a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml +++ b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml @@ -24,7 +24,7 @@ properties: - const: allwinner,sun8i-v3s-de2-clk - const: allwinner,sun50i-a64-de2-clk - const: allwinner,sun50i-h5-de2-clk - - const: allwinner,sun50i-h6-de2-clk + - const: allwinner,sun50i-h6-de3-clk - items: - const: allwinner,sun8i-r40-de2-clk - const: allwinner,sun8i-h3-de2-clk From e42f37591a3796c092c98a54df3ded6ce414fe9b Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:51:50 +0800 Subject: [PATCH 07/39] clk: sunxi: clk-mod0: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085151.4509-1-caihuoqing@baidu.com --- drivers/clk/sunxi/clk-mod0.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c index f9d715ec9908..51800289ada9 100644 --- a/drivers/clk/sunxi/clk-mod0.c +++ b/drivers/clk/sunxi/clk-mod0.c @@ -88,14 +88,12 @@ CLK_OF_DECLARE_DRIVER(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *r; void __iomem *reg; if (!np) return -ENODEV; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, r); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From a021b280b90948e343ad24015ae0863d2ad0cbb3 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:51:58 +0800 Subject: [PATCH 08/39] clk: sunxi-ng: ccu-sun50i-a64: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085158.4560-1-caihuoqing@baidu.com --- drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index fcbd914e84e0..a8c5a92b7d0c 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -938,13 +938,11 @@ static struct ccu_mux_nb sun50i_a64_cpu_nb = { static int sun50i_a64_ccu_probe(struct platform_device *pdev) { - struct resource *res; void __iomem *reg; u32 val; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, res); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From 4b3a3a0375f88b819ff425ed580648215528f817 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:52:05 +0800 Subject: [PATCH 09/39] clk: sunxi-ng: ccu-sun50i-h6: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085206.4611-1-caihuoqing@baidu.com --- drivers/clk/sunxi-ng/ccu-sun50i-h6.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index 9a8902f702c5..e5672c10d065 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -1183,13 +1183,11 @@ static const u32 usb2_clk_regs[] = { static int sun50i_h6_ccu_probe(struct platform_device *pdev) { - struct resource *res; void __iomem *reg; u32 val; int i; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, res); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From defecd547e58c792f900f88331167660b8c755d5 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:52:12 +0800 Subject: [PATCH 10/39] clk: sunxi-ng: ccu-sun8i-a83t: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085213.4662-1-caihuoqing@baidu.com --- drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index e663ab0c9935..3c310aea8cfa 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -887,12 +887,10 @@ static void sun8i_a83t_cpu_pll_fixup(void __iomem *reg) static int sun8i_a83t_ccu_probe(struct platform_device *pdev) { - struct resource *res; void __iomem *reg; u32 val; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, res); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From 3f7785a26c623a5801b20a1e7632cfda05a307ac Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:52:20 +0800 Subject: [PATCH 11/39] clk: sunxi-ng: ccu-sun8i-de2: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085221.4713-1-caihuoqing@baidu.com --- drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 4b94b6041b27..573b5051d305 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -280,7 +280,6 @@ static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc = { static int sunxi_de2_clk_probe(struct platform_device *pdev) { - struct resource *res; struct clk *bus_clk, *mod_clk; struct reset_control *rstc; void __iomem *reg; @@ -291,8 +290,7 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev) if (!ccu_desc) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, res); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From 605c99ff66cd6f5caff42074c543f9c6def9ed73 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:52:27 +0800 Subject: [PATCH 12/39] clk: sunxi-ng: ccu-sun8i-r40: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085228.4764-1-caihuoqing@baidu.com --- drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index a2144ee728a0..8bb18d9add05 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -1307,14 +1307,12 @@ static struct regmap_config sun8i_r40_ccu_regmap_config = { static int sun8i_r40_ccu_probe(struct platform_device *pdev) { - struct resource *res; struct regmap *regmap; void __iomem *reg; u32 val; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, res); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From 9e85bd7248f15c0401967f4376f7510cc334c106 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:52:35 +0800 Subject: [PATCH 13/39] clk: sunxi-ng: ccu-sun9i-a80: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085235.4815-1-caihuoqing@baidu.com --- drivers/clk/sunxi-ng/ccu-sun9i-a80.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c index 68b30fdc60fd..d416af29e0d3 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c @@ -1213,12 +1213,10 @@ static void sun9i_a80_cpu_pll_fixup(void __iomem *reg) static int sun9i_a80_ccu_probe(struct platform_device *pdev) { - struct resource *res; void __iomem *reg; u32 val; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, res); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From cd9e3b1a87166dab38d4f07e9cf8556e9d7013f6 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:52:42 +0800 Subject: [PATCH 14/39] clk: sunxi-ng: ccu-sun9i-a80-de: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085243.4866-1-caihuoqing@baidu.com --- drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c index d2072972b614..3cde2610f467 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c @@ -203,14 +203,12 @@ static const struct sunxi_ccu_desc sun9i_a80_de_clk_desc = { static int sun9i_a80_de_clk_probe(struct platform_device *pdev) { - struct resource *res; struct clk *bus_clk; struct reset_control *rstc; void __iomem *reg; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, res); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From 2dcfd0318354eb48a8ff94c0fc23974a6a06d493 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:52:49 +0800 Subject: [PATCH 15/39] clk: sunxi-ng: ccu-sun9i-a80-usb: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085250.4917-1-caihuoqing@baidu.com --- drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c index 596243b3e0fa..0740e8978ae8 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c @@ -92,13 +92,11 @@ static const struct sunxi_ccu_desc sun9i_a80_usb_clk_desc = { static int sun9i_a80_usb_clk_probe(struct platform_device *pdev) { - struct resource *res; struct clk *bus_clk; void __iomem *reg; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, res); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From 1f38b45b115d5f47154d615fe7206783f6a788f4 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:52:57 +0800 Subject: [PATCH 16/39] clk: sunxi: sun6i-apb0: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085257.4968-1-caihuoqing@baidu.com --- drivers/clk/sunxi/clk-sun6i-apb0.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c index 10f70c35c265..f80c67bafe38 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c @@ -32,12 +32,10 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; const char *clk_name = np->name; const char *clk_parent; - struct resource *r; void __iomem *reg; struct clk *clk; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, r); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From ac57ffb04b53c19d57ce77146f1b45fc440e9bb8 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:53:04 +0800 Subject: [PATCH 17/39] clk: sunxi: sun6i-apb0-gates: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085305.5019-1-caihuoqing@baidu.com --- drivers/clk/sunxi/clk-sun6i-apb0-gates.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c index 4c75b0770c74..e4cf1180b088 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c @@ -40,7 +40,6 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) const struct gates_data *data; const char *clk_parent; const char *clk_name; - struct resource *r; void __iomem *reg; int ngates; int i; @@ -53,8 +52,7 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) if (!data) return -ENODEV; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, r); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From 68a49d35ff08091fe10dad8b63bc56fdb730fea5 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:53:11 +0800 Subject: [PATCH 18/39] clk: sunxi: sun6i-ar100: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085312.5070-1-caihuoqing@baidu.com --- drivers/clk/sunxi/clk-sun6i-ar100.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index 54babc2b4b9e..9f9a2cf54f41 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -71,12 +71,10 @@ static DEFINE_SPINLOCK(sun6i_ar100_lock); static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *r; void __iomem *reg; struct clk *clk; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, r); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From e65d38e3d2d0e61ca464b46ad804f7a94e1ae45f Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:53:19 +0800 Subject: [PATCH 19/39] clk: sunxi: sun8i-apb0: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/20210907085319.5121-1-caihuoqing@baidu.com --- drivers/clk/sunxi/clk-sun8i-apb0.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c index fc5d6e3b77d1..f605ecca879f 100644 --- a/drivers/clk/sunxi/clk-sun8i-apb0.c +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c @@ -87,12 +87,10 @@ CLK_OF_DECLARE_DRIVER(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk", static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *r; void __iomem *reg; struct clk *clk; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg = devm_ioremap_resource(&pdev->dev, r); + reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg)) return PTR_ERR(reg); From c5c1a0ac6a38a39830fdbe70e397dc309ceb9a3b Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:50:59 +0800 Subject: [PATCH 20/39] clk: samsung: exynos-audss: Make use of devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210907085100.4152-1-caihuoqing@baidu.com --- drivers/clk/samsung/clk-exynos-audss.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 42b5d32c6cc7..9cc127a162ad 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -129,7 +129,6 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) struct clk *pll_ref, *pll_in, *cdclk, *sclk_audio, *sclk_pcm_in; const struct exynos_audss_clk_drvdata *variant; struct clk_hw **clk_table; - struct resource *res; struct device *dev = &pdev->dev; int i, ret = 0; @@ -137,8 +136,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) if (!variant) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg_base = devm_ioremap_resource(dev, res); + reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); From 63b86b01556db01bf722effc78641bb37402e95f Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:51:07 +0800 Subject: [PATCH 21/39] clk: samsung: exynos4412-isp: Make use of devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210907085107.4203-1-caihuoqing@baidu.com --- drivers/clk/samsung/clk-exynos4412-isp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c index b69e381b8c0c..471a6fb82670 100644 --- a/drivers/clk/samsung/clk-exynos4412-isp.c +++ b/drivers/clk/samsung/clk-exynos4412-isp.c @@ -110,11 +110,9 @@ static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev) struct samsung_clk_provider *ctx; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct resource *res; void __iomem *reg_base; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg_base = devm_ioremap_resource(dev, res); + reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); From 15b98bcae119009bf916b03d1ccc5e2cc5f42b9e Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:51:14 +0800 Subject: [PATCH 22/39] clk: samsung: exynos5433: Make use of devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210907085115.4254-1-caihuoqing@baidu.com --- drivers/clk/samsung/clk-exynos5433.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index f203074d858b..38bfffc5e5b3 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -5564,7 +5564,6 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev) struct exynos5433_cmu_data *data; struct samsung_clk_provider *ctx; struct device *dev = &pdev->dev; - struct resource *res; void __iomem *reg_base; int i; @@ -5577,8 +5576,7 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev) return -ENOMEM; ctx = &data->ctx; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg_base = devm_ioremap_resource(dev, res); + reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); From 1d26eaeec37a91ff4575f6fead889818c5895304 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Tue, 7 Sep 2021 16:51:21 +0800 Subject: [PATCH 23/39] clk: samsung: s5pv210-audss: Make use of devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210907085122.4305-1-caihuoqing@baidu.com --- drivers/clk/samsung/clk-s5pv210-audss.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c index a7827a120695..b31c00ea331f 100644 --- a/drivers/clk/samsung/clk-s5pv210-audss.c +++ b/drivers/clk/samsung/clk-s5pv210-audss.c @@ -63,15 +63,13 @@ static struct syscore_ops s5pv210_audss_clk_syscore_ops = { static int s5pv210_audss_clk_probe(struct platform_device *pdev) { int i, ret = 0; - struct resource *res; const char *mout_audss_p[2]; const char *mout_i2s_p[3]; const char *hclk_p; struct clk_hw **clk_table; struct clk *hclk, *pll_ref, *pll_in, *cdclk, *sclk_audio; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg_base = devm_ioremap_resource(&pdev->dev, res); + reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); From 2e1205422cb9a8e7aed62ff8c2e715db44644590 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Wed, 14 Jul 2021 01:25:10 +0200 Subject: [PATCH 24/39] clk: meson: meson8b: Export the video clocks Setting the video clocks requires fine-tuned adjustments of various video clocks. Export the required ones to allow changing the video clock for the CVBS and HDMI outputs at runtime. Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210713232510.3057750-7-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.h | 12 +----------- include/dt-bindings/clock/meson8b-clkc.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index b1a5074cf148..c764143e2617 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -107,14 +107,11 @@ #define CLKID_PERIPH_SEL 125 #define CLKID_AXI_SEL 127 #define CLKID_L2_DRAM_SEL 129 -#define CLKID_HDMI_PLL_LVDS_OUT 131 -#define CLKID_HDMI_PLL_HDMI_OUT 132 +#define CLKID_HDMI_PLL_LVDS_OUT 131 #define CLKID_VID_PLL_IN_SEL 133 #define CLKID_VID_PLL_IN_EN 134 #define CLKID_VID_PLL_PRE_DIV 135 #define CLKID_VID_PLL_POST_DIV 136 -#define CLKID_VID_PLL_FINAL_DIV 137 -#define CLKID_VCLK_IN_SEL 138 #define CLKID_VCLK_IN_EN 139 #define CLKID_VCLK_DIV1 140 #define CLKID_VCLK_DIV2_DIV 141 @@ -125,7 +122,6 @@ #define CLKID_VCLK_DIV6 146 #define CLKID_VCLK_DIV12_DIV 147 #define CLKID_VCLK_DIV12 148 -#define CLKID_VCLK2_IN_SEL 149 #define CLKID_VCLK2_IN_EN 150 #define CLKID_VCLK2_DIV1 151 #define CLKID_VCLK2_DIV2_DIV 152 @@ -137,17 +133,11 @@ #define CLKID_VCLK2_DIV12_DIV 158 #define CLKID_VCLK2_DIV12 159 #define CLKID_CTS_ENCT_SEL 160 -#define CLKID_CTS_ENCT 161 #define CLKID_CTS_ENCP_SEL 162 -#define CLKID_CTS_ENCP 163 #define CLKID_CTS_ENCI_SEL 164 -#define CLKID_CTS_ENCI 165 #define CLKID_HDMI_TX_PIXEL_SEL 166 -#define CLKID_HDMI_TX_PIXEL 167 #define CLKID_CTS_ENCL_SEL 168 -#define CLKID_CTS_ENCL 169 #define CLKID_CTS_VDAC0_SEL 170 -#define CLKID_CTS_VDAC0 171 #define CLKID_HDMI_SYS_SEL 172 #define CLKID_HDMI_SYS_DIV 173 #define CLKID_MALI_0_SEL 175 diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h index f33781338eda..78aa07fd7cc0 100644 --- a/include/dt-bindings/clock/meson8b-clkc.h +++ b/include/dt-bindings/clock/meson8b-clkc.h @@ -105,6 +105,16 @@ #define CLKID_PERIPH 126 #define CLKID_AXI 128 #define CLKID_L2_DRAM 130 +#define CLKID_HDMI_PLL_HDMI_OUT 132 +#define CLKID_VID_PLL_FINAL_DIV 137 +#define CLKID_VCLK_IN_SEL 138 +#define CLKID_VCLK2_IN_SEL 149 +#define CLKID_CTS_ENCT 161 +#define CLKID_CTS_ENCP 163 +#define CLKID_CTS_ENCI 165 +#define CLKID_HDMI_TX_PIXEL 167 +#define CLKID_CTS_ENCL 169 +#define CLKID_CTS_VDAC0 171 #define CLKID_HDMI_SYS 174 #define CLKID_VPU 190 #define CLKID_VDEC_1 196 From 1792bdac34a7bc79c2086508b3a1644db2088fbc Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Wed, 14 Jul 2021 01:25:05 +0200 Subject: [PATCH 25/39] clk: meson: meson8b: Use CLK_SET_RATE_NO_REPARENT for vclk{,2}_in_sel Use CLK_SET_RATE_NO_REPARENT for the vclk{,2}_in_sel clocks. The only parent which is actually used is vid_pll_final_div. This should be set using assigned-clock-parents in the .dts rather than removing some "unwanted" clock parents from the clock driver. Suggested-by: Jerome Brunet Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210713232510.3057750-2-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index a844d35b553a..0f8bd707217a 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1175,7 +1175,7 @@ static struct clk_regmap meson8b_vclk_in_sel = { .ops = &clk_regmap_mux_ro_ops, .parent_hws = meson8b_vclk_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, }, }; @@ -1358,7 +1358,7 @@ static struct clk_regmap meson8b_vclk2_in_sel = { .ops = &clk_regmap_mux_ro_ops, .parent_hws = meson8b_vclk_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, }, }; From 9e544b75b20f7e9e7767acc11b46fd38b4989eb4 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Wed, 14 Jul 2021 01:25:06 +0200 Subject: [PATCH 26/39] clk: meson: meson8b: Add the vid_pll_lvds_en gate clock HHI_VID_DIVIDER_CNTL[11] must be enabled for the video clock tree to work. This bit is described as "LVDS_CLK_EN". It is not 100% clear where this bit has to be placed in the hierarchy. But since the "LVDS_OUT" of the HDMI PLL uses it's own set of registers it's more likely that this "LVDS_CLK_EN" bit actually enables the input of the "hdmi_pll_lvds_out" clock to the "vid_pll_in_sel" tree. Add a gate definition for this bit (which will not be exported) so that the kernel can manage all required bits to enable and disable the video clocks. Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210713232510.3057750-3-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 23 ++++++++++++++++++++++- drivers/clk/meson/meson8b.h | 3 ++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 0f8bd707217a..9ccffbfe44e5 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1045,6 +1045,23 @@ static struct clk_regmap meson8b_l2_dram_clk_gate = { }, }; +/* also called LVDS_CLK_EN */ +static struct clk_regmap meson8b_vid_pll_lvds_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_lvds_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &meson8b_hdmi_pll_lvds_out.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + static struct clk_regmap meson8b_vid_pll_in_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_VID_DIVIDER_CNTL, @@ -1061,7 +1078,7 @@ static struct clk_regmap meson8b_vid_pll_in_sel = { * Meson8m2: vid2_pll */ .parent_hws = (const struct clk_hw *[]) { - &meson8b_hdmi_pll_lvds_out.hw + &meson8b_vid_pll_lvds_en.hw }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -2905,6 +2922,7 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = { [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw, [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, [CLKID_CTS_I958] = &meson8b_cts_i958.hw, + [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -3122,6 +3140,7 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw, [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, [CLKID_CTS_I958] = &meson8b_cts_i958.hw, + [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -3341,6 +3360,7 @@ static struct clk_hw_onecell_data meson8m2_hw_onecell_data = { [CLKID_CTS_MCLK_I958_DIV] = &meson8b_cts_mclk_i958_div.hw, [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, [CLKID_CTS_I958] = &meson8b_cts_i958.hw, + [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -3539,6 +3559,7 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_cts_mclk_i958_div, &meson8b_cts_mclk_i958, &meson8b_cts_i958, + &meson8b_vid_pll_lvds_en, }; static const struct meson8b_clk_reset_line { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index c764143e2617..b90c21bbd907 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -172,8 +172,9 @@ #define CLKID_CTS_MCLK_I958_DIV 211 #define CLKID_VCLK_EN 214 #define CLKID_VCLK2_EN 215 +#define CLKID_VID_PLL_LVDS_EN 216 -#define CLK_NR_CLKS 216 +#define CLK_NR_CLKS 217 /* * include the CLKID and RESETID that have From bb8557359806dde16191060cf27d5dd79eaf11d9 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Wed, 14 Jul 2021 01:25:07 +0200 Subject: [PATCH 27/39] clk: meson: meson8b: Add the HDMI PLL M/N parameters The 3.10 vendor kernel uses only specific HDMI PLL M/N parameter combinations. The PLL won't lock for values smaller than 50 if the internal doubling (which is yet unknown how to use it) is disabled. However, when this doubling is enabled then the values smaller than 50 will lock just fine. The only restriction for values greater than 50 is that the resulting frequency must not exceed the 3.0GHz limit. These values are taken from the endlessm 3.10 kernel which includes additional M/N combinations for some VESA and 75Hz display modes. Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210713232510.3057750-4-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 9ccffbfe44e5..8f29d26ed726 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -118,6 +118,27 @@ static struct clk_regmap meson8b_fixed_pll = { }, }; +static const struct pll_params_table hdmi_pll_params_table[] = { + PLL_PARAMS(40, 1), + PLL_PARAMS(42, 1), + PLL_PARAMS(44, 1), + PLL_PARAMS(45, 1), + PLL_PARAMS(49, 1), + PLL_PARAMS(52, 1), + PLL_PARAMS(54, 1), + PLL_PARAMS(56, 1), + PLL_PARAMS(59, 1), + PLL_PARAMS(60, 1), + PLL_PARAMS(61, 1), + PLL_PARAMS(62, 1), + PLL_PARAMS(64, 1), + PLL_PARAMS(66, 1), + PLL_PARAMS(68, 1), + PLL_PARAMS(71, 1), + PLL_PARAMS(82, 1), + { /* sentinel */ } +}; + static struct clk_regmap meson8b_hdmi_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { @@ -150,6 +171,7 @@ static struct clk_regmap meson8b_hdmi_pll_dco = { .shift = 29, .width = 1, }, + .table = hdmi_pll_params_table, }, .hw.init = &(struct clk_init_data){ /* sometimes also called "HPLL" or "HPLL PLL" */ From 040e165bef65ffd137f734b0e6d78d160a93abb2 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Wed, 14 Jul 2021 01:25:08 +0200 Subject: [PATCH 28/39] clk: meson: meson8b: Initialize the HDMI PLL registers Add the reg_sequence to initialize the HDMI PLL with the settings for a video mode that doesn't require PLL internal clock doubling. These settings are taken from the 3.10 vendor kernel's driver for the 2970MHz PLL setting used for the 1080P video mode. This puts the PLL into a defined state and the Linux kernel can take over. While not all bits for this PLL are implemented using these "defaults" and then applying M, N and FRAC seems to work fine. Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210713232510.3057750-5-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 40 +++++++++++++++++++++++++++++++++---- drivers/clk/meson/meson8b.h | 13 +++++++++++- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 8f29d26ed726..21bc29455f0d 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -118,6 +118,35 @@ static struct clk_regmap meson8b_fixed_pll = { }, }; +static struct clk_fixed_factor hdmi_pll_dco_in = { + .mult = 2, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco_in", + .ops = &clk_fixed_factor_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + .index = -1, + }, + .num_parents = 1, + }, +}; + +/* + * Taken from the vendor driver for the 2970/2975MHz (both only differ in the + * FRAC part in HHI_VID_PLL_CNTL2) where these values are identical for Meson8, + * Meson8b and Meson8m2. This doubles the input (or output - it's not clear + * which one but the result is the same) clock. The vendor driver additionally + * has the following comment about: "optimise HPLL VCO 2.97GHz performance". + */ +static const struct reg_sequence meson8b_hdmi_pll_init_regs[] = { + { .reg = HHI_VID_PLL_CNTL2, .def = 0x69c84000 }, + { .reg = HHI_VID_PLL_CNTL3, .def = 0x8a46c023 }, + { .reg = HHI_VID_PLL_CNTL4, .def = 0x4123b100 }, + { .reg = HHI_VID_PLL_CNTL5, .def = 0x00012385 }, + { .reg = HHI_VID2_PLL_CNTL2, .def = 0x0430a800 }, +}; + static const struct pll_params_table hdmi_pll_params_table[] = { PLL_PARAMS(40, 1), PLL_PARAMS(42, 1), @@ -172,15 +201,15 @@ static struct clk_regmap meson8b_hdmi_pll_dco = { .width = 1, }, .table = hdmi_pll_params_table, + .init_regs = meson8b_hdmi_pll_init_regs, + .init_count = ARRAY_SIZE(meson8b_hdmi_pll_init_regs), }, .hw.init = &(struct clk_init_data){ /* sometimes also called "HPLL" or "HPLL PLL" */ .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, - .parent_data = &(const struct clk_parent_data) { - .fw_name = "xtal", - .name = "xtal", - .index = -1, + .parent_hws = (const struct clk_hw *[]) { + &hdmi_pll_dco_in.hw }, .num_parents = 1, }, @@ -2945,6 +2974,7 @@ static struct clk_hw_onecell_data meson8_hw_onecell_data = { [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, [CLKID_CTS_I958] = &meson8b_cts_i958.hw, [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, + [CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -3163,6 +3193,7 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, [CLKID_CTS_I958] = &meson8b_cts_i958.hw, [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, + [CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -3383,6 +3414,7 @@ static struct clk_hw_onecell_data meson8m2_hw_onecell_data = { [CLKID_CTS_MCLK_I958] = &meson8b_cts_mclk_i958.hw, [CLKID_CTS_I958] = &meson8b_cts_i958.hw, [CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw, + [CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index b90c21bbd907..ce62ed47cbfc 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -51,6 +51,16 @@ #define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ #define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ #define HHI_VID_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ +#define HHI_VID_PLL_CNTL3 0x328 /* 0xca offset in data sheet */ +#define HHI_VID_PLL_CNTL4 0x32c /* 0xcb offset in data sheet */ +#define HHI_VID_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ +#define HHI_VID_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ +#define HHI_VID2_PLL_CNTL 0x380 /* 0xe0 offset in data sheet */ +#define HHI_VID2_PLL_CNTL2 0x384 /* 0xe1 offset in data sheet */ +#define HHI_VID2_PLL_CNTL3 0x388 /* 0xe2 offset in data sheet */ +#define HHI_VID2_PLL_CNTL4 0x38c /* 0xe3 offset in data sheet */ +#define HHI_VID2_PLL_CNTL5 0x390 /* 0xe4 offset in data sheet */ +#define HHI_VID2_PLL_CNTL6 0x394 /* 0xe5 offset in data sheet */ /* * MPLL register offeset taken from the S905 datasheet. Vendor kernel source @@ -173,8 +183,9 @@ #define CLKID_VCLK_EN 214 #define CLKID_VCLK2_EN 215 #define CLKID_VID_PLL_LVDS_EN 216 +#define CLKID_HDMI_PLL_DCO_IN 217 -#define CLK_NR_CLKS 217 +#define CLK_NR_CLKS 218 /* * include the CLKID and RESETID that have From 7bcf9ef6b9c50e87bcb1dee5ced50ccfa2b21470 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Wed, 14 Jul 2021 01:25:09 +0200 Subject: [PATCH 29/39] clk: meson: meson8b: Make the video clock trees mutable Switch from the "_ro" clock op variants to the mutable ones for all video clocks. This will allow the VPU driver to change the clocks as needed for the different video output modes. Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210713232510.3057750-6-martin.blumenstingl@googlemail.com --- drivers/clk/meson/meson8b.c | 76 ++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 21bc29455f0d..cd0f5bae24d4 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -207,7 +207,7 @@ static struct clk_regmap meson8b_hdmi_pll_dco = { .hw.init = &(struct clk_init_data){ /* sometimes also called "HPLL" or "HPLL PLL" */ .name = "hdmi_pll_dco", - .ops = &meson_clk_pll_ro_ops, + .ops = &meson_clk_pll_ops, .parent_hws = (const struct clk_hw *[]) { &hdmi_pll_dco_in.hw }, @@ -224,7 +224,7 @@ static struct clk_regmap meson8b_hdmi_pll_lvds_out = { }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_lvds_out", - .ops = &clk_regmap_divider_ro_ops, + .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_hdmi_pll_dco.hw }, @@ -242,7 +242,7 @@ static struct clk_regmap meson8b_hdmi_pll_hdmi_out = { }, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll_hdmi_out", - .ops = &clk_regmap_divider_ro_ops, + .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_hdmi_pll_dco.hw }, @@ -1104,7 +1104,7 @@ static struct clk_regmap meson8b_vid_pll_lvds_en = { }, .hw.init = &(struct clk_init_data){ .name = "vid_pll_lvds_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_hdmi_pll_lvds_out.hw }, @@ -1121,7 +1121,7 @@ static struct clk_regmap meson8b_vid_pll_in_sel = { }, .hw.init = &(struct clk_init_data){ .name = "vid_pll_in_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, /* * TODO: depending on the SoC there is also a second parent: * Meson8: unknown @@ -1143,7 +1143,7 @@ static struct clk_regmap meson8b_vid_pll_in_en = { }, .hw.init = &(struct clk_init_data){ .name = "vid_pll_in_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vid_pll_in_sel.hw }, @@ -1160,7 +1160,7 @@ static struct clk_regmap meson8b_vid_pll_pre_div = { }, .hw.init = &(struct clk_init_data){ .name = "vid_pll_pre_div", - .ops = &clk_regmap_divider_ro_ops, + .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vid_pll_in_en.hw }, @@ -1177,7 +1177,7 @@ static struct clk_regmap meson8b_vid_pll_post_div = { }, .hw.init = &(struct clk_init_data){ .name = "vid_pll_post_div", - .ops = &clk_regmap_divider_ro_ops, + .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vid_pll_pre_div.hw }, @@ -1194,7 +1194,7 @@ static struct clk_regmap meson8b_vid_pll = { }, .hw.init = &(struct clk_init_data){ .name = "vid_pll", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, /* TODO: parent 0x2 is vid_pll_pre_div_mult7_div2 */ .parent_hws = (const struct clk_hw *[]) { &meson8b_vid_pll_pre_div.hw, @@ -1213,7 +1213,7 @@ static struct clk_regmap meson8b_vid_pll_final_div = { }, .hw.init = &(struct clk_init_data){ .name = "vid_pll_final_div", - .ops = &clk_regmap_divider_ro_ops, + .ops = &clk_regmap_divider_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vid_pll.hw }, @@ -1240,7 +1240,7 @@ static struct clk_regmap meson8b_vclk_in_sel = { }, .hw.init = &(struct clk_init_data){ .name = "vclk_in_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, .parent_hws = meson8b_vclk_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, @@ -1254,7 +1254,7 @@ static struct clk_regmap meson8b_vclk_in_en = { }, .hw.init = &(struct clk_init_data){ .name = "vclk_in_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_in_sel.hw }, @@ -1270,7 +1270,7 @@ static struct clk_regmap meson8b_vclk_en = { }, .hw.init = &(struct clk_init_data){ .name = "vclk_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_in_en.hw }, @@ -1286,7 +1286,7 @@ static struct clk_regmap meson8b_vclk_div1_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk_div1_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_en.hw }, @@ -1316,7 +1316,7 @@ static struct clk_regmap meson8b_vclk_div2_div_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk_div2_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_div2_div.hw }, @@ -1346,7 +1346,7 @@ static struct clk_regmap meson8b_vclk_div4_div_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk_div4_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_div4_div.hw }, @@ -1376,7 +1376,7 @@ static struct clk_regmap meson8b_vclk_div6_div_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk_div6_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_div6_div.hw }, @@ -1406,7 +1406,7 @@ static struct clk_regmap meson8b_vclk_div12_div_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk_div12_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk_div12_div.hw }, @@ -1423,7 +1423,7 @@ static struct clk_regmap meson8b_vclk2_in_sel = { }, .hw.init = &(struct clk_init_data){ .name = "vclk2_in_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, .parent_hws = meson8b_vclk_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws), .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, @@ -1437,7 +1437,7 @@ static struct clk_regmap meson8b_vclk2_clk_in_en = { }, .hw.init = &(struct clk_init_data){ .name = "vclk2_in_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_in_sel.hw }, @@ -1453,7 +1453,7 @@ static struct clk_regmap meson8b_vclk2_clk_en = { }, .hw.init = &(struct clk_init_data){ .name = "vclk2_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_clk_in_en.hw }, @@ -1469,7 +1469,7 @@ static struct clk_regmap meson8b_vclk2_div1_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk2_div1_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_clk_en.hw }, @@ -1499,7 +1499,7 @@ static struct clk_regmap meson8b_vclk2_div2_div_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk2_div2_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_div2_div.hw }, @@ -1529,7 +1529,7 @@ static struct clk_regmap meson8b_vclk2_div4_div_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk2_div4_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_div4_div.hw }, @@ -1559,7 +1559,7 @@ static struct clk_regmap meson8b_vclk2_div6_div_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk2_div6_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_div6_div.hw }, @@ -1589,7 +1589,7 @@ static struct clk_regmap meson8b_vclk2_div12_div_gate = { }, .hw.init = &(struct clk_init_data){ .name = "vclk2_div12_en", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_vclk2_div12_div.hw }, @@ -1614,7 +1614,7 @@ static struct clk_regmap meson8b_cts_enct_sel = { }, .hw.init = &(struct clk_init_data){ .name = "cts_enct_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, .parent_hws = meson8b_vclk_enc_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, @@ -1628,7 +1628,7 @@ static struct clk_regmap meson8b_cts_enct = { }, .hw.init = &(struct clk_init_data){ .name = "cts_enct", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_cts_enct_sel.hw }, @@ -1645,7 +1645,7 @@ static struct clk_regmap meson8b_cts_encp_sel = { }, .hw.init = &(struct clk_init_data){ .name = "cts_encp_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, .parent_hws = meson8b_vclk_enc_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, @@ -1659,7 +1659,7 @@ static struct clk_regmap meson8b_cts_encp = { }, .hw.init = &(struct clk_init_data){ .name = "cts_encp", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_cts_encp_sel.hw }, @@ -1676,7 +1676,7 @@ static struct clk_regmap meson8b_cts_enci_sel = { }, .hw.init = &(struct clk_init_data){ .name = "cts_enci_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, .parent_hws = meson8b_vclk_enc_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, @@ -1690,7 +1690,7 @@ static struct clk_regmap meson8b_cts_enci = { }, .hw.init = &(struct clk_init_data){ .name = "cts_enci", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_cts_enci_sel.hw }, @@ -1707,7 +1707,7 @@ static struct clk_regmap meson8b_hdmi_tx_pixel_sel = { }, .hw.init = &(struct clk_init_data){ .name = "hdmi_tx_pixel_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, .parent_hws = meson8b_vclk_enc_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, @@ -1721,7 +1721,7 @@ static struct clk_regmap meson8b_hdmi_tx_pixel = { }, .hw.init = &(struct clk_init_data){ .name = "hdmi_tx_pixel", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_hdmi_tx_pixel_sel.hw }, @@ -1746,7 +1746,7 @@ static struct clk_regmap meson8b_cts_encl_sel = { }, .hw.init = &(struct clk_init_data){ .name = "cts_encl_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, .parent_hws = meson8b_vclk2_enc_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, @@ -1760,7 +1760,7 @@ static struct clk_regmap meson8b_cts_encl = { }, .hw.init = &(struct clk_init_data){ .name = "cts_encl", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_cts_encl_sel.hw }, @@ -1777,7 +1777,7 @@ static struct clk_regmap meson8b_cts_vdac0_sel = { }, .hw.init = &(struct clk_init_data){ .name = "cts_vdac0_sel", - .ops = &clk_regmap_mux_ro_ops, + .ops = &clk_regmap_mux_ops, .parent_hws = meson8b_vclk2_enc_mux_parent_hws, .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws), .flags = CLK_SET_RATE_PARENT, @@ -1791,7 +1791,7 @@ static struct clk_regmap meson8b_cts_vdac0 = { }, .hw.init = &(struct clk_init_data){ .name = "cts_vdac0", - .ops = &clk_regmap_gate_ro_ops, + .ops = &clk_regmap_gate_ops, .parent_hws = (const struct clk_hw *[]) { &meson8b_cts_vdac0_sel.hw }, From 8f90f43a095d99144219fd3a5d1d5ddfb250b808 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 8 Oct 2021 18:43:48 +0300 Subject: [PATCH 30/39] clk: samsung: clk-pll: Implement pll0822x PLL type pll0822x PLL is used in Exynos850 SoC for top-level integer PLLs. The code was derived from very similar pll35xx type, with next differences: 1. Lock time for pll0822x is 150*P_DIV, when for pll35xx it's 270*P_DIV 2. It's not suggested in Exynos850 TRM that S_DIV change doesn't require performing PLL lock procedure (which is done in pll35xx implementation) When defining pll0822x type, CON3 register offset should be provided as a "con" parameter of PLL() macro, like this: PLL(pll_0822x, 0, "fout_shared0_pll", "oscclk", PLL_LOCKTIME_PLL_SHARED0, PLL_CON3_PLL_SHARED0, exynos850_shared0_pll_rates), To define PLL rates table, one can use PLL_35XX_RATE() macro, e.g.: PLL_35XX_RATE(26 * MHZ, 1600 * MHZ, 800, 13, 0) as it's completely appropriate for pl0822x type and there is no sense in duplicating that. If bit #1 (MANUAL_PLL_CTRL) is not set in CON1 register, it won't be possible to set new rate, with next error showing in kernel log: Could not lock PLL fout_shared1_pll That can happen for example if bootloader clears that bit beforehand. PLL driver doesn't account for that, so if MANUAL_PLL_CTRL bit was cleared, it's assumed it was done for a reason and it shouldn't be possible to change that PLL's rate at all. Signed-off-by: Sam Protsenko Signed-off-by: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Link: https://lore.kernel.org/r/20211008154352.19519-2-semen.protsenko@linaro.org Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-pll.c | 91 +++++++++++++++++++++++++++++++++++ drivers/clk/samsung/clk-pll.h | 1 + 2 files changed, 92 insertions(+) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 5873a9354b50..03131b149c0b 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -415,6 +415,89 @@ static const struct clk_ops samsung_pll36xx_clk_min_ops = { .recalc_rate = samsung_pll36xx_recalc_rate, }; +/* + * PLL0822x Clock Type + */ +/* Maximum lock time can be 150 * PDIV cycles */ +#define PLL0822X_LOCK_FACTOR (150) + +#define PLL0822X_MDIV_MASK (0x3FF) +#define PLL0822X_PDIV_MASK (0x3F) +#define PLL0822X_SDIV_MASK (0x7) +#define PLL0822X_MDIV_SHIFT (16) +#define PLL0822X_PDIV_SHIFT (8) +#define PLL0822X_SDIV_SHIFT (0) +#define PLL0822X_LOCK_STAT_SHIFT (29) +#define PLL0822X_ENABLE_SHIFT (31) + +static unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 mdiv, pdiv, sdiv, pll_con3; + u64 fvco = parent_rate; + + pll_con3 = readl_relaxed(pll->con_reg); + mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK; + pdiv = (pll_con3 >> PLL0822X_PDIV_SHIFT) & PLL0822X_PDIV_MASK; + sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + + return (unsigned long)fvco; +} + +static int samsung_pll0822x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + const struct samsung_pll_rate_table *rate; + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 pll_con3; + + /* Get required rate settings from table */ + rate = samsung_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; + } + + /* Change PLL PMS values */ + pll_con3 = readl_relaxed(pll->con_reg); + pll_con3 &= ~((PLL0822X_MDIV_MASK << PLL0822X_MDIV_SHIFT) | + (PLL0822X_PDIV_MASK << PLL0822X_PDIV_SHIFT) | + (PLL0822X_SDIV_MASK << PLL0822X_SDIV_SHIFT)); + pll_con3 |= (rate->mdiv << PLL0822X_MDIV_SHIFT) | + (rate->pdiv << PLL0822X_PDIV_SHIFT) | + (rate->sdiv << PLL0822X_SDIV_SHIFT); + + /* Set PLL lock time */ + writel_relaxed(rate->pdiv * PLL0822X_LOCK_FACTOR, + pll->lock_reg); + + /* Write PMS values */ + writel_relaxed(pll_con3, pll->con_reg); + + /* Wait for PLL lock if the PLL is enabled */ + if (pll_con3 & BIT(pll->enable_offs)) + return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); + + return 0; +} + +static const struct clk_ops samsung_pll0822x_clk_ops = { + .recalc_rate = samsung_pll0822x_recalc_rate, + .round_rate = samsung_pll_round_rate, + .set_rate = samsung_pll0822x_set_rate, + .enable = samsung_pll3xxx_enable, + .disable = samsung_pll3xxx_disable, +}; + +static const struct clk_ops samsung_pll0822x_clk_min_ops = { + .recalc_rate = samsung_pll0822x_recalc_rate, +}; + /* * PLL45xx Clock Type */ @@ -1296,6 +1379,14 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, else init.ops = &samsung_pll35xx_clk_ops; break; + case pll_0822x: + pll->enable_offs = PLL0822X_ENABLE_SHIFT; + pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT; + if (!pll->rate_table) + init.ops = &samsung_pll0822x_clk_min_ops; + else + init.ops = &samsung_pll0822x_clk_ops; + break; case pll_4500: init.ops = &samsung_pll45xx_clk_min_ops; break; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 79e41c226b90..213e94a97f23 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -36,6 +36,7 @@ enum samsung_pll_type { pll_1451x, pll_1452x, pll_1460x, + pll_0822x, }; #define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ From 6a734b3720782f66d34584feeb50811d98c1f389 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 8 Oct 2021 18:43:49 +0300 Subject: [PATCH 31/39] clk: samsung: clk-pll: Implement pll0831x PLL type pll0831x PLL is used in Exynos850 SoC for top-level fractional PLLs. The code was derived from very similar pll36xx type, with next differences: 1. Lock time for pll0831x is 500*P_DIV, when for pll36xx it's 3000*P_DIV 2. It's not suggested in Exynos850 TRM that S_DIV change doesn't require performing PLL lock procedure (which is done in pll36xx implementation) 3. The offset from PMS-values register to K-value register is 0x8 for pll0831x, when for pll36xx it's 0x4 When defining pll0831x type, CON3 register offset should be provided as a "con" parameter of PLL() macro, like this: PLL(pll_0831x, 0, "fout_mmc_pll", "oscclk", PLL_LOCKTIME_PLL_MMC, PLL_CON3_PLL_MMC, pll0831x_26mhz_tbl), To define PLL rates table, one can use PLL_36XX_RATE() macro, e.g.: PLL_36XX_RATE(26 * MHZ, 799999877, 31, 1, 0, -15124) as it's completely appropriate for pl0831x type and there is no sense in duplicating that. If bit #1 (MANUAL_PLL_CTRL) is not set in CON1 register, it won't be possible to set new rate, with next error showing in kernel log: Could not lock PLL fout_mmc_pll That can happen for example if bootloader clears that bit beforehand. PLL driver doesn't account for that, so if MANUAL_PLL_CTRL bit was cleared, it's assumed it was done for a reason and it shouldn't be possible to change that PLL's rate at all. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Link: https://lore.kernel.org/r/20211008154352.19519-3-semen.protsenko@linaro.org Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-pll.c | 105 ++++++++++++++++++++++++++++++++++ drivers/clk/samsung/clk-pll.h | 1 + 2 files changed, 106 insertions(+) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 03131b149c0b..83d1b03647db 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -498,6 +498,103 @@ static const struct clk_ops samsung_pll0822x_clk_min_ops = { .recalc_rate = samsung_pll0822x_recalc_rate, }; +/* + * PLL0831x Clock Type + */ +/* Maximum lock time can be 500 * PDIV cycles */ +#define PLL0831X_LOCK_FACTOR (500) + +#define PLL0831X_KDIV_MASK (0xFFFF) +#define PLL0831X_MDIV_MASK (0x1FF) +#define PLL0831X_PDIV_MASK (0x3F) +#define PLL0831X_SDIV_MASK (0x7) +#define PLL0831X_MDIV_SHIFT (16) +#define PLL0831X_PDIV_SHIFT (8) +#define PLL0831X_SDIV_SHIFT (0) +#define PLL0831X_KDIV_SHIFT (0) +#define PLL0831X_LOCK_STAT_SHIFT (29) +#define PLL0831X_ENABLE_SHIFT (31) + +static unsigned long samsung_pll0831x_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 mdiv, pdiv, sdiv, pll_con3, pll_con5; + s16 kdiv; + u64 fvco = parent_rate; + + pll_con3 = readl_relaxed(pll->con_reg); + pll_con5 = readl_relaxed(pll->con_reg + 8); + mdiv = (pll_con3 >> PLL0831X_MDIV_SHIFT) & PLL0831X_MDIV_MASK; + pdiv = (pll_con3 >> PLL0831X_PDIV_SHIFT) & PLL0831X_PDIV_MASK; + sdiv = (pll_con3 >> PLL0831X_SDIV_SHIFT) & PLL0831X_SDIV_MASK; + kdiv = (s16)((pll_con5 >> PLL0831X_KDIV_SHIFT) & PLL0831X_KDIV_MASK); + + fvco *= (mdiv << 16) + kdiv; + do_div(fvco, (pdiv << sdiv)); + fvco >>= 16; + + return (unsigned long)fvco; +} + +static int samsung_pll0831x_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long parent_rate) +{ + const struct samsung_pll_rate_table *rate; + struct samsung_clk_pll *pll = to_clk_pll(hw); + u32 pll_con3, pll_con5; + + /* Get required rate settings from table */ + rate = samsung_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; + } + + pll_con3 = readl_relaxed(pll->con_reg); + pll_con5 = readl_relaxed(pll->con_reg + 8); + + /* Change PLL PMSK values */ + pll_con3 &= ~((PLL0831X_MDIV_MASK << PLL0831X_MDIV_SHIFT) | + (PLL0831X_PDIV_MASK << PLL0831X_PDIV_SHIFT) | + (PLL0831X_SDIV_MASK << PLL0831X_SDIV_SHIFT)); + pll_con3 |= (rate->mdiv << PLL0831X_MDIV_SHIFT) | + (rate->pdiv << PLL0831X_PDIV_SHIFT) | + (rate->sdiv << PLL0831X_SDIV_SHIFT); + pll_con5 &= ~(PLL0831X_KDIV_MASK << PLL0831X_KDIV_SHIFT); + /* + * kdiv is 16-bit 2's complement (s16), but stored as unsigned int. + * Cast it to u16 to avoid leading 0xffff's in case of negative value. + */ + pll_con5 |= ((u16)rate->kdiv << PLL0831X_KDIV_SHIFT); + + /* Set PLL lock time */ + writel_relaxed(rate->pdiv * PLL0831X_LOCK_FACTOR, pll->lock_reg); + + /* Write PMSK values */ + writel_relaxed(pll_con3, pll->con_reg); + writel_relaxed(pll_con5, pll->con_reg + 8); + + /* Wait for PLL lock if the PLL is enabled */ + if (pll_con3 & BIT(pll->enable_offs)) + return samsung_pll_lock_wait(pll, BIT(pll->lock_offs)); + + return 0; +} + +static const struct clk_ops samsung_pll0831x_clk_ops = { + .recalc_rate = samsung_pll0831x_recalc_rate, + .set_rate = samsung_pll0831x_set_rate, + .round_rate = samsung_pll_round_rate, + .enable = samsung_pll3xxx_enable, + .disable = samsung_pll3xxx_disable, +}; + +static const struct clk_ops samsung_pll0831x_clk_min_ops = { + .recalc_rate = samsung_pll0831x_recalc_rate, +}; + /* * PLL45xx Clock Type */ @@ -1407,6 +1504,14 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, else init.ops = &samsung_pll36xx_clk_ops; break; + case pll_0831x: + pll->enable_offs = PLL0831X_ENABLE_SHIFT; + pll->lock_offs = PLL0831X_LOCK_STAT_SHIFT; + if (!pll->rate_table) + init.ops = &samsung_pll0831x_clk_min_ops; + else + init.ops = &samsung_pll0831x_clk_ops; + break; case pll_6552: case pll_6552_s3c2416: init.ops = &samsung_pll6552_clk_ops; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 213e94a97f23..a739f2b7ae80 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -37,6 +37,7 @@ enum samsung_pll_type { pll_1452x, pll_1460x, pll_0822x, + pll_0831x, }; #define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ From 2ae5c2c3f8d586b709cf67efe94488be397d7544 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 8 Oct 2021 18:43:50 +0300 Subject: [PATCH 32/39] dt-bindings: clock: Add bindings definitions for Exynos850 CMU Clock controller driver is designed to have separate instances for each particular CMU. So clock IDs in this bindings header also start from 1 for each CMU. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211008154352.19519-4-semen.protsenko@linaro.org Signed-off-by: Sylwester Nawrocki --- include/dt-bindings/clock/exynos850.h | 141 ++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 include/dt-bindings/clock/exynos850.h diff --git a/include/dt-bindings/clock/exynos850.h b/include/dt-bindings/clock/exynos850.h new file mode 100644 index 000000000000..8999184f94a2 --- /dev/null +++ b/include/dt-bindings/clock/exynos850.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2021 Linaro Ltd. + * Author: Sam Protsenko + * + * Device Tree binding constants for Exynos850 clock controller. + */ + +#ifndef _DT_BINDINGS_CLOCK_EXYNOS_850_H +#define _DT_BINDINGS_CLOCK_EXYNOS_850_H + +/* CMU_TOP */ +#define CLK_FOUT_SHARED0_PLL 1 +#define CLK_FOUT_SHARED1_PLL 2 +#define CLK_FOUT_MMC_PLL 3 +#define CLK_MOUT_SHARED0_PLL 4 +#define CLK_MOUT_SHARED1_PLL 5 +#define CLK_MOUT_MMC_PLL 6 +#define CLK_MOUT_CORE_BUS 7 +#define CLK_MOUT_CORE_CCI 8 +#define CLK_MOUT_CORE_MMC_EMBD 9 +#define CLK_MOUT_CORE_SSS 10 +#define CLK_MOUT_DPU 11 +#define CLK_MOUT_HSI_BUS 12 +#define CLK_MOUT_HSI_MMC_CARD 13 +#define CLK_MOUT_HSI_USB20DRD 14 +#define CLK_MOUT_PERI_BUS 15 +#define CLK_MOUT_PERI_UART 16 +#define CLK_MOUT_PERI_IP 17 +#define CLK_DOUT_SHARED0_DIV3 18 +#define CLK_DOUT_SHARED0_DIV2 19 +#define CLK_DOUT_SHARED1_DIV3 20 +#define CLK_DOUT_SHARED1_DIV2 21 +#define CLK_DOUT_SHARED0_DIV4 22 +#define CLK_DOUT_SHARED1_DIV4 23 +#define CLK_DOUT_CORE_BUS 24 +#define CLK_DOUT_CORE_CCI 25 +#define CLK_DOUT_CORE_MMC_EMBD 26 +#define CLK_DOUT_CORE_SSS 27 +#define CLK_DOUT_DPU 28 +#define CLK_DOUT_HSI_BUS 29 +#define CLK_DOUT_HSI_MMC_CARD 30 +#define CLK_DOUT_HSI_USB20DRD 31 +#define CLK_DOUT_PERI_BUS 32 +#define CLK_DOUT_PERI_UART 33 +#define CLK_DOUT_PERI_IP 34 +#define CLK_GOUT_CORE_BUS 35 +#define CLK_GOUT_CORE_CCI 36 +#define CLK_GOUT_CORE_MMC_EMBD 37 +#define CLK_GOUT_CORE_SSS 38 +#define CLK_GOUT_DPU 39 +#define CLK_GOUT_HSI_BUS 40 +#define CLK_GOUT_HSI_MMC_CARD 41 +#define CLK_GOUT_HSI_USB20DRD 42 +#define CLK_GOUT_PERI_BUS 43 +#define CLK_GOUT_PERI_UART 44 +#define CLK_GOUT_PERI_IP 45 +#define TOP_NR_CLK 46 + +/* CMU_HSI */ +#define CLK_MOUT_HSI_BUS_USER 1 +#define CLK_MOUT_HSI_MMC_CARD_USER 2 +#define CLK_MOUT_HSI_USB20DRD_USER 3 +#define CLK_MOUT_HSI_RTC 4 +#define CLK_GOUT_USB_RTC_CLK 5 +#define CLK_GOUT_USB_REF_CLK 6 +#define CLK_GOUT_USB_PHY_REF_CLK 7 +#define CLK_GOUT_USB_PHY_ACLK 8 +#define CLK_GOUT_USB_BUS_EARLY_CLK 9 +#define CLK_GOUT_GPIO_HSI_PCLK 10 +#define CLK_GOUT_MMC_CARD_ACLK 11 +#define CLK_GOUT_MMC_CARD_SDCLKIN 12 +#define CLK_GOUT_SYSREG_HSI_PCLK 13 +#define HSI_NR_CLK 14 + +/* CMU_PERI */ +#define CLK_MOUT_PERI_BUS_USER 1 +#define CLK_MOUT_PERI_UART_USER 2 +#define CLK_MOUT_PERI_HSI2C_USER 3 +#define CLK_MOUT_PERI_SPI_USER 4 +#define CLK_DOUT_PERI_HSI2C0 5 +#define CLK_DOUT_PERI_HSI2C1 6 +#define CLK_DOUT_PERI_HSI2C2 7 +#define CLK_DOUT_PERI_SPI0 8 +#define CLK_GOUT_PERI_HSI2C0 9 +#define CLK_GOUT_PERI_HSI2C1 10 +#define CLK_GOUT_PERI_HSI2C2 11 +#define CLK_GOUT_GPIO_PERI_PCLK 12 +#define CLK_GOUT_HSI2C0_IPCLK 13 +#define CLK_GOUT_HSI2C0_PCLK 14 +#define CLK_GOUT_HSI2C1_IPCLK 15 +#define CLK_GOUT_HSI2C1_PCLK 16 +#define CLK_GOUT_HSI2C2_IPCLK 17 +#define CLK_GOUT_HSI2C2_PCLK 18 +#define CLK_GOUT_I2C0_PCLK 19 +#define CLK_GOUT_I2C1_PCLK 20 +#define CLK_GOUT_I2C2_PCLK 21 +#define CLK_GOUT_I2C3_PCLK 22 +#define CLK_GOUT_I2C4_PCLK 23 +#define CLK_GOUT_I2C5_PCLK 24 +#define CLK_GOUT_I2C6_PCLK 25 +#define CLK_GOUT_MCT_PCLK 26 +#define CLK_GOUT_PWM_MOTOR_PCLK 27 +#define CLK_GOUT_SPI0_IPCLK 28 +#define CLK_GOUT_SPI0_PCLK 29 +#define CLK_GOUT_SYSREG_PERI_PCLK 30 +#define CLK_GOUT_UART_IPCLK 31 +#define CLK_GOUT_UART_PCLK 32 +#define CLK_GOUT_WDT0_PCLK 33 +#define CLK_GOUT_WDT1_PCLK 34 +#define PERI_NR_CLK 35 + +/* CMU_CORE */ +#define CLK_MOUT_CORE_BUS_USER 1 +#define CLK_MOUT_CORE_CCI_USER 2 +#define CLK_MOUT_CORE_MMC_EMBD_USER 3 +#define CLK_MOUT_CORE_SSS_USER 4 +#define CLK_MOUT_CORE_GIC 5 +#define CLK_DOUT_CORE_BUSP 6 +#define CLK_GOUT_CCI_ACLK 7 +#define CLK_GOUT_GIC_CLK 8 +#define CLK_GOUT_MMC_EMBD_ACLK 9 +#define CLK_GOUT_MMC_EMBD_SDCLKIN 10 +#define CLK_GOUT_SSS_ACLK 11 +#define CLK_GOUT_SSS_PCLK 12 +#define CORE_NR_CLK 13 + +/* CMU_DPU */ +#define CLK_MOUT_DPU_USER 1 +#define CLK_DOUT_DPU_BUSP 2 +#define CLK_GOUT_DPU_CMU_DPU_PCLK 3 +#define CLK_GOUT_DPU_DECON0_ACLK 4 +#define CLK_GOUT_DPU_DMA_ACLK 5 +#define CLK_GOUT_DPU_DPP_ACLK 6 +#define CLK_GOUT_DPU_PPMU_ACLK 7 +#define CLK_GOUT_DPU_PPMU_PCLK 8 +#define CLK_GOUT_DPU_SMMU_CLK 9 +#define CLK_GOUT_DPU_SYSREG_PCLK 10 +#define DPU_NR_CLK 11 + +#endif /* _DT_BINDINGS_CLOCK_EXYNOS_850_H */ From 5d6298f25a0db3de87f5209eb7b0fa97d4eae280 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 8 Oct 2021 18:43:51 +0300 Subject: [PATCH 33/39] dt-bindings: clock: Document Exynos850 CMU bindings Provide dt-schema documentation for Exynos850 SoC clock controller. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Link: https://lore.kernel.org/r/20211008154352.19519-5-semen.protsenko@linaro.org Signed-off-by: Sylwester Nawrocki --- .../clock/samsung,exynos850-clock.yaml | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml new file mode 100644 index 000000000000..7f8c91a29b91 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml @@ -0,0 +1,185 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/samsung,exynos850-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung Exynos850 SoC clock controller + +maintainers: + - Sam Protsenko + - Chanwoo Choi + - Krzysztof Kozlowski + - Sylwester Nawrocki + - Tomasz Figa + +description: | + Exynos850 clock controller is comprised of several CMU units, generating + clocks for different domains. Those CMU units are modeled as separate device + tree nodes, and might depend on each other. Root clocks in that clock tree are + two external clocks:: OSCCLK (26 MHz) and RTCCLK (32768 Hz). Those external + clocks must be defined as fixed-rate clocks in dts. + + CMU_TOP is a top-level CMU, where all base clocks are prepared using PLLs and + dividers; all other leaf clocks (other CMUs) are usually derived from CMU_TOP. + + Each clock is assigned an identifier and client nodes can use this identifier + to specify the clock which they consume. All clocks available for usage + in clock consumer nodes are defined as preprocessor macros in + 'dt-bindings/clock/exynos850.h' header. + +properties: + compatible: + enum: + - samsung,exynos850-cmu-top + - samsung,exynos850-cmu-core + - samsung,exynos850-cmu-dpu + - samsung,exynos850-cmu-hsi + - samsung,exynos850-cmu-peri + + clocks: + minItems: 1 + maxItems: 5 + + clock-names: + minItems: 1 + maxItems: 5 + + "#clock-cells": + const: 1 + + reg: + maxItems: 1 + +allOf: + - if: + properties: + compatible: + contains: + const: samsung,exynos850-cmu-top + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + + clock-names: + items: + - const: oscclk + + - if: + properties: + compatible: + contains: + const: samsung,exynos850-cmu-core + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: CMU_CORE bus clock (from CMU_TOP) + - description: CCI clock (from CMU_TOP) + - description: eMMC clock (from CMU_TOP) + - description: SSS clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: dout_core_bus + - const: dout_core_cci + - const: dout_core_mmc_embd + - const: dout_core_sss + + - if: + properties: + compatible: + contains: + const: samsung,exynos850-cmu-dpu + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: DPU clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: dout_dpu + + - if: + properties: + compatible: + contains: + const: samsung,exynos850-cmu-hsi + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: External RTC clock (32768 Hz) + - description: CMU_HSI bus clock (from CMU_TOP) + - description: SD card clock (from CMU_TOP) + - description: "USB 2.0 DRD clock (from CMU_TOP)" + + clock-names: + items: + - const: oscclk + - const: rtcclk + - const: dout_hsi_bus + - const: dout_hsi_mmc_card + - const: dout_hsi_usb20drd + + - if: + properties: + compatible: + contains: + const: samsung,exynos850-cmu-peri + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: CMU_PERI bus clock (from CMU_TOP) + - description: UART clock (from CMU_TOP) + - description: Parent clock for HSI2C and SPI (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: dout_peri_bus + - const: dout_peri_uart + - const: dout_peri_ip + +required: + - compatible + - "#clock-cells" + - clocks + - clock-names + - reg + +additionalProperties: false + +examples: + # Clock controller node for CMU_PERI + - | + #include + + cmu_peri: clock-controller@10030000 { + compatible = "samsung,exynos850-cmu-peri"; + reg = <0x10030000 0x8000>; + #clock-cells = <1>; + + clocks = <&oscclk>, <&cmu_top CLK_DOUT_PERI_BUS>, + <&cmu_top CLK_DOUT_PERI_UART>, + <&cmu_top CLK_DOUT_PERI_IP>; + clock-names = "oscclk", "dout_peri_bus", + "dout_peri_uart", "dout_peri_ip"; + }; + +... From 7dd05578198be9e08f3a019dd8b31873fddf51e3 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Fri, 8 Oct 2021 18:43:52 +0300 Subject: [PATCH 34/39] clk: samsung: Introduce Exynos850 clock driver This is the initial implementation adding only basic clocks like UART, MMC, I2C and corresponding parent clocks. Design is influenced by Exynos5433 clock driver. Bus clock is enabled by default (in probe function) for all CMUs except CMU_TOP, the reasoning is as follows. By default if bus clock has no users its "enable count" value is 0. It might be actually running if it's already enabled in bootloader, but then in some cases it can be disabled by mistake. For example, such case was observed when dw_mci_probe() enabled the bus clock, then failed to do something and disabled that bus clock on error path. After that, even the attempt to read the 'clk_summary' file in DebugFS freezed forever, as CMU bus clock ended up being disabled and it wasn't possible to access CMU registers anymore. To avoid such cases, CMU driver must increment the ref count for that bus clock by running clk_prepare_enable(). There is already existing '.clk_name' field in struct samsung_cmu_info, exactly for that reason. It was added in commit 523d3de41f02 ("clk: samsung: exynos5433: Add support for runtime PM"), with next mentioning in commit message: > Also for each CMU there is one special parent clock, which has to be > enabled all the time when any access to CMU registers is being done. But that clock is actually only enabled in Exynos5433 clock driver right now. So the same code is added to exynos850_cmu_probe() function, As was described above, it might be helpful not only for PM reasons, but also to prevent possible erroneous clock gating on error paths. Another way to workaround that issue would be to use CLOCK_IS_CRITICAL flag for corresponding gate clocks. But that might be not very good design decision, as we might still want to disable that bus clock, e.g. on PM suspend. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Link: https://lore.kernel.org/r/20211008154352.19519-6-semen.protsenko@linaro.org Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/Makefile | 1 + drivers/clk/samsung/clk-exynos850.c | 835 ++++++++++++++++++++++++++++ 2 files changed, 836 insertions(+) create mode 100644 drivers/clk/samsung/clk-exynos850.c diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 028b2e27a37e..c46cf11e4d0b 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o obj-$(CONFIG_EXYNOS_CLKOUT) += clk-exynos-clkout.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o +obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos850.o obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c new file mode 100644 index 000000000000..2294989e244c --- /dev/null +++ b/drivers/clk/samsung/clk-exynos850.c @@ -0,0 +1,835 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Linaro Ltd. + * Author: Sam Protsenko + * + * Common Clock Framework support for Exynos850 SoC. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +/* Gate register bits */ +#define GATE_MANUAL BIT(20) +#define GATE_ENABLE_HWACG BIT(28) + +/* Gate register offsets range */ +#define GATE_OFF_START 0x2000 +#define GATE_OFF_END 0x2fff + +/** + * exynos850_init_clocks - Set clocks initial configuration + * @np: CMU device tree node with "reg" property (CMU addr) + * @reg_offs: Register offsets array for clocks to init + * @reg_offs_len: Number of register offsets in reg_offs array + * + * Set manual control mode for all gate clocks. + */ +static void __init exynos850_init_clocks(struct device_node *np, + const unsigned long *reg_offs, size_t reg_offs_len) +{ + void __iomem *reg_base; + size_t i; + + reg_base = of_iomap(np, 0); + if (!reg_base) + panic("%s: failed to map registers\n", __func__); + + for (i = 0; i < reg_offs_len; ++i) { + void __iomem *reg = reg_base + reg_offs[i]; + u32 val; + + /* Modify only gate clock registers */ + if (reg_offs[i] < GATE_OFF_START || reg_offs[i] > GATE_OFF_END) + continue; + + val = readl(reg); + val |= GATE_MANUAL; + val &= ~GATE_ENABLE_HWACG; + writel(val, reg); + } + + iounmap(reg_base); +} + +/* ---- CMU_TOP ------------------------------------------------------------- */ + +/* Register Offset definitions for CMU_TOP (0x120e0000) */ +#define PLL_LOCKTIME_PLL_MMC 0x0000 +#define PLL_LOCKTIME_PLL_SHARED0 0x0004 +#define PLL_LOCKTIME_PLL_SHARED1 0x0008 +#define PLL_CON0_PLL_MMC 0x0100 +#define PLL_CON3_PLL_MMC 0x010c +#define PLL_CON0_PLL_SHARED0 0x0140 +#define PLL_CON3_PLL_SHARED0 0x014c +#define PLL_CON0_PLL_SHARED1 0x0180 +#define PLL_CON3_PLL_SHARED1 0x018c +#define CLK_CON_MUX_MUX_CLKCMU_CORE_BUS 0x1014 +#define CLK_CON_MUX_MUX_CLKCMU_CORE_CCI 0x1018 +#define CLK_CON_MUX_MUX_CLKCMU_CORE_MMC_EMBD 0x101c +#define CLK_CON_MUX_MUX_CLKCMU_CORE_SSS 0x1020 +#define CLK_CON_MUX_MUX_CLKCMU_DPU 0x1034 +#define CLK_CON_MUX_MUX_CLKCMU_HSI_BUS 0x103c +#define CLK_CON_MUX_MUX_CLKCMU_HSI_MMC_CARD 0x1040 +#define CLK_CON_MUX_MUX_CLKCMU_HSI_USB20DRD 0x1044 +#define CLK_CON_MUX_MUX_CLKCMU_PERI_BUS 0x1070 +#define CLK_CON_MUX_MUX_CLKCMU_PERI_IP 0x1074 +#define CLK_CON_MUX_MUX_CLKCMU_PERI_UART 0x1078 +#define CLK_CON_DIV_CLKCMU_CORE_BUS 0x1820 +#define CLK_CON_DIV_CLKCMU_CORE_CCI 0x1824 +#define CLK_CON_DIV_CLKCMU_CORE_MMC_EMBD 0x1828 +#define CLK_CON_DIV_CLKCMU_CORE_SSS 0x182c +#define CLK_CON_DIV_CLKCMU_DPU 0x1840 +#define CLK_CON_DIV_CLKCMU_HSI_BUS 0x1848 +#define CLK_CON_DIV_CLKCMU_HSI_MMC_CARD 0x184c +#define CLK_CON_DIV_CLKCMU_HSI_USB20DRD 0x1850 +#define CLK_CON_DIV_CLKCMU_PERI_BUS 0x187c +#define CLK_CON_DIV_CLKCMU_PERI_IP 0x1880 +#define CLK_CON_DIV_CLKCMU_PERI_UART 0x1884 +#define CLK_CON_DIV_PLL_SHARED0_DIV2 0x188c +#define CLK_CON_DIV_PLL_SHARED0_DIV3 0x1890 +#define CLK_CON_DIV_PLL_SHARED0_DIV4 0x1894 +#define CLK_CON_DIV_PLL_SHARED1_DIV2 0x1898 +#define CLK_CON_DIV_PLL_SHARED1_DIV3 0x189c +#define CLK_CON_DIV_PLL_SHARED1_DIV4 0x18a0 +#define CLK_CON_GAT_GATE_CLKCMU_CORE_BUS 0x201c +#define CLK_CON_GAT_GATE_CLKCMU_CORE_CCI 0x2020 +#define CLK_CON_GAT_GATE_CLKCMU_CORE_MMC_EMBD 0x2024 +#define CLK_CON_GAT_GATE_CLKCMU_CORE_SSS 0x2028 +#define CLK_CON_GAT_GATE_CLKCMU_DPU 0x203c +#define CLK_CON_GAT_GATE_CLKCMU_HSI_BUS 0x2044 +#define CLK_CON_GAT_GATE_CLKCMU_HSI_MMC_CARD 0x2048 +#define CLK_CON_GAT_GATE_CLKCMU_HSI_USB20DRD 0x204c +#define CLK_CON_GAT_GATE_CLKCMU_PERI_BUS 0x2080 +#define CLK_CON_GAT_GATE_CLKCMU_PERI_IP 0x2084 +#define CLK_CON_GAT_GATE_CLKCMU_PERI_UART 0x2088 + +static const unsigned long top_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_MMC, + PLL_LOCKTIME_PLL_SHARED0, + PLL_LOCKTIME_PLL_SHARED1, + PLL_CON0_PLL_MMC, + PLL_CON3_PLL_MMC, + PLL_CON0_PLL_SHARED0, + PLL_CON3_PLL_SHARED0, + PLL_CON0_PLL_SHARED1, + PLL_CON3_PLL_SHARED1, + CLK_CON_MUX_MUX_CLKCMU_CORE_BUS, + CLK_CON_MUX_MUX_CLKCMU_CORE_CCI, + CLK_CON_MUX_MUX_CLKCMU_CORE_MMC_EMBD, + CLK_CON_MUX_MUX_CLKCMU_CORE_SSS, + CLK_CON_MUX_MUX_CLKCMU_DPU, + CLK_CON_MUX_MUX_CLKCMU_HSI_BUS, + CLK_CON_MUX_MUX_CLKCMU_HSI_MMC_CARD, + CLK_CON_MUX_MUX_CLKCMU_HSI_USB20DRD, + CLK_CON_MUX_MUX_CLKCMU_PERI_BUS, + CLK_CON_MUX_MUX_CLKCMU_PERI_IP, + CLK_CON_MUX_MUX_CLKCMU_PERI_UART, + CLK_CON_DIV_CLKCMU_CORE_BUS, + CLK_CON_DIV_CLKCMU_CORE_CCI, + CLK_CON_DIV_CLKCMU_CORE_MMC_EMBD, + CLK_CON_DIV_CLKCMU_CORE_SSS, + CLK_CON_DIV_CLKCMU_DPU, + CLK_CON_DIV_CLKCMU_HSI_BUS, + CLK_CON_DIV_CLKCMU_HSI_MMC_CARD, + CLK_CON_DIV_CLKCMU_HSI_USB20DRD, + CLK_CON_DIV_CLKCMU_PERI_BUS, + CLK_CON_DIV_CLKCMU_PERI_IP, + CLK_CON_DIV_CLKCMU_PERI_UART, + CLK_CON_DIV_PLL_SHARED0_DIV2, + CLK_CON_DIV_PLL_SHARED0_DIV3, + CLK_CON_DIV_PLL_SHARED0_DIV4, + CLK_CON_DIV_PLL_SHARED1_DIV2, + CLK_CON_DIV_PLL_SHARED1_DIV3, + CLK_CON_DIV_PLL_SHARED1_DIV4, + CLK_CON_GAT_GATE_CLKCMU_CORE_BUS, + CLK_CON_GAT_GATE_CLKCMU_CORE_CCI, + CLK_CON_GAT_GATE_CLKCMU_CORE_MMC_EMBD, + CLK_CON_GAT_GATE_CLKCMU_CORE_SSS, + CLK_CON_GAT_GATE_CLKCMU_DPU, + CLK_CON_GAT_GATE_CLKCMU_HSI_BUS, + CLK_CON_GAT_GATE_CLKCMU_HSI_MMC_CARD, + CLK_CON_GAT_GATE_CLKCMU_HSI_USB20DRD, + CLK_CON_GAT_GATE_CLKCMU_PERI_BUS, + CLK_CON_GAT_GATE_CLKCMU_PERI_IP, + CLK_CON_GAT_GATE_CLKCMU_PERI_UART, +}; + +/* + * Do not provide PLL tables to core PLLs, as MANUAL_PLL_CTRL bit is not set + * for those PLLs by default, so set_rate operation would fail. + */ +static const struct samsung_pll_clock top_pll_clks[] __initconst = { + /* CMU_TOP_PURECLKCOMP */ + PLL(pll_0822x, CLK_FOUT_SHARED0_PLL, "fout_shared0_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED0, PLL_CON3_PLL_SHARED0, + NULL), + PLL(pll_0822x, CLK_FOUT_SHARED1_PLL, "fout_shared1_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED1, PLL_CON3_PLL_SHARED1, + NULL), + PLL(pll_0831x, CLK_FOUT_MMC_PLL, "fout_mmc_pll", "oscclk", + PLL_LOCKTIME_PLL_MMC, PLL_CON3_PLL_MMC, NULL), +}; + +/* List of parent clocks for Muxes in CMU_TOP */ +PNAME(mout_shared0_pll_p) = { "oscclk", "fout_shared0_pll" }; +PNAME(mout_shared1_pll_p) = { "oscclk", "fout_shared1_pll" }; +PNAME(mout_mmc_pll_p) = { "oscclk", "fout_mmc_pll" }; +/* List of parent clocks for Muxes in CMU_TOP: for CMU_CORE */ +PNAME(mout_core_bus_p) = { "dout_shared1_div2", "dout_shared0_div3", + "dout_shared1_div3", "dout_shared0_div4" }; +PNAME(mout_core_cci_p) = { "dout_shared0_div2", "dout_shared1_div2", + "dout_shared0_div3", "dout_shared1_div3" }; +PNAME(mout_core_mmc_embd_p) = { "oscclk", "dout_shared0_div2", + "dout_shared1_div2", "dout_shared0_div3", + "dout_shared1_div3", "mout_mmc_pll", + "oscclk", "oscclk" }; +PNAME(mout_core_sss_p) = { "dout_shared0_div3", "dout_shared1_div3", + "dout_shared0_div4", "dout_shared1_div4" }; +/* List of parent clocks for Muxes in CMU_TOP: for CMU_HSI */ +PNAME(mout_hsi_bus_p) = { "dout_shared0_div2", "dout_shared1_div2" }; +PNAME(mout_hsi_mmc_card_p) = { "oscclk", "dout_shared0_div2", + "dout_shared1_div2", "dout_shared0_div3", + "dout_shared1_div3", "mout_mmc_pll", + "oscclk", "oscclk" }; +PNAME(mout_hsi_usb20drd_p) = { "oscclk", "dout_shared0_div4", + "dout_shared1_div4", "oscclk" }; +/* List of parent clocks for Muxes in CMU_TOP: for CMU_PERI */ +PNAME(mout_peri_bus_p) = { "dout_shared0_div4", "dout_shared1_div4" }; +PNAME(mout_peri_uart_p) = { "oscclk", "dout_shared0_div4", + "dout_shared1_div4", "oscclk" }; +PNAME(mout_peri_ip_p) = { "oscclk", "dout_shared0_div4", + "dout_shared1_div4", "oscclk" }; + +/* List of parent clocks for Muxes in CMU_TOP: for CMU_DPU */ +PNAME(mout_dpu_p) = { "dout_shared0_div3", "dout_shared1_div3", + "dout_shared0_div4", "dout_shared1_div4" }; + +static const struct samsung_mux_clock top_mux_clks[] __initconst = { + /* CMU_TOP_PURECLKCOMP */ + MUX(CLK_MOUT_SHARED0_PLL, "mout_shared0_pll", mout_shared0_pll_p, + PLL_CON0_PLL_SHARED0, 4, 1), + MUX(CLK_MOUT_SHARED1_PLL, "mout_shared1_pll", mout_shared1_pll_p, + PLL_CON0_PLL_SHARED1, 4, 1), + MUX(CLK_MOUT_MMC_PLL, "mout_mmc_pll", mout_mmc_pll_p, + PLL_CON0_PLL_MMC, 4, 1), + + /* CORE */ + MUX(CLK_MOUT_CORE_BUS, "mout_core_bus", mout_core_bus_p, + CLK_CON_MUX_MUX_CLKCMU_CORE_BUS, 0, 2), + MUX(CLK_MOUT_CORE_CCI, "mout_core_cci", mout_core_cci_p, + CLK_CON_MUX_MUX_CLKCMU_CORE_CCI, 0, 2), + MUX(CLK_MOUT_CORE_MMC_EMBD, "mout_core_mmc_embd", mout_core_mmc_embd_p, + CLK_CON_MUX_MUX_CLKCMU_CORE_MMC_EMBD, 0, 3), + MUX(CLK_MOUT_CORE_SSS, "mout_core_sss", mout_core_sss_p, + CLK_CON_MUX_MUX_CLKCMU_CORE_SSS, 0, 2), + + /* DPU */ + MUX(CLK_MOUT_DPU, "mout_dpu", mout_dpu_p, + CLK_CON_MUX_MUX_CLKCMU_DPU, 0, 2), + + /* HSI */ + MUX(CLK_MOUT_HSI_BUS, "mout_hsi_bus", mout_hsi_bus_p, + CLK_CON_MUX_MUX_CLKCMU_HSI_BUS, 0, 1), + MUX(CLK_MOUT_HSI_MMC_CARD, "mout_hsi_mmc_card", mout_hsi_mmc_card_p, + CLK_CON_MUX_MUX_CLKCMU_HSI_MMC_CARD, 0, 3), + MUX(CLK_MOUT_HSI_USB20DRD, "mout_hsi_usb20drd", mout_hsi_usb20drd_p, + CLK_CON_MUX_MUX_CLKCMU_HSI_USB20DRD, 0, 2), + + /* PERI */ + MUX(CLK_MOUT_PERI_BUS, "mout_peri_bus", mout_peri_bus_p, + CLK_CON_MUX_MUX_CLKCMU_PERI_BUS, 0, 1), + MUX(CLK_MOUT_PERI_UART, "mout_peri_uart", mout_peri_uart_p, + CLK_CON_MUX_MUX_CLKCMU_PERI_UART, 0, 2), + MUX(CLK_MOUT_PERI_IP, "mout_peri_ip", mout_peri_ip_p, + CLK_CON_MUX_MUX_CLKCMU_PERI_IP, 0, 2), +}; + +static const struct samsung_div_clock top_div_clks[] __initconst = { + /* CMU_TOP_PURECLKCOMP */ + DIV(CLK_DOUT_SHARED0_DIV3, "dout_shared0_div3", "mout_shared0_pll", + CLK_CON_DIV_PLL_SHARED0_DIV3, 0, 2), + DIV(CLK_DOUT_SHARED0_DIV2, "dout_shared0_div2", "mout_shared0_pll", + CLK_CON_DIV_PLL_SHARED0_DIV2, 0, 1), + DIV(CLK_DOUT_SHARED1_DIV3, "dout_shared1_div3", "mout_shared1_pll", + CLK_CON_DIV_PLL_SHARED1_DIV3, 0, 2), + DIV(CLK_DOUT_SHARED1_DIV2, "dout_shared1_div2", "mout_shared1_pll", + CLK_CON_DIV_PLL_SHARED1_DIV2, 0, 1), + DIV(CLK_DOUT_SHARED0_DIV4, "dout_shared0_div4", "dout_shared0_div2", + CLK_CON_DIV_PLL_SHARED0_DIV4, 0, 1), + DIV(CLK_DOUT_SHARED1_DIV4, "dout_shared1_div4", "dout_shared1_div2", + CLK_CON_DIV_PLL_SHARED1_DIV4, 0, 1), + + /* CORE */ + DIV(CLK_DOUT_CORE_BUS, "dout_core_bus", "gout_core_bus", + CLK_CON_DIV_CLKCMU_CORE_BUS, 0, 4), + DIV(CLK_DOUT_CORE_CCI, "dout_core_cci", "gout_core_cci", + CLK_CON_DIV_CLKCMU_CORE_CCI, 0, 4), + DIV(CLK_DOUT_CORE_MMC_EMBD, "dout_core_mmc_embd", "gout_core_mmc_embd", + CLK_CON_DIV_CLKCMU_CORE_MMC_EMBD, 0, 9), + DIV(CLK_DOUT_CORE_SSS, "dout_core_sss", "gout_core_sss", + CLK_CON_DIV_CLKCMU_CORE_SSS, 0, 4), + + /* DPU */ + DIV(CLK_DOUT_DPU, "dout_dpu", "gout_dpu", + CLK_CON_DIV_CLKCMU_DPU, 0, 4), + + /* HSI */ + DIV(CLK_DOUT_HSI_BUS, "dout_hsi_bus", "gout_hsi_bus", + CLK_CON_DIV_CLKCMU_HSI_BUS, 0, 4), + DIV(CLK_DOUT_HSI_MMC_CARD, "dout_hsi_mmc_card", "gout_hsi_mmc_card", + CLK_CON_DIV_CLKCMU_HSI_MMC_CARD, 0, 9), + DIV(CLK_DOUT_HSI_USB20DRD, "dout_hsi_usb20drd", "gout_hsi_usb20drd", + CLK_CON_DIV_CLKCMU_HSI_USB20DRD, 0, 4), + + /* PERI */ + DIV(CLK_DOUT_PERI_BUS, "dout_peri_bus", "gout_peri_bus", + CLK_CON_DIV_CLKCMU_PERI_BUS, 0, 4), + DIV(CLK_DOUT_PERI_UART, "dout_peri_uart", "gout_peri_uart", + CLK_CON_DIV_CLKCMU_PERI_UART, 0, 4), + DIV(CLK_DOUT_PERI_IP, "dout_peri_ip", "gout_peri_ip", + CLK_CON_DIV_CLKCMU_PERI_IP, 0, 4), +}; + +static const struct samsung_gate_clock top_gate_clks[] __initconst = { + /* CORE */ + GATE(CLK_GOUT_CORE_BUS, "gout_core_bus", "mout_core_bus", + CLK_CON_GAT_GATE_CLKCMU_CORE_BUS, 21, 0, 0), + GATE(CLK_GOUT_CORE_CCI, "gout_core_cci", "mout_core_cci", + CLK_CON_GAT_GATE_CLKCMU_CORE_CCI, 21, 0, 0), + GATE(CLK_GOUT_CORE_MMC_EMBD, "gout_core_mmc_embd", "mout_core_mmc_embd", + CLK_CON_GAT_GATE_CLKCMU_CORE_MMC_EMBD, 21, 0, 0), + GATE(CLK_GOUT_CORE_SSS, "gout_core_sss", "mout_core_sss", + CLK_CON_GAT_GATE_CLKCMU_CORE_SSS, 21, 0, 0), + + /* DPU */ + GATE(CLK_GOUT_DPU, "gout_dpu", "mout_dpu", + CLK_CON_GAT_GATE_CLKCMU_DPU, 21, 0, 0), + + /* HSI */ + GATE(CLK_GOUT_HSI_BUS, "gout_hsi_bus", "mout_hsi_bus", + CLK_CON_GAT_GATE_CLKCMU_HSI_BUS, 21, 0, 0), + GATE(CLK_GOUT_HSI_MMC_CARD, "gout_hsi_mmc_card", "mout_hsi_mmc_card", + CLK_CON_GAT_GATE_CLKCMU_HSI_MMC_CARD, 21, 0, 0), + GATE(CLK_GOUT_HSI_USB20DRD, "gout_hsi_usb20drd", "mout_hsi_usb20drd", + CLK_CON_GAT_GATE_CLKCMU_HSI_USB20DRD, 21, 0, 0), + + /* PERI */ + GATE(CLK_GOUT_PERI_BUS, "gout_peri_bus", "mout_peri_bus", + CLK_CON_GAT_GATE_CLKCMU_PERI_BUS, 21, 0, 0), + GATE(CLK_GOUT_PERI_UART, "gout_peri_uart", "mout_peri_uart", + CLK_CON_GAT_GATE_CLKCMU_PERI_UART, 21, 0, 0), + GATE(CLK_GOUT_PERI_IP, "gout_peri_ip", "mout_peri_ip", + CLK_CON_GAT_GATE_CLKCMU_PERI_IP, 21, 0, 0), +}; + +static const struct samsung_cmu_info top_cmu_info __initconst = { + .pll_clks = top_pll_clks, + .nr_pll_clks = ARRAY_SIZE(top_pll_clks), + .mux_clks = top_mux_clks, + .nr_mux_clks = ARRAY_SIZE(top_mux_clks), + .div_clks = top_div_clks, + .nr_div_clks = ARRAY_SIZE(top_div_clks), + .gate_clks = top_gate_clks, + .nr_gate_clks = ARRAY_SIZE(top_gate_clks), + .nr_clk_ids = TOP_NR_CLK, + .clk_regs = top_clk_regs, + .nr_clk_regs = ARRAY_SIZE(top_clk_regs), +}; + +static void __init exynos850_cmu_top_init(struct device_node *np) +{ + exynos850_init_clocks(np, top_clk_regs, ARRAY_SIZE(top_clk_regs)); + samsung_cmu_register_one(np, &top_cmu_info); +} + +CLK_OF_DECLARE(exynos850_cmu_top, "samsung,exynos850-cmu-top", + exynos850_cmu_top_init); + +/* ---- CMU_HSI ------------------------------------------------------------- */ + +/* Register Offset definitions for CMU_HSI (0x13400000) */ +#define PLL_CON0_MUX_CLKCMU_HSI_BUS_USER 0x0600 +#define PLL_CON0_MUX_CLKCMU_HSI_MMC_CARD_USER 0x0610 +#define PLL_CON0_MUX_CLKCMU_HSI_USB20DRD_USER 0x0620 +#define CLK_CON_MUX_MUX_CLK_HSI_RTC 0x1000 +#define CLK_CON_GAT_HSI_USB20DRD_TOP_I_RTC_CLK__ALV 0x2008 +#define CLK_CON_GAT_HSI_USB20DRD_TOP_I_REF_CLK_50 0x200c +#define CLK_CON_GAT_HSI_USB20DRD_TOP_I_PHY_REFCLK_26 0x2010 +#define CLK_CON_GAT_GOUT_HSI_GPIO_HSI_PCLK 0x2018 +#define CLK_CON_GAT_GOUT_HSI_MMC_CARD_I_ACLK 0x2024 +#define CLK_CON_GAT_GOUT_HSI_MMC_CARD_SDCLKIN 0x2028 +#define CLK_CON_GAT_GOUT_HSI_SYSREG_HSI_PCLK 0x2038 +#define CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_ACLK_PHYCTRL_20 0x203c +#define CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_BUS_CLK_EARLY 0x2040 + +static const unsigned long hsi_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_HSI_BUS_USER, + PLL_CON0_MUX_CLKCMU_HSI_MMC_CARD_USER, + PLL_CON0_MUX_CLKCMU_HSI_USB20DRD_USER, + CLK_CON_MUX_MUX_CLK_HSI_RTC, + CLK_CON_GAT_HSI_USB20DRD_TOP_I_RTC_CLK__ALV, + CLK_CON_GAT_HSI_USB20DRD_TOP_I_REF_CLK_50, + CLK_CON_GAT_HSI_USB20DRD_TOP_I_PHY_REFCLK_26, + CLK_CON_GAT_GOUT_HSI_GPIO_HSI_PCLK, + CLK_CON_GAT_GOUT_HSI_MMC_CARD_I_ACLK, + CLK_CON_GAT_GOUT_HSI_MMC_CARD_SDCLKIN, + CLK_CON_GAT_GOUT_HSI_SYSREG_HSI_PCLK, + CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_ACLK_PHYCTRL_20, + CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_BUS_CLK_EARLY, +}; + +/* List of parent clocks for Muxes in CMU_PERI */ +PNAME(mout_hsi_bus_user_p) = { "oscclk", "dout_hsi_bus" }; +PNAME(mout_hsi_mmc_card_user_p) = { "oscclk", "dout_hsi_mmc_card" }; +PNAME(mout_hsi_usb20drd_user_p) = { "oscclk", "dout_hsi_usb20drd" }; +PNAME(mout_hsi_rtc_p) = { "rtcclk", "oscclk" }; + +static const struct samsung_mux_clock hsi_mux_clks[] __initconst = { + MUX(CLK_MOUT_HSI_BUS_USER, "mout_hsi_bus_user", mout_hsi_bus_user_p, + PLL_CON0_MUX_CLKCMU_HSI_BUS_USER, 4, 1), + MUX_F(CLK_MOUT_HSI_MMC_CARD_USER, "mout_hsi_mmc_card_user", + mout_hsi_mmc_card_user_p, PLL_CON0_MUX_CLKCMU_HSI_MMC_CARD_USER, + 4, 1, CLK_SET_RATE_PARENT, 0), + MUX(CLK_MOUT_HSI_USB20DRD_USER, "mout_hsi_usb20drd_user", + mout_hsi_usb20drd_user_p, PLL_CON0_MUX_CLKCMU_HSI_USB20DRD_USER, + 4, 1), + MUX(CLK_MOUT_HSI_RTC, "mout_hsi_rtc", mout_hsi_rtc_p, + CLK_CON_MUX_MUX_CLK_HSI_RTC, 0, 1), +}; + +static const struct samsung_gate_clock hsi_gate_clks[] __initconst = { + GATE(CLK_GOUT_USB_RTC_CLK, "gout_usb_rtc", "mout_hsi_rtc", + CLK_CON_GAT_HSI_USB20DRD_TOP_I_RTC_CLK__ALV, 21, 0, 0), + GATE(CLK_GOUT_USB_REF_CLK, "gout_usb_ref", "mout_hsi_usb20drd_user", + CLK_CON_GAT_HSI_USB20DRD_TOP_I_REF_CLK_50, 21, 0, 0), + GATE(CLK_GOUT_USB_PHY_REF_CLK, "gout_usb_phy_ref", "oscclk", + CLK_CON_GAT_HSI_USB20DRD_TOP_I_PHY_REFCLK_26, 21, 0, 0), + GATE(CLK_GOUT_GPIO_HSI_PCLK, "gout_gpio_hsi_pclk", "mout_hsi_bus_user", + CLK_CON_GAT_GOUT_HSI_GPIO_HSI_PCLK, 21, 0, 0), + GATE(CLK_GOUT_MMC_CARD_ACLK, "gout_mmc_card_aclk", "mout_hsi_bus_user", + CLK_CON_GAT_GOUT_HSI_MMC_CARD_I_ACLK, 21, 0, 0), + GATE(CLK_GOUT_MMC_CARD_SDCLKIN, "gout_mmc_card_sdclkin", + "mout_hsi_mmc_card_user", + CLK_CON_GAT_GOUT_HSI_MMC_CARD_SDCLKIN, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_SYSREG_HSI_PCLK, "gout_sysreg_hsi_pclk", + "mout_hsi_bus_user", + CLK_CON_GAT_GOUT_HSI_SYSREG_HSI_PCLK, 21, 0, 0), + GATE(CLK_GOUT_USB_PHY_ACLK, "gout_usb_phy_aclk", "mout_hsi_bus_user", + CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_ACLK_PHYCTRL_20, 21, 0, 0), + GATE(CLK_GOUT_USB_BUS_EARLY_CLK, "gout_usb_bus_early", + "mout_hsi_bus_user", + CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_BUS_CLK_EARLY, 21, 0, 0), +}; + +static const struct samsung_cmu_info hsi_cmu_info __initconst = { + .mux_clks = hsi_mux_clks, + .nr_mux_clks = ARRAY_SIZE(hsi_mux_clks), + .gate_clks = hsi_gate_clks, + .nr_gate_clks = ARRAY_SIZE(hsi_gate_clks), + .nr_clk_ids = HSI_NR_CLK, + .clk_regs = hsi_clk_regs, + .nr_clk_regs = ARRAY_SIZE(hsi_clk_regs), + .clk_name = "dout_hsi_bus", +}; + +/* ---- CMU_PERI ------------------------------------------------------------ */ + +/* Register Offset definitions for CMU_PERI (0x10030000) */ +#define PLL_CON0_MUX_CLKCMU_PERI_BUS_USER 0x0600 +#define PLL_CON0_MUX_CLKCMU_PERI_HSI2C_USER 0x0610 +#define PLL_CON0_MUX_CLKCMU_PERI_SPI_USER 0x0620 +#define PLL_CON0_MUX_CLKCMU_PERI_UART_USER 0x0630 +#define CLK_CON_DIV_DIV_CLK_PERI_HSI2C_0 0x1800 +#define CLK_CON_DIV_DIV_CLK_PERI_HSI2C_1 0x1804 +#define CLK_CON_DIV_DIV_CLK_PERI_HSI2C_2 0x1808 +#define CLK_CON_DIV_DIV_CLK_PERI_SPI_0 0x180c +#define CLK_CON_GAT_GATE_CLK_PERI_HSI2C_0 0x200c +#define CLK_CON_GAT_GATE_CLK_PERI_HSI2C_1 0x2010 +#define CLK_CON_GAT_GATE_CLK_PERI_HSI2C_2 0x2014 +#define CLK_CON_GAT_GOUT_PERI_GPIO_PERI_PCLK 0x2020 +#define CLK_CON_GAT_GOUT_PERI_HSI2C_0_IPCLK 0x2024 +#define CLK_CON_GAT_GOUT_PERI_HSI2C_0_PCLK 0x2028 +#define CLK_CON_GAT_GOUT_PERI_HSI2C_1_IPCLK 0x202c +#define CLK_CON_GAT_GOUT_PERI_HSI2C_1_PCLK 0x2030 +#define CLK_CON_GAT_GOUT_PERI_HSI2C_2_IPCLK 0x2034 +#define CLK_CON_GAT_GOUT_PERI_HSI2C_2_PCLK 0x2038 +#define CLK_CON_GAT_GOUT_PERI_I2C_0_PCLK 0x203c +#define CLK_CON_GAT_GOUT_PERI_I2C_1_PCLK 0x2040 +#define CLK_CON_GAT_GOUT_PERI_I2C_2_PCLK 0x2044 +#define CLK_CON_GAT_GOUT_PERI_I2C_3_PCLK 0x2048 +#define CLK_CON_GAT_GOUT_PERI_I2C_4_PCLK 0x204c +#define CLK_CON_GAT_GOUT_PERI_I2C_5_PCLK 0x2050 +#define CLK_CON_GAT_GOUT_PERI_I2C_6_PCLK 0x2054 +#define CLK_CON_GAT_GOUT_PERI_MCT_PCLK 0x205c +#define CLK_CON_GAT_GOUT_PERI_PWM_MOTOR_PCLK 0x2064 +#define CLK_CON_GAT_GOUT_PERI_SPI_0_IPCLK 0x209c +#define CLK_CON_GAT_GOUT_PERI_SPI_0_PCLK 0x20a0 +#define CLK_CON_GAT_GOUT_PERI_SYSREG_PERI_PCLK 0x20a4 +#define CLK_CON_GAT_GOUT_PERI_UART_IPCLK 0x20a8 +#define CLK_CON_GAT_GOUT_PERI_UART_PCLK 0x20ac +#define CLK_CON_GAT_GOUT_PERI_WDT_0_PCLK 0x20b0 +#define CLK_CON_GAT_GOUT_PERI_WDT_1_PCLK 0x20b4 + +static const unsigned long peri_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_PERI_BUS_USER, + PLL_CON0_MUX_CLKCMU_PERI_HSI2C_USER, + PLL_CON0_MUX_CLKCMU_PERI_SPI_USER, + PLL_CON0_MUX_CLKCMU_PERI_UART_USER, + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_0, + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_1, + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_2, + CLK_CON_DIV_DIV_CLK_PERI_SPI_0, + CLK_CON_GAT_GATE_CLK_PERI_HSI2C_0, + CLK_CON_GAT_GATE_CLK_PERI_HSI2C_1, + CLK_CON_GAT_GATE_CLK_PERI_HSI2C_2, + CLK_CON_GAT_GOUT_PERI_GPIO_PERI_PCLK, + CLK_CON_GAT_GOUT_PERI_HSI2C_0_IPCLK, + CLK_CON_GAT_GOUT_PERI_HSI2C_0_PCLK, + CLK_CON_GAT_GOUT_PERI_HSI2C_1_IPCLK, + CLK_CON_GAT_GOUT_PERI_HSI2C_1_PCLK, + CLK_CON_GAT_GOUT_PERI_HSI2C_2_IPCLK, + CLK_CON_GAT_GOUT_PERI_HSI2C_2_PCLK, + CLK_CON_GAT_GOUT_PERI_I2C_0_PCLK, + CLK_CON_GAT_GOUT_PERI_I2C_1_PCLK, + CLK_CON_GAT_GOUT_PERI_I2C_2_PCLK, + CLK_CON_GAT_GOUT_PERI_I2C_3_PCLK, + CLK_CON_GAT_GOUT_PERI_I2C_4_PCLK, + CLK_CON_GAT_GOUT_PERI_I2C_5_PCLK, + CLK_CON_GAT_GOUT_PERI_I2C_6_PCLK, + CLK_CON_GAT_GOUT_PERI_MCT_PCLK, + CLK_CON_GAT_GOUT_PERI_PWM_MOTOR_PCLK, + CLK_CON_GAT_GOUT_PERI_SPI_0_IPCLK, + CLK_CON_GAT_GOUT_PERI_SPI_0_PCLK, + CLK_CON_GAT_GOUT_PERI_SYSREG_PERI_PCLK, + CLK_CON_GAT_GOUT_PERI_UART_IPCLK, + CLK_CON_GAT_GOUT_PERI_UART_PCLK, + CLK_CON_GAT_GOUT_PERI_WDT_0_PCLK, + CLK_CON_GAT_GOUT_PERI_WDT_1_PCLK, +}; + +/* List of parent clocks for Muxes in CMU_PERI */ +PNAME(mout_peri_bus_user_p) = { "oscclk", "dout_peri_bus" }; +PNAME(mout_peri_uart_user_p) = { "oscclk", "dout_peri_uart" }; +PNAME(mout_peri_hsi2c_user_p) = { "oscclk", "dout_peri_ip" }; +PNAME(mout_peri_spi_user_p) = { "oscclk", "dout_peri_ip" }; + +static const struct samsung_mux_clock peri_mux_clks[] __initconst = { + MUX(CLK_MOUT_PERI_BUS_USER, "mout_peri_bus_user", mout_peri_bus_user_p, + PLL_CON0_MUX_CLKCMU_PERI_BUS_USER, 4, 1), + MUX(CLK_MOUT_PERI_UART_USER, "mout_peri_uart_user", + mout_peri_uart_user_p, PLL_CON0_MUX_CLKCMU_PERI_UART_USER, 4, 1), + MUX(CLK_MOUT_PERI_HSI2C_USER, "mout_peri_hsi2c_user", + mout_peri_hsi2c_user_p, PLL_CON0_MUX_CLKCMU_PERI_HSI2C_USER, 4, 1), + MUX(CLK_MOUT_PERI_SPI_USER, "mout_peri_spi_user", mout_peri_spi_user_p, + PLL_CON0_MUX_CLKCMU_PERI_SPI_USER, 4, 1), +}; + +static const struct samsung_div_clock peri_div_clks[] __initconst = { + DIV(CLK_DOUT_PERI_HSI2C0, "dout_peri_hsi2c0", "gout_peri_hsi2c0", + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_0, 0, 5), + DIV(CLK_DOUT_PERI_HSI2C1, "dout_peri_hsi2c1", "gout_peri_hsi2c1", + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_1, 0, 5), + DIV(CLK_DOUT_PERI_HSI2C2, "dout_peri_hsi2c2", "gout_peri_hsi2c2", + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_2, 0, 5), + DIV(CLK_DOUT_PERI_SPI0, "dout_peri_spi0", "mout_peri_spi_user", + CLK_CON_DIV_DIV_CLK_PERI_SPI_0, 0, 5), +}; + +static const struct samsung_gate_clock peri_gate_clks[] __initconst = { + GATE(CLK_GOUT_PERI_HSI2C0, "gout_peri_hsi2c0", "mout_peri_hsi2c_user", + CLK_CON_GAT_GATE_CLK_PERI_HSI2C_0, 21, 0, 0), + GATE(CLK_GOUT_PERI_HSI2C1, "gout_peri_hsi2c1", "mout_peri_hsi2c_user", + CLK_CON_GAT_GATE_CLK_PERI_HSI2C_1, 21, 0, 0), + GATE(CLK_GOUT_PERI_HSI2C2, "gout_peri_hsi2c2", "mout_peri_hsi2c_user", + CLK_CON_GAT_GATE_CLK_PERI_HSI2C_2, 21, 0, 0), + GATE(CLK_GOUT_HSI2C0_IPCLK, "gout_hsi2c0_ipclk", "dout_peri_hsi2c0", + CLK_CON_GAT_GOUT_PERI_HSI2C_0_IPCLK, 21, 0, 0), + GATE(CLK_GOUT_HSI2C0_PCLK, "gout_hsi2c0_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_HSI2C_0_PCLK, 21, 0, 0), + GATE(CLK_GOUT_HSI2C1_IPCLK, "gout_hsi2c1_ipclk", "dout_peri_hsi2c1", + CLK_CON_GAT_GOUT_PERI_HSI2C_1_IPCLK, 21, 0, 0), + GATE(CLK_GOUT_HSI2C1_PCLK, "gout_hsi2c1_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_HSI2C_1_PCLK, 21, 0, 0), + GATE(CLK_GOUT_HSI2C2_IPCLK, "gout_hsi2c2_ipclk", "dout_peri_hsi2c2", + CLK_CON_GAT_GOUT_PERI_HSI2C_2_IPCLK, 21, 0, 0), + GATE(CLK_GOUT_HSI2C2_PCLK, "gout_hsi2c2_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_HSI2C_2_PCLK, 21, 0, 0), + GATE(CLK_GOUT_I2C0_PCLK, "gout_i2c0_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_I2C_0_PCLK, 21, 0, 0), + GATE(CLK_GOUT_I2C1_PCLK, "gout_i2c1_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_I2C_1_PCLK, 21, 0, 0), + GATE(CLK_GOUT_I2C2_PCLK, "gout_i2c2_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_I2C_2_PCLK, 21, 0, 0), + GATE(CLK_GOUT_I2C3_PCLK, "gout_i2c3_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_I2C_3_PCLK, 21, 0, 0), + GATE(CLK_GOUT_I2C4_PCLK, "gout_i2c4_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_I2C_4_PCLK, 21, 0, 0), + GATE(CLK_GOUT_I2C5_PCLK, "gout_i2c5_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_I2C_5_PCLK, 21, 0, 0), + GATE(CLK_GOUT_I2C6_PCLK, "gout_i2c6_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_I2C_6_PCLK, 21, 0, 0), + GATE(CLK_GOUT_MCT_PCLK, "gout_mct_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_MCT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PWM_MOTOR_PCLK, "gout_pwm_motor_pclk", + "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_PWM_MOTOR_PCLK, 21, 0, 0), + GATE(CLK_GOUT_SPI0_IPCLK, "gout_spi0_ipclk", "dout_peri_spi0", + CLK_CON_GAT_GOUT_PERI_SPI_0_IPCLK, 21, 0, 0), + GATE(CLK_GOUT_SPI0_PCLK, "gout_spi0_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_SPI_0_PCLK, 21, 0, 0), + GATE(CLK_GOUT_SYSREG_PERI_PCLK, "gout_sysreg_peri_pclk", + "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_SYSREG_PERI_PCLK, 21, 0, 0), + GATE(CLK_GOUT_UART_IPCLK, "gout_uart_ipclk", "mout_peri_uart_user", + CLK_CON_GAT_GOUT_PERI_UART_IPCLK, 21, 0, 0), + GATE(CLK_GOUT_UART_PCLK, "gout_uart_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_UART_PCLK, 21, 0, 0), + GATE(CLK_GOUT_WDT0_PCLK, "gout_wdt0_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_WDT_0_PCLK, 21, 0, 0), + GATE(CLK_GOUT_WDT1_PCLK, "gout_wdt1_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_WDT_1_PCLK, 21, 0, 0), + GATE(CLK_GOUT_GPIO_PERI_PCLK, "gout_gpio_peri_pclk", + "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_GPIO_PERI_PCLK, 21, 0, 0), +}; + +static const struct samsung_cmu_info peri_cmu_info __initconst = { + .mux_clks = peri_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peri_mux_clks), + .div_clks = peri_div_clks, + .nr_div_clks = ARRAY_SIZE(peri_div_clks), + .gate_clks = peri_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peri_gate_clks), + .nr_clk_ids = PERI_NR_CLK, + .clk_regs = peri_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peri_clk_regs), + .clk_name = "dout_peri_bus", +}; + +/* ---- CMU_CORE ------------------------------------------------------------ */ + +/* Register Offset definitions for CMU_CORE (0x12000000) */ +#define PLL_CON0_MUX_CLKCMU_CORE_BUS_USER 0x0600 +#define PLL_CON0_MUX_CLKCMU_CORE_CCI_USER 0x0610 +#define PLL_CON0_MUX_CLKCMU_CORE_MMC_EMBD_USER 0x0620 +#define PLL_CON0_MUX_CLKCMU_CORE_SSS_USER 0x0630 +#define CLK_CON_MUX_MUX_CLK_CORE_GIC 0x1000 +#define CLK_CON_DIV_DIV_CLK_CORE_BUSP 0x1800 +#define CLK_CON_GAT_GOUT_CORE_CCI_550_ACLK 0x2038 +#define CLK_CON_GAT_GOUT_CORE_GIC_CLK 0x2040 +#define CLK_CON_GAT_GOUT_CORE_MMC_EMBD_I_ACLK 0x20e8 +#define CLK_CON_GAT_GOUT_CORE_MMC_EMBD_SDCLKIN 0x20ec +#define CLK_CON_GAT_GOUT_CORE_SSS_I_ACLK 0x2128 +#define CLK_CON_GAT_GOUT_CORE_SSS_I_PCLK 0x212c + +static const unsigned long core_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_CORE_BUS_USER, + PLL_CON0_MUX_CLKCMU_CORE_CCI_USER, + PLL_CON0_MUX_CLKCMU_CORE_MMC_EMBD_USER, + PLL_CON0_MUX_CLKCMU_CORE_SSS_USER, + CLK_CON_MUX_MUX_CLK_CORE_GIC, + CLK_CON_DIV_DIV_CLK_CORE_BUSP, + CLK_CON_GAT_GOUT_CORE_CCI_550_ACLK, + CLK_CON_GAT_GOUT_CORE_GIC_CLK, + CLK_CON_GAT_GOUT_CORE_MMC_EMBD_I_ACLK, + CLK_CON_GAT_GOUT_CORE_MMC_EMBD_SDCLKIN, + CLK_CON_GAT_GOUT_CORE_SSS_I_ACLK, + CLK_CON_GAT_GOUT_CORE_SSS_I_PCLK, +}; + +/* List of parent clocks for Muxes in CMU_CORE */ +PNAME(mout_core_bus_user_p) = { "oscclk", "dout_core_bus" }; +PNAME(mout_core_cci_user_p) = { "oscclk", "dout_core_cci" }; +PNAME(mout_core_mmc_embd_user_p) = { "oscclk", "dout_core_mmc_embd" }; +PNAME(mout_core_sss_user_p) = { "oscclk", "dout_core_sss" }; +PNAME(mout_core_gic_p) = { "dout_core_busp", "oscclk" }; + +static const struct samsung_mux_clock core_mux_clks[] __initconst = { + MUX(CLK_MOUT_CORE_BUS_USER, "mout_core_bus_user", mout_core_bus_user_p, + PLL_CON0_MUX_CLKCMU_CORE_BUS_USER, 4, 1), + MUX(CLK_MOUT_CORE_CCI_USER, "mout_core_cci_user", mout_core_cci_user_p, + PLL_CON0_MUX_CLKCMU_CORE_CCI_USER, 4, 1), + MUX_F(CLK_MOUT_CORE_MMC_EMBD_USER, "mout_core_mmc_embd_user", + mout_core_mmc_embd_user_p, PLL_CON0_MUX_CLKCMU_CORE_MMC_EMBD_USER, + 4, 1, CLK_SET_RATE_PARENT, 0), + MUX(CLK_MOUT_CORE_SSS_USER, "mout_core_sss_user", mout_core_sss_user_p, + PLL_CON0_MUX_CLKCMU_CORE_SSS_USER, 4, 1), + MUX(CLK_MOUT_CORE_GIC, "mout_core_gic", mout_core_gic_p, + CLK_CON_MUX_MUX_CLK_CORE_GIC, 0, 1), +}; + +static const struct samsung_div_clock core_div_clks[] __initconst = { + DIV(CLK_DOUT_CORE_BUSP, "dout_core_busp", "mout_core_bus_user", + CLK_CON_DIV_DIV_CLK_CORE_BUSP, 0, 2), +}; + +static const struct samsung_gate_clock core_gate_clks[] __initconst = { + GATE(CLK_GOUT_CCI_ACLK, "gout_cci_aclk", "mout_core_cci_user", + CLK_CON_GAT_GOUT_CORE_CCI_550_ACLK, 21, 0, 0), + GATE(CLK_GOUT_GIC_CLK, "gout_gic_clk", "mout_core_gic", + CLK_CON_GAT_GOUT_CORE_GIC_CLK, 21, 0, 0), + GATE(CLK_GOUT_MMC_EMBD_ACLK, "gout_mmc_embd_aclk", "dout_core_busp", + CLK_CON_GAT_GOUT_CORE_MMC_EMBD_I_ACLK, 21, 0, 0), + GATE(CLK_GOUT_MMC_EMBD_SDCLKIN, "gout_mmc_embd_sdclkin", + "mout_core_mmc_embd_user", CLK_CON_GAT_GOUT_CORE_MMC_EMBD_SDCLKIN, + 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_SSS_ACLK, "gout_sss_aclk", "mout_core_sss_user", + CLK_CON_GAT_GOUT_CORE_SSS_I_ACLK, 21, 0, 0), + GATE(CLK_GOUT_SSS_PCLK, "gout_sss_pclk", "dout_core_busp", + CLK_CON_GAT_GOUT_CORE_SSS_I_PCLK, 21, 0, 0), +}; + +static const struct samsung_cmu_info core_cmu_info __initconst = { + .mux_clks = core_mux_clks, + .nr_mux_clks = ARRAY_SIZE(core_mux_clks), + .div_clks = core_div_clks, + .nr_div_clks = ARRAY_SIZE(core_div_clks), + .gate_clks = core_gate_clks, + .nr_gate_clks = ARRAY_SIZE(core_gate_clks), + .nr_clk_ids = CORE_NR_CLK, + .clk_regs = core_clk_regs, + .nr_clk_regs = ARRAY_SIZE(core_clk_regs), + .clk_name = "dout_core_bus", +}; + +/* ---- CMU_DPU ------------------------------------------------------------- */ + +/* Register Offset definitions for CMU_DPU (0x13000000) */ +#define PLL_CON0_MUX_CLKCMU_DPU_USER 0x0600 +#define CLK_CON_DIV_DIV_CLK_DPU_BUSP 0x1800 +#define CLK_CON_GAT_CLK_DPU_CMU_DPU_PCLK 0x2004 +#define CLK_CON_GAT_GOUT_DPU_ACLK_DECON0 0x2010 +#define CLK_CON_GAT_GOUT_DPU_ACLK_DMA 0x2014 +#define CLK_CON_GAT_GOUT_DPU_ACLK_DPP 0x2018 +#define CLK_CON_GAT_GOUT_DPU_PPMU_ACLK 0x2028 +#define CLK_CON_GAT_GOUT_DPU_PPMU_PCLK 0x202c +#define CLK_CON_GAT_GOUT_DPU_SMMU_CLK 0x2038 +#define CLK_CON_GAT_GOUT_DPU_SYSREG_PCLK 0x203c + +static const unsigned long dpu_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_DPU_USER, + CLK_CON_DIV_DIV_CLK_DPU_BUSP, + CLK_CON_GAT_CLK_DPU_CMU_DPU_PCLK, + CLK_CON_GAT_GOUT_DPU_ACLK_DECON0, + CLK_CON_GAT_GOUT_DPU_ACLK_DMA, + CLK_CON_GAT_GOUT_DPU_ACLK_DPP, + CLK_CON_GAT_GOUT_DPU_PPMU_ACLK, + CLK_CON_GAT_GOUT_DPU_PPMU_PCLK, + CLK_CON_GAT_GOUT_DPU_SMMU_CLK, + CLK_CON_GAT_GOUT_DPU_SYSREG_PCLK, +}; + +/* List of parent clocks for Muxes in CMU_CORE */ +PNAME(mout_dpu_user_p) = { "oscclk", "dout_dpu" }; + +static const struct samsung_mux_clock dpu_mux_clks[] __initconst = { + MUX(CLK_MOUT_DPU_USER, "mout_dpu_user", mout_dpu_user_p, + PLL_CON0_MUX_CLKCMU_DPU_USER, 4, 1), +}; + +static const struct samsung_div_clock dpu_div_clks[] __initconst = { + DIV(CLK_DOUT_DPU_BUSP, "dout_dpu_busp", "mout_dpu_user", + CLK_CON_DIV_DIV_CLK_DPU_BUSP, 0, 3), +}; + +static const struct samsung_gate_clock dpu_gate_clks[] __initconst = { + GATE(CLK_GOUT_DPU_CMU_DPU_PCLK, "gout_dpu_cmu_dpu_pclk", + "dout_dpu_busp", CLK_CON_GAT_CLK_DPU_CMU_DPU_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_DECON0_ACLK, "gout_dpu_decon0_aclk", "mout_dpu_user", + CLK_CON_GAT_GOUT_DPU_ACLK_DECON0, 21, 0, 0), + GATE(CLK_GOUT_DPU_DMA_ACLK, "gout_dpu_dma_aclk", "mout_dpu_user", + CLK_CON_GAT_GOUT_DPU_ACLK_DMA, 21, 0, 0), + GATE(CLK_GOUT_DPU_DPP_ACLK, "gout_dpu_dpp_aclk", "mout_dpu_user", + CLK_CON_GAT_GOUT_DPU_ACLK_DPP, 21, 0, 0), + GATE(CLK_GOUT_DPU_PPMU_ACLK, "gout_dpu_ppmu_aclk", "mout_dpu_user", + CLK_CON_GAT_GOUT_DPU_PPMU_ACLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_PPMU_PCLK, "gout_dpu_ppmu_pclk", "dout_dpu_busp", + CLK_CON_GAT_GOUT_DPU_PPMU_PCLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_SMMU_CLK, "gout_dpu_smmu_clk", "mout_dpu_user", + CLK_CON_GAT_GOUT_DPU_SMMU_CLK, 21, 0, 0), + GATE(CLK_GOUT_DPU_SYSREG_PCLK, "gout_dpu_sysreg_pclk", "dout_dpu_busp", + CLK_CON_GAT_GOUT_DPU_SYSREG_PCLK, 21, 0, 0), +}; + +static const struct samsung_cmu_info dpu_cmu_info __initconst = { + .mux_clks = dpu_mux_clks, + .nr_mux_clks = ARRAY_SIZE(dpu_mux_clks), + .div_clks = dpu_div_clks, + .nr_div_clks = ARRAY_SIZE(dpu_div_clks), + .gate_clks = dpu_gate_clks, + .nr_gate_clks = ARRAY_SIZE(dpu_gate_clks), + .nr_clk_ids = DPU_NR_CLK, + .clk_regs = dpu_clk_regs, + .nr_clk_regs = ARRAY_SIZE(dpu_clk_regs), + .clk_name = "dout_dpu", +}; + +/* ---- platform_driver ----------------------------------------------------- */ + +static int __init exynos850_cmu_probe(struct platform_device *pdev) +{ + const struct samsung_cmu_info *info; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + info = of_device_get_match_data(dev); + exynos850_init_clocks(np, info->clk_regs, info->nr_clk_regs); + samsung_cmu_register_one(np, info); + + /* Keep bus clock running, so it's possible to access CMU registers */ + if (info->clk_name) { + struct clk *bus_clk; + + bus_clk = clk_get(dev, info->clk_name); + if (IS_ERR(bus_clk)) { + pr_err("%s: could not find bus clock %s; err = %ld\n", + __func__, info->clk_name, PTR_ERR(bus_clk)); + } else { + clk_prepare_enable(bus_clk); + } + } + + return 0; +} + +/* CMUs which belong to Power Domains and need runtime PM to be implemented */ +static const struct of_device_id exynos850_cmu_of_match[] = { + { + .compatible = "samsung,exynos850-cmu-hsi", + .data = &hsi_cmu_info, + }, { + .compatible = "samsung,exynos850-cmu-peri", + .data = &peri_cmu_info, + }, { + .compatible = "samsung,exynos850-cmu-core", + .data = &core_cmu_info, + }, { + .compatible = "samsung,exynos850-cmu-dpu", + .data = &dpu_cmu_info, + }, { + }, +}; + +static struct platform_driver exynos850_cmu_driver __refdata = { + .driver = { + .name = "exynos850-cmu", + .of_match_table = exynos850_cmu_of_match, + .suppress_bind_attrs = true, + }, + .probe = exynos850_cmu_probe, +}; + +static int __init exynos850_cmu_init(void) +{ + return platform_driver_register(&exynos850_cmu_driver); +} +core_initcall(exynos850_cmu_init); From 3270ffe89fe61490b28419cd474b6f12a5e63d65 Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Thu, 14 Oct 2021 19:53:45 +0000 Subject: [PATCH 35/39] clk: samsung: add support for CPU clocks Adds 'struct samsung_cpu_clock' and corresponding CPU clock registration function to the samsung common clk driver. This allows samsung clock drivers to register their CPU clocks with the samsung_cmu_register_one() API. Currently the exynos5433 apollo and atlas clks have their own custom init functions to handle registering their CPU clocks. With this patch we can drop their custom CLK_OF_DECLARE functions and directly call samsung_cmu_register_one(). Signed-off-by: Will McVicker Tested-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20211014195347.3635601-2-willmcvicker@google.com Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-cpu.c | 18 ++++++++++++++++++ drivers/clk/samsung/clk.c | 2 ++ drivers/clk/samsung/clk.h | 26 ++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index 00ef4d1b0888..7f20d9aedaa9 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -469,3 +469,21 @@ free_cpuclk: kfree(cpuclk); return ret; } + +void __init samsung_clk_register_cpu(struct samsung_clk_provider *ctx, + const struct samsung_cpu_clock *list, unsigned int nr_clk) +{ + unsigned int idx; + unsigned int num_cfgs; + struct clk_hw **hws = ctx->clk_data.hws; + + for (idx = 0; idx < nr_clk; idx++, list++) { + /* find count of configuration rates in cfg */ + for (num_cfgs = 0; list->cfg[num_cfgs].prate != 0; ) + num_cfgs++; + + exynos_register_cpu_clock(ctx, list->id, list->name, hws[list->parent_id], + hws[list->alt_parent_id], list->offset, list->cfg, num_cfgs, + list->flags); + } +} diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index 1949ae7851b2..336243c6f120 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -378,6 +378,8 @@ struct samsung_clk_provider * __init samsung_cmu_register_one( samsung_clk_extended_sleep_init(reg_base, cmu->clk_regs, cmu->nr_clk_regs, cmu->suspend_regs, cmu->nr_suspend_regs); + if (cmu->cpu_clks) + samsung_clk_register_cpu(ctx, cmu->cpu_clks, cmu->nr_cpu_clks); samsung_clk_of_add_provider(np, ctx); diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index c1e1a6b2f499..26499e97275b 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -271,6 +271,27 @@ struct samsung_pll_clock { __PLL(_typ, _id, _name, _pname, CLK_GET_RATE_NOCACHE, _lock, \ _con, _rtable) +struct samsung_cpu_clock { + unsigned int id; + const char *name; + unsigned int parent_id; + unsigned int alt_parent_id; + unsigned long flags; + int offset; + const struct exynos_cpuclk_cfg_data *cfg; +}; + +#define CPU_CLK(_id, _name, _pid, _apid, _flags, _offset, _cfg) \ + { \ + .id = _id, \ + .name = _name, \ + .parent_id = _pid, \ + .alt_parent_id = _apid, \ + .flags = _flags, \ + .offset = _offset, \ + .cfg = _cfg, \ + } + struct samsung_clock_reg_cache { struct list_head node; void __iomem *reg_base; @@ -301,6 +322,9 @@ struct samsung_cmu_info { unsigned int nr_fixed_factor_clks; /* total number of clocks with IDs assigned*/ unsigned int nr_clk_ids; + /* list of cpu clocks and respective count */ + const struct samsung_cpu_clock *cpu_clks; + unsigned int nr_cpu_clks; /* list and number of clocks registers */ const unsigned long *clk_regs; @@ -350,6 +374,8 @@ extern void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx, extern void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx, const struct samsung_pll_clock *pll_list, unsigned int nr_clk, void __iomem *base); +extern void samsung_clk_register_cpu(struct samsung_clk_provider *ctx, + const struct samsung_cpu_clock *list, unsigned int nr_clk); extern struct samsung_clk_provider __init *samsung_cmu_register_one( struct device_node *, From 7d4901d96584764388568d68412b4b536312a8fb Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Thu, 14 Oct 2021 19:53:46 +0000 Subject: [PATCH 36/39] clk: samsung: exynos5433: update apollo and atlas clock probing Use the samsung common clk driver to initialize the apollo and atlas clocks. This removes their custom init functions and uses the samsung_cmu_register_one() instead. Signed-off-by: Will McVicker Tested-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20211014195347.3635601-3-willmcvicker@google.com Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-exynos5433.c | 120 +++++++++++---------------- 1 file changed, 48 insertions(+), 72 deletions(-) diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 38bfffc5e5b3..f9daae20f393 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -3675,44 +3675,32 @@ static const struct exynos_cpuclk_cfg_data exynos5433_apolloclk_d[] __initconst { 0 }, }; +static const struct samsung_cpu_clock apollo_cpu_clks[] __initconst = { + CPU_CLK(CLK_SCLK_APOLLO, "apolloclk", CLK_MOUT_APOLLO_PLL, + CLK_MOUT_BUS_PLL_APOLLO_USER, + CLK_CPU_HAS_E5433_REGS_LAYOUT, 0x200, + exynos5433_apolloclk_d), +}; + +static const struct samsung_cmu_info apollo_cmu_info __initconst = { + .pll_clks = apollo_pll_clks, + .nr_pll_clks = ARRAY_SIZE(apollo_pll_clks), + .mux_clks = apollo_mux_clks, + .nr_mux_clks = ARRAY_SIZE(apollo_mux_clks), + .div_clks = apollo_div_clks, + .nr_div_clks = ARRAY_SIZE(apollo_div_clks), + .gate_clks = apollo_gate_clks, + .nr_gate_clks = ARRAY_SIZE(apollo_gate_clks), + .cpu_clks = apollo_cpu_clks, + .nr_cpu_clks = ARRAY_SIZE(apollo_cpu_clks), + .nr_clk_ids = APOLLO_NR_CLK, + .clk_regs = apollo_clk_regs, + .nr_clk_regs = ARRAY_SIZE(apollo_clk_regs), +}; + static void __init exynos5433_cmu_apollo_init(struct device_node *np) { - void __iomem *reg_base; - struct samsung_clk_provider *ctx; - struct clk_hw **hws; - - reg_base = of_iomap(np, 0); - if (!reg_base) { - panic("%s: failed to map registers\n", __func__); - return; - } - - ctx = samsung_clk_init(np, reg_base, APOLLO_NR_CLK); - if (!ctx) { - panic("%s: unable to allocate ctx\n", __func__); - return; - } - - samsung_clk_register_pll(ctx, apollo_pll_clks, - ARRAY_SIZE(apollo_pll_clks), reg_base); - samsung_clk_register_mux(ctx, apollo_mux_clks, - ARRAY_SIZE(apollo_mux_clks)); - samsung_clk_register_div(ctx, apollo_div_clks, - ARRAY_SIZE(apollo_div_clks)); - samsung_clk_register_gate(ctx, apollo_gate_clks, - ARRAY_SIZE(apollo_gate_clks)); - - hws = ctx->clk_data.hws; - - exynos_register_cpu_clock(ctx, CLK_SCLK_APOLLO, "apolloclk", - hws[CLK_MOUT_APOLLO_PLL], hws[CLK_MOUT_BUS_PLL_APOLLO_USER], 0x200, - exynos5433_apolloclk_d, ARRAY_SIZE(exynos5433_apolloclk_d), - CLK_CPU_HAS_E5433_REGS_LAYOUT); - - samsung_clk_sleep_init(reg_base, apollo_clk_regs, - ARRAY_SIZE(apollo_clk_regs)); - - samsung_clk_of_add_provider(np, ctx); + samsung_cmu_register_one(np, &apollo_cmu_info); } CLK_OF_DECLARE(exynos5433_cmu_apollo, "samsung,exynos5433-cmu-apollo", exynos5433_cmu_apollo_init); @@ -3932,44 +3920,32 @@ static const struct exynos_cpuclk_cfg_data exynos5433_atlasclk_d[] __initconst = { 0 }, }; +static const struct samsung_cpu_clock atlas_cpu_clks[] __initconst = { + CPU_CLK(CLK_SCLK_ATLAS, "atlasclk", CLK_MOUT_ATLAS_PLL, + CLK_MOUT_BUS_PLL_ATLAS_USER, + CLK_CPU_HAS_E5433_REGS_LAYOUT, 0x200, + exynos5433_atlasclk_d), +}; + +static const struct samsung_cmu_info atlas_cmu_info __initconst = { + .pll_clks = atlas_pll_clks, + .nr_pll_clks = ARRAY_SIZE(atlas_pll_clks), + .mux_clks = atlas_mux_clks, + .nr_mux_clks = ARRAY_SIZE(atlas_mux_clks), + .div_clks = atlas_div_clks, + .nr_div_clks = ARRAY_SIZE(atlas_div_clks), + .gate_clks = atlas_gate_clks, + .nr_gate_clks = ARRAY_SIZE(atlas_gate_clks), + .cpu_clks = atlas_cpu_clks, + .nr_cpu_clks = ARRAY_SIZE(atlas_cpu_clks), + .nr_clk_ids = ATLAS_NR_CLK, + .clk_regs = atlas_clk_regs, + .nr_clk_regs = ARRAY_SIZE(atlas_clk_regs), +}; + static void __init exynos5433_cmu_atlas_init(struct device_node *np) { - void __iomem *reg_base; - struct samsung_clk_provider *ctx; - struct clk_hw **hws; - - reg_base = of_iomap(np, 0); - if (!reg_base) { - panic("%s: failed to map registers\n", __func__); - return; - } - - ctx = samsung_clk_init(np, reg_base, ATLAS_NR_CLK); - if (!ctx) { - panic("%s: unable to allocate ctx\n", __func__); - return; - } - - samsung_clk_register_pll(ctx, atlas_pll_clks, - ARRAY_SIZE(atlas_pll_clks), reg_base); - samsung_clk_register_mux(ctx, atlas_mux_clks, - ARRAY_SIZE(atlas_mux_clks)); - samsung_clk_register_div(ctx, atlas_div_clks, - ARRAY_SIZE(atlas_div_clks)); - samsung_clk_register_gate(ctx, atlas_gate_clks, - ARRAY_SIZE(atlas_gate_clks)); - - hws = ctx->clk_data.hws; - - exynos_register_cpu_clock(ctx, CLK_SCLK_ATLAS, "atlasclk", - hws[CLK_MOUT_ATLAS_PLL], hws[CLK_MOUT_BUS_PLL_ATLAS_USER], 0x200, - exynos5433_atlasclk_d, ARRAY_SIZE(exynos5433_atlasclk_d), - CLK_CPU_HAS_E5433_REGS_LAYOUT); - - samsung_clk_sleep_init(reg_base, atlas_clk_regs, - ARRAY_SIZE(atlas_clk_regs)); - - samsung_clk_of_add_provider(np, ctx); + samsung_cmu_register_one(np, &atlas_cmu_info); } CLK_OF_DECLARE(exynos5433_cmu_atlas, "samsung,exynos5433-cmu-atlas", exynos5433_cmu_atlas_init); From 9fe667af61d22fbeec823843962a77cd39993966 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Sep 2021 15:36:24 +0200 Subject: [PATCH 37/39] clk: samsung: describe drivers in Kconfig Describe better which driver applies to which SoC, to make configuring kernel for Samsung SoC easier. Signed-off-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Link: https://lore.kernel.org/r/20210924133624.112593-1-krzysztof.kozlowski@canonical.com Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/Kconfig | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/clk/samsung/Kconfig b/drivers/clk/samsung/Kconfig index 0441c4f73ac9..0e18d6ff2916 100644 --- a/drivers/clk/samsung/Kconfig +++ b/drivers/clk/samsung/Kconfig @@ -67,7 +67,8 @@ config EXYNOS_5420_COMMON_CLK depends on COMMON_CLK_SAMSUNG help Support for the clock controller present on the Samsung - Exynos5420 SoCs. Choose Y here only if you build for this SoC. + Exynos5420/Exynos5422/Exynos5800 SoCs. Choose Y here only if you + build for this SoC. config EXYNOS_ARM64_COMMON_CLK bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST @@ -79,38 +80,47 @@ config EXYNOS_AUDSS_CLK_CON default y if ARCH_EXYNOS help Support for the Audio Subsystem CLKCON clock controller present - on some Exynos SoC variants. Choose M or Y here if you want to - use audio devices such as I2S, PCM, etc. + on some Samsung Exynos SoC variants. Choose M or Y here if you want + to use audio devices such as I2S, PCM, etc. config EXYNOS_CLKOUT tristate "Samsung Exynos clock output driver" depends on COMMON_CLK_SAMSUNG default y if ARCH_EXYNOS help - Support for the clock output (XCLKOUT) present on some of Exynos SoC - variants. Usually the XCLKOUT is used to monitor the status of the - certains clocks from SoC, but it could also be tied to other devices - as an input clock. + Support for the clock output (XCLKOUT) present on some of Samsung + Exynos SoC variants. Usually the XCLKOUT is used to monitor the + status of the certains clocks from SoC, but it could also be tied to + other devices as an input clock. # For S3C24XX platforms, select following symbols: config S3C2410_COMMON_CLK bool "Samsung S3C2410 clock controller support" if COMPILE_TEST select COMMON_CLK_SAMSUNG help - Build the s3c2410 clock driver based on the common clock framework. + Support for the clock controller present on the Samsung + S3C2410/S3C2440/S3C2442 SoCs. Choose Y here only if you build for + this SoC. config S3C2410_COMMON_DCLK bool select COMMON_CLK_SAMSUNG select REGMAP_MMIO help - Temporary symbol to build the dclk driver based on the common clock - framework. + Support for the dclk clock controller present on the Samsung + S3C2410/S3C2412/S3C2440/S3C2443 SoCs. Choose Y here only if you build + for this SoC. config S3C2412_COMMON_CLK bool "Samsung S3C2412 clock controller support" if COMPILE_TEST select COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung S3C2412 SoCs. + Choose Y here only if you build for this SoC. config S3C2443_COMMON_CLK bool "Samsung S3C2443 clock controller support" if COMPILE_TEST select COMMON_CLK_SAMSUNG + help + Support for the clock controller present on the Samsung + S3C2416/S3C2443 SoCs. Choose Y here only if you build for this SoC. From 675c496d0f92b481ebe4abf4fb06eadad7789de6 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 16 Oct 2021 12:50:21 +0200 Subject: [PATCH 38/39] clk: composite: Also consider .determine_rate for rate + mux composites Commit 69a00fb3d69706 ("clk: divider: Implement and wire up .determine_rate by default") switches clk_divider_ops to implement .determine_rate by default. This breaks composite clocks with multiple parents because clk-composite.c does not use the special handling for mux + divider combinations anymore (that was restricted to rate clocks which only implement .round_rate, but not .determine_rate). Alex reports: This breaks lot of clocks for Rockchip which intensively uses composites, i.e. those clocks will always stay at the initial parent, which in some cases is the XTAL clock and I strongly guess it is the same for other platforms, which use composite clocks having more than one parent (e.g. mediatek, ti ...) Example (RK3399) clk_sdio is set (initialized) with XTAL (24 MHz) as parent in u-boot. It will always stay at this parent, even if the mmc driver sets a rate of 200 MHz (fails, as the nature of things), which should switch it to any of its possible parent PLLs defined in mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p (see clk-rk3399.c) - which never happens. Restore the original behavior by changing the priority of the conditions inside clk-composite.c. Now the special rate + mux case (with rate_ops having a .round_rate - which is still the case for the default clk_divider_ops) is preferred over rate_ops which have .determine_rate defined (and not further considering the mux). Fixes: 69a00fb3d69706 ("clk: divider: Implement and wire up .determine_rate by default") Reported-by: Alex Bee Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20211016105022.303413-2-martin.blumenstingl@googlemail.com Tested-by: Alex Bee Tested-by: Chen-Yu Tsai Signed-off-by: Stephen Boyd --- drivers/clk/clk-composite.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 0506046a5f4b..510a9965633b 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -58,11 +58,8 @@ static int clk_composite_determine_rate(struct clk_hw *hw, long rate; int i; - if (rate_hw && rate_ops && rate_ops->determine_rate) { - __clk_hw_set_clk(rate_hw, hw); - return rate_ops->determine_rate(rate_hw, req); - } else if (rate_hw && rate_ops && rate_ops->round_rate && - mux_hw && mux_ops && mux_ops->set_parent) { + if (rate_hw && rate_ops && rate_ops->round_rate && + mux_hw && mux_ops && mux_ops->set_parent) { req->best_parent_hw = NULL; if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) { @@ -107,6 +104,9 @@ static int clk_composite_determine_rate(struct clk_hw *hw, req->rate = best_rate; return 0; + } else if (rate_hw && rate_ops && rate_ops->determine_rate) { + __clk_hw_set_clk(rate_hw, hw); + return rate_ops->determine_rate(rate_hw, req); } else if (mux_hw && mux_ops && mux_ops->determine_rate) { __clk_hw_set_clk(mux_hw, hw); return mux_ops->determine_rate(mux_hw, req); From 6594988fd625ff0d9a8f90f1788e16185358a3e6 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 16 Oct 2021 12:50:22 +0200 Subject: [PATCH 39/39] clk: composite: Use rate_ops.determine_rate when also a mux is available Update clk_composite_determine_rate() to use rate_ops.determine_rate when available in combination with a mux. So far clk_divider_ops provide both, .round_rate and .determine_rate. Removing the former would make clk-composite fail silently for example on Rockchip platforms (which heavily use composite clocks). Add support for using rate_ops.determine_rate when either rate_ops.round_rate is not available or both (.round_rate and .determine_rate) are provided. Suggested-by: Alex Bee Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20211016105022.303413-3-martin.blumenstingl@googlemail.com Tested-by: Alex Bee Tested-by: Chen-Yu Tsai Signed-off-by: Stephen Boyd --- drivers/clk/clk-composite.c | 68 ++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 510a9965633b..075c7f2a7ec4 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -42,6 +42,29 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, return rate_ops->recalc_rate(rate_hw, parent_rate); } +static int clk_composite_determine_rate_for_parent(struct clk_hw *rate_hw, + struct clk_rate_request *req, + struct clk_hw *parent_hw, + const struct clk_ops *rate_ops) +{ + long rate; + + req->best_parent_hw = parent_hw; + req->best_parent_rate = clk_hw_get_rate(parent_hw); + + if (rate_ops->determine_rate) + return rate_ops->determine_rate(rate_hw, req); + + rate = rate_ops->round_rate(rate_hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + + return 0; +} + static int clk_composite_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { @@ -51,51 +74,56 @@ static int clk_composite_determine_rate(struct clk_hw *hw, struct clk_hw *rate_hw = composite->rate_hw; struct clk_hw *mux_hw = composite->mux_hw; struct clk_hw *parent; - unsigned long parent_rate; - long tmp_rate, best_rate = 0; unsigned long rate_diff; unsigned long best_rate_diff = ULONG_MAX; - long rate; - int i; + unsigned long best_rate = 0; + int i, ret; - if (rate_hw && rate_ops && rate_ops->round_rate && + if (rate_hw && rate_ops && + (rate_ops->determine_rate || rate_ops->round_rate) && mux_hw && mux_ops && mux_ops->set_parent) { req->best_parent_hw = NULL; if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) { + struct clk_rate_request tmp_req = *req; + parent = clk_hw_get_parent(mux_hw); - req->best_parent_hw = parent; - req->best_parent_rate = clk_hw_get_rate(parent); - rate = rate_ops->round_rate(rate_hw, req->rate, - &req->best_parent_rate); - if (rate < 0) - return rate; + ret = clk_composite_determine_rate_for_parent(rate_hw, + &tmp_req, + parent, + rate_ops); + if (ret) + return ret; + + req->rate = tmp_req.rate; + req->best_parent_rate = tmp_req.best_parent_rate; - req->rate = rate; return 0; } for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) { + struct clk_rate_request tmp_req = *req; + parent = clk_hw_get_parent_by_index(mux_hw, i); if (!parent) continue; - parent_rate = clk_hw_get_rate(parent); - - tmp_rate = rate_ops->round_rate(rate_hw, req->rate, - &parent_rate); - if (tmp_rate < 0) + ret = clk_composite_determine_rate_for_parent(rate_hw, + &tmp_req, + parent, + rate_ops); + if (ret) continue; - rate_diff = abs(req->rate - tmp_rate); + rate_diff = abs(req->rate - tmp_req.rate); if (!rate_diff || !req->best_parent_hw || best_rate_diff > rate_diff) { req->best_parent_hw = parent; - req->best_parent_rate = parent_rate; + req->best_parent_rate = tmp_req.best_parent_rate; best_rate_diff = rate_diff; - best_rate = tmp_rate; + best_rate = tmp_req.rate; } if (!rate_diff)