tasks: mic is functional-pinned (spec'd: sample-dup + unpin test); add 15 idle coordinator
07 rewritten around the working mic-race-fix kernel (f56b1ae08 running): canonical-tree truth, the sample-duplication defect with measured evidence, and the cold-boot unpin protocol. 15 is the freeze/doze/ RTC-wakeup design carved from today's idle-burn numbers.
This commit is contained in:
parent
22d997a394
commit
039d73eb3b
3 changed files with 181 additions and 68 deletions
|
|
@ -1,70 +1,106 @@
|
|||
# TASK 07 — WCD9340 mic: SLIM TX channel/port contract
|
||||
# TASK 07 — WCD9340 mic: functional-pinned; unpin + fidelity remain
|
||||
|
||||
**Status:** diagnosed 2026-07-17. Frontier — no mainline SDM845 phone has
|
||||
mic working. This is the most important open thread.
|
||||
**Status:** FUNCTIONAL 2026-07-20, re-verified 2026-07-21 (3/3 captures,
|
||||
real audio, zero SLIM errors). Two defects remain: a sample-duplication
|
||||
bug that halves audio bandwidth, and the power pin that makes it work.
|
||||
The 2026-07-17 "diagnosed" text below the fold is history — kept because
|
||||
the trace method and dead-end ledger stop future sessions from
|
||||
re-deriving them.
|
||||
|
||||
## Goal
|
||||
## Where the working code actually lives (fixed 2026-07-21)
|
||||
|
||||
Microphone input on blueline (WCD9340 codec over SLIMbus). Audio OUTPUT
|
||||
already works (speaker path is DSP→MI2S→Cirrus cs35l36 amps, never
|
||||
touches the WCD codec). Mic is the only WCD/SLIMbus customer.
|
||||
The phone runs `7.1.1-sdm845-gf56b1ae0831c` — that is commit
|
||||
`f56b1ae08` ("make prepare idempotent across PCM re-prepare",
|
||||
2026-07-20), tip of branch **`mic-race-fix`**.
|
||||
|
||||
## The diagnosis (2026-07-17 regmap trace)
|
||||
- **Canonical tree: `~/Projects/Pixel3Arch/kernel/linux-blueline-current`**
|
||||
(worktree on `mic-race-fix`, now synced to f56b1ae08).
|
||||
- Build tree on archdev: `~/build/pixel3arch-kernel/src/linux-blueline-src`,
|
||||
branch `makepkg` — this is what actually built the running kernel.
|
||||
- Stale claimants, do not trust their STATUS.md: `linux-blueline-work`
|
||||
(detached at 07-18), `linux-blueline-mic-order-g56` (broken worktree,
|
||||
parent .git moved), and the dirty 07-03 checkout at
|
||||
`PostMarketOS-Blueline/references/linux-7.1.1-sdm845-CANONICAL`.
|
||||
|
||||
**The prior diagnosis was wrong.** Commit `5199244ee` dropped the
|
||||
`0x0c96` (SWR_AHB_BRIDGE_ACCESS_STATUS) write, blaming it for the SLIM
|
||||
-110 wedge. A trace taken *with that fix applied* still wedges
|
||||
identically. 0x0c96 was innocent.
|
||||
The mic stack (07-14 → 07-20), newest first: prepare idempotency ·
|
||||
sysclk+MICB2 pin at probe (cd7758eae) · CHAN_CTRL remove on stream
|
||||
disable · **LN_BB_CLK3 extclk (the MCLK fix — codec was on the wrong
|
||||
PMIC clock buffer, root of the original eFuse/-110 era)** · RCO SIDO
|
||||
buck · DMIC DAPM micbias · decimator clk at PRE_PMU · PGA unmute ·
|
||||
ch pairing + AFE CDC_DEV_CFG.
|
||||
|
||||
**The real trigger:** the codec accepts every TX-path setup write
|
||||
cleanly (microsecond latencies). The bus dies on the first *read* after
|
||||
arming TX7/TX8:
|
||||
Audio server truth: the phone runs **PipeWire 1.6.8** (pipewire-pulse;
|
||||
pulseaudio.service inactive — the old "pulseaudio MASKED" note is
|
||||
history). UCM exposes `alsa_input.platform-sound.HiFi__Mic__source`,
|
||||
s16le 1ch 48 kHz. Capture test:
|
||||
`pw-record --target <mic-source-id> /tmp/x.wav`.
|
||||
|
||||
```
|
||||
2552.829597 reg_write 0x800 val=6 # last healthy write
|
||||
2552.829598 hw_read_start 0x801 # polls TX port status
|
||||
2553.875314 hw_read_done 0x801 (1.046s) # first -110 timeout
|
||||
→ forever: NGD 0x82000000 = TX_NACKED_2
|
||||
```
|
||||
## Defect 1 — sample duplication (the "bit buggy")
|
||||
|
||||
Every write succeeds. No single write is poisonous. The wedge is the
|
||||
codec's TX port failing to complete a SLIMbus TX transaction once armed
|
||||
— a **channel/port mapping contract** problem between NGD and the codec,
|
||||
not a bad register write. Last writes before death were the TX7/TX8
|
||||
path-config burst (`CDC_TX7_TX_PATH_CFG0` 0xaa2, `CDC_TX7_TX_VOL_CTL`
|
||||
0xaa4, `CDC_TX8_TX_PATH_CTL/CFG0/VOL_CTL` 0xab1/0xab2/0xab4). Full
|
||||
trace + register map: `~/Projects/Pixel3Arch/kernel/linux-blueline-mic-order/MIC-WEDGE-TRACE-20260717.md`.
|
||||
Every captured sample arrives exactly twice: raw stream begins
|
||||
`-1224, -1224, -190, -190, 1044, 1044, …` (measured 2026-07-21; RMS
|
||||
7179, rail fraction 0.03% — dynamics healthy otherwise). The ALSA layer
|
||||
believes 1ch 48 kHz S16 (`/proc/asound/card0/pcm1c` during capture), so
|
||||
the doubling happens **below the kernel interface**: the TX7/TX8 SLIM
|
||||
channel pair both carry the same 24 kHz decimator output and AFE
|
||||
interleaves the pair into the "48 kHz" stream. Net effect: 12 kHz real
|
||||
bandwidth — voice sounds muffled/underwater.
|
||||
|
||||
## Next step
|
||||
Fix directions, in order of likelihood:
|
||||
1. Map mono 48 kHz capture to **one** SLIM channel (downstream 4.9 uses
|
||||
a single channel for SLIMBUS_0_TX mono; the pair is for stereo).
|
||||
2. If the pair stays, feed it as a true even/odd sample split, not two
|
||||
taps of one decimator.
|
||||
|
||||
Stop hunting "the misidentified register." Compare our SLIM TX
|
||||
channel/port setup against **db845c**'s working mainline SLIM capture
|
||||
path, register-for-register. db845c is the same codec + bus and is the
|
||||
only known-working reference. The fault is in the NGD→codec TX channel
|
||||
contract, likely in port enable / channel-map setup in
|
||||
`sound/soc/codecs/wcd934x.c` or the q6 SLIM DAI config.
|
||||
Acceptance: no exact duplicate pairs in raw capture; spectrum extends
|
||||
past 12 kHz (whistle test).
|
||||
|
||||
## Context
|
||||
## Defect 2 — the power pin (the "unpin test")
|
||||
|
||||
- Kernel tree: `~/Projects/Pixel3Arch/kernel/linux-blueline-mic-order/`
|
||||
(CANONICAL per its STATUS.md). Tip `5199244ee`. Build with
|
||||
`pmbootstrap build --src=<repo>/references/linux-7.1.1-sdm845-CANONICAL
|
||||
linux-postmarketos-qcom-sdm845 --force`.
|
||||
- The TX7 setup fn: `wcd934x_apply_blueline_android_tx7_capture_setup()`
|
||||
in `sound/soc/codecs/wcd934x.c` (~line 1880).
|
||||
- pulseaudio is MASKED on the phone (symlinks to /dev/null). It must stay
|
||||
masked while debugging capture — unmask only once mic is understood.
|
||||
- Repro: cold boot, `arecord -D hw:0,0 -f S16_LE -r 48000 -c 1 -d 2`.
|
||||
Wedges on stream start. Only cold boot clears (unbind deadlocks D-state).
|
||||
- Instrumentation: `~/mic-hunt.sh` on the phone (regmap ftrace + slimbus
|
||||
dynamic debug + arecord, snapshots to `~/mic-hunt-<ts>/`).
|
||||
`cd7758eae` holds a permanent codec sysclk reference + MICB2 pull-up
|
||||
from component probe. Why: capture only produces samples when it opens
|
||||
against an already-powered codec. A capture whose own bring-up starts
|
||||
from codec power-off reads zeros on every route until the next cold
|
||||
boot. Working boots had merely won a race with MBHC's ~3 s probe-time
|
||||
sysclk hold; losing boots lost it by ~1 s.
|
||||
|
||||
## Acceptance
|
||||
Cost: sysclk + SIDO buck + MICB2 pull-up burn from boot, forever —
|
||||
this is standing idle drain and pocket heat, and it blocks any real
|
||||
suspend story (TASK-08/15).
|
||||
|
||||
`arecord -D hw:0,0 -d 2` captures non-zero samples without wedging the
|
||||
bus. No -110 storm in dmesg.
|
||||
The unpin test (cold boots — Casey at the device):
|
||||
1. Build `mic-race-fix` with cd7758eae reverted plus a candidate
|
||||
ordering fix (start from what MBHC's probe path powers that the
|
||||
capture path doesn't: RCO/SIDO buck sequencing — see 3ac06ca49 —
|
||||
and clock-gate readbacks from 323b29715's instrumentation).
|
||||
2. Cold boot. **Wait >3 min before first capture** so the MBHC hold has
|
||||
expired and the race can't be accidentally won.
|
||||
3. `pw-record` → non-zero samples? Repeat across 3 cold boots.
|
||||
4. Zeros → the ordering fix is wrong; pin goes back; iterate. The pin
|
||||
is the fallback, never the end state.
|
||||
|
||||
## Acceptance (task-level)
|
||||
|
||||
Unpinned kernel: first capture after a >3 min-idle cold boot returns
|
||||
real samples, three cold boots in a row. No duplicate-pair signature.
|
||||
No -110/NACK storm in dmesg across repeated open/close.
|
||||
|
||||
## History (2026-07-17, superseded)
|
||||
|
||||
The bus-wedge diagnosis that got us here: every TX-path setup write
|
||||
succeeded; the bus died on the first *read* after arming TX7/TX8
|
||||
(`0x801` poll → 1.046 s timeout → NGD `TX_NACKED_2` forever). Full
|
||||
trace: `linux-blueline-mic-order/MIC-WEDGE-TRACE-20260717.md`. Dead
|
||||
ends already falsified — do not re-derive: 0x0c96 was innocent; codec
|
||||
regs match Android ground truth bit-for-bit; q6afe cdc_codec_config
|
||||
already fires (ret=0); AFE_SLIMBUS_SLAVE_PORT_CONFIG is SLIMBUS_5_TX
|
||||
only; ADSP file-serving complete (only adsp_avs_config.acdb requested);
|
||||
adsp.mbn is stock Google-signed Android-11 era; slot B is wiped, no LOS
|
||||
image on-device to diff. Post-mortem of the whole hunt:
|
||||
`linux-blueline-current/2026-07-19-FABLEWORK.txt`.
|
||||
|
||||
## Connects to
|
||||
|
||||
handoff doc "Microphone bringup leads" (mailing lists show WIP from
|
||||
others), the 2025-26 upstream fix wave already in our base.
|
||||
TASK-15 idle coordinator (the pin is its enemy), TASK-08 device state
|
||||
manager, upstream: LN_BB_CLK3 + CHAN_CTRL-remove + the eventual unpin
|
||||
ordering fix are mainline candidates once stable.
|
||||
|
|
|
|||
76
docs/tasks/15-idle-coordinator.md
Normal file
76
docs/tasks/15-idle-coordinator.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# TASK 15 — Idle coordinator: freeze, doze, and scheduled wakeups
|
||||
|
||||
**Status:** open — design task. Carved 2026-07-21 from Casey's ask
|
||||
("app freeze state for idle, the timeoffs and wakeups to check for
|
||||
notifications") plus the measured idle burn below.
|
||||
|
||||
## Why (measured 2026-07-21, phone idle, screen locked)
|
||||
|
||||
- `culver` 9.8% CPU, 6:11 accumulated — the single biggest idle spinner
|
||||
- `qs` (shell) 4.5%, `souveraine-player` 3.9%
|
||||
- cluster1 peaked 54.9 °C; Casey feels it in-pocket
|
||||
- The mic power pin (TASK-07 defect 2) holds codec sysclk + MICB2 from
|
||||
boot — invisible to `top`, real on the battery
|
||||
|
||||
A phone that is "off" should approach zero. Nothing on the device today
|
||||
even attempts that.
|
||||
|
||||
## Shape of the thing
|
||||
|
||||
One coordinator (substrate side, likely a sessiond sibling or sessiond
|
||||
itself — it already owns lock state, which IS the idle signal) driving
|
||||
three tiers:
|
||||
|
||||
1. **Screen-off, tethered to lock.** Lock → after a grace period,
|
||||
freeze the app tier: `systemctl --user freeze app-*.scope` (cgroup
|
||||
freezer; requires app launches to land in per-app scopes — they may
|
||||
already via uwsm/exec rules, verify). The shell, sessiond, modem
|
||||
stack, and the notification path stay unfrozen. Unlock → thaw
|
||||
everything, instantly.
|
||||
2. **Doze.** After N min locked: stop the polling herd (culver first —
|
||||
find its idle loop regardless; 10% CPU while doing nothing is a bug
|
||||
on its own), drop Wi-Fi to power-save, let UPower's percentage
|
||||
polling coast. The lockscreen glance data (media, agent, notify
|
||||
cards) must still update on wake — cards read on unlock, they don't
|
||||
need background freshness.
|
||||
3. **Suspend + scheduled wakeups — the end state.** s2idle with RTC
|
||||
alarms (`CLOCK_BOOTTIME_ALARM` timers in the coordinator, not
|
||||
rtcwake hacks): wake every M min → thaw the network fetchers for a
|
||||
bounded window (check Matrix/mail/notifications) → banner/lock-card
|
||||
anything that landed (NotifyEvents seam already exists) → re-freeze,
|
||||
re-suspend. Calls/SMS never wait for a poll window: modem IRQs are
|
||||
hardware wake sources. Blocked-by: TASK-09 FTS suspend race
|
||||
(interim-fixed, kernel-side) and the TASK-07 unpin (a pinned codec
|
||||
clock across suspend is either a wake veto or a lie).
|
||||
|
||||
## Design questions to settle before code
|
||||
|
||||
- Freeze unit granularity: per-app scopes vs one `apps.slice`. A slice
|
||||
freeze is one command and no bookkeeping; per-app lets Chatty stay
|
||||
live for SMS-adjacent work. Likely: freeze `apps.slice`, keep an
|
||||
allowlist slice (`apps-wake.slice`) for the few that may run locked.
|
||||
- Who is the notification fetcher during doze? If everything that polls
|
||||
is frozen, the wake window must thaw → settle → fetch → freeze; the
|
||||
coordinator needs a "fetch complete" signal, not a fixed sleep.
|
||||
- culver: freeze it like any app, but ALSO find the spin — freezing a
|
||||
busy-loop just defers the heat to unlock time.
|
||||
- Wi-Fi during suspend: WoWLAN on ath10k_snoc is unproven on this
|
||||
device; assume packets do NOT wake us, only RTC + modem do. Design
|
||||
for that and be pleasantly surprised otherwise.
|
||||
- Interaction with charging: plugged-in can skip tiers 2–3 (it's the
|
||||
desk-clock case; also the only time `grim`/remote debugging works).
|
||||
|
||||
## Acceptance
|
||||
|
||||
Locked overnight on battery: no app-tier CPU time accumulated, wake
|
||||
windows visible in the coordinator's log at the configured cadence, an
|
||||
SMS arriving mid-doze rings within seconds, and morning battery drop
|
||||
measurably better than the current baseline (capture tonight's number
|
||||
first — it is the before).
|
||||
|
||||
## Connects to
|
||||
|
||||
TASK-08 device-state-manager (this IS its idle half — 08 keeps the
|
||||
profile/governor side), TASK-09 (suspend blocker), TASK-07 defect 2
|
||||
(codec pin), NotifyEvents/LockNotifyCard (the landing surface for
|
||||
wake-window arrivals).
|
||||
|
|
@ -15,12 +15,13 @@ plus open threads from the 2026-07-17 session.
|
|||
| 1 | [Favorites — wife's name on her number](01-favorites-contacts.md) | blocked | needs a contacts-store decision (qtpim retired — see archive/06) |
|
||||
| 2 | [Lockscreen-as-Rust-system: glance + swipe](02-lockscreen-rust-system.md) | in progress | stopgap shipped 2026-07-17 |
|
||||
| 3 | [Boot timing: fade splash → lock, no extra fixes](03-boot-timing-splash-to-lock.md) | open | paired with TASK-11 (now archived) |
|
||||
| 7 | [WCD9340 mic: SLIM TX channel/port contract](07-mic-wcd9340-slim-tx.md) | diagnosed | frontier; pairs with kernel series |
|
||||
| 7 | [WCD9340 mic: functional-pinned; unpin + fidelity](07-mic-wcd9340-slim-tx.md) | functional 07-20 | defects: sample-dup, power pin; kernel `mic-race-fix` |
|
||||
| 8 | [Device state manager / power profiles](08-device-state-manager.md) | open | blocked-by TASK-09 suspend item |
|
||||
| 9 | [Suspend-resume FTS calibration race](09-suspend-resume-fts.md) | interim-fix | kernel-side; cold-boot only |
|
||||
| 12 | [Face auth as a capability factor (Gaze reference)](12-gaze-reference-face-auth.md) | open | per-target: phone needs front-cam bring-up |
|
||||
| 13 | [Active Edge (squeeze) as a sensor input](13-active-edge-squeeze.md) | open | substrate up; bring-up unit not drafted |
|
||||
| 14 | [Overview pane → phone app grid](14-overview-appgrid.md) | open | shell-side; appgrid prior art linked in-file |
|
||||
| 15 | [Idle coordinator: freeze, doze, scheduled wakeups](15-idle-coordinator.md) | open | design; blocked-by 09 for suspend tier; eats half of 08 |
|
||||
|
||||
Archived (see `archive/`): 05 crash reporter — done 2026-07-21,
|
||||
CrashReporter.qml in-shell watcher, kill-test verified on device;
|
||||
|
|
|
|||
Loading…
Reference in a new issue