Skip to content

arm: apple: T6040 (M4 Pro, J616s) production boot - #16

Merged
RyanTheTide merged 9 commits into
aurora-wipfrom
j616s/t6040-prod-boot
Oct 28, 2026
Merged

RyanTheTide merged 9 commits into
aurora-wipfrom
j616s/t6040-prod-boot

Conversation

@RyanTheTide

@RyanTheTide RyanTheTide commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

This is the aurora-wip consolidation for U-Boot: it is our only open U-Boot work and sits on the current aurora-wip with nothing behind.

Boot support for the M4 Pro MacBook Pro (J616s, T6040) on the production chain the Neo uses: Stage 1, then an m1n1 Stage 2 on the stub ESP that carries the DTB and this U-Boot, then shim and GRUB from the Fedora ESP.

What changes

  • T6040 memory map (the I/O range, the APCIE ECAM and windows, RAM banks and framebuffer from the m1n1 FDT) and the Aurora EFI boot flow. The T6040 MTP is left to Linux and never bound.
  • NVMe: apple,t6041-nvme-ans2, with the linear submission queue registers in the NVMMU block as in m1n1 0d2ded8b and Linux. Both NVMMU TCB bases are programmed before the controller is enabled, and the TCB arrays are 16 KiB aligned.
  • The T6040 ANS takes the OS-side RTKit handshake once per boot. When it arrives straight from iBoot (no m1n1 stage used NVMe), U-Boot runs that handshake with buffers it never frees, publishes them as no-map ans-rtkit@... reserved memory and hands the session to Linux live. When an m1n1 Stage 1 already ran it, U-Boot adopts the session as on the other post-M4 controllers.
  • ESP choice: when the ESP named in /chosen/asahi,efi-system-partition has no EFI/BOOT/BOOTAA64.EFI and another ESP on the disk does, boot from that one and tell the OS in /chosen. On the J616s Stage 1 names the stub ESP and Fedora lives on its own ESP.
  • DockChannel serial: a Linux-style node names its own data window, so apple,channel no longer offsets it.

Testing (J616s, kernel 7.3.0-aurora-j616s-r6g, Fedora 45, SELinux enforcing)

  • Production-equivalent chain with a current m1n1 Stage 1 (32e60029, filled for the stub ESP) vectored in RAM over KIS: Stage 1, aurora/stage2.bin (m1n1 32e60029 + DTB + this U-Boot), shim, GRUB, the BLS entry. 4 boots out of 4 reached the GDM greeter with EFI, NVMe, GPU (vkcube 300 frames), eDP, Wi-Fi, Bluetooth and the internal keyboard. 0 WARN, user4k granule detected on every boot.
  • m1n1 kboot handing U-Boot over directly from the tether (ANS fresh from iBoot): the handshake path, then GRUB and Linux adopting the live session, also to the greeter.
  • This is the U-Boot in the J616s production aurora/stage2.bin today. Its persistent Stage 1 was replaced from 1TR, and untethered boots reach GDM in about 32 s.
  • Rebuilt for this PR (2026-10-28) with apple_m1_defconfig, NR_DRAM_BANKS=16: 0 warnings. The image is not byte-identical to the installed one only because U-Boot embeds its build time.
  • Still owed: a Neo regression boot, since the TCB, ESP and DockChannel changes touch shared code. aurora-wip is where our work in progress lands, so that boot follows the merge and comes before the next Neo ESP update.

🤖 Generated with Claude Code

Map the T6040 I/O range and boot it with the Aurora EFI flow used on
T8140 and T8132. Every register block below DRAM in the J616s devicetree
lies in 0x2_0000_0000 to 0x6_0000_0000 (the APCIE ECAM at 0x1c_b000_0000
is not used by U-Boot); the RAM banks and the framebuffer come from the
m1n1-prepared FDT, as on T8140, so the MMU maps every bank m1n1 reports
(GPU UAT ranges included).

Leave the T6040 MTP to Linux: its helper and the DockChannel keyboard do
not bind, so U-Boot never starts the coprocessor that Linux's MTP driver
boots itself.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The T6040 ANS is a post-M4 controller (adopted from the boot loader,
never restarted), but its "nvme" register block ends at 0x10000:
LINEAR_SQ_CTRL and the linear submission queue doorbells sit at the same
offsets in the NVMMU block, and the firmware enables the linear queues
itself. Match apple,t6041-nvme-ans2, ring the doorbells through the NVMMU
block there and leave LINEAR_SQ_CTRL as the firmware set it, as m1n1
(0d2ded8b) and Linux's apple,t6041-nvme-ans2 entry do. Only namespace 1
is exposed, as on the other post-M4 controllers.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
In the apple,dockchannel-uart binding the "data" reg entry is the
channel's own data window, and apple,channel is the channel's index in
the shared interrupt mask and flag registers (bits 2n and 2n + 1). The
driver added apple,channel * 0x10000 to the named data window as well,
so on a DT with a non-zero apple,channel (the J616s KIS console is
channel 2) it would write outside the channel. Use the named data window
as it is; the offset still applies to the compact form that only names
the shared window.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The boot loader names its ESP in /chosen/asahi,efi-system-partition, and
U-Boot boots EFI/BOOT/BOOTAA64.EFI from it. On a Mac whose stub ESP
(where Stage 1 finds Stage 2) is not the ESP of the installed OS, that
ESP has no EFI boot loader and the boot falls through to bootflow, while
Linux, told the stub ESP, looks for its vendor firmware in the wrong
place. The J616s is such a Mac: Stage 1 names the AURORA ESP, and Fedora
lives on its own ESP.

Keep the named ESP whenever it has the EFI boot loader (or no ESP has
one). Otherwise use the first ESP on the same disk that has it, and tell
the OS that ESP in /chosen/asahi,efi-system-partition, so its firmware
loader (asahi-scripts) and boot files are found where they were
installed.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
U-Boot's PCIe driver probes the APCIE when a boot falls through to a
bootflow scan; without a mapping for the ECAM it took a synchronous
abort at 0x1c_b000_0000. Map the ECAM and both endpoint windows from the
J616s devicetree, as on J713.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
m1n1 and Linux program the NVMMU base of both the admin and the I/O
submission queue TCB arrays before they enable the controller. U-Boot
programmed the I/O one only when it created the I/O queue, after the
enable. Allocate each TCB array once, 16 KiB aligned as m1n1 and Linux
place them, and on post-M4 controllers program both bases when the admin
queue is set up.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
On the J616s the boot loader hands the ANS over running (CPU_CTRL.RUN,
BOOT_STATUS ok) but with the controller disabled and its RTKit session
asleep: U-Boot's adoption then waits for CSTS.RDY until the watchdog
fires. Linux in the same chain finds the controller disabled, does not
adopt, and wakes the firmware (apple_rtkit_wake(): IOP power state INIT,
then the boot handshake) without resetting the coprocessor.

Do the same on T6040 when the inherited controller is disabled: run the
RTKit handshake with our own SART-backed buffers, wait for BOOT_STATUS,
then program the controller as on adoption. At handoff, leave the ANS as
it was found (controller shut down and disabled, RTKit asleep, CPU
running), so Linux wakes it with its own buffers as it does today.
Controllers handed over enabled are still adopted.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The previous commit woke a T6040 ANS that the boot loader hands over
before the OS-side RTKit handshake and put it back to sleep at handoff.
Linux cannot use that: the firmware takes the HELLO/EPMAP handshake once
per run (Linux in the plain m1n1 chain logs "RTKit: Initializing" and a
cold "boot: mode normal"), and after U-Boot ran it neither sleeping, AP
quiescing nor stopping the IOP lets Linux's wake reach endpoint
discovery again (all three tried on the J616s: -ETIMEDOUT).

So hand the session on live, as Linux expects from a post-M4 boot
loader: after the handshake the controller is set up as on adoption, and
apple_nvme_remove() takes the existing post-M4 path, leaving the
controller enabled and ready for nvme-apple to adopt. The RTKit buffers
the firmware keeps writing come from LMB, are never freed, and are
published to the OS as no-map /reserved-memory nodes (ans-rtkit@...) by
apple_nvme_fdt_fixup(), called from ft_board_setup(); their SART entries
stay in place.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The T6040 firmware takes the OS-side RTKit handshake once per boot; every
later owner has to adopt the live session (after U-Boot ran it, Linux's
wake times out at endpoint discovery, and after an m1n1 Stage 1 ran it,
U-Boot's handshake times out the same way).

Only run the handshake when no OS-side owner has programmed the
controller yet: CC.EN clear and both the NVMMU admin TCB base and the
I/O queue aperture still zero, as iBoot leaves them. An m1n1 stage that
ran the handshake leaves them set when it disables the controller, and
that session is adopted as on the other post-M4 controllers.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
@RyanTheTide
RyanTheTide marked this pull request as ready for review October 28, 2026 03:29
@RyanTheTide
RyanTheTide merged commit cf48be6 into aurora-wip Oct 28, 2026
2 checks passed
@RyanTheTide
RyanTheTide deleted the j616s/t6040-prod-boot branch October 28, 2026 03:31
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.

1 participant