From f224ae87bd6967533d53278541c57414d61d26cf Mon Sep 17 00:00:00 2001 From: Alec Berg Date: Wed, 8 Apr 2015 09:42:43 -0700 Subject: pd: samus: support vconn swap and enable on Samus when in S0/S3 Support VCONN swap on samus and always accept VCONN swap when in S0 or S3. In S5, we can't provide VCONN, so reject VCONN swap requests. BUG=chrome-os-partner:34978 BRANCH=samus TEST=load on two samus' and use "pd 1 swap vconn" to swap which side is source vconn. also run in S5 and verify swap request is rejected. Change-Id: I04be8d1d910a2d6c5ad8b27a790f8e33121c86ee Signed-off-by: Alec Berg Reviewed-on: https://chromium-review.googlesource.com/264856 Reviewed-by: Vincent Palatin --- board/samus_pd/board.h | 1 + board/samus_pd/usb_pd_config.h | 3 + board/samus_pd/usb_pd_policy.c | 6 ++ common/usb_pd_protocol.c | 125 ++++++++++++++++++++++++++++++++++++++--- include/config.h | 3 + include/usb_pd.h | 26 ++++++++- 6 files changed, 155 insertions(+), 9 deletions(-) diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h index 627fc087c2..f2cd65ef96 100644 --- a/board/samus_pd/board.h +++ b/board/samus_pd/board.h @@ -61,6 +61,7 @@ #define CONFIG_USB_SWITCH_PI3USB9281_MUX_GPIO GPIO_USB_C_BC12_SEL #define CONFIG_USBC_SS_MUX #define CONFIG_USBC_VCONN +#define CONFIG_USBC_VCONN_SWAP #define CONFIG_VBOOT_HASH #undef CONFIG_WATCHDOG_HELP diff --git a/board/samus_pd/usb_pd_config.h b/board/samus_pd/usb_pd_config.h index 9702714a56..a7df33e499 100644 --- a/board/samus_pd/usb_pd_config.h +++ b/board/samus_pd/usb_pd_config.h @@ -301,6 +301,9 @@ static inline int pd_snk_is_vbus_provided(int port) #define PD_POWER_SUPPLY_TURN_ON_DELAY 30000 /* us */ #define PD_POWER_SUPPLY_TURN_OFF_DELAY 250000 /* us */ +/* delay to turn on/off vconn */ +#define PD_VCONN_SWAP_DELAY 5000 /* us */ + /* Define typical operating power and max power */ #define PD_OPERATING_POWER_MW 15000 #define PD_MAX_POWER_MW 60000 diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c index 85e3244527..7e1302b018 100644 --- a/board/samus_pd/usb_pd_policy.c +++ b/board/samus_pd/usb_pd_policy.c @@ -151,6 +151,12 @@ int pd_check_data_swap(int port, int data_role) return (data_role == PD_ROLE_UFP) ? 1 : 0; } +int pd_check_vconn_swap(int port) +{ + /* in S5, do not allow vconn swap since pp5000 rail is off */ + return gpio_get_level(GPIO_PCH_SLP_S5_L); +} + void pd_execute_data_swap(int port, int data_role) { /* Open USB switches when taking UFP role */ diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 5cb8f4e13b..0438fb7229 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -313,6 +313,9 @@ static const char * const pd_state_names[] = { #ifdef CONFIG_USB_PD_DUAL_ROLE "SRC_SWAP_INIT", "SRC_SWAP_SNK_DISABLE", "SRC_SWAP_SRC_DISABLE", "SRC_SWAP_STANDBY", +#ifdef CONFIG_USBC_VCONN_SWAP + "VCONN_SWAP_SEND", "VCONN_SWAP_INIT", "VCONN_SWAP_READY", +#endif /* CONFIG_USBC_VCONN_SWAP */ #endif /* CONFIG_USB_PD_DUAL_ROLE */ "SOFT_RESET", "HARD_RESET_SEND", "HARD_RESET_EXECUTE", "BIST_RX", "BIST_TX", @@ -1189,6 +1192,15 @@ static void handle_ctrl_request(int port, uint16_t head, pd[port].msg_id = 0; pd[port].power_role = PD_ROLE_SINK; set_state(port, PD_STATE_SNK_DISCOVERY); +#ifdef CONFIG_USBC_VCONN_SWAP + } else if (pd[port].task_state == PD_STATE_VCONN_SWAP_INIT) { + /* + * If VCONN is on, then this PS_RDY tells us it's + * ok to turn VCONN off + */ + if (pd[port].flags & PD_FLAGS_VCONN_ON) + set_state(port, PD_STATE_VCONN_SWAP_READY); +#endif } else if (pd[port].task_state == PD_STATE_SNK_DISCOVERY) { /* Don't know what power source is ready. Reset. */ set_state(port, PD_STATE_HARD_RESET_SEND); @@ -1210,6 +1222,10 @@ static void handle_ctrl_request(int port, uint16_t head, case PD_CTRL_WAIT: if (pd[port].task_state == PD_STATE_DR_SWAP) set_state(port, READY_RETURN_STATE(port)); +#ifdef CONFIG_USBC_VCONN_SWAP + else if (pd[port].task_state == PD_STATE_VCONN_SWAP_SEND) + set_state(port, READY_RETURN_STATE(port)); +#endif #ifdef CONFIG_USB_PD_DUAL_ROLE else if (pd[port].task_state == PD_STATE_SRC_SWAP_INIT) set_state(port, PD_STATE_SRC_READY); @@ -1227,9 +1243,13 @@ static void handle_ctrl_request(int port, uint16_t head, /* switch data role */ pd_dr_swap(port); set_state(port, READY_RETURN_STATE(port)); - } #ifdef CONFIG_USB_PD_DUAL_ROLE - else if (pd[port].task_state == PD_STATE_SRC_SWAP_INIT) { +#ifdef CONFIG_USBC_VCONN_SWAP + } else if (pd[port].task_state == PD_STATE_VCONN_SWAP_SEND) { + /* switch vconn */ + set_state(port, PD_STATE_VCONN_SWAP_INIT); +#endif + } else if (pd[port].task_state == PD_STATE_SRC_SWAP_INIT) { /* explicit contract goes away for power swap */ pd[port].flags &= ~PD_FLAGS_EXPLICIT_CONTRACT; set_state(port, PD_STATE_SRC_SWAP_SNK_DISABLE); @@ -1241,8 +1261,8 @@ static void handle_ctrl_request(int port, uint16_t head, /* explicit contract is now in place */ pd[port].flags |= PD_FLAGS_EXPLICIT_CONTRACT; set_state(port, PD_STATE_SNK_TRANSITION); - } #endif + } break; case PD_CTRL_SOFT_RESET: execute_soft_reset(port); @@ -1284,7 +1304,20 @@ static void handle_ctrl_request(int port, uint16_t head, } break; case PD_CTRL_VCONN_SWAP: +#ifdef CONFIG_USBC_VCONN_SWAP + if (pd[port].task_state == PD_STATE_SRC_READY || + pd[port].task_state == PD_STATE_SNK_READY) { + if (pd_check_vconn_swap(port)) { + if (send_control(port, PD_CTRL_ACCEPT) > 0) + set_state(port, + PD_STATE_VCONN_SWAP_INIT); + } else { + send_control(port, PD_CTRL_REJECT); + } + } +#else send_control(port, PD_CTRL_REJECT); +#endif break; default: CPRINTF("Unhandled ctrl message type %d\n", type); @@ -1985,6 +2018,7 @@ void pd_task(void) #ifdef CONFIG_USBC_VCONN pd_set_vconn(port, pd[port].polarity, 1); + pd[port].flags |= PD_FLAGS_VCONN_ON; #endif pd[port].flags |= PD_FLAGS_CHECK_PR_ROLE | @@ -2652,6 +2686,76 @@ void pd_task(void) set_state(port, PD_STATE_SRC_DISCOVERY); timeout = 10*MSEC; break; +#ifdef CONFIG_USBC_VCONN_SWAP + case PD_STATE_VCONN_SWAP_SEND: + if (pd[port].last_state != pd[port].task_state) { + res = send_control(port, PD_CTRL_VCONN_SWAP); + if (res < 0) { + timeout = 10*MSEC; + /* + * If failed to get goodCRC, send + * soft reset, otherwise ignore + * failure. + */ + set_state(port, res == -1 ? + PD_STATE_SOFT_RESET : + READY_RETURN_STATE(port)); + break; + } + /* Wait for accept or reject */ + set_state_timeout(port, + get_time().val + + PD_T_SENDER_RESPONSE, + READY_RETURN_STATE(port)); + } + break; + case PD_STATE_VCONN_SWAP_INIT: + if (pd[port].last_state != pd[port].task_state) { + if (!(pd[port].flags & PD_FLAGS_VCONN_ON)) { + /* Turn VCONN on and wait for it */ + pd_set_vconn(port, pd[port].polarity, + 1); + set_state_timeout(port, + get_time().val + PD_VCONN_SWAP_DELAY, + PD_STATE_VCONN_SWAP_READY); + } else { + set_state_timeout(port, + get_time().val + PD_T_VCONN_SOURCE_ON, + READY_RETURN_STATE(port)); + } + } + break; + case PD_STATE_VCONN_SWAP_READY: + if (pd[port].last_state != pd[port].task_state) { + if (!(pd[port].flags & PD_FLAGS_VCONN_ON)) { + /* VCONN is now on, send PS_RDY */ + pd[port].flags |= PD_FLAGS_VCONN_ON; + res = send_control(port, + PD_CTRL_PS_RDY); + if (res == -1) { + timeout = 10*MSEC; + /* + * If failed to get goodCRC, + * send soft reset + */ + set_state(port, + PD_STATE_SOFT_RESET); + break; + } + set_state(port, + READY_RETURN_STATE(port)); + } else { + /* Turn VCONN off and wait for it */ + pd_set_vconn(port, pd[port].polarity, + 0); + pd[port].flags &= ~PD_FLAGS_VCONN_ON; + set_state_timeout(port, + get_time().val + PD_VCONN_SWAP_DELAY, + READY_RETURN_STATE(port)); + } + } + break; +#endif /* CONFIG_USBC_VCONN_SWAP */ #endif /* CONFIG_USB_PD_DUAL_ROLE */ case PD_STATE_SOFT_RESET: if (pd[port].last_state != pd[port].task_state) { @@ -3144,12 +3248,18 @@ static int command_pd(int argc, char **argv) if (argc < 4) return EC_ERROR_PARAM_COUNT; - if (!strncasecmp(argv[3], "power", 5)) + if (!strncasecmp(argv[3], "power", 5)) { pd_request_power_swap(port); - else if (!strncasecmp(argv[3], "data", 4)) + } else if (!strncasecmp(argv[3], "data", 4)) { pd_request_data_swap(port); - else +#ifdef CONFIG_USBC_VCONN_SWAP + } else if (!strncasecmp(argv[3], "vconn", 5)) { + set_state(port, PD_STATE_VCONN_SWAP_SEND); + task_wake(PORT_TO_TASK_ID(port)); +#endif + } else { return EC_ERROR_PARAM3; + } } else if (!strncasecmp(argv[2], "ping", 4)) { int enable; @@ -3192,11 +3302,12 @@ static int command_pd(int argc, char **argv) } else #endif if (!strncasecmp(argv[2], "state", 5)) { - ccprintf("Port C%d, %s - Role: %s-%s Polarity: CC%d " + ccprintf("Port C%d, %s - Role: %s-%s%s Polarity: CC%d " "Flags: 0x%04x, State: %s\n", port, pd_comm_enabled ? "Ena" : "Dis", pd[port].power_role == PD_ROLE_SOURCE ? "SRC" : "SNK", pd[port].data_role == PD_ROLE_DFP ? "DFP" : "UFP", + (pd[port].flags & PD_FLAGS_VCONN_ON) ? "-VC" : "", pd[port].polarity + 1, pd[port].flags, pd_state_names[pd[port].task_state]); diff --git a/include/config.h b/include/config.h index 1a11f2f015..d112e88dd7 100644 --- a/include/config.h +++ b/include/config.h @@ -1279,6 +1279,9 @@ /* Support for USB type-c vconn. Not needed for captive cables. */ #undef CONFIG_USBC_VCONN +/* Support VCONN swap */ +#undef CONFIG_USBC_VCONN_SWAP + /* USB Binary device Object Store support */ #undef CONFIG_USB_BOS diff --git a/include/usb_pd.h b/include/usb_pd.h index 0f226096b8..97dbeed51e 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -136,6 +136,7 @@ enum pd_errors { #define PD_T_NO_RESPONSE (5500*MSEC) /* between 4.5s and 5.5s */ #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 */ /* number of edges and time window to detect CC line is not idle */ #define PD_RX_TRANSITION_COUNT 3 @@ -621,6 +622,12 @@ enum pd_states { PD_STATE_SRC_SWAP_SNK_DISABLE, PD_STATE_SRC_SWAP_SRC_DISABLE, PD_STATE_SRC_SWAP_STANDBY, + +#ifdef CONFIG_USBC_VCONN_SWAP + PD_STATE_VCONN_SWAP_SEND, + PD_STATE_VCONN_SWAP_INIT, + PD_STATE_VCONN_SWAP_READY, +#endif /* CONFIG_USBC_VCONN_SWAP */ #endif /* CONFIG_USB_PD_DUAL_ROLE */ PD_STATE_SOFT_RESET, @@ -647,6 +654,7 @@ enum pd_states { #define PD_FLAGS_CHECK_PR_ROLE (1 << 9) /* check power role in READY */ #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 */ /* Flags to clear on a disconnect */ #define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \ PD_FLAGS_PARTNER_DR_DATA | \ @@ -657,7 +665,8 @@ enum pd_states { PD_FLAGS_PREVIOUS_PD_CONN | \ PD_FLAGS_CHECK_PR_ROLE | \ PD_FLAGS_CHECK_DR_ROLE | \ - PD_FLAGS_PARTNER_EXTPOWER) + PD_FLAGS_PARTNER_EXTPOWER | \ + PD_FLAGS_VCONN_ON) enum pd_cc_states { @@ -736,11 +745,15 @@ enum pd_data_msg_type { #define PD_REV10 0 #define PD_REV20 1 -/* Port role */ +/* Power role */ #define PD_ROLE_SINK 0 #define PD_ROLE_SOURCE 1 +/* Data role */ #define PD_ROLE_UFP 0 #define PD_ROLE_DFP 1 +/* Vconn role */ +#define PD_ROLE_VCONN_OFF 0 +#define PD_ROLE_VCONN_ON 1 /* build message header */ #define PD_HEADER(type, prole, drole, id, cnt) \ @@ -908,6 +921,15 @@ int pd_check_power_swap(int port); */ int pd_check_data_swap(int port, int data_role); +/** + * Check if vconn swap is allowed. + * + * @param port USB-C port number + * @return True if vconn swap is allowed, False otherwise + */ + +int pd_check_vconn_swap(int port); + /** * Check current power role for potential power swap * -- cgit v1.2.1