Audio clocks: pll-audio runs 9.5% slow for the 44.1 kHz family #52
Labels
No labels
blocked-physical
cleanup
hardware
infra
kernel
P1-critical
P2-high
P3-normal
P4-later
reliability
security
upstream
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
tiagoagueda/a80#52
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
pll-audioon sun9i produces the wrong rate for the 44.1 kHz family. The 48 kHzfamily is correct as of the
Mdivider offset fix; this is a separate, still-openfault in the same PLL.
Measured
Playback of a buffer of known length, timed on a Tronsmart Draco AW80 Telos, on the
HDMI card:
Independently, the HDMI transmitter's automatic CTS counter, which is clocked by the
TMDS clock and counts incoming audio frames:
Both say the same thing, by different mechanisms: the audio clock in the 44.1 kHz
family runs about 9.5% slow.
Effect
HDMI audio is silent at 44.1 kHz. The sink is sent an ACR describing a ~40.3 kHz
stream while the audio infoframe claims 44.1 kHz, and a Sony HT-G700 soundbar declines
to lock it rather than playing it flat. Resampling the same track to 48 kHz plays
correctly, which is how this was isolated.
S/PDIF shares this PLL and is presumably affected identically. Not yet tested at
44.1 kHz.
What is known about the cause
For 44.1 kHz the framework selects
N=143, M=37and computes24 MHz * 143 / 38 = 90 315 789 Hz, which is whatclk_summaryreports.The downstream dividers are the same integers the 48 kHz case uses and they are in
sun4i-i2s's divider tables, so the error is upstream of them.Unlike the
M-versus-M+1fault that this PLL already had, the residual here is notan integer divider change. Correcting for the measured startup overhead the ratio is
close to
12/11, which no change ofMexplains.The most likely candidate is the pair of dividers the driver openly does not model:
Those would only bite for
N/Mcombinations the 48 kHz family never selects, whichfits the shape of this exactly. This is a hypothesis, not a measurement.
Next steps
d1/d2out ofreg[008]for both families and see whether they differ, andwhether the "enforce d1 = 0, d2 = 0" claim actually holds.
pll-audioto rates the model provably gets right,so ALSA resamples instead of playing at the wrong pitch. Silently wrong is worse than
unsupported.
Related
The
Mdivider offset fix that corrected the 48 kHz family is a separate commit and isalready in
patches/linux-clk-sun9i/. Before it, every audio rate on this SoC was1.04x slow while reading back as exactly correct - see
47-hdmi-audio-cec.md.Worth noting for whoever picks this up: every symptom of both bugs reads back as
perfectly configured hardware.
clk_summaryreports the rate that was asked for, theI2S registers hold the right dividers, and only a clock the SoC does not control - the
TMDS counter - or a stopwatch, disagrees.
Root-caused: the framework asks this PLL for a VCO the part cannot reach
The hypothesis in the issue is wrong. It is not
d1/d2, not the sigma-deltamodulator, and not a divider offset. Read live, mid-playback, at 44 100 Hz:
d1 = 0,d2 = 0— the driver's "enforce d1 = 0 and d2 = 0" claim holds. The modulator isoff and its pattern word is zero. The PLL reports locked. Every field is exactly what the
model says, and the output is still 9.5% low.
The transfer function puts the fault upstream of every divider
A80 User Manual r1.1 §3.3.5.3,
PLL_AUDIO_CTRL_REGat0x008:Pis a post-divider — it sits after the VCO and does nothing to keep it in range. Withd1 = 0the VCO is simply24 MHz x N. For the 44.1 kHz family the framework picksN = 143, asking for a 3.432 GHz VCO. The manual specifies these PLLs to 3 GHz
("The PLL output ranges from 200MHz to 3GHz", §3.3.5.1).
ccu_nm_find_best()has no VCO bound. It minimises output error overnandmand willhappily pick any N up to 255 — a 6.1 GHz VCO — as long as the quotient comes out close.
Measured: hold the output constant, vary only the VCO
Every pair below has
N/(P+1) ~ 3.7632: the same ~90.3 MHz modelled output, the samei2s1divider of 4, the same everything downstream. Only N changes. If the part behaved as
modelled, all eight rows would be identical.
15.000 s buffer of 44 100 Hz S16_LE stereo, timed around
aplay:Flat to 3.07 GHz, then a clean monotonic fall-off. Backing out the VCO actually delivered
from the four slow rows: 3 141 / 3 147 / 3 130 / 3 137 MHz — four independent estimates
inside +-0.3% of each other.
The VCO saturates at about 3.14 GHz. That is a hard ceiling, not a modelling error.
48 kHz works by luck
122.88 MHz wants
N/(P+1) = 5.12 = 128/25, so N = 128 and the VCO lands at 3.072 GHz —35 MHz under the measured ceiling. It has been running a hair below the rail all along.
The vendor never goes near this
get_factors_pll3()inclk-sun9iw1.csupports exactly two rates and returns-1foranything else. There is no
factor_pll3_tbl; pll1, pll2 and pll4..pll12 all have frequencytables, the audio PLL alone does not.
0xc00121ff0xc000e147Both under 1.5 GHz — less than half the ceiling.
Why sigma-delta is the fix, not an optimisation
No integer N/P can produce the 44.1 kHz family at all:
22.5792 / 24 = 588/625in lowestterms, so an exact solution needs
P+1to be a multiple of 625, andP+1 <= 64. This isexactly why upstream converted a83t, a64, h3, r40, v3s and h6 to sigma-delta for the
audio PLL.
sun9i-a80was never converted, andccu-sun8i-a83t.ccarries the same twopattern words the A80 vendor code uses.
.max_rateis not a fix — it clamps the output rate, and the output rate was never theproblem.
Also worth flagging
The M-offset fix from
47-hdmi-audio-cec.md/49-audio-clock-wrong.mdis confirmed by thedatasheet (the part divides by
P+1), and_SUNXI_CCU_DIV_OFFSET(0, 6, 0)is still intorvalds/master— so mainline's 48 kHz is 4% slow on every A80. Two patches to send here,not one.
S/PDIF picks the same N = 143 and has the same fault (#42), still untested at 44.1 kHz.
Full write-up with method and caveats:
51-audio-pll-vco-ceiling.md. New probe:probe/pllaudiosdm.c.Fixed: sigma-delta table for
pll-audioPatch written, built, deployed and measured on the board.
patches/linux-clk-sun9i/0001-clk-sunxi-ng-sun9i-use-sigma-delta-modulation-for-pl.patch.plus
.sdm = _SUNXI_CCU_SDM(pll_audio_sdm_table, BIT(24), 0x108, BIT(31))andCCU_FEATURE_SIGMA_DELTA_MOD. The table'sm/nare calculation values and themfieldcarries offset 1, so
m = 29writesP = 28- the vendor's exact register values.ccu_nm_set_rate()needed nothing:ccu_sdm_helper_has_rate()short-circuitsccu_nm_find_best()and writes the table's factors and pattern directly, so the unboundedinteger search never runs for these two rates.
What the driver now writes
VCO 1.296 and 1.464 GHz, against the ~3.14 GHz ceiling. Both families are now exact,
where the integer search could only approximate:
pll-audioat 44.1 kHzi2s1at 44.1 kHzpll-audioat 48 kHzi2s1at 48 kHzMeasured
44.1 kHz was 65.719 s for a 60 s buffer before this.
Two buffer lengths on purpose: the residual does not grow with duration, so it is fixed
startup overhead and not a rate error - a rate error would have quadrupled between 15 s and
60 s. That is the argument from
49-audio-clock-wrong.mdrun in reverse, to show there isnothing left rather than to pin what is there.
S/PDIF is fixed with it (#42). It shares this PLL and picked the same N = 143, and had
never been tested at 44.1 kHz until now.
Not closing this yet
The fault was reported as silent, and only the speed has been proven fixed. Every
result above is a stopwatch and a register - nobody has listened to 44.1 kHz, and the
soundbar has not been confirmed to lock it. Leaving this open until someone hears it.
Two smaller things left over:
that lands on a large N could still walk the VCO into the rail. Not reachable through the
current DT; not fixed either.
what the step and bottom register fields mean"). The fractional N values they imply,
54.5664 and 61.44, are now confirmed at the two rates that matter and nowhere else.
Write-up:
51-audio-pll-vco-ceiling.md.Fixed and verified 2026-08-28. Root cause was not the
d1/d2dividers this issuesuspected - those measure 0, as the driver claims.
ccu_nm_find_best()picks N = 143 for the44.1 kHz family, asking the PLL's VCO for 3.432 GHz, and it saturates at about 3.14 GHz. The
48 kHz family only worked by luck: N = 128 is 3.072 GHz, just under the ceiling.
The fix is the
ccu_sdm_settingsigma-delta table that a83t, a64, h3, r40, v3s and h6 allhave and sun9i never got. See
51-audio-pll-vco-ceiling.md.Verified by the same timed-playback method that found it:
Both within the ~0.16 s fixed startup overhead. S/PDIF shares this PLL and is fixed with it,
though a bitstream on the pin is still unverified - that stays in #42.