mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
clk: rockchip: rk3588: fix up the frac pll calculation
rk3588 frac pll: FFVCO = ((m + k / 65536) * FFIN) / p FFOUT = ((m + k / 65536) * FFIN) / (p * 2s) k is the original code, but the K[15:0] is complement code (6'b1000_0000_0000_0000 <= K[15:0] <= 16'b0111_1111_1111_1111), need to be converted. Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com> Change-Id: I107d31d910d260c83891d5b6e927f119761d6fba
This commit is contained in:
@@ -332,6 +332,64 @@ rockchip_rk3066_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
|
||||
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 @@ rockchip_rk3588_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
|
||||
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 @@ rockchip_rk3588_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
|
||||
}
|
||||
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 @@ static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw,
|
||||
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 @@ int rockchip_pll_clk_compensation(struct clk *clk, int ppm)
|
||||
{
|
||||
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 @@ int rockchip_pll_clk_compensation(struct clk *clk, int ppm)
|
||||
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 @@ int rockchip_pll_clk_compensation(struct clk *clk, int ppm)
|
||||
* 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 @@ int rockchip_pll_clk_compensation(struct clk *clk, int ppm)
|
||||
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);
|
||||
|
||||
@@ -79,16 +79,16 @@ static struct rockchip_pll_rate_table rk3588_pll_rates[] = {
|
||||
RK3588_PLL_RATE(1008000000, 2, 336, 2, 0),
|
||||
RK3588_PLL_RATE(1000000000, 3, 500, 2, 0),
|
||||
RK3588_PLL_RATE(983040000, 4, 655, 2, 23592),
|
||||
RK3588_PLL_RATE(955520000, 3, 477, 2, 49806),
|
||||
RK3588_PLL_RATE(955520000, 3, 478, 2, 49807),
|
||||
RK3588_PLL_RATE(903168000, 6, 903, 2, 11009),
|
||||
RK3588_PLL_RATE(900000000, 2, 300, 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(785560000, 3, 392, 2, 51117),
|
||||
RK3588_PLL_RATE(785560000, 3, 393, 2, 51119),
|
||||
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(594000000, 1, 99, 2, 0),
|
||||
RK3588_PLL_RATE(408000000, 2, 272, 3, 0),
|
||||
RK3588_PLL_RATE(312000000, 2, 208, 3, 0),
|
||||
RK3588_PLL_RATE(216000000, 2, 288, 4, 0),
|
||||
|
||||
Reference in New Issue
Block a user