diff options
| author | Tom Rini <[email protected]> | 2025-04-23 11:34:53 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-04-23 11:34:53 -0600 |
| commit | 6e325df4891cb9be954f1e62f16cd3096b267bdb (patch) | |
| tree | 1ddf3ed2807a48df09912561867a26b18ac30f0b /drivers | |
| parent | 873bca77a3dd4f6ba69c244bb1aaecb82679271f (diff) | |
| parent | 1f07d257305c168551370fbaddbc2b2d83aedde4 (diff) | |
Merge tag 'u-boot-rockchip-20250423' of https://source.denx.de/u-boot/custodians/u-boot-rockchip
CI: https://source.denx.de/u-boot/custodians/u-boot-rockchip/-/pipelines/25909
Please pull the updates for rockchip platform:
- New SoC support: RK3528, RK3576
- New Board support: rk3528 Radxa E20C, rk3576 Firefly ROC-RK3576-PC;
- Add generic board for rk3288 and rk3399;
- rng driver binding update;
- misc updates on board level or header files;
Diffstat (limited to 'drivers')
23 files changed, 6370 insertions, 22 deletions
diff --git a/drivers/adc/rockchip-saradc.c b/drivers/adc/rockchip-saradc.c index 7cf9735f60d..1515951403c 100644 --- a/drivers/adc/rockchip-saradc.c +++ b/drivers/adc/rockchip-saradc.c @@ -339,6 +339,14 @@ static const struct rockchip_saradc_data rk3399_saradc_data = { .stop = rockchip_saradc_stop_v1, }; +static const struct rockchip_saradc_data rk3528_saradc_data = { + .num_bits = 10, + .num_channels = 4, + .clk_rate = 1000000, + .channel_data = rockchip_saradc_channel_data_v2, + .start_channel = rockchip_saradc_start_channel_v2, +}; + static const struct rockchip_saradc_data rk3588_saradc_data = { .num_bits = 12, .num_channels = 8, @@ -354,6 +362,8 @@ static const struct udevice_id rockchip_saradc_ids[] = { .data = (ulong)&rk3066_tsadc_data }, { .compatible = "rockchip,rk3399-saradc", .data = (ulong)&rk3399_saradc_data }, + { .compatible = "rockchip,rk3528-saradc", + .data = (ulong)&rk3528_saradc_data }, { .compatible = "rockchip,rk3588-saradc", .data = (ulong)&rk3588_saradc_data }, { } diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 9e379cc2e3b..34b63d4df34 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -15,7 +15,9 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += clk_rk3308.o obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o +obj-$(CONFIG_ROCKCHIP_RK3528) += clk_rk3528.o obj-$(CONFIG_ROCKCHIP_RK3568) += clk_rk3568.o +obj-$(CONFIG_ROCKCHIP_RK3576) += clk_rk3576.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_pll.c b/drivers/clk/rockchip/clk_pll.c index 44c6f14618d..9dec40b1fe8 100644 --- a/drivers/clk/rockchip/clk_pll.c +++ b/drivers/clk/rockchip/clk_pll.c @@ -309,9 +309,11 @@ static int rk3036_pll_set_rate(struct rockchip_pll_clock *pll, * When power on or changing PLL setting, * we must force PLL into slow mode to ensure output stable clock. */ - rk_clrsetreg(base + pll->mode_offset, - pll->mode_mask << pll->mode_shift, - RKCLK_PLL_MODE_SLOW << pll->mode_shift); + if (!(pll->pll_flags & ROCKCHIP_PLL_FIXED_MODE)) { + rk_clrsetreg(base + pll->mode_offset, + pll->mode_mask << pll->mode_shift, + RKCLK_PLL_MODE_SLOW << pll->mode_shift); + } /* Power down */ rk_setreg(base + pll->con_offset + 0x4, @@ -345,8 +347,11 @@ static int rk3036_pll_set_rate(struct rockchip_pll_clock *pll, while (!(readl(base + pll->con_offset + 0x4) & (1 << pll->lock_shift))) udelay(1); - rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift, - RKCLK_PLL_MODE_NORMAL << pll->mode_shift); + if (!(pll->pll_flags & ROCKCHIP_PLL_FIXED_MODE)) { + rk_clrsetreg(base + pll->mode_offset, + pll->mode_mask << pll->mode_shift, + RKCLK_PLL_MODE_NORMAL << pll->mode_shift); + } debug("PLL at %p: con0=%x con1= %x con2= %x mode= %x\n", pll, readl(base + pll->con_offset), readl(base + pll->con_offset + 0x4), @@ -362,12 +367,18 @@ static ulong rk3036_pll_get_rate(struct rockchip_pll_clock *pll, u32 refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac; u32 con = 0, shift, mask; ulong rate; + int mode; con = readl(base + pll->mode_offset); shift = pll->mode_shift; mask = pll->mode_mask << shift; - switch ((con & mask) >> shift) { + if (!(pll->pll_flags & ROCKCHIP_PLL_FIXED_MODE)) + mode = (con & mask) >> shift; + else + mode = RKCLK_PLL_MODE_NORMAL; + + switch (mode) { case RKCLK_PLL_MODE_SLOW: return OSC_HZ; case RKCLK_PLL_MODE_NORMAL: diff --git a/drivers/clk/rockchip/clk_rk3528.c b/drivers/clk/rockchip/clk_rk3528.c new file mode 100644 index 00000000000..06f20895acc --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3528.c @@ -0,0 +1,1754 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + * Author: Joseph Chen <[email protected]> + */ + +#include <bitfield.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/cru_rk3528.h> +#include <asm/arch-rockchip/hardware.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dt-bindings/clock/rockchip,rk3528-cru.h> +#include <linux/delay.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) + +/* + * PLL attention. + * + * [FRAC PLL]: GPLL, PPLL, DPLL + * - frac mode: refdiv can be 1 or 2 only + * - int mode: refdiv has no special limit + * - VCO range: [950, 3800] MHZ + * + * [INT PLL]: CPLL, APLL + * - int mode: refdiv can be 1 or 2 only + * - VCO range: [475, 1900] MHZ + * + * [PPLL]: normal mode only. + * + */ +static struct rockchip_pll_rate_table rk3528_pll_rates[] = { + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ + RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0), + RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0), + RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0), + RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), + RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), + RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), + RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), + RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), + RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), /* GPLL */ + RK3036_PLL_RATE(1092000000, 2, 91, 1, 1, 1, 0), + RK3036_PLL_RATE(1008000000, 1, 42, 1, 1, 1, 0), + RK3036_PLL_RATE(1000000000, 1, 125, 3, 1, 1, 0), /* PPLL */ + RK3036_PLL_RATE(996000000, 2, 83, 1, 1, 1, 0), /* CPLL */ + RK3036_PLL_RATE(960000000, 1, 40, 1, 1, 1, 0), + RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), + RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), + RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0), + RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), + RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), + RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0), + RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), + RK3036_PLL_RATE(96000000, 1, 24, 3, 2, 1, 0), + { /* sentinel */ }, +}; + +static struct rockchip_pll_clock rk3528_pll_clks[] = { + [APLL] = PLL(pll_rk3328, PLL_APLL, RK3528_PLL_CON(0), + RK3528_MODE_CON, 0, 10, 0, rk3528_pll_rates), + + [CPLL] = PLL(pll_rk3328, PLL_CPLL, RK3528_PLL_CON(8), + RK3528_MODE_CON, 2, 10, 0, rk3528_pll_rates), + + [GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3528_PLL_CON(24), + RK3528_MODE_CON, 4, 10, 0, rk3528_pll_rates), + + [PPLL] = PLL(pll_rk3328, PLL_PPLL, RK3528_PCIE_PLL_CON(32), + RK3528_MODE_CON, 6, 10, ROCKCHIP_PLL_FIXED_MODE, rk3528_pll_rates), + + [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3528_DDRPHY_PLL_CON(16), + RK3528_DDRPHY_MODE_CON, 0, 10, 0, rk3528_pll_rates), +}; + +#define RK3528_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg) \ +{ \ + .rate = _rate##U, \ + .aclk_div = (_aclk_m_core), \ + .pclk_div = (_pclk_dbg), \ +} + +/* sign-off: _aclk_m_core: 550M, _pclk_dbg: 137.5M, */ +static struct rockchip_cpu_rate_table rk3528_cpu_rates[] = { + RK3528_CPUCLK_RATE(1896000000, 1, 13), + RK3528_CPUCLK_RATE(1800000000, 1, 12), + RK3528_CPUCLK_RATE(1704000000, 1, 11), + RK3528_CPUCLK_RATE(1608000000, 1, 11), + RK3528_CPUCLK_RATE(1512000000, 1, 11), + RK3528_CPUCLK_RATE(1416000000, 1, 9), + RK3528_CPUCLK_RATE(1296000000, 1, 8), + RK3528_CPUCLK_RATE(1200000000, 1, 8), + RK3528_CPUCLK_RATE(1188000000, 1, 8), + RK3528_CPUCLK_RATE(1092000000, 1, 7), + RK3528_CPUCLK_RATE(1008000000, 1, 6), + RK3528_CPUCLK_RATE(1000000000, 1, 6), + RK3528_CPUCLK_RATE(996000000, 1, 6), + RK3528_CPUCLK_RATE(960000000, 1, 6), + RK3528_CPUCLK_RATE(912000000, 1, 6), + RK3528_CPUCLK_RATE(816000000, 1, 5), + RK3528_CPUCLK_RATE(600000000, 1, 3), + RK3528_CPUCLK_RATE(594000000, 1, 3), + RK3528_CPUCLK_RATE(408000000, 1, 2), + RK3528_CPUCLK_RATE(312000000, 1, 2), + RK3528_CPUCLK_RATE(216000000, 1, 1), + RK3528_CPUCLK_RATE(96000000, 1, 0), +}; + +/* + * + * 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; +} + +static int rk3528_armclk_set_clk(struct rk3528_clk_priv *priv, ulong new_rate) +{ + const struct rockchip_cpu_rate_table *rate; + struct rk3528_cru *cru = priv->cru; + ulong old_rate; + + rate = rockchip_get_cpu_settings(rk3528_cpu_rates, new_rate); + if (!rate) { + printf("%s unsupported rate\n", __func__); + return -EINVAL; + } + + /* + * set up dependent divisors for DBG and ACLK clocks. + */ + old_rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru, APLL); + if (old_rate > new_rate) { + if (rockchip_pll_set_rate(&rk3528_pll_clks[APLL], + priv->cru, APLL, new_rate)) + return -EINVAL; + + rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, + rate->pclk_div << RK3528_DIV_PCLK_DBG_SHIFT); + + rk_clrsetreg(&cru->clksel_con[39], RK3528_DIV_ACLK_M_CORE_MASK, + rate->aclk_div << RK3528_DIV_ACLK_M_CORE_SHIFT); + } else if (old_rate < new_rate) { + rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, + rate->pclk_div << RK3528_DIV_PCLK_DBG_SHIFT); + + rk_clrsetreg(&cru->clksel_con[39], RK3528_DIV_ACLK_M_CORE_MASK, + rate->aclk_div << RK3528_DIV_ACLK_M_CORE_SHIFT); + + if (rockchip_pll_set_rate(&rk3528_pll_clks[APLL], + priv->cru, APLL, new_rate)) + return -EINVAL; + } + + return 0; +} + +static ulong rk3528_ppll_matrix_get_rate(struct rk3528_clk_priv *priv, + ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 div, mask, shift; + void *reg; + + switch (clk_id) { + case CLK_PPLL_50M_MATRIX: + case CLK_GMAC1_RMII_VPU: + mask = PCIE_CLK_MATRIX_50M_SRC_DIV_MASK; + shift = PCIE_CLK_MATRIX_50M_SRC_DIV_SHIFT; + reg = &cru->pcieclksel_con[1]; + break; + + case CLK_PPLL_100M_MATRIX: + mask = PCIE_CLK_MATRIX_100M_SRC_DIV_MASK; + shift = PCIE_CLK_MATRIX_100M_SRC_DIV_SHIFT; + reg = &cru->pcieclksel_con[1]; + break; + + case CLK_PPLL_125M_MATRIX: + case CLK_GMAC1_SRC_VPU: + mask = CLK_MATRIX_125M_SRC_DIV_MASK; + shift = CLK_MATRIX_125M_SRC_DIV_SHIFT; + reg = &cru->clksel_con[60]; + break; + + case CLK_GMAC1_VPU_25M: + mask = CLK_MATRIX_25M_SRC_DIV_MASK; + shift = CLK_MATRIX_25M_SRC_DIV_SHIFT; + reg = &cru->clksel_con[60]; + break; + default: + return -ENOENT; + } + + div = (readl(reg) & mask) >> shift; + + return DIV_TO_RATE(priv->ppll_hz, div); +} + +static ulong rk3528_ppll_matrix_set_rate(struct rk3528_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 id, div, mask, shift; + u8 is_pciecru = 0; + + switch (clk_id) { + case CLK_PPLL_50M_MATRIX: + id = 1; + mask = PCIE_CLK_MATRIX_50M_SRC_DIV_MASK; + shift = PCIE_CLK_MATRIX_50M_SRC_DIV_SHIFT; + is_pciecru = 1; + break; + + case CLK_PPLL_100M_MATRIX: + id = 1; + mask = PCIE_CLK_MATRIX_100M_SRC_DIV_MASK; + shift = PCIE_CLK_MATRIX_100M_SRC_DIV_SHIFT; + is_pciecru = 1; + break; + + case CLK_PPLL_125M_MATRIX: + id = 60; + mask = CLK_MATRIX_125M_SRC_DIV_MASK; + shift = CLK_MATRIX_125M_SRC_DIV_SHIFT; + break; + case CLK_GMAC1_VPU_25M: + id = 60; + mask = CLK_MATRIX_25M_SRC_DIV_MASK; + shift = CLK_MATRIX_25M_SRC_DIV_SHIFT; + break; + default: + return -ENOENT; + } + + div = DIV_ROUND_UP(priv->ppll_hz, rate); + if (is_pciecru) + rk_clrsetreg(&cru->pcieclksel_con[id], mask, (div - 1) << shift); + else + rk_clrsetreg(&cru->clksel_con[id], mask, (div - 1) << shift); + + return rk3528_ppll_matrix_get_rate(priv, clk_id); +} + +static ulong rk3528_cgpll_matrix_get_rate(struct rk3528_clk_priv *priv, + ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 sel, div, mask, shift, con; + u32 sel_mask = 0, sel_shift; + u8 is_gpll_parent = 1; + u8 is_halfdiv = 0; + ulong prate; + + switch (clk_id) { + case CLK_MATRIX_50M_SRC: + con = 0; + mask = CLK_MATRIX_50M_SRC_DIV_MASK; + shift = CLK_MATRIX_50M_SRC_DIV_SHIFT; + is_gpll_parent = 0; + break; + + case CLK_MATRIX_100M_SRC: + con = 0; + mask = CLK_MATRIX_100M_SRC_DIV_MASK; + shift = CLK_MATRIX_100M_SRC_DIV_SHIFT; + is_gpll_parent = 0; + break; + + case CLK_MATRIX_150M_SRC: + con = 1; + mask = CLK_MATRIX_150M_SRC_DIV_MASK; + shift = CLK_MATRIX_150M_SRC_DIV_SHIFT; + break; + + case CLK_MATRIX_200M_SRC: + con = 1; + mask = CLK_MATRIX_200M_SRC_DIV_MASK; + shift = CLK_MATRIX_200M_SRC_DIV_SHIFT; + break; + + case CLK_MATRIX_250M_SRC: + con = 1; + mask = CLK_MATRIX_250M_SRC_DIV_MASK; + shift = CLK_MATRIX_250M_SRC_DIV_SHIFT; + sel_mask = CLK_MATRIX_250M_SRC_SEL_MASK; + sel_shift = CLK_MATRIX_250M_SRC_SEL_SHIFT; + break; + + case CLK_MATRIX_300M_SRC: + con = 2; + mask = CLK_MATRIX_300M_SRC_DIV_MASK; + shift = CLK_MATRIX_300M_SRC_DIV_SHIFT; + break; + + case CLK_MATRIX_339M_SRC: + con = 2; + mask = CLK_MATRIX_339M_SRC_DIV_MASK; + shift = CLK_MATRIX_339M_SRC_DIV_SHIFT; + is_halfdiv = 1; + break; + + case CLK_MATRIX_400M_SRC: + con = 2; + mask = CLK_MATRIX_400M_SRC_DIV_MASK; + shift = CLK_MATRIX_400M_SRC_DIV_SHIFT; + break; + + case CLK_MATRIX_500M_SRC: + con = 3; + mask = CLK_MATRIX_500M_SRC_DIV_MASK; + shift = CLK_MATRIX_500M_SRC_DIV_SHIFT; + sel_mask = CLK_MATRIX_500M_SRC_SEL_MASK; + sel_shift = CLK_MATRIX_500M_SRC_SEL_SHIFT; + break; + + case CLK_MATRIX_600M_SRC: + con = 4; + mask = CLK_MATRIX_600M_SRC_DIV_MASK; + shift = CLK_MATRIX_600M_SRC_DIV_SHIFT; + break; + + case ACLK_BUS_VOPGL_ROOT: + case ACLK_BUS_VOPGL_BIU: + con = 43; + mask = ACLK_BUS_VOPGL_ROOT_DIV_MASK; + shift = ACLK_BUS_VOPGL_ROOT_DIV_SHIFT; + break; + + default: + return -ENOENT; + } + + if (sel_mask) { + sel = (readl(&cru->clksel_con[con]) & sel_mask) >> sel_shift; + if (sel == CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX) // TODO + prate = priv->gpll_hz; + else + prate = priv->cpll_hz; + } else { + if (is_gpll_parent) + prate = priv->gpll_hz; + else + prate = priv->cpll_hz; + } + + div = (readl(&cru->clksel_con[con]) & mask) >> shift; + + /* NOTE: '-1' to balance the DIV_TO_RATE() 'div+1' */ + return is_halfdiv ? DIV_TO_RATE(prate * 2, (3 + 2 * div) - 1) : DIV_TO_RATE(prate, div); +} + +static ulong rk3528_cgpll_matrix_set_rate(struct rk3528_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 sel, div, mask, shift, con; + u32 sel_mask = 0, sel_shift; + u8 is_gpll_parent = 1; + u8 is_halfdiv = 0; + ulong prate = 0; + + switch (clk_id) { + case CLK_MATRIX_50M_SRC: + con = 0; + mask = CLK_MATRIX_50M_SRC_DIV_MASK; + shift = CLK_MATRIX_50M_SRC_DIV_SHIFT; + is_gpll_parent = 0; + break; + + case CLK_MATRIX_100M_SRC: + con = 0; + mask = CLK_MATRIX_100M_SRC_DIV_MASK; + shift = CLK_MATRIX_100M_SRC_DIV_SHIFT; + is_gpll_parent = 0; + break; + + case CLK_MATRIX_150M_SRC: + con = 1; + mask = CLK_MATRIX_150M_SRC_DIV_MASK; + shift = CLK_MATRIX_150M_SRC_DIV_SHIFT; + break; + + case CLK_MATRIX_200M_SRC: + con = 1; + mask = CLK_MATRIX_200M_SRC_DIV_MASK; + shift = CLK_MATRIX_200M_SRC_DIV_SHIFT; + break; + + case CLK_MATRIX_250M_SRC: + con = 1; + mask = CLK_MATRIX_250M_SRC_DIV_MASK; + shift = CLK_MATRIX_250M_SRC_DIV_SHIFT; + sel_mask = CLK_MATRIX_250M_SRC_SEL_MASK; + sel_shift = CLK_MATRIX_250M_SRC_SEL_SHIFT; + break; + + case CLK_MATRIX_300M_SRC: + con = 2; + mask = CLK_MATRIX_300M_SRC_DIV_MASK; + shift = CLK_MATRIX_300M_SRC_DIV_SHIFT; + break; + + case CLK_MATRIX_339M_SRC: + con = 2; + mask = CLK_MATRIX_339M_SRC_DIV_MASK; + shift = CLK_MATRIX_339M_SRC_DIV_SHIFT; + is_halfdiv = 1; + break; + + case CLK_MATRIX_400M_SRC: + con = 2; + mask = CLK_MATRIX_400M_SRC_DIV_MASK; + shift = CLK_MATRIX_400M_SRC_DIV_SHIFT; + break; + + case CLK_MATRIX_500M_SRC: + con = 3; + mask = CLK_MATRIX_500M_SRC_DIV_MASK; + shift = CLK_MATRIX_500M_SRC_DIV_SHIFT; + sel_mask = CLK_MATRIX_500M_SRC_SEL_MASK; + sel_shift = CLK_MATRIX_500M_SRC_SEL_SHIFT; + break; + + case CLK_MATRIX_600M_SRC: + con = 4; + mask = CLK_MATRIX_600M_SRC_DIV_MASK; + shift = CLK_MATRIX_600M_SRC_DIV_SHIFT; + break; + + case ACLK_BUS_VOPGL_ROOT: + case ACLK_BUS_VOPGL_BIU: + con = 43; + mask = ACLK_BUS_VOPGL_ROOT_DIV_MASK; + shift = ACLK_BUS_VOPGL_ROOT_DIV_SHIFT; + break; + + default: + return -ENOENT; + } + + if (sel_mask) { + if (priv->gpll_hz % rate == 0) { + sel = CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX; // TODO + prate = priv->gpll_hz; + } else { + sel = CLK_MATRIX_250M_SRC_SEL_CLK_CPLL_MUX; + prate = priv->cpll_hz; + } + } else { + if (is_gpll_parent) + prate = priv->gpll_hz; + else + prate = priv->cpll_hz; + } + + if (is_halfdiv) + /* NOTE: '+1' to balance the following rk_clrsetreg() 'div-1' */ + div = DIV_ROUND_UP((prate * 2) - (3 * rate), 2 * rate) + 1; + else + div = DIV_ROUND_UP(prate, rate); + + rk_clrsetreg(&cru->clksel_con[con], mask, (div - 1) << shift); + if (sel_mask) + rk_clrsetreg(&cru->clksel_con[con], sel_mask, sel << sel_shift); + + return rk3528_cgpll_matrix_get_rate(priv, clk_id); +} + +static ulong rk3528_i2c_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 id, sel, con, mask, shift; + u8 is_pmucru = 0; + ulong rate; + + switch (clk_id) { + case CLK_I2C0: + id = 79; + mask = CLK_I2C0_SEL_MASK; + shift = CLK_I2C0_SEL_SHIFT; + break; + + case CLK_I2C1: + id = 79; + mask = CLK_I2C1_SEL_MASK; + shift = CLK_I2C1_SEL_SHIFT; + break; + + case CLK_I2C2: + id = 0; + mask = CLK_I2C2_SEL_MASK; + shift = CLK_I2C2_SEL_SHIFT; + is_pmucru = 1; + break; + + case CLK_I2C3: + id = 63; + mask = CLK_I2C3_SEL_MASK; + shift = CLK_I2C3_SEL_SHIFT; + break; + + case CLK_I2C4: + id = 85; + mask = CLK_I2C4_SEL_MASK; + shift = CLK_I2C4_SEL_SHIFT; + break; + + case CLK_I2C5: + id = 63; + mask = CLK_I2C5_SEL_MASK; + shift = CLK_I2C5_SEL_SHIFT; + break; + + case CLK_I2C6: + id = 64; + mask = CLK_I2C6_SEL_MASK; + shift = CLK_I2C6_SEL_SHIFT; + break; + + case CLK_I2C7: + id = 86; + mask = CLK_I2C7_SEL_MASK; + shift = CLK_I2C7_SEL_SHIFT; + break; + + default: + return -ENOENT; + } + + if (is_pmucru) + con = readl(&cru->pmuclksel_con[id]); + else + con = readl(&cru->clksel_con[id]); + sel = (con & mask) >> shift; + if (sel == CLK_I2C3_SEL_CLK_MATRIX_200M_SRC) + rate = 200 * MHz; + else if (sel == CLK_I2C3_SEL_CLK_MATRIX_100M_SRC) + rate = 100 * MHz; + else if (sel == CLK_I2C3_SEL_CLK_MATRIX_50M_SRC) + rate = 50 * MHz; + else + rate = OSC_HZ; + + return rate; +} + +static ulong rk3528_i2c_set_clk(struct rk3528_clk_priv *priv, ulong clk_id, + ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 id, sel, mask, shift; + u8 is_pmucru = 0; + + if (rate >= 198 * MHz) + sel = CLK_I2C3_SEL_CLK_MATRIX_200M_SRC; + else if (rate >= 99 * MHz) + sel = CLK_I2C3_SEL_CLK_MATRIX_100M_SRC; + else if (rate >= 50 * MHz) + sel = CLK_I2C3_SEL_CLK_MATRIX_50M_SRC; + else + sel = CLK_I2C3_SEL_XIN_OSC0_FUNC; + + switch (clk_id) { + case CLK_I2C0: + id = 79; + mask = CLK_I2C0_SEL_MASK; + shift = CLK_I2C0_SEL_SHIFT; + break; + + case CLK_I2C1: + id = 79; + mask = CLK_I2C1_SEL_MASK; + shift = CLK_I2C1_SEL_SHIFT; + break; + + case CLK_I2C2: + id = 0; + mask = CLK_I2C2_SEL_MASK; + shift = CLK_I2C2_SEL_SHIFT; + is_pmucru = 1; + break; + + case CLK_I2C3: + id = 63; + mask = CLK_I2C3_SEL_MASK; + shift = CLK_I2C3_SEL_SHIFT; + break; + + case CLK_I2C4: + id = 85; + mask = CLK_I2C4_SEL_MASK; + shift = CLK_I2C4_SEL_SHIFT; + break; + + case CLK_I2C5: + id = 63; + mask = CLK_I2C5_SEL_MASK; + shift = CLK_I2C5_SEL_SHIFT; + break; + + case CLK_I2C6: + id = 64; + mask = CLK_I2C6_SEL_MASK; + shift = CLK_I2C6_SEL_SHIFT; + break; + + case CLK_I2C7: + id = 86; + mask = CLK_I2C7_SEL_MASK; + shift = CLK_I2C7_SEL_SHIFT; + break; + + default: + return -ENOENT; + } + + if (is_pmucru) + rk_clrsetreg(&cru->pmuclksel_con[id], mask, sel << shift); + else + rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); + + return rk3528_i2c_get_clk(priv, clk_id); +} + +static ulong rk3528_spi_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 id, sel, con, mask, shift; + ulong rate; + + switch (clk_id) { + case CLK_SPI0: + id = 79; + mask = CLK_SPI0_SEL_MASK; + shift = CLK_SPI0_SEL_SHIFT; + break; + + case CLK_SPI1: + id = 63; + mask = CLK_SPI1_SEL_MASK; + shift = CLK_SPI1_SEL_SHIFT; + break; + default: + return -ENOENT; + } + + con = readl(&cru->clksel_con[id]); + sel = (con & mask) >> shift; + if (sel == CLK_SPI1_SEL_CLK_MATRIX_200M_SRC) + rate = 200 * MHz; + else if (sel == CLK_SPI1_SEL_CLK_MATRIX_100M_SRC) + rate = 100 * MHz; + else if (sel == CLK_SPI1_SEL_CLK_MATRIX_50M_SRC) + rate = 50 * MHz; + else + rate = OSC_HZ; + + return rate; +} + +static ulong rk3528_spi_set_clk(struct rk3528_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 id, sel, mask, shift; + + if (rate >= 198 * MHz) + sel = CLK_SPI1_SEL_CLK_MATRIX_200M_SRC; + else if (rate >= 99 * MHz) + sel = CLK_SPI1_SEL_CLK_MATRIX_100M_SRC; + else if (rate >= 50 * MHz) + sel = CLK_SPI1_SEL_CLK_MATRIX_50M_SRC; + else + sel = CLK_SPI1_SEL_XIN_OSC0_FUNC; + + switch (clk_id) { + case CLK_SPI0: + id = 79; + mask = CLK_SPI0_SEL_MASK; + shift = CLK_SPI0_SEL_SHIFT; + break; + + case CLK_SPI1: + id = 63; + mask = CLK_SPI1_SEL_MASK; + shift = CLK_SPI1_SEL_SHIFT; + break; + default: + return -ENOENT; + } + + rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); + + return rk3528_spi_get_clk(priv, clk_id); +} + +static ulong rk3528_pwm_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 id, sel, con, mask, shift; + ulong rate; + + switch (clk_id) { + case CLK_PWM0: + id = 44; + mask = CLK_PWM0_SEL_MASK; + shift = CLK_PWM0_SEL_SHIFT; + break; + + case CLK_PWM1: + id = 44; + mask = CLK_PWM1_SEL_MASK; + shift = CLK_PWM1_SEL_SHIFT; + break; + + default: + return -ENOENT; + } + + con = readl(&cru->clksel_con[id]); + sel = (con & mask) >> shift; + if (sel == CLK_PWM0_SEL_CLK_MATRIX_100M_SRC) + rate = 100 * MHz; + if (sel == CLK_PWM0_SEL_CLK_MATRIX_50M_SRC) + rate = 50 * MHz; + else + rate = OSC_HZ; + + return rate; +} + +static ulong rk3528_pwm_set_clk(struct rk3528_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 id, sel, mask, shift; + + if (rate >= 99 * MHz) + sel = CLK_PWM0_SEL_CLK_MATRIX_100M_SRC; + else if (rate >= 50 * MHz) + sel = CLK_PWM0_SEL_CLK_MATRIX_50M_SRC; + else + sel = CLK_PWM0_SEL_XIN_OSC0_FUNC; + + switch (clk_id) { + case CLK_PWM0: + id = 44; + mask = CLK_PWM0_SEL_MASK; + shift = CLK_PWM0_SEL_SHIFT; + break; + + case CLK_PWM1: + id = 44; + mask = CLK_PWM1_SEL_MASK; + shift = CLK_PWM1_SEL_SHIFT; + break; + + default: + return -ENOENT; + } + + rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift); + + return rk3528_pwm_get_clk(priv, clk_id); +} + +static ulong rk3528_adc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 div, con; + + con = readl(&cru->clksel_con[74]); + switch (clk_id) { + case CLK_SARADC: + div = (con & CLK_SARADC_DIV_MASK) >> + CLK_SARADC_DIV_SHIFT; + break; + + case CLK_TSADC_TSEN: + div = (con & CLK_TSADC_TSEN_DIV_MASK) >> + CLK_TSADC_TSEN_DIV_SHIFT; + break; + + case CLK_TSADC: + div = (con & CLK_TSADC_DIV_MASK) >> + CLK_TSADC_DIV_SHIFT; + break; + + default: + return -ENOENT; + } + + return DIV_TO_RATE(OSC_HZ, div); +} + +static ulong rk3528_adc_set_clk(struct rk3528_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 div, mask, shift; + + switch (clk_id) { + case CLK_SARADC: + mask = CLK_SARADC_DIV_MASK; + shift = CLK_SARADC_DIV_SHIFT; + break; + + case CLK_TSADC_TSEN: + mask = CLK_TSADC_TSEN_DIV_MASK; + shift = CLK_TSADC_TSEN_DIV_SHIFT; + break; + + case CLK_TSADC: + mask = CLK_TSADC_DIV_MASK; + shift = CLK_TSADC_DIV_SHIFT; + break; + + default: + return -ENOENT; + } + + div = DIV_ROUND_UP(OSC_HZ, rate); + rk_clrsetreg(&cru->clksel_con[74], mask, (div - 1) << shift); + + return rk3528_adc_get_clk(priv, clk_id); +} + +static ulong rk3528_sdmmc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 div, sel, con; + ulong prate; + + con = readl(&cru->clksel_con[85]); + div = (con & CCLK_SRC_SDMMC0_DIV_MASK) >> + CCLK_SRC_SDMMC0_DIV_SHIFT; + sel = (con & CCLK_SRC_SDMMC0_SEL_MASK) >> + CCLK_SRC_SDMMC0_SEL_SHIFT; + + if (sel == CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX) + prate = priv->gpll_hz; + else if (sel == CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX) + prate = priv->cpll_hz; + else + prate = OSC_HZ; + + return DIV_TO_RATE(prate, div); +} + +static ulong rk3528_sdmmc_set_clk(struct rk3528_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 div, sel; + + if (OSC_HZ % rate == 0) { + div = DIV_ROUND_UP(OSC_HZ, rate); + sel = CCLK_SRC_SDMMC0_SEL_XIN_OSC0_FUNC; + } else if ((priv->cpll_hz % rate) == 0) { + div = DIV_ROUND_UP(priv->cpll_hz, rate); + sel = CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX; + } else { + div = DIV_ROUND_UP(priv->gpll_hz, rate); + sel = CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX; + } + + assert(div - 1 <= 63); + rk_clrsetreg(&cru->clksel_con[85], + CCLK_SRC_SDMMC0_SEL_MASK | + CCLK_SRC_SDMMC0_DIV_MASK, + sel << CCLK_SRC_SDMMC0_SEL_SHIFT | + (div - 1) << CCLK_SRC_SDMMC0_DIV_SHIFT); + + return rk3528_sdmmc_get_clk(priv, clk_id); +} + +static ulong rk3528_sfc_get_clk(struct rk3528_clk_priv *priv) +{ + struct rk3528_cru *cru = priv->cru; + u32 div, sel, con, parent; + + con = readl(&cru->clksel_con[61]); + div = (con & SCLK_SFC_DIV_MASK) >> + SCLK_SFC_DIV_SHIFT; + sel = (con & SCLK_SFC_SEL_MASK) >> + SCLK_SFC_SEL_SHIFT; + if (sel == SCLK_SFC_SEL_CLK_GPLL_MUX) + parent = priv->gpll_hz; + else if (sel == SCLK_SFC_SEL_CLK_CPLL_MUX) + parent = priv->cpll_hz; + else + parent = OSC_HZ; + + return DIV_TO_RATE(parent, div); +} + +static ulong rk3528_sfc_set_clk(struct rk3528_clk_priv *priv, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + int div, sel; + + if (OSC_HZ % rate == 0) { + div = DIV_ROUND_UP(OSC_HZ, rate); + sel = SCLK_SFC_SEL_XIN_OSC0_FUNC; + } else if ((priv->cpll_hz % rate) == 0) { + div = DIV_ROUND_UP(priv->cpll_hz, rate); + sel = SCLK_SFC_SEL_CLK_CPLL_MUX; + } else { + div = DIV_ROUND_UP(priv->gpll_hz, rate); + sel = SCLK_SFC_SEL_CLK_GPLL_MUX; + } + + assert(div - 1 <= 63); + rk_clrsetreg(&cru->clksel_con[61], + SCLK_SFC_SEL_MASK | + SCLK_SFC_DIV_MASK, + sel << SCLK_SFC_SEL_SHIFT | + (div - 1) << SCLK_SFC_DIV_SHIFT); + + return rk3528_sfc_get_clk(priv); +} + +static ulong rk3528_emmc_get_clk(struct rk3528_clk_priv *priv) +{ + struct rk3528_cru *cru = priv->cru; + u32 div, sel, con, parent; + + con = readl(&cru->clksel_con[62]); + div = (con & CCLK_SRC_EMMC_DIV_MASK) >> + CCLK_SRC_EMMC_DIV_SHIFT; + sel = (con & CCLK_SRC_EMMC_SEL_MASK) >> + CCLK_SRC_EMMC_SEL_SHIFT; + + if (sel == CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX) + parent = priv->gpll_hz; + else if (sel == CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX) + parent = priv->cpll_hz; + else + parent = OSC_HZ; + + return DIV_TO_RATE(parent, div); +} + +static ulong rk3528_emmc_set_clk(struct rk3528_clk_priv *priv, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 div, sel; + + if (OSC_HZ % rate == 0) { + div = DIV_ROUND_UP(OSC_HZ, rate); + sel = CCLK_SRC_EMMC_SEL_XIN_OSC0_FUNC; + } else if ((priv->cpll_hz % rate) == 0) { + div = DIV_ROUND_UP(priv->cpll_hz, rate); + sel = CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX; + } else { + div = DIV_ROUND_UP(priv->gpll_hz, rate); + sel = CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX; + } + + assert(div - 1 <= 63); + rk_clrsetreg(&cru->clksel_con[62], + CCLK_SRC_EMMC_SEL_MASK | + CCLK_SRC_EMMC_DIV_MASK, + sel << CCLK_SRC_EMMC_SEL_SHIFT | + (div - 1) << CCLK_SRC_EMMC_DIV_SHIFT); + + return rk3528_emmc_get_clk(priv); +} + +static ulong rk3528_dclk_vop_get_clk(struct rk3528_clk_priv *priv, ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 div_mask, div_shift; + u32 sel_mask, sel_shift; + u32 id, con, sel, div; + ulong prate; + + switch (clk_id) { + case DCLK_VOP0: + id = 32; + sel_mask = DCLK_VOP_SRC0_SEL_MASK; + sel_shift = DCLK_VOP_SRC0_SEL_SHIFT; + /* FIXME if need src: clk_hdmiphy_pixel_io */ + div_mask = DCLK_VOP_SRC0_DIV_MASK; + div_shift = DCLK_VOP_SRC0_DIV_SHIFT; + break; + + case DCLK_VOP1: + id = 33; + sel_mask = DCLK_VOP_SRC1_SEL_MASK; + sel_shift = DCLK_VOP_SRC1_SEL_SHIFT; + div_mask = DCLK_VOP_SRC1_DIV_MASK; + div_shift = DCLK_VOP_SRC1_DIV_SHIFT; + break; + + default: + return -ENOENT; + } + + con = readl(&cru->clksel_con[id]); + div = (con & div_mask) >> div_shift; + sel = (con & sel_mask) >> sel_shift; + if (sel == DCLK_VOP_SRC_SEL_CLK_GPLL_MUX) + prate = priv->gpll_hz; + else + prate = priv->cpll_hz; + + return DIV_TO_RATE(prate, div); +} + +static ulong rk3528_dclk_vop_set_clk(struct rk3528_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 div_mask, div_shift; + u32 sel_mask, sel_shift; + u32 id, sel, div; + ulong prate; + + switch (clk_id) { + case DCLK_VOP0: + id = 32; + sel_mask = DCLK_VOP_SRC0_SEL_MASK; + sel_shift = DCLK_VOP_SRC0_SEL_SHIFT; + /* FIXME if need src: clk_hdmiphy_pixel_io */ + div_mask = DCLK_VOP_SRC0_DIV_MASK; + div_shift = DCLK_VOP_SRC0_DIV_SHIFT; + break; + + case DCLK_VOP1: + id = 33; + sel_mask = DCLK_VOP_SRC1_SEL_MASK; + sel_shift = DCLK_VOP_SRC1_SEL_SHIFT; + div_mask = DCLK_VOP_SRC1_DIV_MASK; + div_shift = DCLK_VOP_SRC1_DIV_SHIFT; + break; + + default: + return -ENOENT; + } + + if ((priv->gpll_hz % rate) == 0) { + prate = priv->gpll_hz; + sel = (DCLK_VOP_SRC_SEL_CLK_GPLL_MUX << sel_shift) & sel_mask; + } else { + prate = priv->cpll_hz; + sel = (DCLK_VOP_SRC_SEL_CLK_CPLL_MUX << sel_shift) & sel_mask; + } + + div = ((DIV_ROUND_UP(prate, rate) - 1) << div_shift) & div_mask; + rk_clrsetreg(&cru->clksel_con[id], sel, div); + + return rk3528_dclk_vop_get_clk(priv, clk_id); +} + +static ulong rk3528_uart_get_rate(struct rk3528_clk_priv *priv, ulong clk_id) +{ + struct rk3528_cru *cru = priv->cru; + u32 sel_shift, sel_mask, div_shift, div_mask; + u32 sel, id, con, frac_div, div; + ulong m, n, rate; + + switch (clk_id) { + case SCLK_UART0: + id = 6; + sel_shift = SCLK_UART0_SRC_SEL_SHIFT; + sel_mask = SCLK_UART0_SRC_SEL_MASK; + div_shift = CLK_UART0_SRC_DIV_SHIFT; + div_mask = CLK_UART0_SRC_DIV_MASK; + break; + + case SCLK_UART1: + id = 8; + sel_shift = SCLK_UART1_SRC_SEL_SHIFT; + sel_mask = SCLK_UART1_SRC_SEL_MASK; + div_shift = CLK_UART1_SRC_DIV_SHIFT; + div_mask = CLK_UART1_SRC_DIV_MASK; + break; + + case SCLK_UART2: + id = 10; + sel_shift = SCLK_UART2_SRC_SEL_SHIFT; + sel_mask = SCLK_UART2_SRC_SEL_MASK; + div_shift = CLK_UART2_SRC_DIV_SHIFT; + div_mask = CLK_UART2_SRC_DIV_MASK; + break; + + case SCLK_UART3: + id = 12; + sel_shift = SCLK_UART3_SRC_SEL_SHIFT; + sel_mask = SCLK_UART3_SRC_SEL_MASK; + div_shift = CLK_UART3_SRC_DIV_SHIFT; + div_mask = CLK_UART3_SRC_DIV_MASK; + break; + + case SCLK_UART4: + id = 14; + sel_shift = SCLK_UART4_SRC_SEL_SHIFT; + sel_mask = SCLK_UART4_SRC_SEL_MASK; + div_shift = CLK_UART4_SRC_DIV_SHIFT; + div_mask = CLK_UART4_SRC_DIV_MASK; + break; + + case SCLK_UART5: + id = 16; + sel_shift = SCLK_UART5_SRC_SEL_SHIFT; + sel_mask = SCLK_UART5_SRC_SEL_MASK; + div_shift = CLK_UART5_SRC_DIV_SHIFT; + div_mask = CLK_UART5_SRC_DIV_MASK; + break; + + case SCLK_UART6: + id = 18; + sel_shift = SCLK_UART6_SRC_SEL_SHIFT; + sel_mask = SCLK_UART6_SRC_SEL_MASK; + div_shift = CLK_UART6_SRC_DIV_SHIFT; + div_mask = CLK_UART6_SRC_DIV_MASK; + break; + + case SCLK_UART7: + id = 20; + sel_shift = SCLK_UART7_SRC_SEL_SHIFT; + sel_mask = SCLK_UART7_SRC_SEL_MASK; + div_shift = CLK_UART7_SRC_DIV_SHIFT; + div_mask = CLK_UART7_SRC_DIV_MASK; + break; + + default: + return -ENOENT; + } + + con = readl(&cru->clksel_con[id - 2]); + div = (con & div_mask) >> div_shift; + + con = readl(&cru->clksel_con[id]); + sel = (con & sel_mask) >> sel_shift; + + if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_SRC) { + rate = DIV_TO_RATE(priv->gpll_hz, div); + } else if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_FRAC) { + frac_div = readl(&cru->clksel_con[id - 1]); + n = (frac_div & 0xffff0000) >> 16; + m = frac_div & 0x0000ffff; + rate = DIV_TO_RATE(priv->gpll_hz, div) * n / m; + } else { + rate = OSC_HZ; + } + + return rate; +} + +static ulong rk3528_uart_set_rate(struct rk3528_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 sel_shift, sel_mask, div_shift, div_mask; + u32 sel, id, div; + ulong m = 0, n = 0, val; + + if (rate == OSC_HZ) { + sel = SCLK_UART0_SRC_SEL_XIN_OSC0_FUNC; + div = DIV_ROUND_UP(OSC_HZ, rate); + } else if (priv->gpll_hz % rate == 0) { + sel = SCLK_UART0_SRC_SEL_CLK_UART0_SRC; + div = DIV_ROUND_UP(priv->gpll_hz, rate); + } else { + sel = SCLK_UART0_SRC_SEL_CLK_UART0_FRAC; + div = 2; + rational_best_approximation(rate, priv->gpll_hz / div, + GENMASK(16 - 1, 0), + GENMASK(16 - 1, 0), + &n, &m); + } + + switch (clk_id) { + case SCLK_UART0: + id = 6; + sel_shift = SCLK_UART0_SRC_SEL_SHIFT; + sel_mask = SCLK_UART0_SRC_SEL_MASK; + div_shift = CLK_UART0_SRC_DIV_SHIFT; + div_mask = CLK_UART0_SRC_DIV_MASK; + break; + + case SCLK_UART1: + id = 8; + sel_shift = SCLK_UART1_SRC_SEL_SHIFT; + sel_mask = SCLK_UART1_SRC_SEL_MASK; + div_shift = CLK_UART1_SRC_DIV_SHIFT; + div_mask = CLK_UART1_SRC_DIV_MASK; + break; + + case SCLK_UART2: + id = 10; + sel_shift = SCLK_UART2_SRC_SEL_SHIFT; + sel_mask = SCLK_UART2_SRC_SEL_MASK; + div_shift = CLK_UART2_SRC_DIV_SHIFT; + div_mask = CLK_UART2_SRC_DIV_MASK; + break; + + case SCLK_UART3: + id = 12; + sel_shift = SCLK_UART3_SRC_SEL_SHIFT; + sel_mask = SCLK_UART3_SRC_SEL_MASK; + div_shift = CLK_UART3_SRC_DIV_SHIFT; + div_mask = CLK_UART3_SRC_DIV_MASK; + break; + + case SCLK_UART4: + id = 14; + sel_shift = SCLK_UART4_SRC_SEL_SHIFT; + sel_mask = SCLK_UART4_SRC_SEL_MASK; + div_shift = CLK_UART4_SRC_DIV_SHIFT; + div_mask = CLK_UART4_SRC_DIV_MASK; + break; + + case SCLK_UART5: + id = 16; + sel_shift = SCLK_UART5_SRC_SEL_SHIFT; + sel_mask = SCLK_UART5_SRC_SEL_MASK; + div_shift = CLK_UART5_SRC_DIV_SHIFT; + div_mask = CLK_UART5_SRC_DIV_MASK; + break; + + case SCLK_UART6: + id = 18; + sel_shift = SCLK_UART6_SRC_SEL_SHIFT; + sel_mask = SCLK_UART6_SRC_SEL_MASK; + div_shift = CLK_UART6_SRC_DIV_SHIFT; + div_mask = CLK_UART6_SRC_DIV_MASK; + break; + + case SCLK_UART7: + id = 20; + sel_shift = SCLK_UART7_SRC_SEL_SHIFT; + sel_mask = SCLK_UART7_SRC_SEL_MASK; + div_shift = CLK_UART7_SRC_DIV_SHIFT; + div_mask = CLK_UART7_SRC_DIV_MASK; + break; + + default: + return -ENOENT; + } + + rk_clrsetreg(&cru->clksel_con[id - 2], div_mask, (div - 1) << div_shift); + rk_clrsetreg(&cru->clksel_con[id], sel_mask, sel << sel_shift); + if (m && n) { + val = n << 16 | m; + writel(val, &cru->clksel_con[id - 1]); + } + + return rk3528_uart_get_rate(priv, clk_id); +} + +static ulong rk3528_clk_get_rate(struct clk *clk) +{ + struct rk3528_clk_priv *priv = dev_get_priv(clk->dev); + ulong rate = 0; + + if (!priv->gpll_hz || !priv->cpll_hz) { + printf("%s: gpll=%lu, cpll=%ld\n", + __func__, priv->gpll_hz, priv->cpll_hz); + return -ENOENT; + } + + switch (clk->id) { + case PLL_APLL: + case ARMCLK: + rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru, + APLL); + break; + case PLL_CPLL: + rate = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL], priv->cru, + CPLL); + break; + case PLL_GPLL: + rate = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL], priv->cru, + GPLL); + break; + + case PLL_PPLL: + rate = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], priv->cru, + PPLL); + break; + case PLL_DPLL: + rate = rockchip_pll_get_rate(&rk3528_pll_clks[DPLL], priv->cru, + DPLL); + break; + + case TCLK_EMMC: + case TCLK_WDT_NS: + rate = OSC_HZ; + 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: + rate = rk3528_i2c_get_clk(priv, clk->id); + break; + case CLK_SPI0: + case CLK_SPI1: + rate = rk3528_spi_get_clk(priv, clk->id); + break; + case CLK_PWM0: + case CLK_PWM1: + rate = rk3528_pwm_get_clk(priv, clk->id); + break; + case CLK_SARADC: + case CLK_TSADC: + case CLK_TSADC_TSEN: + rate = rk3528_adc_get_clk(priv, clk->id); + break; + case CCLK_SRC_EMMC: + rate = rk3528_emmc_get_clk(priv); + break; + case HCLK_SDMMC0: + case CCLK_SRC_SDMMC0: + rate = rk3528_sdmmc_get_clk(priv, clk->id); + break; + case SCLK_SFC: + rate = rk3528_sfc_get_clk(priv); + break; + case DCLK_VOP0: + case DCLK_VOP1: + rate = rk3528_dclk_vop_get_clk(priv, clk->id); + break; + case DCLK_CVBS: + rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1) / 4; + break; + case DCLK_4X_CVBS: + rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1); + break; + case SCLK_UART0: + case SCLK_UART1: + case SCLK_UART2: + case SCLK_UART3: + case SCLK_UART4: + case SCLK_UART5: + case SCLK_UART6: + case SCLK_UART7: + rate = rk3528_uart_get_rate(priv, clk->id); + break; + case CLK_MATRIX_50M_SRC: + case CLK_MATRIX_100M_SRC: + case CLK_MATRIX_150M_SRC: + case CLK_MATRIX_200M_SRC: + case CLK_MATRIX_250M_SRC: + case CLK_MATRIX_300M_SRC: + case CLK_MATRIX_339M_SRC: + case CLK_MATRIX_400M_SRC: + case CLK_MATRIX_500M_SRC: + case CLK_MATRIX_600M_SRC: + case ACLK_BUS_VOPGL_BIU: + rate = rk3528_cgpll_matrix_get_rate(priv, clk->id); + break; + case CLK_PPLL_50M_MATRIX: + case CLK_PPLL_100M_MATRIX: + case CLK_PPLL_125M_MATRIX: + case CLK_GMAC1_VPU_25M: + case CLK_GMAC1_RMII_VPU: + case CLK_GMAC1_SRC_VPU: + rate = rk3528_ppll_matrix_get_rate(priv, clk->id); + break; + default: + return -ENOENT; + } + + return rate; +}; + +static ulong rk3528_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3528_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; + } + + switch (clk->id) { + case PLL_APLL: + case ARMCLK: + if (priv->armclk_hz) + rk3528_armclk_set_clk(priv, rate); + priv->armclk_hz = rate; + break; + case PLL_CPLL: + ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru, + CPLL, rate); + priv->cpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL], + priv->cru, CPLL); + break; + case PLL_GPLL: + ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru, + GPLL, rate); + priv->gpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL], + priv->cru, GPLL); + break; + case PLL_PPLL: + ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru, + PPLL, rate); + priv->ppll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], + priv->cru, PPLL); + break; + case TCLK_EMMC: + case TCLK_WDT_NS: + return (rate == OSC_HZ) ? 0 : -EINVAL; + case CLK_I2C0: + case CLK_I2C1: + case CLK_I2C2: + case CLK_I2C3: + case CLK_I2C4: + case CLK_I2C5: + case CLK_I2C6: + case CLK_I2C7: + ret = rk3528_i2c_set_clk(priv, clk->id, rate); + break; + case CLK_SPI0: + case CLK_SPI1: + ret = rk3528_spi_set_clk(priv, clk->id, rate); + break; + case CLK_PWM0: + case CLK_PWM1: + ret = rk3528_pwm_set_clk(priv, clk->id, rate); + break; + case CLK_SARADC: + case CLK_TSADC: + case CLK_TSADC_TSEN: + ret = rk3528_adc_set_clk(priv, clk->id, rate); + break; + case HCLK_SDMMC0: + case CCLK_SRC_SDMMC0: + ret = rk3528_sdmmc_set_clk(priv, clk->id, rate); + break; + case SCLK_SFC: + ret = rk3528_sfc_set_clk(priv, rate); + break; + case CCLK_SRC_EMMC: + ret = rk3528_emmc_set_clk(priv, rate); + break; + case DCLK_VOP0: + case DCLK_VOP1: + ret = rk3528_dclk_vop_set_clk(priv, clk->id, rate); + break; + case SCLK_UART0: + case SCLK_UART1: + case SCLK_UART2: + case SCLK_UART3: + case SCLK_UART4: + case SCLK_UART5: + case SCLK_UART6: + case SCLK_UART7: + ret = rk3528_uart_set_rate(priv, clk->id, rate); + break; + case CLK_MATRIX_50M_SRC: + case CLK_MATRIX_100M_SRC: + case CLK_MATRIX_150M_SRC: + case CLK_MATRIX_200M_SRC: + case CLK_MATRIX_250M_SRC: + case CLK_MATRIX_300M_SRC: + case CLK_MATRIX_339M_SRC: + case CLK_MATRIX_400M_SRC: + case CLK_MATRIX_500M_SRC: + case CLK_MATRIX_600M_SRC: + case ACLK_BUS_VOPGL_BIU: + ret = rk3528_cgpll_matrix_set_rate(priv, clk->id, rate); + break; + case CLK_PPLL_50M_MATRIX: + case CLK_PPLL_100M_MATRIX: + case CLK_PPLL_125M_MATRIX: + case CLK_GMAC1_VPU_25M: + ret = rk3528_ppll_matrix_set_rate(priv, clk->id, rate); + break; + case CLK_GMAC1_RMII_VPU: + case CLK_GMAC1_SRC_VPU: + /* dummy set */ + ret = rk3528_ppll_matrix_get_rate(priv, clk->id); + break; + + /* Might occur in cru assigned-clocks, can be ignored here */ + case ACLK_BUS_VOPGL_ROOT: + case BCLK_EMMC: + case XIN_OSC0_DIV: + ret = 0; + break; + default: + return -ENOENT; + } + + return ret; +}; + +static struct clk_ops rk3528_clk_ops = { + .get_rate = rk3528_clk_get_rate, + .set_rate = rk3528_clk_set_rate, +}; + +#ifdef CONFIG_XPL_BUILD + +#define COREGRF_BASE 0xff300000 +#define PVTPLL_CON0_L 0x0 +#define PVTPLL_CON0_H 0x4 + +static int rk3528_cpu_pvtpll_set_rate(struct rk3528_clk_priv *priv, ulong rate) +{ + struct rk3528_cru *cru = priv->cru; + u32 length; + + if (rate >= 1200000000) + length = 8; + else if (rate >= 1008000000) + length = 11; + else + length = 17; + + /* set pclk dbg div to 9 */ + rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, + 9 << RK3528_DIV_PCLK_DBG_SHIFT); + /* set aclk_m_core div to 1 */ + rk_clrsetreg(&cru->clksel_con[39], RK3528_DIV_ACLK_M_CORE_MASK, + 1 << RK3528_DIV_ACLK_M_CORE_SHIFT); + + /* set ring sel = 1 */ + writel(0x07000000 | (1 << 8), COREGRF_BASE + PVTPLL_CON0_L); + /* set length */ + writel(0x007f0000 | length, COREGRF_BASE + PVTPLL_CON0_H); + /* enable pvtpll */ + writel(0x00020002, COREGRF_BASE + PVTPLL_CON0_L); + /* start monitor */ + writel(0x00010001, COREGRF_BASE + PVTPLL_CON0_L); + + /* set core mux pvtpll */ + writel(0x00010001, &cru->clksel_con[40]); + writel(0x00100010, &cru->clksel_con[39]); + + /* set pclk dbg div to 8 */ + rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK, + 8 << RK3528_DIV_PCLK_DBG_SHIFT); + + return 0; +} +#endif + +static int rk3528_clk_init(struct rk3528_clk_priv *priv) +{ + int ret; + + priv->sync_kernel = false; + +#ifdef CONFIG_XPL_BUILD + /* + * BOOTROM: + * CPU 1902/2(postdiv1)=546M + * CPLL 996/2(postdiv1)=498M + * GPLL 1188/2(postdiv1)=594M + * |-- clk_matrix_200m_src_div=1 => rate: 300M + * |-- clk_matrix_300m_src_div=2 => rate: 200M + * + * Avoid overclocking when change GPLL rate: + * Change clk_matrix_200m_src_div to 5. + * Change clk_matrix_300m_src_div to 3. + */ + writel(0x01200120, &priv->cru->clksel_con[1]); + writel(0x00030003, &priv->cru->clksel_con[2]); + + if (!priv->armclk_enter_hz) { + priv->armclk_enter_hz = + rockchip_pll_get_rate(&rk3528_pll_clks[APLL], + priv->cru, APLL); + priv->armclk_init_hz = priv->armclk_enter_hz; + } + + if (priv->armclk_init_hz != APLL_HZ) { + ret = rk3528_armclk_set_clk(priv, APLL_HZ); + if (!ret) + priv->armclk_init_hz = APLL_HZ; + } + + if (!rk3528_cpu_pvtpll_set_rate(priv, CPU_PVTPLL_HZ)) { + debug("cpu pvtpll %d KHz\n", CPU_PVTPLL_HZ / 1000); + priv->armclk_init_hz = CPU_PVTPLL_HZ; + } +#endif + + if (priv->cpll_hz != CPLL_HZ) { + ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru, + CPLL, CPLL_HZ); + if (!ret) + priv->cpll_hz = CPLL_HZ; + } + + if (priv->gpll_hz != GPLL_HZ) { + ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru, + GPLL, GPLL_HZ); + if (!ret) + priv->gpll_hz = GPLL_HZ; + } + + if (priv->ppll_hz != PPLL_HZ) { + ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru, + PPLL, PPLL_HZ); + if (!ret) + priv->ppll_hz = PPLL_HZ; + } + +#ifdef CONFIG_XPL_BUILD + /* Init to override bootrom config */ + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_50M_SRC, 50000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_100M_SRC, 100000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_150M_SRC, 150000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_200M_SRC, 200000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_250M_SRC, 250000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_300M_SRC, 300000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_339M_SRC, 340000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_400M_SRC, 400000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_500M_SRC, 500000000); + rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_600M_SRC, 600000000); + rk3528_cgpll_matrix_set_rate(priv, ACLK_BUS_VOPGL_BIU, 500000000); + + /* The default rate is 100Mhz, it's not friendly for remote IR module */ + rk3528_pwm_set_clk(priv, CLK_PWM0, 24000000); + rk3528_pwm_set_clk(priv, CLK_PWM1, 24000000); +#endif + return 0; +} + +static int rk3528_clk_probe(struct udevice *dev) +{ + struct rk3528_clk_priv *priv = dev_get_priv(dev); + int ret; + + ret = rk3528_clk_init(priv); + if (ret) + return ret; + + /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ + ret = clk_set_defaults(dev, 1); + if (ret) + debug("%s clk_set_defaults failed %d\n", __func__, ret); + else + priv->sync_kernel = true; + + return 0; +} + +static int rk3528_clk_ofdata_to_platdata(struct udevice *dev) +{ + struct rk3528_clk_priv *priv = dev_get_priv(dev); + + priv->cru = dev_read_addr_ptr(dev); + + return 0; +} + +static int rk3528_clk_bind(struct udevice *dev) +{ + struct udevice *sys_child; + struct sysreset_reg *priv; + int ret; + + /* The reset driver does not have a device node, so bind it here */ + ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", + &sys_child); + if (ret) { + debug("Warning: No sysreset driver: ret=%d\n", ret); + } else { + priv = malloc(sizeof(struct sysreset_reg)); + priv->glb_srst_fst_value = offsetof(struct rk3528_cru, + glb_srst_fst); + priv->glb_srst_snd_value = offsetof(struct rk3528_cru, + glb_srst_snd); + dev_set_priv(sys_child, priv); + } + +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP) + ret = offsetof(struct rk3528_cru, softrst_con[0]); + ret = rk3528_reset_bind_lut(dev, ret, 47); + if (ret) + debug("Warning: software reset driver bind failed\n"); +#endif + + return 0; +} + +static const struct udevice_id rk3528_clk_ids[] = { + { .compatible = "rockchip,rk3528-cru" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3528_cru) = { + .name = "rockchip_rk3528_cru", + .id = UCLASS_CLK, + .of_match = rk3528_clk_ids, + .priv_auto = sizeof(struct rk3528_clk_priv), + .of_to_plat = rk3528_clk_ofdata_to_platdata, + .ops = &rk3528_clk_ops, + .bind = rk3528_clk_bind, + .probe = rk3528_clk_probe, +}; diff --git a/drivers/clk/rockchip/clk_rk3576.c b/drivers/clk/rockchip/clk_rk3576.c new file mode 100644 index 00000000000..e84a0943a94 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3576.c @@ -0,0 +1,2513 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Fuzhou Rockchip Electronics Co., Ltd + * Author: Elaine Zhang <[email protected]> + */ + +#include <bitfield.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <syscon.h> +#include <asm/arch-rockchip/cru_rk3576.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/hardware.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dt-bindings/clock/rockchip,rk3576-cru.h> +#include <linux/delay.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) + +static struct rockchip_pll_rate_table rk3576_24m_pll_rates[] = { + /* _mhz, _p, _m, _s, _k */ + RK3588_PLL_RATE(1500000000, 2, 250, 1, 0), + RK3588_PLL_RATE(1200000000, 1, 100, 1, 0), + RK3588_PLL_RATE(1188000000, 2, 198, 1, 0), + RK3588_PLL_RATE(1150000000, 3, 575, 2, 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(742500000, 4, 495, 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 rk3576_pll_clks[] = { + [BPLL] = PLL(pll_rk3588, PLL_BPLL, RK3576_PLL_CON(0), + RK3576_BPLL_MODE_CON0, 0, 15, 0, + rk3576_24m_pll_rates), + [LPLL] = PLL(pll_rk3588, PLL_LPLL, RK3576_LPLL_CON(16), + RK3576_LPLL_MODE_CON0, 0, 15, 0, rk3576_24m_pll_rates), + [VPLL] = PLL(pll_rk3588, PLL_VPLL, RK3576_PLL_CON(88), + RK3576_LPLL_MODE_CON0, 4, 15, 0, rk3576_24m_pll_rates), + [AUPLL] = PLL(pll_rk3588, PLL_AUPLL, RK3576_PLL_CON(96), + RK3576_MODE_CON0, 6, 15, 0, rk3576_24m_pll_rates), + [CPLL] = PLL(pll_rk3588, PLL_CPLL, RK3576_PLL_CON(104), + RK3576_MODE_CON0, 8, 15, 0, rk3576_24m_pll_rates), + [GPLL] = PLL(pll_rk3588, PLL_GPLL, RK3576_PLL_CON(112), + RK3576_MODE_CON0, 2, 15, 0, rk3576_24m_pll_rates), + [PPLL] = PLL(pll_rk3588, PLL_PPLL, RK3576_PMU_PLL_CON(128), + RK3576_MODE_CON0, 10, 15, 0, rk3576_24m_pll_rates), +}; + +#ifdef CONFIG_SPL_BUILD +#ifndef BITS_WITH_WMASK +#define BITS_WITH_WMASK(bits, msk, shift) \ + ((bits) << (shift)) | ((msk) << ((shift) + 16)) +#endif +#endif + +#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 rk3576_bus_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 con, sel, div, rate; + + switch (clk_id) { + case ACLK_BUS_ROOT: + con = readl(&cru->clksel_con[55]); + sel = (con & ACLK_BUS_ROOT_SEL_MASK) >> + ACLK_BUS_ROOT_SEL_SHIFT; + div = (con & ACLK_BUS_ROOT_DIV_MASK) >> + ACLK_BUS_ROOT_DIV_SHIFT; + if (sel == ACLK_BUS_ROOT_SEL_CPLL) + rate = DIV_TO_RATE(priv->cpll_hz, div); + else + rate = DIV_TO_RATE(priv->gpll_hz, div); + break; + case HCLK_BUS_ROOT: + con = readl(&cru->clksel_con[55]); + sel = (con & HCLK_BUS_ROOT_SEL_MASK) >> + HCLK_BUS_ROOT_SEL_SHIFT; + if (sel == HCLK_BUS_ROOT_SEL_200M) + rate = 198 * MHz; + else if (sel == HCLK_BUS_ROOT_SEL_100M) + rate = 100 * MHz; + else if (sel == HCLK_BUS_ROOT_SEL_50M) + rate = 50 * MHz; + else + rate = OSC_HZ; + break; + case PCLK_BUS_ROOT: + con = readl(&cru->clksel_con[55]); + sel = (con & PCLK_BUS_ROOT_SEL_MASK) >> + PCLK_BUS_ROOT_SEL_SHIFT; + if (sel == PCLK_BUS_ROOT_SEL_100M) + rate = 100 * MHz; + else if (sel == PCLK_BUS_ROOT_SEL_50M) + rate = 50 * MHz; + else + rate = OSC_HZ; + break; + default: + return -ENOENT; + } + + return rate; +} + +static ulong rk3576_bus_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int src_clk, src_clk_div; + + switch (clk_id) { + case ACLK_BUS_ROOT: + if (!(priv->cpll_hz % rate)) { + src_clk = ACLK_BUS_ROOT_SEL_CPLL; + src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate); + } else { + src_clk = ACLK_BUS_ROOT_SEL_GPLL; + src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate); + } + rk_clrsetreg(&cru->clksel_con[55], + ACLK_BUS_ROOT_SEL_MASK, + src_clk << ACLK_BUS_ROOT_SEL_SHIFT); + assert(src_clk_div - 1 <= 31); + rk_clrsetreg(&cru->clksel_con[55], + ACLK_BUS_ROOT_DIV_MASK | + ACLK_BUS_ROOT_SEL_MASK, + (src_clk << + ACLK_BUS_ROOT_SEL_SHIFT) | + (src_clk_div - 1) << ACLK_BUS_ROOT_DIV_SHIFT); + break; + case HCLK_BUS_ROOT: + if (rate >= 198 * MHz) + src_clk = HCLK_BUS_ROOT_SEL_200M; + else if (rate >= 99 * MHz) + src_clk = HCLK_BUS_ROOT_SEL_100M; + else if (rate >= 50 * MHz) + src_clk = HCLK_BUS_ROOT_SEL_50M; + else + src_clk = HCLK_BUS_ROOT_SEL_OSC; + rk_clrsetreg(&cru->clksel_con[55], + HCLK_BUS_ROOT_SEL_MASK, + src_clk << HCLK_BUS_ROOT_SEL_SHIFT); + break; + case PCLK_BUS_ROOT: + if (rate >= 99 * MHz) + src_clk = PCLK_BUS_ROOT_SEL_100M; + else if (rate >= 50 * MHz) + src_clk = PCLK_BUS_ROOT_SEL_50M; + else + src_clk = PCLK_BUS_ROOT_SEL_OSC; + rk_clrsetreg(&cru->clksel_con[55], + PCLK_BUS_ROOT_SEL_MASK, + src_clk << PCLK_BUS_ROOT_SEL_SHIFT); + break; + default: + printf("do not support this center freq\n"); + return -EINVAL; + } + + return rk3576_bus_get_clk(priv, clk_id); +} + +static ulong rk3576_top_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 con, sel, div, rate, prate; + + switch (clk_id) { + case ACLK_TOP: + con = readl(&cru->clksel_con[9]); + div = (con & ACLK_TOP_DIV_MASK) >> + ACLK_TOP_DIV_SHIFT; + sel = (con & ACLK_TOP_SEL_MASK) >> + ACLK_TOP_SEL_SHIFT; + if (sel == ACLK_TOP_SEL_CPLL) + prate = priv->cpll_hz; + else if (sel == ACLK_TOP_SEL_AUPLL) + prate = priv->aupll_hz; + else + prate = priv->gpll_hz; + return DIV_TO_RATE(prate, div); + case ACLK_TOP_MID: + con = readl(&cru->clksel_con[10]); + div = (con & ACLK_TOP_MID_DIV_MASK) >> + ACLK_TOP_MID_DIV_SHIFT; + sel = (con & ACLK_TOP_MID_SEL_MASK) >> + ACLK_TOP_MID_SEL_SHIFT; + if (sel == ACLK_TOP_MID_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_SEL_MASK) >> PCLK_TOP_SEL_SHIFT; + if (sel == PCLK_TOP_SEL_100M) + rate = 100 * MHz; + else if (sel == PCLK_TOP_SEL_50M) + rate = 50 * MHz; + else + rate = OSC_HZ; + break; + case HCLK_TOP: + con = readl(&cru->clksel_con[19]); + sel = (con & HCLK_TOP_SEL_MASK) >> HCLK_TOP_SEL_SHIFT; + if (sel == HCLK_TOP_SEL_200M) + rate = 200 * MHz; + else if (sel == HCLK_TOP_SEL_100M) + rate = 100 * MHz; + else if (sel == HCLK_TOP_SEL_50M) + rate = 50 * MHz; + else + rate = OSC_HZ; + break; + default: + return -ENOENT; + } + + return rate; +} + +static ulong rk3576_top_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int src_clk, src_clk_div; + + switch (clk_id) { + case ACLK_TOP: + if (!(priv->cpll_hz % rate)) { + src_clk = ACLK_TOP_SEL_CPLL; + src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate); + } else { + src_clk = ACLK_TOP_SEL_GPLL; + src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate); + } + assert(src_clk_div - 1 <= 31); + rk_clrsetreg(&cru->clksel_con[9], + ACLK_TOP_DIV_MASK | + ACLK_TOP_SEL_MASK, + (src_clk << + ACLK_TOP_SEL_SHIFT) | + (src_clk_div - 1) << ACLK_TOP_SEL_SHIFT); + break; + case ACLK_TOP_MID: + if (!(priv->cpll_hz % rate)) { + src_clk = ACLK_TOP_MID_SEL_CPLL; + src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate); + } else { + src_clk = ACLK_TOP_MID_SEL_GPLL; + src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate); + } + rk_clrsetreg(&cru->clksel_con[10], + ACLK_TOP_MID_DIV_MASK | + ACLK_TOP_MID_SEL_MASK, + (ACLK_TOP_MID_SEL_GPLL << + ACLK_TOP_MID_SEL_SHIFT) | + (src_clk_div - 1) << ACLK_TOP_MID_DIV_SHIFT); + break; + case PCLK_TOP_ROOT: + if (rate >= 99 * MHz) + src_clk = PCLK_TOP_SEL_100M; + else if (rate >= 50 * MHz) + src_clk = PCLK_TOP_SEL_50M; + else + src_clk = PCLK_TOP_SEL_OSC; + rk_clrsetreg(&cru->clksel_con[8], + PCLK_TOP_SEL_MASK, + src_clk << PCLK_TOP_SEL_SHIFT); + break; + case HCLK_TOP: + if (rate >= 198 * MHz) + src_clk = HCLK_TOP_SEL_200M; + else if (rate >= 99 * MHz) + src_clk = HCLK_TOP_SEL_100M; + else if (rate >= 50 * MHz) + src_clk = HCLK_TOP_SEL_50M; + else + src_clk = HCLK_TOP_SEL_OSC; + rk_clrsetreg(&cru->clksel_con[19], + HCLK_TOP_SEL_MASK, + src_clk << HCLK_TOP_SEL_SHIFT); + break; + default: + printf("do not support this top freq\n"); + return -EINVAL; + } + + return rk3576_top_get_clk(priv, clk_id); +} + +static ulong rk3576_i2c_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 sel, con; + ulong rate; + + switch (clk_id) { + case CLK_I2C0: + con = readl(&cru->pmuclksel_con[6]); + sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT; + break; + case CLK_I2C1: + con = readl(&cru->clksel_con[57]); + sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT; + break; + case CLK_I2C2: + con = readl(&cru->clksel_con[57]); + sel = (con & CLK_I2C2_SEL_MASK) >> CLK_I2C2_SEL_SHIFT; + break; + case CLK_I2C3: + con = readl(&cru->clksel_con[57]); + sel = (con & CLK_I2C3_SEL_MASK) >> CLK_I2C3_SEL_SHIFT; + break; + case CLK_I2C4: + con = readl(&cru->clksel_con[57]); + sel = (con & CLK_I2C4_SEL_MASK) >> CLK_I2C4_SEL_SHIFT; + break; + case CLK_I2C5: + con = readl(&cru->clksel_con[57]); + sel = (con & CLK_I2C5_SEL_MASK) >> CLK_I2C5_SEL_SHIFT; + break; + case CLK_I2C6: + con = readl(&cru->clksel_con[57]); + sel = (con & CLK_I2C6_SEL_MASK) >> CLK_I2C6_SEL_SHIFT; + break; + case CLK_I2C7: + con = readl(&cru->clksel_con[57]); + sel = (con & CLK_I2C7_SEL_MASK) >> CLK_I2C7_SEL_SHIFT; + break; + case CLK_I2C8: + con = readl(&cru->clksel_con[57]); + sel = (con & CLK_I2C8_SEL_MASK) >> CLK_I2C8_SEL_SHIFT; + break; + case CLK_I2C9: + con = readl(&cru->clksel_con[58]); + sel = (con & CLK_I2C9_SEL_MASK) >> CLK_I2C9_SEL_SHIFT; + break; + + default: + return -ENOENT; + } + if (sel == CLK_I2C_SEL_200M) + rate = 200 * MHz; + else if (sel == CLK_I2C_SEL_100M) + rate = 100 * MHz; + else if (sel == CLK_I2C_SEL_50M) + rate = 50 * MHz; + else + rate = OSC_HZ; + + return rate; +} + +static ulong rk3576_i2c_set_clk(struct rk3576_clk_priv *priv, ulong clk_id, + ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int src_clk; + + if (rate >= 198 * MHz) + src_clk = CLK_I2C_SEL_200M; + else if (rate >= 99 * MHz) + src_clk = CLK_I2C_SEL_100M; + if (rate >= 50 * MHz) + src_clk = CLK_I2C_SEL_50M; + else + src_clk = CLK_I2C_SEL_OSC; + + switch (clk_id) { + case CLK_I2C0: + rk_clrsetreg(&cru->pmuclksel_con[6], CLK_I2C0_SEL_MASK, + src_clk << CLK_I2C0_SEL_SHIFT); + break; + case CLK_I2C1: + rk_clrsetreg(&cru->clksel_con[57], CLK_I2C1_SEL_MASK, + src_clk << CLK_I2C1_SEL_SHIFT); + break; + case CLK_I2C2: + rk_clrsetreg(&cru->clksel_con[57], CLK_I2C2_SEL_MASK, + src_clk << CLK_I2C2_SEL_SHIFT); + break; + case CLK_I2C3: + rk_clrsetreg(&cru->clksel_con[57], CLK_I2C3_SEL_MASK, + src_clk << CLK_I2C3_SEL_SHIFT); + break; + case CLK_I2C4: + rk_clrsetreg(&cru->clksel_con[57], CLK_I2C4_SEL_MASK, + src_clk << CLK_I2C4_SEL_SHIFT); + break; + case CLK_I2C5: + rk_clrsetreg(&cru->clksel_con[57], CLK_I2C5_SEL_MASK, + src_clk << CLK_I2C5_SEL_SHIFT); + break; + case CLK_I2C6: + rk_clrsetreg(&cru->clksel_con[57], CLK_I2C6_SEL_MASK, + src_clk << CLK_I2C6_SEL_SHIFT); + break; + case CLK_I2C7: + rk_clrsetreg(&cru->clksel_con[57], CLK_I2C7_SEL_MASK, + src_clk << CLK_I2C7_SEL_SHIFT); + break; + case CLK_I2C8: + rk_clrsetreg(&cru->clksel_con[57], CLK_I2C8_SEL_MASK, + src_clk << CLK_I2C8_SEL_SHIFT); + case CLK_I2C9: + rk_clrsetreg(&cru->clksel_con[58], CLK_I2C9_SEL_MASK, + src_clk << CLK_I2C9_SEL_SHIFT); + break; + default: + return -ENOENT; + } + + return rk3576_i2c_get_clk(priv, clk_id); +} + +static ulong rk3576_spi_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 sel, con; + + switch (clk_id) { + case CLK_SPI0: + con = readl(&cru->clksel_con[70]); + sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT; + break; + case CLK_SPI1: + con = readl(&cru->clksel_con[71]); + sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT; + break; + case CLK_SPI2: + con = readl(&cru->clksel_con[71]); + sel = (con & CLK_SPI2_SEL_MASK) >> CLK_SPI2_SEL_SHIFT; + break; + case CLK_SPI3: + con = readl(&cru->clksel_con[71]); + sel = (con & CLK_SPI3_SEL_MASK) >> CLK_SPI3_SEL_SHIFT; + break; + case CLK_SPI4: + con = readl(&cru->clksel_con[71]); + sel = (con & CLK_SPI4_SEL_MASK) >> CLK_SPI4_SEL_SHIFT; + break; + default: + return -ENOENT; + } + + switch (sel) { + case CLK_SPI_SEL_200M: + return 200 * MHz; + case CLK_SPI_SEL_100M: + return 100 * MHz; + case CLK_SPI_SEL_50M: + return 50 * MHz; + case CLK_SPI_SEL_OSC: + return OSC_HZ; + default: + return -ENOENT; + } +} + +static ulong rk3576_spi_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int src_clk; + + if (rate >= 198 * MHz) + src_clk = CLK_SPI_SEL_200M; + else if (rate >= 99 * MHz) + src_clk = CLK_SPI_SEL_100M; + else if (rate >= 50 * MHz) + src_clk = CLK_SPI_SEL_50M; + else + src_clk = CLK_SPI_SEL_OSC; + + switch (clk_id) { + case CLK_SPI0: + rk_clrsetreg(&cru->clksel_con[70], + CLK_SPI0_SEL_MASK, + src_clk << CLK_SPI0_SEL_SHIFT); + break; + case CLK_SPI1: + rk_clrsetreg(&cru->clksel_con[71], + CLK_SPI1_SEL_MASK, + src_clk << CLK_SPI1_SEL_SHIFT); + break; + case CLK_SPI2: + rk_clrsetreg(&cru->clksel_con[71], + CLK_SPI2_SEL_MASK, + src_clk << CLK_SPI2_SEL_SHIFT); + break; + case CLK_SPI3: + rk_clrsetreg(&cru->clksel_con[71], + CLK_SPI3_SEL_MASK, + src_clk << CLK_SPI3_SEL_SHIFT); + break; + case CLK_SPI4: + rk_clrsetreg(&cru->clksel_con[71], + CLK_SPI4_SEL_MASK, + src_clk << CLK_SPI4_SEL_SHIFT); + break; + default: + return -ENOENT; + } + + return rk3576_spi_get_clk(priv, clk_id); +} + +static ulong rk3576_pwm_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 sel, con; + + switch (clk_id) { + case CLK_PWM1: + con = readl(&cru->clksel_con[71]); + sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT; + break; + case CLK_PWM2: + con = readl(&cru->clksel_con[74]); + sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT; + break; + case CLK_PMU1PWM: + con = readl(&cru->pmuclksel_con[5]); + sel = (con & CLK_PMU1PWM_SEL_MASK) >> CLK_PMU1PWM_SEL_SHIFT; + break; + default: + return -ENOENT; + } + + switch (sel) { + case CLK_PWM_SEL_100M: + return 100 * MHz; + case CLK_PWM_SEL_50M: + return 50 * MHz; + case CLK_PWM_SEL_OSC: + return OSC_HZ; + default: + return -ENOENT; + } +} + +static ulong rk3576_pwm_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int src_clk; + + if (rate >= 99 * MHz) + src_clk = CLK_PWM_SEL_100M; + else if (rate >= 50 * MHz) + src_clk = CLK_PWM_SEL_50M; + else + src_clk = CLK_PWM_SEL_OSC; + + switch (clk_id) { + case CLK_PWM1: + rk_clrsetreg(&cru->clksel_con[71], + CLK_PWM1_SEL_MASK, + src_clk << CLK_PWM1_SEL_SHIFT); + break; + case CLK_PWM2: + rk_clrsetreg(&cru->clksel_con[74], + CLK_PWM2_SEL_MASK, + src_clk << CLK_PWM2_SEL_SHIFT); + break; + case CLK_PMU1PWM: + rk_clrsetreg(&cru->pmuclksel_con[5], + CLK_PMU1PWM_SEL_MASK, + src_clk << CLK_PMU1PWM_SEL_SHIFT); + break; + default: + return -ENOENT; + } + + return rk3576_pwm_get_clk(priv, clk_id); +} + +static ulong rk3576_adc_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 div, sel, con, prate; + + switch (clk_id) { + case CLK_SARADC: + con = readl(&cru->clksel_con[58]); + div = (con & CLK_SARADC_DIV_MASK) >> CLK_SARADC_DIV_SHIFT; + sel = (con & CLK_SARADC_SEL_MASK) >> + CLK_SARADC_SEL_SHIFT; + if (sel == CLK_SARADC_SEL_OSC) + prate = OSC_HZ; + else + prate = priv->gpll_hz; + return DIV_TO_RATE(prate, div); + case CLK_TSADC: + con = readl(&cru->clksel_con[59]); + div = (con & CLK_TSADC_DIV_MASK) >> + CLK_TSADC_DIV_SHIFT; + prate = OSC_HZ; + return DIV_TO_RATE(prate, div); + default: + return -ENOENT; + } +} + +static ulong rk3576_adc_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int src_clk_div; + + switch (clk_id) { + case CLK_SARADC: + if (!(OSC_HZ % rate)) { + src_clk_div = DIV_ROUND_UP(OSC_HZ, rate); + assert(src_clk_div - 1 <= 255); + rk_clrsetreg(&cru->clksel_con[58], + CLK_SARADC_SEL_MASK | + CLK_SARADC_DIV_MASK, + (CLK_SARADC_SEL_OSC << + CLK_SARADC_SEL_SHIFT) | + (src_clk_div - 1) << + CLK_SARADC_DIV_SHIFT); + } else { + src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate); + assert(src_clk_div - 1 <= 255); + rk_clrsetreg(&cru->clksel_con[59], + CLK_SARADC_SEL_MASK | + CLK_SARADC_DIV_MASK, + (CLK_SARADC_SEL_GPLL << + CLK_SARADC_SEL_SHIFT) | + (src_clk_div - 1) << + CLK_SARADC_DIV_SHIFT); + } + break; + case CLK_TSADC: + src_clk_div = DIV_ROUND_UP(OSC_HZ, rate); + assert(src_clk_div - 1 <= 255); + rk_clrsetreg(&cru->clksel_con[58], + CLK_TSADC_DIV_MASK, + (src_clk_div - 1) << + CLK_TSADC_DIV_SHIFT); + break; + default: + return -ENOENT; + } + return rk3576_adc_get_clk(priv, clk_id); +} + +static ulong rk3576_mmc_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 sel, con, prate, div = 0; + + switch (clk_id) { + case CCLK_SRC_SDIO: + case HCLK_SDIO: + con = readl(&cru->clksel_con[104]); + div = (con & CCLK_SDIO_SRC_DIV_MASK) >> CCLK_SDIO_SRC_DIV_SHIFT; + sel = (con & CCLK_SDIO_SRC_SEL_MASK) >> + CCLK_SDIO_SRC_SEL_SHIFT; + if (sel == CCLK_SDIO_SRC_SEL_GPLL) + prate = priv->gpll_hz; + else if (sel == CCLK_SDIO_SRC_SEL_CPLL) + prate = priv->cpll_hz; + else + prate = OSC_HZ; + return DIV_TO_RATE(prate, div); + case CCLK_SRC_SDMMC0: + case HCLK_SDMMC0: + con = readl(&cru->clksel_con[105]); + div = (con & CCLK_SDMMC0_SRC_DIV_MASK) >> CCLK_SDMMC0_SRC_DIV_SHIFT; + sel = (con & CCLK_SDMMC0_SRC_SEL_MASK) >> + CCLK_SDMMC0_SRC_SEL_SHIFT; + if (sel == CCLK_SDMMC0_SRC_SEL_GPLL) + prate = priv->gpll_hz; + else if (sel == CCLK_SDMMC0_SRC_SEL_CPLL) + prate = priv->cpll_hz; + else + prate = OSC_HZ; + return DIV_TO_RATE(prate, div); + case CCLK_SRC_EMMC: + case HCLK_EMMC: + con = readl(&cru->clksel_con[89]); + div = (con & CCLK_EMMC_DIV_MASK) >> CCLK_EMMC_DIV_SHIFT; + sel = (con & CCLK_EMMC_SEL_MASK) >> + CCLK_EMMC_SEL_SHIFT; + if (sel == CCLK_EMMC_SEL_GPLL) + prate = priv->gpll_hz; + else if (sel == CCLK_EMMC_SEL_CPLL) + prate = priv->cpll_hz; + else + prate = OSC_HZ; + return DIV_TO_RATE(prate, div); + case BCLK_EMMC: + con = readl(&cru->clksel_con[90]); + sel = (con & BCLK_EMMC_SEL_MASK) >> + BCLK_EMMC_SEL_SHIFT; + if (sel == BCLK_EMMC_SEL_200M) + prate = 200 * MHz; + else if (sel == BCLK_EMMC_SEL_100M) + prate = 100 * MHz; + else if (sel == BCLK_EMMC_SEL_50M) + prate = 50 * MHz; + else + prate = OSC_HZ; + return DIV_TO_RATE(prate, div); + case SCLK_FSPI_X2: + con = readl(&cru->clksel_con[89]); + div = (con & SCLK_FSPI_DIV_MASK) >> SCLK_FSPI_DIV_SHIFT; + sel = (con & SCLK_FSPI_SEL_MASK) >> + SCLK_FSPI_SEL_SHIFT; + if (sel == SCLK_FSPI_SEL_GPLL) + prate = priv->gpll_hz; + else if (sel == SCLK_FSPI_SEL_CPLL) + prate = priv->cpll_hz; + else + prate = OSC_HZ; + return DIV_TO_RATE(prate, div); + case SCLK_FSPI1_X2: + con = readl(&cru->clksel_con[106]); + div = (con & SCLK_FSPI_DIV_MASK) >> SCLK_FSPI_DIV_SHIFT; + sel = (con & SCLK_FSPI_SEL_MASK) >> + SCLK_FSPI_SEL_SHIFT; + if (sel == SCLK_FSPI_SEL_GPLL) + prate = priv->gpll_hz; + else if (sel == SCLK_FSPI_SEL_CPLL) + prate = priv->cpll_hz; + else + prate = OSC_HZ; + return DIV_TO_RATE(prate, div); + case DCLK_DECOM: + con = readl(&cru->clksel_con[72]); + div = (con & DCLK_DECOM_DIV_MASK) >> DCLK_DECOM_DIV_SHIFT; + sel = (con & DCLK_DECOM_SEL_MASK) >> DCLK_DECOM_SEL_SHIFT; + if (sel == DCLK_DECOM_SEL_SPLL) + prate = priv->spll_hz; + else + prate = priv->gpll_hz; + return DIV_TO_RATE(prate, div); + + default: + return -ENOENT; + } +} + +static ulong rk3576_mmc_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int src_clk, div = 0; + + switch (clk_id) { + case CCLK_SRC_SDIO: + case CCLK_SRC_SDMMC0: + case CCLK_SRC_EMMC: + case SCLK_FSPI_X2: + case SCLK_FSPI1_X2: + case HCLK_SDMMC0: + case HCLK_EMMC: + case HCLK_SDIO: + if (!(OSC_HZ % rate)) { + src_clk = SCLK_FSPI_SEL_OSC; + div = DIV_ROUND_UP(OSC_HZ, rate); + } else if (!(priv->cpll_hz % rate)) { + src_clk = SCLK_FSPI_SEL_CPLL; + div = DIV_ROUND_UP(priv->cpll_hz, rate); + } else { + src_clk = SCLK_FSPI_SEL_GPLL; + div = DIV_ROUND_UP(priv->gpll_hz, rate); + } + break; + case BCLK_EMMC: + if (rate >= 198 * MHz) + src_clk = BCLK_EMMC_SEL_200M; + else if (rate >= 99 * MHz) + src_clk = BCLK_EMMC_SEL_100M; + else if (rate >= 50 * MHz) + src_clk = BCLK_EMMC_SEL_50M; + else + src_clk = BCLK_EMMC_SEL_OSC; + break; + case DCLK_DECOM: + if (!(priv->spll_hz % rate)) { + src_clk = DCLK_DECOM_SEL_SPLL; + div = DIV_ROUND_UP(priv->spll_hz, rate); + } else { + src_clk = DCLK_DECOM_SEL_GPLL; + div = DIV_ROUND_UP(priv->gpll_hz, rate); + } + break; + default: + return -ENOENT; + } + + switch (clk_id) { + case CCLK_SRC_SDIO: + case HCLK_SDIO: + rk_clrsetreg(&cru->clksel_con[104], + CCLK_SDIO_SRC_SEL_MASK | + CCLK_SDIO_SRC_DIV_MASK, + (src_clk << CCLK_SDIO_SRC_SEL_SHIFT) | + (div - 1) << CCLK_SDIO_SRC_DIV_SHIFT); + break; + case CCLK_SRC_SDMMC0: + case HCLK_SDMMC0: + rk_clrsetreg(&cru->clksel_con[105], + CCLK_SDMMC0_SRC_SEL_MASK | + CCLK_SDMMC0_SRC_DIV_MASK, + (src_clk << CCLK_SDMMC0_SRC_SEL_SHIFT) | + (div - 1) << CCLK_SDMMC0_SRC_DIV_SHIFT); + break; + case CCLK_SRC_EMMC: + case HCLK_EMMC: + rk_clrsetreg(&cru->clksel_con[89], + CCLK_EMMC_DIV_MASK | + CCLK_EMMC_SEL_MASK, + (src_clk << CCLK_EMMC_SEL_SHIFT) | + (div - 1) << CCLK_EMMC_DIV_SHIFT); + break; + case SCLK_FSPI_X2: + rk_clrsetreg(&cru->clksel_con[89], + SCLK_FSPI_DIV_MASK | + SCLK_FSPI_SEL_MASK, + (src_clk << SCLK_FSPI_SEL_SHIFT) | + (div - 1) << SCLK_FSPI_DIV_SHIFT); + break; + case SCLK_FSPI1_X2: + rk_clrsetreg(&cru->clksel_con[106], + SCLK_FSPI_DIV_MASK | + SCLK_FSPI_SEL_MASK, + (src_clk << SCLK_FSPI_SEL_SHIFT) | + (div - 1) << SCLK_FSPI_DIV_SHIFT); + break; + case BCLK_EMMC: + rk_clrsetreg(&cru->clksel_con[90], + BCLK_EMMC_SEL_MASK, + src_clk << BCLK_EMMC_SEL_SHIFT); + break; + case DCLK_DECOM: + rk_clrsetreg(&cru->clksel_con[72], + DCLK_DECOM_DIV_MASK | + DCLK_DECOM_SEL_MASK, + (src_clk << DCLK_DECOM_SEL_SHIFT) | + (div - 1) << DCLK_DECOM_DIV_SHIFT); + break; + + default: + return -ENOENT; + } + + return rk3576_mmc_get_clk(priv, clk_id); +} + +#ifndef CONFIG_SPL_BUILD + +static ulong rk3576_aclk_vop_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 div, sel, con, parent = 0; + + switch (clk_id) { + case ACLK_VOP_ROOT: + case ACLK_VOP: + con = readl(&cru->clksel_con[144]); + div = (con & ACLK_VOP_ROOT_DIV_MASK) >> ACLK_VOP_ROOT_DIV_SHIFT; + sel = (con & ACLK_VOP_ROOT_SEL_MASK) >> ACLK_VOP_ROOT_SEL_SHIFT; + if (sel == ACLK_VOP_ROOT_SEL_GPLL) + parent = priv->gpll_hz; + else if (sel == ACLK_VOP_ROOT_SEL_CPLL) + parent = priv->cpll_hz; + else if (sel == ACLK_VOP_ROOT_SEL_AUPLL) + parent = priv->aupll_hz; + else if (sel == ACLK_VOP_ROOT_SEL_SPLL) + parent = priv->spll_hz; + else if (sel == ACLK_VOP_ROOT_SEL_LPLL) + parent = priv->lpll_hz / 2; + return DIV_TO_RATE(parent, div); + case ACLK_VO0_ROOT: + con = readl(&cru->clksel_con[149]); + div = (con & ACLK_VO0_ROOT_DIV_MASK) >> ACLK_VO0_ROOT_DIV_SHIFT; + sel = (con & ACLK_VO0_ROOT_SEL_MASK) >> ACLK_VO0_ROOT_SEL_SHIFT; + if (sel == ACLK_VO0_ROOT_SEL_GPLL) + parent = priv->gpll_hz; + else if (sel == ACLK_VO0_ROOT_SEL_CPLL) + parent = priv->cpll_hz; + else if (sel == ACLK_VO0_ROOT_SEL_LPLL) + parent = priv->lpll_hz / 2; + else if (sel == ACLK_VO0_ROOT_SEL_BPLL) + parent = priv->bpll_hz / 4; + return DIV_TO_RATE(parent, div); + case ACLK_VO1_ROOT: + con = readl(&cru->clksel_con[158]); + div = (con & ACLK_VO0_ROOT_DIV_MASK) >> ACLK_VO0_ROOT_DIV_SHIFT; + sel = (con & ACLK_VO0_ROOT_SEL_MASK) >> ACLK_VO0_ROOT_SEL_SHIFT; + if (sel == ACLK_VO0_ROOT_SEL_GPLL) + parent = priv->gpll_hz; + else if (sel == ACLK_VO0_ROOT_SEL_CPLL) + parent = priv->cpll_hz; + else if (sel == ACLK_VO0_ROOT_SEL_LPLL) + parent = priv->lpll_hz / 2; + else if (sel == ACLK_VO0_ROOT_SEL_BPLL) + parent = priv->bpll_hz / 4; + return DIV_TO_RATE(parent, div); + case HCLK_VOP_ROOT: + con = readl(&cru->clksel_con[144]); + sel = (con & HCLK_VOP_ROOT_SEL_MASK) >> HCLK_VOP_ROOT_SEL_SHIFT; + if (sel == HCLK_VOP_ROOT_SEL_200M) + return 200 * MHz; + else if (sel == HCLK_VOP_ROOT_SEL_100M) + return 100 * MHz; + else if (sel == HCLK_VOP_ROOT_SEL_50M) + return 50 * MHz; + else + return OSC_HZ; + case PCLK_VOP_ROOT: + con = readl(&cru->clksel_con[144]); + sel = (con & PCLK_VOP_ROOT_SEL_MASK) >> PCLK_VOP_ROOT_SEL_SHIFT; + if (sel == PCLK_VOP_ROOT_SEL_100M) + return 100 * MHz; + else if (sel == PCLK_VOP_ROOT_SEL_50M) + return 50 * MHz; + else + return OSC_HZ; + + default: + return -ENOENT; + } +} + +static ulong rk3576_aclk_vop_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int src_clk, div; + + switch (clk_id) { + case ACLK_VOP_ROOT: + case ACLK_VOP: + if (rate == 700 * MHz) { + src_clk = ACLK_VOP_ROOT_SEL_SPLL; + div = 1; + } else if (!(priv->cpll_hz % rate)) { + src_clk = ACLK_VOP_ROOT_SEL_CPLL; + div = DIV_ROUND_UP(priv->cpll_hz, rate); + } else { + src_clk = ACLK_VOP_ROOT_SEL_GPLL; + div = DIV_ROUND_UP(priv->gpll_hz, rate); + } + rk_clrsetreg(&cru->clksel_con[144], + ACLK_VOP_ROOT_DIV_MASK | + ACLK_VOP_ROOT_SEL_MASK, + (src_clk << ACLK_VOP_ROOT_SEL_SHIFT) | + (div - 1) << ACLK_VOP_ROOT_DIV_SHIFT); + break; + case ACLK_VO0_ROOT: + if (!(priv->cpll_hz % rate)) { + src_clk = ACLK_VO0_ROOT_SEL_CPLL; + div = DIV_ROUND_UP(priv->cpll_hz, rate); + } else { + src_clk = ACLK_VO0_ROOT_SEL_GPLL; + div = DIV_ROUND_UP(priv->gpll_hz, rate); + } + rk_clrsetreg(&cru->clksel_con[149], + ACLK_VO0_ROOT_DIV_MASK | + ACLK_VO0_ROOT_SEL_MASK, + (src_clk << ACLK_VO0_ROOT_SEL_SHIFT) | + (div - 1) << ACLK_VO0_ROOT_DIV_SHIFT); + break; + case ACLK_VO1_ROOT: + if (!(priv->cpll_hz % rate)) { + src_clk = ACLK_VO0_ROOT_SEL_CPLL; + div = DIV_ROUND_UP(priv->cpll_hz, rate); + } else { + src_clk = ACLK_VO0_ROOT_SEL_GPLL; + div = DIV_ROUND_UP(priv->gpll_hz, rate); + } + rk_clrsetreg(&cru->clksel_con[158], + ACLK_VO0_ROOT_DIV_MASK | + ACLK_VO0_ROOT_SEL_MASK, + (src_clk << ACLK_VO0_ROOT_SEL_SHIFT) | + (div - 1) << ACLK_VO0_ROOT_DIV_SHIFT); + break; + case HCLK_VOP_ROOT: + if (rate == 200 * MHz) + src_clk = HCLK_VOP_ROOT_SEL_200M; + else if (rate == 100 * MHz) + src_clk = HCLK_VOP_ROOT_SEL_100M; + else if (rate == 50 * MHz) + src_clk = HCLK_VOP_ROOT_SEL_50M; + else + src_clk = HCLK_VOP_ROOT_SEL_OSC; + rk_clrsetreg(&cru->clksel_con[144], + HCLK_VOP_ROOT_SEL_MASK, + src_clk << HCLK_VOP_ROOT_SEL_SHIFT); + break; + case PCLK_VOP_ROOT: + if (rate == 100 * MHz) + src_clk = PCLK_VOP_ROOT_SEL_100M; + else if (rate == 50 * MHz) + src_clk = PCLK_VOP_ROOT_SEL_50M; + else + src_clk = PCLK_VOP_ROOT_SEL_OSC; + rk_clrsetreg(&cru->clksel_con[144], + PCLK_VOP_ROOT_SEL_MASK, + src_clk << PCLK_VOP_ROOT_SEL_SHIFT); + break; + + default: + return -ENOENT; + } + + return rk3576_aclk_vop_get_clk(priv, clk_id); +} + +static ulong rk3576_dclk_vop_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 div, sel, con, parent; + + switch (clk_id) { + case DCLK_VP0: + case DCLK_VP0_SRC: + con = readl(&cru->clksel_con[145]); + div = (con & DCLK0_VOP_SRC_DIV_MASK) >> DCLK0_VOP_SRC_DIV_SHIFT; + sel = (con & DCLK0_VOP_SRC_SEL_MASK) >> DCLK0_VOP_SRC_SEL_SHIFT; + break; + case DCLK_VP1: + case DCLK_VP1_SRC: + con = readl(&cru->clksel_con[146]); + div = (con & DCLK0_VOP_SRC_DIV_MASK) >> DCLK0_VOP_SRC_DIV_SHIFT; + sel = (con & DCLK0_VOP_SRC_SEL_MASK) >> DCLK0_VOP_SRC_SEL_SHIFT; + break; + case DCLK_VP2: + case DCLK_VP2_SRC: + con = readl(&cru->clksel_con[147]); + div = (con & DCLK0_VOP_SRC_DIV_MASK) >> DCLK0_VOP_SRC_DIV_SHIFT; + sel = (con & DCLK0_VOP_SRC_SEL_MASK) >> DCLK0_VOP_SRC_SEL_SHIFT; + break; + default: + return -ENOENT; + } + + if (sel == DCLK_VOP_SRC_SEL_VPLL) + parent = priv->vpll_hz; + else if (sel == DCLK_VOP_SRC_SEL_BPLL) + parent = priv->bpll_hz / 4; + else if (sel == DCLK_VOP_SRC_SEL_LPLL) + parent = priv->lpll_hz / 2; + else if (sel == DCLK_VOP_SRC_SEL_GPLL) + parent = priv->gpll_hz; + else + parent = priv->cpll_hz; + + return DIV_TO_RATE(parent, div); +} + +#define RK3576_VOP_PLL_LIMIT_FREQ 600000000 + +static ulong rk3576_dclk_vop_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + ulong pll_rate, now, best_rate = 0; + u32 i, conid, con, sel, div, best_div = 0, best_sel = 0; + u32 mask, div_shift, sel_shift; + + switch (clk_id) { + case DCLK_VP0: + case DCLK_VP0_SRC: + conid = 145; + con = readl(&cru->clksel_con[conid]); + sel = (con & DCLK0_VOP_SRC_SEL_MASK) >> DCLK0_VOP_SRC_SEL_SHIFT; + mask = DCLK0_VOP_SRC_SEL_MASK | DCLK0_VOP_SRC_DIV_MASK; + div_shift = DCLK0_VOP_SRC_DIV_SHIFT; + sel_shift = DCLK0_VOP_SRC_SEL_SHIFT; + break; + case DCLK_VP1: + case DCLK_VP1_SRC: + conid = 146; + con = readl(&cru->clksel_con[conid]); + sel = (con & DCLK0_VOP_SRC_SEL_MASK) >> DCLK0_VOP_SRC_SEL_SHIFT; + mask = DCLK0_VOP_SRC_SEL_MASK | DCLK0_VOP_SRC_DIV_MASK; + div_shift = DCLK0_VOP_SRC_DIV_SHIFT; + sel_shift = DCLK0_VOP_SRC_SEL_SHIFT; + break; + case DCLK_VP2: + case DCLK_VP2_SRC: + conid = 147; + con = readl(&cru->clksel_con[conid]); + sel = (con & DCLK0_VOP_SRC_SEL_MASK) >> DCLK0_VOP_SRC_SEL_SHIFT; + mask = DCLK0_VOP_SRC_SEL_MASK | DCLK0_VOP_SRC_DIV_MASK; + div_shift = DCLK0_VOP_SRC_DIV_SHIFT; + sel_shift = DCLK0_VOP_SRC_SEL_SHIFT; + break; + default: + return -ENOENT; + } + + if (sel == DCLK_VOP_SRC_SEL_VPLL) { + pll_rate = rockchip_pll_get_rate(&rk3576_pll_clks[VPLL], + priv->cru, VPLL); + if (pll_rate >= RK3576_VOP_PLL_LIMIT_FREQ && pll_rate % rate == 0) { + div = DIV_ROUND_UP(pll_rate, rate); + rk_clrsetreg(&cru->clksel_con[conid], + mask, + DCLK_VOP_SRC_SEL_VPLL << sel_shift | + ((div - 1) << div_shift)); + } else { + div = DIV_ROUND_UP(RK3576_VOP_PLL_LIMIT_FREQ, rate); + if (div % 2) + div = div + 1; + rk_clrsetreg(&cru->clksel_con[conid], + mask, + DCLK_VOP_SRC_SEL_VPLL << sel_shift | + ((div - 1) << div_shift)); + rockchip_pll_set_rate(&rk3576_pll_clks[VPLL], + priv->cru, VPLL, div * rate); + priv->vpll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[VPLL], + priv->cru, VPLL); + } + } else { + for (i = 0; i <= DCLK_VOP_SRC_SEL_LPLL; i++) { + switch (i) { + case DCLK_VOP_SRC_SEL_GPLL: + pll_rate = priv->gpll_hz; + break; + case DCLK_VOP_SRC_SEL_CPLL: + pll_rate = priv->cpll_hz; + break; + case DCLK_VOP_SRC_SEL_BPLL: + pll_rate = 0; + break; + case DCLK_VOP_SRC_SEL_LPLL: + pll_rate = 0; + break; + case DCLK_VOP_SRC_SEL_VPLL: + pll_rate = 0; + break; + default: + printf("do not support this vop pll sel\n"); + return -EINVAL; + } + + div = DIV_ROUND_UP(pll_rate, rate); + if (div > 255) + continue; + now = pll_rate / div; + if (abs(rate - now) < abs(rate - best_rate)) { + best_rate = now; + best_div = div; + best_sel = i; + } + debug("p_rate=%lu, best_rate=%lu, div=%u, sel=%u\n", + pll_rate, best_rate, best_div, best_sel); + } + + if (best_rate) { + rk_clrsetreg(&cru->clksel_con[conid], + mask, + best_sel << sel_shift | + (best_div - 1) << div_shift); + } else { + printf("do not support this vop freq %lu\n", rate); + return -EINVAL; + } + } + + return rk3576_dclk_vop_get_clk(priv, clk_id); +} + +static ulong rk3576_clk_csihost_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 div, sel, con, parent; + + switch (clk_id) { + case CLK_DSIHOST0: + con = readl(&cru->clksel_con[151]); + div = (con & CLK_DSIHOST0_DIV_MASK) >> CLK_DSIHOST0_DIV_SHIFT; + sel = (con & CLK_DSIHOST0_SEL_MASK) >> CLK_DSIHOST0_SEL_SHIFT; + break; + default: + return -ENOENT; + } + + if (sel == CLK_DSIHOST0_SEL_VPLL) + parent = priv->vpll_hz; + else if (sel == CLK_DSIHOST0_SEL_BPLL) + parent = priv->bpll_hz / 4; + else if (sel == CLK_DSIHOST0_SEL_LPLL) + parent = priv->lpll_hz / 2; + else if (sel == CLK_DSIHOST0_SEL_GPLL) + parent = priv->gpll_hz; + else if (sel == CLK_DSIHOST0_SEL_SPLL) + parent = priv->spll_hz; + else + parent = priv->cpll_hz; + + return DIV_TO_RATE(parent, div); +} + +static ulong rk3576_clk_csihost_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + ulong pll_rate, now, best_rate = 0; + u32 i, con, div, best_div = 0, best_sel = 0; + u32 mask, div_shift, sel_shift; + + switch (clk_id) { + case CLK_DSIHOST0: + con = 151; + mask = CLK_DSIHOST0_SEL_MASK | CLK_DSIHOST0_DIV_MASK; + div_shift = CLK_DSIHOST0_DIV_SHIFT; + sel_shift = CLK_DSIHOST0_SEL_SHIFT; + break; + default: + return -ENOENT; + } + for (i = 0; i <= CLK_DSIHOST0_SEL_LPLL; i++) { + switch (i) { + case CLK_DSIHOST0_SEL_GPLL: + pll_rate = priv->gpll_hz; + break; + case CLK_DSIHOST0_SEL_CPLL: + pll_rate = priv->cpll_hz; + break; + case CLK_DSIHOST0_SEL_BPLL: + pll_rate = 0; + break; + case CLK_DSIHOST0_SEL_LPLL: + pll_rate = 0; + break; + case CLK_DSIHOST0_SEL_VPLL: + pll_rate = 0; + break; + case CLK_DSIHOST0_SEL_SPLL: + pll_rate = priv->spll_hz; + break; + default: + printf("do not support this vop pll sel\n"); + return -EINVAL; + } + + div = DIV_ROUND_UP(pll_rate, rate); + if (div > 255) + continue; + now = pll_rate / div; + if (abs(rate - now) < abs(rate - best_rate)) { + best_rate = now; + best_div = div; + best_sel = i; + } + debug("p_rate=%lu, best_rate=%lu, div=%u, sel=%u\n", + pll_rate, best_rate, best_div, best_sel); + } + + if (best_rate) { + rk_clrsetreg(&cru->clksel_con[con], + mask, + best_sel << sel_shift | + (best_div - 1) << div_shift); + } else { + printf("do not support this vop freq %lu\n", rate); + return -EINVAL; + } + + return rk3576_clk_csihost_get_clk(priv, clk_id); +} + +static ulong rk3576_dclk_ebc_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 div, sel, con, parent; + unsigned long m = 0, n = 0; + + switch (clk_id) { + case DCLK_EBC: + con = readl(&cru->clksel_con[123]); + div = (con & DCLK_EBC_DIV_MASK) >> DCLK_EBC_DIV_SHIFT; + sel = (con & DCLK_EBC_SEL_MASK) >> DCLK_EBC_SEL_SHIFT; + if (sel == DCLK_EBC_SEL_CPLL) + parent = priv->cpll_hz; + else if (sel == DCLK_EBC_SEL_VPLL) + parent = priv->vpll_hz; + else if (sel == DCLK_EBC_SEL_AUPLL) + parent = priv->aupll_hz; + else if (sel == DCLK_EBC_SEL_LPLL) + parent = priv->lpll_hz / 2; + else if (sel == DCLK_EBC_SEL_GPLL) + parent = priv->gpll_hz; + else if (sel == DCLK_EBC_SEL_FRAC_SRC) + parent = rk3576_dclk_ebc_get_clk(priv, DCLK_EBC_FRAC_SRC); + else + parent = OSC_HZ; + return DIV_TO_RATE(parent, div); + case DCLK_EBC_FRAC_SRC: + con = readl(&cru->clksel_con[123]); + div = readl(&cru->clksel_con[122]); + sel = (con & DCLK_EBC_FRAC_SRC_SEL_MASK) >> DCLK_EBC_FRAC_SRC_SEL_SHIFT; + if (sel == DCLK_EBC_FRAC_SRC_SEL_GPLL) + parent = priv->gpll_hz; + else if (sel == DCLK_EBC_FRAC_SRC_SEL_CPLL) + parent = priv->cpll_hz; + else if (sel == DCLK_EBC_FRAC_SRC_SEL_VPLL) + parent = priv->vpll_hz; + else if (sel == DCLK_EBC_FRAC_SRC_SEL_AUPLL) + parent = priv->aupll_hz; + else + parent = OSC_HZ; + + n = div & CLK_UART_FRAC_NUMERATOR_MASK; + n >>= CLK_UART_FRAC_NUMERATOR_SHIFT; + m = div & CLK_UART_FRAC_DENOMINATOR_MASK; + m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT; + return parent * n / m; + default: + return -ENOENT; + } +} + +static ulong rk3576_dclk_ebc_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + ulong pll_rate, now, best_rate = 0; + u32 i, con, sel, div, best_div = 0, best_sel = 0; + unsigned long m = 0, n = 0, val; + + switch (clk_id) { + case DCLK_EBC: + con = readl(&cru->clksel_con[123]); + sel = (con & DCLK_EBC_SEL_MASK) >> DCLK_EBC_SEL_SHIFT; + if (sel == DCLK_EBC_SEL_VPLL) { + pll_rate = rockchip_pll_get_rate(&rk3576_pll_clks[VPLL], + priv->cru, VPLL); + if (pll_rate >= RK3576_VOP_PLL_LIMIT_FREQ && + pll_rate % rate == 0) { + div = DIV_ROUND_UP(pll_rate, rate); + rk_clrsetreg(&cru->clksel_con[123], + DCLK_EBC_DIV_MASK, + (div - 1) << DCLK_EBC_DIV_SHIFT); + } else { + div = DIV_ROUND_UP(RK3576_VOP_PLL_LIMIT_FREQ, + rate); + if (div % 2) + div = div + 1; + rk_clrsetreg(&cru->clksel_con[123], + DCLK_EBC_DIV_MASK, + (div - 1) << DCLK_EBC_DIV_SHIFT); + rockchip_pll_set_rate(&rk3576_pll_clks[VPLL], + priv->cru, + VPLL, div * rate); + priv->vpll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[VPLL], + priv->cru, + VPLL); + } + } else if (sel == DCLK_EBC_SEL_FRAC_SRC) { + rk3576_dclk_ebc_set_clk(priv, DCLK_EBC_FRAC_SRC, rate); + div = rk3576_dclk_ebc_get_clk(priv, DCLK_EBC_FRAC_SRC) / rate; + rk_clrsetreg(&cru->clksel_con[123], + DCLK_EBC_DIV_MASK, + (div - 1) << DCLK_EBC_DIV_SHIFT); + } else { + for (i = 0; i <= DCLK_EBC_SEL_LPLL; i++) { + switch (i) { + case DCLK_EBC_SEL_GPLL: + pll_rate = priv->gpll_hz; + break; + case DCLK_EBC_SEL_CPLL: + pll_rate = priv->cpll_hz; + break; + case DCLK_EBC_SEL_VPLL: + pll_rate = 0; + break; + case DCLK_EBC_SEL_AUPLL: + pll_rate = priv->aupll_hz; + break; + case DCLK_EBC_SEL_LPLL: + pll_rate = 0; + break; + default: + printf("not support ebc pll sel\n"); + return -EINVAL; + } + + div = DIV_ROUND_UP(pll_rate, rate); + if (div > 255) + continue; + now = pll_rate / div; + if (abs(rate - now) < abs(rate - best_rate)) { + best_rate = now; + best_div = div; + best_sel = i; + } + } + + if (best_rate) { + rk_clrsetreg(&cru->clksel_con[123], + DCLK_EBC_DIV_MASK | + DCLK_EBC_SEL_MASK, + best_sel << + DCLK_EBC_SEL_SHIFT | + (best_div - 1) << + DCLK_EBC_DIV_SHIFT); + } else { + printf("do not support this vop freq %lu\n", + rate); + return -EINVAL; + } + } + break; + case DCLK_EBC_FRAC_SRC: + sel = DCLK_EBC_FRAC_SRC_SEL_GPLL; + div = 1; + rational_best_approximation(rate, priv->gpll_hz, + GENMASK(16 - 1, 0), + GENMASK(16 - 1, 0), + &m, &n); + + if (m < 4 && m != 0) { + if (n % 2 == 0) + val = 1; + else + val = DIV_ROUND_UP(4, m); + + n *= val; + m *= val; + if (n > 0xffff) + n = 0xffff; + } + + rk_clrsetreg(&cru->clksel_con[123], + DCLK_EBC_FRAC_SRC_SEL_MASK, + (sel << DCLK_EBC_FRAC_SRC_SEL_SHIFT)); + if (m && n) { + val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n; + writel(val, &cru->clksel_con[122]); + } + break; + default: + return -ENOENT; + } + return rk3576_dclk_ebc_get_clk(priv, clk_id); +} + +static ulong rk3576_gmac_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 con, div, src, p_rate; + + switch (clk_id) { + case CLK_GMAC0_PTP_REF_SRC: + case CLK_GMAC0_PTP_REF: + con = readl(&cru->clksel_con[105]); + div = (con & CLK_GMAC0_PTP_DIV_MASK) >> CLK_GMAC0_PTP_DIV_SHIFT; + src = (con & CLK_GMAC0_PTP_SEL_MASK) >> CLK_GMAC0_PTP_SEL_SHIFT; + if (src == CLK_GMAC0_PTP_SEL_GPLL) + p_rate = priv->gpll_hz; + else if (src == CLK_GMAC0_PTP_SEL_CPLL) + p_rate = priv->cpll_hz; + else + p_rate = GMAC0_PTP_REFCLK_IN; + return DIV_TO_RATE(p_rate, div); + case CLK_GMAC1_PTP_REF_SRC: + case CLK_GMAC1_PTP_REF: + con = readl(&cru->clksel_con[104]); + div = (con & CLK_GMAC1_PTP_DIV_MASK) >> CLK_GMAC0_PTP_DIV_SHIFT; + src = (con & CLK_GMAC1_PTP_SEL_MASK) >> CLK_GMAC1_PTP_SEL_SHIFT; + if (src == CLK_GMAC1_PTP_SEL_GPLL) + p_rate = priv->gpll_hz; + else if (src == CLK_GMAC1_PTP_SEL_CPLL) + p_rate = priv->cpll_hz; + else + p_rate = GMAC1_PTP_REFCLK_IN; + return DIV_TO_RATE(p_rate, div); + case CLK_GMAC0_125M_SRC: + con = readl(&cru->clksel_con[30]); + div = (con & CLK_GMAC0_125M_DIV_MASK) >> CLK_GMAC0_125M_DIV_SHIFT; + return DIV_TO_RATE(priv->cpll_hz, div); + case CLK_GMAC1_125M_SRC: + con = readl(&cru->clksel_con[31]); + div = (con & CLK_GMAC1_125M_DIV_MASK) >> CLK_GMAC1_125M_DIV_SHIFT; + return DIV_TO_RATE(priv->cpll_hz, div); + default: + return -ENOENT; + } +} + +static ulong rk3576_gmac_set_clk(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + int div, src; + + div = DIV_ROUND_UP(priv->cpll_hz, rate); + + switch (clk_id) { + case CLK_GMAC0_PTP_REF_SRC: + case CLK_GMAC0_PTP_REF: + if (rate == GMAC0_PTP_REFCLK_IN) { + src = CLK_GMAC0_PTP_SEL_REFIN; + div = 1; + } else if (!(priv->gpll_hz % rate)) { + src = CLK_GMAC0_PTP_SEL_GPLL; + div = priv->gpll_hz / rate; + } else { + src = CLK_GMAC0_PTP_SEL_CPLL; + div = priv->cpll_hz / rate; + } + rk_clrsetreg(&cru->clksel_con[105], + CLK_GMAC0_PTP_DIV_MASK | CLK_GMAC0_PTP_SEL_MASK, + src << CLK_GMAC0_PTP_SEL_SHIFT | + (div - 1) << CLK_GMAC0_PTP_DIV_SHIFT); + break; + case CLK_GMAC1_PTP_REF_SRC: + case CLK_GMAC1_PTP_REF: + if (rate == GMAC1_PTP_REFCLK_IN) { + src = CLK_GMAC1_PTP_SEL_REFIN; + div = 1; + } else if (!(priv->gpll_hz % rate)) { + src = CLK_GMAC1_PTP_SEL_GPLL; + div = priv->gpll_hz / rate; + } else { + src = CLK_GMAC1_PTP_SEL_CPLL; + div = priv->cpll_hz / rate; + } + rk_clrsetreg(&cru->clksel_con[104], + CLK_GMAC1_PTP_DIV_MASK | CLK_GMAC1_PTP_SEL_MASK, + src << CLK_GMAC1_PTP_SEL_SHIFT | + (div - 1) << CLK_GMAC1_PTP_DIV_SHIFT); + break; + + case CLK_GMAC0_125M_SRC: + rk_clrsetreg(&cru->clksel_con[30], + CLK_GMAC0_125M_DIV_MASK, + (div - 1) << CLK_GMAC0_125M_DIV_SHIFT); + break; + case CLK_GMAC1_125M_SRC: + rk_clrsetreg(&cru->clksel_con[31], + CLK_GMAC1_125M_DIV_MASK, + (div - 1) << CLK_GMAC1_125M_DIV_SHIFT); + break; + default: + return -ENOENT; + } + + return rk3576_gmac_get_clk(priv, clk_id); +} + +static ulong rk3576_uart_frac_get_rate(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 reg, con, fracdiv, p_src, p_rate; + unsigned long m, n; + + switch (clk_id) { + case CLK_UART_FRAC_0: + reg = 21; + break; + case CLK_UART_FRAC_1: + reg = 23; + break; + case CLK_UART_FRAC_2: + reg = 25; + break; + default: + return -ENOENT; + } + con = readl(&cru->clksel_con[reg + 1]); + p_src = (con & CLK_UART_SRC_SEL_MASK) >> CLK_UART_SRC_SEL_SHIFT; + if (p_src == CLK_UART_SRC_SEL_GPLL) + p_rate = priv->gpll_hz; + else if (p_src == CLK_UART_SRC_SEL_CPLL) + p_rate = priv->cpll_hz; + else if (p_src == CLK_UART_SRC_SEL_AUPLL) + p_rate = priv->aupll_hz; + else + p_rate = OSC_HZ; + + fracdiv = readl(&cru->clksel_con[reg]); + n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK; + n >>= CLK_UART_FRAC_NUMERATOR_SHIFT; + m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK; + m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT; + return p_rate * n / m; +} + +static ulong rk3576_uart_frac_set_rate(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + u32 reg, clk_src, p_rate; + unsigned long m = 0, n = 0, val; + + if (priv->cpll_hz % rate == 0) { + clk_src = CLK_UART_SRC_SEL_CPLL; + p_rate = priv->cpll_hz; + } else if (rate == OSC_HZ) { + clk_src = CLK_UART_SRC_SEL_OSC; + p_rate = OSC_HZ; + } else { + clk_src = CLK_UART_SRC_SEL_GPLL; + p_rate = priv->cpll_hz; + } + + rational_best_approximation(rate, p_rate, GENMASK(16 - 1, 0), + GENMASK(16 - 1, 0), &m, &n); + + if (m < 4 && m != 0) { + if (n % 2 == 0) + val = 1; + else + val = DIV_ROUND_UP(4, m); + + n *= val; + m *= val; + if (n > 0xffff) + n = 0xffff; + } + + switch (clk_id) { + case CLK_UART_FRAC_0: + reg = 21; + break; + case CLK_UART_FRAC_1: + reg = 23; + break; + case CLK_UART_FRAC_2: + reg = 25; + break; + default: + return -ENOENT; + } + + rk_clrsetreg(&cru->clksel_con[reg + 1], + CLK_UART_SRC_SEL_MASK, + (clk_src << CLK_UART_SRC_SEL_SHIFT)); + if (m && n) { + val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n; + writel(val, &cru->clksel_con[reg]); + } + + return rk3576_uart_frac_get_rate(priv, clk_id); +} + +static ulong rk3576_uart_get_rate(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 con, div, src, p_rate; + + switch (clk_id) { + case SCLK_UART0: + con = readl(&cru->clksel_con[60]); + break; + case SCLK_UART1: + con = readl(&cru->pmuclksel_con[8]); + src = (con & CLK_UART1_SEL_MASK) >> CLK_UART1_SEL_SHIFT; + if (src == CLK_UART1_SEL_OSC) + return OSC_HZ; + con = readl(&cru->clksel_con[27]); + break; + case SCLK_UART2: + con = readl(&cru->clksel_con[61]); + break; + case SCLK_UART3: + con = readl(&cru->clksel_con[62]); + break; + case SCLK_UART4: + con = readl(&cru->clksel_con[63]); + break; + case SCLK_UART5: + con = readl(&cru->clksel_con[64]); + break; + case SCLK_UART6: + con = readl(&cru->clksel_con[65]); + break; + case SCLK_UART7: + con = readl(&cru->clksel_con[66]); + break; + case SCLK_UART8: + con = readl(&cru->clksel_con[67]); + break; + case SCLK_UART9: + con = readl(&cru->clksel_con[68]); + break; + case SCLK_UART10: + con = readl(&cru->clksel_con[69]); + break; + case SCLK_UART11: + con = readl(&cru->clksel_con[70]); + break; + default: + return -ENOENT; + } + if (clk_id == SCLK_UART1) { + src = (con & CLK_UART1_SRC_SEL_SHIFT) >> CLK_UART1_SRC_SEL_SHIFT; + div = (con & CLK_UART1_SRC_DIV_MASK) >> CLK_UART1_SRC_DIV_SHIFT; + } else { + src = (con & CLK_UART_SEL_MASK) >> CLK_UART_SEL_SHIFT; + div = (con & CLK_UART_DIV_MASK) >> CLK_UART_DIV_SHIFT; + } + if (src == CLK_UART_SEL_GPLL) + p_rate = priv->gpll_hz; + else if (src == CLK_UART_SEL_CPLL) + p_rate = priv->cpll_hz; + else if (src == CLK_UART_SEL_AUPLL) + p_rate = priv->aupll_hz; + else if (src == CLK_UART_SEL_FRAC0) + p_rate = rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_0); + else if (src == CLK_UART_SEL_FRAC1) + p_rate = rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_1); + else if (src == CLK_UART_SEL_FRAC2) + p_rate = rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_2); + else + p_rate = OSC_HZ; + + return DIV_TO_RATE(p_rate, div); +} + +static ulong rk3576_uart_set_rate(struct rk3576_clk_priv *priv, + ulong clk_id, ulong rate) +{ + struct rk3576_cru *cru = priv->cru; + u32 reg, clk_src = 0, div = 0; + + if (!(priv->gpll_hz % rate)) { + clk_src = CLK_UART_SEL_GPLL; + div = DIV_ROUND_UP(priv->gpll_hz, rate); + } else if (!(priv->cpll_hz % rate)) { + clk_src = CLK_UART_SEL_CPLL; + div = DIV_ROUND_UP(priv->gpll_hz, rate); + } else if (!(rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_0) % rate)) { + clk_src = CLK_UART_SEL_FRAC0; + div = DIV_ROUND_UP(rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_0), rate); + } else if (!(rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_1) % rate)) { + clk_src = CLK_UART_SEL_FRAC1; + div = DIV_ROUND_UP(rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_1), rate); + } else if (!(rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_2) % rate)) { + clk_src = CLK_UART_SEL_FRAC2; + div = DIV_ROUND_UP(rk3576_uart_frac_get_rate(priv, CLK_UART_FRAC_2), rate); + } else if (!(OSC_HZ % rate)) { + clk_src = CLK_UART_SEL_OSC; + div = DIV_ROUND_UP(OSC_HZ, rate); + } + + switch (clk_id) { + case SCLK_UART0: + reg = 60; + break; + case SCLK_UART1: + if (rate == OSC_HZ) { + rk_clrsetreg(&cru->pmuclksel_con[8], + CLK_UART1_SEL_MASK, + CLK_UART1_SEL_OSC << CLK_UART1_SEL_SHIFT); + return 0; + } + + rk_clrsetreg(&cru->clksel_con[27], + CLK_UART1_SRC_SEL_MASK | CLK_UART1_SRC_DIV_MASK, + (clk_src << CLK_UART1_SRC_SEL_SHIFT) | + ((div - 1) << CLK_UART1_SRC_DIV_SHIFT)); + rk_clrsetreg(&cru->pmuclksel_con[8], + CLK_UART1_SEL_MASK, + CLK_UART1_SEL_TOP << CLK_UART1_SEL_SHIFT); + return 0; + case SCLK_UART2: + reg = 61; + break; + case SCLK_UART3: + reg = 62; + break; + case SCLK_UART4: + reg = 63; + break; + case SCLK_UART5: + reg = 64; + break; + case SCLK_UART6: + reg = 65; + break; + case SCLK_UART7: + reg = 66; + break; + case SCLK_UART8: + reg = 67; + break; + case SCLK_UART9: + reg = 68; + break; + case SCLK_UART10: + reg = 69; + break; + case SCLK_UART11: + reg = 70; + break; + default: + return -ENOENT; + } + + rk_clrsetreg(&cru->clksel_con[reg], + CLK_UART_SEL_MASK | + CLK_UART_DIV_MASK, + (clk_src << CLK_UART_SEL_SHIFT) | + ((div - 1) << CLK_UART_DIV_SHIFT)); + + return rk3576_uart_get_rate(priv, clk_id); +} +#endif + +static ulong rk3576_ufs_ref_get_rate(struct rk3576_clk_priv *priv, ulong clk_id) +{ + struct rk3576_cru *cru = priv->cru; + u32 src, div; + + src = readl(&cru->pmuclksel_con[3]) & 0x3; + div = readl(&cru->pmuclksel_con[1]) & 0xff; + if (src == 0) + return OSC_HZ; + else if (src == 2) + return priv->ppll_hz / (div + 1); + else + return 26000000; +} + +static ulong rk3576_clk_get_rate(struct clk *clk) +{ + struct rk3576_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(&rk3576_pll_clks[PPLL], + priv->cru, PPLL); + } + + switch (clk->id) { + case PLL_LPLL: + rate = rockchip_pll_get_rate(&rk3576_pll_clks[LPLL], priv->cru, + LPLL); + priv->lpll_hz = rate; + break; + case PLL_BPLL: + rate = rockchip_pll_get_rate(&rk3576_pll_clks[BPLL], priv->cru, + BPLL); + priv->bpll_hz = rate; + break; + case PLL_GPLL: + rate = rockchip_pll_get_rate(&rk3576_pll_clks[GPLL], priv->cru, + GPLL); + break; + case PLL_CPLL: + rate = rockchip_pll_get_rate(&rk3576_pll_clks[CPLL], priv->cru, + CPLL); + break; + case PLL_VPLL: + rate = rockchip_pll_get_rate(&rk3576_pll_clks[VPLL], priv->cru, + VPLL); + break; + case PLL_AUPLL: + rate = rockchip_pll_get_rate(&rk3576_pll_clks[AUPLL], priv->cru, + AUPLL); + break; + case PLL_PPLL: + rate = rockchip_pll_get_rate(&rk3576_pll_clks[PPLL], priv->cru, + PPLL) * 2; + break; + case ACLK_BUS_ROOT: + case HCLK_BUS_ROOT: + case PCLK_BUS_ROOT: + rate = rk3576_bus_get_clk(priv, clk->id); + break; + case ACLK_TOP: + case HCLK_TOP: + case PCLK_TOP_ROOT: + case ACLK_TOP_MID: + rate = rk3576_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: + case CLK_I2C9: + rate = rk3576_i2c_get_clk(priv, clk->id); + break; + case CLK_SPI0: + case CLK_SPI1: + case CLK_SPI2: + case CLK_SPI3: + case CLK_SPI4: + rate = rk3576_spi_get_clk(priv, clk->id); + break; + case CLK_PWM1: + case CLK_PWM2: + case CLK_PMU1PWM: + rate = rk3576_pwm_get_clk(priv, clk->id); + break; + case CLK_SARADC: + case CLK_TSADC: + rate = rk3576_adc_get_clk(priv, clk->id); + break; + case CCLK_SRC_SDIO: + case CCLK_SRC_SDMMC0: + case CCLK_SRC_EMMC: + case BCLK_EMMC: + case SCLK_FSPI_X2: + case SCLK_FSPI1_X2: + case DCLK_DECOM: + case HCLK_SDMMC0: + case HCLK_EMMC: + case HCLK_SDIO: + rate = rk3576_mmc_get_clk(priv, clk->id); + break; + case TCLK_EMMC: + case TCLK_WDT0: + rate = OSC_HZ; + break; +#ifndef CONFIG_SPL_BUILD + case ACLK_VOP_ROOT: + case ACLK_VOP: + case ACLK_VO0_ROOT: + case ACLK_VO1_ROOT: + case HCLK_VOP_ROOT: + case PCLK_VOP_ROOT: + rate = rk3576_aclk_vop_get_clk(priv, clk->id); + break; + case DCLK_VP0: + case DCLK_VP0_SRC: + case DCLK_VP1: + case DCLK_VP1_SRC: + case DCLK_VP2: + case DCLK_VP2_SRC: + rate = rk3576_dclk_vop_get_clk(priv, clk->id); + break; + case CLK_GMAC0_PTP_REF_SRC: + case CLK_GMAC1_PTP_REF_SRC: + case CLK_GMAC0_PTP_REF: + case CLK_GMAC1_PTP_REF: + case CLK_GMAC0_125M_SRC: + case CLK_GMAC1_125M_SRC: + rate = rk3576_gmac_get_clk(priv, clk->id); + break; + case CLK_UART_FRAC_0: + case CLK_UART_FRAC_1: + case CLK_UART_FRAC_2: + rate = rk3576_uart_frac_get_rate(priv, clk->id); + break; + case SCLK_UART0: + 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: + case SCLK_UART10: + case SCLK_UART11: + rate = rk3576_uart_get_rate(priv, clk->id); + break; + case CLK_DSIHOST0: + rate = rk3576_clk_csihost_get_clk(priv, clk->id); + break; + case DCLK_EBC: + case DCLK_EBC_FRAC_SRC: + rate = rk3576_dclk_ebc_get_clk(priv, clk->id); + break; +#endif + case CLK_REF_UFS_CLKOUT: + case CLK_REF_OSC_MPHY: + rate = rk3576_ufs_ref_get_rate(priv, clk->id); + break; + + default: + return -ENOENT; + } + + return rate; +}; + +static ulong rk3576_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3576_clk_priv *priv = dev_get_priv(clk->dev); + ulong ret = 0; + + if (!priv->ppll_hz) { + priv->ppll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[PPLL], + priv->cru, PPLL); + } + if (!priv->aupll_hz) { + priv->aupll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[AUPLL], + priv->cru, AUPLL); + } + + switch (clk->id) { + case PLL_CPLL: + ret = rockchip_pll_set_rate(&rk3576_pll_clks[CPLL], priv->cru, + CPLL, rate); + priv->cpll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[CPLL], + priv->cru, CPLL); + break; + case PLL_GPLL: + ret = rockchip_pll_set_rate(&rk3576_pll_clks[GPLL], priv->cru, + GPLL, rate); + priv->gpll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[GPLL], + priv->cru, GPLL); + break; + case PLL_VPLL: + ret = rockchip_pll_set_rate(&rk3576_pll_clks[VPLL], priv->cru, + VPLL, rate); + priv->vpll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[VPLL], + priv->cru, VPLL); + break; + case PLL_AUPLL: + ret = rockchip_pll_set_rate(&rk3576_pll_clks[AUPLL], priv->cru, + AUPLL, rate); + priv->aupll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[AUPLL], + priv->cru, AUPLL); + break; + case PLL_PPLL: + ret = rockchip_pll_set_rate(&rk3576_pll_clks[PPLL], priv->cru, + PPLL, rate); + priv->ppll_hz = rockchip_pll_get_rate(&rk3576_pll_clks[PPLL], + priv->cru, PPLL) * 2; + break; + case ACLK_BUS_ROOT: + case HCLK_BUS_ROOT: + case PCLK_BUS_ROOT: + ret = rk3576_bus_set_clk(priv, clk->id, rate); + break; + case ACLK_TOP: + case HCLK_TOP: + case PCLK_TOP_ROOT: + case ACLK_TOP_MID: + ret = rk3576_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: + case CLK_I2C9: + ret = rk3576_i2c_set_clk(priv, clk->id, rate); + break; + case CLK_SPI0: + case CLK_SPI1: + case CLK_SPI2: + case CLK_SPI3: + case CLK_SPI4: + ret = rk3576_spi_set_clk(priv, clk->id, rate); + break; + case CLK_PWM1: + case CLK_PWM2: + case CLK_PMU1PWM: + ret = rk3576_pwm_set_clk(priv, clk->id, rate); + break; + case CLK_SARADC: + case CLK_TSADC: + ret = rk3576_adc_set_clk(priv, clk->id, rate); + break; + case CCLK_SRC_SDIO: + case CCLK_SRC_SDMMC0: + case CCLK_SRC_EMMC: + case BCLK_EMMC: + case SCLK_FSPI_X2: + case SCLK_FSPI1_X2: + case DCLK_DECOM: + case HCLK_SDMMC0: + case HCLK_EMMC: + case HCLK_SDIO: + ret = rk3576_mmc_set_clk(priv, clk->id, rate); + break; + case TCLK_EMMC: + case TCLK_WDT0: + ret = OSC_HZ; + break; + + /* Might occur in cru assigned-clocks, can be ignored here */ + case CLK_AUDIO_FRAC_0: + case CLK_AUDIO_FRAC_1: + case CLK_AUDIO_FRAC_0_SRC: + case CLK_AUDIO_FRAC_1_SRC: + case CLK_CPLL_DIV2: + case CLK_CPLL_DIV4: + case CLK_CPLL_DIV10: + case FCLK_DDR_CM0_CORE: + case ACLK_PHP_ROOT: + ret = 0; + break; +#ifndef CONFIG_SPL_BUILD + case ACLK_VOP_ROOT: + case ACLK_VOP: + case ACLK_VO0_ROOT: + case ACLK_VO1_ROOT: + case HCLK_VOP_ROOT: + case PCLK_VOP_ROOT: + ret = rk3576_aclk_vop_set_clk(priv, clk->id, rate); + break; + case DCLK_VP0: + case DCLK_VP0_SRC: + case DCLK_VP1: + case DCLK_VP1_SRC: + case DCLK_VP2: + case DCLK_VP2_SRC: + ret = rk3576_dclk_vop_set_clk(priv, clk->id, rate); + break; + case CLK_GMAC0_PTP_REF_SRC: + case CLK_GMAC1_PTP_REF_SRC: + case CLK_GMAC0_PTP_REF: + case CLK_GMAC1_PTP_REF: + case CLK_GMAC0_125M_SRC: + case CLK_GMAC1_125M_SRC: + ret = rk3576_gmac_set_clk(priv, clk->id, rate); + break; + case CLK_UART_FRAC_0: + case CLK_UART_FRAC_1: + case CLK_UART_FRAC_2: + ret = rk3576_uart_frac_set_rate(priv, clk->id, rate); + break; + case SCLK_UART0: + 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: + case SCLK_UART10: + case SCLK_UART11: + ret = rk3576_uart_set_rate(priv, clk->id, rate); + break; + case CLK_DSIHOST0: + ret = rk3576_clk_csihost_set_clk(priv, clk->id, rate); + break; + case DCLK_EBC: + case DCLK_EBC_FRAC_SRC: + ret = rk3576_dclk_ebc_set_clk(priv, clk->id, rate); + break; +#endif + default: + return -ENOENT; + } + + return ret; +}; + +#if (IS_ENABLED(OF_CONTROL)) || (!IS_ENABLED(OF_PLATDATA)) +static int __maybe_unused rk3576_dclk_vop_set_parent(struct clk *clk, + struct clk *parent) +{ + struct rk3576_clk_priv *priv = dev_get_priv(clk->dev); + struct rk3576_cru *cru = priv->cru; + u32 sel; + const char *clock_dev_name = parent->dev->name; + + if (parent->id == PLL_VPLL) + sel = 2; + else if (parent->id == PLL_GPLL) + sel = 0; + else if (parent->id == PLL_CPLL) + sel = 1; + else if (parent->id == PLL_BPLL) + sel = 3; + else + sel = 4; + + switch (clk->id) { + case DCLK_VP0_SRC: + rk_clrsetreg(&cru->clksel_con[145], DCLK0_VOP_SRC_SEL_MASK, + sel << DCLK0_VOP_SRC_SEL_SHIFT); + break; + case DCLK_VP1_SRC: + rk_clrsetreg(&cru->clksel_con[146], DCLK0_VOP_SRC_SEL_MASK, + sel << DCLK0_VOP_SRC_SEL_SHIFT); + break; + case DCLK_VP2_SRC: + rk_clrsetreg(&cru->clksel_con[147], DCLK0_VOP_SRC_SEL_MASK, + sel << DCLK0_VOP_SRC_SEL_SHIFT); + break; + case DCLK_VP0: + if (!strcmp(clock_dev_name, "hdmiphypll_clk0")) + sel = 1; + else + sel = 0; + rk_clrsetreg(&cru->clksel_con[147], DCLK0_VOP_SEL_MASK, + sel << DCLK0_VOP_SEL_SHIFT); + break; + case DCLK_VP1: + if (!strcmp(clock_dev_name, "hdmiphypll_clk0")) + sel = 1; + else + sel = 0; + rk_clrsetreg(&cru->clksel_con[147], DCLK1_VOP_SEL_MASK, + sel << DCLK1_VOP_SEL_SHIFT); + break; + case DCLK_VP2: + if (!strcmp(clock_dev_name, "hdmiphypll_clk0")) + sel = 1; + else + sel = 0; + rk_clrsetreg(&cru->clksel_con[147], DCLK2_VOP_SEL_MASK, + sel << DCLK2_VOP_SEL_SHIFT); + break; + case DCLK_EBC: + if (parent->id == PLL_GPLL) + sel = 0; + else if (parent->id == PLL_CPLL) + sel = 1; + else if (parent->id == PLL_VPLL) + sel = 2; + else if (parent->id == PLL_AUPLL) + sel = 3; + else if (parent->id == PLL_LPLL) + sel = 4; + else if (parent->id == DCLK_EBC_FRAC_SRC) + sel = 5; + else + sel = 6; + rk_clrsetreg(&cru->clksel_con[123], DCLK_EBC_SEL_MASK, + sel << DCLK_EBC_SEL_SHIFT); + break; + default: + return -EINVAL; + } + return 0; +} + +static int __maybe_unused rk3576_ufs_ref_set_parent(struct clk *clk, + struct clk *parent) +{ + struct rk3576_clk_priv *priv = dev_get_priv(clk->dev); + struct rk3576_cru *cru = priv->cru; + u32 sel; + const char *clock_dev_name = parent->dev->name; + + if (parent->id == CLK_REF_MPHY_26M) + sel = 2; + else if (!strcmp(clock_dev_name, "xin24m")) + sel = 0; + else + sel = 1; + + rk_clrsetreg(&cru->pmuclksel_con[3], 0x3, sel << 0); + return 0; +} + +static int rk3576_clk_set_parent(struct clk *clk, struct clk *parent) +{ + switch (clk->id) { + case DCLK_VP0_SRC: + case DCLK_VP1_SRC: + case DCLK_VP2_SRC: + case DCLK_VP0: + case DCLK_VP1: + case DCLK_VP2: + case DCLK_EBC: + return rk3576_dclk_vop_set_parent(clk, parent); + case CLK_REF_OSC_MPHY: + return rk3576_ufs_ref_set_parent(clk, parent); + case CLK_AUDIO_FRAC_0_SRC: + case CLK_AUDIO_FRAC_1_SRC: + /* Might occur in cru assigned-clocks, can be ignored here */ + return 0; + default: + return -ENOENT; + } + + return 0; +} +#endif + +static struct clk_ops rk3576_clk_ops = { + .get_rate = rk3576_clk_get_rate, + .set_rate = rk3576_clk_set_rate, +#if (IS_ENABLED(OF_CONTROL)) || (!IS_ENABLED(OF_PLATDATA)) + .set_parent = rk3576_clk_set_parent, +#endif +}; + +static void rk3576_clk_init(struct rk3576_clk_priv *priv) +{ + int ret; + + priv->spll_hz = 702000000; + + if (priv->cpll_hz != CPLL_HZ) { + ret = rockchip_pll_set_rate(&rk3576_pll_clks[CPLL], priv->cru, + CPLL, CPLL_HZ); + if (!ret) + priv->cpll_hz = CPLL_HZ; + } + if (priv->gpll_hz != GPLL_HZ) { + ret = rockchip_pll_set_rate(&rk3576_pll_clks[GPLL], priv->cru, + GPLL, GPLL_HZ); + if (!ret) + priv->gpll_hz = GPLL_HZ; + } + rk_clrsetreg(&priv->cru->clksel_con[123], + DCLK_EBC_FRAC_SRC_SEL_MASK, + (DCLK_EBC_FRAC_SRC_SEL_GPLL << + DCLK_EBC_FRAC_SRC_SEL_SHIFT)); +} + +static int rk3576_clk_probe(struct udevice *dev) +{ + struct rk3576_clk_priv *priv = dev_get_priv(dev); + int ret; + + priv->sync_kernel = false; + +#ifdef CONFIG_SPL_BUILD + /* relase presetn_bigcore_biu/cru/grf */ + writel(0x1c001c00, 0x26010010); + /* set spll to normal mode */ + writel(BITS_WITH_WMASK(2, 0x7U, 6), + RK3576_SCRU_BASE + RK3576_PLL_CON(137)); + writel(BITS_WITH_WMASK(1, 0x3U, 0), + RK3576_SCRU_BASE + RK3576_MODE_CON0); + /* fix ppll\aupll\cpll */ + writel(BITS_WITH_WMASK(2, 0x7U, 6), + RK3576_CRU_BASE + RK3576_PMU_PLL_CON(129)); + writel(BITS_WITH_WMASK(2, 0x7U, 6), + RK3576_CRU_BASE + RK3576_PLL_CON(97)); + writel(BITS_WITH_WMASK(2, 0x7U, 6), + RK3576_CRU_BASE + RK3576_PLL_CON(105)); + writel(BITS_WITH_WMASK(1, 0x3U, 6), + RK3576_CRU_BASE + RK3576_MODE_CON0); + writel(BITS_WITH_WMASK(1, 0x3U, 8), + RK3576_CRU_BASE + RK3576_MODE_CON0); + /* init cci */ + writel(0xffff0000, RK3576_CRU_BASE + RK3576_CCI_CLKSEL_CON(4)); + rockchip_pll_set_rate(&rk3576_pll_clks[BPLL], priv->cru, + BPLL, LPLL_HZ); + if (!priv->armclk_enter_hz) { + ret = rockchip_pll_set_rate(&rk3576_pll_clks[LPLL], priv->cru, + LPLL, LPLL_HZ); + priv->armclk_enter_hz = + rockchip_pll_get_rate(&rk3576_pll_clks[LPLL], + priv->cru, LPLL); + priv->armclk_init_hz = priv->armclk_enter_hz; + rk_clrsetreg(&priv->cru->litclksel_con[0], CLK_LITCORE_DIV_MASK, + 0 << CLK_LITCORE_DIV_SHIFT); + } + /* init cci */ + writel(0xffff20cb, RK3576_CRU_BASE + RK3576_CCI_CLKSEL_CON(4)); + + /* Change bigcore rm from 4 to 3 */ + writel(0x001c000c, RK3576_BIGCORE_GRF_BASE + 0x3c); + writel(0x001c000c, RK3576_BIGCORE_GRF_BASE + 0x44); + writel(0x00020002, RK3576_BIGCORE_GRF_BASE + 0x38); + udelay(1); + writel(0x00020000, RK3576_BIGCORE_GRF_BASE + 0x38); + /* Change litcore rm from 4 to 3 */ + writel(0x001c000c, RK3576_LITCORE_GRF_BASE + 0x3c); + writel(0x001c000c, RK3576_LITCORE_GRF_BASE + 0x44); + writel(0x00020002, RK3576_LITCORE_GRF_BASE + 0x38); + udelay(1); + writel(0x00020000, RK3576_LITCORE_GRF_BASE + 0x38); + /* Change cci rm form 4 to 3 */ + writel(0x001c000c, RK3576_CCI_GRF_BASE + 0x54); +#endif + + rk3576_clk_init(priv); + + /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ + ret = clk_set_defaults(dev, 1); + if (ret) + debug("%s clk_set_defaults failed %d\n", __func__, ret); + else + priv->sync_kernel = true; + + return 0; +} + +static int rk3576_clk_ofdata_to_platdata(struct udevice *dev) +{ + struct rk3576_clk_priv *priv = dev_get_priv(dev); + + priv->cru = dev_read_addr_ptr(dev); + + return 0; +} + +static int rk3576_clk_bind(struct udevice *dev) +{ + int ret; + struct udevice *sys_child; + struct sysreset_reg *priv; + + /* The reset driver does not have a device node, so bind it here */ + ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", + &sys_child); + if (ret) { + debug("Warning: No sysreset driver: ret=%d\n", ret); + } else { + priv = malloc(sizeof(struct sysreset_reg)); + priv->glb_srst_fst_value = offsetof(struct rk3576_cru, + glb_srst_fst); + priv->glb_srst_snd_value = offsetof(struct rk3576_cru, + glb_srsr_snd); + dev_set_priv(sys_child, priv); + } + +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP) + ret = offsetof(struct rk3576_cru, softrst_con[0]); + ret = rk3576_reset_bind_lut(dev, ret, 32776); + if (ret) + debug("Warning: software reset driver bind failed\n"); +#endif + + return 0; +} + +static const struct udevice_id rk3576_clk_ids[] = { + { .compatible = "rockchip,rk3576-cru" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3576_cru) = { + .name = "rockchip_rk3576_cru", + .id = UCLASS_CLK, + .of_match = rk3576_clk_ids, + .priv_auto = sizeof(struct rk3576_clk_priv), + .of_to_plat = rk3576_clk_ofdata_to_platdata, + .ops = &rk3576_clk_ops, + .bind = rk3576_clk_bind, + .probe = rk3576_clk_probe, +}; diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c index 2123c31038f..46820425a84 100644 --- a/drivers/misc/rockchip-otp.c +++ b/drivers/misc/rockchip-otp.c @@ -361,6 +361,13 @@ static const struct rockchip_otp_data rk3568_data = { .block_size = 2, }; +static const struct rockchip_otp_data rk3576_data = { + .read = rockchip_rk3588_otp_read, + .offset = 0x700, + .size = 0x100, + .block_size = 4, +}; + static const struct rockchip_otp_data rk3588_data = { .read = rockchip_rk3588_otp_read, .offset = 0xC00, @@ -384,10 +391,18 @@ static const struct udevice_id rockchip_otp_ids[] = { .data = (ulong)&px30_data, }, { + .compatible = "rockchip,rk3528-otp", + .data = (ulong)&rk3568_data, + }, + { .compatible = "rockchip,rk3568-otp", .data = (ulong)&rk3568_data, }, { + .compatible = "rockchip,rk3576-otp", + .data = (ulong)&rk3576_data, + }, + { .compatible = "rockchip,rk3588-otp", .data = (ulong)&rk3588_data, }, diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 422b8f7e4c8..7a72abaa38a 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -171,6 +171,7 @@ static int rockchip_dwmmc_bind(struct udevice *dev) static const struct udevice_id rockchip_dwmmc_ids[] = { { .compatible = "rockchip,rk2928-dw-mshc" }, { .compatible = "rockchip,rk3288-dw-mshc" }, + { .compatible = "rockchip,rk3576-dw-mshc" }, { } }; diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index da630b9d97a..761e3619329 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -50,6 +50,10 @@ #define DWCMSHC_EMMC_EMMC_CTRL 0x52c #define DWCMSHC_CARD_IS_EMMC BIT(0) #define DWCMSHC_ENHANCED_STROBE BIT(8) +#define DWCMSHC_EMMC_AT_CTRL 0x540 +#define EMMC_AT_CTRL_TUNE_CLK_STOP_EN BIT(16) +#define EMMC_AT_CTRL_PRE_CHANGE_DLY 17 +#define EMMC_AT_CTRL_POST_CHANGE_DLY 19 #define DWCMSHC_EMMC_DLL_CTRL 0x800 #define DWCMSHC_EMMC_DLL_CTRL_RESET BIT(1) #define DWCMSHC_EMMC_DLL_RXCLK 0x804 @@ -156,6 +160,9 @@ struct sdhci_data { u32 flags; u8 hs200_txclk_tapnum; u8 hs400_txclk_tapnum; + u8 hs400_cmdout_tapnum; + u8 hs400_strbin_tapnum; + u8 ddr50_strbin_delay_num; }; static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock) @@ -323,6 +330,11 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab udelay(1); sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); + extra = 0x3 << EMMC_AT_CTRL_POST_CHANGE_DLY | + 0x3 << EMMC_AT_CTRL_PRE_CHANGE_DLY | + EMMC_AT_CTRL_TUNE_CLK_STOP_EN; + sdhci_writel(host, extra, DWCMSHC_EMMC_AT_CTRL); + /* Init DLL settings */ extra = DWCMSHC_EMMC_DLL_START_DEFAULT << DWCMSHC_EMMC_DLL_START_POINT | DWCMSHC_EMMC_DLL_INC_VALUE << DWCMSHC_EMMC_DLL_INC | @@ -348,7 +360,7 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab extra = DLL_CMDOUT_SRC_CLK_NEG | DLL_CMDOUT_BOTH_CLK_EDGE | DWCMSHC_EMMC_DLL_DLYENA | - DLL_CMDOUT_TAPNUM_90_DEGREES | + data->hs400_cmdout_tapnum | DLL_CMDOUT_TAPNUM_FROM_SW; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CMDOUT); } @@ -360,7 +372,7 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); extra = DWCMSHC_EMMC_DLL_DLYENA | - DLL_STRBIN_TAPNUM_DEFAULT | + data->hs400_strbin_tapnum | DLL_STRBIN_TAPNUM_FROM_SW; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); } else { @@ -380,7 +392,7 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab */ extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_STRBIN_DELAY_NUM_SEL | - DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET; + data->ddr50_strbin_delay_num << DLL_STRBIN_DELAY_NUM_OFFSET; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); } @@ -647,6 +659,17 @@ static const struct sdhci_data rk3399_data = { .set_enhanced_strobe = rk3399_sdhci_set_enhanced_strobe, }; +static const struct sdhci_data rk3528_data = { + .set_ios_post = rk3568_sdhci_set_ios_post, + .set_clock = rk3568_sdhci_set_clock, + .config_dll = rk3568_sdhci_config_dll, + .hs200_txclk_tapnum = 0xc, + .hs400_txclk_tapnum = 0x6, + .hs400_cmdout_tapnum = 0x6, + .hs400_strbin_tapnum = 0x3, + .ddr50_strbin_delay_num = 0xa, +}; + static const struct sdhci_data rk3568_data = { .set_ios_post = rk3568_sdhci_set_ios_post, .set_clock = rk3568_sdhci_set_clock, @@ -654,6 +677,20 @@ static const struct sdhci_data rk3568_data = { .flags = FLAG_INVERTER_FLAG_IN_RXCLK, .hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, .hs400_txclk_tapnum = 0x8, + .hs400_cmdout_tapnum = DLL_CMDOUT_TAPNUM_90_DEGREES, + .hs400_strbin_tapnum = DLL_STRBIN_TAPNUM_DEFAULT, + .ddr50_strbin_delay_num = DLL_STRBIN_DELAY_NUM_DEFAULT, +}; + +static const struct sdhci_data rk3576_data = { + .set_ios_post = rk3568_sdhci_set_ios_post, + .set_clock = rk3568_sdhci_set_clock, + .config_dll = rk3568_sdhci_config_dll, + .hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, + .hs400_txclk_tapnum = 0x7, + .hs400_cmdout_tapnum = 0x7, + .hs400_strbin_tapnum = 0x5, + .ddr50_strbin_delay_num = 0xa, }; static const struct sdhci_data rk3588_data = { @@ -662,6 +699,9 @@ static const struct sdhci_data rk3588_data = { .config_dll = rk3568_sdhci_config_dll, .hs200_txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, .hs400_txclk_tapnum = 0x9, + .hs400_cmdout_tapnum = DLL_CMDOUT_TAPNUM_90_DEGREES, + .hs400_strbin_tapnum = DLL_STRBIN_TAPNUM_DEFAULT, + .ddr50_strbin_delay_num = DLL_STRBIN_DELAY_NUM_DEFAULT, }; static const struct udevice_id sdhci_ids[] = { @@ -670,10 +710,18 @@ static const struct udevice_id sdhci_ids[] = { .data = (ulong)&rk3399_data, }, { + .compatible = "rockchip,rk3528-dwcmshc", + .data = (ulong)&rk3528_data, + }, + { .compatible = "rockchip,rk3568-dwcmshc", .data = (ulong)&rk3568_data, }, { + .compatible = "rockchip,rk3576-dwcmshc", + .data = (ulong)&rk3576_data, + }, + { .compatible = "rockchip,rk3588-dwcmshc", .data = (ulong)&rk3588_data, }, diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index b4ec3614696..b1bc422f791 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1612,10 +1612,18 @@ static const struct udevice_id eqos_ids[] = { #endif #if IS_ENABLED(CONFIG_DWC_ETH_QOS_ROCKCHIP) { + .compatible = "rockchip,rk3528-gmac", + .data = (ulong)&eqos_rockchip_config + }, + { .compatible = "rockchip,rk3568-gmac", .data = (ulong)&eqos_rockchip_config }, { + .compatible = "rockchip,rk3576-gmac", + .data = (ulong)&eqos_rockchip_config + }, + { .compatible = "rockchip,rk3588-gmac", .data = (ulong)&eqos_rockchip_config }, diff --git a/drivers/net/dwc_eth_qos_rockchip.c b/drivers/net/dwc_eth_qos_rockchip.c index f3a0f63003e..d646d3ebac8 100644 --- a/drivers/net/dwc_eth_qos_rockchip.c +++ b/drivers/net/dwc_eth_qos_rockchip.c @@ -50,6 +50,132 @@ struct rockchip_platform_data { (((tx) ? soc##_GMAC_TXCLK_DLY_ENABLE : soc##_GMAC_TXCLK_DLY_DISABLE) | \ ((rx) ? soc##_GMAC_RXCLK_DLY_ENABLE : soc##_GMAC_RXCLK_DLY_DISABLE)) +#define RK3528_VO_GRF_GMAC_CON 0x0018 +#define RK3528_VPU_GRF_GMAC_CON5 0x0018 +#define RK3528_VPU_GRF_GMAC_CON6 0x001c + +#define RK3528_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) +#define RK3528_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) +#define RK3528_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14) +#define RK3528_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) + +#define RK3528_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8) +#define RK3528_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0) + +#define RK3528_GMAC0_PHY_INTF_SEL_RMII GRF_BIT(1) +#define RK3528_GMAC1_PHY_INTF_SEL_RGMII GRF_CLR_BIT(8) +#define RK3528_GMAC1_PHY_INTF_SEL_RMII GRF_BIT(8) + +#define RK3528_GMAC1_CLK_SELECT_CRU GRF_CLR_BIT(12) +#define RK3528_GMAC1_CLK_SELECT_IO GRF_BIT(12) + +#define RK3528_GMAC0_CLK_RMII_DIV2 GRF_BIT(3) +#define RK3528_GMAC0_CLK_RMII_DIV20 GRF_CLR_BIT(3) +#define RK3528_GMAC1_CLK_RMII_DIV2 GRF_BIT(10) +#define RK3528_GMAC1_CLK_RMII_DIV20 GRF_CLR_BIT(10) + +#define RK3528_GMAC1_CLK_RGMII_DIV1 (GRF_CLR_BIT(11) | GRF_CLR_BIT(10)) +#define RK3528_GMAC1_CLK_RGMII_DIV5 (GRF_BIT(11) | GRF_BIT(10)) +#define RK3528_GMAC1_CLK_RGMII_DIV50 (GRF_BIT(11) | GRF_CLR_BIT(10)) + +#define RK3528_GMAC0_CLK_RMII_GATE GRF_BIT(2) +#define RK3528_GMAC0_CLK_RMII_NOGATE GRF_CLR_BIT(2) +#define RK3528_GMAC1_CLK_RMII_GATE GRF_BIT(9) +#define RK3528_GMAC1_CLK_RMII_NOGATE GRF_CLR_BIT(9) + +static int rk3528_set_to_rgmii(struct udevice *dev, + int tx_delay, int rx_delay) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + + regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON5, + RK3528_GMAC1_PHY_INTF_SEL_RGMII); + + regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON5, + DELAY_ENABLE(RK3528, tx_delay, rx_delay)); + + regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON6, + RK3528_GMAC_CLK_RX_DL_CFG(rx_delay) | + RK3528_GMAC_CLK_TX_DL_CFG(tx_delay)); + + return 0; +} + +static int rk3528_set_to_rmii(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + + if (data->id == 1) + regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON5, + RK3528_GMAC1_PHY_INTF_SEL_RMII); + else + regmap_write(data->grf, RK3528_VO_GRF_GMAC_CON, + RK3528_GMAC0_PHY_INTF_SEL_RMII | + RK3528_GMAC0_CLK_RMII_DIV2); + + return 0; +} + +static int rk3528_set_gmac_speed(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + u32 val, reg; + + switch (eqos->phy->speed) { + case SPEED_10: + if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII) + val = data->id == 1 ? RK3528_GMAC1_CLK_RMII_DIV20 : + RK3528_GMAC0_CLK_RMII_DIV20; + else + val = RK3528_GMAC1_CLK_RGMII_DIV50; + break; + case SPEED_100: + if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII) + val = data->id == 1 ? RK3528_GMAC1_CLK_RMII_DIV2 : + RK3528_GMAC0_CLK_RMII_DIV2; + else + val = RK3528_GMAC1_CLK_RGMII_DIV5; + break; + case SPEED_1000: + if (pdata->phy_interface != PHY_INTERFACE_MODE_RMII) + val = RK3528_GMAC1_CLK_RGMII_DIV1; + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + reg = data->id == 1 ? RK3528_VPU_GRF_GMAC_CON5 : + RK3528_VO_GRF_GMAC_CON; + regmap_write(data->grf, reg, val); + + return 0; +} + +static void rk3528_set_clock_selection(struct udevice *dev, bool enable) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + u32 val; + + if (data->id == 1) { + val = data->clock_input ? RK3528_GMAC1_CLK_SELECT_IO : + RK3528_GMAC1_CLK_SELECT_CRU; + val |= enable ? RK3528_GMAC1_CLK_RMII_NOGATE : + RK3528_GMAC1_CLK_RMII_GATE; + regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON5, val); + } else { + val = enable ? RK3528_GMAC0_CLK_RMII_NOGATE : + RK3528_GMAC0_CLK_RMII_GATE; + regmap_write(data->grf, RK3528_VO_GRF_GMAC_CON, val); + } +} + #define RK3568_GRF_GMAC0_CON0 0x0380 #define RK3568_GRF_GMAC0_CON1 0x0384 #define RK3568_GRF_GMAC1_CON0 0x0388 @@ -134,6 +260,145 @@ static int rk3568_set_gmac_speed(struct udevice *dev) return 0; } +/* VCCIO0_1_3_IOC */ +#define RK3576_VCCIO0_1_3_IOC_CON2 0x6408 +#define RK3576_VCCIO0_1_3_IOC_CON3 0x640c +#define RK3576_VCCIO0_1_3_IOC_CON4 0x6410 +#define RK3576_VCCIO0_1_3_IOC_CON5 0x6414 + +#define RK3576_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) +#define RK3576_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) +#define RK3576_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7) +#define RK3576_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7) + +#define RK3576_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) +#define RK3576_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) + +/* SDGMAC_GRF */ +#define RK3576_GRF_GMAC_CON0 0x0020 +#define RK3576_GRF_GMAC_CON1 0x0024 + +#define RK3576_GMAC_RMII_MODE GRF_BIT(3) +#define RK3576_GMAC_RGMII_MODE GRF_CLR_BIT(3) + +#define RK3576_GMAC_CLK_SELECT_IO GRF_BIT(7) +#define RK3576_GMAC_CLK_SELECT_CRU GRF_CLR_BIT(7) + +#define RK3576_GMAC_CLK_RMII_DIV2 GRF_BIT(5) +#define RK3576_GMAC_CLK_RMII_DIV20 GRF_CLR_BIT(5) + +#define RK3576_GMAC_CLK_RGMII_DIV1 \ + (GRF_CLR_BIT(6) | GRF_CLR_BIT(5)) +#define RK3576_GMAC_CLK_RGMII_DIV5 \ + (GRF_BIT(6) | GRF_BIT(5)) +#define RK3576_GMAC_CLK_RGMII_DIV50 \ + (GRF_BIT(6) | GRF_CLR_BIT(5)) + +#define RK3576_GMAC_CLK_RMII_GATE GRF_BIT(4) +#define RK3576_GMAC_CLK_RMII_NOGATE GRF_CLR_BIT(4) + +static int rk3576_set_to_rgmii(struct udevice *dev, + int tx_delay, int rx_delay) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + u32 offset_con; + + offset_con = data->id == 1 ? RK3576_GRF_GMAC_CON1 : + RK3576_GRF_GMAC_CON0; + + regmap_write(data->grf, offset_con, RK3576_GMAC_RGMII_MODE); + + offset_con = data->id == 1 ? RK3576_VCCIO0_1_3_IOC_CON4 : + RK3576_VCCIO0_1_3_IOC_CON2; + + /* m0 && m1 delay enabled */ + regmap_write(data->php_grf, offset_con, + DELAY_ENABLE(RK3576, tx_delay, rx_delay)); + regmap_write(data->php_grf, offset_con + 0x4, + DELAY_ENABLE(RK3576, tx_delay, rx_delay)); + + /* m0 && m1 delay value */ + regmap_write(data->php_grf, offset_con, + RK3576_GMAC_CLK_TX_DL_CFG(tx_delay) | + RK3576_GMAC_CLK_RX_DL_CFG(rx_delay)); + regmap_write(data->php_grf, offset_con + 0x4, + RK3576_GMAC_CLK_TX_DL_CFG(tx_delay) | + RK3576_GMAC_CLK_RX_DL_CFG(rx_delay)); + + return 0; +} + +static int rk3576_set_to_rmii(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + u32 offset_con; + + offset_con = data->id == 1 ? RK3576_GRF_GMAC_CON1 : + RK3576_GRF_GMAC_CON0; + + regmap_write(data->grf, offset_con, RK3576_GMAC_RMII_MODE); + + return 0; +} + +static int rk3576_set_gmac_speed(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + u32 val = 0, offset_con; + + switch (eqos->phy->speed) { + case SPEED_10: + if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII) + val = RK3576_GMAC_CLK_RMII_DIV20; + else + val = RK3576_GMAC_CLK_RGMII_DIV50; + break; + case SPEED_100: + if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII) + val = RK3576_GMAC_CLK_RMII_DIV2; + else + val = RK3576_GMAC_CLK_RGMII_DIV5; + break; + case SPEED_1000: + if (pdata->phy_interface != PHY_INTERFACE_MODE_RMII) + val = RK3576_GMAC_CLK_RGMII_DIV1; + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + offset_con = data->id == 1 ? RK3576_GRF_GMAC_CON1 : + RK3576_GRF_GMAC_CON0; + + regmap_write(data->grf, offset_con, val); + + return 0; +} + +static void rk3576_set_clock_selection(struct udevice *dev, bool enable) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + + u32 val = data->clock_input ? RK3576_GMAC_CLK_SELECT_IO : + RK3576_GMAC_CLK_SELECT_CRU; + u32 offset_con; + + val |= enable ? RK3576_GMAC_CLK_RMII_NOGATE : + RK3576_GMAC_CLK_RMII_GATE; + + offset_con = data->id == 1 ? RK3576_GRF_GMAC_CON1 : + RK3576_GRF_GMAC_CON0; + + regmap_write(data->grf, offset_con, val); +} + #define RK3588_DELAY_ENABLE(id, tx, rx) \ (((tx) ? RK3588_GMAC_TXCLK_DLY_ENABLE(id) : RK3588_GMAC_TXCLK_DLY_DISABLE(id)) | \ ((rx) ? RK3588_GMAC_RXCLK_DLY_ENABLE(id) : RK3588_GMAC_RXCLK_DLY_DISABLE(id))) @@ -270,6 +535,18 @@ static void rk3588_set_clock_selection(struct udevice *dev, bool enable) static const struct rk_gmac_ops rk_gmac_ops[] = { { + .compatible = "rockchip,rk3528-gmac", + .set_to_rgmii = rk3528_set_to_rgmii, + .set_to_rmii = rk3528_set_to_rmii, + .set_gmac_speed = rk3528_set_gmac_speed, + .set_clock_selection = rk3528_set_clock_selection, + .regs = { + 0xffbd0000, /* gmac0 */ + 0xffbe0000, /* gmac1 */ + 0x0, /* sentinel */ + }, + }, + { .compatible = "rockchip,rk3568-gmac", .set_to_rgmii = rk3568_set_to_rgmii, .set_to_rmii = rk3568_set_to_rmii, @@ -281,6 +558,18 @@ static const struct rk_gmac_ops rk_gmac_ops[] = { }, }, { + .compatible = "rockchip,rk3576-gmac", + .set_to_rgmii = rk3576_set_to_rgmii, + .set_to_rmii = rk3576_set_to_rmii, + .set_gmac_speed = rk3576_set_gmac_speed, + .set_clock_selection = rk3576_set_clock_selection, + .regs = { + 0x2a220000, /* gmac0 */ + 0x2a230000, /* gmac1 */ + 0x0, /* sentinel */ + }, + }, + { .compatible = "rockchip,rk3588-gmac", .set_to_rgmii = rk3588_set_to_rgmii, .set_to_rmii = rk3588_set_to_rmii, @@ -357,7 +646,8 @@ static int eqos_probe_resources_rk(struct udevice *dev) goto err_free; } - if (device_is_compatible(dev, "rockchip,rk3588-gmac")) { + if (device_is_compatible(dev, "rockchip,rk3588-gmac") || + device_is_compatible(dev, "rockchip,rk3576-gmac")) { data->php_grf = syscon_regmap_lookup_by_phandle(dev, "rockchip,php-grf"); if (IS_ERR(data->php_grf)) { diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 43f6e020a6a..88b33de1b2a 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -40,11 +40,13 @@ struct rockchip_usb2phy_port_cfg { struct rockchip_usb2phy_cfg { unsigned int reg; struct usb2phy_reg clkout_ctl; + struct usb2phy_reg clkout_ctl_phy; const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS]; }; struct rockchip_usb2phy { struct regmap *reg_base; + struct regmap *phy_base; struct clk phyclk; const struct rockchip_usb2phy_cfg *phy_cfg; }; @@ -165,6 +167,22 @@ static struct phy_ops rockchip_usb2phy_ops = { .of_xlate = rockchip_usb2phy_of_xlate, }; +static void rockchip_usb2phy_clkout_ctl(struct clk *clk, struct regmap **base, + const struct usb2phy_reg **clkout_ctl) +{ + struct udevice *parent = dev_get_parent(clk->dev); + struct rockchip_usb2phy *priv = dev_get_priv(parent); + const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg; + + if (priv->phy_cfg->clkout_ctl_phy.enable) { + *base = priv->phy_base; + *clkout_ctl = &phy_cfg->clkout_ctl_phy; + } else { + *base = priv->reg_base; + *clkout_ctl = &phy_cfg->clkout_ctl; + } +} + /** * round_rate() - Adjust a rate to the exact rate a clock can provide. * @clk: The clock to manipulate. @@ -185,13 +203,14 @@ ulong rockchip_usb2phy_clk_round_rate(struct clk *clk, ulong rate) */ int rockchip_usb2phy_clk_enable(struct clk *clk) { - struct udevice *parent = dev_get_parent(clk->dev); - struct rockchip_usb2phy *priv = dev_get_priv(parent); - const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg; + const struct usb2phy_reg *clkout_ctl; + struct regmap *base; + + rockchip_usb2phy_clkout_ctl(clk, &base, &clkout_ctl); /* turn on 480m clk output if it is off */ - if (!property_enabled(priv->reg_base, &phy_cfg->clkout_ctl)) { - property_enable(priv->reg_base, &phy_cfg->clkout_ctl, true); + if (!property_enabled(base, clkout_ctl)) { + property_enable(base, clkout_ctl, true); /* waiting for the clk become stable */ usleep_range(1200, 1300); @@ -208,12 +227,13 @@ int rockchip_usb2phy_clk_enable(struct clk *clk) */ int rockchip_usb2phy_clk_disable(struct clk *clk) { - struct udevice *parent = dev_get_parent(clk->dev); - struct rockchip_usb2phy *priv = dev_get_priv(parent); - const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg; + const struct usb2phy_reg *clkout_ctl; + struct regmap *base; + + rockchip_usb2phy_clkout_ctl(clk, &base, &clkout_ctl); /* turn off 480m clk output */ - property_enable(priv->reg_base, &phy_cfg->clkout_ctl, false); + property_enable(base, clkout_ctl, false); return 0; } @@ -281,7 +301,10 @@ static int rockchip_usb2phy_probe(struct udevice *dev) return ret; } - return 0; + if (priv->phy_cfg->clkout_ctl_phy.enable) + ret = regmap_init_mem_index(dev_ofnode(dev), &priv->phy_base, 0); + + return ret; } static int rockchip_usb2phy_bind(struct udevice *dev) @@ -389,6 +412,22 @@ static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = { { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3528_phy_cfgs[] = { + { + .reg = 0xffdf0000, + .clkout_ctl_phy = { 0x041c, 7, 2, 0, 0x27 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x004c, 1, 0, 2, 1 }, + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x005c, 1, 0, 2, 1 }, + } + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { { .reg = 0xfe8a0000, @@ -471,6 +510,10 @@ static const struct udevice_id rockchip_usb2phy_ids[] = { .data = (ulong)&rk3399_usb2phy_cfgs, }, { + .compatible = "rockchip,rk3528-usb2phy", + .data = (ulong)&rk3528_phy_cfgs, + }, + { .compatible = "rockchip,rk3568-usb2phy", .data = (ulong)&rk3568_phy_cfgs, }, diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile index c91f650b043..e17415e1ca6 100644 --- a/drivers/pinctrl/rockchip/Makefile +++ b/drivers/pinctrl/rockchip/Makefile @@ -14,7 +14,9 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += pinctrl-rk3308.o obj-$(CONFIG_ROCKCHIP_RK3328) += pinctrl-rk3328.o obj-$(CONFIG_ROCKCHIP_RK3368) += pinctrl-rk3368.o obj-$(CONFIG_ROCKCHIP_RK3399) += pinctrl-rk3399.o +obj-$(CONFIG_ROCKCHIP_RK3528) += pinctrl-rk3528.o obj-$(CONFIG_ROCKCHIP_RK3568) += pinctrl-rk3568.o +obj-$(CONFIG_ROCKCHIP_RK3576) += pinctrl-rk3576.o obj-$(CONFIG_ROCKCHIP_RK3588) += pinctrl-rk3588.o obj-$(CONFIG_ROCKCHIP_RV1108) += pinctrl-rv1108.o obj-$(CONFIG_ROCKCHIP_RV1126) += pinctrl-rv1126.o diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3528.c b/drivers/pinctrl/rockchip/pinctrl-rk3528.c new file mode 100644 index 00000000000..a3e1f0b2c9d --- /dev/null +++ b/drivers/pinctrl/rockchip/pinctrl-rk3528.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + */ + +#include <dm.h> +#include <dm/pinctrl.h> +#include <regmap.h> +#include <syscon.h> + +#include "pinctrl-rockchip.h" +#include <dt-bindings/pinctrl/rockchip.h> + +static int rk3528_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + int iomux_num = (pin / 8); + struct regmap *regmap; + int reg, mask; + u8 bit; + u32 data, rmask; + + regmap = priv->regmap_base; + reg = bank->iomux[iomux_num].offset; + if ((pin % 8) >= 4) + reg += 0x4; + bit = (pin % 4) * 4; + mask = 0xf; + + data = (mask << (bit + 16)); + rmask = data | (data >> 16); + data |= (mux & mask) << bit; + + return regmap_update_bits(regmap, reg, rmask, data); +} + +#define RK3528_DRV_BITS_PER_PIN 8 +#define RK3528_DRV_PINS_PER_REG 2 +#define RK3528_DRV_GPIO0_OFFSET 0x100 +#define RK3528_DRV_GPIO1_OFFSET 0x20120 +#define RK3528_DRV_GPIO2_OFFSET 0x30160 +#define RK3528_DRV_GPIO3_OFFSET 0x20190 +#define RK3528_DRV_GPIO4_OFFSET 0x101C0 + +static void rk3528_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + + *regmap = priv->regmap_base; + + if (bank->bank_num == 0) { + *reg = RK3528_DRV_GPIO0_OFFSET; + } else if (bank->bank_num == 1) { + *reg = RK3528_DRV_GPIO1_OFFSET; + } else if (bank->bank_num == 2) { + *reg = RK3528_DRV_GPIO2_OFFSET; + } else if (bank->bank_num == 3) { + *reg = RK3528_DRV_GPIO3_OFFSET; + } else if (bank->bank_num == 4) { + *reg = RK3528_DRV_GPIO4_OFFSET; + } else { + *reg = 0; + debug("unsupported bank_num %d\n", bank->bank_num); + } + + *reg += ((pin_num / RK3528_DRV_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_DRV_PINS_PER_REG; + *bit *= RK3528_DRV_BITS_PER_PIN; +} + +static int rk3528_set_drive(struct rockchip_pin_bank *bank, + int pin_num, int strength) +{ + struct regmap *regmap; + int reg; + u32 data, rmask; + u8 bit; + int drv = (1 << (strength + 1)) - 1; + + rk3528_calc_drv_reg_and_bit(bank, pin_num, ®map, ®, &bit); + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3528_DRV_BITS_PER_PIN) - 1) << (bit + 16); + rmask = data | (data >> 16); + data |= (drv << bit); + + return regmap_update_bits(regmap, reg, rmask, data); +} + +#define RK3528_PULL_BITS_PER_PIN 2 +#define RK3528_PULL_PINS_PER_REG 8 +#define RK3528_PULL_GPIO0_OFFSET 0x200 +#define RK3528_PULL_GPIO1_OFFSET 0x20210 +#define RK3528_PULL_GPIO2_OFFSET 0x30220 +#define RK3528_PULL_GPIO3_OFFSET 0x20230 +#define RK3528_PULL_GPIO4_OFFSET 0x10240 + +static void rk3528_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + + *regmap = priv->regmap_base; + + if (bank->bank_num == 0) { + *reg = RK3528_PULL_GPIO0_OFFSET; + } else if (bank->bank_num == 1) { + *reg = RK3528_PULL_GPIO1_OFFSET; + } else if (bank->bank_num == 2) { + *reg = RK3528_PULL_GPIO2_OFFSET; + } else if (bank->bank_num == 3) { + *reg = RK3528_PULL_GPIO3_OFFSET; + } else if (bank->bank_num == 4) { + *reg = RK3528_PULL_GPIO4_OFFSET; + } else { + *reg = 0; + debug("unsupported bank_num %d\n", bank->bank_num); + } + + *reg += ((pin_num / RK3528_PULL_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_PULL_PINS_PER_REG; + *bit *= RK3528_PULL_BITS_PER_PIN; +} + +static int rk3528_set_pull(struct rockchip_pin_bank *bank, + int pin_num, int pull) +{ + struct regmap *regmap; + int reg, ret; + u8 bit, type; + u32 data, rmask; + + if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) + return -EOPNOTSUPP; + + rk3528_calc_pull_reg_and_bit(bank, pin_num, ®map, ®, &bit); + type = bank->pull_type[pin_num / 8]; + ret = rockchip_translate_pull_value(type, pull); + if (ret < 0) { + debug("unsupported pull setting %d\n", pull); + return ret; + } + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3528_PULL_BITS_PER_PIN) - 1) << (bit + 16); + rmask = data | (data >> 16); + data |= (ret << bit); + + return regmap_update_bits(regmap, reg, rmask, data); +} + +#define RK3528_SMT_BITS_PER_PIN 1 +#define RK3528_SMT_PINS_PER_REG 8 +#define RK3528_SMT_GPIO0_OFFSET 0x400 +#define RK3528_SMT_GPIO1_OFFSET 0x20410 +#define RK3528_SMT_GPIO2_OFFSET 0x30420 +#define RK3528_SMT_GPIO3_OFFSET 0x20430 +#define RK3528_SMT_GPIO4_OFFSET 0x10440 + +static int rk3528_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, + struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + + *regmap = priv->regmap_base; + + if (bank->bank_num == 0) { + *reg = RK3528_SMT_GPIO0_OFFSET; + } else if (bank->bank_num == 1) { + *reg = RK3528_SMT_GPIO1_OFFSET; + } else if (bank->bank_num == 2) { + *reg = RK3528_SMT_GPIO2_OFFSET; + } else if (bank->bank_num == 3) { + *reg = RK3528_SMT_GPIO3_OFFSET; + } else if (bank->bank_num == 4) { + *reg = RK3528_SMT_GPIO4_OFFSET; + } else { + *reg = 0; + debug("unsupported bank_num %d\n", bank->bank_num); + } + + *reg += ((pin_num / RK3528_SMT_PINS_PER_REG) * 4); + *bit = pin_num % RK3528_SMT_PINS_PER_REG; + *bit *= RK3528_SMT_BITS_PER_PIN; + + return 0; +} + +static int rk3528_set_schmitt(struct rockchip_pin_bank *bank, + int pin_num, int enable) +{ + struct regmap *regmap; + int reg; + u32 data, rmask; + u8 bit; + + rk3528_calc_schmitt_reg_and_bit(bank, pin_num, ®map, ®, &bit); + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3528_SMT_BITS_PER_PIN) - 1) << (bit + 16); + rmask = data | (data >> 16); + data |= (enable << bit); + + return regmap_update_bits(regmap, reg, rmask, data); +} + +static struct rockchip_pin_bank rk3528_pin_banks[] = { + PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0, 0, 0, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(1, 32, "gpio1", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x20020, 0x20028, 0x20030, 0x20038), + PIN_BANK_IOMUX_FLAGS_OFFSET(2, 32, "gpio2", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x30040, 0, 0, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(3, 32, "gpio3", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x20060, 0x20068, 0x20070, 0), + PIN_BANK_IOMUX_FLAGS_OFFSET(4, 32, "gpio4", + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + IOMUX_WIDTH_4BIT, + 0x10080, 0x10088, 0x10090, 0x10098), +}; + +static const struct rockchip_pin_ctrl rk3528_pin_ctrl = { + .pin_banks = rk3528_pin_banks, + .nr_banks = ARRAY_SIZE(rk3528_pin_banks), + .grf_mux_offset = 0x0, + .set_mux = rk3528_set_mux, + .set_pull = rk3528_set_pull, + .set_drive = rk3528_set_drive, + .set_schmitt = rk3528_set_schmitt, +}; + +static const struct udevice_id rk3528_pinctrl_ids[] = { + { + .compatible = "rockchip,rk3528-pinctrl", + .data = (ulong)&rk3528_pin_ctrl + }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3528_pinctrl) = { + .name = "rockchip_rk3528_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = rk3528_pinctrl_ids, + .priv_auto = sizeof(struct rockchip_pinctrl_priv), + .ops = &rockchip_pinctrl_ops, +#if CONFIG_IS_ENABLED(OF_REAL) + .bind = dm_scan_fdt_dev, +#endif + .probe = rockchip_pinctrl_probe, +}; diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3576.c b/drivers/pinctrl/rockchip/pinctrl-rk3576.c new file mode 100644 index 00000000000..66e1142ac1f --- /dev/null +++ b/drivers/pinctrl/rockchip/pinctrl-rk3576.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2024 Rockchip Electronics Co., Ltd + */ + +#include <dm.h> +#include <dm/pinctrl.h> +#include <regmap.h> +#include <syscon.h> + +#include "pinctrl-rockchip.h" +#include <dt-bindings/pinctrl/rockchip.h> + +static int rk3576_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + int iomux_num = (pin / 8); + struct regmap *regmap; + int reg, mask; + u8 bit; + u32 data, rmask; + + regmap = priv->regmap_base; + reg = bank->iomux[iomux_num].offset; + if ((pin % 8) >= 4) + reg += 0x4; + bit = (pin % 4) * 4; + mask = 0xf; + + data = (mask << (bit + 16)); + rmask = data | (data >> 16); + data |= (mux & mask) << bit; + + if (bank->bank_num == 0 && pin >= RK_PB4 && pin <= RK_PB7) + reg += 0x1FF4; /* GPIO0_IOC_GPIO0B_IOMUX_SEL_H */ + + return regmap_update_bits(regmap, reg, rmask, data); +} + +#define RK3576_DRV_BITS_PER_PIN 4 +#define RK3576_DRV_PINS_PER_REG 4 +#define RK3576_DRV_GPIO0_AL_OFFSET 0x10 +#define RK3576_DRV_GPIO0_BH_OFFSET 0x2014 +#define RK3576_DRV_GPIO1_OFFSET 0x6020 +#define RK3576_DRV_GPIO2_OFFSET 0x6040 +#define RK3576_DRV_GPIO3_OFFSET 0x6060 +#define RK3576_DRV_GPIO4_AL_OFFSET 0x6080 +#define RK3576_DRV_GPIO4_CL_OFFSET 0xA090 +#define RK3576_DRV_GPIO4_DL_OFFSET 0xB098 + +static void rk3576_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + + *regmap = priv->regmap_base; + if (bank->bank_num == 0 && pin_num < 12) { + *reg = RK3576_DRV_GPIO0_AL_OFFSET; + } else if (bank->bank_num == 0) { + *reg = RK3576_DRV_GPIO0_BH_OFFSET - 0xc; + } else if (bank->bank_num == 1) { + *reg = RK3576_DRV_GPIO1_OFFSET; + } else if (bank->bank_num == 2) { + *reg = RK3576_DRV_GPIO2_OFFSET; + } else if (bank->bank_num == 3) { + *reg = RK3576_DRV_GPIO3_OFFSET; + } else if (bank->bank_num == 4 && pin_num < 16) { + *reg = RK3576_DRV_GPIO4_AL_OFFSET; + } else if (bank->bank_num == 4 && pin_num < 24) { + *reg = RK3576_DRV_GPIO4_CL_OFFSET - 0x10; + } else if (bank->bank_num == 4) { + *reg = RK3576_DRV_GPIO4_DL_OFFSET - 0x18; + } else { + *reg = 0; + debug("unsupported bank_num %d\n", bank->bank_num); + } + + *reg += ((pin_num / RK3576_DRV_PINS_PER_REG) * 4); + *bit = pin_num % RK3576_DRV_PINS_PER_REG; + *bit *= RK3576_DRV_BITS_PER_PIN; +} + +static int rk3576_set_drive(struct rockchip_pin_bank *bank, + int pin_num, int strength) +{ + struct regmap *regmap; + int reg; + u32 data, rmask; + u8 bit; + int drv = ((strength & BIT(2)) >> 2) | ((strength & BIT(0)) << 2) | (strength & BIT(1)); + + rk3576_calc_drv_reg_and_bit(bank, pin_num, ®map, ®, &bit); + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3576_DRV_BITS_PER_PIN) - 1) << (bit + 16); + rmask = data | (data >> 16); + data |= (drv << bit); + + return regmap_update_bits(regmap, reg, rmask, data); +} + +#define RK3576_PULL_BITS_PER_PIN 2 +#define RK3576_PULL_PINS_PER_REG 8 +#define RK3576_PULL_GPIO0_AL_OFFSET 0x20 +#define RK3576_PULL_GPIO0_BH_OFFSET 0x2028 +#define RK3576_PULL_GPIO1_OFFSET 0x6110 +#define RK3576_PULL_GPIO2_OFFSET 0x6120 +#define RK3576_PULL_GPIO3_OFFSET 0x6130 +#define RK3576_PULL_GPIO4_AL_OFFSET 0x6140 +#define RK3576_PULL_GPIO4_CL_OFFSET 0xA148 +#define RK3576_PULL_GPIO4_DL_OFFSET 0xB14C + +static void rk3576_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + + *regmap = priv->regmap_base; + if (bank->bank_num == 0 && pin_num < 12) { + *reg = RK3576_PULL_GPIO0_AL_OFFSET; + } else if (bank->bank_num == 0) { + *reg = RK3576_PULL_GPIO0_BH_OFFSET - 0x4; + } else if (bank->bank_num == 1) { + *reg = RK3576_PULL_GPIO1_OFFSET; + } else if (bank->bank_num == 2) { + *reg = RK3576_PULL_GPIO2_OFFSET; + } else if (bank->bank_num == 3) { + *reg = RK3576_PULL_GPIO3_OFFSET; + } else if (bank->bank_num == 4 && pin_num < 16) { + *reg = RK3576_PULL_GPIO4_AL_OFFSET; + } else if (bank->bank_num == 4 && pin_num < 24) { + *reg = RK3576_PULL_GPIO4_CL_OFFSET - 0x8; + } else if (bank->bank_num == 4) { + *reg = RK3576_PULL_GPIO4_DL_OFFSET - 0xc; + } else { + *reg = 0; + debug("unsupported bank_num %d\n", bank->bank_num); + } + + *reg += ((pin_num / RK3576_PULL_PINS_PER_REG) * 4); + *bit = pin_num % RK3576_PULL_PINS_PER_REG; + *bit *= RK3576_PULL_BITS_PER_PIN; +} + +static int rk3576_set_pull(struct rockchip_pin_bank *bank, + int pin_num, int pull) +{ + struct regmap *regmap; + int reg, ret; + u8 bit, type; + u32 data, rmask; + + if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) + return -ENOTSUPP; + + rk3576_calc_pull_reg_and_bit(bank, pin_num, ®map, ®, &bit); + type = 1; /* FIXME: was always set to 1 in vendor kernel */ + ret = rockchip_translate_pull_value(type, pull); + if (ret < 0) { + debug("unsupported pull setting %d\n", pull); + return ret; + } + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3576_PULL_BITS_PER_PIN) - 1) << (bit + 16); + rmask = data | (data >> 16); + data |= (ret << bit); + + return regmap_update_bits(regmap, reg, rmask, data); +} + +#define RK3576_SMT_BITS_PER_PIN 1 +#define RK3576_SMT_PINS_PER_REG 8 +#define RK3576_SMT_GPIO0_AL_OFFSET 0x30 +#define RK3576_SMT_GPIO0_BH_OFFSET 0x2040 +#define RK3576_SMT_GPIO1_OFFSET 0x6210 +#define RK3576_SMT_GPIO2_OFFSET 0x6220 +#define RK3576_SMT_GPIO3_OFFSET 0x6230 +#define RK3576_SMT_GPIO4_AL_OFFSET 0x6240 +#define RK3576_SMT_GPIO4_CL_OFFSET 0xA248 +#define RK3576_SMT_GPIO4_DL_OFFSET 0xB24C + +static void rk3576_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, + struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + + *regmap = priv->regmap_base; + if (bank->bank_num == 0 && pin_num < 12) { + *reg = RK3576_SMT_GPIO0_AL_OFFSET; + } else if (bank->bank_num == 0) { + *reg = RK3576_SMT_GPIO0_BH_OFFSET - 0x4; + } else if (bank->bank_num == 1) { + *reg = RK3576_SMT_GPIO1_OFFSET; + } else if (bank->bank_num == 2) { + *reg = RK3576_SMT_GPIO2_OFFSET; + } else if (bank->bank_num == 3) { + *reg = RK3576_SMT_GPIO3_OFFSET; + } else if (bank->bank_num == 4 && pin_num < 16) { + *reg = RK3576_SMT_GPIO4_AL_OFFSET; + } else if (bank->bank_num == 4 && pin_num < 24) { + *reg = RK3576_SMT_GPIO4_CL_OFFSET - 0x8; + } else if (bank->bank_num == 4) { + *reg = RK3576_SMT_GPIO4_DL_OFFSET - 0xc; + } else { + *reg = 0; + debug("unsupported bank_num %d\n", bank->bank_num); + } + + *reg += ((pin_num / RK3576_SMT_PINS_PER_REG) * 4); + *bit = pin_num % RK3576_SMT_PINS_PER_REG; + *bit *= RK3576_SMT_BITS_PER_PIN; +} + +static int rk3576_set_schmitt(struct rockchip_pin_bank *bank, + int pin_num, int enable) +{ + struct regmap *regmap; + int reg; + u32 data, rmask; + u8 bit; + + rk3576_calc_schmitt_reg_and_bit(bank, pin_num, ®map, ®, &bit); + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3576_SMT_BITS_PER_PIN) - 1) << (bit + 16); + rmask = data | (data >> 16); + data |= (enable << bit); + + return regmap_update_bits(regmap, reg, rmask, data); +} + +static struct rockchip_pin_bank rk3576_pin_banks[] = { + RK3576_PIN_BANK_FLAGS(0, 32, "gpio0", IOMUX_WIDTH_4BIT, + 0, 0x8, 0x2004, 0x200C), + RK3576_PIN_BANK_FLAGS(1, 32, "gpio1", IOMUX_WIDTH_4BIT, + 0x4020, 0x4028, 0x4030, 0x4038), + RK3576_PIN_BANK_FLAGS(2, 32, "gpio2", IOMUX_WIDTH_4BIT, + 0x4040, 0x4048, 0x4050, 0x4058), + RK3576_PIN_BANK_FLAGS(3, 32, "gpio3", IOMUX_WIDTH_4BIT, + 0x4060, 0x4068, 0x4070, 0x4078), + RK3576_PIN_BANK_FLAGS(4, 32, "gpio4", IOMUX_WIDTH_4BIT, + 0x4080, 0x4088, 0xA390, 0xB398), +}; + +static const struct rockchip_pin_ctrl rk3576_pin_ctrl = { + .pin_banks = rk3576_pin_banks, + .nr_banks = ARRAY_SIZE(rk3576_pin_banks), + .grf_mux_offset = 0x0, + .set_mux = rk3576_set_mux, + .set_pull = rk3576_set_pull, + .set_drive = rk3576_set_drive, + .set_schmitt = rk3576_set_schmitt, +}; + +static const struct udevice_id rk3576_pinctrl_ids[] = { + { + .compatible = "rockchip,rk3576-pinctrl", + .data = (ulong)&rk3576_pin_ctrl + }, + { } +}; + +U_BOOT_DRIVER(pinctrl_rk3576) = { + .name = "rockchip_rk3576_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = rk3576_pinctrl_ids, + .priv_auto = sizeof(struct rockchip_pinctrl_priv), + .ops = &rockchip_pinctrl_ops, +#if CONFIG_IS_ENABLED(OF_REAL) + .bind = dm_scan_fdt_dev, +#endif + .probe = rockchip_pinctrl_probe, +}; diff --git a/drivers/pinctrl/rockchip/pinctrl-rockchip.h b/drivers/pinctrl/rockchip/pinctrl-rockchip.h index df7bc684d29..5e3c9c90760 100644 --- a/drivers/pinctrl/rockchip/pinctrl-rockchip.h +++ b/drivers/pinctrl/rockchip/pinctrl-rockchip.h @@ -458,6 +458,9 @@ struct rockchip_pin_bank { #define MR_PMUGRF(ID, PIN, FUNC, REG, VAL) \ PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, ROUTE_TYPE_PMUGRF) +#define RK3576_PIN_BANK_FLAGS(ID, PIN, LABEL, M, O1, O2, O3, O4) \ + PIN_BANK_IOMUX_FLAGS_OFFSET(ID, PIN, LABEL, M, M, M, M, O1, O2, O3, O4) + #define RK3588_PIN_BANK_FLAGS(ID, PIN, LABEL, M, P) \ PIN_BANK_IOMUX_FLAGS_PULL_FLAGS(ID, PIN, LABEL, M, M, M, M, P, P, P, P) diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index 36dc0500dab..fd94aad0cd4 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -13,7 +13,9 @@ obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o obj-$(CONFIG_ROCKCHIP_RK3308) = sdram_rk3308.o obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o sdram_pctl_px30.o sdram_phy_px30.o obj-$(CONFIG_ROCKCHIP_RK3399) += sdram_rk3399.o +obj-$(CONFIG_ROCKCHIP_RK3528) += sdram_rk3528.o obj-$(CONFIG_ROCKCHIP_RK3568) += sdram_rk3568.o +obj-$(CONFIG_ROCKCHIP_RK3576) += sdram_rk3576.o obj-$(CONFIG_ROCKCHIP_RK3588) += sdram_rk3588.o obj-$(CONFIG_ROCKCHIP_RV1126) += sdram_rv1126.o sdram_pctl_px30.o obj-$(CONFIG_ROCKCHIP_SDRAM_COMMON) += sdram_common.o diff --git a/drivers/ram/rockchip/sdram_rk3528.c b/drivers/ram/rockchip/sdram_rk3528.c new file mode 100644 index 00000000000..89d325bea66 --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3528.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright Contributors to the U-Boot project. + +#include <dm.h> +#include <ram.h> +#include <asm/arch-rockchip/sdram.h> + +#define PMUGRF_BASE 0xff370000 +#define OS_REG18_REG 0x248 + +static int rk3528_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + info->base = CFG_SYS_SDRAM_BASE; + info->size = rockchip_sdram_size(PMUGRF_BASE + OS_REG18_REG); + + return 0; +} + +static struct ram_ops rk3528_dmc_ops = { + .get_info = rk3528_dmc_get_info, +}; + +static const struct udevice_id rk3528_dmc_ids[] = { + { .compatible = "rockchip,rk3528-dmc" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3528_dmc) = { + .name = "rockchip_rk3528_dmc", + .id = UCLASS_RAM, + .of_match = rk3528_dmc_ids, + .ops = &rk3528_dmc_ops, +}; diff --git a/drivers/ram/rockchip/sdram_rk3576.c b/drivers/ram/rockchip/sdram_rk3576.c new file mode 100644 index 00000000000..5a66032ef8f --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3576.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2024 Rockchip Electronics Co., Ltd. + */ + +#include <dm.h> +#include <ram.h> +#include <asm/arch-rockchip/sdram.h> + +#define PMU1GRF_BASE 0x26026000 +#define OS_REG2_REG 0x208 + +static int rk3576_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + info->base = CFG_SYS_SDRAM_BASE; + info->size = rockchip_sdram_size(PMU1GRF_BASE + OS_REG2_REG); + + return 0; +} + +static struct ram_ops rk3576_dmc_ops = { + .get_info = rk3576_dmc_get_info, +}; + +static const struct udevice_id rk3576_dmc_ids[] = { + { .compatible = "rockchip,rk3576-dmc" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3576_dmc) = { + .name = "rockchip_rk3576_dmc", + .id = UCLASS_RAM, + .of_match = rk3576_dmc_ids, + .ops = &rk3576_dmc_ops, +}; diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index b9494396013..1dd3cd99a14 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_AST2500) += reset-ast2500.o obj-$(CONFIG_RESET_AST2600) += reset-ast2600.o -obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o rst-rk3588.o +obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o rst-rk3528.o rst-rk3576.o rst-rk3588.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o diff --git a/drivers/reset/rst-rk3528.c b/drivers/reset/rst-rk3528.c new file mode 100644 index 00000000000..f6e760d468d --- /dev/null +++ b/drivers/reset/rst-rk3528.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + * Based on Sebastian Reichel's implementation for RK3588 + */ + +#include <dm.h> +#include <asm/arch-rockchip/clock.h> +#include <dt-bindings/reset/rockchip,rk3528-cru.h> + +/* 0xFF4A0000 + 0x0A00 */ +#define RK3528_CRU_RESET_OFFSET(id, reg, bit) [id] = (0 + reg * 16 + bit) + +/* mapping table for reset ID to register offset */ +static const int rk3528_register_offset[] = { + /* CRU_SOFTRST_CON03 */ + RK3528_CRU_RESET_OFFSET(SRST_CORE0_PO, 3, 0), + RK3528_CRU_RESET_OFFSET(SRST_CORE1_PO, 3, 1), + RK3528_CRU_RESET_OFFSET(SRST_CORE2_PO, 3, 2), + RK3528_CRU_RESET_OFFSET(SRST_CORE3_PO, 3, 3), + RK3528_CRU_RESET_OFFSET(SRST_CORE0, 3, 4), + RK3528_CRU_RESET_OFFSET(SRST_CORE1, 3, 5), + RK3528_CRU_RESET_OFFSET(SRST_CORE2, 3, 6), + RK3528_CRU_RESET_OFFSET(SRST_CORE3, 3, 7), + RK3528_CRU_RESET_OFFSET(SRST_NL2, 3, 8), + RK3528_CRU_RESET_OFFSET(SRST_CORE_BIU, 3, 9), + RK3528_CRU_RESET_OFFSET(SRST_CORE_CRYPTO, 3, 10), + + /* CRU_SOFTRST_CON05 */ + RK3528_CRU_RESET_OFFSET(SRST_P_DBG, 5, 13), + RK3528_CRU_RESET_OFFSET(SRST_POT_DBG, 5, 14), + RK3528_CRU_RESET_OFFSET(SRST_NT_DBG, 5, 15), + + /* CRU_SOFTRST_CON06 */ + RK3528_CRU_RESET_OFFSET(SRST_P_CORE_GRF, 6, 2), + RK3528_CRU_RESET_OFFSET(SRST_P_DAPLITE_BIU, 6, 3), + RK3528_CRU_RESET_OFFSET(SRST_P_CPU_BIU, 6, 4), + RK3528_CRU_RESET_OFFSET(SRST_REF_PVTPLL_CORE, 6, 7), + + /* CRU_SOFTRST_CON08 */ + RK3528_CRU_RESET_OFFSET(SRST_A_BUS_VOPGL_BIU, 8, 1), + RK3528_CRU_RESET_OFFSET(SRST_A_BUS_H_BIU, 8, 3), + RK3528_CRU_RESET_OFFSET(SRST_A_SYSMEM_BIU, 8, 8), + RK3528_CRU_RESET_OFFSET(SRST_A_BUS_BIU, 8, 10), + RK3528_CRU_RESET_OFFSET(SRST_H_BUS_BIU, 8, 11), + RK3528_CRU_RESET_OFFSET(SRST_P_BUS_BIU, 8, 12), + RK3528_CRU_RESET_OFFSET(SRST_P_DFT2APB, 8, 13), + RK3528_CRU_RESET_OFFSET(SRST_P_BUS_GRF, 8, 15), + + /* CRU_SOFTRST_CON09 */ + RK3528_CRU_RESET_OFFSET(SRST_A_BUS_M_BIU, 9, 0), + RK3528_CRU_RESET_OFFSET(SRST_A_GIC, 9, 1), + RK3528_CRU_RESET_OFFSET(SRST_A_SPINLOCK, 9, 2), + RK3528_CRU_RESET_OFFSET(SRST_A_DMAC, 9, 4), + RK3528_CRU_RESET_OFFSET(SRST_P_TIMER, 9, 5), + RK3528_CRU_RESET_OFFSET(SRST_TIMER0, 9, 6), + RK3528_CRU_RESET_OFFSET(SRST_TIMER1, 9, 7), + RK3528_CRU_RESET_OFFSET(SRST_TIMER2, 9, 8), + RK3528_CRU_RESET_OFFSET(SRST_TIMER3, 9, 9), + RK3528_CRU_RESET_OFFSET(SRST_TIMER4, 9, 10), + RK3528_CRU_RESET_OFFSET(SRST_TIMER5, 9, 11), + RK3528_CRU_RESET_OFFSET(SRST_P_JDBCK_DAP, 9, 12), + RK3528_CRU_RESET_OFFSET(SRST_JDBCK_DAP, 9, 13), + RK3528_CRU_RESET_OFFSET(SRST_P_WDT_NS, 9, 15), + + /* CRU_SOFTRST_CON10 */ + RK3528_CRU_RESET_OFFSET(SRST_T_WDT_NS, 10, 0), + RK3528_CRU_RESET_OFFSET(SRST_H_TRNG_NS, 10, 3), + RK3528_CRU_RESET_OFFSET(SRST_P_UART0, 10, 7), + RK3528_CRU_RESET_OFFSET(SRST_S_UART0, 10, 8), + RK3528_CRU_RESET_OFFSET(SRST_PKA_CRYPTO, 10, 10), + RK3528_CRU_RESET_OFFSET(SRST_A_CRYPTO, 10, 11), + RK3528_CRU_RESET_OFFSET(SRST_H_CRYPTO, 10, 12), + RK3528_CRU_RESET_OFFSET(SRST_P_DMA2DDR, 10, 13), + RK3528_CRU_RESET_OFFSET(SRST_A_DMA2DDR, 10, 14), + + /* CRU_SOFTRST_CON11 */ + RK3528_CRU_RESET_OFFSET(SRST_P_PWM0, 11, 4), + RK3528_CRU_RESET_OFFSET(SRST_PWM0, 11, 5), + RK3528_CRU_RESET_OFFSET(SRST_P_PWM1, 11, 7), + RK3528_CRU_RESET_OFFSET(SRST_PWM1, 11, 8), + RK3528_CRU_RESET_OFFSET(SRST_P_SCR, 11, 10), + RK3528_CRU_RESET_OFFSET(SRST_A_DCF, 11, 11), + RK3528_CRU_RESET_OFFSET(SRST_P_INTMUX, 11, 12), + + /* CRU_SOFTRST_CON25 */ + RK3528_CRU_RESET_OFFSET(SRST_A_VPU_BIU, 25, 6), + RK3528_CRU_RESET_OFFSET(SRST_H_VPU_BIU, 25, 7), + RK3528_CRU_RESET_OFFSET(SRST_P_VPU_BIU, 25, 8), + RK3528_CRU_RESET_OFFSET(SRST_A_VPU, 25, 9), + RK3528_CRU_RESET_OFFSET(SRST_H_VPU, 25, 10), + RK3528_CRU_RESET_OFFSET(SRST_P_CRU_PCIE, 25, 11), + RK3528_CRU_RESET_OFFSET(SRST_P_VPU_GRF, 25, 12), + RK3528_CRU_RESET_OFFSET(SRST_H_SFC, 25, 13), + RK3528_CRU_RESET_OFFSET(SRST_S_SFC, 25, 14), + RK3528_CRU_RESET_OFFSET(SRST_C_EMMC, 25, 15), + + /* CRU_SOFTRST_CON26 */ + RK3528_CRU_RESET_OFFSET(SRST_H_EMMC, 26, 0), + RK3528_CRU_RESET_OFFSET(SRST_A_EMMC, 26, 1), + RK3528_CRU_RESET_OFFSET(SRST_B_EMMC, 26, 2), + RK3528_CRU_RESET_OFFSET(SRST_T_EMMC, 26, 3), + RK3528_CRU_RESET_OFFSET(SRST_P_GPIO1, 26, 4), + RK3528_CRU_RESET_OFFSET(SRST_DB_GPIO1, 26, 5), + RK3528_CRU_RESET_OFFSET(SRST_A_VPU_L_BIU, 26, 6), + RK3528_CRU_RESET_OFFSET(SRST_P_VPU_IOC, 26, 8), + RK3528_CRU_RESET_OFFSET(SRST_H_SAI_I2S0, 26, 9), + RK3528_CRU_RESET_OFFSET(SRST_M_SAI_I2S0, 26, 10), + RK3528_CRU_RESET_OFFSET(SRST_H_SAI_I2S2, 26, 11), + RK3528_CRU_RESET_OFFSET(SRST_M_SAI_I2S2, 26, 12), + RK3528_CRU_RESET_OFFSET(SRST_P_ACODEC, 26, 13), + + /* CRU_SOFTRST_CON27 */ + RK3528_CRU_RESET_OFFSET(SRST_P_GPIO3, 27, 0), + RK3528_CRU_RESET_OFFSET(SRST_DB_GPIO3, 27, 1), + RK3528_CRU_RESET_OFFSET(SRST_P_SPI1, 27, 4), + RK3528_CRU_RESET_OFFSET(SRST_SPI1, 27, 5), + RK3528_CRU_RESET_OFFSET(SRST_P_UART2, 27, 7), + RK3528_CRU_RESET_OFFSET(SRST_S_UART2, 27, 8), + RK3528_CRU_RESET_OFFSET(SRST_P_UART5, 27, 9), + RK3528_CRU_RESET_OFFSET(SRST_S_UART5, 27, 10), + RK3528_CRU_RESET_OFFSET(SRST_P_UART6, 27, 11), + RK3528_CRU_RESET_OFFSET(SRST_S_UART6, 27, 12), + RK3528_CRU_RESET_OFFSET(SRST_P_UART7, 27, 13), + RK3528_CRU_RESET_OFFSET(SRST_S_UART7, 27, 14), + RK3528_CRU_RESET_OFFSET(SRST_P_I2C3, 27, 15), + + /* CRU_SOFTRST_CON28 */ + RK3528_CRU_RESET_OFFSET(SRST_I2C3, 28, 0), + RK3528_CRU_RESET_OFFSET(SRST_P_I2C5, 28, 1), + RK3528_CRU_RESET_OFFSET(SRST_I2C5, 28, 2), + RK3528_CRU_RESET_OFFSET(SRST_P_I2C6, 28, 3), + RK3528_CRU_RESET_OFFSET(SRST_I2C6, 28, 4), + RK3528_CRU_RESET_OFFSET(SRST_A_MAC, 28, 5), + + /* CRU_SOFTRST_CON30 */ + RK3528_CRU_RESET_OFFSET(SRST_P_PCIE, 30, 1), + RK3528_CRU_RESET_OFFSET(SRST_PCIE_PIPE_PHY, 30, 2), + RK3528_CRU_RESET_OFFSET(SRST_PCIE_POWER_UP, 30, 3), + RK3528_CRU_RESET_OFFSET(SRST_P_PCIE_PHY, 30, 6), + RK3528_CRU_RESET_OFFSET(SRST_P_PIPE_GRF, 30, 7), + + /* CRU_SOFTRST_CON32 */ + RK3528_CRU_RESET_OFFSET(SRST_H_SDIO0, 32, 2), + RK3528_CRU_RESET_OFFSET(SRST_H_SDIO1, 32, 4), + RK3528_CRU_RESET_OFFSET(SRST_TS_0, 32, 5), + RK3528_CRU_RESET_OFFSET(SRST_TS_1, 32, 6), + RK3528_CRU_RESET_OFFSET(SRST_P_CAN2, 32, 7), + RK3528_CRU_RESET_OFFSET(SRST_CAN2, 32, 8), + RK3528_CRU_RESET_OFFSET(SRST_P_CAN3, 32, 9), + RK3528_CRU_RESET_OFFSET(SRST_CAN3, 32, 10), + RK3528_CRU_RESET_OFFSET(SRST_P_SARADC, 32, 11), + RK3528_CRU_RESET_OFFSET(SRST_SARADC, 32, 12), + RK3528_CRU_RESET_OFFSET(SRST_SARADC_PHY, 32, 13), + RK3528_CRU_RESET_OFFSET(SRST_P_TSADC, 32, 14), + RK3528_CRU_RESET_OFFSET(SRST_TSADC, 32, 15), + + /* CRU_SOFTRST_CON33 */ + RK3528_CRU_RESET_OFFSET(SRST_A_USB3OTG, 33, 1), + + /* CRU_SOFTRST_CON34 */ + RK3528_CRU_RESET_OFFSET(SRST_A_GPU_BIU, 34, 3), + RK3528_CRU_RESET_OFFSET(SRST_P_GPU_BIU, 34, 5), + RK3528_CRU_RESET_OFFSET(SRST_A_GPU, 34, 8), + RK3528_CRU_RESET_OFFSET(SRST_REF_PVTPLL_GPU, 34, 9), + + /* CRU_SOFTRST_CON36 */ + RK3528_CRU_RESET_OFFSET(SRST_H_RKVENC_BIU, 36, 3), + RK3528_CRU_RESET_OFFSET(SRST_A_RKVENC_BIU, 36, 4), + RK3528_CRU_RESET_OFFSET(SRST_P_RKVENC_BIU, 36, 5), + RK3528_CRU_RESET_OFFSET(SRST_H_RKVENC, 36, 6), + RK3528_CRU_RESET_OFFSET(SRST_A_RKVENC, 36, 7), + RK3528_CRU_RESET_OFFSET(SRST_CORE_RKVENC, 36, 8), + RK3528_CRU_RESET_OFFSET(SRST_H_SAI_I2S1, 36, 9), + RK3528_CRU_RESET_OFFSET(SRST_M_SAI_I2S1, 36, 10), + RK3528_CRU_RESET_OFFSET(SRST_P_I2C1, 36, 11), + RK3528_CRU_RESET_OFFSET(SRST_I2C1, 36, 12), + RK3528_CRU_RESET_OFFSET(SRST_P_I2C0, 36, 13), + RK3528_CRU_RESET_OFFSET(SRST_I2C0, 36, 14), + + /* CRU_SOFTRST_CON37 */ + RK3528_CRU_RESET_OFFSET(SRST_P_SPI0, 37, 2), + RK3528_CRU_RESET_OFFSET(SRST_SPI0, 37, 3), + RK3528_CRU_RESET_OFFSET(SRST_P_GPIO4, 37, 8), + RK3528_CRU_RESET_OFFSET(SRST_DB_GPIO4, 37, 9), + RK3528_CRU_RESET_OFFSET(SRST_P_RKVENC_IOC, 37, 10), + RK3528_CRU_RESET_OFFSET(SRST_H_SPDIF, 37, 14), + RK3528_CRU_RESET_OFFSET(SRST_M_SPDIF, 37, 15), + + /* CRU_SOFTRST_CON38 */ + RK3528_CRU_RESET_OFFSET(SRST_H_PDM, 38, 0), + RK3528_CRU_RESET_OFFSET(SRST_M_PDM, 38, 1), + RK3528_CRU_RESET_OFFSET(SRST_P_UART1, 38, 2), + RK3528_CRU_RESET_OFFSET(SRST_S_UART1, 38, 3), + RK3528_CRU_RESET_OFFSET(SRST_P_UART3, 38, 4), + RK3528_CRU_RESET_OFFSET(SRST_S_UART3, 38, 5), + RK3528_CRU_RESET_OFFSET(SRST_P_RKVENC_GRF, 38, 6), + RK3528_CRU_RESET_OFFSET(SRST_P_CAN0, 38, 7), + RK3528_CRU_RESET_OFFSET(SRST_CAN0, 38, 8), + RK3528_CRU_RESET_OFFSET(SRST_P_CAN1, 38, 9), + RK3528_CRU_RESET_OFFSET(SRST_CAN1, 38, 10), + + /* CRU_SOFTRST_CON39 */ + RK3528_CRU_RESET_OFFSET(SRST_A_VO_BIU, 39, 3), + RK3528_CRU_RESET_OFFSET(SRST_H_VO_BIU, 39, 4), + RK3528_CRU_RESET_OFFSET(SRST_P_VO_BIU, 39, 5), + RK3528_CRU_RESET_OFFSET(SRST_H_RGA2E, 39, 7), + RK3528_CRU_RESET_OFFSET(SRST_A_RGA2E, 39, 8), + RK3528_CRU_RESET_OFFSET(SRST_CORE_RGA2E, 39, 9), + RK3528_CRU_RESET_OFFSET(SRST_H_VDPP, 39, 10), + RK3528_CRU_RESET_OFFSET(SRST_A_VDPP, 39, 11), + RK3528_CRU_RESET_OFFSET(SRST_CORE_VDPP, 39, 12), + RK3528_CRU_RESET_OFFSET(SRST_P_VO_GRF, 39, 13), + RK3528_CRU_RESET_OFFSET(SRST_P_CRU, 39, 15), + + /* CRU_SOFTRST_CON40 */ + RK3528_CRU_RESET_OFFSET(SRST_A_VOP_BIU, 40, 1), + RK3528_CRU_RESET_OFFSET(SRST_H_VOP, 40, 2), + RK3528_CRU_RESET_OFFSET(SRST_D_VOP0, 40, 3), + RK3528_CRU_RESET_OFFSET(SRST_D_VOP1, 40, 4), + RK3528_CRU_RESET_OFFSET(SRST_A_VOP, 40, 5), + RK3528_CRU_RESET_OFFSET(SRST_P_HDMI, 40, 6), + RK3528_CRU_RESET_OFFSET(SRST_HDMI, 40, 7), + RK3528_CRU_RESET_OFFSET(SRST_P_HDMIPHY, 40, 14), + RK3528_CRU_RESET_OFFSET(SRST_H_HDCP_KEY, 40, 15), + + /* CRU_SOFTRST_CON41 */ + RK3528_CRU_RESET_OFFSET(SRST_A_HDCP, 41, 0), + RK3528_CRU_RESET_OFFSET(SRST_H_HDCP, 41, 1), + RK3528_CRU_RESET_OFFSET(SRST_P_HDCP, 41, 2), + RK3528_CRU_RESET_OFFSET(SRST_H_CVBS, 41, 3), + RK3528_CRU_RESET_OFFSET(SRST_D_CVBS_VOP, 41, 4), + RK3528_CRU_RESET_OFFSET(SRST_D_4X_CVBS_VOP, 41, 5), + RK3528_CRU_RESET_OFFSET(SRST_A_JPEG_DECODER, 41, 6), + RK3528_CRU_RESET_OFFSET(SRST_H_JPEG_DECODER, 41, 7), + RK3528_CRU_RESET_OFFSET(SRST_A_VO_L_BIU, 41, 9), + RK3528_CRU_RESET_OFFSET(SRST_A_MAC_VO, 41, 10), + + /* CRU_SOFTRST_CON42 */ + RK3528_CRU_RESET_OFFSET(SRST_A_JPEG_BIU, 42, 0), + RK3528_CRU_RESET_OFFSET(SRST_H_SAI_I2S3, 42, 1), + RK3528_CRU_RESET_OFFSET(SRST_M_SAI_I2S3, 42, 2), + RK3528_CRU_RESET_OFFSET(SRST_MACPHY, 42, 3), + RK3528_CRU_RESET_OFFSET(SRST_P_VCDCPHY, 42, 4), + RK3528_CRU_RESET_OFFSET(SRST_P_GPIO2, 42, 5), + RK3528_CRU_RESET_OFFSET(SRST_DB_GPIO2, 42, 6), + RK3528_CRU_RESET_OFFSET(SRST_P_VO_IOC, 42, 7), + RK3528_CRU_RESET_OFFSET(SRST_H_SDMMC0, 42, 9), + RK3528_CRU_RESET_OFFSET(SRST_P_OTPC_NS, 42, 11), + RK3528_CRU_RESET_OFFSET(SRST_SBPI_OTPC_NS, 42, 12), + RK3528_CRU_RESET_OFFSET(SRST_USER_OTPC_NS, 42, 13), + + /* CRU_SOFTRST_CON43 */ + RK3528_CRU_RESET_OFFSET(SRST_HDMIHDP0, 43, 2), + RK3528_CRU_RESET_OFFSET(SRST_H_USBHOST, 43, 3), + RK3528_CRU_RESET_OFFSET(SRST_H_USBHOST_ARB, 43, 4), + RK3528_CRU_RESET_OFFSET(SRST_HOST_UTMI, 43, 6), + RK3528_CRU_RESET_OFFSET(SRST_P_UART4, 43, 7), + RK3528_CRU_RESET_OFFSET(SRST_S_UART4, 43, 8), + RK3528_CRU_RESET_OFFSET(SRST_P_I2C4, 43, 9), + RK3528_CRU_RESET_OFFSET(SRST_I2C4, 43, 10), + RK3528_CRU_RESET_OFFSET(SRST_P_I2C7, 43, 11), + RK3528_CRU_RESET_OFFSET(SRST_I2C7, 43, 12), + RK3528_CRU_RESET_OFFSET(SRST_P_USBPHY, 43, 13), + RK3528_CRU_RESET_OFFSET(SRST_USBPHY_POR, 43, 14), + RK3528_CRU_RESET_OFFSET(SRST_USBPHY_OTG, 43, 15), + + /* CRU_SOFTRST_CON44 */ + RK3528_CRU_RESET_OFFSET(SRST_USBPHY_HOST, 44, 0), + RK3528_CRU_RESET_OFFSET(SRST_P_DDRPHY_CRU, 44, 4), + RK3528_CRU_RESET_OFFSET(SRST_H_RKVDEC_BIU, 44, 6), + RK3528_CRU_RESET_OFFSET(SRST_A_RKVDEC_BIU, 44, 7), + RK3528_CRU_RESET_OFFSET(SRST_A_RKVDEC, 44, 8), + RK3528_CRU_RESET_OFFSET(SRST_H_RKVDEC, 44, 9), + RK3528_CRU_RESET_OFFSET(SRST_HEVC_CA_RKVDEC, 44, 11), + RK3528_CRU_RESET_OFFSET(SRST_REF_PVTPLL_RKVDEC, 44, 12), + + /* CRU_SOFTRST_CON45 */ + RK3528_CRU_RESET_OFFSET(SRST_P_DDR_BIU, 45, 1), + RK3528_CRU_RESET_OFFSET(SRST_P_DDRC, 45, 2), + RK3528_CRU_RESET_OFFSET(SRST_P_DDRMON, 45, 3), + RK3528_CRU_RESET_OFFSET(SRST_TIMER_DDRMON, 45, 4), + RK3528_CRU_RESET_OFFSET(SRST_P_MSCH_BIU, 45, 5), + RK3528_CRU_RESET_OFFSET(SRST_P_DDR_GRF, 45, 6), + RK3528_CRU_RESET_OFFSET(SRST_P_DDR_HWLP, 45, 8), + RK3528_CRU_RESET_OFFSET(SRST_P_DDRPHY, 45, 9), + RK3528_CRU_RESET_OFFSET(SRST_MSCH_BIU, 45, 10), + RK3528_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL, 45, 11), + RK3528_CRU_RESET_OFFSET(SRST_DDR_UPCTL, 45, 12), + RK3528_CRU_RESET_OFFSET(SRST_DDRMON, 45, 13), + RK3528_CRU_RESET_OFFSET(SRST_A_DDR_SCRAMBLE, 45, 14), + RK3528_CRU_RESET_OFFSET(SRST_A_SPLIT, 45, 15), + + /* CRU_SOFTRST_CON46 */ + RK3528_CRU_RESET_OFFSET(SRST_DDR_PHY, 46, 0), +}; + +int rk3528_reset_bind_lut(struct udevice *pdev, u32 reg_offset, u32 reg_number) +{ + return rockchip_reset_bind_lut(pdev, rk3528_register_offset, + reg_offset, reg_number); +} diff --git a/drivers/reset/rst-rk3576.c b/drivers/reset/rst-rk3576.c new file mode 100644 index 00000000000..a6b83a2fd74 --- /dev/null +++ b/drivers/reset/rst-rk3576.c @@ -0,0 +1,647 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + * Copyright (c) 2024 Collabora Ltd. + * Author: Detlev Casanova <[email protected]> + * Based on Sebastian Reichel's implementation for RK3588 + */ + +#include <dm.h> +#include <asm/arch-rockchip/clock.h> +#include <dt-bindings/reset/rockchip,rk3576-cru.h> + +/* 0x27200000 + 0x0A00 */ +#define RK3576_CRU_RESET_OFFSET(id, reg, bit) [id] = (0 + (reg) * 16 + (bit)) +/* 0x27208000 + 0x0A00 */ +#define RK3576_PHPCRU_RESET_OFFSET(id, reg, bit) [id] = (0x8000 * 4 + (reg) * 16 + (bit)) +/* 0x27210000 + 0x0A00 */ +#define RK3576_SECURENSCRU_RESET_OFFSET(id, reg, bit) [id] = (0x10000 * 4 + (reg) * 16 + (bit)) +/* 0x27220000 + 0x0A00 */ +#define RK3576_PMU1CRU_RESET_OFFSET(id, reg, bit) [id] = (0x20000 * 4 + (reg) * 16 + (bit)) + +/* mapping table for reset ID to register offset */ +static const int rk3576_register_offset[] = { + /* SOFTRST_CON01 */ + RK3576_CRU_RESET_OFFSET(SRST_A_TOP_BIU, 1, 3), + RK3576_CRU_RESET_OFFSET(SRST_P_TOP_BIU, 1, 5), + RK3576_CRU_RESET_OFFSET(SRST_A_TOP_MID_BIU, 1, 6), + RK3576_CRU_RESET_OFFSET(SRST_A_SECURE_HIGH_BIU, 1, 7), + RK3576_CRU_RESET_OFFSET(SRST_H_TOP_BIU, 1, 14), + + /* SOFTRST_CON02 */ + RK3576_CRU_RESET_OFFSET(SRST_H_VO0VOP_CHANNEL_BIU, 2, 0), + RK3576_CRU_RESET_OFFSET(SRST_A_VO0VOP_CHANNEL_BIU, 2, 1), + + /* SOFTRST_CON06 */ + RK3576_CRU_RESET_OFFSET(SRST_BISRINTF, 6, 2), + + /* SOFTRST_CON07 */ + RK3576_CRU_RESET_OFFSET(SRST_H_AUDIO_BIU, 7, 2), + RK3576_CRU_RESET_OFFSET(SRST_H_ASRC_2CH_0, 7, 3), + RK3576_CRU_RESET_OFFSET(SRST_H_ASRC_2CH_1, 7, 4), + RK3576_CRU_RESET_OFFSET(SRST_H_ASRC_4CH_0, 7, 5), + RK3576_CRU_RESET_OFFSET(SRST_H_ASRC_4CH_1, 7, 6), + RK3576_CRU_RESET_OFFSET(SRST_ASRC_2CH_0, 7, 7), + RK3576_CRU_RESET_OFFSET(SRST_ASRC_2CH_1, 7, 8), + RK3576_CRU_RESET_OFFSET(SRST_ASRC_4CH_0, 7, 9), + RK3576_CRU_RESET_OFFSET(SRST_ASRC_4CH_1, 7, 10), + RK3576_CRU_RESET_OFFSET(SRST_M_SAI0_8CH, 7, 12), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI0_8CH, 7, 13), + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_RX0, 7, 14), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_RX0, 7, 15), + + /* SOFTRST_CON08 */ + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_RX1, 8, 0), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_RX1, 8, 1), + RK3576_CRU_RESET_OFFSET(SRST_M_SAI1_8CH, 8, 5), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI1_8CH, 8, 6), + RK3576_CRU_RESET_OFFSET(SRST_M_SAI2_2CH, 8, 8), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI2_2CH, 8, 10), + RK3576_CRU_RESET_OFFSET(SRST_M_SAI3_2CH, 8, 12), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI3_2CH, 8, 14), + + /* SOFTRST_CON09 */ + RK3576_CRU_RESET_OFFSET(SRST_M_SAI4_2CH, 9, 0), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI4_2CH, 9, 2), + RK3576_CRU_RESET_OFFSET(SRST_H_ACDCDIG_DSM, 9, 3), + RK3576_CRU_RESET_OFFSET(SRST_M_ACDCDIG_DSM, 9, 4), + RK3576_CRU_RESET_OFFSET(SRST_PDM1, 9, 5), + RK3576_CRU_RESET_OFFSET(SRST_H_PDM1, 9, 7), + RK3576_CRU_RESET_OFFSET(SRST_M_PDM1, 9, 8), + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_TX0, 9, 9), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_TX0, 9, 10), + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_TX1, 9, 11), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_TX1, 9, 12), + + /* SOFTRST_CON11 */ + RK3576_CRU_RESET_OFFSET(SRST_A_BUS_BIU, 11, 3), + RK3576_CRU_RESET_OFFSET(SRST_P_BUS_BIU, 11, 4), + RK3576_CRU_RESET_OFFSET(SRST_P_CRU, 11, 5), + RK3576_CRU_RESET_OFFSET(SRST_H_CAN0, 11, 6), + RK3576_CRU_RESET_OFFSET(SRST_CAN0, 11, 7), + RK3576_CRU_RESET_OFFSET(SRST_H_CAN1, 11, 8), + RK3576_CRU_RESET_OFFSET(SRST_CAN1, 11, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_INTMUX2BUS, 11, 12), + RK3576_CRU_RESET_OFFSET(SRST_P_VCCIO_IOC, 11, 13), + RK3576_CRU_RESET_OFFSET(SRST_H_BUS_BIU, 11, 14), + RK3576_CRU_RESET_OFFSET(SRST_KEY_SHIFT, 11, 15), + + /* SOFTRST_CON12 */ + RK3576_CRU_RESET_OFFSET(SRST_P_I2C1, 12, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_I2C2, 12, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_I2C3, 12, 2), + RK3576_CRU_RESET_OFFSET(SRST_P_I2C4, 12, 3), + RK3576_CRU_RESET_OFFSET(SRST_P_I2C5, 12, 4), + RK3576_CRU_RESET_OFFSET(SRST_P_I2C6, 12, 5), + RK3576_CRU_RESET_OFFSET(SRST_P_I2C7, 12, 6), + RK3576_CRU_RESET_OFFSET(SRST_P_I2C8, 12, 7), + RK3576_CRU_RESET_OFFSET(SRST_P_I2C9, 12, 8), + RK3576_CRU_RESET_OFFSET(SRST_P_WDT_BUSMCU, 12, 9), + RK3576_CRU_RESET_OFFSET(SRST_T_WDT_BUSMCU, 12, 10), + RK3576_CRU_RESET_OFFSET(SRST_A_GIC, 12, 11), + RK3576_CRU_RESET_OFFSET(SRST_I2C1, 12, 12), + RK3576_CRU_RESET_OFFSET(SRST_I2C2, 12, 13), + RK3576_CRU_RESET_OFFSET(SRST_I2C3, 12, 14), + RK3576_CRU_RESET_OFFSET(SRST_I2C4, 12, 15), + + /* SOFTRST_CON13 */ + RK3576_CRU_RESET_OFFSET(SRST_I2C5, 13, 0), + RK3576_CRU_RESET_OFFSET(SRST_I2C6, 13, 1), + RK3576_CRU_RESET_OFFSET(SRST_I2C7, 13, 2), + RK3576_CRU_RESET_OFFSET(SRST_I2C8, 13, 3), + RK3576_CRU_RESET_OFFSET(SRST_I2C9, 13, 4), + RK3576_CRU_RESET_OFFSET(SRST_P_SARADC, 13, 6), + RK3576_CRU_RESET_OFFSET(SRST_SARADC, 13, 7), + RK3576_CRU_RESET_OFFSET(SRST_P_TSADC, 13, 8), + RK3576_CRU_RESET_OFFSET(SRST_TSADC, 13, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_UART0, 13, 10), + RK3576_CRU_RESET_OFFSET(SRST_P_UART2, 13, 11), + RK3576_CRU_RESET_OFFSET(SRST_P_UART3, 13, 12), + RK3576_CRU_RESET_OFFSET(SRST_P_UART4, 13, 13), + RK3576_CRU_RESET_OFFSET(SRST_P_UART5, 13, 14), + RK3576_CRU_RESET_OFFSET(SRST_P_UART6, 13, 15), + + /* SOFTRST_CON14 */ + RK3576_CRU_RESET_OFFSET(SRST_P_UART7, 14, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_UART8, 14, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_UART9, 14, 2), + RK3576_CRU_RESET_OFFSET(SRST_P_UART10, 14, 3), + RK3576_CRU_RESET_OFFSET(SRST_P_UART11, 14, 4), + RK3576_CRU_RESET_OFFSET(SRST_S_UART0, 14, 5), + RK3576_CRU_RESET_OFFSET(SRST_S_UART2, 14, 6), + RK3576_CRU_RESET_OFFSET(SRST_S_UART3, 14, 9), + RK3576_CRU_RESET_OFFSET(SRST_S_UART4, 14, 12), + RK3576_CRU_RESET_OFFSET(SRST_S_UART5, 14, 15), + + /* SOFTRST_CON15 */ + RK3576_CRU_RESET_OFFSET(SRST_S_UART6, 15, 2), + RK3576_CRU_RESET_OFFSET(SRST_S_UART7, 15, 5), + RK3576_CRU_RESET_OFFSET(SRST_S_UART8, 15, 8), + RK3576_CRU_RESET_OFFSET(SRST_S_UART9, 15, 9), + RK3576_CRU_RESET_OFFSET(SRST_S_UART10, 15, 10), + RK3576_CRU_RESET_OFFSET(SRST_S_UART11, 15, 11), + RK3576_CRU_RESET_OFFSET(SRST_P_SPI0, 15, 13), + RK3576_CRU_RESET_OFFSET(SRST_P_SPI1, 15, 14), + RK3576_CRU_RESET_OFFSET(SRST_P_SPI2, 15, 15), + + /* SOFTRST_CON16 */ + RK3576_CRU_RESET_OFFSET(SRST_P_SPI3, 16, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_SPI4, 16, 1), + RK3576_CRU_RESET_OFFSET(SRST_SPI0, 16, 2), + RK3576_CRU_RESET_OFFSET(SRST_SPI1, 16, 3), + RK3576_CRU_RESET_OFFSET(SRST_SPI2, 16, 4), + RK3576_CRU_RESET_OFFSET(SRST_SPI3, 16, 5), + RK3576_CRU_RESET_OFFSET(SRST_SPI4, 16, 6), + RK3576_CRU_RESET_OFFSET(SRST_P_WDT0, 16, 7), + RK3576_CRU_RESET_OFFSET(SRST_T_WDT0, 16, 8), + RK3576_CRU_RESET_OFFSET(SRST_P_SYS_GRF, 16, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_PWM1, 16, 10), + RK3576_CRU_RESET_OFFSET(SRST_PWM1, 16, 11), + + /* SOFTRST_CON17 */ + RK3576_CRU_RESET_OFFSET(SRST_P_BUSTIMER0, 17, 3), + RK3576_CRU_RESET_OFFSET(SRST_P_BUSTIMER1, 17, 4), + RK3576_CRU_RESET_OFFSET(SRST_TIMER0, 17, 6), + RK3576_CRU_RESET_OFFSET(SRST_TIMER1, 17, 7), + RK3576_CRU_RESET_OFFSET(SRST_TIMER2, 17, 8), + RK3576_CRU_RESET_OFFSET(SRST_TIMER3, 17, 9), + RK3576_CRU_RESET_OFFSET(SRST_TIMER4, 17, 10), + RK3576_CRU_RESET_OFFSET(SRST_TIMER5, 17, 11), + RK3576_CRU_RESET_OFFSET(SRST_P_BUSIOC, 17, 12), + RK3576_CRU_RESET_OFFSET(SRST_P_MAILBOX0, 17, 13), + RK3576_CRU_RESET_OFFSET(SRST_P_GPIO1, 17, 15), + + /* SOFTRST_CON18 */ + RK3576_CRU_RESET_OFFSET(SRST_GPIO1, 18, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_GPIO2, 18, 1), + RK3576_CRU_RESET_OFFSET(SRST_GPIO2, 18, 2), + RK3576_CRU_RESET_OFFSET(SRST_P_GPIO3, 18, 3), + RK3576_CRU_RESET_OFFSET(SRST_GPIO3, 18, 4), + RK3576_CRU_RESET_OFFSET(SRST_P_GPIO4, 18, 5), + RK3576_CRU_RESET_OFFSET(SRST_GPIO4, 18, 6), + RK3576_CRU_RESET_OFFSET(SRST_A_DECOM, 18, 7), + RK3576_CRU_RESET_OFFSET(SRST_P_DECOM, 18, 8), + RK3576_CRU_RESET_OFFSET(SRST_D_DECOM, 18, 9), + RK3576_CRU_RESET_OFFSET(SRST_TIMER6, 18, 11), + RK3576_CRU_RESET_OFFSET(SRST_TIMER7, 18, 12), + RK3576_CRU_RESET_OFFSET(SRST_TIMER8, 18, 13), + RK3576_CRU_RESET_OFFSET(SRST_TIMER9, 18, 14), + RK3576_CRU_RESET_OFFSET(SRST_TIMER10, 18, 15), + + /* SOFTRST_CON19 */ + RK3576_CRU_RESET_OFFSET(SRST_TIMER11, 19, 0), + RK3576_CRU_RESET_OFFSET(SRST_A_DMAC0, 19, 1), + RK3576_CRU_RESET_OFFSET(SRST_A_DMAC1, 19, 2), + RK3576_CRU_RESET_OFFSET(SRST_A_DMAC2, 19, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_SPINLOCK, 19, 4), + RK3576_CRU_RESET_OFFSET(SRST_REF_PVTPLL_BUS, 19, 5), + RK3576_CRU_RESET_OFFSET(SRST_H_I3C0, 19, 7), + RK3576_CRU_RESET_OFFSET(SRST_H_I3C1, 19, 9), + RK3576_CRU_RESET_OFFSET(SRST_H_BUS_CM0_BIU, 19, 11), + RK3576_CRU_RESET_OFFSET(SRST_F_BUS_CM0_CORE, 19, 12), + RK3576_CRU_RESET_OFFSET(SRST_T_BUS_CM0_JTAG, 19, 13), + + /* SOFTRST_CON20 */ + RK3576_CRU_RESET_OFFSET(SRST_P_INTMUX2PMU, 20, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_INTMUX2DDR, 20, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_PVTPLL_BUS, 20, 3), + RK3576_CRU_RESET_OFFSET(SRST_P_PWM2, 20, 4), + RK3576_CRU_RESET_OFFSET(SRST_PWM2, 20, 5), + RK3576_CRU_RESET_OFFSET(SRST_FREQ_PWM1, 20, 8), + RK3576_CRU_RESET_OFFSET(SRST_COUNTER_PWM1, 20, 9), + RK3576_CRU_RESET_OFFSET(SRST_I3C0, 20, 12), + RK3576_CRU_RESET_OFFSET(SRST_I3C1, 20, 13), + + /* SOFTRST_CON21 */ + RK3576_CRU_RESET_OFFSET(SRST_P_DDR_MON_CH0, 21, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_DDR_BIU, 21, 2), + RK3576_CRU_RESET_OFFSET(SRST_P_DDR_UPCTL_CH0, 21, 3), + RK3576_CRU_RESET_OFFSET(SRST_TM_DDR_MON_CH0, 21, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_BIU, 21, 5), + RK3576_CRU_RESET_OFFSET(SRST_DFI_CH0, 21, 6), + RK3576_CRU_RESET_OFFSET(SRST_DDR_MON_CH0, 21, 10), + RK3576_CRU_RESET_OFFSET(SRST_P_DDR_HWLP_CH0, 21, 13), + RK3576_CRU_RESET_OFFSET(SRST_P_DDR_MON_CH1, 21, 14), + RK3576_CRU_RESET_OFFSET(SRST_P_DDR_HWLP_CH1, 21, 15), + + /* SOFTRST_CON22 */ + RK3576_CRU_RESET_OFFSET(SRST_P_DDR_UPCTL_CH1, 22, 0), + RK3576_CRU_RESET_OFFSET(SRST_TM_DDR_MON_CH1, 22, 1), + RK3576_CRU_RESET_OFFSET(SRST_DFI_CH1, 22, 2), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR01_MSCH0, 22, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR01_MSCH1, 22, 4), + RK3576_CRU_RESET_OFFSET(SRST_DDR_MON_CH1, 22, 6), + RK3576_CRU_RESET_OFFSET(SRST_DDR_SCRAMBLE_CH0, 22, 9), + RK3576_CRU_RESET_OFFSET(SRST_DDR_SCRAMBLE_CH1, 22, 10), + RK3576_CRU_RESET_OFFSET(SRST_P_AHB2APB, 22, 12), + RK3576_CRU_RESET_OFFSET(SRST_H_AHB2APB, 22, 13), + RK3576_CRU_RESET_OFFSET(SRST_H_DDR_BIU, 22, 14), + RK3576_CRU_RESET_OFFSET(SRST_F_DDR_CM0_CORE, 22, 15), + + /* SOFTRST_CON23 */ + RK3576_CRU_RESET_OFFSET(SRST_P_DDR01_MSCH0, 23, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_DDR01_MSCH1, 23, 2), + RK3576_CRU_RESET_OFFSET(SRST_DDR_TIMER0, 23, 4), + RK3576_CRU_RESET_OFFSET(SRST_DDR_TIMER1, 23, 5), + RK3576_CRU_RESET_OFFSET(SRST_T_WDT_DDR, 23, 6), + RK3576_CRU_RESET_OFFSET(SRST_P_WDT, 23, 7), + RK3576_CRU_RESET_OFFSET(SRST_P_TIMER, 23, 8), + RK3576_CRU_RESET_OFFSET(SRST_T_DDR_CM0_JTAG, 23, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_DDR_GRF, 23, 11), + + /* SOFTRST_CON25 */ + RK3576_CRU_RESET_OFFSET(SRST_DDR_UPCTL_CH0, 25, 1), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_0_CH0, 25, 2), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_1_CH0, 25, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_2_CH0, 25, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_3_CH0, 25, 5), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_4_CH0, 25, 6), + + /* SOFTRST_CON26 */ + RK3576_CRU_RESET_OFFSET(SRST_DDR_UPCTL_CH1, 26, 1), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_0_CH1, 26, 2), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_1_CH1, 26, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_2_CH1, 26, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_3_CH1, 26, 5), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_UPCTL_4_CH1, 26, 6), + + /* SOFTRST_CON27 */ + RK3576_CRU_RESET_OFFSET(SRST_REF_PVTPLL_DDR, 27, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_PVTPLL_DDR, 27, 1), + + /* SOFTRST_CON28 */ + RK3576_CRU_RESET_OFFSET(SRST_A_RKNN0, 28, 9), + RK3576_CRU_RESET_OFFSET(SRST_A_RKNN0_BIU, 28, 11), + RK3576_CRU_RESET_OFFSET(SRST_L_RKNN0_BIU, 28, 12), + + /* SOFTRST_CON29 */ + RK3576_CRU_RESET_OFFSET(SRST_A_RKNN1, 29, 0), + RK3576_CRU_RESET_OFFSET(SRST_A_RKNN1_BIU, 29, 2), + RK3576_CRU_RESET_OFFSET(SRST_L_RKNN1_BIU, 29, 3), + + /* SOFTRST_CON31 */ + RK3576_CRU_RESET_OFFSET(SRST_NPU_DAP, 31, 0), + RK3576_CRU_RESET_OFFSET(SRST_L_NPUSUBSYS_BIU, 31, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_NPUTOP_BIU, 31, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_NPU_TIMER, 31, 10), + RK3576_CRU_RESET_OFFSET(SRST_NPUTIMER0, 31, 12), + RK3576_CRU_RESET_OFFSET(SRST_NPUTIMER1, 31, 13), + RK3576_CRU_RESET_OFFSET(SRST_P_NPU_WDT, 31, 14), + RK3576_CRU_RESET_OFFSET(SRST_T_NPU_WDT, 31, 15), + + /* SOFTRST_CON32 */ + RK3576_CRU_RESET_OFFSET(SRST_A_RKNN_CBUF, 32, 0), + RK3576_CRU_RESET_OFFSET(SRST_A_RVCORE0, 32, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_NPU_GRF, 32, 2), + RK3576_CRU_RESET_OFFSET(SRST_P_PVTPLL_NPU, 32, 3), + RK3576_CRU_RESET_OFFSET(SRST_NPU_PVTPLL, 32, 4), + RK3576_CRU_RESET_OFFSET(SRST_H_NPU_CM0_BIU, 32, 6), + RK3576_CRU_RESET_OFFSET(SRST_F_NPU_CM0_CORE, 32, 7), + RK3576_CRU_RESET_OFFSET(SRST_T_NPU_CM0_JTAG, 32, 8), + RK3576_CRU_RESET_OFFSET(SRST_A_RKNNTOP_BIU, 32, 11), + RK3576_CRU_RESET_OFFSET(SRST_H_RKNN_CBUF, 32, 12), + RK3576_CRU_RESET_OFFSET(SRST_H_RKNNTOP_BIU, 32, 13), + + /* SOFTRST_CON33 */ + RK3576_CRU_RESET_OFFSET(SRST_H_NVM_BIU, 33, 2), + RK3576_CRU_RESET_OFFSET(SRST_A_NVM_BIU, 33, 3), + RK3576_CRU_RESET_OFFSET(SRST_S_FSPI, 33, 6), + RK3576_CRU_RESET_OFFSET(SRST_H_FSPI, 33, 7), + RK3576_CRU_RESET_OFFSET(SRST_C_EMMC, 33, 8), + RK3576_CRU_RESET_OFFSET(SRST_H_EMMC, 33, 9), + RK3576_CRU_RESET_OFFSET(SRST_A_EMMC, 33, 10), + RK3576_CRU_RESET_OFFSET(SRST_B_EMMC, 33, 11), + RK3576_CRU_RESET_OFFSET(SRST_T_EMMC, 33, 12), + + /* SOFTRST_CON34 */ + RK3576_CRU_RESET_OFFSET(SRST_P_GRF, 34, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_PHP_BIU, 34, 5), + RK3576_CRU_RESET_OFFSET(SRST_A_PHP_BIU, 34, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_PCIE0, 34, 13), + RK3576_CRU_RESET_OFFSET(SRST_PCIE0_POWER_UP, 34, 15), + + /* SOFTRST_CON35 */ + RK3576_CRU_RESET_OFFSET(SRST_A_USB3OTG1, 35, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_MMU0, 35, 11), + RK3576_CRU_RESET_OFFSET(SRST_A_SLV_MMU0, 35, 13), + RK3576_CRU_RESET_OFFSET(SRST_A_MMU1, 35, 14), + + /* SOFTRST_CON36 */ + RK3576_CRU_RESET_OFFSET(SRST_A_SLV_MMU1, 36, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_PCIE1, 36, 7), + RK3576_CRU_RESET_OFFSET(SRST_PCIE1_POWER_UP, 36, 9), + + /* SOFTRST_CON37 */ + RK3576_CRU_RESET_OFFSET(SRST_RXOOB0, 37, 0), + RK3576_CRU_RESET_OFFSET(SRST_RXOOB1, 37, 1), + RK3576_CRU_RESET_OFFSET(SRST_PMALIVE0, 37, 2), + RK3576_CRU_RESET_OFFSET(SRST_PMALIVE1, 37, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_SATA0, 37, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_SATA1, 37, 5), + RK3576_CRU_RESET_OFFSET(SRST_ASIC1, 37, 6), + RK3576_CRU_RESET_OFFSET(SRST_ASIC0, 37, 7), + + /* SOFTRST_CON40 */ + RK3576_CRU_RESET_OFFSET(SRST_P_CSIDPHY1, 40, 2), + RK3576_CRU_RESET_OFFSET(SRST_SCAN_CSIDPHY1, 40, 3), + + /* SOFTRST_CON42 */ + RK3576_CRU_RESET_OFFSET(SRST_P_SDGMAC_GRF, 42, 3), + RK3576_CRU_RESET_OFFSET(SRST_P_SDGMAC_BIU, 42, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_SDGMAC_BIU, 42, 5), + RK3576_CRU_RESET_OFFSET(SRST_H_SDGMAC_BIU, 42, 6), + RK3576_CRU_RESET_OFFSET(SRST_A_GMAC0, 42, 7), + RK3576_CRU_RESET_OFFSET(SRST_A_GMAC1, 42, 8), + RK3576_CRU_RESET_OFFSET(SRST_P_GMAC0, 42, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_GMAC1, 42, 10), + RK3576_CRU_RESET_OFFSET(SRST_H_SDIO, 42, 12), + + /* SOFTRST_CON43 */ + RK3576_CRU_RESET_OFFSET(SRST_H_SDMMC0, 43, 2), + RK3576_CRU_RESET_OFFSET(SRST_S_FSPI1, 43, 3), + RK3576_CRU_RESET_OFFSET(SRST_H_FSPI1, 43, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_DSMC_BIU, 43, 6), + RK3576_CRU_RESET_OFFSET(SRST_A_DSMC, 43, 7), + RK3576_CRU_RESET_OFFSET(SRST_P_DSMC, 43, 8), + RK3576_CRU_RESET_OFFSET(SRST_H_HSGPIO, 43, 10), + RK3576_CRU_RESET_OFFSET(SRST_HSGPIO, 43, 11), + RK3576_CRU_RESET_OFFSET(SRST_A_HSGPIO, 43, 13), + + /* SOFTRST_CON45 */ + RK3576_CRU_RESET_OFFSET(SRST_H_RKVDEC, 45, 3), + RK3576_CRU_RESET_OFFSET(SRST_H_RKVDEC_BIU, 45, 5), + RK3576_CRU_RESET_OFFSET(SRST_A_RKVDEC_BIU, 45, 6), + RK3576_CRU_RESET_OFFSET(SRST_RKVDEC_HEVC_CA, 45, 8), + RK3576_CRU_RESET_OFFSET(SRST_RKVDEC_CORE, 45, 9), + + /* SOFTRST_CON47 */ + RK3576_CRU_RESET_OFFSET(SRST_A_USB_BIU, 47, 3), + RK3576_CRU_RESET_OFFSET(SRST_P_USBUFS_BIU, 47, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_USB3OTG0, 47, 5), + RK3576_CRU_RESET_OFFSET(SRST_A_UFS_BIU, 47, 10), + RK3576_CRU_RESET_OFFSET(SRST_A_MMU2, 47, 12), + RK3576_CRU_RESET_OFFSET(SRST_A_SLV_MMU2, 47, 13), + RK3576_CRU_RESET_OFFSET(SRST_A_UFS_SYS, 47, 15), + + /* SOFTRST_CON48 */ + RK3576_CRU_RESET_OFFSET(SRST_A_UFS, 48, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_USBUFS_GRF, 48, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_UFS_GRF, 48, 2), + + /* SOFTRST_CON49 */ + RK3576_CRU_RESET_OFFSET(SRST_H_VPU_BIU, 49, 6), + RK3576_CRU_RESET_OFFSET(SRST_A_JPEG_BIU, 49, 7), + RK3576_CRU_RESET_OFFSET(SRST_A_RGA_BIU, 49, 10), + RK3576_CRU_RESET_OFFSET(SRST_A_VDPP_BIU, 49, 11), + RK3576_CRU_RESET_OFFSET(SRST_A_EBC_BIU, 49, 12), + RK3576_CRU_RESET_OFFSET(SRST_H_RGA2E_0, 49, 13), + RK3576_CRU_RESET_OFFSET(SRST_A_RGA2E_0, 49, 14), + RK3576_CRU_RESET_OFFSET(SRST_CORE_RGA2E_0, 49, 15), + + /* SOFTRST_CON50 */ + RK3576_CRU_RESET_OFFSET(SRST_A_JPEG, 50, 0), + RK3576_CRU_RESET_OFFSET(SRST_H_JPEG, 50, 1), + RK3576_CRU_RESET_OFFSET(SRST_H_VDPP, 50, 2), + RK3576_CRU_RESET_OFFSET(SRST_A_VDPP, 50, 3), + RK3576_CRU_RESET_OFFSET(SRST_CORE_VDPP, 50, 4), + RK3576_CRU_RESET_OFFSET(SRST_H_RGA2E_1, 50, 5), + RK3576_CRU_RESET_OFFSET(SRST_A_RGA2E_1, 50, 6), + RK3576_CRU_RESET_OFFSET(SRST_CORE_RGA2E_1, 50, 7), + RK3576_CRU_RESET_OFFSET(SRST_H_EBC, 50, 10), + RK3576_CRU_RESET_OFFSET(SRST_A_EBC, 50, 11), + RK3576_CRU_RESET_OFFSET(SRST_D_EBC, 50, 12), + + /* SOFTRST_CON51 */ + RK3576_CRU_RESET_OFFSET(SRST_H_VEPU0_BIU, 51, 2), + RK3576_CRU_RESET_OFFSET(SRST_A_VEPU0_BIU, 51, 3), + RK3576_CRU_RESET_OFFSET(SRST_H_VEPU0, 51, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_VEPU0, 51, 5), + RK3576_CRU_RESET_OFFSET(SRST_VEPU0_CORE, 51, 6), + + /* SOFTRST_CON53 */ + RK3576_CRU_RESET_OFFSET(SRST_A_VI_BIU, 53, 3), + RK3576_CRU_RESET_OFFSET(SRST_H_VI_BIU, 53, 4), + RK3576_CRU_RESET_OFFSET(SRST_P_VI_BIU, 53, 5), + RK3576_CRU_RESET_OFFSET(SRST_D_VICAP, 53, 6), + RK3576_CRU_RESET_OFFSET(SRST_A_VICAP, 53, 7), + RK3576_CRU_RESET_OFFSET(SRST_H_VICAP, 53, 8), + RK3576_CRU_RESET_OFFSET(SRST_ISP0, 53, 10), + RK3576_CRU_RESET_OFFSET(SRST_ISP0_VICAP, 53, 11), + + /* SOFTRST_CON54 */ + RK3576_CRU_RESET_OFFSET(SRST_CORE_VPSS, 54, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_CSI_HOST_0, 54, 4), + RK3576_CRU_RESET_OFFSET(SRST_P_CSI_HOST_1, 54, 5), + RK3576_CRU_RESET_OFFSET(SRST_P_CSI_HOST_2, 54, 6), + RK3576_CRU_RESET_OFFSET(SRST_P_CSI_HOST_3, 54, 7), + RK3576_CRU_RESET_OFFSET(SRST_P_CSI_HOST_4, 54, 8), + + /* SOFTRST_CON59 */ + RK3576_CRU_RESET_OFFSET(SRST_CIFIN, 59, 0), + RK3576_CRU_RESET_OFFSET(SRST_VICAP_I0CLK, 59, 1), + RK3576_CRU_RESET_OFFSET(SRST_VICAP_I1CLK, 59, 2), + RK3576_CRU_RESET_OFFSET(SRST_VICAP_I2CLK, 59, 3), + RK3576_CRU_RESET_OFFSET(SRST_VICAP_I3CLK, 59, 4), + RK3576_CRU_RESET_OFFSET(SRST_VICAP_I4CLK, 59, 5), + + /* SOFTRST_CON61 */ + RK3576_CRU_RESET_OFFSET(SRST_A_VOP_BIU, 61, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_VOP2_BIU, 61, 5), + RK3576_CRU_RESET_OFFSET(SRST_H_VOP_BIU, 61, 6), + RK3576_CRU_RESET_OFFSET(SRST_P_VOP_BIU, 61, 7), + RK3576_CRU_RESET_OFFSET(SRST_H_VOP, 61, 8), + RK3576_CRU_RESET_OFFSET(SRST_A_VOP, 61, 9), + RK3576_CRU_RESET_OFFSET(SRST_D_VP0, 61, 13), + + /* SOFTRST_CON62 */ + RK3576_CRU_RESET_OFFSET(SRST_D_VP1, 62, 0), + RK3576_CRU_RESET_OFFSET(SRST_D_VP2, 62, 1), + RK3576_CRU_RESET_OFFSET(SRST_P_VOP2_BIU, 62, 2), + RK3576_CRU_RESET_OFFSET(SRST_P_VOPGRF, 62, 3), + + /* SOFTRST_CON63 */ + RK3576_CRU_RESET_OFFSET(SRST_H_VO0_BIU, 63, 5), + RK3576_CRU_RESET_OFFSET(SRST_P_VO0_BIU, 63, 7), + RK3576_CRU_RESET_OFFSET(SRST_A_HDCP0_BIU, 63, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_VO0_GRF, 63, 10), + RK3576_CRU_RESET_OFFSET(SRST_A_HDCP0, 63, 12), + RK3576_CRU_RESET_OFFSET(SRST_H_HDCP0, 63, 13), + RK3576_CRU_RESET_OFFSET(SRST_HDCP0, 63, 14), + + /* SOFTRST_CON64 */ + RK3576_CRU_RESET_OFFSET(SRST_P_DSIHOST0, 64, 5), + RK3576_CRU_RESET_OFFSET(SRST_DSIHOST0, 64, 6), + RK3576_CRU_RESET_OFFSET(SRST_P_HDMITX0, 64, 7), + RK3576_CRU_RESET_OFFSET(SRST_HDMITX0_REF, 64, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_EDP0, 64, 13), + RK3576_CRU_RESET_OFFSET(SRST_EDP0_24M, 64, 14), + + /* SOFTRST_CON65 */ + RK3576_CRU_RESET_OFFSET(SRST_M_SAI5_8CH, 65, 4), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI5_8CH, 65, 5), + RK3576_CRU_RESET_OFFSET(SRST_M_SAI6_8CH, 65, 8), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI6_8CH, 65, 9), + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_TX2, 65, 10), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_TX2, 65, 13), + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_RX2, 65, 14), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_RX2, 65, 15), + + /* SOFTRST_CON66 */ + RK3576_CRU_RESET_OFFSET(SRST_H_SAI8_8CH, 66, 0), + RK3576_CRU_RESET_OFFSET(SRST_M_SAI8_8CH, 66, 2), + + /* SOFTRST_CON67 */ + RK3576_CRU_RESET_OFFSET(SRST_H_VO1_BIU, 67, 5), + RK3576_CRU_RESET_OFFSET(SRST_P_VO1_BIU, 67, 6), + RK3576_CRU_RESET_OFFSET(SRST_M_SAI7_8CH, 67, 9), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI7_8CH, 67, 10), + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_TX3, 67, 11), + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_TX4, 67, 12), + RK3576_CRU_RESET_OFFSET(SRST_H_SPDIF_TX5, 67, 13), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_TX3, 67, 14), + + /* SOFTRST_CON68 */ + RK3576_CRU_RESET_OFFSET(SRST_DP0, 68, 0), + RK3576_CRU_RESET_OFFSET(SRST_P_VO1_GRF, 68, 2), + RK3576_CRU_RESET_OFFSET(SRST_A_HDCP1_BIU, 68, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_HDCP1, 68, 4), + RK3576_CRU_RESET_OFFSET(SRST_H_HDCP1, 68, 5), + RK3576_CRU_RESET_OFFSET(SRST_HDCP1, 68, 6), + RK3576_CRU_RESET_OFFSET(SRST_H_SAI9_8CH, 68, 9), + RK3576_CRU_RESET_OFFSET(SRST_M_SAI9_8CH, 68, 11), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_TX4, 68, 12), + RK3576_CRU_RESET_OFFSET(SRST_M_SPDIF_TX5, 68, 13), + + /* SOFTRST_CON69 */ + RK3576_CRU_RESET_OFFSET(SRST_GPU, 69, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_S_GPU_BIU, 69, 6), + RK3576_CRU_RESET_OFFSET(SRST_A_M0_GPU_BIU, 69, 7), + RK3576_CRU_RESET_OFFSET(SRST_P_GPU_BIU, 69, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_GPU_GRF, 69, 13), + RK3576_CRU_RESET_OFFSET(SRST_GPU_PVTPLL, 69, 14), + RK3576_CRU_RESET_OFFSET(SRST_P_PVTPLL_GPU, 69, 15), + + /* SOFTRST_CON72 */ + RK3576_CRU_RESET_OFFSET(SRST_A_CENTER_BIU, 72, 4), + RK3576_CRU_RESET_OFFSET(SRST_A_DMA2DDR, 72, 5), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_SHAREMEM, 72, 6), + RK3576_CRU_RESET_OFFSET(SRST_A_DDR_SHAREMEM_BIU, 72, 7), + RK3576_CRU_RESET_OFFSET(SRST_H_CENTER_BIU, 72, 8), + RK3576_CRU_RESET_OFFSET(SRST_P_CENTER_GRF, 72, 9), + RK3576_CRU_RESET_OFFSET(SRST_P_DMA2DDR, 72, 10), + RK3576_CRU_RESET_OFFSET(SRST_P_SHAREMEM, 72, 11), + RK3576_CRU_RESET_OFFSET(SRST_P_CENTER_BIU, 72, 12), + + /* SOFTRST_CON75 */ + RK3576_CRU_RESET_OFFSET(SRST_LINKSYM_HDMITXPHY0, 75, 1), + + /* SOFTRST_CON78 */ + RK3576_CRU_RESET_OFFSET(SRST_DP0_PIXELCLK, 78, 1), + RK3576_CRU_RESET_OFFSET(SRST_PHY_DP0_TX, 78, 2), + RK3576_CRU_RESET_OFFSET(SRST_DP1_PIXELCLK, 78, 3), + RK3576_CRU_RESET_OFFSET(SRST_DP2_PIXELCLK, 78, 4), + + /* SOFTRST_CON79 */ + RK3576_CRU_RESET_OFFSET(SRST_H_VEPU1_BIU, 79, 1), + RK3576_CRU_RESET_OFFSET(SRST_A_VEPU1_BIU, 79, 2), + RK3576_CRU_RESET_OFFSET(SRST_H_VEPU1, 79, 3), + RK3576_CRU_RESET_OFFSET(SRST_A_VEPU1, 79, 4), + RK3576_CRU_RESET_OFFSET(SRST_VEPU1_CORE, 79, 5), + + /* PPLL_SOFTRST_CON00 */ + RK3576_PHPCRU_RESET_OFFSET(SRST_P_PHPPHY_CRU, 0, 1), + RK3576_PHPCRU_RESET_OFFSET(SRST_P_APB2ASB_SLV_CHIP_TOP, 0, 3), + RK3576_PHPCRU_RESET_OFFSET(SRST_P_PCIE2_COMBOPHY0, 0, 5), + RK3576_PHPCRU_RESET_OFFSET(SRST_P_PCIE2_COMBOPHY0_GRF, 0, 6), + RK3576_PHPCRU_RESET_OFFSET(SRST_P_PCIE2_COMBOPHY1, 0, 7), + RK3576_PHPCRU_RESET_OFFSET(SRST_P_PCIE2_COMBOPHY1_GRF, 0, 8), + + /* PPLL_SOFTRST_CON01 */ + RK3576_PHPCRU_RESET_OFFSET(SRST_PCIE0_PIPE_PHY, 1, 5), + RK3576_PHPCRU_RESET_OFFSET(SRST_PCIE1_PIPE_PHY, 1, 8), + + /* SECURENS_SOFTRST_CON00 */ + RK3576_SECURENSCRU_RESET_OFFSET(SRST_H_CRYPTO_NS, 0, 3), + RK3576_SECURENSCRU_RESET_OFFSET(SRST_H_TRNG_NS, 0, 4), + RK3576_SECURENSCRU_RESET_OFFSET(SRST_P_OTPC_NS, 0, 8), + RK3576_SECURENSCRU_RESET_OFFSET(SRST_OTPC_NS, 0, 9), + + /* PMU1_SOFTRST_CON00 */ + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_HDPTX_GRF, 0, 0), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_HDPTX_APB, 0, 1), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_MIPI_DCPHY, 0, 2), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_DCPHY_GRF, 0, 3), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_BOT0_APB2ASB, 0, 4), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_BOT1_APB2ASB, 0, 5), + RK3576_PMU1CRU_RESET_OFFSET(SRST_USB2DEBUG, 0, 6), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_CSIPHY_GRF, 0, 7), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_CSIPHY, 0, 8), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_USBPHY_GRF_0, 0, 9), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_USBPHY_GRF_1, 0, 10), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_USBDP_GRF, 0, 11), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_USBDPPHY, 0, 12), + RK3576_PMU1CRU_RESET_OFFSET(SRST_USBDP_COMBO_PHY_INIT, 0, 15), + + /* PMU1_SOFTRST_CON01 */ + RK3576_PMU1CRU_RESET_OFFSET(SRST_USBDP_COMBO_PHY_CMN, 1, 0), + RK3576_PMU1CRU_RESET_OFFSET(SRST_USBDP_COMBO_PHY_LANE, 1, 1), + RK3576_PMU1CRU_RESET_OFFSET(SRST_USBDP_COMBO_PHY_PCS, 1, 2), + RK3576_PMU1CRU_RESET_OFFSET(SRST_M_MIPI_DCPHY, 1, 3), + RK3576_PMU1CRU_RESET_OFFSET(SRST_S_MIPI_DCPHY, 1, 4), + RK3576_PMU1CRU_RESET_OFFSET(SRST_SCAN_CSIPHY, 1, 5), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_VCCIO6_IOC, 1, 6), + RK3576_PMU1CRU_RESET_OFFSET(SRST_OTGPHY_0, 1, 7), + RK3576_PMU1CRU_RESET_OFFSET(SRST_OTGPHY_1, 1, 8), + RK3576_PMU1CRU_RESET_OFFSET(SRST_HDPTX_INIT, 1, 9), + RK3576_PMU1CRU_RESET_OFFSET(SRST_HDPTX_CMN, 1, 10), + RK3576_PMU1CRU_RESET_OFFSET(SRST_HDPTX_LANE, 1, 11), + RK3576_PMU1CRU_RESET_OFFSET(SRST_HDMITXHDP, 1, 13), + + /* PMU1_SOFTRST_CON02 */ + RK3576_PMU1CRU_RESET_OFFSET(SRST_MPHY_INIT, 2, 0), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_MPHY_GRF, 2, 1), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_VCCIO7_IOC, 2, 3), + + /* PMU1_SOFTRST_CON03 */ + RK3576_PMU1CRU_RESET_OFFSET(SRST_H_PMU1_BIU, 3, 9), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_PMU1_NIU, 3, 10), + RK3576_PMU1CRU_RESET_OFFSET(SRST_H_PMU_CM0_BIU, 3, 11), + RK3576_PMU1CRU_RESET_OFFSET(SRST_PMU_CM0_CORE, 3, 12), + RK3576_PMU1CRU_RESET_OFFSET(SRST_PMU_CM0_JTAG, 3, 13), + + /* PMU1_SOFTRST_CON04 */ + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_CRU_PMU1, 4, 1), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_PMU1_GRF, 4, 3), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_PMU1_IOC, 4, 4), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_PMU1WDT, 4, 5), + RK3576_PMU1CRU_RESET_OFFSET(SRST_T_PMU1WDT, 4, 6), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_PMUTIMER, 4, 7), + RK3576_PMU1CRU_RESET_OFFSET(SRST_PMUTIMER0, 4, 9), + RK3576_PMU1CRU_RESET_OFFSET(SRST_PMUTIMER1, 4, 10), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_PMU1PWM, 4, 11), + RK3576_PMU1CRU_RESET_OFFSET(SRST_PMU1PWM, 4, 12), + + /* PMU1_SOFTRST_CON05 */ + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_I2C0, 5, 1), + RK3576_PMU1CRU_RESET_OFFSET(SRST_I2C0, 5, 2), + RK3576_PMU1CRU_RESET_OFFSET(SRST_S_UART1, 5, 5), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_UART1, 5, 6), + RK3576_PMU1CRU_RESET_OFFSET(SRST_PDM0, 5, 13), + RK3576_PMU1CRU_RESET_OFFSET(SRST_H_PDM0, 5, 15), + + /* PMU1_SOFTRST_CON06 */ + RK3576_PMU1CRU_RESET_OFFSET(SRST_M_PDM0, 6, 0), + RK3576_PMU1CRU_RESET_OFFSET(SRST_H_VAD, 6, 1), + + /* PMU1_SOFTRST_CON07 */ + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_PMU0GRF, 7, 4), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_PMU0IOC, 7, 5), + RK3576_PMU1CRU_RESET_OFFSET(SRST_P_GPIO0, 7, 6), + RK3576_PMU1CRU_RESET_OFFSET(SRST_DB_GPIO0, 7, 7), +}; + +int rk3576_reset_bind_lut(struct udevice *pdev, u32 reg_offset, u32 reg_number) +{ + return rockchip_reset_bind_lut(pdev, rk3576_register_offset, + reg_offset, reg_number); +} diff --git a/drivers/rng/rockchip_rng.c b/drivers/rng/rockchip_rng.c index 2426648fbd5..d854ea90044 100644 --- a/drivers/rng/rockchip_rng.c +++ b/drivers/rng/rockchip_rng.c @@ -70,6 +70,27 @@ #define TRNG_v1_VERSION_CODE 0x46BC /* end of TRNG V1 register define */ +/* start of RKRNG register define */ +#define RKRNG_CTRL 0x0010 +#define RKRNG_CTRL_INST_REQ BIT(0) +#define RKRNG_CTRL_RESEED_REQ BIT(1) +#define RKRNG_CTRL_TEST_REQ BIT(2) +#define RKRNG_CTRL_SW_DRNG_REQ BIT(3) +#define RKRNG_CTRL_SW_TRNG_REQ BIT(4) + +#define RKRNG_STATE 0x0014 +#define RKRNG_STATE_INST_ACK BIT(0) +#define RKRNG_STATE_RESEED_ACK BIT(1) +#define RKRNG_STATE_TEST_ACK BIT(2) +#define RKRNG_STATE_SW_DRNG_ACK BIT(3) +#define RKRNG_STATE_SW_TRNG_ACK BIT(4) + +/* DRNG_DATA_0 ~ DNG_DATA_7 */ +#define RKRNG_DRNG_DATA_0 0x0070 +#define RKRNG_DRNG_DATA_7 0x008C + +/* end of RKRNG register define */ + #define RK_RNG_TIME_OUT 50000 /* max 50ms */ #define trng_write(pdata, pos, val) writel(val, (pdata)->base + (pos)) @@ -228,6 +249,49 @@ exit: return retval; } +static int rkrng_init(struct udevice *dev) +{ + struct rk_rng_plat *pdata = dev_get_priv(dev); + u32 reg = 0; + + rk_clrreg(pdata->base + RKRNG_CTRL, 0xffff); + + reg = trng_read(pdata, RKRNG_STATE); + trng_write(pdata, RKRNG_STATE, reg); + + return 0; +} + +static int rkrng_rng_read(struct udevice *dev, void *data, size_t len) +{ + struct rk_rng_plat *pdata = dev_get_priv(dev); + u32 reg = 0; + int retval; + + if (len > RK_HW_RNG_MAX) + return -EINVAL; + + reg = RKRNG_CTRL_SW_DRNG_REQ; + + rk_clrsetreg(pdata->base + RKRNG_CTRL, 0xffff, reg); + + retval = readl_poll_timeout(pdata->base + RKRNG_STATE, reg, + (reg & RKRNG_STATE_SW_DRNG_ACK), + RK_RNG_TIME_OUT); + if (retval) + goto exit; + + trng_write(pdata, RKRNG_STATE, reg); + + rk_rng_read_regs(pdata->base + RKRNG_DRNG_DATA_0, data, len); + +exit: + /* close TRNG */ + rk_clrreg(pdata->base + RKRNG_CTRL, 0xffff); + + return retval; +} + static int rockchip_rng_read(struct udevice *dev, void *data, size_t len) { unsigned char *buf = data; @@ -295,6 +359,11 @@ static const struct rk_rng_soc_data rk_trngv1_soc_data = { .rk_rng_read = rk_trngv1_rng_read, }; +static const struct rk_rng_soc_data rkrng_soc_data = { + .rk_rng_init = rkrng_init, + .rk_rng_read = rkrng_rng_read, +}; + static const struct dm_rng_ops rockchip_rng_ops = { .read = rockchip_rng_read, }; @@ -313,13 +382,21 @@ static const struct udevice_id rockchip_rng_match[] = { .data = (ulong)&rk_cryptov1_soc_data, }, { + .compatible = "rockchip,rk3568-rng", + .data = (ulong)&rk_cryptov2_soc_data, + }, + { .compatible = "rockchip,cryptov2-rng", .data = (ulong)&rk_cryptov2_soc_data, }, { - .compatible = "rockchip,trngv1", + .compatible = "rockchip,rk3588-rng", .data = (ulong)&rk_trngv1_soc_data, }, + { + .compatible = "rockchip,rkrng", + .data = (ulong)&rkrng_soc_data, + }, {}, }; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c815764c2bc..46a83141481 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -85,6 +85,7 @@ config USB_GADGET_PRODUCT_NUM default 0x330e if ROCKCHIP_RK3308 default 0x350a if ROCKCHIP_RK3568 default 0x350b if ROCKCHIP_RK3588 + default 0x350c if ROCKCHIP_RK3528 default 0x0 help Product ID of the USB device emulated, reported to the host device. |
