Skip to content

t6022-j475d: Thunderbolt DP tunnels on the M2 Ultra Mac Studio - #463

Open
jcrowthe wants to merge 4 commits into
omacom:integration/aurorafrom
jcrowthe:j475d-tb-dp
Open

jcrowthe wants to merge 4 commits into
omacom:integration/aurorafrom
jcrowthe:j475d-tb-dp

Conversation

@jcrowthe

@jcrowthe jcrowthe commented Nov 13, 2026 •

Copy link
Copy Markdown

Thunderbolt displays on the Mac Studio (M2 Ultra, J475d). Stacked on #462: the first commit here is #462's. Please review the last three.

  1. thunderbolt: apple: qualify the M2 Ultra (t6022) for DP tunnels
  2. phy: apple: atc: qualify the M2 Ultra and the fourth die-0 ATC for DP tunnels
  3. arm64: dts: apple: t6022-j475d: wire Thunderbolt DP tunnels on the rear ports

Problem

A Thunderbolt display on a J475d rear port enumerates, but the DP tunnel is torn down after the DPRX timeout and the display gets no signal:

thunderbolt 0-1: LG Electronics 40WP95C
thunderbolt-apple-nhi f01f00000.nhi: 0:5 <-> 1:13 (DP): not active, tearing down
thunderbolt-apple-nhi f01f00000.nhi: 0:6 <-> 1:13 (DP): not active, tearing down

5a07508 kept M2 desktops out on purpose ("M2 desktops, T6002 and T8112 remain disabled"), pending hardware qualification. On t6022 three gates are closed:

  • apple_dpin_qualified_soc (thunderbolt_apple) has t6020/t6021 but not t6022, so the DP IN adapter never asks for a pipeline.
  • apple_atc_t602x_qualified() (phy-apple-atc) has the same list, and apple_atc_t602x_core_valid() only knows the laptop ATC0-2 bases. The desktops' fourth rear port is ATC3 at 0x1303000000.
  • The M2 pre/post flow needs dual-stream wiring (apple_dp_tunnel_dual_stream()): two DCPs per connector with typecN-dpin0/1 on crossbar cells 1 and 2. The J474/J475 trees only wire dcpext1 to the rear ports, for DP alt mode (arm64: dts: apple: t6022-j475d: enable DP alt mode on the rear USB-C ports #462).

Changes

  1. Add t6022 to apple_dpin_qualified_soc. Its die-0 ACIO, ATC and crossbar are the t6021 blocks, and the DCPs are the same apple,t6020-dcpext.
  2. Add t6022 to apple_atc_t602x_qualified() and ATC3 (0x1303000000) to apple_atc_t602x_core_valid().
  3. J475d DT. HDMI runs from die 1, so die-0 dcpext0 is free:
    • enable it as a USB-C-only pipeline for the four rear ports, at crossbar state 0 (dcpext1 stays at state 2, as on the laptops);
    • give both die-0 DCPs typecN-dpin0/1 controls on crossbar cells 1 and 2;
    • add the second endpoint to each rear connector's port@3;
    • add dispext0_dart to the display iommus;
    • add the dcpext0 alias.

The KUnit tables for both qualification gates are updated, with a t6022 row for unwired connectors that stays disabled.

m1n1 needs an alias for every enabled DCP

m1n1 sets apple,firmware-compat (and reserves the firmware) only through the ADT-indexed dcpext0…dcpext7 aliases. My first boot with dcpext0 enabled had no dcpext0 alias:

apple-dcp 289c00000.dcp: Could not read 'apple,firmware-compat': -22

and the whole apple-drm aggregate stayed down, HDMI included, so the desktop fell back to 1080p simpledrm. On t6022 the ADT index of die-0 dcpext0 is 0 (dcpext0@89C00000), dcpext1 is 1 and die-1 dcpext0 (HDMI) is 4, which is how the aliases are set. Any future board that enables another DCP needs the matching alias.

KUnit

tools/testing/kunit/kunit.py run --arch=arm64 (QEMU, -cpu max, 16K pages, clang 18.1.8) with USB4_APPLE_DPIN_KUNIT_TEST, PHY_APPLE_ATC_KUNIT_TEST and DRM_APPLE_FABRIC_KUNIT_TEST:

Tree Result
This branch 182 tests: 181 passed, 1 skipped (S35_dual_retry_off, skipped by the suite itself)
Updated tests on the old code 3 failed: atc_tunnel_soc_qualification, atc_tunnel_core_qualification, apple_dpin_qualification_profiles
bed544b + #462 181 passed, 1 skipped

Device tree check

Built with the kernel's own scripts/dtc:

  • t6020-j474s and t6021-j475c have the same sorted contents as the dtbs in linux-aurora 7.2.11.aurora16-1.
  • For t6022-j475d, each rear connector (usb-pd@38, @3f, @3b, @3c) has two bidirectional endpoints, to dcpext1 and dcpext0. Both DCPs carry typecN / typecN-dpin0 / typecN-dpin1 on cells 0/1/2 of the same atcN-dpxbar, which is what apple_dp_tunnel_route_wired() checks.

Hardware testing

Mac Studio (M2 Ultra, 2023), apple,j475d / apple,t6022. The base is linux-aurora 7.2.11.aurora16-1 (bed544b). thunderbolt_apple.ko and phy-apple-atc.ko were rebuilt from this branch (clang 18.1.8, same vermagic) into updates/ with the initramfs regenerated, and the J475d dtb was built from this branch. OS firmware 13.5, system firmware 26.6.2. m1n1 stage 2 is ba130ffb + omacom/m1n1#46 + the T602x DART patch from #379, which the HDMI DCP needs on this machine (#428). Hyprland 0.57.2.

Displays: LG 40WP95C (5120x2160) over Thunderbolt; LG UltraFine 4K over a USB-C to DisplayPort cable; Dell U2718Q on HDMI.

All three DCPs bind and boot:

apple-drm soc@200000000:display-subsystem: bound 289c00000.dcp (ops dcp_comp_ops [appledrm])
apple-drm soc@200000000:display-subsystem: bound 315c00000.dcp (ops dcp_comp_ops [appledrm])
apple-drm soc@200000000:display-subsystem: bound 2289c00000.dcp (ops dcp_comp_ops [appledrm])
apple-dcp 289c00000.dcp: DCP booted
apple-dcp 315c00000.dcp: DCP booted
apple-dcp 2289c00000.dcp: DCP booted

Thunderbolt on rear port 2:

apple-dcp 315c00000.dcp: display routed to Thunderbolt DP tunnel dpin0
thunderbolt-apple-acio f01ac0000.cio: dpin0: active handshake=0
thunderbolt-apple-nhi f01f00000.nhi: 0:5 <-> 1:13 (DP): Apple: DP tunnel paths up, not waiting for DPRX
apple-display-crossbar f0304c000.mux: Switched dpin0 to dispext1,0
apple-dcp 315c00000.dcp: set_digital_out_mode(color:71 timing:60) "5120x2160": 72 ...
apple-dcp 315c00000.dcp: set_digital_out_mode() color mode depth:10 ...

Results (rear ports counted from the left, looking at the back):

Action Result
Thunderbolt attached across a reboot, rear 2 (f01ac0000.cio) pass, 5120x2160@72, 10 bpc
Cold power-on with Thunderbolt (rear 1), DP alt (rear 4) and HDMI attached pass, all three up; the USB-C displays appear after the LUKS prompt, once the tps6598x controllers probe after switch-root
Thunderbolt unplug/replug, rear 2 pass: dpin0: inactive, crossbar link down, dcp_dptx_disconnect; back at 5120x2160@72 about 2.4 s after new device found
Thunderbolt on rear 1 (1301ac0000.cio, ATC3 / phy@1303000000) pass, 5120x2160@72
Thunderbolt alone, replugged, rear 1 pass, routed to dcpext0 (289c00000) at 5120x2160@72, 10 bpc; DP alt then added on rear 4 goes to dcpext1
DPMS off/on with the tunnel up, 5 cycles pass, dpin0: inactive / crossbar link down on off, active / crossbar link up and modeset on on
Thunderbolt + DP alt mode (rear 4, dcpext0) + HDMI (dcpext4) at once pass, 5120x2160@72 + 3840x2160@60 + 3840x2160@60
DP alt mode on rear 1–4 (from #462) pass
Front USB-C ports (die 1) not tested, not wired
Second stream on one port (dpin1), MST, dual-stream docks not tested, no such dock here
DP audio over the tunnel not tested
s2idle suspend/resume, 1 cycle, all three displays active pass, all three back within ~18 s; drm_mode_config_helper_resume: Failed to resume (-22) and two copy_edid failed: -EIO logged on resume (first suspend on this machine, no baseline)
PCIe over Thunderbolt not working, out of scope. An ORARA U2E-01 enumerates, then PCIe-C is not initialized by m1n1 or the kernel. apple_pcie_tunnel_cold_init_machines in the built-in pcie-apple also lacks t6022.

No WARNING, BUG or oops in any boot. Messages seen that do not stop the display:

The repeated screen wake while locked is the Dell dropping HPD in standby combined with aquamarine, hyprwm/aquamarine#495. The tunnel goes down and comes back up cleanly through each of those cycles.

Not covered

The J474s and J475c use die-0 dcpext0 for HDMI, so their dual-stream wiring needs a different layout. With the ATC3 fix here, they could probably follow the 14/16-inch pattern (dcpext0 for HDMI plus Type-C routes), but I can't test that.

…ports

On the Mac Studio (M2 Ultra) no display controller is wired to the four
rear USB-C ports, so a USB-C DisplayPort display there never lights up.
The dcpext1 routes in t602x-j474-j475.dtsi sit inside the
APPLE_T602X_NON_ULTRA block together with the USB4/PCIe-C wiring, and
t6022 does not define it.

The die-0 half of the t6022 keeps the plain labels and the same rear-port
wiring as the M2 Max Studio. macOS on a J475d drives a DP alt mode display
on rear ports 1 and 2 from DCPEXT1 through the display crossbar (ADT
display-crossbar0, "display-crossbar,t602x"), the same controller the
non-Ultra boards use. Keep only the USB4 aliases, the PCIe-C tunnels and
the non-Ultra display iommus under the guard. The dcpext1 display routes,
dpaudio2, the ATC crossbars and the always-on ATC common power domains now
apply to J475d too.

t6022-jxxxd.dtsi points the display subsystem at the die-1 HDMI DART only,
so add dispext1_dart to it on J475d for the framebuffers of the new pipe.

J474s and J475c keep the same nodes and properties; only the position of
the dcpext1 alias within /aliases changes.

Signed-off-by: Jacob Crowther <3944151+jcrowthe@users.noreply.github.com>
The M2 Ultra is two t6021 dies. Its die-0 ACIO, ATC and display crossbar
are the ones the M2 Pro/Max laptops use, and the DCPs are the same
apple,t6020-dcpext. With t6022 missing from apple_dpin_qualified_soc, a
Thunderbolt display on a J475d enumerates, but the DP IN adapter never
asks for a pipeline and the tunnel is torn down after the DPRX timeout:

  thunderbolt-apple-nhi f01f00000.nhi: 0:5 <-> 1:13 (DP): not active, tearing down

Qualify t6022 with the same M2 (pre/post) flow. That flow still requires
dual-stream connector wiring, so nothing changes until a board's DT
describes it.

Tested on a Mac Studio (M2 Ultra, J475d) with an LG 40WP95C on rear
ports 1 and 2: 5120x2160@72, hotplug, and DPMS off/on.

Signed-off-by: Jacob Crowther <3944151+jcrowthe@users.noreply.github.com>
… tunnels

Qualify t6022 for the T602x tunnel clock sequence, as for the
Thunderbolt side, and accept the ATC3 core at 0x1303000000. The 14/16-inch
boards only have ATC0-2, so ATC3 was never listed, but the Mac mini and
Mac Studio use it for their fourth rear port. The wiring gate still
applies.

Tested on a Mac Studio (M2 Ultra, J475d): a DP tunnel on rear port 1
(phy@1303000000) runs 5120x2160@72.

Signed-off-by: Jacob Crowther <3944151+jcrowthe@users.noreply.github.com>
…ar ports

On M2, Thunderbolt DP tunnels need dual-stream connector wiring: two
DCPs per Type-C connector, each with typecN-dpin0/1 controls on cells 1
and 2 of the port's crossbar, as on the 14/16-inch boards. The J475d's
HDMI runs from die 1, so die-0 dcpext0 is free. Enable it as a USB-C-only
pipeline for the rear ports (crossbar state 0, dcpext1 state 2), give
both die-0 DCPs the DPIN controls, add the second endpoint to each rear
connector, and add dispext0_dart to the display iommus.

m1n1 fills apple,firmware-compat only through the ADT-indexed dcpextN
aliases. Without "dcpext0" here, probe fails with
"Could not read 'apple,firmware-compat': -22" and the whole apple-drm
aggregate stays down, HDMI included.

Tested on a Mac Studio (M2 Ultra, J475d), together with the two previous
patches: HDMI (dcpext4), a DP alt mode display on rear port 4 (dcpext0)
and a Thunderbolt display on rear port 2 (dcpext1, dpin0) all run at once.

Signed-off-by: Jacob Crowther <3944151+jcrowthe@users.noreply.github.com>

@scottjones scottjones left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks again, this is great work. Three displays at once on an M2 Ultra Studio is a nice thing to see, and the note about m1n1 needing an alias for every enabled DCP will save someone a confusing afternoon.

I went through the last three commits and found no bugs:

  • The die mapping is right: dcpext0 on die 0 for the rear ports, HDMI stays on die 1.
  • The qualification gates stay narrow. t6022 is the only new SoC, and T6002 is still out.
  • KUnit passes here too, and reverting the t6022 and ATC3 lines fails the same three cases as your table.
  • It merges cleanly with #460 and #127. One thing to know: with this in, #460's HPD release timeout path becomes reachable on t6022.

A few questions:

  1. Has a Thunderbolt display gone through dcpext0 yet? For example two Thunderbolt displays at once, or the second stream. The Thunderbolt log in the description is on dcpext1, and dcpext0 only shows up there with DP alt mode.
  2. Was "coldplug" a power-on with the display already attached?
  3. Can anyone run a J474s or J475c, or is the DT diff the only check for those?
  4. Not a blocker, fine as a follow-up: one suspend/resume cycle with a display on a rear port.

As a first-time contributor your CI runs need a maintainer to start them. I've started the full build, KUnit and boot run, and I'll approve once it's green and these are answered.

@jcrowthe

Copy link
Copy Markdown
Author

Thanks for the careful review and for starting CI. All four, tested this morning on the same J475d, same build as the PR (stage 2 m1n1 is now omacom/m1n1#48 at 59530339, see below):

1. Thunderbolt through dcpext0. Yes. In my earlier runs the DP-alt display was already holding dcpext0, so the tunnel always landed on dcpext1. Today I unplugged the DP-alt display and replugged the 40WP95C (rear 1, ATC3), and it took dcpext0:

thunderbolt 0-1: new device found, vendor=0x1e device=0x1119
apple-dcp 289c00000.dcp: allocated Type-C DPTX PHY 3
apple-dcp 289c00000.dcp: display routed to Thunderbolt DP tunnel dpin0
apple-display-crossbar 130304c000.mux: Switched dpin0 to dispext0,0
apple-dcp 289c00000.dcp: set_digital_out_mode(color:71 timing:60) "5120x2160": 72 ...
apple-dcp 289c00000.dcp: set_digital_out_mode() color mode depth:10 ...

Then I plugged the UltraFine back into rear 4, and it went to dcpext1 alongside it:

apple-display-crossbar 70304c000.mux: Switched dpphy to dispext1,0
apple-dcp 315c00000.dcp: allocated Type-C DPTX PHY 0
apple-dcp 315c00000.dcp: set_digital_out_mode(color:71 timing:42) "3840x2160": 60 ...

So both die-0 DCPs have now driven both a tunnel and DP alt mode. Two Thunderbolt displays at once and dpin1 are still untested: I have one Thunderbolt display and no dual-stream dock.

2. Coldplug. No, it wasn't. In the PR it meant "attached across a reboot". I've now done a real one: full power-off, then power-on with all three displays attached. All three DCPs bind and boot, and all three displays come up:

[ 1.722217] apple-drm ...: bound 289c00000.dcp (ops dcp_comp_ops [appledrm])
[ 1.724205] apple-drm ...: bound 315c00000.dcp (ops dcp_comp_ops [appledrm])
[ 1.729950] apple-drm ...: bound 2289c00000.dcp (ops dcp_comp_ops [appledrm])
[37.434115] apple-display-crossbar 70304c000.mux: Switched dpphy to dispext0,0
[37.803268] apple-dcp 289c00000.dcp: set_digital_out_mode(color:71 timing:42) "3840x2160": 60 ...
[41.205335] apple-dcp 315c00000.dcp: display routed to Thunderbolt DP tunnel dpin0
[42.587020] apple-display-crossbar 130304c000.mux: Switched dpin0 to dispext1,0
[42.922140] apple-dcp 315c00000.dcp: set_digital_out_mode(color:71 timing:60) "5120x2160": 72 ...

The USB-C displays only light up after the LUKS prompt: the rear tps6598x controllers sit in deferred probe pending until switch-root (35 s here). I think that's my initramfs not carrying the Type-C stack, not this PR, but I haven't confirmed it. HDMI shows the prompt as before, after the known first-connect timeout (#428). I've corrected the test table.

3. J474s / J475c. I don't have either, so the DT diff is the only check from my side. @ytgconsulting has a J475c (#379, omacom/m1n1#48). If you have a minute, a DP-alt display on a rear port with #462 would be the useful check. With #463 on top, a Thunderbolt display there exercises the ATC3 core_valid change, since the J475c has the same fourth rear port.

4. Suspend/resume. One s2idle cycle, 44 s asleep, with the Thunderbolt display (dcpext0), the UltraFine (dcpext1) and the Dell on HDMI all active. On suspend the tunnel and all three DCPs go down cleanly (dpin0: crossbar link down, dcp_poweroff() done, DP IN tunnel routing: tunnel down). On resume the tunnel is re-established and all three displays are back at their modes within about 18 s. On the way back the tunnel and DP alt mode swapped DCPs (Thunderbolt ended up on dcpext1, DP alt on dcpext0), which looks like the follow-CRTC path doing its job. Two things logged on resume that didn't stop anything:

[drm:drm_mode_config_helper_resume] *ERROR* Failed to resume (-22)
apple-dcp 315c00000.dcp: copy_edid failed: -EIO   (x2)

This was this machine's first suspend ever, so I can't say whether the -22 predates these changes. I'm happy to bisect it in a follow-up if it's interesting.

Noted on #460. I haven't hit an HPD release timeout on the tunnel side here; the only -110s are the HDMI DCP's known boot-time ones.

@scottjones scottjones left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for answering all four, and for the extra testing. Approving. Like #462, I'd like the J475c check before merging, with a Thunderbolt display on the fourth rear port if possible, since that exercises the ATC3 change.

@jcrowthe

Copy link
Copy Markdown
Author

Follow-up stacked on this one: #467 enables die-0 dcpext2/3 on the J475d, so four rear USB-C displays plus HDMI run at once (tested with five). It includes this branch unchanged as its base, so it only adds one DT commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:build Build, test and boot the kernel for this PR now

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants