summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Karlman <jonas@kwiboo.se>2023-04-17 22:07:20 +0300
committerKever Yang <kever.yang@rock-chips.com>2023-04-21 10:16:01 +0300
commit6737771600d4fd8eb48663ea8da37f3f4f49aad5 (patch)
tree687751891c437114ecf071e2697a1ae23406de5d
parent22297581187c346740d5af4ee603701142b58fd6 (diff)
downloadu-boot-6737771600d4fd8eb48663ea8da37f3f4f49aad5.tar.xz
rockchip: rk3588: Add support for sdmmc clocks in SPL
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>
-rw-r--r--arch/arm/include/asm/arch-rockchip/clock.h1
-rw-r--r--arch/arm/include/asm/arch-rockchip/cru_rk3588.h19
-rw-r--r--drivers/clk/rockchip/clk_rk3588.c125
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 90e66c7da0..f002ebcb7a 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 3ea59e9008..7f4a908539 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 a7df553e87..41e31b61a5 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