diff options
-rw-r--r-- | board/plankton/board.c | 1 | ||||
-rw-r--r-- | board/ryu/board.c | 25 | ||||
-rw-r--r-- | board/ryu/board.h | 1 | ||||
-rw-r--r-- | board/ryu/usb_pd_policy.c | 52 | ||||
-rw-r--r-- | board/samus_pd/board.c | 163 | ||||
-rw-r--r-- | board/samus_pd/usb_pd_policy.c | 3 | ||||
-rw-r--r-- | include/usb_pd.h | 14 |
7 files changed, 187 insertions, 72 deletions
diff --git a/board/plankton/board.c b/board/plankton/board.c index fb3a2914dc..2770c5b0ea 100644 --- a/board/plankton/board.c +++ b/board/plankton/board.c @@ -76,6 +76,7 @@ static void set_usbc_action(enum usbc_action act) gpio_set_level(GPIO_USBC_SS_USB_MODE, 0); break; case USBC_ACT_CABLE_FLIP: + pd_send_vdm(0, USB_VID_GOOGLE, VDO_CMD_FLIP, NULL, 0); gpio_set_level(GPIO_USBC_POLARITY, !gpio_get_level(GPIO_USBC_POLARITY)); break; diff --git a/board/ryu/board.c b/board/ryu/board.c index a187eb909d..6129e8dbc1 100644 --- a/board/ryu/board.c +++ b/board/ryu/board.c @@ -138,6 +138,31 @@ int board_get_usb_mux(int port, const char **dp_str, const char **usb_str) return has_ss; } +void board_flip_usb_mux(int port) +{ + int usb_polarity; + + /* Flip DP polarity */ + gpio_set_level(GPIO_USBC_DP_POLARITY, + !gpio_get_level(GPIO_USBC_DP_POLARITY)); + + /* Flip USB polarity if enabled */ + if (gpio_get_level(GPIO_USBC_SS1_USB_MODE_L) && + gpio_get_level(GPIO_USBC_SS2_USB_MODE_L)) + return; + usb_polarity = gpio_get_level(GPIO_USBC_SS1_USB_MODE_L); + + /* + * Disable both sides first so that we don't enable both at the + * same time accidentally. + */ + gpio_set_level(GPIO_USBC_SS1_USB_MODE_L, 1); + gpio_set_level(GPIO_USBC_SS2_USB_MODE_L, 1); + + gpio_set_level(GPIO_USBC_SS1_USB_MODE_L, !usb_polarity); + gpio_set_level(GPIO_USBC_SS2_USB_MODE_L, usb_polarity); +} + /** * Discharge battery when on AC power for factory test. */ diff --git a/board/ryu/board.h b/board/ryu/board.h index 47104dc837..74338bddfc 100644 --- a/board/ryu/board.h +++ b/board/ryu/board.h @@ -21,6 +21,7 @@ /* Optional features */ #define CONFIG_STM_HWTIMER32 #define CONFIG_USB_POWER_DELIVERY +#define CONFIG_USB_PD_CUSTOM_VDM #define CONFIG_USB_PD_DUAL_ROLE #define CONFIG_USB_PD_FLASH_ERASE_CHECK #define CONFIG_USB_PD_INTERNAL_COMP diff --git a/board/ryu/usb_pd_policy.c b/board/ryu/usb_pd_policy.c index 10ceb1c30a..dc28ebd3bd 100644 --- a/board/ryu/usb_pd_policy.c +++ b/board/ryu/usb_pd_policy.c @@ -16,6 +16,7 @@ #include "usb_pd.h" #define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) /* TODO(crosbug.com/p/28869): update source and sink tables to spec. */ const uint32_t pd_src_pdo[] = { @@ -136,3 +137,54 @@ int pd_board_checks(void) return EC_SUCCESS; } +/* ----------------- Vendor Defined Messages ------------------ */ +static int pd_custom_vdm(int port, int cnt, uint32_t *payload, + uint32_t **rpayload) +{ + int cmd = PD_VDO_CMD(payload[0]); + uint16_t dev_id = 0; + CPRINTF("VDM/%d [%d] %08x\n", cnt, cmd, payload[0]); + + /* make sure we have some payload */ + if (cnt == 0) + return 0; + + switch (cmd) { + case VDO_CMD_VERSION: + /* guarantee last byte of payload is null character */ + *(payload + cnt - 1) = 0; + CPRINTF("version: %s\n", (char *)(payload+1)); + break; + case VDO_CMD_READ_INFO: + case VDO_CMD_SEND_INFO: + /* if last word is present, it contains lots of info */ + if (cnt == 7) { + /* TODO: Notify host */ + dev_id = VDO_INFO_HW_DEV_ID(payload[6]); + CPRINTF("Dev:0x%04x SW:%d RW:%d\n", dev_id, + VDO_INFO_SW_DBG_VER(payload[6]), + VDO_INFO_IS_RW(payload[6])); + } + /* copy hash */ + if (cnt >= 6) + pd_dev_store_rw_hash(port, dev_id, payload + 1); + + break; + case VDO_CMD_CURRENT: + CPRINTF("Current: %dmA\n", payload[1]); + break; + case VDO_CMD_FLIP: + board_flip_usb_mux(0); + break; + } + + return 0; +} + +int pd_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) +{ + if (PD_VDO_SVDM(payload[0])) + return pd_svdm(port, cnt, payload, rpayload); + else + return pd_custom_vdm(port, cnt, payload, rpayload); +} diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c index f250dd34a6..deca02675e 100644 --- a/board/samus_pd/board.c +++ b/board/samus_pd/board.c @@ -180,89 +180,82 @@ const struct i2c_port_t i2c_ports[] = { }; const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); -void board_set_usb_mux(int port, enum typec_mux mux, int polarity) +struct usb_port_mux { - if (port == 0) { - /* reset everything */ - gpio_set_level(GPIO_USB_C0_SS1_EN_L, 1); - gpio_set_level(GPIO_USB_C0_SS2_EN_L, 1); - gpio_set_level(GPIO_USB_C0_DP_MODE_L, 1); - gpio_set_level(GPIO_USB_C0_DP_POLARITY, 1); - gpio_set_level(GPIO_USB_C0_SS1_DP_MODE, 1); - gpio_set_level(GPIO_USB_C0_SS2_DP_MODE, 1); - - if (mux == TYPEC_MUX_NONE) - /* everything is already disabled, we can return */ - return; - - if (mux == TYPEC_MUX_USB || mux == TYPEC_MUX_DOCK) { - /* USB 3.0 uses 2 superspeed lanes */ - gpio_set_level(polarity ? GPIO_USB_C0_SS2_DP_MODE : - GPIO_USB_C0_SS1_DP_MODE, 0); - } + enum gpio_signal ss1_en_l; + enum gpio_signal ss2_en_l; + enum gpio_signal dp_mode_l; + enum gpio_signal dp_polarity; + enum gpio_signal ss1_dp_mode; + enum gpio_signal ss2_dp_mode; +}; - if (mux == TYPEC_MUX_DP || mux == TYPEC_MUX_DOCK) { - /* DP uses available superspeed lanes (x2 or x4) */ - gpio_set_level(GPIO_USB_C0_DP_POLARITY, polarity); - gpio_set_level(GPIO_USB_C0_DP_MODE_L, 0); - } - /* switch on superspeed lanes */ - gpio_set_level(GPIO_USB_C0_SS1_EN_L, 0); - gpio_set_level(GPIO_USB_C0_SS2_EN_L, 0); - } else { - /* reset everything */ - gpio_set_level(GPIO_USB_C1_SS1_EN_L, 1); - gpio_set_level(GPIO_USB_C1_SS2_EN_L, 1); - gpio_set_level(GPIO_USB_C1_DP_MODE_L, 1); - gpio_set_level(GPIO_USB_C1_DP_POLARITY, 1); - gpio_set_level(GPIO_USB_C1_SS1_DP_MODE, 1); - gpio_set_level(GPIO_USB_C1_SS2_DP_MODE, 1); - - if (mux == TYPEC_MUX_NONE) - /* everything is already disabled, we can return */ - return; - - if (mux == TYPEC_MUX_USB || mux == TYPEC_MUX_DOCK) { - /* USB 3.0 uses 2 superspeed lanes */ - gpio_set_level(polarity ? GPIO_USB_C1_SS2_DP_MODE : - GPIO_USB_C1_SS1_DP_MODE, 0); - } +const struct usb_port_mux usb_muxes[] = { + { + .ss1_en_l = GPIO_USB_C0_SS1_EN_L, + .ss2_en_l = GPIO_USB_C0_SS2_EN_L, + .dp_mode_l = GPIO_USB_C0_DP_MODE_L, + .dp_polarity = GPIO_USB_C0_DP_POLARITY, + .ss1_dp_mode = GPIO_USB_C0_SS1_DP_MODE, + .ss2_dp_mode = GPIO_USB_C0_SS2_DP_MODE, + }, + { + .ss1_en_l = GPIO_USB_C1_SS1_EN_L, + .ss2_en_l = GPIO_USB_C1_SS2_EN_L, + .dp_mode_l = GPIO_USB_C1_DP_MODE_L, + .dp_polarity = GPIO_USB_C1_DP_POLARITY, + .ss1_dp_mode = GPIO_USB_C1_SS1_DP_MODE, + .ss2_dp_mode = GPIO_USB_C1_SS2_DP_MODE, + }, +}; +BUILD_ASSERT(ARRAY_SIZE(usb_muxes) == PD_PORT_COUNT); - if (mux == TYPEC_MUX_DP || mux == TYPEC_MUX_DOCK) { - /* DP uses available superspeed lanes (x2 or x4) */ - gpio_set_level(GPIO_USB_C1_DP_POLARITY, polarity); - gpio_set_level(GPIO_USB_C1_DP_MODE_L, 0); - } - /* switch on superspeed lanes */ - gpio_set_level(GPIO_USB_C1_SS1_EN_L, 0); - gpio_set_level(GPIO_USB_C1_SS2_EN_L, 0); +void board_set_usb_mux(int port, enum typec_mux mux, int polarity) +{ + const struct usb_port_mux *usb_mux = usb_muxes + port; + + /* reset everything */ + gpio_set_level(usb_mux->ss1_en_l, 1); + gpio_set_level(usb_mux->ss2_en_l, 1); + gpio_set_level(usb_mux->dp_mode_l, 1); + gpio_set_level(usb_mux->dp_polarity, 1); + gpio_set_level(usb_mux->ss1_dp_mode, 1); + gpio_set_level(usb_mux->ss2_dp_mode, 1); + + if (mux == TYPEC_MUX_NONE) + /* everything is already disabled, we can return */ + return; + + if (mux == TYPEC_MUX_USB || mux == TYPEC_MUX_DOCK) { + /* USB 3.0 uses 2 superspeed lanes */ + gpio_set_level(polarity ? usb_mux->ss2_dp_mode : + usb_mux->ss1_dp_mode, 0); + } + + if (mux == TYPEC_MUX_DP || mux == TYPEC_MUX_DOCK) { + /* DP uses available superspeed lanes (x2 or x4) */ + gpio_set_level(usb_mux->dp_polarity, polarity); + gpio_set_level(usb_mux->dp_mode_l, 0); } + /* switch on superspeed lanes */ + gpio_set_level(usb_mux->ss1_en_l, 0); + gpio_set_level(usb_mux->ss2_en_l, 0); } int board_get_usb_mux(int port, const char **dp_str, const char **usb_str) { + const struct usb_port_mux *usb_mux = usb_muxes + port; int has_ss, has_usb, has_dp; const char *dp, *usb; - if (port == 0) { - has_ss = !gpio_get_level(GPIO_USB_C0_SS1_EN_L); - has_usb = !gpio_get_level(GPIO_USB_C0_SS1_DP_MODE) || - !gpio_get_level(GPIO_USB_C0_SS2_DP_MODE); - has_dp = !gpio_get_level(GPIO_USB_C0_DP_MODE_L); - dp = gpio_get_level(GPIO_USB_C0_DP_POLARITY) ? - "DP2" : "DP1"; - usb = gpio_get_level(GPIO_USB_C0_SS1_DP_MODE) ? - "USB2" : "USB1"; - } else { - has_ss = !gpio_get_level(GPIO_USB_C1_SS1_EN_L); - has_usb = !gpio_get_level(GPIO_USB_C1_SS1_DP_MODE) || - !gpio_get_level(GPIO_USB_C1_SS2_DP_MODE); - has_dp = !gpio_get_level(GPIO_USB_C1_DP_MODE_L); - dp = gpio_get_level(GPIO_USB_C1_DP_POLARITY) ? - "DP2" : "DP1"; - usb = gpio_get_level(GPIO_USB_C1_SS1_DP_MODE) ? - "USB2" : "USB1"; - } + has_ss = !gpio_get_level(usb_mux->ss1_en_l); + has_usb = !gpio_get_level(usb_mux->ss1_dp_mode) || + !gpio_get_level(usb_mux->ss2_dp_mode); + has_dp = !gpio_get_level(usb_mux->dp_mode_l); + dp = gpio_get_level(usb_mux->dp_polarity) ? + "DP2" : "DP1"; + usb = gpio_get_level(usb_mux->ss1_dp_mode) ? + "USB2" : "USB1"; *dp_str = has_dp ? dp : NULL; *usb_str = has_usb ? usb : NULL; @@ -270,6 +263,32 @@ int board_get_usb_mux(int port, const char **dp_str, const char **usb_str) return has_ss; } +void board_flip_usb_mux(int port) +{ + const struct usb_port_mux *usb_mux = usb_muxes + port; + int usb_polarity; + + /* Flip DP polarity */ + gpio_set_level(usb_mux->dp_polarity, + !gpio_get_level(usb_mux->dp_polarity)); + + /* Flip USB polarity if enabled */ + if (gpio_get_level(usb_mux->ss1_dp_mode) && + gpio_get_level(usb_mux->ss2_dp_mode)) + return; + usb_polarity = gpio_get_level(usb_mux->ss1_dp_mode); + + /* + * Disable both sides first so that we don't enable both at the + * same time accidentally. + */ + gpio_set_level(usb_mux->ss1_dp_mode, 1); + gpio_set_level(usb_mux->ss2_dp_mode, 1); + + gpio_set_level(usb_mux->ss1_dp_mode, !usb_polarity); + gpio_set_level(usb_mux->ss2_dp_mode, usb_polarity); +} + void board_update_battery_soc(int soc) { batt_soc = soc; diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c index dce1407ec3..dd875f0ec4 100644 --- a/board/samus_pd/usb_pd_policy.c +++ b/board/samus_pd/usb_pd_policy.c @@ -201,6 +201,9 @@ static int pd_custom_vdm(int port, int cnt, uint32_t *payload, case VDO_CMD_CURRENT: ccprintf("Current: %dmA\n", payload[1]); break; + case VDO_CMD_FLIP: + board_flip_usb_mux(port); + break; } return 0; diff --git a/include/usb_pd.h b/include/usb_pd.h index 99e0271a58..8146562df4 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -219,6 +219,7 @@ struct pd_policy { #define VDO_CMD_ERASE_SIG VDO_CMD_VENDOR(8) #define VDO_CMD_PING_ENABLE VDO_CMD_VENDOR(10) #define VDO_CMD_CURRENT VDO_CMD_VENDOR(11) +#define VDO_CMD_FLIP VDO_CMD_VENDOR(12) #define PD_VDO_VID(vdo) ((vdo) >> 16) #define PD_VDO_SVDM(vdo) (((vdo) >> 15) & 1) @@ -688,6 +689,19 @@ void board_set_usb_mux(int port, enum typec_mux mux, int polarity); */ int board_get_usb_mux(int port, const char **dp_str, const char **usb_str); +/** + * Flip the superspeed muxes on type-C port. + * + * This is used for factory test automation. Note that this function should + * only flip the superspeed muxes and leave CC lines alone. Without further + * changes, this function MUST ONLY be used for testing purpose, because + * the protocol layer loses track of the superspeed polarity and DP/USB3.0 + * connection may break. + * + * @param port port number. + */ +void board_flip_usb_mux(int port); + /* --- Physical layer functions : chip specific --- */ /* Packet preparation/retrieval */ |