diff options
-rw-r--r-- | common/usb_pd_protocol.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 71c85f5ecd..81b918dc05 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -93,6 +93,15 @@ static const int debug_level; #define PD_CAPS_COUNT 50 #define PD_SNK_CAP_RETRIES 3 +/* + * The time that we allow the source to send any messages after an explicit + * contract is established. 200ms was chosen somewhat arbitrarily as it should + * be long enough for sources to decide to send a message if they were going to, + * but not so long that a "low power charger connected" notification would be + * shown in the chrome OS UI. + */ +#define SNK_READY_HOLD_OFF_US (200 * MSEC) + enum vdm_states { VDM_STATE_ERR_BUSY = -3, VDM_STATE_ERR_SEND = -2, @@ -233,6 +242,13 @@ static struct pd_protocol { /* protocol revision */ uint8_t rev; #endif + /* + * Time at which the port acting as a sink can start to request for + * higher power and interrogate the port partner. Some port partners + * are really chatty after the initial request so we allow this time for + * the port partner to send any messages in order to avoid a collision. + */ + uint64_t snk_ready_holdoff_timer; } pd[CONFIG_USB_PD_PORT_COUNT]; #ifdef CONFIG_COMMON_RUNTIME @@ -668,6 +684,9 @@ static inline void set_state(int port, enum pd_states next_state) ppc_clear_oc_event_counter(port); } #endif /* CONFIG_USBC_PPC */ + /* Clear the SNK_READY holdoff timer. */ + pd[port].snk_ready_holdoff_timer = 0; + /* Clear the input current limit */ pd_set_input_current_limit(port, 0, 0); #ifdef CONFIG_CHARGE_MANAGER @@ -1680,6 +1699,14 @@ static void handle_ctrl_request(int port, uint16_t head, } else if (pd[port].task_state == PD_STATE_SNK_SWAP_STANDBY) { /* Do nothing, assume this is a redundant PD_RDY */ } else if (pd[port].power_role == PD_ROLE_SINK) { + /* + * Give the source some time to send any messages before + * we start our interrogation. + */ + if (pd[port].task_state == PD_STATE_SNK_TRANSITION) + pd[port].snk_ready_holdoff_timer = + get_time().val + SNK_READY_HOLD_OFF_US; + set_state(port, PD_STATE_SNK_READY); pd_set_input_current_limit(port, pd[port].curr_limit, pd[port].supply_voltage); @@ -3746,6 +3773,16 @@ void pd_task(void *u) timeout = 20*MSEC; /* + * Don't send any traffic yet until our holdoff timer + * has expired. Some devices are chatty once we reach + * the SNK_READY state and we may end up in a collision + * of messages if we try to immediately send our + * interrogations. + */ + if (get_time().val <= pd[port].snk_ready_holdoff_timer) + break; + + /* * Don't send any PD traffic if we woke up due to * incoming packet or if VDO response pending to avoid * collisions. |