diff options
author | Wai-Hong Tam <waihong@google.com> | 2018-06-07 02:37:19 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-12-08 11:23:21 -0800 |
commit | 89e13f198fce934b0f1452255b15f6244dbcabb7 (patch) | |
tree | ffbdea99fdf4d6df1d2e4648eabe27d58fbcffa8 | |
parent | 7f325f2e91482aee604de71f19f6669762594818 (diff) | |
download | chrome-ec-89e13f198fce934b0f1452255b15f6244dbcabb7.tar.gz |
cheza: Mux the 1st-plugged UFP port which is not a charger
There are 2 USB-C ports. A user may plug a USB-C to USB-A male
cable to one of the ports; then EC should mux the port from USB
hub to AP's primary USB controller, which is configured to do USB
peripheral mode only.
The policy is to mux the first-plugged UFP port to AP, with the
following exception:
* If the partner port does PD and it advertises the USB communications
capable bit unset in the fixed-supply PDO, we believe the partner
port is a pure charger.
* If the BC1.2 chip detects the partner is not a SDP or CDP , we
believe the partner port is not a workstation.
Check the design doc at:
http://go/cheza-hs-mux
BRANCH=none
BUG=b:74395451, b:110803836
TEST=Check the following scenario:
* Plug charger w/ PD to P0, plug C-to-A to P1, check P1 mux to AP.
* Plug charger through hub to P0, plug C-to-A to P1, check P1 mux to AP.
* Continue the above case, boot into kernel and check USB peripheral mode.
* Plug BC1.2 charger to P0, plug C-to-A to P1, check P1 mux to AP.
* Plug charger w/o PD to P0, plug C-to-A to P1, check P0 mux to AP.
* Swap P0 and P1 for the above cases and check the results.
Change-Id: I4034fa66c0b27cc48d0959bb3f1750690ad5e3f7
Signed-off-by: Wai-Hong Tam <waihong@google.com>
Reviewed-on: https://chromium-review.googlesource.com/1105404
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r-- | board/cheza/gpio.inc | 2 | ||||
-rw-r--r-- | board/cheza/usb_pd_policy.c | 34 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 9 | ||||
-rw-r--r-- | driver/bc12/pi3usb9281.c | 2 | ||||
-rw-r--r-- | driver/pi3usb9281.h | 3 | ||||
-rw-r--r-- | include/usb_pd.h | 9 |
6 files changed, 55 insertions, 4 deletions
diff --git a/board/cheza/gpio.inc b/board/cheza/gpio.inc index c721f94b73..72cd70ab0f 100644 --- a/board/cheza/gpio.inc +++ b/board/cheza/gpio.inc @@ -102,8 +102,6 @@ GPIO(CHG_LED_W_C1, PIN(C, 0), GPIO_OUT_LOW) /* EC_CHG_LED_W_C1 */ * +------- C1_MUX:D2 * | | * AP --- USB_HUB - * - * TODO(waihong): Support auto-detection and switching. */ /* Switch both port-0 and port-1 to the hub, which matches the SS path. */ GPIO(USB_C0_HS_MUX_OE_L, PIN(A, 4), GPIO_OUT_LOW) diff --git a/board/cheza/usb_pd_policy.c b/board/cheza/usb_pd_policy.c index 5f5e707819..bbc44a746e 100644 --- a/board/cheza/usb_pd_policy.c +++ b/board/cheza/usb_pd_policy.c @@ -6,6 +6,7 @@ #include "charge_manager.h" #include "console.h" #include "gpio.h" +#include "pi3usb9281.h" #include "system.h" #include "usb_mux.h" #include "usbc_ppc.h" @@ -93,7 +94,38 @@ int pd_check_vconn_swap(int port) void pd_execute_data_swap(int port, int data_role) { - /* Do nothing */ + int enable = (data_role == PD_ROLE_UFP); + int type; + + /* + * Exclude the PD charger, in which the "USB Communications Capable" + * bit is unset in the Fixed Supply PDO. + */ + if (pd_capable(port)) + enable = enable && pd_get_partner_usb_comm_capable(port); + + /* + * The hub behind the BC1.2 chip may advertise a BC1.2 type. So + * disconnect the switch when getting the charger type to ensure + * the detected type is from external. + */ + usb_charger_set_switches(port, USB_SWITCH_DISCONNECT); + type = pi3usb9281_get_device_type(port); + usb_charger_set_switches(port, USB_SWITCH_RESTORE); + + /* Exclude the BC1.2 charger, which is not detected as CDP or SDP. */ + enable = enable && (type & (PI3USB9281_TYPE_CDP | PI3USB9281_TYPE_SDP)); + + /* Only mux one port to AP. If already muxed, return. */ + if (enable && (!gpio_get_level(GPIO_USB_C0_HS_MUX_SEL) || + gpio_get_level(GPIO_USB_C1_HS_MUX_SEL))) + return; + + /* Port-0 and port-1 have different polarities. */ + if (port == 0) + gpio_set_level(GPIO_USB_C0_HS_MUX_SEL, enable ? 0 : 1); + else if (port == 1) + gpio_set_level(GPIO_USB_C1_HS_MUX_SEL, enable ? 1 : 0); } int pd_is_valid_input_voltage(int mv) diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 7a8634e174..6abb24ed51 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -336,6 +336,15 @@ int pd_capable(int port) return pd[port].flags & PD_FLAGS_PREVIOUS_PD_CONN; } +/* + * Return true if partner port is capable of communication over USB data + * lines. + */ +int pd_get_partner_usb_comm_capable(int port) +{ + return pd[port].flags & PD_FLAGS_PARTNER_USB_COMM; +} + #ifdef CONFIG_USB_PD_DUAL_ROLE void pd_vbus_low(int port) { diff --git a/driver/bc12/pi3usb9281.c b/driver/bc12/pi3usb9281.c index f1bd3ce8d4..06a1efba61 100644 --- a/driver/bc12/pi3usb9281.c +++ b/driver/bc12/pi3usb9281.c @@ -183,7 +183,7 @@ static int pi3usb9281_get_interrupts(int port) return pi3usb9281_read(port, PI3USB9281_REG_INT); } -static int pi3usb9281_get_device_type(int port) +int pi3usb9281_get_device_type(int port) { return pi3usb9281_read(port, PI3USB9281_REG_DEV_TYPE) & 0x77; } diff --git a/driver/pi3usb9281.h b/driver/pi3usb9281.h index fe19f0e977..fd4375b9b1 100644 --- a/driver/pi3usb9281.h +++ b/driver/pi3usb9281.h @@ -74,4 +74,7 @@ extern struct pi3usb9281_config pi3usb9281_chips[]; /* Enable interrupts. */ int pi3usb9281_enable_interrupts(int port); +/* Get the device type */ +int pi3usb9281_get_device_type(int port); + #endif /* __CROS_EC_PI3USB9281_H */ diff --git a/include/usb_pd.h b/include/usb_pd.h index 1927add067..f451206b4b 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -1832,6 +1832,15 @@ int pd_ts_dts_plugged(int port); */ int pd_capable(int port); + +/** + * Return true if partner port is capable of communication over USB data + * lines. + * + * @param port USB-C port number + */ +int pd_get_partner_usb_comm_capable(int port); + /** * Return true if vbus is present on the specified port. * |