Skip to content

8814: boot the 3081 MCU — TX + RX on every band#97

Merged
josephnef merged 4 commits into
masterfrom
8814-port-audit
Jun 11, 2026
Merged

8814: boot the 3081 MCU — TX + RX on every band#97
josephnef merged 4 commits into
masterfrom
8814-port-audit

Conversation

@josephnef

@josephnef josephnef commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

The RTL8814AU's 3081 MCU firmware never booted under devourer — CPU_DL_READY (REG_MCUFWDL bit15) never asserted — which was the root cause of dead host-pushed TX (#50, #95) while RX worked. (The port-audit groundwork merged separately as #96; this PR is the firmware-boot fix on top.)

Firmware-boot fix

The fwdl bracket is now a verbatim port of the vendor kernel's FirmwareDownload8814A + HalROMDownloadFWRSVDPage8814A, wired through helpers that already existed in-tree but were never called: _FWDownloadEnable_8814A_3081Disable → DDMA BIT16 toggle → RSVD-page download (kernel chunking, beacon-queue state set once, per-section checksum-driven DL_RDY|CHKSUM_OK RMW) → conditional FW_DW_RDY_3081Enable → poll CPU_DL_READY.

The rtw88-mimic power-on prefix is retained (devourer's only 8814 power-on path). The legacy fwdl sequence is preserved bit-for-bit behind DEVOURER_8814_FWDL=rtw88 and still reproduces the failure — clean causal A/B. DEVOURER_8814_FWDL_CHUNK overrides chunk size; _DumpFwdlState8814A traces each bracket step.

Boot trajectory on a virgin chip: REG_MCUFWDL 0x...2079 → 0x...6079 → 0x...E078 (CPU_DL_READY asserts instantly on _3081Enable).

Also in this PR

  • Logger: byte-sized integers stream as numbers, not raw chars (register values like 0xF0 were landing in logs as invalid UTF-8 and crashing tests/regress.py parsing); regress parsers made byte-tolerant
  • Docs: hardware table flips 8814 to TX + RX on every band; stale gotchas removed

Validation (real hardware)

Regress matrix, TX=RTL8814AU / RX=RTL8812AU, VM-mode kernel cells:

channel devourer→kernel devourer→devourer
6 ✓ 4281/4500 ✓ 4500/4500
36 ✓ 2315/4500 ✓ 2200/4500
100 ✓ 1378/4500 ✓ 1400/4500

(kernel-TX cells read 0 at every channel — 88XXau host-push beacon injection doesn't emit on that driver; its probe-request injection does. Pre-existing, documented in CLAUDE.md.)

Fixes #95. Fixes #50. Fixes #36.

🤖 Generated with Claude Code

josephnef and others added 4 commits June 11, 2026 15:55
#50 TX-silence root cause)

The rtw88-mimic fwdl sequence left CPU_DL_READY (REG_MCUFWDL bit15)
permanently deasserted: FW bytes landed (DDMA checksum OK) but the 3081
never booted, so host-pushed TX was 0 on-air while RX worked. Replace
the fwdl bracket with a verbatim port of the vendor kernel's
FirmwareDownload8814A + HalROMDownloadFWRSVDPage8814A
(hal/rtl8814a/rtl8814a_hal_init.c), wired through the pre-existing
kernel-faithful helpers that were never called:

  _FWDownloadEnable_8814A(true)      RMW 0x0080 bit13|bit0
  _3081Disable8814A                  RMW, hold MCU in reset
  _DDMAReset8814A                    0x1080 BIT16 clear->set toggle
  HalROM RSVD-page download          1488-byte chunks; beacon-queue state
                                     set once (not per-chunk); 0x0205 BIT7
                                     ack poll/clear via RMW; per-section
                                     checksum-driven DL_RDY|CHKSUM_OK RMW
  FW_DW_RDY (0x0081 |= BIT6)         only if both section checksums OK
  _3081Enable8814A                   release MCU -> fw boots
  _FWDownloadEnable_8814A(false)     RMW clear bit0
  poll CPU_DL_READY

The rtw88-mimic power-on prefix is retained (it is devourer's only 8814
power-on path), as are the pre-fwdl staging ops whose kernel equivalents
live in _InitPowerOn_8814AU/_InitQueueReservedPage. The legacy sequence
is preserved bit-for-bit behind DEVOURER_8814_FWDL=rtw88;
DEVOURER_8814_FWDL_CHUNK overrides the kernel chunk size. Per-step
register-state dumps (_DumpFwdlState8814A) trace the bracket.

Hardware-validated on a virgin chip (Vbus power-cycled):
- REG_MCUFWDL trajectory 0x...2079 -> 0x...6079 -> 0x...E078
  (CPU_DL_READY asserts instantly on _3081Enable)
- TX on-air at the kernel-monitor witness: ch6 12844, ch36 10752,
  ch100 10817 canonical-SA frames (previously 0 at every channel)
- 8814 RX at ch6 unaffected; 8812 TX unaffected (8463 frames)
- DEVOURER_8814_FWDL=rtw88 still reproduces the failure (0x00606078),
  a clean causal A/B

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The minimal {}-formatter streamed uint8_t via `oss << value`, inserting a
raw char — register values like 0xF0 became invalid UTF-8 bytes in the
log (e.g. the 8814 RFE pin-select line) and crashed tests/regress.py's
strict-UTF-8 log parsing, zeroing the devourer cells. Widen
unsigned/signed char at the stream site (plain `char` untouched), make
regress.py's parsers errors="replace" tolerant anyway, and widen the
fwdl state-dump reads explicitly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
README hardware table: 8814 row flips to TX + RX across 2.4 GHz /
UNII-1 / UNII-2-3 (regress matrix green at ch6/ch36/ch100); intro no
longer lists it as the band-gapped part. CLAUDE.md: chip-status
paragraph reflects the 3081-MCU firmware-boot fix (issue #95), the
regression section drops the stale broken-cells list and gains the
kernel-TX matrix-interpretation caveat (88XXau host-push beacon inject
doesn't emit, judge 8814 TX by devourer-TX cells), and the issue #36
passthrough-cycle gotcha is rewritten as resolved/historical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CLAUDE.md and README describe what the driver does now; git history is
the changelog. Drop the resolved-gotcha entry, the "since fix #NNN"
phrasing, PR-body references, and the redundant 8812 table note. Keep
only operative facts (8814 TX needs the booted 3081 MCU; kernel-TX
matrix cells aren't authoritative for 8814).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@josephnef josephnef changed the title 8814: kernel port audit + boot the 3081 MCU — TX + RX on every band 8814: boot the 3081 MCU — TX + RX on every band Jun 11, 2026
@josephnef josephnef merged commit 63b9834 into master Jun 11, 2026
5 checks passed
@josephnef josephnef deleted the 8814-port-audit branch June 11, 2026 13:17
josephnef added a commit that referenced this pull request Jun 11, 2026
…scaffolds (#98)

## Summary

Post-port hygiene sweep: the codebase is open source and should be
self-explanatory, but comments referenced an internal notes system,
files that were never committed (`TODO.md`, `tools/gen_rtw88_mimic.py`),
and carried debugging scaffolds from the now-finished 8814 TX
investigation. All factual content is preserved in-place; only the
pointers and dead scaffolds go. Net **−4,831 lines**.

### Comments rewritten as self-contained
- Internal-notes citations → plain statements (8814 RF paths C/D are
write-only by HW design; 8821 ch100 wedge is triggered by the second
channel-set, not the band-switch)
- `TODO.md` pointers → "kernel-vs-devourer register canary diff"
provenance
- Dropped the `/tmp/rtw88_init.seq` / `gen_rtw88_mimic.py` pointer
(never committed)

### Scaffolds removed (superseded or never validated)
- `DEVOURER_OOT_REPLAY` + `hal/Hal8814_PostFwdlReplay.h` — 135 KB usbmon
replay table; superseded by the kernel-faithful fwdl bracket (#97)
- `DEVOURER_8814_DEINIT_BEFORE_INIT` — experimental gate; the warm-state
wedge it targeted no longer reproduces
- `DEVOURER_PROBE_MCUFWDL` demo probe and the unconditional 18-line
"8814A TX-state" init log dump

### Docs
- `tests/README.md`: stale "known broken cells (8814 RX, 8821 TX/RX)"
claims replaced with the current operative caveat (kernel-TX cells with
8814: `88XXau` host-push beacon injection doesn't emit — judge by
devourer-TX cells)
- `docs/8814-port-audit.md` deleted — investigation-process report
(pending-validation plans); history lives in git

Kept deliberately: the 2024-era vendor-port TODOs (inherited-code
provenance) and `DEVOURER_USB_SENTINEL` (self-documented, wired to the
in-repo usbmon diff tooling).

## Validation

- Build green (GCC, all targets)
- Hardware smoke after the init-path removals: RTL8814AU TX ch6 → 6,238
frames on-air at the monitor witness; submits clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant