[PATCH 2/3] rockchip: rk3588: Add support for sdmmc clocks in SPL

Jonas Karlman jonas at kwiboo.se
Fri Mar 17 20:16:46 CET 2023


Booting from sdmmc on RK3588 currently works because of a workaround in
the device tree, clocks are reordered so that the driver use ciu-sample
instead of ciu, and the BootRom initializes sdmmc clocks before SPL is
loaded into DRAM.

The sdmmc clocks are normally controlled by TF-A using SCMI. However,
there is a need to control these clocks in SPL, before TF-A has started.

This adds a rk3588_scru driver to control the sdmmc clocks in SPL before
TF-A has started, using scru regs. It also adds a small glue driver to
bind the scmi clock node to the rk3588_scru driver in SPL.

Fixes: 7a474df74023 ("clk: rockchip: Add rk3588 clk support")
Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
---
 arch/arm/include/asm/arch-rockchip/clock.h    |   1 -
 .../include/asm/arch-rockchip/cru_rk3588.h    |  19 ++-
 drivers/clk/rockchip/clk_rk3588.c             | 125 ++++++++++++++++++
 3 files changed, 143 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h
index 90e66c7da049..f002ebcb7ac1 100644
--- a/arch/arm/include/asm/arch-rockchip/clock.h
+++ b/arch/arm/include/asm/arch-rockchip/clock.h
@@ -194,6 +194,5 @@ int rockchip_get_clk(struct udevice **devp);
  * Return: 0 success, or error value
  */
 int rockchip_reset_bind(struct udevice *pdev, u32 reg_offset, u32 reg_number);
-int rockchip_get_scmi_clk(struct udevice **devp);
 
 #endif
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3588.h b/arch/arm/include/asm/arch-rockchip/cru_rk3588.h
index 3ea59e900861..7f4a90853929 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_rk3588.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3588.h
@@ -11,12 +11,12 @@
 #define KHz		1000
 #define OSC_HZ		(24 * MHz)
 
-#define CPU_PVTPLL_HZ	(1008 * MHz)
 #define LPLL_HZ		(816 * MHz)
 #define GPLL_HZ		(1188 * MHz)
 #define CPLL_HZ		(1500 * MHz)
 #define NPLL_HZ         (850 * MHz)
 #define PPLL_HZ		(1100 * MHz)
+#define SPLL_HZ		(702 * MHz)
 
 /* RK3588 pll id */
 enum rk3588_pll_id {
@@ -447,5 +447,22 @@ enum {
 	CLK_I2C0_SEL_MASK			= 1 << CLK_I2C0_SEL_SHIFT,
 	CLK_I2C_SEL_200M			= 0,
 	CLK_I2C_SEL_100M,
+
+	/* SECURECRU_CLKSEL_CON01 */
+	SCMI_HCLK_SD_SEL_SHIFT			= 2,
+	SCMI_HCLK_SD_SEL_MASK			= 3 << SCMI_HCLK_SD_SEL_SHIFT,
+	SCMI_HCLK_SD_SEL_150M			= 0,
+	SCMI_HCLK_SD_SEL_100M,
+	SCMI_HCLK_SD_SEL_50M,
+	SCMI_HCLK_SD_SEL_24M,
+
+	/* SECURECRU_CLKSEL_CON03 */
+	SCMI_CCLK_SD_SEL_SHIFT			= 12,
+	SCMI_CCLK_SD_SEL_MASK			= 3 << SCMI_CCLK_SD_SEL_SHIFT,
+	SCMI_CCLK_SD_SEL_GPLL			= 0,
+	SCMI_CCLK_SD_SEL_SPLL,
+	SCMI_CCLK_SD_SEL_24M,
+	SCMI_CCLK_SD_DIV_SHIFT			= 6,
+	SCMI_CCLK_SD_DIV_MASK			= 0x3f << SCMI_CCLK_SD_DIV_SHIFT,
 };
 #endif
diff --git a/drivers/clk/rockchip/clk_rk3588.c b/drivers/clk/rockchip/clk_rk3588.c
index a7df553e8750..41e31b61a55b 100644
--- a/drivers/clk/rockchip/clk_rk3588.c
+++ b/drivers/clk/rockchip/clk_rk3588.c
@@ -9,6 +9,7 @@
 #include <clk-uclass.h>
 #include <dm.h>
 #include <errno.h>
+#include <scmi_protocols.h>
 #include <syscon.h>
 #include <asm/arch-rockchip/cru_rk3588.h>
 #include <asm/arch-rockchip/clock.h>
@@ -1994,3 +1995,127 @@ U_BOOT_DRIVER(rockchip_rk3588_cru) = {
 	.bind		= rk3588_clk_bind,
 	.probe		= rk3588_clk_probe,
 };
+
+#ifdef CONFIG_SPL_BUILD
+#define SCRU_BASE			0xfd7d0000
+
+static ulong rk3588_scru_clk_get_rate(struct clk *clk)
+{
+	u32 con, div, sel, parent;
+
+	switch (clk->id) {
+	case SCMI_CCLK_SD:
+		con = readl(SCRU_BASE + RK3588_CLKSEL_CON(3));
+		sel = (con & SCMI_CCLK_SD_SEL_MASK) >> SCMI_CCLK_SD_SEL_SHIFT;
+		div = (con & SCMI_CCLK_SD_DIV_MASK) >> SCMI_CCLK_SD_DIV_SHIFT;
+		if (sel == SCMI_CCLK_SD_SEL_GPLL)
+			parent = GPLL_HZ;
+		else if (sel == SCMI_CCLK_SD_SEL_SPLL)
+			parent = SPLL_HZ;
+		else
+			parent = OSC_HZ;
+		return DIV_TO_RATE(parent, div);
+	case SCMI_HCLK_SD:
+		con = readl(SCRU_BASE + RK3588_CLKSEL_CON(1));
+		sel = (con & SCMI_HCLK_SD_SEL_MASK) >> SCMI_HCLK_SD_SEL_SHIFT;
+		if (sel == SCMI_HCLK_SD_SEL_150M)
+			return 150 * MHz;
+		else if (sel == SCMI_HCLK_SD_SEL_100M)
+			return 100 * MHz;
+		else if (sel == SCMI_HCLK_SD_SEL_50M)
+			return 50 * MHz;
+		else
+			return OSC_HZ;
+	default:
+		return -ENOENT;
+	}
+}
+
+static ulong rk3588_scru_clk_set_rate(struct clk *clk, ulong rate)
+{
+	u32 div, sel;
+
+	switch (clk->id) {
+	case SCMI_CCLK_SD:
+		if ((OSC_HZ % rate) == 0) {
+			sel = SCMI_CCLK_SD_SEL_24M;
+			div = DIV_ROUND_UP(OSC_HZ, rate);
+		} else if ((SPLL_HZ % rate) == 0) {
+			sel = SCMI_CCLK_SD_SEL_SPLL;
+			div = DIV_ROUND_UP(SPLL_HZ, rate);
+		} else {
+			sel = SCMI_CCLK_SD_SEL_GPLL;
+			div = DIV_ROUND_UP(GPLL_HZ, rate);
+		}
+		rk_clrsetreg(SCRU_BASE + RK3588_CLKSEL_CON(3),
+			     SCMI_CCLK_SD_SEL_MASK | SCMI_CCLK_SD_DIV_MASK,
+			     sel << SCMI_CCLK_SD_SEL_SHIFT |
+			     (div - 1) << SCMI_CCLK_SD_DIV_SHIFT);
+		break;
+	case SCMI_HCLK_SD:
+		if (rate >= 150 * MHz)
+			sel = SCMI_HCLK_SD_SEL_150M;
+		else if (rate >= 100 * MHz)
+			sel = SCMI_HCLK_SD_SEL_100M;
+		else if (rate >= 50 * MHz)
+			sel = SCMI_HCLK_SD_SEL_50M;
+		else
+			sel = SCMI_HCLK_SD_SEL_24M;
+		rk_clrsetreg(SCRU_BASE + RK3588_CLKSEL_CON(1),
+			     SCMI_HCLK_SD_SEL_MASK,
+			     sel << SCMI_HCLK_SD_SEL_SHIFT);
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	return rk3588_scru_clk_get_rate(clk);
+}
+
+static const struct clk_ops rk3588_scru_clk_ops = {
+	.get_rate = rk3588_scru_clk_get_rate,
+	.set_rate = rk3588_scru_clk_set_rate,
+};
+
+U_BOOT_DRIVER(rockchip_rk3588_scru) = {
+	.name = "rockchip_rk3588_scru",
+	.id = UCLASS_CLK,
+	.ops = &rk3588_scru_clk_ops,
+};
+
+static int rk3588_scmi_spl_glue_bind(struct udevice *dev)
+{
+	ofnode node;
+	u32 protocol_id;
+	const char *name;
+
+	dev_for_each_subnode(node, dev) {
+		if (!ofnode_is_enabled(node))
+			continue;
+
+		if (ofnode_read_u32(node, "reg", &protocol_id))
+			continue;
+
+		if (protocol_id != SCMI_PROTOCOL_ID_CLOCK)
+			continue;
+
+		name = ofnode_get_name(node);
+		return device_bind_driver_to_node(dev, "rockchip_rk3588_scru",
+						  name, node, NULL);
+	}
+
+	return -ENOENT;
+}
+
+static const struct udevice_id rk3588_scmi_spl_glue_ids[] = {
+	{ .compatible = "arm,scmi-smc" },
+	{ }
+};
+
+U_BOOT_DRIVER(rk3588_scmi_spl_glue) = {
+	.name		= "rk3588_scmi_spl_glue",
+	.id		= UCLASS_NOP,
+	.of_match	= rk3588_scmi_spl_glue_ids,
+	.bind		= rk3588_scmi_spl_glue_bind,
+};
+#endif
-- 
2.40.0



More information about the U-Boot mailing list