[PATCH 2/3] rockchip: rk3588: Add support for sdmmc clocks in SPL
Kever Yang
kever.yang at rock-chips.com
Tue Mar 21 04:13:00 CET 2023
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 at kwiboo.se>
Reviewed-by: Kever Yang <kever.yang at 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
More information about the U-Boot
mailing list