[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