summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2015-01-04 09:57:53 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-06 22:19:22 +0000
commit5348dff126127a1fbecc38b8605017ff1b2a4e5a (patch)
tree5d498545036f72eab1314cc41dfeddc5aff209bc
parent2b364421a428ba3c1afdf193498697f7e4267fae (diff)
downloadchrome-ec-5348dff126127a1fbecc38b8605017ff1b2a4e5a.tar.gz
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>
-rw-r--r--common/usb_pd_protocol.c65
-rw-r--r--include/usb_pd.h1
2 files changed, 49 insertions, 17 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index b60113a3a5..610283ce0e 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -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;
diff --git a/include/usb_pd.h b/include/usb_pd.h
index b9e4ee0d6e..0dccc6695b 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -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