summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2015-05-07 08:04:04 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-05-07 19:37:45 +0000
commit6d80aeed939a35859c87517236e88c847604499d (patch)
tree8561050d115b6414cd4ab420d44aee67353110c7
parent3dd6e71828b12b786a7cf84fe1bf9b01a3856eee (diff)
downloadchrome-ec-6d80aeed939a35859c87517236e88c847604499d.tar.gz
ryu: enable alternate modes for USB PD
Enable the support to be a USB-PD alternate mode DFP and add configuration for the DisplayPort alternate mode and the GFU mode. Only on Ryu P6 as the P5 board is using the HPD line for the power sequencing workaround. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=chrome-os-partner:39946 chrome-os-partner:38689 TEST=on Ryu P6, plug a Hoho dongle, see that the superspeed muxes are in DP1 or DP2 mode (using the "typec 0" command), plug and unplug an HDMI monitor and see the HPD line moving when typing "gpioget USBC_DP_HPD". > pd 0 state Port C0, Ena - Role: SRC-DFP-VC Polarity: CC1 Flags: 0x1150, State: SRC_READY > adc VBUS = 4980 CC1_PD = 992 CC2_PD = 57 > typec 0 Port C0: CC1 993 mV CC2 58 mV (polarity:CC1) Superspeed DP1 > gpioget USBC_DP_HPD 0 USBC_DP_HPD <--- PLUG monitor ---> > gpioget USBC_DP_HPD 1* USBC_DP_HPD Change-Id: Ie25a3bb0d6331c1d931b7f542fbc637270c20b3b Reviewed-on: https://chromium-review.googlesource.com/269855 Trybot-Ready: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org> Reviewed-by: Todd Broch <tbroch@chromium.org> Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
-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);