usb: typec: tcpm: add state machine support for SRC_VDM_IDENTITY_REQUEST
Add SRC_VDM_IDENTITY_REQUEST state which first enters after SRC_STARTUP. The state sends Discover Identity on SOP' and transitions to SRC_SEND_CAPABILITIES. SRC_SEND_CAPABILITIES will transition back into SRC_VDM_IDENTITY_REQUEST instead of retrying immediately. Signed-off-by: RD Babiera <rdbabiera@google.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20240108191620.987785-23-rdbabiera@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
fb7ff25ae4
commit
af8b627046
@ -146,7 +146,9 @@
|
||||
S(PORT_RESET_WAIT_OFF), \
|
||||
\
|
||||
S(AMS_START), \
|
||||
S(CHUNK_NOT_SUPP)
|
||||
S(CHUNK_NOT_SUPP), \
|
||||
\
|
||||
S(SRC_VDM_IDENTITY_REQUEST)
|
||||
|
||||
#define FOREACH_AMS(S) \
|
||||
S(NONE_AMS), \
|
||||
@ -1963,6 +1965,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
|
||||
ret = tcpm_ams_start(port, VCONN_SWAP);
|
||||
if (!ret)
|
||||
return 0;
|
||||
/* Cannot perform Vconn swap */
|
||||
port->upcoming_state = INVALID_STATE;
|
||||
port->send_discover_prime = false;
|
||||
}
|
||||
@ -1994,6 +1997,16 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
|
||||
* the svdm_version for the cable moving forward.
|
||||
*/
|
||||
svdm_consume_identity_sop_prime(port, p, cnt);
|
||||
|
||||
/*
|
||||
* If received in SRC_VDM_IDENTITY_REQUEST, continue
|
||||
* to SRC_SEND_CAPABILITIES
|
||||
*/
|
||||
if (port->state == SRC_VDM_IDENTITY_REQUEST) {
|
||||
tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*response_tx_sop_type = TCPC_TX_SOP;
|
||||
response[0] = VDO(USB_SID_PD, 1,
|
||||
typec_get_negotiated_svdm_version(typec),
|
||||
@ -2288,7 +2301,8 @@ static void vdm_run_state_machine(struct tcpm_port *port)
|
||||
* if there's traffic or we're not in PDO ready state don't send
|
||||
* a VDM.
|
||||
*/
|
||||
if (port->state != SRC_READY && port->state != SNK_READY) {
|
||||
if (port->state != SRC_READY && port->state != SNK_READY &&
|
||||
port->state != SRC_VDM_IDENTITY_REQUEST) {
|
||||
port->vdm_sm_running = false;
|
||||
break;
|
||||
}
|
||||
@ -2364,13 +2378,22 @@ static void vdm_run_state_machine(struct tcpm_port *port)
|
||||
tcpm_ams_finish(port);
|
||||
break;
|
||||
case VDM_STATE_ERR_SEND:
|
||||
/*
|
||||
* When sending Discover Identity to SOP' before establishing an
|
||||
* explicit contract, do not retry. Instead, weave sending
|
||||
* Source_Capabilities over SOP and Discover Identity over SOP'.
|
||||
*/
|
||||
if (port->state == SRC_VDM_IDENTITY_REQUEST) {
|
||||
tcpm_ams_finish(port);
|
||||
port->vdm_state = VDM_STATE_DONE;
|
||||
tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
|
||||
/*
|
||||
* A partner which does not support USB PD will not reply,
|
||||
* so this is not a fatal error. At the same time, some
|
||||
* devices may not return GoodCRC under some circumstances,
|
||||
* so we need to retry.
|
||||
*/
|
||||
if (port->vdm_retries < 3) {
|
||||
} else if (port->vdm_retries < 3) {
|
||||
tcpm_log(port, "VDM Tx error, retry");
|
||||
port->vdm_retries++;
|
||||
port->vdm_state = VDM_STATE_READY;
|
||||
@ -4478,8 +4501,12 @@ static void run_state_machine(struct tcpm_port *port)
|
||||
}
|
||||
ret = tcpm_pd_send_source_caps(port);
|
||||
if (ret < 0) {
|
||||
tcpm_set_state(port, SRC_SEND_CAPABILITIES,
|
||||
PD_T_SEND_SOURCE_CAP);
|
||||
if (tcpm_can_communicate_sop_prime(port) &&
|
||||
IS_ERR_OR_NULL(port->cable))
|
||||
tcpm_set_state(port, SRC_VDM_IDENTITY_REQUEST, 0);
|
||||
else
|
||||
tcpm_set_state(port, SRC_SEND_CAPABILITIES,
|
||||
PD_T_SEND_SOURCE_CAP);
|
||||
} else {
|
||||
/*
|
||||
* Per standard, we should clear the reset counter here.
|
||||
@ -5395,6 +5422,15 @@ static void run_state_machine(struct tcpm_port *port)
|
||||
tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP, TCPC_TX_SOP);
|
||||
tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? SRC_READY : SNK_READY, 0);
|
||||
break;
|
||||
|
||||
/* Cable states */
|
||||
case SRC_VDM_IDENTITY_REQUEST:
|
||||
port->send_discover_prime = true;
|
||||
port->tx_sop_type = TCPC_TX_SOP_PRIME;
|
||||
mod_send_discover_delayed_work(port, 0);
|
||||
port->upcoming_state = SRC_SEND_CAPABILITIES;
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN(1, "Unexpected port state %d\n", port->state);
|
||||
break;
|
||||
@ -6120,7 +6156,8 @@ static void tcpm_send_discover_work(struct kthread_work *work)
|
||||
}
|
||||
|
||||
/* Retry if the port is not idle */
|
||||
if ((port->state != SRC_READY && port->state != SNK_READY) || port->vdm_sm_running) {
|
||||
if ((port->state != SRC_READY && port->state != SNK_READY &&
|
||||
port->state != SRC_VDM_IDENTITY_REQUEST) || port->vdm_sm_running) {
|
||||
mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS);
|
||||
goto unlock;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user