summaryrefslogtreecommitdiff
path: root/common/usb_pd_protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usb_pd_protocol.c')
-rw-r--r--common/usb_pd_protocol.c102
1 files changed, 101 insertions, 1 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index a73175a725..6e29bf06b8 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -295,6 +295,7 @@ static const char * const pd_state_names[] = {
"SOFT_RESET", "HARD_RESET_SEND", "HARD_RESET_EXECUTE", "BIST_RX",
"BIST_TX",
"DRP_AUTO_TOGGLE",
+ "ENTER_USB",
};
BUILD_ASSERT(ARRAY_SIZE(pd_state_names) == PD_STATE_COUNT);
#endif
@@ -1689,6 +1690,12 @@ static void handle_data_request(int port, uint16_t head,
#ifdef CONFIG_USB_PD_REV30
case PD_DATA_BATTERY_STATUS:
break;
+ /* TODO : Add case PD_DATA_RESET for exiting USB4 */
+
+ /*
+ * TODO : Add case PD_DATA_ENTER_USB to accept or reject
+ * Enter_USB request from port partner.
+ */
#endif
case PD_DATA_VENDOR_DEF:
handle_vdm_request(port, cnt, payload, head);
@@ -1856,6 +1863,21 @@ static void handle_ctrl_request(int port, uint16_t head,
break;
#endif
case PD_CTRL_REJECT:
+ if (pd[port].task_state == PD_STATE_ENTER_USB) {
+ if (!IS_ENABLED(CONFIG_USBC_SS_MUX))
+ break;
+
+ /*
+ * Since Enter USB sets the mux state to SAFE mode,
+ * resetting the mux state back to USB mode on
+ * recieveing a NACK.
+ */
+ usb_mux_set(port, USB_PD_MUX_USB_ENABLED,
+ USB_SWITCH_CONNECT, pd[port].polarity);
+
+ set_state(port, READY_RETURN_STATE(port));
+ break;
+ }
case PD_CTRL_WAIT:
if (pd[port].task_state == PD_STATE_DR_SWAP) {
if (type == PD_CTRL_WAIT) /* try again ... */
@@ -1918,7 +1940,20 @@ static void handle_ctrl_request(int port, uint16_t head,
#endif
break;
case PD_CTRL_ACCEPT:
- if (pd[port].task_state == PD_STATE_SOFT_RESET) {
+ if (pd[port].task_state == PD_STATE_ENTER_USB) {
+ if (!IS_ENABLED(CONFIG_USBC_SS_MUX))
+ break;
+
+ /* Connect the SBU and USB lines to the connector */
+ if (IS_ENABLED(CONFIG_USBC_PPC_SBU))
+ ppc_set_sbu(port, 1);
+
+ /* Set usb mux to USB4 mode */
+ usb_mux_set(port, USB_PD_MUX_USB4_ENABLED,
+ USB_SWITCH_CONNECT, pd[port].polarity);
+
+ set_state(port, READY_RETURN_STATE(port));
+ } else if (pd[port].task_state == PD_STATE_SOFT_RESET) {
/*
* For the case that we sent soft reset in SNK_DISCOVERY
* on startup due to VBUS never low, clear the flag.
@@ -2836,6 +2871,46 @@ void pd_interrupt_handler_task(void *p)
}
#endif /* HAS_TASK_PD_INT_C0 || HAS_TASK_PD_INT_C1 || HAS_TASK_PD_INT_C2 */
+static void pd_send_enter_usb(int port, int *timeout)
+{
+ uint32_t usb4_payload = get_enter_usb_msg_payload(port);
+ uint16_t header;
+ int res;
+
+ /*
+ * TODO: Enable Enter USB for cables (SOP').
+ * This is needed for active cables
+ */
+ if (!IS_ENABLED(CONFIG_USBC_SS_MUX) || !IS_ENABLED(CONFIG_USB_PD_USB4))
+ return;
+
+ header = PD_HEADER(PD_DATA_ENTER_USB,
+ pd[port].power_role,
+ pd[port].data_role,
+ pd[port].msg_id,
+ 1,
+ PD_REV30,
+ 0);
+
+ res = pd_transmit(port, TCPC_TX_SOP, header, &usb4_payload, AMS_START);
+ if (res < 0) {
+ *timeout = 10*MSEC;
+ /*
+ * If failed to get goodCRC, send soft reset, otherwise ignore
+ * failure.
+ */
+ set_state(port, res == -1 ?
+ PD_STATE_SOFT_RESET :
+ READY_RETURN_STATE(port));
+ return;
+ }
+
+ /* Disable Enter USB4 mode prevent re-entry */
+ disable_enter_usb4_mode(port);
+
+ set_state(port, PD_STATE_ENTER_USB);
+}
+
void pd_task(void *u)
{
int head;
@@ -3699,6 +3774,15 @@ void pd_task(void *u)
break;
}
+ /*
+ * Enter_USB if port partner and cable are
+ * USB4 compatible.
+ */
+ if (should_enter_usb4_mode(port)) {
+ pd_send_enter_usb(port, &timeout);
+ break;
+ }
+
if (!(pd[port].flags & PD_FLAGS_PING_ENABLED))
break;
@@ -4312,6 +4396,15 @@ void pd_task(void *u)
break;
}
+ /*
+ * Enter_USB if port partner and cable are
+ * USB4 compatible.
+ */
+ if (should_enter_usb4_mode(port)) {
+ pd_send_enter_usb(port, &timeout);
+ break;
+ }
+
/* Sent all messages, don't need to wake very often */
timeout = 200*MSEC;
break;
@@ -4687,6 +4780,13 @@ void pd_task(void *u)
break;
}
#endif
+ case PD_STATE_ENTER_USB:
+ if (pd[port].last_state != pd[port].task_state) {
+ set_state_timeout(port,
+ get_time().val + PD_T_SENDER_RESPONSE,
+ READY_RETURN_STATE(port));
+ }
+ break;
default:
break;
}