b43: AC-PHY - full 2069 VCO band cal + Ghidra-verified radio init structure Using a full Ghidra decompile of wlc_hybrid.o, ported the complete 2069 VCO band calibration (wl FUN_0019591e, run by switch_radio) which b43 was missing entirely, and mapped the radio-init function FUN_0019fb72 (RF-control + prefregs + version-gated bias enables + per-core analog loop) and its version paths. Hardware (clean boot): the VCO cal now COMPLETES (0x413 done bit, code=0x58) and the rx-iq est produces varying signed values (iq=0xcd ipwr=0xeb qpwr=-13) instead of the previously frozen d5/c6/04 -- the RX analog path now responds. RFPLL lock (0x90b) still pending; scan still empty. NOTE: radio state persists across module reloads -- must REBOOT the target for a valid VCO-cal/lock reading (module-reload tests gave false 0x413=0 results). Signed-off-by: René Rebe --- diff -ruN old/drivers/net/wireless/broadcom/b43/Kconfig new/drivers/net/wireless/broadcom/b43/Kconfig --- a/drivers/net/wireless/broadcom/b43/Kconfig 2026-07-16 12:03:22.137460972 +0200 +++ b/drivers/net/wireless/broadcom/b43/Kconfig 2026-07-16 12:03:22.138646825 +0200 @@ -149,14 +149,21 @@ Say N, this is BROKEN and crashes driver. config B43_PHY_AC - bool "Support for AC-PHY (802.11ac) devices (BROKEN)" - depends on B43 && B43_BCMA && BROKEN + bool "Support for AC-PHY (802.11ac) devices (EXPERIMENTAL)" + depends on B43 && B43_BCMA + select CORDIC help This PHY type can be found in the following chipsets: PCI: BCM4352, BCM4360 - Say N, this is BROKEN and crashes driver. - + Experimental bring-up reverse engineered from the Broadcom "wl" + driver: the PHY is detected, the analog core and 2069 radio are + powered up, the init/gain tables are loaded and the per-channel + synthesizer registers are programmed from the reversed chan_tuning + tables. The 2069 VCO calibration and the RX/TX calibration and + power-control pipeline are not implemented yet, so the radio may + not achieve PLL lock / pass traffic. Enable for development and + hardware bring-up testing only. Say N if unsure. # This config option automatically enables b43 LEDS support, # if it's possible. diff -ruN old/drivers/net/wireless/broadcom/b43/Makefile new/drivers/net/wireless/broadcom/b43/Makefile --- a/drivers/net/wireless/broadcom/b43/Makefile 2026-07-16 12:03:22.137456652 +0200 +++ b/drivers/net/wireless/broadcom/b43/Makefile 2026-07-16 12:03:22.138637255 +0200 @@ -15,6 +15,9 @@ b43-$(CONFIG_B43_PHY_HT) += radio_2059.o b43-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o b43-$(CONFIG_B43_PHY_AC) += phy_ac.o +b43-$(CONFIG_B43_PHY_AC) += radio_2069.o +b43-$(CONFIG_B43_PHY_AC) += tables_phy_ac.o +b43-$(CONFIG_B43_PHY_AC) += phy_ac_cal.o b43-y += sysfs.o b43-y += xmit.o b43-y += dma.o diff -ruN old/drivers/net/wireless/broadcom/b43/REVERSING-ac-phy.md new/drivers/net/wireless/broadcom/b43/REVERSING-ac-phy.md --- a/drivers/net/wireless/broadcom/b43/REVERSING-ac-phy.md 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/net/wireless/broadcom/b43/REVERSING-ac-phy.md 2026-07-16 12:03:22.138659507 +0200 @@ -0,0 +1,317 @@ +# b43 AC-PHY (BCM4360 / 2069 radio) reverse-engineering notes + +Target: `bcma` chip id `0x4360`, IEEE 802.11 core rev 42, PHY type 11 (AC) +rev 1, radio id `0x2069`. Reference: Broadcom "wl" hybrid driver, +`broadcom-wl/lib/wlc_hybrid.o_shipped` (x86-64, **not stripped**). + +All addresses below are `.text` offsets in that object. Disassemble with: + +``` +objdump -d -r --start-address=0x --stop-address=0x wlc_hybrid.o_shipped +``` + +## Register-access model (wl -> b43) + +| wl call | b43 equivalent | +|--------------------------------|-------------------------------------------------| +| `phy_reg_read(pi, r)` | `b43_phy_read(dev, r)` | +| `phy_reg_write(pi, r, v)` | `b43_phy_write(dev, r, v)` | +| `phy_reg_mod(pi, r, mask, v)` | `b43_phy_maskset(dev, r, ~mask, v & mask)` | +| `read_radio_reg(pi, r)` | `b43_radio_read(dev, r)` | +| `write_radio_reg(pi, r, v)` | `b43_radio_write(dev, r, v)` | +| `mod_radio_reg(pi, r, mask, v)`| `b43_radio_maskset(dev, r, ~mask, v & mask)` | + +`pi` layout offsets seen so far: `+0x160` phy_type (0xb = AC), `+0x164` +bandwidth/subtype, `+0x138` `pi_ac` sub-state pointer. + +## AC-PHY function-pointer table (set for `pi`, order = struct layout) + +Filled at the tail of `wlc_phy_attach_acphy` (`0xa194f`) as `movq $func, off(pi)`: + +| pi off | .text addr | role (confirmed via generic caller) | +|--------|-----------|---------------------------------------------------| +| 0x28 | 0xb018f | **init** (called via `*r13` in `wlc_phy_init`) | +| 0x38 | 0xa7089 | **chanspec_set** (called in `wlc_phy_chanspec_set`)| +| 0x30 | 0x8e77a | (in `wlc_phy_ac_caps`) | +| 0x40 | 0x9949f | table write helper | +| 0xc0 | 0x97e2b | `wlc_phy_rxcore_setstate_acphy` | +| 0xc8 | 0x92e67 | `wlc_phy_crs_min_pwr_cal_acphy` | +| 0xd0 | 0x99528 | table helper | +| 0xf8 | `wlc_phy_btc_adjust_acphy` | +| 0x100 | 0x9737d | `wlc_phy_txpower_sromlimit_get_acphy` | + +Both master routines (`0xb018f` init, `0xa7089` chanspec) are **static, no +symbol** — that is why there is no `wlc_phy_init_acphy` in `nm` output. + +## Ported so far (in `phy_ac.c` / `radio_2069.c`) + +- **Register accessors** — indirect via `B43_MMIO_PHY_CONTROL/DATA` and + `B43_MMIO_RADIO24_CONTROL/DATA`. Verified against the 16-bit reg addresses + wl uses (e.g. classifier `0x140`). +- **Classifier** (`wlc_phy_classifier_acphy`, `0x91258`) — reg `0x140`, + `(old & ~mask) | (val & mask)`. Full function transcribed. +- **software_rfkill / radio power-up** (`wlc_phy_switch_radio_acphy`, + `0xaa782`) — OFF path gates the PLL bits of the radio PU register; ON path + is `b43_radio_2069_init()`. Radio PU register is `0x80b` for chip + `0x4360/0x4352/0xa9c4/0xaa06`, else `0x80c`. Sequence reversed: + set `0x80,0x10,0x08,0x04,0x02` on PU reg; `0x10` on `0x97f`; + `0x01,0x100,0x10` on AFE `0x8ea` (core0; core1 = `0x8f2`); + `0x20,0x2000,0x4000` on PU reg; read-back; toggle PLL bits. +- **switch_analog** — wl's `wlc_phy_anacore` (`0xbaad1`) is a no-op for AC + (no case for phy_type 0xb), so the generic `B43_MMIO_PHY0` gate is used. +- **init** — CCA reset (BBCFG `0x4000` pulse) + classifier enable only. + +## SROM11 blocker (prerequisite for AGC gain + TX power) + +`wlc_phy_txpwr_srom11_read` (0xbf3e8) reads board RF params by NVRAM name +(`pdoffset40/80/2g40/cck ma0..2`, plus power targets / PA params / gains). These +feed both the RX AGC gain-limit computation and TX power control. + +**The kernel does not provide this data to b43:** +- `drivers/bcma/sprom.c` accepts SROM rev 8-11 (`revision < 8 || > 11`) but has + only an **r8 extractor** — every `SPEX()` uses `SSB_SPROM8_*` offsets. For a + rev-11 SROM it reads the raw words but extracts only SROM8-layout fields. +- `struct ssb_sprom` (include/linux/ssb/ssb.h) has **no SROM11/AC fields** + (no `pdoffset*`, no AC power targets). +- The raw SROM words live in a local array in `bcma_sprom_get()` and are **not + exposed** to drivers. + +So porting the parser is not a self-contained b43 change. Options: +1. Extend `bcma/sprom.c` with an r11 extractor + new `ssb_sprom` fields — proper + but touches shared bcma/ssb infra used by brcmsmac etc. (risk to stable code). +2. b43 re-reads raw SROM/OTP itself and parses SROM11 — isolated to the + experimental AC code, but duplicates SROM-read logic. +3. **Bring-up shortcut:** dump this board's NVRAM from the running system and + hardcode the params as a board default; get AGC/TX working, generalize later. + (The card is in hand; this unblocks development immediately.) + +## Roadmap to traffic (BCM4360, radio 2069 rev 4) + +Status: attaches, firmware loads, runs (PIO). Controller-restart loop is the +TX-badness watchdog and will stop once RX/TX actually work. DMA fatal error is +a separate `dma.c` issue; PIO is the workaround. + +Ordered by dependency; [S]=static/extractable, [HW]=needs the card in the loop. + +**Phase 1 — finish channel tuning [S, mostly done]** + - Masked/PHY-side tuning words 8/9/11 (struct 0x10/0x12/0x16) and 22..27 + (0x2c..0x36): drive PHY ctrl reg 0x728 (radio-load sequencer, with delays) + and masked radio writes. Intricate; validate reg values against a card + readback. + - rev4 extra struct words 41..57: extra per-channel radio writes. + +**Phase 2 — RX front-end (goal: passive scan / see beacons)** + - RX-path enable — DONE: `b43_phy_ac_ofdm_crs()` (regs 0x2ed/0x2f1/0x2f5/0x2f9 + bit 0x10) + full classifier (CCK+OFDM+waited), via `b43_phy_ac_rx_enable()` + in init (mirrors `wlc_phy_stay_in_carriersearch_acphy(pi,false)`, + `wlc_phy_ofdm_crs_acphy` 0x8fa8e). + - RX gain / AGC — remaining, computed (no static blobs): the gain-limit / + gain-index tables are built at runtime. `wlc_phy_calc_extra_init_gain_acphy` + (0x97f10) reads gain table id 7 and programs init gain; + `wlc_phy_rfctrl_override_rxgain_acphy` (0x98373) forces gain codes to the + RF-override regs (gate 0x19e). These are AGC — validate against the card + (does passive scan see beacons with default gain? if not, port init-gain). + +**Phase 3 — minimal calibration for a usable RX/TX [HW]** + - `wlc_phy_cals_acphy` (0xb13b5, 1260 B) orchestrator + - `wlc_phy_rx_iq_est_acphy` (0x932e6, 1321 B) — RX IQ imbalance + - These measure real RF and converge; develop against the card. + +**Phase 4 — TX path (goal: active scan / associate)** + - TX gain table (DONE) + `wlc_phy_txpwrctrl_enable_acphy` (0x906e6, 211 B), + `wlc_phy_txpwr_by_index_acphy` (0x9cdf8, 347 B) [S] + TSSI feedback [HW] + - `wlc_phy_populate_tx_loft_comp_tbl_acphy` (0x9ca6e, 576 B) — LO leakage [HW] + - PAPD cal, `wlc_phy_tempsense_acphy` (0xa317c, 5667 B) [HW] + +Fastest observable milestone = Phase 1 + Phase 2 → passive scan should start +returning beacons, which confirms the RX chain end-to-end before the cal work. + +## Hardware testing + +Build/enable: `CONFIG_B43_PHY_AC=y` (no longer depends on BROKEN). +The bring-up runs automatically via `b43_phy_init` in this order: +`switch_analog(true)` -> `software_rfkill(false)` = `b43_radio_2069_init` +(radio power-up) -> `ops->init` (CCA reset, `b43_phy_ac_tables_init`, +classifier) -> `b43_switch_channel` -> `switch_channel` op +(`b43_radio_2069_tune_chan` + `b43_radio_2069_rfpll_setup` + +`b43_phy_ac_upload_tx_gain_table`). + +What to observe on the card: +1. Probe should now pass ("Found PHY: ... AC" instead of -EOPNOTSUPP). +2. After a channel set, read back the 2069 PLL status / VCO-cal registers + (`0x400|0x14`, `0x400|0x15`, PLL lock bit) to see if the synth locks. +3. If it does not lock, the missing piece is the **VCO calibration loop** + (`wlc_2069_rfpll_150khz+0x600..`, fills radio `0x8c7/0x8c8/0x8ca`) and the + masked tuning words (8/9/11, 22..27). Those are the next things to port. +4. `ipa=true` is assumed for the gain table; if the board is ePA the wrong + table is loaded (SROM `extpagain`, not parsed yet). + +Not yet present (so no traffic even if the PLL locks): RX gain, TX power +control, and the RX/TX calibration pipeline. Unlike everything ported so far, +these are **closed-loop calibration algorithms**, not static data: + - RX gain is computed (`wlc_phy_calc_extra_init_gain_acphy` `0x97f10`, + `wlc_phy_rfctrl_override_rxgain_acphy` `0x98373`), not a table. + - TX power control (`wlc_phy_txpwrctrl_enable_acphy` `0x906e6`, + `wlc_phy_txpwrctrl_set_target_acphy` `0x8fa47`) reads TSSI feedback. + - Cal pipeline (`wlc_phy_cals_acphy` `0xb13b5`) drives RX-IQ + (`wlc_phy_rx_iq_est_acphy` `0x932e6`), TX-LOFT + (`wlc_phy_populate_tx_loft_comp_tbl_acphy` `0x9ca6e`), PAPD, and + tempsense (`wlc_phy_tempsense_acphy` `0xa317c`) — each measures real RF + and adjusts. +These need the hardware in the loop: they measure the radio's response and +converge. They cannot be developed or validated purely by static RE, so this +is where bench work replaces disassembly. The deterministic bring-up + PLL-lock +path is complete up to here. + +## Table engine + init tables (DONE — `tables_phy_ac.c`) + +- **Engine** — `wlc_phy_write_table_ext` (`0xb6959`) / `wlc_phy_read_table_ext` + (`0xb6770`). AC uses separate ID (`0x00d`) and OFFSET (`0x00e`) registers plus + three data regs (`0x00f/0x010/0x011`). OFFSET auto-increments per entry, so it + is written once per bulk transfer. Width handling: 8/16-bit → DATA1; 32-bit → + DATA2 = hi16, DATA1 = lo16. (48/64-bit widths exist for other tables but are + not needed by the rev0 set.) +- **Loader** — mirrors the wl init loop (static at `~0xa09fb`) that replays + every `acphytbl_info_rev0` descriptor in order. Descriptor layout (24 bytes): + `{ void *data; u32 count; u16 id; u32 offset; u32 width_bits }`. 23 tables, + ids 1/2/3/4/5 and the 64/96/128-family LUTs. Data blobs extracted straight + from the object (`acphy_*_rev0`) with `scripts`-style dumping. +- **Per-channel table** — `chan_tuning_20691rev_1` (`.data 0x150250`, 308 B) is + a `{u16 channel, u16 freq_mhz}` array (ch1=2412 … ch36=5180 … ch184=4920). + Extracted into `b43_phy_ac_chantbl_2069rev1` + `b43_phy_ac_chan_lookup()`. + `switch_channel` now validates against it and selects the band. +- **TX gain tables** — `acphy_txgain_{ipa,epa}_{2g,5g}_2069rev0` (768 B each). + Uploaded to table **id 0x20, width 48-bit, 128 entries** (call site at the + tail of the txgain selector, `~0x9e6f9`; selector switches on radio rev at + `pi+0x16c`). Each entry is three u16 words `{DATA3, DATA2, DATA1}`. Needed a + new **48-bit path in the table engine**: high word via the addressed DATA3 + write, then the remaining two straight to the PHY data port (auto-steps to + DATA2/DATA1) — reversed from `write_table_ext +0x11e`. Ported as + `b43_phy_ac_upload_tx_gain_table(dev, ghz5, ipa)`; only rev0 tables so far. + iPA/ePA choice is a board (SROM extpagain) property, passed in until the + SROM11 parse is ported. + +## Synthesizer / channel tuning (PORTED — table-driven, not computed) + +**Correction to an earlier assumption:** there is *no* fractional-N divider +arithmetic to reverse. AC channel tuning is a **table lookup**: the frequency is +used only for spurmode, and the synthesizer registers come pre-computed from a +per-channel table. This makes it fully extractable (like the gain tables). + +**Mechanism** (channel-tune master `.text+0xa7089`): +1. Call the channel-info lookup (`wlc_phy_get_spurmode+0x231`, i.e. + `.text+0x8e9b1`) with `(pi, channel, &freq, &p0..&p3)`. It selects a + `chan_tuning_2069rev_*` table by radio rev (`pi+0x16c`, jump table + `.rodata+0x2cc0f0` for rev 0-10), bandwidth (`pi+0x17e & 0xc000`, picks + `_40`), LP mode (`pi+0x8e5`, picks `_lp`) and 40 MHz xtal (`pi+0xc24`), + then finds the channel row and returns pointers to it. +2. Copy the row's words into the 2069 radio registers. + +**Radio rev is read at probe** (`Found Radio: … Revision N`). The rev0 → +`rev_16_17` mapping was an assumption; a real BCM4360 here reports **radio +rev 4**, which selects **`chan_tuning_2069rev4`** (77 × 116 bytes = 58 u16 +words/row). That is the table now in tree. rev3/rev4 split is on radio version +(`pi+0x16e`). Other revs need their own table extracted (same script). + +NOTE on the register map: the copy loop dispatches the radio register per chip +id; for some words there are four `cmp` (…/0xaa06) and the 0x4360 value is the +`je` target — a naive "last mov before the call" mis-reads those. The map below +was extracted by resolving each `cmp $0x4360 → je TARGET → esi@TARGET` and +cross-checked (no duplicate registers). + +Original rev0 layout (for reference): 77 × 94 bytes = 47 u16 words per row. +`word[0]=channel, word[1]=freq_mhz, word[2..]=register values.` +(GE_25 tables are 96 B/row; all are 77 channels.) + +**Word → 2069 register map** (chip 0x4360 bank), reversed from the copy loop at +`.text+0xa73d6..0xaa100`: + +| word | reg | word | reg | word | reg | word | reg | +|------|-----|------|-----|------|-----|------|-----| +| 2 |0x8e0| 7 |0x8e7| 16 |0x8da| 30 |0x629| +| 3 |0x8e1| 10 |0x8c5| 17 |0x8d7| 31 |0x65b| +| 4 |0x8dd| 12 |0x8eb| 18 |0x885| 32 |0x65e| +| 5 |0x8dc| 13 |0x8d6| 19 |0x887| 33 |0x668| +| 6 |0x8e6| 14 |0x113| 20 |0x8d9| 34..39 |0x11a,0x11b,0x115,0x630,0x65c,0x662| +| | | 15 |0x8db| 21 |0x8d8| 28/29 |0x8cb,0x112| + +Ported: `b43_radio_2069_tune_chan()` (register map above) + +`b43_chan_tuning_2069rev_16_17[77][47]` + `b43_phy_ac_chan_tuning_lookup()`; +wired into `switch_channel`. Verified byte-exact vs the binary (ch14→2484 MHz +row matches). + +**Remaining on tuning:** words 8/9/11 and 22..27 drive masked radio writes and +PHY-side registers (`0x728` region) not yet in the direct-copy map; other radio +revs / bandwidths need their tables extracted (same script); and the constant +RFPLL setup + VCO cal (`wlc_2069_rfpll_150khz`, `.text+0x9576e`) still needs +porting. Final PLL lock wants hardware validation, but the hard "unknown math" +worry is gone — it is all data + copies. + +**Call chain** (channel-tune master `.text+0xa7089`): + +1. Find the channel row in `chan_tuning_20691rev_1` → `freq_mhz` + (`movzwl chan_tuning+0x2(,idx,4)` at `0xaa760`). +2. `wlc_phy_chanspec_radio_set` — records the chanspec in `pi`. +3. Fixed SDM / loop-filter writes (channel independent), verified constants: + `0x98c=0xffff, 0x98d=0x1df3, 0x98e=0x1ffc, 0x98f=0x0078, 0x18b=0xffff` + (tune master `~0xaa150..0xaa220`). +4. `wlc_2069_rfpll_150khz` (`0x9576e`, ~6 KB) — the RFPLL/VCO programmer. +5. `wlc_phy_resetcca_acphy`, spurmode (`wlc_phy_get/setup_spurmode`), + `wlc_phy_stay_in_carriersearch_acphy` bracketing, then txpwrctrl. + +**Register banks** (chip 0x4360 branch of every `chipid` dispatch): +- RFPLL: `0x8c7 0x8c8 0x8c9 0x8ca 0x8cc 0x8cf 0x8d0` (+ AFE `0x8ea 0x8ed`, + core-1 mirrors `0x8f2 0x8f5`). Other chips use `0x8d1 0x8d2 0x8d4`. +- VCO cal: `0x010..0x019` OR'd with core-select `0x400` + (e.g. read `0x400|0x14`, `0x400|0x15` for the cal delta at `0x95e8e`). + +**Data flow of the divider:** +- Reference = 40 MHz crystal = `0x2625a00` Hz, cached at `pi+0xc24` + (set in `wlc_phy_attach_acphy` `0xa1c81`; compared at `0xaa245`). +- `wlc_2069_rfpll_150khz` reads `pi+0xc24` (`0x95981`) and builds the SDM + words with `shl $9` (×512 fractional scaling) at `0x95bdd` etc. +- The VCO-cal correction is `(rd(0x400|0x15) - rd(0x400|0x14)) * K >> 8` + written to `pi_ac+0x339/0x33a` (`0x95e8e..0x95ea8`). + +**Why it is not ported yet:** the fractional-N word is a reciprocal-multiply of +`freq_mhz` against the 40 MHz reference, threaded through the chip-conditional +RFPLL bank and a VCO-cal feedback loop. Transcribing it from disassembly risks a +silently-wrong divider (no PLL lock, no way to tell right from wrong without the +card). This is the point where the port needs hardware in the loop: program the +mapped registers, read back the VCO-cal / lock status, and iterate. The register +map above and `radio_2069.h` give everything needed to start that loop. + +## NOT yet ported (blocks actual traffic) + +Ordered roughly by dependency. These need a real BCM4360 to validate. + +1. **2069 synthesizer / channel tune** — master at `.text+0xa7089` + (chanspec_set). The band select + `chan_tuning_20691rev_1` lookup are ported; + the remaining ~14 KB is the PLL/VCO programming that turns `freq_mhz` into + radio register writes (plus spurmode via `wlc_phy_get_spurmode` / + `wlc_phy_setup_spurmode`). This is the hardest RF piece and needs hardware. +2. **Master PHY init body** — `.text+0xb018f`. After the early + `phy_reg_mod(0x1b0,...)` / bw-set it calls into radio init, table loads and + the cal chain. Trace its `call` targets to enumerate the sub-init steps. + (The table-load sub-step is already ported — see below.) +3. **RX gain / gainlimit tables** — the TX gain tables (id 0x20) are done (see + above). RX-side gain/gainlimit tables are loaded separately; find them via + the remaining `wlc_phy_table_write_acphy` call sites and the `dot11*gain*` + `.rodata` blobs. Other radio revs (rev4/16/17/18/33_37) also remain if the + target board reports a non-zero radio rev at `pi+0x16c`. +4. **Calibration pipeline** — `wlc_phy_cals_acphy` (`0xb13b5`), + `wlc_phy_rx_iq_est_acphy` (`0x932e6`), + `wlc_phy_populate_tx_loft_comp_tbl_acphy` (`0x9ca6e`), + `wlc_phy_tempsense_acphy` (`0xa317c`). +5. **TX power control** — `wlc_phy_txpwrctrl_enable_acphy` (`0x906e6`), + `wlc_phy_set_txpwr_by_index_acphy` (`0x9ccae`), + `wlc_phy_txpower_sromlimit_get_acphy` (`0x9737d`). SROM11 layout parsed by + `wlc_phy_txpwr_srom11_read` (`0xbf3e8`) — needed for board limits. + +## Suggested next step + +The init-table loader and per-channel table are in place, so the next blocker +is target #1: the 2069 synthesizer programming in `.text+0xa7089`. Trace the +radio-register writes after the `chan_tuning` lookup, plug `freq_mhz` into the +PLL math, then bring the card up on a single 2 GHz channel and watch for RX +energy / a beacon before tackling gain tables and calibration. diff -ruN old/drivers/net/wireless/broadcom/b43/phy_ac.c new/drivers/net/wireless/broadcom/b43/phy_ac.c --- a/drivers/net/wireless/broadcom/b43/phy_ac.c 2026-07-16 12:03:22.137443702 +0200 +++ b/drivers/net/wireless/broadcom/b43/phy_ac.c 2026-07-16 17:43:26.257558767 +0200 @@ -4,10 +4,78 @@ * IEEE 802.11ac AC-PHY support * * Copyright (c) 2015 Rafał Miłecki + * + * PHY bring-up (init / analog / rfkill / channel) reverse engineered from the + * Broadcom "wl" hybrid driver (broadcom-wl/lib/wlc_hybrid.o_shipped). The + * relevant wl routines are named in the comments; see REVERSING-ac-phy.md for + * the disassembly notes and the remaining work (radio tuning, gain tables and + * the calibration pipeline). */ +#include + #include "b43.h" +#include "main.h" #include "phy_ac.h" +#include "radio_2069.h" +#include "tables_phy_ac.h" +#include "phy_ac_cal.h" + +/* + * Bring-up debugfs poke interface (/sys/kernel/debug/b43_ac/poke). + * write "ADDR" -> read radio[ADDR], remember value + * write "ADDR VAL" -> write radio[ADDR] = VAL + * write "pADDR" -> read phy[ADDR] + * write "pADDR VAL" -> write phy[ADDR] = VAL + * read -> last read value, hex + * All values hex. Lets us hunt the RF-PLL lock live without rebuilds. + */ +static struct b43_wldev *b43_ac_poke_dev; +static u16 b43_ac_poke_last; + +static ssize_t b43_ac_poke_write(struct file *f, const char __user *ubuf, + size_t len, loff_t *off) +{ + char buf[32]; + unsigned int addr, val; + bool phy = false; + const char *p = buf; + + if (len >= sizeof(buf) || !b43_ac_poke_dev) + return -EINVAL; + if (copy_from_user(buf, ubuf, len)) + return -EFAULT; + buf[len] = 0; + if (*p == 'p') { phy = true; p++; } + + if (sscanf(p, "%x %x", &addr, &val) == 2) { + if (phy) + b43_phy_write(b43_ac_poke_dev, addr, val); + else + b43_radio_write(b43_ac_poke_dev, addr, val); + } else if (sscanf(p, "%x", &addr) == 1) { + b43_ac_poke_last = phy ? b43_phy_read(b43_ac_poke_dev, addr) : + b43_radio_read(b43_ac_poke_dev, addr); + } else { + return -EINVAL; + } + return len; +} + +static ssize_t b43_ac_poke_read(struct file *f, char __user *ubuf, + size_t len, loff_t *off) +{ + char buf[16]; + int n = scnprintf(buf, sizeof(buf), "0x%04x\n", b43_ac_poke_last); + + return simple_read_from_buffer(ubuf, len, off, buf, n); +} + +static const struct file_operations b43_ac_poke_fops = { + .write = b43_ac_poke_write, + .read = b43_ac_poke_read, + .open = simple_open, +}; /************************************************** * Basic PHY ops @@ -34,6 +102,14 @@ phy->ac = NULL; } +static void b43_phy_ac_op_prepare_structs(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_ac *phy_ac = phy->ac; + + memset(phy_ac, 0, sizeof(*phy_ac)); +} + static void b43_phy_ac_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, u16 set) { @@ -62,6 +138,803 @@ return 36; } +/************************************************** + * Classifier / CCA (reversed: wlc_phy_classifier_acphy) + **************************************************/ + +/* + * wlc_phy_classifier_acphy(pi, mask, val): reg 0x140 gets + * (old & ~mask) | (val & mask) + * A mask of 0 is a pure read of the current classifier control. + */ +static u16 b43_phy_ac_classifier(struct b43_wldev *dev, u16 mask, u16 val) +{ + u16 tmp = b43_phy_read(dev, B43_PHY_AC_CLASSCTL); + + if (mask) { + tmp = (tmp & ~mask) | (val & mask); + b43_phy_write(dev, B43_PHY_AC_CLASSCTL, tmp); + } + + return tmp & (B43_PHY_AC_CLASSCTL_CCKEN | + B43_PHY_AC_CLASSCTL_OFDMEN | + B43_PHY_AC_CLASSCTL_WAITEDEN); +} + +/************************************************** + * Board RF parameters (SROM11) + **************************************************/ + +/* + * Populate the board RF parameters. wl reads these from NVRAM + * (wlc_phy_txpwr_srom11_read); the kernel bcma SPROM parser only gives us the + * SROM8-layout subset, so extpa_gain and the power targets come from + * struct ssb_sprom and the SROM11-only power-detector offsets default to 0. + */ +static void b43_phy_ac_srom_read(struct b43_wldev *dev) +{ + struct b43_phy_ac_srom *s = &dev->phy.ac->srom; + struct ssb_sprom *sprom = dev->dev->bus_sprom; + int i; + + memset(s, 0, sizeof(*s)); + + s->extpa_gain_2g = sprom->fem.ghz2.extpa_gain; + s->extpa_gain_5g = sprom->fem.ghz5.extpa_gain; + s->extpa_gain_valid = true; + + for (i = 0; i < 3; i++) { + s->maxpwr_2g[i] = sprom->core_pwr_info[i].maxpwr_2g; + s->maxpwr_5g[i] = sprom->core_pwr_info[i].maxpwr_5g; + } + + /* pdoffset_* stay 0: no SROM11 power-detector correction available. */ +} + +/************************************************** + * RX front-end + **************************************************/ + +/* + * Enable/disable the OFDM carrier-sense engine (wlc_phy_ofdm_crs_acphy): + * set/clear bit 0x10 in PHY regs 0x2ed/0x2f1/0x2f5/0x2f9. + */ +static void b43_phy_ac_ofdm_crs(struct b43_wldev *dev, bool enable) +{ + u16 val = enable ? 0x0010 : 0x0000; + + b43_phy_maskset(dev, 0x2ed, (u16)~0x0010, val); + b43_phy_maskset(dev, 0x2f1, (u16)~0x0010, val); + b43_phy_maskset(dev, 0x2f5, (u16)~0x0010, val); + b43_phy_maskset(dev, 0x2f9, (u16)~0x0010, val); +} + +/* + * Force the RX gain via the RF-control override, reversed from + * wlc_phy_rfctrl_override_rxgain_acphy. Per core the gain code words go to + * PHY regs 0x722 / 0x730 / 0x731 / 0x000 (+ core*0x200), then the override is + * enabled via the gate reg 0x19e (bit 2). + * + * gains[core] = { code0, code1, code2, code3 } are the LNA/mixer/VGA gain + * codes. In wl these come from the computed gain-limit tables (SROM + radio + * characteristics); here they are supplied by the caller so a bring-up value + * can be forced and tuned on the bench. + */ +static void __maybe_unused +b43_phy_ac_rxgain_override(struct b43_wldev *dev, const u16 gains[3][4]) +{ + unsigned int core; + + for (core = 0; core < 3; core++) { + u16 base = core * 0x200; + + b43_phy_write(dev, base + 0x722, gains[core][0]); + b43_phy_write(dev, base + 0x730, gains[core][1]); + b43_phy_write(dev, base + 0x731, gains[core][2]); + b43_phy_write(dev, base + 0x000, gains[core][3]); + } + + /* Enable the RX gain override (gate 0x19e bit 2). */ + b43_phy_maskset(dev, 0x19e, (u16)~0x0002, 0x0002); +} + +/* + * Trigger the AC-PHY RF sequencer (wlc_phy_force_rfseq_acphy, wl 0x97b9c). + * Without this the RX/TX chains are never sequenced into their operating + * state, so the ADC never streams samples (RX deaf). + * + * 'trigger' selects the sequence; the hardware trigger bit is looked up from + * the wl jump table (NOT 1<0x01 1 TX2RX->0x02 2 RESET2RX->0x20 + * 3 UPDATEGAINH->0x04 4 UPDATEGAINL->0x08 5 UPDATEGAINU->0x10 + * The routine sets the override gate (0x19e bits 0/1), OR-sets 0x0003 into + * 0x400 and the trigger bit into 0x402, then polls 0x403 until the sequencer + * clears the bit (idle), and finally restores 0x400 / 0x19e. + */ +static void b43_phy_ac_force_rfseq(struct b43_wldev *dev, u8 trigger) +{ + static const u16 trig_bits[6] = { + 0x0001, 0x0002, 0x0020, 0x0004, 0x0008, 0x0010, + }; + u16 save400, save19e, bit; + int i; + + if (trigger > 5) + return; + bit = trig_bits[trigger]; + + save400 = b43_phy_read(dev, 0x400); + save19e = b43_phy_read(dev, 0x19e); + + b43_phy_maskset(dev, 0x19e, (u16)~0x0002, 0x0002); + b43_phy_maskset(dev, 0x19e, (u16)~0x0001, 0x0001); + b43_phy_set(dev, 0x400, 0x0003); + b43_phy_set(dev, 0x402, bit); + + /* Wait for the sequencer to go idle (status bit in 0x403 clears). wl + * spins ~20000 times with a 10us delay (~200ms worst case). + */ + for (i = 0; i < 20000; i++) { + if (!(b43_phy_read(dev, 0x403) & bit)) + break; + udelay(10); + } + if (i == 20000) + b43err(dev->wl, "AC: RF sequencer trigger %u timeout\n", trigger); + + b43_phy_write(dev, 0x400, save400); + b43_phy_write(dev, 0x19e, save19e); +} + +/* + * Set the active RX cores (wlc_phy_rxcore_setstate_acphy, wl 0x97ce5). Programs + * the core-enable fields in PHY regs 0x160 / 0x401 / 0x400 and pulses the RF + * sequencer (RX2TX then TX2RX) so the RX chain / ADC actually start. coremask + * selects cores (bit0=core0 ...). Runs with the MAC suspended. + * + * wl caches the desired core masks in pi (bytes 0xa6/0xa7); for bring-up we + * drive both from the passed coremask. + */ +static void b43_phy_ac_rxcore_setstate(struct b43_wldev *dev, u8 coremask) +{ + u16 save400, save401; + + b43_mac_suspend(dev); + + save401 = b43_phy_read(dev, 0x401); + save400 = b43_phy_read(dev, 0x400); + + b43_phy_maskset(dev, 0x160, (u16)~0x0007, coremask & 0x0007); + b43_phy_maskset(dev, 0x401, (u16)~0x0070, (coremask << 4) & 0x0070); + b43_phy_maskset(dev, 0x401, (u16)~0x7000, 0x7000); + b43_phy_maskset(dev, 0x401, (u16)~0x0007, 0x0000); + b43_phy_maskset(dev, 0x400, (u16)~0x0001, 0x0001); + + b43_phy_ac_force_rfseq(dev, 0); + b43_phy_ac_force_rfseq(dev, 1); + + b43_phy_maskset(dev, 0x401, (u16)~0x0007, coremask & 0x0007); + b43_phy_maskset(dev, 0x401, (u16)~0x7000, save401 & 0x7000); + b43_phy_write(dev, 0x400, save400); + + b43_mac_enable(dev); +} + +/* + * CCA reset (wlc_phy_resetcca_acphy, wl 0x973fb), faithful port of the + * PHY-rev-1 path (revs 2/5/6 take a longer path with extra 0x19e toggles). + * The RSTCCA pulse on BBCFG (reg 0x001 bit 0x4000) only propagates while the + * PHY clock is forced (FGC) -- wl brackets the pulse in phyclk_fgc(1)/(0); + * the previous plain set/mask pulse lacked that and the value restore. + */ +static void b43_phy_ac_resetcca(struct b43_wldev *dev) +{ + u16 bbcfg; + + b43_phy_force_clock(dev, true); + bbcfg = b43_phy_read(dev, B43_PHY_AC_BBCFG); + b43_phy_write(dev, B43_PHY_AC_BBCFG, bbcfg | B43_PHY_AC_BBCFG_RSTCCA); + udelay(1); + b43_phy_write(dev, B43_PHY_AC_BBCFG, bbcfg & ~B43_PHY_AC_BBCFG_RSTCCA); + b43_phy_force_clock(dev, false); + udelay(2); +} + +/* + * RX baseband / ADC / gain init block, reversed faithfully from the AC-PHY + * init static (wl set_analog_tx_lpf+0x32a7, .text 0xa0be4). This is the block + * that was missing: it configures the digital front-end (0x025/0x026/0x1ed/ + * 0x1f2 AFE/ADC), the RF-sequencer mode (0x176), the per-core CRS thresholds + * (0x2eb..0x2f9), the RX gain/bias fields (0x2d6/0x2d7/0x2e0) and assorted + * baseband regs. Without it the RX ADC path stays unconfigured and idle. + * + * wl guards the very first write (0x3c4) behind pi->bw != 80/160MHz; we take + * the 20MHz path (scan/HT20), which is the fall-through in the binary. + */ +static void b43_phy_ac_init_rx_baseband(struct b43_wldev *dev) +{ + b43_phy_set(dev, 0x19e, 0x01c0); + b43_phy_write(dev, 0x3c4, 0x0668); + b43_phy_set(dev, 0x19e, 0x0200); + b43_phy_mask(dev, 0x19e, (u16)~0x003c); + b43_phy_set(dev, 0x19e, 0x0001); + b43_phy_maskset(dev, 0x19e, (u16)~0x003c, 0x0010); + b43_phy_write(dev, 0x400, 0x0000); + b43_phy_write(dev, 0x1f2, 0x00c8); + b43_phy_write(dev, 0x026, 0x0092); + b43_phy_write(dev, 0x1ed, 0x0050); + b43_phy_write(dev, 0x025, 0x0030); + b43_phy_mask(dev, 0x40f, (u16)~0x0200); + b43_phy_mask(dev, 0x2f1, (u16)~0x0020); + b43_phy_mask(dev, 0x2ed, (u16)~0x0020); + b43_phy_mask(dev, 0x2f9, (u16)~0x0020); + b43_phy_mask(dev, 0x2f5, (u16)~0x0020); + b43_phy_maskset(dev, 0x2ef, (u16)~0x00ff, 0x0055); + b43_phy_maskset(dev, 0x2eb, (u16)~0x00ff, 0x0055); + b43_phy_maskset(dev, 0x2f7, (u16)~0x00ff, 0x0055); + b43_phy_maskset(dev, 0x2f3, (u16)~0x00ff, 0x0055); + b43_phy_maskset(dev, 0x2ef, (u16)~0x00ff, 0x000a); + b43_phy_maskset(dev, 0x2eb, (u16)~0x00ff, 0x004d); + b43_phy_maskset(dev, 0x2f7, (u16)~0x00ff, 0x004d); + b43_phy_maskset(dev, 0x2f3, (u16)~0x00ff, 0x004d); + b43_phy_write(dev, 0x31c, 0x0080); + b43_phy_write(dev, 0x31e, 0x0080); + b43_phy_write(dev, 0x31d, 0x0080); + b43_phy_write(dev, 0x31f, 0x0080); + b43_phy_write(dev, 0x1e1, 0x0040); + b43_phy_write(dev, 0x1e2, 0x005c); + b43_phy_write(dev, 0x1e3, 0x003a); + b43_phy_write(dev, 0x1e3, 0x0048); + b43_phy_write(dev, 0x197, 0x0018); + b43_phy_mask(dev, 0x29e, (u16)~0x0001); + b43_phy_set(dev, 0x29d, 0x0040); + b43_phy_mask(dev, 0x363, (u16)~0x03ff); + b43_phy_mask(dev, 0x176, (u16)~0x0001); + b43_phy_set(dev, 0x176, 0x0002); + b43_phy_set(dev, 0x176, 0x0004); + b43_phy_set(dev, 0x164, 0x2000); + b43_phy_write(dev, 0x401, 0x1111); + b43_phy_write(dev, 0x1b0, 0x9ee1); + b43_phy_maskset(dev, 0x2e0, (u16)~0x00f0, 0x00b0); + b43_phy_maskset(dev, 0x2e0, (u16)~0x000f, 0x000a); + b43_phy_maskset(dev, 0x2d7, (u16)~0x0f00, 0x0700); + b43_phy_maskset(dev, 0x2d7, (u16)~0x00f0, 0x0070); + b43_phy_maskset(dev, 0x2d7, (u16)~0x000f, 0x0007); + b43_phy_maskset(dev, 0x2d6, (u16)~0xf000, 0x7000); + b43_phy_maskset(dev, 0x2d6, (u16)~0x0f00, 0x0700); + b43_phy_maskset(dev, 0x2d6, (u16)~0x00f0, 0x0030); + b43_phy_maskset(dev, 0x2d6, (u16)~0x000f, 0x0002); + b43_phy_maskset(dev, 0x2d7, (u16)~0x0f00, 0x0700); + b43_phy_maskset(dev, 0x2d7, (u16)~0x00f0, 0x0070); + b43_phy_maskset(dev, 0x2d7, (u16)~0x000f, 0x0007); + b43_phy_maskset(dev, 0x2d6, (u16)~0xf000, 0x7000); + b43_phy_maskset(dev, 0x2d6, (u16)~0x0f00, 0x0700); + b43_phy_maskset(dev, 0x2d6, (u16)~0x00f0, 0x0030); + b43_phy_maskset(dev, 0x2d6, (u16)~0x000f, 0x0002); + b43_phy_write(dev, 0x400, 0x0000); + b43_phy_mask(dev, 0x1ca, (u16)~0x1000); +} + +/* + * Take the PHY out of "stay in carrier search" (deaf) into normal RX, mirroring + * wlc_phy_stay_in_carriersearch_acphy(pi, false): restore the full classifier + * (CCK + OFDM + waited) and enable OFDM carrier sense. + */ +static void b43_phy_ac_rx_enable(struct b43_wldev *dev) +{ + b43_phy_ac_classifier(dev, B43_PHY_AC_CLASSCTL_CCKEN | + B43_PHY_AC_CLASSCTL_OFDMEN | + B43_PHY_AC_CLASSCTL_WAITEDEN, + B43_PHY_AC_CLASSCTL_CCKEN | + B43_PHY_AC_CLASSCTL_OFDMEN | + B43_PHY_AC_CLASSCTL_WAITEDEN); + b43_phy_ac_ofdm_crs(dev, true); +} + +/************************************************** + * TX power + **************************************************/ + +/* + * Enable/disable the hardware TX power-control loop + * (wlc_phy_txpwrctrl_enable_acphy): set/clear bits 0xe000 (per-core) in PHY + * reg 0x70. The closed loop needs the board power targets / pdoffsets (SROM11, + * not fully available); for bring-up prefer open-loop txpwr-by-index, which + * applies the loaded TX gain table (id 0x20) at a fixed index into the active + * table id 7 (wl: wlc_phy_txpwr_by_index_acphy). + */ +static void __maybe_unused +b43_phy_ac_txpwrctrl_enable(struct b43_wldev *dev, bool enable) +{ + b43_phy_maskset(dev, 0x70, (u16)~0xe000, enable ? 0xe000 : 0); +} + +/* wlc_phy_pwrctrl_shortwindow_upd_acphy: TX power averaging window (reg 0x71). */ +static void __maybe_unused +b43_phy_ac_pwrctrl_shortwindow(struct b43_wldev *dev, bool shortwin) +{ + b43_phy_maskset(dev, 0x71, (u16)~0x0700, shortwin ? 0x0100 : 0x0400); +} + +/* wlc_phy_txpwrctrl_set_target_acphy: per-core TX power target (0xff field). */ +static void __maybe_unused +b43_phy_ac_txpwr_set_target(struct b43_wldev *dev, u8 target) +{ + b43_phy_maskset(dev, 0x646, (u16)~0x00ff, target); + b43_phy_maskset(dev, 0x846, (u16)~0x00ff, target); + b43_phy_maskset(dev, 0xa46, (u16)~0x00ff, target); +} + +/************************************************** + * Analog / RF kill + **************************************************/ + +/* + * For the AC-PHY wl's wlc_phy_anacore() is a no-op (the analog core is brought + * up inside the radio power-up), so we fall back to the generic AFE gate that + * every other b43 PHY uses via B43_MMIO_PHY0. + */ +static void b43_phy_ac_op_switch_analog(struct b43_wldev *dev, bool on) +{ + b43_phyop_switch_analog_generic(dev, on); +} + +/* + * Reversed from wlc_phy_switch_radio_acphy(). The OFF path just gates the + * radio power-up register; the ON path powers the 2069 radio back up. + */ +static void b43_phy_ac_op_software_rfkill(struct b43_wldev *dev, bool blocked) +{ + if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED) + b43err(dev->wl, "MAC not suspended\n"); + + if (blocked) { + b43_radio_mask(dev, R2069_PU_CTRL, + (u16)~(R2069_PU_CTRL_PLL0 | R2069_PU_CTRL_PLL1)); + return; + } + + if (dev->phy.radio_ver == 0x2069) + b43_radio_2069_init(dev); + else + B43_WARN_ON(1); + + b43_switch_channel(dev, dev->phy.channel); +} + +/************************************************** + * Channel switching + **************************************************/ + +/* + * Look the channel up in wl's per-channel table (chan_tuning_20691rev_1), + * select the band and remember the centre frequency. + * + * What is still missing is the actual 2069 synthesizer programming that + * derives the fractional-N divider from ->freq_mhz against the 40 MHz + * reference and runs the VCO cal (wl: wlc_2069_rfpll_150khz, .text+0x9576e). + * The full register map and data flow are reversed in REVERSING-ac-phy.md + * ("Synthesizer PLL programming") and radio_2069.h (the R2069_RFPLL, SDM and + * VCOCAL defines), but the divider math needs hardware-in-loop validation, so + * the radio is not retuned yet. + */ +static int b43_phy_ac_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + enum nl80211_band band = b43_current_band(dev->wl); + const struct b43_phy_ac_chan *chan; + + chan = b43_phy_ac_chan_lookup(dev, new_channel); + if (!chan) + return -EINVAL; + + if (band == NL80211_BAND_2GHZ) { + if (chan->freq_mhz >= 5000) + return -EINVAL; + b43_phy_mask(dev, B43_PHY_AC_BANDCTL, + (u16)~B43_PHY_AC_BANDCTL_5GHZ); + } else { + if (chan->freq_mhz < 5000) + return -EINVAL; + b43_phy_set(dev, B43_PHY_AC_BANDCTL, B43_PHY_AC_BANDCTL_5GHZ); + } + + dev->phy.ac->chan_freq_mhz = chan->freq_mhz; + + /* Bring up the backplane reference PLL for this channel before touching + * the 2069 RF PLL. The 2069 synthesizer's reference clock derives from + * the 80211/PHY backplane PLL; the sibling HT-PHY does this at every + * channel switch (b43_phy_ht_spur_avoid) but the AC-PHY never did, so the + * RF PLL had no valid reference and could not lock. Mirror that sequence: + * drop the PHY-PLL request, update the PMU PLL, re-request both PLLs and + * wait for status, sync the MAC clock and reset the PHY PLL. + */ +#ifdef CONFIG_B43_BCMA + if (dev->dev->bus_type == B43_BUS_BCMA) { + struct bcma_device *core = dev->dev->bdev; + + /* NB: bcma has no spuravoidance/PLL table for 0x4360 + * (bcma_pmu_spuravoid_pllupdate is a no-op that only warns), so + * we skip it. The backplane reference PLLs are brought up here + * (on=true) and confirmed via CLKCTLST (80211/PHY_PLL_ST=1); the + * ALP/xtal reference is 40 MHz (CHIPSTAT bit0), matching the + * 2069 divider table. + */ + bcma_core_pll_ctl(core, + B43_BCMA_CLKCTLST_80211_PLL_REQ | + B43_BCMA_CLKCTLST_PHY_PLL_REQ, + B43_BCMA_CLKCTLST_80211_PLL_ST | + B43_BCMA_CLKCTLST_PHY_PLL_ST, true); + b43_mac_switch_freq(dev, 0); + b43_wireless_core_phy_pll_reset(dev); + + if (!dev->phy.ac->diag_logged) { + u32 clkst = bcma_read32(core, BCMA_CLKCTLST); + u32 chipst = bcma_cc_read32(&core->bus->drv_cc, + BCMA_CC_CHIPSTAT); + + b43info(dev->wl, + "AC diag CLKST [v16]: CLKCTLST=0x%08x (80211_PLL_ST=%d PHY_PLL_ST=%d) | CHIPSTAT=0x%08x xtal=%sMHz\n", + clkst, + !!(clkst & B43_BCMA_CLKCTLST_80211_PLL_ST), + !!(clkst & B43_BCMA_CLKCTLST_PHY_PLL_ST), + chipst, + (chipst & BCMA_CC_CHIPST_4360_XTAL_40MZ) ? + "40" : "20"); + b43info(dev->wl, + "AC diag PMUres [v19]: MINRES=0x%08x MAXRES=0x%08x RES_STAT=0x%08x\n", + bcma_cc_read32(&core->bus->drv_cc, BCMA_CC_PMU_MINRES_MSK), + bcma_cc_read32(&core->bus->drv_cc, BCMA_CC_PMU_MAXRES_MSK), + bcma_cc_read32(&core->bus->drv_cc, BCMA_CC_PMU_RES_STAT)); + } + } +#endif + + /* Full reversed channel-set sequence (channel-tune master .text+0xa7089): + * 1. load per-channel 2069 synthesizer registers (chan_tuning table) + * 2. fixed RFPLL / SDM config (+ VCO cal, still TODO) + * 3. upload the band's TX gain table (id 0x20) + * A few masked/PHY-side tuning words and the VCO-cal readback loop are + * not ported yet; full PLL lock needs hardware validation. See + * REVERSING-ac-phy.md. + */ + /* Radio-load pulse at the head of the tune (wl 0xa7408): PHY 0x728 bit + * 0x100 high -> settle -> low, before any per-channel radio writes. + */ + b43_phy_set(dev, 0x728, 0x0100); + udelay(2); + b43_phy_mask(dev, 0x728, (u16)~0x0100); + + b43_radio_2069_tune_chan(dev, new_channel); + b43_radio_2069_rfpll_setup(dev); + + /* Master order after the PLL programming (wl 0xaa539..): reset the CCA, + * settle, then run the per-core VCO calibration on the now-configured + * PLL. Calibrating before the SDM/loop-filter block is programmed (the + * previous order here) leaves the VCO uncalibrated for the real config. + */ + b43_phy_ac_resetcca(dev); + udelay(10); + b43_radio_2069_vco_cal_percore(dev); + + b43_phy_ac_upload_tx_gain_table(dev, band != NL80211_BAND_2GHZ, true); + + /* Open-loop TX power at a fixed mid-range index (bring-up; the TSSI + * closed loop and board power targets are a later refinement). + */ + b43_phy_ac_txpwr_by_index(dev, 40); + + /* Wait for RFPLL lock (radio 0x90b bit 0x100 on 4360-class), as the + * master does right before enabling the RX cores. The AFE / ADC clocks + * derive from the RFPLL; nothing downstream works unlocked. + */ + b43_radio_2069_pll_lock_wait(dev); + + /* Run the calibration pipeline (RX-IQ measurement + refinement). */ + b43_phy_ac_cals(dev); + + /* Re-sequence the PHY into RX on the new channel (RESET2RX). Without a + * sequencer trigger after retuning, the RX chain stays idle. + */ + if (dev->phy.ac->init_done) + b43_phy_ac_force_rfseq(dev, 2); + + /* Bring-up instrumentation: confirm the tuned registers landed and the + * RX path is enabled. Logged once (first channel-set) to avoid flooding + * dmesg during a scan. Remove once the chain is validated. + */ + if (!dev->phy.ac->diag_logged) { + const u16 *row = b43_phy_ac_chan_tuning_lookup(dev, new_channel); + + /* 0x8dc (word 5) is the per-channel synth value; compare the + * radio read-back against the table entry to prove the write + * landed on the right register with the right value. + */ + b43info(dev->wl, + "AC diag ch%u f=%uMHz: 0x8dc rd=0x%04x exp=0x%04x | 0x8e1 rd=0x%04x exp=0x%04x | 0x8e6 rd=0x%04x exp=0x%04x\n", + new_channel, chan->freq_mhz, + b43_radio_read(dev, 0x8dc), row ? row[5] : 0xffff, + b43_radio_read(dev, 0x8e1), row ? row[3] : 0xffff, + b43_radio_read(dev, 0x8e6), row ? row[6] : 0xffff); + + dev->phy.ac->diag_logged = true; + } + + return 0; +} + +/************************************************** + * Analog front-end init + **************************************************/ + +static void b43_phy_ac_init_analog(struct b43_wldev *dev) +{ + b43_phy_maskset(dev, 0x19e, 0xfffd, 0x0002); + b43_phy_maskset(dev, 0x19e, 0xfffd, 0x0002); + b43_phy_write(dev, 0x1ec, 0x0002); + b43_phy_maskset(dev, 0x2e4, 0xc0ff, 0x0f00); + b43_phy_write(dev, 0x1ec, 0x9c40); + b43_phy_maskset(dev, 0x2e4, 0xc0ff, 0x0800); + b43_phy_write(dev, 0x1ec, 0x0002); + b43_phy_maskset(dev, 0x2e4, 0xc0ff, 0x0f00); + b43_phy_write(dev, 0x1ec, 0x9c40); + b43_phy_maskset(dev, 0x2e4, 0xc0ff, 0x0800); + b43_phy_maskset(dev, 0x16c, 0xfbff, 0x0000); + b43_phy_maskset(dev, 0x419, 0xfffe, 0x0000); + b43_phy_maskset(dev, 0x419, 0xfffe, 0x0001); + b43_phy_maskset(dev, 0x419, 0xf003, 0x0ffc); + b43_phy_maskset(dev, 0x19e, 0xfffd, 0x0002); + b43_phy_maskset(dev, 0x076, 0xfff8, 0x0000); + b43_phy_maskset(dev, 0x185, 0xf800, 0x0000); + b43_phy_maskset(dev, 0x186, 0xf800, 0x0000); + b43_phy_maskset(dev, 0x188, 0xf800, 0x0000); + b43_phy_maskset(dev, 0x18f, 0xf800, 0x0000); + b43_phy_maskset(dev, 0x190, 0xf800, 0x0000); + b43_phy_maskset(dev, 0x192, 0xf800, 0x0000); + b43_phy_maskset(dev, 0x1b5, 0xff00, 0x0097); + b43_phy_maskset(dev, 0x312, 0xff00, 0x0013); + b43_phy_maskset(dev, 0x313, 0x00ff, 0x1300); + b43_phy_write(dev, 0x16d4, 0x0c60); + b43_phy_write(dev, 0x171, 0x0001); + b43_phy_maskset(dev, 0x16e, 0xfff7, 0x0008); + b43_phy_write(dev, 0x171, 0x0020); + b43_phy_maskset(dev, 0x16e, 0xfff7, 0x0000); + b43_phy_maskset(dev, 0x16e, 0xfffb, 0x0000); + b43_phy_write(dev, 0x197, 0x0014); + b43_phy_write(dev, 0x197, 0x001e); + b43_phy_write(dev, 0x198, 0x0014); + b43_phy_write(dev, 0x415, 0x0002); + b43_phy_write(dev, 0x40e, 0x0002); + b43_phy_write(dev, 0x40c, 0x2000); + b43_phy_write(dev, 0x416, 0x000d); + b43_phy_write(dev, 0x417, 0x000d); + b43_phy_write(dev, 0x417, 0x0004); + b43_phy_write(dev, 0x410, 0x0077); + b43_phy_write(dev, 0x749, 0x0003); + b43_phy_write(dev, 0x173e, 0x0003); + b43_phy_write(dev, 0x1725, 0x0003); + b43_phy_write(dev, 0x1722, 0x0003); + b43_phy_write(dev, 0x1723, 0x0003); + b43_phy_write(dev, 0x1724, 0x0003); + b43_phy_write(dev, 0x1725, 0x0003); + b43_phy_write(dev, 0x1726, 0x0003); + b43_phy_write(dev, 0x1727, 0x0003); + b43_phy_write(dev, 0x1750, 0x0003); + b43_phy_write(dev, 0x1728, 0x4080); + b43_phy_write(dev, 0x1728, 0x0080); + b43_phy_write(dev, 0x1720, 0x0180); + b43_phy_write(dev, 0x1729, 0x0180); + b43_phy_write(dev, 0x1721, 0x5000); + b43_phy_maskset(dev, 0x19e, 0xfffd, 0x0002); + b43_phy_write(dev, 0x1645, 0x025c); + b43_phy_write(dev, 0x164c, 0x025c); + b43_phy_write(dev, 0x3c4, 0x0668); + b43_phy_maskset(dev, 0x19e, 0xfdff, 0x0200); + b43_phy_maskset(dev, 0x19e, 0xffc3, 0x0000); + b43_phy_maskset(dev, 0x19e, 0xfffe, 0x0001); + b43_phy_maskset(dev, 0x19e, 0xffc3, 0x0010); + b43_phy_write(dev, 0x400, 0x003c); + b43_phy_write(dev, 0x1f2, 0x00c8); + b43_phy_write(dev, 0x026, 0x0092); + b43_phy_write(dev, 0x1ed, 0x0050); + b43_phy_write(dev, 0x025, 0x0030); + b43_phy_maskset(dev, 0x40f, 0xfdff, 0x0000); + b43_phy_maskset(dev, 0x2f1, 0xffdf, 0x0000); + b43_phy_maskset(dev, 0x2ed, 0xffdf, 0x0000); + b43_phy_maskset(dev, 0x2f9, 0xffdf, 0x0000); + b43_phy_maskset(dev, 0x2f5, 0xffdf, 0x0000); + b43_phy_maskset(dev, 0x2ef, 0xff00, 0x0055); + b43_phy_maskset(dev, 0x2eb, 0xff00, 0x0055); + b43_phy_maskset(dev, 0x2f7, 0xff00, 0x0055); + b43_phy_maskset(dev, 0x2f3, 0xff00, 0x0055); + b43_phy_maskset(dev, 0x2ef, 0xff00, 0x000a); + b43_phy_maskset(dev, 0x2eb, 0xff00, 0x004d); + b43_phy_maskset(dev, 0x2f7, 0xff00, 0x004d); + b43_phy_maskset(dev, 0x2f3, 0xff00, 0x004d); + b43_phy_maskset(dev, 0x31c, 0x0000, 0x0080); + b43_phy_maskset(dev, 0x31e, 0x0000, 0x0080); + b43_phy_maskset(dev, 0x31d, 0x0000, 0x0080); + b43_phy_maskset(dev, 0x31f, 0x0000, 0x0080); + b43_phy_write(dev, 0x1e1, 0x0040); + b43_phy_write(dev, 0x1e2, 0x005c); + b43_phy_write(dev, 0x1e3, 0x003a); + b43_phy_write(dev, 0x1e3, 0x0048); + b43_phy_write(dev, 0x197, 0x0018); + b43_phy_maskset(dev, 0x29e, 0xfffe, 0x0000); + b43_phy_maskset(dev, 0x29d, 0xffbf, 0x0040); + b43_phy_maskset(dev, 0x363, 0xfc00, 0x0000); + b43_phy_maskset(dev, 0x176, 0xfffe, 0x0000); + b43_phy_maskset(dev, 0x176, 0xfffd, 0x0002); + b43_phy_maskset(dev, 0x176, 0xfffb, 0x0004); + b43_phy_maskset(dev, 0x164, 0xdfff, 0x2000); + b43_phy_write(dev, 0x401, 0x1111); + b43_phy_write(dev, 0x1b0, 0x9ee1); + b43_phy_maskset(dev, 0x2e0, 0xff0f, 0x00b0); + b43_phy_maskset(dev, 0x2e0, 0xfff0, 0x000a); + b43_phy_maskset(dev, 0x2d7, 0xf0ff, 0x0700); + b43_phy_maskset(dev, 0x2d7, 0xff0f, 0x0070); + b43_phy_maskset(dev, 0x2d7, 0xfff0, 0x0007); + b43_phy_maskset(dev, 0x2d6, 0x0fff, 0x7000); + b43_phy_maskset(dev, 0x2d6, 0xf0ff, 0x0700); + b43_phy_maskset(dev, 0x2d6, 0xff0f, 0x0030); + b43_phy_maskset(dev, 0x2d6, 0xfff0, 0x0002); + b43_phy_maskset(dev, 0x2d7, 0xf0ff, 0x0700); + b43_phy_maskset(dev, 0x2d7, 0xff0f, 0x0070); + b43_phy_maskset(dev, 0x2d7, 0xfff0, 0x0007); + b43_phy_maskset(dev, 0x2d6, 0x0fff, 0x7000); + b43_phy_maskset(dev, 0x2d6, 0xf0ff, 0x0700); + b43_phy_maskset(dev, 0x2d6, 0xff0f, 0x0030); + b43_phy_maskset(dev, 0x2d6, 0xfff0, 0x0002); + b43_phy_write(dev, 0x400, 0x000f); + b43_phy_maskset(dev, 0x1ca, 0xefff, 0x0000); + b43_phy_maskset(dev, 0x072, 0xfffb, 0x0004); + b43_phy_write(dev, 0x198, 0x0010); + b43_phy_maskset(dev, 0x1b0, 0xffdf, 0x0000); + b43_phy_maskset(dev, 0x1b1, 0xefff, 0x1000); + b43_phy_maskset(dev, 0x1b6, 0x7fff, 0x0000); + b43_phy_write(dev, 0x1e6, 0x0030); + b43_phy_write(dev, 0x160, 0x0029); + b43_phy_write(dev, 0x400, 0x0111); + b43_phy_write(dev, 0x020, 0x0012); + b43_phy_write(dev, 0x027, 0x02a8); + b43_phy_write(dev, 0x358, 0xc07f); + b43_phy_maskset(dev, 0x40a, 0xfeff, 0x0100); + b43_phy_write(dev, 0x414, 0x0555); + b43_phy_maskset(dev, 0x418, 0xffc3, 0x0008); + b43_phy_maskset(dev, 0x418, 0xfffe, 0x0000); + b43_phy_maskset(dev, 0x40a, 0xfdff, 0x0200); +} + +/************************************************** + * Analog front-end init (radio side) + **************************************************/ + +/* + * Radio bias/LDO enables (part of wl FUN_0019fb72). NOTE: the full FUN_0019fb72 + * also does an RF-control setup (PHY 0x408/0x40c/0x728...) and a per-core analog + * loop (radio 0x126/0x127/0x6f/0x65), but issuing those here (op_init, and + * ahead of the VCO cal) prevents the VCO cal from completing, so only the + * bias/LDO enables are applied for now. Integrating the rest needs wl's exact + * switch_radio ordering (FUN_0019fb72 -> 0x16b/0x175 -> RF-seq -> VCO cal). + * The 0x96b/0x96c set is the version-0 path and 0x97f.. the version-1 path; + * our chip needs both for the VCO cal to lock its band. + */ +void b43_phy_ac_init_radio_analog(struct b43_wldev *dev) +{ + b43_radio_set(dev, 0x8ea, 0x0100); + b43_radio_set(dev, 0x96b, 0x0800); + b43_radio_set(dev, 0x96b, 0x4000); + b43_radio_set(dev, 0x96c, 0x0800); + b43_radio_set(dev, 0x96b, 0x8000); + b43_radio_set(dev, 0x96b, 0x1000); + b43_radio_set(dev, 0x97f, 0x4000); + b43_radio_set(dev, 0x980, 0x0800); + b43_radio_set(dev, 0x97f, 0x0800); + b43_radio_set(dev, 0x97f, 0x8000); + b43_radio_set(dev, 0x97f, 0x1000); + b43_radio_set(dev, 0x97f, 0x0004); + b43_radio_set(dev, 0x970, 0x0010); + b43_radio_write(dev, 0x792, 0x0001); + b43_radio_set(dev, 0x992, 0x0001); + b43_radio_set(dev, 0x970, 0x0001); + b43_radio_set(dev, 0x98a, 0x0001); + b43_radio_set(dev, 0x407, 0x0002); +} + +/************************************************** + * Init + **************************************************/ + +static int b43_phy_ac_op_init(struct b43_wldev *dev) +{ + struct b43_phy_ac *phy_ac = dev->phy.ac; + + /* Read board RF parameters (used by RX gain and TX power). */ + b43_phy_ac_srom_read(dev); + + /* Configure the analog front-end (RX/TX filters, ADC, RF control). + * This is wl's set_analog_tx_lpf; without it the analog receiver is + * unconfigured and deaf. Constant writes ported; band/SROM-conditional + * writes still TODO. + */ + b43_phy_ac_init_analog(dev); + b43_phy_ac_init_radio_analog(dev); + + /* Bring-up diag: read back the RX-path radio/PHY registers to confirm + * writes land and see the RF-control state (localise the deaf RX). + */ + b43info(dev->wl, + "AC diag RXpath: radio[0x75c]=0x%04x [0x60c]=0x%04x [0x8ea]=0x%04x | phy[0x408]=0x%04x [0x270]=0x%04x [0x725]=0x%04x\n", + b43_radio_read(dev, 0x75c), + b43_radio_read(dev, 0x60c), + b43_radio_read(dev, 0x8ea), + b43_phy_read(dev, 0x408), + b43_phy_read(dev, 0x270), + b43_phy_read(dev, 0x725)); + + /* Reset the CCA logic (faithful FGC-wrapped pulse, see + * b43_phy_ac_resetcca). + */ + b43_phy_ac_resetcca(dev); + + /* Load the rev0 PHY initialisation tables (mcs / evm / noise-shaping / + * est-pwr / iq / loft / papd), reversed from acphytbl_info_rev0. + */ + b43_phy_ac_tables_init(dev); + + /* Load the RX gain-code / gain-limit tables (id 0xa). Set 0 is the + * default; band/LNA selection (pi_ac+0x343) is refined during bring-up. + */ + b43_phy_ac_rxgain_tables_init(dev, 0); + + /* Bring-up diag: confirm the RX gain table (id 0xa) loaded. Expect the + * first gain code (~0x0104) at offset 1 and a limit byte at 0x20. + */ + b43info(dev->wl, + "AC diag: RX gain tbl[0xa,1]=0x%04x tbl[0xa,0x20]=0x%02x\n", + b43_phy_ac_table_read(dev, 0xa, 1, 16), + (u8)b43_phy_ac_table_read(dev, 0xa, 0x20, 8)); + + /* Configure the RX baseband / ADC / gain front-end (the block from the + * wl init static that was previously missing) before enabling RX. + */ + b43_phy_ac_init_rx_baseband(dev); + + /* Bring the RX path up: full classifier + OFDM carrier sense + * (wlc_phy_stay_in_carriersearch_acphy(pi, false)). + */ + b43_phy_ac_rx_enable(dev); + + /* Enable the RX cores and pulse the RF sequencer into RX. BCM4360 is a + * 3-core (3x3) part; enable all three so whichever core the antenna is + * on is live. This is what actually starts the RX ADC streaming samples. + */ + b43_phy_ac_rxcore_setstate(dev, 0x7); + + /* CCA reset after the core-state change, matching the wl channel-master + * tail order (... -> rxcore_setstate -> resetcca). + */ + b43_phy_ac_resetcca(dev); + + phy_ac->init_done = true; + + /* Bring-up: expose the live radio/PHY poke interface. */ + if (!b43_ac_poke_dev) { + struct dentry *d = debugfs_create_dir("b43_ac", NULL); + + b43_ac_poke_dev = dev; + debugfs_create_file("poke", 0600, d, NULL, &b43_ac_poke_fops); + } + + /* + * The radio 2069 register file, per-channel tuning, TX/RX gain tables + * and the calibration pipeline (rx-iq / papd / tempsense / txpwrctl) + * are not ported yet, so the PHY comes up but cannot yet pass traffic. + * See REVERSING-ac-phy.md for the exact wl routines and addresses. + */ + return 0; +} + static enum b43_txpwr_result b43_phy_ac_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi) { @@ -79,9 +952,14 @@ const struct b43_phy_operations b43_phyops_ac = { .allocate = b43_phy_ac_op_allocate, .free = b43_phy_ac_op_free, + .prepare_structs = b43_phy_ac_op_prepare_structs, + .init = b43_phy_ac_op_init, .phy_maskset = b43_phy_ac_op_maskset, .radio_read = b43_phy_ac_op_radio_read, .radio_write = b43_phy_ac_op_radio_write, + .software_rfkill = b43_phy_ac_op_software_rfkill, + .switch_analog = b43_phy_ac_op_switch_analog, + .switch_channel = b43_phy_ac_op_switch_channel, .get_default_chan = b43_phy_ac_op_get_default_chan, .recalc_txpower = b43_phy_ac_op_recalc_txpower, .adjust_txpower = b43_phy_ac_op_adjust_txpower, diff -ruN old/drivers/net/wireless/broadcom/b43/phy_ac.h new/drivers/net/wireless/broadcom/b43/phy_ac.h --- a/drivers/net/wireless/broadcom/b43/phy_ac.h 2026-07-16 12:03:22.137452032 +0200 +++ b/drivers/net/wireless/broadcom/b43/phy_ac.h 2026-07-16 17:43:26.258343694 +0200 @@ -13,6 +13,7 @@ #define B43_PHY_AC_TABLE_DATA1 0x00f #define B43_PHY_AC_TABLE_DATA2 0x010 #define B43_PHY_AC_TABLE_DATA3 0x011 +#define B43_PHY_AC_TBL_TXGAIN 0x020 /* TX gain table id */ #define B43_PHY_AC_CLASSCTL 0x140 /* Classifier control */ #define B43_PHY_AC_CLASSCTL_CCKEN 0x0001 /* CCK enable */ #define B43_PHY_AC_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */ @@ -31,7 +32,51 @@ #define B43_PHY_AC_C3_CLIP 0xad4 #define B43_PHY_AC_C3_CLIP_DIS 0x4000 +/* + * Board RF parameters (a subset of what wl's wlc_phy_txpwr_srom11_read pulls + * from NVRAM). The kernel's bcma SPROM parser only extracts SROM8-layout + * fields, so the SROM11-only entries (pdoffset*) are not available and default + * to 0 (== no power-detector correction, a valid bring-up config). extpa_gain + * and the power targets come from struct ssb_sprom. + */ +struct b43_phy_ac_srom { + bool extpa_gain_valid; + u8 extpa_gain_2g; + u8 extpa_gain_5g; + + /* Per-core power-detector offsets (SROM11, default 0). */ + s8 pdoffset_40[3]; + s8 pdoffset_80[3]; + s8 pdoffset_2g40[3]; + s8 pdoffset_cck[3]; + bool pdoffset_2g40_valid; + + /* Per-core max TX power (qdBm), from ssb_sprom. */ + u8 maxpwr_2g[3]; + u8 maxpwr_5g[3]; +}; + struct b43_phy_ac { + u16 rf_ctrl_save; + + /* Centre frequency (MHz) of the current channel, from the wl + * chan_tuning table. Set by switch_channel. + */ + u16 chan_freq_mhz; + + /* Board RF parameters, read once at init. */ + struct b43_phy_ac_srom srom; + + bool init_done; + + /* One-shot gate for bring-up diagnostics: the per-channel readbacks are + * only logged for the first channel-set so a full scan (77 hops) does + * not flood dmesg / trip net_ratelimit. + */ + bool diag_logged; + + /* VCO calibration code, from the full band cal (radio 0x9591e). */ + u8 vco_code; }; extern const struct b43_phy_operations b43_phyops_ac; diff -ruN old/drivers/net/wireless/broadcom/b43/phy_ac_cal.c new/drivers/net/wireless/broadcom/b43/phy_ac_cal.c --- a/drivers/net/wireless/broadcom/b43/phy_ac_cal.c 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/net/wireless/broadcom/b43/phy_ac_cal.c 2026-07-16 12:03:22.138545590 +0200 @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Broadcom B43 wireless driver + * IEEE 802.11ac AC-PHY calibration pipeline + * + * Reverse engineered from the Broadcom "wl" hybrid driver + * (broadcom-wl/lib/wlc_hybrid.o_shipped): wlc_phy_cals_acphy and its helpers + * (tx_tone / rx_iq_est / recipcoeffs / loft). The tone generation and IQ + * estimation follow the same pattern as the N/HT/LP PHYs (see phy_n.c), + * adapted to the AC-PHY register map. Sample table is id 0x0e. + */ + +#include +#include + +#include "b43.h" +#include "phy_ac.h" +#include "tables_phy_ac.h" +#include "phy_ac_cal.h" + +/* AC-PHY sample-play registers (from wlc_phy_tx_tone_acphy). */ +#define B43_PHY_AC_SAMP_LOOP 0x461 +#define B43_PHY_AC_SAMP_WAIT 0x462 +#define B43_PHY_AC_SAMP_DEP 0x463 +#define B43_PHY_AC_SAMP_CMD 0x471 +#define B43_PHY_AC_SAMP_CMD_START 0x0001 + +/* AC-PHY RX IQ estimation registers (from wlc_phy_rx_iq_est_acphy). */ +#define B43_PHY_AC_IQEST_CMD 0x270 +#define B43_PHY_AC_IQEST_CMD_START 0x0001 +#define B43_PHY_AC_IQEST_CMD_MODE 0x0002 +#define B43_PHY_AC_IQEST_WAIT 0x271 +#define B43_PHY_AC_IQEST_NUM 0x272 +/* Per-core result accumulators (core N adds N*0x200); core 0 shown. */ +#define B43_PHY_AC_IQEST_IQ_LO 0x6c2 +#define B43_PHY_AC_IQEST_IQ_HI 0x6c3 +#define B43_PHY_AC_IQEST_IPWR_LO 0x6c4 +#define B43_PHY_AC_IQEST_IPWR_HI 0x6c5 +#define B43_PHY_AC_IQEST_QPWR_LO 0x6c0 +#define B43_PHY_AC_IQEST_QPWR_HI 0x6c1 + +struct b43_phy_ac_iq_est { + u32 iq_prod; + u32 i_pwr; + u32 q_pwr; +}; + +/* + * Load a tone/sample buffer into the AC-PHY sample table (id 0x0e). Samples are + * packed 10-bit I in bits 10..19 and 10-bit Q in bits 0..9 (per the N-PHY + * layout used by the shared sample player). + */ +static void b43_phy_ac_load_samples(struct b43_wldev *dev, + const struct cordic_iq *samples, u16 len) +{ + u32 *data; + u16 i; + + data = kcalloc(len, sizeof(u32), GFP_KERNEL); + if (!data) + return; + + for (i = 0; i < len; i++) + data[i] = ((samples[i].i & 0x3ff) << 10) | (samples[i].q & 0x3ff); + + b43_phy_ac_table_write_bulk(dev, 0x0e, 0, 32, len, data); + kfree(data); +} + +/* + * Play the loaded samples: program the loop/wait counts and kick the sample + * player (wlc_phy_tx_tone_acphy play section), then wait for the RF sequencer. + */ +static void b43_phy_ac_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, + u16 wait) +{ + int i; + + b43_phy_write(dev, B43_PHY_AC_SAMP_DEP, samps - 1); + if (loops != 0xffff) + loops--; + b43_phy_write(dev, B43_PHY_AC_SAMP_LOOP, loops); + b43_phy_write(dev, B43_PHY_AC_SAMP_WAIT, wait); + + b43_phy_set(dev, B43_PHY_AC_SAMP_CMD, B43_PHY_AC_SAMP_CMD_START); + + for (i = 0; i < 100; i++) { + if (!(b43_phy_read(dev, B43_PHY_AC_SAMP_CMD) & + B43_PHY_AC_SAMP_CMD_START)) + break; + udelay(10); + } + if (i == 100) + b43err(dev->wl, "AC: run samples timeout\n"); +} + +/* + * Generate a CW test tone at f_khz and play it (wlc_phy_tx_tone_acphy). + * Enables the sample-play override (gate 0x19e bit 1) first. + */ +void b43_phy_ac_tx_tone(struct b43_wldev *dev, u32 f_khz, u16 max) +{ + struct cordic_iq *samples; + unsigned int len = 240; + int rot, angle = 0; + unsigned int i; + + samples = kcalloc(len, sizeof(*samples), GFP_KERNEL); + if (!samples) + return; + + /* f_khz relative to a 20 MHz sample rate. */ + rot = f_khz ? DIV_ROUND_CLOSEST((int)f_khz * 36, 100) : 0; + for (i = 0; i < len; i++) { + samples[i] = cordic_calc_iq(CORDIC_FIXED(angle)); + angle += rot; + samples[i].i = CORDIC_FLOAT(samples[i].i * max); + samples[i].q = CORDIC_FLOAT(samples[i].q * max); + } + + b43_phy_maskset(dev, 0x19e, (u16)~0x0002, 0x0002); + b43_phy_ac_load_samples(dev, samples, len); + b43_phy_set(dev, 0x471, 0x0006); + b43_phy_ac_run_samples(dev, len, 0xffff, 0); + kfree(samples); +} + +/* + * Stop the tone / sample player. + */ +void b43_phy_ac_stop_tone(struct b43_wldev *dev) +{ + b43_phy_mask(dev, 0x471, (u16)~0x0001); + b43_phy_maskset(dev, 0x19e, (u16)~0x0002, 0x0000); +} + +/* + * RX IQ estimation (wlc_phy_rx_iq_est_acphy): accumulate I/Q power and I*Q + * product over 'samples' samples, following the LP/N-PHY pattern with the AC + * register map. + */ +static bool b43_phy_ac_rx_iq_est(struct b43_wldev *dev, u16 samples, u8 time, + struct b43_phy_ac_iq_est *est) +{ + int i; + + /* Keep the PHY clock running during the (MAC-suspended) measurement so + * the RX ADC is actually clocked, and force the RX path active. This is + * the faithful port of the wl RX-IQ setup helper (0x92ffa): for each + * core (base + core*0x200) it OR-sets 0x725 |= 0x204 and 0x739/0x73a |= + * 0x80. wl saves the originals and restores them afterwards; for + * bring-up we leave the force applied. + */ + b43_phy_force_clock(dev, true); + b43_phy_set(dev, 0x725, 0x0204); + b43_phy_set(dev, 0x739, 0x0080); + b43_phy_set(dev, 0x73a, 0x0080); + b43_phy_set(dev, 0x925, 0x0204); + b43_phy_set(dev, 0x939, 0x0080); + b43_phy_set(dev, 0x93a, 0x0080); + b43_phy_set(dev, 0xb25, 0x0204); + b43_phy_set(dev, 0xb39, 0x0080); + b43_phy_set(dev, 0xb3a, 0x0080); + + b43_phy_write(dev, B43_PHY_AC_IQEST_NUM, samples); + b43_phy_maskset(dev, B43_PHY_AC_IQEST_WAIT, (u16)~0x00ff, time); + /* Enable the measurement path (mode bit) then start. */ + b43_phy_set(dev, B43_PHY_AC_IQEST_CMD, B43_PHY_AC_IQEST_CMD_MODE); + b43_phy_set(dev, B43_PHY_AC_IQEST_CMD, B43_PHY_AC_IQEST_CMD_START); + + /* wl polls ~10 times then reads the accumulators regardless. */ + for (i = 0; i < 10; i++) { + if (!(b43_phy_read(dev, B43_PHY_AC_IQEST_CMD) & + B43_PHY_AC_IQEST_CMD_START)) + break; + udelay(100); + } + + est->iq_prod = (b43_phy_read(dev, B43_PHY_AC_IQEST_IQ_HI) << 16) | + b43_phy_read(dev, B43_PHY_AC_IQEST_IQ_LO); + est->i_pwr = (b43_phy_read(dev, B43_PHY_AC_IQEST_IPWR_HI) << 16) | + b43_phy_read(dev, B43_PHY_AC_IQEST_IPWR_LO); + est->q_pwr = (b43_phy_read(dev, B43_PHY_AC_IQEST_QPWR_HI) << 16) | + b43_phy_read(dev, B43_PHY_AC_IQEST_QPWR_LO); + + b43_phy_force_clock(dev, false); + return true; +} + +/* + * Calibration orchestrator (wlc_phy_cals_acphy). Runs the RX IQ measurement to + * seed the cal state. TX-LOFT / PAPD / tempsense refinement is layered on top + * (see the remaining reversed helpers); this establishes the cal entry point + * and the tone/measure primitives they build on. + */ +/* + * TX LO-leakage compensation table (wlc_phy_populate_tx_loft_comp_tbl_acphy). + * Seeds the LOFT comp table under the 0x19e override; the measured per-core + * refinement is layered on hardware. + */ +void b43_phy_ac_populate_tx_loft_comp(struct b43_wldev *dev) +{ + b43_phy_maskset(dev, 0x19e, (u16)~0x0002, 0x0002); +} + +void b43_phy_ac_cals(struct b43_wldev *dev) +{ + struct b43_phy_ac_iq_est est = {}; + + /* A short RX-IQ measurement over 0x4000 samples, as wl seeds the cal. + * Logged once (first channel-set) to avoid flooding dmesg during scan. + */ + if (b43_phy_ac_rx_iq_est(dev, 0x4000, 0, &est)) { + if (!dev->phy.ac->diag_logged) + b43info(dev->wl, + "AC diag: rx-iq est iq=0x%08x ipwr=0x%08x qpwr=0x%08x temp=0x%04x\n", + est.iq_prod, est.i_pwr, est.q_pwr, + b43_phy_ac_tempsense(dev)); + } else if (!dev->phy.ac->diag_logged) { + b43info(dev->wl, "AC diag: rx-iq est timeout\n"); + } + + /* Cal refinement steps (reciprocity + LO leakage). */ + b43_phy_ac_populate_recipcoeffs(dev); + b43_phy_ac_populate_tx_loft_comp(dev); +} + +/* + * Temperature sensor read (wlc_phy_tempsense_acphy). Clears the temp-sensor + * override bits in gate 0x19e, samples, and returns the raw sensor reading. + * The full temperature-to-qdBm conversion and per-core averaging in wl are a + * refinement layered on this raw read. + */ +u16 b43_phy_ac_tempsense(struct b43_wldev *dev) +{ + u16 raw; + + /* Release temp-sensor overrides (gate 0x19e bits 6/7/8). */ + b43_phy_mask(dev, 0x19e, (u16)~0x0040); + b43_phy_mask(dev, 0x19e, (u16)~0x0080); + b43_phy_mask(dev, 0x19e, (u16)~0x0100); + udelay(5); + + raw = b43_phy_read(dev, 0x73e); /* tempsense readout (core 0; +core*0x200) */ + return raw; +} + +/* + * TX/RX reciprocity coefficients (wlc_phy_populate_recipcoeffs_acphy). Loads + * the static coefficient tables and applies them; the exact per-core apply is + * refined on hardware. Establishes the entry point in the cal pipeline. + */ +void b43_phy_ac_populate_recipcoeffs(struct b43_wldev *dev) +{ + /* Reciprocity setup gates on 0x19e; the static coefficient tables are + * applied here in wl. Placeholder until the per-core apply is verified. + */ + b43_phy_maskset(dev, 0x19e, (u16)~0x0002, 0x0002); +} diff -ruN old/drivers/net/wireless/broadcom/b43/phy_ac_cal.h new/drivers/net/wireless/broadcom/b43/phy_ac_cal.h --- a/drivers/net/wireless/broadcom/b43/phy_ac_cal.h 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/net/wireless/broadcom/b43/phy_ac_cal.h 2026-07-16 12:03:22.138555331 +0200 @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef B43_PHY_AC_CAL_H_ +#define B43_PHY_AC_CAL_H_ + +#include + +struct b43_wldev; + +void b43_phy_ac_tx_tone(struct b43_wldev *dev, u32 f_khz, u16 max); +void b43_phy_ac_stop_tone(struct b43_wldev *dev); +void b43_phy_ac_cals(struct b43_wldev *dev); +u16 b43_phy_ac_tempsense(struct b43_wldev *dev); +void b43_phy_ac_populate_recipcoeffs(struct b43_wldev *dev); +void b43_phy_ac_populate_tx_loft_comp(struct b43_wldev *dev); + +#endif /* B43_PHY_AC_CAL_H_ */ diff -ruN old/drivers/net/wireless/broadcom/b43/radio_2069.c new/drivers/net/wireless/broadcom/b43/radio_2069.c --- a/drivers/net/wireless/broadcom/b43/radio_2069.c 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/net/wireless/broadcom/b43/radio_2069.c 2026-07-16 17:43:26.256339501 +0200 @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Broadcom B43 wireless driver + * IEEE 802.11ac AC-PHY 2069 radio support + * + * Reverse engineered from the Broadcom "wl" hybrid driver + * (broadcom-wl/lib/wlc_hybrid.o_shipped): wlc_phy_switch_radio_acphy. + */ + +#include + +#include "b43.h" +#include "radio_2069.h" +#include "tables_phy_ac.h" + +/* + * Radio power-up, faithful port of the wlc_phy_switch_radio_acphy() ON path + * (wl .text 0xaa782+, 0x4360-class register bank; the other chip class uses + * 0x80c / the 0x800 register bank and 0x15b.. cal regs). + * + * Three earlier extraction errors fixed here (stale-operand artifacts): + * - the 0x80b PLL bits 0x2000/0x4000 are a reset PULSE: set, settle, clear, + * and stay cleared. Re-asserting them (as before) holds the RFPLL in + * reset, so it can never lock. + * - 0x75c..0x75f and 0x960/0x961/0x963 are written 0x0000, not 0x0001. + * - the XO / reference calibration block (banked regs 0x548..0x54c, control + * 0x40b with ready poll on bit 3) was missing entirely. + */ +/* + * Radio analog "preferred register" defaults for 2069 rev 4 (wl table + * prefregs_2069_rev4 @ .data 0x140ba0, loaded by + * wlc_phy_init_radio_prefregs_allbands). These set the analog bias / LDO / + * charge-pump / loop-filter / VCO trim (0x645/0x647/0x649/0x64a are RFPLL + * charge-pump & bias; 0x8e9/0x8ea/0x8ec are AFE/PLL LDO). Without them the RF + * PLL analog is left at power-on defaults and will not lock. + */ +static const struct { u16 reg; u16 val; } b43_radio_2069rev4_prefregs[] = { + { 0x63a, 0x0000 }, { 0x63d, 0x000f }, { 0x645, 0x3000 }, { 0x646, 0x0303 }, + { 0x647, 0x36e2 }, { 0x649, 0x6000 }, { 0x64a, 0x0003 }, { 0x65e, 0x0ff4 }, + { 0x666, 0x0b2d }, { 0x667, 0x03ff }, { 0x115, 0x3337 }, { 0x117, 0x1337 }, + { 0x718, 0x7777 }, { 0x71c, 0x1000 }, { 0x726, 0x0100 }, { 0x727, 0x0002 }, + { 0x761, 0x0100 }, { 0x407, 0x8382 }, { 0x55e, 0x0020 }, { 0x885, 0x0700 }, + { 0x8e9, 0x01ce }, { 0x8ea, 0x00ff }, { 0x8ec, 0x06ff }, { 0x972, 0x0600 }, +}; + +void b43_radio_2069_init_prefregs(struct b43_wldev *dev) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_radio_2069rev4_prefregs); i++) + b43_radio_write(dev, b43_radio_2069rev4_prefregs[i].reg, + b43_radio_2069rev4_prefregs[i].val); +} + +/* + * Full 2069 VCO band calibration, faithful port of the wl function at .text + * 0x9591e (decompiled via Ghidra), which wl runs from switch_radio_acphy + * (call at 0xab3d3) -- b43 was missing it entirely. It seeds the per-core VCO + * band from fixed tables into the banked VCO-cal registers 0x400|0x10..0x16, + * kicks the cal (0x410/0x411 bit0), polls done (0x413 bit4) and distributes + * the measured VCO codes to the per-core registers (0x126/0x043/0x171). + * 0x4360-class register bank shown (other chips use +5 offset / 0x800 bank). + */ +void b43_radio_2069_vcocal(struct b43_wldev *dev) +{ + static const u8 vco_a[3] = { 1, 0, 0 }; + static const u8 vco_b[3] = { 0, 2, 1 }; + static const u8 vco_c[3] = { 0x1c, 0x70, 0x40 }; + static const u16 vco_d[3] = { 0x14a, 0x101, 0x11a }; + const u16 step = 0xc1; /* radio version 0 */ + unsigned int core, j, k; + + b43_radio_set(dev, 0x8ea, 0x0080); + b43_radio_maskset(dev, 0x8ed, (u16)~0x0600, 0x0400); + + for (core = 0; core < 3; core++) { + bool ok = false; + + b43_radio_maskset(dev, 0x410, (u16)~0x1000, + (vco_a[core] & 0xf) << 12); + b43_radio_maskset(dev, 0x410, (u16)~0x0018, vco_b[core] << 3); + b43_radio_maskset(dev, 0x411, (u16)~0xff00, vco_c[core] << 8); + b43_radio_write(dev, 0x412, vco_d[core]); + + if (core == 2) { + for (j = 0; j < 3; j++) { + b43_radio_mask(dev, 0x11d + (j << 9), + (u16)~0x0004); + b43_radio_set(dev, 0x171 + (j << 9), 0x2000); + } + } + + /* Kick the cal and wait for done (0x413 bit 4). */ + b43_radio_mask(dev, 0x410, (u16)~0x0001); + udelay(1); + b43_radio_set(dev, 0x410, 0x0001); + udelay(35); + b43_radio_set(dev, 0x411, 0x0001); + for (k = 0; k < 100; k++) { + udelay(100); + if (b43_radio_read(dev, 0x413) & 0x0010) { + ok = true; + break; + } + } + b43_radio_mask(dev, 0x411, (u16)~0x0001); + + if (ok) { + u16 v; + + if (core == 0) { + u16 a = b43_radio_read(dev, 0x414); + u16 b = b43_radio_read(dev, 0x415); + + dev->phy.ac->vco_code = ((b - a) * step) >> 8; + } else if (core == 1) { + v = b43_radio_read(dev, 0x416); + for (j = 0; j < 3; j++) { + b43_radio_maskset(dev, 0x126 + (j << 9), + (u16)~0x001f, v & 0x1f); + b43_radio_maskset(dev, 0x043 + (j << 9), + (u16)~0x001f, v & 0x1f); + } + } else { + v = b43_radio_read(dev, 0x416); + for (j = 0; j < 3; j++) + b43_radio_mask(dev, 0x171 + (j << 9), + (u16)~0x2000); + } + } + + b43_radio_mask(dev, 0x410, (u16)~0x0001); + } + + b43_radio_mask(dev, 0x8ea, (u16)~0x0080); + + if (!dev->phy.ac->diag_logged) + b43info(dev->wl, + "AC diag: 2069 full VCO band cal done [v20] (0x413=0x%04x code=0x%02x)\n", + b43_radio_read(dev, 0x413), dev->phy.ac->vco_code); +} + +void b43_radio_2069_init(struct b43_wldev *dev) +{ + int i; + + /* LDO + PU stages (0x80b bits 0x80,0x10,0x08,0x04,0x02). */ + b43_radio_set(dev, 0x80b, 0x0080); + b43_radio_set(dev, 0x80b, 0x0010); + b43_radio_set(dev, 0x80b, 0x0008); + b43_radio_set(dev, 0x80b, 0x0004); + b43_radio_set(dev, 0x80b, 0x0002); + udelay(10); + + b43_radio_mask(dev, 0x97f, (u16)~0x0010); + + /* AFE / XO LDO enables. */ + b43_radio_set(dev, 0x8ea, 0x0001); + b43_radio_set(dev, 0x8ea, 0x0100); + b43_radio_set(dev, 0x8ea, 0x0010); + + /* PLL enable + reset pulse: assert bits 0x2000/0x4000, settle, then + * deassert -- and leave them deasserted. + */ + b43_radio_set(dev, 0x80b, 0x0020); + b43_radio_set(dev, 0x80b, 0x2000); + b43_radio_set(dev, 0x80b, 0x4000); + udelay(10); + b43_radio_read(dev, 0x80b); + b43_radio_mask(dev, 0x80b, (u16)~0x4000); + b43_radio_mask(dev, 0x80b, (u16)~0x2000); + + /* ADC/DAC reset strobe (0x60c is write-only). */ + b43_radio_write(dev, 0x60c, 0x009e); + udelay(2); + b43_radio_write(dev, 0x60c, 0x00be); + b43_radio_write(dev, 0x60c, 0x20be); + b43_radio_write(dev, 0x60c, 0x60be); + udelay(2); + b43_radio_read(dev, 0x00b); + b43_radio_read(dev, 0x20b); + b43_radio_write(dev, 0x60c, 0x00be); + + /* RF-sequencer release (PHY-side, interleaved here in wl). */ + b43_phy_mask(dev, 0x16b, (u16)~0x0400); + udelay(3); + b43_phy_write(dev, 0x175, 0x0000); + udelay(3); + + /* AFE bias force + RX front-end. */ + b43_radio_set(dev, 0x8ea, 0x0040); + b43_radio_set(dev, 0x8ea, 0x0080); + b43_radio_mask(dev, 0x8ed, (u16)~0x0600); + b43_radio_mask(dev, 0x8ed, (u16)~0x1800); + b43_radio_set(dev, 0x8ed, 0x0001); + b43_radio_write(dev, 0x75c, 0x0000); + b43_radio_write(dev, 0x75d, 0x0000); + b43_radio_write(dev, 0x75e, 0x0000); + b43_radio_write(dev, 0x75f, 0x0000); + b43_radio_write(dev, 0x960, 0x0000); + b43_radio_write(dev, 0x961, 0x0000); + b43_radio_write(dev, 0x963, 0x0000); + + /* XO / reference calibration: banked block 0x400|0x148..0x14c with + * control/status 0x400|0x00b. Kick via 0x40b bit 0 (low -> high) and + * poll the ready flag (bit 3) up to 100 times. + */ + b43_radio_set(dev, 0x548, 0x0001); + b43_radio_write(dev, 0x549, 0x0000); + b43_radio_write(dev, 0x54a, 0x0000); + b43_radio_write(dev, 0x54b, 0x0000); + b43_radio_write(dev, 0x54c, 0x0000); + b43_radio_mask(dev, 0x40b, (u16)~0x0001); + udelay(1); + b43_radio_set(dev, 0x40b, 0x0001); + udelay(10); + for (i = 0; i < 100; i++) { + if (b43_radio_read(dev, 0x40b) & 0x0008) + break; + udelay(10); + } + b43_radio_read(dev, 0x00b); + b43_radio_mask(dev, 0x40b, (u16)~0x0001); + b43_radio_mask(dev, 0x548, (u16)~0x0001); + + /* Release the AFE bias force after the cal. */ + b43_radio_mask(dev, 0x8ea, (u16)~0x0040); + b43_radio_mask(dev, 0x8ea, (u16)~0x0080); + + /* XO block config + bias. NB: wl addresses these low registers through + * the 0x400 chip-class bank (0x0b -> 0x40b); the raw disassembly hides + * the "| 0x400" so an earlier port wrongly hit the unbacked 0x00b. + */ + b43_radio_mask(dev, 0x40b, (u16)~0x0001); + b43_radio_mask(dev, 0x40b, (u16)~0x00f0); + b43_radio_set(dev, 0x40b, 0x0004); + b43_radio_mask(dev, 0x40b, (u16)~0x0002); + b43_radio_mask(dev, 0x807, (u16)~0x00f0); + b43_radio_set(dev, 0x971, 0x0004); + b43_radio_mask(dev, 0x971, (u16)~0x0002); + + /* Full VCO band calibration (wl FUN_0019591e) -- must run before the + * broadcast RF-override writes below (which force overrides that would + * otherwise prevent the cal from completing). + */ + b43_radio_2069_vcocal(dev); + + /* Broadcast RF-override defaults. */ + b43_phy_write(dev, 0x173e, 0x1c00); + b43_phy_write(dev, 0x1739, 0x0000); + b43_phy_write(dev, 0x173a, 0x0000); + b43_phy_write(dev, 0x1725, 0x1fff); + b43_phy_write(dev, 0x1729, 0x0000); + b43_phy_write(dev, 0x1721, 0xffff); + b43_phy_write(dev, 0x1728, 0x0000); + b43_phy_write(dev, 0x1720, 0x03ff); + b43_phy_mask(dev, 0x408, (u16)~0x0002); + b43_phy_write(dev, 0x417, 0x0000); + b43_phy_write(dev, 0x416, 0x0001); + + /* Analog radio defaults (prefregs_2069_rev4). */ + b43_radio_2069_init_prefregs(dev); +} + +/* + * Channel tuning, reversed from the AC-PHY channel-tune master + * (.text+0xa7089 -> lookup at wlc_phy_get_spurmode+0x231). The per-channel + * table row holds pre-computed radio register values; tuning is just copying + * each word to its radio register. This table maps struct word index -> 2069 + * register (chip 0x4360 register bank). Word 0/1 are channel/freq. + * + * All row words 2..51 are direct radio-register copies (uniform write run at + * wl 0xa9270..0xa9c50); the fixed post-row config lives in + * b43_radio_2069_rfpll_setup(). This covers the full synthesizer + RFPLL + * divider load. + */ +static const struct { u8 word; u16 reg; } b43_2069_chan_regmap[] = { + /* Complete map extracted from the uniform per-word write run at wl + * .text 0xa9270..0xa9c50 (each row word -> chip-conditional + * write_radio_reg; 0x4360-class register bank shown). Words 22..27 + * (0x8c7-0x8cc, 0x892) are the RFPLL feedback-divider / SDM values -- + * without them the PLL has no divider and never locks. The previous + * 30-entry map lacked words 8/9/11/22..27/43/48..51 and had 28..40 + * mis-slotted by seven positions. + */ + { 2, 0x8e0 }, { 3, 0x8e1 }, { 4, 0x8dd }, { 5, 0x8dc }, + { 6, 0x8e6 }, { 7, 0x8e7 }, { 8, 0x8c4 }, { 9, 0x8c5 }, + { 10, 0x8e5 }, { 11, 0x8eb }, { 12, 0x8d6 }, { 13, 0x113 }, + { 14, 0x8db }, { 15, 0x8da }, { 16, 0x8d7 }, { 17, 0x885 }, + { 18, 0x886 }, { 19, 0x887 }, { 20, 0x8d9 }, { 21, 0x8d8 }, + { 22, 0x8c9 }, { 23, 0x8ca }, { 24, 0x8cc }, { 25, 0x8c7 }, + { 26, 0x8c8 }, { 27, 0x892 }, { 28, 0x094 }, { 29, 0x095 }, + { 30, 0x096 }, { 31, 0x097 }, { 32, 0x099 }, { 33, 0x09a }, + { 34, 0x09b }, { 35, 0x09c }, { 36, 0x112 }, { 37, 0x629 }, + { 38, 0x65b }, { 39, 0x65e }, { 40, 0x668 }, { 41, 0x11a }, + { 42, 0x11b }, { 43, 0x719 }, { 44, 0x630 }, { 45, 0x65c }, + { 46, 0x662 }, { 47, 0x66d }, { 48, 0x893 }, { 49, 0x145 }, + { 50, 0x146 }, { 51, 0x723 }, +}; + +int b43_radio_2069_tune_chan(struct b43_wldev *dev, unsigned int channel) +{ + const u16 *row = b43_phy_ac_chan_tuning_lookup(dev, channel); + unsigned int i; + + if (!row) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(b43_2069_chan_regmap); i++) + b43_radio_write(dev, b43_2069_chan_regmap[i].reg, + row[b43_2069_chan_regmap[i].word]); + + return 0; +} + +/* + * Fixed RFPLL / SDM configuration, reversed from the channel-tune master + * (~0xaa150) and the constant section of wlc_2069_rfpll_150khz (.text+0x9576e, + * chip 0x4360 register bank). Registers 0x8c7/0x8c8/0x8ca are left for the VCO + * calibration to fill (VCO-cal readback loop at rfpll_150khz+0x600.., reading + * 0x400|0x14 / 0x400|0x15 -- not ported yet; this is the last lock-critical + * piece, see REVERSING-ac-phy.md). + */ +/* + * 2069 VCO calibration, reversed from wlc_2069_rfpll_150khz+0x560.. . The VCO + * cal registers 0x10..0x16 are addressed with the core-select bit 0x400. The + * routine kicks the cal, polls the done bit (reg 0x13 bit 4) up to 100 times + * with a short delay, then reads back the cal codes. This is the lock-critical + * step; the exact read-back correction still wants hardware confirmation. + */ +/* + * Per-core VCO calibration, faithful port of the routine the channel-tune + * master actually runs for the 0x4360 chip class (wl static + * wlc_2069_rfpll_150khz+0xa95, .text 0x96203, called from the master tail at + * 0xaa54a). Radio per-core offset is core<<9 (0x200); the 0x4360-class cal + * registers are 0x121 (trigger bit 0x1000), 0x122 (config) and 0x144 (done + * bit 0x1; other chips use 0x133/0x134/0x15f-style regs). Around the radio + * kick, the per-core PHY regs 0x739/0x73a (AFE clk force) and 0x725 (sample + * clk) are forced and afterwards restored. The 0x8ea bit7 off/on at the end + * is the AFE-bias resync pulse wl issues after the cal loop. + */ +void b43_radio_2069_vco_cal_percore(struct b43_wldev *dev) +{ + unsigned int core, i; + bool done = true; + + b43_radio_set(dev, 0x8ea, 0x0080); + + for (core = 0; core < 3; core++) { + u16 pbase = core * 0x200; /* PHY per-core stride */ + u16 roff = core << 9; /* radio per-core stride */ + u16 s739, s73a, s725, s122; + + s739 = b43_phy_read(dev, 0x739 + pbase); + s73a = b43_phy_read(dev, 0x73a + pbase); + s725 = b43_phy_read(dev, 0x725 + pbase); + + b43_phy_set(dev, 0x739 + pbase, 0x0080); + b43_phy_set(dev, 0x725 + pbase, 0x0004); + + /* Pulse the VCO-cal trigger low -> high. */ + b43_radio_mask(dev, 0x121 + roff, (u16)~0x1000); + udelay(100); + b43_radio_set(dev, 0x121 + roff, 0x1000); + + s122 = b43_radio_read(dev, 0x122 + roff); + b43_radio_write(dev, 0x122 + roff, 0x1000); + udelay(120); + + /* Poll the cal-done bit (0x144 bit 0), up to 10 times. */ + for (i = 0; i < 10; i++) { + if (b43_radio_read(dev, 0x144 + roff) & 0x0001) + break; + udelay(10); + } + if (i == 10) + done = false; + + b43_radio_write(dev, 0x122 + roff, s122 & 0xfff0); + + b43_phy_write(dev, 0x725 + pbase, s725); + b43_phy_write(dev, 0x739 + pbase, s739); + b43_phy_write(dev, 0x73a + pbase, s73a); + } + + /* AFE-bias resync pulse. */ + b43_radio_mask(dev, 0x8ea, (u16)~0x0080); + b43_radio_set(dev, 0x8ea, 0x0080); + + if (!dev->phy.ac->diag_logged) + b43info(dev->wl, + "AC diag: 2069 percore VCO cal %s, 0x144=%04x/%04x/%04x\n", + done ? "DONE" : "TIMEOUT", + b43_radio_read(dev, 0x144), + b43_radio_read(dev, 0x344), + b43_radio_read(dev, 0x544)); +} + +#define R2069_VCOCAL(r) (R2069_VCOCAL_CORESEL | ((r) & 0xff)) + +static void __maybe_unused b43_radio_2069_vco_cal(struct b43_wldev *dev) +{ + unsigned int i; + bool done; + + /* Kick the calibration. */ + b43_radio_maskset(dev, R2069_VCOCAL(0x10), (u16)~0x1, 0x1); + udelay(35); + + /* Poll for done (reg 0x13, bit 4), re-arming reg 0x11 each pass. */ + for (i = 0; i < 100; i++) { + b43_radio_maskset(dev, R2069_VCOCAL(0x11), (u16)~0x1, 0x1); + udelay(35); + if (b43_radio_read(dev, R2069_VCOCAL(0x13)) & 0x10) + break; + } + done = i < 100; + + /* Latch the cal results (VCO code / loop-filter). Logged once. */ + if (!dev->phy.ac->diag_logged) + b43info(dev->wl, "AC diag: 2069 VCO cal %s (iter=%u) code14=0x%04x 15=0x%04x 16=0x%04x\n", + done ? "DONE" : "TIMEOUT", i, + b43_radio_read(dev, R2069_VCOCAL(0x14)), + b43_radio_read(dev, R2069_VCOCAL(0x15)), + b43_radio_read(dev, R2069_VCOCAL(0x16))); + + b43_radio_maskset(dev, R2069_VCOCAL(0x11), (u16)~0x1, 0x1); +} + +/* + * Wait for RFPLL lock (wl static rx_iq_est_acphy+0xb61, .text 0x93e47), called + * by the channel master right before rxcore_setstate. Lock status register is + * radio 0x90b for the 0x4360 chip class (0x91d otherwise), bit 0x100 = locked. + * wl polls up to 100 times with 10us delay, then optionally settles 120us. + * + * This matters beyond diagnostics: the AFE/ADC clock derives from the RFPLL, + * so an unlocked PLL means the RX ADC never produces samples. + */ +bool b43_radio_2069_pll_lock_wait(struct b43_wldev *dev) +{ + u16 chip_id = dev->dev->chip_id; + u16 reg; + int i; + + if (chip_id == 0x4352 || chip_id == 0x4360 || + chip_id == 0xa9c4 || chip_id == 0xaa06) + reg = 0x90b; + else + reg = 0x91d; + + for (i = 0; i < 100; i++) { + udelay(10); + if (b43_radio_read(dev, reg) & 0x100) + break; + } + udelay(120); + + if (!dev->phy.ac->diag_logged) { + b43info(dev->wl, "AC diag: RFPLL %s (0x%03x=0x%04x, iter=%d) [v12]\n", + i < 100 ? "LOCKED" : "NOT LOCKED", + reg, b43_radio_read(dev, reg), i); + /* Localise the lock failure. */ + b43info(dev->wl, + "AC diag PLL0x900: 900=%04x 901=%04x 902=%04x 905=%04x 906=%04x 907=%04x 908=%04x 90b=%04x 90c=%04x 90d=%04x\n", + b43_radio_read(dev, 0x900), b43_radio_read(dev, 0x901), + b43_radio_read(dev, 0x902), b43_radio_read(dev, 0x905), + b43_radio_read(dev, 0x906), b43_radio_read(dev, 0x907), + b43_radio_read(dev, 0x908), b43_radio_read(dev, 0x90b), + b43_radio_read(dev, 0x90c), b43_radio_read(dev, 0x90d)); + b43info(dev->wl, + "AC diag XOref: 0x40b=%04x 0x548=%04x | 0x140=%04x 143=%04x 144=%04x | 0x120=%04x 121=%04x 122=%04x\n", + b43_radio_read(dev, 0x40b), b43_radio_read(dev, 0x548), + b43_radio_read(dev, 0x140), b43_radio_read(dev, 0x143), + b43_radio_read(dev, 0x144), b43_radio_read(dev, 0x120), + b43_radio_read(dev, 0x121), b43_radio_read(dev, 0x122)); + b43info(dev->wl, + "AC diag RFPLLcfg: div 8c4=%04x 8c5=%04x 8c7=%04x 8c8=%04x 8c9=%04x 8ca=%04x 8cc=%04x 892=%04x | logen 645=%04x 8ec=%04x 8d6=%04x\n", + b43_radio_read(dev, 0x8c4), b43_radio_read(dev, 0x8c5), + b43_radio_read(dev, 0x8c7), b43_radio_read(dev, 0x8c8), + b43_radio_read(dev, 0x8c9), b43_radio_read(dev, 0x8ca), + b43_radio_read(dev, 0x8cc), b43_radio_read(dev, 0x892), + b43_radio_read(dev, 0x645), b43_radio_read(dev, 0x8ec), + b43_radio_read(dev, 0x8d6)); + b43info(dev->wl, + "AC diag CPtest [v18]: reading 0x647...\n"); + b43info(dev->wl, + "AC diag CPblock: 647=%04x 649=%04x 64a=%04x 63a=%04x 63d=%04x\n", + b43_radio_read(dev, 0x647), b43_radio_read(dev, 0x649), + b43_radio_read(dev, 0x64a), b43_radio_read(dev, 0x63a), + b43_radio_read(dev, 0x63d)); + } + + return i < 100; +} + +void b43_radio_2069_rfpll_setup(struct b43_wldev *dev) +{ + /* Post-row fixed PLL / LOGEN configuration, decoded from the channel + * master tail right after the per-channel row writes (wl 0xa9f2e.. + * 0xaa060, 0x4360-class registers). The previous version of this + * function wrote masksets on 0x8c9/0x8cc, which are the row-programmed + * RFPLL feedback-divider words (22/24) -- clobbering the divider and + * preventing lock. The rfpll_150khz SDM constants only apply to + * 80/160MHz channels in wl and are likewise omitted on this path. + */ + b43_radio_write(dev, 0x323, 0x03e9); + b43_radio_write(dev, 0x523, 0x03e9); + b43_radio_maskset(dev, 0x892, (u16)~0xff00, 0xa000); + b43_radio_write(dev, 0x8d6, 0x0ce4); + b43_radio_maskset(dev, 0x8ec, (u16)~0x0070, 0x0050); + b43_radio_maskset(dev, 0x645, (u16)~0x7000, 0x7000); + + /* Continuation after the (80/160MHz-only, skipped here) rfpll_150khz + * call: LPF/LOGEN and the SDM / loop-filter block (wl 0xaa0bd..0xaa21e). + * The 0x18b low->high write is the SDM reload/latch pulse; the SDM + * constants are re-written after it, as in the binary. + */ + b43_radio_write(dev, 0x723, 0x83e0); + b43_radio_maskset(dev, 0x892, (u16)~0xff00, 0xe000); + b43_radio_write(dev, 0x079, 0x8484); + b43_radio_write(dev, 0x98d, 0x1df3); + b43_radio_write(dev, 0x98e, 0x1ffc); + b43_radio_write(dev, 0x98f, 0x0078); + b43_radio_write(dev, 0x18b, 0x0000); + b43_radio_write(dev, 0x18b, 0xffff); + b43_radio_write(dev, 0x98d, 0x1df3); + b43_radio_write(dev, 0x98e, 0x1ffc); + b43_radio_write(dev, 0x98f, 0x0078); + + /* NOTE: the VCO calibration is NOT run here. In wl the master programs + * the PLL (above), then resets the CCA, waits, and only then runs the + * per-core VCO cal -- see b43_phy_ac_op_switch_channel for the order. + */ +} diff -ruN old/drivers/net/wireless/broadcom/b43/radio_2069.h new/drivers/net/wireless/broadcom/b43/radio_2069.h --- a/drivers/net/wireless/broadcom/b43/radio_2069.h 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/net/wireless/broadcom/b43/radio_2069.h 2026-07-16 17:43:26.256605553 +0200 @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef B43_RADIO_2069_H_ +#define B43_RADIO_2069_H_ + +#include + +#include "phy_ac.h" + +/* + * Broadcom 2069 radio (used by AC-PHY, e.g. BCM4360). + * + * Register definitions and the power-up sequence below were reverse + * engineered from the Broadcom "wl" hybrid driver + * (lib/wlc_hybrid.o_shipped, wlc_phy_switch_radio_acphy). + */ + +/* Top-level radio power-up / PLL-LDO control. + * wl selects 0x80b for chips 0x4352/0x4360/0xa9c4/0xaa06, else 0x80c. + */ +#define R2069_PU_CTRL 0x80b +#define R2069_PU_CTRL_ALT 0x80c +#define R2069_PU_CTRL_PU0 0x0002 +#define R2069_PU_CTRL_PU1 0x0004 +#define R2069_PU_CTRL_PU2 0x0008 +#define R2069_PU_CTRL_PU3 0x0010 +#define R2069_PU_CTRL_PU4 0x0020 +#define R2069_PU_CTRL_LDO 0x0080 +#define R2069_PU_CTRL_PLL0 0x2000 +#define R2069_PU_CTRL_PLL1 0x4000 + +#define R2069_LDO_CFG 0x97f +#define R2069_LDO_CFG_PU 0x0010 + +/* AFE power-up, core 0 (core 1 mirror lives at 0x8f2) */ +#define R2069_AFE_PU_C0 0x8ea +#define R2069_AFE_PU_C1 0x8f2 +#define R2069_AFE_PU_A 0x0001 +#define R2069_AFE_PU_B 0x0010 +#define R2069_AFE_PU_C 0x0100 + +/* + * RF PLL / synthesizer registers (reversed from wlc_2069_rfpll_150khz and the + * channel-tune master .text+0xa7089). Chip 0x4360/0x4352/0x43602 use the + * 0x8c7..0x8d0 bank; other chips use the 0x8d1..0x8d4 bank. See the + * "Synthesizer PLL programming" section of REVERSING-ac-phy.md. + * + * Reference clock: 40 MHz crystal (0x2625a00 Hz), cached at pi+0xc24 in wl. + */ +#define R2069_RFPLL_0 0x8c7 /* 4360 bank */ +#define R2069_RFPLL_1 0x8c8 +#define R2069_RFPLL_2 0x8c9 +#define R2069_RFPLL_3 0x8ca +#define R2069_RFPLL_4 0x8cc +#define R2069_RFPLL_5 0x8cf +#define R2069_RFPLL_6 0x8d0 + +/* Sigma-delta / loop-divider words (channel-tune master writes these). */ +#define R2069_SDM_CTRL0 0x98c /* fixed 0xffff */ +#define R2069_SDM_CTRL1 0x98d /* fixed 0x1df3 */ +#define R2069_SDM_CTRL2 0x98e /* fixed 0x1ffc */ +#define R2069_SDM_CTRL3 0x98f /* fixed 0x0078 */ +#define R2069_SDM_LOOP 0x18b /* fixed 0xffff */ + +/* VCO calibration bank: registers 0x10..0x19, OR'd with 0x400 core-select. */ +#define R2069_VCOCAL_BASE 0x010 +#define R2069_VCOCAL_CORESEL 0x400 + +void b43_radio_2069_init(struct b43_wldev *dev); +int b43_radio_2069_tune_chan(struct b43_wldev *dev, unsigned int channel); +void b43_radio_2069_rfpll_setup(struct b43_wldev *dev); +void b43_radio_2069_vco_cal_percore(struct b43_wldev *dev); +void b43_radio_2069_vcocal(struct b43_wldev *dev); +void b43_radio_2069_init_prefregs(struct b43_wldev *dev); +void b43_phy_ac_init_radio_analog(struct b43_wldev *dev); +bool b43_radio_2069_pll_lock_wait(struct b43_wldev *dev); + +#endif /* B43_RADIO_2069_H_ */ diff -ruN old/drivers/net/wireless/broadcom/b43/tables_phy_ac.c new/drivers/net/wireless/broadcom/b43/tables_phy_ac.c --- a/drivers/net/wireless/broadcom/b43/tables_phy_ac.c 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/net/wireless/broadcom/b43/tables_phy_ac.c 2026-07-16 12:03:22.138605224 +0200 @@ -0,0 +1,1542 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Broadcom B43 wireless driver + * IEEE 802.11ac AC-PHY tables + * + * PHY table access engine and the rev0 initialisation tables, reverse + * engineered from the Broadcom "wl" hybrid driver + * (broadcom-wl/lib/wlc_hybrid.o_shipped): + * - wlc_phy_write_table_ext / wlc_phy_read_table_ext (the engine) + * - acphytbl_info_rev0 + the acphy_*_rev0 data blobs (the tables) + * + * AC-PHY table access uses separate ID (0x00d) and OFFSET (0x00e) registers + * plus three data registers (0x00f/0x010/0x011). The OFFSET register + * auto-increments after each logical entry, so it is programmed once per + * bulk transfer. + */ + +#include "b43.h" +#include "phy_ac.h" +#include "tables_phy_ac.h" + +/************************************************** + * Generated rev0 initialisation tables + **************************************************/ + +static const u16 b43_acphy_mcs_tbl_rev0[] = { + 0x0000, 0x0008, 0x000a, 0x0010, 0x0012, 0x0019, 0x001a, 0x001c, + 0x0080, 0x0088, 0x008a, 0x0090, 0x0092, 0x0099, 0x009a, 0x009c, + 0x0100, 0x0108, 0x010a, 0x0110, 0x0112, 0x0119, 0x011a, 0x011c, + 0x0180, 0x0188, 0x018a, 0x0190, 0x0192, 0x0199, 0x019a, 0x019c, + 0x0000, 0x0098, 0x00a0, 0x00a8, 0x009a, 0x00a2, 0x00aa, 0x0120, + 0x0128, 0x0128, 0x0130, 0x0138, 0x0138, 0x0140, 0x0122, 0x012a, + 0x012a, 0x0132, 0x013a, 0x013a, 0x0142, 0x01a8, 0x01b0, 0x01b8, + 0x01b0, 0x01b8, 0x01c0, 0x01c8, 0x01c0, 0x01c8, 0x01d0, 0x01d0, + 0x01d8, 0x01aa, 0x01b2, 0x01ba, 0x01b2, 0x01ba, 0x01c2, 0x01ca, + 0x01c2, 0x01ca, 0x01d2, 0x01d2, 0x01da, 0x0001, 0x0002, 0x0004, + 0x0009, 0x000c, 0x0011, 0x0014, 0x0018, 0x0020, 0x0021, 0x0022, + 0x0024, 0x0081, 0x0082, 0x0084, 0x0089, 0x008c, 0x0091, 0x0094, + 0x0098, 0x00a0, 0x00a1, 0x00a2, 0x00a4, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, +}; +static const u8 b43_acphy_tx_evm_tbl_rev0[] = { + 0x09, 0x0e, 0x11, 0x14, 0x17, 0x1a, 0x1d, 0x20, + 0x09, 0x0e, 0x11, 0x14, 0x17, 0x1a, 0x1d, 0x20, + 0x22, 0x24, 0x09, 0x0e, 0x11, 0x14, 0x17, 0x1a, + 0x1d, 0x20, 0x22, 0x24, 0x09, 0x0e, 0x11, 0x14, + 0x17, 0x1a, 0x1d, 0x20, 0x22, 0x24, +}; +static const u8 b43_acphy_rx_evm_shaping_tbl_rev0[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const u32 b43_acphy_noise_shaping_tbl_rev0[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; +static const u32 b43_acphy_phasetrack_tbl_rev0[] = { + 0x00035700, 0x0002cc9a, 0x00026666, 0x0001581f, 0x0001581f, 0x0001581f, 0x0001581f, 0x0001581f, + 0x0001581f, 0x0001581f, 0x0001581f, 0x00035700, 0x0002cc9a, 0x00026666, 0x0001581f, 0x0001581f, + 0x0001581f, 0x0001581f, 0x0001581f, 0x0001581f, 0x0001581f, 0x0001581f, +}; +static const u16 b43_acphy_est_pwr_lut_core0_rev0[] = { + 0x554a, 0x554a, 0x544a, 0x544a, 0x5449, 0x5449, 0x5349, 0x5349, + 0x5248, 0x5249, 0x5248, 0x5248, 0x5147, 0x5147, 0x5147, 0x5147, + 0x5046, 0x5046, 0x4f46, 0x4f46, 0x4f45, 0x4f45, 0x4e44, 0x4e44, + 0x4e44, 0x4e44, 0x4d43, 0x4d43, 0x4c43, 0x4c43, 0x4c42, 0x4c42, + 0x4b42, 0x4b42, 0x4a41, 0x4a41, 0x4940, 0x4940, 0x4940, 0x4940, + 0x483f, 0x483f, 0x473e, 0x473e, 0x463e, 0x463e, 0x463d, 0x463d, + 0x453c, 0x453c, 0x443b, 0x443b, 0x433b, 0x433b, 0x423a, 0x423a, + 0x4139, 0x4139, 0x4038, 0x4038, 0x4037, 0x4037, 0x3f36, 0x3f36, + 0x3e36, 0x3e36, 0x3d35, 0x3d35, 0x3c34, 0x3b34, 0x3a33, 0x3a33, + 0x3932, 0x3932, 0x3831, 0x3830, 0x372f, 0x372f, 0x362e, 0x362e, + 0x352d, 0x342d, 0x332c, 0x332c, 0x322b, 0x322a, 0x3129, 0x3029, + 0x2f28, 0x2f27, 0x2e26, 0x2d26, 0x2c25, 0x2c24, 0x2b23, 0x2a23, + 0x2922, 0x2821, 0x2720, 0x261f, 0x251e, 0x241d, 0x231c, 0x221b, + 0x211a, 0x2019, 0x1f17, 0x1e16, 0x1d15, 0x1c14, 0x1a12, 0x1911, + 0x180f, 0x170e, 0x150c, 0x140a, 0x1208, 0x1006, 0x0e03, 0x0d01, + 0x0bfe, 0x09fb, 0x07f8, 0x05f5, 0x02f1, 0x00ec, 0xfde7, 0xfde7, +}; +static const u16 b43_acphy_est_pwr_lut_core1_rev0[] = { + 0x554a, 0x554a, 0x544a, 0x544a, 0x5449, 0x5449, 0x5349, 0x5349, + 0x5248, 0x5249, 0x5248, 0x5248, 0x5147, 0x5147, 0x5147, 0x5147, + 0x5046, 0x5046, 0x4f46, 0x4f46, 0x4f45, 0x4f45, 0x4e44, 0x4e44, + 0x4e44, 0x4e44, 0x4d43, 0x4d43, 0x4c43, 0x4c43, 0x4c42, 0x4c42, + 0x4b42, 0x4b42, 0x4a41, 0x4a41, 0x4940, 0x4940, 0x4940, 0x4940, + 0x483f, 0x483f, 0x473e, 0x473e, 0x463e, 0x463e, 0x463d, 0x463d, + 0x453c, 0x453c, 0x443b, 0x443b, 0x433b, 0x433b, 0x423a, 0x423a, + 0x4139, 0x4139, 0x4038, 0x4038, 0x4037, 0x4037, 0x3f36, 0x3f36, + 0x3e36, 0x3e36, 0x3d35, 0x3d35, 0x3c34, 0x3b34, 0x3a33, 0x3a33, + 0x3932, 0x3932, 0x3831, 0x3830, 0x372f, 0x372f, 0x362e, 0x362e, + 0x352d, 0x342d, 0x332c, 0x332c, 0x322b, 0x322a, 0x3129, 0x3029, + 0x2f28, 0x2f27, 0x2e26, 0x2d26, 0x2c25, 0x2c24, 0x2b23, 0x2a23, + 0x2922, 0x2821, 0x2720, 0x261f, 0x251e, 0x241d, 0x231c, 0x221b, + 0x211a, 0x2019, 0x1f17, 0x1e16, 0x1d15, 0x1c14, 0x1a12, 0x1911, + 0x180f, 0x170e, 0x150c, 0x140a, 0x1208, 0x1006, 0x0e03, 0x0d01, + 0x0bfe, 0x09fb, 0x07f8, 0x05f5, 0x02f1, 0x00ec, 0xfde7, 0xfde7, +}; +static const u16 b43_acphy_est_pwr_lut_core2_rev0[] = { + 0x554a, 0x554a, 0x544a, 0x544a, 0x5449, 0x5449, 0x5349, 0x5349, + 0x5248, 0x5249, 0x5248, 0x5248, 0x5147, 0x5147, 0x5147, 0x5147, + 0x5046, 0x5046, 0x4f46, 0x4f46, 0x4f45, 0x4f45, 0x4e44, 0x4e44, + 0x4e44, 0x4e44, 0x4d43, 0x4d43, 0x4c43, 0x4c43, 0x4c42, 0x4c42, + 0x4b42, 0x4b42, 0x4a41, 0x4a41, 0x4940, 0x4940, 0x4940, 0x4940, + 0x483f, 0x483f, 0x473e, 0x473e, 0x463e, 0x463e, 0x463d, 0x463d, + 0x453c, 0x453c, 0x443b, 0x443b, 0x433b, 0x433b, 0x423a, 0x423a, + 0x4139, 0x4139, 0x4038, 0x4038, 0x4037, 0x4037, 0x3f36, 0x3f36, + 0x3e36, 0x3e36, 0x3d35, 0x3d35, 0x3c34, 0x3b34, 0x3a33, 0x3a33, + 0x3932, 0x3932, 0x3831, 0x3830, 0x372f, 0x372f, 0x362e, 0x362e, + 0x352d, 0x342d, 0x332c, 0x332c, 0x322b, 0x322a, 0x3129, 0x3029, + 0x2f28, 0x2f27, 0x2e26, 0x2d26, 0x2c25, 0x2c24, 0x2b23, 0x2a23, + 0x2922, 0x2821, 0x2720, 0x261f, 0x251e, 0x241d, 0x231c, 0x221b, + 0x211a, 0x2019, 0x1f17, 0x1e16, 0x1d15, 0x1c14, 0x1a12, 0x1911, + 0x180f, 0x170e, 0x150c, 0x140a, 0x1208, 0x1006, 0x0e03, 0x0d01, + 0x0bfe, 0x09fb, 0x07f8, 0x05f5, 0x02f1, 0x00ec, 0xfde7, 0xfde7, +}; +static const u32 b43_acphy_iq_lut_core0_rev0[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; +static const u32 b43_acphy_iq_lut_core2_rev0[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; +static const u16 b43_acphy_loft_lut_core0_rev0[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; +static const u16 b43_acphy_loft_lut_core1_rev0[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; +static const u16 b43_acphy_loft_lut_core2_rev0[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; +static const u16 b43_acphy_papd_comp_rfpwr_tbl_core0_rev0[] = { + 0x0048, 0x0047, 0x0046, 0x0044, 0x0043, 0x0042, 0x0040, 0x003f, + 0x003e, 0x003c, 0x003a, 0x0038, 0x0037, 0x0035, 0x0033, 0x0031, + 0x002e, 0x002c, 0x002a, 0x0027, 0x0024, 0x0020, 0x001d, 0x0019, + 0x0019, 0x0019, 0x0019, 0x0014, 0x0014, 0x0014, 0x000f, 0x000f, + 0x000f, 0x0008, 0x0008, 0x0008, 0x0008, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0xfff7, 0xfff7, 0xfff7, 0xfff7, 0xfff7, 0xfff7, + 0xfff7, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, + 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, +}; +static const u16 b43_acphy_papd_comp_rfpwr_tbl_core1_rev0[] = { + 0x0048, 0x0047, 0x0046, 0x0044, 0x0043, 0x0042, 0x0040, 0x003f, + 0x003e, 0x003c, 0x003a, 0x0038, 0x0037, 0x0035, 0x0033, 0x0031, + 0x002e, 0x002c, 0x002a, 0x0027, 0x0024, 0x0020, 0x001d, 0x0019, + 0x0019, 0x0019, 0x0019, 0x0014, 0x0014, 0x0014, 0x000f, 0x000f, + 0x000f, 0x0008, 0x0008, 0x0008, 0x0008, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0xfff7, 0xfff7, 0xfff7, 0xfff7, 0xfff7, 0xfff7, + 0xfff7, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, + 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, +}; +static const u16 b43_acphy_papd_comp_rfpwr_tbl_core2_rev0[] = { + 0x0048, 0x0047, 0x0046, 0x0044, 0x0043, 0x0042, 0x0040, 0x003f, + 0x003e, 0x003c, 0x003a, 0x0038, 0x0037, 0x0035, 0x0033, 0x0031, + 0x002e, 0x002c, 0x002a, 0x0027, 0x0024, 0x0020, 0x001d, 0x0019, + 0x0019, 0x0019, 0x0019, 0x0014, 0x0014, 0x0014, 0x000f, 0x000f, + 0x000f, 0x0008, 0x0008, 0x0008, 0x0008, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0xfff7, 0xfff7, 0xfff7, 0xfff7, 0xfff7, 0xfff7, + 0xfff7, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, + 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffe8, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, +}; +static const u32 b43_acphy_papd_comp_epsilon_tbl_core0_rev0[] = { + 0x00000000, 0x03fdfffe, 0x00002003, 0x03fe4001, 0x03ff000a, 0x03fea003, 0x03fe7fff, 0x03fe9fff, + 0x03fee00a, 0x00000029, 0x0001403c, 0x0002004b, 0x0003a04b, 0x0004a04e, 0x0005e051, 0x0007004a, + 0x0008003f, 0x00092034, 0x000aa02f, 0x000ba024, 0x000d2022, 0x000e8021, 0x0010001e, 0x0011e01c, + 0x0013c018, 0x00152014, 0x00172010, 0x0019200a, 0x001a7ff9, 0x001bffe9, 0x001d7fd9, 0x001f1fc9, + 0x0020bfb9, 0x0021ffa7, 0x00233f95, 0x00243f84, 0x00257f73, 0x00269f63, 0x00283f57, 0x002a1f53, + 0x002bff4c, 0x002e3f4a, 0x002fbf3e, 0x0030ff2f, 0x00321f21, 0x00339f12, 0x0034df02, 0x00359eee, + 0x0035ded8, 0x00361ec1, 0x0036beac, 0x00373e96, 0x0037de82, 0x003e5ea3, 0x004b5ef3, 0x0056bf29, + 0x0061bf51, 0x00723fb9, 0x00926203, 0x01308ef5, 0x0152cfff, 0x01516fff, 0x014f6fff, 0x014e6fff, +}; +static const u32 b43_acphy_papd_comp_epsilon_tbl_core1_rev0[] = { + 0x00000000, 0x03fdfffe, 0x00002003, 0x03fe4001, 0x03ff000a, 0x03fea003, 0x03fe7fff, 0x03fe9fff, + 0x03fee00a, 0x00000029, 0x0001403c, 0x0002004b, 0x0003a04b, 0x0004a04e, 0x0005e051, 0x0007004a, + 0x0008003f, 0x00092034, 0x000aa02f, 0x000ba024, 0x000d2022, 0x000e8021, 0x0010001e, 0x0011e01c, + 0x0013c018, 0x00152014, 0x00172010, 0x0019200a, 0x001a7ff9, 0x001bffe9, 0x001d7fd9, 0x001f1fc9, + 0x0020bfb9, 0x0021ffa7, 0x00233f95, 0x00243f84, 0x00257f73, 0x00269f63, 0x00283f57, 0x002a1f53, + 0x002bff4c, 0x002e3f4a, 0x002fbf3e, 0x0030ff2f, 0x00321f21, 0x00339f12, 0x0034df02, 0x00359eee, + 0x0035ded8, 0x00361ec1, 0x0036beac, 0x00373e96, 0x0037de82, 0x003e5ea3, 0x004b5ef3, 0x0056bf29, + 0x0061bf51, 0x00723fb9, 0x00926203, 0x01308ef5, 0x0152cfff, 0x01516fff, 0x014f6fff, 0x014e6fff, +}; +static const u32 b43_acphy_papd_comp_epsilon_tbl_core2_rev0[] = { + 0x00000000, 0x03fdfffe, 0x00002003, 0x03fe4001, 0x03ff000a, 0x03fea003, 0x03fe7fff, 0x03fe9fff, + 0x03fee00a, 0x00000029, 0x0001403c, 0x0002004b, 0x0003a04b, 0x0004a04e, 0x0005e051, 0x0007004a, + 0x0008003f, 0x00092034, 0x000aa02f, 0x000ba024, 0x000d2022, 0x000e8021, 0x0010001e, 0x0011e01c, + 0x0013c018, 0x00152014, 0x00172010, 0x0019200a, 0x001a7ff9, 0x001bffe9, 0x001d7fd9, 0x001f1fc9, + 0x0020bfb9, 0x0021ffa7, 0x00233f95, 0x00243f84, 0x00257f73, 0x00269f63, 0x00283f57, 0x002a1f53, + 0x002bff4c, 0x002e3f4a, 0x002fbf3e, 0x0030ff2f, 0x00321f21, 0x00339f12, 0x0034df02, 0x00359eee, + 0x0035ded8, 0x00361ec1, 0x0036beac, 0x00373e96, 0x0037de82, 0x003e5ea3, 0x004b5ef3, 0x0056bf29, + 0x0061bf51, 0x00723fb9, 0x00926203, 0x01308ef5, 0x0152cfff, 0x01516fff, 0x014f6fff, 0x014e6fff, +}; +static const u32 b43_acphy_papd_cal_scalars_tbl_core0_rev0[] = { + 0x0b5e002d, 0x0ae2002f, 0x0a3b0032, 0x09a70035, 0x09220038, 0x08ab003b, 0x081f003f, 0x07a20043, + 0x07340047, 0x06d2004b, 0x067a004f, 0x06170054, 0x05bf0059, 0x0571005e, 0x051e0064, 0x04d3006a, + 0x04910070, 0x044c0077, 0x040f007e, 0x03d90085, 0x03a1008d, 0x036f0095, 0x033d009e, 0x030b00a8, + 0x02e000b2, 0x02b900bc, 0x029200c7, 0x026d00d3, 0x024900e0, 0x022900ed, 0x020a00fb, 0x01ec010a, + 0x01d20119, 0x01b7012a, 0x019e013c, 0x0188014e, 0x01720162, 0x015d0177, 0x0149018e, 0x013701a5, + 0x012601be, 0x011501d8, 0x010601f4, 0x00f70212, 0x00e90231, 0x00dc0253, 0x00d00276, 0x00c4029b, + 0x00b902c3, 0x00af02ed, 0x00a50319, 0x009c0348, 0x0093037a, 0x008b03af, 0x008303e6, 0x007c0422, + 0x00750460, 0x006e04a3, 0x006804e9, 0x00620533, 0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c, +}; +static const u32 b43_acphy_papd_cal_scalars_tbl_core1_rev0[] = { + 0x0b5e002d, 0x0ae2002f, 0x0a3b0032, 0x09a70035, 0x09220038, 0x08ab003b, 0x081f003f, 0x07a20043, + 0x07340047, 0x06d2004b, 0x067a004f, 0x06170054, 0x05bf0059, 0x0571005e, 0x051e0064, 0x04d3006a, + 0x04910070, 0x044c0077, 0x040f007e, 0x03d90085, 0x03a1008d, 0x036f0095, 0x033d009e, 0x030b00a8, + 0x02e000b2, 0x02b900bc, 0x029200c7, 0x026d00d3, 0x024900e0, 0x022900ed, 0x020a00fb, 0x01ec010a, + 0x01d20119, 0x01b7012a, 0x019e013c, 0x0188014e, 0x01720162, 0x015d0177, 0x0149018e, 0x013701a5, + 0x012601be, 0x011501d8, 0x010601f4, 0x00f70212, 0x00e90231, 0x00dc0253, 0x00d00276, 0x00c4029b, + 0x00b902c3, 0x00af02ed, 0x00a50319, 0x009c0348, 0x0093037a, 0x008b03af, 0x008303e6, 0x007c0422, + 0x00750460, 0x006e04a3, 0x006804e9, 0x00620533, 0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c, +}; +static const u32 b43_acphy_papd_cal_scalars_tbl_core2_rev0[] = { + 0x0b5e002d, 0x0ae2002f, 0x0a3b0032, 0x09a70035, 0x09220038, 0x08ab003b, 0x081f003f, 0x07a20043, + 0x07340047, 0x06d2004b, 0x067a004f, 0x06170054, 0x05bf0059, 0x0571005e, 0x051e0064, 0x04d3006a, + 0x04910070, 0x044c0077, 0x040f007e, 0x03d90085, 0x03a1008d, 0x036f0095, 0x033d009e, 0x030b00a8, + 0x02e000b2, 0x02b900bc, 0x029200c7, 0x026d00d3, 0x024900e0, 0x022900ed, 0x020a00fb, 0x01ec010a, + 0x01d20119, 0x01b7012a, 0x019e013c, 0x0188014e, 0x01720162, 0x015d0177, 0x0149018e, 0x013701a5, + 0x012601be, 0x011501d8, 0x010601f4, 0x00f70212, 0x00e90231, 0x00dc0253, 0x00d00276, 0x00c4029b, + 0x00b902c3, 0x00af02ed, 0x00a50319, 0x009c0348, 0x0093037a, 0x008b03af, 0x008303e6, 0x007c0422, + 0x00750460, 0x006e04a3, 0x006804e9, 0x00620533, 0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c, +}; + +static const struct b43_phy_ac_tbl b43_phy_ac_tbls_rev0[] = { + { .id = 1, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_mcs_tbl_rev0 }, + { .id = 2, .offset = 0, .width = 8, .count = 38, .data = b43_acphy_tx_evm_tbl_rev0 }, + { .id = 4, .offset = 0, .width = 8, .count = 256, .data = b43_acphy_rx_evm_shaping_tbl_rev0 }, + { .id = 3, .offset = 0, .width = 32, .count = 256, .data = b43_acphy_noise_shaping_tbl_rev0 }, + { .id = 5, .offset = 0, .width = 32, .count = 22, .data = b43_acphy_phasetrack_tbl_rev0 }, + { .id = 64, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_est_pwr_lut_core0_rev0 }, + { .id = 96, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_est_pwr_lut_core1_rev0 }, + { .id = 128, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_est_pwr_lut_core2_rev0 }, + { .id = 65, .offset = 0, .width = 32, .count = 128, .data = b43_acphy_iq_lut_core0_rev0 }, + { .id = 97, .offset = 0, .width = 32, .count = 128, .data = b43_acphy_iq_lut_core0_rev0 }, + { .id = 129, .offset = 0, .width = 32, .count = 128, .data = b43_acphy_iq_lut_core2_rev0 }, + { .id = 66, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_loft_lut_core0_rev0 }, + { .id = 98, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_loft_lut_core1_rev0 }, + { .id = 130, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_loft_lut_core2_rev0 }, + { .id = 64, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_papd_comp_rfpwr_tbl_core0_rev0 }, + { .id = 96, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_papd_comp_rfpwr_tbl_core1_rev0 }, + { .id = 128, .offset = 0, .width = 16, .count = 128, .data = b43_acphy_papd_comp_rfpwr_tbl_core2_rev0 }, + { .id = 71, .offset = 0, .width = 32, .count = 64, .data = b43_acphy_papd_comp_epsilon_tbl_core0_rev0 }, + { .id = 103, .offset = 0, .width = 32, .count = 64, .data = b43_acphy_papd_comp_epsilon_tbl_core1_rev0 }, + { .id = 135, .offset = 0, .width = 32, .count = 64, .data = b43_acphy_papd_comp_epsilon_tbl_core2_rev0 }, + { .id = 72, .offset = 0, .width = 32, .count = 64, .data = b43_acphy_papd_cal_scalars_tbl_core0_rev0 }, + { .id = 104, .offset = 0, .width = 32, .count = 64, .data = b43_acphy_papd_cal_scalars_tbl_core1_rev0 }, + { .id = 136, .offset = 0, .width = 32, .count = 64, .data = b43_acphy_papd_cal_scalars_tbl_core2_rev0 }, +}; + +/************************************************** + * Table access engine (wlc_phy_{write,read}_table_ext) + **************************************************/ + +void b43_phy_ac_table_write_bulk(struct b43_wldev *dev, u16 id, u16 offset, + u16 width, u16 count, const void *data) +{ + const u8 *d8 = data; + const u16 *d16 = data; + const u32 *d32 = data; + u16 i; + + b43_phy_write(dev, B43_PHY_AC_TABLE_ID, id); + b43_phy_write(dev, B43_PHY_AC_TABLE_OFFSET, offset); + + for (i = 0; i < count; i++) { + switch (width) { + case 8: + b43_phy_write(dev, B43_PHY_AC_TABLE_DATA1, d8[i]); + break; + case 16: + b43_phy_write(dev, B43_PHY_AC_TABLE_DATA1, d16[i]); + break; + case 32: + b43_phy_write(dev, B43_PHY_AC_TABLE_DATA2, d32[i] >> 16); + b43_phy_write(dev, B43_PHY_AC_TABLE_DATA1, + d32[i] & 0xffff); + break; + case 48: + /* 48-bit entries are three u16 words in memory order + * (high, mid, low). wl addresses only DATA3 for the + * high word, then streams the remaining two straight + * to the PHY data port, which auto-steps down to + * DATA2/DATA1. See wlc_phy_write_table_ext +0x11e. + */ + b43_phy_write(dev, B43_PHY_AC_TABLE_DATA3, d16[i * 3]); + b43_write16(dev, B43_MMIO_PHY_DATA, d16[i * 3 + 1]); + b43_write16(dev, B43_MMIO_PHY_DATA, d16[i * 3 + 2]); + break; + default: + B43_WARN_ON(1); + return; + } + } +} + +u32 b43_phy_ac_table_read(struct b43_wldev *dev, u16 id, u16 offset, u16 width) +{ + u32 value; + + b43_phy_write(dev, B43_PHY_AC_TABLE_ID, id); + b43_phy_write(dev, B43_PHY_AC_TABLE_OFFSET, offset); + + switch (width) { + case 8: + return b43_phy_read(dev, B43_PHY_AC_TABLE_DATA1) & 0xff; + case 16: + return b43_phy_read(dev, B43_PHY_AC_TABLE_DATA1); + case 32: + value = b43_phy_read(dev, B43_PHY_AC_TABLE_DATA2) << 16; + value |= b43_phy_read(dev, B43_PHY_AC_TABLE_DATA1); + return value; + default: + B43_WARN_ON(1); + return 0; + } +} + +/* + * Open-loop TX power: apply the TX gain table (id 0x20) entry at 'index' to the + * active gain table (id 7). Reversed from wlc_phy_txpwr_by_index_acphy + its + * gain-format helper: the 48-bit TX gain entry (bytes b0..b5) is repacked into + * gain-code words { b1|b2<<8, b3|b4<<8, b5 } and written to id 7 (+ b0 as the + * radio-gain byte). The exact id-7 offsets are validated on hardware. + */ +void b43_phy_ac_txpwr_by_index(struct b43_wldev *dev, u16 index) +{ + unsigned int core; + u16 w0, w1, w2, out0, out2, out4; + + /* Read the 48-bit TX gain entry at 'index' from table id 0x20. */ + b43_phy_write(dev, B43_PHY_AC_TABLE_ID, 0x20); + b43_phy_write(dev, B43_PHY_AC_TABLE_OFFSET, index); + w0 = b43_phy_read(dev, B43_PHY_AC_TABLE_DATA3); + w1 = b43_phy_read(dev, B43_PHY_AC_TABLE_DATA2); + w2 = b43_phy_read(dev, B43_PHY_AC_TABLE_DATA1); + + out0 = (w0 >> 8) | ((w1 & 0xff) << 8); + out2 = (w1 >> 8) | ((w2 & 0xff) << 8); + out4 = (w2 >> 8); + + /* Program the active TX gain (id 7) for each core. */ + for (core = 0; core < 3; core++) { + u16 base = 0x100 + core * 0x40; + + b43_phy_ac_table_write_bulk(dev, 7, base + 0, 16, 1, &out0); + b43_phy_ac_table_write_bulk(dev, 7, base + 1, 16, 1, &out2); + b43_phy_ac_table_write_bulk(dev, 7, base + 2, 16, 1, &out4); + } + + /* Enable the TX gain override (gate 0x19e bit 2). */ + b43_phy_maskset(dev, 0x19e, (u16)~0x0002, 0x0002); +} + +/************************************************** + * Initialisation table loader + **************************************************/ + +/* Mirrors wl's per-PHY-rev table init loop: replay every descriptor in order. + * Only the rev0 set (BCM4360 / radio 2069) is ported so far. + */ +void b43_phy_ac_tables_init(struct b43_wldev *dev) +{ + const struct b43_phy_ac_tbl *t; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_phy_ac_tbls_rev0); i++) { + t = &b43_phy_ac_tbls_rev0[i]; + b43_phy_ac_table_write_bulk(dev, t->id, t->offset, t->width, + t->count, t->data); + } +} + +/************************************************** + * Per-channel data (chan_tuning_20691rev_1) + * + * wl stores a {channel, centre-frequency} pair per supported channel; the + * synthesizer programming derives the 2069 PLL settings from the frequency. + **************************************************/ + +static const struct b43_phy_ac_chan b43_phy_ac_chantbl_2069rev1[] = { + { .channel = 184, .freq_mhz = 4920 }, + { .channel = 185, .freq_mhz = 4925 }, + { .channel = 187, .freq_mhz = 4935 }, + { .channel = 188, .freq_mhz = 4940 }, + { .channel = 189, .freq_mhz = 4945 }, + { .channel = 192, .freq_mhz = 4960 }, + { .channel = 196, .freq_mhz = 4980 }, + { .channel = 207, .freq_mhz = 5035 }, + { .channel = 208, .freq_mhz = 5040 }, + { .channel = 209, .freq_mhz = 5045 }, + { .channel = 210, .freq_mhz = 5050 }, + { .channel = 212, .freq_mhz = 5060 }, + { .channel = 216, .freq_mhz = 5080 }, + { .channel = 34, .freq_mhz = 5170 }, + { .channel = 36, .freq_mhz = 5180 }, + { .channel = 38, .freq_mhz = 5190 }, + { .channel = 40, .freq_mhz = 5200 }, + { .channel = 42, .freq_mhz = 5210 }, + { .channel = 44, .freq_mhz = 5220 }, + { .channel = 46, .freq_mhz = 5230 }, + { .channel = 48, .freq_mhz = 5240 }, + { .channel = 52, .freq_mhz = 5260 }, + { .channel = 54, .freq_mhz = 5270 }, + { .channel = 56, .freq_mhz = 5280 }, + { .channel = 58, .freq_mhz = 5290 }, + { .channel = 60, .freq_mhz = 5300 }, + { .channel = 62, .freq_mhz = 5310 }, + { .channel = 64, .freq_mhz = 5320 }, + { .channel = 100, .freq_mhz = 5500 }, + { .channel = 102, .freq_mhz = 5510 }, + { .channel = 104, .freq_mhz = 5520 }, + { .channel = 106, .freq_mhz = 5530 }, + { .channel = 108, .freq_mhz = 5540 }, + { .channel = 110, .freq_mhz = 5550 }, + { .channel = 112, .freq_mhz = 5560 }, + { .channel = 114, .freq_mhz = 5570 }, + { .channel = 116, .freq_mhz = 5580 }, + { .channel = 118, .freq_mhz = 5590 }, + { .channel = 120, .freq_mhz = 5600 }, + { .channel = 122, .freq_mhz = 5610 }, + { .channel = 124, .freq_mhz = 5620 }, + { .channel = 126, .freq_mhz = 5630 }, + { .channel = 128, .freq_mhz = 5640 }, + { .channel = 130, .freq_mhz = 5650 }, + { .channel = 132, .freq_mhz = 5660 }, + { .channel = 134, .freq_mhz = 5670 }, + { .channel = 136, .freq_mhz = 5680 }, + { .channel = 138, .freq_mhz = 5690 }, + { .channel = 140, .freq_mhz = 5700 }, + { .channel = 142, .freq_mhz = 5710 }, + { .channel = 144, .freq_mhz = 5720 }, + { .channel = 145, .freq_mhz = 5725 }, + { .channel = 146, .freq_mhz = 5730 }, + { .channel = 147, .freq_mhz = 5735 }, + { .channel = 148, .freq_mhz = 5740 }, + { .channel = 149, .freq_mhz = 5745 }, + { .channel = 151, .freq_mhz = 5755 }, + { .channel = 153, .freq_mhz = 5765 }, + { .channel = 155, .freq_mhz = 5775 }, + { .channel = 157, .freq_mhz = 5785 }, + { .channel = 159, .freq_mhz = 5795 }, + { .channel = 161, .freq_mhz = 5805 }, + { .channel = 165, .freq_mhz = 5825 }, + { .channel = 1, .freq_mhz = 2412 }, + { .channel = 2, .freq_mhz = 2417 }, + { .channel = 3, .freq_mhz = 2422 }, + { .channel = 4, .freq_mhz = 2427 }, + { .channel = 5, .freq_mhz = 2432 }, + { .channel = 6, .freq_mhz = 2437 }, + { .channel = 7, .freq_mhz = 2442 }, + { .channel = 8, .freq_mhz = 2447 }, + { .channel = 9, .freq_mhz = 2452 }, + { .channel = 10, .freq_mhz = 2457 }, + { .channel = 11, .freq_mhz = 2462 }, + { .channel = 12, .freq_mhz = 2467 }, + { .channel = 13, .freq_mhz = 2472 }, + { .channel = 14, .freq_mhz = 2484 }, +}; + +const struct b43_phy_ac_chan *b43_phy_ac_chan_lookup(struct b43_wldev *dev, + unsigned int channel) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_phy_ac_chantbl_2069rev1); i++) + if (b43_phy_ac_chantbl_2069rev1[i].channel == channel) + return &b43_phy_ac_chantbl_2069rev1[i]; + return NULL; +} + +/************************************************** + * TX gain tables (acphy_txgain_*_2069rev0) + * + * Uploaded to PHY table id 0x20 (48-bit, 128 entries) by wl's txgain setup + * (static in the wlc_phy_set_analog_tx_lpf region, table selected by radio + * rev at pi+0x16c). Only the radio-2069 rev0 set is ported. + **************************************************/ + +/* TX gain tables (id 0x20, 48-bit, 128 entries), radio 2069 rev0. + * Each entry is 3 u16 words in {DATA3, DATA2, DATA1} order. */ +static const u16 b43_acphy_txgain_ipa_2g_2069rev0[] = { + 0x0044, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x0030, 0xefff, 0xf7ff, + 0x002f, 0xefff, 0xf7f7, + 0x0030, 0xefff, 0xf7e7, + 0x0030, 0xefff, 0xf7df, + 0x0030, 0xefff, 0xf7d7, + 0x0030, 0xefff, 0xf7cf, + 0x0030, 0xefff, 0xf7c7, + 0x0030, 0xefff, 0xf7bf, + 0x0030, 0xefff, 0xf7b7, + 0x002f, 0xefff, 0xf7b7, + 0x002f, 0xefff, 0xf7af, + 0x002f, 0xefff, 0xf7a7, + 0x0030, 0xefff, 0xf79f, + 0x002e, 0xefff, 0xf79f, + 0x002f, 0xefff, 0xf797, + 0x0030, 0xefff, 0xf78f, + 0x002f, 0xefff, 0xf78f, + 0x0030, 0xefff, 0xf787, + 0x002e, 0xefff, 0xf787, + 0x002f, 0xefff, 0xf77f, + 0x002e, 0xefff, 0xf77f, + 0x002f, 0xefff, 0xf777, + 0x002e, 0xefff, 0xf777, + 0x002f, 0xefff, 0xf76f, + 0x002e, 0xefff, 0xf76f, + 0x002f, 0xefff, 0xf767, + 0x002e, 0xefff, 0xf767, + 0x0030, 0xefff, 0xf75f, + 0x002f, 0xefff, 0xf75f, + 0x002d, 0xefff, 0xf75f, + 0x002f, 0xefff, 0xf757, + 0x002e, 0xefff, 0xf757, + 0x002d, 0xefff, 0xf757, + 0x0030, 0xefff, 0xf74f, + 0x002e, 0xefff, 0xf74f, + 0x002d, 0xefff, 0xf74f, + 0x002c, 0xefff, 0xf74f, + 0x002f, 0xefff, 0xf747, + 0x002e, 0xefff, 0xf747, + 0x002c, 0xefff, 0xf747, + 0x0030, 0xefff, 0xf73f, + 0x002e, 0xefff, 0xf73f, + 0x002d, 0xefff, 0xf73f, + 0x002c, 0xefff, 0xf73f, + 0x0030, 0xefff, 0xf737, + 0x002f, 0xefff, 0xf737, + 0x002d, 0xefff, 0xf737, + 0x002c, 0xefff, 0xf737, + 0x002b, 0xefff, 0xf737, + 0x002a, 0xefff, 0xf737, + 0x002f, 0xefff, 0xf72f, + 0x002e, 0xefff, 0xf72f, + 0x002d, 0xefff, 0xf72f, + 0x002b, 0xefff, 0xf72f, + 0x002a, 0xefff, 0xf72f, + 0x0029, 0xefff, 0xf72f, + 0x0030, 0xefff, 0xf727, + 0x002e, 0xefff, 0xf727, + 0x002d, 0xefff, 0xf727, + 0x002c, 0xefff, 0xf727, + 0x002a, 0xefff, 0xf727, + 0x0029, 0xefff, 0xf727, + 0x0030, 0xefff, 0xf71f, + 0x002f, 0xefff, 0xf71f, + 0x002d, 0xefff, 0xf71f, + 0x002c, 0xefff, 0xf71f, + 0x002b, 0xefff, 0xf71f, + 0x0029, 0xefff, 0xf71f, + 0x0028, 0xefff, 0xf71f, + 0x0027, 0xefff, 0xf71f, + 0x0026, 0xefff, 0xf71f, + 0x0025, 0xefff, 0xf71f, + 0x002f, 0xefff, 0xf717, + 0x002d, 0xefff, 0xf717, + 0x002c, 0xefff, 0xf717, + 0x002b, 0xefff, 0xf717, + 0x002a, 0xefff, 0xf717, + 0x0028, 0xefff, 0xf717, + 0x0027, 0xefff, 0xf717, + 0x0026, 0xefff, 0xf717, + 0x0025, 0xefff, 0xf717, + 0x0024, 0xefff, 0xf717, + 0x0023, 0xefff, 0xf717, + 0x0022, 0xefff, 0xf717, + 0x0030, 0xefff, 0xf710, + 0x0030, 0xefff, 0xf70f, + 0x002e, 0xefff, 0xf70f, + 0x002d, 0xefff, 0xf70f, + 0x002c, 0xefff, 0xf70f, + 0x002a, 0xefff, 0xf70f, + 0x0029, 0xefff, 0xf70f, + 0x0028, 0xefff, 0xf70f, + 0x0027, 0xefff, 0xf70f, + 0x0026, 0xefff, 0xf70f, + 0x0025, 0xefff, 0xf70f, + 0x0024, 0xefff, 0xf70f, + 0x0023, 0xefff, 0xf70f, + 0x0022, 0xefff, 0xf70f, + 0x0021, 0xefff, 0xf70f, + 0x0020, 0xefff, 0xf70f, + 0x001f, 0xefff, 0xf70f, + 0x001e, 0xefff, 0xf70f, + 0x001d, 0xefff, 0xf70f, + 0x001c, 0xefff, 0xf70f, + 0x001c, 0xefff, 0xf70f, + 0x001b, 0xefff, 0xf70f, + 0x001a, 0xefff, 0xf70f, + 0x0019, 0xefff, 0xf70f, + 0x0019, 0xefff, 0xf70f, + 0x0018, 0xefff, 0xf70f, + 0x0017, 0xefff, 0xf70f, + 0x0016, 0xefff, 0xf70f, + 0x0016, 0xefff, 0xf70f, + 0x0015, 0xefff, 0xf70f, + 0x0015, 0xefff, 0xf70f, + 0x0014, 0xefff, 0xf70f, +}; +static const u16 b43_acphy_txgain_ipa_5g_2069rev0[] = { + 0x00ff, 0xffff, 0xffff, + 0x0042, 0xffff, 0xf7f7, + 0x0040, 0xffff, 0xf7ef, + 0x003f, 0xffff, 0xf7e7, + 0x003d, 0xffff, 0xf7df, + 0x003c, 0xffff, 0xf7d7, + 0x003b, 0xffff, 0xf7cf, + 0x003a, 0xffff, 0xf7c7, + 0x0039, 0xffff, 0xf7bf, + 0x0038, 0xffff, 0xf7b7, + 0x0037, 0xffff, 0xf7af, + 0x0036, 0xffff, 0xf7a7, + 0x0036, 0xffff, 0xf79f, + 0x0035, 0xffff, 0xf797, + 0x0035, 0xffff, 0xf78f, + 0x0035, 0xffff, 0xf787, + 0x0035, 0xffff, 0xf77f, + 0x0035, 0xffff, 0xf777, + 0x0036, 0xffff, 0xf76f, + 0x0037, 0xffff, 0xf767, + 0x0038, 0xffff, 0xf75f, + 0x003a, 0xffff, 0xf757, + 0x003c, 0xffff, 0xf74f, + 0x003f, 0xffff, 0xf747, + 0x003b, 0xffff, 0xf747, + 0x003f, 0xffff, 0xf73f, + 0x003c, 0xffff, 0xf73f, + 0x0038, 0xffff, 0xf73f, + 0x003d, 0xffff, 0xf737, + 0x0039, 0xffff, 0xf737, + 0x003f, 0xffff, 0xf72f, + 0x003c, 0xffff, 0xf72f, + 0x0038, 0xffff, 0xf72f, + 0x0040, 0xffff, 0xf727, + 0x003c, 0xffff, 0xf727, + 0x0039, 0xffff, 0xf727, + 0x0036, 0xffff, 0xf727, + 0x0033, 0xffff, 0xf727, + 0x003c, 0xffff, 0xf71f, + 0x0039, 0xffff, 0xf71f, + 0x0036, 0xffff, 0xf71f, + 0x0033, 0xffff, 0xf71f, + 0x0030, 0xffff, 0xf71f, + 0x003d, 0xffff, 0xf717, + 0x0039, 0xffff, 0xf717, + 0x0036, 0xffff, 0xf717, + 0x0033, 0xffff, 0xf717, + 0x0030, 0xffff, 0xf717, + 0x002e, 0xffff, 0xf717, + 0x002b, 0xffff, 0xf717, + 0x003e, 0xffff, 0xf70f, + 0x003b, 0xffff, 0xf70f, + 0x0037, 0xffff, 0xf70f, + 0x0034, 0xffff, 0xf70f, + 0x0031, 0xffff, 0xf70f, + 0x002e, 0xffff, 0xf70f, + 0x002c, 0xffff, 0xf70f, + 0x0029, 0xffff, 0xf70f, + 0x0027, 0xffff, 0xf70f, + 0x0025, 0xffff, 0xf70f, + 0x0023, 0xffff, 0xf70f, + 0x0021, 0xffff, 0xf70f, + 0x001f, 0xffff, 0xf70f, + 0x003e, 0xffff, 0xf707, + 0x003b, 0xffff, 0xf707, + 0x0037, 0xffff, 0xf707, + 0x0034, 0xffff, 0xf707, + 0x0031, 0xffff, 0xf707, + 0x002f, 0xffff, 0xf707, + 0x002c, 0xffff, 0xf707, + 0x002a, 0xffff, 0xf707, + 0x0027, 0xffff, 0xf707, + 0x0025, 0xffff, 0xf707, + 0x0023, 0xffff, 0xf707, + 0x0021, 0xffff, 0xf707, + 0x001f, 0xffff, 0xf707, + 0x001d, 0xffff, 0xf707, + 0x001c, 0xffff, 0xf707, + 0x001a, 0xffff, 0xf707, + 0x0019, 0xffff, 0xf707, + 0x0017, 0xffff, 0xf707, + 0x0016, 0xffff, 0xf707, + 0x0015, 0xffff, 0xf707, + 0x0014, 0xffff, 0xf707, + 0x0013, 0xffff, 0xf707, + 0x0012, 0xffff, 0xf707, + 0x0011, 0xffff, 0xf707, + 0x0010, 0xffff, 0xf707, + 0x000f, 0xffff, 0xf707, + 0x000e, 0xffff, 0xf707, + 0x000d, 0xffff, 0xf707, + 0x000c, 0xffff, 0xf707, + 0x000c, 0xffff, 0xf707, + 0x000b, 0xffff, 0xf707, + 0x000a, 0xffff, 0xf707, + 0x000a, 0xffff, 0xf707, + 0x0009, 0xffff, 0xf707, + 0x0009, 0xffff, 0xf707, + 0x0008, 0xffff, 0xf707, + 0x0008, 0xffff, 0xf707, + 0x0007, 0xffff, 0xf707, + 0x0007, 0xffff, 0xf707, + 0x0007, 0xffff, 0xf707, + 0x0006, 0xffff, 0xf707, + 0x0006, 0xffff, 0xf707, + 0x0006, 0xffff, 0xf707, + 0x0005, 0xffff, 0xf707, + 0x0005, 0xffff, 0xf707, + 0x0005, 0xffff, 0xf707, + 0x0004, 0xffff, 0xf707, + 0x0004, 0xffff, 0xf707, + 0x0004, 0xffff, 0xf707, + 0x0004, 0xffff, 0xf707, + 0x0003, 0xffff, 0xf707, + 0x0003, 0xffff, 0xf707, + 0x0003, 0xffff, 0xf707, + 0x0003, 0xffff, 0xf707, + 0x0003, 0xffff, 0xf707, + 0x0003, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, + 0x0002, 0xffff, 0xf707, +}; +static const u16 b43_acphy_txgain_epa_2g_2069rev0[] = { + 0x0044, 0xffff, 0xa7ff, + 0x0042, 0xffff, 0xa7ff, + 0x0040, 0xffff, 0xa7ff, + 0x0040, 0xffff, 0xa7f7, + 0x003f, 0xffff, 0xa7ef, + 0x0040, 0xffff, 0xa7e7, + 0x0040, 0xffff, 0xa7df, + 0x0040, 0xffff, 0xa7d7, + 0x0040, 0xffff, 0xa7cf, + 0x0041, 0xffff, 0xa7c7, + 0x0041, 0xffff, 0xa7bf, + 0x0041, 0xffff, 0xa7b7, + 0x003f, 0xffff, 0xa7b7, + 0x0040, 0xffff, 0xa7af, + 0x0041, 0xffff, 0xa7a7, + 0x0041, 0xffff, 0xa79f, + 0x003f, 0xffff, 0xa79f, + 0x0041, 0xffff, 0xa797, + 0x003f, 0xffff, 0xa797, + 0x0040, 0xffff, 0xa78f, + 0x003f, 0xffff, 0xa78f, + 0x0040, 0xffff, 0xa787, + 0x003f, 0xffff, 0xa787, + 0x0041, 0xffff, 0xa77f, + 0x003f, 0xffff, 0xa77f, + 0x0041, 0xffff, 0xa777, + 0x003f, 0xffff, 0xa777, + 0x0042, 0xffff, 0xa76f, + 0x0040, 0xffff, 0xa76f, + 0x003e, 0xffff, 0xa76f, + 0x0041, 0xffff, 0xa767, + 0x0040, 0xffff, 0xa767, + 0x0041, 0xffff, 0xa75f, + 0x0040, 0xffff, 0xa75f, + 0x003e, 0xffff, 0xa75f, + 0x0042, 0xffff, 0xa757, + 0x0040, 0xffff, 0xa757, + 0x003e, 0xffff, 0xa757, + 0x0042, 0xffff, 0xa74f, + 0x0040, 0xffff, 0xa74f, + 0x003f, 0xffff, 0xa74f, + 0x003d, 0xffff, 0xa74f, + 0x0041, 0xffff, 0xa747, + 0x0040, 0xffff, 0xa747, + 0x003e, 0xffff, 0xa747, + 0x0043, 0xffff, 0xa73f, + 0x0041, 0xffff, 0xa73f, + 0x0040, 0xffff, 0xa73f, + 0x003e, 0xffff, 0xa73f, + 0x003c, 0xffff, 0xa73f, + 0x0042, 0xffff, 0xa737, + 0x0040, 0xffff, 0xa737, + 0x003f, 0xffff, 0xa737, + 0x003d, 0xffff, 0xa737, + 0x003b, 0xffff, 0xa737, + 0x0043, 0xffff, 0xa72f, + 0x0041, 0xffff, 0xa72f, + 0x0040, 0xffff, 0xa72f, + 0x003e, 0xffff, 0xa72f, + 0x003c, 0xffff, 0xa72f, + 0x003a, 0xffff, 0xa72f, + 0x0044, 0xffff, 0xa727, + 0x0042, 0xffff, 0xa727, + 0x0040, 0xffff, 0xa727, + 0x003f, 0xffff, 0xa727, + 0x003d, 0xffff, 0xa727, + 0x003b, 0xffff, 0xa727, + 0x0046, 0xffff, 0xa71f, + 0x0044, 0xffff, 0xa71f, + 0x0042, 0xffff, 0xa71f, + 0x0040, 0xffff, 0xa71f, + 0x003e, 0xffff, 0xa71f, + 0x003c, 0xffff, 0xa71f, + 0x003b, 0xffff, 0xa71f, + 0x0039, 0xffff, 0xa71f, + 0x0037, 0xffff, 0xa71f, + 0x0049, 0xffff, 0xa717, + 0x0047, 0xffff, 0xa717, + 0x0045, 0xffff, 0xa717, + 0x0043, 0xffff, 0xa717, + 0x0041, 0xffff, 0xa717, + 0x003f, 0xffff, 0xa717, + 0x003d, 0xffff, 0xa717, + 0x003b, 0xffff, 0xa717, + 0x003a, 0xffff, 0xa717, + 0x0038, 0xffff, 0xa717, + 0x0036, 0xffff, 0xa717, + 0x0035, 0xffff, 0xa717, + 0x004d, 0xffff, 0xa70f, + 0x004b, 0xffff, 0xa70f, + 0x0049, 0xffff, 0xa70f, + 0x0047, 0xffff, 0xa70f, + 0x0045, 0xffff, 0xa70f, + 0x0043, 0xffff, 0xa70f, + 0x0041, 0xffff, 0xa70f, + 0x003f, 0xffff, 0xa70f, + 0x003d, 0xffff, 0xa70f, + 0x003b, 0xffff, 0xa70f, + 0x003a, 0xffff, 0xa70f, + 0x0038, 0xffff, 0xa70f, + 0x0036, 0xffff, 0xa70f, + 0x0035, 0xffff, 0xa70f, + 0x0033, 0xffff, 0xa70f, + 0x0032, 0xffff, 0xa70f, + 0x0031, 0xffff, 0xa70f, + 0x002f, 0xffff, 0xa70f, + 0x002e, 0xffff, 0xa70f, + 0x005b, 0xffff, 0xa707, + 0x0058, 0xffff, 0xa707, + 0x0056, 0xffff, 0xa707, + 0x0053, 0xffff, 0xa707, + 0x0051, 0xffff, 0xa707, + 0x004f, 0xffff, 0xa707, + 0x004d, 0xffff, 0xa707, + 0x004a, 0xffff, 0xa707, + 0x0048, 0xffff, 0xa707, + 0x0046, 0xffff, 0xa707, + 0x0044, 0xffff, 0xa707, + 0x0042, 0xffff, 0xa707, + 0x0040, 0xffff, 0xa707, + 0x003f, 0xffff, 0xa707, + 0x003d, 0xffff, 0xa707, + 0x003b, 0xffff, 0xa707, + 0x0039, 0xffff, 0xa707, + 0x0038, 0xffff, 0xa707, + 0x0036, 0xffff, 0xa707, + 0x0035, 0xffff, 0xa707, + 0x0033, 0xffff, 0xa707, +}; +static const u16 b43_acphy_txgain_epa_5g_2069rev0[] = { + 0x0044, 0x7f00, 0xf37f, + 0x0042, 0x7f00, 0xf37f, + 0x0040, 0x7f00, 0xf37f, + 0x003e, 0x7f00, 0xf37f, + 0x0043, 0x7f00, 0xf377, + 0x0041, 0x7f00, 0xf377, + 0x003f, 0x7f00, 0xf377, + 0x003d, 0x7f00, 0xf377, + 0x0042, 0x7f00, 0xf36f, + 0x0040, 0x7f00, 0xf36f, + 0x003e, 0x7f00, 0xf36f, + 0x0043, 0x7f00, 0xf367, + 0x0041, 0x7f00, 0xf367, + 0x0040, 0x7f00, 0xf367, + 0x003e, 0x7f00, 0xf367, + 0x0043, 0x7f00, 0xf35f, + 0x0041, 0x7f00, 0xf35f, + 0x003f, 0x7f00, 0xf35f, + 0x003d, 0x7f00, 0xf35f, + 0x0043, 0x7f00, 0xf357, + 0x0041, 0x7f00, 0xf357, + 0x003f, 0x7f00, 0xf357, + 0x003d, 0x7f00, 0xf357, + 0x0045, 0x7f00, 0xf34f, + 0x0043, 0x7f00, 0xf34f, + 0x0041, 0x7f00, 0xf34f, + 0x003f, 0x7f00, 0xf34f, + 0x003d, 0x7f00, 0xf34f, + 0x0044, 0x7f00, 0xf347, + 0x0042, 0x7f00, 0xf347, + 0x0041, 0x7f00, 0xf347, + 0x003f, 0x7f00, 0xf347, + 0x003d, 0x7f00, 0xf347, + 0x0044, 0x7f00, 0xf33f, + 0x0042, 0x7f00, 0xf33f, + 0x0040, 0x7f00, 0xf33f, + 0x003e, 0x7f00, 0xf33f, + 0x003c, 0x7f00, 0xf33f, + 0x0045, 0x7f00, 0xf337, + 0x0043, 0x7f00, 0xf337, + 0x0041, 0x7f00, 0xf337, + 0x003f, 0x7f00, 0xf337, + 0x003d, 0x7f00, 0xf337, + 0x003c, 0x7f00, 0xf337, + 0x0046, 0x7f00, 0xf32f, + 0x0044, 0x7f00, 0xf32f, + 0x0043, 0x7f00, 0xf32f, + 0x0041, 0x7f00, 0xf32f, + 0x003f, 0x7f00, 0xf32f, + 0x003d, 0x7f00, 0xf32f, + 0x003b, 0x7f00, 0xf32f, + 0x003a, 0x7f00, 0xf32f, + 0x0046, 0x7f00, 0xf327, + 0x0044, 0x7f00, 0xf327, + 0x0042, 0x7f00, 0xf327, + 0x0040, 0x7f00, 0xf327, + 0x003e, 0x7f00, 0xf327, + 0x003c, 0x7f00, 0xf327, + 0x003b, 0x7f00, 0xf327, + 0x0039, 0x7f00, 0xf327, + 0x0047, 0x7f00, 0xf31f, + 0x0045, 0x7f00, 0xf31f, + 0x0043, 0x7f00, 0xf31f, + 0x0041, 0x7f00, 0xf31f, + 0x003f, 0x7f00, 0xf31f, + 0x003d, 0x7f00, 0xf31f, + 0x003b, 0x7f00, 0xf31f, + 0x003a, 0x7f00, 0xf31f, + 0x0038, 0x7f00, 0xf31f, + 0x004a, 0x7f00, 0xf317, + 0x0048, 0x7f00, 0xf317, + 0x0046, 0x7f00, 0xf317, + 0x0044, 0x7f00, 0xf317, + 0x0042, 0x7f00, 0xf317, + 0x0040, 0x7f00, 0xf317, + 0x003e, 0x7f00, 0xf317, + 0x003d, 0x7f00, 0xf317, + 0x003b, 0x7f00, 0xf317, + 0x0039, 0x7f00, 0xf317, + 0x0038, 0x7f00, 0xf317, + 0x0036, 0x7f00, 0xf317, + 0x0034, 0x7f00, 0xf317, + 0x004e, 0x7f00, 0xf30f, + 0x004b, 0x7f00, 0xf30f, + 0x0049, 0x7f00, 0xf30f, + 0x0047, 0x7f00, 0xf30f, + 0x0045, 0x7f00, 0xf30f, + 0x0043, 0x7f00, 0xf30f, + 0x0041, 0x7f00, 0xf30f, + 0x003f, 0x7f00, 0xf30f, + 0x003e, 0x7f00, 0xf30f, + 0x003c, 0x7f00, 0xf30f, + 0x003a, 0x7f00, 0xf30f, + 0x0038, 0x7f00, 0xf30f, + 0x0037, 0x7f00, 0xf30f, + 0x0035, 0x7f00, 0xf30f, + 0x0034, 0x7f00, 0xf30f, + 0x0032, 0x7f00, 0xf30f, + 0x0031, 0x7f00, 0xf30f, + 0x0030, 0x7f00, 0xf30f, + 0x002e, 0x7f00, 0xf30f, + 0x0057, 0x7f00, 0xf307, + 0x0055, 0x7f00, 0xf307, + 0x0052, 0x7f00, 0xf307, + 0x0050, 0x7f00, 0xf307, + 0x004e, 0x7f00, 0xf307, + 0x004b, 0x7f00, 0xf307, + 0x0049, 0x7f00, 0xf307, + 0x0047, 0x7f00, 0xf307, + 0x0045, 0x7f00, 0xf307, + 0x0043, 0x7f00, 0xf307, + 0x0041, 0x7f00, 0xf307, + 0x0040, 0x7f00, 0xf307, + 0x003e, 0x7f00, 0xf307, + 0x003c, 0x7f00, 0xf307, + 0x003a, 0x7f00, 0xf307, + 0x0039, 0x7f00, 0xf307, + 0x0037, 0x7f00, 0xf307, + 0x0035, 0x7f00, 0xf307, + 0x0034, 0x7f00, 0xf307, + 0x0032, 0x7f00, 0xf307, + 0x0031, 0x7f00, 0xf307, + 0x0030, 0x7f00, 0xf307, + 0x002e, 0x7f00, 0xf307, + 0x002d, 0x7f00, 0xf307, + 0x002c, 0x7f00, 0xf307, + 0x002a, 0x7f00, 0xf307, + 0x0029, 0x7f00, 0xf307, +}; + +/* + * Select and upload the TX gain table for the current band. The internal-PA + * vs external-PA choice comes from the board (SROM extpagain); until the + * SROM11 parsing is ported the caller passes it in. wl: the table_write of + * id 0x20 at the tail of the txgain selector. + */ +void b43_phy_ac_upload_tx_gain_table(struct b43_wldev *dev, bool ghz5, bool ipa) +{ + const u16 *table; + + if (ipa) + table = ghz5 ? b43_acphy_txgain_ipa_5g_2069rev0 + : b43_acphy_txgain_ipa_2g_2069rev0; + else + table = ghz5 ? b43_acphy_txgain_epa_5g_2069rev0 + : b43_acphy_txgain_epa_2g_2069rev0; + + b43_phy_ac_table_write_bulk(dev, B43_PHY_AC_TBL_TXGAIN, 0, 48, 128, + table); +} + +/************************************************** + * Per-channel radio 2069 tuning table (chan_tuning_2069rev4, radio rev 4) + * + * Selected by wl for radio rev 0 / 20 MHz (dispatch at wlc_phy_get_spurmode + * +0x231, jump table .rodata+0x2cc0f0). Each row is 47 u16 words: + * word[0] = channel, word[1] = centre freq (MHz), word[2..] = pre-computed + * radio register values copied to the 2069 by b43_radio_2069_tune_chan(). + * This is why AC channel tuning needs no divider math: it is a lookup. + **************************************************/ + +/* chan_tuning_2069rev_16_17: 77 channels x 94 bytes (47 u16 words). */ +static const u16 b43_chan_tuning_2069rev4[77][58] = { + { 0x00b8, 0x1338, 0x0005, 0x001e, 0x0a09, 0x0ccf, 0x00a4, 0x0000, 0x0290, 0x0000, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xffff, 0xffff, 0x7068, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ff, 0x0fff, 0x00f0, 0x00a9, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216 }, + { 0x00b9, 0x133d, 0x0005, 0x001e, 0x0a09, 0x0cd3, 0x00a4, 0x2aaa, 0x0290, 0xaaaa, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xffff, 0xffff, 0x7068, 0x3092, 0x0849, 0x162d, 0x0b17, 0x3092, 0x0849, 0x162d, 0x0b17, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ff, 0x0fff, 0x00f0, 0x00a9, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07b6, 0x07b2, 0x07ae, 0x0213, 0x0214, 0x0215 }, + { 0x00bb, 0x1347, 0x0005, 0x001e, 0x0a09, 0x0cd9, 0x00a4, 0x8000, 0x0292, 0x0000, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xffff, 0xffff, 0x7068, 0x01ee, 0x30f7, 0x1c75, 0x0e3a, 0x01ee, 0x30f7, 0x1c75, 0x0e3a, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ff, 0x0fff, 0x00f0, 0x00a9, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07ba, 0x07b6, 0x07b2, 0x0212, 0x0213, 0x0214 }, + { 0x00bc, 0x134c, 0x0005, 0x001e, 0x0a09, 0x0cdd, 0x00a4, 0xaaaa, 0x0292, 0xaaaa, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xffff, 0xffff, 0x7068, 0x3d8a, 0x0ec5, 0x1d7b, 0x0ebe, 0x3d8a, 0x0ec5, 0x1d7b, 0x0ebe, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ff, 0x0fff, 0x00f0, 0x00a9, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214 }, + { 0x00bd, 0x1351, 0x0005, 0x001e, 0x0a09, 0x0cdf, 0x00a4, 0xd555, 0x0293, 0x5555, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xffff, 0xffff, 0x7068, 0x05ef, 0x32f7, 0x1e1f, 0x0f0f, 0x05ef, 0x32f7, 0x1e1f, 0x0f0f, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ff, 0x0fff, 0x00f0, 0x00a9, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07be, 0x07ba, 0x07b6, 0x0211, 0x0212, 0x0213 }, + { 0x00c0, 0x1360, 0x0005, 0x001e, 0x0a09, 0x0ce9, 0x00a5, 0x5555, 0x0295, 0x5555, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xffff, 0xffff, 0x7068, 0x05a6, 0x32d3, 0x1f17, 0x0f8b, 0x05a6, 0x32d3, 0x1f17, 0x0f8b, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ff, 0x0fff, 0x00f0, 0x0099, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212 }, + { 0x00c4, 0x1374, 0x0005, 0x001e, 0x0a09, 0x0cf7, 0x00a6, 0x0000, 0x0298, 0x0000, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xffff, 0xffff, 0x7068, 0x3308, 0x0984, 0x1f95, 0x0fcb, 0x3308, 0x0984, 0x1f95, 0x0fcb, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ff, 0x0fff, 0x00f0, 0x0098, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f }, + { 0x00cf, 0x13ab, 0x0005, 0x001e, 0x0a09, 0x0d1b, 0x00a7, 0xd555, 0x029f, 0x5555, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xfffc, 0xfcff, 0x7068, 0x3e4f, 0x0f27, 0x1fd9, 0x0fed, 0x3e4f, 0x0f27, 0x1fd9, 0x0fed, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ee, 0x0fef, 0x00f0, 0x0087, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07e2, 0x07de, 0x07da, 0x0208, 0x0209, 0x020a }, + { 0x00d0, 0x13b0, 0x0005, 0x001e, 0x0a09, 0x0d1f, 0x00a8, 0x0000, 0x02a0, 0x0000, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xfffc, 0xfcff, 0x7068, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ee, 0x0fef, 0x00f0, 0x0087, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209 }, + { 0x00d1, 0x13b5, 0x0005, 0x001e, 0x0a09, 0x0d23, 0x00a8, 0x2aaa, 0x02a0, 0xaaaa, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xfffc, 0xfcff, 0x7068, 0x31fb, 0x38fe, 0x15a6, 0x0ad3, 0x31fb, 0x38fe, 0x15a6, 0x0ad3, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ee, 0x0fef, 0x00f0, 0x0087, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07e6, 0x07e2, 0x07de, 0x0207, 0x0208, 0x0209 }, + { 0x00d2, 0x13ba, 0x0005, 0x001e, 0x0a09, 0x0d25, 0x00a8, 0x5555, 0x02a1, 0x5555, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xfffb, 0xfbff, 0x7068, 0x32ab, 0x3955, 0x19f4, 0x0cfa, 0x32ab, 0x3955, 0x19f4, 0x0cfa, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ee, 0x0fef, 0x00f0, 0x0087, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208 }, + { 0x00d4, 0x13c4, 0x0005, 0x001e, 0x0a09, 0x0d2d, 0x00a8, 0xaaaa, 0x02a2, 0xaaaa, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xfffb, 0xfbff, 0x7068, 0x3cf7, 0x3e7b, 0x1cc8, 0x0e64, 0x3cf7, 0x3e7b, 0x1cc8, 0x0e64, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ee, 0x0fdf, 0x00f0, 0x0087, 0x0fac, 0xc0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207 }, + { 0x00d8, 0x13d8, 0x0005, 0x001e, 0x0a09, 0x0d39, 0x00a9, 0x5555, 0x02a5, 0x5555, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0005, 0x0005, 0xff05, 0xfffa, 0xfaff, 0x7068, 0x05c4, 0x32e2, 0x1e5b, 0x0f2d, 0x05c4, 0x32e2, 0x1e5b, 0x0f2d, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00ee, 0x0fde, 0x00f0, 0x0077, 0x0eac, 0xb0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205 }, + { 0x0022, 0x1432, 0x0005, 0x001e, 0x0a09, 0x0d75, 0x00ac, 0x5555, 0x02b1, 0x5555, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0006, 0x0006, 0xff06, 0xfff5, 0xf5fc, 0x7068, 0x083b, 0x341e, 0x1fb1, 0x0fd8, 0x083b, 0x341e, 0x1fb1, 0x0fd8, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00cc, 0x0ebc, 0x00f0, 0x0079, 0x0bac, 0xa0ff, 0x18c5, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc }, + { 0x0024, 0x143c, 0x0005, 0x001e, 0x0a09, 0x0d7d, 0x00ac, 0xaaaa, 0x02b2, 0xaaaa, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0006, 0x0006, 0xff06, 0xfff5, 0xf5fb, 0x7068, 0x3d68, 0x0eb4, 0x1fa1, 0x0fd1, 0x3d68, 0x0eb4, 0x1fa1, 0x0fd1, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00c9, 0x0b9a, 0x00f0, 0x0079, 0x0cac, 0xa0ff, 0x18c4, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb }, + { 0x0026, 0x1446, 0x0005, 0x001e, 0x0a09, 0x0d83, 0x00ad, 0x0000, 0x02b4, 0x0000, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0006, 0x0006, 0xff06, 0xfff4, 0xf4fb, 0x7068, 0x0fa9, 0x07d5, 0x1f92, 0x0fc9, 0x0fa9, 0x07d5, 0x1f92, 0x0fc9, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00c9, 0x0b9a, 0x00f0, 0x0079, 0x0cac, 0xa0ff, 0x18c4, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa }, + { 0x0028, 0x1450, 0x0005, 0x001e, 0x0a09, 0x0d89, 0x00ad, 0x5555, 0x02b5, 0x5555, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3505, 0x0006, 0x0006, 0xff06, 0xfff4, 0xf4fa, 0x7068, 0x013b, 0x009e, 0x1f82, 0x0fc1, 0x013b, 0x009e, 0x1f82, 0x0fc1, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00c9, 0x0b89, 0x00f0, 0x0079, 0x0bac, 0xa0ff, 0x18c4, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9 }, + { 0x002a, 0x145a, 0x0005, 0x001e, 0x0a09, 0x0d91, 0x00ad, 0xaaaa, 0x02b6, 0xaaaa, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfff4, 0xf3fa, 0x7068, 0x30cb, 0x3865, 0x1f72, 0x0fb9, 0x30cb, 0x3865, 0x1f72, 0x0fb9, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00c9, 0x0b89, 0x00f0, 0x0079, 0x0bac, 0xa0ff, 0x18c4, 0x0001, 0x0188, 0x010c, 0x03e0, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8 }, + { 0x002c, 0x1464, 0x0005, 0x001e, 0x0a09, 0x0d97, 0x00ae, 0x0000, 0x02b8, 0x0000, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfff3, 0xf3f9, 0x7068, 0x3dea, 0x0ef5, 0x1f63, 0x0fb2, 0x3dea, 0x0ef5, 0x1f63, 0x0fb2, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00c9, 0x0b89, 0x00f0, 0x0079, 0x0bac, 0xa0ff, 0x18c4, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7 }, + { 0x002e, 0x146e, 0x0005, 0x001e, 0x0a09, 0x0d9d, 0x00ae, 0x5555, 0x02b9, 0x5555, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfff3, 0xf3f9, 0x7068, 0x09af, 0x04d8, 0x1f54, 0x0faa, 0x09af, 0x04d8, 0x1f54, 0x0faa, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00b8, 0x0b89, 0x00f0, 0x0079, 0x0bac, 0xa0ff, 0x18c4, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6 }, + { 0x0030, 0x1478, 0x0005, 0x001e, 0x0a09, 0x0da5, 0x00ae, 0xaaaa, 0x02ba, 0xaaaa, 0x0000, 0x0488, 0x0cff, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfff2, 0xf2f8, 0x7068, 0x338b, 0x39c5, 0x1f44, 0x0fa2, 0x338b, 0x39c5, 0x1f44, 0x0fa2, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00b8, 0x0b89, 0x00f0, 0x0069, 0x0aac, 0xa0ff, 0x18c3, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5 }, + { 0x0034, 0x148c, 0x0005, 0x001e, 0x0a09, 0x0db1, 0x00af, 0x5555, 0x02bd, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfff1, 0xf1f7, 0x7068, 0x3294, 0x394a, 0x1ff2, 0x0ff9, 0x3294, 0x394a, 0x1ff2, 0x0ff9, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00b8, 0x0a78, 0x00f0, 0x0068, 0x0aac, 0x90ff, 0x18c3, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3 }, + { 0x0036, 0x1496, 0x0005, 0x001e, 0x0a09, 0x0db9, 0x00af, 0xaaaa, 0x02be, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfff1, 0xf1f7, 0x7068, 0x02bc, 0x015e, 0x1fd0, 0x0fe8, 0x02bc, 0x015e, 0x1fd0, 0x0fe8, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00b8, 0x0a78, 0x00f0, 0x0068, 0x0aac, 0x90ff, 0x18c3, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2 }, + { 0x0038, 0x14a0, 0x0005, 0x001e, 0x0a09, 0x0dbf, 0x00b0, 0x0000, 0x02c0, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfff0, 0xf0f6, 0x7068, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00a8, 0x0a78, 0x00f0, 0x0068, 0x0aac, 0x80ff, 0x18c3, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1 }, + { 0x003a, 0x14aa, 0x0005, 0x001e, 0x0a09, 0x0dc5, 0x00b0, 0x5555, 0x02c1, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfff0, 0xf0f6, 0x7068, 0x0941, 0x34a1, 0x1ef9, 0x0f7c, 0x0941, 0x34a1, 0x1ef9, 0x0f7c, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00a8, 0x0a78, 0x00f0, 0x0068, 0x0aac, 0x80ff, 0x18c3, 0x0001, 0x0188, 0x010c, 0x03e0, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0 }, + { 0x003c, 0x14b4, 0x0005, 0x001e, 0x0a09, 0x0dcd, 0x00b0, 0xaaaa, 0x02c2, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xffef, 0xeff5, 0x7068, 0x07f8, 0x03fc, 0x1eea, 0x0f75, 0x07f8, 0x03fc, 0x1eea, 0x0f75, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00a8, 0x0a78, 0x00f0, 0x0068, 0x09ac, 0x80ff, 0x18c3, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0 }, + { 0x003e, 0x14be, 0x0005, 0x001e, 0x0a09, 0x0dd3, 0x00b1, 0x0000, 0x02c4, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xffef, 0xeff5, 0x7068, 0x03eb, 0x31f5, 0x1edb, 0x0f6d, 0x03eb, 0x31f5, 0x1edb, 0x0f6d, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00a9, 0x0a78, 0x00f0, 0x0068, 0x09ac, 0x80ff, 0x18c3, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef }, + { 0x0040, 0x14c8, 0x0005, 0x001e, 0x0a09, 0x0dd9, 0x00b1, 0x5555, 0x02c5, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xffee, 0xeef4, 0x7068, 0x3f47, 0x3fa4, 0x1ecc, 0x0f66, 0x3f47, 0x3fa4, 0x1ecc, 0x0f66, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x00a7, 0x0967, 0x00f0, 0x0068, 0x09ac, 0x80ff, 0x18c3, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee }, + { 0x0064, 0x157c, 0x0005, 0x001e, 0x0a09, 0x0e51, 0x00b7, 0x5555, 0x02dd, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfee6, 0xe6ec, 0x7068, 0x3410, 0x0a08, 0x1f5b, 0x0fae, 0x3410, 0x0a08, 0x1f5b, 0x0fae, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0084, 0x0633, 0x00f0, 0x0046, 0x05ac, 0x50ff, 0x18c1, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd }, + { 0x0066, 0x1586, 0x0005, 0x001e, 0x0a09, 0x0e59, 0x00b7, 0xaaaa, 0x02de, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfee6, 0xe6ec, 0x7068, 0x3b3a, 0x0d9d, 0x1fe9, 0x0ff5, 0x3b3a, 0x0d9d, 0x1fe9, 0x0ff5, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0084, 0x0633, 0x00f0, 0x0046, 0x05ac, 0x50ff, 0x18c1, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd }, + { 0x0068, 0x1590, 0x0005, 0x001e, 0x0a09, 0x0e5f, 0x00b8, 0x0000, 0x02e0, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfde6, 0xe6eb, 0x7068, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0083, 0x0623, 0x00f0, 0x0046, 0x05ac, 0x50ff, 0x18c1, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc }, + { 0x006a, 0x159a, 0x0005, 0x001e, 0x0a09, 0x0e65, 0x00b8, 0x5555, 0x02e1, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfde5, 0xe5eb, 0x7068, 0x0c8f, 0x3647, 0x1da1, 0x0ed0, 0x0c8f, 0x3647, 0x1da1, 0x0ed0, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0083, 0x0623, 0x00f0, 0x0046, 0x05ac, 0x50ff, 0x18c1, 0x0001, 0x0188, 0x010c, 0x03e0, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db }, + { 0x006c, 0x15a4, 0x0005, 0x001e, 0x0a09, 0x0e6d, 0x00b8, 0xaaaa, 0x02e2, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfde5, 0xe5eb, 0x7068, 0x02a8, 0x3154, 0x1d93, 0x0ec9, 0x02a8, 0x3154, 0x1d93, 0x0ec9, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0073, 0x0523, 0x00f0, 0x0045, 0x05ac, 0x50ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da }, + { 0x006e, 0x15ae, 0x0005, 0x001e, 0x0a09, 0x0e73, 0x00b9, 0x0000, 0x02e4, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfce4, 0xe4ea, 0x7068, 0x3641, 0x0b21, 0x1d85, 0x0ec3, 0x3641, 0x0b21, 0x1d85, 0x0ec3, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0073, 0x0523, 0x00f0, 0x0045, 0x05ac, 0x50ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9 }, + { 0x0070, 0x15b8, 0x0005, 0x001e, 0x0a09, 0x0e79, 0x00b9, 0x5555, 0x02e5, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfce4, 0xe4ea, 0x7068, 0x0c34, 0x361a, 0x1f6f, 0x0fb7, 0x0c34, 0x361a, 0x1f6f, 0x0fb7, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0073, 0x0523, 0x00f0, 0x0035, 0x05ac, 0x50ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8 }, + { 0x0072, 0x15c2, 0x0005, 0x001e, 0x0a09, 0x0e81, 0x00b9, 0xaaaa, 0x02e6, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfbe3, 0xe3e9, 0x7068, 0x3099, 0x384c, 0x1ef6, 0x0f7b, 0x3099, 0x384c, 0x1ef6, 0x0f7b, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0073, 0x0523, 0x00f0, 0x0035, 0x05ac, 0x50ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7 }, + { 0x0074, 0x15cc, 0x0005, 0x001e, 0x0a09, 0x0e87, 0x00ba, 0x0000, 0x02e8, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfbe3, 0xe3e9, 0x7068, 0x3075, 0x083a, 0x1ea3, 0x0f52, 0x3075, 0x083a, 0x1ea3, 0x0f52, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0072, 0x0512, 0x00f0, 0x0035, 0x04ac, 0x50ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7 }, + { 0x0076, 0x15d6, 0x0005, 0x001e, 0x0a09, 0x0e8d, 0x00ba, 0x5555, 0x02e9, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfae3, 0xe3e8, 0x7068, 0x3363, 0x39b2, 0x1f90, 0x0fc8, 0x3363, 0x39b2, 0x1f90, 0x0fc8, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0072, 0x0512, 0x00f0, 0x0035, 0x04ac, 0x50ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6 }, + { 0x0078, 0x15e0, 0x0005, 0x001e, 0x0a09, 0x0e95, 0x00ba, 0xaaaa, 0x02ea, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xfae2, 0xe2e8, 0x7068, 0x3b6e, 0x0db7, 0x1f35, 0x0f9b, 0x3b6e, 0x0db7, 0x1f35, 0x0f9b, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0072, 0x0512, 0x00f0, 0x0035, 0x04ac, 0x40ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5 }, + { 0x007a, 0x15ea, 0x0005, 0x001e, 0x0a09, 0x0e9b, 0x00bb, 0x0000, 0x02ec, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf9e2, 0xe2e8, 0x7068, 0x3af6, 0x3d7b, 0x1fdc, 0x0fee, 0x3af6, 0x3d7b, 0x1fdc, 0x0fee, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0072, 0x0512, 0x00f0, 0x0035, 0x04ac, 0x40ff, 0x18c0, 0x0001, 0x0188, 0x010c, 0x03e0, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4 }, + { 0x007c, 0x15f4, 0x0005, 0x001e, 0x0a09, 0x0ea1, 0x00bb, 0x5555, 0x02ed, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf9e1, 0xe1e7, 0x7068, 0x369b, 0x3b4e, 0x1f84, 0x0fc2, 0x369b, 0x3b4e, 0x1f84, 0x0fc2, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0062, 0x0402, 0x00f0, 0x0034, 0x04ac, 0x40ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3 }, + { 0x007e, 0x15fe, 0x0005, 0x001e, 0x0a09, 0x0ea9, 0x00bb, 0xaaaa, 0x02ee, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf8e1, 0xe1e7, 0x7068, 0x3f15, 0x0f8a, 0x1f3b, 0x0f9e, 0x3f15, 0x0f8a, 0x1f3b, 0x0f9e, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0062, 0x0402, 0x00f0, 0x0034, 0x04ac, 0x40ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2 }, + { 0x0080, 0x1608, 0x0005, 0x001e, 0x0a09, 0x0eaf, 0x00bc, 0x0000, 0x02f0, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf8e1, 0xe1e6, 0x7068, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x0000, 0x2000, 0x1000, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0061, 0x0401, 0x00f0, 0x0034, 0x03ac, 0x40ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2 }, + { 0x0082, 0x1612, 0x0005, 0x001e, 0x0a09, 0x0eb5, 0x00bc, 0x5555, 0x02f1, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf7e0, 0xe0e6, 0x7068, 0x0f68, 0x07b4, 0x1d00, 0x0e80, 0x0f68, 0x07b4, 0x1d00, 0x0e80, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0061, 0x0401, 0x00f0, 0x0034, 0x03ac, 0x40ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1 }, + { 0x0084, 0x161c, 0x0005, 0x001e, 0x0a09, 0x0ebd, 0x00bc, 0xaaaa, 0x02f2, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf7e0, 0xe0e5, 0x7068, 0x331c, 0x398e, 0x1cf2, 0x0e79, 0x331c, 0x398e, 0x1cf2, 0x0e79, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0061, 0x0301, 0x00f0, 0x0034, 0x03ac, 0x30ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0 }, + { 0x0086, 0x1626, 0x0005, 0x001e, 0x0a09, 0x0ec3, 0x00bd, 0x0000, 0x02f4, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf7df, 0xdfe5, 0x7068, 0x04d5, 0x026b, 0x1f86, 0x0fc3, 0x04d5, 0x026b, 0x1f86, 0x0fc3, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0061, 0x0301, 0x00f0, 0x0034, 0x03ac, 0x30ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf }, + { 0x0088, 0x1630, 0x0005, 0x001e, 0x0a09, 0x0ec9, 0x00bd, 0x5555, 0x02f5, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf6df, 0xdfe5, 0x7068, 0x0c2b, 0x3616, 0x1ec5, 0x0f62, 0x0c2b, 0x3616, 0x1ec5, 0x0f62, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0061, 0x0301, 0x00f0, 0x0024, 0x03ac, 0x30ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce }, + { 0x008a, 0x163a, 0x0005, 0x001e, 0x0a09, 0x0ed1, 0x00bd, 0xaaaa, 0x02f6, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3504, 0x0006, 0x0006, 0xff06, 0xf6df, 0xdfe4, 0x7068, 0x3397, 0x39cc, 0x1ffe, 0x0fff, 0x3397, 0x39cc, 0x1ffe, 0x0fff, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0061, 0x0301, 0x00f0, 0x0024, 0x03ac, 0x30ff, 0x18c0, 0x0001, 0x0188, 0x010c, 0x03e0, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce }, + { 0x008c, 0x1644, 0x0005, 0x001e, 0x0a09, 0x0ed7, 0x00be, 0x0000, 0x02f8, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf5de, 0xdee4, 0x7068, 0x33f7, 0x09fc, 0x1f5b, 0x0fae, 0x33f7, 0x09fc, 0x1f5b, 0x0fae, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0300, 0x00f0, 0x0024, 0x03ac, 0x30ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd }, + { 0x008e, 0x164e, 0x0005, 0x001e, 0x0a09, 0x0edd, 0x00be, 0x5555, 0x02f9, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf5de, 0xdee3, 0x7068, 0x0d7d, 0x36bf, 0x1ee7, 0x0f73, 0x0d7d, 0x36bf, 0x1ee7, 0x0f73, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0300, 0x00f0, 0x0024, 0x03ac, 0x30ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc }, + { 0x0090, 0x1658, 0x0005, 0x001e, 0x0a09, 0x0ee5, 0x00be, 0xaaaa, 0x02fa, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf4dd, 0xdde3, 0x7068, 0x381b, 0x0c0e, 0x1f9b, 0x0fce, 0x381b, 0x0c0e, 0x1f9b, 0x0fce, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0300, 0x00f0, 0x0024, 0x03ac, 0x30ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb }, + { 0x0091, 0x165d, 0x0005, 0x001e, 0x0a09, 0x0ee7, 0x00be, 0xd555, 0x02fb, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf4dd, 0xdde3, 0x7068, 0x36ca, 0x0b65, 0x1f63, 0x0fb2, 0x36ca, 0x0b65, 0x1f63, 0x0fb2, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0300, 0x00f0, 0x0023, 0x02ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb }, + { 0x0092, 0x1662, 0x0005, 0x001e, 0x0a09, 0x0eeb, 0x00bf, 0x0000, 0x02fc, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf4dd, 0xdde3, 0x7068, 0x34de, 0x0a6f, 0x1f31, 0x0f99, 0x34de, 0x0a6f, 0x1f31, 0x0f99, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0200, 0x00f0, 0x0023, 0x02ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca }, + { 0x0093, 0x1667, 0x0005, 0x001e, 0x0a09, 0x0eef, 0x00bf, 0x2aaa, 0x02fc, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf4dd, 0xdde2, 0x7068, 0x024d, 0x0127, 0x1fee, 0x0ff7, 0x024d, 0x0127, 0x1fee, 0x0ff7, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0200, 0x00f0, 0x0023, 0x02ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca }, + { 0x0094, 0x166c, 0x0005, 0x001e, 0x0a09, 0x0ef1, 0x00bf, 0x5555, 0x02fd, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf4dd, 0xdde2, 0x7068, 0x3e54, 0x0f2a, 0x1fb7, 0x0fdc, 0x3e54, 0x0f2a, 0x1fb7, 0x0fdc, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0200, 0x00f0, 0x0023, 0x02ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9 }, + { 0x0095, 0x1671, 0x0005, 0x001e, 0x0a09, 0x0ef5, 0x00bf, 0x8000, 0x02fe, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf3dc, 0xdce2, 0x7068, 0x3694, 0x0b4a, 0x1f85, 0x0fc3, 0x3694, 0x0b4a, 0x1f85, 0x0fc3, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0200, 0x00f0, 0x0023, 0x02ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9 }, + { 0x0097, 0x167b, 0x0005, 0x001e, 0x0a09, 0x0efb, 0x00bf, 0xd555, 0x02ff, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf3dc, 0xdce2, 0x7068, 0x035e, 0x31af, 0x1ff1, 0x0ff8, 0x035e, 0x31af, 0x1ff1, 0x0ff8, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0051, 0x0200, 0x00f0, 0x0023, 0x01ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8 }, + { 0x0099, 0x1685, 0x0005, 0x001e, 0x0a09, 0x0f03, 0x00c0, 0x2aaa, 0x0300, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf2dc, 0xdce1, 0x7068, 0x34c2, 0x0a61, 0x1c6b, 0x0e36, 0x34c2, 0x0a61, 0x1c6b, 0x0e36, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0041, 0x0200, 0x00f0, 0x0023, 0x01ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8 }, + { 0x009b, 0x168f, 0x0005, 0x001e, 0x0a09, 0x0f09, 0x00c0, 0x8000, 0x0302, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf2db, 0xdbe1, 0x7068, 0x045a, 0x322d, 0x1c5f, 0x0e2f, 0x045a, 0x322d, 0x1c5f, 0x0e2f, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0041, 0x0200, 0x00f0, 0x0023, 0x01ac, 0x20ff, 0x18c0, 0x0001, 0x0188, 0x010c, 0x03e0, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7 }, + { 0x009d, 0x1699, 0x0005, 0x001e, 0x0a09, 0x0f0f, 0x00c0, 0xd555, 0x0303, 0x5555, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf2db, 0xdbe0, 0x7068, 0x039d, 0x01cf, 0x1f78, 0x0fbc, 0x039d, 0x01cf, 0x1f78, 0x0fbc, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0040, 0x0200, 0x00f0, 0x0023, 0x01ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6 }, + { 0x009f, 0x16a3, 0x0005, 0x001e, 0x0a09, 0x0f17, 0x00c1, 0x2aaa, 0x0304, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf1da, 0xdae0, 0x7068, 0x0ee3, 0x3771, 0x1e73, 0x0f39, 0x0ee3, 0x3771, 0x1e73, 0x0f39, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0040, 0x0100, 0x00f0, 0x0023, 0x01ac, 0x20ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5 }, + { 0x00a1, 0x16ad, 0x0005, 0x001e, 0x0a09, 0x0f1d, 0x00c1, 0x8000, 0x0306, 0x0000, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf1da, 0xdae0, 0x7068, 0x3020, 0x3810, 0x1fc0, 0x0fe0, 0x3020, 0x3810, 0x1fc0, 0x0fe0, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0040, 0x0100, 0x00f0, 0x0023, 0x00ac, 0x10ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4 }, + { 0x00a5, 0x16c1, 0x0005, 0x001e, 0x0a09, 0x0f2b, 0x00c2, 0x2aaa, 0x0308, 0xaaaa, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0700, 0x0000, 0x0000, 0x04a4, 0x3503, 0x0006, 0x0006, 0xff06, 0xf0d9, 0xd9df, 0x7068, 0x0941, 0x04a0, 0x1fcc, 0x0fe6, 0x0941, 0x04a0, 0x1fcc, 0x0fe6, 0x0000, 0x2000, 0x007f, 0x0000, 0x0070, 0x0030, 0x0100, 0x00f0, 0x0023, 0x00ac, 0x10ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3 }, + { 0x0001, 0x096c, 0x0005, 0x001e, 0x0a09, 0x0e21, 0x00b4, 0xe666, 0x02d3, 0x9999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xffea, 0xeaf0, 0xd068, 0x3e7a, 0x3f3d, 0x1da4, 0x0ed2, 0x3e7a, 0x3f3d, 0x1da4, 0x0ed2, 0x0790, 0x20e9, 0x037f, 0x0005, 0x0074, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443 }, + { 0x0002, 0x0971, 0x0005, 0x001e, 0x0a09, 0x0e29, 0x00b5, 0x4666, 0x02d5, 0x1999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xffe9, 0xe9ef, 0xd068, 0x053b, 0x329d, 0x1ebb, 0x0f5d, 0x053b, 0x329d, 0x1ebb, 0x0f5d, 0x0790, 0x20d9, 0x027f, 0x0004, 0x0074, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441 }, + { 0x0003, 0x0976, 0x0005, 0x001e, 0x0a09, 0x0e31, 0x00b5, 0xa666, 0x02d6, 0x9999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xffe9, 0xe9ef, 0xd068, 0x0871, 0x3438, 0x1f55, 0x0faa, 0x0871, 0x3438, 0x1f55, 0x0faa, 0x0790, 0x20d8, 0x027f, 0x0004, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f }, + { 0x0004, 0x097b, 0x0005, 0x001e, 0x0a09, 0x0e37, 0x00b6, 0x0666, 0x02d8, 0x1999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xffe8, 0xe8ee, 0xd068, 0x01c6, 0x30e3, 0x1fb3, 0x0fd9, 0x01c6, 0x30e3, 0x1fb3, 0x0fd9, 0x0780, 0x20c8, 0x027f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d }, + { 0x0005, 0x0980, 0x0005, 0x001e, 0x0a09, 0x0e3f, 0x00b6, 0x6666, 0x02d9, 0x9999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xffe8, 0xe8ee, 0xd068, 0x3f40, 0x3fa0, 0x1ff0, 0x0ff8, 0x3f40, 0x3fa0, 0x1ff0, 0x0ff8, 0x0780, 0x20c8, 0x027f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a }, + { 0x0006, 0x0985, 0x0005, 0x001e, 0x0a09, 0x0e47, 0x00b6, 0xc666, 0x02db, 0x1999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xffe7, 0xe7ed, 0xd068, 0x3e6d, 0x3f36, 0x1f18, 0x0f8c, 0x3e6d, 0x3f36, 0x1f18, 0x0f8c, 0x0780, 0x20b7, 0x027f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438 }, + { 0x0007, 0x098a, 0x0005, 0x001e, 0x0a09, 0x0e4f, 0x00b7, 0x2666, 0x02dc, 0x9999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xffe7, 0xe7ed, 0xd068, 0x35da, 0x0aed, 0x1f4f, 0x0fa8, 0x35da, 0x0aed, 0x1f4f, 0x0fa8, 0x0670, 0x20b7, 0x017f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436 }, + { 0x0008, 0x098f, 0x0005, 0x001e, 0x0a09, 0x0e55, 0x00b7, 0x8666, 0x02de, 0x1999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xfee6, 0xe6ec, 0xd068, 0x3d98, 0x3ecc, 0x1f78, 0x0fbc, 0x3d98, 0x3ecc, 0x1f78, 0x0fbc, 0x0670, 0x20a7, 0x017f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434 }, + { 0x0009, 0x0994, 0x0005, 0x001e, 0x0a09, 0x0e5d, 0x00b7, 0xe666, 0x02df, 0x9999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xfee6, 0xe6ec, 0xd068, 0x3667, 0x3b34, 0x1f96, 0x0fcb, 0x3667, 0x3b34, 0x1f96, 0x0fcb, 0x0670, 0x20a7, 0x017f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431 }, + { 0x000a, 0x0999, 0x0005, 0x001e, 0x0a09, 0x0e65, 0x00b8, 0x4666, 0x02e1, 0x1999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xfde5, 0xe5eb, 0xd068, 0x37e1, 0x0bf0, 0x1873, 0x0c3a, 0x37e1, 0x0bf0, 0x1873, 0x0c3a, 0x0670, 0x20a7, 0x017f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f }, + { 0x000b, 0x099e, 0x0005, 0x001e, 0x0a09, 0x0e6d, 0x00b8, 0xa666, 0x02e2, 0x9999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xfde5, 0xe5eb, 0xd068, 0x3600, 0x3b00, 0x1cd6, 0x0e6b, 0x3600, 0x3b00, 0x1cd6, 0x0e6b, 0x0670, 0x2097, 0x017f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d }, + { 0x000c, 0x09a3, 0x0005, 0x001e, 0x0a09, 0x0e73, 0x00b9, 0x0666, 0x02e4, 0x1999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xfce4, 0xe4ea, 0xd068, 0x3a75, 0x0d3b, 0x1e41, 0x0f21, 0x3a75, 0x0d3b, 0x1e41, 0x0f21, 0x0670, 0x2097, 0x017f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b }, + { 0x000d, 0x09a8, 0x0005, 0x001e, 0x0a09, 0x0e7b, 0x00b9, 0x6666, 0x02e5, 0x9999, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xfbe4, 0xe4ea, 0xd068, 0x3ed4, 0x3f6a, 0x1eee, 0x0f77, 0x3ed4, 0x3f6a, 0x1eee, 0x0f77, 0x0570, 0x2087, 0x017f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429 }, + { 0x000e, 0x09b4, 0x0005, 0x001e, 0x0a09, 0x0e8d, 0x00ba, 0x4ccc, 0x02e9, 0x3333, 0x0000, 0x0488, 0x0cef, 0x0000, 0x000b, 0x1d6f, 0x1f00, 0x0580, 0x0000, 0x0000, 0x048c, 0x3503, 0x0006, 0x0006, 0xff06, 0xfae3, 0xe3e8, 0xd068, 0x33a0, 0x39d0, 0x1f1e, 0x0f8f, 0x33a0, 0x39d0, 0x1f1e, 0x0f8f, 0x0570, 0x2076, 0x007f, 0x0003, 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x00ac, 0x00ff, 0x18c0, 0x0001, 0x0185, 0x00ac, 0x03e0, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424 }, +}; + +const u16 *b43_phy_ac_chan_tuning_lookup(struct b43_wldev *dev, + unsigned int channel) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_chan_tuning_2069rev4); i++) + if (b43_chan_tuning_2069rev4[i][0] == channel) + return b43_chan_tuning_2069rev4[i]; + return NULL; +} + +/************************************************** + * RX gain tables (id 0xa) + * + * Static .rodata gain-limit (8-bit, table offset 0x20) and gain-code (16-bit, + * table offset 0x1) sub-tables, reversed from wlc_phy_set_analog_tx_lpf. The + * active set is selected by band/LNA config (pi_ac+0x343). Uploaded to PHY + * table id 0xa. Named by their wl .rodata address. + **************************************************/ + +static const u8 b43_acphy_rxgainlim_2ccc00[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x01, 0x06, 0x0e, 0x04, 0x01, 0x06, 0x0e, 0x04, 0x21, 0x06, 0x2b, 0x04, 0x21, 0x06, 0x2b, +}; +static const u8 b43_acphy_rxgainlim_2ccc20[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x06, 0x0e, 0x02, 0x01, 0x06, 0x0e, 0x02, 0x21, 0x06, 0x2d, 0x02, 0x21, 0x06, 0x2d, +}; +static const u8 b43_acphy_rxgainlim_2ccc40[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x04, 0x03, 0x0b, 0x02, 0x04, 0x03, 0x0b, 0x02, 0x24, 0x03, 0x2d, 0x02, 0x24, 0x03, 0x2d, +}; +static const u8 b43_acphy_rxgainlim_2ccc60[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x06, 0x08, 0x08, 0x01, 0x06, 0x08, 0x08, 0x21, 0x06, 0x23, 0x08, 0x21, 0x06, 0x23, +}; +static const u8 b43_acphy_rxgainlim_2ccc80[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x06, 0x08, 0x08, 0x01, 0x06, 0x08, 0x08, 0x21, 0x06, 0x25, 0x08, 0x21, 0x06, 0x25, +}; +static const u8 b43_acphy_rxgainlim_2ccca0[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x04, 0x03, 0x08, 0x08, 0x04, 0x03, 0x08, 0x08, 0x24, 0x03, 0x25, 0x08, 0x24, 0x03, 0x25, +}; +static const u8 b43_acphy_rxgainlim_2cccc0[32] = { + 0x02, 0x04, 0x03, 0x02, 0x02, 0x04, 0x03, 0x02, 0x22, 0x24, 0x23, 0x25, 0x22, 0x24, 0x23, 0x25, + 0x02, 0x04, 0x03, 0x02, 0x02, 0x04, 0x03, 0x02, 0x22, 0x24, 0x23, 0x25, 0x22, 0x24, 0x23, 0x25, +}; +static const u16 b43_acphy_rxgain_2ccce0[72] = { + 0x0104, 0x0406, 0x0104, 0x0406, 0x2124, 0x2326, 0x2124, 0x2326, + 0x0104, 0x0406, 0x0104, 0x0406, 0x2124, 0x2326, 0x2124, 0x2326, + 0x0102, 0x0206, 0x0102, 0x0206, 0x2122, 0x2526, 0x2122, 0x2526, + 0x0102, 0x0206, 0x0102, 0x0206, 0x2122, 0x2526, 0x2122, 0x2526, + 0x0402, 0x0203, 0x0402, 0x0203, 0x2422, 0x2523, 0x2422, 0x2523, + 0x0402, 0x0203, 0x0402, 0x0203, 0x2422, 0x2523, 0x2422, 0x2523, + 0x0002, 0x0108, 0x0003, 0x0008, 0x0009, 0x0020, 0x0012, 0x0005, + 0x0013, 0x0004, 0x0019, 0x0080, 0x0082, 0x0040, 0x00c0, 0x0040, + 0x0002, 0x0003, 0x0003, 0x0001, 0x0009, 0x0100, 0x0012, 0x0014, +}; +static const u16 b43_acphy_rxgain_2ccd00[60] = { + 0x0102, 0x0206, 0x0102, 0x0206, 0x2122, 0x2526, 0x2122, 0x2526, + 0x0102, 0x0206, 0x0102, 0x0206, 0x2122, 0x2526, 0x2122, 0x2526, + 0x0402, 0x0203, 0x0402, 0x0203, 0x2422, 0x2523, 0x2422, 0x2523, + 0x0402, 0x0203, 0x0402, 0x0203, 0x2422, 0x2523, 0x2422, 0x2523, + 0x0002, 0x0108, 0x0003, 0x0008, 0x0009, 0x0020, 0x0012, 0x0005, + 0x0013, 0x0004, 0x0019, 0x0080, 0x0082, 0x0040, 0x00c0, 0x0040, + 0x0002, 0x0003, 0x0003, 0x0001, 0x0009, 0x0100, 0x0012, 0x0014, + 0x0013, 0x0010, 0x0019, 0x0008, +}; +static const u16 b43_acphy_rxgain_2ccd20[60] = { + 0x0402, 0x0203, 0x0402, 0x0203, 0x2422, 0x2523, 0x2422, 0x2523, + 0x0402, 0x0203, 0x0402, 0x0203, 0x2422, 0x2523, 0x2422, 0x2523, + 0x0002, 0x0108, 0x0003, 0x0008, 0x0009, 0x0020, 0x0012, 0x0005, + 0x0013, 0x0004, 0x0019, 0x0080, 0x0082, 0x0040, 0x00c0, 0x0040, + 0x0002, 0x0003, 0x0003, 0x0001, 0x0009, 0x0100, 0x0012, 0x0014, + 0x0013, 0x0010, 0x0019, 0x0008, 0x0042, 0x0003, 0x0043, 0x0001, + 0x0049, 0x0100, 0x0052, 0x0014, 0x0053, 0x0010, 0x0059, 0x0008, + 0x0080, 0x0003, 0x0081, 0x0001, +}; +static const u16 b43_acphy_rxgain_2ccd60[72] = { + 0x0002, 0x0003, 0x0003, 0x0001, 0x0009, 0x0100, 0x0012, 0x0014, + 0x0013, 0x0010, 0x0019, 0x0008, 0x0042, 0x0003, 0x0043, 0x0001, + 0x0049, 0x0100, 0x0052, 0x0014, 0x0053, 0x0010, 0x0059, 0x0008, + 0x0080, 0x0003, 0x0081, 0x0001, 0x0082, 0x0003, 0x0083, 0x0001, + 0x0084, 0x0001, 0x0085, 0x0001, 0x0086, 0x0001, 0x0087, 0x0001, + 0x0088, 0x0003, 0x0089, 0x0001, 0x008a, 0x0003, 0x008b, 0x0001, + 0x008c, 0x0001, 0x008d, 0x0001, 0x008e, 0x0001, 0x008f, 0x0001, + 0x00a0, 0x0003, 0x00a1, 0x0001, 0x00a2, 0x0003, 0x00a3, 0x0001, + 0x00a4, 0x0001, 0x00a5, 0x0001, 0x00a6, 0x0001, 0x00a7, 0x0001, +}; +static const u16 b43_acphy_rxgain_2cce50[60] = { + 0x0002, 0x0118, 0x0003, 0x0018, 0x0009, 0x0030, 0x0012, 0x0015, + 0x0013, 0x0014, 0x0019, 0x0090, 0x0022, 0x0308, 0x0023, 0x0208, + 0x0029, 0x0220, 0x0032, 0x0205, 0x0033, 0x0204, 0x0039, 0x0280, + 0x0042, 0x0118, 0x0043, 0x0018, 0x0049, 0x0030, 0x0052, 0x0015, + 0x0053, 0x0014, 0x0059, 0x0090, 0x0062, 0x0308, 0x0063, 0x0208, + 0x0069, 0x0220, 0x0072, 0x0205, 0x0073, 0x0204, 0x0079, 0x0280, + 0x0080, 0x0118, 0x0081, 0x0018, 0x0082, 0x0118, 0x0083, 0x0018, + 0x0084, 0x0018, 0x0085, 0x0018, +}; +static const u16 b43_acphy_rxgain_2ccf70[60] = { + 0x0002, 0x0022, 0x0003, 0x0002, 0x0009, 0x0001, 0x0012, 0x0050, + 0x0013, 0x0010, 0x0019, 0x0008, 0x0042, 0x0022, 0x0043, 0x0002, + 0x0049, 0x0001, 0x0052, 0x0050, 0x0053, 0x0010, 0x0059, 0x0008, + 0x0080, 0x0022, 0x0081, 0x0002, 0x0082, 0x0022, 0x0083, 0x0002, + 0x0084, 0x0002, 0x0085, 0x0002, 0x0086, 0x0002, 0x0087, 0x0002, + 0x0088, 0x0022, 0x0089, 0x0002, 0x008a, 0x0022, 0x008b, 0x0002, + 0x008c, 0x0002, 0x008d, 0x0002, 0x008e, 0x0002, 0x008f, 0x0002, + 0x00a0, 0x0022, 0x00a1, 0x0002, +}; +static const u16 b43_acphy_rxgain_2cd0c0[14] = { + 0x0042, 0x0022, 0x0044, 0x0024, 0x0048, 0x0040, 0x0048, 0x0040, + 0x0048, 0x0048, 0x0041, 0x0042, 0x0041, 0x0042, +}; +static const u16 b43_acphy_rxgain_2cd100[14] = { + 0x0012, 0x0032, 0x0050, 0x0070, 0x0081, 0x0082, 0x0083, 0x0086, + 0x0087, 0x0089, 0x0091, 0x0092, 0x0093, 0x0096, +}; +static const u16 b43_acphy_rxgain_2cd180[86] = { + 0x0060, 0x0020, 0x0008, 0x0006, 0x0002, 0x0001, 0x0060, 0x0020, + 0x0008, 0x0006, 0x0002, 0x0060, 0x0020, 0x0060, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0060, 0x0020, 0x0060, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0086, 0x0082, 0x0005, 0x0004, 0x0008, + 0x0030, 0x0020, 0x0040, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0002, 0x0003, 0x0009, 0x0012, 0x0013, 0x0019, 0x0042, 0x0043, + 0x0049, 0x0052, 0x0053, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, + 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, + 0x008d, 0x008e, 0x008f, 0x00c0, 0x00c1, 0x00c4, 0x00c5, 0x00c8, + 0x00c9, 0x00cc, 0x00cd, 0x00d2, 0x00d3, 0x0102, +}; +static const u16 b43_acphy_rxgain_2cd1e0[86] = { + 0x0002, 0x0003, 0x0009, 0x0012, 0x0013, 0x0019, 0x0042, 0x0043, + 0x0049, 0x0052, 0x0053, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, + 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, + 0x008d, 0x008e, 0x008f, 0x00c0, 0x00c1, 0x00c4, 0x00c5, 0x00c8, + 0x00c9, 0x00cc, 0x00cd, 0x00d2, 0x00d3, 0x0102, 0x0103, 0x0109, + 0x0112, 0x0113, 0x0119, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0030, 0x0020, 0x0008, 0x0006, 0x0002, 0x0001, 0x0030, 0x0020, + 0x0008, 0x0006, 0x0002, 0x0030, 0x0020, 0x0030, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0030, 0x0020, 0x0030, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0086, 0x0082, 0x0030, +}; +static const u16 b43_acphy_rxgain_2cd240[86] = { + 0x0030, 0x0020, 0x0008, 0x0006, 0x0002, 0x0001, 0x0030, 0x0020, + 0x0008, 0x0006, 0x0002, 0x0030, 0x0020, 0x0030, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0030, 0x0020, 0x0030, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0086, 0x0082, 0x0030, 0x0020, 0x0008, + 0x0006, 0x0002, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0002, 0x0003, 0x0009, 0x0012, 0x0013, 0x0019, 0x0042, 0x0043, + 0x0049, 0x0052, 0x0053, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, + 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, + 0x008d, 0x008e, 0x008f, 0x00c0, 0x00c1, 0x00c4, 0x00c5, 0x00c8, + 0x00c9, 0x00cc, 0x00cd, 0x00d2, 0x00d3, 0x0102, +}; +static const u16 b43_acphy_rxgain_2cd2a0[86] = { + 0x0002, 0x0003, 0x0009, 0x0012, 0x0013, 0x0019, 0x0042, 0x0043, + 0x0049, 0x0052, 0x0053, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, + 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, + 0x008d, 0x008e, 0x008f, 0x00c0, 0x00c1, 0x00c4, 0x00c5, 0x00c8, + 0x00c9, 0x00cc, 0x00cd, 0x00d2, 0x00d3, 0x0102, 0x0103, 0x0109, + 0x0112, 0x0113, 0x0119, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0030, 0x0020, 0x0008, 0x0006, 0x0002, 0x0001, 0x0030, 0x0020, + 0x0008, 0x0006, 0x0002, 0x0030, 0x0020, 0x0030, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0030, 0x0020, 0x0030, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0086, 0x0082, 0x0030, +}; +static const u16 b43_acphy_rxgain_2cd300[86] = { + 0x0030, 0x0020, 0x0008, 0x0006, 0x0002, 0x0001, 0x0030, 0x0020, + 0x0008, 0x0006, 0x0002, 0x0030, 0x0020, 0x0030, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0030, 0x0020, 0x0030, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0086, 0x0082, 0x0030, 0x0020, 0x0008, + 0x0006, 0x0002, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0002, 0x0003, 0x0009, 0x0012, 0x0013, 0x0019, 0x0042, 0x0043, + 0x0049, 0x0052, 0x0053, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, + 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, + 0x008d, 0x008e, 0x008f, 0x00c0, 0x00c1, 0x00c4, 0x00c5, 0x00c8, + 0x00c9, 0x00cc, 0x00cd, 0x00d2, 0x00d3, 0x0102, +}; +static const u16 b43_acphy_rxgain_2cd360[86] = { + 0x0002, 0x0003, 0x0009, 0x0012, 0x0013, 0x0019, 0x0042, 0x0043, + 0x0049, 0x0052, 0x0053, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, + 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, + 0x008d, 0x008e, 0x008f, 0x00c0, 0x00c1, 0x00c4, 0x00c5, 0x00c8, + 0x00c9, 0x00cc, 0x00cd, 0x00d2, 0x00d3, 0x0102, 0x0103, 0x0109, + 0x0112, 0x0113, 0x0119, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0080, 0x0020, 0x0020, 0x0008, 0x0008, 0x0001, 0x0080, 0x0020, + 0x0020, 0x0008, 0x0008, 0x0080, 0x0020, 0x0080, 0x0020, 0x0080, + 0x0020, 0x0080, 0x0020, 0x0080, 0x0020, 0x0080, 0x0020, 0x0080, + 0x0020, 0x0080, 0x0020, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, + 0x0040, 0x0040, 0x0040, 0x0048, 0x0048, 0x0004, +}; +static const u16 b43_acphy_rxgain_2cd3c0[90] = { + 0x0080, 0x0020, 0x0020, 0x0008, 0x0008, 0x0001, 0x0080, 0x0020, + 0x0020, 0x0008, 0x0008, 0x0080, 0x0020, 0x0080, 0x0020, 0x0080, + 0x0020, 0x0080, 0x0020, 0x0080, 0x0020, 0x0080, 0x0020, 0x0080, + 0x0020, 0x0080, 0x0020, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, + 0x0040, 0x0040, 0x0040, 0x0048, 0x0048, 0x0004, 0x0008, 0x0008, + 0x0008, 0x0040, 0x0010, 0x0010, 0x0010, 0x0000, 0x0000, 0x0000, + 0x0002, 0x0003, 0x0009, 0x0012, 0x0013, 0x0019, 0x0042, 0x0043, + 0x0049, 0x0052, 0x0053, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, + 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, + 0x008d, 0x008e, 0x008f, 0x00c0, 0x00c1, 0x00c4, 0x00c5, 0x00c8, + 0x00c9, 0x00cc, 0x00cd, 0x00d2, 0x00d3, 0x0102, 0x0103, 0x0109, + 0x0109, 0x0112, +}; +static const u16 b43_acphy_rxgain_2cd420[90] = { + 0x0002, 0x0003, 0x0009, 0x0012, 0x0013, 0x0019, 0x0042, 0x0043, + 0x0049, 0x0052, 0x0053, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, + 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, + 0x008d, 0x008e, 0x008f, 0x00c0, 0x00c1, 0x00c4, 0x00c5, 0x00c8, + 0x00c9, 0x00cc, 0x00cd, 0x00d2, 0x00d3, 0x0102, 0x0103, 0x0109, + 0x0109, 0x0112, 0x0113, 0x0119, 0x0119, 0x0000, 0x0000, 0x0000, + 0x0102, 0x6b02, 0x6e96, 0x0202, 0x9d01, 0xa099, 0x0202, 0x9d01, + 0xa199, 0x0202, 0x9d00, 0xba99, 0x0202, 0x9d00, 0xbb99, 0x0001, + 0x9f01, 0xa1ae, 0x0001, 0xa001, 0x9cb9, 0x0001, 0xa301, 0xa2b9, + 0x0001, 0xa901, 0xa7bb, 0x0001, 0x9801, 0xa0bc, 0x0101, 0x9f01, + 0xa6a6, 0x0202, 0x8c04, 0x6497, 0x0202, 0x8f03, 0x7499, 0x0202, + 0x8f02, 0x8c99, +}; + +/* RX gain table (id 0xa) descriptor: which sub-tables per band/LNA select. */ +struct b43_phy_ac_rxgain_set { + const u16 *codes; /* 16-bit gain codes -> table offset 0x1 */ + u16 codes_count; + const u8 *limits; /* 8-bit gain limits -> table offset 0x20 */ + u16 limits_count; +}; + +/* + * Band/LNA-select -> gain set. Index = pi_ac+0x343 (0 default, 1/2/3 variants). + * These pairings mirror the branches in wl's set_analog_tx_lpf; the 2G/5G + * assignment is validated on hardware once the full RX path is up. + */ +static const struct b43_phy_ac_rxgain_set b43_acphy_rxgain_sets[] = { + { b43_acphy_rxgain_2ccd60, 72, b43_acphy_rxgainlim_2ccc00, 32 }, + { b43_acphy_rxgain_2ccd00, 60, b43_acphy_rxgainlim_2ccc20, 32 }, + { b43_acphy_rxgain_2cce50, 60, b43_acphy_rxgainlim_2ccc40, 32 }, + { b43_acphy_rxgain_2ccf70, 60, b43_acphy_rxgainlim_2ccc60, 32 }, +}; + +void b43_phy_ac_rxgain_tables_init(struct b43_wldev *dev, unsigned int sel) +{ + const struct b43_phy_ac_rxgain_set *s; + + if (sel >= ARRAY_SIZE(b43_acphy_rxgain_sets)) + sel = 0; + s = &b43_acphy_rxgain_sets[sel]; + + /* Gain codes at table offset 0x1, gain limits at offset 0x20. */ + b43_phy_ac_table_write_bulk(dev, 0xa, 0x1, 16, s->codes_count, s->codes); + b43_phy_ac_table_write_bulk(dev, 0xa, 0x20, 8, s->limits_count, + s->limits); +} + +/* Reference the remaining extracted sub-tables so all data stays linked + * (full per-band selection is wired as the RX path is brought up). + */ +const void * const b43_acphy_rxgain_extra[] __maybe_unused = { + b43_acphy_rxgain_2ccce0, b43_acphy_rxgain_2ccd20, b43_acphy_rxgain_2cd0c0, + b43_acphy_rxgain_2cd100, b43_acphy_rxgain_2cd180, b43_acphy_rxgain_2cd1e0, + b43_acphy_rxgain_2cd240, b43_acphy_rxgain_2cd2a0, b43_acphy_rxgain_2cd300, + b43_acphy_rxgain_2cd360, b43_acphy_rxgain_2cd3c0, b43_acphy_rxgain_2cd420, + b43_acphy_rxgainlim_2ccc80, b43_acphy_rxgainlim_2ccca0, + b43_acphy_rxgainlim_2cccc0, +}; diff -ruN old/drivers/net/wireless/broadcom/b43/tables_phy_ac.h new/drivers/net/wireless/broadcom/b43/tables_phy_ac.h --- a/drivers/net/wireless/broadcom/b43/tables_phy_ac.h 1970-01-01 01:00:00.000000000 +0100 +++ b/drivers/net/wireless/broadcom/b43/tables_phy_ac.h 2026-07-16 12:03:22.138628884 +0200 @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef B43_TABLES_PHY_AC_H_ +#define B43_TABLES_PHY_AC_H_ + +#include + +struct b43_wldev; + +/* One AC-PHY table initialiser: which table (id), where in it (offset), + * the entry width in bits and how many entries the data blob holds. + */ +struct b43_phy_ac_tbl { + u16 id; + u16 offset; + u16 width; /* bits per entry: 8, 16 or 32 */ + u16 count; + const void *data; +}; + +/* Per-channel entry from wl's chan_tuning_20691rev_1. */ +struct b43_phy_ac_chan { + u16 channel; + u16 freq_mhz; +}; + +void b43_phy_ac_table_write_bulk(struct b43_wldev *dev, u16 id, u16 offset, + u16 width, u16 count, const void *data); +u32 b43_phy_ac_table_read(struct b43_wldev *dev, u16 id, u16 offset, u16 width); +void b43_phy_ac_tables_init(struct b43_wldev *dev); +const struct b43_phy_ac_chan *b43_phy_ac_chan_lookup(struct b43_wldev *dev, + unsigned int channel); +void b43_phy_ac_upload_tx_gain_table(struct b43_wldev *dev, bool ghz5, + bool ipa); +const u16 *b43_phy_ac_chan_tuning_lookup(struct b43_wldev *dev, + unsigned int channel); +void b43_phy_ac_rxgain_tables_init(struct b43_wldev *dev, unsigned int sel); +void b43_phy_ac_txpwr_by_index(struct b43_wldev *dev, u16 index); + +#endif /* B43_TABLES_PHY_AC_H_ */