summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbe Levkoy <alevkoy@chromium.org>2020-10-15 10:52:50 -0600
committerCommit Bot <commit-bot@chromium.org>2020-10-22 19:38:09 +0000
commite1728abb335acf11e2c9512ae88181a770935850 (patch)
tree75e3d109394193178e2552bf41f0492d44f5db01
parent67645100a8dd165840c65f4bb73343ec1e53300f (diff)
downloadchrome-ec-e1728abb335acf11e2c9512ae88181a770935850.tar.gz
TCPMv2: Add typeccontrol enter-mode subcommand
Define and implement TYPEC_CONTROL_COMMAND_ENTER_MODE. Allow DPM state to be accessed asynchronously by host commands. Add support for this command to ectool. BUG=b:168030639 TEST=Attach DP dongle; discovers but does not enter TEST=ectool typeccontrol 1 2 0; enters DP TEST=Attach TBT dock and TBT active cable; discovers but does not enter TEST=ectool typeccontrol 1 2 1; enters TBT BRANCH=none Change-Id: I218c4b9a92004ef1efe9a27b2a920031961b33f3 Signed-off-by: Abe Levkoy <alevkoy@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2454538 Reviewed-by: Diana Z <dzigterman@chromium.org>
-rw-r--r--common/usbc/usb_pd_dpm.c148
-rw-r--r--common/usbc/usb_pd_host.c3
-rw-r--r--include/config.h6
-rw-r--r--include/ec_commands.h9
-rw-r--r--include/usb_pd.h12
-rw-r--r--include/usb_pd_dpm.h3
-rw-r--r--util/ectool.c26
7 files changed, 182 insertions, 25 deletions
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c
index 87516e4390..c131bc9a2a 100644
--- a/common/usbc/usb_pd_dpm.c
+++ b/common/usbc/usb_pd_dpm.c
@@ -11,12 +11,14 @@
#include "charge_state.h"
#include "compile_time_macros.h"
#include "console.h"
+#include "ec_commands.h"
+#include "system.h"
+#include "tcpm.h"
#include "usb_dp_alt_mode.h"
#include "usb_mode.h"
#include "usb_pd.h"
#include "usb_pd_dpm.h"
#include "usb_tbt_alt_mode.h"
-#include "tcpm.h"
#ifdef CONFIG_COMMON_RUNTIME
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
@@ -27,29 +29,100 @@
#endif
static struct {
- bool mode_entry_done;
- bool mode_exit_request;
+ uint32_t flags;
} dpm[CONFIG_USB_PD_PORT_MAX_COUNT];
+#define DPM_SET_FLAG(port, flag) \
+ deprecated_atomic_or(&dpm[(port)].flags, (flag))
+#define DPM_CLR_FLAG(port, flag) \
+ deprecated_atomic_clear_bits(&dpm[(port)].flags, (flag))
+#define DPM_CHK_FLAG(port, flag) (dpm[(port)].flags & (flag))
+
+/* Flags for internal DPM state */
+#define DPM_FLAG_MODE_ENTRY_DONE BIT(0)
+#define DPM_FLAG_EXIT_REQUEST BIT(1)
+#define DPM_FLAG_ENTER_DP BIT(2)
+#define DPM_FLAG_ENTER_TBT BIT(3)
+#define DPM_FLAG_ENTER_USB4 BIT(4)
+
+enum ec_status pd_request_enter_mode(int port, enum typec_mode mode)
+{
+ if (port >= board_get_usb_pd_port_count())
+ return EC_RES_INVALID_PARAM;
+
+ /* Only one enter request may be active at a time. */
+ if (DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP |
+ DPM_FLAG_ENTER_TBT |
+ DPM_FLAG_ENTER_USB4))
+ return EC_RES_BUSY;
+
+ switch (mode) {
+ case TYPEC_MODE_DP:
+ DPM_SET_FLAG(port, DPM_FLAG_ENTER_DP);
+ break;
+#ifdef CONFIG_USB_PD_TBT_COMPAT_MODE
+ case TYPEC_MODE_TBT:
+ DPM_SET_FLAG(port, DPM_FLAG_ENTER_TBT);
+ break;
+#endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */
+#ifdef CONFIG_USB_PD_USB4
+ case TYPEC_MODE_USB4:
+ DPM_SET_FLAG(port, DPM_FLAG_ENTER_USB4);
+ break;
+#endif
+ default:
+ return EC_RES_INVALID_PARAM;
+ }
+
+ DPM_CLR_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE);
+ DPM_CLR_FLAG(port, DPM_FLAG_EXIT_REQUEST);
+
+ return EC_RES_SUCCESS;
+}
+
void dpm_init(int port)
{
- dpm[port].mode_entry_done = false;
- dpm[port].mode_exit_request = false;
+ dpm[port].flags = 0;
}
static void dpm_set_mode_entry_done(int port)
{
- dpm[port].mode_entry_done = true;
+ DPM_SET_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE);
+ DPM_CLR_FLAG(port, DPM_FLAG_ENTER_DP | DPM_FLAG_ENTER_TBT |
+ DPM_FLAG_ENTER_USB4);
}
void dpm_set_mode_exit_request(int port)
{
- dpm[port].mode_exit_request = true;
+ DPM_SET_FLAG(port, DPM_FLAG_EXIT_REQUEST);
}
static void dpm_clear_mode_exit_request(int port)
{
- dpm[port].mode_exit_request = false;
+ DPM_CLR_FLAG(port, DPM_FLAG_EXIT_REQUEST);
+}
+
+/*
+ * Returns true if the current policy requests that the EC try to enter this
+ * mode on this port. If the EC is in charge of policy, the answer is always
+ * yes.
+ */
+static bool dpm_mode_entry_requested(int port, enum typec_mode mode)
+{
+ /* If the AP isn't controlling policy, the EC is. */
+ if (!IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY))
+ return true;
+
+ switch (mode) {
+ case TYPEC_MODE_DP:
+ return !!DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP);
+ case TYPEC_MODE_TBT:
+ return !!DPM_CHK_FLAG(port, DPM_FLAG_ENTER_TBT);
+ case TYPEC_MODE_USB4:
+ return !!DPM_CHK_FLAG(port, DPM_FLAG_ENTER_USB4);
+ default:
+ return false;
+ }
}
void dpm_vdm_acked(int port, enum tcpm_transmit_type type, int vdo_count,
@@ -93,18 +166,32 @@ void dpm_vdm_naked(int port, enum tcpm_transmit_type type, uint16_t svid,
}
/*
- * The call to this function requests that the PE send one VDM, whichever is
- * next in the mode entry sequence. This only happens if preconditions for mode
- * entry are met.
+ * Requests that the PE send one VDM, whichever is next in the mode entry
+ * sequence. This only happens if preconditions for mode entry are met. If
+ * CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY is enabled, this function waits for the
+ * AP to direct mode entry.
*/
static void dpm_attempt_mode_entry(int port)
{
int vdo_count = 0;
uint32_t vdm[VDO_MAX_SIZE];
enum tcpm_transmit_type tx_type = TCPC_TX_SOP;
+ bool enter_mode_requested =
+ IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY) ? false : true;
- if (pd_get_data_role(port) != PD_ROLE_DFP)
+ if (pd_get_data_role(port) != PD_ROLE_DFP) {
+ if (DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP |
+ DPM_FLAG_ENTER_TBT |
+ DPM_FLAG_ENTER_USB4))
+ DPM_CLR_FLAG(port, DPM_FLAG_ENTER_DP |
+ DPM_FLAG_ENTER_TBT |
+ DPM_FLAG_ENTER_USB4);
+ /*
+ * TODO(b/168030639): Notify the AP that the enter mode request
+ * failed.
+ */
return;
+ }
/*
* Do not try to enter mode while CPU is off.
* CPU transitions (e.g b/158634281) can occur during the discovery
@@ -131,29 +218,46 @@ static void dpm_attempt_mode_entry(int port)
}
/* Check if the device and cable support USB4. */
- if (IS_ENABLED(CONFIG_USB_PD_USB4) && enter_usb_is_capable(port)) {
+ if (IS_ENABLED(CONFIG_USB_PD_USB4) && enter_usb_is_capable(port) &&
+ dpm_mode_entry_requested(port, TYPEC_MODE_USB4)) {
pd_dpm_request(port, DPM_REQUEST_ENTER_USB);
return;
}
/* If not, check if they support Thunderbolt alt mode. */
if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) &&
- pd_is_mode_discovered_for_svid(port, TCPC_TX_SOP, USB_VID_INTEL))
+ pd_is_mode_discovered_for_svid(port, TCPC_TX_SOP, USB_VID_INTEL) &&
+ dpm_mode_entry_requested(port, TYPEC_MODE_TBT)) {
+ enter_mode_requested = true;
vdo_count = tbt_setup_next_vdm(port,
ARRAY_SIZE(vdm), vdm, &tx_type);
+ }
/* If not, check if they support DisplayPort alt mode. */
- if (vdo_count == 0 && !dpm[port].mode_entry_done &&
+ if (vdo_count == 0 && !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE) &&
pd_is_mode_discovered_for_svid(port, TCPC_TX_SOP,
- USB_SID_DISPLAYPORT))
+ USB_SID_DISPLAYPORT) &&
+ dpm_mode_entry_requested(port, TYPEC_MODE_DP)) {
+ enter_mode_requested = true;
vdo_count = dp_setup_next_vdm(port, ARRAY_SIZE(vdm), vdm);
+ }
/*
- * If the PE didn't discover any supported alternate mode, just mark
- * setup done and get out of here.
+ * If the PE didn't discover any supported (requested) alternate mode,
+ * just mark setup done and get out of here.
*/
- if (vdo_count == 0 && !dpm[port].mode_entry_done) {
- CPRINTS("C%d: No supported alt mode discovered", port);
+ if (vdo_count == 0 && !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE)) {
+ if (enter_mode_requested) {
+ /*
+ * TODO(b/168030639): Notify the AP that mode entry
+ * failed.
+ */
+ CPRINTS("C%d: No supported alt mode discovered", port);
+ }
+ /*
+ * If the AP did not request mode entry, it may do so in the
+ * future, but the DPM is done trying for now.
+ */
dpm_set_mode_entry_done(port);
return;
}
@@ -208,8 +312,8 @@ static void dpm_attempt_mode_exit(int port)
void dpm_run(int port)
{
- if (dpm[port].mode_exit_request)
+ if (DPM_CHK_FLAG(port, DPM_FLAG_EXIT_REQUEST))
dpm_attempt_mode_exit(port);
- else if (!dpm[port].mode_entry_done)
+ else if (!DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE))
dpm_attempt_mode_entry(port);
}
diff --git a/common/usbc/usb_pd_host.c b/common/usbc/usb_pd_host.c
index 61dfa8bf49..8f084a0cb9 100644
--- a/common/usbc/usb_pd_host.c
+++ b/common/usbc/usb_pd_host.c
@@ -111,6 +111,9 @@ static enum ec_status hc_typec_control(struct host_cmd_handler_args *args)
case TYPEC_CONTROL_COMMAND_CLEAR_EVENTS:
pd_clear_events(p->port, p->clear_events_mask);
break;
+ case TYPEC_CONTROL_COMMAND_ENTER_MODE: {
+ return pd_request_enter_mode(p->port, p->mode_to_enter);
+ }
default:
return EC_RES_INVALID_PARAM;
}
diff --git a/include/config.h b/include/config.h
index 8966f0e0e8..4c3ec5289e 100644
--- a/include/config.h
+++ b/include/config.h
@@ -3905,6 +3905,12 @@
/* Support for USB PD alternate mode of Downward Facing Port */
#undef CONFIG_USB_PD_ALT_MODE_DFP
+/*
+ * Do not enter USB PD alternate modes or USB4 automatically. Wait for the AP to
+ * direct the EC to enter a mode. This requires AP software support.
+ */
+#undef CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY
+
/* HPD is sent to the GPU from the EC via a GPIO */
#undef CONFIG_USB_PD_DP_HPD_GPIO
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 226571b005..c378847904 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -6371,6 +6371,14 @@ struct ec_response_typec_discovery {
enum typec_control_command {
TYPEC_CONTROL_COMMAND_EXIT_MODES,
TYPEC_CONTROL_COMMAND_CLEAR_EVENTS,
+ TYPEC_CONTROL_COMMAND_ENTER_MODE,
+};
+
+/* Modes (USB or alternate) that a type-C port may enter. */
+enum typec_mode {
+ TYPEC_MODE_DP,
+ TYPEC_MODE_TBT,
+ TYPEC_MODE_USB4,
};
struct ec_params_typec_control {
@@ -6385,6 +6393,7 @@ struct ec_params_typec_control {
*/
union {
uint32_t clear_events_mask;
+ uint8_t mode_to_enter; /* enum typec_mode */
uint8_t placeholder[128];
};
} __ec_align1;
diff --git a/include/usb_pd.h b/include/usb_pd.h
index df5f785135..6c9de3307e 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -2609,6 +2609,18 @@ uint32_t pd_get_events(int port);
*/
void pd_clear_events(int port, uint32_t clear_mask);
+/*
+ * Requests that the port enter the specified mode. A successful result just
+ * means that the request was received, not that the mode has been entered yet.
+ *
+ * @param port USB-C port number
+ * @param mode The mode to enter
+ * @return EC_RES_SUCCESS if the request was made
+ * EC_RES_INVALID_PARAM for an invalid port or mode;
+ * EC_RES_BUSY if another mode entry request is already in progress
+ */
+enum ec_status pd_request_enter_mode(int port, enum typec_mode mode);
+
/**
* Get port partner data swap capable status
*
diff --git a/include/usb_pd_dpm.h b/include/usb_pd_dpm.h
index d1c029bc03..ccc7c57ff7 100644
--- a/include/usb_pd_dpm.h
+++ b/include/usb_pd_dpm.h
@@ -11,6 +11,9 @@
#ifndef __CROS_EC_USB_DPM_H
#define __CROS_EC_USB_DPM_H
+#include "ec_commands.h"
+#include "usb_pd_tcpm.h"
+
/*
* Initializes DPM state for a port.
*
diff --git a/util/ectool.c b/util/ectool.c
index 3220f3fd98..78f7a89473 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -9479,6 +9479,7 @@ int cmd_pd_write_log(int argc, char *argv[])
int cmd_typec_control(int argc, char *argv[])
{
struct ec_params_typec_control p;
+ long conversion_result;
char *endptr;
int rv;
@@ -9486,9 +9487,13 @@ int cmd_typec_control(int argc, char *argv[])
fprintf(stderr,
"Usage: %s <port> <command> [args]\n"
" <port> is the type-c port to query\n"
- " <type> is one of:\n"
+ " <command> is one of:\n"
" 0: Exit modes\n"
- " 1: Clear events\n", argv[0]);
+ " 1: Clear events\n"
+ " args: <event mask>\n"
+ " 2: Enter mode\n"
+ " args: <0: DP, 1:TBT, 2:USB4>\n",
+ argv[0]);
return -1;
}
@@ -9504,7 +9509,8 @@ int cmd_typec_control(int argc, char *argv[])
return -1;
}
- if (p.command == TYPEC_CONTROL_COMMAND_CLEAR_EVENTS) {
+ switch (p.command) {
+ case TYPEC_CONTROL_COMMAND_CLEAR_EVENTS:
if (argc < 4) {
fprintf(stderr, "Missing event mask\n");
return -1;
@@ -9515,6 +9521,20 @@ int cmd_typec_control(int argc, char *argv[])
fprintf(stderr, "Bad event mask\n");
return -1;
}
+ break;
+ case TYPEC_CONTROL_COMMAND_ENTER_MODE:
+ if (argc < 4) {
+ fprintf(stderr, "Missing mode\n");
+ return -1;
+ }
+
+ conversion_result = strtol(argv[3], &endptr, 0);
+ if ((endptr && *endptr) || conversion_result > UINT8_MAX ||
+ conversion_result < 0) {
+ fprintf(stderr, "Bad mode\n");
+ return -1;
+ }
+ p.mode_to_enter = conversion_result;
}
rv = ec_command(EC_CMD_TYPEC_CONTROL, 0, &p, sizeof(p),