From e9cd22921615ab4c8c10749f0ac2129def4bcb93 Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 19 Jun 2015 11:03:34 -0700 Subject: pd: Add Try.SRC functionality to the pd_protocol state machine 1. Added new config option CONFIG_USB_PD_TRY_SRC 2. Added pd_try_source_enable global flag with console command 3. Added bit to pd.flags to indicate Try.SRC states are active BUG=chrome-os-partner:39724 TEST=Manual samus to samus with the Try.SRC enabled on both and just one samus. Tested Samus to Honeybuns and Samus to Zinger connections. BRANCH=TOT Change-Id: Ifa5d5d82e443f376e546aaf852ff24d92ef04d72 Signed-off-by: Scott Collyer Reviewed-on: https://chromium-review.googlesource.com/282052 Reviewed-by: Alec Berg Tested-by: Alec Berg --- board/samus_pd/board.h | 1 + common/usb_pd_protocol.c | 129 +++++++++++++++++++++++++++++++++++++++++------ include/config.h | 3 ++ include/usb_pd.h | 6 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h index 1d54501e61..a2cba6d77c 100644 --- a/board/samus_pd/board.h +++ b/board/samus_pd/board.h @@ -52,6 +52,7 @@ #define CONFIG_USB_PD_COMM_ENABLED 0 #define CONFIG_USB_PD_CUSTOM_VDM #define CONFIG_USB_PD_DUAL_ROLE +#define CONFIG_USB_PD_TRY_SRC #define CONFIG_USB_PD_FLASH_ERASE_CHECK #define CONFIG_USB_PD_INTERNAL_COMP #define CONFIG_USB_PD_LOGGING diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 25774cd62e..3ca0ab2733 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -87,6 +87,9 @@ enum pd_dual_role_states drp_state = PD_DRP_TOGGLE_OFF; /* Last received source cap */ static uint32_t pd_src_caps[CONFIG_USB_PD_PORT_COUNT][PDO_MAX_OBJECTS]; static int pd_src_cap_cnt[CONFIG_USB_PD_PORT_COUNT]; + +/* Enable varible for Try.SRC states */ +static uint8_t pd_try_src_enable; #endif static struct pd_protocol { @@ -127,6 +130,8 @@ static struct pd_protocol { int new_power_request; /* Store previously requested voltage request */ int prev_request_mv; + /* Time for Try.SRC states */ + uint64_t try_src_marker; #endif /* PD state for Vendor Defined Messages */ @@ -260,6 +265,9 @@ static inline void set_state(int port, enum pd_states next_state) typec_set_input_current_limit(port, 0, 0); charge_manager_set_ceil(port, CHARGE_CEIL_NONE); #endif +#ifdef CONFIG_USBC_VCONN + tcpm_set_vconn(port, 0); +#endif #else /* CONFIG_USB_PD_DUAL_ROLE */ if (next_state == PD_STATE_SRC_DISCONNECTED) { #endif @@ -274,9 +282,6 @@ static inline void set_state(int port, enum pd_states next_state) #ifdef CONFIG_USBC_SS_MUX usb_mux_set(port, TYPEC_MUX_NONE, USB_SWITCH_DISCONNECT, pd[port].polarity); -#endif -#ifdef CONFIG_USBC_VCONN - tcpm_set_vconn(port, 0); #endif /* Disable TCPC RX */ tcpm_set_rx_enable(port, 0); @@ -1166,6 +1171,18 @@ void pd_set_dual_role(enum pd_dual_role_states state) int i; drp_state = state; +#ifdef CONFIG_USB_PD_TRY_SRC + pd_try_src_enable = (state == PD_DRP_TOGGLE_ON) ? 1 : 0; + for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { + /* + * Clear this flag to cover case where a TrySrc + * mode went from enabled to disabled and trying_source + * was active at that time. + */ + pd[i].flags &= ~PD_FLAGS_TRY_SRC; + } +#endif + for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { /* * Change to sink if port is currently a source AND (new DRP @@ -1416,13 +1433,25 @@ void pd_task(void) PD_STATE_SRC_DISCONNECTED_DEBOUNCE); } #ifdef CONFIG_USB_PD_DUAL_ROLE - /* Swap roles if time expired */ - else if (drp_state != PD_DRP_FORCE_SOURCE && - get_time().val >= next_role_swap) { + /* + * Try.SRC state is embedded here. Wait for SNK + * detect, or if timer expires, transition to + * SNK_DISCONNETED. + * + * If Try.SRC state is not active, then this block + * handles the normal DRP toggle from SRC->SNK + */ + else if ((pd[port].flags & PD_FLAGS_TRY_SRC && + get_time().val >= pd[port].try_src_marker) || + (!(pd[port].flags & PD_FLAGS_TRY_SRC) && + drp_state != PD_DRP_FORCE_SOURCE && + get_time().val >= next_role_swap)) { pd[port].power_role = PD_ROLE_SINK; set_state(port, PD_STATE_SNK_DISCONNECTED); tcpm_set_cc(port, TYPEC_CC_RD); next_role_swap = get_time().val + PD_T_DRP_SNK; + pd[port].try_src_marker = get_time().val + + PD_T_TRY_WAIT; /* Swap states quickly */ timeout = 2*MSEC; @@ -1455,15 +1484,18 @@ void pd_task(void) timeout = 5*MSEC; break; } - - /* Debounce the cc state */ - if (new_cc_state != pd[port].cc_state) { - pd[port].cc_debounce = get_time().val + - PD_T_CC_DEBOUNCE; - pd[port].cc_state = new_cc_state; - break; - } else if (get_time().val < pd[port].cc_debounce) { - break; + /* If in Try.SRC state, then don't need to debounce */ + if (!(pd[port].flags & PD_FLAGS_TRY_SRC)) { + /* Debounce the cc state */ + if (new_cc_state != pd[port].cc_state) { + pd[port].cc_debounce = get_time().val + + PD_T_CC_DEBOUNCE; + pd[port].cc_state = new_cc_state; + break; + } else if (get_time().val < + pd[port].cc_debounce) { + break; + } } /* Debounce complete */ @@ -1857,6 +1889,18 @@ void pd_task(void) break; } + /* + * If Try.SRC is active and failed to detect a SNK, + * then it transitions to TryWait.SNK. Need to prevent + * normal dual role toggle until tDRPTryWait timer + * expires. + */ + if (pd[port].flags & PD_FLAGS_TRY_SRC) { + if (get_time().val > pd[port].try_src_marker) + pd[port].flags &= ~PD_FLAGS_TRY_SRC; + break; + } + /* * If no source detected, check for role toggle. * If VBUS is detected, and we are in the debug @@ -1892,6 +1936,24 @@ void pd_task(void) !pd_snk_is_vbus_provided(port)) break; + if (pd_try_src_enable && + !(pd[port].flags & PD_FLAGS_TRY_SRC)) { + /* + * If TRY_SRC is enabled, but not active, + * then force attempt to connect as source. + */ + pd[port].try_src_marker = get_time().val + + PD_T_TRY_SRC; + /* Swap roles to source */ + pd[port].power_role = PD_ROLE_SOURCE; + tcpm_set_cc(port, TYPEC_CC_RP); + timeout = 2*MSEC; + set_state(port, PD_STATE_SRC_DISCONNECTED); + /* Set flag after the state change */ + pd[port].flags |= PD_FLAGS_TRY_SRC; + break; + } + /* We are attached */ pd[port].polarity = (cc2 != TYPEC_CC_VOLT_OPEN); tcpm_set_polarity(port, pd[port].polarity); @@ -2376,6 +2438,26 @@ void pd_task(void) set_state(port, PD_STATE_SRC_DISCONNECTED); /* Debouncing */ timeout = 10*MSEC; +#ifdef CONFIG_USB_PD_DUAL_ROLE + /* + * If Try.SRC is configured, then ATTACHED_SRC + * needs to transition to TryWait.SNK. Change + * power role to SNK and start state timer. + */ + if (pd_try_src_enable) { + /* Swap roles to sink */ + pd[port].power_role = PD_ROLE_SINK; + tcpm_set_cc(port, TYPEC_CC_RD); + /* Set timer for TryWait.SNK state */ + pd[port].try_src_marker = get_time().val + + PD_T_TRY_WAIT; + /* Advance to TryWait.SNK state */ + set_state(port, + PD_STATE_SNK_DISCONNECTED); + /* Mark state as TryWait.SNK */ + pd[port].flags |= PD_FLAGS_TRY_SRC; + } +#endif } } #ifdef CONFIG_USB_PD_DUAL_ROLE @@ -2678,7 +2760,21 @@ static int command_pd(int argc, char **argv) return EC_SUCCESS; } #endif /* CONFIG_CMD_PD_DEV_DUMP_INFO */ +#ifdef CONFIG_USB_PD_TRY_SRC + else if (!strncasecmp(argv[1], "trysrc", 6)) { + int enable; + + if (argc < 3) + return EC_ERROR_PARAM_COUNT; + enable = strtoi(argv[2], &e, 10); + if (*e) + return EC_ERROR_PARAM3; + pd_try_src_enable = enable ? 1 : 0; + ccprintf("Try.SRC %s\n", enable ? "on" : "off"); + return EC_SUCCESS; + } +#endif #endif /* command: pd [args] */ port = strtoi(argv[1], &e, 10); @@ -2800,7 +2896,8 @@ static int command_pd(int argc, char **argv) return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(pd, command_pd, - "dualrole|dump|enable [0|1]|rwhashtable|\n\t " + "dualrole|dump|enable [0|1]|rwhashtable" + "trysrc [0|1]\n\t " "[tx|bist_rx|bist_tx|charger|clock|dev" "|soft|hash|hard|ping|state|swap [power|data]|" "vdm [ping | curr | vers]]", diff --git a/include/config.h b/include/config.h index 3bff029e2f..b456a81f39 100644 --- a/include/config.h +++ b/include/config.h @@ -1535,6 +1535,9 @@ /* Define the type-c port controller I2C base address. */ #undef CONFIG_TCPC_I2C_BASE_ADDR +/* Use this option to enable Try.SRC mode for Dual Role devices */ +#undef CONFIG_USB_PD_TRY_SRC + /* Alternative configuration keeping only the TX part of PHY */ #undef CONFIG_USB_PD_TX_PHY_ONLY diff --git a/include/usb_pd.h b/include/usb_pd.h index a5bfe7ab3b..6950e8065b 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -160,6 +160,8 @@ enum pd_rx_errors { #define PD_T_BIST_TRANSMIT (50*MSEC) /* 50ms (used for task_wait arg) */ #define PD_T_BIST_RECEIVE (60*MSEC) /* 60ms (max time to process bist) */ #define PD_T_VCONN_SOURCE_ON (100*MSEC) /* 100ms */ +#define PD_T_TRY_SRC (125*MSEC) /* Max time for Try.SRC state */ +#define PD_T_TRY_WAIT (600*MSEC) /* Max time for TryWait.SNK state */ /* number of edges and time window to detect CC line is not idle */ #define PD_RX_TRANSITION_COUNT 3 @@ -699,6 +701,7 @@ enum pd_states { #define PD_FLAGS_CHECK_DR_ROLE (1 << 10)/* check data role in READY */ #define PD_FLAGS_PARTNER_EXTPOWER (1 << 11)/* port partner has external pwr */ #define PD_FLAGS_VCONN_ON (1 << 12)/* vconn is being sourced */ +#define PD_FLAGS_TRY_SRC (1 << 13)/* Try.SRC states are active */ /* Flags to clear on a disconnect */ #define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \ PD_FLAGS_PARTNER_DR_DATA | \ @@ -710,7 +713,8 @@ enum pd_states { PD_FLAGS_CHECK_PR_ROLE | \ PD_FLAGS_CHECK_DR_ROLE | \ PD_FLAGS_PARTNER_EXTPOWER | \ - PD_FLAGS_VCONN_ON) + PD_FLAGS_VCONN_ON | \ + PD_FLAGS_TRY_SRC) enum pd_cc_states { -- cgit v1.2.1