Skip to content

drm/apple: the T6050 display with Linux on the hardware - #894

Closed
funkzy wants to merge 5 commits into
aurora-silicon:t6050/dcpfrom
funkzy:pr/t6050-dcp-native
Closed

funkzy wants to merge 5 commits into
aurora-silicon:t6050/dcpfrom
funkzy:pr/t6050-dcp-native

Conversation

@funkzy

@funkzy funkzy commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Summary

#485 brings up the T6050 (M5 Pro/Max/Ultra) display co-processors on firmware 27 for the APIF guest. On the M5
Ultra Mac Studio (J775D) with Linux running on the hardware, the same DCP code met two things the guest never does:
DPTX ports that the T8140 external rules refused, and a DCP running firmware 27.2, which renumbered the IOMFB
methods. With these commits, and the T6050 DART PR on aurora-wip for the display DARTs the boot loader leaves
locked, the external display comes up under Hyprland on J775D.

They also answer the analytics event every firmware 27 DCP sends about an hour in (a zeroed reply crashed it), fix
the surface records firmware 27 reads, and print each T6050 DCP's recent host traffic when it crashes.

What it changes

  1. Firmware 27's analytics event (callback D113): its dictionary is passed by pointer and deserialized again by the
    firmware when the call returns, so it is answered as the desktop 26.6 table answers the same event (D114): the
    dictionary returned unchanged, the event reported not sent. The record and the reply move to iomfb.h, shared
    by both tables. Desktop 26.6 behaves as before, except that a reply to an event without a dictionary is now
    zeroed.
  2. DPTX: the T8140 external rules (one port named by the DCP index, J700 training and lane checks, its max-drive
    reply) key on dcp_is_external_h17p(). Before, they keyed on wire_v2, which every firmware 27 DCP sets, so
    T6050's ports 0 and 1 were refused (-EINVAL).
  3. DCP: one IOMFB method table per firmware 27.x build. 27.2 moved the IOMobileFramebufferAP methods up by 50 and
    three others up by one; the UPPipe methods did not move. A 27.2 DCP that is sent a 27.0 tag panics. The table is
    chosen at probe from apple,firmware-compat, and a compat with no table is refused with a message naming it.
  4. Surfaces on firmware 27 (dcp_surface_element_geometry(), one predicate for planes and the default
    framebuffer): pix_size and a linear plane's tile_size in bytes per element, the element's size in pixels,
    and has_compr_info only for Interchange planes. Earlier firmware keeps the values it has run with.
  5. DCP (T6050 only): each DCP keeps its last 256 IOMFB calls, callbacks, swaps and mailbox messages in a ring of
    its own (8 KiB), from before its bind, and prints it once when it crashes, before the crash handling sends
    anything. The ring is fed by the driver's existing tracepoints through probes registered with the DCP as their
    data, so each DCP records only its own traffic and no call site changes. call_history=0 turns it off; without
    CONFIG_TRACING (the driver's tracepoints are not built) it is compiled out.

Why

Without 1, the DCP crashes about an hour after it starts ("OSDictionary deserialization failed", 0.4 ms after it
acked the event; on J775D twice of two desktop sessions, about 60.5 minutes in), and the display stays dark until a
reboot. Without 2, no DisplayPort link comes up. Without 3, the first IOMFB call on 27.2 panics the DCP. Without 4,
firmware 27 is sent byte sizes of 1 and a compression record for linear surfaces. 5 is what the one natural DCP
crash on J775D lacked: what the host had asked for before it. A crashed DCP needs a reboot before it shows anything
again, so the record goes to the kernel log, beside the firmware's crash log, not to a buffer read afterwards.

What the guest sees

1 to 4 change #485's firmware 27 path, which the guest shares:

  • 1: a guest DCP that runs long enough to send the analytics event gets its dictionary back instead of zeros.
  • 2: a guest DCP that is not the T8140 external profile now names its ports by unit, as earlier firmware does.
  • 3: a guest on 27.0 gets the same table as before (unchanged IDs); a guest on 27.2 gets the 27.2 table.
  • 4: guest surfaces on firmware 27 get the element sizes too.

5 is keyed on the T6050 compatibles, so a guest DCP keeps its 8 KiB ring as well; with call_history=0 it does
nothing.

Testing (J775D, M5 Ultra)

The kernel: our J775D series (integration/aurora's lineage, as on the Studio every day) with these commits, the
DART PR's and the combo PHY PR's in place of the series' own forms, booted once each on 2026-11-02 and 2026-11-03,
the display handed over by the boot loader on dcpext0, one-shot, for about three minutes each:

  • dcpext0 on firmware 27.2 took the 27.2 table (in the first run every IOMFB call was answered), and the DCP did
    not crash in either run.
  • DPTX: "DCP index:1 dptx target phy: 0"; at hotplug, "connected:1 ... nr_modes:25", then power-on and the first
    modeset.
  • Hyprland came up on the external display. In the first run (with the earlier, trace-instance form of 5) the first
    minute had 682 swaps submitted and 682 completed and 1416 mailbox pushes. In the second, with these commits as
    they are, "call history: keeping the last 256 AP-link messages" at 1.33 s, before the bind, and the desktop up.
  • No panic, BUG, Oops, WARNING or SError line in either run; the machine rebooted cleanly at the end.
  • Builds on drm/apple: Add T6050 firmware-27 display support #485, each commit: 0 errors, 0 warnings in the kernel (our initramfs step fails on drm/apple: Add T6050 firmware-27 display support #485's older DRM
    UAPI, which is ours, not this branch's); the tip also with CONFIG_TRACING=n (CONFIG_FTRACE off,
    DRM_APPLE=y): 0 errors, 0 warnings.
  • checkpatch --strict: one alignment note, on a signature kept as it was.

Not tested

  • The APIF guest (M5 Pro). The changes to its path are listed above.
  • Firmware 27.0 on bare metal: J775D's DCPs run 27.2. The 27.0 table is drm/apple: Add T6050 firmware-27 display support #485's, unchanged.
  • The 27.2 position of dfb_ready_query (A385): it follows the renumbering and has not been seen in a call.
  • A crash with the call history on: none happened in the runs, so the print at a crash has not run on hardware.
  • A full hour of drawing on this branch, so the analytics event (1) itself: both runs were a few minutes long, and
    the event comes about an hour in. The reply follows the desktop 26.6 table's answer to the same event.
  • On drm/apple: Add T6050 firmware-27 display support #485's base: this branch builds there (every commit), but its hardware runs were on our J775D series, whose
    display code is drm/apple: Add T6050 firmware-27 display support #485 merged onto a newer Aurora tree.

Dependencies

#485 (t6050/dcp). On J775D the display DARTs need the T6050 DART PR (aurora-wip); without it shmem_setup
cannot resolve the DCP's log buffer. The J775D board DT that uses these compatibles comes later with the J775D board.
The display handoff from the boot loader is aurora-silicon/aura#61.

For dj

funkzy and others added 5 commits November 2, 2026 15:58
About an hour after it starts, and periodically after that, the 27.x DCP
firmware sends an analytics event as callback D113: an event name and a
serialized dictionary in, the dictionary again out. The dictionary is
passed by pointer, so when the call returns the firmware deserializes the
reply's copy, and if that fails it stops. The firmware 27 callback table
answered D113 with zeros. On the M5 Ultra (J775D) the external DCP
crashed 0.4 ms after acking one ("OSDictionary deserialization failed"),
with nothing else on the link for 20 s, and the display was gone until a
reboot.

Answer D113 as the desktop 26.6 table already answers the same event
(D114 there): return the dictionary unchanged and report the event not
sent. The record and the reply move to iomfb.h, shared by both tables, so
the two answers cannot drift apart again. Desktop 26.6 behaves as before,
except that a reply to an event without a dictionary is now zeroed rather
than left as the firmware's buffer held it.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The T8140 external DPTX rules (the one port named by the DCP index, the
J700 training and lane checks, and its max-drive reply) are keyed on
the AFK v2 codec flag. Firmware 27 sets that flag for every DCP, so on
T6050 the rules refused its ports 0 and 1 (-EINVAL) and no DisplayPort
link came up.

Key them on the T8140 external profile (dcp_is_external_h17p()) instead.
T8140's external DCP takes the same paths as before; firmware 27 DCPs
name their ports by unit, as earlier firmware does, and use the common
DPTX calls.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Firmware 27.2 renumbered the IOMFB AP methods: the IOMobileFramebufferAP
methods moved up by 50, and set_create_DFB, vi_set_temperature_hint and
dfb_ready_query by one. The UPPipe methods are unchanged. A DCP running
27.2 that is sent a 27.0 tag panics ("link_rpc_lookup callback not
found"); on T6050 the first one sent was A427.

Keep a method table per 27.x build and choose it at probe from
apple,firmware-compat ("27.0.0" or "27.2.0"). A firmware-compat with no
table is refused at probe with a message naming it, where a 27.x string
other than 27.0.0 was refused silently before.

The 27.2 position of dfb_ready_query (A385) follows the renumbering and
has not been observed in a call.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The DCP reads a surface's pix_size and each plane's tile_size as bytes
per element. Linear planes sent 1 (block width times height) and the DFB
sent 1, where XRGB8888 is 4 and the DFB's own format says 4 or 8.
has_compr_info is a presence flag, set only when compression_info
describes a compressed (Interchange) plane, and was 1 for linear
surfaces too.

On firmware 27 (DCP_FIRMWARE_V_27_0), send bytes per element, the
element's width and height in pixels, and has_compr_info only for
Interchange planes. The DFB's format and bytes per element now come
from one helper, apple_dcp_dfb_format(), which its allocation also
uses. Earlier firmware keeps the values it has run with: before
widening this, check a linear XRGB8888 and an NV12 swap on 12.x to
26.x firmware.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A DCP crash's log names the failing check, but not what the host had
asked for just before it. The one natural crash on J775D left no trace of
its calls, and a crashed DCP needs a reboot before the display works
again, so whatever is kept has to reach the kernel log.

Each T6050 DCP now keeps its last 256 IOMFB calls, callbacks and swaps
and its mailbox messages on every endpoint in a ring of its own (8 KiB),
and prints it once when it crashes, before the crash handling sends
anything. The ring is fed by the driver's existing tracepoints
(iomfb_push, iomfb_callback, iomfb_swap_submit, iomfb_swap_complete,
dcp_send_msg, dcp_recv_msg) through probes registered with the DCP as
their data, so each DCP records only its own traffic and no call site
changes. The probes are registered before the bind and removed when the
DCP is unbound.

call_history=0 (module parameter) turns it off. T6050 only
(apple,t6050-dcp and apple,t6050-dcpext). Without CONFIG_TRACING the
tracepoints are not built and the history is compiled out.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@funkzy

funkzy commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Closing: this change now lives in the funkzy/j775d branch of aurora-silicon/linux-aurora (the J775D series as built and booted, 681521644671), which dj merges directly; no PR flow for it any more.

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