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 <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/264856
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Alec Berg
2015-04-08 09:42:43 -07:00
committed by ChromeOS Commit Bot
parent 007fadda59
commit f224ae87bd
6 changed files with 155 additions and 9 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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]);

View File

@@ -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

View File

@@ -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
*