summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/plankton/board.c1
-rw-r--r--board/ryu/board.c25
-rw-r--r--board/ryu/board.h1
-rw-r--r--board/ryu/usb_pd_policy.c52
-rw-r--r--board/samus_pd/board.c163
-rw-r--r--board/samus_pd/usb_pd_policy.c3
-rw-r--r--include/usb_pd.h14
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 */