Commit af8b6270 authored by RD Babiera's avatar RD Babiera Committed by Greg Kroah-Hartman

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: default avatarRD Babiera <rdbabiera@google.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20240108191620.987785-23-rdbabiera@google.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fb7ff25a
...@@ -146,7 +146,9 @@ ...@@ -146,7 +146,9 @@
S(PORT_RESET_WAIT_OFF), \ S(PORT_RESET_WAIT_OFF), \
\ \
S(AMS_START), \ S(AMS_START), \
S(CHUNK_NOT_SUPP) S(CHUNK_NOT_SUPP), \
\
S(SRC_VDM_IDENTITY_REQUEST)
#define FOREACH_AMS(S) \ #define FOREACH_AMS(S) \
S(NONE_AMS), \ S(NONE_AMS), \
...@@ -1963,6 +1965,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, ...@@ -1963,6 +1965,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
ret = tcpm_ams_start(port, VCONN_SWAP); ret = tcpm_ams_start(port, VCONN_SWAP);
if (!ret) if (!ret)
return 0; return 0;
/* Cannot perform Vconn swap */
port->upcoming_state = INVALID_STATE; port->upcoming_state = INVALID_STATE;
port->send_discover_prime = false; port->send_discover_prime = false;
} }
...@@ -1994,6 +1997,16 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, ...@@ -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. * the svdm_version for the cable moving forward.
*/ */
svdm_consume_identity_sop_prime(port, p, cnt); 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_tx_sop_type = TCPC_TX_SOP;
response[0] = VDO(USB_SID_PD, 1, response[0] = VDO(USB_SID_PD, 1,
typec_get_negotiated_svdm_version(typec), typec_get_negotiated_svdm_version(typec),
...@@ -2288,7 +2301,8 @@ static void vdm_run_state_machine(struct tcpm_port *port) ...@@ -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 * if there's traffic or we're not in PDO ready state don't send
* a VDM. * 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; port->vdm_sm_running = false;
break; break;
} }
...@@ -2364,13 +2378,22 @@ static void vdm_run_state_machine(struct tcpm_port *port) ...@@ -2364,13 +2378,22 @@ static void vdm_run_state_machine(struct tcpm_port *port)
tcpm_ams_finish(port); tcpm_ams_finish(port);
break; break;
case VDM_STATE_ERR_SEND: 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, * A partner which does not support USB PD will not reply,
* so this is not a fatal error. At the same time, some * so this is not a fatal error. At the same time, some
* devices may not return GoodCRC under some circumstances, * devices may not return GoodCRC under some circumstances,
* so we need to retry. * so we need to retry.
*/ */
if (port->vdm_retries < 3) { } else if (port->vdm_retries < 3) {
tcpm_log(port, "VDM Tx error, retry"); tcpm_log(port, "VDM Tx error, retry");
port->vdm_retries++; port->vdm_retries++;
port->vdm_state = VDM_STATE_READY; port->vdm_state = VDM_STATE_READY;
...@@ -4478,8 +4501,12 @@ static void run_state_machine(struct tcpm_port *port) ...@@ -4478,8 +4501,12 @@ static void run_state_machine(struct tcpm_port *port)
} }
ret = tcpm_pd_send_source_caps(port); ret = tcpm_pd_send_source_caps(port);
if (ret < 0) { if (ret < 0) {
tcpm_set_state(port, SRC_SEND_CAPABILITIES, if (tcpm_can_communicate_sop_prime(port) &&
PD_T_SEND_SOURCE_CAP); 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 { } else {
/* /*
* Per standard, we should clear the reset counter here. * Per standard, we should clear the reset counter here.
...@@ -5395,6 +5422,15 @@ static void run_state_machine(struct tcpm_port *port) ...@@ -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_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); tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? SRC_READY : SNK_READY, 0);
break; 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: default:
WARN(1, "Unexpected port state %d\n", port->state); WARN(1, "Unexpected port state %d\n", port->state);
break; break;
...@@ -6120,7 +6156,8 @@ static void tcpm_send_discover_work(struct kthread_work *work) ...@@ -6120,7 +6156,8 @@ static void tcpm_send_discover_work(struct kthread_work *work)
} }
/* Retry if the port is not idle */ /* 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); mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS);
goto unlock; goto unlock;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment