summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/ryu/board.c41
-rw-r--r--board/ryu/board.h8
-rw-r--r--board/ryu/gpio.inc7
-rw-r--r--board/ryu/usb_pd_policy.c228
4 files changed, 258 insertions, 26 deletions
diff --git a/board/ryu/board.c b/board/ryu/board.c
index a5b5346e93..a9792ed8ed 100644
--- a/board/ryu/board.c
+++ b/board/ryu/board.c
@@ -320,16 +320,6 @@ static void board_init(void)
/* Enable interrupts on VBUS transitions. */
gpio_enable_interrupt(GPIO_CHGR_ACOK);
-
- /*
- * TODO(crosbug.com/p/38689) Workaround for PMIC issue on P5.
- * remove when P5 are de-commissioned.
- * We are re-using EXTINT1 for the new power sequencing workaround
- * this is killing the base closing detection on P5
- * we won't charge it.
- */
- if (board_get_version() == 5)
- gpio_enable_interrupt(GPIO_HPD_IN);
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
@@ -340,16 +330,6 @@ const struct power_signal_info power_signal_list[] = {
};
BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
-/*
- * TODO(crosbug.com/p/38689) Workaround for MAX77620 PMIC EN_PP3300 issue.
- * remove when P5 are de-commissioned.
- */
-void pp1800_on_off_evt(enum gpio_signal signal)
-{
- int level = gpio_get_level(signal);
- gpio_set_level(GPIO_EN_PP3300_RSVD, level);
-}
-
/* ADC channels */
const struct adc_t adc_channels[] = {
/* Vbus sensing. Converted to mV, /10 voltage divider. */
@@ -439,6 +419,21 @@ int board_get_usb_mux(int port, const char **dp_str, const char **usb_str)
return has_dp || has_usb;
}
+void board_flip_usb_mux(int port)
+{
+ int has_usb, has_dp, polarity;
+ enum typec_mux mux;
+
+ has_usb = gpio_get_level(GPIO_USBC_MUX_CONF2);
+ has_dp = gpio_get_level(GPIO_USBC_MUX_CONF1);
+ polarity = gpio_get_level(GPIO_USBC_MUX_CONF0);
+ mux = has_usb && has_dp ? TYPEC_MUX_DOCK :
+ (has_dp ? TYPEC_MUX_DP :
+ (has_usb ? TYPEC_MUX_USB : TYPEC_MUX_NONE));
+
+ board_set_usb_mux(port, mux, usb_switch_state, !polarity);
+}
+
/**
* Discharge battery when on AC power for factory test.
*/
@@ -511,6 +506,12 @@ void board_set_charge_limit(int charge_ma)
CPRINTS("Failed to set input current limit for PD");
}
+/* Send host event up to AP */
+void pd_send_host_event(int mask)
+{
+ /* TODO(crosbug.com/p/33194): implement host events */
+}
+
/**
* Enable and disable SPI for case closed debugging. This forces the AP into
* reset while SPI is enabled, thus preventing contention on the SPI interface.
diff --git a/board/ryu/board.h b/board/ryu/board.h
index 2e3b71ad30..f0210f8f5d 100644
--- a/board/ryu/board.h
+++ b/board/ryu/board.h
@@ -24,6 +24,9 @@
#define CONFIG_FORCE_CONSOLE_RESUME
#define CONFIG_STM_HWTIMER32
#define CONFIG_USB_POWER_DELIVERY
+#define CONFIG_USB_PD_ALT_MODE
+#define CONFIG_USB_PD_ALT_MODE_DFP
+#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
@@ -121,7 +124,7 @@
/* Maximum number of deferrable functions */
#undef DEFERRABLE_MAX_COUNT
-#define DEFERRABLE_MAX_COUNT 14
+#define DEFERRABLE_MAX_COUNT 16
#ifndef __ASSEMBLER__
@@ -185,6 +188,9 @@ int board_discharge_on_ac(int enable);
/* Set the charge current limit. */
void board_set_charge_limit(int charge_ma);
+/* Send host event to AP */
+void pd_send_host_event(int mask);
+
/* PP1800 transition GPIO interrupt handler */
void pp1800_on_off_evt(enum gpio_signal signal);
diff --git a/board/ryu/gpio.inc b/board/ryu/gpio.inc
index 03963164b9..0cbf0b55a8 100644
--- a/board/ryu/gpio.inc
+++ b/board/ryu/gpio.inc
@@ -13,11 +13,6 @@ GPIO_INT(LID_OPEN, E, 1, GPIO_INT_BOTH | GPIO_PULL_UP, lid_inter
GPIO_INT(CHARGE_DONE, E, 6, GPIO_INT_BOTH, inductive_charging_interrupt)
GPIO_INT(AP_IN_SUSPEND, F, 9, GPIO_INT_BOTH, power_signal_interrupt)
GPIO_INT(AP_HOLD, E, 3, GPIO_INT_BOTH, power_signal_interrupt)
-/*
- * TODO(crosbug.com/p/38689) Workaround for MAX77620 PMIC PP3300 issue
- * Put back as GPIO_ODR_HIGH for P6+
- */
-GPIO_INT(HPD_IN, C, 1, GPIO_INT_BOTH, pp1800_on_off_evt)
/* Interrupt lines not used yet */
GPIO(BC_TEMP_ALERT_L, C, 5, GPIO_INT_FALLING)
@@ -81,6 +76,8 @@ GPIO(USBC_MUX_CONF0, D, 3, GPIO_OUT_LOW)
GPIO(USBC_MUX_CONF1, D, 9, GPIO_OUT_LOW)
GPIO(USBC_MUX_CONF2, E, 0, GPIO_OUT_LOW)
+GPIO(USBC_DP_HPD, C, 1, GPIO_OUT_LOW)
+
/* Inputs */
GPIO(BOARD_ID0, E, 11, GPIO_INPUT)
GPIO(BOARD_ID1, E, 12, GPIO_INPUT)
diff --git a/board/ryu/usb_pd_policy.c b/board/ryu/usb_pd_policy.c
index 7bb5aea2e4..d423fe22f0 100644
--- a/board/ryu/usb_pd_policy.c
+++ b/board/ryu/usb_pd_policy.c
@@ -12,6 +12,7 @@
#include "hooks.h"
#include "host_command.h"
#include "registers.h"
+#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
@@ -136,8 +137,235 @@ void pd_execute_data_swap(int port, int data_role)
/* TODO: what do we need to do to change host controller data role? */
}
+/* ----------------- Vendor Defined Messages ------------------ */
+const struct svdm_response svdm_rsp = {
+ .identity = NULL,
+ .svids = NULL,
+ .modes = NULL,
+};
+
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;
+ int is_rw, is_latest;
+
+ /* 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:
+ /* copy hash */
+ if (cnt == 7) {
+ dev_id = VDO_INFO_HW_DEV_ID(payload[6]);
+ is_rw = VDO_INFO_IS_RW(payload[6]);
+ is_latest = pd_dev_store_rw_hash(port,
+ dev_id,
+ payload + 1,
+ is_rw ?
+ SYSTEM_IMAGE_RW :
+ SYSTEM_IMAGE_RO);
+
+ /*
+ * Send update host event unless our RW hash is
+ * already known to be the latest update RW.
+ */
+ if (!is_rw || !is_latest)
+ pd_send_host_event(PD_EVENT_UPDATE_DEVICE);
+
+ CPRINTF("DevId:%d.%d SW:%d RW:%d\n",
+ HW_DEV_ID_MAJ(dev_id),
+ HW_DEV_ID_MIN(dev_id),
+ VDO_INFO_SW_DBG_VER(payload[6]),
+ is_rw);
+ } else if (cnt == 6) {
+ /* really old devices don't have last byte */
+ pd_dev_store_rw_hash(port, dev_id, payload + 1,
+ SYSTEM_IMAGE_UNKNOWN);
+ }
+ break;
+ case VDO_CMD_CURRENT:
+ CPRINTF("Current: %dmA\n", payload[1]);
+ break;
+ case VDO_CMD_FLIP:
+ board_flip_usb_mux(port);
+ break;
+#ifdef CONFIG_USB_PD_LOGGING
+ case VDO_CMD_GET_LOG:
+ pd_log_recv_vdm(port, cnt, payload);
+ break;
+#endif /* CONFIG_USB_PD_LOGGING */
+ }
+
+ return 0;
+}
+
+static int dp_flags;
+/* DP Status VDM as returned by UFP */
+static uint32_t dp_status;
+
+static void svdm_safe_dp_mode(int port)
+{
+ /* make DP interface safe until configure */
+ board_set_usb_mux(port, TYPEC_MUX_NONE, USB_SWITCH_CONNECT, 0);
+ dp_flags = 0;
+ dp_status = 0;
+}
+
+static int svdm_enter_dp_mode(int port, uint32_t mode_caps)
+{
+ /* Only enter mode if device is DFP_D capable */
+ if (mode_caps & MODE_DP_SNK) {
+ svdm_safe_dp_mode(port);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int svdm_dp_status(int port, uint32_t *payload)
+{
+ int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
+ payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
+ CMD_DP_STATUS | VDO_OPOS(opos));
+ payload[1] = VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */
+ 0, /* HPD level ... not applicable */
+ 0, /* exit DP? ... no */
+ 0, /* usb mode? ... no */
+ 0, /* multi-function ... no */
+ (!!(dp_flags & DP_FLAGS_DP_ON)),
+ 0, /* power low? ... no */
+ (!!(dp_flags & DP_FLAGS_DP_ON)));
+ return 2;
+};
+
+static int svdm_dp_config(int port, uint32_t *payload)
+{
+ int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
+ int mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status);
+ int pin_mode = pd_dfp_dp_get_pin_mode(port, dp_status);
+
+ if (!pin_mode)
+ return 0;
+
+ board_set_usb_mux(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP,
+ USB_SWITCH_CONNECT, pd_get_polarity(port));
+
+ payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
+ CMD_DP_CONFIG | VDO_OPOS(opos));
+ payload[1] = VDO_DP_CFG(pin_mode, /* UFP_U as UFP_D */
+ 0, /* UFP_U as DFP_D */
+ 1, /* DPv1.3 signaling */
+ 2); /* UFP_U connected as UFP_D */
+ return 2;
+};
+
+static void svdm_dp_post_config(int port)
+{
+ dp_flags |= DP_FLAGS_DP_ON;
+ if (!(dp_flags & DP_FLAGS_HPD_HI_PENDING))
+ return;
+
+ gpio_set_level(GPIO_USBC_DP_HPD, 1);
+}
+
+static void hpd_irq_deferred(void)
+{
+ gpio_set_level(GPIO_USBC_DP_HPD, 1);
+}
+DECLARE_DEFERRED(hpd_irq_deferred);
+
+static int svdm_dp_attention(int port, uint32_t *payload)
+{
+ int cur_lvl;
+ int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]);
+ int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]);
+ cur_lvl = gpio_get_level(GPIO_USBC_DP_HPD);
+
+ dp_status = payload[1];
+
+ /* Its initial DP status message prior to config */
+ if (!(dp_flags & DP_FLAGS_DP_ON)) {
+ if (lvl)
+ dp_flags |= DP_FLAGS_HPD_HI_PENDING;
+ return 1;
+ }
+
+ if (irq & cur_lvl) {
+ gpio_set_level(GPIO_USBC_DP_HPD, 0);
+ hook_call_deferred(hpd_irq_deferred,
+ HPD_DEBOUNCE_IRQ);
+ } else if (irq & !cur_lvl) {
+ CPRINTF("ERR:HPD:IRQ&LOW\n");
+ return 0; /* nak */
+ } else {
+ gpio_set_level(GPIO_USBC_DP_HPD, lvl);
+ }
+ /* ack */
+ return 1;
+}
+
+static void svdm_exit_dp_mode(int port)
+{
+ svdm_safe_dp_mode(port);
+ gpio_set_level(GPIO_USBC_DP_HPD, 0);
+}
+
+static int svdm_enter_gfu_mode(int port, uint32_t mode_caps)
+{
+ /* Always enter GFU mode */
return 0;
}
+
+static void svdm_exit_gfu_mode(int port)
+{
+}
+
+static int svdm_gfu_status(int port, uint32_t *payload)
+{
+ /*
+ * This is called after enter mode is successful, send unstructured
+ * VDM to read info.
+ */
+ pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_READ_INFO, NULL, 0);
+ return 0;
+}
+
+static int svdm_gfu_config(int port, uint32_t *payload)
+{
+ return 0;
+}
+
+static int svdm_gfu_attention(int port, uint32_t *payload)
+{
+ return 0;
+}
+
+const struct svdm_amode_fx supported_modes[] = {
+ {
+ .svid = USB_SID_DISPLAYPORT,
+ .enter = &svdm_enter_dp_mode,
+ .status = &svdm_dp_status,
+ .config = &svdm_dp_config,
+ .post_config = &svdm_dp_post_config,
+ .attention = &svdm_dp_attention,
+ .exit = &svdm_exit_dp_mode,
+ },
+ {
+ .svid = USB_VID_GOOGLE,
+ .enter = &svdm_enter_gfu_mode,
+ .status = &svdm_gfu_status,
+ .config = &svdm_gfu_config,
+ .attention = &svdm_gfu_attention,
+ .exit = &svdm_exit_gfu_mode,
+ }
+};
+const int supported_modes_cnt = ARRAY_SIZE(supported_modes);