|
146 | 146 | S(PORT_RESET_WAIT_OFF), \ |
147 | 147 | \ |
148 | 148 | S(AMS_START), \ |
149 | | - S(CHUNK_NOT_SUPP) |
| 149 | + S(CHUNK_NOT_SUPP), \ |
| 150 | + \ |
| 151 | + S(SRC_VDM_IDENTITY_REQUEST) |
150 | 152 |
|
151 | 153 | #define FOREACH_AMS(S) \ |
152 | 154 | S(NONE_AMS), \ |
@@ -1963,6 +1965,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, |
1963 | 1965 | ret = tcpm_ams_start(port, VCONN_SWAP); |
1964 | 1966 | if (!ret) |
1965 | 1967 | return 0; |
| 1968 | + /* Cannot perform Vconn swap */ |
1966 | 1969 | port->upcoming_state = INVALID_STATE; |
1967 | 1970 | port->send_discover_prime = false; |
1968 | 1971 | } |
@@ -1994,6 +1997,16 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, |
1994 | 1997 | * the svdm_version for the cable moving forward. |
1995 | 1998 | */ |
1996 | 1999 | 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 | + |
1997 | 2010 | *response_tx_sop_type = TCPC_TX_SOP; |
1998 | 2011 | response[0] = VDO(USB_SID_PD, 1, |
1999 | 2012 | typec_get_negotiated_svdm_version(typec), |
@@ -2288,7 +2301,8 @@ static void vdm_run_state_machine(struct tcpm_port *port) |
2288 | 2301 | * if there's traffic or we're not in PDO ready state don't send |
2289 | 2302 | * a VDM. |
2290 | 2303 | */ |
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) { |
2292 | 2306 | port->vdm_sm_running = false; |
2293 | 2307 | break; |
2294 | 2308 | } |
@@ -2364,13 +2378,22 @@ static void vdm_run_state_machine(struct tcpm_port *port) |
2364 | 2378 | tcpm_ams_finish(port); |
2365 | 2379 | break; |
2366 | 2380 | 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); |
2367 | 2390 | /* |
2368 | 2391 | * A partner which does not support USB PD will not reply, |
2369 | 2392 | * so this is not a fatal error. At the same time, some |
2370 | 2393 | * devices may not return GoodCRC under some circumstances, |
2371 | 2394 | * so we need to retry. |
2372 | 2395 | */ |
2373 | | - if (port->vdm_retries < 3) { |
| 2396 | + } else if (port->vdm_retries < 3) { |
2374 | 2397 | tcpm_log(port, "VDM Tx error, retry"); |
2375 | 2398 | port->vdm_retries++; |
2376 | 2399 | port->vdm_state = VDM_STATE_READY; |
@@ -4478,8 +4501,12 @@ static void run_state_machine(struct tcpm_port *port) |
4478 | 4501 | } |
4479 | 4502 | ret = tcpm_pd_send_source_caps(port); |
4480 | 4503 | 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); |
4483 | 4510 | } else { |
4484 | 4511 | /* |
4485 | 4512 | * Per standard, we should clear the reset counter here. |
@@ -5395,6 +5422,15 @@ static void run_state_machine(struct tcpm_port *port) |
5395 | 5422 | tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP, TCPC_TX_SOP); |
5396 | 5423 | tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? SRC_READY : SNK_READY, 0); |
5397 | 5424 | 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 | + |
5398 | 5434 | default: |
5399 | 5435 | WARN(1, "Unexpected port state %d\n", port->state); |
5400 | 5436 | break; |
@@ -6120,7 +6156,8 @@ static void tcpm_send_discover_work(struct kthread_work *work) |
6120 | 6156 | } |
6121 | 6157 |
|
6122 | 6158 | /* 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) { |
6124 | 6161 | mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS); |
6125 | 6162 | goto unlock; |
6126 | 6163 | } |
|
0 commit comments