From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 19 Dec 2024 01:47:39 +0000
Subject: [PATCH] add wifi6 8852be driver

---
 kernel/drivers/clk/rockchip/clk-pll.c |  173 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 139 insertions(+), 34 deletions(-)

diff --git a/kernel/drivers/clk/rockchip/clk-pll.c b/kernel/drivers/clk/rockchip/clk-pll.c
index 91a0674..89ecdd0 100644
--- a/kernel/drivers/clk/rockchip/clk-pll.c
+++ b/kernel/drivers/clk/rockchip/clk-pll.c
@@ -332,6 +332,64 @@
 	return rate_table;
 }
 
+static u32
+rockchip_rk3588_pll_frac_get(u32 m, u32 p, u32 s, u64 fin_hz, u64 fvco)
+{
+	u64 fref, fout, ffrac;
+	u32 k = 0;
+
+	fref = fin_hz / p;
+	ffrac = fvco - (m * fref);
+	fout = ffrac * 65536;
+	k = fout / fref;
+	if (k > 32767) {
+		fref = fin_hz / p;
+		ffrac = ((m + 1) * fref) - fvco;
+		fout = ffrac * 65536;
+		k = ((fout * 10 / fref) + 7) / 10;
+		if (k > 32767)
+			k = 0;
+		else
+			k = ~k + 1;
+	}
+	return k;
+}
+
+static struct rockchip_pll_rate_table *
+rockchip_rk3588_pll_frac_by_auto(unsigned long fin_hz,  unsigned long fout_hz)
+{
+	struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get();
+	u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ;
+	u32 p, m, s, k;
+	u64 fvco;
+
+	for (s = 0; s <= 6; s++) {
+		fvco = (u64)fout_hz << s;
+		if (fvco < fvco_min || fvco > fvco_max)
+			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)) {
+					k = rockchip_rk3588_pll_frac_get(m, p, s,
+									 (u64)fin_hz,
+									 fvco);
+					if (!k)
+						continue;
+					rate_table->p = p;
+					rate_table->s = s;
+					rate_table->k = k;
+					if (k > 32767)
+						rate_table->m = m + 1;
+					else
+						rate_table->m = m;
+					return rate_table;
+				}
+			}
+		}
+	}
+	return NULL;
+}
+
 static struct rockchip_pll_rate_table *
 rockchip_rk3588_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
 				    unsigned long fin_hz,
@@ -341,7 +399,7 @@
 	u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ;
 	u64 fout_min = 37 * MHZ, fout_max = 4500 * MHZ;
 	u32 p, m, s;
-	u64 fvco, fref, fout, ffrac;
+	u64 fvco;
 
 	if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
 		return NULL;
@@ -368,26 +426,11 @@
 		}
 		pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz);
 	} else {
-		for (s = 0; s <= 6; s++) {
-			fvco = (u64)fout_hz << s;
-			if (fvco < fvco_min || fvco > fvco_max)
-				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);
+		rate_table = rockchip_rk3588_pll_frac_by_auto(fin_hz, fout_hz);
+		if (!rate_table)
+			pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz);
+		else
+			return rate_table;
 	}
 	return NULL;
 }
@@ -1345,7 +1388,17 @@
 	rate64 *= cur.m;
 	do_div(rate64, cur.p);
 
-	if (cur.k) {
+	if (cur.k & BIT(15)) {
+		/* fractional mode */
+		u64 frac_rate64;
+
+		cur.k = (~(cur.k - 1)) & RK3588_PLLCON2_K_MASK;
+		frac_rate64 = prate * cur.k;
+		postdiv = cur.p;
+		postdiv *= 65536;
+		do_div(frac_rate64, postdiv);
+		rate64 -= frac_rate64;
+	} else {
 		/* fractional mode */
 		u64 frac_rate64 = prate * cur.k;
 
@@ -1516,7 +1569,7 @@
 {
 	struct clk *parent = clk_get_parent(clk);
 	struct rockchip_clk_pll *pll;
-	static u32 frac, fbdiv;
+	static u32 frac, fbdiv, s, p;
 	bool negative;
 	u32 pllcon, pllcon0, pllcon2, fbdiv_mask, frac_mask, frac_shift;
 	u64 fracdiv, m, n;
@@ -1567,11 +1620,6 @@
 	negative = !!(ppm & BIT(31));
 	ppm = negative ? ~ppm + 1 : ppm;
 
-	if (!frac) {
-		frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask;
-		fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask;
-	}
-
 	switch (pll->type) {
 	case pll_rk3036:
 	case pll_rk3328:
@@ -1583,6 +1631,10 @@
 		 *    1 << 24                 1 << 24       1000000
 		 *
 		 */
+		if (!frac) {
+			frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask;
+			fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask;
+		}
 		m = div64_u64((uint64_t)frac * ppm, 1000000);
 		n = div64_u64((uint64_t)ppm << 24, 1000000) * fbdiv;
 
@@ -1597,13 +1649,65 @@
 		writel_relaxed(pllcon, pll->reg_base + pllcon2);
 		break;
 	case pll_rk3588:
-		m = div64_u64((uint64_t)frac * ppm, 100000);
-		n = div64_u64((uint64_t)ppm * 65535 * fbdiv, 100000);
+		if (!fbdiv) {
+			frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask;
+			fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask;
+		}
+		if (!frac) {
+			pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1));
+			s = ((pllcon >> RK3588_PLLCON1_S_SHIFT)
+				& RK3588_PLLCON1_S_MASK);
+			p = ((pllcon >> RK3588_PLLCON1_P_SHIFT)
+				& RK3588_PLLCON1_P_MASK);
+			m = div64_u64((uint64_t)clk_get_rate(clk) * ppm, 24000000);
+			n = div64_u64((uint64_t)m * 65536 * p * (1 << s), 1000000);
 
-		fracdiv = negative ? frac - (div64_u64(m + n, 10)) : frac + (div64_u64(m + n, 10));
-
-		if (!frac || fracdiv > frac_mask)
-			return -EINVAL;
+			if (n > 32767)
+				return -EINVAL;
+			fracdiv = negative ? ~n + 1 : n;
+		} else if (frac & BIT(15)) {
+			frac = (~(frac - 1)) & RK3588_PLLCON2_K_MASK;
+			m = div64_u64((uint64_t)frac * ppm, 100000);
+			n = div64_u64((uint64_t)ppm * 65536 * fbdiv, 100000);
+			if (negative) {
+				fracdiv = frac + (div64_u64(m + n, 10));
+				if (fracdiv > 32767)
+					return -EINVAL;
+				fracdiv = ~fracdiv + 1;
+			} else {
+				s = div64_u64(m + n, 10);
+				if (frac >= s) {
+					fracdiv = frac - s;
+					if (fracdiv > 32767)
+						return -EINVAL;
+					fracdiv = ~fracdiv + 1;
+				} else {
+					fracdiv = s - frac;
+					if (fracdiv > 32767)
+						return -EINVAL;
+				}
+			}
+		} else {
+			m = div64_u64((uint64_t)frac * ppm, 100000);
+			n = div64_u64((uint64_t)ppm * 65536 * fbdiv, 100000);
+			if (!negative) {
+				fracdiv = frac + (div64_u64(m + n, 10));
+				if (fracdiv > 32767)
+					return -EINVAL;
+			} else {
+				s = div64_u64(m + n, 10);
+				if (frac >= s) {
+					fracdiv = frac - s;
+					if (fracdiv > 32767)
+						return -EINVAL;
+				} else {
+					fracdiv = s - frac;
+					if (fracdiv > 32767)
+						return -EINVAL;
+					fracdiv = ~fracdiv + 1;
+				}
+			}
+		}
 
 		writel_relaxed(HIWORD_UPDATE(fracdiv, frac_mask, frac_shift),
 			       pll->reg_base + pllcon2);
@@ -1772,6 +1876,7 @@
 	return mux_clk;
 
 err_pll:
+	kfree(pll->rate_table);
 	clk_unregister(mux_clk);
 	mux_clk = pll_clk;
 err_mux:

--
Gitblit v1.6.2