Skip to content

Commit af8b627

Browse files
RD Babieragregkh
authored andcommitted
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 <[email protected]> Reviewed-by: Heikki Krogerus <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent fb7ff25 commit af8b627

File tree

1 file changed

+43
-6
lines changed

1 file changed

+43
-6
lines changed

drivers/usb/typec/tcpm/tcpm.c

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@
146146
S(PORT_RESET_WAIT_OFF), \
147147
\
148148
S(AMS_START), \
149-
S(CHUNK_NOT_SUPP)
149+
S(CHUNK_NOT_SUPP), \
150+
\
151+
S(SRC_VDM_IDENTITY_REQUEST)
150152

151153
#define FOREACH_AMS(S) \
152154
S(NONE_AMS), \
@@ -1963,6 +1965,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
19631965
ret = tcpm_ams_start(port, VCONN_SWAP);
19641966
if (!ret)
19651967
return 0;
1968+
/* Cannot perform Vconn swap */
19661969
port->upcoming_state = INVALID_STATE;
19671970
port->send_discover_prime = false;
19681971
}
@@ -1994,6 +1997,16 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
19941997
* the svdm_version for the cable moving forward.
19951998
*/
19961999
svdm_consume_identity_sop_prime(port, p, cnt);
2000+
2001+
/*
2002+
* If received in SRC_VDM_IDENTITY_REQUEST, continue
2003+
* to SRC_SEND_CAPABILITIES
2004+
*/
2005+
if (port->state == SRC_VDM_IDENTITY_REQUEST) {
2006+
tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
2007+
return 0;
2008+
}
2009+
19972010
*response_tx_sop_type = TCPC_TX_SOP;
19982011
response[0] = VDO(USB_SID_PD, 1,
19992012
typec_get_negotiated_svdm_version(typec),
@@ -2288,7 +2301,8 @@ static void vdm_run_state_machine(struct tcpm_port *port)
22882301
* if there's traffic or we're not in PDO ready state don't send
22892302
* a VDM.
22902303
*/
2291-
if (port->state != SRC_READY && port->state != SNK_READY) {
2304+
if (port->state != SRC_READY && port->state != SNK_READY &&
2305+
port->state != SRC_VDM_IDENTITY_REQUEST) {
22922306
port->vdm_sm_running = false;
22932307
break;
22942308
}
@@ -2364,13 +2378,22 @@ static void vdm_run_state_machine(struct tcpm_port *port)
23642378
tcpm_ams_finish(port);
23652379
break;
23662380
case VDM_STATE_ERR_SEND:
2381+
/*
2382+
* When sending Discover Identity to SOP' before establishing an
2383+
* explicit contract, do not retry. Instead, weave sending
2384+
* Source_Capabilities over SOP and Discover Identity over SOP'.
2385+
*/
2386+
if (port->state == SRC_VDM_IDENTITY_REQUEST) {
2387+
tcpm_ams_finish(port);
2388+
port->vdm_state = VDM_STATE_DONE;
2389+
tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
23672390
/*
23682391
* A partner which does not support USB PD will not reply,
23692392
* so this is not a fatal error. At the same time, some
23702393
* devices may not return GoodCRC under some circumstances,
23712394
* so we need to retry.
23722395
*/
2373-
if (port->vdm_retries < 3) {
2396+
} else if (port->vdm_retries < 3) {
23742397
tcpm_log(port, "VDM Tx error, retry");
23752398
port->vdm_retries++;
23762399
port->vdm_state = VDM_STATE_READY;
@@ -4478,8 +4501,12 @@ static void run_state_machine(struct tcpm_port *port)
44784501
}
44794502
ret = tcpm_pd_send_source_caps(port);
44804503
if (ret < 0) {
4481-
tcpm_set_state(port, SRC_SEND_CAPABILITIES,
4482-
PD_T_SEND_SOURCE_CAP);
4504+
if (tcpm_can_communicate_sop_prime(port) &&
4505+
IS_ERR_OR_NULL(port->cable))
4506+
tcpm_set_state(port, SRC_VDM_IDENTITY_REQUEST, 0);
4507+
else
4508+
tcpm_set_state(port, SRC_SEND_CAPABILITIES,
4509+
PD_T_SEND_SOURCE_CAP);
44834510
} else {
44844511
/*
44854512
* Per standard, we should clear the reset counter here.
@@ -5395,6 +5422,15 @@ static void run_state_machine(struct tcpm_port *port)
53955422
tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP, TCPC_TX_SOP);
53965423
tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? SRC_READY : SNK_READY, 0);
53975424
break;
5425+
5426+
/* Cable states */
5427+
case SRC_VDM_IDENTITY_REQUEST:
5428+
port->send_discover_prime = true;
5429+
port->tx_sop_type = TCPC_TX_SOP_PRIME;
5430+
mod_send_discover_delayed_work(port, 0);
5431+
port->upcoming_state = SRC_SEND_CAPABILITIES;
5432+
break;
5433+
53985434
default:
53995435
WARN(1, "Unexpected port state %d\n", port->state);
54005436
break;
@@ -6120,7 +6156,8 @@ static void tcpm_send_discover_work(struct kthread_work *work)
61206156
}
61216157

61226158
/* Retry if the port is not idle */
6123-
if ((port->state != SRC_READY && port->state != SNK_READY) || port->vdm_sm_running) {
6159+
if ((port->state != SRC_READY && port->state != SNK_READY &&
6160+
port->state != SRC_VDM_IDENTITY_REQUEST) || port->vdm_sm_running) {
61246161
mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS);
61256162
goto unlock;
61266163
}

0 commit comments

Comments
 (0)