Skip to content

drm/apple: m4: adopt the J604 internal panel (preferred 120 Hz mode) - #1178

Merged
DjDeveloperr merged 3 commits into
integration/aurorafrom
m4/j604-panel-profile
Nov 7, 2026
Merged

DjDeveloperr merged 3 commits into
integration/aurorafrom
m4/j604-panel-profile

Conversation

@DjDeveloperr

Copy link
Copy Markdown
Contributor

Summary

The M4 internal display backend gets a J604 panel profile (MacBook Pro 14-inch, M4, Mac16,1, T8132), alongside the J713 and J715 profiles. The timing parser can now pick the preferred element out of a multi-element report. The J604 display does not come up with this PR alone. #1171 already moved the kernel's display gates to the 26.6.2 firmware path. The remaining blocker is aura's DCP handoff, which is still J713-only (see below). This PR covers only the panel profile and the parser.

J604 timing elements

Source: macOS 26B123, ioreg -lw0 -r -n disp0, TimingElements. I checked every element's porches and totals, not just the preferred one.

ID Preferred Rate Horizontal: Active, Total, FP, Sync, BP H PreciseSyncRate Vertical: Active, Total, FP, Sync, BP V PreciseSyncRate
2 Yes 120 Hz 3024, 3104, 8, 32, 40 16986999 1964, 2160, 102, 8, 86 7864351
3 No 60 Hz 3024, 3104, 8, 32, 40 16986999 1964, 2160, 102, 8, 86 3932160
4 No 48 Hz 3024, 3104, 8, 32, 40 16986999 1964, 2160, 102, 8, 86 3145728
5 No 59.94 Hz 3024, 3104, 8, 32, 40 16969960 1964, 2160, 102, 8, 86 3928232
6 No 47.95 Hz 3024, 3104, 8, 32, 40 16969960 1964, 2160, 102, 8, 86 3142585
7 No 50 Hz 3024, 3104, 8, 32, 40 16986931 1964, 2592, 534, 8, 86 3276800
  • All six have SyncPolarity 1 and PixelRepetition 0 on both axes.
  • All six have IsVirtual, IsInterlaced, IsSplit and IsOverscanned set to No, TimingType 3, and VRR min/max 0.
  • Each has one color mode: ID 1, Depth 8, PixelEncoding 0, DynamicRange 0, EOTF 0, Colorimetry 16, SupportsDSC 0.
  • Totals add up for every element: 3024+8+32+40 = 3104, 1964+102+8+86 = 2160, and for ID 7, 1964+534+8+86 = 2592.
  • The adopted ID 2 mode decodes to 3024x1964, hsync 3032-3064, vsync 2066-2074 and an 804560 kHz pixel clock.

Changes

  1. drm/apple: m4: select the preferred timing among several
    • dcp_m4_parse_timing() used to require exactly one element.
    • A profile now gives the most elements its panel reports (timing_elements): 1 for the J713 and J715.
    • The parser picks the element with ID 2 and still matches it exactly against the profile. It also requires that every element is a dictionary with an integer ID, that ID 2 appears exactly once, and that no other element is preferred.
    • The J713/J715 checks are not loosened. With one element allowed, they accept and refuse the same reports as before.
  2. drm/apple: m4: add a J604 panel profile
    • The profile has the ID 2 timing and timing_elements = 6.
    • It is selected by the existing machine-compatible lookup (apple,j604), so no other hook was needed.

Not supported: ProMotion mode switching. Only the preferred 120 Hz element (ID 2) is adopted. The 60, 59.94, 50, 48 and 47.95 Hz elements are accepted in the report but never used.

Assumptions

  • Same firmware ABI. The J604 runs the same DCP firmware 26.6.2 as the Airs, so the swap and callback offsets are copied from the J713/J715. These are swap_size, swap_surface, swap_dva, swap_nullable, swap_tail, swap_nits, swap_intent, done_method, done_size and open_method. This has not been verified on a J604.
  • Property contents. The driver reads the DCP's PreferredTimingElements. The capture is macOS's TimingElements, and I assume the DCP property carries those six elements or a subset of them. A report holding only ID 2 is accepted too.
  • Boot stride. boot_stride is assumed unpadded: 3024 × 4 = 12096, matching the Airs' 2560 × 4 and 2880 × 4.
  • Brightness.
    • brightness_max = 1000 is the panel's rated SDR maximum (XDR mini-LED), as 500 is the Airs'.
    • brightness_default = 120 is unchanged because these values are absolute nits, not a fraction of the maximum. 120 nits is the same indoor level the Airs start at.
    • The M4 backend does not read either profile field yet. iomfb_m4_configure_backlight() hard-codes 500/120 and the swap encoder refuses more than 500 nits. Until those read the profile, the J604 tops out at 500 nits. I left that out of this PR to keep its scope to the profile and parser.
  • Panel size. width_mm/height_mm are 0, as in the other profiles.

J604 display gates: what #1171 covers, what is left

This branch has merged integration/aurora at 38b2b8b, so it includes #1170 and #1171. After #1171, the kernel gates on the internal-panel path key on apple_t8132_firmware_path(): the Airs, or any T8132 whose /chosen/asahi,os-fw-version is exactly 26.6.2.

Already covered by #1171 for a J604 on 26.6.2:

The kernel's remaining apple_t8132_air() uses are not on the display path:

  • the PCI identity default domain in apple-dart.c;
  • t8132_pmgr_policy() in t8132-platform-handoff.c;
  • t8132-platform-test.c.

Still blocking the J604 internal display: the boot loader.

  • dt_set_j713_dcp_handoff() in aura's src/kboot.c (main 98765bcc, which includes aura MacBook Pro · M2 family #106) still refuses any root compatible other than apple,j713. On a J604 it prints "J713 DCP handoff refused; keeping the boot framebuffer". It then publishes none of the following:
    • apple,firmware-uuid;
    • the DCP firmware reservation;
    • apple,j713-inherited-mappings on disp0_piodma.
  • Without those, iomfb_m4_init() refuses with "unqualified firmware 26.6.2 handoff" and the boot framebuffer stays.
  • The same check would refuse a J715 (root compatible apple,j715).
  • The kernel side also needs aura to write asahi,os-fw-version = "26.6.2", as it does for the firmware path.

One more thing to check on hardware. dcp_m4_boot_framebuffer_check() accepts a handed-over console of panel_height or panel_height - 64 lines. The 64 lines are the Airs' notch. A full-height 1964-line console passes. If the J604 loader hands over a console that excludes the notch, the 14-inch notch height has to be checked against that 64.

Tests

  • The new host test m4-panel-timing runs the actual parser on encoded reports. It is in the m4 group and uses the J604 report as the fixture m4-fixtures/timing-elements.json.
  • J604 cases:
    • Adopted: all six elements; ID 2 moved last; ID 2 alone; a changed non-preferred element.
    • Refused:
      • each of the 16 H/V values of ID 2 changed;
      • any flag, VRR value or color mode changed;
      • a second color mode;
      • no ID 2, whether renumbered or removed;
      • two ID 2 elements, or a second preferred element;
      • an element without IsPreferred, without an ID, or that is not a dictionary;
      • seven elements;
      • J604 reports on the J713/J715, and the reverse.
  • J713/J715 cases:
    • Adopted: the single-element reports, with the decoded mode checked.
    • Refused:
      • every timing value changed in turn;
      • the report on the other Air;
      • a second element, no ID 2, not preferred, an empty report.
  • I compiled the same 81 cases against the base parser as a one-off control. All 41 J713/J715 cases gave identical results. The only differences were the three J604 multi-element adoption cases, which base refuses.
  • Full suite on macOS: python3 -E -s -B run.py --output DIR gives 87/87 ok, both before and after the merge (the 86 existing tests plus m4-panel-timing).
  • Kernel build of the merged head: ./linux-build/build kernel --profile asahi <tree> -- Image modules dtbs succeeded from an empty output directory with Rust on. iomfb_m4.o, appledrm.ko and t8132-j604.dtb were built, with no warnings or errors. A first attempt crashed clang with SIGILL in unrelated files (the build VM's guest-memory zeroing). I discarded that output and verified the guest (0 bad files) before the clean build.

🤖 Generated with Claude Code

The M4 backend adopts the internal panel only when the DCP's
PreferredTimingElements holds exactly one element, ID 2, matching the
profile. That fits the J713 and J715. macOS 26B123 reports six timing
elements for the J604's ProMotion panel, the preferred 120 Hz one (ID 2)
and five 48 to 60 Hz ones, and such a report would be refused.

Give each profile the most elements its panel reports, one for the J713
and J715, and select the element with ID 2 among them. It is matched
exactly as before. Every element must be a dictionary with an integer ID,
ID 2 must appear once and no other element may be preferred. With one
element allowed, the J713 and J715 accept and refuse the same reports as
before.

Add a host test that runs the parser on encoded reports: J713 and J715
single-element reports with each timing value changed in turn, and the
J604's six-element report from macOS as a fixture.

Signed-off-by: Diljit Singh <hey@djdev.me>
The J604 (MacBook Pro 14-inch, M4) has a 3024x1964 ProMotion XDR panel.
macOS 26B123 reports six timing elements for it. Each has the Airs'
single 8-bit color mode, 3024 active pixels on a 3104 total, horizontal
porches 8 and 40, sync widths 32 and 8 and positive syncs:

  ID  rate      vtotal  vertical front/back porch
  2   120 Hz    2160    102/86 (preferred)
  3   60 Hz     2160    102/86
  4   48 Hz     2160    102/86
  5   59.94 Hz  2160    102/86
  6   47.95 Hz  2160    102/86
  7   50 Hz     2592    534/86

Add a profile with the preferred 120 Hz timing that allows six elements.
Only that mode is adopted; switching to the lower ProMotion rates is not
supported.

The J604 runs the Airs' 26.6.2 DCP firmware, so the profile assumes the
same swap and callback offsets. The boot framebuffer stride is assumed
unpadded, 3024 * 4 bytes, as on the Airs.

brightness_max is the panel's rated SDR maximum, 1000 nits, as 500 is
the Airs'. The default stays at the Airs' 120 nits, since these values
are absolute nits. The M4 backend does not read either field yet: it sets
every panel up for 500 and 120 nits.

The internal DCP still does not probe on a J604: the PMP display power
bridge, the display DARTs and the display gate are limited to the J713
and J715.

Signed-off-by: Diljit Singh <hey@djdev.me>
Picks up #1170 (G15/G16 on by default) and #1171 (T8132 display, PMP and
GPU gates on SoC plus firmware 26.6.2). No conflicts.

Signed-off-by: Diljit Singh <hey@djdev.me>
@DjDeveloperr
DjDeveloperr merged commit f5fa539 into integration/aurora Nov 7, 2026
1 check 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.

1 participant