diff --git a/target/linux/rockchip/patches-6.6/111-01-clk-rockchip-rk3588-drop-unused-code.patch b/target/linux/rockchip/patches-6.6/111-01-clk-rockchip-rk3588-drop-unused-code.patch new file mode 100644 index 0000000000..54ccef8410 --- /dev/null +++ b/target/linux/rockchip/patches-6.6/111-01-clk-rockchip-rk3588-drop-unused-code.patch @@ -0,0 +1,79 @@ +From: Sebastian Reichel +To: Michael Turquette , + Stephen Boyd , + linux-clk@vger.kernel.org +Cc: Elaine Zhang , + Kever Yang , + Heiko Stuebner , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + huangtao@rock-chips.com, andy.yan@rock-chips.com, + Michal Tomek , Ilya K , + Chad LeClair , + devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, + Sebastian Reichel , + kernel@collabora.com +Subject: [PATCH v9 1/7] clk: rockchip: rk3588: drop unused code +Date: Mon, 25 Mar 2024 20:33:32 +0100 [thread overview] +Message-ID: <20240325193609.237182-2-sebastian.reichel@collabora.com> (raw) +In-Reply-To: <20240325193609.237182-1-sebastian.reichel@collabora.com> + +All clocks are registered early using CLK_OF_DECLARE(), which marks +the DT node as processed. For the processed DT node the probe routine +is never called. Thus this whole code is never executed. This could +be "fixed" by using CLK_OF_DECLARE_DRIVER, which avoids marking the +DT node as processed. But then the probe routine would re-register +all the clocks by calling rk3588_clk_init() again. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk-rk3588.c | 40 ------------------------------- + 1 file changed, 40 deletions(-) + +--- a/drivers/clk/rockchip/clk-rk3588.c ++++ b/drivers/clk/rockchip/clk-rk3588.c +@@ -2502,43 +2502,3 @@ static void __init rk3588_clk_init(struc + } + + CLK_OF_DECLARE(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_init); +- +-struct clk_rk3588_inits { +- void (*inits)(struct device_node *np); +-}; +- +-static const struct clk_rk3588_inits clk_3588_cru_init = { +- .inits = rk3588_clk_init, +-}; +- +-static const struct of_device_id clk_rk3588_match_table[] = { +- { +- .compatible = "rockchip,rk3588-cru", +- .data = &clk_3588_cru_init, +- }, +- { } +-}; +- +-static int __init clk_rk3588_probe(struct platform_device *pdev) +-{ +- const struct clk_rk3588_inits *init_data; +- struct device *dev = &pdev->dev; +- +- init_data = device_get_match_data(dev); +- if (!init_data) +- return -EINVAL; +- +- if (init_data->inits) +- init_data->inits(dev->of_node); +- +- return 0; +-} +- +-static struct platform_driver clk_rk3588_driver = { +- .driver = { +- .name = "clk-rk3588", +- .of_match_table = clk_rk3588_match_table, +- .suppress_bind_attrs = true, +- }, +-}; +-builtin_platform_driver_probe(clk_rk3588_driver, clk_rk3588_probe); diff --git a/target/linux/rockchip/patches-6.6/111-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch b/target/linux/rockchip/patches-6.6/111-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch deleted file mode 100644 index d368bbb0fa..0000000000 --- a/target/linux/rockchip/patches-6.6/111-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch +++ /dev/null @@ -1,33 +0,0 @@ -From ab1b4994d0d920a17ddead2b1ae8131f9d873cba Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 24 Oct 2023 16:09:35 +0200 -Subject: [PATCH] math.h: add DIV_ROUND_UP_NO_OVERFLOW - -Add a new DIV_ROUND_UP helper, which cannot overflow when -big numbers are being used. - -Signed-off-by: Sebastian Reichel ---- - include/linux/math.h | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/include/linux/math.h -+++ b/include/linux/math.h -@@ -36,6 +36,17 @@ - - #define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP - -+/** -+ * DIV_ROUND_UP_NO_OVERFLOW - divide two numbers and always round up -+ * @n: numerator / dividend -+ * @d: denominator / divisor -+ * -+ * This functions does the same as DIV_ROUND_UP, but internally uses a -+ * division and a modulo operation instead of math tricks. This way it -+ * avoids overflowing when handling big numbers. -+ */ -+#define DIV_ROUND_UP_NO_OVERFLOW(n, d) (((n) / (d)) + !!((n) % (d))) -+ - #define DIV_ROUND_DOWN_ULL(ll, d) \ - ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) - diff --git a/target/linux/rockchip/patches-6.6/111-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch b/target/linux/rockchip/patches-6.6/111-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch deleted file mode 100644 index 321be7c665..0000000000 --- a/target/linux/rockchip/patches-6.6/111-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch +++ /dev/null @@ -1,59 +0,0 @@ -From b55f69688803c3c7d8fd51d8c833002591dd271b Mon Sep 17 00:00:00 2001 -From: Sebastian Reichel -Date: Tue, 24 Oct 2023 16:13:50 +0200 -Subject: [PATCH] clk: divider: Fix divisor masking on 64 bit platforms - -The clock framework handles clock rates as "unsigned long", so u32 on -32-bit architectures and u64 on 64-bit architectures. - -The current code casts the dividend to u64 on 32-bit to avoid a -potential overflow. For example DIV_ROUND_UP(3000000000, 1500000000) -= (3.0G + 1.5G - 1) / 1.5G = = OVERFLOW / 1.5G, which has been -introduced in commit 9556f9dad8f5 ("clk: divider: handle integer overflow -when dividing large clock rates"). - -On 64 bit platforms this masks the divisor, so that only the lower -32 bit are used. Thus requesting a frequency >= 4.3GHz results -in incorrect values. For example requesting 4300000000 (4.3 GHz) will -effectively request ca. 5 MHz. Requesting clk_round_rate(clk, ULONG_MAX) -is a bit of a special case, since that still returns correct values as -long as the parent clock is below 8.5 GHz. - -Fix this by switching to DIV_ROUND_UP_NO_OVERFLOW, which cannot -overflow. This avoids any requirements on the arguments (except -that divisor should not be 0 obviously). - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/clk-divider.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - ---- a/drivers/clk/clk-divider.c -+++ b/drivers/clk/clk-divider.c -@@ -220,7 +220,7 @@ static int _div_round_up(const struct cl - unsigned long parent_rate, unsigned long rate, - unsigned long flags) - { -- int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); -+ int div = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); - - if (flags & CLK_DIVIDER_POWER_OF_TWO) - div = __roundup_pow_of_two(div); -@@ -237,7 +237,7 @@ static int _div_round_closest(const stru - int up, down; - unsigned long up_rate, down_rate; - -- up = DIV_ROUND_UP_ULL((u64)parent_rate, rate); -+ up = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); - down = parent_rate / rate; - - if (flags & CLK_DIVIDER_POWER_OF_TWO) { -@@ -473,7 +473,7 @@ int divider_get_val(unsigned long rate, - { - unsigned int div, value; - -- div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); -+ div = DIV_ROUND_UP_NO_OVERFLOW(parent_rate, rate); - - if (!_is_valid_div(table, div, flags)) - return -EINVAL; diff --git a/target/linux/rockchip/patches-6.6/111-02-clk-rockchip-handle-missing-clocks-with-EPROBE_DEFER.patch b/target/linux/rockchip/patches-6.6/111-02-clk-rockchip-handle-missing-clocks-with-EPROBE_DEFER.patch new file mode 100644 index 0000000000..9d138264b7 --- /dev/null +++ b/target/linux/rockchip/patches-6.6/111-02-clk-rockchip-handle-missing-clocks-with-EPROBE_DEFER.patch @@ -0,0 +1,42 @@ +From: Sebastian Reichel +To: Michael Turquette , + Stephen Boyd , + linux-clk@vger.kernel.org +Cc: Elaine Zhang , + Kever Yang , + Heiko Stuebner , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + huangtao@rock-chips.com, andy.yan@rock-chips.com, + Michal Tomek , Ilya K , + Chad LeClair , + devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, + Sebastian Reichel , + kernel@collabora.com +Subject: [PATCH v9 2/7] clk: rockchip: handle missing clocks with -EPROBE_DEFER +Date: Mon, 25 Mar 2024 20:33:33 +0100 [thread overview] +Message-ID: <20240325193609.237182-3-sebastian.reichel@collabora.com> (raw) +In-Reply-To: <20240325193609.237182-1-sebastian.reichel@collabora.com> + +In the future some clocks will be registered using CLK_OF_DECLARE +and some are registered later from the driver probe routine. Any +clock handled by the probe routine should return -EPROBE_DEFER +until that routine has been called. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/clk/rockchip/clk.c ++++ b/drivers/clk/rockchip/clk.c +@@ -376,7 +376,7 @@ struct rockchip_clk_provider *rockchip_c + goto err_free; + + for (i = 0; i < nr_clks; ++i) +- clk_table[i] = ERR_PTR(-ENOENT); ++ clk_table[i] = ERR_PTR(-EPROBE_DEFER); + + ctx->reg_base = base; + ctx->clk_data.clks = clk_table; diff --git a/target/linux/rockchip/patches-6.6/111-03-clk-rockchip-rk3588-register-GATE_LINK-later.patch b/target/linux/rockchip/patches-6.6/111-03-clk-rockchip-rk3588-register-GATE_LINK-later.patch new file mode 100644 index 0000000000..5647896c35 --- /dev/null +++ b/target/linux/rockchip/patches-6.6/111-03-clk-rockchip-rk3588-register-GATE_LINK-later.patch @@ -0,0 +1,157 @@ +From: Sebastian Reichel +To: Michael Turquette , + Stephen Boyd , + linux-clk@vger.kernel.org +Cc: Elaine Zhang , + Kever Yang , + Heiko Stuebner , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + huangtao@rock-chips.com, andy.yan@rock-chips.com, + Michal Tomek , Ilya K , + Chad LeClair , + devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, + Sebastian Reichel , + kernel@collabora.com +Subject: [PATCH v9 3/7] clk: rockchip: rk3588: register GATE_LINK later +Date: Mon, 25 Mar 2024 20:33:34 +0100 [thread overview] +Message-ID: <20240325193609.237182-4-sebastian.reichel@collabora.com> (raw) +In-Reply-To: <20240325193609.237182-1-sebastian.reichel@collabora.com> + +The proper GATE_LINK implementation will use runtime PM to handle the +linked gate clocks, which requires device context. Currently all clocks +are registered early via CLK_OF_DECLARE, which is before the kernel +knows about devices. + +Moving the full clocks registration to the probe routine does not work, +since the clocks needed for timers must be registered early. + +To work around this issue, most of the clock tree is registered early, +but GATE_LINK clocks are handled in the probe routine. Since the resets +are not needed early either, they have also been moved to the probe +routine. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk-rk3588.c | 64 +++++++++++++++++++++++++++---- + 1 file changed, 56 insertions(+), 8 deletions(-) + +--- a/drivers/clk/rockchip/clk-rk3588.c ++++ b/drivers/clk/rockchip/clk-rk3588.c +@@ -266,6 +266,8 @@ static struct rockchip_pll_rate_table rk + }, \ + } + ++static struct rockchip_clk_provider *early_ctx; ++ + static struct rockchip_cpuclk_rate_table rk3588_cpub0clk_rates[] __initdata = { + RK3588_CPUB01CLK_RATE(2496000000, 1), + RK3588_CPUB01CLK_RATE(2400000000, 1), +@@ -694,7 +696,7 @@ static struct rockchip_pll_clock rk3588_ + RK3588_MODE_CON0, 10, 15, 0, rk3588_pll_rates), + }; + +-static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { ++static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { + /* + * CRU Clock-Architecture + */ +@@ -2428,7 +2430,9 @@ static struct rockchip_clk_branch rk3588 + RK3588_CLKGATE_CON(68), 5, GFLAGS), + GATE(ACLK_AV1, "aclk_av1", "aclk_av1_pre", 0, + RK3588_CLKGATE_CON(68), 2, GFLAGS), ++}; + ++static struct rockchip_clk_branch rk3588_clk_branches[] = { + GATE_LINK(ACLK_ISP1_PRE, "aclk_isp1_pre", "aclk_isp1_root", ACLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 6, GFLAGS), + GATE_LINK(HCLK_ISP1_PRE, "hclk_isp1_pre", "hclk_isp1_root", HCLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 8, GFLAGS), + GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(31), 2, GFLAGS), +@@ -2453,14 +2457,18 @@ static struct rockchip_clk_branch rk3588 + GATE_LINK(PCLK_VO1GRF, "pclk_vo1grf", "pclk_vo1_root", HCLK_VO1, CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(59), 12, GFLAGS), + }; + +-static void __init rk3588_clk_init(struct device_node *np) ++static void __init rk3588_clk_early_init(struct device_node *np) + { + struct rockchip_clk_provider *ctx; +- unsigned long clk_nr_clks; ++ unsigned long clk_nr_clks, max_clk_id1, max_clk_id2; + void __iomem *reg_base; + +- clk_nr_clks = rockchip_clk_find_max_clk_id(rk3588_clk_branches, +- ARRAY_SIZE(rk3588_clk_branches)) + 1; ++ max_clk_id1 = rockchip_clk_find_max_clk_id(rk3588_clk_branches, ++ ARRAY_SIZE(rk3588_clk_branches)); ++ max_clk_id2 = rockchip_clk_find_max_clk_id(rk3588_early_clk_branches, ++ ARRAY_SIZE(rk3588_early_clk_branches)); ++ clk_nr_clks = max(max_clk_id1, max_clk_id2) + 1; ++ + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); +@@ -2473,6 +2481,7 @@ static void __init rk3588_clk_init(struc + iounmap(reg_base); + return; + } ++ early_ctx = ctx; + + rockchip_clk_register_plls(ctx, rk3588_pll_clks, + ARRAY_SIZE(rk3588_pll_clks), +@@ -2491,14 +2500,53 @@ static void __init rk3588_clk_init(struc + &rk3588_cpub1clk_data, rk3588_cpub1clk_rates, + ARRAY_SIZE(rk3588_cpub1clk_rates)); + ++ rockchip_clk_register_branches(ctx, rk3588_early_clk_branches, ++ ARRAY_SIZE(rk3588_early_clk_branches)); ++ ++ rockchip_clk_of_add_provider(np, ctx); ++} ++CLK_OF_DECLARE_DRIVER(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_early_init); ++ ++static int clk_rk3588_probe(struct platform_device *pdev) ++{ ++ struct rockchip_clk_provider *ctx = early_ctx; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ + rockchip_clk_register_branches(ctx, rk3588_clk_branches, + ARRAY_SIZE(rk3588_clk_branches)); + +- rk3588_rst_init(np, reg_base); +- ++ rk3588_rst_init(np, ctx->reg_base); + rockchip_register_restart_notifier(ctx, RK3588_GLB_SRST_FST, NULL); + ++ /* ++ * Re-add clock provider, so that the newly added clocks are also ++ * re-parented and get their defaults configured. ++ */ ++ of_clk_del_provider(np); + rockchip_clk_of_add_provider(np, ctx); ++ ++ return 0; + } + +-CLK_OF_DECLARE(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_init); ++static const struct of_device_id clk_rk3588_match_table[] = { ++ { ++ .compatible = "rockchip,rk3588-cru", ++ }, ++ { } ++}; ++ ++static struct platform_driver clk_rk3588_driver = { ++ .probe = clk_rk3588_probe, ++ .driver = { ++ .name = "clk-rk3588", ++ .of_match_table = clk_rk3588_match_table, ++ .suppress_bind_attrs = true, ++ }, ++}; ++ ++static int __init rockchip_clk_rk3588_drv_register(void) ++{ ++ return platform_driver_register(&clk_rk3588_driver); ++} ++core_initcall(rockchip_clk_rk3588_drv_register); diff --git a/target/linux/rockchip/patches-6.6/111-04-clk-rockchip-expose-rockchip_clk_set_lookup.patch b/target/linux/rockchip/patches-6.6/111-04-clk-rockchip-expose-rockchip_clk_set_lookup.patch new file mode 100644 index 0000000000..ef176f68d7 --- /dev/null +++ b/target/linux/rockchip/patches-6.6/111-04-clk-rockchip-expose-rockchip_clk_set_lookup.patch @@ -0,0 +1,104 @@ +From: Sebastian Reichel +To: Michael Turquette , + Stephen Boyd , + linux-clk@vger.kernel.org +Cc: Elaine Zhang , + Kever Yang , + Heiko Stuebner , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + huangtao@rock-chips.com, andy.yan@rock-chips.com, + Michal Tomek , Ilya K , + Chad LeClair , + devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, + Sebastian Reichel , + kernel@collabora.com +Subject: [PATCH v9 4/7] clk: rockchip: expose rockchip_clk_set_lookup +Date: Mon, 25 Mar 2024 20:33:35 +0100 [thread overview] +Message-ID: <20240325193609.237182-5-sebastian.reichel@collabora.com> (raw) +In-Reply-To: <20240325193609.237182-1-sebastian.reichel@collabora.com> + +Move rockchip_clk_add_lookup to clk.h, so that it can be used +by sub-devices with their own driver. These might also have to +do a lookup, so rename the function to rockchip_clk_set_lookup +and add a matching rockchip_clk_add_lookup. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk.c | 14 ++++---------- + drivers/clk/rockchip/clk.h | 12 ++++++++++++ + 2 files changed, 16 insertions(+), 10 deletions(-) + +--- a/drivers/clk/rockchip/clk.c ++++ b/drivers/clk/rockchip/clk.c +@@ -197,12 +197,6 @@ static void rockchip_fractional_approxim + clk_fractional_divider_general_approximation(hw, rate, parent_rate, m, n); + } + +-static void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx, +- struct clk *clk, unsigned int id) +-{ +- ctx->clk_data.clks[id] = clk; +-} +- + static struct clk *rockchip_clk_register_frac_branch( + struct rockchip_clk_provider *ctx, const char *name, + const char *const *parent_names, u8 num_parents, +@@ -292,7 +286,7 @@ static struct clk *rockchip_clk_register + return mux_clk; + } + +- rockchip_clk_add_lookup(ctx, mux_clk, child->id); ++ rockchip_clk_set_lookup(ctx, mux_clk, child->id); + + /* notifier on the fraction divider to catch rate changes */ + if (frac->mux_frac_idx >= 0) { +@@ -424,7 +418,7 @@ void rockchip_clk_register_plls(struct r + continue; + } + +- rockchip_clk_add_lookup(ctx, clk, list->id); ++ rockchip_clk_set_lookup(ctx, clk, list->id); + } + } + EXPORT_SYMBOL_GPL(rockchip_clk_register_plls); +@@ -585,7 +579,7 @@ void rockchip_clk_register_branches(stru + continue; + } + +- rockchip_clk_add_lookup(ctx, clk, list->id); ++ rockchip_clk_set_lookup(ctx, clk, list->id); + } + } + EXPORT_SYMBOL_GPL(rockchip_clk_register_branches); +@@ -609,7 +603,7 @@ void rockchip_clk_register_armclk(struct + return; + } + +- rockchip_clk_add_lookup(ctx, clk, lookup_id); ++ rockchip_clk_set_lookup(ctx, clk, lookup_id); + } + EXPORT_SYMBOL_GPL(rockchip_clk_register_armclk); + +--- a/drivers/clk/rockchip/clk.h ++++ b/drivers/clk/rockchip/clk.h +@@ -969,6 +969,18 @@ struct rockchip_clk_branch { + #define SGRF_GATE(_id, cname, pname) \ + FACTOR(_id, cname, pname, 0, 1, 1) + ++static inline struct clk *rockchip_clk_get_lookup(struct rockchip_clk_provider *ctx, ++ unsigned int id) ++{ ++ return ctx->clk_data.clks[id]; ++} ++ ++static inline void rockchip_clk_set_lookup(struct rockchip_clk_provider *ctx, ++ struct clk *clk, unsigned int id) ++{ ++ ctx->clk_data.clks[id] = clk; ++} ++ + struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, + void __iomem *base, unsigned long nr_clks); + void rockchip_clk_of_add_provider(struct device_node *np, diff --git a/target/linux/rockchip/patches-6.6/111-05-clk-rockchip-fix-error-for-unknown-clocks.patch b/target/linux/rockchip/patches-6.6/111-05-clk-rockchip-fix-error-for-unknown-clocks.patch new file mode 100644 index 0000000000..4db2b80674 --- /dev/null +++ b/target/linux/rockchip/patches-6.6/111-05-clk-rockchip-fix-error-for-unknown-clocks.patch @@ -0,0 +1,49 @@ +From: Sebastian Reichel +To: Michael Turquette , + Stephen Boyd , + linux-clk@vger.kernel.org +Cc: Elaine Zhang , + Kever Yang , + Heiko Stuebner , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + huangtao@rock-chips.com, andy.yan@rock-chips.com, + Michal Tomek , Ilya K , + Chad LeClair , + devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, + Sebastian Reichel , + kernel@collabora.com +Subject: [PATCH v9 5/7] clk: rockchip: fix error for unknown clocks +Date: Mon, 25 Mar 2024 20:33:36 +0100 [thread overview] +Message-ID: <20240325193609.237182-6-sebastian.reichel@collabora.com> (raw) +In-Reply-To: <20240325193609.237182-1-sebastian.reichel@collabora.com> + +There is a clk == NULL check after the switch to check for +unsupported clk types. Since clk is re-assigned in a loop, +this check is useless right now for anything but the first +round. Let's fix this up by assigning clk = NULL in the +loop before the switch statement. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/clk/rockchip/clk.c ++++ b/drivers/clk/rockchip/clk.c +@@ -444,12 +444,13 @@ void rockchip_clk_register_branches(stru + struct rockchip_clk_branch *list, + unsigned int nr_clk) + { +- struct clk *clk = NULL; ++ struct clk *clk; + unsigned int idx; + unsigned long flags; + + for (idx = 0; idx < nr_clk; idx++, list++) { + flags = list->flags; ++ clk = NULL; + + /* catch simple muxes */ + switch (list->branch_type) { diff --git a/target/linux/rockchip/patches-6.6/111-06-clk-rockchip-implement-linked-gate-clock-support.patch b/target/linux/rockchip/patches-6.6/111-06-clk-rockchip-implement-linked-gate-clock-support.patch new file mode 100644 index 0000000000..999c6223cd --- /dev/null +++ b/target/linux/rockchip/patches-6.6/111-06-clk-rockchip-implement-linked-gate-clock-support.patch @@ -0,0 +1,342 @@ +From: Sebastian Reichel +To: Michael Turquette , + Stephen Boyd , + linux-clk@vger.kernel.org +Cc: Elaine Zhang , + Kever Yang , + Heiko Stuebner , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + huangtao@rock-chips.com, andy.yan@rock-chips.com, + Michal Tomek , Ilya K , + Chad LeClair , + devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, + Sebastian Reichel , + kernel@collabora.com +Subject: [PATCH v9 6/7] clk: rockchip: implement linked gate clock support +Date: Mon, 25 Mar 2024 20:33:37 +0100 [thread overview] +Message-ID: <20240325193609.237182-7-sebastian.reichel@collabora.com> (raw) +In-Reply-To: <20240325193609.237182-1-sebastian.reichel@collabora.com> + +Recent Rockchip SoCs have a new hardware block called Native Interface +Unit (NIU), which gates clocks to devices behind them. These clock +gates will only have a running output clock when all of the following +conditions are met: + +1. the parent clock is enabled +2. the enable bit is set correctly +3. the linked clock is enabled + +To handle them this code registers them as a normal gate type clock, +which takes care of condition 1 + 2. The linked clock is handled by +using runtime PM clocks. Handling it via runtime PM requires setting +up a struct device for each of these clocks with a driver attached +to use the correct runtime PM operations. Thus the complete handling +of these clocks has been moved into its own driver. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/Makefile | 1 + + drivers/clk/rockchip/clk-rk3588.c | 23 +------ + drivers/clk/rockchip/clk.c | 52 ++++++++++++++++ + drivers/clk/rockchip/clk.h | 25 ++++++++ + drivers/clk/rockchip/gate-link.c | 99 +++++++++++++++++++++++++++++++ + 5 files changed, 179 insertions(+), 21 deletions(-) + create mode 100644 drivers/clk/rockchip/gate-link.c + +--- a/drivers/clk/rockchip/Makefile ++++ b/drivers/clk/rockchip/Makefile +@@ -13,6 +13,7 @@ clk-rockchip-y += clk-inverter.o + clk-rockchip-y += clk-mmc-phase.o + clk-rockchip-y += clk-muxgrf.o + clk-rockchip-y += clk-ddr.o ++clk-rockchip-y += gate-link.o + clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o + + obj-$(CONFIG_CLK_PX30) += clk-px30.o +--- a/drivers/clk/rockchip/clk-rk3588.c ++++ b/drivers/clk/rockchip/clk-rk3588.c +@@ -12,25 +12,6 @@ + #include + #include "clk.h" + +-/* +- * Recent Rockchip SoCs have a new hardware block called Native Interface +- * Unit (NIU), which gates clocks to devices behind them. These effectively +- * need two parent clocks. +- * +- * Downstream enables the linked clock via runtime PM whenever the gate is +- * enabled. This implementation uses separate clock nodes for each of the +- * linked gate clocks, which leaks parts of the clock tree into DT. +- * +- * The GATE_LINK macro instead takes the second parent via 'linkname', but +- * ignores the information. Once the clock framework is ready to handle it, the +- * information should be passed on here. But since these clocks are required to +- * access multiple relevant IP blocks, such as PCIe or USB, we mark all linked +- * clocks critical until a better solution is available. This will waste some +- * power, but avoids leaking implementation details into DT or hanging the +- * system. +- */ +-#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \ +- GATE(_id, cname, pname, f, o, b, gf) + #define RK3588_LINKED_CLK CLK_IS_CRITICAL + + +@@ -2513,8 +2494,8 @@ static int clk_rk3588_probe(struct platf + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + +- rockchip_clk_register_branches(ctx, rk3588_clk_branches, +- ARRAY_SIZE(rk3588_clk_branches)); ++ rockchip_clk_register_late_branches(dev, ctx, rk3588_clk_branches, ++ ARRAY_SIZE(rk3588_clk_branches)); + + rk3588_rst_init(np, ctx->reg_base); + rockchip_register_restart_notifier(ctx, RK3588_GLB_SRST_FST, NULL); +--- a/drivers/clk/rockchip/clk.c ++++ b/drivers/clk/rockchip/clk.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -440,6 +441,29 @@ unsigned long rockchip_clk_find_max_clk_ + } + EXPORT_SYMBOL_GPL(rockchip_clk_find_max_clk_id); + ++static struct platform_device *rockchip_clk_register_gate_link( ++ struct device *parent_dev, ++ struct rockchip_clk_provider *ctx, ++ struct rockchip_clk_branch *clkbr) ++{ ++ struct rockchip_gate_link_platdata gate_link_pdata = { ++ .ctx = ctx, ++ .clkbr = clkbr, ++ }; ++ ++ struct platform_device_info pdevinfo = { ++ .parent = parent_dev, ++ .name = "rockchip-gate-link-clk", ++ .id = clkbr->id, ++ .fwnode = dev_fwnode(parent_dev), ++ .of_node_reused = true, ++ .data = &gate_link_pdata, ++ .size_data = sizeof(gate_link_pdata), ++ }; ++ ++ return platform_device_register_full(&pdevinfo); ++} ++ + void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, + unsigned int nr_clk) +@@ -565,6 +589,9 @@ void rockchip_clk_register_branches(stru + list->div_width, list->div_flags, + ctx->reg_base, &ctx->lock); + break; ++ case branch_linked_gate: ++ /* must be registered late, fall-through for error message */ ++ break; + } + + /* none of the cases above matched */ +@@ -585,6 +612,31 @@ void rockchip_clk_register_branches(stru + } + EXPORT_SYMBOL_GPL(rockchip_clk_register_branches); + ++void rockchip_clk_register_late_branches(struct device *dev, ++ struct rockchip_clk_provider *ctx, ++ struct rockchip_clk_branch *list, ++ unsigned int nr_clk) ++{ ++ unsigned int idx; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ struct platform_device *pdev = NULL; ++ ++ switch (list->branch_type) { ++ case branch_linked_gate: ++ pdev = rockchip_clk_register_gate_link(dev, ctx, list); ++ break; ++ default: ++ dev_err(dev, "unknown clock type %d\n", list->branch_type); ++ break; ++ } ++ ++ if (!pdev) ++ dev_err(dev, "failed to register device for clock %s\n", list->name); ++ } ++} ++EXPORT_SYMBOL_GPL(rockchip_clk_register_late_branches); ++ + void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx, + unsigned int lookup_id, + const char *name, const char *const *parent_names, +--- a/drivers/clk/rockchip/clk.h ++++ b/drivers/clk/rockchip/clk.h +@@ -517,6 +517,7 @@ enum rockchip_clk_branch_type { + branch_divider, + branch_fraction_divider, + branch_gate, ++ branch_linked_gate, + branch_mmc, + branch_inverter, + branch_factor, +@@ -544,6 +545,7 @@ struct rockchip_clk_branch { + int gate_offset; + u8 gate_shift; + u8 gate_flags; ++ unsigned int linked_clk_id; + struct rockchip_clk_branch *child; + }; + +@@ -842,6 +844,20 @@ struct rockchip_clk_branch { + .gate_flags = gf, \ + } + ++#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \ ++ { \ ++ .id = _id, \ ++ .branch_type = branch_linked_gate, \ ++ .name = cname, \ ++ .parent_names = (const char *[]){ pname }, \ ++ .linked_clk_id = linkedclk, \ ++ .num_parents = 1, \ ++ .flags = f, \ ++ .gate_offset = o, \ ++ .gate_shift = b, \ ++ .gate_flags = gf, \ ++ } ++ + #define MMC(_id, cname, pname, offset, shift) \ + { \ + .id = _id, \ +@@ -981,6 +997,11 @@ static inline void rockchip_clk_set_look + ctx->clk_data.clks[id] = clk; + } + ++struct rockchip_gate_link_platdata { ++ struct rockchip_clk_provider *ctx; ++ struct rockchip_clk_branch *clkbr; ++}; ++ + struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np, + void __iomem *base, unsigned long nr_clks); + void rockchip_clk_of_add_provider(struct device_node *np, +@@ -990,6 +1011,10 @@ unsigned long rockchip_clk_find_max_clk_ + void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, + unsigned int nr_clk); ++void rockchip_clk_register_late_branches(struct device *dev, ++ struct rockchip_clk_provider *ctx, ++ struct rockchip_clk_branch *list, ++ unsigned int nr_clk); + void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx, + struct rockchip_pll_clock *pll_list, + unsigned int nr_pll, int grf_lock_offset); +--- /dev/null ++++ b/drivers/clk/rockchip/gate-link.c +@@ -0,0 +1,99 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2024 Collabora Ltd. ++ * Author: Sebastian Reichel ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++static int rk_clk_gate_link_register(struct device *dev, ++ struct rockchip_clk_provider *ctx, ++ struct rockchip_clk_branch *clkbr) ++{ ++ unsigned long flags = clkbr->flags | CLK_SET_RATE_PARENT; ++ struct clk *clk; ++ ++ clk = clk_register_gate(dev, clkbr->name, clkbr->parent_names[0], ++ flags, ctx->reg_base + clkbr->gate_offset, ++ clkbr->gate_shift, clkbr->gate_flags, ++ &ctx->lock); ++ ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ rockchip_clk_set_lookup(ctx, clk, clkbr->id); ++ return 0; ++} ++ ++static int rk_clk_gate_link_probe(struct platform_device *pdev) ++{ ++ struct rockchip_gate_link_platdata *pdata; ++ struct device *dev = &pdev->dev; ++ struct clk *linked_clk; ++ int ret; ++ ++ pdata = dev_get_platdata(dev); ++ if (!pdata) ++ return dev_err_probe(dev, -ENODEV, "missing platform data"); ++ ++ ret = devm_pm_runtime_enable(dev); ++ if (ret) ++ return ret; ++ ++ ret = devm_pm_clk_create(dev); ++ if (ret) ++ return ret; ++ ++ linked_clk = rockchip_clk_get_lookup(pdata->ctx, pdata->clkbr->linked_clk_id); ++ ret = pm_clk_add_clk(dev, linked_clk); ++ if (ret) ++ return ret; ++ ++ ret = rk_clk_gate_link_register(dev, pdata->ctx, pdata->clkbr); ++ if (ret) ++ goto err; ++ ++ return 0; ++ ++err: ++ pm_clk_remove_clk(dev, linked_clk); ++ return ret; ++} ++ ++static void rk_clk_gate_link_remove(struct platform_device *pdev) ++{ ++ struct rockchip_gate_link_platdata *pdata; ++ struct device *dev = &pdev->dev; ++ struct clk *clk, *linked_clk; ++ ++ pdata = dev_get_platdata(dev); ++ clk = rockchip_clk_get_lookup(pdata->ctx, pdata->clkbr->id); ++ linked_clk = rockchip_clk_get_lookup(pdata->ctx, pdata->clkbr->linked_clk_id); ++ rockchip_clk_set_lookup(pdata->ctx, ERR_PTR(-ENODEV), pdata->clkbr->id); ++ clk_unregister_gate(clk); ++ pm_clk_remove_clk(dev, linked_clk); ++} ++ ++static const struct dev_pm_ops rk_clk_gate_link_pm_ops = { ++ SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) ++}; ++ ++struct platform_driver rk_clk_gate_link_driver = { ++ .probe = rk_clk_gate_link_probe, ++ .remove_new = rk_clk_gate_link_remove, ++ .driver = { ++ .name = "rockchip-gate-link-clk", ++ .pm = &rk_clk_gate_link_pm_ops, ++ }, ++}; ++ ++static int __init rk_clk_gate_link_drv_register(void) ++{ ++ return platform_driver_register(&rk_clk_gate_link_driver); ++} ++core_initcall(rk_clk_gate_link_drv_register); diff --git a/target/linux/rockchip/patches-6.6/111-07-clk-rockchip-rk3588-drop-RK3588_LINKED_CLK.patch b/target/linux/rockchip/patches-6.6/111-07-clk-rockchip-rk3588-drop-RK3588_LINKED_CLK.patch new file mode 100644 index 0000000000..cbae321b85 --- /dev/null +++ b/target/linux/rockchip/patches-6.6/111-07-clk-rockchip-rk3588-drop-RK3588_LINKED_CLK.patch @@ -0,0 +1,126 @@ +From: Sebastian Reichel +To: Michael Turquette , + Stephen Boyd , + linux-clk@vger.kernel.org +Cc: Elaine Zhang , + Kever Yang , + Heiko Stuebner , + Rob Herring , + Krzysztof Kozlowski , + Conor Dooley , + huangtao@rock-chips.com, andy.yan@rock-chips.com, + Michal Tomek , Ilya K , + Chad LeClair , + devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, + Sebastian Reichel , + kernel@collabora.com +Subject: [PATCH v9 7/7] clk: rockchip: rk3588: drop RK3588_LINKED_CLK +Date: Mon, 25 Mar 2024 20:33:38 +0100 [thread overview] +Message-ID: <20240325193609.237182-8-sebastian.reichel@collabora.com> (raw) +In-Reply-To: <20240325193609.237182-1-sebastian.reichel@collabora.com> + +With the proper GATE_LINK support, we no longer need to keep the +linked clocks always on. Thus it's time to drop the CLK_IS_CRITICAL +flag for them. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk-rk3588.c | 27 ++++++++++++--------------- + 1 file changed, 12 insertions(+), 15 deletions(-) + +--- a/drivers/clk/rockchip/clk-rk3588.c ++++ b/drivers/clk/rockchip/clk-rk3588.c +@@ -12,9 +12,6 @@ + #include + #include "clk.h" + +-#define RK3588_LINKED_CLK CLK_IS_CRITICAL +- +- + #define RK3588_GRF_SOC_STATUS0 0x600 + #define RK3588_PHYREF_ALT_GATE 0xc38 + +@@ -1439,7 +1436,7 @@ static struct rockchip_clk_branch rk3588 + COMPOSITE_NODIV(HCLK_NVM_ROOT, "hclk_nvm_root", mux_200m_100m_50m_24m_p, 0, + RK3588_CLKSEL_CON(77), 0, 2, MFLAGS, + RK3588_CLKGATE_CON(31), 0, GFLAGS), +- COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, RK3588_LINKED_CLK, ++ COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, 0, + RK3588_CLKSEL_CON(77), 7, 1, MFLAGS, 2, 5, DFLAGS, + RK3588_CLKGATE_CON(31), 1, GFLAGS), + GATE(ACLK_EMMC, "aclk_emmc", "aclk_nvm_root", 0, +@@ -1668,13 +1665,13 @@ static struct rockchip_clk_branch rk3588 + RK3588_CLKGATE_CON(42), 9, GFLAGS), + + /* vdpu */ +- COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, RK3588_LINKED_CLK, ++ COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, 0, + RK3588_CLKSEL_CON(98), 5, 2, MFLAGS, 0, 5, DFLAGS, + RK3588_CLKGATE_CON(44), 0, GFLAGS), + COMPOSITE_NODIV(ACLK_VDPU_LOW_ROOT, "aclk_vdpu_low_root", mux_400m_200m_100m_24m_p, 0, + RK3588_CLKSEL_CON(98), 7, 2, MFLAGS, + RK3588_CLKGATE_CON(44), 1, GFLAGS), +- COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, ++ COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, 0, + RK3588_CLKSEL_CON(98), 9, 2, MFLAGS, + RK3588_CLKGATE_CON(44), 2, GFLAGS), + COMPOSITE(ACLK_JPEG_DECODER_ROOT, "aclk_jpeg_decoder_root", gpll_cpll_aupll_spll_p, 0, +@@ -1725,9 +1722,9 @@ static struct rockchip_clk_branch rk3588 + COMPOSITE(ACLK_RKVENC0_ROOT, "aclk_rkvenc0_root", gpll_cpll_npll_p, 0, + RK3588_CLKSEL_CON(102), 7, 2, MFLAGS, 2, 5, DFLAGS, + RK3588_CLKGATE_CON(47), 1, GFLAGS), +- GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", RK3588_LINKED_CLK, ++ GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", 0, + RK3588_CLKGATE_CON(47), 4, GFLAGS), +- GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", RK3588_LINKED_CLK, ++ GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", 0, + RK3588_CLKGATE_CON(47), 5, GFLAGS), + COMPOSITE(CLK_RKVENC0_CORE, "clk_rkvenc0_core", gpll_cpll_aupll_npll_p, 0, + RK3588_CLKSEL_CON(102), 14, 2, MFLAGS, 9, 5, DFLAGS, +@@ -1737,10 +1734,10 @@ static struct rockchip_clk_branch rk3588 + RK3588_CLKGATE_CON(48), 6, GFLAGS), + + /* vi */ +- COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, RK3588_LINKED_CLK, ++ COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, 0, + RK3588_CLKSEL_CON(106), 5, 3, MFLAGS, 0, 5, DFLAGS, + RK3588_CLKGATE_CON(49), 0, GFLAGS), +- COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, ++ COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, 0, + RK3588_CLKSEL_CON(106), 8, 2, MFLAGS, + RK3588_CLKGATE_CON(49), 1, GFLAGS), + COMPOSITE_NODIV(PCLK_VI_ROOT, "pclk_vi_root", mux_100m_50m_24m_p, 0, +@@ -1910,10 +1907,10 @@ static struct rockchip_clk_branch rk3588 + COMPOSITE(ACLK_VOP_ROOT, "aclk_vop_root", gpll_cpll_dmyaupll_npll_spll_p, 0, + RK3588_CLKSEL_CON(110), 5, 3, MFLAGS, 0, 5, DFLAGS, + RK3588_CLKGATE_CON(52), 0, GFLAGS), +- COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, RK3588_LINKED_CLK, ++ COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, 0, + RK3588_CLKSEL_CON(110), 8, 2, MFLAGS, + RK3588_CLKGATE_CON(52), 1, GFLAGS), +- COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, ++ COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, 0, + RK3588_CLKSEL_CON(110), 10, 2, MFLAGS, + RK3588_CLKGATE_CON(52), 2, GFLAGS), + COMPOSITE_NODIV(PCLK_VOP_ROOT, "pclk_vop_root", mux_100m_50m_24m_p, 0, +@@ -2416,7 +2413,7 @@ static struct rockchip_clk_branch rk3588 + static struct rockchip_clk_branch rk3588_clk_branches[] = { + GATE_LINK(ACLK_ISP1_PRE, "aclk_isp1_pre", "aclk_isp1_root", ACLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 6, GFLAGS), + GATE_LINK(HCLK_ISP1_PRE, "hclk_isp1_pre", "hclk_isp1_root", HCLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 8, GFLAGS), +- GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(31), 2, GFLAGS), ++ GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, 0, RK3588_CLKGATE_CON(31), 2, GFLAGS), + GATE_LINK(ACLK_USB, "aclk_usb", "aclk_usb_root", ACLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(42), 2, GFLAGS), + GATE_LINK(HCLK_USB, "hclk_usb", "hclk_usb_root", HCLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(42), 3, GFLAGS), + GATE_LINK(ACLK_JPEG_DECODER_PRE, "aclk_jpeg_decoder_pre", "aclk_jpeg_decoder_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(44), 7, GFLAGS), +@@ -2428,9 +2425,9 @@ static struct rockchip_clk_branch rk3588 + GATE_LINK(HCLK_RKVDEC1_PRE, "hclk_rkvdec1_pre", "hclk_rkvdec1_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(41), 4, GFLAGS), + GATE_LINK(ACLK_RKVDEC1_PRE, "aclk_rkvdec1_pre", "aclk_rkvdec1_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(41), 5, GFLAGS), + GATE_LINK(ACLK_HDCP0_PRE, "aclk_hdcp0_pre", "aclk_vo0_root", ACLK_VOP_LOW_ROOT, 0, RK3588_CLKGATE_CON(55), 9, GFLAGS), +- GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", HCLK_VOP_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(55), 5, GFLAGS), ++ GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", HCLK_VOP_ROOT, 0, RK3588_CLKGATE_CON(55), 5, GFLAGS), + GATE_LINK(ACLK_HDCP1_PRE, "aclk_hdcp1_pre", "aclk_hdcp1_root", ACLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(59), 6, GFLAGS), +- GATE_LINK(HCLK_VO1, "hclk_vo1", "hclk_vo1_root", HCLK_VO1USB_TOP_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(59), 9, GFLAGS), ++ GATE_LINK(HCLK_VO1, "hclk_vo1", "hclk_vo1_root", HCLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(59), 9, GFLAGS), + GATE_LINK(ACLK_AV1_PRE, "aclk_av1_pre", "aclk_av1_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(68), 1, GFLAGS), + GATE_LINK(PCLK_AV1_PRE, "pclk_av1_pre", "pclk_av1_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(68), 4, GFLAGS), + GATE_LINK(HCLK_SDIO_PRE, "hclk_sdio_pre", "hclk_sdio_root", HCLK_NVM, 0, RK3588_CLKGATE_CON(75), 1, GFLAGS), diff --git a/target/linux/rockchip/patches-6.6/111-08-clk-rockchip-implement-proper-GATE_LINK-support.patch b/target/linux/rockchip/patches-6.6/111-08-clk-rockchip-implement-proper-GATE_LINK-support.patch deleted file mode 100644 index 61635661b8..0000000000 --- a/target/linux/rockchip/patches-6.6/111-08-clk-rockchip-implement-proper-GATE_LINK-support.patch +++ /dev/null @@ -1,435 +0,0 @@ -From: Sebastian Reichel -To: Michael Turquette , - Stephen Boyd , - linux-clk@vger.kernel.org -Cc: Elaine Zhang , - Kever Yang , - Heiko Stuebner , - Rob Herring , - Krzysztof Kozlowski , - Conor Dooley , - huangtao@rock-chips.com, andy.yan@rock-chips.com, - devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, - Sebastian Reichel , - kernel@collabora.com -Subject: [PATCH v8 7/7] clk: rockchip: implement proper GATE_LINK support -Date: Fri, 26 Jan 2024 19:18:28 +0100 [thread overview] -Message-ID: <20240126182919.48402-8-sebastian.reichel@collabora.com> (raw) -In-Reply-To: <20240126182919.48402-1-sebastian.reichel@collabora.com> - -Recent Rockchip SoCs have a new hardware block called Native Interface -Unit (NIU), which gates clocks to devices behind them. These effectively -need two parent clocks. - -GATE_LINK type clocks handle the second parent via 'linkedclk' by using -runtime PM clocks. To make that possible a new platform device is created -for every clock handled in this way. - -Note, that before this patch clk_rk3588_probe() has never been called, -because CLK_OF_DECLARE marks the DT node as processed. This patch replaces -that with CLK_OF_DECLARE_DRIVER and thus the probe function is used now. -This is necessary to have 'struct device' available. - -Also instead of builtin_platform_driver_probe, the driver has been -switched to use core_initcall, since it should be fully probed before -the Rockchip PM domain driver (and that is using postcore_initcall). - -Signed-off-by: Sebastian Reichel ---- - drivers/clk/rockchip/clk-rk3588.c | 122 +++++++++++++----------------- - drivers/clk/rockchip/clk.c | 69 ++++++++++++++++- - drivers/clk/rockchip/clk.h | 16 ++++ - 3 files changed, 138 insertions(+), 69 deletions(-) - ---- a/drivers/clk/rockchip/clk-rk3588.c -+++ b/drivers/clk/rockchip/clk-rk3588.c -@@ -12,28 +12,6 @@ - #include - #include "clk.h" - --/* -- * Recent Rockchip SoCs have a new hardware block called Native Interface -- * Unit (NIU), which gates clocks to devices behind them. These effectively -- * need two parent clocks. -- * -- * Downstream enables the linked clock via runtime PM whenever the gate is -- * enabled. This implementation uses separate clock nodes for each of the -- * linked gate clocks, which leaks parts of the clock tree into DT. -- * -- * The GATE_LINK macro instead takes the second parent via 'linkname', but -- * ignores the information. Once the clock framework is ready to handle it, the -- * information should be passed on here. But since these clocks are required to -- * access multiple relevant IP blocks, such as PCIe or USB, we mark all linked -- * clocks critical until a better solution is available. This will waste some -- * power, but avoids leaking implementation details into DT or hanging the -- * system. -- */ --#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \ -- GATE(_id, cname, pname, f, o, b, gf) --#define RK3588_LINKED_CLK CLK_IS_CRITICAL -- -- - #define RK3588_GRF_SOC_STATUS0 0x600 - #define RK3588_PHYREF_ALT_GATE 0xc38 - -@@ -266,6 +244,8 @@ static struct rockchip_pll_rate_table rk - }, \ - } - -+static struct rockchip_clk_provider *early_ctx; -+ - static struct rockchip_cpuclk_rate_table rk3588_cpub0clk_rates[] __initdata = { - RK3588_CPUB01CLK_RATE(2496000000, 1), - RK3588_CPUB01CLK_RATE(2400000000, 1), -@@ -694,7 +674,7 @@ static struct rockchip_pll_clock rk3588_ - RK3588_MODE_CON0, 10, 15, 0, rk3588_pll_rates), - }; - --static struct rockchip_clk_branch rk3588_clk_branches[] __initdata = { -+static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = { - /* - * CRU Clock-Architecture - */ -@@ -1456,7 +1436,7 @@ static struct rockchip_clk_branch rk3588 - COMPOSITE_NODIV(HCLK_NVM_ROOT, "hclk_nvm_root", mux_200m_100m_50m_24m_p, 0, - RK3588_CLKSEL_CON(77), 0, 2, MFLAGS, - RK3588_CLKGATE_CON(31), 0, GFLAGS), -- COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, RK3588_LINKED_CLK, -+ COMPOSITE(ACLK_NVM_ROOT, "aclk_nvm_root", gpll_cpll_p, 0, - RK3588_CLKSEL_CON(77), 7, 1, MFLAGS, 2, 5, DFLAGS, - RK3588_CLKGATE_CON(31), 1, GFLAGS), - GATE(ACLK_EMMC, "aclk_emmc", "aclk_nvm_root", 0, -@@ -1685,13 +1665,13 @@ static struct rockchip_clk_branch rk3588 - RK3588_CLKGATE_CON(42), 9, GFLAGS), - - /* vdpu */ -- COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, RK3588_LINKED_CLK, -+ COMPOSITE(ACLK_VDPU_ROOT, "aclk_vdpu_root", gpll_cpll_aupll_p, 0, - RK3588_CLKSEL_CON(98), 5, 2, MFLAGS, 0, 5, DFLAGS, - RK3588_CLKGATE_CON(44), 0, GFLAGS), - COMPOSITE_NODIV(ACLK_VDPU_LOW_ROOT, "aclk_vdpu_low_root", mux_400m_200m_100m_24m_p, 0, - RK3588_CLKSEL_CON(98), 7, 2, MFLAGS, - RK3588_CLKGATE_CON(44), 1, GFLAGS), -- COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, -+ COMPOSITE_NODIV(HCLK_VDPU_ROOT, "hclk_vdpu_root", mux_200m_100m_50m_24m_p, 0, - RK3588_CLKSEL_CON(98), 9, 2, MFLAGS, - RK3588_CLKGATE_CON(44), 2, GFLAGS), - COMPOSITE(ACLK_JPEG_DECODER_ROOT, "aclk_jpeg_decoder_root", gpll_cpll_aupll_spll_p, 0, -@@ -1742,9 +1722,9 @@ static struct rockchip_clk_branch rk3588 - COMPOSITE(ACLK_RKVENC0_ROOT, "aclk_rkvenc0_root", gpll_cpll_npll_p, 0, - RK3588_CLKSEL_CON(102), 7, 2, MFLAGS, 2, 5, DFLAGS, - RK3588_CLKGATE_CON(47), 1, GFLAGS), -- GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", RK3588_LINKED_CLK, -+ GATE(HCLK_RKVENC0, "hclk_rkvenc0", "hclk_rkvenc0_root", 0, - RK3588_CLKGATE_CON(47), 4, GFLAGS), -- GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", RK3588_LINKED_CLK, -+ GATE(ACLK_RKVENC0, "aclk_rkvenc0", "aclk_rkvenc0_root", 0, - RK3588_CLKGATE_CON(47), 5, GFLAGS), - COMPOSITE(CLK_RKVENC0_CORE, "clk_rkvenc0_core", gpll_cpll_aupll_npll_p, 0, - RK3588_CLKSEL_CON(102), 14, 2, MFLAGS, 9, 5, DFLAGS, -@@ -1754,10 +1734,10 @@ static struct rockchip_clk_branch rk3588 - RK3588_CLKGATE_CON(48), 6, GFLAGS), - - /* vi */ -- COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, RK3588_LINKED_CLK, -+ COMPOSITE(ACLK_VI_ROOT, "aclk_vi_root", gpll_cpll_npll_aupll_spll_p, 0, - RK3588_CLKSEL_CON(106), 5, 3, MFLAGS, 0, 5, DFLAGS, - RK3588_CLKGATE_CON(49), 0, GFLAGS), -- COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, -+ COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_200m_100m_50m_24m_p, 0, - RK3588_CLKSEL_CON(106), 8, 2, MFLAGS, - RK3588_CLKGATE_CON(49), 1, GFLAGS), - COMPOSITE_NODIV(PCLK_VI_ROOT, "pclk_vi_root", mux_100m_50m_24m_p, 0, -@@ -1927,10 +1907,10 @@ static struct rockchip_clk_branch rk3588 - COMPOSITE(ACLK_VOP_ROOT, "aclk_vop_root", gpll_cpll_dmyaupll_npll_spll_p, 0, - RK3588_CLKSEL_CON(110), 5, 3, MFLAGS, 0, 5, DFLAGS, - RK3588_CLKGATE_CON(52), 0, GFLAGS), -- COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, RK3588_LINKED_CLK, -+ COMPOSITE_NODIV(ACLK_VOP_LOW_ROOT, "aclk_vop_low_root", mux_400m_200m_100m_24m_p, 0, - RK3588_CLKSEL_CON(110), 8, 2, MFLAGS, - RK3588_CLKGATE_CON(52), 1, GFLAGS), -- COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, RK3588_LINKED_CLK, -+ COMPOSITE_NODIV(HCLK_VOP_ROOT, "hclk_vop_root", mux_200m_100m_50m_24m_p, 0, - RK3588_CLKSEL_CON(110), 10, 2, MFLAGS, - RK3588_CLKGATE_CON(52), 2, GFLAGS), - COMPOSITE_NODIV(PCLK_VOP_ROOT, "pclk_vop_root", mux_100m_50m_24m_p, 0, -@@ -2428,10 +2408,12 @@ static struct rockchip_clk_branch rk3588 - RK3588_CLKGATE_CON(68), 5, GFLAGS), - GATE(ACLK_AV1, "aclk_av1", "aclk_av1_pre", 0, - RK3588_CLKGATE_CON(68), 2, GFLAGS), -+}; - -+static struct rockchip_clk_branch rk3588_clk_branches[] = { - GATE_LINK(ACLK_ISP1_PRE, "aclk_isp1_pre", "aclk_isp1_root", ACLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 6, GFLAGS), - GATE_LINK(HCLK_ISP1_PRE, "hclk_isp1_pre", "hclk_isp1_root", HCLK_VI_ROOT, 0, RK3588_CLKGATE_CON(26), 8, GFLAGS), -- GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(31), 2, GFLAGS), -+ GATE_LINK(HCLK_NVM, "hclk_nvm", "hclk_nvm_root", ACLK_NVM_ROOT, 0, RK3588_CLKGATE_CON(31), 2, GFLAGS), - GATE_LINK(ACLK_USB, "aclk_usb", "aclk_usb_root", ACLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(42), 2, GFLAGS), - GATE_LINK(HCLK_USB, "hclk_usb", "hclk_usb_root", HCLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(42), 3, GFLAGS), - GATE_LINK(ACLK_JPEG_DECODER_PRE, "aclk_jpeg_decoder_pre", "aclk_jpeg_decoder_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(44), 7, GFLAGS), -@@ -2443,9 +2425,9 @@ static struct rockchip_clk_branch rk3588 - GATE_LINK(HCLK_RKVDEC1_PRE, "hclk_rkvdec1_pre", "hclk_rkvdec1_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(41), 4, GFLAGS), - GATE_LINK(ACLK_RKVDEC1_PRE, "aclk_rkvdec1_pre", "aclk_rkvdec1_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(41), 5, GFLAGS), - GATE_LINK(ACLK_HDCP0_PRE, "aclk_hdcp0_pre", "aclk_vo0_root", ACLK_VOP_LOW_ROOT, 0, RK3588_CLKGATE_CON(55), 9, GFLAGS), -- GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", HCLK_VOP_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(55), 5, GFLAGS), -+ GATE_LINK(HCLK_VO0, "hclk_vo0", "hclk_vo0_root", HCLK_VOP_ROOT, 0, RK3588_CLKGATE_CON(55), 5, GFLAGS), - GATE_LINK(ACLK_HDCP1_PRE, "aclk_hdcp1_pre", "aclk_hdcp1_root", ACLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(59), 6, GFLAGS), -- GATE_LINK(HCLK_VO1, "hclk_vo1", "hclk_vo1_root", HCLK_VO1USB_TOP_ROOT, RK3588_LINKED_CLK, RK3588_CLKGATE_CON(59), 9, GFLAGS), -+ GATE_LINK(HCLK_VO1, "hclk_vo1", "hclk_vo1_root", HCLK_VO1USB_TOP_ROOT, 0, RK3588_CLKGATE_CON(59), 9, GFLAGS), - GATE_LINK(ACLK_AV1_PRE, "aclk_av1_pre", "aclk_av1_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(68), 1, GFLAGS), - GATE_LINK(PCLK_AV1_PRE, "pclk_av1_pre", "pclk_av1_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(68), 4, GFLAGS), - GATE_LINK(HCLK_SDIO_PRE, "hclk_sdio_pre", "hclk_sdio_root", HCLK_NVM, 0, RK3588_CLKGATE_CON(75), 1, GFLAGS), -@@ -2453,14 +2435,18 @@ static struct rockchip_clk_branch rk3588 - GATE_LINK(PCLK_VO1GRF, "pclk_vo1grf", "pclk_vo1_root", HCLK_VO1, CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(59), 12, GFLAGS), - }; - --static void __init rk3588_clk_init(struct device_node *np) -+static void __init rk3588_clk_early_init(struct device_node *np) - { - struct rockchip_clk_provider *ctx; -- unsigned long clk_nr_clks; -+ unsigned long clk_nr_clks, max_clk_id1, max_clk_id2; - void __iomem *reg_base; - -- clk_nr_clks = rockchip_clk_find_max_clk_id(rk3588_clk_branches, -- ARRAY_SIZE(rk3588_clk_branches)) + 1; -+ max_clk_id1 = rockchip_clk_find_max_clk_id(rk3588_clk_branches, -+ ARRAY_SIZE(rk3588_clk_branches)); -+ max_clk_id2 = rockchip_clk_find_max_clk_id(rk3588_early_clk_branches, -+ ARRAY_SIZE(rk3588_early_clk_branches)); -+ clk_nr_clks = max(max_clk_id1, max_clk_id2) + 1; -+ - reg_base = of_iomap(np, 0); - if (!reg_base) { - pr_err("%s: could not map cru region\n", __func__); -@@ -2473,6 +2459,7 @@ static void __init rk3588_clk_init(struc - iounmap(reg_base); - return; - } -+ early_ctx = ctx; - - rockchip_clk_register_plls(ctx, rk3588_pll_clks, - ARRAY_SIZE(rk3588_pll_clks), -@@ -2491,54 +2478,53 @@ static void __init rk3588_clk_init(struc - &rk3588_cpub1clk_data, rk3588_cpub1clk_rates, - ARRAY_SIZE(rk3588_cpub1clk_rates)); - -+ rockchip_clk_register_branches(ctx, rk3588_early_clk_branches, -+ ARRAY_SIZE(rk3588_early_clk_branches)); -+ -+ rockchip_clk_of_add_provider(np, ctx); -+} -+CLK_OF_DECLARE_DRIVER(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_early_init); -+ -+static int clk_rk3588_probe(struct platform_device *pdev) -+{ -+ struct rockchip_clk_provider *ctx = early_ctx; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ - rockchip_clk_register_branches(ctx, rk3588_clk_branches, - ARRAY_SIZE(rk3588_clk_branches)); - -- rk3588_rst_init(np, reg_base); -- -+ rk3588_rst_init(np, ctx->reg_base); - rockchip_register_restart_notifier(ctx, RK3588_GLB_SRST_FST, NULL); - -+ /* -+ * Re-add clock provider, so that the newly added clocks are also -+ * re-parented and get their defaults configured. -+ */ -+ of_clk_del_provider(np); - rockchip_clk_of_add_provider(np, ctx); --} -- --CLK_OF_DECLARE(rk3588_cru, "rockchip,rk3588-cru", rk3588_clk_init); - --struct clk_rk3588_inits { -- void (*inits)(struct device_node *np); --}; -- --static const struct clk_rk3588_inits clk_3588_cru_init = { -- .inits = rk3588_clk_init, --}; -+ return 0; -+} - - static const struct of_device_id clk_rk3588_match_table[] = { - { - .compatible = "rockchip,rk3588-cru", -- .data = &clk_3588_cru_init, - }, - { } - }; - --static int __init clk_rk3588_probe(struct platform_device *pdev) --{ -- const struct clk_rk3588_inits *init_data; -- struct device *dev = &pdev->dev; -- -- init_data = device_get_match_data(dev); -- if (!init_data) -- return -EINVAL; -- -- if (init_data->inits) -- init_data->inits(dev->of_node); -- -- return 0; --} -- - static struct platform_driver clk_rk3588_driver = { -+ .probe = clk_rk3588_probe, - .driver = { - .name = "clk-rk3588", - .of_match_table = clk_rk3588_match_table, - .suppress_bind_attrs = true, - }, - }; --builtin_platform_driver_probe(clk_rk3588_driver, clk_rk3588_probe); -+ -+static int __init rockchip_clk_rk3588_drv_register(void) -+{ -+ return platform_driver_register(&clk_rk3588_driver); -+} -+core_initcall(rockchip_clk_rk3588_drv_register); ---- a/drivers/clk/rockchip/clk.c -+++ b/drivers/clk/rockchip/clk.c -@@ -19,8 +19,12 @@ - #include - #include - #include -+#include -+#include -+#include - #include - #include -+#include - - #include "../clk-fractional-divider.h" - #include "clk.h" -@@ -376,7 +380,7 @@ struct rockchip_clk_provider *rockchip_c - goto err_free; - - for (i = 0; i < nr_clks; ++i) -- clk_table[i] = ERR_PTR(-ENOENT); -+ clk_table[i] = ERR_PTR(-EPROBE_DEFER); - - ctx->reg_base = base; - ctx->clk_data.clks = clk_table; -@@ -446,6 +450,66 @@ unsigned long rockchip_clk_find_max_clk_ - } - EXPORT_SYMBOL_GPL(rockchip_clk_find_max_clk_id); - -+static struct platform_device *rockchip_clk_register_pdev( -+ struct platform_device *parent, -+ const char *name, -+ struct device_node *np) -+{ -+ struct platform_device_info pdevinfo = { -+ .parent = &parent->dev, -+ .name = name, -+ .fwnode = of_fwnode_handle(np), -+ .of_node_reused = true, -+ }; -+ -+ return platform_device_register_full(&pdevinfo); -+} -+ -+static struct clk *rockchip_clk_register_linked_gate( -+ struct rockchip_clk_provider *ctx, -+ struct rockchip_clk_branch *clkbr) -+{ -+ struct clk *linked_clk = ctx->clk_data.clks[clkbr->linked_clk_id]; -+ unsigned long flags = clkbr->flags | CLK_SET_RATE_PARENT; -+ struct device_node *np = ctx->cru_node; -+ struct platform_device *parent, *pdev; -+ struct device *dev = NULL; -+ int ret; -+ -+ parent = of_find_device_by_node(np); -+ if (!parent) { -+ pr_err("failed to find device for %pOF\n", np); -+ goto exit; -+ } -+ -+ pdev = rockchip_clk_register_pdev(parent, clkbr->name, np); -+ put_device(&parent->dev); -+ if (!pdev) { -+ pr_err("failed to register device for clock %s\n", clkbr->name); -+ goto exit; -+ } -+ -+ dev = &pdev->dev; -+ pm_runtime_enable(dev); -+ ret = pm_clk_create(dev); -+ if (ret) { -+ pr_err("failed to create PM clock list for %s\n", clkbr->name); -+ goto exit; -+ } -+ -+ ret = pm_clk_add_clk(dev, linked_clk); -+ if (ret) { -+ pr_err("failed to setup linked clock for %s\n", clkbr->name); -+ } -+ -+exit: -+ return clk_register_gate(dev, clkbr->name, -+ clkbr->parent_names[0], flags, -+ ctx->reg_base + clkbr->gate_offset, -+ clkbr->gate_shift, clkbr->gate_flags, -+ &ctx->lock); -+} -+ - void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, - struct rockchip_clk_branch *list, - unsigned int nr_clk) -@@ -526,6 +590,9 @@ void rockchip_clk_register_branches(stru - ctx->reg_base + list->gate_offset, - list->gate_shift, list->gate_flags, &ctx->lock); - break; -+ case branch_linked_gate: -+ clk = rockchip_clk_register_linked_gate(ctx, list); -+ break; - case branch_composite: - clk = rockchip_clk_register_branch(list->name, - list->parent_names, list->num_parents, ---- a/drivers/clk/rockchip/clk.h -+++ b/drivers/clk/rockchip/clk.h -@@ -517,6 +517,7 @@ enum rockchip_clk_branch_type { - branch_divider, - branch_fraction_divider, - branch_gate, -+ branch_linked_gate, - branch_mmc, - branch_inverter, - branch_factor, -@@ -544,6 +545,7 @@ struct rockchip_clk_branch { - int gate_offset; - u8 gate_shift; - u8 gate_flags; -+ unsigned int linked_clk_id; - struct rockchip_clk_branch *child; - }; - -@@ -838,6 +840,20 @@ struct rockchip_clk_branch { - .num_parents = 1, \ - .flags = f, \ - .gate_offset = o, \ -+ .gate_shift = b, \ -+ .gate_flags = gf, \ -+ } -+ -+#define GATE_LINK(_id, cname, pname, linkedclk, f, o, b, gf) \ -+ { \ -+ .id = _id, \ -+ .branch_type = branch_linked_gate, \ -+ .name = cname, \ -+ .parent_names = (const char *[]){ pname }, \ -+ .linked_clk_id = linkedclk, \ -+ .num_parents = 1, \ -+ .flags = f, \ -+ .gate_offset = o, \ - .gate_shift = b, \ - .gate_flags = gf, \ - }