Skip to content

drm: apple: answer the DPTX port's group 1 calls as macOS does - #1

Closed
nekolyanich wants to merge 1 commit into
aurora-wipfrom
pr/dptx-call-groups
Closed

nekolyanich wants to merge 1 commit into
aurora-wipfrom
pr/dptx-call-groups

Conversation

@nekolyanich

Copy link
Copy Markdown
Owner

On an M2 Pro (j416s) with the DCP 13.5 firmware, DCP's DPTX port (AppleDCPDPTXRemotePort) sends the AP
calls of group 1, commands 3 and 4, around link (re)configuration, audio prepare included. The group sits in
the call header (the group of struct epic_service_call, one word into the notify payload), and the AFK
v1 notify path didn't read it, so these calls reached the group 0 handlers with the same numbers,
SET_DRIVE_SETTINGS and GET_DRIVE_SETTINGS. Our log had set_drive_settings: 2:0:1089336960:-1:0:0:0:
0xffffffff40edf680 with the high word, a DCP address from the call's payload. With a TV on a USB-C to HDMI
adapter, DCP then refused the first audio start ("Restarting interfaces with reason - Capabilities changed"),
replugged the display, and sometimes never confirmed the stream (report 0xe0115001 stays 1). macOS 13 with the
same TV on the same adapter, traced in 3 cold boots, had 0 refusals in 5 audio prepares.

The reply. I traced macOS 13 on the m1n1 hypervisor in three sessions: the TV on that adapter, the TV in
an earlier session whose adapter wasn't recorded (macOS got 1 refusal there), and a Dell over Thunderbolt.
All 42 group 1 calls get a NotifyAck with the 68-byte header unchanged and the data
echoed, with some fields cleared:

call data len n lane count macOS clears J700 (85d81b7)
(1, 3) 0x30 TV, 0x40 Dell 11 +0x10 +0x00..0x03 drive settings: count at +0x10, levels from +0x20
(1, 4) 0x30 TV, 0x40 Dell 31 +0x00 +0x10..0x13, +0x20 to the end refused; its group 0 GET (0, 4) has the count at +0x00

The lane count is 2 on the TV path and 4 on the Dell, and macOS keeps it in all 42. In (1, 4) it clears
what DCP left past +0x20 (non-zero in all 31, DCP addresses included). A plain echo matches 9 of the 42; this
rule matches 42 of 42. Clearing 4 bytes at +0x10 rather than 8 rests on 1 call (the only one with a
non-zero high word there). The first word of the ack isn't in the traces (the tracer dumps from +4); it's
copied from the notify, as before.

The commit.

  • afk.c: the notify header is now { __le32 unk0; struct epic_service_call call; } (68 bytes, asserted)
    instead of a private copy. If a service has call_v2, every call goes there with its group; else .call
    gets group 0 only. A group call to a service without call_v2 gets a rate-limited warning and no reply,
    as a call to a service without a handler does now.
  • dptxep.c: .call_v2 = dptxport_group_call. Group 0 goes to dptxport_call() unchanged, (1, 3) and
    (1, 4) get the macOS reply above, and any other (group, command) is echoed with a rate-limited warning: no
    reply might stall DCP's caller.
  • trace.h: dptxport_apcall records the group (AP Call 1:4 (-); group 0 keeps the command name).

Relation to the J700 work. call_v2 and its signature come from 85d81b7 ("phy: apple: implement
bounded J700 DisplayPort main-link training") on test/t8140-external-output-qualification, which isn't in
aurora-wip. I didn't base this on that branch. Merging the two:

  • afk.h: both add the same call_v2 line.
  • afk.c: this changes the v1 notify path, 85d81b7 the v2 callback; they don't overlap.
  • dptxep.c: both set .call_v2 = dptxport_group_call, with different bodies. Theirs sends (1, 3) to
    dptx_j700_training() and refuses (1, 4) with -EOPNOTSUPP on AFK v2; this one acks both as macOS 13 does
    on AFK v1, where USB4 DP-in has no ATC PHY for the training. One body that branches on service->ep->wire_v2 keeps both.

Testing: MacBook Pro 16" M2 Pro (j416s), DCP firmware 13.5. A TV on a USB-C to HDMI adapter
(dcpext0), Dell U2725QE over Thunderbolt (dcpext1). An initramfs starts 2 s of silence on the TV's card
about every 7 s from 40 s, 8 audio starts on the TV per boot; nobody replugs anything. Under the m1n1 hypervisor, cold boots,
with and without the commit interleaved, on aurora-wip 30812f49 + aurora-silicon#275 + aurora-silicon#276 + aurora-silicon#277 + the AFK slots series

without (3 boots) with (5 boots)
first audio prepare refused 3 of 3 accepted 5 of 5
AV service generations per boot 3 1
"Capabilities changed" refusals per boot 2 0
aurora-silicon#275 relinks per boot 2 0
set_drive_settings lines per boot (the group 1 calls reaching group 0) 16 0
starts played in full 4 of 8 8 of 8
Dell: refusals 0 0
unknown/unhandled group call warnings – 0

The control is 3 boots. Earlier, on our downstream tree (Asahi fairydust with the USB4 series backported),
the same setup without the fix refused the first prepare in 5 of 5 cold boots, with 3 to 9 refusals each.
With this change on that tree: 3 of 3 boots clean under the hypervisor, 8 of 8 played, no set_drive_settings
line.

Natively on our tree, with TV adapter hot replugs: the boot connect and 3 of 8 replugs reached DCP (the other 5
failed earlier, in the Type-C PHY: "Failed to lock pipehandler", a separate problem). All 4 connects had no
refusal, link up and stream confirmed. Before the fix, the same setup had 10 refusals in 5 connects (boot and 4
replugs; 2 of the 5 connects were refused 5 times each).

Not tested: other Macs and SoCs, the 12.3 and 14.x firmware, AFK v2, and the paths for other groups and
for a service without call_v2 (no such call was seen in the traces or on Linux).

🤖 Generated with Claude Code

On t6020 with the 13.5 firmware, DCP's DPTX port sends AP calls of group
1, commands 3 and 4, around link (re)configuration, audio prepare
included. The AFK v1 notify path dropped the group, so they reached the
group 0 handlers of the same numbers, SET/GET_DRIVE_SETTINGS: DCP
addresses from the payload were stored as drive settings. Behind a USB-C
to HDMI adapter DCP then refused the audio start ("Capabilities
changed") or never confirmed the stream.

Pass the group through a call_v2 op, with the signature of call_v2 on
aurora's J700 test branch (85d81b7, not in aurora-wip), and keep .call
for group 0 only. A group call to a service without call_v2 gets a
warning and no reply: AFK has no handler and does not guess one.

The DPTX port answers group 1 commands 3 and 4 the way macOS 13 does in
42 of 42 traced pairs (TV through the adapter, Dell over Thunderbolt):
an echo of the request with +0x00..0x03 cleared for (1, 3), and
+0x10..0x13 and +0x20 to the end cleared for (1, 4). The lane count sits
at +0x10 in (1, 3) and at +0x00 in (1, 4); macOS keeps it in all 42 and
clears the other slot. The J700 code reads (1, 3) the same way, with
per-lane levels from +0x20, which macOS does not clear there; it refuses
(1, 4), and its group 0 GET (0, 4) has the count at +0x00. Other groups
are echoed with a rate-limited warning.

Testing: MacBook Pro 16" M2 Pro (j416s), DCP firmware 13.5, a TV on a
USB-C to HDMI adapter and a Dell over Thunderbolt, 8 audio starts on
the TV per boot. Cold boots under the m1n1 hypervisor, aurora-wip with
PRs aurora-silicon#275-aurora-silicon#277, the AFK slots series and a bench DT change,
interleaved: with this commit the first start was accepted in 5 of 5
boots, with 0 refusals and 8 of 8 starts played; without it, 3 of 3
boots refused the first start, 2 refusals each, 4 of 8 played. The
Dell had no refusals in any boot, and no group warning was logged.
Natively, on a downstream tree with the same reply rule, the boot
connect and 3 of 8 TV replugs reached DCP (the rest failed earlier, in
the PHY): 0 refusals in 4 connects; before, 10 refusals in 5 connects.
Not tested: other SoCs, other firmware, AFK v2.

Assisted-by: Claude:claude-opus-5-5 checkpatch
Signed-off-by: nekolyanich <me@nekolyanich.com>
@nekolyanich

Copy link
Copy Markdown
Owner Author

Published as aurora-silicon#282

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