summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/renesas/Kconfig1
-rw-r--r--drivers/clk/rockchip/Makefile1
-rw-r--r--drivers/clk/rockchip/clk_pll.c267
-rw-r--r--drivers/clk/rockchip/clk_rk3568.c3
-rw-r--r--drivers/clk/rockchip/clk_rk3588.c1996
-rw-r--r--drivers/gpio/rk_gpio.c20
-rw-r--r--drivers/misc/Kconfig4
-rw-r--r--drivers/misc/rockchip-efuse.c333
-rw-r--r--drivers/misc/rockchip-otp.c230
-rw-r--r--drivers/mmc/renesas-sdhi.c30
-rw-r--r--drivers/mmc/rockchip_dw_mmc.c8
-rw-r--r--drivers/phy/rockchip/Kconfig7
-rw-r--r--drivers/phy/rockchip/Makefile1
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-usb2.c65
-rw-r--r--drivers/phy/rockchip/phy-rockchip-naneng-combphy.c441
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-37xx.c14
-rw-r--r--drivers/pinctrl/renesas/sh_pfc.h15
-rw-r--r--drivers/pinctrl/rockchip/Makefile1
-rw-r--r--drivers/pinctrl/rockchip/pinctrl-rk3568.c362
-rw-r--r--drivers/ram/rockchip/Makefile1
-rw-r--r--drivers/ram/rockchip/sdram_rk3588.c57
-rw-r--r--drivers/sysinfo/rcar3.c19
-rw-r--r--drivers/timer/sandbox_timer.c2
-rw-r--r--drivers/usb/Kconfig11
24 files changed, 3742 insertions, 147 deletions
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 1686410d6d3..d58e897ca1b 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -49,6 +49,7 @@ config CLK_RCAR_GEN3
def_bool y if RCAR_GEN3
depends on CLK_RENESAS
select CLK_RCAR_CPG_LIB
+ select DM_RESET
help
Enable this to support the clocks on Renesas RCar Gen3 SoC.
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index f719f4e3791..9e379cc2e3b 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -16,5 +16,6 @@ obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o
obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o
obj-$(CONFIG_ROCKCHIP_RK3568) += clk_rk3568.o
+obj-$(CONFIG_ROCKCHIP_RK3588) += clk_rk3588.o
obj-$(CONFIG_ROCKCHIP_RV1108) += clk_rv1108.o
obj-$(CONFIG_ROCKCHIP_RV1126) += clk_rv1126.o
diff --git a/drivers/clk/rockchip/clk_pll.c b/drivers/clk/rockchip/clk_pll.c
index 09b97cf57a2..d657ef38f3c 100644
--- a/drivers/clk/rockchip/clk_pll.c
+++ b/drivers/clk/rockchip/clk_pll.c
@@ -45,6 +45,10 @@ enum {
#define MIN_FOUTVCO_FREQ (800 * MHZ)
#define MAX_FOUTVCO_FREQ (2000 * MHZ)
+#define RK3588_VCO_MIN_HZ (2250UL * MHZ)
+#define RK3588_VCO_MAX_HZ (4500UL * MHZ)
+#define RK3588_FOUT_MIN_HZ (37UL * MHZ)
+#define RK3588_FOUT_MAX_HZ (4500UL * MHZ)
int gcd(int m, int n)
{
@@ -164,6 +168,65 @@ rockchip_pll_clk_set_by_auto(ulong fin_hz,
return rate_table;
}
+static struct rockchip_pll_rate_table *
+rk3588_pll_clk_set_by_auto(unsigned long fin_hz,
+ unsigned long fout_hz)
+{
+ struct rockchip_pll_rate_table *rate_table = &rockchip_auto_table;
+ u32 p, m, s;
+ ulong fvco, fref, fout, ffrac;
+
+ if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
+ return NULL;
+
+ if (fout_hz > RK3588_FOUT_MAX_HZ || fout_hz < RK3588_FOUT_MIN_HZ)
+ return NULL;
+
+ if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) {
+ for (s = 0; s <= 6; s++) {
+ fvco = fout_hz << s;
+ if (fvco < RK3588_VCO_MIN_HZ ||
+ fvco > RK3588_VCO_MAX_HZ)
+ continue;
+ for (p = 2; p <= 4; p++) {
+ for (m = 64; m <= 1023; m++) {
+ if (fvco == m * fin_hz / p) {
+ rate_table->p = p;
+ rate_table->m = m;
+ rate_table->s = s;
+ rate_table->k = 0;
+ return rate_table;
+ }
+ }
+ }
+ }
+ pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz);
+ } else {
+ for (s = 0; s <= 6; s++) {
+ fvco = fout_hz << s;
+ if (fvco < RK3588_VCO_MIN_HZ ||
+ fvco > RK3588_VCO_MAX_HZ)
+ continue;
+ for (p = 1; p <= 4; p++) {
+ for (m = 64; m <= 1023; m++) {
+ if ((fvco >= m * fin_hz / p) && (fvco < (m + 1) * fin_hz / p)) {
+ rate_table->p = p;
+ rate_table->m = m;
+ rate_table->s = s;
+ fref = fin_hz / p;
+ ffrac = fvco - (m * fref);
+ fout = ffrac * 65536;
+ rate_table->k = fout / fref;
+ return rate_table;
+ }
+ }
+ }
+ }
+ pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz);
+ }
+ return NULL;
+}
+
static const struct rockchip_pll_rate_table *
rockchip_get_pll_settings(struct rockchip_pll_clock *pll, ulong rate)
{
@@ -174,10 +237,14 @@ rockchip_get_pll_settings(struct rockchip_pll_clock *pll, ulong rate)
break;
rate_table++;
}
- if (rate_table->rate != rate)
- return rockchip_pll_clk_set_by_auto(24 * MHZ, rate);
- else
+ if (rate_table->rate != rate) {
+ if (pll->type == pll_rk3588)
+ return rk3588_pll_clk_set_by_auto(24 * MHZ, rate);
+ else
+ return rockchip_pll_clk_set_by_auto(24 * MHZ, rate);
+ } else {
return rate_table;
+ }
}
static int rk3036_pll_set_rate(struct rockchip_pll_clock *pll,
@@ -296,6 +363,192 @@ static ulong rk3036_pll_get_rate(struct rockchip_pll_clock *pll,
}
}
+#define RK3588_PLLCON(i) ((i) * 0x4)
+#define RK3588_PLLCON0_M_MASK 0x3ff << 0
+#define RK3588_PLLCON0_M_SHIFT 0
+#define RK3588_PLLCON1_P_MASK 0x3f << 0
+#define RK3588_PLLCON1_P_SHIFT 0
+#define RK3588_PLLCON1_S_MASK 0x7 << 6
+#define RK3588_PLLCON1_S_SHIFT 6
+#define RK3588_PLLCON2_K_MASK 0xffff
+#define RK3588_PLLCON2_K_SHIFT 0
+#define RK3588_PLLCON1_PWRDOWN BIT(13)
+#define RK3588_PLLCON6_LOCK_STATUS BIT(15)
+#define RK3588_B0PLL_CLKSEL_CON(i) ((i) * 0x4 + 0x50000 + 0x300)
+#define RK3588_B1PLL_CLKSEL_CON(i) ((i) * 0x4 + 0x52000 + 0x300)
+#define RK3588_LPLL_CLKSEL_CON(i) ((i) * 0x4 + 0x58000 + 0x300)
+#define RK3588_CORE_DIV_MASK 0x1f
+#define RK3588_CORE_L02_DIV_SHIFT 0
+#define RK3588_CORE_L13_DIV_SHIFT 7
+#define RK3588_CORE_B02_DIV_SHIFT 8
+#define RK3588_CORE_B13_DIV_SHIFT 0
+
+static int rk3588_pll_set_rate(struct rockchip_pll_clock *pll,
+ void __iomem *base, ulong pll_id,
+ ulong drate)
+{
+ const struct rockchip_pll_rate_table *rate;
+
+ rate = rockchip_get_pll_settings(pll, drate);
+ if (!rate) {
+ printf("%s unsupported rate\n", __func__);
+ return -EINVAL;
+ }
+
+ debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n",
+ __func__, rate->rate, rate->p, rate->m, rate->s, rate->k);
+
+ /*
+ * When power on or changing PLL setting,
+ * we must force PLL into slow mode to ensure output stable clock.
+ */
+ if (pll_id == 3)
+ rk_clrsetreg(base + 0x84c, 0x1 << 1, 0x1 << 1);
+
+ rk_clrsetreg(base + pll->mode_offset,
+ pll->mode_mask << pll->mode_shift,
+ RKCLK_PLL_MODE_SLOW << pll->mode_shift);
+ if (pll_id == 0)
+ rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(0),
+ pll->mode_mask << 6,
+ RKCLK_PLL_MODE_SLOW << 6);
+ else if (pll_id == 1)
+ rk_clrsetreg(base + RK3588_B1PLL_CLKSEL_CON(0),
+ pll->mode_mask << 6,
+ RKCLK_PLL_MODE_SLOW << 6);
+ else if (pll_id == 2)
+ rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(5),
+ pll->mode_mask << 14,
+ RKCLK_PLL_MODE_SLOW << 14);
+
+ /* Power down */
+ rk_setreg(base + pll->con_offset + RK3588_PLLCON(1),
+ RK3588_PLLCON1_PWRDOWN);
+
+ rk_clrsetreg(base + pll->con_offset,
+ RK3588_PLLCON0_M_MASK,
+ (rate->m << RK3588_PLLCON0_M_SHIFT));
+ rk_clrsetreg(base + pll->con_offset + RK3588_PLLCON(1),
+ (RK3588_PLLCON1_P_MASK |
+ RK3588_PLLCON1_S_MASK),
+ (rate->p << RK3588_PLLCON1_P_SHIFT |
+ rate->s << RK3588_PLLCON1_S_SHIFT));
+ if (rate->k) {
+ rk_clrsetreg(base + pll->con_offset + RK3588_PLLCON(2),
+ RK3588_PLLCON2_K_MASK,
+ rate->k << RK3588_PLLCON2_K_SHIFT);
+ }
+ /* Power up */
+ rk_clrreg(base + pll->con_offset + RK3588_PLLCON(1),
+ RK3588_PLLCON1_PWRDOWN);
+
+ /* waiting for pll lock */
+ while (!(readl(base + pll->con_offset + RK3588_PLLCON(6)) &
+ RK3588_PLLCON6_LOCK_STATUS)) {
+ udelay(1);
+ debug("%s: wait pll lock, pll_id=%ld\n", __func__, pll_id);
+ }
+
+ rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift,
+ RKCLK_PLL_MODE_NORMAL << pll->mode_shift);
+ if (pll_id == 0) {
+ rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(0),
+ pll->mode_mask << 6,
+ 2 << 6);
+ rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(0),
+ RK3588_CORE_DIV_MASK << RK3588_CORE_B02_DIV_SHIFT,
+ 0 << RK3588_CORE_B02_DIV_SHIFT);
+ rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(1),
+ RK3588_CORE_DIV_MASK << RK3588_CORE_B13_DIV_SHIFT,
+ 0 << RK3588_CORE_B13_DIV_SHIFT);
+ } else if (pll_id == 1) {
+ rk_clrsetreg(base + RK3588_B1PLL_CLKSEL_CON(0),
+ pll->mode_mask << 6,
+ 2 << 6);
+ rk_clrsetreg(base + RK3588_B1PLL_CLKSEL_CON(0),
+ RK3588_CORE_DIV_MASK << RK3588_CORE_B02_DIV_SHIFT,
+ 0 << RK3588_CORE_B02_DIV_SHIFT);
+ rk_clrsetreg(base + RK3588_B1PLL_CLKSEL_CON(1),
+ RK3588_CORE_DIV_MASK << RK3588_CORE_B13_DIV_SHIFT,
+ 0 << RK3588_CORE_B13_DIV_SHIFT);
+ } else if (pll_id == 2) {
+ rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(5),
+ pll->mode_mask << 14,
+ 2 << 14);
+ rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(6),
+ RK3588_CORE_DIV_MASK << RK3588_CORE_L13_DIV_SHIFT,
+ 0 << RK3588_CORE_L13_DIV_SHIFT);
+ rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(6),
+ RK3588_CORE_DIV_MASK << RK3588_CORE_L02_DIV_SHIFT,
+ 0 << RK3588_CORE_L02_DIV_SHIFT);
+ rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(7),
+ RK3588_CORE_DIV_MASK << RK3588_CORE_L13_DIV_SHIFT,
+ 0 << RK3588_CORE_L13_DIV_SHIFT);
+ rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(7),
+ RK3588_CORE_DIV_MASK << RK3588_CORE_L02_DIV_SHIFT,
+ 0 << RK3588_CORE_L02_DIV_SHIFT);
+ }
+
+ if (pll_id == 3)
+ rk_clrsetreg(base + 0x84c, 0x1 << 1, 0);
+
+ 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),
+ readl(base + pll->con_offset + 0x8),
+ readl(base + pll->mode_offset));
+
+ return 0;
+}
+
+static ulong rk3588_pll_get_rate(struct rockchip_pll_clock *pll,
+ void __iomem *base, ulong pll_id)
+{
+ u32 m, p, s, k;
+ u32 con = 0, shift, mode;
+ u64 rate, postdiv;
+
+ con = readl(base + pll->mode_offset);
+ shift = pll->mode_shift;
+ if (pll_id == 8)
+ mode = RKCLK_PLL_MODE_NORMAL;
+ else
+ mode = (con & (pll->mode_mask << shift)) >> shift;
+ switch (mode) {
+ case RKCLK_PLL_MODE_SLOW:
+ return OSC_HZ;
+ case RKCLK_PLL_MODE_NORMAL:
+ /* normal mode */
+ con = readl(base + pll->con_offset);
+ m = (con & RK3588_PLLCON0_M_MASK) >>
+ RK3588_PLLCON0_M_SHIFT;
+ con = readl(base + pll->con_offset + RK3588_PLLCON(1));
+ p = (con & RK3588_PLLCON1_P_MASK) >>
+ RK3036_PLLCON0_FBDIV_SHIFT;
+ s = (con & RK3588_PLLCON1_S_MASK) >>
+ RK3588_PLLCON1_S_SHIFT;
+ con = readl(base + pll->con_offset + RK3588_PLLCON(2));
+ k = (con & RK3588_PLLCON2_K_MASK) >>
+ RK3588_PLLCON2_K_SHIFT;
+
+ rate = OSC_HZ / p;
+ rate *= m;
+ if (k) {
+ /* fractional mode */
+ u64 frac_rate64 = OSC_HZ * k;
+
+ postdiv = p * 65536;
+ do_div(frac_rate64, postdiv);
+ rate += frac_rate64;
+ }
+ rate = rate >> s;
+ return rate;
+ case RKCLK_PLL_MODE_DEEP:
+ default:
+ return 32768;
+ }
+}
+
ulong rockchip_pll_get_rate(struct rockchip_pll_clock *pll,
void __iomem *base,
ulong pll_id)
@@ -311,6 +564,10 @@ ulong rockchip_pll_get_rate(struct rockchip_pll_clock *pll,
pll->mode_mask = PLL_RK3328_MODE_MASK;
rate = rk3036_pll_get_rate(pll, base, pll_id);
break;
+ case pll_rk3588:
+ pll->mode_mask = PLL_MODE_MASK;
+ rate = rk3588_pll_get_rate(pll, base, pll_id);
+ break;
default:
printf("%s: Unknown pll type for pll clk %ld\n",
__func__, pll_id);
@@ -336,6 +593,10 @@ int rockchip_pll_set_rate(struct rockchip_pll_clock *pll,
pll->mode_mask = PLL_RK3328_MODE_MASK;
ret = rk3036_pll_set_rate(pll, base, pll_id, drate);
break;
+ case pll_rk3588:
+ pll->mode_mask = PLL_MODE_MASK;
+ ret = rk3588_pll_set_rate(pll, base, pll_id, drate);
+ break;
default:
printf("%s: Unknown pll type for pll clk %ld\n",
__func__, pll_id);
diff --git a/drivers/clk/rockchip/clk_rk3568.c b/drivers/clk/rockchip/clk_rk3568.c
index d5e45e7602c..99c195b3afe 100644
--- a/drivers/clk/rockchip/clk_rk3568.c
+++ b/drivers/clk/rockchip/clk_rk3568.c
@@ -1442,6 +1442,7 @@ static ulong rk3568_sdmmc_set_clk(struct rk3568_clk_priv *priv,
switch (rate) {
case OSC_HZ:
case 26 * MHz:
+ case 25 * MHz:
src_clk = CLK_SDMMC_SEL_24M;
break;
case 400 * MHz:
@@ -1631,6 +1632,8 @@ static ulong rk3568_emmc_set_clk(struct rk3568_clk_priv *priv, ulong rate)
switch (rate) {
case OSC_HZ:
+ case 26 * MHz:
+ case 25 * MHz:
src_clk = CCLK_EMMC_SEL_24M;
break;
case 52 * MHz:
diff --git a/drivers/clk/rockchip/clk_rk3588.c b/drivers/clk/rockchip/clk_rk3588.c
new file mode 100644
index 00000000000..5271d943483
--- /dev/null
+++ b/drivers/clk/rockchip/clk_rk3588.c
@@ -0,0 +1,1996 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Elaine Zhang <zhangqing@rock-chips.com>
+ */
+
+#include <common.h>
+#include <bitfield.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/arch-rockchip/cru_rk3588.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dt-bindings/clock/rockchip,rk3588-cru.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
+
+static struct rockchip_pll_rate_table rk3588_pll_rates[] = {
+ /* _mhz, _p, _m, _s, _k */
+ RK3588_PLL_RATE(1500000000, 2, 250, 1, 0),
+ RK3588_PLL_RATE(1200000000, 2, 200, 1, 0),
+ RK3588_PLL_RATE(1188000000, 2, 198, 1, 0),
+ RK3588_PLL_RATE(1100000000, 3, 550, 2, 0),
+ RK3588_PLL_RATE(1008000000, 2, 336, 2, 0),
+ RK3588_PLL_RATE(1000000000, 3, 500, 2, 0),
+ RK3588_PLL_RATE(900000000, 2, 300, 2, 0),
+ RK3588_PLL_RATE(850000000, 3, 425, 2, 0),
+ RK3588_PLL_RATE(816000000, 2, 272, 2, 0),
+ RK3588_PLL_RATE(786432000, 2, 262, 2, 9437),
+ RK3588_PLL_RATE(786000000, 1, 131, 2, 0),
+ RK3588_PLL_RATE(722534400, 8, 963, 2, 24850),
+ RK3588_PLL_RATE(600000000, 2, 200, 2, 0),
+ RK3588_PLL_RATE(594000000, 2, 198, 2, 0),
+ RK3588_PLL_RATE(200000000, 3, 400, 4, 0),
+ RK3588_PLL_RATE(100000000, 3, 400, 5, 0),
+ { /* sentinel */ },
+};
+
+static struct rockchip_pll_clock rk3588_pll_clks[] = {
+ [B0PLL] = PLL(pll_rk3588, PLL_B0PLL, RK3588_B0_PLL_CON(0),
+ RK3588_B0_PLL_MODE_CON, 0, 15, 0,
+ rk3588_pll_rates),
+ [B1PLL] = PLL(pll_rk3588, PLL_B1PLL, RK3588_B1_PLL_CON(8),
+ RK3588_B1_PLL_MODE_CON, 0, 15, 0,
+ rk3588_pll_rates),
+ [LPLL] = PLL(pll_rk3588, PLL_LPLL, RK3588_LPLL_CON(16),
+ RK3588_LPLL_MODE_CON, 0, 15, 0, rk3588_pll_rates),
+ [V0PLL] = PLL(pll_rk3588, PLL_V0PLL, RK3588_PLL_CON(88),
+ RK3588_MODE_CON0, 4, 15, 0, rk3588_pll_rates),
+ [AUPLL] = PLL(pll_rk3588, PLL_AUPLL, RK3588_PLL_CON(96),
+ RK3588_MODE_CON0, 6, 15, 0, rk3588_pll_rates),
+ [CPLL] = PLL(pll_rk3588, PLL_CPLL, RK3588_PLL_CON(104),
+ RK3588_MODE_CON0, 8, 15, 0, rk3588_pll_rates),
+ [GPLL] = PLL(pll_rk3588, PLL_GPLL, RK3588_PLL_CON(112),
+ RK3588_MODE_CON0, 2, 15, 0, rk3588_pll_rates),
+ [NPLL] = PLL(pll_rk3588, PLL_NPLL, RK3588_PLL_CON(120),
+ RK3588_MODE_CON0, 0, 15, 0, rk3588_pll_rates),
+ [PPLL] = PLL(pll_rk3588, PLL_PPLL, RK3588_PMU_PLL_CON(128),
+ RK3588_MODE_CON0, 10, 15, 0, rk3588_pll_rates),
+};
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *
+ * rational_best_approximation(31415, 10000,
+ * (1 << 8) - 1, (1 << 5) - 1, &n, &d);
+ *
+ * you may look at given_numerator as a fixed point number,
+ * with the fractional part size described in given_denominator.
+ *
+ * for theoretical background, see:
+ * http://en.wikipedia.org/wiki/Continued_fraction
+ */
+static void rational_best_approximation(unsigned long given_numerator,
+ unsigned long given_denominator,
+ unsigned long max_numerator,
+ unsigned long max_denominator,
+ unsigned long *best_numerator,
+ unsigned long *best_denominator)
+{
+ unsigned long n, d, n0, d0, n1, d1;
+
+ n = given_numerator;
+ d = given_denominator;
+ n0 = 0;
+ d1 = 0;
+ n1 = 1;
+ d0 = 1;
+ for (;;) {
+ unsigned long t, a;
+
+ if (n1 > max_numerator || d1 > max_denominator) {
+ n1 = n0;
+ d1 = d0;
+ break;
+ }
+ if (d == 0)
+ break;
+ t = d;
+ a = n / d;
+ d = n % d;
+ n = t;
+ t = n0 + a * n1;
+ n0 = n1;
+ n1 = t;
+ t = d0 + a * d1;
+ d0 = d1;
+ d1 = t;
+ }
+ *best_numerator = n1;
+ *best_denominator = d1;
+}
+#endif
+
+static ulong rk3588_center_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 con, sel, rate;
+
+ switch (clk_id) {
+ case ACLK_CENTER_ROOT:
+ con = readl(&cru->clksel_con[165]);
+ sel = (con & ACLK_CENTER_ROOT_SEL_MASK) >>
+ ACLK_CENTER_ROOT_SEL_SHIFT;
+ if (sel == ACLK_CENTER_ROOT_SEL_700M)
+ rate = 702 * MHz;
+ else if (sel == ACLK_CENTER_ROOT_SEL_400M)
+ rate = 396 * MHz;
+ else if (sel == ACLK_CENTER_ROOT_SEL_200M)
+ rate = 200 * MHz;
+ else
+ rate = OSC_HZ;
+ break;
+ case ACLK_CENTER_LOW_ROOT:
+ con = readl(&cru->clksel_con[165]);
+ sel = (con & ACLK_CENTER_LOW_ROOT_SEL_MASK) >>
+ ACLK_CENTER_LOW_ROOT_SEL_SHIFT;
+ if (sel == ACLK_CENTER_LOW_ROOT_SEL_500M)
+ rate = 500 * MHz;
+ else if (sel == ACLK_CENTER_LOW_ROOT_SEL_250M)
+ rate = 250 * MHz;
+ else if (sel == ACLK_CENTER_LOW_ROOT_SEL_100M)
+ rate = 100 * MHz;
+ else
+ rate = OSC_HZ;
+ break;
+ case HCLK_CENTER_ROOT:
+ con = readl(&cru->clksel_con[165]);
+ sel = (con & HCLK_CENTER_ROOT_SEL_MASK) >>
+ HCLK_CENTER_ROOT_SEL_SHIFT;
+ if (sel == HCLK_CENTER_ROOT_SEL_400M)
+ rate = 396 * MHz;
+ else if (sel == HCLK_CENTER_ROOT_SEL_200M)
+ rate = 200 * MHz;
+ else if (sel == HCLK_CENTER_ROOT_SEL_100M)
+ rate = 100 * MHz;
+ else
+ rate = OSC_HZ;
+ break;
+ case PCLK_CENTER_ROOT:
+ con = readl(&cru->clksel_con[165]);
+ sel = (con & PCLK_CENTER_ROOT_SEL_MASK) >>
+ PCLK_CENTER_ROOT_SEL_SHIFT;
+ if (sel == PCLK_CENTER_ROOT_SEL_200M)
+ rate = 200 * MHz;
+ else if (sel == PCLK_CENTER_ROOT_SEL_100M)
+ rate = 100 * MHz;
+ else if (sel == PCLK_CENTER_ROOT_SEL_50M)
+ rate = 50 * MHz;
+ else
+ rate = OSC_HZ;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rate;
+}
+
+static ulong rk3588_center_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ int src_clk;
+
+ switch (clk_id) {
+ case ACLK_CENTER_ROOT:
+ if (rate >= 700 * MHz)
+ src_clk = ACLK_CENTER_ROOT_SEL_700M;
+ else if (rate >= 396 * MHz)
+ src_clk = ACLK_CENTER_ROOT_SEL_400M;
+ else if (rate >= 200 * MHz)
+ src_clk = ACLK_CENTER_ROOT_SEL_200M;
+ else
+ src_clk = ACLK_CENTER_ROOT_SEL_24M;
+ rk_clrsetreg(&cru->clksel_con[165],
+ ACLK_CENTER_ROOT_SEL_MASK,
+ src_clk << ACLK_CENTER_ROOT_SEL_SHIFT);
+ break;
+ case ACLK_CENTER_LOW_ROOT:
+ if (rate >= 500 * MHz)
+ src_clk = ACLK_CENTER_LOW_ROOT_SEL_500M;
+ else if (rate >= 250 * MHz)
+ src_clk = ACLK_CENTER_LOW_ROOT_SEL_250M;
+ else if (rate >= 99 * MHz)
+ src_clk = ACLK_CENTER_LOW_ROOT_SEL_100M;
+ else
+ src_clk = ACLK_CENTER_LOW_ROOT_SEL_24M;
+ rk_clrsetreg(&cru->clksel_con[165],
+ ACLK_CENTER_LOW_ROOT_SEL_MASK,
+ src_clk << ACLK_CENTER_LOW_ROOT_SEL_SHIFT);
+ break;
+ case HCLK_CENTER_ROOT:
+ if (rate >= 396 * MHz)
+ src_clk = HCLK_CENTER_ROOT_SEL_400M;
+ else if (rate >= 198 * MHz)
+ src_clk = HCLK_CENTER_ROOT_SEL_200M;
+ else if (rate >= 99 * MHz)
+ src_clk = HCLK_CENTER_ROOT_SEL_100M;
+ else
+ src_clk = HCLK_CENTER_ROOT_SEL_24M;
+ rk_clrsetreg(&cru->clksel_con[165],
+ HCLK_CENTER_ROOT_SEL_MASK,
+ src_clk << HCLK_CENTER_ROOT_SEL_SHIFT);
+ break;
+ case PCLK_CENTER_ROOT:
+ if (rate >= 198 * MHz)
+ src_clk = PCLK_CENTER_ROOT_SEL_200M;
+ else if (rate >= 99 * MHz)
+ src_clk = PCLK_CENTER_ROOT_SEL_100M;
+ else if (rate >= 50 * MHz)
+ src_clk = PCLK_CENTER_ROOT_SEL_50M;
+ else
+ src_clk = PCLK_CENTER_ROOT_SEL_24M;
+ rk_clrsetreg(&cru->clksel_con[165],
+ PCLK_CENTER_ROOT_SEL_MASK,
+ src_clk << PCLK_CENTER_ROOT_SEL_SHIFT);
+ break;
+ default:
+ printf("do not support this center freq\n");
+ return -EINVAL;
+ }
+
+ return rk3588_center_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_top_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 con, sel, div, rate, prate;
+
+ switch (clk_id) {
+ case ACLK_TOP_ROOT:
+ con = readl(&cru->clksel_con[8]);
+ div = (con & ACLK_TOP_ROOT_DIV_MASK) >>
+ ACLK_TOP_ROOT_DIV_SHIFT;
+ sel = (con & ACLK_TOP_ROOT_SRC_SEL_MASK) >>
+ ACLK_TOP_ROOT_SRC_SEL_SHIFT;
+ if (sel == ACLK_TOP_ROOT_SRC_SEL_CPLL)
+ prate = priv->cpll_hz;
+ else
+ prate = priv->gpll_hz;
+ return DIV_TO_RATE(prate, div);
+ case ACLK_LOW_TOP_ROOT:
+ con = readl(&cru->clksel_con[8]);
+ div = (con & ACLK_LOW_TOP_ROOT_DIV_MASK) >>
+ ACLK_LOW_TOP_ROOT_DIV_SHIFT;
+ sel = (con & ACLK_LOW_TOP_ROOT_SRC_SEL_MASK) >>
+ ACLK_LOW_TOP_ROOT_SRC_SEL_SHIFT;
+ if (sel == ACLK_LOW_TOP_ROOT_SRC_SEL_CPLL)
+ prate = priv->cpll_hz;
+ else
+ prate = priv->gpll_hz;
+ return DIV_TO_RATE(prate, div);
+ case PCLK_TOP_ROOT:
+ con = readl(&cru->clksel_con[8]);
+ sel = (con & PCLK_TOP_ROOT_SEL_MASK) >> PCLK_TOP_ROOT_SEL_SHIFT;
+ if (sel == PCLK_TOP_ROOT_SEL_100M)
+ rate = 100 * MHz;
+ else if (sel == PCLK_TOP_ROOT_SEL_50M)
+ rate = 50 * MHz;
+ else
+ rate = OSC_HZ;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rate;
+}
+
+static ulong rk3588_top_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ int src_clk, src_clk_div;
+
+ switch (clk_id) {
+ case ACLK_TOP_ROOT:
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ assert(src_clk_div - 1 <= 31);
+ rk_clrsetreg(&cru->clksel_con[8],
+ ACLK_TOP_ROOT_DIV_MASK |
+ ACLK_TOP_ROOT_SRC_SEL_MASK,
+ (ACLK_TOP_ROOT_SRC_SEL_GPLL <<
+ ACLK_TOP_ROOT_SRC_SEL_SHIFT) |
+ (src_clk_div - 1) << ACLK_TOP_ROOT_DIV_SHIFT);
+ break;
+ case ACLK_LOW_TOP_ROOT:
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ assert(src_clk_div - 1 <= 31);
+ rk_clrsetreg(&cru->clksel_con[8],
+ ACLK_LOW_TOP_ROOT_DIV_MASK |
+ ACLK_LOW_TOP_ROOT_SRC_SEL_MASK,
+ (ACLK_LOW_TOP_ROOT_SRC_SEL_GPLL <<
+ ACLK_LOW_TOP_ROOT_SRC_SEL_SHIFT) |
+ (src_clk_div - 1) << ACLK_LOW_TOP_ROOT_DIV_SHIFT);
+ break;
+ case PCLK_TOP_ROOT:
+ if (rate == 100 * MHz)
+ src_clk = PCLK_TOP_ROOT_SEL_100M;
+ else if (rate == 50 * MHz)
+ src_clk = PCLK_TOP_ROOT_SEL_50M;
+ else
+ src_clk = PCLK_TOP_ROOT_SEL_24M;
+ rk_clrsetreg(&cru->clksel_con[8],
+ PCLK_TOP_ROOT_SEL_MASK,
+ src_clk << PCLK_TOP_ROOT_SEL_SHIFT);
+ break;
+ default:
+ printf("do not support this top freq\n");
+ return -EINVAL;
+ }
+
+ return rk3588_top_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_i2c_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 sel, con;
+ ulong rate;
+
+ switch (clk_id) {
+ case CLK_I2C0:
+ con = readl(&cru->pmuclksel_con[3]);
+ sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT;
+ break;
+ case CLK_I2C1:
+ con = readl(&cru->clksel_con[38]);
+ sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT;
+ break;
+ case CLK_I2C2:
+ con = readl(&cru->clksel_con[38]);
+ sel = (con & CLK_I2C2_SEL_MASK) >> CLK_I2C2_SEL_SHIFT;
+ break;
+ case CLK_I2C3:
+ con = readl(&cru->clksel_con[38]);
+ sel = (con & CLK_I2C3_SEL_MASK) >> CLK_I2C3_SEL_SHIFT;
+ break;
+ case CLK_I2C4:
+ con = readl(&cru->clksel_con[38]);
+ sel = (con & CLK_I2C4_SEL_MASK) >> CLK_I2C4_SEL_SHIFT;
+ break;
+ case CLK_I2C5:
+ con = readl(&cru->clksel_con[38]);
+ sel = (con & CLK_I2C5_SEL_MASK) >> CLK_I2C5_SEL_SHIFT;
+ break;
+ case CLK_I2C6:
+ con = readl(&cru->clksel_con[38]);
+ sel = (con & CLK_I2C6_SEL_MASK) >> CLK_I2C6_SEL_SHIFT;
+ break;
+ case CLK_I2C7:
+ con = readl(&cru->clksel_con[38]);
+ sel = (con & CLK_I2C7_SEL_MASK) >> CLK_I2C7_SEL_SHIFT;
+ break;
+ case CLK_I2C8:
+ con = readl(&cru->clksel_con[38]);
+ sel = (con & CLK_I2C8_SEL_MASK) >> CLK_I2C8_SEL_SHIFT;
+ break;
+ default:
+ return -ENOENT;
+ }
+ if (sel == CLK_I2C_SEL_200M)
+ rate = 200 * MHz;
+ else
+ rate = 100 * MHz;
+
+ return rate;
+}
+
+static ulong rk3588_i2c_set_clk(struct rk3588_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ int src_clk;
+
+ if (rate >= 198 * MHz)
+ src_clk = CLK_I2C_SEL_200M;
+ else
+ src_clk = CLK_I2C_SEL_100M;
+
+ switch (clk_id) {
+ case CLK_I2C0:
+ rk_clrsetreg(&cru->pmuclksel_con[3], CLK_I2C0_SEL_MASK,
+ src_clk << CLK_I2C0_SEL_SHIFT);
+ break;
+ case CLK_I2C1:
+ rk_clrsetreg(&cru->clksel_con[38], CLK_I2C1_SEL_MASK,
+ src_clk << CLK_I2C1_SEL_SHIFT);
+ break;
+ case CLK_I2C2:
+ rk_clrsetreg(&cru->clksel_con[38], CLK_I2C2_SEL_MASK,
+ src_clk << CLK_I2C2_SEL_SHIFT);
+ break;
+ case CLK_I2C3:
+ rk_clrsetreg(&cru->clksel_con[38], CLK_I2C3_SEL_MASK,
+ src_clk << CLK_I2C3_SEL_SHIFT);
+ break;
+ case CLK_I2C4:
+ rk_clrsetreg(&cru->clksel_con[38], CLK_I2C4_SEL_MASK,
+ src_clk << CLK_I2C4_SEL_SHIFT);
+ break;
+ case CLK_I2C5:
+ rk_clrsetreg(&cru->clksel_con[38], CLK_I2C5_SEL_MASK,
+ src_clk << CLK_I2C5_SEL_SHIFT);
+ break;
+ case CLK_I2C6:
+ rk_clrsetreg(&cru->clksel_con[38], CLK_I2C6_SEL_MASK,
+ src_clk << CLK_I2C6_SEL_SHIFT);
+ break;
+ case CLK_I2C7:
+ rk_clrsetreg(&cru->clksel_con[38], CLK_I2C7_SEL_MASK,
+ src_clk << CLK_I2C7_SEL_SHIFT);
+ break;
+ case CLK_I2C8:
+ rk_clrsetreg(&cru->clksel_con[38], CLK_I2C8_SEL_MASK,
+ src_clk << CLK_I2C8_SEL_SHIFT);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3588_i2c_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_spi_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 sel, con;
+
+ con = readl(&cru->clksel_con[59]);
+
+ switch (clk_id) {
+ case CLK_SPI0:
+ sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
+ break;
+ case CLK_SPI1:
+ sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT;
+ break;
+ case CLK_SPI2:
+ sel = (con & CLK_SPI2_SEL_MASK) >> CLK_SPI2_SEL_SHIFT;
+ break;
+ case CLK_SPI3:
+ sel = (con & CLK_SPI3_SEL_MASK) >> CLK_SPI3_SEL_SHIFT;
+ break;
+ case CLK_SPI4:
+ 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_150M:
+ return 150 * MHz;
+ case CLK_SPI_SEL_24M:
+ return OSC_HZ;
+ default:
+ return -ENOENT;
+ }
+}
+
+static ulong rk3588_spi_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ int src_clk;
+
+ if (rate >= 198 * MHz)
+ src_clk = CLK_SPI_SEL_200M;
+ else if (rate >= 140 * MHz)
+ src_clk = CLK_SPI_SEL_150M;
+ else
+ src_clk = CLK_SPI_SEL_24M;
+
+ switch (clk_id) {
+ case CLK_SPI0:
+ rk_clrsetreg(&cru->clksel_con[59],
+ CLK_SPI0_SEL_MASK,
+ src_clk << CLK_SPI0_SEL_SHIFT);
+ break;
+ case CLK_SPI1:
+ rk_clrsetreg(&cru->clksel_con[59],
+ CLK_SPI1_SEL_MASK,
+ src_clk << CLK_SPI1_SEL_SHIFT);
+ break;
+ case CLK_SPI2:
+ rk_clrsetreg(&cru->clksel_con[59],
+ CLK_SPI2_SEL_MASK,
+ src_clk << CLK_SPI2_SEL_SHIFT);
+ break;
+ case CLK_SPI3:
+ rk_clrsetreg(&cru->clksel_con[59],
+ CLK_SPI3_SEL_MASK,
+ src_clk << CLK_SPI3_SEL_SHIFT);
+ break;
+ case CLK_SPI4:
+ rk_clrsetreg(&cru->clksel_con[59],
+ CLK_SPI4_SEL_MASK,
+ src_clk << CLK_SPI4_SEL_SHIFT);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3588_spi_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_pwm_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 sel, con;
+
+ switch (clk_id) {
+ case CLK_PWM1:
+ con = readl(&cru->clksel_con[59]);
+ sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
+ break;
+ case CLK_PWM2:
+ con = readl(&cru->clksel_con[59]);
+ sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT;
+ break;
+ case CLK_PWM3:
+ con = readl(&cru->clksel_con[60]);
+ sel = (con & CLK_PWM3_SEL_MASK) >> CLK_PWM3_SEL_SHIFT;
+ break;
+ case CLK_PMU1PWM:
+ con = readl(&cru->pmuclksel_con[2]);
+ 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_24M:
+ return OSC_HZ;
+ default:
+ return -ENOENT;
+ }
+}
+
+static ulong rk3588_pwm_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_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_24M;
+
+ switch (clk_id) {
+ case CLK_PWM1:
+ rk_clrsetreg(&cru->clksel_con[59],
+ CLK_PWM1_SEL_MASK,
+ src_clk << CLK_PWM1_SEL_SHIFT);
+ break;
+ case CLK_PWM2:
+ rk_clrsetreg(&cru->clksel_con[59],
+ CLK_PWM2_SEL_MASK,
+ src_clk << CLK_PWM2_SEL_SHIFT);
+ break;
+ case CLK_PWM3:
+ rk_clrsetreg(&cru->clksel_con[60],
+ CLK_PWM3_SEL_MASK,
+ src_clk << CLK_PWM3_SEL_SHIFT);
+ break;
+ case CLK_PMU1PWM:
+ rk_clrsetreg(&cru->pmuclksel_con[2],
+ CLK_PMU1PWM_SEL_MASK,
+ src_clk << CLK_PMU1PWM_SEL_SHIFT);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3588_pwm_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_adc_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 div, sel, con, prate;
+
+ switch (clk_id) {
+ case CLK_SARADC:
+ con = readl(&cru->clksel_con[40]);
+ 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_24M)
+ prate = OSC_HZ;
+ else
+ prate = priv->gpll_hz;
+ return DIV_TO_RATE(prate, div);
+ case CLK_TSADC:
+ con = readl(&cru->clksel_con[41]);
+ div = (con & CLK_TSADC_DIV_MASK) >>
+ CLK_TSADC_DIV_SHIFT;
+ sel = (con & CLK_TSADC_SEL_MASK) >>
+ CLK_TSADC_SEL_SHIFT;
+ if (sel == CLK_TSADC_SEL_24M)
+ prate = OSC_HZ;
+ else
+ prate = 100 * MHz;
+ return DIV_TO_RATE(prate, div);
+ default:
+ return -ENOENT;
+ }
+}
+
+static ulong rk3588_adc_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_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[40],
+ CLK_SARADC_SEL_MASK |
+ CLK_SARADC_DIV_MASK,
+ (CLK_SARADC_SEL_24M <<
+ 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[40],
+ 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:
+ if (!(OSC_HZ % rate)) {
+ src_clk_div = DIV_ROUND_UP(OSC_HZ, rate);
+ assert(src_clk_div - 1 <= 255);
+ rk_clrsetreg(&cru->clksel_con[41],
+ CLK_TSADC_SEL_MASK |
+ CLK_TSADC_DIV_MASK,
+ (CLK_TSADC_SEL_24M <<
+ CLK_TSADC_SEL_SHIFT) |
+ (src_clk_div - 1) <<
+ CLK_TSADC_DIV_SHIFT);
+ } else {
+ src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ assert(src_clk_div - 1 <= 7);
+ rk_clrsetreg(&cru->clksel_con[41],
+ CLK_TSADC_SEL_MASK |
+ CLK_TSADC_DIV_MASK,
+ (CLK_TSADC_SEL_GPLL <<
+ CLK_TSADC_SEL_SHIFT) |
+ (src_clk_div - 1) <<
+ CLK_TSADC_DIV_SHIFT);
+ }
+ break;
+ default:
+ return -ENOENT;
+ }
+ return rk3588_adc_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_mmc_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 sel, con, div, prate;
+
+ switch (clk_id) {
+ case CCLK_SRC_SDIO:
+ con = readl(&cru->clksel_con[172]);
+ 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_EMMC:
+ con = readl(&cru->clksel_con[77]);
+ 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[78]);
+ div = (con & BCLK_EMMC_DIV_MASK) >> BCLK_EMMC_DIV_SHIFT;
+ sel = (con & BCLK_EMMC_SEL_MASK) >>
+ BCLK_EMMC_SEL_SHIFT;
+ if (sel == CCLK_EMMC_SEL_CPLL)
+ prate = priv->cpll_hz;
+ else
+ prate = priv->gpll_hz;
+ return DIV_TO_RATE(prate, div);
+ case SCLK_SFC:
+ con = readl(&cru->clksel_con[78]);
+ 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_GPLL)
+ prate = priv->gpll_hz;
+ else if (sel == SCLK_SFC_SEL_CPLL)
+ prate = priv->cpll_hz;
+ else
+ prate = OSC_HZ;
+ return DIV_TO_RATE(prate, div);
+ case DCLK_DECOM:
+ con = readl(&cru->clksel_con[62]);
+ 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 = 702 * MHz;
+ else
+ prate = priv->gpll_hz;
+ return DIV_TO_RATE(prate, div);
+ default:
+ return -ENOENT;
+ }
+}
+
+static ulong rk3588_mmc_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ int src_clk, div;
+
+ switch (clk_id) {
+ case CCLK_SRC_SDIO:
+ case CCLK_EMMC:
+ case SCLK_SFC:
+ if (!(OSC_HZ % rate)) {
+ src_clk = SCLK_SFC_SEL_24M;
+ div = DIV_ROUND_UP(OSC_HZ, rate);
+ } else if (!(priv->cpll_hz % rate)) {
+ src_clk = SCLK_SFC_SEL_CPLL;
+ div = DIV_ROUND_UP(priv->cpll_hz, rate);
+ } else {
+ src_clk = SCLK_SFC_SEL_GPLL;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ }
+ break;
+ case BCLK_EMMC:
+ if (!(priv->cpll_hz % rate)) {
+ src_clk = CCLK_EMMC_SEL_CPLL;
+ div = DIV_ROUND_UP(priv->cpll_hz, rate);
+ } else {
+ src_clk = CCLK_EMMC_SEL_GPLL;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ }
+ break;
+ case DCLK_DECOM:
+ if (!(702 * MHz % rate)) {
+ src_clk = DCLK_DECOM_SEL_SPLL;
+ div = DIV_ROUND_UP(702 * MHz, 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:
+ rk_clrsetreg(&cru->clksel_con[172],
+ 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_EMMC:
+ rk_clrsetreg(&cru->clksel_con[77],
+ CCLK_EMMC_SEL_MASK |
+ CCLK_EMMC_DIV_MASK,
+ (src_clk << CCLK_EMMC_SEL_SHIFT) |
+ (div - 1) << CCLK_EMMC_DIV_SHIFT);
+ break;
+ case BCLK_EMMC:
+ rk_clrsetreg(&cru->clksel_con[78],
+ BCLK_EMMC_DIV_MASK |
+ BCLK_EMMC_SEL_MASK,
+ (src_clk << BCLK_EMMC_SEL_SHIFT) |
+ (div - 1) << BCLK_EMMC_DIV_SHIFT);
+ break;
+ case SCLK_SFC:
+ rk_clrsetreg(&cru->clksel_con[78],
+ SCLK_SFC_DIV_MASK |
+ SCLK_SFC_SEL_MASK,
+ (src_clk << SCLK_SFC_SEL_SHIFT) |
+ (div - 1) << SCLK_SFC_DIV_SHIFT);
+ break;
+ case DCLK_DECOM:
+ rk_clrsetreg(&cru->clksel_con[62],
+ 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 rk3588_mmc_get_clk(priv, clk_id);
+}
+
+#ifndef CONFIG_SPL_BUILD
+static ulong rk3588_aux16m_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 div, con, parent;
+
+ parent = priv->gpll_hz;
+ con = readl(&cru->clksel_con[117]);
+
+ switch (clk_id) {
+ case CLK_AUX16M_0:
+ div = (con & CLK_AUX16MHZ_0_DIV_MASK) >> CLK_AUX16MHZ_0_DIV_SHIFT;
+ return DIV_TO_RATE(parent, div);
+ case CLK_AUX16M_1:
+ div = (con & CLK_AUX16MHZ_1_DIV_MASK) >> CLK_AUX16MHZ_1_DIV_SHIFT;
+ return DIV_TO_RATE(parent, div);
+ default:
+ return -ENOENT;
+ }
+}
+
+static ulong rk3588_aux16m_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 div;
+
+ if (!priv->gpll_hz) {
+ printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
+ return -ENOENT;
+ }
+
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+
+ switch (clk_id) {
+ case CLK_AUX16M_0:
+ rk_clrsetreg(&cru->clksel_con[117], CLK_AUX16MHZ_0_DIV_MASK,
+ (div - 1) << CLK_AUX16MHZ_0_DIV_SHIFT);
+ break;
+ case CLK_AUX16M_1:
+ rk_clrsetreg(&cru->clksel_con[117], CLK_AUX16MHZ_1_DIV_MASK,
+ (div - 1) << CLK_AUX16MHZ_1_DIV_SHIFT);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3588_aux16m_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_aclk_vop_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 div, sel, con, parent;
+
+ switch (clk_id) {
+ case ACLK_VOP_ROOT:
+ case ACLK_VOP:
+ con = readl(&cru->clksel_con[110]);
+ 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_NPLL)
+ parent = priv->npll_hz;
+ else
+ parent = 702 * MHz;
+ return DIV_TO_RATE(parent, div);
+ case ACLK_VOP_LOW_ROOT:
+ con = readl(&cru->clksel_con[110]);
+ sel = (con & ACLK_VOP_LOW_ROOT_SEL_MASK) >>
+ ACLK_VOP_LOW_ROOT_SEL_SHIFT;
+ if (sel == ACLK_VOP_LOW_ROOT_SEL_400M)
+ return 396 * MHz;
+ else if (sel == ACLK_VOP_LOW_ROOT_SEL_200M)
+ return 200 * MHz;
+ else if (sel == ACLK_VOP_LOW_ROOT_SEL_100M)
+ return 100 * MHz;
+ else
+ return OSC_HZ;
+ case HCLK_VOP_ROOT:
+ con = readl(&cru->clksel_con[110]);
+ 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;
+ default:
+ return -ENOENT;
+ }
+}
+
+static ulong rk3588_aclk_vop_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ int src_clk, div;
+
+ switch (clk_id) {
+ case ACLK_VOP_ROOT:
+ case ACLK_VOP:
+ if (rate >= 850 * MHz) {
+ src_clk = ACLK_VOP_ROOT_SEL_NPLL;
+ div = 1;
+ } else if (rate >= 750 * MHz) {
+ src_clk = ACLK_VOP_ROOT_SEL_CPLL;
+ div = 2;
+ } else 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[110],
+ 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_VOP_LOW_ROOT:
+ if (rate == 400 * MHz || rate == 396 * MHz)
+ src_clk = ACLK_VOP_LOW_ROOT_SEL_400M;
+ else if (rate == 200 * MHz)
+ src_clk = ACLK_VOP_LOW_ROOT_SEL_200M;
+ else if (rate == 100 * MHz)
+ src_clk = ACLK_VOP_LOW_ROOT_SEL_100M;
+ else
+ src_clk = ACLK_VOP_LOW_ROOT_SEL_24M;
+ rk_clrsetreg(&cru->clksel_con[110],
+ ACLK_VOP_LOW_ROOT_SEL_MASK,
+ src_clk << ACLK_VOP_LOW_ROOT_SEL_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_24M;
+ rk_clrsetreg(&cru->clksel_con[110],
+ HCLK_VOP_ROOT_SEL_MASK,
+ src_clk << HCLK_VOP_ROOT_SEL_SHIFT);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3588_aclk_vop_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_dclk_vop_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 div, sel, con, parent;
+
+ switch (clk_id) {
+ case DCLK_VOP0:
+ case DCLK_VOP0_SRC:
+ con = readl(&cru->clksel_con[111]);
+ 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_VOP1:
+ case DCLK_VOP1_SRC:
+ con = readl(&cru->clksel_con[111]);
+ div = (con & DCLK1_VOP_SRC_DIV_MASK) >> DCLK1_VOP_SRC_DIV_SHIFT;
+ sel = (con & DCLK1_VOP_SRC_SEL_MASK) >> DCLK1_VOP_SRC_SEL_SHIFT;
+ break;
+ case DCLK_VOP2:
+ case DCLK_VOP2_SRC:
+ con = readl(&cru->clksel_con[112]);
+ div = (con & DCLK2_VOP_SRC_DIV_MASK) >> DCLK2_VOP_SRC_DIV_SHIFT;
+ sel = (con & DCLK2_VOP_SRC_SEL_MASK) >> DCLK2_VOP_SRC_SEL_SHIFT;
+ break;
+ case DCLK_VOP3:
+ con = readl(&cru->clksel_con[113]);
+ div = (con & DCLK3_VOP_SRC_DIV_MASK) >> DCLK3_VOP_SRC_DIV_SHIFT;
+ sel = (con & DCLK3_VOP_SRC_SEL_MASK) >> DCLK3_VOP_SRC_SEL_SHIFT;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (sel == DCLK_VOP_SRC_SEL_AUPLL)
+ parent = priv->aupll_hz;
+ else if (sel == DCLK_VOP_SRC_SEL_V0PLL)
+ parent = rockchip_pll_get_rate(&rk3588_pll_clks[V0PLL],
+ priv->cru, V0PLL);
+ else if (sel == DCLK_VOP_SRC_SEL_GPLL)
+ parent = priv->gpll_hz;
+ else if (sel == DCLK_VOP_SRC_SEL_CPLL)
+ parent = priv->cpll_hz;
+ else
+ return -ENOENT;
+
+ return DIV_TO_RATE(parent, div);
+}
+
+#define RK3588_VOP_PLL_LIMIT_FREQ 600000000
+
+static ulong rk3588_dclk_vop_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_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_VOP0:
+ case DCLK_VOP0_SRC:
+ conid = 111;
+ con = readl(&cru->clksel_con[111]);
+ 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_VOP1:
+ case DCLK_VOP1_SRC:
+ conid = 111;
+ con = readl(&cru->clksel_con[111]);
+ sel = (con & DCLK1_VOP_SRC_SEL_MASK) >> DCLK1_VOP_SRC_SEL_SHIFT;
+ mask = DCLK1_VOP_SRC_SEL_MASK | DCLK1_VOP_SRC_DIV_MASK;
+ div_shift = DCLK1_VOP_SRC_DIV_SHIFT;
+ sel_shift = DCLK1_VOP_SRC_SEL_SHIFT;
+ break;
+ case DCLK_VOP2:
+ case DCLK_VOP2_SRC:
+ conid = 112;
+ con = readl(&cru->clksel_con[112]);
+ sel = (con & DCLK2_VOP_SRC_SEL_MASK) >> DCLK2_VOP_SRC_SEL_SHIFT;
+ mask = DCLK2_VOP_SRC_SEL_MASK | DCLK2_VOP_SRC_DIV_MASK;
+ div_shift = DCLK2_VOP_SRC_DIV_SHIFT;
+ sel_shift = DCLK2_VOP_SRC_SEL_SHIFT;
+ break;
+ case DCLK_VOP3:
+ conid = 113;
+ con = readl(&cru->clksel_con[113]);
+ sel = (con & DCLK3_VOP_SRC_SEL_MASK) >> DCLK3_VOP_SRC_SEL_SHIFT;
+ mask = DCLK3_VOP_SRC_SEL_MASK | DCLK3_VOP_SRC_DIV_MASK;
+ div_shift = DCLK3_VOP_SRC_DIV_SHIFT;
+ sel_shift = DCLK3_VOP_SRC_SEL_SHIFT;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (sel == DCLK_VOP_SRC_SEL_V0PLL) {
+ div = DIV_ROUND_UP(RK3588_VOP_PLL_LIMIT_FREQ, rate);
+ rk_clrsetreg(&cru->clksel_con[conid],
+ mask,
+ DCLK_VOP_SRC_SEL_V0PLL << sel_shift |
+ ((div - 1) << div_shift));
+ rockchip_pll_set_rate(&rk3588_pll_clks[V0PLL],
+ priv->cru, V0PLL, div * rate);
+ } else {
+ for (i = 0; i <= DCLK_VOP_SRC_SEL_AUPLL; 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_AUPLL:
+ pll_rate = priv->aupll_hz;
+ break;
+ case DCLK_VOP_SRC_SEL_V0PLL:
+ 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 rk3588_dclk_vop_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_gmac_get_clk(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 con, div;
+
+ switch (clk_id) {
+ case CLK_GMAC0_PTP_REF:
+ con = readl(&cru->clksel_con[81]);
+ div = (con & CLK_GMAC0_PTP_DIV_MASK) >> CLK_GMAC0_PTP_DIV_SHIFT;
+ return DIV_TO_RATE(priv->cpll_hz, div);
+ case CLK_GMAC1_PTP_REF:
+ con = readl(&cru->clksel_con[81]);
+ div = (con & CLK_GMAC1_PTP_DIV_MASK) >> CLK_GMAC1_PTP_DIV_SHIFT;
+ return DIV_TO_RATE(priv->cpll_hz, div);
+ case CLK_GMAC_125M:
+ con = readl(&cru->clksel_con[83]);
+ div = (con & CLK_GMAC_125M_DIV_MASK) >> CLK_GMAC_125M_DIV_SHIFT;
+ return DIV_TO_RATE(priv->cpll_hz, div);
+ case CLK_GMAC_50M:
+ con = readl(&cru->clksel_con[84]);
+ div = (con & CLK_GMAC_50M_DIV_MASK) >> CLK_GMAC_50M_DIV_SHIFT;
+ return DIV_TO_RATE(priv->cpll_hz, div);
+ default:
+ return -ENOENT;
+ }
+}
+
+static ulong rk3588_gmac_set_clk(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ int div;
+
+ div = DIV_ROUND_UP(priv->cpll_hz, rate);
+
+ switch (clk_id) {
+ case CLK_GMAC0_PTP_REF:
+ rk_clrsetreg(&cru->clksel_con[81],
+ CLK_GMAC0_PTP_DIV_MASK | CLK_GMAC0_PTP_SEL_MASK,
+ CLK_GMAC0_PTP_SEL_CPLL << CLK_GMAC0_PTP_SEL_SHIFT |
+ (div - 1) << CLK_GMAC0_PTP_DIV_SHIFT);
+ break;
+ case CLK_GMAC1_PTP_REF:
+ rk_clrsetreg(&cru->clksel_con[81],
+ CLK_GMAC1_PTP_DIV_MASK | CLK_GMAC1_PTP_SEL_MASK,
+ CLK_GMAC1_PTP_SEL_CPLL << CLK_GMAC1_PTP_SEL_SHIFT |
+ (div - 1) << CLK_GMAC1_PTP_DIV_SHIFT);
+ break;
+
+ case CLK_GMAC_125M:
+ rk_clrsetreg(&cru->clksel_con[83],
+ CLK_GMAC_125M_DIV_MASK | CLK_GMAC_125M_SEL_MASK,
+ CLK_GMAC_125M_SEL_CPLL << CLK_GMAC_125M_SEL_SHIFT |
+ (div - 1) << CLK_GMAC_125M_DIV_SHIFT);
+ break;
+ case CLK_GMAC_50M:
+ rk_clrsetreg(&cru->clksel_con[84],
+ CLK_GMAC_50M_DIV_MASK | CLK_GMAC_50M_SEL_MASK,
+ CLK_GMAC_50M_SEL_CPLL << CLK_GMAC_50M_SEL_SHIFT |
+ (div - 1) << CLK_GMAC_50M_DIV_SHIFT);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3588_gmac_get_clk(priv, clk_id);
+}
+
+static ulong rk3588_uart_get_rate(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 reg, con, fracdiv, div, src, p_src, p_rate;
+ unsigned long m, n;
+
+ switch (clk_id) {
+ case SCLK_UART1:
+ reg = 41;
+ break;
+ case SCLK_UART2:
+ reg = 43;
+ break;
+ case SCLK_UART3:
+ reg = 45;
+ break;
+ case SCLK_UART4:
+ reg = 47;
+ break;
+ case SCLK_UART5:
+ reg = 49;
+ break;
+ case SCLK_UART6:
+ reg = 51;
+ break;
+ case SCLK_UART7:
+ reg = 53;
+ break;
+ case SCLK_UART8:
+ reg = 55;
+ break;
+ case SCLK_UART9:
+ reg = 57;
+ break;
+ default:
+ return -ENOENT;
+ }
+ con = readl(&cru->clksel_con[reg + 2]);
+ src = (con & CLK_UART_SEL_MASK) >> CLK_UART_SEL_SHIFT;
+ con = readl(&cru->clksel_con[reg]);
+ div = (con & CLK_UART_SRC_DIV_MASK) >> CLK_UART_SRC_DIV_SHIFT;
+ 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
+ p_rate = priv->cpll_hz;
+
+ if (src == CLK_UART_SEL_SRC) {
+ return DIV_TO_RATE(p_rate, div);
+ } else if (src == CLK_UART_SEL_FRAC) {
+ fracdiv = readl(&cru->clksel_con[reg + 1]);
+ 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 DIV_TO_RATE(p_rate, div) * n / m;
+ } else {
+ return OSC_HZ;
+ }
+}
+
+static ulong rk3588_uart_set_rate(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 reg, clk_src, uart_src, div;
+ unsigned long m = 0, n = 0, val;
+
+ if (priv->gpll_hz % rate == 0) {
+ clk_src = CLK_UART_SRC_SEL_GPLL;
+ uart_src = CLK_UART_SEL_SRC;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ } else if (priv->cpll_hz % rate == 0) {
+ clk_src = CLK_UART_SRC_SEL_CPLL;
+ uart_src = CLK_UART_SEL_SRC;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ } else if (rate == OSC_HZ) {
+ clk_src = CLK_UART_SRC_SEL_GPLL;
+ uart_src = CLK_UART_SEL_XIN24M;
+ div = 2;
+ } else {
+ clk_src = CLK_UART_SRC_SEL_GPLL;
+ uart_src = CLK_UART_SEL_FRAC;
+ div = 2;
+ rational_best_approximation(rate, priv->gpll_hz / div,
+ GENMASK(16 - 1, 0),
+ GENMASK(16 - 1, 0),
+ &m, &n);
+ }
+
+ switch (clk_id) {
+ case SCLK_UART1:
+ reg = 41;
+ break;
+ case SCLK_UART2:
+ reg = 43;
+ break;
+ case SCLK_UART3:
+ reg = 45;
+ break;
+ case SCLK_UART4:
+ reg = 47;
+ break;
+ case SCLK_UART5:
+ reg = 49;
+ break;
+ case SCLK_UART6:
+ reg = 51;
+ break;
+ case SCLK_UART7:
+ reg = 53;
+ break;
+ case SCLK_UART8:
+ reg = 55;
+ break;
+ case SCLK_UART9:
+ reg = 57;
+ break;
+ default:
+ return -ENOENT;
+ }
+ rk_clrsetreg(&cru->clksel_con[reg],
+ CLK_UART_SRC_SEL_MASK |
+ CLK_UART_SRC_DIV_MASK,
+ (clk_src << CLK_UART_SRC_SEL_SHIFT) |
+ ((div - 1) << CLK_UART_SRC_DIV_SHIFT));
+ rk_clrsetreg(&cru->clksel_con[reg + 2],
+ CLK_UART_SEL_MASK,
+ (uart_src << CLK_UART_SEL_SHIFT));
+ if (m && n) {
+ val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n;
+ writel(val, &cru->clksel_con[reg + 1]);
+ }
+
+ return rk3588_uart_get_rate(priv, clk_id);
+}
+
+static ulong rk3588_pciephy_get_rate(struct rk3588_clk_priv *priv, ulong clk_id)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 con, div, src;
+
+ switch (clk_id) {
+ case CLK_REF_PIPE_PHY0:
+ con = readl(&cru->clksel_con[177]);
+ src = (con & CLK_PCIE_PHY0_REF_SEL_MASK) >> CLK_PCIE_PHY0_REF_SEL_SHIFT;
+ con = readl(&cru->clksel_con[176]);
+ div = (con & CLK_PCIE_PHY0_PLL_DIV_MASK) >> CLK_PCIE_PHY0_PLL_DIV_SHIFT;
+ break;
+ case CLK_REF_PIPE_PHY1:
+ con = readl(&cru->clksel_con[177]);
+ src = (con & CLK_PCIE_PHY1_REF_SEL_MASK) >> CLK_PCIE_PHY1_REF_SEL_SHIFT;
+ con = readl(&cru->clksel_con[176]);
+ div = (con & CLK_PCIE_PHY1_PLL_DIV_MASK) >> CLK_PCIE_PHY1_PLL_DIV_SHIFT;
+ break;
+ case CLK_REF_PIPE_PHY2:
+ con = readl(&cru->clksel_con[177]);
+ src = (con & CLK_PCIE_PHY2_REF_SEL_MASK) >> CLK_PCIE_PHY2_REF_SEL_SHIFT;
+ div = (con & CLK_PCIE_PHY2_PLL_DIV_MASK) >> CLK_PCIE_PHY2_PLL_DIV_SHIFT;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (src == CLK_PCIE_PHY_REF_SEL_PPLL)
+ return DIV_TO_RATE(priv->ppll_hz, div);
+ else
+ return OSC_HZ;
+}
+
+static ulong rk3588_pciephy_set_rate(struct rk3588_clk_priv *priv,
+ ulong clk_id, ulong rate)
+{
+ struct rk3588_cru *cru = priv->cru;
+ u32 clk_src, div;
+
+ if (rate == OSC_HZ) {
+ clk_src = CLK_PCIE_PHY_REF_SEL_24M;
+ div = 1;
+ } else {
+ clk_src = CLK_PCIE_PHY_REF_SEL_PPLL;
+ div = DIV_ROUND_UP(priv->ppll_hz, rate);
+ }
+
+ switch (clk_id) {
+ case CLK_REF_PIPE_PHY0:
+ rk_clrsetreg(&cru->clksel_con[177], CLK_PCIE_PHY0_REF_SEL_MASK,
+ (clk_src << CLK_PCIE_PHY0_REF_SEL_SHIFT));
+ rk_clrsetreg(&cru->clksel_con[176], CLK_PCIE_PHY0_PLL_DIV_MASK,
+ ((div - 1) << CLK_PCIE_PHY0_PLL_DIV_SHIFT));
+ break;
+ case CLK_REF_PIPE_PHY1:
+ rk_clrsetreg(&cru->clksel_con[177], CLK_PCIE_PHY1_REF_SEL_MASK,
+ (clk_src << CLK_PCIE_PHY1_REF_SEL_SHIFT));
+ rk_clrsetreg(&cru->clksel_con[176], CLK_PCIE_PHY1_PLL_DIV_MASK,
+ ((div - 1) << CLK_PCIE_PHY1_PLL_DIV_SHIFT));
+ break;
+ case CLK_REF_PIPE_PHY2:
+ rk_clrsetreg(&cru->clksel_con[177], CLK_PCIE_PHY2_REF_SEL_MASK |
+ CLK_PCIE_PHY2_PLL_DIV_MASK,
+ (clk_src << CLK_PCIE_PHY2_REF_SEL_SHIFT) |
+ ((div - 1) << CLK_PCIE_PHY2_PLL_DIV_SHIFT));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3588_pciephy_get_rate(priv, clk_id);
+}
+#endif
+
+static ulong rk3588_clk_get_rate(struct clk *clk)
+{
+ struct rk3588_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong rate = 0;
+
+ if (!priv->gpll_hz) {
+ printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
+ return -ENOENT;
+ }
+
+ if (!priv->ppll_hz) {
+ priv->ppll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL],
+ priv->cru, PPLL);
+ }
+
+ switch (clk->id) {
+ case PLL_LPLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[LPLL], priv->cru,
+ LPLL);
+ break;
+ case PLL_B0PLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[B0PLL], priv->cru,
+ B0PLL);
+ break;
+ case PLL_B1PLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[B1PLL], priv->cru,
+ B1PLL);
+ break;
+ case PLL_GPLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[GPLL], priv->cru,
+ GPLL);
+ break;
+ case PLL_CPLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[CPLL], priv->cru,
+ CPLL);
+ break;
+ case PLL_NPLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[NPLL], priv->cru,
+ NPLL);
+ break;
+ case PLL_V0PLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[V0PLL], priv->cru,
+ V0PLL);
+ break;
+ case PLL_AUPLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[AUPLL], priv->cru,
+ AUPLL);
+ break;
+ case PLL_PPLL:
+ rate = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL], priv->cru,
+ PPLL);
+ break;
+ case ACLK_CENTER_ROOT:
+ case PCLK_CENTER_ROOT:
+ case HCLK_CENTER_ROOT:
+ case ACLK_CENTER_LOW_ROOT:
+ rate = rk3588_center_get_clk(priv, clk->id);
+ break;
+ case ACLK_TOP_ROOT:
+ case PCLK_TOP_ROOT:
+ case ACLK_LOW_TOP_ROOT:
+ rate = rk3588_top_get_clk(priv, clk->id);
+ break;
+ case CLK_I2C0:
+ case CLK_I2C1:
+ case CLK_I2C2:
+ case CLK_I2C3:
+ case CLK_I2C4:
+ case CLK_I2C5:
+ case CLK_I2C6:
+ case CLK_I2C7:
+ case CLK_I2C8:
+ rate = rk3588_i2c_get_clk(priv, clk->id);
+ break;
+ case CLK_SPI0:
+ case CLK_SPI1:
+ case CLK_SPI2:
+ case CLK_SPI3:
+ case CLK_SPI4:
+ rate = rk3588_spi_get_clk(priv, clk->id);
+ break;
+ case CLK_PWM1:
+ case CLK_PWM2:
+ case CLK_PWM3:
+ case CLK_PMU1PWM:
+ rate = rk3588_pwm_get_clk(priv, clk->id);
+ break;
+ case CLK_SARADC:
+ case CLK_TSADC:
+ rate = rk3588_adc_get_clk(priv, clk->id);
+ break;
+ case CCLK_SRC_SDIO:
+ case CCLK_EMMC:
+ case BCLK_EMMC:
+ case SCLK_SFC:
+ case DCLK_DECOM:
+ rate = rk3588_mmc_get_clk(priv, clk->id);
+ break;
+ case TCLK_WDT0:
+ rate = OSC_HZ;
+ break;
+#ifndef CONFIG_SPL_BUILD
+ case CLK_AUX16M_0:
+ case CLK_AUX16M_1:
+ rk3588_aux16m_get_clk(priv, clk->id);
+ break;
+ case ACLK_VOP_ROOT:
+ case ACLK_VOP:
+ case ACLK_VOP_LOW_ROOT:
+ case HCLK_VOP_ROOT:
+ rate = rk3588_aclk_vop_get_clk(priv, clk->id);
+ break;
+ case DCLK_VOP0:
+ case DCLK_VOP0_SRC:
+ case DCLK_VOP1:
+ case DCLK_VOP1_SRC:
+ case DCLK_VOP2:
+ case DCLK_VOP2_SRC:
+ case DCLK_VOP3:
+ rate = rk3588_dclk_vop_get_clk(priv, clk->id);
+ break;
+ case CLK_GMAC0_PTP_REF:
+ case CLK_GMAC1_PTP_REF:
+ case CLK_GMAC_125M:
+ case CLK_GMAC_50M:
+ rate = rk3588_gmac_get_clk(priv, clk->id);
+ break;
+ case SCLK_UART1:
+ case SCLK_UART2:
+ case SCLK_UART3:
+ case SCLK_UART4:
+ case SCLK_UART5:
+ case SCLK_UART6:
+ case SCLK_UART7:
+ case SCLK_UART8:
+ case SCLK_UART9:
+ rate = rk3588_uart_get_rate(priv, clk->id);
+ break;
+ case CLK_REF_PIPE_PHY0:
+ case CLK_REF_PIPE_PHY1:
+ case CLK_REF_PIPE_PHY2:
+ rate = rk3588_pciephy_get_rate(priv, clk->id);
+ break;
+#endif
+ default:
+ return -ENOENT;
+ }
+
+ return rate;
+};
+
+static ulong rk3588_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct rk3588_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong ret = 0;
+
+ if (!priv->gpll_hz) {
+ printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
+ return -ENOENT;
+ }
+
+ if (!priv->ppll_hz) {
+ priv->ppll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL],
+ priv->cru, PPLL);
+ }
+
+ switch (clk->id) {
+ case PLL_CPLL:
+ ret = rockchip_pll_set_rate(&rk3588_pll_clks[CPLL], priv->cru,
+ CPLL, rate);
+ priv->cpll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[CPLL],
+ priv->cru, CPLL);
+ break;
+ case PLL_GPLL:
+ ret = rockchip_pll_set_rate(&rk3588_pll_clks[GPLL], priv->cru,
+ GPLL, rate);
+ priv->gpll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[GPLL],
+ priv->cru, GPLL);
+ break;
+ case PLL_NPLL:
+ ret = rockchip_pll_set_rate(&rk3588_pll_clks[NPLL], priv->cru,
+ NPLL, rate);
+ break;
+ case PLL_V0PLL:
+ ret = rockchip_pll_set_rate(&rk3588_pll_clks[V0PLL], priv->cru,
+ V0PLL, rate);
+ priv->v0pll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[V0PLL],
+ priv->cru, V0PLL);
+ break;
+ case PLL_AUPLL:
+ ret = rockchip_pll_set_rate(&rk3588_pll_clks[AUPLL], priv->cru,
+ AUPLL, rate);
+ priv->aupll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[AUPLL],
+ priv->cru, AUPLL);
+ break;
+ case PLL_PPLL:
+ ret = rockchip_pll_set_rate(&rk3588_pll_clks[PPLL], priv->cru,
+ PPLL, rate);
+ priv->ppll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL],
+ priv->cru, PPLL);
+ break;
+ case ACLK_CENTER_ROOT:
+ case PCLK_CENTER_ROOT:
+ case HCLK_CENTER_ROOT:
+ case ACLK_CENTER_LOW_ROOT:
+ ret = rk3588_center_set_clk(priv, clk->id, rate);
+ break;
+ case ACLK_TOP_ROOT:
+ case PCLK_TOP_ROOT:
+ case ACLK_LOW_TOP_ROOT:
+ ret = rk3588_top_set_clk(priv, clk->id, rate);
+ break;
+ case CLK_I2C0:
+ case CLK_I2C1:
+ case CLK_I2C2:
+ case CLK_I2C3:
+ case CLK_I2C4:
+ case CLK_I2C5:
+ case CLK_I2C6:
+ case CLK_I2C7:
+ case CLK_I2C8:
+ ret = rk3588_i2c_set_clk(priv, clk->id, rate);
+ break;
+ case CLK_SPI0:
+ case CLK_SPI1:
+ case CLK_SPI2:
+ case CLK_SPI3:
+ case CLK_SPI4:
+ ret = rk3588_spi_set_clk(priv, clk->id, rate);
+ break;
+ case CLK_PWM1:
+ case CLK_PWM2:
+ case CLK_PWM3:
+ case CLK_PMU1PWM:
+ ret = rk3588_pwm_set_clk(priv, clk->id, rate);
+ break;
+ case CLK_SARADC:
+ case CLK_TSADC:
+ ret = rk3588_adc_set_clk(priv, clk->id, rate);
+ break;
+ case CCLK_SRC_SDIO:
+ case CCLK_EMMC:
+ case BCLK_EMMC:
+ case SCLK_SFC:
+ case DCLK_DECOM:
+ ret = rk3588_mmc_set_clk(priv, clk->id, rate);
+ break;
+ case TCLK_WDT0:
+ ret = OSC_HZ;
+ break;
+#ifndef CONFIG_SPL_BUILD
+ case CLK_AUX16M_0:
+ case CLK_AUX16M_1:
+ rk3588_aux16m_set_clk(priv, clk->id, rate);
+ break;
+ case ACLK_VOP_ROOT:
+ case ACLK_VOP:
+ case ACLK_VOP_LOW_ROOT:
+ case HCLK_VOP_ROOT:
+ ret = rk3588_aclk_vop_set_clk(priv, clk->id, rate);
+ break;
+ case DCLK_VOP0:
+ case DCLK_VOP0_SRC:
+ case DCLK_VOP1:
+ case DCLK_VOP1_SRC:
+ case DCLK_VOP2:
+ case DCLK_VOP2_SRC:
+ case DCLK_VOP3:
+ ret = rk3588_dclk_vop_set_clk(priv, clk->id, rate);
+ break;
+ case CLK_GMAC0_PTP_REF:
+ case CLK_GMAC1_PTP_REF:
+ case CLK_GMAC_125M:
+ case CLK_GMAC_50M:
+ ret = rk3588_gmac_set_clk(priv, clk->id, rate);
+ break;
+ case SCLK_UART1:
+ case SCLK_UART2:
+ case SCLK_UART3:
+ case SCLK_UART4:
+ case SCLK_UART5:
+ case SCLK_UART6:
+ case SCLK_UART7:
+ case SCLK_UART8:
+ case SCLK_UART9:
+ ret = rk3588_uart_set_rate(priv, clk->id, rate);
+ break;
+ case CLK_REF_PIPE_PHY0:
+ case CLK_REF_PIPE_PHY1:
+ case CLK_REF_PIPE_PHY2:
+ ret = rk3588_pciephy_set_rate(priv, clk->id, rate);
+ break;
+#endif
+ default:
+ return -ENOENT;
+ }
+
+ return ret;
+};
+
+#define ROCKCHIP_MMC_DELAY_SEL BIT(10)
+#define ROCKCHIP_MMC_DEGREE_MASK 0x3
+#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
+#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
+
+#define PSECS_PER_SEC 1000000000000LL
+/*
+ * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
+ * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
+ */
+#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
+
+#if (IS_ENABLED(OF_CONTROL)) || (!IS_ENABLED(OF_PLATDATA))
+static int __maybe_unused rk3588_dclk_vop_set_parent(struct clk *clk,
+ struct clk *parent)
+{
+ struct rk3588_clk_priv *priv = dev_get_priv(clk->dev);
+ struct rk3588_cru *cru = priv->cru;
+ u32 sel;
+ const char *clock_dev_name = parent->dev->name;
+
+ if (parent->id == PLL_V0PLL)
+ sel = 2;
+ else if (parent->id == PLL_GPLL)
+ sel = 0;
+ else if (parent->id == PLL_CPLL)
+ sel = 1;
+ else
+ sel = 3;
+
+ switch (clk->id) {
+ case DCLK_VOP0_SRC:
+ rk_clrsetreg(&cru->clksel_con[111], DCLK0_VOP_SRC_SEL_MASK,
+ sel << DCLK0_VOP_SRC_SEL_SHIFT);
+ break;
+ case DCLK_VOP1_SRC:
+ rk_clrsetreg(&cru->clksel_con[111], DCLK1_VOP_SRC_SEL_MASK,
+ sel << DCLK1_VOP_SRC_SEL_SHIFT);
+ break;
+ case DCLK_VOP2_SRC:
+ rk_clrsetreg(&cru->clksel_con[112], DCLK2_VOP_SRC_SEL_MASK,
+ sel << DCLK2_VOP_SRC_SEL_SHIFT);
+ break;
+ case DCLK_VOP3:
+ rk_clrsetreg(&cru->clksel_con[113], DCLK3_VOP_SRC_SEL_MASK,
+ sel << DCLK3_VOP_SRC_SEL_SHIFT);
+ break;
+ case DCLK_VOP0:
+ if (!strcmp(clock_dev_name, "hdmiphypll_clk0"))
+ sel = 1;
+ else if (!strcmp(clock_dev_name, "hdmiphypll_clk1"))
+ sel = 2;
+ else
+ sel = 0;
+ rk_clrsetreg(&cru->clksel_con[112], DCLK0_VOP_SEL_MASK,
+ sel << DCLK0_VOP_SEL_SHIFT);
+ break;
+ case DCLK_VOP1:
+ if (!strcmp(clock_dev_name, "hdmiphypll_clk0"))
+ sel = 1;
+ else if (!strcmp(clock_dev_name, "hdmiphypll_clk1"))
+ sel = 2;
+ else
+ sel = 0;
+ rk_clrsetreg(&cru->clksel_con[112], DCLK1_VOP_SEL_MASK,
+ sel << DCLK1_VOP_SEL_SHIFT);
+ break;
+ case DCLK_VOP2:
+ if (!strcmp(clock_dev_name, "hdmiphypll_clk0"))
+ sel = 1;
+ else if (!strcmp(clock_dev_name, "hdmiphypll_clk1"))
+ sel = 2;
+ else
+ sel = 0;
+ rk_clrsetreg(&cru->clksel_con[112], DCLK2_VOP_SEL_MASK,
+ sel << DCLK2_VOP_SEL_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int rk3588_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ switch (clk->id) {
+ case DCLK_VOP0_SRC:
+ case DCLK_VOP1_SRC:
+ case DCLK_VOP2_SRC:
+ case DCLK_VOP0:
+ case DCLK_VOP1:
+ case DCLK_VOP2:
+ case DCLK_VOP3:
+ return rk3588_dclk_vop_set_parent(clk, parent);
+ default:
+ return -ENOENT;
+ }
+
+ return 0;
+}
+#endif
+
+static struct clk_ops rk3588_clk_ops = {
+ .get_rate = rk3588_clk_get_rate,
+ .set_rate = rk3588_clk_set_rate,
+#if (IS_ENABLED(OF_CONTROL)) || (!IS_ENABLED(OF_PLATDATA))
+ .set_parent = rk3588_clk_set_parent,
+#endif
+};
+
+static void rk3588_clk_init(struct rk3588_clk_priv *priv)
+{
+ int ret, div;
+
+ div = DIV_ROUND_UP(GPLL_HZ, 300 * MHz);
+ rk_clrsetreg(&priv->cru->clksel_con[38],
+ ACLK_BUS_ROOT_SEL_MASK |
+ ACLK_BUS_ROOT_DIV_MASK,
+ div << ACLK_BUS_ROOT_DIV_SHIFT);
+
+ if (priv->cpll_hz != CPLL_HZ) {
+ ret = rockchip_pll_set_rate(&rk3588_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(&rk3588_pll_clks[GPLL], priv->cru,
+ GPLL, GPLL_HZ);
+ if (!ret)
+ priv->gpll_hz = GPLL_HZ;
+ }
+
+#ifdef CONFIG_PCI
+ if (priv->ppll_hz != PPLL_HZ) {
+ ret = rockchip_pll_set_rate(&rk3588_pll_clks[PPLL], priv->cru,
+ PPLL, PPLL_HZ);
+ priv->ppll_hz = rockchip_pll_get_rate(&rk3588_pll_clks[PPLL],
+ priv->cru, PPLL);
+ }
+#endif
+ rk_clrsetreg(&priv->cru->clksel_con[9],
+ ACLK_TOP_S400_SEL_MASK |
+ ACLK_TOP_S200_SEL_MASK,
+ (ACLK_TOP_S400_SEL_400M << ACLK_TOP_S400_SEL_SHIFT) |
+ (ACLK_TOP_S200_SEL_200M << ACLK_TOP_S200_SEL_SHIFT));
+}
+
+static int rk3588_clk_probe(struct udevice *dev)
+{
+ struct rk3588_clk_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->sync_kernel = false;
+
+#ifdef CONFIG_SPL_BUILD
+ rockchip_pll_set_rate(&rk3588_pll_clks[B0PLL], priv->cru,
+ B0PLL, LPLL_HZ);
+ rockchip_pll_set_rate(&rk3588_pll_clks[B1PLL], priv->cru,
+ B1PLL, LPLL_HZ);
+ if (!priv->armclk_enter_hz) {
+ ret = rockchip_pll_set_rate(&rk3588_pll_clks[LPLL], priv->cru,
+ LPLL, LPLL_HZ);
+ priv->armclk_enter_hz =
+ rockchip_pll_get_rate(&rk3588_pll_clks[LPLL],
+ priv->cru, LPLL);
+ priv->armclk_init_hz = priv->armclk_enter_hz;
+ }
+#endif
+
+ priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ if (IS_ERR(priv->grf))
+ return PTR_ERR(priv->grf);
+
+ rk3588_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 rk3588_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct rk3588_clk_priv *priv = dev_get_priv(dev);
+
+ priv->cru = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+static int rk3588_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 rk3588_cru,
+ glb_srst_fst);
+ priv->glb_srst_snd_value = offsetof(struct rk3588_cru,
+ glb_srsr_snd);
+ dev_set_priv(sys_child, priv);
+ }
+
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
+ ret = offsetof(struct rk3588_cru, softrst_con[0]);
+ ret = rockchip_reset_bind(dev, ret, 49158);
+ if (ret)
+ debug("Warning: software reset driver bind faile\n");
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id rk3588_clk_ids[] = {
+ { .compatible = "rockchip,rk3588-cru" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_rk3588_cru) = {
+ .name = "rockchip_rk3588_cru",
+ .id = UCLASS_CLK,
+ .of_match = rk3588_clk_ids,
+ .priv_auto = sizeof(struct rk3588_clk_priv),
+ .of_to_plat = rk3588_clk_ofdata_to_platdata,
+ .ops = &rk3588_clk_ops,
+ .bind = rk3588_clk_bind,
+ .probe = rk3588_clk_probe,
+};
diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c
index 68f30157a9a..f7ad4d68b45 100644
--- a/drivers/gpio/rk_gpio.c
+++ b/drivers/gpio/rk_gpio.c
@@ -142,6 +142,7 @@ static int rockchip_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct rockchip_gpio_priv *priv = dev_get_priv(dev);
+ struct ofnode_phandle_args args;
char *end;
int ret;
@@ -150,9 +151,22 @@ static int rockchip_gpio_probe(struct udevice *dev)
if (ret)
return ret;
- uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
- end = strrchr(dev->name, '@');
- priv->bank = trailing_strtoln(dev->name, end);
+ /*
+ * If "gpio-ranges" is present in the devicetree use it to parse
+ * the GPIO bank ID, otherwise use the legacy method.
+ */
+ ret = ofnode_parse_phandle_with_args(dev_ofnode(dev),
+ "gpio-ranges", NULL, 3,
+ 0, &args);
+ if (!ret || ret != -ENOENT) {
+ uc_priv->gpio_count = args.args[2];
+ priv->bank = args.args[1] / args.args[2];
+ } else {
+ uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
+ end = strrchr(dev->name, '@');
+ priv->bank = trailing_strtoln(dev->name, end);
+ }
+
priv->name[0] = 'A' + priv->bank;
uc_priv->bank_name = priv->name;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b07261d3db5..b5707a15c50 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -92,10 +92,6 @@ config ROCKCHIP_EFUSE
or through child-nodes that are generated based on the e-fuse map
retrieved from the DTS.
- This driver currently supports the RK3399 only, but can easily be
- extended (by porting the read function from the Linux kernel sources)
- to support other recent Rockchip devices.
-
config ROCKCHIP_OTP
bool "Rockchip OTP Support"
depends on MISC
diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c
index 083ee65e0ad..60931a51312 100644
--- a/drivers/misc/rockchip-efuse.c
+++ b/drivers/misc/rockchip-efuse.c
@@ -13,50 +13,57 @@
#include <dm.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <malloc.h>
#include <misc.h>
-#define RK3399_A_SHIFT 16
-#define RK3399_A_MASK 0x3ff
-#define RK3399_NFUSES 32
-#define RK3399_BYTES_PER_FUSE 4
-#define RK3399_STROBSFTSEL BIT(9)
-#define RK3399_RSB BIT(7)
-#define RK3399_PD BIT(5)
-#define RK3399_PGENB BIT(3)
-#define RK3399_LOAD BIT(2)
-#define RK3399_STROBE BIT(1)
-#define RK3399_CSB BIT(0)
-
-struct rockchip_efuse_regs {
- u32 ctrl; /* 0x00 efuse control register */
- u32 dout; /* 0x04 efuse data out register */
- u32 rf; /* 0x08 efuse redundancy bit used register */
- u32 _rsvd0;
- u32 jtag_pass; /* 0x10 JTAG password */
- u32 strobe_finish_ctrl;
- /* 0x14 efuse strobe finish control register */
-};
+#define EFUSE_CTRL 0x0000
+#define RK3036_A_SHIFT 8
+#define RK3036_A_MASK GENMASK(15, 8)
+#define RK3036_ADDR(n) ((n) << RK3036_A_SHIFT)
+#define RK3128_A_SHIFT 7
+#define RK3128_A_MASK GENMASK(15, 7)
+#define RK3128_ADDR(n) ((n) << RK3128_A_SHIFT)
+#define RK3288_A_SHIFT 6
+#define RK3288_A_MASK GENMASK(15, 6)
+#define RK3288_ADDR(n) ((n) << RK3288_A_SHIFT)
+#define RK3399_A_SHIFT 16
+#define RK3399_A_MASK GENMASK(25, 16)
+#define RK3399_ADDR(n) ((n) << RK3399_A_SHIFT)
+#define RK3399_STROBSFTSEL BIT(9)
+#define RK3399_RSB BIT(7)
+#define RK3399_PD BIT(5)
+#define EFUSE_PGENB BIT(3)
+#define EFUSE_LOAD BIT(2)
+#define EFUSE_STROBE BIT(1)
+#define EFUSE_CSB BIT(0)
+#define EFUSE_DOUT 0x0004
+#define RK3328_INT_STATUS 0x0018
+#define RK3328_INT_FINISH BIT(0)
+#define RK3328_DOUT 0x0020
+#define RK3328_AUTO_CTRL 0x0024
+#define RK3328_AUTO_RD BIT(1)
+#define RK3328_AUTO_ENB BIT(0)
struct rockchip_efuse_plat {
void __iomem *base;
- struct clk *clk;
+};
+
+struct rockchip_efuse_data {
+ int (*read)(struct udevice *dev, int offset, void *buf, int size);
+ int offset;
+ int size;
+ int block_size;
};
#if defined(DEBUG)
-static int dump_efuses(struct cmd_tbl *cmdtp, int flag,
- int argc, char *const argv[])
+static int dump_efuse(struct cmd_tbl *cmdtp, int flag,
+ int argc, char *const argv[])
{
- /*
- * N.B.: This function is tailored towards the RK3399 and assumes that
- * there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to
- * be read.
- */
-
struct udevice *dev;
- u8 fuses[128];
- int ret;
+ u8 data[4];
+ int ret, i;
- /* retrieve the device */
ret = uclass_get_device_by_driver(UCLASS_MISC,
DM_DRIVER_GET(rockchip_efuse), &dev);
if (ret) {
@@ -64,65 +71,152 @@ static int dump_efuses(struct cmd_tbl *cmdtp, int flag,
return 0;
}
- ret = misc_read(dev, 0, &fuses, sizeof(fuses));
- if (ret < 0) {
- printf("%s: misc_read failed\n", __func__);
- return 0;
- }
+ for (i = 0; true; i += sizeof(data)) {
+ ret = misc_read(dev, i, &data, sizeof(data));
+ if (ret < 0)
+ return 0;
- printf("efuse-contents:\n");
- print_buffer(0, fuses, 1, 128, 16);
+ print_buffer(i, data, 1, sizeof(data), sizeof(data));
+ }
return 0;
}
U_BOOT_CMD(
- rk3399_dump_efuses, 1, 1, dump_efuses,
- "Dump the content of the efuses",
+ dump_efuse, 1, 1, dump_efuse,
+ "Dump the content of the efuse",
""
);
#endif
-static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
+static int rockchip_rk3036_efuse_read(struct udevice *dev, int offset,
void *buf, int size)
{
- struct rockchip_efuse_plat *plat = dev_get_plat(dev);
- struct rockchip_efuse_regs *efuse =
- (struct rockchip_efuse_regs *)plat->base;
+ struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
+ u8 *buffer = buf;
- unsigned int addr_start, addr_end, addr_offset;
- u32 out_value;
- u8 bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE];
- int i = 0;
- u32 addr;
+ /* Switch to read mode */
+ writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
+ udelay(2);
- addr_start = offset / RK3399_BYTES_PER_FUSE;
- addr_offset = offset % RK3399_BYTES_PER_FUSE;
- addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE);
+ while (size--) {
+ clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3036_A_MASK,
+ RK3036_ADDR(offset++));
+ udelay(2);
+ setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
+ udelay(2);
+ *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
+ clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
+ udelay(2);
+ }
- /* cap to the size of the efuse block */
- if (addr_end > RK3399_NFUSES)
- addr_end = RK3399_NFUSES;
+ /* Switch to inactive mode */
+ writel(0x0, efuse->base + EFUSE_CTRL);
- writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
- &efuse->ctrl);
- udelay(1);
- for (addr = addr_start; addr < addr_end; addr++) {
- setbits_le32(&efuse->ctrl,
- RK3399_STROBE | (addr << RK3399_A_SHIFT));
- udelay(1);
- out_value = readl(&efuse->dout);
- clrbits_le32(&efuse->ctrl, RK3399_STROBE);
- udelay(1);
+ return 0;
+}
+
+static int rockchip_rk3128_efuse_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
+ u8 *buffer = buf;
- memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE);
- i += RK3399_BYTES_PER_FUSE;
+ /* Switch to read mode */
+ writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL);
+ udelay(2);
+
+ while (size--) {
+ clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3128_A_MASK,
+ RK3128_ADDR(offset++));
+ udelay(2);
+ setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
+ udelay(2);
+ *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
+ clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
+ udelay(2);
+ }
+
+ /* Switch to inactive mode */
+ writel(0x0, efuse->base + EFUSE_CTRL);
+
+ return 0;
+}
+
+static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
+ u8 *buffer = buf;
+
+ /* Switch to read mode */
+ writel(EFUSE_CSB, efuse->base + EFUSE_CTRL);
+ writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
+ udelay(2);
+
+ while (size--) {
+ clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3288_A_MASK,
+ RK3288_ADDR(offset++));
+ udelay(2);
+ setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
+ udelay(2);
+ *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF);
+ clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
+ udelay(2);
}
/* Switch to standby mode */
- writel(RK3399_PD | RK3399_CSB, &efuse->ctrl);
+ writel(EFUSE_CSB | EFUSE_PGENB, efuse->base + EFUSE_CTRL);
- memcpy(buf, bytes + addr_offset, size);
+ return 0;
+}
+
+static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
+ u32 status, *buffer = buf;
+ int ret;
+
+ while (size--) {
+ writel(RK3328_AUTO_RD | RK3328_AUTO_ENB | RK3399_ADDR(offset++),
+ efuse->base + RK3328_AUTO_CTRL);
+ udelay(1);
+
+ ret = readl_poll_sleep_timeout(efuse->base + RK3328_INT_STATUS,
+ status, (status & RK3328_INT_FINISH), 1, 50);
+ if (ret)
+ return ret;
+
+ *buffer++ = readl(efuse->base + RK3328_DOUT);
+ writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);
+ }
+
+ return 0;
+}
+
+static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
+ u32 *buffer = buf;
+
+ /* Switch to array read mode */
+ writel(EFUSE_LOAD | EFUSE_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
+ efuse->base + EFUSE_CTRL);
+ udelay(1);
+
+ while (size--) {
+ setbits_le32(efuse->base + EFUSE_CTRL,
+ EFUSE_STROBE | RK3399_ADDR(offset++));
+ udelay(1);
+ *buffer++ = readl(efuse->base + EFUSE_DOUT);
+ clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE);
+ udelay(1);
+ }
+
+ /* Switch to power-down mode */
+ writel(RK3399_PD | EFUSE_CSB, efuse->base + EFUSE_CTRL);
return 0;
}
@@ -130,7 +224,38 @@ static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
static int rockchip_efuse_read(struct udevice *dev, int offset,
void *buf, int size)
{
- return rockchip_rk3399_efuse_read(dev, offset, buf, size);
+ const struct rockchip_efuse_data *data =
+ (void *)dev_get_driver_data(dev);
+ u32 block_start, block_end, block_offset, blocks;
+ u8 *buffer;
+ int ret;
+
+ if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
+ return -EINVAL;
+
+ if (!data->read)
+ return -ENOSYS;
+
+ offset += data->offset;
+
+ if (data->block_size <= 1)
+ return data->read(dev, offset, buf, size);
+
+ block_start = offset / data->block_size;
+ block_offset = offset % data->block_size;
+ block_end = DIV_ROUND_UP(offset + size, data->block_size);
+ blocks = block_end - block_start;
+
+ buffer = calloc(blocks, data->block_size);
+ if (!buffer)
+ return -ENOMEM;
+
+ ret = data->read(dev, block_start, buffer, blocks);
+ if (!ret)
+ memcpy(buf, buffer + block_offset, size);
+
+ free(buffer);
+ return ret;
}
static const struct misc_ops rockchip_efuse_ops = {
@@ -142,11 +267,71 @@ static int rockchip_efuse_of_to_plat(struct udevice *dev)
struct rockchip_efuse_plat *plat = dev_get_plat(dev);
plat->base = dev_read_addr_ptr(dev);
+
return 0;
}
+static const struct rockchip_efuse_data rk3036_data = {
+ .read = rockchip_rk3036_efuse_read,
+ .size = 0x20,
+};
+
+static const struct rockchip_efuse_data rk3128_data = {
+ .read = rockchip_rk3128_efuse_read,
+ .size = 0x40,
+};
+
+static const struct rockchip_efuse_data rk3288_data = {
+ .read = rockchip_rk3288_efuse_read,
+ .size = 0x20,
+};
+
+static const struct rockchip_efuse_data rk3328_data = {
+ .read = rockchip_rk3328_efuse_read,
+ .offset = 0x60,
+ .size = 0x20,
+ .block_size = 4,
+};
+
+static const struct rockchip_efuse_data rk3399_data = {
+ .read = rockchip_rk3399_efuse_read,
+ .size = 0x80,
+ .block_size = 4,
+};
+
static const struct udevice_id rockchip_efuse_ids[] = {
- { .compatible = "rockchip,rk3399-efuse" },
+ {
+ .compatible = "rockchip,rk3036-efuse",
+ .data = (ulong)&rk3036_data,
+ },
+ {
+ .compatible = "rockchip,rk3066a-efuse",
+ .data = (ulong)&rk3288_data,
+ },
+ {
+ .compatible = "rockchip,rk3128-efuse",
+ .data = (ulong)&rk3128_data,
+ },
+ {
+ .compatible = "rockchip,rk3188-efuse",
+ .data = (ulong)&rk3288_data,
+ },
+ {
+ .compatible = "rockchip,rk3228-efuse",
+ .data = (ulong)&rk3288_data,
+ },
+ {
+ .compatible = "rockchip,rk3288-efuse",
+ .data = (ulong)&rk3288_data,
+ },
+ {
+ .compatible = "rockchip,rk3328-efuse",
+ .data = (ulong)&rk3328_data,
+ },
+ {
+ .compatible = "rockchip,rk3399-efuse",
+ .data = (ulong)&rk3399_data,
+ },
{}
};
@@ -155,6 +340,6 @@ U_BOOT_DRIVER(rockchip_efuse) = {
.id = UCLASS_MISC,
.of_match = rockchip_efuse_ids,
.of_to_plat = rockchip_efuse_of_to_plat,
- .plat_auto = sizeof(struct rockchip_efuse_plat),
+ .plat_auto = sizeof(struct rockchip_efuse_plat),
.ops = &rockchip_efuse_ops,
};
diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c
index cc9a5450e0c..c19cd5ce625 100644
--- a/drivers/misc/rockchip-otp.c
+++ b/drivers/misc/rockchip-otp.c
@@ -6,9 +6,12 @@
#include <common.h>
#include <asm/io.h>
#include <command.h>
+#include <display_options.h>
#include <dm.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <malloc.h>
#include <misc.h>
/* OTP Register Offsets */
@@ -47,37 +50,80 @@
#define OTPC_TIMEOUT 10000
+#define RK3588_OTPC_AUTO_CTRL 0x0004
+#define RK3588_ADDR_SHIFT 16
+#define RK3588_ADDR(n) ((n) << RK3588_ADDR_SHIFT)
+#define RK3588_BURST_SHIFT 8
+#define RK3588_BURST(n) ((n) << RK3588_BURST_SHIFT)
+#define RK3588_OTPC_AUTO_EN 0x0008
+#define RK3588_AUTO_EN BIT(0)
+#define RK3588_OTPC_DOUT0 0x0020
+#define RK3588_OTPC_INT_ST 0x0084
+#define RK3588_RD_DONE BIT(1)
+
struct rockchip_otp_plat {
void __iomem *base;
- unsigned long secure_conf_base;
- unsigned long otp_mask_base;
};
-static int rockchip_otp_wait_status(struct rockchip_otp_plat *otp,
- u32 flag)
+struct rockchip_otp_data {
+ int (*read)(struct udevice *dev, int offset, void *buf, int size);
+ int offset;
+ int size;
+ int block_size;
+};
+
+#if defined(DEBUG)
+static int dump_otp(struct cmd_tbl *cmdtp, int flag,
+ int argc, char *const argv[])
{
- int delay = OTPC_TIMEOUT;
-
- while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
- udelay(1);
- delay--;
- if (delay <= 0) {
- printf("%s: wait init status timeout\n", __func__);
- return -ETIMEDOUT;
- }
+ struct udevice *dev;
+ u8 data[4];
+ int ret, i;
+
+ ret = uclass_get_device_by_driver(UCLASS_MISC,
+ DM_DRIVER_GET(rockchip_otp), &dev);
+ if (ret) {
+ printf("%s: no misc-device found\n", __func__);
+ return 0;
}
- /* clean int status */
- writel(flag, otp->base + OTPC_INT_STATUS);
+ for (i = 0; true; i += sizeof(data)) {
+ ret = misc_read(dev, i, &data, sizeof(data));
+ if (ret < 0)
+ return 0;
+
+ print_buffer(i, data, 1, sizeof(data), sizeof(data));
+ }
return 0;
}
-static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp,
- bool enable)
+U_BOOT_CMD(
+ dump_otp, 1, 1, dump_otp,
+ "Dump the content of the otp",
+ ""
+);
+#endif
+
+static int rockchip_otp_poll_timeout(struct rockchip_otp_plat *otp,
+ u32 flag, u32 reg)
{
- int ret = 0;
+ u32 status;
+ int ret;
+
+ ret = readl_poll_sleep_timeout(otp->base + reg, status,
+ (status & flag), 1, OTPC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ /* Clear int flag */
+ writel(flag, otp->base + reg);
+ return 0;
+}
+
+static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp, bool enable)
+{
writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
otp->base + OTPC_SBPI_CTRL);
@@ -92,11 +138,7 @@ static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp,
writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
- ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
- if (ret < 0)
- printf("%s timeout during ecc_enable\n", __func__);
-
- return ret;
+ return rockchip_otp_poll_timeout(otp, OTPC_SBPI_DONE, OTPC_INT_STATUS);
}
static int rockchip_px30_otp_read(struct udevice *dev, int offset,
@@ -104,29 +146,61 @@ static int rockchip_px30_otp_read(struct udevice *dev, int offset,
{
struct rockchip_otp_plat *otp = dev_get_plat(dev);
u8 *buffer = buf;
- int ret = 0;
+ int ret;
ret = rockchip_otp_ecc_enable(otp, false);
- if (ret < 0) {
- printf("%s rockchip_otp_ecc_enable err\n", __func__);
+ if (ret)
return ret;
+
+ writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
+ udelay(5);
+
+ while (size--) {
+ writel(offset++ | OTPC_USER_ADDR_MASK,
+ otp->base + OTPC_USER_ADDR);
+ writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
+ otp->base + OTPC_USER_ENABLE);
+
+ ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE,
+ OTPC_INT_STATUS);
+ if (ret)
+ goto read_end;
+
+ *buffer++ = (u8)(readl(otp->base + OTPC_USER_Q) & 0xFF);
}
+read_end:
+ writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
+
+ return ret;
+}
+
+static int rockchip_rk3568_otp_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ struct rockchip_otp_plat *otp = dev_get_plat(dev);
+ u16 *buffer = buf;
+ int ret;
+
+ ret = rockchip_otp_ecc_enable(otp, false);
+ if (ret)
+ return ret;
+
writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
udelay(5);
+
while (size--) {
writel(offset++ | OTPC_USER_ADDR_MASK,
otp->base + OTPC_USER_ADDR);
writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
otp->base + OTPC_USER_ENABLE);
- ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
- if (ret < 0) {
- printf("%s timeout during read setup\n", __func__);
+ ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE,
+ OTPC_INT_STATUS);
+ if (ret)
goto read_end;
- }
- *buffer++ = readb(otp->base + OTPC_USER_Q);
+ *buffer++ = (u16)(readl(otp->base + OTPC_USER_Q) & 0xFFFF);
}
read_end:
@@ -135,10 +209,64 @@ read_end:
return ret;
}
+static int rockchip_rk3588_otp_read(struct udevice *dev, int offset,
+ void *buf, int size)
+{
+ struct rockchip_otp_plat *otp = dev_get_plat(dev);
+ u32 *buffer = buf;
+ int ret;
+
+ while (size--) {
+ writel(RK3588_ADDR(offset++) | RK3588_BURST(1),
+ otp->base + RK3588_OTPC_AUTO_CTRL);
+ writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN);
+
+ ret = rockchip_otp_poll_timeout(otp, RK3588_RD_DONE,
+ RK3588_OTPC_INT_ST);
+ if (ret)
+ return ret;
+
+ *buffer++ = readl(otp->base + RK3588_OTPC_DOUT0);
+ }
+
+ return 0;
+}
+
static int rockchip_otp_read(struct udevice *dev, int offset,
void *buf, int size)
{
- return rockchip_px30_otp_read(dev, offset, buf, size);
+ const struct rockchip_otp_data *data =
+ (void *)dev_get_driver_data(dev);
+ u32 block_start, block_end, block_offset, blocks;
+ u8 *buffer;
+ int ret;
+
+ if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
+ return -EINVAL;
+
+ if (!data->read)
+ return -ENOSYS;
+
+ offset += data->offset;
+
+ if (data->block_size <= 1)
+ return data->read(dev, offset, buf, size);
+
+ block_start = offset / data->block_size;
+ block_offset = offset % data->block_size;
+ block_end = DIV_ROUND_UP(offset + size, data->block_size);
+ blocks = block_end - block_start;
+
+ buffer = calloc(blocks, data->block_size);
+ if (!buffer)
+ return -ENOMEM;
+
+ ret = data->read(dev, block_start, buffer, blocks);
+ if (!ret)
+ memcpy(buf, buffer + block_offset, size);
+
+ free(buffer);
+ return ret;
}
static const struct misc_ops rockchip_otp_ops = {
@@ -147,21 +275,47 @@ static const struct misc_ops rockchip_otp_ops = {
static int rockchip_otp_of_to_plat(struct udevice *dev)
{
- struct rockchip_otp_plat *otp = dev_get_plat(dev);
+ struct rockchip_otp_plat *plat = dev_get_plat(dev);
- otp->base = dev_read_addr_ptr(dev);
+ plat->base = dev_read_addr_ptr(dev);
return 0;
}
+static const struct rockchip_otp_data px30_data = {
+ .read = rockchip_px30_otp_read,
+ .size = 0x40,
+};
+
+static const struct rockchip_otp_data rk3568_data = {
+ .read = rockchip_rk3568_otp_read,
+ .size = 0x80,
+ .block_size = 2,
+};
+
+static const struct rockchip_otp_data rk3588_data = {
+ .read = rockchip_rk3588_otp_read,
+ .offset = 0xC00,
+ .size = 0x400,
+ .block_size = 4,
+};
+
static const struct udevice_id rockchip_otp_ids[] = {
{
.compatible = "rockchip,px30-otp",
- .data = (ulong)&rockchip_px30_otp_read,
+ .data = (ulong)&px30_data,
},
{
.compatible = "rockchip,rk3308-otp",
- .data = (ulong)&rockchip_px30_otp_read,
+ .data = (ulong)&px30_data,
+ },
+ {
+ .compatible = "rockchip,rk3568-otp",
+ .data = (ulong)&rk3568_data,
+ },
+ {
+ .compatible = "rockchip,rk3588-otp",
+ .data = (ulong)&rk3588_data,
},
{}
};
@@ -170,7 +324,7 @@ U_BOOT_DRIVER(rockchip_otp) = {
.name = "rockchip_otp",
.id = UCLASS_MISC,
.of_match = rockchip_otp_ids,
- .ops = &rockchip_otp_ops,
.of_to_plat = rockchip_otp_of_to_plat,
- .plat_auto = sizeof(struct rockchip_otp_plat),
+ .plat_auto = sizeof(struct rockchip_otp_plat),
+ .ops = &rockchip_otp_ops,
};
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 4a1accebfcb..34119f949aa 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -977,34 +977,50 @@ static int renesas_sdhi_probe(struct udevice *dev)
/* optional SDnH clock */
ret = clk_get_by_name(dev, "clkh", &priv->clkh);
- if (ret < 0)
+ if (ret < 0) {
dev_dbg(dev, "failed to get clkh\n");
+ } else {
+ ret = clk_set_rate(&priv->clkh, 800000000);
+ if (ret < 0) {
+ dev_err(dev, "failed to set rate for SDnH clock (%d)\n", ret);
+ goto err_clk;
+ }
+ }
/* set to max rate */
ret = clk_set_rate(&priv->clk, 200000000);
if (ret < 0) {
- dev_err(dev, "failed to set rate for host clock\n");
- clk_free(&priv->clk);
- return ret;
+ dev_err(dev, "failed to set rate for SDn clock (%d)\n", ret);
+ goto err_clkh;
}
ret = clk_enable(&priv->clk);
if (ret) {
- dev_err(dev, "failed to enable host clock\n");
- return ret;
+ dev_err(dev, "failed to enable SDn clock (%d)\n", ret);
+ goto err_clkh;
}
priv->quirks = quirks;
ret = tmio_sd_probe(dev, quirks);
+ if (ret)
+ goto err_tmio_probe;
renesas_sdhi_filter_caps(dev);
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
- if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS))
+ if (priv->caps & TMIO_SD_CAP_RCAR_UHS)
renesas_sdhi_reset_tuning(priv);
#endif
+ return 0;
+
+err_tmio_probe:
+ clk_disable(&priv->clk);
+err_clkh:
+ clk_free(&priv->clkh);
+err_clk:
+ clk_free(&priv->clk);
return ret;
}
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index 573bf16c875..3661ce33143 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -41,6 +41,14 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
struct rockchip_dwmmc_priv *priv = dev_get_priv(dev);
int ret;
+ /*
+ * The clock frequency chosen here affects CLKDIV in the dw_mmc core.
+ * That can be either 0 or 1, but it must be set to 1 for eMMC DDR52
+ * 8-bit mode. It will be set to 0 for all other modes.
+ */
+ if (host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8)
+ freq *= 2;
+
ret = clk_set_rate(&priv->clk, freq);
if (ret < 0) {
debug("%s: err=%d\n", __func__, ret);
diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index e477a6cd9e9..13057639403 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -11,6 +11,13 @@ config PHY_ROCKCHIP_INNO_USB2
help
Support for Rockchip USB2.0 PHY with Innosilicon IP block.
+config PHY_ROCKCHIP_NANENG_COMBOPHY
+ bool "Support Rockchip NANENG combo PHY Driver"
+ depends on ARCH_ROCKCHIP
+ select PHY
+ help
+ Enable this to support the Rockchip NANENG combo PHY.
+
config PHY_ROCKCHIP_PCIE
bool "Rockchip PCIe PHY Driver"
depends on ARCH_ROCKCHIP
diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile
index f6ad3bf59ae..a236877234b 100644
--- a/drivers/phy/rockchip/Makefile
+++ b/drivers/phy/rockchip/Makefile
@@ -4,6 +4,7 @@
#
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
+obj-$(CONFIG_PHY_ROCKCHIP_NANENG_COMBOPHY) += phy-rockchip-naneng-combphy.o
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index b32a498ea71..55e1dbcfef7 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -179,12 +179,21 @@ static int rockchip_usb2phy_probe(struct udevice *dev)
if (IS_ERR(priv->reg_base))
return PTR_ERR(priv->reg_base);
- ret = ofnode_read_u32(dev_ofnode(dev), "reg", &reg);
+ ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", 0, &reg);
if (ret) {
dev_err(dev, "failed to read reg property (ret = %d)\n", ret);
return ret;
}
+ /* support address_cells=2 */
+ if (reg == 0) {
+ if (ofnode_read_u32_index(dev_ofnode(dev), "reg", 1, &reg)) {
+ dev_err(dev, "%s must have reg[1]\n",
+ ofnode_get_name(dev_ofnode(dev)));
+ return -EINVAL;
+ }
+ }
+
phy_cfgs = (const struct rockchip_usb2phy_cfg *)
dev_get_driver_data(dev);
if (!phy_cfgs)
@@ -289,11 +298,65 @@ static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
{ /* sentinel */ }
};
+static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
+ {
+ .reg = 0xfe8a0000,
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0x0000, 8, 0, 0x052, 0x1d1 },
+ .bvalid_det_en = { 0x0080, 2, 2, 0, 1 },
+ .bvalid_det_st = { 0x0084, 2, 2, 0, 1 },
+ .bvalid_det_clr = { 0x0088, 2, 2, 0, 1 },
+ .ls_det_en = { 0x0080, 0, 0, 0, 1 },
+ .ls_det_st = { 0x0084, 0, 0, 0, 1 },
+ .ls_det_clr = { 0x0088, 0, 0, 0, 1 },
+ .utmi_avalid = { 0x00c0, 10, 10, 0, 1 },
+ .utmi_bvalid = { 0x00c0, 9, 9, 0, 1 },
+ .utmi_ls = { 0x00c0, 5, 4, 0, 1 },
+ },
+ [USB2PHY_PORT_HOST] = {
+ .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d1 },
+ .ls_det_en = { 0x0080, 1, 1, 0, 1 },
+ .ls_det_st = { 0x0084, 1, 1, 0, 1 },
+ .ls_det_clr = { 0x0088, 1, 1, 0, 1 },
+ .utmi_ls = { 0x00c0, 17, 16, 0, 1 },
+ .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 }
+ }
+ },
+ },
+ {
+ .reg = 0xfe8b0000,
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0x0000, 8, 0, 0x1d2, 0x1d1 },
+ .ls_det_en = { 0x0080, 0, 0, 0, 1 },
+ .ls_det_st = { 0x0084, 0, 0, 0, 1 },
+ .ls_det_clr = { 0x0088, 0, 0, 0, 1 },
+ .utmi_ls = { 0x00c0, 5, 4, 0, 1 },
+ .utmi_hstdet = { 0x00c0, 7, 7, 0, 1 }
+ },
+ [USB2PHY_PORT_HOST] = {
+ .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d1 },
+ .ls_det_en = { 0x0080, 1, 1, 0, 1 },
+ .ls_det_st = { 0x0084, 1, 1, 0, 1 },
+ .ls_det_clr = { 0x0088, 1, 1, 0, 1 },
+ .utmi_ls = { 0x00c0, 17, 16, 0, 1 },
+ .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 }
+ }
+ },
+ },
+ { /* sentinel */ }
+};
+
static const struct udevice_id rockchip_usb2phy_ids[] = {
{
.compatible = "rockchip,rk3399-usb2phy",
.data = (ulong)&rk3399_usb2phy_cfgs,
},
+ {
+ .compatible = "rockchip,rk3568-usb2phy",
+ .data = (ulong)&rk3568_phy_cfgs,
+ },
{ /* sentinel */ }
};
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
new file mode 100644
index 00000000000..78da5fe7970
--- /dev/null
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip USB3.0/PCIe Gen2/SATA/SGMII combphy driver
+ *
+ * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dt-bindings/phy/phy.h>
+#include <generic-phy.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch-rockchip/clock.h>
+#include <regmap.h>
+#include <reset-uclass.h>
+#include <dm/device_compat.h>
+
+#define BIT_WRITEABLE_SHIFT 16
+
+struct rockchip_combphy_priv;
+
+struct combphy_reg {
+ u16 offset;
+ u16 bitend;
+ u16 bitstart;
+ u16 disable;
+ u16 enable;
+};
+
+struct rockchip_combphy_grfcfg {
+ struct combphy_reg pcie_mode_set;
+ struct combphy_reg usb_mode_set;
+ struct combphy_reg sgmii_mode_set;
+ struct combphy_reg qsgmii_mode_set;
+ struct combphy_reg pipe_rxterm_set;
+ struct combphy_reg pipe_txelec_set;
+ struct combphy_reg pipe_txcomp_set;
+ struct combphy_reg pipe_clk_25m;
+ struct combphy_reg pipe_clk_100m;
+ struct combphy_reg pipe_phymode_sel;
+ struct combphy_reg pipe_rate_sel;
+ struct combphy_reg pipe_rxterm_sel;
+ struct combphy_reg pipe_txelec_sel;
+ struct combphy_reg pipe_txcomp_sel;
+ struct combphy_reg pipe_clk_ext;
+ struct combphy_reg pipe_sel_usb;
+ struct combphy_reg pipe_sel_qsgmii;
+ struct combphy_reg pipe_phy_status;
+ struct combphy_reg con0_for_pcie;
+ struct combphy_reg con1_for_pcie;
+ struct combphy_reg con2_for_pcie;
+ struct combphy_reg con3_for_pcie;
+ struct combphy_reg con0_for_sata;
+ struct combphy_reg con1_for_sata;
+ struct combphy_reg con2_for_sata;
+ struct combphy_reg con3_for_sata;
+ struct combphy_reg pipe_con0_for_sata;
+ struct combphy_reg pipe_sgmii_mac_sel;
+ struct combphy_reg pipe_xpcs_phy_ready;
+ struct combphy_reg u3otg0_port_en;
+ struct combphy_reg u3otg1_port_en;
+};
+
+struct rockchip_combphy_cfg {
+ const struct rockchip_combphy_grfcfg *grfcfg;
+ int (*combphy_cfg)(struct rockchip_combphy_priv *priv);
+};
+
+struct rockchip_combphy_priv {
+ u32 mode;
+ void __iomem *mmio;
+ struct udevice *dev;
+ struct regmap *pipe_grf;
+ struct regmap *phy_grf;
+ struct phy *phy;
+ struct reset_ctl phy_rst;
+ struct clk ref_clk;
+ const struct rockchip_combphy_cfg *cfg;
+};
+
+static int param_write(struct regmap *base,
+ const struct combphy_reg *reg, bool en)
+{
+ u32 val, mask, tmp;
+
+ tmp = en ? reg->enable : reg->disable;
+ mask = GENMASK(reg->bitend, reg->bitstart);
+ val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
+
+ return regmap_write(base, reg->offset, val);
+}
+
+static int rockchip_combphy_pcie_init(struct rockchip_combphy_priv *priv)
+{
+ int ret = 0;
+
+ if (priv->cfg->combphy_cfg) {
+ ret = priv->cfg->combphy_cfg(priv);
+ if (ret) {
+ dev_err(priv->dev, "failed to init phy for pcie\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int rockchip_combphy_usb3_init(struct rockchip_combphy_priv *priv)
+{
+ int ret = 0;
+
+ if (priv->cfg->combphy_cfg) {
+ ret = priv->cfg->combphy_cfg(priv);
+ if (ret) {
+ dev_err(priv->dev, "failed to init phy for usb3\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int rockchip_combphy_sata_init(struct rockchip_combphy_priv *priv)
+{
+ int ret = 0;
+
+ if (priv->cfg->combphy_cfg) {
+ ret = priv->cfg->combphy_cfg(priv);
+ if (ret) {
+ dev_err(priv->dev, "failed to init phy for sata\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int rockchip_combphy_sgmii_init(struct rockchip_combphy_priv *priv)
+{
+ int ret = 0;
+
+ if (priv->cfg->combphy_cfg) {
+ ret = priv->cfg->combphy_cfg(priv);
+ if (ret) {
+ dev_err(priv->dev, "failed to init phy for sgmii\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int rockchip_combphy_set_mode(struct rockchip_combphy_priv *priv)
+{
+ switch (priv->mode) {
+ case PHY_TYPE_PCIE:
+ rockchip_combphy_pcie_init(priv);
+ break;
+ case PHY_TYPE_USB3:
+ rockchip_combphy_usb3_init(priv);
+ break;
+ case PHY_TYPE_SATA:
+ rockchip_combphy_sata_init(priv);
+ break;
+ case PHY_TYPE_SGMII:
+ case PHY_TYPE_QSGMII:
+ return rockchip_combphy_sgmii_init(priv);
+ default:
+ dev_err(priv->dev, "incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rockchip_combphy_init(struct phy *phy)
+{
+ struct rockchip_combphy_priv *priv = dev_get_priv(phy->dev);
+ int ret;
+
+ ret = clk_enable(&priv->ref_clk);
+ if (ret < 0 && ret != -ENOSYS)
+ return ret;
+
+ ret = rockchip_combphy_set_mode(priv);
+ if (ret)
+ goto err_clk;
+
+ reset_deassert(&priv->phy_rst);
+
+ return 0;
+
+err_clk:
+ clk_disable(&priv->ref_clk);
+
+ return ret;
+}
+
+static int rockchip_combphy_exit(struct phy *phy)
+{
+ struct rockchip_combphy_priv *priv = dev_get_priv(phy->dev);
+
+ clk_disable(&priv->ref_clk);
+ reset_assert(&priv->phy_rst);
+
+ return 0;
+}
+
+static int rockchip_combphy_xlate(struct phy *phy, struct ofnode_phandle_args *args)
+{
+ struct rockchip_combphy_priv *priv = dev_get_priv(phy->dev);
+
+ if (args->args_count != 1) {
+ pr_err("invalid number of arguments\n");
+ return -EINVAL;
+ }
+
+ priv->mode = args->args[0];
+
+ return 0;
+}
+
+static const struct phy_ops rochchip_combphy_ops = {
+ .init = rockchip_combphy_init,
+ .exit = rockchip_combphy_exit,
+ .of_xlate = rockchip_combphy_xlate,
+};
+
+static int rockchip_combphy_parse_dt(struct udevice *dev,
+ struct rockchip_combphy_priv *priv)
+{
+ struct udevice *syscon;
+ int ret;
+
+ ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,pipe-grf", &syscon);
+ if (ret) {
+ dev_err(dev, "failed to find peri_ctrl pipe-grf regmap");
+ return ret;
+ }
+ priv->pipe_grf = syscon_get_regmap(syscon);
+
+ ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,pipe-phy-grf", &syscon);
+ if (ret) {
+ dev_err(dev, "failed to find peri_ctrl pipe-phy-grf regmap\n");
+ return ret;
+ }
+ priv->phy_grf = syscon_get_regmap(syscon);
+
+ ret = clk_get_by_index(dev, 0, &priv->ref_clk);
+ if (ret) {
+ dev_err(dev, "failed to find ref clock\n");
+ return PTR_ERR(&priv->ref_clk);
+ }
+
+ ret = reset_get_by_index(dev, 0, &priv->phy_rst);
+ if (ret) {
+ dev_err(dev, "no phy reset control specified\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rockchip_combphy_probe(struct udevice *udev)
+{
+ struct rockchip_combphy_priv *priv = dev_get_priv(udev);
+ const struct rockchip_combphy_cfg *phy_cfg;
+
+ priv->mmio = (void __iomem *)dev_read_addr(udev);
+ if (IS_ERR(priv->mmio))
+ return PTR_ERR(priv->mmio);
+
+ phy_cfg = (const struct rockchip_combphy_cfg *)dev_get_driver_data(udev);
+ if (!phy_cfg) {
+ dev_err(udev, "No OF match data provided\n");
+ return -EINVAL;
+ }
+
+ priv->dev = udev;
+ priv->mode = PHY_TYPE_SATA;
+ priv->cfg = phy_cfg;
+
+ return rockchip_combphy_parse_dt(udev, priv);
+}
+
+static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)
+{
+ const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
+ u32 val;
+
+ switch (priv->mode) {
+ case PHY_TYPE_PCIE:
+ /* Set SSC downward spread spectrum */
+ val = readl(priv->mmio + (0x1f << 2));
+ val &= ~GENMASK(5, 4);
+ val |= 0x01 << 4;
+ writel(val, priv->mmio + 0x7c);
+
+ param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
+ param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
+ break;
+ case PHY_TYPE_USB3:
+ /* Set SSC downward spread spectrum */
+ val = readl(priv->mmio + (0x1f << 2));
+ val &= ~GENMASK(5, 4);
+ val |= 0x01 << 4;
+ writel(val, priv->mmio + 0x7c);
+
+ /* Enable adaptive CTLE for USB3.0 Rx */
+ val = readl(priv->mmio + (0x0e << 2));
+ val &= ~GENMASK(0, 0);
+ val |= 0x01;
+ writel(val, priv->mmio + (0x0e << 2));
+
+ /* Set PLL KVCO fine tuning signals */
+ val = readl(priv->mmio + (0x20 << 2));
+ val &= ~(0x7 << 2);
+ val |= 0x2 << 2;
+ writel(val, priv->mmio + (0x20 << 2));
+
+ /* Set PLL LPF R1 to su_trim[10:7]=1001 */
+ writel(0x4, priv->mmio + (0xb << 2));
+
+ /* Set PLL input clock divider 1/2 */
+ val = readl(priv->mmio + (0x5 << 2));
+ val &= ~(0x3 << 6);
+ val |= 0x1 << 6;
+ writel(val, priv->mmio + (0x5 << 2));
+
+ /* Set PLL loop divider */
+ writel(0x32, priv->mmio + (0x11 << 2));
+
+ /* Set PLL KVCO to min and set PLL charge pump current to max */
+ writel(0xf0, priv->mmio + (0xa << 2));
+
+ param_write(priv->phy_grf, &cfg->pipe_sel_usb, true);
+ param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
+ param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
+ param_write(priv->phy_grf, &cfg->usb_mode_set, true);
+ break;
+ case PHY_TYPE_SATA:
+ writel(0x41, priv->mmio + 0x38);
+ writel(0x8F, priv->mmio + 0x18);
+ param_write(priv->phy_grf, &cfg->con0_for_sata, true);
+ param_write(priv->phy_grf, &cfg->con1_for_sata, true);
+ param_write(priv->phy_grf, &cfg->con2_for_sata, true);
+ param_write(priv->phy_grf, &cfg->con3_for_sata, true);
+ param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true);
+ break;
+ case PHY_TYPE_SGMII:
+ param_write(priv->pipe_grf, &cfg->pipe_xpcs_phy_ready, true);
+ param_write(priv->phy_grf, &cfg->pipe_phymode_sel, true);
+ param_write(priv->phy_grf, &cfg->pipe_sel_qsgmii, true);
+ param_write(priv->phy_grf, &cfg->sgmii_mode_set, true);
+ break;
+ case PHY_TYPE_QSGMII:
+ param_write(priv->pipe_grf, &cfg->pipe_xpcs_phy_ready, true);
+ param_write(priv->phy_grf, &cfg->pipe_phymode_sel, true);
+ param_write(priv->phy_grf, &cfg->pipe_rate_sel, true);
+ param_write(priv->phy_grf, &cfg->pipe_sel_qsgmii, true);
+ param_write(priv->phy_grf, &cfg->qsgmii_mode_set, true);
+ break;
+ default:
+ pr_err("%s, phy-type %d\n", __func__, priv->mode);
+ return -EINVAL;
+ }
+
+ /* The default ref clock is 25Mhz */
+ param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
+
+ if (dev_read_bool(priv->dev, "rockchip,enable-ssc")) {
+ val = readl(priv->mmio + (0x7 << 2));
+ val |= BIT(4);
+ writel(val, priv->mmio + (0x7 << 2));
+ }
+
+ return 0;
+}
+
+static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = {
+ /* pipe-phy-grf */
+ .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
+ .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
+ .sgmii_mode_set = { 0x0000, 5, 0, 0x00, 0x01 },
+ .qsgmii_mode_set = { 0x0000, 5, 0, 0x00, 0x21 },
+ .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
+ .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
+ .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
+ .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 },
+ .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
+ .pipe_phymode_sel = { 0x0008, 1, 1, 0x00, 0x01 },
+ .pipe_rate_sel = { 0x0008, 2, 2, 0x00, 0x01 },
+ .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
+ .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
+ .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
+ .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
+ .pipe_sel_usb = { 0x000c, 14, 13, 0x00, 0x01 },
+ .pipe_sel_qsgmii = { 0x000c, 15, 13, 0x00, 0x07 },
+ .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
+ .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 },
+ .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 },
+ .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 },
+ .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
+ .con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0119 },
+ .con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0040 },
+ .con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c3 },
+ .con3_for_sata = { 0x000c, 15, 0, 0x00, 0x4407 },
+ /* pipe-grf */
+ .pipe_con0_for_sata = { 0x0000, 15, 0, 0x00, 0x2220 },
+ .pipe_sgmii_mac_sel = { 0x0040, 1, 1, 0x00, 0x01 },
+ .pipe_xpcs_phy_ready = { 0x0040, 2, 2, 0x00, 0x01 },
+ .u3otg0_port_en = { 0x0104, 15, 0, 0x0181, 0x1100 },
+ .u3otg1_port_en = { 0x0144, 15, 0, 0x0181, 0x1100 },
+};
+
+static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = {
+ .grfcfg = &rk3568_combphy_grfcfgs,
+ .combphy_cfg = rk3568_combphy_cfg,
+};
+
+static const struct udevice_id rockchip_combphy_ids[] = {
+ {
+ .compatible = "rockchip,rk3568-naneng-combphy",
+ .data = (ulong)&rk3568_combphy_cfgs
+ },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_naneng_combphy) = {
+ .name = "naneng-combphy",
+ .id = UCLASS_PHY,
+ .of_match = rockchip_combphy_ids,
+ .ops = &rochchip_combphy_ops,
+ .probe = rockchip_combphy_probe,
+ .priv_auto = sizeof(struct rockchip_combphy_priv),
+};
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 25fbe39abd1..1be6252227d 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -745,6 +745,19 @@ static int armada_37xx_pinctrl_probe(struct udevice *dev)
return 0;
}
+static int armada_37xx_pinctrl_bind(struct udevice *dev)
+{
+ /*
+ * Make sure that the pinctrl driver gets probed after binding
+ * as on A37XX the pinctrl driver is the one that is also
+ * registering the GPIO one during probe, so if its not probed
+ * GPIO-s are not registered as well.
+ */
+ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
+
+ return 0;
+}
+
static const struct udevice_id armada_37xx_pinctrl_of_match[] = {
{
.compatible = "marvell,armada3710-sb-pinctrl",
@@ -762,6 +775,7 @@ U_BOOT_DRIVER(armada_37xx_pinctrl) = {
.id = UCLASS_PINCTRL,
.of_match = of_match_ptr(armada_37xx_pinctrl_of_match),
.probe = armada_37xx_pinctrl_probe,
+ .bind = armada_37xx_pinctrl_bind,
.priv_auto = sizeof(struct armada_37xx_pinctrl),
.ops = &armada_37xx_pinctrl_ops,
};
diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h
index 59d447ead5c..0ab743e80d5 100644
--- a/drivers/pinctrl/renesas/sh_pfc.h
+++ b/drivers/pinctrl/renesas/sh_pfc.h
@@ -309,21 +309,6 @@ extern const struct sh_pfc_soc_info r8a77980_pinmux_info;
extern const struct sh_pfc_soc_info r8a77990_pinmux_info;
extern const struct sh_pfc_soc_info r8a77995_pinmux_info;
extern const struct sh_pfc_soc_info r8a779a0_pinmux_info;
-extern const struct sh_pfc_soc_info r8a779f0_pinmux_info;
-extern const struct sh_pfc_soc_info r8a779g0_pinmux_info;
-extern const struct sh_pfc_soc_info sh7203_pinmux_info;
-extern const struct sh_pfc_soc_info sh7264_pinmux_info;
-extern const struct sh_pfc_soc_info sh7269_pinmux_info;
-extern const struct sh_pfc_soc_info sh73a0_pinmux_info;
-extern const struct sh_pfc_soc_info sh7720_pinmux_info;
-extern const struct sh_pfc_soc_info sh7722_pinmux_info;
-extern const struct sh_pfc_soc_info sh7723_pinmux_info;
-extern const struct sh_pfc_soc_info sh7724_pinmux_info;
-extern const struct sh_pfc_soc_info sh7734_pinmux_info;
-extern const struct sh_pfc_soc_info sh7757_pinmux_info;
-extern const struct sh_pfc_soc_info sh7785_pinmux_info;
-extern const struct sh_pfc_soc_info sh7786_pinmux_info;
-extern const struct sh_pfc_soc_info shx3_pinmux_info;
/* -----------------------------------------------------------------------------
* Helper macros to create pin and port lists
diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile
index 98843554733..90461ae8819 100644
--- a/drivers/pinctrl/rockchip/Makefile
+++ b/drivers/pinctrl/rockchip/Makefile
@@ -14,5 +14,6 @@ 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_RK3568) += pinctrl-rk3568.o
obj-$(CONFIG_ROCKCHIP_RV1108) += pinctrl-rv1108.o
obj-$(CONFIG_ROCKCHIP_RV1126) += pinctrl-rv1126.o
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3568.c b/drivers/pinctrl/rockchip/pinctrl-rk3568.c
new file mode 100644
index 00000000000..935aed9efc6
--- /dev/null
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3568.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2020 Rockchip Electronics Co., Ltd
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+
+#include "pinctrl-rockchip.h"
+
+static struct rockchip_mux_route_data rk3568_mux_route_data[] = {
+ MR_TOPGRF(RK_GPIO0, RK_PB3, RK_FUNC_2, 0x0300, RK_GENMASK_VAL(0, 0, 0)), /* CAN0 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO2, RK_PA1, RK_FUNC_4, 0x0300, RK_GENMASK_VAL(0, 0, 1)), /* CAN0 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO1, RK_PA1, RK_FUNC_3, 0x0300, RK_GENMASK_VAL(2, 2, 0)), /* CAN1 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO4, RK_PC3, RK_FUNC_3, 0x0300, RK_GENMASK_VAL(2, 2, 1)), /* CAN1 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO4, RK_PB5, RK_FUNC_3, 0x0300, RK_GENMASK_VAL(4, 4, 0)), /* CAN2 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO2, RK_PB2, RK_FUNC_4, 0x0300, RK_GENMASK_VAL(4, 4, 1)), /* CAN2 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO4, RK_PC4, RK_FUNC_1, 0x0300, RK_GENMASK_VAL(6, 6, 0)), /* EDPDP_HPDIN IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO0, RK_PC2, RK_FUNC_2, 0x0300, RK_GENMASK_VAL(6, 6, 1)), /* EDPDP_HPDIN IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PB1, RK_FUNC_3, 0x0300, RK_GENMASK_VAL(8, 8, 0)), /* GMAC1 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO4, RK_PA7, RK_FUNC_3, 0x0300, RK_GENMASK_VAL(8, 8, 1)), /* GMAC1 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO4, RK_PD1, RK_FUNC_1, 0x0300, RK_GENMASK_VAL(10, 10, 0)), /* HDMITX IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO0, RK_PC7, RK_FUNC_1, 0x0300, RK_GENMASK_VAL(10, 10, 1)), /* HDMITX IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO0, RK_PB6, RK_FUNC_1, 0x0300, RK_GENMASK_VAL(14, 14, 0)), /* I2C2 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO4, RK_PB4, RK_FUNC_1, 0x0300, RK_GENMASK_VAL(14, 14, 1)), /* I2C2 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO1, RK_PA0, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(0, 0, 0)), /* I2C3 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PB6, RK_FUNC_4, 0x0304, RK_GENMASK_VAL(0, 0, 1)), /* I2C3 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO4, RK_PB2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(2, 2, 0)), /* I2C4 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO2, RK_PB1, RK_FUNC_2, 0x0304, RK_GENMASK_VAL(2, 2, 1)), /* I2C4 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PB4, RK_FUNC_4, 0x0304, RK_GENMASK_VAL(4, 4, 0)), /* I2C5 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO4, RK_PD0, RK_FUNC_2, 0x0304, RK_GENMASK_VAL(4, 4, 1)), /* I2C5 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(6, 6, 0)), /* PWM4 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(6, 6, 1)), /* PWM4 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(8, 8, 0)), /* PWM5 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(8, 8, 1)), /* PWM5 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(10, 10, 0)), /* PWM6 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(10, 10, 1)), /* PWM6 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(12, 12, 0)), /* PWM7 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(12, 12, 1)), /* PWM7 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(14, 14, 0)), /* PWM8 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0304, RK_GENMASK_VAL(14, 14, 1)), /* PWM8 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(0, 0, 0)), /* PWM9 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(0, 0, 1)), /* PWM9 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(2, 2, 0)), /* PWM10 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(2, 2, 1)), /* PWM10 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(4, 4, 0)), /* PWM11 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(4, 4, 1)), /* PWM11 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(6, 6, 0)), /* PWM12 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(6, 6, 1)), /* PWM12 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(8, 8, 0)), /* PWM13 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(8, 8, 1)), /* PWM13 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(10, 10, 0)), /* PWM14 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(10, 10, 1)), /* PWM14 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(12, 12, 0)), /* PWM15 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0308, RK_GENMASK_VAL(12, 12, 1)), /* PWM15 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_3, 0x0308, RK_GENMASK_VAL(14, 14, 0)), /* SDMMC2 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PA5, RK_FUNC_5, 0x0308, RK_GENMASK_VAL(14, 14, 1)), /* SDMMC2 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO0, RK_PB5, RK_FUNC_2, 0x030c, RK_GENMASK_VAL(0, 0, 0)), /* SPI0 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO2, RK_PD3, RK_FUNC_3, 0x030c, RK_GENMASK_VAL(0, 0, 1)), /* SPI0 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO2, RK_PB5, RK_FUNC_3, 0x030c, RK_GENMASK_VAL(2, 2, 0)), /* SPI1 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PC3, RK_FUNC_3, 0x030c, RK_GENMASK_VAL(2, 2, 1)), /* SPI1 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO2, RK_PC1, RK_FUNC_4, 0x030c, RK_GENMASK_VAL(4, 4, 0)), /* SPI2 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PA0, RK_FUNC_3, 0x030c, RK_GENMASK_VAL(4, 4, 1)), /* SPI2 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO4, RK_PB3, RK_FUNC_4, 0x030c, RK_GENMASK_VAL(6, 6, 0)), /* SPI3 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO4, RK_PC2, RK_FUNC_2, 0x030c, RK_GENMASK_VAL(6, 6, 1)), /* SPI3 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO2, RK_PB4, RK_FUNC_2, 0x030c, RK_GENMASK_VAL(8, 8, 0)), /* UART1 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO0, RK_PD1, RK_FUNC_1, 0x030c, RK_GENMASK_VAL(8, 8, 1)), /* UART1 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO0, RK_PD1, RK_FUNC_1, 0x030c, RK_GENMASK_VAL(10, 10, 0)), /* UART2 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO1, RK_PD5, RK_FUNC_2, 0x030c, RK_GENMASK_VAL(10, 10, 1)), /* UART2 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO1, RK_PA1, RK_FUNC_2, 0x030c, RK_GENMASK_VAL(12, 12, 0)), /* UART3 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PB7, RK_FUNC_4, 0x030c, RK_GENMASK_VAL(12, 12, 1)), /* UART3 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO1, RK_PA6, RK_FUNC_2, 0x030c, RK_GENMASK_VAL(14, 14, 0)), /* UART4 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PB2, RK_FUNC_4, 0x030c, RK_GENMASK_VAL(14, 14, 1)), /* UART4 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO2, RK_PA2, RK_FUNC_3, 0x0310, RK_GENMASK_VAL(0, 0, 0)), /* UART5 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PC2, RK_FUNC_4, 0x0310, RK_GENMASK_VAL(0, 0, 1)), /* UART5 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO2, RK_PA4, RK_FUNC_3, 0x0310, RK_GENMASK_VAL(2, 2, 0)), /* UART6 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO1, RK_PD5, RK_FUNC_3, 0x0310, RK_GENMASK_VAL(2, 2, 1)), /* UART6 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO2, RK_PA6, RK_FUNC_3, 0x0310, RK_GENMASK_VAL(5, 4, 0)), /* UART7 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PC4, RK_FUNC_4, 0x0310, RK_GENMASK_VAL(5, 4, 1)), /* UART7 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PD2, RK_FUNC_1, 0x0310, RK_GENMASK_VAL(5, 4, 2)), /* UART7 IO mux selection M2 */
+ MR_TOPGRF(RK_GPIO2, RK_PC5, RK_FUNC_3, 0x0310, RK_GENMASK_VAL(6, 6, 0)), /* UART8 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO2, RK_PD7, RK_FUNC_4, 0x0310, RK_GENMASK_VAL(6, 6, 1)), /* UART8 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO2, RK_PB0, RK_FUNC_3, 0x0310, RK_GENMASK_VAL(9, 8, 0)), /* UART9 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO4, RK_PC5, RK_FUNC_4, 0x0310, RK_GENMASK_VAL(9, 8, 1)), /* UART9 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO4, RK_PA4, RK_FUNC_4, 0x0310, RK_GENMASK_VAL(9, 8, 2)), /* UART9 IO mux selection M2 */
+ MR_TOPGRF(RK_GPIO1, RK_PA2, RK_FUNC_1, 0x0310, RK_GENMASK_VAL(11, 10, 0)), /* I2S1 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PC6, RK_FUNC_4, 0x0310, RK_GENMASK_VAL(11, 10, 1)), /* I2S1 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO2, RK_PD0, RK_FUNC_5, 0x0310, RK_GENMASK_VAL(11, 10, 2)), /* I2S1 IO mux selection M2 */
+ MR_TOPGRF(RK_GPIO2, RK_PC1, RK_FUNC_1, 0x0310, RK_GENMASK_VAL(12, 12, 0)), /* I2S2 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO4, RK_PB6, RK_FUNC_5, 0x0310, RK_GENMASK_VAL(12, 12, 1)), /* I2S2 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO3, RK_PA2, RK_FUNC_4, 0x0310, RK_GENMASK_VAL(14, 14, 0)), /* I2S3 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO4, RK_PC2, RK_FUNC_5, 0x0310, RK_GENMASK_VAL(14, 14, 1)), /* I2S3 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO1, RK_PA6, RK_FUNC_3, 0x0314, RK_GENMASK_VAL(0, 0, 0)), /* PDM IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO3, RK_PD6, RK_FUNC_5, 0x0314, RK_GENMASK_VAL(0, 0, 1)), /* PDM IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO0, RK_PA5, RK_FUNC_3, 0x0314, RK_GENMASK_VAL(3, 2, 0)), /* PCIE20 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO2, RK_PD0, RK_FUNC_4, 0x0314, RK_GENMASK_VAL(3, 2, 1)), /* PCIE20 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO1, RK_PB0, RK_FUNC_4, 0x0314, RK_GENMASK_VAL(3, 2, 2)), /* PCIE20 IO mux selection M2 */
+ MR_TOPGRF(RK_GPIO0, RK_PA4, RK_FUNC_3, 0x0314, RK_GENMASK_VAL(5, 4, 0)), /* PCIE30X1 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO2, RK_PD2, RK_FUNC_4, 0x0314, RK_GENMASK_VAL(5, 4, 1)), /* PCIE30X1 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO1, RK_PA5, RK_FUNC_4, 0x0314, RK_GENMASK_VAL(5, 4, 2)), /* PCIE30X1 IO mux selection M2 */
+ MR_TOPGRF(RK_GPIO0, RK_PA6, RK_FUNC_2, 0x0314, RK_GENMASK_VAL(7, 6, 0)), /* PCIE30X2 IO mux selection M0 */
+ MR_TOPGRF(RK_GPIO2, RK_PD4, RK_FUNC_4, 0x0314, RK_GENMASK_VAL(7, 6, 1)), /* PCIE30X2 IO mux selection M1 */
+ MR_TOPGRF(RK_GPIO4, RK_PC2, RK_FUNC_4, 0x0314, RK_GENMASK_VAL(7, 6, 2)), /* PCIE30X2 IO mux selection M2 */
+};
+
+static int rk3568_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, ret, mask;
+ u8 bit;
+ u32 data;
+
+ debug("setting mux of GPIO%d-%d to %d\n", bank->bank_num, pin, mux);
+
+ if (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ regmap = priv->regmap_pmu;
+ else
+ 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));
+ data |= (mux & mask) << bit;
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
+#define RK3568_PULL_PMU_OFFSET 0x20
+#define RK3568_PULL_GRF_OFFSET 0x80
+#define RK3568_PULL_BITS_PER_PIN 2
+#define RK3568_PULL_PINS_PER_REG 8
+#define RK3568_PULL_BANK_STRIDE 0x10
+
+static void rk3568_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *info = bank->priv;
+
+ if (bank->bank_num == 0) {
+ *regmap = info->regmap_pmu;
+ *reg = RK3568_PULL_PMU_OFFSET;
+ *reg += bank->bank_num * RK3568_PULL_BANK_STRIDE;
+ } else {
+ *regmap = info->regmap_base;
+ *reg = RK3568_PULL_GRF_OFFSET;
+ *reg += (bank->bank_num - 1) * RK3568_PULL_BANK_STRIDE;
+ }
+
+ *reg += ((pin_num / RK3568_PULL_PINS_PER_REG) * 4);
+ *bit = (pin_num % RK3568_PULL_PINS_PER_REG);
+ *bit *= RK3568_PULL_BITS_PER_PIN;
+}
+
+#define RK3568_DRV_PMU_OFFSET 0x70
+#define RK3568_DRV_GRF_OFFSET 0x200
+#define RK3568_DRV_BITS_PER_PIN 8
+#define RK3568_DRV_PINS_PER_REG 2
+#define RK3568_DRV_BANK_STRIDE 0x40
+
+static void rk3568_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *info = bank->priv;
+
+ /* The first 32 pins of the first bank are located in PMU */
+ if (bank->bank_num == 0) {
+ *regmap = info->regmap_pmu;
+ *reg = RK3568_DRV_PMU_OFFSET;
+ } else {
+ *regmap = info->regmap_base;
+ *reg = RK3568_DRV_GRF_OFFSET;
+ *reg += (bank->bank_num - 1) * RK3568_DRV_BANK_STRIDE;
+ }
+
+ *reg += ((pin_num / RK3568_DRV_PINS_PER_REG) * 4);
+ *bit = (pin_num % RK3568_DRV_PINS_PER_REG);
+ *bit *= RK3568_DRV_BITS_PER_PIN;
+}
+
+#define RK3568_SCHMITT_BITS_PER_PIN 2
+#define RK3568_SCHMITT_PINS_PER_REG 8
+#define RK3568_SCHMITT_BANK_STRIDE 0x10
+#define RK3568_SCHMITT_GRF_OFFSET 0xc0
+#define RK3568_SCHMITT_PMUGRF_OFFSET 0x30
+
+static int rk3568_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *info = bank->priv;
+
+ if (bank->bank_num == 0) {
+ *regmap = info->regmap_pmu;
+ *reg = RK3568_SCHMITT_PMUGRF_OFFSET;
+ } else {
+ *regmap = info->regmap_base;
+ *reg = RK3568_SCHMITT_GRF_OFFSET;
+ *reg += (bank->bank_num - 1) * RK3568_SCHMITT_BANK_STRIDE;
+ }
+
+ *reg += ((pin_num / RK3568_SCHMITT_PINS_PER_REG) * 4);
+ *bit = pin_num % RK3568_SCHMITT_PINS_PER_REG;
+ *bit *= RK3568_SCHMITT_BITS_PER_PIN;
+
+ return 0;
+}
+
+static int rk3568_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -ENOTSUPP;
+
+ rk3568_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &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 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+
+ data |= (ret << bit);
+ ret = regmap_write(regmap, reg, data);
+
+ return ret;
+}
+
+static int rk3568_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg;
+ u32 data;
+ u8 bit;
+ int drv = (1 << (strength + 1)) - 1;
+ int ret = 0;
+
+ rk3568_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << RK3568_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (drv << bit);
+
+ ret = regmap_write(regmap, reg, data);
+ if (ret)
+ return ret;
+
+ if (bank->bank_num == 1 && pin_num == 21)
+ reg = 0x0840;
+ else if (bank->bank_num == 2 && pin_num == 2)
+ reg = 0x0844;
+ else if (bank->bank_num == 2 && pin_num == 8)
+ reg = 0x0848;
+ else if (bank->bank_num == 3 && pin_num == 0)
+ reg = 0x084c;
+ else if (bank->bank_num == 3 && pin_num == 6)
+ reg = 0x0850;
+ else if (bank->bank_num == 4 && pin_num == 0)
+ reg = 0x0854;
+ else
+ return 0;
+
+ data = ((1 << RK3568_DRV_BITS_PER_PIN) - 1) << 16;
+ data |= drv;
+
+ return regmap_write(regmap, reg, data);
+}
+
+static int rk3568_set_schmitt(struct rockchip_pin_bank *bank,
+ int pin_num, int enable)
+{
+ struct regmap *regmap;
+ int reg;
+ u32 data;
+ u8 bit;
+
+ rk3568_calc_schmitt_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << RK3568_SCHMITT_BITS_PER_PIN) - 1) << (bit + 16);
+ data |= (enable << bit);
+
+ return regmap_write(regmap, reg, data);
+}
+
+static struct rockchip_pin_bank rk3568_pin_banks[] = {
+ PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU | IOMUX_WIDTH_4BIT,
+ IOMUX_SOURCE_PMU | IOMUX_WIDTH_4BIT,
+ IOMUX_SOURCE_PMU | IOMUX_WIDTH_4BIT,
+ IOMUX_SOURCE_PMU | IOMUX_WIDTH_4BIT),
+ PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT),
+ PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT),
+ PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT),
+ PIN_BANK_IOMUX_FLAGS(4, 32, "gpio4", IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT),
+};
+
+static const struct rockchip_pin_ctrl rk3568_pin_ctrl = {
+ .pin_banks = rk3568_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3568_pin_banks),
+ .nr_pins = 160,
+ .grf_mux_offset = 0x0,
+ .pmu_mux_offset = 0x0,
+ .iomux_routes = rk3568_mux_route_data,
+ .niomux_routes = ARRAY_SIZE(rk3568_mux_route_data),
+ .set_mux = rk3568_set_mux,
+ .set_pull = rk3568_set_pull,
+ .set_drive = rk3568_set_drive,
+ .set_schmitt = rk3568_set_schmitt,
+};
+
+static const struct udevice_id rk3568_pinctrl_ids[] = {
+ {
+ .compatible = "rockchip,rk3568-pinctrl",
+ .data = (ulong)&rk3568_pin_ctrl
+ },
+ { }
+};
+
+U_BOOT_DRIVER(pinctrl_rk3568) = {
+ .name = "rockchip_rk3568_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = rk3568_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/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile
index 98839ad6a6c..36dc0500dab 100644
--- a/drivers/ram/rockchip/Makefile
+++ b/drivers/ram/rockchip/Makefile
@@ -14,5 +14,6 @@ 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_RK3568) += sdram_rk3568.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_rk3588.c b/drivers/ram/rockchip/sdram_rk3588.c
new file mode 100644
index 00000000000..cf56e2a9412
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_rk3588.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2021 Rockchip Electronics Co., Ltd.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <syscon.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/grf_rk3588.h>
+#include <asm/arch-rockchip/sdram.h>
+
+struct dram_info {
+ struct ram_info info;
+ struct rk3588_pmu1grf *pmugrf;
+};
+
+static int rk3588_dmc_probe(struct udevice *dev)
+{
+ struct dram_info *priv = dev_get_priv(dev);
+
+ priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
+ priv->info.base = CFG_SYS_SDRAM_BASE;
+ priv->info.size =
+ rockchip_sdram_size((phys_addr_t)&priv->pmugrf->os_reg[2]) +
+ rockchip_sdram_size((phys_addr_t)&priv->pmugrf->os_reg[4]);
+
+ return 0;
+}
+
+static int rk3588_dmc_get_info(struct udevice *dev, struct ram_info *info)
+{
+ struct dram_info *priv = dev_get_priv(dev);
+
+ *info = priv->info;
+
+ return 0;
+}
+
+static struct ram_ops rk3588_dmc_ops = {
+ .get_info = rk3588_dmc_get_info,
+};
+
+static const struct udevice_id rk3588_dmc_ids[] = {
+ { .compatible = "rockchip,rk3588-dmc" },
+ { }
+};
+
+U_BOOT_DRIVER(dmc_rk3588) = {
+ .name = "rockchip_rk3588_dmc",
+ .id = UCLASS_RAM,
+ .of_match = rk3588_dmc_ids,
+ .ops = &rk3588_dmc_ops,
+ .probe = rk3588_dmc_probe,
+ .priv_auto = sizeof(struct dram_info),
+};
diff --git a/drivers/sysinfo/rcar3.c b/drivers/sysinfo/rcar3.c
index c2f4ddfbbe3..7b127986da7 100644
--- a/drivers/sysinfo/rcar3.c
+++ b/drivers/sysinfo/rcar3.c
@@ -16,12 +16,14 @@
#define BOARD_SALVATOR_X 0x0
#define BOARD_KRIEK 0x1
#define BOARD_STARTER_KIT 0x2
+#define BOARD_EAGLE 0x3
#define BOARD_SALVATOR_XS 0x4
+#define BOARD_CONDOR 0x6
+#define BOARD_DRAAK 0x7
#define BOARD_EBISU 0x8
#define BOARD_STARTER_KIT_PRE 0xB
#define BOARD_EBISU_4D 0xD
-#define BOARD_DRAAK 0xE
-#define BOARD_EAGLE 0xF
+#define BOARD_CONDOR_I 0x10
/**
* struct sysinfo_rcar_priv - sysinfo private data
@@ -65,6 +67,7 @@ static void sysinfo_rcar_parse(struct sysinfo_rcar_priv *priv)
const u8 board_rev = priv->val & BOARD_REV_MASK;
bool salvator_xs = false;
bool ebisu_4d = false;
+ bool condor_i = false;
char rev_major = '?';
char rev_minor = '?';
@@ -138,6 +141,18 @@ static void sysinfo_rcar_parse(struct sysinfo_rcar_priv *priv)
"Renesas Kriek board rev %c.%c",
rev_major, rev_minor);
return;
+ case BOARD_CONDOR_I:
+ condor_i = true;
+ fallthrough;
+ case BOARD_CONDOR:
+ if (!board_rev) { /* Only rev 0 is valid */
+ rev_major = '1';
+ rev_minor = '0';
+ }
+ snprintf(priv->boardmodel, sizeof(priv->boardmodel),
+ "Renesas Condor%s board rev %c.%c",
+ condor_i ? "-I" : "", rev_major, rev_minor);
+ return;
default:
snprintf(priv->boardmodel, sizeof(priv->boardmodel),
"Renesas -Unknown- board rev ?.?");
diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c
index c846bfb9f12..1da7e0c3a76 100644
--- a/drivers/timer/sandbox_timer.c
+++ b/drivers/timer/sandbox_timer.c
@@ -66,6 +66,8 @@ U_BOOT_DRIVER(sandbox_timer) = {
};
/* This is here in case we don't have a device tree */
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
U_BOOT_DRVINFO(sandbox_timer_non_fdt) = {
.name = "sandbox_timer",
};
+#endif
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index ebe6bf94981..94fb32d107c 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -115,6 +115,17 @@ config USB_ONBOARD_HUB
power regulator. An example for such a hub is the Microchip
USB2514B.
+config USB_HUB_DEBOUNCE_TIMEOUT
+ int "Timeout in milliseconds for USB HUB connection"
+ default 1000
+ help
+ Value in milliseconds of the USB connection timeout, the max delay to
+ wait the hub port status to be connected steadily after being powered
+ off and powered on in the usb hub driver.
+ This define allows to increase the HUB_DEBOUNCE_TIMEOUT default
+ value = 1s because some usb device needs around 1.5s to be initialized
+ and a 2s value should solve detection issue on problematic USB keys.
+
if USB_KEYBOARD
config USB_KEYBOARD_FN_KEYS