Skip to content

N1 Wi-Fi and Bluetooth on bare-metal T6050, with 6 GHz and WPA3-Personal - #938

Merged
DjDeveloperr merged 51 commits into
integration/aurorafrom
j716c/t6050-n1
Nov 9, 2026
Merged

DjDeveloperr merged 51 commits into
integration/aurorafrom
j716c/t6050-n1

Conversation

@erikwb

@erikwb erikwb commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Add automatic N1 startup, protocol-27 Wi-Fi and Bluetooth support behind the native T6050 PCIe host. Stacked on #937 (j716c/t6050-pcie). Preserve the original feature commits by Dj and Jeff Queisser, including factory Bluetooth addressing, BSSID/channel-directed connection, firmware-reported bands including 6 GHz, and WPA3-Personal SAE offload.

The current base also contains a J813/J873 Centauri implementation with different startup, IPC, IRQ and DMA assumptions. Keep those existing paths intact and put the T6050 transport in centauri/t6050/, with separate private symbols, Kconfig selections and module/driver names (apple_centauri_t6050, btcentauri_t6050). Host checks select ownership before allocation, MMIO or Bluetooth supplier-link creation. This preserves both implementations; fixes affecting both transports will need deliberate propagation.

T6050 uses APPLE_CENTAURI_T6050, APPLE_CENTAURI_T6050_WIFI and BT_HCICENTAURI. The existing APPLE_CENTAURI / BT_CENTAURI selections retain the J813/J873 implementation.

Validation:

  • Both radio and Bluetooth implementations build together for arm64/16 KiB with W=1; combined relocatable linking and both binding schemas pass. Diff whitespace checks pass. Checkpatch has no errors, with advisory warnings remaining.
  • Device-tree property names match the original driver and bindings; the coexistence rename leaves those external names intact.
  • J716c 7.3.0-ewb50+ boots with both implementations enabled and the intended T6050 drivers bound. Wi-Fi association, Bluetooth discovery, and GPU compute pass.
  • Automatic devices and platform PM stages pass. One normal asynchronous system suspend slept for 143 seconds and resumed with no failure counters; the desktop worked and a 16 MiB storage checksum matched. GPU compute and Bluetooth discovery pass after resume.
  • Post-resume Wi-Fi disconnect/reconnect passes, followed by 60 seconds of SSH traffic with 60 MiB verified byte-for-byte in each direction. No kernel fault or suspend/resume failure was recorded.

The hardware test uses these exact radio/Bluetooth sources on the known-working native platform baseline with the s2idle implementation from #1199. The complete integration tree has not been booted, and J813/J873 hardware and paired Bluetooth peripheral continuity were not tested. Existing J813/J873 transport behavior is preserved by source comparison and build coverage.

Reviewed with sol-loop: 2 rounds with gpt-6.1-sol. Sol verdict: approved

Created with GPT-6 Astra in T3 Code.

@DjDeveloperr DjDeveloperr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works on the M5 Pro (MacBook Pro 14", J714sAP, T6050), bare metal: Wi-Fi associates and moves data, and Bluetooth answers l2ping.

Setup: the boot loader trains port 0 (see #937), and this head (1a59756) is in the same kernel as #937. The firmware apple/centauri/j714s-ftab.bin comes from the M5's Linux root (mounted read-only), and so do iw, wpa_supplicant and btmgmt (run in a chroot). In the J714s DT the N1 nodes are as on J716c, with platform ID 0x00086050 and that firmware name.

  • Firmware and functions: Wi-Fi firmware channel list: 709 bytes, capabilities: 570 bytes; wlan0 with the factory MAC from /chosen; hci0.
  • Scan: 16 BSSs on 2.4 and 5 GHz.
  • Station: WPA2-PSK join to a 5 GHz AP (5180 MHz, about -56 dBm), a DHCP lease, and gateway ping 20/20. After the AP's country IE the firmware's list grows to 6 GHz 59 (167 entries), so the firmware-reported bands work here too.
  • Data: 64 MiB host→M5 and 32 MiB M5→host over TCP, sha256 matching both ways, at about 280 Mbit/s. It was still associated, with no driver errors, about 15 min later after a GPU dEQP run.
  • Bluetooth: hci0 at FC:B2:14:B7:35:82 (manufacturer 76, version 17); host→M5 l2ping 5/5 over BR/EDR, about 6 ms. LE discovery wasn't tried, because our config has BT_LE off.
  • Reboot with both drivers loaded is clean (Beta detach requires fresh firmware boot; retaining DMA arena, then the SMC restart).
  • Note: unloading and reloading apple_centauri_t6050 in one boot fails with N1 automatic startup failed in phase0: -16, as the detach message says. No freeze and no DART faults.

Not tested: WPA3/SAE (no SAE network here), 6 GHz association, paired peripherals, suspend.

One gap, handled in a follow-up: this driver (centauri/t6050/) doesn't send #828's host-awake commands, because #828 targets the old t6050/centauri-wifi file. #1316 ports them, stacked on this PR.

funkzy and others added 4 commits November 9, 2026 22:39
…oader

Add apple,t6050-pcie, a T6050 (M5 Ultra) PCIe host whose root ports the
boot loader powered, trained and left running. Each such port is marked
apple,link-trained-by-bootloader and named by its port<n>, phy<n> and
intr2axi<n> register ranges and its port<n> interrupt; the host's local
MSI map starts at apple,msi-vector-base. The OS adopts the trained state
and never resets, retrains or changes the port's power: reset-gpios,
pwren-gpios and power-domains are not allowed on it.

Also name nonposted-mmio, which these hosts take.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
On the M5 Ultra (T6050, J775D) running Linux on the hardware, the boot
loader brings up the internal PCIe host's ports itself: it powers the
shared PHY, trains each port's link and leaves it up, with the endpoint
idle. Port 2 carries the onboard RTL8127 Ethernet controller and port 3
the ASM3142 xHCI behind the rear USB-A ports. Repeating the reset and
training sequence from Linux is not needed and not known to be safe on
this SoC.

Add apple,t6050-pcie, a host whose root ports marked
apple,link-trained-by-bootloader are adopted as they are: no reset, no
tunable replay, no clock or power change and no retraining. Every
resource comes from the DT by the port's index (port<n>, phy<n>,
intr2axi<n>, interrupt port<n>, the iommu-map entry for the endpoint's
RID). Before the first PCIe register write the driver checks that the
link is up and not retraining at Gen3 x1, that the boot loader numbered
the root port's buses (primary 0, one secondary), that the endpoint on
it is device 0 function 0 with DMA and MSI off and a well-formed
capability list, and that the port's RID table holds no valid entry. A
port that fails a check is left alone and the others are still adopted.
Then the endpoint's RID is routed to its SID, the host's MSI map is set
up from apple,msi-vector-base, and only the adopted root ports and the
endpoint behind each are enumerated. The links cannot be recovered by a
user reset or removal, since the boot loader owns them.

No other SoC sets adopt_link.

Testing: on J775D, every boot adopts port 2 (RTL8127, DHCP and SSH over
it on every boot) and port 3 (ASM3142, a USB keyboard and mouse driving
the desktop session).

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
A driver's work item that rescans or resets part of a bus takes the
rescan/remove lock. When the device is being removed, the remover holds
that lock while it cancels the work, so a worker that blocks on the lock
deadlocks against its own cancellation.

Add pci_trylock_rescan_remove(), which takes the rescan/remove lock only
if it is free. A worker that cannot get it returns and retries later,
and the remover's cancellation completes.

Signed-off-by: Dj <hey@djdev.me>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
…uences

An adopted T6050 port is left as the boot loader trained it, but an
endpoint that has to come back on a retrained link (the N1 on port 0,
after its ROM boot) needs the host to take the port down and bring it
up again. Add the sequences for that, on the port's own register blocks
(port<n>, phy<n> and intr2axi<n>) and the root port's config space:

- Disable: wait for the link to leave L1 and go idle, assert the
  port's PERST# through its handshake, then stop the lane clocks and
  the port's application clock.
- Enable: the port reset table, which also clears the RID2SID and MSI
  map tables, the port's tunables, then the application clock and the
  PERST# release handshake, until the port is ready and its link idle.
- Configure: with the root complex's read-only registers opened, its
  tunables and the per-rate shadow tunables, then a Gen3 x1 link
  (target speed, link width and capability) and a directed speed
  change; Intr2AXI enabled.
- Train: the lane's reference clocks, the endpoint's PERST# released
  through its pad, the LTSSM started, then the 100 ms wait after link
  up.

The tunables are the lists the boot loader copies onto the root port
node, groups of (offset, 4, mask, value); a list it did not copy is
skipped. The root-port reset that runs the sequences follows; until
then they are marked __maybe_unused.


Co-developed-by: Dj <hey@djdev.me>
Signed-off-by: Dj <hey@djdev.me>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
DjDeveloperr and others added 10 commits November 9, 2026 12:01
integration/aurora now has the J713 display DART power gating (#1059),
whose register definitions sit where this series' DART commit adds the
v2.2/v2.4 error, client-partition and context-cache definitions. Keep
both blocks; they define different registers.

Signed-off-by: Diljit Singh <hey@djdev.me>
Keep this transport alongside the current J813/J873 implementation.
Select it only for a T6050 host, with separate objects and private helper
names so both implementations can be built and registered together.

Boot the N1 firmware and expose its shared ACIPC transport behind the T6050 PCIe host. After the ROM boot, isolate and quiesce function 0, put it in D3hot with PME enabled, let the host's root-port reset take the link through L2, PERST# and retraining, then restore the root port's and the endpoint's state. Keep firmware and calibration as external inputs, and retain supplier lifetime for the separate Wi-Fi and Bluetooth consumers.

Source snapshot: t6050-gpu ee68abb105200e99636a5edfc647a5cfc1d89954
Integration base: 9cbdd07

Signed-off-by: Dj <hey@djdev.me>
Co-developed-by: Jeff Queisser <funkzy@users.noreply.github.com>
Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
Add the N1 protocol-27 cfg80211 station interface, Alpha command/data rings, scanning, and WPA2-PSK/CCMP connections. The shared firmware and PCIe transport are supplied by the sibling core PR.

Source snapshot: t6050-gpu ee68abb105200e99636a5edfc647a5cfc1d89954
Integration base: 9cbdd07

Signed-off-by: Dj <hey@djdev.me>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
Keep the J813/J873 transport intact. Give the T6050 driver its own
module name and reject other hosts before creating a supplier link.

Add the N1 protocol-27 Beta HCI/ACL transport and its Control-supplier lifetime. Carry the bounded HCI command-cache reset hook while preserving standard status and command-credit semantics.

Source snapshot: t6050-gpu ee68abb105200e99636a5edfc647a5cfc1d89954
Integration base: 9cbdd07

Signed-off-by: Dj <hey@djdev.me>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
cen_hci_reset_dup_filter() never uses the driver data it looks up, and
clang warns about it.

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
Boot loaders fill the standard local-bd-address property from the
bluetooth0 alias. Take the factory address from it (least significant
byte first), falling back to local-mac-address, and let the binding
accept either.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
A connect request carries the BSSID and channel the client chose from
its own scan results. The driver looked the target up in cfg80211's
scan list instead and refused the connect with -ENOENT when the entry
was not there. iwd runs a requested scan as channel subsets, each with
the flush flag, and at the end of each subset cfg80211 expires every
BSS that subset did not see, on every band. After a last subset of
2.4 GHz channels with no access point, the list holds none of the
network's BSSes while iwd's own list holds all of them, so every connect
right after such a scan failed until a later unflushed scan refilled
cfg80211's list.

- The target is the request's BSSID and channel, or its hints. The
  scan entry is looked up only when the request names neither.
- The RSN capabilities sent to the firmware are the station's own, from
  the request's RSN element (the client's MFP choice), rather than the
  AP's from the scan entry.
- A successful connect is reported against cfg80211's entry for the
  target. When the client's scans expired it, one is informed from the
  request (BSSID, channel, SSID), and the AP's beacons, which the
  firmware reports once associated, fill in its elements.
- Scan and connect failures name the firmware's status: a refused
  command, a connect or disconnect event with a non-zero status, a scan
  whose completion event carries one, or no event at all. command()
  still returns -EREMOTEIO for a refusal.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
The firmware owns the radio's channel list, its per-country rules and
its capabilities; the driver registered a fixed 2.4/5 GHz table and
never asked. Read the firmware's two reports once the interface is
configured: system command 19, the channels the hardware supports, and
system command 8, the system capabilities. Both are kept as read in
debugfs (ieee80211/phyN/hw_channels and system_caps) and their sizes are
logged. The band table is built from them next.

command() gains a reply buffer, command_reply(): the payload of the
reply to the command that asked is copied there, in place of the ring
consumer's per-command copies. query_link_status() parses the interface
status reply (20) from it; the copy of the country reply (10), which
nothing requested, goes.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
The driver registered a fixed table: 2.4 GHz channels 1-13 and 25 5 GHz
channels, every one at 20 dBm, and no 6 GHz band. The firmware reports
which channels the current country allows (system command 19), at each
width and with passive and radar flags, and its own capability elements
(system command 8). Before a country is set it reports 2.4 and 5 GHz
only; under US rules it reports 167 entries, 6 GHz channels 1-233 among
them.

- The band plan (2.4 GHz 1-14, 5 GHz 36-177, 6 GHz 1-233) is registered
  once, and the firmware's list is applied over cfg80211's rules: a
  channel it leaves out is disabled, its passive and radar flags become
  NO_IR and RADAR, and a width no entry covers is not used. The power
  limit is left to the regulatory domain and the firmware.
- The regulatory notifier sets the country (command 9, as before), then
  reads the list again and applies it, after every regulatory change.
- 6 GHz is registered with the HE capabilities element the firmware
  reports, and 6 GHz band capabilities from its VHT element; without an
  HE element there is no 6 GHz band. The radio is started before the
  wiphy is registered, since the bands come from it.
- One band encoding, firmware_band(), for scan, connect and beacons. 6 GHz
  beacons carry neither DS parameters nor HT operation, so they take
  their channel from the HE operation's 6 GHz information.
- Scans include the listen-only channels (radar channels, and all of
  6 GHz under US rules) with the firmware's passive and radar bits, as its
  channel list encodes them, instead of skipping them.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
The firmware runs SAE itself from the password. Offer SAE (AKM
00-0F-AC:8, SAE offload). The connect command carries one authentication
and AKM pair: a request that offers SAE with a password sends SAE
authentication (3) and AKM 8, with the password in TLV 313 as a 16-bit
length and its bytes, and no PMK; one that offers PSK with a PMK sends
open authentication and AKM 4 as before.

Management frame protection travels in the station's RSN element only.
TLV 316 is the security roaming groups bitmap, not a PMF flag: send 0
(no roaming groups), and TLV 304 (the join mode) as 5 for every join.
6 GHz admits WPA3-Personal only with management frame protection, so a
6 GHz connect without both is refused.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>

Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
@DjDeveloperr
DjDeveloperr changed the base branch from j716c/t6050-pcie to integration/aurora November 9, 2026 17:02
@DjDeveloperr

Copy link
Copy Markdown
Contributor

Rebased and retargeted to integration/aurora. #937 (this PR's old base, j716c/t6050-pcie) is being merged as part of #1323, which carries its seven commits rebased onto integration. So this branch now sits on #1323's head 3b7ab89 and carries only its own nine commits; once #1323 is merged the diff is just these. The old head 1a59756 is kept as backup/j716c/t6050-n1-pre-rebase-20261109. The commits replayed without conflicts, and authors and Signed-off-by lines are unchanged.

The N1 driver files on this head are byte-identical to the ones retested on the M5 Pro today. Kernel 7.3.0-m5-merge: firmware channel list and capabilities read, WPA2 5 GHz join, gateway ping 20/20, 64 MiB in / 32 MiB out sha256-exact over Wi-Fi, Bluetooth l2ping 5/5 from the host. I'll merge after #1323 once CI passes here.

🤖 Generated with Claude Code

@DjDeveloperr DjDeveloperr mentioned this pull request Nov 9, 2026
@DjDeveloperr

Copy link
Copy Markdown
Contributor

Retested before merging on the M5 Pro (J714sAP, bare metal, SSD boot), kernel 7.3.0-m5-merge (the M5's integration kernel with this round's rebased heads; this PR's files identical to this head). CI green; merged after #1323, whose head this branch sits on.

  • N1 firmware boots (channel list 709 B, capabilities 570 B); WPA2 join on 5 GHz, gateway ping 20/20; 64 MiB in (2.24 s) and 32 MiB out (1.37 s) over Wi-Fi with matching sha256; Bluetooth l2ping 5/5 from the host.

🤖 Generated with Claude Code

@DjDeveloperr
DjDeveloperr merged commit 54562f6 into integration/aurora Nov 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants