All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 5/7] rockchip: clk: pll: add pll_rk3588 type for RK3588 Soc
@ 2023-01-24 19:17 fatorangecat
  0 siblings, 0 replies; only message in thread
From: fatorangecat @ 2023-01-24 19:17 UTC (permalink / raw)
  To: u-boot; +Cc: sjg, philipp.tomsich, kever.yang, lukma, seanga2, Elaine Zhang

From: Elaine Zhang <zhangqing@rock-chips.com>

Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
---
 arch/arm/include/asm/arch-rockchip/clock.h |  15 ++
 drivers/clk/rockchip/clk_pll.c             | 231 ++++++++++++++++++++-
 2 files changed, 243 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h
index 52eaf6f5e4..6b09fa0057 100644
--- a/arch/arm/include/asm/arch-rockchip/clock.h
+++ b/arch/arm/include/asm/arch-rockchip/clock.h
@@ -68,6 +68,15 @@ enum rk_clk_id {
 	.frac = _frac,						\
 }
 
+#define RK3588_PLL_RATE(_rate, _p, _m, _s, _k)			\
+{								\
+	.rate	= _rate##U,					\
+	.p = _p,						\
+	.m = _m,						\
+	.s = _s,						\
+	.k = _k,						\
+}
+
 struct rockchip_pll_rate_table {
 	unsigned long rate;
 	unsigned int nr;
@@ -81,6 +90,11 @@ struct rockchip_pll_rate_table {
 	unsigned int postdiv2;
 	unsigned int dsmpd;
 	unsigned int frac;
+	/* for RK3588 */
+	unsigned int m;
+	unsigned int p;
+	unsigned int s;
+	unsigned int k;
 };
 
 enum rockchip_pll_type {
@@ -89,6 +103,7 @@ enum rockchip_pll_type {
 	pll_rk3328,
 	pll_rk3366,
 	pll_rk3399,
+	pll_rk3588,
 };
 
 struct rockchip_pll_clock {
diff --git a/drivers/clk/rockchip/clk_pll.c b/drivers/clk/rockchip/clk_pll.c
index 09b97cf57a..ac37dd494c 100644
--- a/drivers/clk/rockchip/clk_pll.c
+++ b/drivers/clk/rockchip/clk_pll.c
@@ -41,6 +41,10 @@ enum {
 	VCO_MIN_HZ	= 800 * 1000000,
 	OUTPUT_MAX_HZ	= 3200U * 1000000,
 	OUTPUT_MIN_HZ	= 24 * 1000000,
+	RK3588_VCO_MIN_HZ = 2250U * 1000000,
+	RK3588_VCO_MAX_HZ = 4500U * 1000000,
+	RK3588_FOUT_MIN_HZ = 37U * 1000000,
+	RK3588_FOUT_MAX_HZ = 4500U * 1000000,
 };
 
 #define MIN_FOUTVCO_FREQ	(800 * MHZ)
@@ -164,6 +168,66 @@ 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 {
+		fout = (fout_hz / MHZ) * MHZ;
+		ffrac = (fout_hz % MHZ);
+		for (s = 0; s <= 6; s++) {
+			fvco = fout << 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) {
+						rate_table->p = p;
+						rate_table->m = m;
+						rate_table->s = s;
+						fref = fin_hz / p;
+						fout = (ffrac << s) * 65535;
+						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 +238,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 +364,155 @@ 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)
+
+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.
+	 */
+	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);
+	else if (pll_id == 1)
+		rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(0),
+			     pll->mode_mask << 6,
+			     2 << 6);
+	else if (pll_id == 2)
+		rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(5),
+			     pll->mode_mask << 14,
+			     2 << 14);
+	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 * 65535;
+			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 +528,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 +557,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);
-- 
2.39.1


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2023-01-24 19:18 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-24 19:17 [PATCH 5/7] rockchip: clk: pll: add pll_rk3588 type for RK3588 Soc fatorangecat

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.