From bf4237a188f872e535de8cbfc7903c1387b83b01 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 29 Jan 2020 17:38:19 +0100 Subject: [PATCH 01/19] clk: rockchip: convert rk3399 pll type to use readl_relaxed_poll_timeout Instead of open coding the polling of the lock status, use the handy readl_relaxed_poll_timeout for this. As the pll locking is normally blazingly fast and we don't want to incur additional delays, we're not doing any sleeps similar to for example the imx clk-pllv4 and define a very safe but still short timeout of 1ms. Suggested-by: Stephen Boyd Signed-off-by: Heiko Stuebner Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20200129163821.1547295-1-heiko@sntech.de --- drivers/clk/rockchip/clk-pll.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 10560d963baf..28b04aad31ad 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -589,19 +589,20 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = { static int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll) { u32 pllcon; - int delay = 24000000; + int ret; - /* poll check the lock status in rk3399 xPLLCON2 */ - while (delay > 0) { - pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); - if (pllcon & RK3399_PLLCON2_LOCK_STATUS) - return 0; + /* + * Lock time typical 250, max 500 input clock cycles @24MHz + * So define a very safe maximum of 1000us, meaning 24000 cycles. + */ + ret = readl_relaxed_poll_timeout(pll->reg_base + RK3399_PLLCON(2), + pllcon, + pllcon & RK3399_PLLCON2_LOCK_STATUS, + 0, 1000); + if (ret) + pr_err("%s: timeout waiting for pll to lock\n", __func__); - delay--; - } - - pr_err("%s: timeout waiting for pll to lock\n", __func__); - return -ETIMEDOUT; + return ret; } static void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll, From 3507df1a4615113ae6509e0f14f6546f0d1c84b4 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 29 Jan 2020 17:38:20 +0100 Subject: [PATCH 02/19] clk: rockchip: convert basic pll lock_wait to use regmap_read_poll_timeout Instead of open coding the polling of the lock status, use the handy regmap_read_poll_timeout for this. As the pll locking is normally blazingly fast and we don't want to incur additional delays, we're not doing any sleeps similar to for example the imx clk-pllv4 and define a very safe but still short timeout of 1ms. Suggested-by: Stephen Boyd Signed-off-by: Heiko Stuebner Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20200129163821.1547295-2-heiko@sntech.de --- drivers/clk/rockchip/clk-pll.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 28b04aad31ad..945f8b2cacc1 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -86,23 +86,14 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) { struct regmap *grf = pll->ctx->grf; unsigned int val; - int delay = 24000000, ret; + int ret; - while (delay > 0) { - ret = regmap_read(grf, pll->lock_offset, &val); - if (ret) { - pr_err("%s: failed to read pll lock status: %d\n", - __func__, ret); - return ret; - } + ret = regmap_read_poll_timeout(grf, pll->lock_offset, val, + val & BIT(pll->lock_shift), 0, 1000); + if (ret) + pr_err("%s: timeout waiting for pll to lock\n", __func__); - if (val & BIT(pll->lock_shift)) - return 0; - delay--; - } - - pr_err("%s: timeout waiting for pll to lock\n", __func__); - return -ETIMEDOUT; + return ret; } /** From 7f6ffbb885d147557bdca471c37b7b1204005798 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 29 Jan 2020 17:38:21 +0100 Subject: [PATCH 03/19] clk: rockchip: convert rk3036 pll type to use internal lock status The rk3036 pll type exposes its lock status in both its pllcon registers as well as the General Register Files. To remove one dependency convert it to the "internal" lock status, similar to how rk3399 handles it. Signed-off-by: Heiko Stuebner Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20200129163821.1547295-3-heiko@sntech.de --- drivers/clk/rockchip/clk-pll.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 945f8b2cacc1..4c6c9167ef50 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "clk.h" @@ -109,12 +110,31 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) #define RK3036_PLLCON1_REFDIV_SHIFT 0 #define RK3036_PLLCON1_POSTDIV2_MASK 0x7 #define RK3036_PLLCON1_POSTDIV2_SHIFT 6 +#define RK3036_PLLCON1_LOCK_STATUS BIT(10) #define RK3036_PLLCON1_DSMPD_MASK 0x1 #define RK3036_PLLCON1_DSMPD_SHIFT 12 +#define RK3036_PLLCON1_PWRDOWN BIT(13) #define RK3036_PLLCON2_FRAC_MASK 0xffffff #define RK3036_PLLCON2_FRAC_SHIFT 0 -#define RK3036_PLLCON1_PWRDOWN (1 << 13) +static int rockchip_rk3036_pll_wait_lock(struct rockchip_clk_pll *pll) +{ + u32 pllcon; + int ret; + + /* + * Lock time typical 250, max 500 input clock cycles @24MHz + * So define a very safe maximum of 1000us, meaning 24000 cycles. + */ + ret = readl_relaxed_poll_timeout(pll->reg_base + RK3036_PLLCON(1), + pllcon, + pllcon & RK3036_PLLCON1_LOCK_STATUS, + 0, 1000); + if (ret) + pr_err("%s: timeout waiting for pll to lock\n", __func__); + + return ret; +} static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll, struct rockchip_pll_rate_table *rate) @@ -212,7 +232,7 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll, writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2)); /* wait for the pll to lock */ - ret = rockchip_pll_wait_lock(pll); + ret = rockchip_rk3036_pll_wait_lock(pll); if (ret) { pr_warn("%s: pll update unsuccessful, trying to restore old params\n", __func__); @@ -251,7 +271,7 @@ static int rockchip_rk3036_pll_enable(struct clk_hw *hw) writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0), pll->reg_base + RK3036_PLLCON(1)); - rockchip_pll_wait_lock(pll); + rockchip_rk3036_pll_wait_lock(pll); return 0; } From 1627f683636df70fb25358b0a7b39a24e8fce5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= Date: Tue, 2 Jun 2020 10:06:43 +0200 Subject: [PATCH 04/19] clk: rockchip: Handle clock tree for rk3288w variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The revision rk3288w has a different clock tree about "hclk_vio" clock, according to the BSP kernel code. This patch handles this difference by detecting which device-tree we are using. If it is a "rockchip,rk3288-cru", let's register the clock tree as it was before. If the device-tree node is "rockchip,rk3288w-cru", we will apply the difference with this version of this SoC. Noticed that this new device-tree compatible must be handled in bootloader such as u-boot. Signed-off-by: Mylène Josserand Link: https://lore.kernel.org/r/20200602080644.11333-2-mylene.josserand@collabora.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3288.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index cc2a177bbdbf..204976e2d0cb 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -425,8 +425,6 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3288_CLKGATE_CON(3), 0, GFLAGS), - DIV(0, "hclk_vio", "aclk_vio0", 0, - RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), COMPOSITE(0, "aclk_vio1", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(3), 2, GFLAGS), @@ -819,6 +817,16 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { INVERTER(0, "pclk_isp", "pclk_isp_in", RK3288_CLKSEL_CON(29), 3, IFLAGS), }; +static struct rockchip_clk_branch rk3288w_hclkvio_branch[] __initdata = { + DIV(0, "hclk_vio", "aclk_vio1", 0, + RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), +}; + +static struct rockchip_clk_branch rk3288_hclkvio_branch[] __initdata = { + DIV(0, "hclk_vio", "aclk_vio0", 0, + RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), +}; + static const char *const rk3288_critical_clocks[] __initconst = { "aclk_cpu", "aclk_peri", @@ -936,6 +944,14 @@ static void __init rk3288_clk_init(struct device_node *np) RK3288_GRF_SOC_STATUS1); rockchip_clk_register_branches(ctx, rk3288_clk_branches, ARRAY_SIZE(rk3288_clk_branches)); + + if (of_device_is_compatible(np, "rockchip,rk3288w-cru")) + rockchip_clk_register_branches(ctx, rk3288w_hclkvio_branch, + ARRAY_SIZE(rk3288w_hclkvio_branch)); + else + rockchip_clk_register_branches(ctx, rk3288_hclkvio_branch, + ARRAY_SIZE(rk3288_hclkvio_branch)); + rockchip_clk_protect_critical(rk3288_critical_clocks, ARRAY_SIZE(rk3288_critical_clocks)); From 00bd404144241155653bb0d0c15be51e4e6983aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= Date: Tue, 2 Jun 2020 10:06:44 +0200 Subject: [PATCH 05/19] dt-bindings: clocks: add rk3288w variant compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the possible compatible "rockchip,rk3288w-cru" that handles the difference between the rk3288 and the new revision rk3288w. This compatible will be added by bootloaders. Signed-off-by: Mylène Josserand Acked-by: Rob Herring Link: https://lore.kernel.org/r/20200602080644.11333-3-mylene.josserand@collabora.com Signed-off-by: Heiko Stuebner --- .../devicetree/bindings/clock/rockchip,rk3288-cru.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt index 8cb47c39ba53..bf3a9ec19241 100644 --- a/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3288-cru.txt @@ -4,9 +4,15 @@ The RK3288 clock controller generates and supplies clock to various controllers within the SoC and also implements a reset controller for SoC peripherals. +A revision of this SoC is available: rk3288w. The clock tree is a bit +different so another dt-compatible is available. Noticed that it is only +setting the difference but there is no automatic revision detection. This +should be performed by bootloaders. + Required Properties: -- compatible: should be "rockchip,rk3288-cru" +- compatible: should be "rockchip,rk3288-cru" or "rockchip,rk3288w-cru" in + case of this revision of Rockchip rk3288. - reg: physical base address of the controller and length of memory mapped region. - #clock-cells: should be 1. From 0a7f99aad259d223ce69c03e792c7e2bfcf8c2c6 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 3 Jul 2020 17:49:48 +0200 Subject: [PATCH 06/19] clk: rockchip: use separate compatibles for rk3288w-cru Commit 1627f683636d ("clk: rockchip: Handle clock tree for rk3288w variant") added the check for rk3288w-specific clock-tree changes but in turn would require a double-compatible due to re-using the main rockchip,rk3288-cru compatible as entry point. The binding change actually describes the compatibles as one or the other so adapt the code accordingly and add a real second entry-point for the clock controller. Signed-off-by: Heiko Stuebner Reviewed-by: Ezequiel Garcia Reviewed-by: Jagan Teki Tested-by: Jagan Teki # rock-pi-n8 Link: https://lore.kernel.org/r/20200703154948.260369-1-heiko@sntech.de --- drivers/clk/rockchip/clk-rk3288.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 204976e2d0cb..93c794695c46 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -15,6 +15,11 @@ #define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) #define RK3288_GRF_SOC_STATUS1 0x284 +enum rk3288_variant { + RK3288_CRU, + RK3288W_CRU, +}; + enum rk3288_plls { apll, dpll, cpll, gpll, npll, }; @@ -922,7 +927,8 @@ static struct syscore_ops rk3288_clk_syscore_ops = { .resume = rk3288_clk_resume, }; -static void __init rk3288_clk_init(struct device_node *np) +static void __init rk3288_common_init(struct device_node *np, + enum rk3288_variant soc) { struct rockchip_clk_provider *ctx; @@ -945,7 +951,7 @@ static void __init rk3288_clk_init(struct device_node *np) rockchip_clk_register_branches(ctx, rk3288_clk_branches, ARRAY_SIZE(rk3288_clk_branches)); - if (of_device_is_compatible(np, "rockchip,rk3288w-cru")) + if (soc == RK3288W_CRU) rockchip_clk_register_branches(ctx, rk3288w_hclkvio_branch, ARRAY_SIZE(rk3288w_hclkvio_branch)); else @@ -970,4 +976,15 @@ static void __init rk3288_clk_init(struct device_node *np) rockchip_clk_of_add_provider(np, ctx); } + +static void __init rk3288_clk_init(struct device_node *np) +{ + rk3288_common_init(np, RK3288_CRU); +} CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); + +static void __init rk3288w_clk_init(struct device_node *np) +{ + rk3288_common_init(np, RK3288W_CRU); +} +CLK_OF_DECLARE(rk3288w_cru, "rockchip,rk3288w-cru", rk3288w_clk_init); From 465931e70881476a210d44705102ef8b6ee6cdb0 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 18 Jun 2020 18:56:29 +0100 Subject: [PATCH 07/19] clk: rockchip: Revert "fix wrong mmc sample phase shift for rk3328" This reverts commit 82f4b67f018c88a7cc9337f0067ed3d6ec352648. According to a subsequent revert in the vendor kernel, the original change was based on unclear documentation and was in fact incorrect. Emprically, my board's HS200 eMMC at 200MHZ apparently gets lucky with a phase where this had no impact, but limiting max-frequency to 150MHz to match the nominal capability of the I/O pins made it virtually unusable, constantly throwing errors and retuning. With this revert, it starts behaving perfectly at 150MHz too. Fixes: 82f4b67f018c ("clk: rockchip: fix wrong mmc sample phase shift for rk3328") Signed-off-by: Robin Murphy Reviewed-by: Shawn Lin Link: https://lore.kernel.org/r/c80eb52e34c03f817586b6b7912fbd4e31be9079.1589475794.git.robin.murphy@arm.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3328.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c index c186a1985bf4..2429b7c2a8b3 100644 --- a/drivers/clk/rockchip/clk-rk3328.c +++ b/drivers/clk/rockchip/clk-rk3328.c @@ -808,22 +808,22 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = { MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "clk_sdmmc", RK3328_SDMMC_CON0, 1), MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "clk_sdmmc", - RK3328_SDMMC_CON1, 0), + RK3328_SDMMC_CON1, 1), MMC(SCLK_SDIO_DRV, "sdio_drv", "clk_sdio", RK3328_SDIO_CON0, 1), MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "clk_sdio", - RK3328_SDIO_CON1, 0), + RK3328_SDIO_CON1, 1), MMC(SCLK_EMMC_DRV, "emmc_drv", "clk_emmc", RK3328_EMMC_CON0, 1), MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "clk_emmc", - RK3328_EMMC_CON1, 0), + RK3328_EMMC_CON1, 1), MMC(SCLK_SDMMC_EXT_DRV, "sdmmc_ext_drv", "clk_sdmmc_ext", RK3328_SDMMC_EXT_CON0, 1), MMC(SCLK_SDMMC_EXT_SAMPLE, "sdmmc_ext_sample", "clk_sdmmc_ext", - RK3328_SDMMC_EXT_CON1, 0), + RK3328_SDMMC_EXT_CON1, 1), }; static const char *const rk3328_critical_clocks[] __initconst = { From f47ee279d25fb0e010cae5d6e758e39b40eb6378 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 3 Jul 2020 20:05:07 +0300 Subject: [PATCH 08/19] clk: actions: Fix h_clk for Actions S500 SoC The h_clk clock in the Actions Semi S500 SoC clock driver has an invalid parent. Replace with the correct one. Fixes: ed6b4795ece4 ("clk: actions: Add clock driver for S500 SoC") Signed-off-by: Cristian Ciocaltea Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/c57e7ebabfa970014f073b92fe95b47d3e5a70b1.1593788312.git.cristian.ciocaltea@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/actions/owl-s500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/actions/owl-s500.c b/drivers/clk/actions/owl-s500.c index e2007ac4d235..0eb83a0b70bc 100644 --- a/drivers/clk/actions/owl-s500.c +++ b/drivers/clk/actions/owl-s500.c @@ -183,7 +183,7 @@ static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0); static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0); /* divider clocks */ -static OWL_DIVIDER(h_clk, "h_clk", "ahbprevdiv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0); +static OWL_DIVIDER(h_clk, "h_clk", "ahbprediv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0); static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0); /* factor clocks */ From 1a4ae4138f386600fc539747bb978873299017f8 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 3 Jul 2020 20:05:08 +0300 Subject: [PATCH 09/19] dt-bindings: clock: Add APB, DMAC, GPIO bindings for Actions S500 SoC Add the missing APB, DMAC and GPIO clock bindings constants for Actions Semi S500 SoC. Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/67112af4f5bc0cc5e70ce8410feb369cc72972b8.1593788312.git.cristian.ciocaltea@gmail.com Reviewed-by: Manivannan Sadhasivam Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- include/dt-bindings/clock/actions,s500-cmu.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/actions,s500-cmu.h b/include/dt-bindings/clock/actions,s500-cmu.h index 030981cd2d56..a250a52a6192 100644 --- a/include/dt-bindings/clock/actions,s500-cmu.h +++ b/include/dt-bindings/clock/actions,s500-cmu.h @@ -72,7 +72,12 @@ #define CLK_NAND 52 #define CLK_ECC 53 #define CLK_RMII_REF 54 +#define CLK_GPIO 55 -#define CLK_NR_CLKS (CLK_RMII_REF + 1) +/* system clock (part 2) */ +#define CLK_APB 56 +#define CLK_DMAC 57 + +#define CLK_NR_CLKS (CLK_DMAC + 1) #endif /* __DT_BINDINGS_CLOCK_S500_CMU_H */ From b81e88dead64b4d3725b02bf275d5594943c125a Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 3 Jul 2020 20:05:09 +0300 Subject: [PATCH 10/19] clk: actions: Add APB, DMAC, GPIO clock support for Actions S500 SoC Add support for the missing APB, DMAC and GPIO clocks in the Actions Semi S500 SoC clock driver. Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/87964ae012e513597b8b4c7be2e7ac332a70087a.1593788312.git.cristian.ciocaltea@gmail.com Reviewed-by: Manivannan Sadhasivam Signed-off-by: Stephen Boyd --- drivers/clk/actions/owl-s500.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/actions/owl-s500.c b/drivers/clk/actions/owl-s500.c index 0eb83a0b70bc..025a8f6d6482 100644 --- a/drivers/clk/actions/owl-s500.c +++ b/drivers/clk/actions/owl-s500.c @@ -175,6 +175,8 @@ static OWL_MUX(dev_clk, "dev_clk", dev_clk_mux_p, CMU_DEVPLL, 12, 1, CLK_SET_RAT static OWL_MUX(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT); /* gate clocks */ +static OWL_GATE(gpio_clk, "gpio_clk", "apb_clk", CMU_DEVCLKEN0, 18, 0, 0); +static OWL_GATE(dmac_clk, "dmac_clk", "h_clk", CMU_DEVCLKEN0, 1, 0, 0); static OWL_GATE(spi0_clk, "spi0_clk", "ahb_clk", CMU_DEVCLKEN1, 10, 0, CLK_IGNORE_UNUSED); static OWL_GATE(spi1_clk, "spi1_clk", "ahb_clk", CMU_DEVCLKEN1, 11, 0, CLK_IGNORE_UNUSED); static OWL_GATE(spi2_clk, "spi2_clk", "ahb_clk", CMU_DEVCLKEN1, 12, 0, CLK_IGNORE_UNUSED); @@ -184,6 +186,7 @@ static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0); /* divider clocks */ static OWL_DIVIDER(h_clk, "h_clk", "ahbprediv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0); +static OWL_DIVIDER(apb_clk, "apb_clk", "ahb_clk", CMU_BUSCLK1, 14, 2, NULL, 0, 0); static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0); /* factor clocks */ @@ -428,6 +431,9 @@ static struct owl_clk_common *s500_clks[] = { &spdif_clk.common, &nand_clk.common, &ecc_clk.common, + &apb_clk.common, + &dmac_clk.common, + &gpio_clk.common, }; static struct clk_hw_onecell_data s500_hw_clks = { @@ -484,6 +490,9 @@ static struct clk_hw_onecell_data s500_hw_clks = { [CLK_SPDIF] = &spdif_clk.common.hw, [CLK_NAND] = &nand_clk.common.hw, [CLK_ECC] = &ecc_clk.common.hw, + [CLK_APB] = &apb_clk.common.hw, + [CLK_DMAC] = &dmac_clk.common.hw, + [CLK_GPIO] = &gpio_clk.common.hw, }, .num = CLK_NR_CLKS, }; From fac1d443a2b73dfb5b277d4e3c202609f0927eb5 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 3 Jul 2020 20:05:10 +0300 Subject: [PATCH 11/19] dt-bindings: reset: Add binding constants for Actions S500 RMU Add device tree binding constants for Actions Semi S500 SoC Reset Management Unit (RMU). Signed-off-by: Cristian Ciocaltea Acked-by: Philipp Zabel Link: https://lore.kernel.org/r/daf615160b3be9f38dcf7926cc82128c9c2d73e3.1593788312.git.cristian.ciocaltea@gmail.com Reviewed-by: Manivannan Sadhasivam Acked-by: Rob Herring Signed-off-by: Stephen Boyd --- .../dt-bindings/reset/actions,s500-reset.h | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 include/dt-bindings/reset/actions,s500-reset.h diff --git a/include/dt-bindings/reset/actions,s500-reset.h b/include/dt-bindings/reset/actions,s500-reset.h new file mode 100644 index 000000000000..f5d94176d10b --- /dev/null +++ b/include/dt-bindings/reset/actions,s500-reset.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Device Tree binding constants for Actions Semi S500 Reset Management Unit + * + * Copyright (c) 2014 Actions Semi Inc. + * Copyright (c) 2020 Cristian Ciocaltea + */ + +#ifndef __DT_BINDINGS_ACTIONS_S500_RESET_H +#define __DT_BINDINGS_ACTIONS_S500_RESET_H + +#define RESET_DMAC 0 +#define RESET_NORIF 1 +#define RESET_DDR 2 +#define RESET_NANDC 3 +#define RESET_SD0 4 +#define RESET_SD1 5 +#define RESET_PCM1 6 +#define RESET_DE 7 +#define RESET_LCD 8 +#define RESET_SD2 9 +#define RESET_DSI 10 +#define RESET_CSI 11 +#define RESET_BISP 12 +#define RESET_KEY 13 +#define RESET_GPIO 14 +#define RESET_AUDIO 15 +#define RESET_PCM0 16 +#define RESET_VDE 17 +#define RESET_VCE 18 +#define RESET_GPU3D 19 +#define RESET_NIC301 20 +#define RESET_LENS 21 +#define RESET_PERIPHRESET 22 +#define RESET_USB2_0 23 +#define RESET_TVOUT 24 +#define RESET_HDMI 25 +#define RESET_HDCP2TX 26 +#define RESET_UART6 27 +#define RESET_UART0 28 +#define RESET_UART1 29 +#define RESET_UART2 30 +#define RESET_SPI0 31 +#define RESET_SPI1 32 +#define RESET_SPI2 33 +#define RESET_SPI3 34 +#define RESET_I2C0 35 +#define RESET_I2C1 36 +#define RESET_USB3 37 +#define RESET_UART3 38 +#define RESET_UART4 39 +#define RESET_UART5 40 +#define RESET_I2C2 41 +#define RESET_I2C3 42 +#define RESET_ETHERNET 43 +#define RESET_CHIPID 44 +#define RESET_USB2_1 45 +#define RESET_WD0RESET 46 +#define RESET_WD1RESET 47 +#define RESET_WD2RESET 48 +#define RESET_WD3RESET 49 +#define RESET_DBG0RESET 50 +#define RESET_DBG1RESET 51 +#define RESET_DBG2RESET 52 +#define RESET_DBG3RESET 53 + +#endif /* __DT_BINDINGS_ACTIONS_S500_RESET_H */ From 9fb961da91393e33b09a87582ee526e6328869a1 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 3 Jul 2020 20:05:11 +0300 Subject: [PATCH 12/19] clk: actions: Add Actions S500 SoC Reset Management Unit support Add Reset Management Unit (RMU) support for Actions Semi S500 SoC. Signed-off-by: Cristian Ciocaltea Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/3fba2e6f0edfac97cb8c6ce60f95c24852578eac.1593788312.git.cristian.ciocaltea@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/actions/owl-s500.c | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/drivers/clk/actions/owl-s500.c b/drivers/clk/actions/owl-s500.c index 025a8f6d6482..61bb224f6330 100644 --- a/drivers/clk/actions/owl-s500.c +++ b/drivers/clk/actions/owl-s500.c @@ -23,8 +23,10 @@ #include "owl-gate.h" #include "owl-mux.h" #include "owl-pll.h" +#include "owl-reset.h" #include +#include #define CMU_COREPLL (0x0000) #define CMU_DEVPLL (0x0004) @@ -497,20 +499,96 @@ static struct clk_hw_onecell_data s500_hw_clks = { .num = CLK_NR_CLKS, }; +static const struct owl_reset_map s500_resets[] = { + [RESET_DMAC] = { CMU_DEVRST0, BIT(0) }, + [RESET_NORIF] = { CMU_DEVRST0, BIT(1) }, + [RESET_DDR] = { CMU_DEVRST0, BIT(2) }, + [RESET_NANDC] = { CMU_DEVRST0, BIT(3) }, + [RESET_SD0] = { CMU_DEVRST0, BIT(4) }, + [RESET_SD1] = { CMU_DEVRST0, BIT(5) }, + [RESET_PCM1] = { CMU_DEVRST0, BIT(6) }, + [RESET_DE] = { CMU_DEVRST0, BIT(7) }, + [RESET_LCD] = { CMU_DEVRST0, BIT(8) }, + [RESET_SD2] = { CMU_DEVRST0, BIT(9) }, + [RESET_DSI] = { CMU_DEVRST0, BIT(10) }, + [RESET_CSI] = { CMU_DEVRST0, BIT(11) }, + [RESET_BISP] = { CMU_DEVRST0, BIT(12) }, + [RESET_KEY] = { CMU_DEVRST0, BIT(14) }, + [RESET_GPIO] = { CMU_DEVRST0, BIT(15) }, + [RESET_AUDIO] = { CMU_DEVRST0, BIT(17) }, + [RESET_PCM0] = { CMU_DEVRST0, BIT(18) }, + [RESET_VDE] = { CMU_DEVRST0, BIT(19) }, + [RESET_VCE] = { CMU_DEVRST0, BIT(20) }, + [RESET_GPU3D] = { CMU_DEVRST0, BIT(22) }, + [RESET_NIC301] = { CMU_DEVRST0, BIT(23) }, + [RESET_LENS] = { CMU_DEVRST0, BIT(26) }, + [RESET_PERIPHRESET] = { CMU_DEVRST0, BIT(27) }, + [RESET_USB2_0] = { CMU_DEVRST1, BIT(0) }, + [RESET_TVOUT] = { CMU_DEVRST1, BIT(1) }, + [RESET_HDMI] = { CMU_DEVRST1, BIT(2) }, + [RESET_HDCP2TX] = { CMU_DEVRST1, BIT(3) }, + [RESET_UART6] = { CMU_DEVRST1, BIT(4) }, + [RESET_UART0] = { CMU_DEVRST1, BIT(5) }, + [RESET_UART1] = { CMU_DEVRST1, BIT(6) }, + [RESET_UART2] = { CMU_DEVRST1, BIT(7) }, + [RESET_SPI0] = { CMU_DEVRST1, BIT(8) }, + [RESET_SPI1] = { CMU_DEVRST1, BIT(9) }, + [RESET_SPI2] = { CMU_DEVRST1, BIT(10) }, + [RESET_SPI3] = { CMU_DEVRST1, BIT(11) }, + [RESET_I2C0] = { CMU_DEVRST1, BIT(12) }, + [RESET_I2C1] = { CMU_DEVRST1, BIT(13) }, + [RESET_USB3] = { CMU_DEVRST1, BIT(14) }, + [RESET_UART3] = { CMU_DEVRST1, BIT(15) }, + [RESET_UART4] = { CMU_DEVRST1, BIT(16) }, + [RESET_UART5] = { CMU_DEVRST1, BIT(17) }, + [RESET_I2C2] = { CMU_DEVRST1, BIT(18) }, + [RESET_I2C3] = { CMU_DEVRST1, BIT(19) }, + [RESET_ETHERNET] = { CMU_DEVRST1, BIT(20) }, + [RESET_CHIPID] = { CMU_DEVRST1, BIT(21) }, + [RESET_USB2_1] = { CMU_DEVRST1, BIT(22) }, + [RESET_WD0RESET] = { CMU_DEVRST1, BIT(24) }, + [RESET_WD1RESET] = { CMU_DEVRST1, BIT(25) }, + [RESET_WD2RESET] = { CMU_DEVRST1, BIT(26) }, + [RESET_WD3RESET] = { CMU_DEVRST1, BIT(27) }, + [RESET_DBG0RESET] = { CMU_DEVRST1, BIT(28) }, + [RESET_DBG1RESET] = { CMU_DEVRST1, BIT(29) }, + [RESET_DBG2RESET] = { CMU_DEVRST1, BIT(30) }, + [RESET_DBG3RESET] = { CMU_DEVRST1, BIT(31) }, +}; + static struct owl_clk_desc s500_clk_desc = { .clks = s500_clks, .num_clks = ARRAY_SIZE(s500_clks), .hw_clks = &s500_hw_clks, + + .resets = s500_resets, + .num_resets = ARRAY_SIZE(s500_resets), }; static int s500_clk_probe(struct platform_device *pdev) { struct owl_clk_desc *desc; + struct owl_reset *reset; + int ret; desc = &s500_clk_desc; owl_clk_regmap_init(pdev, desc); + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + reset->rcdev.of_node = pdev->dev.of_node; + reset->rcdev.ops = &owl_reset_ops; + reset->rcdev.nr_resets = desc->num_resets; + reset->reset_map = desc->resets; + reset->regmap = desc->regmap; + + ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev); + if (ret) + dev_err(&pdev->dev, "Failed to register reset controller\n"); + return owl_clk_probe(&pdev->dev, desc->hw_clks); } From cb7c6677bfb5c92526df73b20760d65bd9189344 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Fri, 3 Jul 2020 20:05:12 +0300 Subject: [PATCH 13/19] MAINTAINERS: Add reset binding entry for Actions Semi Owl SoCs Add a reset binding entry to match all members of Actions Semi Owl SoCs. Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/78d63d97e3a8a8f7a9048b6eec74a9d158578833.1593788312.git.cristian.ciocaltea@gmail.com Reviewed-by: Manivannan Sadhasivam Signed-off-by: Stephen Boyd --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 68f21d46614c..931c78a5e035 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1533,6 +1533,7 @@ F: drivers/mmc/host/owl-mmc.c F: drivers/pinctrl/actions/* F: drivers/soc/actions/ F: include/dt-bindings/power/owl-* +F: include/dt-bindings/reset/actions,* F: include/linux/soc/actions/ N: owl From ef990bcad58cf1d13c5a49191a2c2342eb8d6709 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Wed, 22 Jul 2020 18:18:20 +0200 Subject: [PATCH 14/19] clk: rockchip: add sclk_mac_lbtest to rk3188_critical_clocks Since the loopbacktest clock is not exported and is not touched in the driver, it has to be added to rk3188_critical_clocks to be protected from being disabled and in order to get the emac working. Signed-off-by: Alex Bee Link: https://lore.kernel.org/r/20200722161820.5316-1-knaerzche@gmail.com Signed-off-by: Heiko Stuebner --- drivers/clk/rockchip/clk-rk3188.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 77aebfb1d6d5..730020fcc7fe 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -751,6 +751,7 @@ static const char *const rk3188_critical_clocks[] __initconst = { "pclk_peri", "hclk_cpubus", "hclk_vio_bus", + "sclk_mac_lbtest", }; static struct rockchip_clk_provider *__init rk3188_common_clk_init(struct device_node *np) From 9f7d5042a64160e20c73d734f9ed5dd8c6bba205 Mon Sep 17 00:00:00 2001 From: Lori Hikichi Date: Fri, 12 Jun 2020 15:52:12 -0700 Subject: [PATCH 15/19] clk: iproc: round clock rate to the closest Change from 'DIV_ROUND_UP' to 'DIV_ROUND_CLOSEST' when calculating the clock divisor in the iProc ASIU clock driver to allow to get to the closest clock rate. Fixes: 5fe225c105fd ("clk: iproc: add initial common clock support") Signed-off-by: Lori Hikichi Signed-off-by: Ray Jui Link: https://lore.kernel.org/r/20200612225212.124301-1-ray.jui@broadcom.com Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-iproc-asiu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c index 6fb8af506777..e062dd4992ea 100644 --- a/drivers/clk/bcm/clk-iproc-asiu.c +++ b/drivers/clk/bcm/clk-iproc-asiu.c @@ -119,7 +119,7 @@ static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate, if (rate == *parent_rate) return *parent_rate; - div = DIV_ROUND_UP(*parent_rate, rate); + div = DIV_ROUND_CLOSEST(*parent_rate, rate); if (div < 2) return *parent_rate; @@ -145,7 +145,7 @@ static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } - div = DIV_ROUND_UP(parent_rate, rate); + div = DIV_ROUND_CLOSEST(parent_rate, rate); if (div < 2) return -EINVAL; From 8529fc0aaa704c6618e69e8d35834aa977b6ece9 Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Thu, 16 Jul 2020 14:30:30 +0800 Subject: [PATCH 16/19] clk: intel: Use devm_clk_hw_register() instead of clk_hw_register() To ensure that clks are unregistered in case of any failure, use devm_clk_hw_register() instead of clk_hw_register(). Signed-off-by: Rahul Tanwar Link: https://lore.kernel.org/r/7ef7009b4e9f986fd6dfbf487c0e85de68a4ba9b.1594880946.git.rahul.tanwar@linux.intel.com Signed-off-by: Stephen Boyd --- drivers/clk/x86/clk-cgu-pll.c | 2 +- drivers/clk/x86/clk-cgu.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/x86/clk-cgu-pll.c b/drivers/clk/x86/clk-cgu-pll.c index c03cc6b85b9f..3179557b5f78 100644 --- a/drivers/clk/x86/clk-cgu-pll.c +++ b/drivers/clk/x86/clk-cgu-pll.c @@ -128,7 +128,7 @@ lgm_clk_register_pll(struct lgm_clk_provider *ctx, pll->hw.init = &init; hw = &pll->hw; - ret = clk_hw_register(dev, hw); + ret = devm_clk_hw_register(dev, hw); if (ret) return ERR_PTR(ret); diff --git a/drivers/clk/x86/clk-cgu.c b/drivers/clk/x86/clk-cgu.c index 56af0e04ec1e..88ebeb53b109 100644 --- a/drivers/clk/x86/clk-cgu.c +++ b/drivers/clk/x86/clk-cgu.c @@ -119,7 +119,7 @@ lgm_clk_register_mux(struct lgm_clk_provider *ctx, mux->hw.init = &init; hw = &mux->hw; - ret = clk_hw_register(dev, hw); + ret = devm_clk_hw_register(dev, hw); if (ret) return ERR_PTR(ret); @@ -247,7 +247,7 @@ lgm_clk_register_divider(struct lgm_clk_provider *ctx, div->hw.init = &init; hw = &div->hw; - ret = clk_hw_register(dev, hw); + ret = devm_clk_hw_register(dev, hw); if (ret) return ERR_PTR(ret); @@ -361,7 +361,7 @@ lgm_clk_register_gate(struct lgm_clk_provider *ctx, gate->hw.init = &init; hw = &gate->hw; - ret = clk_hw_register(dev, hw); + ret = devm_clk_hw_register(dev, hw); if (ret) return ERR_PTR(ret); @@ -624,7 +624,7 @@ int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx, ddiv->hw.init = &init; hw = &ddiv->hw; - ret = clk_hw_register(dev, hw); + ret = devm_clk_hw_register(dev, hw); if (ret) { dev_err(dev, "register clk: %s failed!\n", list->name); return ret; From c9e28fe649f76ee13a9bcc09f89ae0189f85801b Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Thu, 16 Jul 2020 14:30:31 +0800 Subject: [PATCH 17/19] clk: intel: Improve locking in the driver Remove/reduce unnecessary spin locking of the code. Signed-off-by: Rahul Tanwar Link: https://lore.kernel.org/r/79c0f5f9f5bc512a7e2b5f3c91f6341f28b5854c.1594880946.git.rahul.tanwar@linux.intel.com Signed-off-by: Stephen Boyd --- drivers/clk/x86/clk-cgu.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/clk/x86/clk-cgu.c b/drivers/clk/x86/clk-cgu.c index 88ebeb53b109..c379fedfb9f2 100644 --- a/drivers/clk/x86/clk-cgu.c +++ b/drivers/clk/x86/clk-cgu.c @@ -420,18 +420,14 @@ lgm_clk_ddiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw); unsigned int div0, div1, exdiv; - unsigned long flags; u64 prate; - spin_lock_irqsave(&ddiv->lock, flags); div0 = lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift0, ddiv->width0) + 1; div1 = lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift1, ddiv->width1) + 1; exdiv = lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, ddiv->width2); - spin_unlock_irqrestore(&ddiv->lock, flags); - prate = (u64)parent_rate; do_div(prate, div0); do_div(prate, div1); @@ -548,24 +544,21 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate, div = div * 2; div = DIV_ROUND_CLOSEST_ULL((u64)div, 5); } + spin_unlock_irqrestore(&ddiv->lock, flags); - if (div <= 0) { - spin_unlock_irqrestore(&ddiv->lock, flags); + if (div <= 0) return *prate; - } - if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2) != 0) { - if (lgm_clk_get_ddiv_val(div + 1, &ddiv1, &ddiv2) != 0) { - spin_unlock_irqrestore(&ddiv->lock, flags); + if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2) != 0) + if (lgm_clk_get_ddiv_val(div + 1, &ddiv1, &ddiv2) != 0) return -EINVAL; - } - } rate64 = *prate; do_div(rate64, ddiv1); do_div(rate64, ddiv2); /* if predivide bit is enabled, modify rounded rate by factor of 2.5 */ + spin_lock_irqsave(&ddiv->lock, flags); if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) { rate64 = rate64 * 2; rate64 = DIV_ROUND_CLOSEST_ULL(rate64, 5); From d310124cd99df5e5011d79f36a6d16d3452de348 Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Thu, 16 Jul 2020 14:30:32 +0800 Subject: [PATCH 18/19] clk: intel: Avoid unnecessary memset by improving code memset can be avoided in a loop if the variables used are declared inside the loop. Move such variables declaration inside the loop to avoid memset. Signed-off-by: Rahul Tanwar Link: https://lore.kernel.org/r/26624b65d0e6b958c4765a406b9929d1a9ce1c2c.1594880946.git.rahul.tanwar@linux.intel.com [sboyd@kernel.org: Drop NULL assignment that is overwritten] Signed-off-by: Stephen Boyd --- drivers/clk/x86/clk-cgu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/clk/x86/clk-cgu.c b/drivers/clk/x86/clk-cgu.c index c379fedfb9f2..33de600e0c38 100644 --- a/drivers/clk/x86/clk-cgu.c +++ b/drivers/clk/x86/clk-cgu.c @@ -581,19 +581,18 @@ int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx, unsigned int nr_clk) { struct device *dev = ctx->dev; - struct clk_init_data init = {}; - struct lgm_clk_ddiv *ddiv; struct clk_hw *hw; unsigned int idx; int ret; for (idx = 0; idx < nr_clk; idx++, list++) { - ddiv = NULL; + struct clk_init_data init = {}; + struct lgm_clk_ddiv *ddiv; + ddiv = devm_kzalloc(dev, sizeof(*ddiv), GFP_KERNEL); if (!ddiv) return -ENOMEM; - memset(&init, 0, sizeof(init)); init.name = list->name; init.ops = &lgm_clk_ddiv_ops; init.flags = list->flags; From 03111b1088f18f93d38e888c41e8a1e6aba9f8bb Mon Sep 17 00:00:00 2001 From: Mike Tipton Date: Mon, 29 Jun 2020 17:30:24 -0700 Subject: [PATCH 19/19] clk: Add support for enabling/disabling clocks from debugfs For test and debug purposes, it's simple enough to enable or disable clocks from shell. Add a new debugfs file 'clk_prepare_enable' that calls clk_prepare_enable() when writing "1" and clk_disable_unprepare() when writing "0". This can have security implications, so only support it when the code has been modified to #define CLOCK_ALLOW_WRITE_DEBUGFS. Signed-off-by: Mike Tipton Link: https://lore.kernel.org/r/20200630003024.6282-1-mdtipton@codeaurora.org [sboyd@kernel.org: Reword commit text and remove comment update] Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 3f588ed06ce3..4d455a657b01 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3039,6 +3039,31 @@ static int clk_rate_set(void *data, u64 val) } #define clk_rate_mode 0644 + +static int clk_prepare_enable_set(void *data, u64 val) +{ + struct clk_core *core = data; + int ret = 0; + + if (val) + ret = clk_prepare_enable(core->hw->clk); + else + clk_disable_unprepare(core->hw->clk); + + return ret; +} + +static int clk_prepare_enable_get(void *data, u64 *val) +{ + struct clk_core *core = data; + + *val = core->enable_count && core->prepare_count; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(clk_prepare_enable_fops, clk_prepare_enable_get, + clk_prepare_enable_set, "%llu\n"); + #else #define clk_rate_set NULL #define clk_rate_mode 0444 @@ -3216,6 +3241,10 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count); debugfs_create_file("clk_duty_cycle", 0444, root, core, &clk_duty_cycle_fops); +#ifdef CLOCK_ALLOW_WRITE_DEBUGFS + debugfs_create_file("clk_prepare_enable", 0644, root, core, + &clk_prepare_enable_fops); +#endif if (core->num_parents > 0) debugfs_create_file("clk_parent", 0444, root, core,