Skip to content

usb: typec: tipd: put an empty CD321x port to sleep, as macOS - #5

Closed
nekolyanich wants to merge 1 commit into
base/integration-aurora-420a1c8f5492from
pr/cd321x-unplug-sleep-73
Closed

nekolyanich wants to merge 1 commit into
base/integration-aurora-420a1c8f5492from
pr/cd321x-unplug-sleep-73

Conversation

@nekolyanich

@nekolyanich nekolyanich commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Replaces aurora-silicon#296, which was opened on aurora-wip (since retired). Same change on integration/aurora, with the wake moved earlier, S0 restored when the driver is removed, and aurora's controller setup recovery taken into account.

On an M2 Pro (j416s), replugs of a USB-C to HDMI adapter in DP alt mode often never reach the display. On integration/aurora under the m1n1 hypervisor, 10 of 24 guided replugs were lost (6, 4 and 4 of 8 reached the display in three sessions), every other plug from some cycle on. Natively on our tree before this change, 26 of 56. A lost plug gets the Type-C partner, but nothing enumerates behind the adapter, the port gets no DP route and DCP no HPD.

Cause. After the unplug of a session with DP, the CD321x stays half-connected: a trace of its status showed the cable power path still "in" and the session's data status kept, and the next plug got no VBUS and never reached PD (2 of 2). Unplugging that plug clears the state, hence the alternation. macOS, traced on the same port with the same TV and adapter, puts the port into system power state 2 on every disconnect (0x2000 to the undocumented register 0x50, SSPS 2, 0x2000 and 0 to 0x50; 8 of 8) and sends SSPS 0 as soon as STATUS shows the next plug. At boot it also puts the empty MagSafe controller to sleep.

The change (CD321x only, port_sleep in tipd_cd321x_data; the driver tracks the port as unknown, awake or asleep):

  • the cable work finds no plug on a port not known to be asleep (a disconnect, a retried one, an empty port at probe): the macOS sequence, after reading STATUS again; a plug present skips it;
  • it sees a plug on a port not known to be awake: SSPS 0, before any teardown or partner registration;
  • removing the driver: SSPS 0;
  • a failure only warns and leaves the state unknown, as do resume and the controller setup recovery (which restores S0), so the next pass tries again.

Testing: MacBook Pro 16" M2 Pro (j416s), DCP firmware 13.5, a TV on the adapter, a Dell over Thunderbolt on another port, under the m1n1 hypervisor (with a bench-only DT change):

  • integration/aurora without this change: 10 of 24 TV replugs lost, in three sessions;
  • this commit: 8 of 8. An I2C trace of the controller shows the sleep sequence (state read back 2) at each of the 8 unplugs and SSPS 0 (state read back 0) at each of the 8 plugs;
  • this commit, another session: unbinding the driver on the emptied port sends SSPS 0, binding it again puts the port to sleep at probe, then a plug and a replug about 1.4 s after an unplug both bring the TV back;
  • no failed sleep or wake and no kernel warning in either session;
  • earlier, as usb: typec: tipd: put an empty CD321x port to sleep, as macOS aurora-silicon/linux#296: on aurora-wip 4 of 16 replugs lost without it, 0 of 24 with it, 22 of 22 clean cold boots; natively on our tree 16 of 16 replugs, 3 of 3 fast replugs, MagSafe and Dell replugs back, a USB-C charger negotiated a contract.

Not tested:

  • other Macs, SoCs, firmware, adapters and sinks; USB-only devices and docks;
  • natively on integration/aurora; on it also MagSafe after its probe-time sleep, Dell replugs, resume, more than three cold boots, a replug within the 500 ms debounce;
  • the controller setup recovery over a sleeping port (it needs a controller reset);
  • shutdown and reboot: tipd has no shutdown path, so empty controllers may stay in state 2 while the Mac is off or boots another OS.

On an M2 Pro (j416s), replugs of a USB-C to HDMI adapter in DP alt mode
often never reach the display: 10 of 24 on integration/aurora under the
m1n1 hypervisor, 26 of 56 natively. After the unplug of a session with
DP, the controller keeps the cable power path "in" and the session's
data status; the next plug gets no VBUS and never reaches PD (2 of 2 in
a trace). Unplugging that plug clears the state, so plugs alternate.

macOS, traced on the same port, puts the port into system power state 2
on every disconnect: 0x2000 to the undocumented register 0x50, SSPS 2,
0x2000 and 0 to 0x50 (8 of 8). It sends SSPS 0 as soon as STATUS shows
the next plug, and puts the empty MagSafe controller to sleep at boot.

Do the same from the cable work, on the CD321x only (port_sleep): when
it finds no plug on a port not known to be asleep, the sequence above,
after reading STATUS again (a plug skips it); when it sees a plug on a
port not known to be awake, SSPS 0 before anything else. Removing the
driver also restores S0. A failure only warns and leaves the state
unknown, as do resume and the controller setup recovery, so the next
pass tries again.

Testing: MacBook Pro 16" M2 Pro (j416s), DCP firmware 13.5, a TV on the
adapter and a Dell over Thunderbolt, under the m1n1 hypervisor. On
integration/aurora, 8 of 8 TV replugs reached the display; an I2C trace
showed the sleep (state 2 read back) at each unplug and SSPS 0 (state 0)
at each plug. Unbinding on the empty port restored S0, rebinding slept
it, a plug and a replug about 1.4 s after an unplug came back. No
failed sleep or wake, no kernel warning. Earlier: 0 of 24 lost against
4 of 16 on aurora-wip, and 16 of 16 natively on a downstream tree.

Assisted-by: Claude:claude-opus-5-5 checkpatch
Signed-off-by: nekolyanich <me@nekolyanich.com>
@nekolyanich
nekolyanich force-pushed the pr/cd321x-unplug-sleep-73 branch from 2e84450 to e1d066f Compare October 24, 2026 14:41
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