Hi Jagan, On 2023-01-30 15:57, Jagan Teki wrote: > Add clock driver support for Rockchip RK3588 SoC. > > Signed-off-by: Elaine Zhang <zhangq...@rock-chips.com> > Signed-off-by: Jagan Teki <ja...@edgeble.ai> > --- > drivers/clk/rockchip/Makefile | 1 + > drivers/clk/rockchip/clk_rk3588.c | 1996 +++++++++++++++++++++++++++++ > 2 files changed, 1997 insertions(+) > create mode 100644 drivers/clk/rockchip/clk_rk3588.c > > diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile > index f719f4e379..9e379cc2e3 100644 > --- a/drivers/clk/rockchip/Makefile > +++ b/drivers/clk/rockchip/Makefile > @@ -16,5 +16,6 @@ obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o > obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o > obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o > obj-$(CONFIG_ROCKCHIP_RK3568) += clk_rk3568.o > +obj-$(CONFIG_ROCKCHIP_RK3588) += clk_rk3588.o > obj-$(CONFIG_ROCKCHIP_RV1108) += clk_rv1108.o > obj-$(CONFIG_ROCKCHIP_RV1126) += clk_rv1126.o > diff --git a/drivers/clk/rockchip/clk_rk3588.c > b/drivers/clk/rockchip/clk_rk3588.c > new file mode 100644 > index 0000000000..b87b023bd7 > --- /dev/null > +++ b/drivers/clk/rockchip/clk_rk3588.c > @@ -0,0 +1,1996 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2021 Fuzhou Rockchip Electronics Co., Ltd > + * Author: Elaine Zhang <zhangq...@rock-chips.com> > + */ > + > +#include <common.h> > +#include <bitfield.h> > +#include <clk-uclass.h> > +#include <dm.h> > +#include <errno.h> > +#include <syscon.h> > +#include <asm/arch-rockchip/cru_rk3588.h> > +#include <asm/arch-rockchip/clock.h> > +#include <asm/arch-rockchip/hardware.h> > +#include <asm/io.h> > +#include <dm/device-internal.h> > +#include <dm/lists.h> > +#include <dt-bindings/clock/rockchip,rk3588-cru.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) > + > +static struct rockchip_pll_rate_table rk3588_pll_rates[] = { > + /* _mhz, _p, _m, _s, _k */ > + RK3588_PLL_RATE(1500000000, 2, 250, 1, 0), > + RK3588_PLL_RATE(1200000000, 2, 200, 1, 0), > + RK3588_PLL_RATE(1188000000, 2, 198, 1, 0), > + RK3588_PLL_RATE(1100000000, 3, 550, 2, 0), > + RK3588_PLL_RATE(1008000000, 2, 336, 2, 0), > + RK3588_PLL_RATE(1000000000, 3, 500, 2, 0), > + RK3588_PLL_RATE(900000000, 2, 300, 2, 0), > + RK3588_PLL_RATE(850000000, 3, 425, 2, 0), > + RK3588_PLL_RATE(816000000, 2, 272, 2, 0), > + RK3588_PLL_RATE(786432000, 2, 262, 2, 9437), > + RK3588_PLL_RATE(786000000, 1, 131, 2, 0), > + RK3588_PLL_RATE(722534400, 8, 963, 2, 24850), > + RK3588_PLL_RATE(600000000, 2, 200, 2, 0), > + RK3588_PLL_RATE(594000000, 2, 198, 2, 0), > + RK3588_PLL_RATE(200000000, 3, 400, 4, 0), > + RK3588_PLL_RATE(100000000, 3, 400, 5, 0), > + { /* sentinel */ }, > +}; > + > +static struct rockchip_pll_clock rk3588_pll_clks[] = { > + [B0PLL] = PLL(pll_rk3588, PLL_B0PLL, RK3588_B0_PLL_CON(0), > + RK3588_B0_PLL_MODE_CON, 0, 15, 0, > + rk3588_pll_rates), > + [B1PLL] = PLL(pll_rk3588, PLL_B1PLL, RK3588_B1_PLL_CON(8), > + RK3588_B1_PLL_MODE_CON, 0, 15, 0, > + rk3588_pll_rates), > + [LPLL] = PLL(pll_rk3588, PLL_LPLL, RK3588_LPLL_CON(16), > + RK3588_LPLL_MODE_CON, 0, 15, 0, rk3588_pll_rates), > + [V0PLL] = PLL(pll_rk3588, PLL_V0PLL, RK3588_PLL_CON(88), > + RK3588_MODE_CON0, 4, 15, 0, rk3588_pll_rates), > + [AUPLL] = PLL(pll_rk3588, PLL_AUPLL, RK3588_PLL_CON(96), > + RK3588_MODE_CON0, 6, 15, 0, rk3588_pll_rates), > + [CPLL] = PLL(pll_rk3588, PLL_CPLL, RK3588_PLL_CON(104), > + RK3588_MODE_CON0, 8, 15, 0, rk3588_pll_rates), > + [GPLL] = PLL(pll_rk3588, PLL_GPLL, RK3588_PLL_CON(112), > + RK3588_MODE_CON0, 2, 15, 0, rk3588_pll_rates), > + [NPLL] = PLL(pll_rk3588, PLL_NPLL, RK3588_PLL_CON(120), > + RK3588_MODE_CON0, 0, 15, 0, rk3588_pll_rates), > + [PPLL] = PLL(pll_rk3588, PLL_PPLL, RK3588_PMU_PLL_CON(128), > + RK3588_MODE_CON0, 10, 15, 0, rk3588_pll_rates), > +}; > + > +#ifndef CONFIG_SPL_BUILD > +/* > + * > + * rational_best_approximation(31415, 10000, > + * (1 << 8) - 1, (1 << 5) - 1, &n, &d); > + * > + * you may look at given_numerator as a fixed point number, > + * with the fractional part size described in given_denominator. > + * > + * for theoretical background, see: > + * http://en.wikipedia.org/wiki/Continued_fraction > + */ > +static void rational_best_approximation(unsigned long given_numerator, > + unsigned long given_denominator, > + unsigned long max_numerator, > + unsigned long max_denominator, > + unsigned long *best_numerator, > + unsigned long *best_denominator) > +{ > + unsigned long n, d, n0, d0, n1, d1; > + > + n = given_numerator; > + d = given_denominator; > + n0 = 0; > + d1 = 0; > + n1 = 1; > + d0 = 1; > + for (;;) { > + unsigned long t, a; > + > + if (n1 > max_numerator || d1 > max_denominator) { > + n1 = n0; > + d1 = d0; > + break; > + } > + if (d == 0) > + break; > + t = d; > + a = n / d; > + d = n % d; > + n = t; > + t = n0 + a * n1; > + n0 = n1; > + n1 = t; > + t = d0 + a * d1; > + d0 = d1; > + d1 = t; > + } > + *best_numerator = n1; > + *best_denominator = d1; > +} > +#endif > +
[...] > + > +static ulong rk3588_top_get_clk(struct rk3588_clk_priv *priv, ulong clk_id) > +{ > + struct rk3588_cru *cru = priv->cru; > + u32 con, sel, div, rate, prate; > + > + switch (clk_id) { > + case ACLK_TOP_ROOT: > + con = readl(&cru->clksel_con[8]); > + div = (con & ACLK_TOP_ROOT_DIV_MASK) >> > + ACLK_TOP_ROOT_DIV_SHIFT; > + sel = (con & ACLK_TOP_ROOT_SRC_SEL_MASK) >> > + ACLK_TOP_ROOT_SRC_SEL_SHIFT; > + if (sel == ACLK_TOP_ROOT_SRC_SEL_CPLL) > + prate = priv->cpll_hz; > + else > + prate = priv->cpll_hz; Should be gpll_hz instead of cpll_hz. > + return DIV_TO_RATE(prate, div); > + case ACLK_LOW_TOP_ROOT: > + con = readl(&cru->clksel_con[8]); > + div = (con & ACLK_LOW_TOP_ROOT_DIV_MASK) >> > + ACLK_LOW_TOP_ROOT_DIV_SHIFT; > + sel = (con & ACLK_LOW_TOP_ROOT_SRC_SEL_MASK) >> > + ACLK_LOW_TOP_ROOT_SRC_SEL_SHIFT; > + if (sel == ACLK_LOW_TOP_ROOT_SRC_SEL_CPLL) > + prate = priv->cpll_hz; > + else > + prate = priv->gpll_hz; > + return DIV_TO_RATE(prate, div); > + case PCLK_TOP_ROOT: > + con = readl(&cru->clksel_con[8]); > + sel = (con & PCLK_TOP_ROOT_SEL_MASK) >> PCLK_TOP_ROOT_SEL_SHIFT; > + if (sel == PCLK_TOP_ROOT_SEL_100M) > + rate = 100 * MHz; > + else if (sel == PCLK_TOP_ROOT_SEL_50M) > + rate = 50 * MHz; > + else > + rate = OSC_HZ; > + break; > + default: > + return -ENOENT; > + } > + > + return rate; > +} > + [...] > + > +static ulong rk3588_clk_get_rate(struct clk *clk) > +{ > + struct rk3588_clk_priv *priv = dev_get_priv(clk->dev); > + ulong rate = 0; > + > + if (!priv->gpll_hz) { > + printf("%s gpll=%lu\n", __func__, priv->gpll_hz); > + return -ENOENT; > + } > + > + if (!priv->ppll_hz) { > + priv->ppll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL], > + priv->cru, PPLL); > + } > + > + switch (clk->id) { > + case PLL_LPLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[LPLL], priv->cru, > + LPLL); > + break; > + case PLL_B0PLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[B0PLL], priv->cru, > + B0PLL); > + break; > + case PLL_B1PLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[B1PLL], priv->cru, > + B1PLL); > + break; > + case PLL_GPLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[GPLL], priv->cru, > + GPLL); > + break; > + case PLL_CPLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[CPLL], priv->cru, > + CPLL); > + break; > + case PLL_NPLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[NPLL], priv->cru, > + NPLL); > + break; > + case PLL_V0PLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[V0PLL], priv->cru, > + V0PLL); > + break; > + case PLL_AUPLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[AUPLL], priv->cru, > + AUPLL); > + break; > + case PLL_PPLL: > + rate = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL], priv->cru, > + PPLL); > + break; > + case ACLK_CENTER_ROOT: > + case PCLK_CENTER_ROOT: > + case HCLK_CENTER_ROOT: > + case ACLK_CENTER_LOW_ROOT: > + rate = rk3588_center_get_clk(priv, clk->id); > + break; > + case ACLK_TOP_ROOT: > + case PCLK_TOP_ROOT: > + case ACLK_LOW_TOP_ROOT: > + rate = rk3588_top_get_clk(priv, clk->id); > + break; > + case CLK_I2C0: > + case CLK_I2C1: > + case CLK_I2C2: > + case CLK_I2C3: > + case CLK_I2C4: > + case CLK_I2C5: > + case CLK_I2C6: > + case CLK_I2C7: > + case CLK_I2C8: > + rate = rk3588_i2c_get_clk(priv, clk->id); > + break; > + case CLK_SPI0: > + case CLK_SPI1: > + case CLK_SPI2: > + case CLK_SPI3: > + case CLK_SPI4: > + rate = rk3588_spi_get_clk(priv, clk->id); > + break; > + case CLK_PWM1: > + case CLK_PWM2: > + case CLK_PWM3: > + case CLK_PMU1PWM: > + rate = rk3588_pwm_get_clk(priv, clk->id); > + break; > + case CLK_SARADC: > + case CLK_TSADC: > + rate = rk3588_adc_get_clk(priv, clk->id); > + break; > + case CCLK_SRC_SDIO: > + case CCLK_EMMC: > + case BCLK_EMMC: > + case SCLK_SFC: > + case DCLK_DECOM: > + rate = rk3588_mmc_get_clk(priv, clk->id); > + break; > + case TCLK_WDT0: > + rate = OSC_HZ; > + break; > +#ifndef CONFIG_SPL_BUILD > + case CLK_AUX16M_0: > + case CLK_AUX16M_1: > + rk3588_aux16m_get_clk(priv, clk->id); This is missing "rate =" before function call. > + break; > + case ACLK_VOP_ROOT: > + case ACLK_VOP: > + case ACLK_VOP_LOW_ROOT: > + case HCLK_VOP_ROOT: > + rate = rk3588_aclk_vop_get_clk(priv, clk->id); > + break; > + case DCLK_VOP0: > + case DCLK_VOP0_SRC: > + case DCLK_VOP1: > + case DCLK_VOP1_SRC: > + case DCLK_VOP2: > + case DCLK_VOP2_SRC: > + case DCLK_VOP3: > + rate = rk3588_dclk_vop_get_clk(priv, clk->id); > + break; > + case CLK_GMAC0_PTP_REF: > + case CLK_GMAC1_PTP_REF: > + case CLK_GMAC_125M: > + case CLK_GMAC_50M: > + rate = rk3588_gmac_get_clk(priv, clk->id); > + break; > + case SCLK_UART1: > + case SCLK_UART2: > + case SCLK_UART3: > + case SCLK_UART4: > + case SCLK_UART5: > + case SCLK_UART6: > + case SCLK_UART7: > + case SCLK_UART8: > + case SCLK_UART9: > + rate = rk3588_uart_get_rate(priv, clk->id); > + break; > + case CLK_REF_PIPE_PHY0: > + case CLK_REF_PIPE_PHY1: > + case CLK_REF_PIPE_PHY2: > + rate = rk3588_pciephy_get_rate(priv, clk->id); > + break; > +#endif > + default: > + return -ENOENT; > + } > + > + return rate; > +}; > + > +static ulong rk3588_clk_set_rate(struct clk *clk, ulong rate) > +{ > + struct rk3588_clk_priv *priv = dev_get_priv(clk->dev); > + ulong ret = 0; > + > + if (!priv->gpll_hz) { > + printf("%s gpll=%lu\n", __func__, priv->gpll_hz); > + return -ENOENT; > + } > + > + if (!priv->ppll_hz) { > + priv->ppll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL], > + priv->cru, PPLL); > + } > + > + switch (clk->id) { > + case PLL_CPLL: > + ret = rockchip_pll_set_rate(&rk3588_pll_clks[CPLL], priv->cru, > + CPLL, rate); > + priv->cpll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[CPLL], > + priv->cru, CPLL); > + break; > + case PLL_GPLL: > + ret = rockchip_pll_set_rate(&rk3588_pll_clks[GPLL], priv->cru, > + GPLL, rate); > + priv->gpll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[GPLL], > + priv->cru, GPLL); > + break; > + case PLL_NPLL: > + ret = rockchip_pll_set_rate(&rk3588_pll_clks[NPLL], priv->cru, > + NPLL, rate); > + break; > + case PLL_V0PLL: > + ret = rockchip_pll_set_rate(&rk3588_pll_clks[V0PLL], priv->cru, > + V0PLL, rate); > + priv->v0pll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[V0PLL], > + priv->cru, V0PLL); > + break; > + case PLL_AUPLL: > + ret = rockchip_pll_set_rate(&rk3588_pll_clks[AUPLL], priv->cru, > + AUPLL, rate); > + priv->aupll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[AUPLL], > + priv->cru, AUPLL); > + break; > + case PLL_PPLL: > + ret = rockchip_pll_set_rate(&rk3588_pll_clks[PPLL], priv->cru, > + PPLL, rate); > + priv->ppll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL], > + priv->cru, PPLL); > + break; > + case ACLK_CENTER_ROOT: > + case PCLK_CENTER_ROOT: > + case HCLK_CENTER_ROOT: > + case ACLK_CENTER_LOW_ROOT: > + ret = rk3588_center_set_clk(priv, clk->id, rate); > + break; > + case ACLK_TOP_ROOT: > + case PCLK_TOP_ROOT: > + case ACLK_LOW_TOP_ROOT: > + ret = rk3588_top_set_clk(priv, clk->id, rate); > + break; > + case CLK_I2C0: > + case CLK_I2C1: > + case CLK_I2C2: > + case CLK_I2C3: > + case CLK_I2C4: > + case CLK_I2C5: > + case CLK_I2C6: > + case CLK_I2C7: > + case CLK_I2C8: > + ret = rk3588_i2c_set_clk(priv, clk->id, rate); > + break; > + case CLK_SPI0: > + case CLK_SPI1: > + case CLK_SPI2: > + case CLK_SPI3: > + case CLK_SPI4: > + ret = rk3588_spi_set_clk(priv, clk->id, rate); > + break; > + case CLK_PWM1: > + case CLK_PWM2: > + case CLK_PWM3: > + case CLK_PMU1PWM: > + ret = rk3588_pwm_set_clk(priv, clk->id, rate); > + break; > + case CLK_SARADC: > + case CLK_TSADC: > + ret = rk3588_adc_set_clk(priv, clk->id, rate); > + break; > + case CCLK_SRC_SDIO: > + case CCLK_EMMC: > + case BCLK_EMMC: > + case SCLK_SFC: > + case DCLK_DECOM: > + ret = rk3588_mmc_set_clk(priv, clk->id, rate); > + break; > + case TCLK_WDT0: > + ret = OSC_HZ; > + break; > +#ifndef CONFIG_SPL_BUILD > + case CLK_AUX16M_0: > + case CLK_AUX16M_1: > + rk3588_aux16m_set_clk(priv, clk->id, rate); This is missing "ret = " before function call. Regards, Jonas > + break; > + case ACLK_VOP_ROOT: > + case ACLK_VOP: > + case ACLK_VOP_LOW_ROOT: > + case HCLK_VOP_ROOT: > + ret = rk3588_aclk_vop_set_clk(priv, clk->id, rate); > + break; > + case DCLK_VOP0: > + case DCLK_VOP0_SRC: > + case DCLK_VOP1: > + case DCLK_VOP1_SRC: > + case DCLK_VOP2: > + case DCLK_VOP2_SRC: > + case DCLK_VOP3: > + ret = rk3588_dclk_vop_set_clk(priv, clk->id, rate); > + break; > + case CLK_GMAC0_PTP_REF: > + case CLK_GMAC1_PTP_REF: > + case CLK_GMAC_125M: > + case CLK_GMAC_50M: > + ret = rk3588_gmac_set_clk(priv, clk->id, rate); > + break; > + case SCLK_UART1: > + case SCLK_UART2: > + case SCLK_UART3: > + case SCLK_UART4: > + case SCLK_UART5: > + case SCLK_UART6: > + case SCLK_UART7: > + case SCLK_UART8: > + case SCLK_UART9: > + ret = rk3588_uart_set_rate(priv, clk->id, rate); > + break; > + case CLK_REF_PIPE_PHY0: > + case CLK_REF_PIPE_PHY1: > + case CLK_REF_PIPE_PHY2: > + ret = rk3588_pciephy_set_rate(priv, clk->id, rate); > + break; > +#endif > + default: > + return -ENOENT; > + } > + > + return ret; > +}; > + [...]