diff options
-rw-r--r-- | common/mock/tcpci_i2c_mock.c | 12 | ||||
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 114 | ||||
-rw-r--r-- | include/usb_pd.h | 38 | ||||
-rw-r--r-- | test/usb_pe_drp.c | 9 | ||||
-rw-r--r-- | test/usb_tcpmv2_compliance_common.c | 22 |
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; |