feat: add Broadcom FullMAC Wi-Fi driver
This commit is contained in:
1 parent
8b4a938164
commit
51a2b3a932
34 files changed
+4719
-95
No files matched your search
+85
-2
@@ -157,6 +157,7 @@ PL011 on GPIO 14/15: header pins 8 (TX) and 10 (RX), ground on pin 6, 115200
|
||||
| VideoCore firmware mailbox (radio power, clocks, board MAC) | `BCM2849` (`RPIQ`) | `Drivers/Platform/RpiFirmware.cpp` |
|
||||
| GPIO pin functions | `BCM2845` (`GPI0`) | `Drivers/Platform/RpiGpio.cpp` |
|
||||
| Ethernet (GENET v5 MAC, BCM54213PE PHY) | `BCM6E4E` (`\_SB.ETH0`) | `Drivers/Net/Genet.cpp` |
|
||||
| Wi-Fi (the same CYW4345x, SDIO) | Arasan SD controller `BCM2847`, GPIO 34-39 | `Drivers/Net/Wifi/Brcmf*.cpp` |
|
||||
|
||||
The VL805 sits behind the BCM2711's PCIe, whose config space is not ECAM
|
||||
(the root bridge's `_DSD` says `linux-ecam-quirk-id = "bcm2711"`), so the
|
||||
@@ -239,18 +240,100 @@ The MAC address is the board's, read from OTP through the firmware mailbox
|
||||
driver programmed is the fallback. `dhcp.elf` waits up to 10 s for a wired
|
||||
link, since autonegotiation takes about 3 s after the PHY reset.
|
||||
|
||||
## Wi-Fi
|
||||
|
||||
The radio's WLAN half is an SDIO card on the BCM2711's older SD controller,
|
||||
the Arasan-derived EMMC (`BCM2847`, `0x7E300000`); the card slot is on
|
||||
EMMC2, so the two never share a bus. Its pins are GPIO 34-39 (ALT3; clock
|
||||
without a pull, the rest pulled up, as Linux's `sdio_pins`) and its power
|
||||
switch, `WL_ON`, is line 1 of the firmware's GPIO expander. The probe
|
||||
claims the controller only while the slot is on EMMC2 (`BRCME88C` present);
|
||||
if the tables do not describe the Arasan, its address is taken as EMMC2's
|
||||
less 256 KiB.
|
||||
|
||||
It is a FullMAC radio: the firmware does the 802.11 MLME itself and the host
|
||||
sees Ethernet frames. The driver follows Linux's brcmfmac (ISC license,
|
||||
Broadcom; its notice is in `NOTICES.txt`):
|
||||
|
||||
| File | Part |
|
||||
|---|---|
|
||||
| `BrcmfSdio.cpp` | the Arasan as an SDIO host: CMD5/3/7, 4-bit at 25 MHz, CMD52/CMD53, polled PIO, 32-bit register access |
|
||||
| `BrcmfChip.cpp` | backplane window (function 1), clocks, the enumeration ROM's core list, firmware + NVRAM download, function 2, the firmware console |
|
||||
| `BrcmfProto.cpp` | SDPCM framing and transmit credit, CDC ioctls, BDC data, events, the receive pump, the transmit queue |
|
||||
| `BrcmfConnect.cpp` | preinit and CLM, escan, join, keys, link state |
|
||||
|
||||
Once the root is mounted the idle loop:
|
||||
|
||||
1. routes the pins, switches the EMMC clock on, pulses `WL_ON`, enumerates
|
||||
the card (function 1 blocks of 64 bytes, function 2 of 512);
|
||||
2. requests the ALP clock, reads the chip ID: `0x4345` revision 9 is the
|
||||
CYW43456 (Pi 400), any other revision the CYW43455 (Pi 4B), which picks
|
||||
`0:/os/firmware/brcm/brcmfmac43456-sdio.*` or `brcmfmac43455-sdio.*`
|
||||
(shipped unmodified from Raspberry Pi OS's firmware-nonfree);
|
||||
3. halts the ARM Cortex-R4, holds the 802.11 core in reset, sizes the RAM
|
||||
from the CR4's banks, writes the firmware at `0x198000` and the NVRAM
|
||||
(stripped to `key=value\0` pairs and a length token) at the top of RAM,
|
||||
reading both back to verify, puts the reset vector at address 0 and
|
||||
releases the CPU;
|
||||
4. waits for the HT clock, sends the SDPCM protocol version through the
|
||||
mailbox, enables function 2, the F2 watermark and MES busy signalling of
|
||||
Linux's CYW43455 settings, save/restore if the chip has it, and the card
|
||||
interrupt;
|
||||
5. reads `cur_etheraddr` (the NVRAM's shared placeholder address
|
||||
`b8:27:eb:74:f2:6c` is replaced with the board address + 1, as on
|
||||
Raspberry Pi OS), loads the CLM blob (`clmload`, 1400-byte chunks: these
|
||||
firmware builds carry no regulatory data of their own), turns off glom,
|
||||
roaming, ARP/ND offload and power save, enables the events it handles and
|
||||
brings the interface up (`WLC_UP`).
|
||||
|
||||
Nothing uses the controller's interrupt: the bus is swept from the idle
|
||||
loop (and from the timer tick when the cores never idle), every 10 ms while
|
||||
a scan or a connection is active and every 250 ms otherwise, and at once when
|
||||
the controller shows the card interrupt. Every sweep reads the SDIO core's
|
||||
interrupt status, then every frame waiting in function 2 (a 4-byte header
|
||||
read, then the rest). Ioctls wait for transmit credit and their answer by
|
||||
sweeping the bus themselves. Frames are delivered with the bus unlocked, and
|
||||
transmitting never waits for the bus: data frames go into a 32-frame queue
|
||||
that whoever holds the bus, or the next sweep, sends.
|
||||
|
||||
Scans are escans (all channels, active, firmware dwell times); each result
|
||||
event carries a `brcmf_bss_info_le` whose information elements go into the
|
||||
same scan table the Intel driver fills from beacons. A join sets `wpaie`
|
||||
(the RSN element our supplicant builds), `wpa_auth`, `auth` and `wsec`, then
|
||||
`join` with the BSSID and the chanspec escan reported. The 4-way handshake
|
||||
runs in the host's supplicant (`Wpa.cpp`) as for the Intel adapter: EAPOL
|
||||
frames are ordinary Ethernet frames here, and the keys go to the firmware
|
||||
with `wsec_key` once message 4 has left the transmit queue. The radio does
|
||||
AES-CCMP only: GCMP networks are refused, as are WPA3-only (SAE), WEP and
|
||||
TKIP ones.
|
||||
|
||||
Unanswered ioctls (a leaky bucket of three), a halt reported through
|
||||
the mailbox, or repeated bus errors mark the radio failed: the firmware's
|
||||
console and any trap record are printed to the kernel log (`WiFi-FW`), and
|
||||
the facade's recovery powers the radio off and repeats the bring-up (at
|
||||
most three times).
|
||||
|
||||
`tests/wifi/run.sh` drives `BrcmfProto.cpp` and `BrcmfConnect.cpp` with the
|
||||
real supplicant against a simulated firmware: preinit and the CLM chunks,
|
||||
escan parsing, open and WPA2 joins (an independent authenticator checks
|
||||
messages 2 and 4 and the installed keys), the wrong passphrase, refusals,
|
||||
join timeouts and a firmware that stops answering.
|
||||
|
||||
## Not supported yet
|
||||
|
||||
- SD high-speed mode: the driver transfers by polled PIO at 25 MHz on a
|
||||
4-bit bus (multi-block CMD18/CMD25 with Auto CMD12), at most 12.5 MB/s;
|
||||
switching the card to 50 MHz (CMD6) would double that.
|
||||
- Wi-Fi (the CYW4345x's SDIO half, on the Arasan controller).
|
||||
- Wi-Fi beyond 802.11 station mode on one interface: no access point mode,
|
||||
no SDIO high speed (50 MHz), no glom, no firmware supplicant.
|
||||
- Audio (HDMI via VideoCore, the 3.5 mm jack via PWM).
|
||||
|
||||
## Status
|
||||
|
||||
Bluetooth works on a Pi 400 (CYW43456), including A2DP music to
|
||||
headphones. Ethernet has not run yet: QEMU has no GENET model. It is untested on a Pi 4B (CYW43455), and QEMU has no model of
|
||||
headphones. Ethernet has not run yet: QEMU has no GENET model. Wi-Fi has
|
||||
not run on hardware yet either (QEMU has no model of the radio); only its
|
||||
protocol and connection layers are tested, in the host harness. It is untested on a Pi 4B (CYW43455), and QEMU has no model of
|
||||
the radio.
|
||||
|
||||
Everything else above is verified on QEMU only, including the Pi-specific path:
|
||||
|
||||
Reference in new issue
Block a user