PAF becomes saf/device (history kept), STATE.md dissolves into saf/state.md with the dated era archived, the substrate SAF moves up from souveraine, and every agreement points at saf/INDEX.md and nowhere else. one map, nothing to remember
836 lines
51 KiB
Markdown
836 lines
51 KiB
Markdown
# Audio — WCD9340 / SLIMbus
|
|
|
|
## Current — 2026-08-07
|
|
|
|
This is a working phone audio stack, not an active microphone bring-up.
|
|
|
|
- **Runtime:** PipeWire + WirePlumber + pipewire-pulse + pipewire-alsa. Native
|
|
PulseAudio and the ABI-provider shims are historical experiments, not the
|
|
running authority.
|
|
- **HiFi:** both CS35L36 speakers play; the WCD9340 microphone captures clean
|
|
mono audio through DMIC4 → DEC5/TX5. Casey uses it regularly for STT.
|
|
- **Calls:** the `Voice Call` UCM profile, `souveraine-callaudio`,
|
|
`souveraine-q6voiced`, and `souveraine-callaudiod` carry real two-way calls
|
|
and the earpiece/speaker path.
|
|
- **Persistence:** WirePlumber restores volumes and the selected profile. Do
|
|
not add another volume writer; role policy remains TASK-39.
|
|
- **One hardware debt remains:** the kernel permanently holds codec sysclk and
|
|
MICB2 from probe. Audio works, but the hold costs idle power and blocks a
|
|
clean suspend story. TASK-07 owns removing it.
|
|
|
|
The July **“UN-PIN TEST PASSED”** below removed the userspace always-open mic
|
|
pin. It did **not** remove kernel commit `cd7758eae`'s sysclk + MICB2 hold; that
|
|
similar noun is the likely source of the remembered “we resolved it.”
|
|
|
|
The implementation lives in Pixel3Arch under `pkgs/souveraine-ucm-blueline`,
|
|
`pkgs/souveraine-wireplumber-blueline` (which packages the canonical
|
|
WirePlumber policy from `rootfs-overlay/`), `pkgs/blueline-callaudio` (package
|
|
name `souveraine-callaudio`), `pkgs/souveraine-callaudiod`, and
|
|
`pkgs/q6voiced` (package name `souveraine-q6voiced`).
|
|
|
|
Everything below is the evidence ledger. Headings such as “still open” describe
|
|
the date beneath them unless the current block above repeats the defect.
|
|
|
|
## UCM PROFILE GONE AT BOOT — 2026-08-16, fixed same day
|
|
|
|
Boot-time music died after kernel `7.1.1.r162.g457a667bd3eb` (installed
|
|
2026-08-13, first boot 08-16 00:46): the card came up with only `off` and
|
|
`pro-audio`, no UCM profiles, so no HiFi sink existed at boot. In-session
|
|
audio (calls, STT mic) kept working — the regression only hit the fresh-boot
|
|
state, which is why it surfaced as “music at boot”.
|
|
|
|
Measured chain, all on-device:
|
|
|
|
- **Kernel made routed capture strictly mono 48k.** The wcd934x
|
|
recorder-state work in r162 (`b30e849be` “program all DMIC interface pads”,
|
|
`9610ef9cf` “replay complete blueline recorder state”) rejects stereo
|
|
capture hw_params on the routed MultiMedia2 (`CHANNELS: [1 4]` advertised,
|
|
but `arecord -c 2` → -EINVAL, `-c 1` → fine).
|
|
- **ACP probes with declared UCM values.** The Mic devices declared no
|
|
`CaptureChannels`/`CaptureRate`, so ACP assumed stereo at the FE-default
|
|
rate → capture probe failed -EINVAL → every profile “not supported” → ACP
|
|
fell back to `pro-audio` (priority 1) at boot.
|
|
- **Secondary lock, not the cause:** `90-blueline.conf` sets
|
|
`session.suspend-timeout-seconds = 0` on `~alsa_output.*`, so the pro-audio
|
|
sink never released hw:0,0; later probes died “Device or resource busy”.
|
|
The persisted `default-profile` state (wireplumber saves the selected
|
|
profile, by design) then re-pinned `pro-audio` each boot.
|
|
- **Fix:** declared `CaptureChannels 1` + `CaptureRate 48000` in both Mic
|
|
devices (HiFi + VoiceCall). ACP probe now succeeds; all three UCM profiles
|
|
form; card activates HiFi at boot. Tone verified audible on glass; mic
|
|
capture nonzero through the UCM source. Shipped as
|
|
`souveraine-ucm-blueline 0.1.0-2` (commit `9f0f103`, CI run 1696);
|
|
rootfs-overlay UCM copies kept identical to the package.
|
|
- **Not shipped, known hardening:** scope the never-suspend output rule to
|
|
`~alsa_output.platform-sound.*__sink` (the UCM sinks) so a stray pro-audio
|
|
fallback can never hold hw:0,0 forever.
|
|
|
|
Probe mechanics learned (canonical, 2026-08-16):
|
|
|
|
- `spa-acp-tool -v -v hw:0` is the ACP probe; “Probing profile X” with no
|
|
failure lines after it = supported. The trailing “unknown command hw:0” is
|
|
a harmless arg-parsing quirk.
|
|
- `alsaucm -c hw:0 set _verb HiFi` is the real-card UCM branch; it runs the
|
|
verb EnableSequence (and enables devices — TX5 mapping included). `-c G3`
|
|
and `-c "Google Pixel 3"` hit the *no-hw* branch (conf.virt.d / legacy
|
|
paths) and fail ENOENT even when UCM is healthy — red herrings.
|
|
- `alsaucm list profiles` / `get _verbs` fail with ENOENT quirks on this
|
|
box; they are not valid probes.
|
|
- `cat /proc/asound/card0/pcm*p/sub0/status` shows `owner_pid` — the way to
|
|
find who holds a PCM.
|
|
- Raw `arecord -D hw:0,1` only works while the verb routes are applied;
|
|
`spa-acp-tool` runs DisableSequence on exit and tears them. Re-apply the
|
|
verb before raw capture tests.
|
|
|
|
## PIPEWIRE RESTORED — 2026-07-19 late evening
|
|
|
|
The PA-native arrangement is retired. Live state, all verified on-device:
|
|
|
|
- **Stack:** pipewire 1.6.8 + wireplumber 0.5.15 + pipewire-pulse +
|
|
pipewire-alsa. The shims (`pipewire-abi-provider`, `pulse-native-provider`)
|
|
and the patched `pulseaudio-q6` are removed (rollback pkg kept at
|
|
`~/build/pulseaudio-q6-r3/`; `/etc/pulse` backed up as
|
|
`/etc/pulse.bak-20260719`). The `enable-pipewire` gate drop-ins were
|
|
deleted — PipeWire is unconditional now.
|
|
- **UCM discovery works under ACP/wireplumber.** HiFi verb → Speaker sink +
|
|
Mic source appear named from the UCM comments. The old `alsaucm -c G3`
|
|
`-2` failure is an id-vs-longname CLI quirk; `-c "Google Pixel 3"` parses
|
|
both verbs fine. Real clients are unaffected.
|
|
- **Playback:** `51-blueline-audio-s16.conf` (S16LE + disable-mmap +
|
|
generous periods, recovered verbatim from `8920c3c`) reinstated; chime
|
|
confirmed audible on glass.
|
|
- **Capture:** mic source pinned mono S16LE 48k, suspend disabled,
|
|
period 4800 / headroom 9600 (`90-blueline.conf`). Nonzero on every test
|
|
capture.
|
|
- **UN-PIN TEST PASSED.** With the kernel sysclk hold (`cd7758eae`) and no
|
|
loopback hold, two consecutive same-map reopens both captured nonzero
|
|
(451k/470k nonzero samples). The userspace mic pin is DELETED — kernel
|
|
hold alone is sufficient. Cold-boot confirmation pending.
|
|
- **New kernel bug found and fixed:** any xrun → userspace
|
|
`snd_pcm_prepare()` re-enters wcd934x prepare without shutdown →
|
|
`slim_stream_prepare` -EINVAL "Stream already Prepared" retried ~50/s
|
|
forever (PipeWire recover loop starved the whole graph). Fix
|
|
`f56b1ae08` on `mic-race-fix`: per-dai `prepared` flag, re-prepare
|
|
no-ops, stream stays armed (alternation-law friendly). Wireplumber
|
|
headroom masks the common case until the kernel is installed.
|
|
- **VoiceCall.conf `hw:0,5` → `hw:0,2`** fixed on-device + repo.
|
|
- **Voice-call discovery:** VoiceMMode1 (`hw:0,2`) open fails -EINVAL until
|
|
the voice BE routes (`SLIMBUS_0_RX Voice Mixer VoiceMMode1`,
|
|
`VoiceMMode1 Capture Mixer SLIMBUS_0_TX`) are applied — DPCM
|
|
no-backend rejection. With routes applied the PCM opens. This is why
|
|
q6voiced logged "Failed to open tx/rx: Invalid argument". ~~Because the
|
|
PCM is unprobeable, ACP can never synthesize a VoiceCall profile, so
|
|
callaudiod's profile-switching path is structurally dead on this card.~~
|
|
**Wrong — see 2026-07-29.** ACP never probes `hw:0,2`; it probes the PCMs
|
|
the verb *declares*, and the profile was lost for two reasons of our own
|
|
making. Shipped `blueline-callaudio-hook` (system service): MM `CallAdded`
|
|
→ UCM voice verb, last call terminating → HiFi verb restore. q6voiced then
|
|
opens an already-routed PCM.
|
|
|
|
## PHONE CALLS WORK — TWO-WAY AUDIO ON A REAL BEARER — 2026-07-29
|
|
|
|
Incoming call, answered, audio both directions, confirmed by ear at both ends.
|
|
Five defects had to fall, every one of them ours:
|
|
|
|
- **Verb named `VoiceCall`.** alsa-lib's `SND_USE_CASE_VERB_VOICECALL` is
|
|
`"Voice Call"`, with the space, and callaudiod accepts only a profile
|
|
carrying that prefix (`cad-pulse.c:508`). Renamed.
|
|
- **The voice verb gave MultiMedia1 no backend.** HiFi routes it through
|
|
`QUAT_TDM_RX_0`; the voice verb routed nothing, so opening `hw:0,0` under
|
|
the verb returned -EINVAL and ACP dropped the profile — *"Profile 'Voice
|
|
Call' mapping 'Voice Call: Speaker: sink': output PCM open failed"*,
|
|
`spa-acp-tool -v -v`. That, not an unprobeable `hw:0,2`, is why no voice
|
|
profile ever appeared. The card carries one now.
|
|
- **Downlink went to `SLIMBUS_0_RX`.** blueline's earpiece and loudspeaker are
|
|
both CS35L36 amps on `QUAT_TDM_RX_0`; the WCD9340 is the uplink and the
|
|
headset jack. Voice sent to the codec reached nothing — audible as a call
|
|
the far end heard perfectly while this end heard silence.
|
|
- **A front-end takes exactly one backend.** These mixers are *not* additive:
|
|
enabling a second silently clears the first, measured in both directions.
|
|
Setting `QUAT` and `SLIMBUS` together is not belt-and-braces, it is a no-op.
|
|
- **q6voiced latches a failed open.** tinyalsa's `pcm_open()` returns a
|
|
non-NULL handle on failure and `q6voiced_open()` guards on `if (v->tx)`, so
|
|
one lost race silences the whole call. Reachable on any outgoing call:
|
|
`mm_state_is_active()` counts DIALING, emitted in the same instant as
|
|
`CallAdded`. Incoming calls are safe only by accident — RINGING_IN is not
|
|
counted active, so their open lands well after the routes. Patched in
|
|
`souveraine-q6voiced` to release and retry.
|
|
|
|
Two further findings:
|
|
|
|
- **The mic died after every call**, not just occasionally. `alsaucm` holds its
|
|
UCM context in-process, so a one-shot `set _verb HiFi` has no previous verb
|
|
to dismantle and never runs its `DisableSequence`. TX5 and TX7 both stayed
|
|
mapped into `AIF1_CAP`, SLIM_0_TX carried two channels into a mono front-end,
|
|
and capture read exact zeros. The hook now unmaps the outgoing leg explicitly.
|
|
- **callaudiod cannot own earpiece/speaker on this card.** It switches a sink
|
|
*port* (`cad-pulse.c:961`) and needs both port types on one sink, but ACP
|
|
models UCM devices as one profile per combination — `Voice Call (Earpiece,
|
|
Mic)` and `Voice Call (Mic, Speaker)`. `ConflictingDevices` does not change
|
|
it. enchilada sidesteps this by giving each transducer its own PCM; blueline
|
|
has both amps behind one. The toggle is therefore
|
|
`blueline-callaudio-hook speaker on|off`, writing the amps directly.
|
|
|
|
## ROOT CAUSE FOUND AND FIXED — MICS CAPTURE REAL AUDIO — 2026-07-19
|
|
|
|
**The wall was the codec master clock.** Mainline DT fed the WCD9340's `extclk`
|
|
from `RPMH_LN_BB_CLK2` (inherited from the reference-board dtsi). On blueline,
|
|
Android's own DT gives **LN_BB_CLK2 to the Pixel Visual Core (`mnh-sm`)** and
|
|
feeds the codec from **`clock_rpmh` index 4 = LN_BB_CLK3** (verified by
|
|
decompiling the phone's `dtbo_b`; `audio_ext_clk_lnbb` → `<&clock_rpmh 0x04>`).
|
|
The RPMh vote on the wrong buffer succeeds, so nothing errors — the codec just
|
|
never receives 19.2 MHz. That single fault explained the entire residue:
|
|
|
|
- eFuse sensing timed out every boot (`-110`, `status=0x0`) — needs MCLK, no
|
|
ports involved. After the fix: `eFuse sense complete: status=0x01 out14=0xda
|
|
out15=0x01` — first time ever on mainline.
|
|
- Analog AND digital capture read zeros (whole audio core unclocked) while
|
|
every SLIM control write ACKed (SLIMbus clock is separate).
|
|
- IRQ 213 (codec SLIM data line) never fired in the machine's life; after the
|
|
fix it fires on every capture.
|
|
- MBHC read garbage impedance at probe.
|
|
|
|
Fix: `&wcd9340 { clocks = <&rpmhcc RPMH_LN_BB_CLK3>; }` in
|
|
`sdm845-google-common.dtsi` (committed in the kernel tree). Deployed initially
|
|
as a verified one-byte DTB patch (`/boot/dtbs/sdm845-google-blueline.dtb`,
|
|
backup `.lnbb2-orig` beside it; kexec chain reads the DTB from `/boot`, NOT
|
|
from the boot_a image — see below).
|
|
|
|
**Live capture results after the fix (kernel `g8cbfbb939327`, same boot):**
|
|
- AMIC1 → ADC1 → DEC0 → TX0: 121,724 / 144,000 nonzero samples
|
|
- DMIC0 → DEC7 → TX7 (`hw:0,1`): 94,198 nonzero
|
|
- DMIC4 → DEC5 → TX5 (Android triple-mic route): 81,545 nonzero
|
|
- DMIC3 → DEC6 → TX6 (Android triple-mic route): 92,216 nonzero
|
|
- DMIC4 → DEC7 → TX7 (Android handset-mic route): 124,050 nonzero
|
|
|
|
All three physical mics (DMIC0/3/4 per Android's `triple-mic` path) and the
|
|
analog path produce real ambient audio through plain ALSA `hw:0,1` —
|
|
**no HAL, no ADM usecase, no ACDB OEM tree in the loop**. This falsifies the
|
|
"ADM usecase routing is required for samples to flow" hypothesis from the
|
|
2026-07-19 live-reconciliation doc, and retroactively confirms every "codec
|
|
registers are bit-perfect but silent" audit: the registers were right; the
|
|
silicon was unclocked.
|
|
|
|
### Boot chain discovery (why kernel deploys "never landed")
|
|
`boot_a` holds pocketboot (LinuxBoot, a 7.2.0-rc1 first-stage kernel). It
|
|
kexecs `/boot/vmlinuz-blueline` + `/boot/dtbs/sdm845-google-blueline.dtb` per
|
|
`/boot/extlinux/extlinux.conf` on Arch_root (`linux,booted-from-kexec` in the
|
|
live chosen node). Flashing boot_a via fastboot does NOT change the running
|
|
kernel/DTB — install to `/boot` on the rootfs instead.
|
|
|
|
### Then-open capture intermittency — superseded later on 2026-07-19
|
|
- Ordering effect observed on the first post-fix boot: DMIC3/4 through
|
|
MUX6/MUX7 read zero until the DEC5/DEC6 (Android-native) routes ran once;
|
|
after that, the previously-dead MUX7+DMIC4 handset route worked. Some
|
|
first-use state sticks. Full codec+IFD regmap snapshots of the known-good
|
|
state saved on-phone (`/tmp/codec-good-state.txt`, `/tmp/ifd-good-state.txt`
|
|
— copy off before they evaporate; /tmp is tmpfs).
|
|
- The last test of the session (speaker-tone loopback) read all-zero again
|
|
right after a string of successes — cause unestablished. Per the
|
|
live-reconciliation doc's warning, record airplane/radio/mode state before
|
|
interpreting ANY zero capture from now on.
|
|
- Android runtime parity notes for the diff: Android recording state has
|
|
`0xd25 = 0x11` (ADC MUX3/7 mode reg) where ours reads 0x00 even while
|
|
working; pads `0x8015-0x8018 = 0x00`, `0x8019/1a = 0x0a` — identical to what
|
|
our kernel programs (my in-session debugfs pad pokes don't persist).
|
|
- Regmap-cache caveat from the reconciliation doc applies to OUR debugfs reads
|
|
of IFD/PGD registers too: prefer live-read paths when auditing those.
|
|
|
|
### THE ALTERNATION LAW — exact zombie mechanism (2026-07-19, evening)
|
|
Every capture result from all three boots today reduces to ONE deterministic
|
|
rule: **a SLIM TX capture produces samples only when its channel map differs
|
|
from the previous capture session's map. Re-opening with the identical map
|
|
always reads zeros.** Verified live: TX5→TX5 = work,zero; TX5→TX6→TX5 =
|
|
work,work,work; boot-first TX7 always zero (ch135 is pre-touched by ADSP
|
|
boot/cal state, so the first TX7 session counts as a same-map reopen).
|
|
Everything earlier read as input-specific (DMIC3/4 dead), power-related
|
|
(PA holding sysclk), or "priming" was test-order artifact of this law.
|
|
- Codec side is fully correct per-session (DEF_ACT_CHAN wbuf identical
|
|
between dead and working sessions except TID; teardown calls
|
|
slim_stream_unprepare which sends DEACTIVATE/REMOVE/RECONFIGURE per
|
|
drivers/slimbus/stream.c).
|
|
- Clock gates during a zombie capture are bit-identical to Android's working
|
|
recording (0x711=0x91 0xd41=0x01 0xd42=0x0d).
|
|
- Conclusion: the ADSP's SLIM-master/AFE side treats an identical re-DEFINE
|
|
as a no-op and never re-arms the data path. Android never hits this because
|
|
its HAL/ADM re-arms per session (the reconciliation doc's ADM hypothesis,
|
|
refined: not "ADM required for routing" but "ADM masks the stale-restart").
|
|
- NEXT INSTRUMENTATION: log outgoing MCs in qcom_slim_ngd xfer path and
|
|
diff same-map vs changed-map session teardown/setup on the wire; then
|
|
candidate kernel fix = force a map perturbation or explicit port
|
|
disconnect+reconnect on every SLIM capture start.
|
|
- Userspace mitigation shipped meanwhile (see 90-blueline-alsa.pa): a
|
|
null-sink loopback holds blueline_mic open from PA start — the boot-time
|
|
open is on virgin TX5 (works), and a held-open source never re-opens, so
|
|
the law is never violated. VALIDATED on true cold boot 2026-07-19 12:09:
|
|
blueline_mic RUNNING at boot, 262k/263k nonzero samples first client,
|
|
two back-to-back client sessions both live (peaks 5256/5590/26044).
|
|
Costs continuous capture power (remove once the kernel fix lands).
|
|
|
|
### THE BOOT RACE — pinned boot capture is a coin flip; kernel + config were red herrings (2026-07-19 evening)
|
|
Journal survey of ALL 9 boots of 2026-07-19 (`journalctl -b -8 .. -b 0`,
|
|
MICDBG sysclk lines at the pin's boot-time capture open):
|
|
|
|
| boots | kernel | at pin open | MICB2 | outcome |
|
|
|---|---|---|---|---|
|
|
| -7 | g323b297 | `users=2 skip` (joined a live hold) | 0x50 | 262k WORKING |
|
|
| -3 | gbdf098937 | `users=2 skip` | 0x50 | never tested (!) |
|
|
| -8 | g323b297 | `users=1 full bring-up` after `users=0 HW POWER-OFF` | 0x10 | zero |
|
|
| -6 -5 -4, 0 | gbdf098937 | same losing pattern | 0x10 | zero |
|
|
| -2 -1 | gfdb22e5 | same losing pattern | 0x10 | zero |
|
|
|
|
An early boot-time actor grabs codec sysclk ~3s after boot, holds ~3s, and has
|
|
MICB2's 0x40 bit up while it holds. If PA's pin lands INSIDE that window the
|
|
capture joins as user 2 and samples flow; if it lands after the release (codec
|
|
did a HW POWER-OFF), capture does its own full bring-up and reads zero on every
|
|
route for the rest of the boot — the same persistent zombie the PA-stop
|
|
experiment produced. Same kernel both wins and loses (g323b297: won -7, lost
|
|
-8; gbdf098937: won -3, lost four). Therefore:
|
|
- **QRTR=y (`fdb22e5`/`f245323`) is exonerated.** Every "dead on fdb22e5"
|
|
observation was a lost race, sampled. Config stays QRTR=m / PD_MAPPER=m
|
|
(Kconfig forces PD_MAPPER ≤ QRTR anyway); it is orthogonal to the mic.
|
|
- **The CHAN_CTRL-remove commit (`bdf098937`) is exonerated for "dead at
|
|
boot"** — its code path is open-inert (only adds `disable_stream`, verified
|
|
by diff) and it won the race on boot -3.
|
|
- **The un-pin question is STILL unanswered.** It needs a race-winning boot:
|
|
pinned baseline nonzero, `pactl unload-module` the loopback, then same-map
|
|
reopen; nonzero reopen = pin can be deleted.
|
|
- The early holder is unidentified; MBHC headset-detect is the prime suspect
|
|
(boot-time codec user, raises MICB2 for impedance sensing). MICB2
|
|
0x50-vs-0x10 tracks outcome 8/8 but is NOT yet proven causal — it may just
|
|
fingerprint the hold. Verify before building on it: read Android's ANA_MICB2
|
|
during a working slot-B recording, and/or set the 0x40 bit via debugfs during
|
|
a fresh lost-race boot's capture.
|
|
- Kernel fix direction (pick after causality check): wire the DMIC supply
|
|
(micbias) into the capture DAPM path, or hold sysclk from probe until first
|
|
capture so the boot window cannot close early.
|
|
|
|
### Afternoon findings — zombie state + wedge reproduction (2026-07-19)
|
|
- Cold-boot experiment (radios all on, recorded): first `arecord` after boot
|
|
opened ONLY the FE — zero kernel-side codec/BE activity, zeros. Second and
|
|
third captures (any route) worked. The morning "DEC5 unlocks MUX7" story is
|
|
partly this: two distinct zero-classes exist — (a) BE-never-opened,
|
|
(b) BE-open-but-silent.
|
|
- Stopping PulseAudio (releasing the card → last sysclk user drops →
|
|
`wcd934x_disable_ana_bias_and_syclk` powers the codec down) put capture into
|
|
a persistent all-zero state on EVERY route, and restarting PA did not
|
|
recover it. Mixer state is bit-identical PA-up vs PA-down (diff empty), so
|
|
it is a power-lifecycle effect, not mixer state.
|
|
- In the zombie state, live volatile reads DURING capture show the analog
|
|
domain healthy: `ANA_BIAS=0x80 BUCK=0x07 MICB4=0x90`. The bias/buck theory
|
|
is dead. Codec-internal clock gates (0xd41/0xd42) were not yet live-readable
|
|
— instrumented build `323b29715` makes them volatile and logs
|
|
enable/disable/sido lifecycle + per-capture clock-gate reads.
|
|
- Manually zeroing `CLK_SYS_MCLK_PRG` (0x711) via debugfs wedged the SLIM bus
|
|
into the historical `-110` NACK loop (`Failed to read IRQ status: -110`,
|
|
`Error Interrupt 0x82000000`, 1 Hz). One historical "SLIM wedge" class is
|
|
therefore reproducible as pure codec-clock-state loss — consistent with the
|
|
2026-07-19 warning that not every wedge was a bus/driver fault. Phone needs
|
|
a cold boot after this (self-inflicted, cause exactly known).
|
|
- Upstream comparison: `enable_ana_bias_and_sysclk`/`disable` and the
|
|
sido-cache skip are upstream-inherited structure, not our divergence; our
|
|
only body change is the Android-parity buck sequence (captures work with
|
|
it). No structural smoking gun found by code audit — hence instrumentation.
|
|
|
|
## SLIM NACK loop confirmed boot-invariant on a real cold boot — 2026-07-15
|
|
|
|
- Fixed three misidentified raw-hex register writes in
|
|
`wcd934x_apply_blueline_android_tx7_capture_setup()` (kernel `5199244ee0ee`):
|
|
`0x0b07-0x0b3f` were RX playback compander `CTL6` registers (not TX
|
|
per-path enables), `0x0c96` is `WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS` (a
|
|
status register, not a TX enable — writing it was the suspected cause of a
|
|
SLIM wedge seen on the prior build `9610ef9cf45a`), and `0x0d1e`/`0x0d25`
|
|
are `ADC_MUX0_CFG1`/`ADC_MUX3_CFG1` (TX0/TX3, not TX7/TX8 as the old
|
|
comment claimed). Verified against downstream
|
|
`techpack/include/asoc/wcd934x_registers.h`. This fix did NOT resolve the
|
|
SLIM wedge — see below.
|
|
- The recurring error is a genuine **NACK**, not a bus hang:
|
|
`qcom,slim-ngd-ctrl: Error Interrupt received 0x82000000` decodes to
|
|
`NGD_INT_TX_MSG_SENT (BIT 31) | NGD_INT_TX_NACKED_2 (BIT 25)` — the
|
|
message transmitted and the target actively refused it. The target is
|
|
`LA:0xcf` (the WCD934x codec's assigned logical address, confirmed not
|
|
`SLIM_LA_MGR`/`0xff`), message code `0x60` =
|
|
`SLIM_MSG_MC_REQUEST_VALUE`. The read is `regmap-irq`'s generic
|
|
`regmap_irq_thread()` polling the codec's IRQ status registers
|
|
(`drivers/base/regmap/regmap-irq.c`) — the codec's IRQ line is
|
|
`IRQF_TRIGGER_HIGH` (level), so a failed status read never clears it and
|
|
it refires every ~1s, forever, from ~1-2min post-boot onward.
|
|
- Tested with a **user-operated true power-off (`shutdown -h now`, not
|
|
`fastboot reboot`) followed by manual power-on**, specifically to rule
|
|
out the in-place-ADSP-restart degradation `b0b813f` warned about. Result:
|
|
the NACK loop reproduces identically on this real cold boot (confirmed
|
|
climbing at 110s uptime, same `MC:0x60,LA:0xcf` signature). **This is not
|
|
a warm-reboot or ADSP-restart artifact** — it is boot-invariant, matching
|
|
the entry below from earlier the same day.
|
|
- `blueline-hexagonrpcd-adsp.service` (`b0b813f`, still uncommitted to
|
|
gitea as of this entry) attaches cleanly on this same cold boot — no
|
|
fluence/ECNS/AVS module errors, only the unrelated `lowi_lp.conf` miss.
|
|
So the ADSP audio-PD HexagonFS gap is fixed and not the current blocker;
|
|
capture still fails at the ALSA `hw_params` layer (`arecord` "Unable to
|
|
install hw params") before the ADSP module question is even reachable,
|
|
because the SLIM NACK loop blocks it upstream.
|
|
- **Current standing blocker, plainly:** the SLIM NACK loop on `LA:0xcf`.
|
|
Not yet root-caused. Two real, separate bugs were found and fixed
|
|
tonight (the register-write bug above, and the ADSP HexagonFS gap in
|
|
`b0b813f`); this is a third, still-open one.
|
|
|
|
## Cold-boot SLIM-NGD correction — 2026-07-14
|
|
|
|
- A user-operated full power-off while unplugged, followed by power-on, still
|
|
logs `qcom,slim-ngd-ctrl ... QMI wait timeout` at 12:29:52, immediately
|
|
after ADSP boot/WCD934x probe, followed by repeated `SLIM SAT: Rcvd master
|
|
capability`. This happened before any ALSA/Pulse microphone client opened.
|
|
- Therefore the timeout/capability loop is **not merely a warm-reboot or
|
|
long-uptime artifact**. ADSP, CDSP, SLPI, and MSS all reach `running`, so
|
|
the fault is specifically in the ADSP↔NGD SLIM initialization exchange and
|
|
is now the primary boot-invariant microphone lead. Do not restart ADSP or
|
|
NGD while investigating; preserve this state for tracing.
|
|
- The adjacent WCD MBHC threshold/impedance messages concern headset/accessory
|
|
detection (including the available USB-to-mic adapter), not the target
|
|
internal DMIC4 → DEC7 → TX7 capture path.
|
|
|
|
## Q6 VoiceMMode1 call path — staged 2026-07-14
|
|
|
|
- This is deliberately separate from the still-silent raw `MultiMedia1/2`
|
|
capture path. Android proves the board microphone works; normal PCM remains
|
|
an ADM/calibration problem, while modem calls use the hostless Q6Voice path.
|
|
- The missing board wiring was real: `sdm845.dtsi` left Q6 MVM/CVS/CVP
|
|
disabled and blueline had no `VoiceMMode1` DAI/card link. Kernel commit
|
|
`551d3bb1b` enables those services and instantiates the link on the tested
|
|
Type-C baseline. Its matching module tree is installed on the phone at
|
|
`7.1.1-sdm845-g551d3bb1bd35`; its boot image is staged locally.
|
|
- The preserved prior device package, found at
|
|
`archive/pmos-20260709/pmaports/device/testing/device-google-blueline/`,
|
|
is the authoritative board data: `VoiceMMode1` enumerates as **`hw:0,5`**,
|
|
not the raw MultiMedia devices. Its exact `VoiceCall.conf` routing
|
|
(`SLIMBUS_0_RX Voice Mixer VoiceMMode1`, `VoiceMMode1 Capture Mixer
|
|
SLIMBUS_0_TX`, DMIC4→DEC7→TX7) is installed in the Arch UCM overlay.
|
|
- `q6voiced-blueline` was built and installed natively, with that exact PCM-5
|
|
configuration. Its system unit is deliberately **disabled until the new
|
|
kernel cold-boot confirms `00-05: VoiceMMode1`**; enabling it on the old
|
|
kernel would create meaningless restart noise. First test must be a clean
|
|
cold boot and an actual ModemManager call *before any HiFi/raw-capture
|
|
experiment*, because the historical second call failure was SLIMBUS RX
|
|
already claimed by earlier HiFi activity.
|
|
|
|
## Live state — 2026-07-12 evening (mic)
|
|
|
|
**Live Android Recorder ground truth — 2026-07-14:** On the rooted Lineage
|
|
slot-B reference system (`4.9.337-gb929452c5c49`), an ordinary
|
|
`org.lineageos.recorder` recording was observed live, not inferred from XML.
|
|
It opens **MultiMedia1 / PCM device 0** (not MultiMedia2): its userspace input
|
|
is mono S16_LE at 8 kHz, while the active backend is
|
|
`SLIMBUS_0_TX`, mono S16_LE at 48 kHz. The downstream HAL enables
|
|
`DMIC4 -> DEC7 -> TX7`; `SLIM_0_TX Channels=One`; and its active capture
|
|
app-type control is `[69938, 4, 48000, 3]`: downstream's documented field
|
|
order makes that `app_type=69938` (the Qualcomm default TX-path app type),
|
|
`acdb_dev_id=4`, `sample_rate=48000`, `backend_id=3`. The capture track was active and
|
|
non-silent in AudioFlinger. Crucially, Android's dedicated WCD SLIM-interface
|
|
debug dump during that recording read `0x032=0x80`, `0x057=0x05`,
|
|
`0x097=0x21`, and `0x11c=0x80`. (`tavil-slim-pgd` regmap is codec register
|
|
space, not this interface-device space.) Every earlier Arch microphone
|
|
negative test targeted `hw:0,1` / MultiMedia2 at 48 kHz. The exact
|
|
**MultiMedia1 `hw:0,0` 8-kHz FE / 48-kHz SLIMBUS backend** retest then ran on
|
|
Arch with TX7/DMIC4 and the active speaker RX route preserved: its 8-second
|
|
raw payload was 128,000 bytes / **zero non-zero samples**. (An earlier
|
|
apparent 19-sample result was immediately identified as `arecord`'s 44-byte
|
|
WAV header and corrected with `-t raw`.) This closes the FE/rate mismatch as a
|
|
microphone fix. The Android HAL's ADM identity and ACDB path is now the
|
|
leading differential: it programs this FE's app type, topology, and device
|
|
calibration, whereas mainline q6routing passes zeros.
|
|
|
|
**DEF_ACT_CHAN client-field test — 2026-07-13:** The Android downstream NGD
|
|
driver encodes the first `DEF_ACT_CHAN` payload byte as
|
|
`(data_fmt << 5) | (laddr & 0x1f)`; mainline had sent the full WCD9340 logical
|
|
address (`0xcf`) and consequently put its high bits into the data-format field.
|
|
The one-line correction was built on the current Type-C/G56 test base as
|
|
`3ceab71eded0`, its matching module tree was installed before flashing, and
|
|
the resulting `7.1.1-sdm845-g3ceab71eded0` boot was verified on glass. A
|
|
controlled single-direction `DMIC4 → DEC7 → TX7 → MultiMedia2` 48 kHz mono
|
|
capture (TX6 disabled) produced `384000` bytes / `192000` samples, with **0
|
|
non-zero bytes** and signed-16 range `0..0`. ALSA state restored (only the
|
|
known read-only HPH controls complained); no new SLIM/Q6/NGD timeout or audio
|
|
error appeared. This fix is a valid protocol correction and must remain, but
|
|
it is **not sufficient to make blueline microphone capture work**.
|
|
|
|
**Android DMIC-pad + analog split test — 2026-07-13:** Android's WCD9340
|
|
initial register table writes `DMIC3_CLK_PINCFG`/`DMIC3_DATA_PINCFG`
|
|
(`0x8019`/`0x801a`) to `0x0a`; mainline defined but never programmed those
|
|
registers. That exact pair was added to WCD934x component initialization,
|
|
built as `959f0d5e6`, and booted as
|
|
`7.1.1-sdm845-g959f0d5e65fc`. The normal Android handset route
|
|
`DMIC4 -> DEC7 -> TX7 -> SLIMBUS_0_TX -> MultiMedia2` remained exactly zero
|
|
(384000 bytes / 192000 signed-16 samples / zero non-zero bytes), without a
|
|
capture-time SLIM, Q6, or ADSP error. A separate reversible replay of
|
|
Android's analog fallback `AMIC1 -> ADC1 -> DEC6 -> TX6` also produced the
|
|
same exact zero stream. Thus neither the DMIC3 pad configuration nor a
|
|
bottom-DMIC/flex-only fault can explain the failure: the common remaining
|
|
boundary is codec TX channel activation and/or the ADM/ADSP capture path.
|
|
The only ALSA restore errors were the known read-only HPH impedance/type
|
|
controls.
|
|
|
|
**ADM/calibration lead — 2026-07-13 (refined 2026-07-14):** Mainline `q6routing_stream_open()`
|
|
unconditionally passes `NULL_COPP_TOPOLOGY` and app/acdb values of zero to
|
|
`q6adm_open()`. Pixel Android's `msm-pcm-routing-v2.c` starts with that
|
|
fallback but looks up topology, app type, and ACDB device ID by FE/BE/session
|
|
from audio-calibration tables before opening ADM. Do not replace the topology
|
|
with a guessed constant: the live Android `MultiMedia1 + SLIMBUS_0_TX`
|
|
recorder has now identified `app_type=69938`, `acdb_dev_id=4`,
|
|
`sample_rate=48000` (and backend ID 3). The exact ADM topology was decoded
|
|
from the extracted board-matched ACDB on 2026-07-14; see the next entry.
|
|
|
|
**ADM identity-only test — 2026-07-14 (negative):** Kernel
|
|
`7.1.1-sdm845-g3b9cf346af3a` passed Android's observed `app_type=69938` and
|
|
`acdb_dev_id=4` only for live `SLIMBUS_0_TX` capture, leaving the topology
|
|
`NULL` rather than inventing one. The matching modules were installed before
|
|
the pmOS-chain `boot_a` image was flashed; the running kernel and modules
|
|
matched. A controlled `MultiMedia1` / `hw:0,0`, mono S16_LE 8 kHz raw capture
|
|
with the Android-equivalent `DMIC4 -> DEC7 -> TX7` route yielded 128,000 bytes
|
|
with **zero non-zero samples**. ALSA state was restored (only the known
|
|
read-only HPH controls refused writes). This eliminates the two ADM identity
|
|
numbers alone as a microphone fix. The remaining Android differential is the
|
|
calibration-selected ADM topology and/or downstream codec-side programming.
|
|
|
|
**Board ACDB topology decoded — 2026-07-14:** The local Lineage vendor blob
|
|
`blobs/los-vendor/etc/acdbdata/OEM/sdm845-tavil-b1-snd-card/Handset_cal.acdb`
|
|
is not merely a future reference: `acdb-ldp` decodes its `HANDSET_MIC` device
|
|
4 configuration map as `69938 -> 0x00010315` (at 48 kHz). Downstream's
|
|
`apr_audio-v2.h` names `0x00010315` as
|
|
`ADM_CMD_COPP_OPENOPOLOGY_ID_MIC_MONO_AUDIO_COPP`; it is the specific Android
|
|
mono-microphone COPP, rather than the mainline null passthrough
|
|
`0x00010312` or a guessed default. This explains why the identity-only test
|
|
was necessarily incomplete. The present 7.1.1 tree also contains q6core's
|
|
optional ACDB topology-registration code, but blueline's q6core DT node has
|
|
no `qcom,acdb-name` and no `Global_cal.acdb` is installed as firmware, so that
|
|
path is currently dormant.
|
|
|
|
**ADM topology + AudProc test — 2026-07-14 (negative):** The current kernel
|
|
opens `SLIMBUS_0_TX` capture with topology `0x10315`, app type 69938, and ACDB
|
|
device 4, then parses and sends the board ACDB's complete 524-byte AudProc
|
|
table. Live dmesg confirms `SLIMBUS_0_TX applied ACDB AudProc calibration:
|
|
device=4 rate=48000 app=69938 (524 bytes)`, but capture remains exactly zero.
|
|
This eliminates the selected COPP topology plus AudProc table as a complete
|
|
fix; Android also sends the separate AudVol table.
|
|
|
|
**AFE calibration delivery audit — 2026-07-14:** All three local Pixel
|
|
Handset ACDB variants agree. Device 4 has no `AFECLUT0` common-calibration
|
|
row, and its `AFE_CMN_TOPID_V2` device property is `0x000112fb`, Qualcomm's
|
|
`AFE_TX_TOPOLOGY_ID_NONE`. The only device-4 AFE datum is a 48-kHz AV-sync
|
|
delay of 578, which cannot account for an all-zero stream. Qualcomm's SDM670
|
|
ACDB loader passes the same device ID 4 to AFE (there is no hidden remap to
|
|
the unrelated AFE-common IDs 100/128/130/149), tries topology, common table,
|
|
then hardware delay. Therefore adding an AFE common/topology sender here
|
|
would deliver no microphone payload. Do not revisit AFE delivery without new
|
|
Android evidence.
|
|
|
|
**ADM AudVol + explicit SLIM-error test — 2026-07-14 (negative):** Device 4,
|
|
app type 69938, volume index 0 decodes to a 40-byte table: soft-volume
|
|
stepping parameters and mono gain `0x2000` (unity). Kernel
|
|
`7.1.1-sdm845-gfb8f067e12f2` parses `AVOLLUT0`/`AVOLCDFT`/`AVOLCDOT` with the
|
|
same validated generic table builder and sends AudProc then AudVol, matching
|
|
Android's order. The same build propagates previously ignored failures from
|
|
SLIM port connection and WCD934x stream prepare/enable. A controlled 5-second
|
|
`DMIC4 -> DEC7 -> TX7 -> MultiMedia2` mono 48-kHz capture completed normally
|
|
and produced 480,000 bytes / 240,000 samples, all exactly zero. Live dmesg
|
|
confirms `SLIMBUS_0_TX applied ACDB AudProc/AudVol calibration: device=4
|
|
rate=48000 app=69938 (524/40 bytes)` and contains no capture-time SLIM
|
|
connect/prepare/enable, WCD934x, Q6, permission, or missing-file error.
|
|
Therefore neither the missing AudVol table nor a silently discarded SLIM
|
|
setup failure explains the zero stream.
|
|
|
|
Do not stream the ADSP-owned `217:250:0:0` debugfs regmap `registers` file
|
|
during capture: a filtered read blocked after the capture had completed and
|
|
had to be killed. This is consistent with the earlier observation that IFD
|
|
`0x097` is controlled by the ADSP SLIM master; it is not a safe codec-style
|
|
bulk register snapshot path and yielded no new state evidence.
|
|
|
|
**True cold-boot re-validation — 2026-07-13:** Kernel
|
|
`7.1.1-sdm845-g44d43e6ef336` includes the WCD934x `.prepare`/`.shutdown`
|
|
stream-lifecycle experiment. On a physical shutdown/power-on with native WCN
|
|
boot healthy, the controlled DMIC4 → DEC7 → TX7 → MultiMedia2 raw capture was
|
|
again exactly zero (`192000` bytes, `0` non-zero bytes). The temporary
|
|
`mic-ngd` trace proves the entire kernel-visible sequence ran successfully:
|
|
`q6afe_port_start ret=0`, `slim_stream_enable` entered,
|
|
`qcom_slim_ngd_enable_stream` entered and returned `0`. There was no SLIM/Q6
|
|
timeout. ALSA was restored immediately; the three HPH-impedance restore errors
|
|
are documented read-only controls. **This falsifies the prepare-order patch as
|
|
a microphone fix and makes silent ADSP-side channel activation (not userspace,
|
|
Q6 return handling, or NGD error propagation) the current boundary.**
|
|
|
|
**Stable-SLPI follow-up capture — 2026-07-13:** After the repaired sensor
|
|
registry cleared CHRE's five-minute watchdog and the SSC desktop sensor clients
|
|
were exercised successfully, the same safe single-direction TX7/DMIC4 route
|
|
was captured as 48 kHz mono raw audio for five seconds. It produced 480,000
|
|
bytes / 240,000 samples, all exactly zero. ALSA state was restored by trap;
|
|
SLPI, hexagonrpcd, and iio-sensor-proxy stayed active, with no `MC:0x2c`,
|
|
`-110`, or CHRE fatal. The sensor repair therefore improves platform stability
|
|
but does **not** open the microphone path.
|
|
|
|
**NGD/update audit — 2026-07-13:** The running 7.1.1 source already contains
|
|
the complete upstream May-2026 NGD probe/SSR race-fix series that landed for
|
|
7.2-rc: deferred IRQ enable, controller-owned workqueue initialization, safe
|
|
SSR/PDR cleanup, and the `tx_lock` ABBA deadlock fix. It therefore must not be
|
|
re-applied as a speculative microphone patch. This boot still logged one
|
|
`QMI wait timeout`; that is the driver's one-second wait for the remote QMI
|
|
service, not an `EPERM` or file-access failure. It remains a boot-stability
|
|
lead, but the subsequent raw capture's core `CONNECT_SOURCE` transaction
|
|
returned `0` and the audio data was still all zero.
|
|
|
|
- The on-device session's mic doc (collected to
|
|
`docs/tasks/mic-slim-tx-20260712.md`, source
|
|
phone `~/projects/unfinished/pixel3-microphone/`) found every capture
|
|
start at ~23h uptime logging 3x `TX timed out:MC:0x2c` /
|
|
`failed:-110` — the SLIMbus `CONNECT_SRC` user message to the ADSP
|
|
master never answered — and called that the localized root cause.
|
|
- **Re-test after a WARM reboot (same day, laptop-driven): the 0x2c
|
|
timeout did not reproduce — but the boot was NOT clean.** That boot was
|
|
produced by `sudo reboot` (warm), and its dmesg shows `QMI wait timeout`
|
|
at 8.1s plus the repeating "Rcvd master capability" retry loop — the
|
|
documented degraded slim-ngd state that warm reboots carry over (same
|
|
TZ-poison family as the WiFi MSA issue; only an UNPLUGGED cold power-off
|
|
clears it). Within that caveat: a `hw:0,1` capture with the doc's exact
|
|
TX7/DMIC4 arming logged 37 slim transfers — all MC `0x60`/`0x68` value
|
|
messages, zero errors, zero timeouts — and was still bit-for-bit zero,
|
|
with IFD `0097/0320/0330/0970` all `00` mid-capture. **Both datapoints
|
|
(0x2c timeout at 23h uptime; silent no-activation here) need
|
|
re-validation on a true cold boot before either is trusted.**
|
|
- No root-cause conclusion is valid yet. The `-110` may be a degraded-NGD
|
|
artifact of long uptime / remoteproc restarts, while the silent all-zero
|
|
capture may be a separate normal-state failure; the only attempted contrast
|
|
was tainted by a warm reboot. Kernel-visible Q6 and NGD success plus Android's
|
|
`IFD 0x097=21` versus mainline `00` remain observations, **not a proven
|
|
boot-invariant activation failure**.
|
|
- Note: `0320/0330` read `00` here vs `c0/01` in the 07-11 canonical 2ch
|
|
trace — arming differed (single TX7 vs TX7+TX8); observation only.
|
|
- What the phone doc contributes regardless: OnePlus 6 (enchilada) mic
|
|
works on pmOS 6.x kernels with this same driver stack (6.x->7.x
|
|
regression candidate in slimbus/ngd/wcd934x, or blueline-specific ADSP
|
|
behavior); pmOS's blueline UCM ships with the whole mic section
|
|
commented out (nobody has solved this on mainline); operational
|
|
hazards — never restart the adsp remoteproc while debugging slim (NGD
|
|
stays degraded until reboot, reproducible), never leave MultiMedia2
|
|
with both `SLIMBUS_0_RX` and `SLIMBUS_0_TX` routes enabled (q6adm/q6asm
|
|
wedge); QUAT_TDM_TX_0 in DT would give a WCD-free CS35L36 VMON/IMON
|
|
capture reference.
|
|
- Refined next steps: trace the `qcom_slim_ngd_enable_stream` user-message
|
|
exchange on a fresh boot (is CONNECT_SRC sent and ACKed, or skipped?);
|
|
diff `drivers/slimbus/{qcom-ngd-ctrl.c,stream.c,messaging.c}` +
|
|
`wcd934x.c` against pmOS's 6.x sdm845 tree; if an enchilada is handy,
|
|
boot this 7.1.1 kernel on it to split regression vs blueline-specific;
|
|
ask #sdm845-mainline about silent no-activation with working value
|
|
messages.
|
|
|
|
### Upstream/device-branch archaeology — 2026-07-12 (no phone test)
|
|
|
|
- The current `sdm845/7.1-dev` upstream line is active (its tip is two months
|
|
newer than our 7.1.1 base) but its audio delta is the CS35L36 speaker DTS
|
|
support already mined for the working speaker route; it contains no WCD934x
|
|
microphone/SLIM-TX fix. Do not hold a cold-boot test for an imagined pending
|
|
7.1 microphone update.
|
|
- **Real candidate to test after a true cold baseline:** historical
|
|
`joel/op6-audio-fixes-wip` commit `1d5776ca` changes WCD934x SLIM lifecycle
|
|
from `.trigger` (enable on PCM START) to `.prepare` plus `.shutdown` (enable
|
|
before START, disable on close). Our current `wcd934x.c` still has the old
|
|
`.trigger` implementation. This is not upstream and not proof of a fix, but
|
|
it moves the `slim_stream_enable()` / CONNECT_SRC exchange out of PCM START
|
|
into the backend prepare phase. Static inspection confirms the Q6 SLIM DAI
|
|
starts its AFE port in `.prepare`, while DPCM prepares BEs before the FE;
|
|
that makes this a concrete stream-ordering hypothesis rather than a generic
|
|
codec tweak. First make an instrumentation-only patch or trace plan that
|
|
establishes the exact per-DAI callback order; only then consider a
|
|
rollback-approved kernel test.
|
|
- Related branch commits were inspected and are **not** default candidates for
|
|
blueline DMIC capture: `75ad5bb0` adds separate AIF2/AIF3 SLIM DAI links for
|
|
OnePlus use cases (our AIF1 `SLIMBUS_0_TX` link already matches its AIF1
|
|
portion); `4a05bee2` and beryllium `07078b5c` repair MBHC/MIC_BIAS2 headset
|
|
handling, not the DMIC4/MIC_BIAS4 path. Keep them as topology references,
|
|
not a grab-bag patch series.
|
|
- **Candidate build/deploy and cold-boot result (2026-07-13):** the lifecycle
|
|
change was ported exactly onto the running Type-C-bisect base
|
|
(`56b0a053b`) as `44d43e6ef` / Gitea branch
|
|
`mic-slim-prepare-order-g56`, built on ArchDev, module tree installed, and
|
|
boot image flashed to slot A. Casey then performed an unplugged shutdown and
|
|
power-on; on `7.1.1-sdm845-g44d43e6ef336`, the controlled
|
|
`DMIC4 → DEC7 → TX7 → MultiMedia2` `hw:0,1` capture still contained only
|
|
zero samples. No `MC:0x2c` / `-110` occurred during that capture. Thus the
|
|
prepare-order hypothesis is a valid deployed negative result, not an
|
|
untested lead; retain the kernel as the current microphone-test baseline.
|
|
|
|
## Live state — 2026-07-12 (speakers)
|
|
|
|
- BOTH speakers now fire: the earlier "speaker playback works" state was in
|
|
fact top-speaker-only — both CS35L36 amps had `Channel Mux = RX1`, so the
|
|
bottom loudspeaker never received a channel. Fixed with the pmOS backup
|
|
image's routing (Left=RX1 top, Right=RX2 bottom, plus LDM select / PDM
|
|
ramps / zero-cross / per-amp ASPTX sources) in the overlay UCM
|
|
(commit 2f39c06), installed on-device and persisted via `alsactl store`.
|
|
Verified by ear: distinct left/right/stereo tones.
|
|
- Phone-side handoff doc `~/projects/unfinished/pixel3-speaker-routing/`
|
|
(README + baseline state + test tones) documents the diagnosis trail;
|
|
its "next step" (pmOS MRs online) was superseded by reading the local
|
|
pmos-20260703 rootfs image directly (debugfs, no mount needed).
|
|
- **Regression and guardrail — 2026-07-13:** the live TDM split was still
|
|
correct (`Left Channel Mux=RX1`, `Right Channel Mux=RX2`), but both amp and
|
|
boost switches were off. Re-enabled all four and stored the corrected state
|
|
on the phone. `docs/tasks/asound-baseline-20260712.state` is a *pre-fix
|
|
diagnostic snapshot* (`Right Channel Mux=RX1`); it must never be passed to
|
|
`alsactl restore`, because doing so regresses the bottom speaker. Use the
|
|
deployed UCM and current `/var/lib/alsa/asound.state` as the restore source.
|
|
|
|
## Prior live state — 2026-07-11
|
|
|
|
- Speaker playback works end-to-end through PipeWire, UCM, QUAT TDM and the
|
|
CS35L36 amplifiers (top speaker only — see above).
|
|
- `arecord -D hw:0,1 -f S16_LE -r 48000 -c 2` (the canonical MultiMedia2
|
|
front-end, whose `SLIMBUS_0_TX` link is enabled) opens and runs, but capture is
|
|
bit-for-bit zero. This is a hardware/ASoC transport investigation, not a
|
|
PipeWire source-selection failure; no PipeWire source can exist until ALSA
|
|
produces samples.
|
|
- This work did not start `iio-sensor-proxy`. There is no evidence that the
|
|
sensor-client HACK or SLPI wake-lockup mechanism gates this audio path.
|
|
|
|
## Verified zero-capture path — historical 2026-07-11
|
|
|
|
The controlled route is Android's documented handset/endfire pair:
|
|
|
|
- DMIC4 -> DEC7 -> SLIM TX7 and DMIC3 -> DEC8 -> SLIM TX8.
|
|
- Q6 function tracing during `arecord` observed, in order:
|
|
`q6slim_set_channel_map`, `wcd934x_hw_params`,
|
|
`q6afe_slim_port_prepare`, `q6afe_port_start`, and `wcd934x_trigger`.
|
|
- A temporary argument probe observed the two expected shared-channel IDs
|
|
delivered to Q6 when TX6 is off: `tx_num=2`, `0x87`, `0x88` (135, 136).
|
|
The resulting 478,078 signed-16 samples on `hw:0,1` were all zero.
|
|
- The WCD9340 interface device (`217:250:0:0`, `WCD9340-IFC-DEV`) receives
|
|
the expected driver writes for both ports: TX7 map/config `0x11c=80`,
|
|
`0x11d=01`, `0x57=05`; TX8 `0x120=80`, `0x121=01`, `0x58=05`.
|
|
Its live interrupt enables are `0x32=c0` and `0x33=01`, so their absence is
|
|
**not** the explanation for silence.
|
|
- On that same canonical front-end, `q6afe_port_start()` returns `0`, then
|
|
`slim_stream_enable()` invokes `qcom_slim_ngd_enable_stream()`, which returns
|
|
`0` after the controller's `DEF_ACT_CHAN` and `RECONFIG_NOW` operations.
|
|
Kernel-visible Q6 and NGD schedule activation therefore succeeded.
|
|
- **Corrected DAPM observation:** a clean live `hw:0,1` capture powers
|
|
codec-side `AIF1 CAP` and `AIF1_CAP Mixer`. Its prepare phase calls
|
|
`wcd934x_codec_enable_slim` and two `wcd934x_codec_enable_dec` events.
|
|
The earlier report that these callbacks never fired was false: the trace
|
|
missed the prepare-phase calls. Do not use that earlier result as evidence.
|
|
- The *persistent* mixer state leaves `CDC_IF TX7 MUX` and `CDC_IF TX8 MUX`
|
|
at `ZERO`, despite the corresponding AIF mixer switches and DMIC muxes
|
|
being selected. Consequently the TX7/TX8 branch is off during an ordinary
|
|
capture and no `wcd934x_codec_enable_dmic` event occurs. This is a real UCM
|
|
route omission, not an ADSP conclusion.
|
|
- A controlled, automatically reverted test set those muxes to `DEC7` and
|
|
`DEC8` and disabled stray TX6. It powered the entire intended branch and
|
|
invoked `wcd934x_codec_enable_dmic` twice (with matching shutdown calls).
|
|
The independent two-second PCM capture was nevertheless 384,000 zero bytes.
|
|
Thus the codec DAPM path and physical DMIC endpoints are viable once the
|
|
muxes are selected, but that route omission is not the final silence cause.
|
|
- This is **not** a missing FE-to-BE connection: runtime ASoC state reports
|
|
`MultiMedia2 Capture: start` with `SLIM Capture 1: start` as its active
|
|
backend, and the codec's AIF/decimator event callbacks run. With the CDC
|
|
muxes selected, the DMIC callbacks run too; the unresolved point at that
|
|
date was after the fully powered codec capture path.
|
|
- Reducing the route to the downstream-style single TX7/DMIC4 channel did not
|
|
change the result: a four-second `hw:0,1` mono capture contained 192,000
|
|
zero samples. Channel count/configuration is therefore not the activation
|
|
trigger.
|
|
|
|
## What the 2026-07-11 evidence did and did not say
|
|
|
|
Android's captured recording state has IFD `0x097=21`; mainline reads `00`.
|
|
During a five-second live TX7/TX8 capture, writing `0097 21` through the
|
|
debugfs regmap returned success but read back `0097: 00`, and all 478,078
|
|
samples remained zero. This confirms that a userspace register replay cannot
|
|
enable that state on this path. It does **not** establish what `0x097` means
|
|
or prove that it is the root cause. Do not turn it into an unconditional
|
|
codec write or call it an “ADSP-master fix” without an implementation-level
|
|
source or Android-side transition capture.
|
|
|
|
TX6 is enabled by the current mixer default alongside TX7/TX8. It makes the
|
|
unconstrained map three channels (`0x86`, `0x87`, `0x88`), while disabling it
|
|
produces the correct TX7/TX8 pair above. That is a real UCM/machine-routing
|
|
cleanup item, but it did not restore capture and is not the root cause.
|
|
|
|
## Proposed next work on 2026-07-11 — superseded
|
|
|
|
1. Capture the working Android interface-device transition, or find the
|
|
downstream owner/meaning of IFD `0x097`; compare the actual write sequence,
|
|
not just idle/recording register snapshots.
|
|
2. Add the TX7/TX8 `CDC_IF` mux selections to the eventual microphone UCM
|
|
enable sequence (and keep TX6 off for this two-channel route). Do not
|
|
expose a broken PipeWire source before its capture is non-zero.
|
|
3. Repeat the WCD9340 interface/ADSP comparison only with that fully powered
|
|
codec path. The still-zero full-path test strengthens, but does not prove,
|
|
the relevance of the non-sticking Android IFD `0x097=21` delta. Capture an
|
|
Android transition or find the downstream owner before making a firmware
|
|
or register claim. Do not flash a kernel test without an explicit
|
|
rollback-approved deployment plan.
|
|
4. Only after that, compare the remaining post-activation state with Android
|
|
at the firmware boundary. Q6 and NGD success alone do not show that the
|
|
codec/ADSP hardware emits decimator samples.
|
|
5. Fix the stray TX6 default separately in the persistent UCM/machine route,
|
|
then verify it with the channel-map probe. Do not claim mic support until a
|
|
live capture contains non-zero samples.
|
|
|
|
## Instrumentation
|
|
|
|
`/usr/local/sbin/blueline-lockup-trace` is a root helper deployed from
|
|
`rootfs-overlay/`. `mic-start` traces the Q6/WCD stream functions and the
|
|
three WCD codec DAPM event callbacks; `mic-map-start`, `mic-ifc-start`, and
|
|
`mic-ngd-start` collect Q6 channel-map, WCD interface-register-write, and
|
|
Q6/NGD return traces respectively. Trace sessions are temporary and must
|
|
always be paired with the matching `*-stop` command; the current phone was
|
|
checked clean afterwards (`tracing_on=0`, tracer `nop`, no kprobes).
|
|
|
|
## 2026-07-18 full Android power-state reconciliation
|
|
|
|
A clean, single-channel PulseAudio/UCM capture on kernel `4c3a94153` proved
|
|
that the intended TX7/DMIC4 path is selected and fully ACKed, but every one of
|
|
55,680 S16 samples is exactly zero. A simultaneous live codec dump exposed
|
|
two remaining Android/mainline power-state differences which earlier tests had
|
|
not actually eliminated:
|
|
|
|
- `ANA_MICB4` is `0x50` on mainline versus `0x90` during Android recording.
|
|
The DT opt-in `qcom,blueline-dmic-micbias-pullup` is on the `codec@1,0`
|
|
node, but `wcd934x_codec_parse_data()` queried `dev->parent->of_node` (the
|
|
SLIM controller). Therefore `micbias_pullup` was always false and the
|
|
earlier claim that pull-up mode had been tested is invalid. The code now
|
|
queries `dev->of_node`, selecting Qualcomm's downstream
|
|
`MICB_PULLUP_ENABLE` path (`0x90`).
|
|
- `ANA_BUCK_CTL` is `0x00` on mainline versus `0x07` on Android. Qualcomm's
|
|
resource manager sets RCO followed by buck `PRE_EN1`, `PRE_EN2`, and
|
|
`HIGH_ACCURACY_EN`, with 100 us between stages. The mainline driver had
|
|
dropped this sequence. It is restored as ordered masked writes, including
|
|
the reverse transition; this is not the harmful unsequenced Android
|
|
end-state replay removed earlier.
|
|
|
|
The same correction (`a75371b49`) also matches Android's board state by
|
|
programming only DMIC interface 3 pads (the real DMIC3/4 inputs) and avoids
|
|
leaving TX7 at the transient 150 Hz HPF setting (`CFG0=0xd0`) indefinitely;
|
|
Android's steady recording state is `CFG0=0x90`. One boot-time log reports
|
|
whether pull-up mode was parsed, and the capture log reports live BUCK and all
|
|
MICB registers so the next capture validates the complete state in one pass.
|
|
|
|
## 2026-07-18 eFuse initialization regression and cache fix
|
|
|
|
On the clean `3b85e688f` boot, the complete downstream AFE codec-control map
|
|
registered successfully and TX7 again reached `port_start`, CONNECT_SOURCE,
|
|
DEF_ACT_CHAN, and RECONFIG_NOW with positive ACKs. PulseAudio captured 760,318
|
|
raw bytes (380,159 S16 samples), all exactly zero. The journal exposed a real
|
|
codec boot failure: `wcd934x_enable_efuse_sensing` read `EFUSE_STATUS=0` and
|
|
reported that sensing never completed.
|
|
|
|
History showed that `1c095f7a7` had added the downstream-required
|
|
internal-SIDO start before eFuse sensing, but `c1b6371c6` removed the call while
|
|
dropping unrelated experiments. The exact downstream SIDO/buck transition
|
|
helper was later restored by `a75371b49` without reconnecting it to eFuse init.
|
|
The audit also found that downstream treats `EFUSE_CTL`, all eFuse value
|
|
outputs, and status as volatile, while mainline cached them in `REGCACHE_MAPLE`.
|
|
|
|
Commit `82355eac0` batches the complete correction: internal SIDO before the
|
|
sense enable, the required 5 ms delay before RCO/BG, downstream-parity volatile
|
|
register handling for the eFuse/clock/buck sequence, live completion polling,
|
|
register error propagation, and explicit status/out14/out15 logging. Do not
|
|
interpret another zero capture until a cold boot proves the codec prints
|
|
`eFuse sense complete`; otherwise the physical codec trim/version state is
|
|
still uninitialized even though SLIM management commands ACK normally.
|