Skip to contentSkip to conversation

usb: typec: handle tcpc vconn oc fault by triggering tcpm error recovery

PATCH In review RD Babiera 3 participants 7 messages Nov 21, 2023 – Nov 28, 2023

Subsystems (3)
lore
Share & tools
lore

RD Babiera

author
#0 lore raw

cover usb: typec: handle tcpc vconn oc fault by triggering tcpm error recovery

When a Vconn swap results in a Vconn over current fault, typec port interoperability is affected and cannot be recovered unless the connection is reset and restablished.

The tcpm currently does not have an export symbol to set the port to the error recovery state in the event of tcpc faults. This patch set adds tcpm_port_error_recovery for tcpci drivers to use when a fault should result in a connection reset. Vconn over current fault handling is added to the maxim tcpci driver.

RD Babiera (2):
usb: typec: tcpm: add tcpm_port_error_recovery symbol
usb: typec: tcpci: add vconn over current fault handling to maxim_core

 drivers/usb/typec/tcpm/tcpci_maxim_core.c | 20 +++++++++++++++++++-
 drivers/usb/typec/tcpm/tcpm.c             | 14 ++++++++++++++
 include/linux/usb/tcpci.h                 |  5 ++++-
 include/linux/usb/tcpm.h                  |  1 +
 4 files changed, 38 insertions(+), 2 deletions(-)
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
author
#1 lore raw

PATCH 1/2 usb: typec: tcpm: add tcpm_port_error_recovery symbol

Add tcpm_port_error_recovery symbol and corresponding event that runs in tcpm_pd_event handler to set the port to the ERROR_RECOVERY state. tcpci drivers can use the symbol to reset the port when tcpc faults affect port functionality.

---
 drivers/usb/typec/tcpm/tcpm.c | 14 ++++++++++++++
 include/linux/usb/tcpm.h      |  1 +
 2 files changed, 15 insertions(+)
drivers/usb/typec/tcpm/tcpm.c +14 -0
index 058d5b853b57..2e553dc63619 100644
@@ -251,6 +251,7 @@ enum frs_typec_current {
 #define TCPM_FRS_EVENT		BIT(3)
 #define TCPM_SOURCING_VBUS	BIT(4)
 #define TCPM_PORT_CLEAN		BIT(5)
+#define TCPM_PORT_ERROR		BIT(6)
 
 #define LOG_BUFFER_ENTRIES	1024
 #define LOG_BUFFER_ENTRY_SIZE	128
@@ -5477,6 +5478,10 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
 					tcpm_set_state(port, tcpm_default_state(port), 0);
 			}
 		}
+		if (events & TCPM_PORT_ERROR) {
+			tcpm_log(port, "port triggering error recovery");
+			tcpm_set_state(port, ERROR_RECOVERY, 0);
+		}
 
 		spin_lock(&port->pd_event_lock);
 	}
@@ -5544,6 +5549,15 @@ bool tcpm_port_is_toggling(struct tcpm_port *port)
 }
 EXPORT_SYMBOL_GPL(tcpm_port_is_toggling);
 
+void tcpm_port_error_recovery(struct tcpm_port *port)
+{
+	spin_lock(&port->pd_event_lock);
+	port->pd_events |= TCPM_PORT_ERROR;
+	spin_unlock(&port->pd_event_lock);
+	kthread_queue_work(port->wq, &port->event_work);
+}
+EXPORT_SYMBOL_GPL(tcpm_port_error_recovery);
+
 static void tcpm_enable_frs_work(struct kthread_work *work)
 {
 	struct tcpm_port *port = container_of(work, struct tcpm_port, enable_frs);
include/linux/usb/tcpm.h +1 -0
index ab7ca872950b..65fac5e1f317 100644
@@ -173,5 +173,6 @@ void tcpm_pd_hard_reset(struct tcpm_port *port);
 void tcpm_tcpc_reset(struct tcpm_port *port);
 void tcpm_port_clean(struct tcpm_port *port);
 bool tcpm_port_is_toggling(struct tcpm_port *port);
+void tcpm_port_error_recovery(struct tcpm_port *port);
 
 #endif /* __LINUX_USB_TCPM_H */
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
maintainer Reviewed-by on v1 1/2
#2 lore raw

Re: [PATCH v1 1/2] usb: typec: tcpm: add tcpm_port_error_recovery symbol

Quoted 6 lines · RD Babiera

Add tcpm_port_error_recovery symbol and corresponding event that runs in tcpm_pd_event handler to set the port to the ERROR_RECOVERY state. tcpci drivers can use the symbol to reset the port when tcpc faults affect port functionality.

Quoted 57 lines
---
 drivers/usb/typec/tcpm/tcpm.c | 14 ++++++++++++++
 include/linux/usb/tcpm.h      |  1 +
 2 files changed, 15 insertions(+)
drivers/usb/typec/tcpm/tcpm.c +14 -0
index 058d5b853b57..2e553dc63619 100644
@@ -251,6 +251,7 @@ enum frs_typec_current {
 #define TCPM_FRS_EVENT		BIT(3)
 #define TCPM_SOURCING_VBUS	BIT(4)
 #define TCPM_PORT_CLEAN		BIT(5)
+#define TCPM_PORT_ERROR		BIT(6)
 
 #define LOG_BUFFER_ENTRIES	1024
 #define LOG_BUFFER_ENTRY_SIZE	128
@@ -5477,6 +5478,10 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
 					tcpm_set_state(port, tcpm_default_state(port), 0);
 			}
 		}
+		if (events & TCPM_PORT_ERROR) {
+			tcpm_log(port, "port triggering error recovery");
+			tcpm_set_state(port, ERROR_RECOVERY, 0);
+		}
 
 		spin_lock(&port->pd_event_lock);
 	}
@@ -5544,6 +5549,15 @@ bool tcpm_port_is_toggling(struct tcpm_port *port)
 }
 EXPORT_SYMBOL_GPL(tcpm_port_is_toggling);
 
+void tcpm_port_error_recovery(struct tcpm_port *port)
+{
+	spin_lock(&port->pd_event_lock);
+	port->pd_events |= TCPM_PORT_ERROR;
+	spin_unlock(&port->pd_event_lock);
+	kthread_queue_work(port->wq, &port->event_work);
+}
+EXPORT_SYMBOL_GPL(tcpm_port_error_recovery);
+
 static void tcpm_enable_frs_work(struct kthread_work *work)
 {
 	struct tcpm_port *port = container_of(work, struct tcpm_port, enable_frs);
include/linux/usb/tcpm.h +1 -0
index ab7ca872950b..65fac5e1f317 100644
@@ -173,5 +173,6 @@ void tcpm_pd_hard_reset(struct tcpm_port *port);
 void tcpm_tcpc_reset(struct tcpm_port *port);
 void tcpm_port_clean(struct tcpm_port *port);
 bool tcpm_port_is_toggling(struct tcpm_port *port);
+void tcpm_port_error_recovery(struct tcpm_port *port);
 
 #endif /* __LINUX_USB_TCPM_H */
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
Signature · 1 line
heikki
Reviewed-by on v1 1/2
#3 lore raw

Re: [PATCH v1 1/2] usb: typec: tcpm: add tcpm_port_error_recovery symbol

In reply to RD Babiera
Quoted 6 lines · RD Babiera

Add tcpm_port_error_recovery symbol and corresponding event that runs in tcpm_pd_event handler to set the port to the ERROR_RECOVERY state. tcpci drivers can use the symbol to reset the port when tcpc faults affect port functionality.

author
#4 lore raw

PATCH 2/2 usb: typec: tcpci: add vconn over current fault handling to maxim_core

In reply to RD Babiera

Add TCPC_FAULT_STATUS_VCONN_OC constant and corresponding mask definition. Maxim TCPC is capable of detecting VConn over current faults, so add fault to alert mask. When a Vconn over current fault is triggered, put the port in an error recovery state via tcpm_port_error_recovery.

---
 drivers/usb/typec/tcpm/tcpci_maxim_core.c | 20 +++++++++++++++++++-
 include/linux/usb/tcpci.h                 |  5 ++++-
 2 files changed, 23 insertions(+), 2 deletions(-)
drivers/usb/typec/tcpm/tcpci_maxim_core.c +19 -1
index 9454b12a073c..7fb966fd639b 100644
@@ -92,11 +92,16 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
 		return;
 	}
 
+	/* Vconn Over Current Protection */
+	ret = max_tcpci_write8(chip, TCPC_FAULT_STATUS_MASK, TCPC_FAULT_STATUS_MASK_VCONN_OC);
+	if (ret < 0)
+		return;
+
 	alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED |
 		TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS |
 		TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS |
 		/* Enable Extended alert for detecting Fast Role Swap Signal */
-		TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS;
+		TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS | TCPC_ALERT_FAULT;
 
 	ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask);
 	if (ret < 0) {
@@ -295,6 +300,19 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
 		}
 	}
 
+	if (status & TCPC_ALERT_FAULT) {
+		ret = max_tcpci_read8(chip, TCPC_FAULT_STATUS, &reg_status);
+		if (ret < 0)
+			return ret;
+
+		ret = max_tcpci_write8(chip, TCPC_FAULT_STATUS, reg_status);
+		if (ret < 0)
+			return ret;
+
+		if (reg_status & TCPC_FAULT_STATUS_VCONN_OC)
+			tcpm_port_error_recovery(chip->port);
+	}
+
 	if (status & TCPC_ALERT_EXTND) {
 		ret = max_tcpci_read8(chip, TCPC_ALERT_EXTENDED, &reg_status);
 		if (ret < 0)
include/linux/usb/tcpci.h +4 -1
index 83376473ac76..467e8045e9f8 100644
@@ -36,7 +36,9 @@
 
 #define TCPC_ALERT_MASK			0x12
 #define TCPC_POWER_STATUS_MASK		0x14
-#define TCPC_FAULT_STATUS_MASK		0x15
+
+#define TCPC_FAULT_STATUS_MASK			0x15
+#define TCPC_FAULT_STATUS_MASK_VCONN_OC		BIT(1)
 
 #define TCPC_EXTENDED_STATUS_MASK		0x16
 #define TCPC_EXTENDED_STATUS_MASK_VSAFE0V	BIT(0)
@@ -104,6 +106,7 @@
 
 #define TCPC_FAULT_STATUS		0x1f
 #define TCPC_FAULT_STATUS_ALL_REG_RST_TO_DEFAULT BIT(7)
+#define TCPC_FAULT_STATUS_VCONN_OC	BIT(1)
 
 #define TCPC_ALERT_EXTENDED		0x21
 
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
maintainer Reviewed-by on v1 2/2
#5 lore raw

Re: [PATCH v1 2/2] usb: typec: tcpci: add vconn over current fault handling to maxim_core

Quoted 6 lines · RD Babiera

Add TCPC_FAULT_STATUS_VCONN_OC constant and corresponding mask definition. Maxim TCPC is capable of detecting VConn over current faults, so add fault to alert mask. When a Vconn over current fault is triggered, put the port in an error recovery state via tcpm_port_error_recovery.

Quoted 72 lines
---
 drivers/usb/typec/tcpm/tcpci_maxim_core.c | 20 +++++++++++++++++++-
 include/linux/usb/tcpci.h                 |  5 ++++-
 2 files changed, 23 insertions(+), 2 deletions(-)
drivers/usb/typec/tcpm/tcpci_maxim_core.c +19 -1
index 9454b12a073c..7fb966fd639b 100644
@@ -92,11 +92,16 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
 		return;
 	}
 
+	/* Vconn Over Current Protection */
+	ret = max_tcpci_write8(chip, TCPC_FAULT_STATUS_MASK, TCPC_FAULT_STATUS_MASK_VCONN_OC);
+	if (ret < 0)
+		return;
+
 	alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED |
 		TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS |
 		TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS |
 		/* Enable Extended alert for detecting Fast Role Swap Signal */
-		TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS;
+		TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS | TCPC_ALERT_FAULT;
 
 	ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask);
 	if (ret < 0) {
@@ -295,6 +300,19 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
 		}
 	}
 
+	if (status & TCPC_ALERT_FAULT) {
+		ret = max_tcpci_read8(chip, TCPC_FAULT_STATUS, &reg_status);
+		if (ret < 0)
+			return ret;
+
+		ret = max_tcpci_write8(chip, TCPC_FAULT_STATUS, reg_status);
+		if (ret < 0)
+			return ret;
+
+		if (reg_status & TCPC_FAULT_STATUS_VCONN_OC)
+			tcpm_port_error_recovery(chip->port);
+	}
+
 	if (status & TCPC_ALERT_EXTND) {
 		ret = max_tcpci_read8(chip, TCPC_ALERT_EXTENDED, &reg_status);
 		if (ret < 0)
include/linux/usb/tcpci.h +4 -1
index 83376473ac76..467e8045e9f8 100644
@@ -36,7 +36,9 @@
 
 #define TCPC_ALERT_MASK			0x12
 #define TCPC_POWER_STATUS_MASK		0x14
-#define TCPC_FAULT_STATUS_MASK		0x15
+
+#define TCPC_FAULT_STATUS_MASK			0x15
+#define TCPC_FAULT_STATUS_MASK_VCONN_OC		BIT(1)
 
 #define TCPC_EXTENDED_STATUS_MASK		0x16
 #define TCPC_EXTENDED_STATUS_MASK_VSAFE0V	BIT(0)
@@ -104,6 +106,7 @@
 
 #define TCPC_FAULT_STATUS		0x1f
 #define TCPC_FAULT_STATUS_ALL_REG_RST_TO_DEFAULT BIT(7)
+#define TCPC_FAULT_STATUS_VCONN_OC	BIT(1)
 
 #define TCPC_ALERT_EXTENDED		0x21
 
Signature · 1 line
2.43.0.rc1.413.gea7ed67945-goog
Signature · 1 line
heikki
Reviewed-by on v1 2/2
#6 lore raw

Re: [PATCH v1 2/2] usb: typec: tcpci: add vconn over current fault handling to maxim_core

In reply to RD Babiera
Quoted 6 lines · RD Babiera

Add TCPC_FAULT_STATUS_VCONN_OC constant and corresponding mask definition. Maxim TCPC is capable of detecting VConn over current faults, so add fault to alert mask. When a Vconn over current fault is triggered, put the port in an error recovery state via tcpm_port_error_recovery.