summaryrefslogtreecommitdiff
path: root/driver/usb_mux/usb_mux.c
diff options
context:
space:
mode:
authorMadhusudanarao Amara <madhusudanarao.amara@intel.corp-partner.google.com>2021-01-15 22:21:15 +0530
committerCommit Bot <commit-bot@chromium.org>2021-01-26 00:02:01 +0000
commitaffbf150d56d16cbb881e239b78a38512152e777 (patch)
tree9dd274dbc855cdd6cef8b6a2a9a62f3d2327fded /driver/usb_mux/usb_mux.c
parent7ebc7659f157e2dc787660773bf12b5641993c6b (diff)
downloadchrome-ec-affbf150d56d16cbb881e239b78a38512152e777.tar.gz
usb_mux: Send missed disconnect mode in S3/S0ix
If the Type-C devices are connected in S0 and when DUT enters S3/S0ix, if the type-C devices are disconnected and re-connected, Kernel won't receive the disconnected state from EC once DUT boots to S0 as EC moves on and updates the new connected state to Kernel Mux driver. This leads to failure of Type-C device detection on resuming to S0 from S3/S0iX. To overcome this scenario, adding an explicit condition to send previous disconnect state to Kernel Mux driver once initial mux request is received upon resuming from S3/S0iX. Missing Disconnect mode Patch Details: Set disconnect latch flag for the init and disconnect requests For AP to EC PD command: EC_CMD_USB_PD_CONTROL -Check disconnect latch flag if it is true set pd.enabled = 0 For AP to EC mux command: EC_CMD_USB_PD_MUX_INFO -Check the disconnect latch flag if it is true then send disconnect mode -Reset the disconnect latch flag -Send host event EC_HOST_EVENT_USB_MUX for configuring the virtual mux with the latest Mux configuration BUG=b:176604380 BRANCH=None TEST=Type C devices in s0ix disconnect/connect or swapping across the ports scenarios tested Change-Id: Ic38d3632cb0fadb29393405e13ed3606a740c81e Signed-off-by: Madhusudanarao Amara <madhusudanarao.amara@intel.corp-partner.google.com> Signed-off-by: Ayushee Shah <ayushee.shah@intel.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2632551 Reviewed-by: Keith Short <keithshort@chromium.org> Commit-Queue: Keith Short <keithshort@chromium.org>
Diffstat (limited to 'driver/usb_mux/usb_mux.c')
-rw-r--r--driver/usb_mux/usb_mux.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/driver/usb_mux/usb_mux.c b/driver/usb_mux/usb_mux.c
index 22be81843d..743b9a6203 100644
--- a/driver/usb_mux/usb_mux.c
+++ b/driver/usb_mux/usb_mux.c
@@ -31,7 +31,11 @@ static int enable_debug_prints;
*/
static uint32_t flags[CONFIG_USB_PD_PORT_MAX_COUNT];
-#define USB_MUX_FLAG_IN_LPM BIT(0) /* Device is in low power mode. */
+/* Device is in low power mode. */
+#define USB_MUX_FLAG_IN_LPM BIT(0)
+
+/* The following bit is used to configure virtual mux in disconnect mode */
+#define USB_MUX_FLAG_DISCONNECT_LATCH BIT(1)
enum mux_config_type {
USB_MUX_INIT,
@@ -58,6 +62,11 @@ static int configure_mux(int port,
*mux_state = USB_PD_MUX_NONE;
}
+ if ((config == USB_MUX_SET_MODE && *mux_state == USB_PD_MUX_NONE) ||
+ config == USB_MUX_INIT) {
+ usb_mux_set_disconnect_latch_flag(port, true);
+ }
+
/*
* a MUX for a particular port can be a linked list chain of
* MUXes. So when we change one, we traverse the whole list
@@ -247,6 +256,35 @@ mux_state_t usb_mux_get(int port)
return rv ? USB_PD_MUX_NONE : mux_state;
}
+/* Get USB MUX (virtual MUX) disconnect flag */
+bool usb_mux_get_disconnect_latch_flag(int port)
+{
+ bool rv = false;
+
+ if (port >= board_get_usb_pd_port_count())
+ return rv;
+
+ if (!IS_ENABLED(CONFIG_USB_MUX_VIRTUAL))
+ return rv;
+
+ return !!(flags[port] & USB_MUX_FLAG_DISCONNECT_LATCH);
+}
+
+/* Set USB MUX (virtual MUX) disconnect flag */
+void usb_mux_set_disconnect_latch_flag(int port, bool enable)
+{
+ if (port >= board_get_usb_pd_port_count())
+ return;
+
+ if (!IS_ENABLED(CONFIG_USB_MUX_VIRTUAL))
+ return;
+
+ if (enable)
+ atomic_or(&flags[port], USB_MUX_FLAG_DISCONNECT_LATCH);
+ else
+ atomic_clear_bits(&flags[port], USB_MUX_FLAG_DISCONNECT_LATCH);
+}
+
void usb_mux_flip(int port)
{
mux_state_t mux_state;
@@ -366,6 +404,19 @@ static enum ec_status hc_usb_pd_mux_info(struct host_cmd_handler_args *args)
r->flags = mux_state;
+ /*
+ * Force disconnect mode if disconnect latch flag is set.
+ * Send host event for configuring the latest mux state
+ */
+ if (IS_ENABLED(CONFIG_USB_MUX_VIRTUAL) &&
+ usb_mux_get_disconnect_latch_flag(port)) {
+ r->flags = USB_PD_MUX_NONE;
+ usb_mux_set_disconnect_latch_flag(port, false);
+ args->response_size = sizeof(*r);
+ host_set_single_event(EC_HOST_EVENT_USB_MUX);
+ return EC_RES_SUCCESS;
+ }
+
/* Clear HPD IRQ event since we're about to inform host of it. */
if (IS_ENABLED(CONFIG_USB_MUX_VIRTUAL) &&
(r->flags & USB_PD_MUX_HPD_IRQ)) {