summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJameson Thies <jthies@google.com>2022-04-26 00:31:30 +0000
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-05-04 22:27:27 +0000
commitcb74b8ed9fdc852bc5b4d79424a5b4434a939742 (patch)
treed321af60342f68aa0f8b2cb08b0e22e2e9c0027c
parent94b53640add6248bd7f6847a1c0096e07db04188 (diff)
downloadchrome-ec-cb74b8ed9fdc852bc5b4d79424a5b4434a939742.tar.gz
TCPMv2: Request partner's revision information in src/snk startup
Adding features from the USB PD 3.1 revision of the specification requires us to know the difference between USB PD Rev 3.0 and USB PD Rev 3.1 devices. But, the message header only has 2 bits for revision and only provides the major revision. To determine a devices minor revision, TCPMv2 will need to send a Get_Revision command and store the Revision response which has major/minor revision/version information. This CL adds support for sending Get_Revision, and receiving Revision. BUG=b:214087135 TEST=Checked that the PE state was correctly holding the Revision response from a USB PD Rev 3.1 partner, and also checked that the stored RMDO value was 0 for a USB PD Rev 3.0 partner. BRANCH=none Signed-off-by: Jameson Thies <jthies@google.com> Change-Id: I99f10c15750c3a1fee1d8bad89b0c4a0b0a6b2ba Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3607054 Reviewed-by: Abe Levkoy <alevkoy@chromium.org>
-rw-r--r--common/mock/tcpci_i2c_mock.c12
-rw-r--r--common/usbc/usb_pe_drp_sm.c114
-rw-r--r--include/usb_pd.h38
-rw-r--r--test/usb_pe_drp.c9
-rw-r--r--test/usb_tcpmv2_compliance_common.c22
5 files changed, 189 insertions, 6 deletions
diff --git a/common/mock/tcpci_i2c_mock.c b/common/mock/tcpci_i2c_mock.c
index 8ec7556fca..c9b9f71738 100644
--- a/common/mock/tcpci_i2c_mock.c
+++ b/common/mock/tcpci_i2c_mock.c
@@ -99,6 +99,9 @@ static const char * const ctrl_msg_name[] = {
[PD_CTRL_FR_SWAP] = "C-FR_SWAP",
[PD_CTRL_GET_PPS_STATUS] = "C-GET_PPS_STATUS",
[PD_CTRL_GET_COUNTRY_CODES] = "C-GET_COUNTRY_CODES",
+ [PD_CTRL_GET_SINK_CAP_EXT] = "C-GET_SINK_CAP_EXT",
+ [PD_CTRL_GET_SOURCE_INFO] = "C-GET_SOURCE_INFO",
+ [PD_CTRL_GET_REVISION] = "C-GET_REVISION",
};
static const char * const data_msg_name[] = {
@@ -113,6 +116,11 @@ static const char * const data_msg_name[] = {
[PD_DATA_GET_COUNTRY_INFO] = "D-GET_COUNTRY_CODES",
/* 8-14 Reserved for REV 3.0 */
[PD_DATA_ENTER_USB] = "D-ENTER_USB",
+ [PD_DATA_EPR_REQUEST] = "D-EPR_REQUEST",
+ [PD_DATA_EPR_MODE] = "D-EPR_MODE",
+ [PD_DATA_SOURCE_INFO] = "D-EPR_SOURCE_INFO",
+ [PD_DATA_REVISION] = "D-REVISION",
+ /* 13-14 Reserved for REV 3.0 */
[PD_DATA_VENDOR_DEF] = "D-VDM",
};
@@ -132,6 +140,10 @@ static const char * const ext_msg_name[] = {
[PD_EXT_PPS_STATUS] = "X-PPS_STATUS",
[PD_EXT_COUNTRY_INFO] = "X-COUNTRY_INFO",
[PD_EXT_COUNTRY_CODES] = "X-COUNTRY_CODES",
+ [PD_EXT_SINK_CAP] = "X-SNK_CAP",
+ [PD_EXT_CONTROL] = "X-CONTROL",
+ [PD_EXT_EPR_SOURCE_CAP] = "X-EPR_SRC_CAP",
+ [PD_EXT_EPR_SINK_CAP] = "X-EPR_SNK_CAP",
};
static const char * const rev_name[] = {
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index bc3dcf48e7..352e2b4fe3 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -275,6 +275,7 @@ enum usb_pe_state {
PE_SRC_CHUNK_RECEIVED,
PE_SNK_CHUNK_RECEIVED,
PE_VCS_FORCE_VCONN,
+ PE_GET_REVISION,
};
/*
@@ -390,6 +391,7 @@ __maybe_unused static __const_data const char * const pe_state_names[] = {
/* PD3.0 only states below here*/
#ifdef CONFIG_USB_PD_REV30
[PE_FRS_SNK_SRC_START_AMS] = "PE_FRS_SNK_SRC_Start_Ams",
+ [PE_GET_REVISION] = "PE_Get_Revision",
#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
[PE_GIVE_BATTERY_CAP] = "PE_Give_Battery_Cap",
[PE_GIVE_BATTERY_STATUS] = "PE_Give_Battery_Status",
@@ -435,6 +437,8 @@ GEN_NOT_SUPPORTED(PE_SRC_CHUNK_RECEIVED);
#define PE_SRC_CHUNK_RECEIVED PE_SRC_CHUNK_RECEIVED_NOT_SUPPORTED
GEN_NOT_SUPPORTED(PE_SNK_CHUNK_RECEIVED);
#define PE_SNK_CHUNK_RECEIVED PE_SNK_CHUNK_RECEIVED_NOT_SUPPORTED
+GEN_NOT_SUPPORTED(PE_GET_REVISION);
+#define PE_GET_REVISION PE_GET_REVISION_NOT_SUPPORTED
#endif /* CONFIG_USB_PD_REV30 */
#if !defined(CONFIG_USBC_VCONN) || !defined(CONFIG_USB_PD_REV30)
@@ -622,6 +626,9 @@ static struct policy_engine {
uint32_t snk_caps[PDO_MAX_OBJECTS];
int snk_cap_cnt;
+ /* Last received Revision Message Data Object (RMDO) from the partner */
+ struct rmdo partner_rmdo;
+
/* Attached ChromeOS device id, RW hash, and current RO / RW image */
uint16_t dev_id;
uint32_t dev_rw_hash[PD_RW_HASH_SIZE/4];
@@ -1353,6 +1360,15 @@ static void pe_clear_port_data(int port)
pd_set_src_caps(port, 0, NULL);
pe_set_snk_caps(port, 0, NULL);
+ /*
+ * Saved Revision responses are no longer valid on disconnect
+ */
+ pe[port].partner_rmdo.reserved = 0;
+ pe[port].partner_rmdo.minor_ver = 0;
+ pe[port].partner_rmdo.major_ver = 0;
+ pe[port].partner_rmdo.minor_rev = 0;
+ pe[port].partner_rmdo.major_rev = 0;
+
/* Clear any stored discovery data, but leave modes for alt mode exit */
pd_dfp_discovery_init(port);
@@ -1558,6 +1574,11 @@ static bool common_src_snk_dpm_requests(int port)
else
return false;
return true;
+ } else if (IS_ENABLED(CONFIG_USB_PD_REV30) &&
+ PE_CHK_DPM_REQUEST(port, DPM_REQUEST_GET_REVISION)) {
+ pe_set_dpm_curr_request(port, DPM_REQUEST_GET_REVISION);
+ set_state_pe(port, PE_GET_REVISION);
+ return true;
}
return false;
@@ -2190,6 +2211,14 @@ static void pe_src_startup_entry(int port)
CONFIG_USB_PD_3A_PORTS > 0 ||
IS_ENABLED(CONFIG_USB_PD_FRS))
pd_dpm_request(port, DPM_REQUEST_GET_SNK_CAPS);
+
+ /*
+ * Request partner's revision information. The PE_Get_Revision
+ * state will only send Get_Revision to partners with major
+ * revision 3.0
+ */
+ pd_dpm_request(port, DPM_REQUEST_GET_REVISION);
+
}
}
@@ -3080,6 +3109,13 @@ static void pe_snk_startup_entry(int port)
IS_ENABLED(CONFIG_USB_PD_FRS))
pd_dpm_request(port, DPM_REQUEST_GET_SNK_CAPS);
+ /*
+ * Request partner's revision information. The PE_Get_Revision
+ * state will only send Get_Revision to partners with major
+ * revision 3.0
+ */
+ pd_dpm_request(port, DPM_REQUEST_GET_REVISION);
+
}
static void pe_snk_startup_run(int port)
@@ -7072,6 +7108,79 @@ static void pe_dr_src_get_source_cap_exit(int port)
pe_sender_response_msg_exit(port);
}
+/*
+ * PE_Get_Revision
+ */
+__maybe_unused static void pe_get_revision_entry(int port)
+{
+ print_current_state(port);
+
+ /*
+ * Only USB PD partners with major revision 3.0 could potentially
+ * respond to Get_Revision.
+ */
+ if (prl_get_rev(port, TCPCI_MSG_SOP) != PD_REV30)
+ return;
+
+ /* Send a Get_Revision message */
+ send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_GET_REVISION);
+ pe_sender_response_msg_entry(port);
+}
+
+__maybe_unused static void pe_get_revision_run(int port)
+{
+ int type;
+ int cnt;
+ int ext;
+ enum pe_msg_check msg_check;
+
+ if (prl_get_rev(port, TCPCI_MSG_SOP) != PD_REV30) {
+ pe_set_ready_state(port);
+ return;
+ }
+
+ /* Check the state of the message sent */
+ msg_check = pe_sender_response_msg_run(port);
+
+ if ((msg_check & PE_MSG_SENT) &&
+ PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
+ PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
+
+ type = PD_HEADER_TYPE(rx_emsg[port].header);
+ cnt = PD_HEADER_CNT(rx_emsg[port].header);
+ ext = PD_HEADER_EXT(rx_emsg[port].header);
+
+ if (ext == 0 && cnt == 1 && type == PD_DATA_REVISION) {
+ /* Revision returned by partner */
+ pe[port].partner_rmdo =
+ *((struct rmdo *) rx_emsg[port].buf);
+ }
+
+ /*
+ * Get_Revision is an interruptible AMS. Return to ready state
+ * after response whether or not there was a protocol error.
+ */
+ pe_set_ready_state(port);
+ return;
+ }
+
+ /*
+ * Return to ready state if the message was discarded or timer expires
+ */
+ if ((msg_check & PE_MSG_DISCARDED) ||
+ pd_timer_is_expired(port, PE_TIMER_SENDER_RESPONSE))
+ pe_set_ready_state(port);
+
+}
+
+__maybe_unused static void pe_get_revision_exit(int port)
+{
+ if (prl_get_rev(port, TCPCI_MSG_SOP) != PD_REV30)
+ return;
+
+ pe_sender_response_msg_exit(port);
+}
+
#ifdef CONFIG_USB_PD_DATA_RESET_MSG
/*
* PE_DDR_Send_Data_Reset
@@ -7797,6 +7906,11 @@ static __const_data const struct usb_state pe_states[] = {
.entry = pe_frs_snk_src_start_ams_entry,
.parent = &pe_states[PE_PRS_FRS_SHARED],
},
+ [PE_GET_REVISION] = {
+ .entry = pe_get_revision_entry,
+ .run = pe_get_revision_run,
+ .exit = pe_get_revision_exit,
+ },
#ifdef CONFIG_USB_PD_EXTENDED_MESSAGES
[PE_GIVE_BATTERY_CAP] = {
.entry = pe_give_battery_cap_entry,
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 5b389e1bb4..8ec4e9eaf3 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -590,6 +590,18 @@ struct partner_active_modes {
#define PD_PRODUCT_PID(vdo) (((vdo) >> 16) & 0xffff)
/*
+ * PD Rev 3.1 Revision Message Data Object (RMDO)
+ * Only bits 16-31 have data. A uint_16t is used to hold RMDOs upper 16 bits.
+ */
+struct rmdo {
+ int reserved : 16;
+ int minor_ver : 4;
+ int major_ver : 4;
+ int minor_rev : 4;
+ int major_rev : 4;
+};
+
+/*
* Message id starts from 0 to 7. If last_msg_id is initialized to 0,
* it will lead to repetitive message id with first received packet,
* so initialize it with an invalid value 0xff.
@@ -1017,6 +1029,7 @@ enum pd_dpm_request {
DPM_REQUEST_FRS_DET_ENABLE = BIT(21),
DPM_REQUEST_FRS_DET_DISABLE = BIT(22),
DPM_REQUEST_DATA_RESET = BIT(23),
+ DPM_REQUEST_GET_REVISION = BIT(24),
};
/**
@@ -1152,7 +1165,11 @@ enum pd_ctrl_msg_type {
PD_CTRL_FR_SWAP = 19,
PD_CTRL_GET_PPS_STATUS = 20,
PD_CTRL_GET_COUNTRY_CODES = 21,
- /* 22-31 Reserved */
+ PD_CTRL_GET_SINK_CAP_EXT = 22,
+ /* Used for REV 3.1 */
+ PD_CTRL_GET_SOURCE_INFO = 23,
+ PD_CTRL_GET_REVISION = 24,
+ /* 25-31 Reserved */
};
/* Control message types which always mark the start of an AMS */
@@ -1225,7 +1242,14 @@ enum pd_ext_msg_type {
PD_EXT_PPS_STATUS = 12,
PD_EXT_COUNTRY_INFO = 13,
PD_EXT_COUNTRY_CODES = 14,
- /* 15-31 Reserved */
+ /* Used for REV 3.1 */
+ PD_EXT_SINK_CAP = 15,
+ PD_EXT_CONTROL = 16,
+ PD_EXT_EPR_SOURCE_CAP = 17,
+ PD_EXT_EPR_SINK_CAP = 18,
+ /* 19-29 Reserved */
+ PD_EXT_VENDOR_DEF = 30,
+ /* 31 Reserved */
};
/* Alert Data Object fields for REV 3.0 */
@@ -1245,13 +1269,19 @@ enum pd_data_msg_type {
PD_DATA_REQUEST = 2,
PD_DATA_BIST = 3,
PD_DATA_SINK_CAP = 4,
- /* 5-14 Reserved for REV 2.0 */
+ /* Used for REV 3.0 */
PD_DATA_BATTERY_STATUS = 5,
PD_DATA_ALERT = 6,
PD_DATA_GET_COUNTRY_INFO = 7,
- /* 8-14 Reserved for REV 3.0 */
PD_DATA_ENTER_USB = 8,
+ /* Used for REV 3.1 */
+ PD_DATA_EPR_REQUEST = 9,
+ PD_DATA_EPR_MODE = 10,
+ PD_DATA_SOURCE_INFO = 11,
+ PD_DATA_REVISION = 12,
+ /* 13-14 Reserved */
PD_DATA_VENDOR_DEF = 15,
+ /* 16-31 Reserved */
};
diff --git a/test/usb_pe_drp.c b/test/usb_pe_drp.c
index 189cb41987..5130c4a4a9 100644
--- a/test/usb_pe_drp.c
+++ b/test/usb_pe_drp.c
@@ -97,6 +97,15 @@ test_static int finish_src_discovery(int startup_cable_probes)
rx_message(TCPCI_MSG_SOP, PD_CTRL_NOT_SUPPORTED, 0,
PD_ROLE_SINK, PD_ROLE_UFP, 0);
+ /* Expect GET_REVISION, reply NOT_SUPPORTED. */
+ TEST_EQ(mock_prl_wait_for_tx_msg(PORT0, TCPCI_MSG_SOP,
+ PD_CTRL_GET_REVISION, 0, 10 * MSEC),
+ EC_SUCCESS, "%d");
+ mock_prl_message_sent(PORT0);
+ task_wait_event(10 * MSEC);
+ rx_message(TCPCI_MSG_SOP, PD_CTRL_NOT_SUPPORTED, 0,
+ PD_ROLE_SINK, PD_ROLE_UFP, 0);
+
/*
* Cable identity discovery is attempted 6 times total. 1 was done
* above, so expect 5 more now.
diff --git a/test/usb_tcpmv2_compliance_common.c b/test/usb_tcpmv2_compliance_common.c
index c1c4f21e09..67aba61f52 100644
--- a/test/usb_tcpmv2_compliance_common.c
+++ b/test/usb_tcpmv2_compliance_common.c
@@ -385,9 +385,13 @@ int handle_attach_expected_msgs(enum pd_data_role data_role)
possible[3].ctrl_msg = 0;
possible[3].data_msg = PD_DATA_VENDOR_DEF;
+ possible[4].tx_type = TCPCI_MSG_SOP;
+ possible[4].ctrl_msg = PD_CTRL_GET_REVISION;
+ possible[4].data_msg = 0;
+
do {
rv = verify_tcpci_possible_tx(possible,
- 4,
+ 5,
&found_index,
NULL,
0,
@@ -422,6 +426,11 @@ int handle_attach_expected_msgs(enum pd_data_role data_role)
PD_CTRL_NOT_SUPPORTED,
0, 0, NULL);
break;
+ case 4: /* TCPCI_MSG_SOP PD_CTRL_GET_REVISION */
+ partner_send_msg(TCPCI_MSG_SOP,
+ PD_CTRL_NOT_SUPPORTED,
+ 0, 0, NULL);
+ break;
default:
TEST_ASSERT(0);
break;
@@ -446,9 +455,13 @@ int handle_attach_expected_msgs(enum pd_data_role data_role)
possible[3].ctrl_msg = PD_CTRL_VCONN_SWAP;
possible[3].data_msg = 0;
+ possible[4].tx_type = TCPCI_MSG_SOP;
+ possible[4].ctrl_msg = PD_CTRL_GET_REVISION;
+ possible[4].data_msg = 0;
+
do {
rv = verify_tcpci_possible_tx(possible,
- 4,
+ 5,
&found_index,
NULL,
0,
@@ -484,6 +497,11 @@ int handle_attach_expected_msgs(enum pd_data_role data_role)
PD_CTRL_REJECT,
0, 0, NULL);
break;
+ case 4: /* TCPCI_MSG_SOP PD_CTRL_GET_REVISION */
+ partner_send_msg(TCPCI_MSG_SOP,
+ PD_CTRL_NOT_SUPPORTED,
+ 0, 0, NULL);
+ break;
default:
TEST_ASSERT(0);
break;