Skip to content

Commit adea8b7

Browse files
josephnefclaude
andauthored
RTL8814AU: port PHY_SetTxPowerIndex_8814A (BB 0x1998 packed write) (#26)
## Summary - Port `PHY_SetTxPowerIndex_8814A` from upstream `hal/rtl8814a/rtl8814a_phycfg.c:743` — the 8814 TX-power-table uses a single packed DWord write to BB register `0x1998` per (path, rate), totally different from 8812's per-byte per-rate register layout (`rTxAGC_A_CCK*`, `rTxAGC_A_Ofdm*`, etc.). - The previous code path was writing 8812 register addresses on 8814; those registers don't exist there, so the writes scribbled random bits and the chip's BB stalled on each one — the full TX-power loop took ~6 minutes to finish on 8814, which is why an earlier workaround skipped it entirely in monitor mode. - Branched at the top of `PHY_SetTxPowerIndex_8812A` on `CHIP_8814A`; existing 8812 fanout below is untouched. Also extends `phy_set_tx_power_level_by_path` to cover `HT_MCS16_MCS23` and `VHT_3SSMCS0_3SSMCS9` for 8814 (upstream `PHY_SetTxPowerLevel8814` populates all rate sections regardless of link capability). ## Background The fix matches upstream verbatim: ```c u32 txagc_table_wd = 0x00801000; txagc_table_wd |= (RFPath << 8) | MRateToHwRate(Rate) | (PowerIndex << 24); phy_set_bb_reg(Adapter, 0x1998, bMaskDWord, txagc_table_wd); if (Rate == MGN_1M) phy_set_bb_reg(Adapter, 0x1998, bMaskDWord, txagc_table_wd); ``` The previous "skip TX power on 8814 in monitor mode" workaround landed in `8814AU RX WORKING: skip TX power setup in monitor mode + log packets` is removed; gating the loop with `DEVOURER_SKIP_TXPWR=1` remains as an escape hatch. ## What this does NOT fix End-to-end 8814 TX. With this change, init completes fast and the TX-power table is correctly programmed, but bulk OUT EP 0x02 still times out (`rc=-7`) post-init — chip-init leaves the USB controller in a state where EP 0x02 doesn't drain, for a different reason. That gate is tracked separately and will be a follow-up PR. ## Test plan - [x] Build green on macOS (`cmake --build build`) - [x] Build green on Arch Linux 6.18 (trainer-arch box) - [x] 8814 RX regression on CF-938AC (0bda:8813), channel 6: 10+ packets received in demo window (was previously working via the skip workaround; still works after this change) - [x] Init completes in ~5s on 8814 (vs prior ~6 minutes when the loop ran on the broken 8812 register format) - [ ] 8812 RX regression — code path is gated by `CHIP_8814A` so the 8812 path is untouched, but ideally smoke-tested before merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 67589c0 commit adea8b7

1 file changed

Lines changed: 54 additions & 15 deletions

File tree

src/RadioManagementModule.cpp

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
#include "Hal8812PhyReg.h"
33
#include "registry_priv.h"
44

5+
extern "C" {
6+
#include "ieee80211_radiotap.h"
7+
}
8+
59
#include <chrono>
610
#include <map>
711
#include <thread>
@@ -237,19 +241,18 @@ void RadioManagementModule::phy_SwChnlAndSetBwMode8812() {
237241
phy_PostSetBwMode8812();
238242
_setChannelBw = false;
239243
}
240-
/* For 8814AU specifically, TX power setup iterates 4 RF paths ×
241-
* ~8 rate sections, totaling ~370 PHY_SetTxPowerIndex calls and
242-
* roughly 20–30 seconds of control transfers. The values are only
243-
* consumed by the TX path, so monitor-mode RX gains nothing from
244-
* doing the work. Set DEVOURER_FORCE_TXPWR=1 to enable the full
245-
* loop (required if you actually want to TX from an 8814 build —
246-
* TX path is not yet end-to-end validated). */
247-
if (_eepromManager->version_id.ICType != CHIP_8814A ||
248-
std::getenv("DEVOURER_FORCE_TXPWR")) {
249-
PHY_SetTxPowerLevel8812(_currentChannel);
244+
/* 8814A uses a packed single-DWord write to BB 0x1998 per (path,rate)
245+
* instead of the 8812's per-rate per-byte register fanout (see the
246+
* CHIP_8814A branch at the top of PHY_SetTxPowerIndex_8812A). The
247+
* earlier "skip TX power on 8814" workaround was a symptom of the
248+
* 8812 register layout being wrong for 8814 — every write hit the
249+
* wrong bits and the chip's BB stalled on each one. Setting
250+
* DEVOURER_SKIP_TXPWR=1 keeps the old skip behaviour as an escape
251+
* hatch (e.g. for RX-only experiments). */
252+
if (std::getenv("DEVOURER_SKIP_TXPWR")) {
253+
_logger->info("DEVOURER_SKIP_TXPWR=1 — skipping TX power setup");
250254
} else {
251-
_logger->info("8814A: skipping TX power setup (monitor-mode RX-only; "
252-
"set DEVOURER_FORCE_TXPWR=1 to enable)");
255+
PHY_SetTxPowerLevel8812(_currentChannel);
253256
}
254257

255258
_needIQK = false;
@@ -1145,6 +1148,15 @@ void RadioManagementModule::phy_set_tx_power_level_by_path(uint8_t channel,
11451148
phy_set_tx_power_index_by_rate_section(path, channel,
11461149
RATE_SECTION::VHT_2SSMCS0_2SSMCS9);
11471150
}
1151+
/* 8814A 3-stream rate sections — must be programmed so the chip's TXAGC
1152+
* table is fully populated even though the USB-2 link can't sustain 3-SS
1153+
* data rates. Upstream PHY_SetTxPowerLevel8814 iterates all sections. */
1154+
if (_eepromManager->version_id.ICType == CHIP_8814A) {
1155+
phy_set_tx_power_index_by_rate_section(path, channel,
1156+
RATE_SECTION::HT_MCS16_MCS23);
1157+
phy_set_tx_power_index_by_rate_section(path, channel,
1158+
RATE_SECTION::VHT_3SSMCS0_3SSMCS9);
1159+
}
11481160
}
11491161

11501162
const static std::vector<MGN_RATE> mgn_rates_cck = {
@@ -1229,11 +1241,38 @@ void RadioManagementModule::PHY_SetTxPowerIndex_8812A(uint32_t powerIndex,
12291241
MGN_RATE rate) {
12301242

12311243
_logger->debug("PHY_SetTxPowerIndex {} {} {}", powerIndex, (int)rfPath, rate);
1244+
1245+
/* 8814A: per-rate per-path power index is programmed via a single packed
1246+
* BB-register write at 0x1998. Port of PHY_SetTxPowerIndex_8814A from
1247+
* upstream hal/rtl8814a/rtl8814a_phycfg.c:743.
1248+
*
1249+
* txagc_table_wd[31:24] = PowerIndex
1250+
* txagc_table_wd[15:8] = RFPath
1251+
* txagc_table_wd[7:0] = MRateToHwRate(Rate)
1252+
* txagc_table_wd |= 0x00801000 (TXAGC table-write enable + addr)
1253+
*
1254+
* The 8812 per-rate fanout below uses register addresses (rTxAGC_A_CCK_*
1255+
* etc.) that don't exist on 8814 — using it on 8814 scribbles random bits
1256+
* and stalls the BB; that's what the earlier "skip TX power for monitor
1257+
* mode" workaround was masking. */
1258+
if (_eepromManager->version_id.ICType == CHIP_8814A) {
1259+
uint32_t txagc_table_wd =
1260+
0x00801000u |
1261+
(static_cast<uint32_t>(rfPath) << 8) |
1262+
static_cast<uint32_t>(MRateToHwRate(static_cast<uint8_t>(rate))) |
1263+
(powerIndex << 24);
1264+
_device.phy_set_bb_reg(0x1998, bMaskDWord, txagc_table_wd);
1265+
if (rate == MGN_1M) {
1266+
/* Upstream comment: "first time to turn on the txagc table". */
1267+
_device.phy_set_bb_reg(0x1998, bMaskDWord, txagc_table_wd);
1268+
}
1269+
return;
1270+
}
1271+
12321272
/* The per-rate register table below only encodes paths A/B (8812-family).
12331273
* 8814AU paths C/D use a different per-path register layout (the rTxAGC_C_
1234-
* and rTxAGC_D_ symbol family in Hal8814PhyReg.h) not yet wired here. For
1235-
* now, silently skip C/D so the bring-up trace isn't flooded with errors;
1236-
* follow-up Phase-4 work will extend the table. */
1274+
* and rTxAGC_D_ symbol family in Hal8814PhyReg.h) — that's handled by the
1275+
* CHIP_8814A branch above. */
12371276
if (static_cast<uint8_t>(rfPath) >= RF_PATH_C) {
12381277
return;
12391278
}

0 commit comments

Comments
 (0)