RK3588 Clocks
Example: Setting up v0pll
- Force PLL into slow mode
Connects the PLL to a slow clock to ensure stability while we set it up.
CRU_MODE_CON00.clk_v0pll_mode = clk_deepslow
(or xin_osc0_func) - Power down the PLL
CRU_V0PLL_CON1.v0pll_resetb = 1
- See calulating settings
- Set pre-divider value:
CRU_V0PLL_CON1.v0pll_p = P
- set main divider value:
CRU_V0PLL_CON0.v0pll_m = M
- Set scalar value:
CRU_V0PLL_CON1.v0pll_s = S
- Optional: Set DSM:
CRU_V0PLL_CON2.v0pll_k = K
- Power up:
CRU_V0PLL_CON1.v0pll_resetb = 0
- Wait until PLL is locked:
CRU_V0PLL_CON6.v0pll_lock == 1
Calculating settings
There are 4 settings that need to be set:
P
Pre divider value.
M
Main divider value.
S
Scalar value
K
Delta-sigma modulation value. For eliminating noise. TODO: Document this more.
The Linux kernel has a pre-calculated table for getting these values:
/* _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(742500000, 4, 495, 2, 0),
RK3588_PLL_RATE(722534400, 8, 963, 2, 24850),
RK3588_PLL_RATE(600000000, 2, 200, 2, 0),
RK3588_PLL_RATE(594000000, 2, 198, 2, 0),
RK3588_PLL_RATE(200000000, 3, 400, 4, 0),
RK3588_PLL_RATE(100000000, 3, 400, 5, 0),
And some code to calculate the idela values from an input and output frequency.
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 = &rockchip_auto_table;
u32 p, m, s, k;
u64 fvco;
for (s = 0; s <= 6; s++) {
fvco = (u64)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)) {
//k = rockchip_rk3588_pll_k_get(m, p, s,
// fin_hz,
// fvco);
//if (!k)
// continue;
rate_table->p = p;
rate_table->s = s;
rate_table->k = 0;
if (k > 32767)
rate_table->m = m + 1;
else
rate_table->m = m;
return rate_table;
}
}
}
}
return NULL;
}