From a6f4e8ca3024d598cece6abe50c2b4a5b3cdb23a Mon Sep 17 00:00:00 2001 From: AxxzyWasTaken Date: Sat, 7 Nov 2026 12:31:54 +0000 Subject: [PATCH 1/5] arm64: dts: apple: t6041: describe the USB4 resources, disabled The J616C has the same ACIO, NHI, DART and PCIe-C blocks as T6040 at the same addresses and interrupts, checked against its ADT. Take the T6040 description and stop deleting the power domains and mailboxes it needs. Everything stays disabled. Signed-off-by: AxxzyWasTaken --- arch/arm64/boot/dts/apple/t6041.dtsi | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6041.dtsi b/arch/arm64/boot/dts/apple/t6041.dtsi index 094a7c4bd8fa6..87e1718a22b12 100644 --- a/arch/arm64/boot/dts/apple/t6041.dtsi +++ b/arch/arm64/boot/dts/apple/t6041.dtsi @@ -23,9 +23,6 @@ /delete-node/ &jpeg0_dart; /delete-node/ &jpeg1_dart; /delete-node/ &scaler0_dart; -/delete-node/ &usb4_0_mbox; -/delete-node/ &usb4_1_mbox; -/delete-node/ &usb4_2_mbox; /delete-node/ &sio_mbox; /delete-node/ &pinctrl_smc; /delete-node/ &ps_gpx; @@ -128,19 +125,7 @@ /delete-node/ &ps_dispext0_fe; /delete-node/ &ps_dispext0_cpu; /delete-node/ &ps_pcpu0_3; -/delete-node/ &ps_atc0_cio; -/delete-node/ &ps_atc0_pcie; -/delete-node/ &ps_atc0_cio_pcie; -/delete-node/ &ps_atc0_cio_usb; -/delete-node/ &ps_atc1_cio; -/delete-node/ &ps_atc1_pcie; -/delete-node/ &ps_atc1_cio_pcie; -/delete-node/ &ps_atc1_cio_usb; -/delete-node/ &ps_atc2_cio; -/delete-node/ &ps_atc2_pcie; -/delete-node/ &ps_atc2_cio_pcie; /delete-node/ &ps_pcpu0_4; -/delete-node/ &ps_atc2_cio_usb; /delete-node/ &ps_atc3_cio; /delete-node/ &ps_atc3_pcie; /delete-node/ &ps_atc3_cio_pcie; @@ -358,6 +343,8 @@ /delete-node/ &opp_p0; /delete-node/ &opp_p1; +#include "t6040-usb4.dtsi" + / { opp_p0: opp-table-p0 { compatible = "operating-points-v2"; From cf727761e6f91c535383cab76827f51e820d2970 Mon Sep 17 00:00:00 2001 From: AxxzyWasTaken Date: Sat, 7 Nov 2026 12:40:12 +0000 Subject: [PATCH 2/5] phy: apple: t6040: add the CIO (USB4/Thunderbolt) mode Take the lanes for USB4 or the Thunderbolt alternate mode: the common tunables and the CIO ones, the crossbar with orientation in one bit, both lanes released, then the same PHY firmware as USB3. USB3 stays parked until the lanes come back. The order is AppleT6040TypeCPhy mode 2 from the 25G83 kernelcache and matches the T6050 recipe, except for the AHB clock request at CFG +0x28. Not run on hardware. Signed-off-by: AxxzyWasTaken --- drivers/phy/apple/t6040-usb2.c | 214 +++++++++++++++++++++++++++++---- 1 file changed, 193 insertions(+), 21 deletions(-) diff --git a/drivers/phy/apple/t6040-usb2.c b/drivers/phy/apple/t6040-usb2.c index cb4146d91faf1..73b687686294d 100644 --- a/drivers/phy/apple/t6040-usb2.c +++ b/drivers/phy/apple/t6040-usb2.c @@ -49,6 +49,8 @@ #include #include #include +#include +#include #define T6040_USB2_USBCTL 0x00 #define T6040_USB2_USBCTL_MODE GENMASK(2, 0) @@ -120,7 +122,10 @@ #define T6040_CORE_CMN_OVRD_SLEEP_B_BIG BIT(0) #define T6040_CORE_CMN_OVRD_SLEEP_B_SML BIT(2) #define T6040_CORE_CMN_OVRD_CLAMP BIT(4) +#define T6040_CORE_LANE_RX 0x10 /* CFG1_TOP */ #define T6040_CORE_SLP_CTRL 0x120 /* CFG_SLP_CTRL */ +#define T6040_CORE_LN0_RX_TOP_CIO 0x935c +#define T6040_CORE_LN1_RX_TOP_CIO 0x1935c #define T6040_CORE_CMN_BIAS 0xa00 /* AUS40CMN_SHM CMN_BIAS_REG */ #define T6040_CORE_CMN_BIAS_BGBIAS_EN_OV BIT(1) #define T6040_CORE_UC_CTRL 0x260 /* ACIOPHY_TOP_BLK_UC_CTRL_REG */ @@ -241,6 +246,7 @@ struct t6040_usb2_phy { bool usb3_pipe; /* dwc3 asked for the PIPE switch this power cycle */ bool usb3_lent; /* DP mode took the lanes of this Type-C port */ bool pipe_switched; /* the controller's PIPE runs on this PHY */ + bool cio_up; /* the lanes run USB4/Thunderbolt */ /* DisplayPort; dp_ok is false when the DT lacks a DP route */ struct phy *dp; @@ -598,14 +604,15 @@ static int t6040_usb3_cpu_start(struct t6040_usb2_phy *tphy) * every detach; each start makes the firmware tune the PHY. Then release the * PHY reset (D). */ -static int t6040_usb3_run_firmware(struct t6040_usb2_phy *tphy, bool swap) +static int t6040_usb3_run_firmware(struct t6040_usb2_phy *tphy, bool usb, bool swap) { void __iomem *cpu = t6040_cpu(tphy); u32 uc_before; int ret; - t6040_usb2_mask32(t6040_cfg(tphy) + T6040_CFG_SPARE0, T6040_CFG_SPARE0_USB_LN_SWAP, - swap ? T6040_CFG_SPARE0_USB_LN_SWAP : 0); + if (usb) + t6040_usb2_mask32(t6040_cfg(tphy) + T6040_CFG_SPARE0, T6040_CFG_SPARE0_USB_LN_SWAP, + swap ? T6040_CFG_SPARE0_USB_LN_SWAP : 0); fsleep(20); t6040_usb2_set32(cpu + T6040_CPU_IDLE_CTRL, T6040_CPU_IDLE_CTRL_EN); fsleep(10); @@ -750,24 +757,12 @@ static void t6040_usb3_bist_off(struct t6040_usb2_phy *tphy) * aciophy_phy_shutdown_partA: the PHY's USB link side down (the same BIST * handshake as the PIPE switch), both TX lanes, then the common block. */ -static void t6040_usb3_shutdown_lanes(struct t6040_usb2_phy *tphy) +/* aciophy_tx_powerdown(0), (1), then aciophy_cmn_shutdown: USB and CIO alike. */ +static void t6040_phy_tx_cmn_down(struct t6040_usb2_phy *tphy) { - void __iomem *bist = t6040_bist(tphy); void __iomem *core = t6040_core(tphy); unsigned int lane; - t6040_usb2_set32(bist + T6040_BIST_CFG0, BIT(0)); - t6040_usb2_clear32(bist + T6040_BIST_OVRD0, 0x100000); - t6040_usb2_mask32(bist + T6040_BIST_OVRD1, 0x60, 0x20); - t6040_usb3_bist_pulse(tphy, T6040_BIST_CFG0, BIT(3)); - t6040_usb3_bist_wait(tphy, T6040_BIST_STATUS_PHY_2, true, 1000); - t6040_usb2_mask32(bist + T6040_BIST_OVRD0, ~0xe1ffffffu, 0x4000000); - t6040_usb2_mask32(bist + T6040_BIST_OVRD1, 0x600, 0x200); - t6040_usb3_bist_pulse(tphy, T6040_BIST_CFG0, BIT(3)); - t6040_usb3_bist_wait(tphy, T6040_BIST_STATUS_PHY_2, true, 1000); - t6040_usb2_clear32(bist + T6040_BIST_CFG0, BIT(0)); - - /* aciophy_tx_powerdown(0), (1) */ for (lane = 0; lane < 2; lane++) { t6040_usb2_set32(core + T6040_CORE_SLP_CTRL, 0x100 << lane); udelay(1); @@ -786,6 +781,25 @@ static void t6040_usb3_shutdown_lanes(struct t6040_usb2_phy *tphy) udelay(1); t6040_usb2_clear32(core + T6040_CORE_CMN_OVRD, T6040_CORE_CMN_OVRD_SLEEP_B_SML); udelay(1); +} + + +static void t6040_usb3_shutdown_lanes(struct t6040_usb2_phy *tphy) +{ + void __iomem *bist = t6040_bist(tphy); + + t6040_usb2_set32(bist + T6040_BIST_CFG0, BIT(0)); + t6040_usb2_clear32(bist + T6040_BIST_OVRD0, 0x100000); + t6040_usb2_mask32(bist + T6040_BIST_OVRD1, 0x60, 0x20); + t6040_usb3_bist_pulse(tphy, T6040_BIST_CFG0, BIT(3)); + t6040_usb3_bist_wait(tphy, T6040_BIST_STATUS_PHY_2, true, 1000); + t6040_usb2_mask32(bist + T6040_BIST_OVRD0, ~0xe1ffffffu, 0x4000000); + t6040_usb2_mask32(bist + T6040_BIST_OVRD1, 0x600, 0x200); + t6040_usb3_bist_pulse(tphy, T6040_BIST_CFG0, BIT(3)); + t6040_usb3_bist_wait(tphy, T6040_BIST_STATUS_PHY_2, true, 1000); + t6040_usb2_clear32(bist + T6040_BIST_CFG0, BIT(0)); + + t6040_phy_tx_cmn_down(tphy); fsleep(200); } @@ -896,8 +910,8 @@ static void t6040_usb3_up_locked(struct t6040_usb2_phy *tphy) lockdep_assert_held(&tphy->lock); if (!tphy->usb3_ok || tphy->usb3_up) return; - /* DP mode owns all four lanes; USB3 comes back in t6040_usb3_reclaim_locked(). */ - if (tphy->dp_up) { + /* DP and CIO own all four lanes; USB3 comes back in t6040_usb3_reclaim_locked(). */ + if (tphy->dp_up || tphy->cio_up) { dev_dbg(tphy->dev, "USB3: lanes held by DP, USB2 only for now\n"); return; } @@ -922,7 +936,7 @@ static void t6040_usb3_up_locked(struct t6040_usb2_phy *tphy) goto sleep; /* the coprocessor block may be unclocked: never touch it */ t6040_usb3_tunables(tphy); t6040_usb3_lanes(tphy, swap); - ret = t6040_usb3_run_firmware(tphy, swap); + ret = t6040_usb3_run_firmware(tphy, true, swap); if (ret) goto usb2_only; @@ -1409,7 +1423,7 @@ static void t6040_dp_drive(struct t6040_usb2_phy *tphy, unsigned int lane, u32 p static void t6040_usb3_reclaim_locked(struct t6040_usb2_phy *tphy) { lockdep_assert_held(&tphy->lock); - if (!tphy->usb3_lent || tphy->dp_up || tphy->dp_alt) + if (!tphy->usb3_lent || tphy->dp_up || tphy->dp_alt || tphy->cio_up) return; tphy->usb3_lent = false; if (!tphy->usb3_on || tphy->usb3_up) @@ -1422,6 +1436,156 @@ static void t6040_usb3_reclaim_locked(struct t6040_usb2_phy *tphy) dev_info(tphy->dev, "USB3 %s after DP\n", tphy->usb3_up ? "back" : "not restored"); } +/* ---- CIO: USB4 and Thunderbolt on both lanes ---- */ + +/* The ADT tables of the common set, then the CIO ones; no DPTX writes. */ +static void t6040_cio_tunables(struct t6040_usb2_phy *tphy) +{ + void __iomem *core = t6040_core(tphy); + size_t i; + + for (i = 0; i < T6040_USB3_NR_TUNABLES; i++) + apple_tunable_apply(tphy->regs[t6040_usb3_tunable_list[i].region], + tphy->tunables[i]); + /* tunable_LN0/1_RX_TOP_CIO_DFLT; UC_REGS_CIO and RX_EQ_CIO are empty. */ + t6040_usb2_clear32(core + T6040_CORE_LN0_RX_TOP_CIO, 0xe00); + t6040_usb2_clear32(core + T6040_CORE_LN1_RX_TOP_CIO, 0xe00); +} + +/* aciophy_xbar_config, mode 2: orientation is one crossbar bit. */ +static void t6040_cio_xbar(struct t6040_usb2_phy *tphy, bool flip) +{ + void __iomem *core = t6040_core(tphy); + + t6040_usb2_clear32(core + T6040_CORE_XBAR, 0xfc); + t6040_usb2_mask32(core + T6040_CORE_XBAR_LANES, 0x1f, flip ? 1 : 0); + t6040_usb2_mask32(core + T6040_CORE_XBAR, 0x3, 0x2); +} + +/* aciophy_slpctrl_init, mode 2: both lanes, whatever the orientation. */ +static void t6040_cio_lanes_on(struct t6040_usb2_phy *tphy) +{ + static const struct { u32 off, bit; bool set; } steps[] = { + { T6040_CORE_LANE_RX, 0x10, true }, { T6040_CORE_LANE_RX, 0x40, true }, + { T6040_CORE_LANE_RX, 0x1, true }, { T6040_CORE_LANE_RX, 0x4, true }, + { T6040_CORE_CMN_OVRD, 0x400, true }, { T6040_CORE_CMN_OVRD, 0x1000, true }, + { T6040_CORE_CMN_OVRD, 0x40, true }, { T6040_CORE_CMN_OVRD, 0x100, true }, + { T6040_CORE_CMN_OVRD, 0x4000, false }, { T6040_CORE_CMN_OVRD, 0x10000, true }, + { T6040_CORE_SLP_CTRL, 0x40, false }, { T6040_CORE_SLP_CTRL, 0x4, false }, + { T6040_CORE_SLP_CTRL, 0x400, false }, + }; + void __iomem *core = t6040_core(tphy); + unsigned int lane; + size_t i; + + t6040_usb2_clear32(core + T6040_CORE_CMN_OVRD, 0x2a); + udelay(1); + for (lane = 0; lane < 2; lane++) { + for (i = 0; i < ARRAY_SIZE(steps); i++) { + if (steps[i].set) + t6040_usb2_set32(core + steps[i].off, steps[i].bit << lane); + else + t6040_usb2_clear32(core + steps[i].off, steps[i].bit << lane); + udelay(1); + } + } +} + +/* aciophy_rx_powerdown(0), (1): CIO powers the receivers down, USB does not. */ +static void t6040_cio_rx_down(struct t6040_usb2_phy *tphy) +{ + void __iomem *core = t6040_core(tphy); + unsigned int lane; + + for (lane = 0; lane < 2; lane++) { + t6040_usb2_set32(core + T6040_CORE_CMN_OVRD, 0x4000 << lane); + udelay(1); + t6040_usb2_clear32(core + T6040_CORE_CMN_OVRD, 0x40 << lane); + udelay(1); + t6040_usb2_clear32(core + T6040_CORE_CMN_OVRD, 0x400 << lane); + udelay(1); + t6040_usb2_clear32(core + T6040_CORE_LANE_RX, 0x1 << lane); + udelay(1); + t6040_usb2_clear32(core + T6040_CORE_LANE_RX, 0x10 << lane); + udelay(1); + } +} + +/* The Type-C state that needs CIO: USB4 entered, or the Thunderbolt alt mode. */ +static bool t6040_cio_state(const struct typec_mux_state *state) +{ + if (state->alt) + return state->alt->svid == USB_TYPEC_TBT_SID; + if (state->mode != TYPEC_MODE_USB4 || !state->data) + return false; + return FIELD_GET(EUDO_USB_MODE_MASK, + ((const struct enter_usb_data *)state->data)->eudo) == EUDO_USB_MODE_USB4; +} + +static int t6040_cio_up_locked(struct t6040_usb2_phy *tphy) +{ + bool flip; + int ret; + + lockdep_assert_held(&tphy->lock); + if (!tphy->usb3_ok || tphy->dp_up) + return -EBUSY; + switch (tphy->orientation) { + case TYPEC_ORIENTATION_NORMAL: + flip = false; + break; + case TYPEC_ORIENTATION_REVERSE: + flip = true; + break; + default: + dev_warn(tphy->dev, "CIO: no plug orientation\n"); + return -EINVAL; + } + if (tphy->usb3_up || tphy->pipe_switched) + t6040_usb3_down_locked(tphy); + tphy->usb3_lent = tphy->usb3_on; + + ret = pm_runtime_resume_and_get(tphy->dev); + if (ret) + return ret; + ret = t6040_usb3_wake(tphy); + if (ret) + goto sleep; /* the coprocessor block may be unclocked: never touch it */ + t6040_cio_tunables(tphy); + t6040_cio_xbar(tphy, flip); + t6040_cio_lanes_on(tphy); + ret = t6040_usb3_run_firmware(tphy, false, flip); + if (ret) { + t6040_usb3_firmware_power_down(tphy); + goto sleep; + } + tphy->cio_up = true; + dev_info(tphy->dev, "CIO PHY up, %s orientation\n", flip ? "reverse" : "normal"); + return 0; + +sleep: + t6040_usb3_sleep(tphy); + pm_runtime_put(tphy->dev); + dev_warn(tphy->dev, "CIO PHY bring-up failed: %d\n", ret); + return ret; +} + +static void t6040_cio_down_locked(struct t6040_usb2_phy *tphy) +{ + lockdep_assert_held(&tphy->lock); + if (!tphy->cio_up) + return; + t6040_phy_tx_cmn_down(tphy); + t6040_cio_rx_down(tphy); + fsleep(200); + t6040_usb3_firmware_power_down(tphy); + t6040_usb3_sleep(tphy); + tphy->cio_up = false; + pm_runtime_put(tphy->dev); + dev_info(tphy->dev, "CIO PHY asleep\n"); + t6040_usb3_reclaim_locked(tphy); +} + /* ---- DP phy_ops ---- */ static int t6040_dp_power_on(struct phy *phy) @@ -1432,6 +1596,8 @@ static int t6040_dp_power_on(struct phy *phy) guard(mutex)(&tphy->lock); if (!tphy->dp_ok || tphy->dp_up) return 0; + if (tphy->cio_up) + return -EBUSY; /* Pin D shares the running PHY with USB3. Keep its PIPE and firmware. */ if (tphy->dp_two_lanes) { if (!tphy->usb3_ok || !tphy->dp_alt) @@ -1581,6 +1747,12 @@ static int t6040_dp_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *s bool alt = false; guard(mutex)(&tphy->lock); + if (t6040_cio_state(state)) { + if (tphy->cio_up) + return 0; + return t6040_cio_up_locked(tphy); + } + t6040_cio_down_locked(tphy); tphy->dp_flip = (tphy->orientation == TYPEC_ORIENTATION_REVERSE); /* * Latch the DP alt mode state for the DCP's Type-C route. Pin From 02e6c3f1aee87c461a214b41730733cd21187fc7 Mon Sep 17 00:00:00 2001 From: AxxzyWasTaken Date: Sat, 7 Nov 2026 12:43:00 +0000 Subject: [PATCH 3/5] arm64: dts: apple: t6041: add the CIO reset and LSTX pins Reset: ADT pmgr reg[44] +0x2024, the T6000 layout, as macOS uses it. The slot per port and the LSTX pin function are inferred. Signed-off-by: AxxzyWasTaken --- arch/arm64/boot/dts/apple/t6041.dtsi | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/arch/arm64/boot/dts/apple/t6041.dtsi b/arch/arm64/boot/dts/apple/t6041.dtsi index 87e1718a22b12..5be2b85208ec9 100644 --- a/arch/arm64/boot/dts/apple/t6041.dtsi +++ b/arch/arm64/boot/dts/apple/t6041.dtsi @@ -345,6 +345,58 @@ #include "t6040-usb4.dtsi" +/ { + /* ADT pmgr reg[44]: AppleT6041PMGR::enableCioReconfig at +0x2024. */ + pmgr_cio: power-management@502820000 { + compatible = "apple,t6041-pmgr-cio", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x5 0x02820000 0 0x4000>; + + cio_reset: reset-controller@2024 { + compatible = "apple,t6041-cio-reset", "apple,t6000-cio-reset"; + reg = <0x2024 0x4>; + #reset-cells = <1>; + }; + }; +}; + +&pinctrl_aop { + /* ADT acioN gpio-lstx. */ + usb4_0_lstx_pins: usb4-0-lstx-pins { + pinmux = ; + }; + + usb4_1_lstx_pins: usb4-1-lstx-pins { + pinmux = ; + }; + + usb4_2_lstx_pins: usb4-2-lstx-pins { + pinmux = ; + }; +}; + +&usb4_0_acio { + resets = <&cio_reset 0>; + pinctrl-names = "lstx"; + pinctrl-0 = <&usb4_0_lstx_pins>; + lstx-gpios = <&pinctrl_aop 49 GPIO_ACTIVE_HIGH>; +}; + +&usb4_1_acio { + resets = <&cio_reset 1>; + pinctrl-names = "lstx"; + pinctrl-0 = <&usb4_1_lstx_pins>; + lstx-gpios = <&pinctrl_aop 51 GPIO_ACTIVE_HIGH>; +}; + +&usb4_2_acio { + resets = <&cio_reset 2>; + pinctrl-names = "lstx"; + pinctrl-0 = <&usb4_2_lstx_pins>; + lstx-gpios = <&pinctrl_aop 53 GPIO_ACTIVE_HIGH>; +}; + / { opp_p0: opp-table-p0 { compatible = "operating-points-v2"; From f9dc13432d3763d084363be890b9fc8ee04ea5e4 Mon Sep 17 00:00:00 2001 From: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Date: Sun, 8 Nov 2026 03:56:37 +1100 Subject: [PATCH 4/5] arm64: dts: apple: t6040: share the USB4 router resets and LSTX pins The CIO reconfig reset and the routers' LSTX pins sat in t6041.dtsi, so only the J616c had them. The M4 Pro MacBook Pros (J614s, J616s) have the same three routers behind the same lines: their ADT acioN gpio-lstx are AOP pins 49, 51 and 53 as on the J616c. Move both into t6040-usb4.dtsi, which every T604x board with routers includes, and give each router its reset line, LSTX pin and lstx-gpios there. Keep the CIO reconfig block disabled until a board enables its routers, as on T8132. Label the routers' Type-C graph endpoints so boards can link their connectors. Nothing new is enabled: the J614s, J616s and J616c DTBs build with the same dtc warnings as before. Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM --- arch/arm64/boot/dts/apple/t6040-usb4.dtsi | 55 ++++++++++++++++++++--- arch/arm64/boot/dts/apple/t6041.dtsi | 52 --------------------- 2 files changed, 49 insertions(+), 58 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6040-usb4.dtsi b/arch/arm64/boot/dts/apple/t6040-usb4.dtsi index c0980ba16e90c..bf3650f0ead20 100644 --- a/arch/arm64/boot/dts/apple/t6040-usb4.dtsi +++ b/arch/arm64/boot/dts/apple/t6040-usb4.dtsi @@ -33,7 +33,10 @@ interrupts = ; interrupt-names = "sram-parity"; mboxes = <&usb4_0_mbox>; - resets = <&ps_atc0_cio>; + resets = <&cio_reset 0>; + pinctrl-names = "lstx"; + pinctrl-0 = <&usb4_0_lstx_pins>; + lstx-gpios = <&pinctrl_aop 49 GPIO_ACTIVE_HIGH>; power-domains = <&ps_atc0_cio>, <&ps_atc0_cio_pcie>, <&ps_atc0_cio_usb>, <&ps_atc0_pcie>; thunderbolt-switch; @@ -50,7 +53,7 @@ port@1 { reg = <1>; - endpoint { }; + usb4_0_acio_tbt: endpoint { }; }; }; @@ -127,7 +130,10 @@ interrupts = ; interrupt-names = "sram-parity"; mboxes = <&usb4_1_mbox>; - resets = <&ps_atc1_cio>; + resets = <&cio_reset 1>; + pinctrl-names = "lstx"; + pinctrl-0 = <&usb4_1_lstx_pins>; + lstx-gpios = <&pinctrl_aop 51 GPIO_ACTIVE_HIGH>; power-domains = <&ps_atc1_cio>, <&ps_atc1_cio_pcie>, <&ps_atc1_cio_usb>, <&ps_atc1_pcie>; thunderbolt-switch; @@ -144,7 +150,7 @@ port@1 { reg = <1>; - endpoint { }; + usb4_1_acio_tbt: endpoint { }; }; }; @@ -221,7 +227,10 @@ interrupts = ; interrupt-names = "sram-parity"; mboxes = <&usb4_2_mbox>; - resets = <&ps_atc2_cio>; + resets = <&cio_reset 2>; + pinctrl-names = "lstx"; + pinctrl-0 = <&usb4_2_lstx_pins>; + lstx-gpios = <&pinctrl_aop 53 GPIO_ACTIVE_HIGH>; power-domains = <&ps_atc2_cio>, <&ps_atc2_cio_pcie>, <&ps_atc2_cio_usb>, <&ps_atc2_pcie>; thunderbolt-switch; @@ -238,7 +247,7 @@ port@1 { reg = <1>; - endpoint { }; + usb4_2_acio_tbt: endpoint { }; }; }; @@ -514,3 +523,37 @@ }; }; }; + + +/ { + /* ADT pmgr reg[44]: AppleT6041PMGR::enableCioReconfig at +0x2024. */ + pmgr_cio: power-management@502820000 { + compatible = "apple,t6041-pmgr-cio", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x5 0x02820000 0 0x4000>; + /* Enabled together with the routers. */ + status = "disabled"; + + cio_reset: reset-controller@2024 { + compatible = "apple,t6041-cio-reset", "apple,t6000-cio-reset"; + reg = <0x2024 0x4>; + #reset-cells = <1>; + }; + }; +}; + +&pinctrl_aop { + /* ADT acioN gpio-lstx. */ + usb4_0_lstx_pins: usb4-0-lstx-pins { + pinmux = ; + }; + + usb4_1_lstx_pins: usb4-1-lstx-pins { + pinmux = ; + }; + + usb4_2_lstx_pins: usb4-2-lstx-pins { + pinmux = ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t6041.dtsi b/arch/arm64/boot/dts/apple/t6041.dtsi index 5be2b85208ec9..87e1718a22b12 100644 --- a/arch/arm64/boot/dts/apple/t6041.dtsi +++ b/arch/arm64/boot/dts/apple/t6041.dtsi @@ -345,58 +345,6 @@ #include "t6040-usb4.dtsi" -/ { - /* ADT pmgr reg[44]: AppleT6041PMGR::enableCioReconfig at +0x2024. */ - pmgr_cio: power-management@502820000 { - compatible = "apple,t6041-pmgr-cio", "syscon", "simple-mfd"; - #address-cells = <1>; - #size-cells = <1>; - reg = <0x5 0x02820000 0 0x4000>; - - cio_reset: reset-controller@2024 { - compatible = "apple,t6041-cio-reset", "apple,t6000-cio-reset"; - reg = <0x2024 0x4>; - #reset-cells = <1>; - }; - }; -}; - -&pinctrl_aop { - /* ADT acioN gpio-lstx. */ - usb4_0_lstx_pins: usb4-0-lstx-pins { - pinmux = ; - }; - - usb4_1_lstx_pins: usb4-1-lstx-pins { - pinmux = ; - }; - - usb4_2_lstx_pins: usb4-2-lstx-pins { - pinmux = ; - }; -}; - -&usb4_0_acio { - resets = <&cio_reset 0>; - pinctrl-names = "lstx"; - pinctrl-0 = <&usb4_0_lstx_pins>; - lstx-gpios = <&pinctrl_aop 49 GPIO_ACTIVE_HIGH>; -}; - -&usb4_1_acio { - resets = <&cio_reset 1>; - pinctrl-names = "lstx"; - pinctrl-0 = <&usb4_1_lstx_pins>; - lstx-gpios = <&pinctrl_aop 51 GPIO_ACTIVE_HIGH>; -}; - -&usb4_2_acio { - resets = <&cio_reset 2>; - pinctrl-names = "lstx"; - pinctrl-0 = <&usb4_2_lstx_pins>; - lstx-gpios = <&pinctrl_aop 53 GPIO_ACTIVE_HIGH>; -}; - / { opp_p0: opp-table-p0 { compatible = "operating-points-v2"; From 156b9ad7abf3c5d333c0d71652e3f5cf882b0fc3 Mon Sep 17 00:00:00 2001 From: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Date: Sun, 8 Nov 2026 03:56:37 +1100 Subject: [PATCH 5/5] arm64: dts: apple: j614s/j616s: link the Type-C ports to their USB4 routers Each router sits behind one ATC PHY (ADT acioN atc-phy-parent is atc-phyN), and each Type-C connector uses the same PHY: typec0 (left back) goes with ACIO0, typec1 (left front) with ACIO1 and typec2 (right) with ACIO2. Describe that in the OF graph (connector port@2, router port@1) so the port controller can hand the router its USB4 and Thunderbolt state once the routers are enabled. The routers stay disabled. The Type-C connection lookup skips a disabled remote node, so the ports keep working as before without a router. Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM --- .../boot/dts/apple/t604x-j614-j616-usb4.dtsi | 54 +++++++++++++++++++ .../arm64/boot/dts/apple/t604x-j614-j616.dtsi | 2 + 2 files changed, 56 insertions(+) create mode 100644 arch/arm64/boot/dts/apple/t604x-j614-j616-usb4.dtsi diff --git a/arch/arm64/boot/dts/apple/t604x-j614-j616-usb4.dtsi b/arch/arm64/boot/dts/apple/t604x-j614-j616-usb4.dtsi new file mode 100644 index 0000000000000..ec32ca4bf9c03 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t604x-j614-j616-usb4.dtsi @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * MacBook Pro (14-inch and 16-inch, M4 Pro) USB4/Thunderbolt: each Type-C + * port's connector is linked to the USB4 router behind the same ATC PHY + * (ADT acioN atc-phy-parent = atc-phyN): typec0 (left back) to ACIO0, + * typec1 (left front) to ACIO1, typec2 (right) to ACIO2. The routers stay + * disabled, and a port controller skips a link to a disabled router, so this + * changes nothing until a board enables them. + */ + +&usb4_0_acio_tbt { + remote-endpoint = <&typec0_con_tbt>; +}; + +&usb4_1_acio_tbt { + remote-endpoint = <&typec1_con_tbt>; +}; + +&usb4_2_acio_tbt { + remote-endpoint = <&typec2_con_tbt>; +}; + +&typec0 { + ports { + port@2 { + reg = <2>; + typec0_con_tbt: endpoint { + remote-endpoint = <&usb4_0_acio_tbt>; + }; + }; + }; +}; + +&typec1 { + ports { + port@2 { + reg = <2>; + typec1_con_tbt: endpoint { + remote-endpoint = <&usb4_1_acio_tbt>; + }; + }; + }; +}; + +&typec2 { + ports { + port@2 { + reg = <2>; + typec2_con_tbt: endpoint { + remote-endpoint = <&usb4_2_acio_tbt>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t604x-j614-j616.dtsi b/arch/arm64/boot/dts/apple/t604x-j614-j616.dtsi index 2c4e9d8cec2bc..e0d279a8635e4 100644 --- a/arch/arm64/boot/dts/apple/t604x-j614-j616.dtsi +++ b/arch/arm64/boot/dts/apple/t604x-j614-j616.dtsi @@ -4997,3 +4997,5 @@ power-domain-names = "sys", "cpu", "mpm", "td", "base", "perf"; status = "okay"; }; + +#include "t604x-j614-j616-usb4.dtsi"