[PATCH v1 05/18] clk: rockchip: Add rk3588 clk support
Jonas Karlman
jonas at kwiboo.se
Thu Feb 16 22:44:03 CET 2023
Hi Jagan,
On 2023-01-30 15:57, Jagan Teki wrote:
> Add clock driver support for Rockchip RK3588 SoC.
>
> Signed-off-by: Elaine Zhang <zhangqing at rock-chips.com>
> Signed-off-by: Jagan Teki <jagan at 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 <zhangqing at 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;
> +};
> +
[...]
More information about the U-Boot
mailing list