Repository navigation
J616s (M4 Pro): external displays (Type-C through the display fabric, HDMI and USB-C DisplayPort behind the T6041 display gate) and the third loaded GPU image - #451
Conversation
The dcpext of a T6041 listed the DP PHY and crossbar of every Type-C port and picked the port whose PHY had entered DP alt mode at connect time. The display fabric already routes the T602x, T6030 and J700 Type-C ports: a typec-routes node under the DCP, one mode switch per port, driven by the port controller. Use it for desktop 26.x as well and drop the private route (apple,dptx-phys, dp-phyN/dp-xbarN, apple_t6040_phy_dp_alt()). Three things differ from the other fabric users: - The T6040 DP PHY must be powered when the display connects, not when a route is claimed. The port controller calls the PHY's and the route's mode switch in connector order, and the PHY has to have seen DP alt mode and the plug orientation before its lanes are programmed. - The compact DPTX of desktop 26.x takes the crossbar link down and up around a link configuration through dcp->xbar, while the fabric's own direct-link helper is T6030 only. The route sets dcp->xbar for the time it is active; without it the link never trains. - There is a single Type-C pipeline. A port in DP alt mode without a sink (a dock, or a pin assignment the PHY cannot drive) must not hold it against the port that has a display: claim it on HPD only. Tested on a J616s (Mac16,7) with a USB-C display on one port: attach at boot, rebind of the port controller (replug) and a device suspend test (pm_test=devices). The other ports and a second display are not tested. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
…lers The H17P callbacks are checked against the record sizes the firmware sends; the desktop 26.6 ones were not. The u16 offset keeps a record inside the shared memory, but a handler could still read past a short request or write past a short reply into the next record. Give every desktop 26.6 handler the request and reply size it reads and writes, and refuse a callback whose record is shorter, or whose lengths do not fit the message, the way H17P refuses a malformed one. Longer records stay accepted. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
t6040_dp_power_on() shuts the USB3 side down, but t6040_dp_power_off() only cleared dp_up, and t6040_usb3_power_on() could re-initialise the PHY under a live DP mode. Once a Type-C DP session ended with the plug still in, USB3 on that port stayed down until dwc3 power cycled the PHY. Track whether dwc3 holds the USB3 phy on and asked for the PIPE switch. USB3 bring-up now waits while DP mode is programmed, and when DP mode ends and the port has left DP alt mode, from the DP power-off or the mode switch, whichever comes last, USB3 is brought up again and the PIPE goes back to the PHY. On an unplug or a DP mode change tipd drops the USB role first, dwc3 powers the USB3 phy off, and nothing changes there. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
RyanTheTide
left a comment
There was a problem hiding this comment.
Nice cleanup, and moving onto the fabric is the right call. I read all three commits against integration/aurora 3b77f0f. Nothing changes for the other fabric users: every new branch in dcp-fabric.c is gated on the desktop firmware or on phy_powered, and other SoCs keep their routes[0].phy and fixed xbar. No hard module dependency comes back either. The crossbar still goes through dcp_dpxbar_link(), and apple_t6040_phy_dp_alt() is gone along with its stub. The callback size table matches cb_handlers[] tag for tag, and the bound can't overflow. Thanks for closing item 5 as well.
A few things I'd like to see fixed before it goes in, all on the T6041 path:
-
PHY power on connect isn't ordered against route release. dcp_typec_phy_on() checks active_typec_route under hpd_mutex only, because the desktop connect skips the fabric session the other SoCs take. Meanwhile dcp_typec_route_phy_off() runs under tb_lock inside the fabric lock. An OOB hotplug connect racing a route deactivate can power the PHY after the crossbar is deselected and leave phy_powered set, and then the USB3 give-back in commit 3 never runs. #446 kept this ordered through hpd_mutex ("which also orders dcp->phy against a connect"). Taking the fabric lock around the phy_on, or another lock deactivate also holds, would restore that.
-
The start-up gate in dcp_start() changed from !dcp->phy && !d->ndyn to !dcp->phy. At probe, route registration points dcp->phy at routes[0], so the first start is fine. But after an unplug the desktop deactivate sets dcp->phy to NULL, so a later dcp_start() (master rebind) would skip iBoot, DPTX, EXPERT and EPIC25, and Type-C would stay down until reboot. Separately, the startup dcp_dptx_connect(dcp, 0) now runs with dcp->phy on route 0, an unpowered PHY with no crossbar selected, which goes against the new "an idle pipeline must not point at one" comment. Gating on dcp->phy || dcp->nr_typec_routes, and skipping the startup connect while no route is active, would cover both.
-
Claiming on HPD only covers the claim but not the release. When HPD drops while the port stays in DP alt mode, the fabric calls dcp_dptx_disconnect_oob() but keeps port->owner, and dcp_desktop_dptx_disconnect_oob() no longer releases the route or the PHY. A dock whose monitor gets unplugged keeps the only pipeline, its crossbar and a powered DP PHY, and a display on another port then gets dcp_typec_port_busy. So a sinkless DP alt port does still hold the pipeline, once it has had a display.
-
The USB3 give-back switches PIPE back while xHCI is already running, where set_mode() says the switch belongs after core init and before xHCI starts. There's no USB3-after-DP row in the test table. A USB3 device on that port after a DP session (speed and enumeration) would settle it.
Smaller ones. dcp->xbar is overwritten on route activate and only cleared again on the USB-only branch, and it's cleared outside tb_lock while dptxport_compact_xbar_link() reads it unlocked. That's harmless with routes only on dcpext1, but worth tidying. In the new record check, hdr->tag is read before length < sizeof(*hdr) is checked, and unlike H17P it doesn't check offset + length against the shared buffer.
I'm running the universal WERROR build, KUnit and the apple-dcp host selftests on this branch now and will add the results here. USB-C display behaviour can only be checked on hardware with a monitor plugged in, which is a morning job on our J616s.
The comment in dcp_is_typec_output() still described the private route the previous commit removed. Desktop 26.x now takes its Type-C route from the fabric and only drives the link through its own compact DPTX connect. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
|
Gate results on integration/aurora 3b77f0f with this branch and #394:
|
After a Type-C route is released, #451 parks dcp->phy at NULL. A later firmware start must still discover the DPTX services for the registered routes; testing only the current PHY skips them and leaves later hotplug without a service. Keep endpoint discovery enabled for a Type-C pipeline, with link admission still requiring an active route. Exercise the real startup function with no route, parked Type-C routes, and a fixed HDMI PHY in a hardware-free host fixture. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
|
Thanks for this series. I'd like to test it on a second J616s with a USB-C monitor (DP alt mode, pin assignment C), and to follow up with the PHY unplug sequence from a macOS capture ( Two pieces are only on your machine so far, as far as I can see:
Could you publish them, or point me at a branch? If you'd rather not, I'll write the device tree from the ADT and open it as a PR, but yours is the tested one. What I can add from macOS 26.6.2 (25G83) on the J616s, in case it helps the review:
|
…peline with the sink Review of the Type-C fabric series found four holes on the T6041 path. dcp_typec_phy_on() looked at the active route under hpd_mutex only, while the deactivate powers the PHY off and releases the crossbar under tb_lock. A connect racing a release could power the PHY after the crossbar was deselected and leave phy_powered set. Take tb_lock around the check and the power-on, and refuse a route whose crossbar is already released. The start-up gate in dcp_start_desktop() is again satisfied by a Type-C route, so a restart after an unplug (dcp->phy is NULL then) still brings the DPTX services up, and the start-up link is only connected when a fixed PHY or an active route exists: an idle pipeline has no powered PHY and no crossbar selection to connect on. When HPD drops while the port stays in DP alt mode, the route, its crossbar and the PHY were kept. Release them with the sink, as a mode change does, so a display on another port is not refused as busy; the route is claimed again when HPD returns. Check that a desktop callback record lies inside the shared buffer before its header is read, and access dcp->xbar with READ_ONCE()/WRITE_ONCE() as it is read by the DPTX worker without a lock. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The fabric extraction now reaches dcp_typec_route_phy_off() and the DCP_FIRMWARE_V_26_6_DESKTOP tests, and the dispatcher extraction the desktop callback check. Add the define and, as for the other desktop paths, a stub that asserts if a non-desktop scenario reaches the check; the PHY power-off is a no-op there as the real one returns for an unpowered PHY. Seven of the eight units that stopped compiling build and pass again; mux-release-stages needs -Wno-unused-but-set-global with clang 23. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
|
Thanks for testing it. Answers in order. 1. Device tree. It is on a branch of my fork: https://github.com/fbalazsy/linux/tree/j616s/dt-t6041-extdisp (one commit on top of
This tree builds 2. Boot loader side. Today nothing on my side writes anything for 3. On the second J616s with a USB-C monitor and the unplug sequence: happy to run any test you want on this one. |
|
Thanks, that's a lot of hard-won detail. The DISPEXTn_CPU and FAB7_SOC notes alone would have cost me a few resets. I checked your tree against this unit's ADT (macOS 25G83 too). The dcpext0/1, mailbox, DART, crossbar, PMGR and ATC3 values match. The The missing piece for a second machine is the enabling step. Could you push the gate module, even as a WIP branch? I'd like to run your order exactly (PMP acknowledgement first, then the HDMI chain, then dcpext1 with its routes and the tipd rebind) rather than reinvent it. Longer term, your loader proposal (segment ranges, Test offer accepted, thanks. I'll post my results here: all three ports, both orientations, USB3 after a DP session (Ryan's item 4), and later the unplug sequence with and without |
|
The gate is on The order, which Built in, it stays off unless |
|
Pushed two commits on top for the review (361d633).
Tested on the J616s (kernel with these two commits, plus a gate module and the DT on a local base): clean boot with eDP, HDMI and DP at 1920x2160@120, a rebind of the port controller (the route is released and claimed again, the display comes back), and a Selftests: the eight units that stopped compiling build again and pass, except |
…tput session A desktop 26.x Type-C display took its route from the fabric but was connected by dcp_desktop_dptx_connect(), outside the session the other SoCs use: no attach and detach bookkeeping (cable flag, generation, firmware metadata, unplug count), no relink, no reconnect retry and none of the IRQ_HPD handling the fabric already dispatches to it. dcp_is_typec_output() is no longer false for the desktop firmware, and dcp_dptx_connect(), dcp_dptx_connect_oob() and dcp_dptx_disconnect_oob() take the common path for it. What compact DPTX does differently stays where it differs: - the connection validation call does not exist, so it is skipped; - the PHY is powered when the display connects, before the DPTX connect; - a link configuration that has not arrived when the wait ends is not an error, it comes once a sink arrives; - a disconnect marks the external pipe as shut down by the firmware. The fixed HDMI output (dcpext0) has no Type-C session and keeps dcp_desktop_dptx_connect(). Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
dcp_dptx_connect_raw() now asks the DPTX endpoint whether it is compact and has the route power the PHY. This scenario's endpoint is the classic one and its PHY needs no route: report not compact and stub the PHY power-on. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
|
Pushed two more commits (6dc79aa): the desktop 26.x Type-C display now connects through the common Type-C output session instead of
Tested on the J616s on top of integration/aurora 85c1ce7 (with #452) plus this branch and my local DT and gate: clean boot with eDP, HDMI and DP at 1920x2160@120; a rebind of the port controller (route released, claimed again, display back, no Still not tested, as it needs the cable moved by hand: HPD dropping while the port stays in DP alt mode, and a USB3 device on the port after a DP session (item 4). On the port of this monitor the USB devices behind the monitor's hub stay at USB2 during DP; a USB3 dock on another port enumerates at 5000M after that port's PIPE switch ( |
|
Hardware results for the open items, on 7.3.0-m4.106 (= integration/aurora ff1510c + this PR's head 6dc79aa + #454) on the J616s, DCP firmware 26.6.2, with the m4-loader (rev 19 + dcpext firmware memory from the ADT):
Also checked: the monitor on a second USB-C port (DP-2) and on the first (DP-1), HDMI (dcpext0, 1920x2160) at the same time as the Type-C output, lid close/open with the externals up, and the Samsung G95NC with PBP off (single 16:9 image over USB-C). The internal panel keeps its 120 Hz mode throughout. |
|
@jgoyvaerts the loader half is up: jgoyvaerts/m4-loader#5 fills the dcpext0/1 firmware memory from the ADT into disabled placeholders of |
|
Correction and the real result for item 4. My earlier note on item 4 described a USB3 device enumerating while a DP tunnel was up on another port; that is not the give-back you asked about. Tested it properly now, same branch head (6dc79aa) on 7.3.0-m4.108:
So the PIPE give-back after DP works on the J616s: the switch happens with xHCI torn down and re-created around it, not under a running controller. Afterwards the monitor on a different port (atc1, PHY 1) came up again. |
apple,irq-safe on a PMP report entry marks an entry that parents the IRQ-safe PMGR power states of a coprocessor: genpd requires the parent of an IRQ-safe subdomain to be IRQ safe as well. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
A PMP device-state entry that parents PMGR power states (which are IRQ safe) must be IRQ safe too, or genpd refuses the subdomain. Setting the state takes a spinlock and polls the acknowledgment atomically, so the entry may run with interrupts disabled. Opt in with apple,irq-safe. Tested on a MacBook Pro M4 Pro (J616s): the DISPEXT0 and DISPEXT1 device-state entries parent the dispext0/1 PMGR chains that power the HDMI and USB-C DisplayPort controllers. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The M4 Pro (T6041) external display processors use the generic dcpext fallback like the other dcpext variants; the driver already matches apple,t6041-dcpext. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
Describe the J616s external display chain, all disabled: dcpext0 behind the HDMI port (atc3 display crossbar, atcphy3, the DP-to-HDMI converter), dcpext1 behind the three Type-C ports (display fabric routes, atc0..2 crossbars), their DISPEXT power domains with the PMP acknowledgement entries, the display DARTs and mailboxes, and the dcpext firmware memory as disabled placeholders that the boot loader fills from the ADT. Nothing is enabled by the device tree: powering the DISPEXT chain without the PMP acknowledgement hangs the machine before root, and a boot loader that does not provide the firmware memory leaves the placeholders disabled. A gate enables the chain (next commit). Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
Extend the T6041 display gate to the external displays. When both external display processors have their firmware memory (the memory-region nodes of the dcpext are available: the boot loader filled the placeholders), enable the chain after the PMP firmware is bound: the Type-C routes before any device exists (so the port controllers wait for dcpext1's mode switches) with the display subsystem held back, then the HDMI chain, the Type-C chain, and last both processors and the display subsystem together, so the display master is created once with every DART in its iommus. The port controllers are probed again once dcpext1 is bound, as the Type-C core treats a mode switch below a disabled node as absent at their first probe. If the PMP does not come within 20 s, or a step fails, the routes are withdrawn and only the internal panel stays. The processors are enabled only once the infrastructure devices have their drivers (the crossbar and PHY are modules), as a processor that finds one missing is given up for good. Without the firmware memory, with nomodeset, or on another machine, nothing changes. Tested on a J616s with m4-loader rev19-j616s-1 (which fills the memory from the ADT): HDMI and USB-C DisplayPort from boot, eDP unchanged. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
…utes on dcpext0 The desktop 26.6 firmware names the display pipes by their display index (endpoint 0 the internal panel, 1 dcpext0, 2 dcpext1) when two of them drive one display: apple,dcp-endpoint records it, separate from apple,dcp-index, which the driver also uses for the doorbell and the PHY mode. The two external pipes merge upwards only, so a display wider than one pipe (the Samsung Odyssey G95NC, 7680x2160) needs dcpext0 as the primary. dcpext0 therefore also gets a route to every Type-C port next to its fixed HDMI path (a hybrid pipeline, as the T6030 J514s): crossbar state 0 on atcphy0..2 (the ADT's dp-switch-dfp-endpoint 0 = dispext0, as its HDMI route on atcphy3), the connectors' port@3 with an endpoint per pipe. The routes are disabled with the rest of the chain; the display gate enables them in the HDMI stage.
The g5 line already validates exact record lengths for its desktop 26.6 callbacks. #451 adds a minimum-length table for the full handler set, so a straight replay defines the checker twice and fails the WERROR build. Keep the g5 exact checks as a helper, fill the four g5 handlers absent from the new table, then require both checks. The table now covers every registered desktop handler. Point the synthetic desktop fixtures at the exact helper; production dispatch uses the combined checker. The original #451 commits remain attributed to František Balázsy. This is a g5 integration fixup. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
…pipes
One DISPEXT pipe of the desktop 26.6 firmware drives modes up to 6720 px
wide ("IOMFB removing mode: 7680 x 2160, max width: 6720"); a 7680x2160
sink lost its native mode. The firmware supports a two-pipe display: the
primary pipe and a peer merge their frame timing generators and each
encodes half of the line, as the T6050 firmware-27 peer (aurora-silicon#485) does.
The primary answers the display allocation in SET_TILED_DISPLAY_HINTS
with its own and the peer's endpoint IDs when the sink is wider than one
pipe and an idle pipe above it exists (apple,dcp-endpoint; the pipes
merge upwards only: dcpext0 is the primary, dcpext1 its peer; its sinkless
HDMI link does not make dcpext0 busy, that link is released before the
pair comes up). With the pair reserved the hotplug record is echoed as
on firmware 27, so both pipes know each other's display ID.
A DRM mode set wider than one pipe then runs the merge on both pipes:
the primary's video data (A364) is split into a half-width derived mode
inserted on both (A365, A366), both pipes are powered as a pair (A473),
their master swap IDs aligned (A360/A361), and the paired mode set
(A413) run with the tiling rendezvous the firmware drives through D115
(read) and D116 (write): membership, phase, display IDs, offsets; the
DSC capabilities, bits per pixel and slice hints are copied from the
primary to the peer in between (A367..A373). The same mode set again
keeps the pair (DRM repeats it right after the connector came up, and
the merged pipe no longer resolves the original timing).
Each frame is the primary's swap: its left tile stays in the swap, the
right tile goes to the peer as its own swap_start/swap_submit chain with
the primary's swap ID (the firmware does not use the IOMFB transaction
queue on this firmware); the peer's completion is not a DRM event. A
merged pair is stopped as a pair before the primary's power-off or sleep:
the single-pipe power-off of a merged primary timed out and the peer's
firmware looped.
Adaptive sync follows the CRTC on the pair: IOMFBParameter 14 goes to
both pipes with the same minimum rate before the paired mode set. A pipe
keeps the parameter across a replug, so a peer that last ran a VRR mode
alone merged with VRR on while the primary ran without it, and its
firmware crashed. A changed rate (VRR switched on or off) stops the pair
and installs it again, as the mode set applies it on one pipe.
The hybrid pipeline (a fixed output plus Type-C routes, dcpext0 on the J616s) scores last for a Type-C port, kept for the fixed display. On the J616s it is also the only pipe that can be the primary of a two-pipe display, so a 7680 px sink on USB-C can only be driven through it. appledrm.typec_hybrid_first drops that penalty: a Type-C port is planned onto the hybrid pipeline first and dcpext1 stays free as its peer. The HDMI display then has no pipe while the Type-C display is up; the default keeps today's order.
A pair's peer stayed marked as its owner's peer after the owner's display was gone: after system sleep, or a cable change, the port could move to the peer pipe, and the peer then ran its own display with the owner recorded. dcp_peer_swap_complete_26_6() takes the swaps of a reserved peer for the pair's and discarded the display's own swaps: the picture stuttered and the CRTC retrained in a loop. The reservation is released when the primary disconnects its DPTX link (a merged pair is stopped first by the power-off, and a pair that still runs is kept); the next allocation reserves a peer again. A peer's swap is only taken for the pair's while the peer has no route of its own. A pipe that was unbound is no longer refused as a peer after it binds again.
…he DT, no debounce without a sink apple,typec-hybrid-first on dcpext0 (the J616s: the only pipe that can be the primary of a display wider than one pipe) makes the fabric plan a Type-C port onto the hybrid pipeline first, as appledrm.typec_hybrid_first does, so a 7680 px sink on USB-C is paired at boot without a module parameter. The pipeline is only available while its fixed output has no sink, so an HDMI display plugged in first keeps it. The HDMI presence debounce (ten seconds) delayed a sample that finds no sink where there was none before, at start-up and after system sleep. The pipeline still counted as taken when the port was planned at start-up, or re-planned after the sink dropped its link in sleep, and the port went to the other pipe (a flattened 3840x2160, and after sleep no pair). Such a sample now stays absent; a sample after a real unplug is debounced as before.
…lug finds no mode A Type-C display that wakes from system sleep may list only its base modes at first: its EDID is not ready yet. The retrain after that hotplug then finds no mode for the active CRTC (the sink's 7680x2160 is not listed), and nothing reads the EDID again until the next HPD event, which can be a minute away; the compositor stays at a fallback mode (a 3840x2160 picture stretched over a 7680x2160 monitor). Disconnect and connect the link again, as a replug does, two seconds after such a retrain failed, unless a mode set completed in between; at most four times per resume. The work goes with the other Type-C works: disabled at probe, while unbound and across system sleep, so that nothing arms it behind a cancel.
The pair was installed first with adaptive sync off, because the CRTC still had VRR disabled, and the compositor then switched VRR on: that stopped the pair and installed it again. When the sink drops its link in between (a monitor waking up or switching its input layout), the second install fails (set_digital_out_mode 0x6) and the display stays dark until the next replug. Install the pair with the mode's minimum refresh rate from the start, whatever the CRTC asks. A VRR toggle then finds the pair with the same timing, colour and rate and keeps it. Swaps on a VRR mode carry their timestamps either way, so the compositor still paces the frames.
…m its Type-C route's On desktop 26.x a Type-C route sets dcp->xbar to its own crossbar control, for the compact DPTX link configuration. dcp->xbar was also the fixed HDMI output's control, so on the hybrid dcpext0 every later use for HDMI went to the Type-C port's control instead: when the route was let go with an HDMI display present, handing the pipeline back to HDMI selected the Type-C port's control with the HDMI index. The next route of that port, on dcpext1, then waited in mux_control_select() for good, holding the fabric lock, with the port controller's update work and interrupt thread stuck behind it (seen with a G95NC on USB-C and HDMI, switching its picture-by-picture layout). Keep the fixed output's control in dcp->fixed_xbar and select, release and check the fixed route with it only; dcp->xbar stays the control a link configuration takes up and down, and points at the fixed one again when the pipeline is handed back to HDMI. A Type-C route's control is taken with mux_control_try_select(): only a route of the same port can hold it, and that one lets it go under the fabric lock held here, so a wait could never end.
…ps HPD When the sink of a desktop 26.x Type-C route drops HPD, the route gives its pipeline back and the freed pipeline goes to a port left waiting. The port's own DP state still said HPD at that point, so it was taken as waiting itself and routed again at once, onto the same pipeline or, with an HDMI display on the hybrid, onto the other one, and its connection was replayed against a sink without HPD. Clear the port's HPD before the pipeline is freed (the pairing pass still sees what it counted before), connect a live HDMI display the hybrid has gone back to, as the DP-exit path does, and leave a parked hybrid without a link crossbar: the released route's control may now belong to the other pipeline. The error path that restores the fixed route points the link crossbar at it again.
…splay onto the freed hybrid On a desktop 26.x processor the HDMI HPD handler left disconnects to the firmware. The J616s's DP-to-HDMI converter (a Parade DP855) keeps its DP link up without a sink, so the firmware never reports an unplug: the HDMI connector stayed connected and the hybrid pipeline busy until the next plug. Debounce both edges for 500 ms; when HPD stays low, report the unplug as a CRTC power-off with HPD low does, and start the HDMI presence hold, which frees the hybrid when it expires. A Type-C display wider than one pipe that came while HDMI held the hybrid sits on the Type-C-only pipeline, which pairs with nothing above it. When the hybrid becomes free again, move such a display onto it, as a replug does, so that it gets both pipes. While the hybrid drives a Type-C display, an HDMI plug only waits: the cold-plug HPD pulse would have hit the Type-C display's link.
…e-C display A monitor on both the HDMI port and a USB-C port of a J616s (a Samsung G95NC at 7680x2160) can have both display pipes on one input only: the hybrid dcpext0 is the HDMI output's pipeline and the only primary of a pair. The monitor does not tell which input it shows: both keep HPD up, and the unselected DP input still answers for its EDID. So typec_hybrid_first says who gets the hybrid: -1 follows the device tree (the default), 0 puts an HDMI display first, 1 a Type-C display. A write applies at once, so that the desktop can follow the monitor's input. - Type-C first: a Type-C display that asked for two pipes and found no peer takes the hybrid. The HDMI display is reported gone, its link released (retried while the firmware is busy with a link nobody answers) and it waits; it gets the hybrid back when the Type-C display sets a mode within one pipe (picture by picture) or leaves. - HDMI first: an HDMI display keeps the hybrid. One wider than one pipe also takes the other pipe from a Type-C display, which waits, routed nowhere, until the HDMI display fits one pipe or leaves. A hand-over is an unplug and replug: at most one per ten seconds, and no more than two failed takes until the next plug. Peer reservations that outlived their pair are dropped: when a Type-C route takes a pipeline reserved as another display's peer, and when a display asks for a pair while the pipe it reserved, or the pipe it is reserved for, drives a display of its own.
|
Commits since 562eb4c (562eb4c..0d43a7f): a monitor wider than one pipe (Samsung Odyssey G95NC, 7680x2160@120) runs on two desktop 26.6 pipes, over USB-C and HDMI, at boot, after system sleep and after a replug. Why. One DISPEXT pipe of this firmware drives modes up to 6720 px wide; the Samsung Odyssey G95NC's 7680x2160 was dropped ("IOMFB removing mode: 7680 x 2160, max width: 6720") and the monitor ran 5120x1440. The firmware has the two-pipe display the T6050 firmware-27 peer in #485 uses: the primary and a peer merge their frame timing generators and each encodes half of the line. Commits up to 50ba71c (pushed before, no comment yet).
Commits on top of 50ba71c.
Hardware tested on: J616s, DCP firmware 26.6.2, m4-loader rev19-j616s-1, Samsung Odyssey G95NC on USB-C (DP80 cable; Left Back and Left Front ports) and HDMI. Kernel 7.3.0-m4.163 = this branch head plus the local J616s platform layer.
Known limits. 7680x2160@240 stays out of reach (the firmware clamps the ATC port to HBR3 and allows 4 DSC slices per pipe; macOS does not offer it on this machine either). The monitor reports no selected input, hence the parameter; a hand-over between the inputs is an unplug and replug, so the monitor blinks. After s2idle the first enumeration is partial and the link is connected again once. Re-pairing after an unpair caused by a failed frame fails A364 of the original timing (a clean stop and re-pair works). Not tested: two different monitors on HDMI and USB-C that both want two pipes. |
…c-carry J616s external displays: carry #451 with a FORTIFY build fix and selftest fixtures
|
Thank you, this is now in integration/aurora through #526, with all 28 of your commits unchanged under your authorship. Two things turned up while testing it, and #526 carries the fixes:
It was tested on a J616s through a DP Alt Mode dock (mode switches up to 1080p180, DPMS, GPU) and on a Neo (boot and display regression). Details are in #526. Closing this one as merged there. |
The g5 line already has the internal-panel adaptive-sync policy and failure fallback that overlap the last two commits of aurora-silicon#451. Keep that panel path, admit VRR advertised by external sink modes, and program the desktop sync parameter when an external pipe enters or leaves VRR. Ported from the external-display intent of fbalazsy's aurora-silicon#451 while preserving its preceding commits. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The g5 lifecycle fixture already extracts the real desktop 26.6 callback checker. The aurora-silicon#451 fixture follow-up adds an assert stub for its older base, which makes three g5 host scenarios fail to compile with a duplicate symbol. Keep the extracted checker and remove only that redundant stub. The original aurora-silicon#451 commits remain attributed to František Balázsy. This is a g5 integration fixup. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Publish the entered partner DisplayPort alternate mode, consume SPMI events latched before IRQ registration, expose pin E, and provide the connector fwnode fallback. The tether route gate follow-up belongs with aurora-silicon#451 and is included in the batch3 candidate. Assisted-by: LLM
…ora-silicon#518, aurora-silicon#516, aurora-silicon#519 and aurora-silicon#451 This is the tree of the J616s test kernel 7.3.0-aurora-j616s-batch5, built from these parents: - wip/j616s-batch1-20261027 (e1a25b5): the J616s bring-up series - integration/aurora 647f084 (includes aurora-silicon#498, aurora-silicon#512, aurora-silicon#523 and DJ's G17 merges) - aurora-silicon#518 ad14f2d: 25G83 tiler growth fix (Jonathan Goyvaerts) - aurora-silicon#516 31340ab: T6040 two-lane DP pin D beside USB3 - aurora-silicon#519 d769aaf: tipd reconcile of firmware-entered J616s DP Alt Mode - aurora-silicon#451 0d43a7f: J616s external displays (František Balázsy) Resolution notes: - aurora-silicon#451's display code supersedes the older aurora-silicon#451 copy carried by batch1, including its desktop 26.6 adaptive sync. Batch1's callback guard, ProMotion presentation timestamps, minRR=0 restore and swap watchdog stay. - The display gate finds a Type-C route's PHY by its typecN name, so aurora-silicon#451's dcpext0 route@0 is not enabled on a tether whose ATC0 PHY is disabled. - aurora-silicon#516's pin D and aurora-silicon#519's tipd reconcile are kept as in the J616s series. Batch2's selftest fixture reconcile for the G17 owner and CLPC fixtures is part of this tree. Tested on the J616s with the follow-up commits: boots with 0 WARN, external display at 1920x1080@180 through DP Alt Mode, 20/20 mode switches and 15/15 DPMS cycles with no new kernel errors. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
…nc in batch5 The batch5 merge takes aurora-silicon#451's desktop 26.6 adaptive sync and removes the J616s series' parameter sequence (dcp_modeset_sync(), its fixed-refresh fallback on a rejected VRR mode set) and its admission gate (dcp_desktop_vrr_check(), dcp_desktop_vrr_supported()). Retire panel-adaptive-fallback, which drove only that removed sequence; vrr-rejection now pins aurora-silicon#451's VRR_ENABLED-to-mode-set admission. Drop the stubs other fixtures kept for the removed functions (desktop-unknown-modeset-recovery, vrr-rejection), which no longer compile as unused. In the publication fixture, take lookup_mode() by its definition: the J616s takeover check starts a line with a lookup_mode() call, which the line-start pattern matched first. panel-adaptive-watchdog is unchanged: the fixed-refresh latch after an adaptive swap times out remains. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Brings the J616s batch5 kernel (the tree running on the M4 Pro) up to the current integration/aurora, which adds aurora-silicon#524 (J713 T8132 energy model), aurora-silicon#526 (the T6041 display fabric carry, whose peer allocation field group batch5 already has) and aurora-silicon#529 (J713 USB-C idle power). Conflict resolution: - selftests apple-dcp rate.py: keep batch5's version. Its fixtures follow aurora-silicon#451's desktop adaptive sync and the T6041 external EDID. The integration/aurora side only changed how the lookup_mode() definition is found; its line-start pattern also matches the indented "lookup_mode(dcp, ..." call that batch5's iomfb.c has before the definition, while batch5's 'bool lookup_mode(' marker finds the definition in either form. aurora-silicon#529's ATC and dwc3 changes merge cleanly beside aurora-silicon#516's two-lane DP pin D. Assisted-by: LLM Signed-off-by: Ryan Murray <ryan@aurorasilicon.org> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-up to #446 (merged). This PR now carries the whole J616s external display work as one series (it folds #436, which the display gate needs, the device tree and gate, and the GPU image digest that was #500), merged with the current integration/aurora (9cbdd07) without rewriting the earlier commits.
Series.
J616s (M4 Pro): external displays (Type-C through the display fabric, HDMI and USB-C DisplayPort behind the T6041 display gate) and the third loaded GPU image #451's own eight commits: the T6041 Type-C displays through the display fabric (
typec-routesunder dcpext1, one mode switch per port), the callback record check, USB3 lanes given back after DP, the review items.dt-bindings: power: apple: add apple,irq-safe to the PMP report entriesandpmdomain: apple: pmp-report: IRQ-safe entries(was pmdomain: apple: IRQ-safe PMP report entries #436): the DISPEXT power domains sit below the PMP report entries and are IRQ safe, so their parent must be.dt-bindings: display: apple,dcp: add apple,t6041-dcpext: the driver already matches it.arm64: dts: apple: t6040-j616s: external display chain: dcpext0 behind HDMI (atc3 crossbar, atcphy3, the DP-to-HDMI converter), dcpext1 behind the Type-C ports, the DISPEXT domains with their PMP acknowledgement entries, DARTs, mailboxes, the dcpext firmware memory as disabled placeholders the boot loader fills from the ADT. Every node is disabled: powering DISPEXT without the PMP acknowledgement hangs the machine before root.soc: apple: t6041-display-gate: power up the J616s external displays: the existing display gate enables the chain once both external processors have their firmware memory (the dcpext memory-region nodes are available): Type-C routes before any device exists with the display subsystem held back; after the PMP firmware is bound the HDMI chain, the Type-C chain, and last both processors and the display subsystem together. It waits for the crossbar and PHY drivers (modules) first, because with a deferred probe timeout of 0 a processor that finds its crossbar missing is given up for good, and probes the Type-C port controllers again once dcpext1 is bound (the Type-C core treats a mode switch below a disabled node as absent at their first probe). If the PMP does not come within 20 s, or a step fails, the routes are withdrawn and only the internal panel stays. Without the firmware memory, with nomodeset, or on another machine nothing changes.drm/asahi: admit a third loaded T6040 25G83 image(was drm/asahi: admit a third loaded T6040 25G83 image #500, a follow-up to drm/asahi: admit the alternate T6040 loaded 25G83 image #453): this J616s loads a third normalized T6040 TEXT identity (TEXT 0x60000, DATA 0x138000, the same entropy offsets, sha256d725264d4831b95a5b8a375abf2fb5cdfbd6d7cbc7f1baa2cc8b37ee5d6e5e98). Without it the probe stops withunsupported GPU firmware build ... GPU firmware image not admitted: Error(22)and the device has no render node. The digest is added to the 26.6.2 T6040 list and to the KUnit test that runs every listed image through the lookup used byidentify(); digest only, no Apple bytes.Loader contract. The gate's condition is the firmware memory, not a loader name: m4-loader (jgoyvaerts/m4-loader#4) fills the placeholders from the ADT. m1n1 does not do that today; with m1n1 the externals stay off. The m1n1 side is a contract this PR neither implements nor tests.
Hardware tested on: MacBook Pro 16" M4 Pro (J616s), DCP firmware 26.6.2, m4-loader rev19-j616s-1, Samsung G95NC on HDMI and USB-C, a USB-C dock with USB3 storage and Ethernet. Kernel 7.3.0-m4.116 = integration/aurora 9cbdd07 + this series + a local J616s platform layer for m4-loader (NVMe write guard, DART filter, device tree, this unit's GPU image digest); the tree of this branch is identical to it outside those local files.
renderD128present,vulkaninfolists Apple M4 Pro (G16S B1), the Hyprland session runs on the GPU; the kernel without the entry (m4.113, one boot) shows the error above; no asahi fault, error or timeout in the logsNot done for commit 6: KUnit and the Buildbox gates were not run (the test edit is formatted with the pinned rustfmt but not compiled in a KUnit build) and the image was not compared byte for byte with the IPSW firmware as #453 did. Not tested: two USB-C displays at once; m1n1 as the boot loader; a kernel with the crossbar and PHY built in. The DISPEXT1_SYS and DISPEXT1_FE pmgr power-state devices never bind here (silent probe deferral, cause not found); the displays work regardless.
Earlier description of the fabric part (unchanged):
Follow-up to #446 (merged).
The T6041 Type-C routes from #446 use the private dynamic route from the original series (
apple,dptx-phys,dp-phyN/dp-xbarN,apple_t6040_phy_dp_alt()). The display fabric already routes the T602x, T6030 and J700 Type-C ports, so this moves desktop 26.x onto it and closes the remaining notes from the #445 review.Change. Three commits:
drm/apple: route the T6041 Type-C displays through the display fabric:typec-routesunder dcpext1, one mode switch per port, driven by the port controller. The private route andapple_t6040_phy_dp_alt()go away. Three things differ from the other fabric users:dcp->xbar, and the fabric's direct-link helper is T6030 only, so the route setsdcp->xbarwhile it is active (without it the link fails training at 4, 2 and 1 lanes);drm/apple: check the desktop 26.6 callback records against their handlers: the size check from the review notes.phy: apple: t6040: give the Type-C lanes back to USB3 after DP: review item 5.Hardware tested on: MacBook Pro 16" M4 Pro (J616s), DCP firmware 26.6.2, Samsung G95NC on HDMI and USB-C (PBP). Local kernel 7.3.0-m4.93 = the daily J616s tree with the same driver logic (the J616s device tree with
typec-routeson dcpext1 is local, as for #446).pm_test=devices)DRM_APPLE=mandDRM_APPLE=y(crossbar and PHY as modules)Not tested: the other two Type-C ports with a display, two USB-C displays at once (one pipeline), s2idle with the fabric route.
Adaptive sync (commits 16 and 17: internal panel, external displays)
The desktop 26.6 mode set (get_mode_info, then set_digital_out_mode) never sent IOMFBParameter 14, so the ProMotion panel had no VRR and its VRR modes were hidden. The commit sends adaptive sync (minRR in 16.16 Hz, 0 when
VRR_ENABLEDis off) before the mode is selected, makes aVRR_ENABLEDchange a mode set, and offers VRR on the internal panel only.Tested on the J616s, DCP firmware 26.6.2, kernel 7.3.0-m4.124 = integration/aurora 9cbdd07 + this PR + the J616s platform layer, no module options:
vrr_capableIOMFBParameter_adaptive_sync Req minRR = 0x180000, then3456x2234@120 Hz DSC=NO VRR=YES;VRR=NOwith minRR 0 when VRR is switched offCommit 17 sends the same parameter on the external pipes and stops hiding their VRR range. Kernel 7.3.0-m4.125 (= the above + commit 17), Samsung G95NC on USB-C DP (3840x2160@60, range 48-60 Hz from the EDID), Hyprland
misc:vrr 1:vrr_capableIOMFBParameter_adaptive_sync Req minRR = 0x300000,3840x2160@60 Hz DSC=NO VRR=YESvrr_capable1, dcpext0minRR = 0x300000andVRR=YES; 54 fps client every 18.5 ms with VRR (84% off the 60 Hz grid), 16.7/33.3 ms without; the monitor OSD reports Adaptive-Sync onOn the internal panel swap completion follows the content rate with VRR off too, so the numbers there do not prove a scanout difference; the panel was checked by eye. Not tested: s2idle with VRR on.