pd: Add NoResponseTimer to disconnect after no response

Add NoResponseTimer to go to disconnected state after some number
of hard resets with the port partner non-responsive. This only takes
affect when the port partner is known to be PD capable, i.e. has sent
us PD communications in the past. This is useful as a last resort to
attempt to restore PD communications with a port partner.

BUG=chrome-os-partner:34976
BRANCH=samus
TEST=load onto two samus', connect with C to C cable, and let them
form a PD contract, then on one side disable PD comms with "pd enable 0"
and from the other side initiate some PD traffic, such as "pd 1 soft".
See that the side with PD communications enabled sends two hard resets
and then goes to disconnected state, then goes to discovery state and
acts as if a non-PD capable device is attached.

Change-Id: Id40ce7eb05b8b7ae6a4f70b9d08ce6cad0d471fe
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/238300
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Alec Berg
2015-01-04 09:57:53 -08:00
committed by ChromeOS Commit Bot
parent 2b364421a4
commit 5348dff126
2 changed files with 49 additions and 17 deletions

View File

@@ -213,6 +213,7 @@ static int pd_src_cap_cnt[PD_PORT_COUNT];
#define PD_FLAGS_NEW_CONTRACT (1 << 6) /* new power contract established */
#define PD_FLAGS_EXPLICIT_CONTRACT (1 << 7) /* explicit pwr contract in place */
#define PD_FLAGS_SFT_RST_DIS_COMM (1 << 8) /* disable comms after soft reset */
#define PD_FLAGS_PREVIOUS_PD_CONN (1 << 9) /* previously PD connected */
/* Flags to clear on a disconnect */
#define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \
PD_FLAGS_PARTNER_DR_DATA | \
@@ -220,7 +221,8 @@ static int pd_src_cap_cnt[PD_PORT_COUNT];
PD_FLAGS_SNK_CAP_RECVD | \
PD_FLAGS_GET_SNK_CAP_SENT | \
PD_FLAGS_NEW_CONTRACT | \
PD_FLAGS_EXPLICIT_CONTRACT)
PD_FLAGS_EXPLICIT_CONTRACT | \
PD_FLAGS_PREVIOUS_PD_CONN)
static struct pd_protocol {
/* current port power role (SOURCE or SINK) */
@@ -897,6 +899,9 @@ static void handle_data_request(int port, uint16_t head,
PD_STATE_SNK_HARD_RESET_RECOVER)
#endif
|| (pd[port].task_state == PD_STATE_SNK_READY)) {
/* Port partner is now known to be PD capable */
pd[port].flags |= PD_FLAGS_PREVIOUS_PD_CONN;
pd_store_src_cap(port, cnt, payload);
/* src cap 0 should be fixed PDO */
pd_update_pdo_flags(port, payload[0]);
@@ -1558,9 +1563,9 @@ void pd_task(void)
int timeout = 10*MSEC;
int cc1_volt, cc2_volt;
int res, incoming_packet = 0;
int hard_reset_count = 0;
#ifdef CONFIG_USB_PD_DUAL_ROLE
uint64_t next_role_swap = PD_T_DRP_SNK;
int hard_reset_count = 0;
#ifndef CONFIG_USB_PD_NO_VBUS_DETECT
int snk_hard_reset_vbus_off = 0;
#endif
@@ -1676,6 +1681,7 @@ void pd_task(void)
pd_set_vconn(port, pd[port].polarity, 1);
#endif
hard_reset_count = 0;
set_state(port, PD_STATE_SRC_STARTUP);
}
#ifdef CONFIG_USB_PD_DUAL_ROLE
@@ -1729,11 +1735,25 @@ void pd_task(void)
}
break;
case PD_STATE_SRC_DISCOVERY:
if (pd[port].last_state != pd[port].task_state) {
#ifdef CONFIG_USB_PD_DUAL_ROLE
/* Keep VBUS up for the hold period */
if (pd[port].last_state != pd[port].task_state)
/* Keep VBUS up for the hold period */
next_role_swap = get_time().val + PD_T_DRP_HOLD;
#endif
/*
* If we have had PD connection with this port
* partner, then start NoResponseTimer.
*/
if (pd[port].flags & PD_FLAGS_PREVIOUS_PD_CONN)
set_state_timeout(port,
get_time().val +
PD_T_NO_RESPONSE,
hard_reset_count <
PD_HARD_RESET_COUNT ?
PD_STATE_HARD_RESET_SEND :
PD_STATE_SRC_DISCONNECTED);
}
/*
* While we were enabling VBUS, other side could have
* toggled roles, so now wait until other side settles
@@ -1757,7 +1777,12 @@ void pd_task(void)
if (res >= 0) {
set_state(port,
PD_STATE_SRC_NEGOCIATE);
timeout = 10*MSEC;
hard_reset_count = 0;
caps_count = 0;
/* Port partner is PD capable */
pd[port].flags |=
PD_FLAGS_PREVIOUS_PD_CONN;
} else { /* failed, retry later */
timeout = PD_T_SEND_SOURCE_CAP;
caps_count++;
@@ -1973,6 +1998,7 @@ void pd_task(void)
typec_set_input_current_limit(
port, typec_curr, TYPE_C_VOLTAGE);
#endif
hard_reset_count = 0;
set_state(port, PD_STATE_SNK_DISCOVERY);
timeout = 10*MSEC;
hook_call_deferred(
@@ -1997,7 +2023,6 @@ void pd_task(void)
* If no source detected, reset hard reset counter and
* check for role swap
*/
hard_reset_count = 0;
if (drp_state == PD_DRP_TOGGLE_ON &&
get_time().val >= next_role_swap) {
/* Swap roles to source */
@@ -2064,12 +2089,8 @@ void pd_task(void)
#endif
break;
case PD_STATE_SNK_DISCOVERY:
/*
* Wait for source cap expired only if we are enabled
* and haven't passed the hard reset counter
*/
/* Wait for source cap expired only if we are enabled */
if ((pd[port].last_state != pd[port].task_state)
&& hard_reset_count < PD_HARD_RESET_COUNT
&& pd_comm_enabled) {
/*
* fake set data role swapped flag so we send
@@ -2077,10 +2098,24 @@ void pd_task(void)
*/
pd[port].flags |= PD_FLAGS_DATA_SWAPPED;
pd[port].flags |= PD_FLAGS_NEW_CONTRACT;
set_state_timeout(port,
/*
* If we haven't passed hard reset counter,
* start SinkWaitCapTimer, otherwise start
* NoResponseTimer.
*/
if (hard_reset_count < PD_HARD_RESET_COUNT)
set_state_timeout(port,
get_time().val +
PD_T_SINK_WAIT_CAP,
PD_STATE_HARD_RESET_SEND);
else if (pd[port].flags &
PD_FLAGS_PREVIOUS_PD_CONN)
/* ErrorRecovery */
set_state_timeout(port,
get_time().val +
PD_T_NO_RESPONSE,
PD_STATE_SNK_DISCONNECTED);
#ifdef CONFIG_CHARGE_MANAGER
/*
* If we didn't come from disconnected, must
@@ -2269,6 +2304,7 @@ void pd_task(void)
if (res < 0) {
set_state(port,
PD_STATE_HARD_RESET_SEND);
timeout = 5*MSEC;
break;
}
@@ -2279,12 +2315,7 @@ void pd_task(void)
}
break;
case PD_STATE_HARD_RESET_SEND:
#ifdef CONFIG_USB_PD_DUAL_ROLE
if (pd[port].last_state == PD_STATE_SNK_DISCOVERY ||
pd[port].last_state ==
PD_STATE_SNK_HARD_RESET_RECOVER)
hard_reset_count++;
#endif
hard_reset_count++;
if (pd[port].last_state != pd[port].task_state)
hard_reset_sent = 0;

View File

@@ -130,6 +130,7 @@ enum pd_errors {
#define PD_T_SRC_RECOVER_MAX (1000*MSEC) /* 1000ms */
#define PD_T_SRC_TURN_ON (275*MSEC) /* 275ms */
#define PD_T_SAFE_0V (650*MSEC) /* 650ms */
#define PD_T_NO_RESPONSE (5500*MSEC) /* between 4.5s and 5.5s */
/* number of edges and time window to detect CC line is not idle */
#define PD_RX_TRANSITION_COUNT 3