[PATCH v8 24/29] phy: rockchip: usbdp: Support going from DP-only mode to USB mode

From: Sebastian Reichel

Date: Fri Jun 26 2026 - 17:01:30 EST


When a USB-C adapter, which maps all Superspeed lanes to DP is plugged
in, the USB support is disabled in the PHY. When the adapter is
unplugged and a different adapter with USB functionality is plugged in
afterwards, USB functionality is not restored as the USB controller
keeps the PHY enabled for the entire time.

Signed-off-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxx>
---
drivers/phy/rockchip/phy-rockchip-usbdp.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 837a4cb3e4b6..4566822d70c4 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -179,6 +179,7 @@ struct rk_udphy {

/* utilized for USB */
bool hs; /* flag for high-speed */
+ bool usb_in_use;

/* utilized for DP */
struct gpio_desc *sbu1_dc_gpio;
@@ -1025,6 +1026,10 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
ret = rk_udphy_init(udphy);
if (ret)
return ret;
+
+ if (udphy->mode & UDPHY_MODE_USB)
+ rk_udphy_u3_port_disable(udphy, false);
+
udphy->phy_needs_reinit = false;
}

@@ -1288,16 +1293,24 @@ static const struct phy_ops rk_udphy_dp_phy_ops = {
static int rk_udphy_usb3_phy_init(struct phy *phy)
{
struct rk_udphy *udphy = phy_get_drvdata(phy);
+ int ret;

guard(mutex)(&udphy->mutex);

/* DP only or high-speed, disable U3 port */
if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
rk_udphy_u3_port_disable(udphy, true);
+ udphy->usb_in_use = true;
return 0;
}

- return rk_udphy_power_on(udphy, UDPHY_MODE_USB);
+ ret = rk_udphy_power_on(udphy, UDPHY_MODE_USB);
+ if (ret)
+ return ret;
+
+ udphy->usb_in_use = true;
+
+ return 0;
}

static int rk_udphy_usb3_phy_exit(struct phy *phy)
@@ -1306,6 +1319,8 @@ static int rk_udphy_usb3_phy_exit(struct phy *phy)

guard(mutex)(&udphy->mutex);

+ udphy->usb_in_use = false;
+
/* DP only or high-speed */
if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs)
return 0;
@@ -1347,6 +1362,17 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,

rk_udphy_set_typec_state(udphy, state->mode);

+ /*
+ * If the new mode includes USB, but it has not yet been powered
+ * (because the previous mode was DP-only) and the USB PHY was
+ * already initialized by the USB controller, we need to power on
+ * the USB side now since no subsequent phy_init call will come
+ * from the controller.
+ */
+ if ((udphy->mode & UDPHY_MODE_USB) && !(udphy->status & UDPHY_MODE_USB) &&
+ udphy->usb_in_use && !udphy->hs)
+ return rk_udphy_power_on(udphy, UDPHY_MODE_USB);
+
return 0;
}


--
2.53.0