[PATCH v1 1/4] usb: tcpm: improve handling of some power-supplies

Sebastian Reichel sebastian.reichel at collabora.com
Thu Oct 31 18:50:30 CET 2024


When the Rock 5B is booted with the current TCPM with its power supplied
by a "Cambrionix PDSync-C4" port it reaches the power-supply ready state.
Once that has happened the hub starts sending GetSinkCap messages, but
U-Boot already stopped processing PD messages. After retrying a bunch of
times the hub instead sends soft resets. Since U-Boot will also not
react to them, the USB hub will follow-up with a hard reset and that
cuts off the supply voltage.

Since the state machine is already prepared to handle GetSinkCap
messages, try to avoid this by handling incoming messages for another
50ms after reaching the ready state.

Fixes: 1db4c0ac77e3 ("usb: tcpm: add core framework")
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/usb/tcpm/tcpm.c | 31 ++++++++++++++++++++++++++-----
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/tcpm/tcpm.c b/drivers/usb/tcpm/tcpm.c
index 0aee57cb2f4a..b754b4dcd0b5 100644
--- a/drivers/usb/tcpm/tcpm.c
+++ b/drivers/usb/tcpm/tcpm.c
@@ -2229,6 +2229,17 @@ static int tcpm_port_init(struct udevice *dev)
 	return 0;
 }
 
+static inline void tcpm_poll_one_event(struct udevice *dev)
+{
+	const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
+	struct tcpm_port *port = dev_get_uclass_plat(dev);
+
+	drvops->poll_event(dev);
+	port->poll_event_cnt++;
+	udelay(500);
+	tcpm_check_and_run_delayed_work(dev);
+}
+
 static void tcpm_poll_event(struct udevice *dev)
 {
 	const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
@@ -2242,15 +2253,25 @@ static void tcpm_poll_event(struct udevice *dev)
 		    (port->state == SNK_READY || port->state == SRC_READY))
 			break;
 
-		drvops->poll_event(dev);
-		port->poll_event_cnt++;
-		udelay(500);
-		tcpm_check_and_run_delayed_work(dev);
+		tcpm_poll_one_event(dev);
 	}
 
-	if (port->state != SNK_READY && port->state != SRC_READY)
+	/*
+	 * Some power-supplies send GetSinkCap shortly after they are ready.
+	 * If they do not receive a response after a few retries they will issue
+	 * a soft-reset followed by a hard reset, which kills the board power.
+	 * Let's poll for 50ms after reaching the ready state to check if the
+	 * power-supply wants something from us.
+	 */
+	if (port->state == SNK_READY) {
+		port->poll_event_cnt = 0;
+
+		while (port->poll_event_cnt < 100)
+			tcpm_poll_one_event(dev);
+	} else {
 		dev_warn(dev, "TCPM: exit in state %s\n",
 			 tcpm_states[port->state]);
+	}
 
 	/*
 	 * At this time, call the callback function of the respective pd chip
-- 
2.45.2



More information about the U-Boot mailing list