summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usbc/usb_pe_ctvpd_sm.c4
-rw-r--r--common/usbc/usb_pe_drp_sm.c207
-rw-r--r--common/usbc/usb_prl_sm.c46
-rw-r--r--include/usb_prl_sm.h7
-rw-r--r--test/fake_prl.c5
-rw-r--r--test/usb_prl.c2
6 files changed, 177 insertions, 94 deletions
diff --git a/common/usbc/usb_pe_ctvpd_sm.c b/common/usbc/usb_pe_ctvpd_sm.c
index 5fe7a6b5a3..3e78ebcbb5 100644
--- a/common/usbc/usb_pe_ctvpd_sm.c
+++ b/common/usbc/usb_pe_ctvpd_sm.c
@@ -190,9 +190,9 @@ static void pe_request_run(const int port)
emsg[port].len = 20;
/* Set to highest revision supported by both ports. */
- prl_set_rev(port, (PD_HEADER_REV(header) > PD_REV30) ?
+ prl_set_rev(port, TCPC_TX_SOP_PRIME,
+ (PD_HEADER_REV(header) > PD_REV30) ?
PD_REV30 : PD_HEADER_REV(header));
-
/* Send the ACK */
prl_send_data_msg(port, TCPC_TX_SOP_PRIME,
PD_DATA_VENDOR_DEF);
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index 36921f7e73..f44a03abff 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -101,8 +101,10 @@
#define PE_FLAGS_FAST_ROLE_SWAP_SIGNALED BIT(22)
/* For PD2.0, triggers a DR SWAP from UFP to DFP before sending a DiscID msg */
#define PE_FLAGS_DR_SWAP_TO_DFP BIT(23)
+/* Flag to trigger a message resend after receiving a WAIT from port partner */
+#define PE_FLAGS_WAITING_DR_SWAP BIT(24)
/* FLAG to track if port partner is dualrole capable */
-#define PE_FLAGS_PORT_PARTNER_IS_DUALROLE BIT(24)
+#define PE_FLAGS_PORT_PARTNER_IS_DUALROLE BIT(25)
/* 6.7.3 Hard Reset Counter */
#define N_HARD_RESET_COUNT 2
@@ -111,7 +113,19 @@
#define N_CAPS_COUNT 25
/* 6.7.5 Discover Identity Counter */
-#define N_DISCOVER_IDENTITY_COUNT 20
+/*
+ * NOTE: The Protocol Layer tries to send a message 4 time before giving up,
+ * so a Discover Identity message will be sent 4*5 = 20 times.
+ */
+#define N_DISCOVER_IDENTITY_COUNT 5
+/*
+ * ChromeOS policy:
+ * For PD2.0, We must be DFP before sending Discover Identity message
+ * to the port partner. Attempt to DR SWAP from UFP to DFP
+ * N_DR_SWAP_ATTEMPT_COUNT times before giving up on sending a
+ * Discover Identity message.
+ */
+#define N_DR_SWAP_ATTEMPT_COUNT 5
#define TIMER_DISABLED 0xffffffffffffffff /* Unreachable time in future */
@@ -358,9 +372,9 @@ static struct policy_engine {
/*
* This timer is used during an Explicit Contract when discovering
- * whether a Cable Plug is PD Capable using SOP’.
+ * whether a Port Partner is PD Capable using SOP.
*/
- uint64_t discover_identity_timer;
+ uint64_t discover_port_identity_timer;
/*
* This timer is used in a Source to ensure that the Sink has had
@@ -432,11 +446,16 @@ static struct policy_engine {
uint32_t caps_counter;
/*
- * These counter maintain a count of Messages sent to a Port and
- * Cable Plug, respectively.
+ * This counter maintains a count of Discover Identity Messages sent
+ * to a port partner.
+ */
+ uint32_t discover_port_identity_counter;
+ /*
+ * For PD2.0, we need to be a DFP before sending a discovery identity
+ * messaage to our port partner. This counter keeps track of how
+ * many attempts to DR SWAP from UFP to DFP.
*/
- uint32_t port_discover_identity_count;
- uint32_t cable_discover_identity_count;
+ uint32_t dr_swap_attempt_counter;
/* Last received source cap */
uint32_t src_caps[PDO_MAX_OBJECTS];
@@ -932,6 +951,85 @@ static void pe_prl_execute_hard_reset(int port)
prl_execute_hard_reset(port);
}
+/*
+ * This function must only be called from the PE_SNK_READY entry and
+ * PE_SRC_READY entry State.
+ */
+static void pe_attempt_port_discovery(int port)
+{
+ if (!PE_CHK_FLAG(port, PE_FLAGS_MODAL_OPERATION |
+ PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE) &&
+ pe[port].discover_port_identity_counter <=
+ N_DISCOVER_IDENTITY_COUNT) {
+ /*
+ * If we are operating as PD2.0 version, make sure we are
+ * DFP before sending Discover Identity message.
+ */
+ if (prl_get_rev(port, TCPC_TX_SOP) == PD_REV20 &&
+ pe[port].data_role == PD_ROLE_UFP) {
+ /*
+ * If we are UFP and DR SWAP fails
+ * N_DR_SWAP_ATTEMPT_COUNT number of times, give up
+ * port discovery. Also give up if the Port Partner
+ * rejected the DR_SWAP.
+ */
+ if ((pe[port].dr_swap_attempt_counter >=
+ N_DR_SWAP_ATTEMPT_COUNT) ||
+ (pe[port].dr_swap_attempt_counter > 0 &&
+ !PE_CHK_FLAG(port, PE_FLAGS_WAITING_DR_SWAP))) {
+ PE_SET_FLAG(port,
+ PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE);
+ pe[port].discover_port_identity_timer =
+ TIMER_DISABLED;
+ } else {
+ PE_SET_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP);
+ pe[port].discover_port_identity_timer =
+ get_time().val + PD_T_DISCOVER_IDENTITY;
+ }
+ } else {
+ pe[port].discover_port_identity_timer =
+ get_time().val + PD_T_DISCOVER_IDENTITY;
+ }
+ } else {
+ PE_SET_FLAG(port, PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE);
+ pe[port].discover_port_identity_timer = TIMER_DISABLED;
+ }
+
+ /*
+ * For PD2.0, add some jitter of up to 100ms before sending a message.
+ * Some devices are chatty once we reach the SRC_READY state and we may
+ * end up in a collision of messages if we try to immediately send our
+ * interrogations.
+ */
+ if (prl_get_rev(port, TCPC_TX_SOP) == PD_REV20) {
+ if (pe[port].discover_port_identity_timer != TIMER_DISABLED)
+ pe[port].discover_port_identity_timer +=
+ (get_time().le.lo % (100 * MSEC));
+ }
+
+ /* Clear the PE_FLAGS_WAITING_DR_SWAP flag if it was set. */
+ PE_CLR_FLAG(port, PE_FLAGS_WAITING_DR_SWAP);
+}
+
+/*
+ * This function must only be called from the PE_SNK_READY run and
+ * PE_SRC_READY run State.
+ */
+static void pe_start_port_discovery(int port)
+{
+ if (PE_CHK_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP)) {
+ PE_CLR_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP);
+ pe[port].dr_swap_attempt_counter++;
+ set_state_pe(port, PE_DRS_SEND_SWAP);
+ } else {
+ pe[port].discover_port_identity_counter++;
+ pe[port].vdm_cmd = DO_PORT_DISCOVERY_START;
+ PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_NAKED |
+ PE_FLAGS_VDM_REQUEST_BUSY);
+ set_state_pe(port, PE_DO_PORT_DISCOVERY);
+ }
+}
+
/**
* PE_SRC_Startup
*/
@@ -961,8 +1059,12 @@ static void pe_src_startup_entry(int port)
/* Clear explicit contract. */
pe_invalidate_explicit_contract(port);
- pe[port].cable_discover_identity_count = 0;
- pe[port].port_discover_identity_count = 0;
+ /* Clear port discovery flags */
+ PE_CLR_FLAG(port, PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE);
+ pe[port].discover_port_identity_counter = 0;
+
+ /* Reset dr swap attempt counter */
+ pe[port].dr_swap_attempt_counter = 0;
if (PE_CHK_FLAG(port, PE_FLAGS_RUN_SOURCE_START_TIMER)) {
PE_CLR_FLAG(port, PE_FLAGS_RUN_SOURCE_START_TIMER);
@@ -1111,7 +1213,7 @@ static void pe_src_send_capabilities_run(int port)
* Set to highest revision supported by both
* ports.
*/
- prl_set_rev(port,
+ prl_set_rev(port, TCPC_TX_SOP,
(PD_HEADER_REV(emsg[port].header) > PD_REV30) ?
PD_REV30 : PD_HEADER_REV(emsg[port].header));
@@ -1315,20 +1417,11 @@ static void pe_src_ready_entry(int port)
/*
* Do port partner discovery
+ *
+ * This function modifies state variables that are used in the run
+ * part of this state. See pe_attempt_port_discovery for details.
*/
- if (!PE_CHK_FLAG(port, PE_FLAGS_MODAL_OPERATION |
- PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE) &&
- pe[port].port_discover_identity_count <=
- N_DISCOVER_IDENTITY_COUNT) {
- pe[port].discover_identity_timer =
- get_time().val + PD_T_DISCOVER_IDENTITY;
- } else {
- PE_SET_FLAG(port, PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE);
- pe[port].discover_identity_timer = TIMER_DISABLED;
- }
-
- /* NOTE: PPS Implementation should be added here. */
-
+ pe_attempt_port_discovery(port);
}
static void pe_src_ready_run(int port)
@@ -1342,12 +1435,8 @@ static void pe_src_ready_run(int port)
* Start Port Discovery when:
* 1) The DiscoverIdentityTimer times out.
*/
- if (get_time().val > pe[port].discover_identity_timer) {
- pe[port].port_discover_identity_count++;
- pe[port].vdm_cmd = DO_PORT_DISCOVERY_START;
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_NAKED |
- PE_FLAGS_VDM_REQUEST_BUSY);
- set_state_pe(port, PE_DO_PORT_DISCOVERY);
+ if (get_time().val > pe[port].discover_port_identity_timer) {
+ pe_start_port_discovery(port);
return;
}
@@ -1691,6 +1780,13 @@ static void pe_snk_startup_entry(int port)
/* Clear explicit contract */
pe_invalidate_explicit_contract(port);
+
+ /* Clear port discovery flags */
+ PE_CLR_FLAG(port, PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE);
+ pe[port].discover_port_identity_counter = 0;
+
+ /* Reset dr swap attempt counter */
+ pe[port].dr_swap_attempt_counter = 0;
}
static void pe_snk_startup_run(int port)
@@ -1781,7 +1877,7 @@ static void pe_snk_evaluate_capability_entry(int port)
pe[port].hard_reset_counter = 0;
/* Set to highest revision supported by both ports. */
- prl_set_rev(port, (PD_HEADER_REV(header) > PD_REV30) ?
+ prl_set_rev(port, TCPC_TX_SOP, (PD_HEADER_REV(header) > PD_REV30) ?
PD_REV30 : PD_HEADER_REV(header));
pe[port].src_cap_cnt = num;
@@ -1964,6 +2060,7 @@ static void pe_snk_transition_sink_exit(int port)
CEIL_REQUESTOR_PD, pe[port].curr_limit);
}
+
/**
* PE_SNK_Ready State
*/
@@ -1989,24 +2086,11 @@ static void pe_snk_ready_entry(int port)
/*
* Do port partner discovery
+ *
+ * This function modifies state variables that are used in the run
+ * part of this state. See pe_attempt_port_discovery for details.
*/
- if (!PE_CHK_FLAG(port, PE_FLAGS_MODAL_OPERATION |
- PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE) &&
- pe[port].port_discover_identity_count <=
- N_DISCOVER_IDENTITY_COUNT) {
- pe[port].discover_identity_timer =
- get_time().val + PD_T_DISCOVER_IDENTITY;
- } else {
- PE_SET_FLAG(port, PE_FLAGS_DISCOVER_PORT_IDENTITY_DONE);
- pe[port].discover_identity_timer = TIMER_DISABLED;
- }
-
- /*
- * On entry to the PE_SNK_Ready state if the current Explicit Contract
- * is for a PPS APDO, then do the following:
- * 1) Initialize and run the SinkPPSPeriodicTimer.
- * NOTE: PPS Implementation should be added here.
- */
+ pe_attempt_port_discovery(port);
}
static void pe_snk_ready_run(int port)
@@ -2023,14 +2107,10 @@ static void pe_snk_ready_run(int port)
/*
* Start Port Discovery when:
- * 1) The DiscoverIdentityTimer times out.
+ * 1) The PortDiscoverIdentityTimer times out.
*/
- if (get_time().val > pe[port].discover_identity_timer) {
- pe[port].port_discover_identity_count++;
- pe[port].vdm_cmd = DO_PORT_DISCOVERY_START;
- PE_CLR_FLAG(port, PE_FLAGS_VDM_REQUEST_NAKED |
- PE_FLAGS_VDM_REQUEST_BUSY);
- set_state_pe(port, PE_DO_PORT_DISCOVERY);
+ if (get_time().val > pe[port].discover_port_identity_timer) {
+ pe_start_port_discovery(port);
return;
}
@@ -2400,7 +2480,7 @@ static void pe_send_not_supported_entry(int port)
print_current_state(port);
/* Request the Protocol Layer to send a Not_Supported Message. */
- if (prl_get_rev(port) > PD_REV20)
+ if (prl_get_rev(port, TCPC_TX_SOP) > PD_REV20)
prl_send_ctrl_msg(port, TCPC_TX_SOP, PD_CTRL_NOT_SUPPORTED);
else
prl_send_ctrl_msg(port, TCPC_TX_SOP, PD_CTRL_REJECT);
@@ -2673,6 +2753,9 @@ static void pe_drs_change_run(int port)
/* Update the data role */
pe[port].data_role = tc_get_data_role(port);
+ if (pe[port].data_role == PD_ROLE_DFP)
+ PE_CLR_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP);
+
/*
* Port changed. Transition back to PE_SRC_Ready or
* PE_SNK_Ready.
@@ -2735,6 +2818,10 @@ static void pe_drs_send_swap_run(int port)
return;
} else if ((type == PD_CTRL_REJECT) ||
(type == PD_CTRL_WAIT)) {
+ if (type == PD_CTRL_WAIT)
+ PE_SET_FLAG(port,
+ PE_FLAGS_WAITING_DR_SWAP);
+
if (pe[port].power_role == PD_ROLE_SINK)
set_state_pe(port, PE_SNK_READY);
else
@@ -4059,8 +4146,8 @@ static void pe_vcs_turn_off_vconn_swap_run(int port)
* A VCONN Swap Shall reset the DiscoverIdentityCounter
* to zero
*/
- pe[port].cable_discover_identity_count = 0;
- pe[port].port_discover_identity_count = 0;
+ pe[port].discover_port_identity_counter = 0;
+ pe[port].dr_swap_attempt_counter = 0;
if (pe[port].power_role == PD_ROLE_SOURCE)
set_state_pe(port, PE_SRC_READY);
@@ -4108,8 +4195,8 @@ static void pe_vcs_send_ps_rdy_swap_run(int port)
* A VCONN Swap Shall reset the
* DiscoverIdentityCounter to zero
*/
- pe[port].cable_discover_identity_count = 0;
- pe[port].port_discover_identity_count = 0;
+ pe[port].discover_port_identity_counter = 0;
+ pe[port].dr_swap_attempt_counter = 0;
if (pe[port].power_role == PD_ROLE_SOURCE)
set_state_pe(port, PE_SRC_READY);
diff --git a/common/usbc/usb_prl_sm.c b/common/usbc/usb_prl_sm.c
index 00460d86cb..de4dda7db1 100644
--- a/common/usbc/usb_prl_sm.c
+++ b/common/usbc/usb_prl_sm.c
@@ -205,9 +205,7 @@ static struct pd_message {
/* extended message */
uint8_t ext;
/* PD revision */
- enum pd_rev_type rev;
- /* Cable PD revision */
- enum pd_rev_type cable_rev;
+ enum pd_rev_type rev[NUM_SOP_STAR_TYPES];
/* Number of 32-bit objects in chk_buf */
uint16_t data_objs;
/* temp chunk buffer */
@@ -325,8 +323,11 @@ static void prl_init(int port)
* partner doesn't support this revision, the Protocol Engine will
* lower this value to the revision supported by the partner.
*/
- pdmsg[port].cable_rev = PD_REV30;
- pdmsg[port].rev = PD_REV30;
+ pdmsg[port].rev[TCPC_TX_SOP] = PD_REV30;
+ pdmsg[port].rev[TCPC_TX_SOP_PRIME] = PD_REV30;
+ pdmsg[port].rev[TCPC_TX_SOP_PRIME_PRIME] = PD_REV30;
+ pdmsg[port].rev[TCPC_TX_SOP_DEBUG_PRIME] = PD_REV30;
+ pdmsg[port].rev[TCPC_TX_SOP_DEBUG_PRIME_PRIME] = PD_REV30;
pdmsg[port].flags = 0;
prl_hr[port].flags = 0;
@@ -453,24 +454,14 @@ void prl_run(int port, int evt, int en)
}
}
-void prl_set_rev(int port, enum pd_rev_type rev)
+void prl_set_rev(int port, enum tcpm_transmit_type type,
+ enum pd_rev_type rev)
{
- pdmsg[port].rev = rev;
+ pdmsg[port].rev[type] = rev;
}
-
-enum pd_rev_type prl_get_rev(int port)
-{
- return pdmsg[port].rev;
-}
-
-void prl_set_cable_rev(int port, enum pd_rev_type rev)
+enum pd_rev_type prl_get_rev(int port, enum tcpm_transmit_type type)
{
- pdmsg[port].cable_rev = rev;
-}
-
-enum pd_rev_type prl_get_cable_rev(int port)
-{
- return pdmsg[port].cable_rev;
+ return pdmsg[port].rev[type];
}
/* Common Protocol Layer Message Transmission */
@@ -517,8 +508,9 @@ static void prl_tx_wait_for_message_request_run(const int port)
}
return;
- } else if ((pdmsg[port].rev == PD_REV30) && PRL_TX_CHK_FLAG(port,
- (PRL_FLAGS_START_AMS | PRL_FLAGS_END_AMS))) {
+ } else if ((prl_get_rev(port, pdmsg[port].xmit_type) == PD_REV30) &&
+ PRL_TX_CHK_FLAG(port, (PRL_FLAGS_START_AMS |
+ PRL_FLAGS_END_AMS))) {
if (tc_get_power_role(port) == PD_ROLE_SOURCE) {
/*
* Start of AMS notification received from
@@ -639,8 +631,7 @@ static uint32_t get_sop_star_header(const int port)
tc_get_data_role(port) : 0,
prl_tx[port].msg_id_counter[pdmsg[port].xmit_type],
pdmsg[port].data_objs,
- is_sop_packet ?
- pdmsg[port].rev : pdmsg[port].cable_rev,
+ pdmsg[port].rev[pdmsg[port].xmit_type],
pdmsg[port].ext);
}
@@ -960,7 +951,7 @@ static void rch_wait_for_message_from_protocol_layer_run(const int port)
* Are we communicating with a PD3.0 device and is
* this an extended message?
*/
- if (pdmsg[port].rev == PD_REV30 &&
+ if (prl_get_rev(port, pdmsg[port].xmit_type) == PD_REV30 &&
PD_HEADER_EXT(emsg[port].header)) {
uint16_t exhdr = GET_EXT_HEADER(*pdmsg[port].chk_buf);
uint8_t chunked = PD_EXT_HEADER_CHUNKED(exhdr);
@@ -1261,7 +1252,8 @@ static void tch_wait_for_message_request_from_pe_run(const int port)
/*
* Extended Message Request & Chunking
*/
- if ((pdmsg[port].rev == PD_REV30) && pdmsg[port].ext &&
+ if (prl_get_rev(port, pdmsg[port].xmit_type) == PD_REV30
+ && pdmsg[port].ext &&
TCH_CHK_FLAG(port, PRL_FLAGS_CHUNKING)) {
/*
* NOTE: TCH_Prepare_To_Send_Chunked_Message
@@ -1575,7 +1567,7 @@ static void prl_rx_wait_for_phy_message(const int port, int evt)
* Discard any pending tx message if this is
* not a ping message
*/
- if ((pdmsg[port].rev == PD_REV30) &&
+ if (prl_get_rev(port, pdmsg[port].xmit_type) == PD_REV30 &&
(cnt == 0) && type != PD_CTRL_PING) {
if (prl_tx_get_state(port) == PRL_TX_SRC_PENDING ||
prl_tx_get_state(port) == PRL_TX_SNK_PENDING)
diff --git a/include/usb_prl_sm.h b/include/usb_prl_sm.h
index 447cbb994f..e17a28c131 100644
--- a/include/usb_prl_sm.h
+++ b/include/usb_prl_sm.h
@@ -45,17 +45,20 @@ void prl_run(int port, int evt, int en);
* Set the PD revision
*
* @param port USB-C port number
+ * @param type port address
* @param rev revision
*/
-void prl_set_rev(int port, enum pd_rev_type rev);
+void prl_set_rev(int port, enum tcpm_transmit_type type,
+ enum pd_rev_type rev);
/**
* Get the PD revision
*
* @param port USB-C port number
+ * @param type port address
* @return pd rev
*/
-enum pd_rev_type prl_get_rev(int port);
+enum pd_rev_type prl_get_rev(int port, enum tcpm_transmit_type type);
/**
* Sends a PD control message
diff --git a/test/fake_prl.c b/test/fake_prl.c
index 58f3c17130..77e3331729 100644
--- a/test/fake_prl.c
+++ b/test/fake_prl.c
@@ -16,7 +16,7 @@ void prl_end_ams(int port)
void prl_execute_hard_reset(int port)
{}
-enum pd_rev_type prl_get_rev(int port)
+enum pd_rev_type prl_get_rev(int port, enum tcpm_transmit_type partner)
{
return PD_REV30;
}
@@ -47,7 +47,8 @@ void prl_send_ext_data_msg(int port, enum tcpm_transmit_type type,
enum pd_ext_msg_type msg)
{}
-void prl_set_rev(int port, enum pd_rev_type rev)
+void prl_set_rev(int port, enum tcpm_transmit_type partner,
+ enum pd_rev_type rev)
{}
void prl_start_ams(int port)
diff --git a/test/usb_prl.c b/test/usb_prl.c
index 90cadbb230..425ba8ceca 100644
--- a/test/usb_prl.c
+++ b/test/usb_prl.c
@@ -714,7 +714,7 @@ static void enable_prl(int port, int en)
/* Init PRL */
cycle_through_state_machine(port, 10, MSEC);
- prl_set_rev(port, pd_port[port].rev);
+ prl_set_rev(port, TCPC_TX_SOP, pd_port[port].rev);
}
enum pd_power_role tc_get_power_role(int port)