mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/4] phy: apple: atc: Add M3 support
@ 2026-11-08 15:43 Sasha Finkelstein
  2026-11-08 15:43 ` [PATCH 1/4] dt-bindings: phy: atcphy: Add M3 series Sasha Finkelstein
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Sasha Finkelstein @ 2026-11-08 15:43 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Vinod Koul, Neil Armstrong,
	Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: asahi, linux-arm-kernel, linux-phy, devicetree, linux-kernel,
	Sasha Finkelstein, Ramzi Abdiche

The M3 series introduced a new Type-C phy. Add support for initializing
and configuring it. This is one of the puzzle pieces needed for
USB3/TB/DP support on those devices.

To simplify the merge strategy, the device tree entries will be sent
in a future patch series.

Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
---
Ramzi Abdiche (1):
      phy: apple: atc: Add T8122 DisplayPort support

Sasha Finkelstein (3):
      dt-bindings: phy: atcphy: Add M3 series
      soc: apple: tunable: Allow passing NULL to tunable_apply
      phy: apple: atc: Add initial M3 series support

 .../devicetree/bindings/phy/apple,atcphy.yaml      |    6 +
 drivers/phy/apple/atc.c                            | 1021 ++++++++++++++++++--
 drivers/soc/apple/tunable.c                        |    2 +
 3 files changed, 924 insertions(+), 105 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261108-t8122-phy-bc3190cbcfc4

Best regards,
--  
Sasha Finkelstein <k@chaosmail.tech>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/4] dt-bindings: phy: atcphy: Add M3 series
  2026-11-08 15:43 [PATCH 0/4] phy: apple: atc: Add M3 support Sasha Finkelstein
@ 2026-11-08 15:43 ` Sasha Finkelstein
  2026-11-08 15:43 ` [PATCH 2/4] soc: apple: tunable: Allow passing NULL to tunable_apply Sasha Finkelstein
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Sasha Finkelstein @ 2026-11-08 15:43 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Vinod Koul, Neil Armstrong,
	Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: asahi, linux-arm-kernel, linux-phy, devicetree, linux-kernel,
	Sasha Finkelstein

M3 series SoCs have new phys that are different enough to need
a new compatible

Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
---
 Documentation/devicetree/bindings/phy/apple,atcphy.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/apple,atcphy.yaml b/Documentation/devicetree/bindings/phy/apple,atcphy.yaml
index 0acac7e3ee67..39461c5dcf20 100644
--- a/Documentation/devicetree/bindings/phy/apple,atcphy.yaml
+++ b/Documentation/devicetree/bindings/phy/apple,atcphy.yaml
@@ -55,6 +55,12 @@ properties:
               - apple,t8112-atcphy
           - const: apple,t8103-atcphy
       - const: apple,t8103-atcphy
+      - const: apple,t8122-atcphy
+      - items:
+          - enum:
+              - apple,t6030-atcphy
+              - apple,t6031-atcphy
+          - const: apple,t8122-atcphy
 
   reg:
     items:

-- 
2.56.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/4] soc: apple: tunable: Allow passing NULL to tunable_apply
  2026-11-08 15:43 [PATCH 0/4] phy: apple: atc: Add M3 support Sasha Finkelstein
  2026-11-08 15:43 ` [PATCH 1/4] dt-bindings: phy: atcphy: Add M3 series Sasha Finkelstein
@ 2026-11-08 15:43 ` Sasha Finkelstein
  2026-11-08 15:48   ` Sven Peter
  2026-11-08 15:43 ` [PATCH 3/4] phy: apple: atc: Add initial M3 series support Sasha Finkelstein
  2026-11-08 15:43 ` [PATCH 4/4] phy: apple: atc: Add T8122 DisplayPort support Sasha Finkelstein
  3 siblings, 1 reply; 10+ messages in thread
From: Sasha Finkelstein @ 2026-11-08 15:43 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Vinod Koul, Neil Armstrong,
	Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: asahi, linux-arm-kernel, linux-phy, devicetree, linux-kernel,
	Sasha Finkelstein

Make it easier to have optional tunables by tolerating NULL entries and
doing nothing when one is passed

Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
---
 drivers/soc/apple/tunable.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/soc/apple/tunable.c b/drivers/soc/apple/tunable.c
index 659323839171..e89e8f9bb455 100644
--- a/drivers/soc/apple/tunable.c
+++ b/drivers/soc/apple/tunable.c
@@ -63,6 +63,8 @@ void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable)
 {
 	size_t i;
 
+	if (!tunable)
+		return;
 	for (i = 0; i < tunable->sz; ++i) {
 		u32 val, old_val;
 

-- 
2.56.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/4] phy: apple: atc: Add initial M3 series support
  2026-11-08 15:43 [PATCH 0/4] phy: apple: atc: Add M3 support Sasha Finkelstein
  2026-11-08 15:43 ` [PATCH 1/4] dt-bindings: phy: atcphy: Add M3 series Sasha Finkelstein
  2026-11-08 15:43 ` [PATCH 2/4] soc: apple: tunable: Allow passing NULL to tunable_apply Sasha Finkelstein
@ 2026-11-08 15:43 ` Sasha Finkelstein
  2026-11-08 18:15   ` Sven Peter
  2026-11-08 18:17   ` Sven Peter
  2026-11-08 15:43 ` [PATCH 4/4] phy: apple: atc: Add T8122 DisplayPort support Sasha Finkelstein
  3 siblings, 2 replies; 10+ messages in thread
From: Sasha Finkelstein @ 2026-11-08 15:43 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Vinod Koul, Neil Armstrong,
	Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: asahi, linux-arm-kernel, linux-phy, devicetree, linux-kernel,
	Sasha Finkelstein

Adds initial support for the new t8122 phy. USB/TB only for now, DP
will fail to negotiate

Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
---
 drivers/phy/apple/atc.c | 382 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 297 insertions(+), 85 deletions(-)

diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c
index 45f1280a6faa..256a08499646 100644
--- a/drivers/phy/apple/atc.c
+++ b/drivers/phy/apple/atc.c
@@ -100,9 +100,15 @@
 #define AUSPLL_FREQ_CFG 0x2224
 #define AUSPLL_FREQ_REFCLK GENMASK(1, 0)
 
+#define AUS_COMMON_SHIM_BLK_BIAS_REG 0x0a00
+#define AUS_COMMON_SHIM_BLK_BIAS_REG_BGBIAS_OV BIT(1)
+
 #define AUS_COMMON_SHIM_BLK_VREG 0x0a04
 #define AUS_VREG_TRIM GENMASK(6, 2)
 
+#define AUS_COMMON_DIG_RCAL1 0x804
+#define AUS_COMMON_DIG_RCAL1_ALL_CODES_DONE BIT(0)
+
 #define AUS_UNK_A20 0x0a20
 #define AUS_UNK_A20_TX_CAL_CODE GENMASK(23, 20)
 
@@ -123,15 +129,23 @@
 #define CIO3PLL_DTC_VREG 0x2a20
 #define CIO3PLL_DTC_VREG_ADJUST GENMASK(16, 14)
 
+#define ATCPHY_EVT_USB2_CTL 0x0
+#define ATCPHY_EVT_USB2_CTL_EVT_EN 0x1
+#define ATCPHY_EVT_USB2_CTL_LOAD_CNT 0x8
+
 #define ACIOPHY_CFG0 0x08
+#define ACIOPHY_CFG0_COMMON_BIG BIT(0)
 #define ACIOPHY_CFG0_COMMON_BIG_OV BIT(1)
+#define ACIOPHY_CFG0_COMMON_SMALL BIT(2)
 #define ACIOPHY_CFG0_COMMON_SMALL_OV BIT(3)
+#define ACIOPHY_CFG0_COMMON_CLAMP BIT(4)
 #define ACIOPHY_CFG0_COMMON_CLAMP_OV BIT(5)
 #define ACIOPHY_CFG0_RX_SMALL_OV GENMASK(9, 8)
 #define ACIOPHY_CFG0_RX_BIG_OV GENMASK(13, 12)
 #define ACIOPHY_CFG0_RX_CLAMP_OV GENMASK(17, 16)
 
-#define ACIOPHY_CROSSBAR 0x4c
+#define ACIOPHY_CROSSBAR_T8103 0x4c
+#define ACIOPHY_CROSSBAR_T8122 0x64
 #define ACIOPHY_CROSSBAR_PROTOCOL GENMASK(4, 0)
 #define ACIOPHY_CROSSBAR_PROTOCOL_USB4 0x0
 #define ACIOPHY_CROSSBAR_PROTOCOL_USB4_SWAPPED 0x1
@@ -146,7 +160,8 @@
 #define ACIOPHY_CROSSBAR_DP_SINGLE_PMA_UNK008 0x008
 #define ACIOPHY_CROSSBAR_DP_BOTH_PMA BIT(17)
 
-#define ACIOPHY_LANE_MODE 0x48
+#define ACIOPHY_LANE_MODE_T8103 0x48
+#define ACIOPHY_LANE_MODE_T8122 0x60
 #define ACIOPHY_LANE_MODE_RX0 GENMASK(2, 0)
 #define ACIOPHY_LANE_MODE_TX0 GENMASK(5, 3)
 #define ACIOPHY_LANE_MODE_RX1 GENMASK(8, 6)
@@ -180,6 +195,24 @@ enum atcphy_lane_mode {
 #define ACIOPHY_TOP_BIST_PHY_CFG1 0xac
 #define ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN GENMASK(13, 10)
 
+#define ACIOPHY_BIST_CFG1 0x17000
+#define ACIOPHY_BIST_CFG1_CLOCK_EN BIT(0)
+#define ACIOPHY_BIST_CFG1_USB_EN BIT(2)
+
+#define ACIOPHY_BIST_CFG2 0x17004
+#define ACIOPHY_BIST_CFG2_LN0_PHY_STATUS_RE BIT(2)
+
+#define ACIOPHY_BIST_MAC_USBPHY_STATUS2 0x17080
+#define ACIOPHY_BIST_MAC_USBPHY_STATUS2_LN0_PHY_STATUS2 BIT(7)
+
+#define ACIOPHY_BIST_MAC_USBPHY_CFG_OV1 0x17088
+#define ACIOPHY_BIST_MAC_USBPHY_CFG_OV1_LN0_PIPE_RESET_N_OV 0x100000
+#define ACIOPHY_BIST_MAC_USBPHY_CFG_OV1_LN0_PWR_DOWN_OV GENMASK(26, 25)
+
+#define ACIOPHY_BIST_MAC_USBPHY_CFG_OV2 0x1708c
+#define ACIOPHY_BIST_MAC_USBPHY_CFG_OV2_LN0_RESET_N_OV 0x200
+#define ACIOPHY_BIST_MAC_USBPHY_CFG_OV2_LN0_PWR_DOWN_OV 0x20
+
 #define ACIOPHY_SLEEP_CTRL 0x1b0
 #define ACIOPHY_SLEEP_CTRL_TX_BIG_OV GENMASK(3, 2)
 #define ACIOPHY_SLEEP_CTRL_TX_SMALL_OV GENMASK(7, 6)
@@ -463,6 +496,7 @@ enum atcphy_lane_mode {
 
 /* USB2 PHY regs */
 #define USB2PHY_USBCTL 0x00
+#define USB2PHY_USBCTL_USB_MODE 0x7
 #define USB2PHY_USBCTL_RUN 2
 #define USB2PHY_USBCTL_ISOLATION 4
 
@@ -483,6 +517,11 @@ enum atcphy_lane_mode {
 #define USB2PHY_MISCTUNE_APBCLK_GATE_OFF BIT(29)
 #define USB2PHY_MISCTUNE_REFCLK_GATE_OFF BIT(30)
 
+enum atcphy_generation {
+	ATCPHY_GENERATION_T8103,
+	ATCPHY_GENERATION_T8122,
+};
+
 enum atcphy_dp_link_rate {
 	ATCPHY_DP_LINK_RATE_RBR,
 	ATCPHY_DP_LINK_RATE_HBR,
@@ -556,6 +595,15 @@ struct atcphy_mode_configuration {
 	bool set_swap;
 };
 
+struct apple_atcphy;
+
+struct atcphy_hw {
+	void (*configure_post_tunable)(struct apple_atcphy *atcphy, enum atcphy_mode mode);
+	enum atcphy_generation gen;
+	int aciophy_lane_mode;
+	int aciophy_crossbar;
+};
+
 /**
  * struct apple_atcphy - Apple Type-C PHY device struct
  * @np: Device node pointer
@@ -599,9 +647,10 @@ struct apple_atcphy {
 		struct apple_tunable *lane_usb4[2];
 	} tunables;
 
+	const struct atcphy_hw *hw;
 	enum atcphy_mode mode;
-	bool swap_lanes;
 	int dp_link_rate;
+	bool swap_lanes;
 	bool pipehandler_up;
 
 	struct {
@@ -983,11 +1032,141 @@ static void atcphy_pipehandler_set_mux(struct apple_atcphy *atcphy, u32 data, u3
 	udelay(10);
 }
 
-static int atcphy_configure_pipehandler_usb3(struct apple_atcphy *atcphy, bool host)
+static void atcphy_clear_nonselected_phy_reset(struct apple_atcphy *atcphy)
+{
+	/* Clear reset for non-selected USB3 PHY (?) */
+	mask32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+	       PIPEHANDLER_NATIVE_POWER_DOWN, FIELD_PREP(PIPEHANDLER_NATIVE_POWER_DOWN, 3));
+	clear32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
+		PIPEHANDLER_NATIVE_RESET);
+}
+
+static void atcphy_configure_pipehandler_usb3_host_t8122(struct apple_atcphy *atcphy)
 {
 	int ret;
 	u32 reg;
 
+	core_set32(atcphy, ACIOPHY_BIST_CFG1, ACIOPHY_BIST_CFG1_CLOCK_EN);
+	/* This should be a mask, but unsure what bits should be cleared */
+	writel(ACIOPHY_BIST_MAC_USBPHY_CFG_OV1_LN0_PIPE_RESET_N_OV |
+	       FIELD_PREP(ACIOPHY_BIST_MAC_USBPHY_CFG_OV1_LN0_PWR_DOWN_OV, 2),
+	       atcphy->regs.core + ACIOPHY_BIST_MAC_USBPHY_CFG_OV1);
+	/* This should be a mask, but unsure what bits should be cleared */
+	writel(ACIOPHY_BIST_MAC_USBPHY_CFG_OV2_LN0_RESET_N_OV |
+	       ACIOPHY_BIST_MAC_USBPHY_CFG_OV2_LN0_PWR_DOWN_OV,
+	       atcphy->regs.core + ACIOPHY_BIST_MAC_USBPHY_CFG_OV2);
+	core_set32(atcphy, ACIOPHY_BIST_CFG1, ACIOPHY_BIST_CFG1_USB_EN);
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_BIST_CFG1, reg,
+				 (reg & ACIOPHY_BIST_CFG1_USB_EN), 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev,
+			 "Timed out waiting for ACIOPHY_BIST_CFG1_USB_EN\n");
+	core_clear32(atcphy, ACIOPHY_BIST_CFG1, ACIOPHY_BIST_CFG1_USB_EN);
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_BIST_MAC_USBPHY_STATUS2, reg,
+				 !(reg & ACIOPHY_BIST_MAC_USBPHY_STATUS2_LN0_PHY_STATUS2),
+				 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev,
+			 "Timed out waiting for ACIOPHY_BIST_MAC_USBPHY_STATUS2_LN0_PHY_STATUS2\n");
+
+	core_set32(atcphy, ACIOPHY_BIST_CFG2, ACIOPHY_BIST_CFG2_LN0_PHY_STATUS_RE);
+	udelay(10);
+	core_clear32(atcphy, ACIOPHY_BIST_CFG2, ACIOPHY_BIST_CFG2_LN0_PHY_STATUS_RE);
+	core_mask32(atcphy, ACIOPHY_BIST_MAC_USBPHY_CFG_OV1,
+		    ACIOPHY_BIST_MAC_USBPHY_CFG_OV1_LN0_PWR_DOWN_OV,
+		    FIELD_PREP(ACIOPHY_BIST_MAC_USBPHY_CFG_OV1_LN0_PWR_DOWN_OV, 3));
+
+	/* there is a read and write of ACIOPHY_BIST_MAC_USBPHY_CFG_OV2 here with same values */
+	udelay(10);
+	core_set32(atcphy, ACIOPHY_BIST_CFG1, ACIOPHY_BIST_CFG1_USB_EN);
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_BIST_CFG1, reg,
+				 (reg & ACIOPHY_BIST_CFG1_USB_EN), 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev,
+			 "Timed out waiting for ACIOPHY_BIST_CFG1_USB_EN 2nd toggle\n");
+	core_clear32(atcphy, ACIOPHY_BIST_CFG1, ACIOPHY_BIST_CFG1_USB_EN);
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_BIST_MAC_USBPHY_STATUS2, reg,
+				 !(reg & ACIOPHY_BIST_MAC_USBPHY_STATUS2_LN0_PHY_STATUS2),
+				 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev,
+			 "Timed out waiting for ACIOPHY_BIST_MAC_USBPHY_STATUS2_LN0_PHY_STATUS2 2nd time\n");
+	core_set32(atcphy, ACIOPHY_BIST_CFG2, ACIOPHY_BIST_CFG2_LN0_PHY_STATUS_RE);
+	udelay(10);
+	core_clear32(atcphy, ACIOPHY_BIST_CFG2, ACIOPHY_BIST_CFG2_LN0_PHY_STATUS_RE);
+
+	atcphy_clear_nonselected_phy_reset(atcphy);
+
+	core_clear32(atcphy, ACIOPHY_BIST_MAC_USBPHY_CFG_OV2,
+		     ACIOPHY_BIST_MAC_USBPHY_CFG_OV2_LN0_RESET_N_OV |
+		     ACIOPHY_BIST_MAC_USBPHY_CFG_OV2_LN0_PWR_DOWN_OV);
+	core_set32(atcphy, ACIOPHY_BIST_CFG1, ACIOPHY_BIST_CFG1_USB_EN);
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_BIST_CFG1, reg,
+				 (reg & ACIOPHY_BIST_CFG1_USB_EN), 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev,
+			 "Timed out waiting for ACIOPHY_BIST_CFG1_USB_EN 3rd toggle\n");
+	core_clear32(atcphy, ACIOPHY_BIST_CFG1, ACIOPHY_BIST_CFG1_USB_EN);
+	core_clear32(atcphy, ACIOPHY_BIST_CFG1, ACIOPHY_BIST_CFG1_CLOCK_EN);
+}
+
+static void atcphy_configure_pipehandler_usb3_host_t8103(struct apple_atcphy *atcphy)
+{
+	int ret;
+	u32 reg;
+
+	core_set32(atcphy, ACIOPHY_TOP_BIST_PHY_CFG0,
+		   ACIOPHY_TOP_BIST_PHY_CFG0_LN0_RESET_N);
+	core_set32(atcphy, ACIOPHY_TOP_BIST_OV_CFG, ACIOPHY_TOP_BIST_OV_CFG_LN0_RESET_N_OV);
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+				 !(reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK23), 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev,
+			 "Timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK23\n");
+
+	core_set32(atcphy, ACIOPHY_TOP_BIST_READ_CTRL,
+		   ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE);
+	core_clear32(atcphy, ACIOPHY_TOP_BIST_READ_CTRL,
+		     ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE);
+
+	core_mask32(atcphy, ACIOPHY_TOP_BIST_PHY_CFG1,
+		    ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN,
+		    FIELD_PREP(ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN, 3));
+
+	core_set32(atcphy, ACIOPHY_TOP_BIST_OV_CFG,
+		   ACIOPHY_TOP_BIST_OV_CFG_LN0_PWR_DOWN_OV);
+	core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+		   ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN);
+	core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+		   ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN);
+	writel(0, atcphy->regs.core + ACIOPHY_TOP_BIST_CIOPHY_CFG1);
+
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+				 (reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK0), 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev,
+			 "timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK0\n");
+
+	ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
+				 !(reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK23), 10, 10000);
+	if (ret)
+		dev_warn(atcphy->dev,
+			 "timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK23\n");
+
+	atcphy_clear_nonselected_phy_reset(atcphy);
+
+	/* More BIST stuff (?) */
+	writel(0, atcphy->regs.core + ACIOPHY_TOP_BIST_OV_CFG);
+	core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+		   ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN);
+	core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
+		   ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN);
+}
+
+static int atcphy_configure_pipehandler_usb3(struct apple_atcphy *atcphy, bool host)
+{
+	int ret;
+
 	ret = atcphy_pipehandler_check(atcphy);
 	if (ret)
 		return ret;
@@ -1012,56 +1191,10 @@ static int atcphy_configure_pipehandler_usb3(struct apple_atcphy *atcphy, bool h
 		}
 
 		/* BIST dance */
-		core_set32(atcphy, ACIOPHY_TOP_BIST_PHY_CFG0,
-			   ACIOPHY_TOP_BIST_PHY_CFG0_LN0_RESET_N);
-		core_set32(atcphy, ACIOPHY_TOP_BIST_OV_CFG, ACIOPHY_TOP_BIST_OV_CFG_LN0_RESET_N_OV);
-		ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
-					 !(reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK23), 10, 10000);
-		if (ret)
-			dev_warn(atcphy->dev,
-				 "Timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK23\n");
-
-		core_set32(atcphy, ACIOPHY_TOP_BIST_READ_CTRL,
-			   ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE);
-		core_clear32(atcphy, ACIOPHY_TOP_BIST_READ_CTRL,
-			     ACIOPHY_TOP_BIST_READ_CTRL_LN0_PHY_STATUS_RE);
-
-		core_mask32(atcphy, ACIOPHY_TOP_BIST_PHY_CFG1,
-			    ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN,
-			    FIELD_PREP(ACIOPHY_TOP_BIST_PHY_CFG1_LN0_PWR_DOWN, 3));
-
-		core_set32(atcphy, ACIOPHY_TOP_BIST_OV_CFG,
-			   ACIOPHY_TOP_BIST_OV_CFG_LN0_PWR_DOWN_OV);
-		core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
-			   ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN);
-		core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
-			   ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN);
-		writel(0, atcphy->regs.core + ACIOPHY_TOP_BIST_CIOPHY_CFG1);
-
-		ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
-					 (reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK0), 10, 10000);
-		if (ret)
-			dev_warn(atcphy->dev,
-				 "timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK0\n");
-
-		ret = readl_poll_timeout(atcphy->regs.core + ACIOPHY_TOP_PHY_STAT, reg,
-					 !(reg & ACIOPHY_TOP_PHY_STAT_LN0_UNK23), 10, 10000);
-		if (ret)
-			dev_warn(atcphy->dev,
-				 "timed out waiting for ACIOPHY_TOP_PHY_STAT_LN0_UNK23\n");
-
-		/* Clear reset for non-selected USB3 PHY (?) */
-		mask32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
-		       PIPEHANDLER_NATIVE_POWER_DOWN, FIELD_PREP(PIPEHANDLER_NATIVE_POWER_DOWN, 3));
-		clear32(atcphy->regs.pipehandler + PIPEHANDLER_NONSELECTED_OVERRIDE,
-			PIPEHANDLER_NATIVE_RESET);
-
-		/* More BIST stuff (?) */
-		writel(0, atcphy->regs.core + ACIOPHY_TOP_BIST_OV_CFG);
-		core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
-			   ACIOPHY_TOP_BIST_CIOPHY_CFG1_CLK_EN);
-		core_set32(atcphy, ACIOPHY_TOP_BIST_CIOPHY_CFG1,
-			   ACIOPHY_TOP_BIST_CIOPHY_CFG1_BIST_EN);
+		if (atcphy->hw->gen == ATCPHY_GENERATION_T8103)
+			atcphy_configure_pipehandler_usb3_host_t8103(atcphy);
+		else
+			atcphy_configure_pipehandler_usb3_host_t8122(atcphy);
 	}
 
 	/* Configure PIPE mux to USB3 PHY */
@@ -1187,15 +1320,15 @@ static void atcphy_configure_lanes(struct apple_atcphy *atcphy, enum atcphy_mode
 {
 	const struct atcphy_mode_configuration *mode_cfg = atcphy_get_mode_config(atcphy, mode);
 
-	core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_RX0,
+	core_mask32(atcphy, atcphy->hw->aciophy_lane_mode, ACIOPHY_LANE_MODE_RX0,
 		    FIELD_PREP(ACIOPHY_LANE_MODE_RX0, mode_cfg->lane_mode[0]));
-	core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_TX0,
+	core_mask32(atcphy, atcphy->hw->aciophy_lane_mode, ACIOPHY_LANE_MODE_TX0,
 		    FIELD_PREP(ACIOPHY_LANE_MODE_TX0, mode_cfg->lane_mode[0]));
-	core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_RX1,
+	core_mask32(atcphy, atcphy->hw->aciophy_lane_mode, ACIOPHY_LANE_MODE_RX1,
 		    FIELD_PREP(ACIOPHY_LANE_MODE_RX1, mode_cfg->lane_mode[1]));
-	core_mask32(atcphy, ACIOPHY_LANE_MODE, ACIOPHY_LANE_MODE_TX1,
+	core_mask32(atcphy, atcphy->hw->aciophy_lane_mode, ACIOPHY_LANE_MODE_TX1,
 		    FIELD_PREP(ACIOPHY_LANE_MODE_TX1, mode_cfg->lane_mode[1]));
-	core_mask32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_PROTOCOL,
+	core_mask32(atcphy, atcphy->hw->aciophy_crossbar, ACIOPHY_CROSSBAR_PROTOCOL,
 		    FIELD_PREP(ACIOPHY_CROSSBAR_PROTOCOL, mode_cfg->crossbar));
 
 	if (mode_cfg->set_swap)
@@ -1203,12 +1336,15 @@ static void atcphy_configure_lanes(struct apple_atcphy *atcphy, enum atcphy_mode
 	else
 		core_clear32(atcphy, ATCPHY_MISC, ATCPHY_MISC_LANE_SWAP);
 
-	core_mask32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_SINGLE_PMA,
+	core_mask32(atcphy, atcphy->hw->aciophy_crossbar, ACIOPHY_CROSSBAR_DP_SINGLE_PMA,
 		    FIELD_PREP(ACIOPHY_CROSSBAR_DP_SINGLE_PMA, mode_cfg->crossbar_dp_single_pma));
 	if (mode_cfg->crossbar_dp_both_pma)
-		core_set32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_BOTH_PMA);
+		core_set32(atcphy, atcphy->hw->aciophy_crossbar, ACIOPHY_CROSSBAR_DP_BOTH_PMA);
 	else
-		core_clear32(atcphy, ACIOPHY_CROSSBAR, ACIOPHY_CROSSBAR_DP_BOTH_PMA);
+		core_clear32(atcphy, atcphy->hw->aciophy_crossbar, ACIOPHY_CROSSBAR_DP_BOTH_PMA);
+
+	if (atcphy->hw->gen == ATCPHY_GENERATION_T8122)
+		return;
 
 	if (mode_cfg->dp_lane[0]) {
 		core_set32(atcphy, LN0_AUSPMA_RX_TOP + LN_AUSPMA_RX_TOP_PMAFSM,
@@ -1639,7 +1775,8 @@ static int atcphy_dp_configure(struct apple_atcphy *atcphy, enum atcphy_dp_link_
 static void atcphy_usb2_power_off(struct apple_atcphy *atcphy)
 {
 	/* Disable the PHY, this clears USB2PHY_USBCTL_RUN */
-	writel(USB2PHY_USBCTL_ISOLATION, atcphy->regs.usb2phy + USB2PHY_USBCTL);
+	mask32(atcphy->regs.usb2phy + USB2PHY_USBCTL, USB2PHY_USBCTL_USB_MODE,
+	       USB2PHY_USBCTL_ISOLATION);
 	udelay(10);
 
 	/* Switch the PHY to low power mode */
@@ -1705,6 +1842,13 @@ static void atcphy_usb2_power_on(struct apple_atcphy *atcphy)
 	udelay(10);
 	clear32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_PORT_RESET);
 	udelay(10);
+
+	if (atcphy->hw->gen == ATCPHY_GENERATION_T8122) {
+		core_set32(atcphy, ATCPHY_EVT_USB2_CTL, ATCPHY_EVT_USB2_CTL_LOAD_CNT |
+			ATCPHY_EVT_USB2_CTL_EVT_EN);
+		udelay(10);
+	}
+
 	set32(atcphy->regs.usb2phy + USB2PHY_CTL, USB2PHY_CTL_APB_RESET_N);
 	udelay(10);
 	clear32(atcphy->regs.usb2phy + USB2PHY_MISCTUNE, USB2PHY_MISCTUNE_APBCLK_GATE_OFF);
@@ -1745,24 +1889,8 @@ static int atcphy_power_on(struct apple_atcphy *atcphy)
 	return 0;
 }
 
-static int atcphy_configure(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+static void atcphy_configure_post_tunable_t8103(struct apple_atcphy *atcphy, enum atcphy_mode _mode)
 {
-	int ret = 0;
-
-	lockdep_assert_held(&atcphy->lock);
-
-	if (mode == APPLE_ATCPHY_MODE_OFF) {
-		ret = atcphy_power_off(atcphy);
-		atcphy->mode = mode;
-		return ret;
-	}
-
-	ret = atcphy_power_on(atcphy);
-	if (ret)
-		return ret;
-
-	atcphy_apply_tunables(atcphy, mode);
-
 	core_set32(atcphy, AUSPLL_FSM_CTRL, 0x1fe000);
 	core_set32(atcphy, AUSPLL_APB_CMD_OVERRIDE, AUSPLL_APB_CMD_OVERRIDE_UNK28);
 
@@ -1792,18 +1920,76 @@ static int atcphy_configure(struct apple_atcphy *atcphy, enum atcphy_mode mode)
 	mask32(atcphy->regs.core + ACIOPHY_CFG0, ACIOPHY_CFG0_RX_CLAMP_OV,
 	       FIELD_PREP(ACIOPHY_CFG0_RX_CLAMP_OV, 3));
 	udelay(10);
+}
+
+static void atcphy_configure_post_tunable_t8122(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+	if (atcphy_modes[mode].pipehandler_state != ATCPHY_PIPEHANDLER_STATE_USB3)
+		return;
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_SMALL);
+	udelay(10);
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_SMALL_OV);
+	udelay(10);
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_BIG);
+	udelay(10);
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_BIG_OV);
+	udelay(10);
+	core_clear32(atcphy, ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_CLAMP);
+	udelay(10);
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_CLAMP_OV);
+	udelay(10);
+	core_set32(atcphy, AUS_COMMON_SHIM_BLK_BIAS_REG, AUS_COMMON_SHIM_BLK_BIAS_REG_BGBIAS_OV);
+	udelay(10);
+}
+
+static int atcphy_configure(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+	int ret = 0;
+	u32 reg;
+
+	lockdep_assert_held(&atcphy->lock);
+
+	if (mode == APPLE_ATCPHY_MODE_OFF) {
+		ret = atcphy_power_off(atcphy);
+		atcphy->mode = mode;
+		return ret;
+	}
+
+	ret = atcphy_power_on(atcphy);
+	if (ret)
+		return ret;
+
+	atcphy_apply_tunables(atcphy, mode);
+	atcphy->hw->configure_post_tunable(atcphy, mode);
 
 	/* Setup AUX channel if DP altmode is requested */
 	if (atcphy_modes[mode].enable_dp_aux)
 		atcphy_enable_dp_aux(atcphy);
 
 	/* Enable clocks and configure lanes */
-	core_set32(atcphy, CIO3PLL_CLK_CTRL, CIO3PLL_CLK_PCLK_EN);
-	core_set32(atcphy, CIO3PLL_CLK_CTRL, CIO3PLL_CLK_REFCLK_EN);
+	if (atcphy->hw->gen == ATCPHY_GENERATION_T8103) {
+		core_set32(atcphy, CIO3PLL_CLK_CTRL, CIO3PLL_CLK_PCLK_EN);
+		core_set32(atcphy, CIO3PLL_CLK_CTRL, CIO3PLL_CLK_REFCLK_EN);
+	}
 	atcphy_configure_lanes(atcphy, mode);
 
 	/* Take the USB3 PHY out of reset */
 	core_set32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_PHY_RESET_N);
+	/*
+	 * NOTE: Not what macos does, it takes the phy out of reset right before writing to
+	 * ACIOPHY_CFG0_COMMON_SMALL does lane configuration with phy out of reset, and the poll is
+	 * right after AUS_COMMON_SHIM_BLK_BIAS_REG write. Does not seem to matter, but if something
+	 * does not work, consider re-ordering things to macos order.
+	 */
+	if (atcphy->hw->gen == ATCPHY_GENERATION_T8122 &&
+	    atcphy_modes[mode].pipehandler_state == ATCPHY_PIPEHANDLER_STATE_USB3) {
+		ret = readl_poll_timeout(atcphy->regs.core + AUS_COMMON_DIG_RCAL1, reg,
+					 (reg & AUS_COMMON_DIG_RCAL1_ALL_CODES_DONE), 10, 100000);
+		if (ret) {
+			dev_err(atcphy->dev, "Failed to wait for RCAL1 done\n");
+			return ret;
+		}
+	}
 
 	atcphy->mode = mode;
 
@@ -2201,6 +2387,7 @@ static int atcphy_probe_mux(struct apple_atcphy *atcphy)
 
 static int atcphy_load_tunables(struct apple_atcphy *atcphy)
 {
+	size_t tunable_count;
 	struct {
 		const char *dt_name;
 		struct apple_tunable **tunable;
@@ -2216,8 +2403,14 @@ static int atcphy_load_tunables(struct apple_atcphy *atcphy)
 		{ "apple,tunable-lane0-dp", &atcphy->tunables.lane_dp[0], atcphy->res.core },
 		{ "apple,tunable-lane1-dp", &atcphy->tunables.lane_dp[1], atcphy->res.core },
 	};
-
-	for (int i = 0; i < ARRAY_SIZE(tunables); i++) {
+	if (atcphy->hw->gen == ATCPHY_GENERATION_T8122) {
+		tunable_count = ARRAY_SIZE(tunables) - 2;
+		atcphy->tunables.lane_dp[0] = NULL;
+		atcphy->tunables.lane_dp[1] = NULL;
+	} else
+		tunable_count = ARRAY_SIZE(tunables);
+
+	for (size_t i = 0; i < tunable_count; i++) {
 		*tunables[i].tunable = devm_apple_tunable_parse(
 			atcphy->dev, atcphy->np, tunables[i].dt_name, tunables[i].res);
 		if (IS_ERR(*tunables[i].tunable)) {
@@ -2301,6 +2494,10 @@ static int atcphy_probe(struct platform_device *pdev)
 	if (!atcphy)
 		return -ENOMEM;
 
+	atcphy->hw = of_device_get_match_data(&pdev->dev);
+	if (!atcphy->hw)
+		return -EINVAL;
+
 	atcphy->dev = dev;
 	atcphy->np = dev->of_node;
 	mutex_init(&atcphy->lock);
@@ -2319,8 +2516,23 @@ static int atcphy_probe(struct platform_device *pdev)
 	return atcphy_probe_finalize(atcphy);
 }
 
+static const struct atcphy_hw atcphy_hw_t8103 = {
+	.gen = ATCPHY_GENERATION_T8103,
+	.aciophy_lane_mode = ACIOPHY_LANE_MODE_T8103,
+	.aciophy_crossbar = ACIOPHY_CROSSBAR_T8103,
+	.configure_post_tunable = atcphy_configure_post_tunable_t8103,
+};
+
+static const struct atcphy_hw atcphy_hw_t8122 = {
+	.gen = ATCPHY_GENERATION_T8122,
+	.aciophy_lane_mode = ACIOPHY_LANE_MODE_T8122,
+	.aciophy_crossbar = ACIOPHY_CROSSBAR_T8122,
+	.configure_post_tunable = atcphy_configure_post_tunable_t8122,
+};
+
 static const struct of_device_id atcphy_match[] = {
-	{ .compatible = "apple,t8103-atcphy" },
+	{ .compatible = "apple,t8103-atcphy", .data = &atcphy_hw_t8103 },
+	{ .compatible = "apple,t8122-atcphy", .data = &atcphy_hw_t8122 },
 	{},
 };
 MODULE_DEVICE_TABLE(of, atcphy_match);

-- 
2.56.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 4/4] phy: apple: atc: Add T8122 DisplayPort support
  2026-11-08 15:43 [PATCH 0/4] phy: apple: atc: Add M3 support Sasha Finkelstein
                   ` (2 preceding siblings ...)
  2026-11-08 15:43 ` [PATCH 3/4] phy: apple: atc: Add initial M3 series support Sasha Finkelstein
@ 2026-11-08 15:43 ` Sasha Finkelstein
  3 siblings, 0 replies; 10+ messages in thread
From: Sasha Finkelstein @ 2026-11-08 15:43 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Vinod Koul, Neil Armstrong,
	Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: asahi, linux-arm-kernel, linux-phy, devicetree, linux-kernel,
	Sasha Finkelstein, Ramzi Abdiche

From: Ramzi Abdiche <abdicheramzi@gmail.com>

Add DisplayPort AUX and lane setup for T8122-family PHYs.
Select clock and lane settings by link rate and stop active
lanes before orientation changes.

Signed-off-by: Ramzi Abdiche <abdicheramzi@gmail.com>
Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
---
 drivers/phy/apple/atc.c | 645 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 622 insertions(+), 23 deletions(-)

diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c
index 256a08499646..068d985b62a6 100644
--- a/drivers/phy/apple/atc.c
+++ b/drivers/phy/apple/atc.c
@@ -431,6 +431,129 @@ enum atcphy_lane_mode {
 #define LN_LDOCLK_EN_BIG_OV BIT(14)
 #define LN_LDOCLK_EN_BIG BIT(15)
 
+/* T8122 DisplayPort registers; power bit names inferred from the sequences */
+#define ACIOPHY_CFG1 0x000c
+#define ACIOPHY_SLEEP_CTRL_T8122 0x010c
+#define ACIOPHY_TX_SLEEP_BIG(lane) BIT(lane)
+#define ACIOPHY_TX_SLEEP_BIG_OV(lane) BIT(2 + (lane))
+#define ACIOPHY_TX_SLEEP_SMALL(lane) BIT(4 + (lane))
+#define ACIOPHY_TX_SLEEP_SMALL_OV(lane) BIT(6 + (lane))
+#define ACIOPHY_TX_CLAMP(lane) BIT(8 + (lane))
+#define ACIOPHY_TX_CLAMP_OV(lane) BIT(10 + (lane))
+#define ACIOPHY_RXTX_SLEEP_BIG(lane) BIT(lane)
+#define ACIOPHY_RXTX_SLEEP_BIG_OV(lane) BIT(2 + (lane))
+#define ACIOPHY_RXTX_SLEEP_SMALL(lane) BIT(4 + (lane))
+#define ACIOPHY_RXTX_SLEEP_SMALL_OV(lane) BIT(6 + (lane))
+#define ACIOPHY_RX_SLEEP_BIG(lane) BIT(6 + (lane))
+#define ACIOPHY_RX_SLEEP_BIG_OV(lane) BIT(8 + (lane))
+#define ACIOPHY_RX_SLEEP_SMALL(lane) BIT(10 + (lane))
+#define ACIOPHY_RX_SLEEP_SMALL_OV(lane) BIT(12 + (lane))
+#define ACIOPHY_RX_CLAMP(lane) BIT(14 + (lane))
+#define ACIOPHY_RX_CLAMP_OV(lane) BIT(16 + (lane))
+
+#define AUSPLL_BGR_T8122 0x2218
+#define AUSPLL_FREQ_CFG_T8122 0x2234
+#define AUSPLL_CLKOUT_MASTER_PCLK_DRVR_EN_T8122 BIT(3)
+#define ACIOPHY_DP_PCLK_STAT_T8122 0x7034
+
+#define LN_AUSPMA_TX_TOP_EQ1 0x0050
+#define LN_AUSPMA_TX_TOP_EQ17 0x00d0
+#define LN_AUSPMA_TX_TOP_EQ18 0x00d4
+#define LN_AUSPMA_RX_TOP_EQ1 0x0210
+#define LN_AUSPMA_RX_TOP_EQ17 0x0244
+#define LN_AUSPMA_RX_TOP_EQ18 0x0248
+#define LN_EQ_SWING GENMASK(3, 0)
+#define LN_EQ_SWING_LSB GENMASK(15, 14)
+#define LN_EQ_SWING_OV BIT(28)
+#define LN_EQ_AUTO_CTRL_DP BIT(20)
+/* Deemphasis and override bits; individual fields unknown */
+#define LN_EQ_DEEMPH_FIELDS GENMASK(18, 0)
+
+#define LN_AUSPMA_TX_SHM_MAIN2 0x0004
+#define LN_MAIN2_BYTECLK_SYNC_SEL BIT(24)
+#define LN_MAIN2_BYTECLK_SYNC_SEL_OV BIT(25)
+#define LN_MAIN2_BYTECLK_SYNC_EN BIT(28)
+#define LN_MAIN2_BYTECLK_SYNC_EN_OV BIT(29)
+#define LN_AUSPMA_TX_SHM_MAIN4 0x000c
+#define LN_MAIN4_DIV2_4_EN GENMASK(25, 24)
+#define LN_MAIN4_DIV2_4_EN_OV BIT(26)
+#define LN_AUSPMA_TX_SHM_MAIN5 0x0010
+#define LN_MAIN5_CLK_EN BIT(9)
+#define LN_MAIN5_CLK_EN_OV BIT(10)
+#define LN_AUSPMA_TX_SHM_CLKMON1 0x001c
+#define LN_CLKMON1_HIZ BIT(22)
+#define LN_CLKMON1_HIZ_OV BIT(23)
+#define LN_AUSPMA_TX_SHM_LDOCLK1 0x0044
+#define LN_LDOCLK1_VREG_ADJ GENMASK(10, 6)
+#define LN_LDOCLK1_VREF_EN BIT(12)
+#define LN_LDOCLK1_VREF_FILTER_BOOST (GENMASK(18, 17) | GENMASK(15, 14))
+#define LN_LDOCLK1_BYPASS_SMALL BIT(20)
+#define LN_LDOCLK1_BYPASS_BIG BIT(22)
+#define LN_LDOCLK1_EN_SMALL BIT(24)
+#define LN_LDOCLK1_EN_BIG BIT(26)
+
+#define LN_AUSPMA_RX_TOP_TXMODE 0x0160
+#define LN_AUSPMA_RX_TOP_AFE1 0x01d4
+#define LN_AFE1_DIV20_RESET_N_OV BIT(0)
+#define LN_AFE1_DIV20_RESET_N BIT(1)
+#define LN_AUSPMA_RX_TOP_DCO1 0x01dc
+#define LN_DCO1_LPBKIN_RECOVERED_DATA GENMASK(16, 15)
+
+#define LN_AUSPMA_RX_SHM_CTLE2 0x0030
+#define LN_CTLE2_TX_CLK_EN BIT(10)
+#define LN_CTLE2_TX_CLK_EN_OV BIT(11)
+#define LN_AUSPMA_RX_SHM_DFE101 0x0064
+#define LN_DFE101_DFEH1FB_EN BIT(2)
+#define LN_DFE101_DFEH1FB_EN_OV BIT(3)
+#define LN_DFE101_DTVREG_ADJUST_FIELDS GENMASK(15, 10)
+#define LN_AUSPMA_RX_SHM_DFE111 0x0068
+#define LN_DFE111_DTVREG_BIG_EN BIT(5)
+#define LN_DFE111_DTVREG_BIG_EN_OV BIT(6)
+#define LN_DFE111_DTVREG_SMALL_EN BIT(7)
+#define LN_DFE111_DTVREG_SMALL_EN_OV BIT(8)
+#define LN_AUSPMA_RX_SHM_DFE121 0x006c
+#define LN_DFE121_TX_BYTECLK_SYNC_CLR BIT(9)
+#define LN_DFE121_TX_BYTECLK_SYNC_CLR_OV BIT(10)
+#define LN_DFE121_TX_BYTECLK_SYNC_EN BIT(11)
+#define LN_DFE121_TX_HRCLK_SEL BIT(13)
+#define LN_DFE121_TX_HRCLK_SEL_OV BIT(14)
+#define LN_DFE121_TX_PBIAS_EN BIT(15)
+#define LN_DFE121_TX_PBIAS_EN_OV BIT(16)
+#define LN_AUSPMA_RX_SHM_SAVOS161 0x00a4
+#define LN_SAVOS161_RXTERM_EN BIT(0)
+#define LN_SAVOS161_RXTERM_EN_OV BIT(1)
+#define LN_AUSPMA_RX_SHM_TERM191 0x00a8
+#define LN_TERM191_TX_TEST_EN BIT(15)
+#define LN_TERM191_TX_TEST_EN_OV BIT(16)
+#define LN_TERM191_TX_EN BIT(17)
+#define LN_TERM191_TX_EN_OV BIT(18)
+#define LN_TERM191_TX_DIV2_EN GENMASK(20, 19)
+#define LN_TERM191_TX_DIV2_EN_OV BIT(21)
+#define LN_TERM191_TX_DIV2_RST BIT(22)
+#define LN_TERM191_TX_DIV2_RST_OV BIT(23)
+#define LN_AUSPMA_RX_SHM_VREF221 0x00d4
+/* Adjust, filter and enable overrides; individual fields unknown */
+#define LN_VREF221_INIT_FIELDS (GENMASK(20, 16) | GENMASK(12, 7))
+#define LN_VREF221_BIAS_FIELDS GENMASK(15, 13)
+#define LN_VREF221_EN BIT(16)
+#define LN_VREF221_FILTER_ADJUST GENMASK(19, 18)
+#define LN_AUSPMA_RX_SHM_VREF231 0x00d8
+#define LN_VREF231_BOOST_CTRL GENMASK(1, 0)
+#define LN_VREF231_BOOST_CTRL_OV BIT(2)
+#define LN_AUSPMA_RX_SHM_VREG1 0x00dc
+#define LN_VREG1_DTVREG_POWER_MODE GENMASK(4, 3)
+
+/* T8122 AUX registers (core window) */
+#define AUX_TOP_CTRL 0x16000
+#define AUX_TOP_PWRDN BIT(0)
+#define AUX_SHM_PWR 0x16400
+#define AUX_SLEEP_SML_OV BIT(0)
+#define AUX_SLEEP_SML BIT(1)
+#define AUX_SLEEP_BIG_OV BIT(2)
+#define AUX_SLEEP_BIG BIT(3)
+#define AUX_CLAMP_OV BIT(8)
+#define AUX_CLAMP BIT(9)
+
 /* LPDPTX registers */
 #define LPDPTX_AUX_CFG_BLK_AUX_CTRL 0x0000
 #define LPDPTX_BLK_AUX_CTRL_PWRDN BIT(4)
@@ -529,6 +652,9 @@ enum atcphy_dp_link_rate {
 	ATCPHY_DP_LINK_RATE_HBR3,
 };
 
+#define ATCPHY_DP_LINK_RATE_IDLE		(-1)
+#define ATCPHY_DP_LINK_RATE_PENDING	(-2)
+
 /**
  * enum atcphy_pipehandler_state - States of the PIPE mux interface ("pipehandler")
  * @ATCPHY_PIPEHANDLER_STATE_DUMMY: "Dummy PHY" (disables USB3, USB2 only)
@@ -597,8 +723,16 @@ struct atcphy_mode_configuration {
 
 struct apple_atcphy;
 
+struct atcphy_dp_ops {
+	void (*enable_aux)(struct apple_atcphy *atcphy);
+	void (*disable_aux)(struct apple_atcphy *atcphy);
+	int (*set_rate)(struct apple_atcphy *atcphy, enum atcphy_dp_link_rate lr);
+	int (*stop)(struct apple_atcphy *atcphy);
+};
+
 struct atcphy_hw {
 	void (*configure_post_tunable)(struct apple_atcphy *atcphy, enum atcphy_mode mode);
+	const struct atcphy_dp_ops *dp;
 	enum atcphy_generation gen;
 	int aciophy_lane_mode;
 	int aciophy_crossbar;
@@ -616,7 +750,8 @@ struct atcphy_hw {
  * @tunables.lane_usb4: USB4 lane-specific tunables
  * @mode: Current PHY operating mode
  * @swap_lanes: True if lanes must be swapped due to cable orientation
- * @dp_link_rate: DisplayPort link rate
+ * @dp_link_rate: DisplayPort link rate index, ATCPHY_DP_LINK_RATE_IDLE, or
+ *               ATCPHY_DP_LINK_RATE_PENDING when cleanup is still needed
  * @pipehandler_up: True if the PIPE mux ("pipehandler") is set to USB3 or USB4 mode
  * @regs: Memory-mapped registers
  * @regs.core: Core registers
@@ -878,6 +1013,28 @@ static const struct atcphy_dp_link_rate_configuration dp_lr_config[] = {
 	},
 };
 
+static const struct {
+	u8 vclk_op_divn;
+	bool vclk_pre_divn;
+} dp_lr_config_t8122[] = {
+	[ATCPHY_DP_LINK_RATE_RBR] = {
+		.vclk_op_divn = 1,
+		.vclk_pre_divn = false,
+	},
+	[ATCPHY_DP_LINK_RATE_HBR] = {
+		.vclk_op_divn = 1,
+		.vclk_pre_divn = false,
+	},
+	[ATCPHY_DP_LINK_RATE_HBR2] = {
+		.vclk_op_divn = 1,
+		.vclk_pre_divn = true,
+	},
+	[ATCPHY_DP_LINK_RATE_HBR3] = {
+		.vclk_op_divn = 1,
+		.vclk_pre_divn = true,
+	},
+};
+
 static inline void mask32(void __iomem *reg, u32 mask, u32 set)
 {
 	u32 value = readl(reg);
@@ -912,6 +1069,12 @@ static inline void core_clear32(struct apple_atcphy *atcphy, u32 reg, u32 clear)
 	core_mask32(atcphy, reg, clear, 0);
 }
 
+static void __iomem *atcphy_lane_reg(struct apple_atcphy *atcphy,
+				  unsigned int lane, u32 lane0_reg)
+{
+	return atcphy->regs.core + lane0_reg + lane * (LN1_AUSPMA_RX_TOP - LN0_AUSPMA_RX_TOP);
+}
+
 static const struct atcphy_mode_configuration *atcphy_get_mode_config(struct apple_atcphy *atcphy,
 								      enum atcphy_mode mode)
 {
@@ -1371,6 +1534,390 @@ static void atcphy_configure_lanes(struct apple_atcphy *atcphy, enum atcphy_mode
 	}
 }
 
+static int atcphy_dp_poll(struct apple_atcphy *atcphy, u32 reg, u32 mask, u32 expected)
+{
+	u32 value;
+	int ret;
+
+	lockdep_assert_held(&atcphy->lock);
+	ret = readl_poll_timeout_atomic(atcphy->regs.core + reg, value,
+					(value & mask) == expected, 1, 1000);
+	if (ret)
+		dev_err(atcphy->dev, "DP timeout reg=%#x mask=%#x want=%#x got=%#x\n",
+			reg, mask, expected, value);
+	return ret;
+}
+
+static int atcphy_auspll_set_command(struct apple_atcphy *atcphy, u32 command, bool request)
+{
+	core_mask32(atcphy, AUSPLL_APB_CMD_OVERRIDE,
+		    AUSPLL_APB_CMD_OVERRIDE_REQ | AUSPLL_APB_CMD_OVERRIDE_CMD |
+		    AUSPLL_APB_CMD_OVERRIDE_UNK28,
+		    FIELD_PREP(AUSPLL_APB_CMD_OVERRIDE_CMD, command) |
+		    AUSPLL_APB_CMD_OVERRIDE_UNK28 | (request ? AUSPLL_APB_CMD_OVERRIDE_REQ : 0));
+	return atcphy_dp_poll(atcphy, AUSPLL_APB_CMD_OVERRIDE, AUSPLL_APB_CMD_OVERRIDE_ACK,
+			     request ? AUSPLL_APB_CMD_OVERRIDE_ACK : 0);
+}
+
+static int atcphy_dp_start_pll_t8122(struct apple_atcphy *atcphy,
+				  enum atcphy_dp_link_rate lr)
+{
+	const struct atcphy_dp_link_rate_configuration *cfg = &dp_lr_config[lr];
+	int ret;
+
+	core_clear32(atcphy, AUSPLL_FREQ_CFG_T8122, AUSPLL_FREQ_REFCLK);
+	core_mask32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0,
+		    DPTX_PCLK1_SELECT | DPTX_PCLK2_SELECT | DPRX_PCLK_SELECT,
+		    FIELD_PREP(DPTX_PCLK1_SELECT, 1) | FIELD_PREP(DPTX_PCLK2_SELECT, 1) |
+		    FIELD_PREP(DPRX_PCLK_SELECT, 1));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_A, U32_MAX,
+		    FIELD_PREP(AUSPLL_FD_FREQ_COUNT_TARGET, cfg->freqinit_count_target) |
+		    FIELD_PREP(AUSPLL_FD_KI_MAN, 8) | FIELD_PREP(AUSPLL_FD_KI_EXP, 3) |
+		    FIELD_PREP(AUSPLL_FD_KP_MAN, 8) | FIELD_PREP(AUSPLL_FD_KP_EXP, 7));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_B, U32_MAX,
+		    FIELD_PREP(AUSPLL_FD_FBDIVN_FRAC_DEN, cfg->fbdivn_frac_den) |
+		    FIELD_PREP(AUSPLL_FD_FBDIVN_FRAC_NUM, cfg->fbdivn_frac_num));
+	core_mask32(atcphy, AUSPLL_FREQ_DESC_C, U32_MAX,
+		    FIELD_PREP(AUSPLL_FD_PCLK_DIV_SEL, cfg->pclk_div_sel) |
+		    FIELD_PREP(AUSPLL_FD_LFSDM_DIV, 1) |
+		    FIELD_PREP(AUSPLL_FD_LFCLK_CTRL, cfg->lfclk_ctrl) |
+		    FIELD_PREP(AUSPLL_FD_VCLK_OP_DIVN, dp_lr_config_t8122[lr].vclk_op_divn) |
+		    (dp_lr_config_t8122[lr].vclk_pre_divn ? AUSPLL_FD_VCLK_PRE_DIVN : 0));
+	core_mask32(atcphy, AUSPLL_CLKOUT_DIV, AUSPLL_CLKOUT_PLLA_REFBUFCLK_DI,
+		    FIELD_PREP(AUSPLL_CLKOUT_PLLA_REFBUFCLK_DI, 7));
+	core_set32(atcphy, AUSPLL_BGR_T8122, AUSPLL_BGR_CTRL_AVAIL);
+	core_set32(atcphy, AUSPLL_CLKOUT_MASTER, AUSPLL_CLKOUT_MASTER_PCLK_DRVR_EN_T8122);
+	ret = atcphy_auspll_set_command(atcphy, 0, true);
+	if (ret)
+		return ret;
+	ret = atcphy_dp_poll(atcphy, ACIOPHY_DP_PCLK_STAT_T8122, ACIOPHY_AUSPLL_LOCK,
+			     ACIOPHY_AUSPLL_LOCK);
+	if (ret)
+		return ret;
+	return atcphy_auspll_set_command(atcphy, 0x2800, false);
+}
+
+static void atcphy_dp_power_on_tx_t8122(struct apple_atcphy *atcphy, unsigned int lane)
+{
+	core_set32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_SLEEP_SMALL(lane));
+	core_set32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_SLEEP_SMALL_OV(lane));
+	udelay(1);
+	core_set32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_SLEEP_BIG(lane));
+	core_set32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_SLEEP_BIG_OV(lane));
+	udelay(1);
+	core_clear32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_CLAMP(lane));
+	core_set32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_CLAMP_OV(lane));
+	udelay(1);
+}
+
+static void atcphy_dp_power_on_rxtx_t8122(struct apple_atcphy *atcphy, unsigned int lane)
+{
+	core_set32(atcphy, ACIOPHY_CFG1, ACIOPHY_RXTX_SLEEP_SMALL(lane));
+	core_set32(atcphy, ACIOPHY_CFG1, ACIOPHY_RXTX_SLEEP_SMALL_OV(lane));
+	udelay(1);
+	core_set32(atcphy, ACIOPHY_CFG1, ACIOPHY_RXTX_SLEEP_BIG(lane));
+	core_set32(atcphy, ACIOPHY_CFG1, ACIOPHY_RXTX_SLEEP_BIG_OV(lane));
+	udelay(1);
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_SLEEP_SMALL(lane));
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_SLEEP_SMALL_OV(lane));
+	udelay(1);
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_SLEEP_BIG(lane));
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_SLEEP_BIG_OV(lane));
+	udelay(1);
+	core_clear32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_CLAMP(lane));
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_CLAMP_OV(lane));
+	udelay(1);
+}
+
+static void atcphy_dp_configure_tx_t8122(struct apple_atcphy *atcphy, unsigned int lane,
+					 const struct atcphy_dp_link_rate_configuration *cfg)
+{
+	void __iomem *shm = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_TX_SHM);
+	void __iomem *top = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_TX_TOP);
+
+	atcphy_dp_power_on_tx_t8122(atcphy, lane);
+	/* Fixed LDO initialization value, not a calibration tunable. */
+	mask32(shm + LN_AUSPMA_TX_SHM_LDOCLK1, U32_MAX, 0x0aafb800);
+	udelay(1);
+	set32(shm + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_EN_SMALL);
+	udelay(1);
+	set32(shm + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_EN_BIG);
+	udelay(1);
+	mask32(shm + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_VREG_ADJ,
+	       FIELD_PREP(LN_LDOCLK1_VREG_ADJ, 12));
+	udelay(1);
+	clear32(shm + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_VREF_FILTER_BOOST);
+	udelay(1);
+	set32(top + LN_AUSPMA_TX_TOP_EQ17, LN_EQ_AUTO_CTRL_DP);
+	clear32(top + LN_AUSPMA_TX_TOP_EQ1, LN_EQ_SWING | LN_EQ_SWING_LSB);
+	set32(top + LN_AUSPMA_TX_TOP_EQ18, LN_EQ_SWING_OV);
+	mask32(top + LN_AUSPMA_TX_TOP_EQ17, LN_EQ_DEEMPH_FIELDS, 1);
+	if (cfg->txa_ldoclk_bypass) {
+		set32(shm + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_BYPASS_SMALL);
+		udelay(1);
+		set32(shm + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_BYPASS_BIG);
+		udelay(1);
+	}
+	mask32(shm + LN_AUSPMA_TX_SHM_MAIN2,
+	       LN_MAIN2_BYTECLK_SYNC_SEL | LN_MAIN2_BYTECLK_SYNC_SEL_OV,
+	       LN_MAIN2_BYTECLK_SYNC_SEL_OV);
+	set32(shm + LN_AUSPMA_TX_SHM_MAIN2, LN_MAIN2_BYTECLK_SYNC_EN | LN_MAIN2_BYTECLK_SYNC_EN_OV);
+	mask32(shm + LN_AUSPMA_TX_SHM_MAIN4, LN_MAIN4_DIV2_4_EN | LN_MAIN4_DIV2_4_EN_OV,
+	       FIELD_PREP(LN_MAIN4_DIV2_4_EN, cfg->txa_div2_en) | LN_MAIN4_DIV2_4_EN_OV);
+	set32(shm + LN_AUSPMA_TX_SHM_MAIN5, LN_MAIN5_CLK_EN | LN_MAIN5_CLK_EN_OV);
+	mask32(shm + LN_AUSPMA_TX_SHM_CLKMON1, LN_CLKMON1_HIZ | LN_CLKMON1_HIZ_OV,
+	       LN_CLKMON1_HIZ_OV);
+}
+
+static void atcphy_dp_configure_rxtx_t8122(struct apple_atcphy *atcphy, unsigned int lane,
+					   const struct atcphy_dp_link_rate_configuration *cfg)
+{
+	void __iomem *shm = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_RX_SHM);
+	void __iomem *top = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_RX_TOP);
+
+	set32(top + LN_AUSPMA_RX_TOP_TXMODE, LN_RX_TXMODE);
+	set32(top + LN_AUSPMA_RX_TOP_DCO1, LN_DCO1_LPBKIN_RECOVERED_DATA);
+	mask32(shm + LN_AUSPMA_RX_SHM_SAVOS161, LN_SAVOS161_RXTERM_EN | LN_SAVOS161_RXTERM_EN_OV,
+	       LN_SAVOS161_RXTERM_EN_OV);
+	mask32(shm + LN_AUSPMA_RX_SHM_TERM191, LN_TERM191_TX_TEST_EN | LN_TERM191_TX_TEST_EN_OV,
+	       LN_TERM191_TX_TEST_EN_OV);
+	mask32(shm + LN_AUSPMA_RX_SHM_DFE121, LN_DFE121_TX_PBIAS_EN | LN_DFE121_TX_PBIAS_EN_OV,
+	       LN_DFE121_TX_PBIAS_EN_OV);
+	mask32(shm + LN_AUSPMA_RX_SHM_VREF221, LN_VREF221_INIT_FIELDS, 0x121180);
+	mask32(shm + LN_AUSPMA_RX_SHM_DFE101, LN_DFE101_DTVREG_ADJUST_FIELDS, 0xb800);
+	mask32(shm + LN_AUSPMA_RX_SHM_VREF231,
+	       LN_VREF231_BOOST_CTRL | LN_VREF231_BOOST_CTRL_OV,
+	       LN_VREF231_BOOST_CTRL_OV);
+	clear32(shm + LN_AUSPMA_RX_SHM_VREG1, LN_VREG1_DTVREG_POWER_MODE);
+	mask32(shm + LN_AUSPMA_RX_SHM_VREF221, LN_VREF221_BIAS_FIELDS, 0xc000);
+	udelay(1);
+	atcphy_dp_power_on_rxtx_t8122(atcphy, lane);
+	set32(shm + LN_AUSPMA_RX_SHM_DFE121, LN_DFE121_TX_BYTECLK_SYNC_EN);
+	mask32(top + LN_AUSPMA_RX_TOP_AFE1, LN_AFE1_DIV20_RESET_N | LN_AFE1_DIV20_RESET_N_OV,
+	       LN_AFE1_DIV20_RESET_N_OV);
+	udelay(1);
+	set32(top + LN_AUSPMA_RX_TOP_AFE1, LN_AFE1_DIV20_RESET_N);
+	mask32(shm + LN_AUSPMA_RX_SHM_DFE121,
+	       LN_DFE121_TX_BYTECLK_SYNC_CLR | LN_DFE121_TX_BYTECLK_SYNC_CLR_OV,
+	       LN_DFE121_TX_BYTECLK_SYNC_CLR_OV);
+	udelay(1);
+	mask32(shm + LN_AUSPMA_RX_SHM_VREF221, LN_VREF221_EN | LN_VREF221_FILTER_ADJUST,
+	       LN_VREF221_EN | FIELD_PREP(LN_VREF221_FILTER_ADJUST, 1));
+	mask32(shm + LN_AUSPMA_RX_SHM_VREF231, LN_VREF231_BOOST_CTRL,
+	       FIELD_PREP(LN_VREF231_BOOST_CTRL, 1));
+	udelay(1);
+	clear32(shm + LN_AUSPMA_RX_SHM_VREF221, LN_VREF221_FILTER_ADJUST);
+	udelay(1);
+	set32(shm + LN_AUSPMA_RX_SHM_DFE111,
+	      LN_DFE111_DTVREG_SMALL_EN | LN_DFE111_DTVREG_SMALL_EN_OV);
+	udelay(1);
+	set32(shm + LN_AUSPMA_RX_SHM_DFE111, LN_DFE111_DTVREG_BIG_EN | LN_DFE111_DTVREG_BIG_EN_OV);
+	udelay(1);
+	mask32(shm + LN_AUSPMA_RX_SHM_VREF231, LN_VREF231_BOOST_CTRL,
+	       FIELD_PREP(LN_VREF231_BOOST_CTRL, 3));
+	udelay(1);
+	mask32(shm + LN_AUSPMA_RX_SHM_VREF231, LN_VREF231_BOOST_CTRL,
+	       FIELD_PREP(LN_VREF231_BOOST_CTRL, 2));
+	udelay(1);
+	clear32(shm + LN_AUSPMA_RX_SHM_VREF231, LN_VREF231_BOOST_CTRL);
+	udelay(1);
+	set32(shm + LN_AUSPMA_RX_SHM_TERM191, LN_TERM191_TX_EN | LN_TERM191_TX_EN_OV);
+	udelay(1);
+	mask32(shm + LN_AUSPMA_RX_SHM_DFE121, LN_DFE121_TX_HRCLK_SEL | LN_DFE121_TX_HRCLK_SEL_OV,
+	       LN_DFE121_TX_HRCLK_SEL_OV);
+	clear32(top + LN_AUSPMA_RX_TOP_EQ1, LN_EQ_SWING | LN_EQ_SWING_LSB);
+	set32(top + LN_AUSPMA_RX_TOP_EQ18, LN_EQ_SWING_OV);
+	mask32(top + LN_AUSPMA_RX_TOP_EQ17, LN_EQ_DEEMPH_FIELDS, 0x1f81);
+	mask32(shm + LN_AUSPMA_RX_SHM_TERM191, LN_TERM191_TX_DIV2_EN | LN_TERM191_TX_DIV2_EN_OV,
+	       FIELD_PREP(LN_TERM191_TX_DIV2_EN, cfg->txa_div2_en) | LN_TERM191_TX_DIV2_EN_OV);
+	mask32(shm + LN_AUSPMA_RX_SHM_TERM191, LN_TERM191_TX_DIV2_RST | LN_TERM191_TX_DIV2_RST_OV,
+	       LN_TERM191_TX_DIV2_RST_OV);
+	udelay(1);
+	set32(shm + LN_AUSPMA_RX_SHM_CTLE2, LN_CTLE2_TX_CLK_EN | LN_CTLE2_TX_CLK_EN_OV);
+	udelay(1);
+}
+
+static void atcphy_dp_stop_lane_t8122(struct apple_atcphy *atcphy, unsigned int lane)
+{
+	void __iomem *tx = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_TX_SHM);
+	void __iomem *rx = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_RX_SHM);
+	void __iomem *top = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_RX_TOP);
+
+	set32(tx + LN_AUSPMA_TX_SHM_CLKMON1, LN_CLKMON1_HIZ | LN_CLKMON1_HIZ_OV);
+	mask32(tx + LN_AUSPMA_TX_SHM_MAIN5, LN_MAIN5_CLK_EN | LN_MAIN5_CLK_EN_OV,
+	       LN_MAIN5_CLK_EN_OV);
+	mask32(tx + LN_AUSPMA_TX_SHM_MAIN2, LN_MAIN2_BYTECLK_SYNC_EN | LN_MAIN2_BYTECLK_SYNC_EN_OV,
+	       LN_MAIN2_BYTECLK_SYNC_EN_OV);
+	udelay(1);
+	clear32(tx + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_BYPASS_SMALL);
+	udelay(1);
+	clear32(tx + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_BYPASS_BIG);
+	udelay(1);
+	clear32(tx + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_EN_BIG);
+	udelay(1);
+	clear32(tx + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_EN_SMALL);
+	udelay(1);
+	clear32(tx + LN_AUSPMA_TX_SHM_LDOCLK1, LN_LDOCLK1_VREF_EN);
+	core_set32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_CLAMP(lane));
+	udelay(1);
+	core_clear32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_SLEEP_BIG(lane));
+	udelay(1);
+	core_clear32(atcphy, ACIOPHY_SLEEP_CTRL_T8122, ACIOPHY_TX_SLEEP_SMALL(lane));
+	udelay(1);
+
+	mask32(rx + LN_AUSPMA_RX_SHM_CTLE2, LN_CTLE2_TX_CLK_EN | LN_CTLE2_TX_CLK_EN_OV,
+	       LN_CTLE2_TX_CLK_EN_OV);
+	udelay(1);
+	set32(rx + LN_AUSPMA_RX_SHM_TERM191, LN_TERM191_TX_DIV2_RST | LN_TERM191_TX_DIV2_RST_OV);
+	udelay(1);
+	mask32(rx + LN_AUSPMA_RX_SHM_TERM191, LN_TERM191_TX_EN | LN_TERM191_TX_EN_OV,
+	       LN_TERM191_TX_EN_OV);
+	mask32(rx + LN_AUSPMA_RX_SHM_DFE111, LN_DFE111_DTVREG_BIG_EN | LN_DFE111_DTVREG_BIG_EN_OV,
+	       LN_DFE111_DTVREG_BIG_EN_OV);
+	udelay(1);
+	mask32(rx + LN_AUSPMA_RX_SHM_DFE111,
+	       LN_DFE111_DTVREG_SMALL_EN | LN_DFE111_DTVREG_SMALL_EN_OV,
+	       LN_DFE111_DTVREG_SMALL_EN_OV);
+	udelay(1);
+	clear32(rx + LN_AUSPMA_RX_SHM_VREF221, LN_VREF221_EN);
+	udelay(1);
+	set32(rx + LN_AUSPMA_RX_SHM_DFE121,
+	      LN_DFE121_TX_BYTECLK_SYNC_CLR | LN_DFE121_TX_BYTECLK_SYNC_CLR_OV);
+	mask32(top + LN_AUSPMA_RX_TOP_AFE1, LN_AFE1_DIV20_RESET_N | LN_AFE1_DIV20_RESET_N_OV,
+	       LN_AFE1_DIV20_RESET_N_OV);
+	clear32(rx + LN_AUSPMA_RX_SHM_DFE121, LN_DFE121_TX_BYTECLK_SYNC_EN);
+	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_CLAMP(lane));
+	udelay(1);
+	core_clear32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_SLEEP_BIG(lane));
+	udelay(1);
+	core_clear32(atcphy, ACIOPHY_CFG0, ACIOPHY_RX_SLEEP_SMALL(lane));
+	udelay(1);
+	core_clear32(atcphy, ACIOPHY_CFG1, ACIOPHY_RXTX_SLEEP_BIG(lane));
+	udelay(1);
+	core_clear32(atcphy, ACIOPHY_CFG1, ACIOPHY_RXTX_SLEEP_SMALL(lane));
+	udelay(1);
+}
+
+static int atcphy_dp_start_link_t8122(struct apple_atcphy *atcphy, u8 pmas,
+				   enum atcphy_dp_link_rate lr)
+{
+	const struct atcphy_dp_link_rate_configuration *cfg = &dp_lr_config[lr];
+	int ret;
+
+	lockdep_assert_held(&atcphy->lock);
+	if (!pmas || pmas > 3)
+		return -EINVAL;
+	ret = atcphy_dp_start_pll_t8122(atcphy, lr);
+	if (ret)
+		return ret;
+	/* Set both feedback overrides before releasing the shared lane reset. */
+	for (unsigned int lane = 0; lane < 2; lane++) {
+		void __iomem *shm = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_RX_SHM);
+
+		if (pmas & BIT(lane))
+			mask32(shm + LN_AUSPMA_RX_SHM_DFE101,
+			       LN_DFE101_DFEH1FB_EN | LN_DFE101_DFEH1FB_EN_OV,
+			       LN_DFE101_DFEH1FB_EN_OV);
+	}
+	core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0,
+		   DPTXPHY_PMA_LANE_RESET_N | DPTXPHY_PMA_LANE_RESET_N_OV);
+	udelay(1);
+	for (unsigned int lane = 0; lane < 2; lane++) {
+		if (!(pmas & BIT(lane)))
+			continue;
+		atcphy_dp_configure_tx_t8122(atcphy, lane, cfg);
+		atcphy_dp_configure_rxtx_t8122(atcphy, lane, cfg);
+	}
+	core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DP_PMA_BYTECLK_RESET);
+	return 0;
+}
+
+static int atcphy_dp_stop_link_t8122(struct apple_atcphy *atcphy)
+{
+	const struct atcphy_mode_configuration *cfg;
+	int ret;
+
+	lockdep_assert_held(&atcphy->lock);
+	if (atcphy->dp_link_rate == ATCPHY_DP_LINK_RATE_IDLE)
+		return 0;
+	cfg = atcphy_get_mode_config(atcphy, atcphy->mode);
+	atcphy->dp_link_rate = ATCPHY_DP_LINK_RATE_PENDING;
+	core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DP_PMA_BYTECLK_RESET);
+	for (unsigned int lane = 0; lane < 2; lane++) {
+		if (cfg->dp_lane[lane])
+			atcphy_dp_stop_lane_t8122(atcphy, lane);
+	}
+	core_mask32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0,
+		    DPTXPHY_PMA_LANE_RESET_N | DPTXPHY_PMA_LANE_RESET_N_OV,
+		    DPTXPHY_PMA_LANE_RESET_N_OV);
+	ret = atcphy_auspll_set_command(atcphy, 0, true);
+	if (ret)
+		return ret;
+	ret = atcphy_auspll_set_command(atcphy, 3, false);
+	if (ret)
+		return ret;
+	ret = atcphy_dp_poll(atcphy, ACIOPHY_DP_PCLK_STAT_T8122, ACIOPHY_AUSPLL_LOCK, 0);
+	if (ret)
+		return ret;
+	core_clear32(atcphy, AUSPLL_CLKOUT_MASTER, AUSPLL_CLKOUT_MASTER_PCLK_DRVR_EN_T8122);
+	atcphy->dp_link_rate = ATCPHY_DP_LINK_RATE_IDLE;
+	return 0;
+}
+
+static int atcphy_dp_set_rate_t8122(struct apple_atcphy *atcphy, enum atcphy_dp_link_rate lr)
+{
+	const struct atcphy_mode_configuration *cfg;
+	u8 pmas;
+	int ret;
+
+	guard(mutex)(&atcphy->lock);
+	if (!atcphy_modes[atcphy->mode].enable_dp_aux)
+		return -ENOLINK;
+	cfg = atcphy_get_mode_config(atcphy, atcphy->mode);
+	pmas = cfg->dp_lane[0] | (cfg->dp_lane[1] << 1);
+	if (!pmas)
+		return -EINVAL;
+	if (atcphy->dp_link_rate == lr)
+		return 0;
+	ret = atcphy_dp_stop_link_t8122(atcphy);
+	if (ret)
+		return ret;
+	atcphy->dp_link_rate = ATCPHY_DP_LINK_RATE_PENDING;
+	ret = atcphy_dp_start_link_t8122(atcphy, pmas, lr);
+	if (ret) {
+		atcphy_dp_stop_link_t8122(atcphy);
+		return ret;
+	}
+	atcphy->dp_link_rate = lr;
+	return 0;
+}
+
+static void atcphy_enable_dp_aux_t8122(struct apple_atcphy *atcphy)
+{
+	core_set32(atcphy, AUX_SHM_PWR, AUX_SLEEP_SML_OV | AUX_SLEEP_SML);
+	udelay(1);
+	core_set32(atcphy, AUX_SHM_PWR, AUX_SLEEP_BIG_OV | AUX_SLEEP_BIG);
+	udelay(1);
+	core_mask32(atcphy, AUX_SHM_PWR, AUX_CLAMP_OV | AUX_CLAMP,
+		    AUX_CLAMP_OV);
+	udelay(1);
+	core_clear32(atcphy, AUX_TOP_CTRL, AUX_TOP_PWRDN);
+	udelay(1);
+	atcphy->dp_link_rate = ATCPHY_DP_LINK_RATE_IDLE;
+}
+
+static void atcphy_disable_dp_aux_t8122(struct apple_atcphy *atcphy)
+{
+	core_set32(atcphy, AUX_TOP_CTRL, AUX_TOP_PWRDN);
+	udelay(1);
+	core_set32(atcphy, AUX_SHM_PWR, AUX_CLAMP);
+	udelay(1);
+	core_clear32(atcphy, AUX_SHM_PWR, AUX_SLEEP_BIG);
+	udelay(1);
+	core_clear32(atcphy, AUX_SHM_PWR, AUX_SLEEP_SML);
+	udelay(1);
+}
+
 static void atcphy_enable_dp_aux(struct apple_atcphy *atcphy)
 {
 	core_set32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTXPHY_PMA_LANE_RESET_N);
@@ -1420,7 +1967,7 @@ static void atcphy_enable_dp_aux(struct apple_atcphy *atcphy)
 	mask32(atcphy->regs.lpdptx + LPDPTX_AUX_CFG_BLK_AUX_MARGIN, LPDPTX_AUX_MARGIN_RCAL_TXSWING,
 	       FIELD_PREP(LPDPTX_AUX_MARGIN_RCAL_TXSWING, 12));
 
-	atcphy->dp_link_rate = -1;
+	atcphy->dp_link_rate = ATCPHY_DP_LINK_RATE_IDLE;
 }
 
 static void atcphy_disable_dp_aux(struct apple_atcphy *atcphy)
@@ -1439,6 +1986,20 @@ static void atcphy_disable_dp_aux(struct apple_atcphy *atcphy)
 	core_clear32(atcphy, ACIOPHY_LANE_DP_CFG_BLK_TX_DP_CTRL0, DPTX_PCLK2_ENABLE);
 }
 
+static void atcphy_dp_enable_aux(struct apple_atcphy *atcphy)
+{
+	if (atcphy->hw->dp)
+		atcphy->hw->dp->enable_aux(atcphy);
+	else
+		dev_warn_once(atcphy->dev, "DisplayPort AUX initialization is not implemented\n");
+}
+
+static void atcphy_dp_disable_aux(struct apple_atcphy *atcphy)
+{
+	if (atcphy->hw->dp)
+		atcphy->hw->dp->disable_aux(atcphy);
+}
+
 static int atcphy_dp_configure_lane(struct apple_atcphy *atcphy, enum atcphy_lane lane,
 				    const struct atcphy_dp_link_rate_configuration *cfg)
 {
@@ -1447,20 +2008,11 @@ static int atcphy_dp_configure_lane(struct apple_atcphy *atcphy, enum atcphy_lan
 
 	lockdep_assert_held(&atcphy->lock);
 
-	switch (lane) {
-	case APPLE_ATCPHY_LANE_0:
-		tx_shm = atcphy->regs.core + LN0_AUSPMA_TX_SHM;
-		rx_shm = atcphy->regs.core + LN0_AUSPMA_RX_SHM;
-		rx_top = atcphy->regs.core + LN0_AUSPMA_RX_TOP;
-		break;
-	case APPLE_ATCPHY_LANE_1:
-		tx_shm = atcphy->regs.core + LN1_AUSPMA_TX_SHM;
-		rx_shm = atcphy->regs.core + LN1_AUSPMA_RX_SHM;
-		rx_top = atcphy->regs.core + LN1_AUSPMA_RX_TOP;
-		break;
-	default:
+	if ((unsigned int)lane > APPLE_ATCPHY_LANE_1)
 		return -EINVAL;
-	}
+	tx_shm = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_TX_SHM);
+	rx_shm = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_RX_SHM);
+	rx_top = atcphy_lane_reg(atcphy, lane, LN0_AUSPMA_RX_TOP);
 
 	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_SML);
 	set32(tx_shm + LN_AUSPMA_TX_SHM_TXA_LDOCLK, LN_LDOCLK_EN_SML_OV);
@@ -1799,7 +2351,7 @@ static int atcphy_power_off(struct apple_atcphy *atcphy)
 	u32 reg;
 	int ret;
 
-	atcphy_disable_dp_aux(atcphy);
+	atcphy_dp_disable_aux(atcphy);
 
 	/* Enable all reset lines */
 	core_clear32(atcphy, ATCPHY_POWER_CTRL, ATCPHY_POWER_PHY_RESET_N);
@@ -1922,10 +2474,8 @@ static void atcphy_configure_post_tunable_t8103(struct apple_atcphy *atcphy, enu
 	udelay(10);
 }
 
-static void atcphy_configure_post_tunable_t8122(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+static void atcphy_power_on_common_t8122(struct apple_atcphy *atcphy)
 {
-	if (atcphy_modes[mode].pipehandler_state != ATCPHY_PIPEHANDLER_STATE_USB3)
-		return;
 	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_SMALL);
 	udelay(10);
 	core_set32(atcphy, ACIOPHY_CFG0, ACIOPHY_CFG0_COMMON_SMALL_OV);
@@ -1942,12 +2492,24 @@ static void atcphy_configure_post_tunable_t8122(struct apple_atcphy *atcphy, enu
 	udelay(10);
 }
 
+static void atcphy_configure_post_tunable_t8122(struct apple_atcphy *atcphy, enum atcphy_mode mode)
+{
+	if (atcphy_modes[mode].pipehandler_state == ATCPHY_PIPEHANDLER_STATE_USB3 ||
+	    (atcphy->hw->dp && atcphy_modes[mode].enable_dp_aux))
+		atcphy_power_on_common_t8122(atcphy);
+}
+
 static int atcphy_configure(struct apple_atcphy *atcphy, enum atcphy_mode mode)
 {
 	int ret = 0;
 	u32 reg;
 
 	lockdep_assert_held(&atcphy->lock);
+	if (atcphy->hw->dp && atcphy->hw->dp->stop) {
+		ret = atcphy->hw->dp->stop(atcphy);
+		if (ret)
+			return ret;
+	}
 
 	if (mode == APPLE_ATCPHY_MODE_OFF) {
 		ret = atcphy_power_off(atcphy);
@@ -1964,7 +2526,7 @@ static int atcphy_configure(struct apple_atcphy *atcphy, enum atcphy_mode mode)
 
 	/* Setup AUX channel if DP altmode is requested */
 	if (atcphy_modes[mode].enable_dp_aux)
-		atcphy_enable_dp_aux(atcphy);
+		atcphy_dp_enable_aux(atcphy);
 
 	/* Enable clocks and configure lanes */
 	if (atcphy->hw->gen == ATCPHY_GENERATION_T8103) {
@@ -2115,6 +2677,10 @@ static int atcphy_dpphy_configure(struct phy *phy, union phy_configure_opts *opt
 		return -EINVAL;
 
 	if (opts->set_rate) {
+		if (!atcphy->hw->dp) {
+			dev_warn(atcphy->dev, "DisplayPort lane setup is not implemented\n");
+			return -EOPNOTSUPP;
+		}
 		switch (opts->link_rate) {
 		case 1620:
 			link_rate = ATCPHY_DP_LINK_RATE_RBR;
@@ -2129,12 +2695,18 @@ static int atcphy_dpphy_configure(struct phy *phy, union phy_configure_opts *opt
 			link_rate = ATCPHY_DP_LINK_RATE_HBR3;
 			break;
 		case 0:
+			if (atcphy->hw->dp->stop) {
+				guard(mutex)(&atcphy->lock);
+				return atcphy->hw->dp->stop(atcphy);
+			}
 			return 0;
 		default:
 			dev_err(atcphy->dev, "Unsupported link rate: %d\n", opts->link_rate);
 			return -EINVAL;
 		}
 
+		if (atcphy->hw->dp->set_rate)
+			return atcphy->hw->dp->set_rate(atcphy, link_rate);
 		return atcphy_dp_configure(atcphy, link_rate);
 	}
 
@@ -2257,19 +2829,31 @@ static int atcphy_probe_rcdev(struct apple_atcphy *atcphy)
 static int atcphy_sw_set(struct typec_switch_dev *sw, enum typec_orientation orientation)
 {
 	struct apple_atcphy *atcphy = typec_switch_get_drvdata(sw);
+	bool swap_lanes;
+	int ret;
 
 	guard(mutex)(&atcphy->lock);
 
 	switch (orientation) {
 	case TYPEC_ORIENTATION_NONE:
-		break;
+		return 0;
 	case TYPEC_ORIENTATION_NORMAL:
-		atcphy->swap_lanes = false;
+		swap_lanes = false;
 		break;
 	case TYPEC_ORIENTATION_REVERSE:
-		atcphy->swap_lanes = true;
+		swap_lanes = true;
 		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Cleanup needs the old lane configuration until shutdown succeeds. */
+	if (swap_lanes != atcphy->swap_lanes && atcphy->hw->dp && atcphy->hw->dp->stop) {
+		ret = atcphy->hw->dp->stop(atcphy);
+		if (ret)
+			return ret;
 	}
+	atcphy->swap_lanes = swap_lanes;
 
 	return 0;
 }
@@ -2511,12 +3095,26 @@ static int atcphy_probe(struct platform_device *pdev)
 		return ret;
 
 	atcphy->mode = APPLE_ATCPHY_MODE_OFF;
+	atcphy->dp_link_rate = ATCPHY_DP_LINK_RATE_IDLE;
 	atcphy->pipehandler_up = false;
 
 	return atcphy_probe_finalize(atcphy);
 }
 
+static const struct atcphy_dp_ops atcphy_dp_ops_default = {
+	.enable_aux = atcphy_enable_dp_aux,
+	.disable_aux = atcphy_disable_dp_aux,
+};
+
+static const struct atcphy_dp_ops atcphy_dp_ops_t8122 = {
+	.enable_aux = atcphy_enable_dp_aux_t8122,
+	.disable_aux = atcphy_disable_dp_aux_t8122,
+	.set_rate = atcphy_dp_set_rate_t8122,
+	.stop = atcphy_dp_stop_link_t8122,
+};
+
 static const struct atcphy_hw atcphy_hw_t8103 = {
+	.dp = &atcphy_dp_ops_default,
 	.gen = ATCPHY_GENERATION_T8103,
 	.aciophy_lane_mode = ACIOPHY_LANE_MODE_T8103,
 	.aciophy_crossbar = ACIOPHY_CROSSBAR_T8103,
@@ -2524,6 +3122,7 @@ static const struct atcphy_hw atcphy_hw_t8103 = {
 };
 
 static const struct atcphy_hw atcphy_hw_t8122 = {
+	.dp = &atcphy_dp_ops_t8122,
 	.gen = ATCPHY_GENERATION_T8122,
 	.aciophy_lane_mode = ACIOPHY_LANE_MODE_T8122,
 	.aciophy_crossbar = ACIOPHY_CROSSBAR_T8122,

-- 
2.56.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/4] soc: apple: tunable: Allow passing NULL to tunable_apply
  2026-11-08 15:43 ` [PATCH 2/4] soc: apple: tunable: Allow passing NULL to tunable_apply Sasha Finkelstein
@ 2026-11-08 15:48   ` Sven Peter
  0 siblings, 0 replies; 10+ messages in thread
From: Sven Peter @ 2026-11-08 15:48 UTC (permalink / raw)
  To: Sasha Finkelstein, Janne Grunau, Neal Gompa, Vinod Koul,
	Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: asahi, linux-arm-kernel, linux-phy, devicetree, linux-kernel


On 11/8/26 16:43, Sasha Finkelstein wrote:
> Make it easier to have optional tunables by tolerating NULL entries and
> doing nothing when one is passed
>
> Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
> ---

Acked-by: Sven Peter <sven@kernel.org>

Feel free to take this with the rest of the series through the PHY tree 
once everything's ready.



Sven

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] phy: apple: atc: Add initial M3 series support
  2026-11-08 15:43 ` [PATCH 3/4] phy: apple: atc: Add initial M3 series support Sasha Finkelstein
@ 2026-11-08 18:15   ` Sven Peter
  2026-11-08 18:17   ` Sven Peter
  1 sibling, 0 replies; 10+ messages in thread
From: Sven Peter @ 2026-11-08 18:15 UTC (permalink / raw)
  To: Sasha Finkelstein, Janne Grunau, Neal Gompa, Vinod Koul,
	Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: asahi, linux-arm-kernel, linux-phy, devicetree, linux-kernel

Hi,


On 11/8/26 16:43, Sasha Finkelstein wrote:
> Adds initial support for the new t8122 phy. USB/TB only for now, DP
> will fail to negotiate
>
> Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
> ---

So I wonder if it's time to split this into multiple files now.
Maybe something like atc.c that does the core stuff (probing, 
phy/reset/etc. interfacing, mode transitions, tunables, etc.) and then 
atc-t8103.c and atc-t8112.c for the hardware specific parts since 
especially DP seems to be quite different between the two generations now.


>   drivers/phy/apple/atc.c | 382 +++++++++++++++++++++++++++++++++++++-----------
>   1 file changed, 297 insertions(+), 85 deletions(-)

[...]

> diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c
> index 45f1280a6faa..256a08499646 100644
> --- a/drivers/phy/apple/atc.c
> +++ b/drivers/phy/apple/atc.c
> @@ -100,9 +100,15 @@
>   #define AUSPLL_FREQ_CFG 0x2224
>   #define AUSPLL_FREQ_REFCLK GENMASK(1, 0)
>   
> +#define AUS_COMMON_SHIM_BLK_BIAS_REG 0x0a00
> +#define AUS_COMMON_SHIM_BLK_BIAS_REG_BGBIAS_OV BIT(1)
> +
>   #define AUS_COMMON_SHIM_BLK_VREG 0x0a04
>   #define AUS_VREG_TRIM GENMASK(6, 2)
>   
[...]
>   	atcphy->mode = mode;
>   
> @@ -2201,6 +2387,7 @@ static int atcphy_probe_mux(struct apple_atcphy *atcphy)
>   
>   static int atcphy_load_tunables(struct apple_atcphy *atcphy)
>   {
> +	size_t tunable_count;
>   	struct {
>   		const char *dt_name;
>   		struct apple_tunable **tunable;
> @@ -2216,8 +2403,14 @@ static int atcphy_load_tunables(struct apple_atcphy *atcphy)
>   		{ "apple,tunable-lane0-dp", &atcphy->tunables.lane_dp[0], atcphy->res.core },
>   		{ "apple,tunable-lane1-dp", &atcphy->tunables.lane_dp[1], atcphy->res.core },
>   	};
> -
> -	for (int i = 0; i < ARRAY_SIZE(tunables); i++) {
> +	if (atcphy->hw->gen == ATCPHY_GENERATION_T8122) {
> +		tunable_count = ARRAY_SIZE(tunables) - 2;
> +		atcphy->tunables.lane_dp[0] = NULL;
> +		atcphy->tunables.lane_dp[1] = NULL;
> +	} else
> +		tunable_count = ARRAY_SIZE(tunables);

nit: I think else { .. } looks nicer when the if already has braces even 
though it's just a single line.



Sven


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] phy: apple: atc: Add initial M3 series support
  2026-11-08 15:43 ` [PATCH 3/4] phy: apple: atc: Add initial M3 series support Sasha Finkelstein
  2026-11-08 18:15   ` Sven Peter
@ 2026-11-08 18:17   ` Sven Peter
  2026-11-08 18:21     ` Sasha Finkelstein
  1 sibling, 1 reply; 10+ messages in thread
From: Sven Peter @ 2026-11-08 18:17 UTC (permalink / raw)
  To: Sasha Finkelstein, Janne Grunau, Neal Gompa, Vinod Koul,
	Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: asahi, linux-arm-kernel, linux-phy, devicetree, linux-kernel


On 11/8/26 16:43, Sasha Finkelstein wrote:
> Adds initial support for the new t8122 phy. USB/TB only for now, DP
> will fail to negotiate
>
> Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
> ---
>   
[...]
>   /**
>    * struct apple_atcphy - Apple Type-C PHY device struct
>    * @np: Device node pointer
> @@ -599,9 +647,10 @@ struct apple_atcphy {
>   		struct apple_tunable *lane_usb4[2];
>   	} tunables;
>   
> +	const struct atcphy_hw *hw;
>   	enum atcphy_mode mode;
> -	bool swap_lanes;
>   	int dp_link_rate;
> +	bool swap_lanes;

ugh.. somehow dropped this comment from the email i just sent..
is there any reason you move swap_lanes around here?


Sven




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] phy: apple: atc: Add initial M3 series support
  2026-11-08 18:17   ` Sven Peter
@ 2026-11-08 18:21     ` Sasha Finkelstein
  2026-11-08 18:25       ` Sven Peter
  0 siblings, 1 reply; 10+ messages in thread
From: Sasha Finkelstein @ 2026-11-08 18:21 UTC (permalink / raw)
  To: Sven Peter
  Cc: Janne Grunau, Neal Gompa, Vinod Koul, Neil Armstrong,
	Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, asahi, linux-arm-kernel, linux-phy, devicetree,
	linux-kernel

On Nov 8, 2026, at 19:17, Sven Peter <sven@kernel.org> wrote:
> 
>>  /**
>>   * struct apple_atcphy - Apple Type-C PHY device struct
>>   * @np: Device node pointer
>> @@ -599,9 +647,10 @@ struct apple_atcphy {
>>   struct apple_tunable *lane_usb4[2];
>>   } tunables;
>>  + const struct atcphy_hw *hw;
>>   enum atcphy_mode mode;
>> - bool swap_lanes;
>>   int dp_link_rate;
>> + bool swap_lanes;
> 
> ugh.. somehow dropped this comment from the email i just sent..
> is there any reason you move swap_lanes around here?

It saves 3 bytes of alignment padding. Yes, it makes no sense on
machines of that performance class, but I could not resist. Can drop it
in v2.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/4] phy: apple: atc: Add initial M3 series support
  2026-11-08 18:21     ` Sasha Finkelstein
@ 2026-11-08 18:25       ` Sven Peter
  0 siblings, 0 replies; 10+ messages in thread
From: Sven Peter @ 2026-11-08 18:25 UTC (permalink / raw)
  To: Sasha Finkelstein
  Cc: Janne Grunau, Neal Gompa, Vinod Koul, Neil Armstrong,
	Manivannan Sadhasivam, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, asahi, linux-arm-kernel, linux-phy, devicetree,
	linux-kernel

On 11/8/26 19:21, Sasha Finkelstein wrote:
> On Nov 8, 2026, at 19:17, Sven Peter <sven@kernel.org> wrote:
>>>   /**
>>>    * struct apple_atcphy - Apple Type-C PHY device struct
>>>    * @np: Device node pointer
>>> @@ -599,9 +647,10 @@ struct apple_atcphy {
>>>    struct apple_tunable *lane_usb4[2];
>>>    } tunables;
>>>   + const struct atcphy_hw *hw;
>>>    enum atcphy_mode mode;
>>> - bool swap_lanes;
>>>    int dp_link_rate;
>>> + bool swap_lanes;
>> ugh.. somehow dropped this comment from the email i just sent..
>> is there any reason you move swap_lanes around here?
> It saves 3 bytes of alignment padding. Yes, it makes no sense on
> machines of that performance class, but I could not resist. Can drop it
> in v2.

Fine with me either way ;)

Sven


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-11-08 18:25 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-08 15:43 [PATCH 0/4] phy: apple: atc: Add M3 support Sasha Finkelstein
2026-11-08 15:43 ` [PATCH 1/4] dt-bindings: phy: atcphy: Add M3 series Sasha Finkelstein
2026-11-08 15:43 ` [PATCH 2/4] soc: apple: tunable: Allow passing NULL to tunable_apply Sasha Finkelstein
2026-11-08 15:48   ` Sven Peter
2026-11-08 15:43 ` [PATCH 3/4] phy: apple: atc: Add initial M3 series support Sasha Finkelstein
2026-11-08 18:15   ` Sven Peter
2026-11-08 18:17   ` Sven Peter
2026-11-08 18:21     ` Sasha Finkelstein
2026-11-08 18:25       ` Sven Peter
2026-11-08 15:43 ` [PATCH 4/4] phy: apple: atc: Add T8122 DisplayPort support Sasha Finkelstein

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®