From a87e404eb8be59c75aab616245d873593124210a Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Fri, 26 Jan 2024 14:08:30 +0800 Subject: [PATCH] rockchip: import pending clk patches for rk3588 Signed-off-by: Tianling Shen --- ...-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch | 33 ++ ...divisor-masking-on-64-bit-platforms.patch} | 36 +- ...ockchip-rk3588-fix-CLK_NR_CLKS-usage.patch | 76 ++++ ...clock-rk3588-add-missing-PCLK_VO1GRF.patch | 23 + ...588-fix-pclk_vo0grf-and-pclk_vo1grf.patch} | 29 +- ...11-06-clk-rockchip-rk3588-fix-indent.patch | 24 + ...88-use-linked-clock-ID-for-GATE_LINK.patch | 76 ++++ ...p-implement-proper-GATE_LINK-support.patch | 422 ++++++++++++++++++ 8 files changed, 668 insertions(+), 51 deletions(-) create mode 100644 target/linux/rockchip/patches-6.1/111-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch rename target/linux/rockchip/patches-6.1/{111-01-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch => 111-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch} (64%) create mode 100644 target/linux/rockchip/patches-6.1/111-03-clk-rockchip-rk3588-fix-CLK_NR_CLKS-usage.patch create mode 100644 target/linux/rockchip/patches-6.1/111-04-dt-bindings-clock-rk3588-add-missing-PCLK_VO1GRF.patch rename target/linux/rockchip/patches-6.1/{111-02-clk-rockchip-rk3588-fix-pclk_vo0grf-and-pclk_vo1grf.patch => 111-05-clk-rockchip-rk3588-fix-pclk_vo0grf-and-pclk_vo1grf.patch} (79%) create mode 100644 target/linux/rockchip/patches-6.1/111-06-clk-rockchip-rk3588-fix-indent.patch create mode 100644 target/linux/rockchip/patches-6.1/111-07-clk-rockchip-rk3588-use-linked-clock-ID-for-GATE_LINK.patch create mode 100644 target/linux/rockchip/patches-6.1/111-08-clk-rockchip-implement-proper-GATE_LINK-support.patch diff --git a/target/linux/rockchip/patches-6.1/111-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch b/target/linux/rockchip/patches-6.1/111-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch new file mode 100644 index 0000000000..d368bbb0fa --- /dev/null +++ b/target/linux/rockchip/patches-6.1/111-01-math-h-add-DIV_ROUND_UP_NO_OVERFLOW.patch @@ -0,0 +1,33 @@ +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.1/111-01-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch b/target/linux/rockchip/patches-6.1/111-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch similarity index 64% rename from target/linux/rockchip/patches-6.1/111-01-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch rename to target/linux/rockchip/patches-6.1/111-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch index 67c203e204..321be7c665 100644 --- a/target/linux/rockchip/patches-6.1/111-01-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch +++ b/target/linux/rockchip/patches-6.1/111-02-clk-divider-Fix-divisor-masking-on-64-bit-platforms.patch @@ -1,6 +1,6 @@ -From 80094450f857ce8e5e00c1952f072eede3902f64 Mon Sep 17 00:00:00 2001 +From b55f69688803c3c7d8fd51d8c833002591dd271b Mon Sep 17 00:00:00 2001 From: Sebastian Reichel -Date: Thu, 18 May 2023 05:19:48 +0200 +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 @@ -19,16 +19,14 @@ 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 introducing a new helper, which avoids the overflow -by using a modulo operation instead of math tricks. This avoids -any requirements on the arguments (except that divisor should not -be 0 obviously). +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 +++--- - include/linux/math.h | 11 +++++++++++ - 2 files changed, 14 insertions(+), 3 deletions(-) + 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 @@ -59,23 +57,3 @@ Signed-off-by: Sebastian Reichel if (!_is_valid_div(table, div, flags)) return -EINVAL; ---- 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.1/111-03-clk-rockchip-rk3588-fix-CLK_NR_CLKS-usage.patch b/target/linux/rockchip/patches-6.1/111-03-clk-rockchip-rk3588-fix-CLK_NR_CLKS-usage.patch new file mode 100644 index 0000000000..94b2cf7780 --- /dev/null +++ b/target/linux/rockchip/patches-6.1/111-03-clk-rockchip-rk3588-fix-CLK_NR_CLKS-usage.patch @@ -0,0 +1,76 @@ +From a5946bf5ce48ed73fffb1542be606e7b8659b017 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Wed, 13 Dec 2023 18:58:43 +0100 +Subject: [PATCH] clk: rockchip: rk3588: fix CLK_NR_CLKS usage + +CLK_NR_CLKS is not part of the DT bindings and needs to be removed +from it, just like it recently happened for other platforms. This +takes care of it by introducing a new function identifying the +maximum used clock ID at runtime. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk-rk3588.c | 5 ++++- + drivers/clk/rockchip/clk.c | 17 +++++++++++++++++ + drivers/clk/rockchip/clk.h | 2 ++ + 3 files changed, 23 insertions(+), 1 deletion(-) + +--- a/drivers/clk/rockchip/clk-rk3588.c ++++ b/drivers/clk/rockchip/clk-rk3588.c +@@ -2458,15 +2458,18 @@ static struct rockchip_clk_branch rk3588 + static void __init rk3588_clk_init(struct device_node *np) + { + struct rockchip_clk_provider *ctx; ++ unsigned long clk_nr_clks; + void __iomem *reg_base; + ++ clk_nr_clks = rockchip_clk_find_max_clk_id(rk3588_clk_branches, ++ ARRAY_SIZE(rk3588_clk_branches)) + 1; + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + +- ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); ++ ctx = rockchip_clk_init(np, reg_base, clk_nr_clks); + if (IS_ERR(ctx)) { + pr_err("%s: rockchip clk init failed\n", __func__); + iounmap(reg_base); +--- a/drivers/clk/rockchip/clk.c ++++ b/drivers/clk/rockchip/clk.c +@@ -430,6 +430,23 @@ void rockchip_clk_register_plls(struct r + } + EXPORT_SYMBOL_GPL(rockchip_clk_register_plls); + ++unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list, ++ unsigned int nr_clk) ++{ ++ unsigned int idx; ++ unsigned long max; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if (list->id > max) ++ max = list->id; ++ if (list->child && list->child->id > max) ++ max = list->id; ++ } ++ ++ return max; ++} ++EXPORT_SYMBOL_GPL(rockchip_clk_find_max_clk_id); ++ + void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, + unsigned int nr_clk) +--- a/drivers/clk/rockchip/clk.h ++++ b/drivers/clk/rockchip/clk.h +@@ -973,6 +973,8 @@ struct rockchip_clk_provider *rockchip_c + void __iomem *base, unsigned long nr_clks); + void rockchip_clk_of_add_provider(struct device_node *np, + struct rockchip_clk_provider *ctx); ++unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list, ++ unsigned int nr_clk); + void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx, + struct rockchip_clk_branch *list, + unsigned int nr_clk); diff --git a/target/linux/rockchip/patches-6.1/111-04-dt-bindings-clock-rk3588-add-missing-PCLK_VO1GRF.patch b/target/linux/rockchip/patches-6.1/111-04-dt-bindings-clock-rk3588-add-missing-PCLK_VO1GRF.patch new file mode 100644 index 0000000000..b29a700cd5 --- /dev/null +++ b/target/linux/rockchip/patches-6.1/111-04-dt-bindings-clock-rk3588-add-missing-PCLK_VO1GRF.patch @@ -0,0 +1,23 @@ +From fb7ba4ede6ab6c37bc1146f7fa1f07a7810439ab Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Wed, 13 Dec 2023 19:02:57 +0100 +Subject: [PATCH] dt-bindings: clock: rk3588: add missing PCLK_VO1GRF + +Add PCLK_VO1GRF to complement PCLK_VO0GRF. This will be needed +for HDMI support. + +Signed-off-by: Sebastian Reichel +--- + include/dt-bindings/clock/rockchip,rk3588-cru.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/dt-bindings/clock/rockchip,rk3588-cru.h ++++ b/include/dt-bindings/clock/rockchip,rk3588-cru.h +@@ -733,6 +733,7 @@ + #define ACLK_AV1_PRE 718 + #define PCLK_AV1_PRE 719 + #define HCLK_SDIO_PRE 720 ++#define PCLK_VO1GRF 721 + + #define CLK_NR_CLKS (HCLK_SDIO_PRE + 1) + diff --git a/target/linux/rockchip/patches-6.1/111-02-clk-rockchip-rk3588-fix-pclk_vo0grf-and-pclk_vo1grf.patch b/target/linux/rockchip/patches-6.1/111-05-clk-rockchip-rk3588-fix-pclk_vo0grf-and-pclk_vo1grf.patch similarity index 79% rename from target/linux/rockchip/patches-6.1/111-02-clk-rockchip-rk3588-fix-pclk_vo0grf-and-pclk_vo1grf.patch rename to target/linux/rockchip/patches-6.1/111-05-clk-rockchip-rk3588-fix-pclk_vo0grf-and-pclk_vo1grf.patch index f857261676..e1b9922cb3 100644 --- a/target/linux/rockchip/patches-6.1/111-02-clk-rockchip-rk3588-fix-pclk_vo0grf-and-pclk_vo1grf.patch +++ b/target/linux/rockchip/patches-6.1/111-05-clk-rockchip-rk3588-fix-pclk_vo0grf-and-pclk_vo1grf.patch @@ -1,11 +1,11 @@ -From a8dc483b1653a2b99f9b63803b4575ba4a91d8d8 Mon Sep 17 00:00:00 2001 +From 8824bba8426bab1a05b2f285283bc0e99de678d1 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel -Date: Tue, 13 Jun 2023 16:45:05 +0200 +Date: Wed, 13 Dec 2023 19:06:30 +0100 Subject: [PATCH] clk: rockchip: rk3588: fix pclk_vo0grf and pclk_vo1grf Currently pclk_vo1grf is not exposed, but it should be referenced -from the vo1_grf syscon, which needs it enabled. That syscon will -be required for HDMI-RX functionality among other things. +from the vo1_grf syscon, which needs it enabled. That syscon is +required for HDMI RX and TX functionality among other things. Apart from that pclk_vo0grf and pclk_vo1grf are both linked gates and need the VO's hclk enabled in addition to their parent clock. @@ -15,9 +15,8 @@ is not yet upstream anyways. Signed-off-by: Sebastian Reichel --- - drivers/clk/rockchip/clk-rk3588.c | 11 +++++------ - include/dt-bindings/clock/rockchip,rk3588-cru.h | 3 ++- - 2 files changed, 7 insertions(+), 7 deletions(-) + drivers/clk/rockchip/clk-rk3588.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) --- a/drivers/clk/rockchip/clk-rk3588.c +++ b/drivers/clk/rockchip/clk-rk3588.c @@ -39,7 +38,7 @@ Signed-off-by: Sebastian Reichel GATE(PCLK_S_EDP0, "pclk_s_edp0", "pclk_vo1_s_root", 0, RK3588_CLKGATE_CON(59), 14, GFLAGS), GATE(PCLK_S_EDP1, "pclk_s_edp1", "pclk_vo1_s_root", 0, -@@ -2447,12 +2443,15 @@ static struct rockchip_clk_branch rk3588 +@@ -2447,12 +2443,14 @@ 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), @@ -53,20 +52,6 @@ Signed-off-by: Sebastian Reichel GATE_LINK(HCLK_SDIO_PRE, "hclk_sdio_pre", "hclk_sdio_root", "hclk_nvm", 0, RK3588_CLKGATE_CON(75), 1, GFLAGS), + GATE_LINK(PCLK_VO0GRF, "pclk_vo0grf", "pclk_vo0_root", "hclk_vo0", CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(55), 10, GFLAGS), + 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) ---- a/include/dt-bindings/clock/rockchip,rk3588-cru.h -+++ b/include/dt-bindings/clock/rockchip,rk3588-cru.h -@@ -733,8 +733,9 @@ - #define ACLK_AV1_PRE 718 - #define PCLK_AV1_PRE 719 - #define HCLK_SDIO_PRE 720 -+#define PCLK_VO1GRF 721 - --#define CLK_NR_CLKS (HCLK_SDIO_PRE + 1) -+#define CLK_NR_CLKS (PCLK_VO1GRF + 1) - - /* scmi-clocks indices */ - diff --git a/target/linux/rockchip/patches-6.1/111-06-clk-rockchip-rk3588-fix-indent.patch b/target/linux/rockchip/patches-6.1/111-06-clk-rockchip-rk3588-fix-indent.patch new file mode 100644 index 0000000000..f46bb47f42 --- /dev/null +++ b/target/linux/rockchip/patches-6.1/111-06-clk-rockchip-rk3588-fix-indent.patch @@ -0,0 +1,24 @@ +From 1d45059214265717c8bc1fd32b966896e91ec51d Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Tue, 21 Nov 2023 17:52:54 +0100 +Subject: [PATCH] clk: rockchip: rk3588: fix indent + +pclk_mailbox2 is the only RK3588 clock indented with one tab instead of +two tabs. Let's fix this. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk-rk3588.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/clk/rockchip/clk-rk3588.c ++++ b/drivers/clk/rockchip/clk-rk3588.c +@@ -1004,7 +1004,7 @@ static struct rockchip_clk_branch rk3588 + GATE(PCLK_MAILBOX1, "pclk_mailbox1", "pclk_top_root", 0, + RK3588_CLKGATE_CON(16), 12, GFLAGS), + GATE(PCLK_MAILBOX2, "pclk_mailbox2", "pclk_top_root", 0, +- RK3588_CLKGATE_CON(16), 13, GFLAGS), ++ RK3588_CLKGATE_CON(16), 13, GFLAGS), + GATE(PCLK_PMU2, "pclk_pmu2", "pclk_top_root", CLK_IS_CRITICAL, + RK3588_CLKGATE_CON(19), 3, GFLAGS), + GATE(PCLK_PMUCM0_INTMUX, "pclk_pmucm0_intmux", "pclk_top_root", CLK_IS_CRITICAL, diff --git a/target/linux/rockchip/patches-6.1/111-07-clk-rockchip-rk3588-use-linked-clock-ID-for-GATE_LINK.patch b/target/linux/rockchip/patches-6.1/111-07-clk-rockchip-rk3588-use-linked-clock-ID-for-GATE_LINK.patch new file mode 100644 index 0000000000..1b48d85412 --- /dev/null +++ b/target/linux/rockchip/patches-6.1/111-07-clk-rockchip-rk3588-use-linked-clock-ID-for-GATE_LINK.patch @@ -0,0 +1,76 @@ +From 923c6fa62da49b895fc110e2bad8d6e812b37d1a Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Wed, 22 Nov 2023 19:23:13 +0100 +Subject: [PATCH] clk: rockchip: rk3588: use linked clock ID for GATE_LINK + +In preparation for properly supporting GATE_LINK switch the unused +linked clock argument from the clock's name to its ID. This allows +easy and fast lookup of the 'struct clk'. + +Signed-off-by: Sebastian Reichel +--- + drivers/clk/rockchip/clk-rk3588.c | 46 +++++++++++++++---------------- + 1 file changed, 23 insertions(+), 23 deletions(-) + +--- a/drivers/clk/rockchip/clk-rk3588.c ++++ b/drivers/clk/rockchip/clk-rk3588.c +@@ -29,7 +29,7 @@ + * power, but avoids leaking implementation details into DT or hanging the + * system. + */ +-#define GATE_LINK(_id, cname, pname, linkname, f, o, b, gf) \ ++#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 + +@@ -2429,28 +2429,28 @@ static struct rockchip_clk_branch rk3588 + GATE(ACLK_AV1, "aclk_av1", "aclk_av1_pre", 0, + RK3588_CLKGATE_CON(68), 2, GFLAGS), + +- 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(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), +- GATE_LINK(ACLK_VDPU_LOW_PRE, "aclk_vdpu_low_pre", "aclk_vdpu_low_root", "aclk_vdpu_root", 0, RK3588_CLKGATE_CON(44), 5, GFLAGS), +- GATE_LINK(ACLK_RKVENC1_PRE, "aclk_rkvenc1_pre", "aclk_rkvenc1_root", "aclk_rkvenc0", 0, RK3588_CLKGATE_CON(48), 3, GFLAGS), +- GATE_LINK(HCLK_RKVENC1_PRE, "hclk_rkvenc1_pre", "hclk_rkvenc1_root", "hclk_rkvenc0", 0, RK3588_CLKGATE_CON(48), 2, GFLAGS), +- GATE_LINK(HCLK_RKVDEC0_PRE, "hclk_rkvdec0_pre", "hclk_rkvdec0_root", "hclk_vdpu_root", 0, RK3588_CLKGATE_CON(40), 5, GFLAGS), +- GATE_LINK(ACLK_RKVDEC0_PRE, "aclk_rkvdec0_pre", "aclk_rkvdec0_root", "aclk_vdpu_root", 0, RK3588_CLKGATE_CON(40), 6, GFLAGS), +- 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(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(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), +- GATE_LINK(PCLK_VO0GRF, "pclk_vo0grf", "pclk_vo0_root", "hclk_vo0", CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(55), 10, GFLAGS), +- GATE_LINK(PCLK_VO1GRF, "pclk_vo1grf", "pclk_vo1_root", "hclk_vo1", CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(59), 12, GFLAGS), ++ 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(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), ++ GATE_LINK(ACLK_VDPU_LOW_PRE, "aclk_vdpu_low_pre", "aclk_vdpu_low_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(44), 5, GFLAGS), ++ GATE_LINK(ACLK_RKVENC1_PRE, "aclk_rkvenc1_pre", "aclk_rkvenc1_root", ACLK_RKVENC0, 0, RK3588_CLKGATE_CON(48), 3, GFLAGS), ++ GATE_LINK(HCLK_RKVENC1_PRE, "hclk_rkvenc1_pre", "hclk_rkvenc1_root", HCLK_RKVENC0, 0, RK3588_CLKGATE_CON(48), 2, GFLAGS), ++ GATE_LINK(HCLK_RKVDEC0_PRE, "hclk_rkvdec0_pre", "hclk_rkvdec0_root", HCLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(40), 5, GFLAGS), ++ GATE_LINK(ACLK_RKVDEC0_PRE, "aclk_rkvdec0_pre", "aclk_rkvdec0_root", ACLK_VDPU_ROOT, 0, RK3588_CLKGATE_CON(40), 6, GFLAGS), ++ 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(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(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), ++ GATE_LINK(PCLK_VO0GRF, "pclk_vo0grf", "pclk_vo0_root", HCLK_VO0, CLK_IGNORE_UNUSED, RK3588_CLKGATE_CON(55), 10, GFLAGS), ++ 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) diff --git a/target/linux/rockchip/patches-6.1/111-08-clk-rockchip-implement-proper-GATE_LINK-support.patch b/target/linux/rockchip/patches-6.1/111-08-clk-rockchip-implement-proper-GATE_LINK-support.patch new file mode 100644 index 0000000000..a2adea4c8f --- /dev/null +++ b/target/linux/rockchip/patches-6.1/111-08-clk-rockchip-implement-proper-GATE_LINK-support.patch @@ -0,0 +1,422 @@ +From 42987730c377951c90e9cfe55652e812db4a9ac9 Mon Sep 17 00:00:00 2001 +From: Sebastian Reichel +Date: Thu, 23 Nov 2023 17:58:21 +0100 +Subject: [PATCH] clk: rockchip: implement proper GATE_LINK support + +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,9 +19,13 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include ++#include + + #include "../clk-fractional-divider.h" + #include "clk.h" +@@ -377,7 +381,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; +@@ -447,6 +451,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) +@@ -527,6 +591,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, \ + }