Commit 02d5be46 authored by Badhri Jagan Sridharan's avatar Badhri Jagan Sridharan Committed by Greg Kroah-Hartman

staging: typec: tcpm: Prevent TCPM from looping in SRC_TRYWAIT

According to the spec the following is the condition
for exiting TryWait.SRC:

"The port shall transition to Attached.SRC when V BUS is at vSafe0V
and the SRC.Rd state is detected on exactly one of the CC pins for at
least tCCDebounce. The port shall transition to Unattached.SNK after
tDRPTry if neither of the CC1 or CC2 pins are in the SRC.Rd state"

TCPM at present keeps re-entering the SRC_TRYWAIT and keeps restarting
tDRPTry if the CC presents Rp and disconnects within tCCDebounce.

For example:
[  447.164308] pending state change SRC_TRYWAIT -> SRC_ATTACHED @ 200 ms
[  447.164386] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected]
[  447.164406] state change SRC_TRYWAIT -> SRC_TRYWAIT
[  447.164573] cc:=3
[  447.191408] pending state change SRC_TRYWAIT -> SRC_TRYWAIT_UNATTACHED @ 100 ms
[  447.191478] CC1: 0 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected]
[  447.207261] CC1: 0 -> 2, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, connected]
[  447.207306] state change SRC_TRYWAIT -> SRC_TRYWAIT
[  447.207485] cc:=3
[  447.237283] pending state change SRC_TRYWAIT -> SRC_ATTACHED @ 200 ms
[  447.237357] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected]
[  447.237379] state change SRC_TRYWAIT -> SRC_TRYWAIT
[  447.237532] cc:=3
[  447.263219] pending state change SRC_TRYWAIT -> SRC_TRYWAIT_UNATTACHED @ 100 ms
[  447.263289] CC1: 0 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected]
[  447.280926] CC1: 0 -> 2, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, connected]
[  447.280970] state change SRC_TRYWAIT -> SRC_TRYWAIT
[  447.281158] cc:=3
[  447.307767] pending state change SRC_TRYWAIT -> SRC_ATTACHED @ 200 ms
[  447.307838] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_TRYWAIT, polarity 0, disconnected]
[  447.307858] state change SRC_TRYWAIT -> SRC_TRYWAIT

In TCPM, tDRPTry is set tp 100ms (min 75ms and max 150ms)
and tCCdebounce is set to 200ms (min 100ms and max 200ms).
To overcome the issue, record the time at which the port
enters TryWait.SRC(SRC_TRYWAIT) and re-enter SRC_TRYWAIT
only when CC keeps debouncing within tDRPTry.
Signed-off-by: default avatarBadhri Jagan Sridharan <Badhri@google.com>
Reviewed-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ff6c8cb1
......@@ -17,6 +17,7 @@
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
......@@ -105,6 +106,7 @@
S(SNK_TRY), \
S(SNK_TRY_WAIT), \
S(SRC_TRYWAIT), \
S(SRC_TRYWAIT_DEBOUNCE), \
S(SRC_TRYWAIT_UNATTACHED), \
\
S(SRC_TRY), \
......@@ -284,6 +286,9 @@ struct tcpm_port {
struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX];
struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX];
/* Deadline in jiffies to exit src_try_wait state */
unsigned long max_wait;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
struct mutex logbuffer_lock; /* log buffer access lock */
......@@ -2209,6 +2214,7 @@ static void run_state_machine(struct tcpm_port *port)
if (!tcpm_port_is_sink(port)) {
tcpm_set_state(port, SRC_TRYWAIT,
PD_T_PD_DEBOUNCE);
port->max_wait = 0;
break;
}
/* No vbus, cc state is sink or open */
......@@ -2216,11 +2222,22 @@ static void run_state_machine(struct tcpm_port *port)
break;
case SRC_TRYWAIT:
tcpm_set_cc(port, tcpm_rp_cc(port));
if (!port->vbus_present && tcpm_port_is_source(port))
tcpm_set_state(port, SRC_ATTACHED, PD_T_CC_DEBOUNCE);
else
if (port->max_wait == 0) {
port->max_wait = jiffies +
msecs_to_jiffies(PD_T_DRP_TRY);
tcpm_set_state(port, SRC_TRYWAIT_UNATTACHED,
PD_T_DRP_TRY);
} else {
if (time_is_after_jiffies(port->max_wait))
tcpm_set_state(port, SRC_TRYWAIT_UNATTACHED,
jiffies_to_msecs(port->max_wait -
jiffies));
else
tcpm_set_state(port, SNK_UNATTACHED, 0);
}
break;
case SRC_TRYWAIT_DEBOUNCE:
tcpm_set_state(port, SRC_ATTACHED, PD_T_CC_DEBOUNCE);
break;
case SRC_TRYWAIT_UNATTACHED:
tcpm_set_state(port, SNK_UNATTACHED, 0);
......@@ -2903,11 +2920,10 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
case SRC_TRYWAIT:
/* Hand over to state machine if needed */
if (!port->vbus_present && tcpm_port_is_source(port))
new_state = SRC_ATTACHED;
else
new_state = SRC_TRYWAIT_UNATTACHED;
if (new_state != port->delayed_state)
tcpm_set_state(port, SRC_TRYWAIT_DEBOUNCE, 0);
break;
case SRC_TRYWAIT_DEBOUNCE:
if (port->vbus_present || !tcpm_port_is_source(port))
tcpm_set_state(port, SRC_TRYWAIT, 0);
break;
case SNK_TRY_WAIT:
......@@ -2995,9 +3011,10 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)
/* Do nothing, waiting for timeout */
break;
case SRC_TRYWAIT:
/* Hand over to state machine if needed */
if (port->delayed_state != SRC_TRYWAIT_UNATTACHED)
tcpm_set_state(port, SRC_TRYWAIT, 0);
/* Do nothing, Waiting for Rd to be detected */
break;
case SRC_TRYWAIT_DEBOUNCE:
tcpm_set_state(port, SRC_TRYWAIT, 0);
break;
case SNK_TRY_WAIT:
if (tcpm_port_is_sink(port)) {
......@@ -3044,11 +3061,7 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
case SRC_TRYWAIT:
/* Hand over to state machine if needed */
if (tcpm_port_is_source(port))
new_state = SRC_ATTACHED;
else
new_state = SRC_TRYWAIT_UNATTACHED;
if (new_state != port->delayed_state)
tcpm_set_state(port, SRC_TRYWAIT, 0);
tcpm_set_state(port, SRC_TRYWAIT_DEBOUNCE, 0);
break;
case SNK_TRY_WAIT:
if (!tcpm_port_is_sink(port))
......
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