
On 2023/3/18 03:16, Jonas Karlman wrote:
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@kwiboo.se
Reviewed-by: Kever Yang kever.yang@rock-chips.com
Thanks, - Kever
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