WL
SDIO initialization
The WL wireless driver uses the SDIO host controller at 0x0D080000. init_sdio_card (0x13F1DD90) reads the 32 bit Present State register at 0x0D080024 and checks Card Inserted before continuing initialization.
| Bits | Field | Meaning |
|---|---|---|
16 |
Card Inserted | 1 indicates a card is present. 0 prevents initialization from continuing. |
When Card Inserted is clear, the routine returns 1. attach_sdio_host (0x13F1E9D4) retries initialization once. If both attempts fail, it releases the host object and returns a null pointer. This failure propagates through the attachment routines.
wireless_worker (0x13F0A4E0) does not check the returned driver pointer before reading its message queue handle at offset 0x1C8. It calls receive_message (0x13F2869C) with that handle and retries immediately whenever the call returns a nonzero result.
Host setup
Initialization checks the Capabilities register at 0x0D080040:
| Bits | Field | Firmware use |
|---|---|---|
5:0 |
Timeout Clock Frequency | Must equal 48 for clock setup to proceed. |
22 |
SDMA Support | Must be set for initialization to proceed. |
24 |
3.3 V Support | Selects the 3.3 V power encoding when set. |
25 |
3.0 V Support | Selects the 3.0 V power encoding when bit 24 is clear. |
26 |
1.8 V Support | Selects the 1.8 V power encoding when bits 24 and 25 are clear. |
reset_host (0x13F1D534) requests a card reset with CMD52, writing 8 to function 0 register 6. It then writes all three host reset bits and polls until they clear.
The word at 0x0D08002C contains the clock controls and reset requests used by WL:
| Bits | Field | Firmware use |
|---|---|---|
0 |
Internal Clock Enable | Set before polling clock stability. |
1 |
Internal Clock Stable | Polled until set before enabling the card clock. |
2 |
SD Clock Enable | Set after the internal clock becomes stable. |
19:16 |
Data Timeout Counter Value | Written with 14 after card selection. |
15:8 |
SDCLK Frequency Select | Written with the clock divider encoding. |
24 |
Software Reset For All | Set during host reset. |
25 |
Software Reset For CMD Line | Set during host reset. |
26 |
Software Reset For DAT Line | Set during host reset. |
After enabling the clock, WL selects a supported voltage and enables bus power through the word at 0x0D080028:
| Bits | Field | Meaning |
|---|---|---|
1 |
Data Transfer Width | Set for a 4 bit bus. |
8 |
SD Bus Power | Set to enable power. |
11:9 |
SD Bus Voltage Select | 5 selects 1.8 V, 6 selects 3.0 V and 7 selects 3.3 V. |
It then calls delay (0x13F0AA28) for 50,000 microseconds. This delay creates a timer and waits for a message on its completion queue before initialization continues.
Command completion and initialization failure
After the power delay, initialization submits CMD5 with argument zero through send_command (0x13F1CF58). This writes 0x05020000 to 0x0D08000C and polls the lower halfword of the interrupt status register at 0x0D080030.
| Bits | Field | Firmware use |
|---|---|---|
1 |
Transfer Complete | Wait for it after writing CMD53 data. |
4 |
Buffer Write Ready | Wait for it before writing CMD53 data to 0x0D080020. |
5 |
Buffer Read Ready | Wait for it before reading CMD53 data from 0x0D080020. |
0 |
Command completion | Wait for it to become set then acknowledge it by writing 1. |
31:16 |
Error status | Any nonzero value makes the completed command fail. |
The polling counter starts at 5000 and is decremented after each read. If it reaches zero, the routine requests a command-line reset through the clock and reset register and returns 1. A command timeout makes card initialization fail. The attachment routine retries initialization once before returning a null pointer.
After completion, the routine checks error status. A nonzero error status causes it to return 1. With no error, probe_card (0x13F1DC8C) reads the CMD5 response. A zero response causes another CMD5 attempt. After 200 unsuccessful attempts, the probe returns 1 and initialization fails.
The worker's unchecked driver pointer then causes the receive loop to use a queue handle read from address 0x000001C8. If that handle is rejected, the worker immediately retries the receive call without blocking.
CMD5 response
The CMD5 response is read from 0x0D080010. The probe and initialization routines use these fields:
| Bits | Field | Firmware use |
|---|---|---|
31 |
Ready | Repeat CMD5 while clear. Return success when set. |
30:28 |
I/O function count | Require a nonzero count before continuing initialization. |
21:20 |
Voltage window bits | If either is set, submit CMD5 again with argument 0x00FFF000. |
After the probe succeeds and the function count is nonzero, initialization proceeds to CMD3 with argument zero.
CMD3 response
CMD3 publishes the card's relative address in its R6 response. WL submits it by writing 0x03020000 to 0x0D08000C with argument zero. After command completion, it reads the response from 0x0D080010 and checks these fields:
| Bits | Field | Firmware use |
|---|---|---|
31:16 |
Relative card address | Save this value and use it in the upper halfword of the CMD7 argument. |
15 |
Command CRC error | Fail initialization when set. |
14 |
Illegal command | Fail initialization when set. |
13 |
Error | Fail initialization when set. |
When the error fields are clear, initialization sends CMD7 to select the published address.
CMD7 response
WL selects the card by writing 0x071A0000 to 0x0D08000C with the relative card address in the upper halfword of the argument. After completion, it requires the response at 0x0D080010 to equal 0x00001E00. Any other value makes initialization fail.
| Bits | Field | Required value |
|---|---|---|
12:9 |
Current state | 15, indicating an I/O-only card |
The comparison covers the entire response word, so every bit outside the current-state field must be clear.
CMD52 register access
read_card (0x13F1D620) uses CMD52 for single byte reads and accesses to function 0. write_card (0x13F1D3AC) uses CMD52 for the corresponding writes. The host command word is 0x341A0000 after card selection. The argument at 0x0D080008 has these fields:
| Bits | Field | Meaning |
|---|---|---|
31 |
Write | 1 writes a byte. 0 reads a byte. |
30:28 |
Function | Selects the I/O function. |
27 |
Read after write | Requests the register value after a write. WL clears this field in these helpers. |
25:9 |
Register address | Selects the byte within the function. |
7:0 |
Data | Byte to write. |
The read helper takes the returned byte from bits 7:0 of the response at 0x0D080010.
After CMD7 succeeds, initialization performs these accesses through function 0:
read_cis_pointer(0x13F1DD10) reads four bytes starting at0x09for the common Card Information Structure (CIS) pointer. It repeats this atfunction * 0x100 + 0x09for each reported function. It interprets the bytes in little endian order and retains the low 17 bits.- It writes
0x02to I/O Enable at0x02to enable function 1. - For a 4 bit bus, it reads Bus Interface Control at
0x07, replaces the width field with2and writes it back. It also sets Data Transfer Width in the host register. set_block_size(0x13F1CEEC) writes the low and high bytes of function 1's block size to0x110and0x111. Initialization selects 64 bytes.- With one reported function, it writes
0x03to Interrupt Enable at0x04.
| Function 0 address | Bits | Field | Value used during initialization |
|---|---|---|---|
0x02 |
1 |
Function 1 enable | 1 |
0x04 |
1 |
Function 1 interrupt enable | 1 |
0x04 |
0 |
Master interrupt enable | 1 |
0x07 |
1:0 |
Bus width | 2 selects 4 bits. |
CMD53 data reads
For reads larger than one byte from a nonzero function, read_card submits CMD53 in byte mode with address increment enabled. The argument contains:
| Bits | Field | Firmware use |
|---|---|---|
31 |
Write | Clear for reads. |
30:28 |
Function | Select the requested function. |
27 |
Block mode | Clear for byte mode. |
26 |
Address increment | Set. |
25:9 |
Register address | Select the first byte. |
8:0 |
Count | Requested byte count. |
For a 4 byte read, the host block size is 4 and the block count is 1 in the low and high halfwords of 0x0D080004. The host command word is 0x353A0010.
After command completion, the polling path waits for Buffer Read Ready in the interrupt status register. It uses a counter initialized to 5000 and returns 1 if that counter expires. Once ready, it reads the word at 0x0D080020. It then reads normal interrupt status and acknowledges the set flags except Card Interrupt.
| Bits | Field | Firmware use |
|---|---|---|
8 |
Card Interrupt | Excluded from the acknowledgement after a data read. |
CMD53 data writes
For writes larger than one byte to a nonzero function, write_card submits CMD53 with the same byte count and address fields as a read. It sets the Write field. For a 4 byte write, the host command word is 0x353A0000.
After command completion, the polling path waits for Buffer Write Ready. It uses a counter initialized to 5000 and returns 1 if that counter expires. It acknowledges Buffer Write Ready before writing the data at 0x0D080020. A 2 byte write uses the low halfword of that register.
The routine then polls Transfer Complete with another counter initialized to 5000. It leaves this loop when completion arrives or the counter expires. It acknowledges the set normal status flags except Card Interrupt and returns 0, including when this second counter expires.
PHY and radio identification
attach_phy (0x13EFD5BC) reads the physical-layer hardware's version and radio identity before returning a PHY object. The following offsets are relative to the wireless core's base on the chip's internal backplane. WL accesses these registers through SDIO function 1.
| Offset | Width | Firmware access | Purpose |
|---|---|---|---|
0x3E0 |
16 bits | Read | PHY version |
0x3F6 |
16 bits | Write | Radio register selector |
0x3F8 |
16 bits | Read | Upper half of the radio identity |
0x3FA |
16 bits | Read | Selected radio register data |
0x3FC |
16 bits | Write | PHY register selector |
0x3FE |
16 bits | Read/write | Selected PHY register data |
The PHY version contains:
| Bits | Field | Firmware use |
|---|---|---|
15:12 |
Analog revision | Save in the PHY object. |
11:8 |
PHY type | Accept 0, 1, 2 or 4 during attachment. |
3:0 |
PHY revision | Save for later compatibility checks. |
For the 2.4 GHz attachment path, a rejected PHY type makes attach_phy release its allocation and return a null pointer. After PHY attachment, attach_wireless_core (0x13EDC774) accepts PHY revisions 1, 2, 6, 7 and 8.
When the chip package is neither 14 nor 15, attachment obtains the radio identity by writing selector 1 to 0x3F6 and reading 0x3F8. It writes selector 1 again before reading 0x3FA. The first read supplies the upper halfword and the second supplies the lower halfword:
uint32_t identity = ((uint32_t)upper << 16) | lower;
| Bits | Field | Firmware use |
|---|---|---|
31:28 |
Radio revision | Save in the PHY object. |
27:12 |
Radio number | Require 0x2050 or 0x2055. |
A rejected radio number makes attachment release its allocation and return a null pointer. Packages 14 and 15 instead select the internal identifier 0xE4F5 without this identity read.
Indirect PHY access
read_phy (0x13EF54E0) writes a 16 bit register index to 0x3FC then reads 16 bits from 0x3FE. write_phy (0x13EF552C) writes the index followed by the value. Selecting an index and writing its data are separate operations.
set_phy_bits (0x13EF55DC) selects a register, reads its value and writes the bitwise OR of that value and its mask. mask_phy_bits (0x13EF557C) performs the corresponding bitwise AND. Both operate on 16 bit values.
MAC initialization
WL accesses the wireless chip's MAC registers through SDIO function 1. These addresses belong to the chip's backplane.
| Address | Width | Name | Firmware use |
|---|---|---|---|
0x18001120 |
32 bits | MAC control | Stop and start microcode execution. |
0x18001128 |
32 bits | Interrupt status | Poll the microcode startup response. |
0x18001160 |
32 bits | Object address | Select the destination for uploaded words. |
0x18001164 |
32 bits | Object data | Write microcode and PCM data. |
init_mac (0x13EDF148) writes 0x00000404 to MAC control before loading microcode. load_microcode (0x13ED4CE0) writes object address 0x03000000 then streams the microcode through object data. load_pcm (0x13ED4D48) writes object address 0x000301EA and data 0x00004000 then selects 0x000301EB and streams the PCM data.
After uploading both blocks, initialization writes 0xFFFFFFFF to interrupt status and 0x00020402 to MAC control. It polls the following status field:
| Bits | Field | Firmware use |
|---|---|---|
0 |
MAC suspended | End the startup wait when set. |
The polling loop starts with a budget of 1000009. After each unsuccessful read, it subtracts 10 from the budget. If the previous budget exceeds 9, it delays for 10 microseconds before reading again. Otherwise it exits the loop. Initialization continues after either a set status bit or budget exhaustion.
MAC suspension
suspend_mac (0x13ED0EDC) clears MAC control's enable field then polls the same MAC suspended status field. It delays for 10 microseconds between unsuccessful reads and stops after 3500 delays even if the status remains clear. It then reads MAC control and returns its value.
| Register | Bits | Field | Firmware use |
|---|---|---|---|
MAC control (0x18001120) |
0 |
MAC enabled | Clear before waiting for suspension. |