Skip to content

drm/apple: add opt-in J516M/T6034 native display and G15C support - #415

Draft
DanielLemky wants to merge 25 commits into
omacom:integration/aurorafrom
DanielLemky:j516m-native-graphics
Draft

DanielLemky wants to merge 25 commits into
omacom:integration/aurorafrom
DanielLemky:j516m-native-graphics

Conversation

@DanielLemky

@DanielLemky DanielLemky commented Nov 8, 2026 •

Copy link
Copy Markdown

Depends on #292, #258 and #261; companion loader: omacom/m1n1#41, which carries omacom/m1n1#21 and #24 (#24 was originally stacked on #23, replaced by merged #31). Merged kernel foundations: #363 and #408 (carrying/replacing #372). Target: integration/aurora.
Runtime tested with local Mesa packages based on omacom/mesa#32.

Add the 16-inch J516M M3 Max (14 CPU / 30 GPU cores) to the native display and G15C GPU path. Admit its pinned DCP image, 3456x2234 internal panel, HDMI dcpext0 route, measured GPU firmware digest and fused identity 0x7b5ed7f5fd. Extend the existing PMP GFX bandwidth request to this exact board/SoC pair and use this board's T6034 display opt-out in the PMP startup-failure diagnostic.

Reuse the shared six-channel T6034 layout while preserving J514M's independent profile and supplier. Keep J516M's established T6031 display/PMP metadata namespace, explicit display opt-ins, full firmware checks and existing 120 Hz swap timestamp mechanism. Includes the endpoint-definition include needed to build the combined dependency stack's J514M DTB. Built-in brightness is a separate follow-up: #416.

Validation: main and brightness-follow-up Image/modules/DTBs builds passed. Seven existing host suites passed, including PMP graph/supplier controls and mutants with ASan/UBSan. Independent read-only reviews found no actionable findings. Existing host fixtures are adapted for J516M. The later recovery-diagnostic correction adds no test cases; that exact failure branch was verified statically.

The signed source tree is identical to the tested tree. The combined stack, including the separate brightness follow-up and corrected companion loader, passed native OpenGL/Vulkan pixel checks, matching loaded module build IDs, native compositor, PMP bandwidth request, internal 3456x2234 at 120 Hz, direct HDMI BenQ 2560x1440 at 59.951 Hz, and visible brightness/playback/pointer checks. An earlier small focus-change hitch was not quantitatively retested. USB-C, repeated hotplug, suspend/resume, other GPU bins and sustained power/thermal behavior remain unqualified.

This draft includes the open dependency stack; rebase as those PRs merge so the diff reduces to the J516M commits. Firmware/raw ADT binaries, local boot-image packaging and app-specific playback settings are excluded.

Assisted-by: Codex:GPT-6

Samuel Carreño and others added 25 commits October 28, 2026 11:51
The T6031 (M3 Max) G15 GPU is powered by its PMGR domain alone, with no
RTKit vote, and nothing sets its PTD power request. PMP then ignores the
GPU's bandwidth demand and memory stays at its idle floor.

Port the T6030 report (9bb7476) to T6031: AGX is the acknowledged
soc-device ID 14 (record 13) of the J516C table, on the T6031 report
apertures. Set it after firmware and backend setup, clearing it first,
since an earlier request is acknowledged without enabling bandwidth
scaling. A failure only warns and clears the request, which is how the
GPU ran before. The session and the request stay until reboot.

With Mesa unchanged, compute-copy bandwidth (test-backend-ops perf -o CPY,
Vulkan) goes from 75 to 316 GB/s for 1.5 GB f32 copies and from 56 to
200 GB/s for 768 MB f16/bf16 copies. Tested on an M3 Max J516C, on top
of local patches (HDMI, panel brightness, AVD AV1, in-flight cap); the
panel, HDMI, brightness and AVD keep working.

Generated-by: LLM
Signed-off-by: Samuel Carreño <soyminero11yt@gmail.com>
…th g15_max_inflight

On the T6031 (J516C) a browser submits one render per job. With only two
prefixes in flight and ~612 us of host/firmware turnaround per flight while
the GPU work per render is ~88 us (asahi-g15/stats span vs busy), the engine
held publication on the in-flight cap ~3 times per job (stats hold[0]) and the
GPU idled ~85% of every flight: at 120 Hz Chrome's ~2.7k renders/s hit the
~3.3k/s ceiling and frames queued up as stutter. Power (17-24 W) and a
resolution-scaling test (1322 -> 1276 fps for 4x pixels) showed the GPU was
starved, not busy; pstate was already 8/8.

Raise FLIGHTS and MAX_INFLIGHT to 8 and add g15_max_inflight (0: tuned value,
1..8) so it can be lowered without a rebuild. Later flights still have to be of
the same VM; pass slots (16) and CT buffers bound the rest, and
publish_prefix_into already backs off with EAGAIN when they are held.

Generated-by: LLM
Signed-off-by: Samuel Carreño <soyminero11yt@gmail.com>
…ssbars

Add the M3 Max's four external display processors, their mailboxes and
firmware DARTs, all disabled, at the addresses, interrupts and power
states of the J516C ADT (dcpextN, dart-dcpextN), translated through
/arm-io ranges. The internal DCP's ADT values translate to exactly what
t6031-dcp.dtsi already has, which checks the translation.

  dcpext0 0x3_06c00000  mbox IRQ 1068..1071  DART 0x3_0530c000 IRQ 1047
  dcpext1 0x4_4ac00000  mbox IRQ 1104..1107  DART 0x4_4930c000 IRQ 1083
  dcpext2 0x4_4ec00000  mbox IRQ 1140..1143  DART 0x4_4d30c000 IRQ 1119
  dcpext3 0x2_cac00000  mbox IRQ 1176..1179  DART 0x2_c930c000 IRQ 1155

Each processor's ADT power gate is DISPEXTn-CPU-V, whose parents are
DISPEXTn_CPU and DISPEXTn_FE, as DISP-CPU-V is the internal DCP's. So
each sits on ps_dispextN_fe, as the internal DCP sits on ps_disp_fe.

The node shape is T6030's dcpext: Type-C routes to ATC0..2, disabled
until the display gate enables their processor. The compatible keeps
apple,t6030-dcpext as a fallback so the display driver takes its T6030
external path. apple,typec-mux-indices is N for dcpextN because the
ADT's display-crossbar0 lists its upstream ports as dispext0..7 in
order; this is not yet confirmed on hardware.

Add the three ATC display crossbars (ADT atcN-dpxbar, atc-dpxbar,t602x)
at the T6030 addresses. With the t6020 compatible their probe writes no
register.

Give the PMP's pmp-dispext0..3 requests apple,always-on and
apple,defer-startup-ack, as T6030's. They stay disabled, and the report
driver seeds only available entries, so nothing changes until the gate
enables one.

Add the J514C/J516C Type-C port@3 endpoints for all four processors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
Enable the dcpext gate on T6031 behind its own switch,
apple_t6031_display.dcpext=1, which is off by default. Without it, or
without the boot loader's handoff markers, every processor and its
Type-C routes stay disabled.

The gate's dcpext path assumed T6030's power order: the processor on
dispextN_cpu, the child of dispextN_fe. On T6031 the processor is on
dispextN_fe, the child of dispextN_cpu. Resolve the chain in the SoC's
order, and check the mailbox, firmware DART and display DART against the
processor's own power state, which also gets the active floor (its
parents follow it).

The boot loader's markers stay the T6030 ones
(apple,t6030-dcpext-memory-ready, apple,t6030-dispext-handoff), so the
display driver's checks need no change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
A T6031 dcpext loads the same DCP image as its internal DCP
(F493F03E-CC40-3D89-9A08-5F259BA2B246, per the J516C ADT's iop nubs).
Accept that image on apple,t6031-dcpext nodes only; every other
external processor still needs the T6030 image.

Also give T6031 the T6030 display-crossbar programming. Both use the
same dispext pipes and the same t602x crossbar, and the T6030 path
handles dispext bits 0..3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
The display gate needs the pmp-dispextN report entry to have a phandle,
and dtc emits one only for referenced nodes. Name the entry in
apple,pmp-report, as T8122 does; the gate sets the same value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
dcp_t6030_ext_native() looked only for apple,t6030-display-subsystem, so
a T6031 dcpext the gate had handed its display DART fell back to the
manual diagnostic path and never joined the DRM device. Look up the
subsystem of the processor's own SoC.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
dcpext_check_power() required the processor's power domain to be
dispext<N>_cpu, as on T6030. On T6031 the dcpext sits on dispext<N>_fe,
whose parent is the CPU domain, and the display gate puts the active
floor there, so startup was refused with -EINVAL on attach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
A T6031 dispext<N>_fe power state does not hold the PMGR minimum-state
field: with apple,min-state written it still reads 0xff, as the
internal display's FE state does, while the CPU states keep it. Floor
the CPU domain in the display gate (the same node as before on T6030),
and have the driver check the floor there, reached through the FE
domain the T6031 dcpext sits on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
The J516C 14.7 firmware on a T6031 external processor publishes every
timing with an empty ColorModes array; the display's color modes are
only in ColorElements, and each timing names the ones it excludes in
UnsafeColorElementIDs and DSCRequiredColorElementIDs. Every timing so
had no color mode, parse_mode() rejected all of them, and the
connector stayed disconnected with HPD asserted.

When an external timing has no color mode of its own, select one from
the published ColorElements, less its excluded IDs, with the external
SDR ranking (full-range SDR RGB, 8 or 10 bits).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
The display crossbar runs T6031 in its T6030 mode (t6030_dpin): a route
is selected on activate, and its clocks come up only from the DCP's
DidChangeLinkConfiguration call, through dcp_direct_crossbar_link().
That function returned early on anything but apple,t6030, so on T6031
the direct DP PHY output stayed unclocked ('T602X route 0, clocks
disabled'), and every mode set failed in the firmware with
'IOAVVideoInterface prepareLink() failed'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
T6031 (M3 Max) has the T6030 (M3 Pro) display fabric: T8122-generation
ATC PHYs, a crossbar in t6030_dpin mode and dcpext processors bound as
apple,t6030-dcpext. Its DP IN tunnel path was still disabled, though:

 - the Thunderbolt driver leaves DP IN off on SoCs missing from
   apple_dpin_qualified_soc, and the T6031 ACIO matched only the t8103
   fallback (M1 DP IN policy);
 - the DCP fabric and the ATC PHY pick the T6030 DP IN pixel clock path
   and its source map on of_machine_is_compatible("apple,t6030") alone.

Qualify T6031, give its ACIO the T6030 DP IN policy while it keeps the
t8103 boot sequence (its DT node has no MxWrap region), and take the
T6030 clock path on T6031 too. The T6030 source map (crossbar sources
0 and 2 feed DP IN0/1) is assumed to hold on T6031; untested.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
The T6031 (M3 Max) DCP DPTX firmware drives a DP tunnel like a plain DP
link: it never requests bandwidth through the DP IN adapter's allocation
registers. With allocation mode enabled the tunnel reported "consumed
bandwidth 0/12960 Mb/s", the mode set completed and the sink (a DisplayPort
monitor behind a USB4 dock, DP OUT x2 HBR3) dropped the stream
about 1.5 s later (DPTX INACTIVE_SINK_DETECTED). The same setup works
with thunderbolt.bw_alloc_mode=0.

Add a TB_HOST_DP_NO_BW_ALLOC host policy that takes the bw_alloc_mode=0
path for that host's tunnels only, and give T6031 its own policy: the
T6030 flow plus the new flag. T6030 keeps its current behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
The J516C's HDMI port is ATC3 used as a DisplayPort-only PHY behind
display-crossbar0, feeding an on-board DP-to-HDMI converter, as on the
J514S/J516S (t603x-j514s-j516s-hdmi.dtsi). The T6031 tree described
only ATC0..2, so the port had no connector.

From the J516C ADT:
- atc-phy3 and atc3-dpxbar sit where the T6030's do (0x1303000000,
  0x130304c000);
- dp2hdmi-gpio0: hdmi_pwr_en and dp2hdmi_pwr_en are SMC gP0f and gP1a,
  the J514S/J516S pins;
- atc3-hdmi: function-hdmi_hpd is AOP GPIO 42 (47 on the J514S/J516S).

dcpext0 takes the fixed route and stays a hybrid pipeline, lent to a
USB-C port while no HDMI display is attached. The atcphy3 alias lets
m1n1 copy the ADT's atc-phy3 calibration; without it the PHY reports
"Calibration tunables missing, DisplayPort disabled".

HDMI audio (DPA1 over the SIO) is not described yet.

Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the J516C only dcpext0 brings up an external display. dcpext1..3
time out in the DPTX remote port on USB-C (HPD assert, link
configuration) and dcpext3 does the same on the HDMI route:

  AppleDCPDPTXRemotePort (chan:1) command type 0xc0 tag 0x0300 timed out after 1000 ms
  dcp_dptx_connect: failed to assert Type-C HPD: -110
  DPTXPort: firmware reports link fault 22 on target 0:3

With the HDMI route on dcpext0, the allocator offers a hybrid pipeline to
USB-C last, so a USB-C display always landed on a broken processor.
Mark dcpext1..3 "fail": the display gate enables only processors left
"disabled", and the DRM device waits only for available ones, so
dcpext0 serves USB-C and HDMI alike.

This is a stopgap that limits the J516C to one external display until
dcpext1..3 are fixed; drop it then.

Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A T6031 external processor's timings take their colors from
ColorElements, but dcp_v14_external_published() built the mode catalog
only on a TimingElements publication. Timings published before their
colors so gave no mode until republished, replaced colors (ID 7 by 11)
left the catalog on the old ID, and withdrawn colors left an admitted
catalog naming color IDs that were gone. The fallback also applied to
every native v14.7 external processor, beyond the T6031 opt-in.

Opt the T6031 dcpext in explicitly (shared_colors), and on it rebuild
the catalog from the published timings and the colors published now
whenever either is published, replaced or withdrawn, in either order.
A color change that leaves the timings no mode withdraws the catalog
(dcp_modes_withdraw(): no longer admitted, kept for snapshot readers)
and the timings' part of the description, and reports the display
withdrawn once: the firmware withdraws ColorElements before
TimingElements on an unplug, and a second report would release a
connector kept connected through the withdrawal. A removal has no
transfer and applies to the current attachment; a transfer begun
before it is still refused as stale.

The dcp_v14_shared_colors KUnit suite runs the production callback
through both publication orders, replacement, unsafe-ID exclusion,
withdrawal in both orders (one report each), republication, stale
generations, and a processor without the opt-in. With the rebuild on
a color change disabled, six of its eight cases fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WHu9VBxYcBYR8voXKiSV65
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
A T6031 external session whose first mode was fast hung on its first
swap: with 3840x2560@60 (DSC) on the J516C 14.7 image, the firmware
dropped swap ID 1 and its A407 never completed, ending the session
until reboot:

  IOMFB: swap_submit_dcp: swallowed swap ID 1 as timinsg are not enabled for External Display
  DCP call 0x41343037 failed: -110; recovery requires a reboot

The firmware starts a display's timings in a deferred run mode change
after A472(1) and then sets the boolean property NormalModeActive (D104)
to 1; A472(1) sets it to 0 first. With a slow mode (2560x1600@60) the
change ends within A472, NormalModeActive already 1 when it replies.
With the DSC mode it ends about 20 ms after A472 replied, and the swap
sent meanwhile is dropped. Later swaps sent early are held instead, so
only a session's first mode failed. Logged on a J516C:

  8.597  A472(1)
  8.599  D104 NormalModeActive = 0
  8.613  A472 replied; A406, A407 sent
  8.614  swallowed swap ID 1 as timings are not enabled
  8.633  switch to normal mode succeeded; D104 NormalModeActive = 1

After A472(1), wait under the RPC lock for NormalModeActive (service 0)
to be 1, handling the queued callbacks as dcp_v14_idle() does, for up
to 500 ms. A timeout fails the mode set into the retry path; a failed
callback stops the session; a firmware that never reported the property
is not waited for. Every power-on is waited for, about 20 ms for the
first DSC mode and 10 ms for later ones.

On the J516C with a 3840x2560 display (DP over USB-C), six boots
(reboot, power cycle, replug) set 3840x2560@60 first and showed its
first swap in 18 ms; 14 later mode sets, 3840x2560@120 included, all
succeeded. Without the wait, 5 of 5 boots lost the session.

The dcp_v14_normal_mode KUnit suite runs the wait and the production
D104 handler with a scripted link pump.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WHu9VCTrUXYgBxj2gKTGrp
Signed-off-by: DB <rafal+claudeai@digitalbrew.io>
Assisted-by: Codex:GPT-6
Signed-off-by: Daniel Lemky <daniel@quantumfirelabs.com>

# Conflicts:
#	drivers/gpu/drm/apple/iomfb_v14_7.c
Assisted-by: Codex:GPT-6
Signed-off-by: Daniel Lemky <daniel@quantumfirelabs.com>
Assisted-by: Codex:GPT-6
Signed-off-by: Daniel Lemky <daniel@quantumfirelabs.com>
The in-flight T6034 display profile includes t6031-dcp.dtsi, whose
external routes reference the Type-C endpoints. Include the same
endpoint definitions already used by J514C to resolve the twelve
undefined phandles when combining PR372 with the current display
base. This supplies graph endpoints without enabling a processor.

Keep this integration correction separate from the J516M board work.

Assisted-by: Codex:GPT-6
Signed-off-by: Daniel Lemky <daniel@quantumfirelabs.com>
Reuse the ADT-confirmed T6031 display layout on the J516M/T6034,
with its exact board/SoC and pinned 14.7 DCP image. Retain the
working T6031 handoff namespace separately from J514M and require
explicit display and dcpext owner choices. Only dcpext0 is qualified.

Enable the existing swap timestamp behavior for the 120 Hz internal
panel and carry the J516M panel admission cases into the existing
host fixture. Other boards and their default policy are unchanged.

Assisted-by: Codex:GPT-6
Signed-off-by: Daniel Lemky <daniel@quantumfirelabs.com>
Share the existing six-channel T6034 G15C hardware layout while
keeping J516M machine and full firmware admission independent of
J514M. Require the measured 30-core fused identity 0x7b5ed7f5fd and
retain strict refusal of the generic firmware-prefix override.

Link J516M GPU startup to its T6031 display supplier; keep J514M on
its separate T6034 supplier. Extend the existing profile and display
order fixtures with the prior J516M admission cases. Inherited
J516C power/reference values remain thermally unqualified.

Assisted-by: Codex:GPT-6
Signed-off-by: Daniel Lemky <daniel@quantumfirelabs.com>
Extend the T6031 GFX bandwidth helper to the exact J516M/T6034 root
pair. This board uses the same report layout and the existing GFX
request/ack protocol. Keep other T6034 boards outside this guard
and retain the existing supplier readiness and timeout behavior.

Assisted-by: Codex:GPT-6
Signed-off-by: Daniel Lemky <daniel@quantumfirelabs.com>
J516M uses the T6031 PMP report layout, whose fallback tells users to
boot with apple_t6031_display.enable=0 after startup fails. Its display
gate only honors apple_t6034_display.enable, so that advice can leave a
retained T6034 enable active and retry the failed startup.

Select apple_t6034_display.enable=0 for the exact J516M/T6034 machine
pair. Keep other report profiles' recovery switches and the nomodeset
alternative unchanged. No PMP startup or report protocol changes.

Fixes: 727efc7 ("drm/apple: add opt-in J516M native panel and HDMI admission")
Assisted-by: Codex:GPT-6
Signed-off-by: Daniel Lemky <daniel@quantumfirelabs.com>
@hungbenjamin402

Copy link
Copy Markdown

Second J516M: 120 Hz display, DPMS and suspend pass; G15C needed a second fused-core mask

I tested #416 (which carries #415) with omacom/m1n1#41 on a second J516M. The internal panel runs natively at a measured 120 Hz and survives DPMS and s2idle cycles. G15C refused this die's fused-core mask, then admitted and rendered after a one-line change to hw/j516m.rs (patch below).

Mac and installed build

Both firmware versions and provisioning

  • asahi,os-fw-version: 14.7
  • asahi,system-fw-version: unknown
  • iBoot1 mBoot-20457.40.150.0.1, iBoot2 iBoot-10151.140.19.700.2
  • m1n1 stage 1 v1.6.1-dirty, stage 2 b05e6acd-dirty
  • Provisioning: not relevant to these results.

Actions and results

Feature / action Result Details
Boot with the new m1n1 and display opt-in, but no kernel opt-in as designed native display not requested (apple_t6034_display.enable=1 is not on the command line); the display stays on simpledrm. The kernel opt-in is easy to miss for testers.
Native internal display pass J516M display started: 3456x2234@120, 74 notch rows shown, 346x223 mm; Hyprland drives eDP-1 at 3456x2234@120
120 Hz flip cadence pass DRM page-flip test from a VT with the compositor on another VT, 600 flips on two dumb buffers: avg 8.333 ms (120.00 Hz), min 8.276, max 8.402. 590 of 590 intervals near 8.33 ms, none near 16.67 ms, so no #31-style halving.
Built-in panel brightness (#416) pass /sys/class/backlight/apple-panel-bl, max 500. The brightness keys visibly dim and brighten the panel, and the DCP logs each step, e.g. brightness_changed: brightness value: 2621440 … 9175040 (40 to 140 nits in 25-nit steps). Current reading is 350/500. Full range and photometric accuracy not measured.
G15C with #416 as-is fail T6034 G15C: power acknowledged, version=0x7041100 counts=0x21040a core-mask=0x73df57f5fd, then J516M powered identity differs from the measured bin, probe ... failed with error -71. The desktop stays on llvmpipe at about 400–500 % CPU.
G15C with the patch below pass T6034 G15C admitted, cores enabled per cluster: [8, 8, 7, 7], firmware J516M RTKit 2419.140.12 accepted and READY, /dev/dri/renderD128 present
OpenGL / Vulkan pass GL 4.6 (Core Profile) Mesa 26.3.0-devel (git-b7b03c5b3b), renderer Apple M3 Max (G15C B1); Vulkan 1.4.363 Apple M3 Max (G15C B1) (Borealis). Hyprland runs on the render node at about 3 % CPU. No GPU or DART faults logged.
Panel off/on (DPMS) pass, 10/10 hl.dsp.dpms disable for 3 s, then enable, 10 times. Each cycle reads dpmsStatus 0 then 1 and comes back at 3456x2234@120. No DCP, RTKit, DART or GPU messages in the kernel log during the run.
s2idle suspend/resume pass, 3/3 systemctl suspend, woken by a key press after about 10 s each time (no RTC wake alarm on macsmc-rtc). After each resume: eDP-1 at 3456x2234@120, renderD128 present, GL renderer still Apple M3 Max (G15C B1), and the backlight unchanged at 350/500. The only kernel errors are from an attached USB storage device (sd/ses) and brcmfmac join_pref -52.
USB-C to HDMI cable (LG 4K60) fail, expected The Type-C partner is detected, but no DisplayPort alt mode is entered and no DRM connector appears. Only dcpext0 (the HDMI route) is wired in this stack. dcpext1–3 are status = "fail" and skipped by the gate. Out of scope here; this is the #406 path.
Stock linux-aurora 7.2.11.aurora14-1 booted on the same boot.bin pass It ignores the handoff and stays on simpledrm, so the side-by-side fallback is safe.

Not tested yet: the built-in HDMI port (dcpext0 with apple_t6034_display.dcpext=1), lid-close and long sleeps, sustained GPU load, and power and thermals.

Fused-core mask

version counts core mask clusters (10 bits each, cluster 0 first)
measured bin in hw/j516m.rs 0x07041100 0x0021040a 0x7b5ed7f5fd 0x1fd 0x1fd 0x1ed 0x1ed (8/8/7/7)
this J516M 0x07041100 0x0021040a 0x73df57f5fd 0x1fd 0x1fd 0x1f5 0x1cf (8/8/7/7)

m1n1 reports the same value in /chosen/asahi,t6034-gpu-powered-identity (core-mask-1:0 = 0x73:0xdf57f5fd), and Mesa #33 already admits any 30-core 4×10 layout. So the kernel's exact-mask check is the only blocker.

Proposed change

The patch keeps the exact-identity policy and lists both measured masks. Version and counts stay pinned, and other masks, including the J514M's 0x7b5fc7f5fd, are still refused. The host test gains three cases: the new mask is admitted, and it is refused with a wrong version or with one core removed. tools/asahi/g15-t6034-profile-tests.py passes on Rust 1.93.1. With the new assertions and the old j516m.rs, it fails at the new-mask assertion, as expected.

The commit is on top of #416's head, signed off, in hungbenjamin402/linux-aurora@j516m-second-core-mask:

git fetch https://github.com/hungbenjamin402/linux-aurora.git j516m-second-core-mask
git cherry-pick a15193148e77fff39b214cb4e766cb48f39a08e3
Patch (on e9e02dc5e057)
diff --git a/drivers/gpu/drm/asahi/g15/hw/j516m.rs b/drivers/gpu/drm/asahi/g15/hw/j516m.rs
index 642abbd0999c..08471d7f0b19 100644
--- a/drivers/gpu/drm/asahi/g15/hw/j516m.rs
+++ b/drivers/gpu/drm/asahi/g15/hw/j516m.rs
@@ -25,6 +25,13 @@
     ..super::t6034::CONFIG
 };
 
+/// Fused-core masks measured on J516M boards. Each enables 30 cores, split 8/8/7/7
+/// across the four ten-slot clusters; which slot is fused off differs per die.
+const MEASURED_CORE_MASKS: [u64; 2] = [
+    0x7b5ed7f5fd, // [0x1fd, 0x1fd, 0x1ed, 0x1ed]
+    0x73df57f5fd, // [0x1fd, 0x1fd, 0x1f5, 0x1cf]
+];
+
 pub(crate) fn identity_matches(version: u32, counts: u32, cores: u64) -> bool {
-    version == 0x07041100 && counts == 0x0021040a && cores == 0x7b5ed7f5fd
+    version == 0x07041100 && counts == 0x0021040a && MEASURED_CORE_MASKS.contains(&cores)
 }
diff --git a/tools/asahi/g15-t6034-profile-tests.py b/tools/asahi/g15-t6034-profile-tests.py
index 90605f84d124..d7a6a7d17660 100644
--- a/tools/asahi/g15-t6034-profile-tests.py
+++ b/tools/asahi/g15-t6034-profile-tests.py
@@ -163,7 +163,7 @@ j516m_source = j516m_source.replace('apple,j514m', 'apple,j516m')
 j516m_source = j516m_source.replace('b"apple,j516m",b"apple,j514s"', 'b"apple,j514m",b"apple,j514s"')
 j516m_source = j516m_source.replace('0x7b5fc7f5fd', '0x7b5ed7f5fd')
 j516m_source = j516m_source.replace('[0x1fd,0x1fd,0x1fc,0x1ed]', '[0x1fd,0x1fd,0x1ed,0x1ed]')
-j516m_source = j516m_source.replace(' assert_eq!((c.hw_ids', ' assert!(j516m::identity_matches(0x07041100,0x0021040a,0x7b5ed7f5fd));\n assert!(!j516m::identity_matches(0x07041200,0x0021040a,0x7b5ed7f5fd));\n assert!(!j516m::identity_matches(0x07041100,0x0001040a,0x7b5ed7f5fd));\n assert!(!j516m::identity_matches(0x07041100,0x0021040a,0x7b5fc7f5fd));\n' + ' assert_eq!((c.hw_ids', 1)
+j516m_source = j516m_source.replace(' assert_eq!((c.hw_ids', ' assert!(j516m::identity_matches(0x07041100,0x0021040a,0x7b5ed7f5fd));\n assert!(!j516m::identity_matches(0x07041200,0x0021040a,0x7b5ed7f5fd));\n assert!(!j516m::identity_matches(0x07041100,0x0001040a,0x7b5ed7f5fd));\n assert!(!j516m::identity_matches(0x07041100,0x0021040a,0x7b5fc7f5fd));\n assert!(j516m::identity_matches(0x07041100,0x0021040a,0x73df57f5fd));\n assert!(!j516m::identity_matches(0x07041200,0x0021040a,0x73df57f5fd));\n assert!(!j516m::identity_matches(0x07041100,0x0021040a,0x73df57f5fc));\n' + ' assert_eq!((c.hw_ids', 1)
 with tempfile.TemporaryDirectory(prefix='t6034-profile-') as temp:
  for name,code in [('profile-j514m',source),('profile-j516m',j516m_source),('measurement-refusal',identity_source)]:
   p=Path(temp)/name;p.with_suffix('.rs').write_text(code)
Signed-off-by: Benjamin Nguyen <hungbenjamin402@gmail.com>

If you would rather admit any 30-core 8/8/7/7 J516M bin than add masks one at a time, the same data supports that. I followed the existing policy of admitting only measured masks.

@scottjones

Copy link
Copy Markdown
Collaborator

Thanks for this, it's a really thorough report. A second J516M with a different core mask is exactly the data we needed, and it's great to see the 120 Hz, DPMS and s2idle results hold up on another Mac.

#415 is Daniel's work, and we've carried it forward in #429 (#429), which supersedes it. #429 already does what you suggested at the end. Commit b4cff0e ("drm/asahi: g15: admit any 30-core J516M bin, not one Mac's core mask") checks the G15C version and counts plus exactly 30 enabled cores, and the existing per-cluster check still requires every cluster to be non-empty. Your mask 0x73df57f5fd has 30 cores split 8/8/7/7, so it should be admitted without a patch. Thanks for putting together a151931 with tests, but we won't need it. To be clear, we've only checked your mask against the code, not booted #429 on your Mac.

#429 also makes the display and GPU default-on, so the apple_t6034_display.enable=1 opt-in you found easy to miss goes away. It pairs with omacom/m1n1#42 (omacom/m1n1#42), which builds on m1n1#32 and makes the loader side default-on too.

HDMI and USB-C to HDMI are deliberately out of scope for this carry.

If you have time, could you boot #429 plus m1n1#42 with no opt-in lines (none in /etc/m1n1.conf, nothing on the kernel command line) and without your mask patch, and share:

  • the asahi-g15 lines from journalctl -k -b | grep -i g15
  • the "cores enabled per cluster" line
  • whether /dev/dri/renderD128 is present
  • the display mode you get

That would give us a second default-on J516M test, on a different bin. To go back afterwards, reinstall your #416 and m1n1#41 packages and restore your opt-in lines.

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.

3 participants