Skip to content

Commit c8f3531

Browse files
snokvistclaudejosephnef
authored
rtl8733b: port FastRetune — intra-band hop with TSSI tracking kept live (#398)
## What Ports `FastRetune` to the RTL8733B backend — the last generation without a fast path. Intra-band, same-width hops only; a band/width change or cold radio declines with the chip untouched and the wrapper falls back to the full `SetMonitorChannel`, per the `IRtlDevice` contract. `AdapterCaps.fastretune_ok` now states it. ## Why / how it was sized Per-stage profiling of the full path on the USB-HS validation unit (`0bda:f72b`, cut D): ~330–440 ms total = **~165 ms TSSI disable/re-enable + ~90 ms band/bandwidth switches + ~60 ms channel switch** + HALMAC/readback. A same-band same-width hop needs almost none of that. The fast path keeps: RF18 synth program from a compose cache (bandwidth bits preserved; primed by one read on the first fast hop after each full set), RF19 sub-band bits and channel-keyed BB constants on bucket change only, BB reset + IGI toggle. **TSSI tracking stays enabled across the hop**, with the per-channel rate-offset dwords rewritten in place only when the plan differs — the in-place-with-tracking-live shape #389 validated. Everything that can refuse is computed before the first chip write. ## Measured (one unit — the standing 8733B caveat — no SDR) - Call: **~55 ms** (full: 330–440). Radio-live from hop start: **10.0 ms p50** (min 3.6 / p90 12.9 / **max 40.3 — a 1-in-20 tail, not noise**), vs 70–100 ms radio-live through the full path. 20-cycle settle harness against a 1 kHz witness emitter, warm-ups excluded, honest-refusal counters all zero. - Register parity: `read_channel_state().matches(plan)` + synth-ready held on 7/7 fast hops (5180→5805). - TSSI-live TX proof: 300-frame MCS0 burst injected immediately after five fast hops — **299/300 decoded** by an independent RTL8812AU witness. - Full-path regression: unchanged (~340–440 ms call, 70–100 ms radio-live, same session). - Host build green, ctest 53/53. Docs updated (`src/rtl8733b/CLAUDE.md`, root `CLAUDE.md` frequency-hopping section, `docs/rtl8733b.md` deferred matrix) with the adversarial counterparts alongside the numbers, per the repo rule. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Hri3rWJfbvw8iCyDDwXRit --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Joseph <162703152+josephnef@users.noreply.github.com>
1 parent a0dfd17 commit c8f3531

8 files changed

Lines changed: 350 additions & 39 deletions

File tree

CLAUDE.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ construction from the `SYS_CFG2` chip-id (Kestrel: PID-first):
5959
only what an independent witness decoded — legacy OFDM + HT MCS0-7, BCC,
6060
20/40 MHz on 2.4/5 GHz, plus long-preamble CCK on 2.4 GHz at 20 MHz.
6161
Everything the backend has not ported (TSF/beacons, hardware ACK, A-MPDU,
62-
FastRetune, the runtime TX-power levers) falls through to `IRtlDevice`'s
62+
the runtime TX-power levers) falls through to `IRtlDevice`'s
6363
not-ported defaults rather than being faked, so read the base class before
64-
assuming a cross-generation feature below applies here. SGI, LDPC, STBC, VHT
64+
assuming a cross-generation feature below applies here. `FastRetune` IS
65+
ported (intra-band, TSSI kept live — `src/rtl8733b/CLAUDE.md`). SGI, LDPC, STBC, VHT
6566
and HE are refused outright. Scope, one-unit validation record and the
6667
deferred matrix: `docs/rtl8733b.md`.
6768

@@ -380,10 +381,13 @@ temporal layer and injects each at its ladder's rate
380381
## Frequency hopping
381382

382383
`IRtlDevice::FastRetune(channel)` — lean intra-band, same-bandwidth retune on
383-
the four Jaguar/Kestrel generations (RF channel switch only, write-only from a
384-
compose cache); falls back to full `SetMonitorChannel` on a band change, and to
385-
the full path entirely on the RTL8733B, which has no fast path yet.
386-
FHSS-grade: ~0.5–2.5 ms per hop depending on chip. On the Jaguar2 dies (8822B, 8821C) and Jaguar3
384+
all five generations (RF channel switch only, write-only from a
385+
compose cache); falls back to full `SetMonitorChannel` on a band change.
386+
FHSS-grade on the Jaguar/Kestrel dies: ~0.5–2.5 ms per hop depending on chip.
387+
On the RTL8733B the hop keeps TSSI tracking live (per-channel rate-offset
388+
dwords rewritten in place) and costs ~55 ms call / ~10 ms p50 radio-live on
389+
the USB-HS validation unit — vs its ~330-440 ms full path — with a measured
390+
1-in-20 40 ms radio-live tail; one unit, no SDR (`src/rtl8733b/CLAUDE.md`). On the Jaguar2 dies (8822B, 8821C) and Jaguar3
387391
(8822C, 8822E), `DEVOURER_FASTRETUNE_FW=1` hands the hop to the chip firmware
388392
instead (H2C 0x1D, fire-and-confirm-later): ~1.4 ms dead air on the 8822B (a
389393
tie on-air on the 8822C/8822E, but ~3× cheaper host-side), and `=2` extends it

docs/rtl8733b.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,18 @@ These results have **not** been claimed:
202202
- SGI remains disabled: a descriptor with its short-GI bit set submitted
203203
successfully, but an independent RTL8812AU decoded both broadcast and
204204
unicast probes as long GI. STBC and LDPC remain rejected. ACK/BlockAck
205-
response, A-MPDU, fast retune and throughput were not independently
205+
response, A-MPDU and throughput were not independently
206206
validated and remain unadvertised or unsupported by this backend.
207+
- Fast retune is now ported and independently witnessed (intra-band,
208+
same-width; `src/rtl8733b/CLAUDE.md` has the measured contract and its
209+
counterparts): channel-state readback parity 7/7 hops, a 299/300 post-hop
210+
burst decoded by an RTL8812AU witness, ~55 ms call / ~10 ms p50 radio-live
211+
on this unit. The channel-bucketed TSSI-DE offsets are rewritten in place
212+
across the hop with tracking live (the first cut skipped them — caught in
213+
review): DE readback parity 22/22 across ch1→ch13 hops, tracking-enable
214+
field held at 7 throughout, settle p50 unchanged at 10.4 ms. Radiated
215+
power across a hop remains SDR-gated like every other RF-domain quantity
216+
here.
207217
- A vendor-kernel-driver cross-test was attempted with the 2024 source on Linux
208218
6.14, but its module did not build: its Makefile omitted required include
209219
paths, and after supplying the main include path compilation stopped on an

src/rtl8733b/CLAUDE.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,41 @@ The SGI refusal is the one worth re-opening: the descriptor bit was set and the
127127
frame submitted, but the witness decoded long GI. Descriptor and air disagree,
128128
and the reason is not yet understood.
129129

130+
## FastRetune
131+
132+
Ported: intra-band, same-width hops (`Phy8733b::fast_retune`). The full
133+
`SetMonitorChannel` on this USB-HS part costs ~330-440 ms — profiled as
134+
~165 ms TSSI disable/re-enable, ~90 ms band+bandwidth switches, ~60 ms
135+
channel switch — and the fast path keeps only what a hop needs: the RF18
136+
synth program (bandwidth bits preserved via a compose cache primed on the
137+
first fast hop after a full set), RF19 sub-band bits and the channel-keyed
138+
BB constants on bucket change only, then BB reset + IGI toggle. **TSSI
139+
tracking stays enabled across the hop**, with the per-channel rate-offset
140+
dwords AND the channel-bucketed TSSI-DE offsets rewritten in place when
141+
their plans differ — the in-place shape #389 validated; every full set
142+
still runs the disable/re-enable pair. The DE rewrite is the one that
143+
matters intra-band: the rate offsets are band-keyed and never change
144+
across a 2.4 GHz hop, while the DE buckets are ~3 channels wide
145+
(boundaries at ch 2/5/8/11/14, trim at 7/14), so most hops cross one —
146+
skipping them leaves the loop tracking with the previous channel's
147+
calibration (found by review on the first cut of this port). The rewrite
148+
replays prepare_tssi_offsets' field sequence minus its tracking-disable
149+
write; measured across 22 ch1→ch13 hops on the validation unit: readback
150+
parity 22/22, tracking-enable field stayed 7 throughout, settle p50
151+
unchanged (10.4 ms). Measured
152+
on the validation unit (20-cycle settle harness, 1 kHz witness emitter):
153+
call ~55 ms, radio-live 10.0 ms p50 from hop start (min 3.6 / p90 12.9 /
154+
**max 40.3 ms — a 1-in-20 tail, not noise**), vs 70-100 ms radio-live
155+
through the full path. Channel-state readback parity held 7/7 hops, and a
156+
300-frame post-hop burst decoded 299/300 at an independent witness — the
157+
TSSI-live claim is air-verified. The counterparts: one physical unit, like
158+
every on-air claim in this subtree; no SDR, so radiated power ACROSS a hop
159+
is uncharacterized; and cross-band or width-change hops decline (chip
160+
untouched) and fall back to the full path.
161+
130162
## Not ported
131163

132-
`ReadTsf`/beacons, hardware ACK/BlockAck, A-MPDU, `FastRetune`,
164+
`ReadTsf`/beacons, hardware ACK/BlockAck, A-MPDU,
133165
`FastSetBandwidth`, the runtime TX-power knobs, `rx.path` per-chain telemetry,
134166
and CCA disable. These inherit `IRtlDevice`'s not-ported defaults (`false`,
135167
`0`, or a full-path fallback) rather than being faked. `SetCcaMode` is the one

src/rtl8733b/Phy8733b.cpp

Lines changed: 213 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,50 @@ void Phy8733b::spur_cancellation() {
694694
set_bb(0x1908, 0xf0u, 9);
695695
}
696696

697+
/* Channel-keyed constants shared by switch_channel (which writes them on
698+
* every full set) and fast_retune (which writes them only when their bucket
699+
* changes across the hop). One copy, so full-vs-fast register parity cannot
700+
* silently diverge. */
701+
namespace {
702+
703+
constexpr uint32_t kScoFc2a38_2g[15] = {
704+
0, 0x1cfea, 0x1d0e1, 0x1d1d7, 0x1d2cd, 0x1d3c3, 0x1d4b9,
705+
0x1d5b0, 0x1d6a6, 0x1d79c, 0x1d892, 0x1d988, 0x1da7f,
706+
0x1db75, 0x1ddc4};
707+
constexpr uint32_t kScoFc2a3c_2g[15] = {
708+
0, 0x27de3, 0x27f35, 0x28088, 0x281da, 0x2832d, 0x2847f,
709+
0x285d2, 0x28724, 0x28877, 0x289c9, 0x28b1c, 0x28c6e,
710+
0x28dc1, 0x290ed};
711+
712+
constexpr uint32_t agc_bucket_5g(uint8_t center) {
713+
return center <= 64 ? 6u : center <= 144 ? 7u : 0u;
714+
}
715+
716+
constexpr uint32_t sco_bucket_0c30(uint8_t center) {
717+
return center >= 173 ? 0x411u
718+
: center >= 120 ? 0x412u
719+
: center >= 112 ? 0x452u
720+
: center >= 56 ? 0x453u
721+
: center >= 52 ? 0x493u
722+
: center >= 16 ? 0x494u
723+
: center >= 13 ? 0x969u
724+
: center >= 11 ? 0x96au
725+
: 0x9aau;
726+
}
727+
728+
constexpr std::array<uint32_t, 8> tx_shape_2g(uint8_t center) {
729+
return {center == 14 ? 0x452484u : 0x7847cfu,
730+
center == 14 ? 0x0fe3c8u : 0x57a6b1u,
731+
center == 14 ? 0u : 0x1f2af412u,
732+
center == 14 ? 0u : 0x09717du,
733+
center == 14 ? 0u : 0xfb9003u,
734+
center == 14 ? 0u : 0xfb1fa5u,
735+
center == 14 ? 0u : 0xfe2fcau,
736+
center == 14 ? 0u : 0xffcff3u};
737+
}
738+
739+
} // namespace
740+
697741
bool Phy8733b::switch_channel(const ChannelPlan8733b &plan) {
698742
uint32_t rf18 = read_rf(0, 0x18);
699743
uint32_t rf19 = read_rf(0, 0x19);
@@ -722,44 +766,18 @@ bool Phy8733b::switch_channel(const ChannelPlan8733b &plan) {
722766
set_bb(0x18ac, 0x000001f0u, 4);
723767
} else {
724768
set_bb(0x1ea8, 1u << 7, 0);
725-
const uint32_t agc = plan.center <= 64 ? 6 : plan.center <= 144 ? 7 : 0;
726-
set_bb(0x18ac, 0x000001f0u, agc);
769+
set_bb(0x18ac, 0x000001f0u, agc_bucket_5g(plan.center));
727770
}
728771

729-
static constexpr uint32_t sco38[15] = {
730-
0, 0x1cfea, 0x1d0e1, 0x1d1d7, 0x1d2cd, 0x1d3c3, 0x1d4b9,
731-
0x1d5b0, 0x1d6a6, 0x1d79c, 0x1d892, 0x1d988, 0x1da7f,
732-
0x1db75, 0x1ddc4};
733-
static constexpr uint32_t sco3c[15] = {
734-
0, 0x27de3, 0x27f35, 0x28088, 0x281da, 0x2832d, 0x2847f,
735-
0x285d2, 0x28724, 0x28877, 0x289c9, 0x28b1c, 0x28c6e,
736-
0x28dc1, 0x290ed};
737772
if (plan.center <= 14) {
738773
set_bb(0x2a38, 1u << 27, 0);
739-
set_bb(0x2a38, 0x07ffff00u, sco38[plan.center]);
740-
set_bb(0x2a3c, 0x000fffffu, sco3c[plan.center]);
774+
set_bb(0x2a38, 0x07ffff00u, kScoFc2a38_2g[plan.center]);
775+
set_bb(0x2a3c, 0x000fffffu, kScoFc2a3c_2g[plan.center]);
741776
}
742-
const uint32_t sco = plan.center >= 173 ? 0x411
743-
: plan.center >= 120 ? 0x412
744-
: plan.center >= 112 ? 0x452
745-
: plan.center >= 56 ? 0x453
746-
: plan.center >= 52 ? 0x493
747-
: plan.center >= 16 ? 0x494
748-
: plan.center >= 13 ? 0x969
749-
: plan.center >= 11 ? 0x96a
750-
: 0x9aa;
751-
set_bb(0x0c30, 0xfffu, sco);
777+
set_bb(0x0c30, 0xfffu, sco_bucket_0c30(plan.center));
752778

753779
if (plan.is_2g) {
754-
const uint32_t shape[8] = {
755-
plan.center == 14 ? 0x452484u : 0x7847cfu,
756-
plan.center == 14 ? 0x0fe3c8u : 0x57a6b1u,
757-
plan.center == 14 ? 0u : 0x1f2af412u,
758-
plan.center == 14 ? 0u : 0x09717du,
759-
plan.center == 14 ? 0u : 0xfb9003u,
760-
plan.center == 14 ? 0u : 0xfb1fa5u,
761-
plan.center == 14 ? 0u : 0xfe2fcau,
762-
plan.center == 14 ? 0u : 0xffcff3u};
780+
const auto shape = tx_shape_2g(plan.center);
763781
for (unsigned i = 0; i < 8; ++i)
764782
set_bb(static_cast<uint16_t>(0x1a00 + i * 4),
765783
i == 2 ? kDwordMask : 0x00ffffffu, shape[i]);
@@ -1315,6 +1333,11 @@ bool Phy8733b::enable_tssi_tracking(SelectedChannel channel,
13151333
_tssi_digital_snapshot = digital_snapshot;
13161334
_tssi_analog_snapshot = analog_snapshot;
13171335
_tssi_is_2g = channel_cfg->is_2g;
1336+
/* fast_retune bookkeeping: the offsets the chip now carries and the RF
1337+
* path bit (RFE routing — static per session), for the in-place
1338+
* per-channel rewrite. */
1339+
_fr_tssi_offsets = capped->rate_offsets;
1340+
_fr_tssi_path = path;
13181341
_logger->info(
13191342
"RTL8733B TSSI tracking enabled: ch={} path={} ceiling={} "
13201343
"rates={:08x}/{:08x}/{:08x}/{:08x}/{:08x}",
@@ -1365,6 +1388,9 @@ bool Phy8733b::disable_tssi_tracking() {
13651388
_tssi_digital_snapshot.reset();
13661389
_tssi_analog_snapshot.reset();
13671390
}
1391+
_fr_tssi_offsets.reset();
1392+
_fr_tssi_de.reset();
1393+
_fr_tssi_power.reset();
13681394
_logger->info("RTL8733B TSSI tracking disabled: rollback={}", ok);
13691395
devourer::Ev(_logger->events(), "rtl8733b.tssi_tracking")
13701396
.f("enabled", false)
@@ -1428,6 +1454,13 @@ bool Phy8733b::prepare_tssi_offsets(SelectedChannel channel,
14281454

14291455
const TssiDeState8733b state = read_tssi_de_state();
14301456
const bool ok = state.matches_disabled(*de);
1457+
if (ok) {
1458+
/* fast_retune bookkeeping: the DE plan the chip now carries and the
1459+
* EFUSE calibration that derives it, for the in-place per-channel
1460+
* rewrite on bucket-crossing hops. */
1461+
_fr_tssi_de = *de;
1462+
_fr_tssi_power = efuse.tssi_power;
1463+
}
14311464
_logger->info(
14321465
"RTL8733B TSSI-DE: ready={} enabled={} ch={} cck={}/{} ht40={}/{} "
14331466
"ofdm={}/{} ht20={}/{}",
@@ -1489,6 +1522,15 @@ bool Phy8733b::set_channel(SelectedChannel channel) {
14891522

14901523
const ChannelState8733b state = read_channel_state();
14911524
const bool ok = state.matches(*plan);
1525+
/* fast_retune bookkeeping: record where the radio is, and invalidate the
1526+
* RF compose cache — the switch functions above rewrote both words, so a
1527+
* cached copy is stale until the next fast hop re-primes it. */
1528+
if (ok)
1529+
_fr_plan = *plan;
1530+
else
1531+
_fr_plan.reset();
1532+
_fr_rf18.reset();
1533+
_fr_rf19.reset();
14921534
_logger->info(
14931535
"RTL8733B channel: ready={} primary={} center={} width={} offset={} "
14941536
"RF18={:05x}/{:05x} RF19={:05x}/{:05x} BB9B0={:08x} "
@@ -1513,6 +1555,146 @@ bool Phy8733b::set_channel(SelectedChannel channel) {
15131555
return ok;
15141556
}
15151557

1558+
bool Phy8733b::fast_retune(SelectedChannel channel, bool tssi_live,
1559+
uint8_t max_target_qdbm, bool cache_rf) {
1560+
const auto plan = channel_plan(channel);
1561+
if (!_initialized || !plan || !_fr_plan)
1562+
return false;
1563+
const ChannelPlan8733b cur = *_fr_plan;
1564+
if (plan->is_2g != cur.is_2g || plan->width != cur.width ||
1565+
plan->offset != cur.offset)
1566+
return false;
1567+
if (plan->center == cur.center && plan->primary == cur.primary)
1568+
return true;
1569+
1570+
/* Everything that can refuse is computed BEFORE the first chip write, so a
1571+
* declined hop leaves the radio untouched for the caller's full-path
1572+
* fallback rather than half-hopped. */
1573+
std::optional<TssiBbPlan8733b> tssi;
1574+
std::optional<TssiDePlan8733b> de;
1575+
if (tssi_live && _fr_tssi_offsets) {
1576+
tssi = tssi_bb_plan(_tx_power_targets, channel.Channel, _rfe_type,
1577+
_fr_tssi_path, max_target_qdbm);
1578+
if (!tssi)
1579+
return false;
1580+
}
1581+
if (tssi_live && _fr_tssi_de && _fr_tssi_power) {
1582+
de = tssi_de_plan(*_fr_tssi_power, channel.Channel);
1583+
if (!de)
1584+
return false;
1585+
}
1586+
if (!cache_rf || !_fr_rf18) {
1587+
const uint32_t rf18 = read_rf(0, 0x18);
1588+
if (rf18 == 0xffffffffu)
1589+
return false;
1590+
_fr_rf18 = rf18;
1591+
}
1592+
if (!cache_rf || !_fr_rf19) {
1593+
const uint32_t rf19 = read_rf(0, 0x19);
1594+
if (rf19 == 0xffffffffu)
1595+
return false;
1596+
_fr_rf19 = rf19;
1597+
}
1598+
1599+
uint32_t rf18 = *_fr_rf18;
1600+
uint32_t rf19 = *_fr_rf19;
1601+
if (plan->is_2g) {
1602+
rf18 &= ~((3u << 16) | (3u << 8) | 0xffu);
1603+
rf18 |= plan->center;
1604+
} else {
1605+
rf18 &= ~((1u << 17) | (1u << 9) | 0xffu);
1606+
rf18 |= (1u << 16) | (1u << 8) | plan->center;
1607+
rf19 &= ~((1u << 19) | (1u << 18));
1608+
if (plan->center > 144)
1609+
rf19 |= 1u << 19;
1610+
else if (plan->center > 80)
1611+
rf19 |= 1u << 18;
1612+
}
1613+
/* From the first chip write onward a transport failure leaves the radio
1614+
* part-hopped, so the catch drops the fast-path bookkeeping: the next call
1615+
* declines (stale _fr_plan gone) and the caller's full-path fallback
1616+
* reprograms everything, instead of a later fast hop bucket-comparing
1617+
* against a baseline the chip no longer holds. */
1618+
try {
1619+
if (!program_synth(rf18)) {
1620+
_fr_plan.reset();
1621+
return false;
1622+
}
1623+
_fr_rf18 = rf18;
1624+
if (rf19 != *_fr_rf19) {
1625+
write_rf(0, 0x19, kRfMask, rf19);
1626+
write_rf(1, 0x19, kRfMask, rf19);
1627+
_fr_rf19 = rf19;
1628+
}
1629+
1630+
/* Channel-keyed constants from switch_channel, written only when their
1631+
* bucket changes across the hop. Band-keyed constants (0x1ea8, the
1632+
* 2.4 GHz 0x18ac pair, spur cancellation) were set by the last full set
1633+
* at this band and are untouched — that is the fast path's contract. */
1634+
if (plan->is_2g) {
1635+
if (plan->center <= 14) {
1636+
set_bb(0x2a38, 0x07ffff00u, kScoFc2a38_2g[plan->center]);
1637+
set_bb(0x2a3c, 0x000fffffu, kScoFc2a3c_2g[plan->center]);
1638+
}
1639+
if ((plan->center == 14) != (cur.center == 14)) {
1640+
const auto shape = tx_shape_2g(plan->center);
1641+
for (unsigned i = 0; i < 8; ++i)
1642+
set_bb(static_cast<uint16_t>(0x1a00 + i * 4),
1643+
i == 2 ? kDwordMask : 0x00ffffffu, shape[i]);
1644+
}
1645+
} else {
1646+
if (agc_bucket_5g(plan->center) != agc_bucket_5g(cur.center))
1647+
set_bb(0x18ac, 0x000001f0u, agc_bucket_5g(plan->center));
1648+
}
1649+
if (sco_bucket_0c30(plan->center) != sco_bucket_0c30(cur.center))
1650+
set_bb(0x0c30, 0xfffu, sco_bucket_0c30(plan->center));
1651+
if ((plan->center == 13) != (cur.center == 13))
1652+
set_bb(0x0808, 0x7fu, plan->center == 13 ? 0x30 : 0x40);
1653+
1654+
bb_reset();
1655+
igi_toggle();
1656+
1657+
/* TSSI: tracking stays enabled; the per-channel rate-offset dwords and
1658+
* the channel-bucketed DE offsets are rewritten, in place, each only
1659+
* when the new channel's plan differs (the #389 shape). Intra-band the
1660+
* rate offsets are band-keyed and never change — the DE buckets, ~3
1661+
* channels wide at 2.4 GHz, are the calibration a hop actually moves.
1662+
* The rollback snapshots are untouched — they record the pre-enable
1663+
* state, which these rewrites do not change. */
1664+
if (tssi && tssi->rate_offsets != *_fr_tssi_offsets) {
1665+
for (size_t i = 0; i < tssi->rate_offsets.size(); ++i)
1666+
set_bb(static_cast<uint16_t>(0x3a00 + i * 4), kDwordMask,
1667+
tssi->rate_offsets[i]);
1668+
_fr_tssi_offsets = tssi->rate_offsets;
1669+
}
1670+
if (de && !(*de == *_fr_tssi_de)) {
1671+
/* The prepare_tssi_offsets field sequence, minus its 0x4318
1672+
* tracking-disable write — the loop stays live across the rewrite. */
1673+
set_bb(0x433c, 0x0ff00000u, static_cast<uint8_t>(de->cck[0]));
1674+
set_bb(0x434c, 0x0ff00000u, static_cast<uint8_t>(de->cck[1]));
1675+
set_bb(0x4334, 0x0ff00000u, static_cast<uint8_t>(de->ht40[0]));
1676+
set_bb(0x4344, 0x0ff00000u, static_cast<uint8_t>(de->ht40[1]));
1677+
set_bb(0x43b0, 0x000000ffu, static_cast<uint8_t>(de->ofdm[0]));
1678+
set_bb(0x43b0, 0x0000ff00u, static_cast<uint8_t>(de->ht40[0]));
1679+
set_bb(0x43b0, 0x00ff0000u, static_cast<uint8_t>(de->ht40[0]));
1680+
set_bb(0x43b4, 0x0000ff00u, static_cast<uint8_t>(de->ofdm[1]));
1681+
set_bb(0x43b4, 0x000000ffu, static_cast<uint8_t>(de->ht40[1]));
1682+
set_bb(0x43b4, 0x00ff0000u, static_cast<uint8_t>(de->ht40[1]));
1683+
set_bb(0x43b4, 0xff000000u, static_cast<uint8_t>(de->ht40[1]));
1684+
set_bb(0x43b0, 0xff000000u, static_cast<uint8_t>(de->ht20[0]));
1685+
set_bb(0x43b8, 0x000000ffu, static_cast<uint8_t>(de->ht20[1]));
1686+
_fr_tssi_de = *de;
1687+
}
1688+
_fr_plan = *plan;
1689+
return true;
1690+
} catch (...) {
1691+
_fr_plan.reset();
1692+
_fr_rf18.reset();
1693+
_fr_rf19.reset();
1694+
throw;
1695+
}
1696+
}
1697+
15161698
bool Phy8733b::initialize(uint8_t cut, const EfuseInfo &efuse) {
15171699
if (!efuse.valid || efuse.rfe_type == 0xff || efuse.xtal == 0xff) {
15181700
_logger->error("RTL8733B PHY: refusing initialization without EFUSE data");

0 commit comments

Comments
 (0)