summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;