summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2015-04-08 09:42:43 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-04-11 04:32:33 +0000
commitf224ae87bd6967533d53278541c57414d61d26cf (patch)
tree188d650825dee59070b5b917be2f40ac4867b9e9
parent007fadda59dc617976eb87bcc325af7453d11a53 (diff)
downloadchrome-ec-f224ae87bd6967533d53278541c57414d61d26cf.tar.gz
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>
-rw-r--r--board/samus_pd/board.h1
-rw-r--r--board/samus_pd/usb_pd_config.h3
-rw-r--r--board/samus_pd/usb_pd_policy.c6
-rw-r--r--common/usb_pd_protocol.c125
-rw-r--r--include/config.h3
-rw-r--r--include/usb_pd.h26
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) \
@@ -909,6 +922,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
*
* @param port USB-C port number