[PATCH v3 2/2] usb: typec: tcpm: AMS for PD2.0

From: Kyle Tso
Date: Thu Sep 19 2019 - 23:25:36 EST


AMS is defined in PD2.0 as well. Remove the filter in tcpm_ams_start
and change the CC for Collision Avoidance only if the negotiated
revision is higher than PD2.0.

Signed-off-by: Kyle Tso <kyletso@xxxxxxxxxx>
---
Changelog since v2:
- N/A; This is the first version.

drivers/usb/typec/tcpm/tcpm.c | 129 +++++++++++++++-------------------
1 file changed, 57 insertions(+), 72 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 7d1c30c33097..aca1c5bbe870 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -391,6 +391,12 @@ struct pd_rx_event {
struct pd_message msg;
};

+static const char * const pd_rev[] = {
+ [PD_REV10] = "rev1",
+ [PD_REV20] = "rev2",
+ [PD_REV30] = "rev3",
+};
+
#define tcpm_cc_is_sink(cc) \
((cc) == TYPEC_CC_RP_DEF || (cc) == TYPEC_CC_RP_1_5 || \
(cc) == TYPEC_CC_RP_3_0)
@@ -431,8 +437,6 @@ struct pd_rx_event {
(tcpm_port_is_sink(port) && \
((port)->cc1 == TYPEC_CC_RP_3_0 || (port)->cc2 == TYPEC_CC_RP_3_0))

-#define support_ams(port) ((port)->negotiated_rev >= PD_REV30)
-
static enum tcpm_state tcpm_default_state(struct tcpm_port *port)
{
if (port->port_type == TYPEC_PORT_DRP) {
@@ -679,14 +683,9 @@ static int tcpm_ams_finish(struct tcpm_port *port)
{
int ret = 0;

- if (!support_ams(port)) {
- port->upcoming_state = INVALID_STATE;
- return -EOPNOTSUPP;
- }
-
tcpm_log(port, "AMS %s finished", tcpm_ams_str[port->ams]);

- if (port->pwr_role == TYPEC_SOURCE)
+ if (port->negotiated_rev >= PD_REV30 && port->pwr_role == TYPEC_SOURCE)
tcpm_set_cc(port, SINK_TX_OK);

port->in_ams = false;
@@ -723,12 +722,13 @@ static int tcpm_pd_transmit(struct tcpm_port *port,
case TCPC_TX_SUCCESS:
port->message_id = (port->message_id + 1) & PD_HEADER_ID_MASK;
/*
+ * USB PD rev 2.0, 8.3.2.2.1:
* USB PD rev 3.0, 8.3.2.1.3:
* "... Note that every AMS is Interruptible until the first
* Message in the sequence has been successfully sent (GoodCRC
* Message received)."
*/
- if (support_ams(port) && port->ams != NONE_AMS)
+ if (port->ams != NONE_AMS)
port->in_ams = true;
break;
case TCPC_TX_DISCARDED:
@@ -994,20 +994,18 @@ static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state,
unsigned int delay_ms)
{
if (delay_ms) {
- tcpm_log(port, "pending state change %s -> %s @ %u ms%s%s",
+ tcpm_log(port, "pending state change %s -> %s @ %u ms [%s %s]",
tcpm_states[port->state], tcpm_states[state], delay_ms,
- support_ams(port) ? " in AMS " : "",
- support_ams(port) ? tcpm_ams_str[port->ams] : "");
+ pd_rev[port->negotiated_rev], tcpm_ams_str[port->ams]);
port->delayed_state = state;
mod_delayed_work(port->wq, &port->state_machine,
msecs_to_jiffies(delay_ms));
port->delayed_runtime = jiffies + msecs_to_jiffies(delay_ms);
port->delay_ms = delay_ms;
} else {
- tcpm_log(port, "state change %s -> %s%s%s",
+ tcpm_log(port, "state change %s -> %s [%s %s]",
tcpm_states[port->state], tcpm_states[state],
- support_ams(port) ? " in AMS " : "",
- support_ams(port) ? tcpm_ams_str[port->ams] : "");
+ pd_rev[port->negotiated_rev], tcpm_ams_str[port->ams]);
port->delayed_state = INVALID_STATE;
port->prev_state = port->state;
port->state = state;
@@ -1029,12 +1027,11 @@ static void tcpm_set_state_cond(struct tcpm_port *port, enum tcpm_state state,
tcpm_set_state(port, state, delay_ms);
else
tcpm_log(port,
- "skipped %sstate change %s -> %s [%u ms], context state %s%s%s",
+ "skipped %sstate change %s -> %s [%u ms], context state %s [%s %s]",
delay_ms ? "delayed " : "",
tcpm_states[port->state], tcpm_states[state],
delay_ms, tcpm_states[port->enter_state],
- support_ams(port) ? " in AMS " : "",
- support_ams(port) ? tcpm_ams_str[port->ams] : "");
+ pd_rev[port->negotiated_rev], tcpm_ams_str[port->ams]);
}

static void tcpm_queue_message(struct tcpm_port *port,
@@ -1100,11 +1097,6 @@ static int tcpm_ams_start(struct tcpm_port *port, enum tcpm_ams ams)
{
int ret = 0;

- if (!support_ams(port)) {
- port->upcoming_state = INVALID_STATE;
- return -EOPNOTSUPP;
- }
-
tcpm_log(port, "AMS %s start", tcpm_ams_str[ams]);

if (!tcpm_ams_interruptible(port) && ams != HARD_RESET) {
@@ -1132,24 +1124,41 @@ static int tcpm_ams_start(struct tcpm_port *port, enum tcpm_ams ams)
}
} else if (tcpm_vdm_ams(port)) {
/* tSinkTx is enforced in vdm_run_state_machine */
- tcpm_set_cc(port, SINK_TX_NG);
+ if (port->negotiated_rev >= PD_REV30)
+ tcpm_set_cc(port, SINK_TX_NG);
return ret;
}

- cc_req = port->cc_req;
- tcpm_set_cc(port, SINK_TX_NG);
- if (port->state == SRC_READY ||
- port->state == SRC_STARTUP ||
- port->state == SRC_SOFT_RESET_WAIT_SNK_TX ||
- port->state == SOFT_RESET ||
- port->state == SOFT_RESET_SEND)
- tcpm_set_state(port, AMS_START, cc_req == SINK_TX_OK ?
- PD_T_SINK_TX : 0);
- else
- tcpm_set_state(port, SRC_READY, cc_req == SINK_TX_OK ?
- PD_T_SINK_TX : 0);
+ if (port->negotiated_rev >= PD_REV30) {
+ cc_req = port->cc_req;
+ tcpm_set_cc(port, SINK_TX_NG);
+ }
+
+ switch (port->state) {
+ case SRC_READY:
+ case SRC_STARTUP:
+ case SRC_SOFT_RESET_WAIT_SNK_TX:
+ case SOFT_RESET:
+ case SOFT_RESET_SEND:
+ if (port->negotiated_rev >= PD_REV30)
+ tcpm_set_state(port, AMS_START,
+ cc_req == SINK_TX_OK ?
+ PD_T_SINK_TX : 0);
+ else
+ tcpm_set_state(port, AMS_START, 0);
+ break;
+ default:
+ if (port->negotiated_rev >= PD_REV30)
+ tcpm_set_state(port, SRC_READY,
+ cc_req == SINK_TX_OK ?
+ PD_T_SINK_TX : 0);
+ else
+ tcpm_set_state(port, SRC_READY, 0);
+ break;
+ }
} else {
- if (!tcpm_sink_tx_ok(port) &&
+ if (port->negotiated_rev >= PD_REV30 &&
+ !tcpm_sink_tx_ok(port) &&
ams != SOFT_RESET_AMS &&
ams != HARD_RESET) {
port->upcoming_state = INVALID_STATE;
@@ -1565,13 +1574,13 @@ static void vdm_run_state_machine(struct tcpm_port *port)
break;
}

- if (res == -EAGAIN)
+ if (res < 0)
return;
}

port->vdm_state = VDM_STATE_SEND_MESSAGE;
mod_delayed_work(port->wq, &port->vdm_state_machine,
- (res != -EOPNOTSUPP) &&
+ (port->negotiated_rev >= PD_REV30) &&
(port->pwr_role == TYPEC_SOURCE) &&
(PD_VDO_CMDT(port->vdo_data[0]) == CMDT_INIT) ?
PD_T_SINK_TX : 0);
@@ -1975,7 +1984,6 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
{
enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
enum tcpm_state next_state;
- int ret = 0;

switch (type) {
case PD_CTRL_GOOD_CRC:
@@ -2094,11 +2102,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
tcpm_ams_finish(port);
if (port->pwr_role == TYPEC_SOURCE) {
port->upcoming_state = SRC_SEND_CAPABILITIES;
- ret = tcpm_ams_start(port, POWER_NEGOTIATION);
- if (ret == -EOPNOTSUPP)
- tcpm_set_state(port,
- SRC_SEND_CAPABILITIES,
- 0);
+ tcpm_ams_start(port, POWER_NEGOTIATION);
} else {
tcpm_set_state(port, SNK_WAIT_CAPABILITIES, 0);
}
@@ -3254,9 +3258,7 @@ static void run_state_machine(struct tcpm_port *port)
port->ams == FAST_ROLE_SWAP)
tcpm_ams_finish(port);
port->upcoming_state = SRC_SEND_CAPABILITIES;
- ret = tcpm_ams_start(port, POWER_NEGOTIATION);
- if (ret == -EOPNOTSUPP)
- tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+ tcpm_ams_start(port, POWER_NEGOTIATION);
break;
case SRC_SEND_CAPABILITIES:
port->caps_count++;
@@ -3620,11 +3622,7 @@ static void run_state_machine(struct tcpm_port *port)
* thus set upcoming_state to INVALID_STATE.
*/
port->upcoming_state = INVALID_STATE;
- ret = tcpm_ams_start(port, HARD_RESET);
- if (ret == -EOPNOTSUPP) {
- tcpm_pd_transmit(port, TCPC_TX_HARD_RESET, NULL);
- tcpm_set_state(port, HARD_RESET_START, 0);
- }
+ tcpm_ams_start(port, HARD_RESET);
break;
case HARD_RESET_START:
port->hard_reset_count++;
@@ -3709,9 +3707,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
if (port->pwr_role == TYPEC_SOURCE) {
port->upcoming_state = SRC_SEND_CAPABILITIES;
- ret = tcpm_ams_start(port, POWER_NEGOTIATION);
- if (ret == -EOPNOTSUPP)
- tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+ tcpm_ams_start(port, POWER_NEGOTIATION);
} else {
tcpm_set_state(port, SNK_WAIT_CAPABILITIES, 0);
}
@@ -3721,9 +3717,7 @@ static void run_state_machine(struct tcpm_port *port)
if (port->ams != NONE_AMS)
tcpm_ams_finish(port);
port->upcoming_state = SOFT_RESET_SEND;
- ret = tcpm_ams_start(port, SOFT_RESET_AMS);
- if (ret == -EOPNOTSUPP)
- tcpm_set_state(port, SOFT_RESET_SEND, 0);
+ tcpm_ams_start(port, SOFT_RESET_AMS);
break;
case SOFT_RESET_SEND:
port->message_id = 0;
@@ -3930,7 +3924,7 @@ static void run_state_machine(struct tcpm_port *port)
port->vbus_present ? PD_T_PS_SOURCE_OFF : 0);
break;

- /* Collision Avoidance state */
+ /* AMS intermediate state */
case AMS_START:
if (port->upcoming_state == INVALID_STATE) {
tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ?
@@ -4392,9 +4386,6 @@ static int tcpm_dr_set(const struct typec_capability *cap,
if (ret == -EAGAIN) {
port->upcoming_state = INVALID_STATE;
goto port_unlock;
- } else if (ret == -EOPNOTSUPP) {
- port->upcoming_state = INVALID_STATE;
- tcpm_set_state(port, DR_SWAP_SEND, 0);
}
}

@@ -4447,9 +4438,6 @@ static int tcpm_pr_set(const struct typec_capability *cap,
if (ret == -EAGAIN) {
port->upcoming_state = INVALID_STATE;
goto port_unlock;
- } else if (ret == -EOPNOTSUPP) {
- port->upcoming_state = INVALID_STATE;
- tcpm_set_state(port, PR_SWAP_SEND, 0);
}

port->swap_status = 0;
@@ -4496,9 +4484,6 @@ static int tcpm_vconn_set(const struct typec_capability *cap,
if (ret == -EAGAIN) {
port->upcoming_state = INVALID_STATE;
goto port_unlock;
- } else if (ret == -EOPNOTSUPP) {
- port->upcoming_state = INVALID_STATE;
- tcpm_set_state(port, VCONN_SWAP_SEND, 0);
}

port->swap_status = 0;
@@ -4570,7 +4555,7 @@ static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 op_curr)

port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES;
ret = tcpm_ams_start(port, POWER_NEGOTIATION);
- if (ret == -EAGAIN || ret == -EOPNOTSUPP) {
+ if (ret == -EAGAIN) {
port->upcoming_state = INVALID_STATE;
goto port_unlock;
}
@@ -4632,7 +4617,7 @@ static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 out_volt)

port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES;
ret = tcpm_ams_start(port, POWER_NEGOTIATION);
- if (ret == -EAGAIN || ret == -EOPNOTSUPP) {
+ if (ret == -EAGAIN) {
port->upcoming_state = INVALID_STATE;
goto port_unlock;
}
@@ -4688,7 +4673,7 @@ static int tcpm_pps_activate(struct tcpm_port *port, bool activate)
else
port->upcoming_state = SNK_NEGOTIATE_CAPABILITIES;
ret = tcpm_ams_start(port, POWER_NEGOTIATION);
- if (ret == -EAGAIN || ret == -EOPNOTSUPP) {
+ if (ret == -EAGAIN) {
port->upcoming_state = INVALID_STATE;
goto port_unlock;
}
--
2.23.0.351.gc4317032e6-goog