Repository navigation
drm/apple: T6041 (M4 Pro/Max) displays on desktop 26.6 firmware: J616s internal panel, HDMI and USB-C DisplayPort - #445
Conversation
The link sequences of the T6050 fixed DP PHY, taken unchanged from aurora-silicon#248 ("phy: apple: Add T6050 fixed DP and four-clock crossbar support", 440f79f) as the single file the T6040 Type-C PHY needs for its DisplayPort mode: the T6050 ADT names its PHY "atc-phy,t6050", "atc-phy,t6040", and the sequences run unchanged on the T6040 PHY core. Only the data header is carried here; the T6050 PHY driver, its binding and the crossbar changes of aurora-silicon#248 stay in that pull request. Once aurora-silicon#248 lands, this commit disappears on rebase. [fbalazsy: picked drivers/phy/apple/atc-t6050-dp-data.h alone from aurora-silicon#248] Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
…ed DP PHY
The T6040 Type-C PHY also carries DisplayPort: the PHY of a USB-C port as
the alt mode switch of its connector (mode-switch), and the PHY of an HDMI
converter as a fixed DisplayPort link. The fixed instance has no USB
controller behind it, so no PIPE interface ("pipehandler" region), no reset
line and no connector port. Describe the DP phy type, the mode switch and
the ten-region variant, and require #reset-cells only where the PIPE
interface exists.
Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
Add PHY_TYPE_DP to the T6040 Type-C PHY: PHY mode 3 of the paired
AppleT6040TypeCPhy driver, DisplayPort on all four lanes, for a Type-C port
whose controller selected DP alt mode with pin assignment C or E, and for
the fixed DP PHY of an HDMI converter, a node without the PIPE interface
and the DWC3 reset line, which now probes too.
Bring-up follows the paired driver's mode 3: wake the CFG block, apply the
generic ADT tunables and the DPTX tunables, set the lane crossbar to DP,
hold the common block and both TX lanes on by override (the PHY
coprocessor does not run in this mode), release the reset, then set the
lane mode and the AUX block. On a Type-C port the USB3 side is shut down
first. The per-rate link sequences (RBR to HBR3) and the drive-setting
presets are the T6050 fixed-DP tables, whose PHY the T6050 ADT marks as
T6040-compatible ("atc-phy,t6050", "atc-phy,t6040"); the T6050 clock shim
steps are replaced by the T6040 DP clock switch of the CFG window, run
after the lane program as the paired driver does. Pin assignment D (two DP
lanes next to USB3) is not supported.
The Type-C mode switch latches whether the port is in DP alt mode;
apple_t6040_phy_dp_alt() (include/linux/soc/apple/dp-tunnel.h) exposes it
for a DCP that lists several Type-C DP PHYs and routes to the one with a
sink plugged.
Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The IOMFB template keys its H17 (A18 Pro, M5) wire changes on DCP_FW_VER >= 26.0. The desktop firmware of the M4 Pro/Max DCP (T6041) also reports 26.x, but continues the 14.7 IOMFB. Mark a desktop instance's version with DCP_FW_DESKTOP and key the H17 branches on DCP_FW_H17(). No functional change: the 12.3, 13.3, 14.7 and H17P template objects are unchanged. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The 26.6 firmware of the M4 Pro/Max DCP (T6041) continues the 14.7 IOMFB rather than the H17 protocol: most method numbers match H17P, but the records and the start, power and mode-set flows are those of 14.7 with extensions. Add it as a template instance, iomfb_v26_6_desktop.c, with firmware compatibility value DCP_FIRMWARE_V_26_6_DESKTOP. Nothing selects it yet. The instance carries this firmware's wire layout: a 0x588-byte swap record with presents_surface, has_completion and the panel level in nits as a binary64, a 0x1bd8-byte swap_submit with six surf2 entries, swap_start with an opaque client cookie, set_power_state with four transition flags, and the padded abort_swaps, read_edt_data, hotplug, swap intent and frame_sync records. DCP_FW_LAYOUT_14_7() covers the desktop 26.x versions, and static assertions pin the record sizes. Power-on is A414, first_client_open, A474, is_main_display and set_power_state(1), then set_display_device; power-off clears the swap and sets power state 0. A mode set selects the timing through get_mode_info (A364) before set_digital_out_mode. A pipe without a live mode is bootstrapped through the timing's best virtual color element, which the parser now records. GAMMA_LUT is composed with the firmware's gamma table (A420/A421). VRR timings are not offered. The per-DCP desktop state is allocated only for this firmware, so other instances keep their struct apple_dcp size and the 12.3, 13.3, 14.7 and H17P template objects are unchanged. Co-developed-by: Niklas Sheth <hi@niklassheth.com> Signed-off-by: Niklas Sheth <hi@niklassheth.com> Co-developed-by: Josh Rodd <josh@rodd.us> Signed-off-by: Josh Rodd <josh@rodd.us> Co-developed-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The desktop 26.6 firmware of the T6041 DCP speaks a compact EPIC on its system and auxiliary endpoints: an 8-byte transport header (sequence, flags, interface, total length), the timestamp, an 8-byte sub-header and the payload. Messages longer than 1028 bytes arrive in fragments that repeat the header. Services announce themselves with type 0x11 and are opened with type 0x12; commands, replies and calls carry a status/length descriptor. On DCP_FIRMWARE_V_26_6_DESKTOP endpoints, switch to it on the first compact message: reassemble fragments, register and open announced services, answer calls, deliver reports and match replies to pending commands. Send commands and replies the same way, fragmented when needed, waiting for ring space with WAIT_FOR_SPACE, and answer the firmware's WAIT_FOR_SPACE after draining the receive ring. Call replies are sent from a separate workqueue so that a full transmit ring cannot stall reception. Ring pointers read from shared memory are validated before use; a send that fails part-way fails the commands in flight without shutting the endpoint down. Other firmware never takes these paths. Co-developed-by: Niklas Sheth <hi@niklassheth.com> Signed-off-by: Niklas Sheth <hi@niklassheth.com> Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
Match apple,t6041-dcp and apple,t6041-dcpext and drive the internal DCP of the M4 Pro/Max (J616s) through the desktop 26.6 IOMFB instance. Probe accepts a T6041 processor only with apple,firmware-version and apple,firmware-compat both 26.6.2, and the internal one only if its register windows, iommus, mboxes and piodma match the ADT. The clock is optional there, and without apple,max-brightness the backlight maximum defaults to the panel's 600 nits. The firmware does not tolerate being left running with its endpoints unserviced, so bind sets the coprocessor running and dcp_start() wakes RTKit once every handler is in place. It starts the system endpoint, the IOMFB transport and the auxiliary endpoints the firmware advertises, routes their messages, and binds the IOMFB shared memory last. An auxiliary endpoint that fails to start is skipped. Before the boot framebuffer is evicted, the panel goes through a takeover trial: DCP ready, modes known, panel connected, power-on and one mode set, boot-like mode first. If it fails, the DCP is left running, the DRM device is kept, shutdown and resume leave the DCP alone and suspend is refused, and the boot framebuffer keeps the screen. The T6041 external processors stay out of the DRM device unless t6041_dcpext=1, and then as unusable pipes. Co-developed-by: Cody Ho <codyho@stanford.edu> Signed-off-by: Cody Ho <codyho@stanford.edu> Co-developed-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The T6041 external display processors publish their DPTX port services as dcpdptx-port-epic:0 and :1 in compact EPIC on EPIC2C (0x2c). Bind them by unit, open port 0 last, and follow the firmware's own client where the compact ABI differs: - set_hpd returns an IOReturn status in its first word; - GET_SUPPORTS_HPD and GET_VIRTUAL_DEVICE_MODE are answered with 0; - GET_MAX_LINK_RATE offers HBR3; - the crossbar link is taken down before a link configuration change and brought up after it; - group 1 calls 3 and 4 keep the first 32 bytes of their record and clear the result word. The DPAVSERV EDID request asks for 2 KiB there, as a 32 KiB inline request does not fit the compact ring, and dcpdp-service-epic is not opened. Co-developed-by: Niklas Sheth <hi@niklassheth.com> Signed-off-by: Niklas Sheth <hi@niklassheth.com> Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The two external display processors of the M4 Pro/Max (J616s) join the panel's DRM device as further pipelines; t6041_dcpext=0 leaves them alone. dcpext0 drives the HDMI port through its fixed route (atcphy3 and its crossbar), dcpext1 the USB-C ports through a route chosen at connect from the PHY that entered DP alt mode. - probe powers the fixed route's DP PHY and lists the dynamic routes (dp-phyN, dp-xbarN, apple,dptx-phys, apple,dptx-mux-index); - start brings up the advertised auxiliary endpoints, the DPTX port services, DPAVSERV, EXPERT and EPIC25, and connects DPTX port 0; - a connect asserts HPD after the display request and does not fail when no display is attached; - an HDMI hotplug on a connected port pulses HPD, so the firmware exports the modes of a display plugged in after boot; - a USB-C hotplug selects and releases the route through the connector's out-of-band hotplug under hpd_mutex; a failed connect and unbind release it; - a CRTC kept active across a replug is powered on and set up again on its next flush. A dcpext that is absent or fails to probe or bind is kept as an unusable pipe and never holds up the panel. apple_t6040_phy_dp_alt() gets a stub, and DRM_APPLE cannot be built in with the T6040 USB2 PHY as a module. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
RyanTheTide
left a comment
There was a problem hiding this comment.
I read the whole series against integration/aurora 653c489. The shared paths look safe for the other machines on the universal kernel. I preprocessed iomfb_template.c for the v12.3, v13.3, v14.7 and H17P instances before and after. They only differ by the DCP_FW_SWAP() spelling, the moved swap_req declaration and the surf2_null size, so DCP_FW_H17 still matches only H17P. The compact EPIC paths in afk.c, dcp.c, dptxep.c and dpavservep.c are all gated on the desktop firmware or the t6041 compatibles. The fragment reassembly bounds look right to me (total capped at 1 MiB, each piece checked against what is left, seq and interface continuity), and so do the TX ring wrap and space checks.
The attribution is in order. Every Co-developed-by sign-off matches the original commits, and the Gravity files these come from carry the same GPL-2.0-only OR MIT licence.
Things to fix before this can go in:
-
Commit 1 doesn't need to wait for #248. Its file is byte-identical to atc-t6050-dp-data.h in 440f79f, and that commit carries "Signed-off-by: Dj hey@djdev.me". So the original does have the author's sign-off, and you can carry it over above yours with a line pointing at 440f79f, the usual way for a file picked from a signed commit. #248 itself is stacked on the APIF branch and doesn't apply on integration/aurora, so landing it first isn't practical.
-
dptxep.c dptxport_compact_xbar_link() calls apple_dpxbar_link_up() and apple_dpxbar_link_down() directly. DRM_APPLE has no dependency on MUX_APPLE_DPXBAR, so DRM_APPLE=y with the crossbar as a module fails to link. In the universal config both are modules, so appledrm.ko now pulls in the crossbar module on every machine. dcp-fabric.c already has dcp_dpxbar_link(), which uses symbol_get() for exactly this reason. Making that non-static and calling it here would keep the crossbar optional.
-
The same applies to apple_t6040_phy_dp_alt() in dcp.c together with the new "depends on PHY_APPLE_T6040_USB2 || !PHY_APPLE_T6040_USB2". It builds, but appledrm.ko now needs the T6040 PHY module on every SoC, and DRM_APPLE=y is quietly demoted to m wherever the PHY is a module. A symbol_get() lookup like the crossbar one would avoid both.
-
t6040-usb2.c, a stale ERR_PTR tunable. When t6040_usb3_probe() fails to parse a tunable, it leaves the ERR_PTR in tphy->tunables[i] and returns 0. t6040_dp_probe() then treats the node as DP only, and for an absent property it hits
continuewithout clearing that slot. t6040_dp_phy_init() then passes the ERR_PTR to apple_tunable_apply(), which only checks for NULL. Nothing in the tree reaches this yet, since no DT consumes the DP PHY, but clearing the slot on every skip and error path would close it. It also means a Type-C PHY whose USB3 setup failed is now classed as DP only, which may not be what you want. -
t6040-usb2.c, USB3 and DP ownership. t6040_dp_power_on() shuts the USB3 side down, but t6040_dp_power_off() only clears dp_up and doesn't bring USB3 back. Nothing stops t6040_usb3_power_on() from re-initialising the PHY under a live DP mode either. After a Type-C DP session ends, USB3 on that port looks like it stays down until dwc3 power cycles the PHY. This is T6041 only, and not reachable with the current DT.
Smaller notes. The desktop callbacks in iomfb.c don't validate in_len/out_len the way iomfb_check_callback_h17p() does for H17P. The u16 offset keeps them inside the shared memory, so this isn't an overflow, but a size check would be cheap. Also, dcp_desktop_dyn_route_select_locked() takes the drvdata of whatever dp-phyN points at. A compatible check there would guard against a DT that names a different PHY.
I'm building the full series together with #435, #436, #427 and #428 on the universal recipe with WERROR, and running KUnit, the apple-dcp host selftests and the DT checks. I'll add the results and a J616s internal panel boot here once they're done.
|
Thanks a lot for this series! It's now carried in #446 with your eight commits unchanged, your authorship, sign-off and the co-developer credit intact. Commit 1 is now Dj's own signed commit from #248, and there are three small fixes on top (runtime lookups for the crossbar and DP alt helpers, the stale tunable pointer, and the host selftest fixtures). The internal panel came up on our J616s with it. Closing this one in favour of #446. |
drm/apple: T6041 (M4 Pro/Max) displays on desktop 26.6 firmware (carries #445)
The M4 Pro/Max display coprocessors (T6041: the internal
dcpand the externaldcpext0/dcpext1) run DCP firmware 26.6.2, but that firmware is not the H17 protocol of the A18 Pro/M5 (iomfb_h17p.c): it continues the 14.7 IOMFB of the earlier desktop chips (A029 setup_video_limits, A407 swap_submit with the 0x1bd8-byte request, A473 on the command channel, compact EPIC on every auxiliary endpoint). This adds it to the driver as its own template instance,DCP_FIRMWARE_V_26_6_DESKTOP(not the J613 DCPLinkDCP_FIRMWARE_V_26_6), and drives the J616s internal panel, the HDMI output (dcpext0, fixed DP PHY on ATC3 → DP-to-HDMI converter) and USB-C DisplayPort (dcpext1, Type-C route chosen from the PHY in DP alt mode) with it.Externals follow the J700 model where it does not depend on the protocol: one DRM device, each dcpext an extra CRTC, connectors with fwnode for out-of-band hotplug, a dcpext that fails to probe or start becomes an unusable pipe and never takes the panel down (no hard coupling as for t8140-dcpext). The Type-C display fabric (
typec-routes) is not used yet for T6041; the route comes from the DT'sapple,dptx-physlist and tipd's DP alt mode.Change. Nine commits:
phy: apple: T6050 fixed DisplayPort PHY register sequences, 2.dt-bindings: phy: apple,t6040-atcphy: DisplayPort mode switch and fixed DP PHY, 3.phy: apple: t6040: DisplayPort mode— phy: apple: t6040: DisplayPort mode (Type-C alt mode and the fixed HDMI PHY) #444 unchanged, folded in here (the drm side needsapple_t6040_phy_dp_alt()); phy: apple: t6040: DisplayPort mode (Type-C alt mode and the fixed HDMI PHY) #444 is closed in favour of this PR.drm/apple: tell the H17 26.x lineage apart from the desktop one—DCP_FW_H17()/DCP_FW_DESKTOPinversion_utils.h; the H17 branches of the template key on it. No functional change:iomfb_h17p.o,iomfb_v12_3.o,iomfb_v13_3.oandiomfb_v14_7_tpl.okeep byte-identical code and data sections (compared section by section, also after every later commit).drm/apple: add the desktop 26.6 IOMFB template instance for T6041—iomfb_v26_6_desktop.c/.h: method and callback tables, the 26.6 wire structs with size asserts, power-on/off/sleep sequences, modeset, swap, gamma.drm/apple: afk: speak compact EPIC on desktop 26.x endpoints— compact framing with fragment reassembly (afk-fragment.h, lengths bounded, ring pointers validated), only for the desktop firmware.drm/apple: drive the T6041 internal panel on desktop 26.6 firmware—apple,t6041-dcpmatch, exact 26.6.2 firmware gate, endpoint graph as advertised, takeover trial (boot mode first).drm/apple: compact DPTX and DPAVSERV for desktop 26.x external displays— DPTX on EPIC2C 0x2c, ports bound by unit, set_hpd status in word 0, HBR3.drm/apple: drive the T6041 external displays on desktop 26.6 firmware—apple,t6041-dcpext, HDMI HPD with the cold-plug pulse, Type-C route select/release underhpd_mutex, re-power of a replugged pipe, no keepalive across a disconnect. New module parametert6041_dcpext(default 1,0keeps the dcpext out of the component set).Commits 5–8 port the 26.6 work of Niklas Sheth (T8132 hotplug, compact AFK), Josh Rodd (J715 on 26.6.2), Cody Ho (firmware gate) and Jonathan Goyvaerts (J616s internal panel), credited with
Co-developed-by/Signed-off-by.Dependencies. Runtime: the T6041 crossbar of #435 (externals; the panel does not need it) and the DISPEXT power states of #436. Device tree: the internal panel uses the
dcpnode already int6040.dtsi; the J616s dcpext0/1, atcphy3, crossbar, DART and DISPEXT nodes are not part of this PR — they follow once the loader enables them (today they are switched on at runtime here).Sign-off note (@RyanTheTide, @DjDeveloperr). Commit 1 is Dj's
atc-t6050-dp-data.hfrom #248 (440f79f) unchanged with his authorship; the original has no Signed-off-by from Dj, so checkpatch reports the missing author sign-off. Dj, could you add yours (or should this wait for #248)? The other commits have all sign-offs.Hardware tested on: MacBook Pro 16" M4 Pro (J616s, T6040/T6041), DCP firmware 26.6.2, Samsung G95NC on HDMI and USB-C (PBP), Hyprland 0.56. Local kernel 7.3.0-m4.79 = the daily J616s tree (integration/aurora 420a1c8 + J616s series) with
drivers/gpu/drm/apple= integration/aurora 653c489 + exactly these drm commits, the #435 crossbar and #444 PHY.How tested:
appledrmW=1 clean per commit (bisectable)kunit.py --arch=arm64,DRM_APPLE=y,PHY_APPLE_T6040_USB2=n)checkpatch.plDCP_FW_NAME()/DCP_FW_VERspacing and comparison reports on the template follow its existing style; MAINTAINERS note for the new filesNot tested: 7680x2160 on the G95NC (needs the firmware's dual-pipe path, max width 6720 per pipe), pin assignment D, HDMI/DP audio, VRR (no VRR timings offered on this firmware for now), HDCP.