Appendix · reference

RK3399 CRU (clock and reset unit)

Source of every clock and reset line on the SoC

Identity

PartRK3399 Clock and Reset Unit (CRU) + PMU CRU
RoleGenerates all SoC clocks (PLLs, dividers, gates) and asserts/deasserts every reset line
Bus / addressMMIO 0xff760000 (CRU), 0xff750000 (PMU CRU)
GPIO / IRQnone
DatasheetRK3399 TRM Part 1 chapter 3 (CRU)
Pine64 wikiPinePhone Pro main page
Schematicon-SoC (no external schematic)

Status — ● working

CRU drives the entire boot path: every other working driver in the tree (eMMC, SD, USB, I2C, I2S, panfrost, VOP, DSI) depends on this node. The PMU CRU is a separate compatible node and also attaches.

The driver carries a per-PLL write filter so U-Boot’s live framebuffer hand-off survives kernel boot. As of 13e94af rk_cru: per-PLL whitelist for RK3399 PLL register window the filter is split per PLL window rather than blocking the whole 0x000–0x0FF page:

OffsetPLLAllow?Why
0x00-0x17LPLL (CRU) / PPLL (PMUCRU)yesA53 cluster / PMU
0x20-0x37BPLLyesA72 cluster
0x40-0x57DPLLNODRAM — would freeze RAM
0x60-0x77CPLLNOdisplay alt source
0x80-0x97GPLLyesperipherals
0xA0-0xB7NPLLyesnetwork / GMAC
0xC0-0xD7VPLLNOthe display PLL
≥ 0x100CLKSEL / CLKGATE / SOFTRSTyesalways allowed

The display path on the PinePhone Pro feeds VOP-Lit through vop_lit_dclk_src, which muxes between VPLL and CPLL — so both stay frozen. DPLL stays frozen because every CPU is currently fetching from DRAM through it; a bad write halts the SoC. Everything else is writable at runtime, which means cpufreq_dt(4) writes to LPLL / BPLL succeed and powerd -a adaptive runs cleanly across both clusters.

Driver

The filter went through several shapes before 13e94af rk_cru: per-PLL whitelist for RK3399 PLL register window : 9c82b07 cru: only block VPLL writes (display), allow all other PLLs for audio/I2C blocked only VPLL; 854d8b2 cru: block CPLL + VPLL (display), allow GPLL/NPLL/LPLL/BPLL/DPLL blocked CPLL+VPLL; c15e051 cru: only allow GPLL writes (for audio), block all other PLLs — CPU/DDR/display PLLs crash tightened to allow GPLL only for audio; bb92c4f cru: allow CPLL/GPLL/NPLL/VPLL, only block CPU PLLs (LPLL/BPLL) and DDR (DPLL) went the other way and allowed CPLL/GPLL/NPLL/VPLL while blocking the cluster PLLs; the short-lived if (addr >= 0x100) return 1; blanket-block guarded the display through the eMMC migration. 1057e87 debug: log any blocked CRU register writes kept the debug log for blocked writes so surprises surface in dmesg.

cpufreq + powerd

Verified live on kernel #150 after 13e94af rk_cru: per-PLL whitelist for RK3399 PLL register window :

$ sysctl dev.cpu.0.freq_levels
dev.cpu.0.freq_levels: 1416/-1 1200/-1 1008/-1 816/-1 600/-1 408/-1
$ sudo sysctl dev.cpu.0.freq=1416
dev.cpu.0.freq: 600 -> 1416
$ sudo service powerd onestart
$ sysctl dev.cpu.0.freq dev.cpu.4.freq
dev.cpu.0.freq: 1008
dev.cpu.4.freq: 1008

No BLOCKED write lines after the freq change; both clusters scale together under load; display stays mapped through every transition. Init-time CPLL writes (0x60, 0x64, 0x68, 0x6c) from rk3399_cru’s clock-graph init are still blocked at boot, which is exactly what we want — those would re-tune the display feeder.

Open work