summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Broch <tbroch@chromium.org>2014-11-12 16:32:02 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-05-01 01:08:10 +0000
commit7cc3136da56eaea8cfa7f9139ebaf6361707ade2 (patch)
tree9a66caa15bf4a2df6954c592ca6978a1bda1ad11
parent56653dec06ede2c62ec35c74f0e133f18dd7ea50 (diff)
downloadchrome-ec-7cc3136da56eaea8cfa7f9139ebaf6361707ade2.tar.gz
plankton: HPD over USB PD.
HPD needs to be transported over USB PD as both SBU lines are consumed for differential AUX signalling. This CL does the following: 1. Enables GPIO DPSRC_HPD as interrupt. 2. Sends debounced HPD across CC via the SVDM DP status message. 3. Adds polling for GPIO_DBG_20V_TO_DUT_L as it shares the same interrupt as DPSRC_HPD. 4. Configures DP redriver in presence of HPD high. Signed-off-by: Todd Broch <tbroch@chromium.org> BRANCH=none BUG=chrome-os-partner:33132,chrome-os-partner:33761 TEST=manual, 1. Connect samus -> plankton via type-C 2. Connect plankton -> DP monitor via displayport See initial SVDM discovery on samus console See EDID information See SVDM status message correct when plug/unplug DP cable from plankton 3. Press 'CHARGING_20V_TO_DUT_L' button and see below on plankton console. Button 8 = 0 Change-Id: Id95567a3bfa073ffa2c699335be8c5bf0327675f Reviewed-on: https://chromium-review.googlesource.com/229429 Reviewed-by: Alec Berg <alecaberg@chromium.org> Commit-Queue: Todd Broch <tbroch@chromium.org> Tested-by: Todd Broch <tbroch@chromium.org>
-rw-r--r--board/plankton/board.c107
-rw-r--r--board/plankton/board.h8
-rw-r--r--board/plankton/gpio.inc8
-rw-r--r--board/plankton/usb_pd_policy.c156
-rw-r--r--common/usb_pd_policy.c2
-rw-r--r--common/usb_pd_protocol.c2
6 files changed, 273 insertions, 10 deletions
diff --git a/board/plankton/board.c b/board/plankton/board.c
index 7140942ab1..bd6fe3637a 100644
--- a/board/plankton/board.c
+++ b/board/plankton/board.c
@@ -21,6 +21,78 @@
#include "usb_pd_config.h"
#include "util.h"
+void button_event(enum gpio_signal signal);
+void hpd_event(enum gpio_signal signal);
+void vbus_event(enum gpio_signal signal);
+#include "gpio_list.h"
+
+static volatile uint64_t hpd_prev_ts;
+static volatile int hpd_prev_level;
+static volatile int hpd_possible_irq;
+
+static int sn75dp130_dpcd_init(void);
+
+/**
+ * Hotplug detect deferred task
+ *
+ * Called after level change on hpd GPIO to evaluate (and debounce) what event
+ * has occurred. There are 3 events that occur on HPD:
+ * 1. low : downstream display sink is deattached
+ * 2. high : downstream display sink is attached
+ * 3. irq : downstream display sink signalling an interrupt.
+ *
+ * The debounce times for these various events are:
+ * 100MSEC : min pulse width of level value.
+ * 2MSEC : min pulse width of IRQ low pulse. Max is level debounce min.
+ *
+ * lvl(n-2) lvl(n-1) lvl prev_delta now_delta event
+ * ----------------------------------------------------
+ * 1 0 1 <2ms n/a low glitch (ignore)
+ * 1 0 1 >2ms <100ms irq
+ * x 0 1 n/a >100ms high
+ * 0 1 0 <100ms n/a high glitch (ignore)
+ * x 1 0 n/a >100ms low
+ */
+
+void hpd_lvl_deferred(void)
+{
+ int level = gpio_get_level(GPIO_DPSRC_HPD);
+
+ if (level != hpd_prev_level) {
+ /* Stable level changed. Send HPD event */
+ hpd_prev_level = level;
+ pd_send_hpd(0, level ? hpd_high : hpd_low);
+ /* Configure redriver's back side */
+ if (level)
+ sn75dp130_dpcd_init();
+
+ }
+
+ /* Send queued IRQ if the cable is attached */
+ if (hpd_possible_irq && level)
+ pd_send_hpd(0, hpd_irq);
+ hpd_possible_irq = 0;
+
+}
+DECLARE_DEFERRED(hpd_lvl_deferred);
+
+void hpd_event(enum gpio_signal signal)
+{
+ timestamp_t now = get_time();
+ int level = gpio_get_level(signal);
+ uint64_t cur_delta = now.val - hpd_prev_ts;
+
+ /* Record low pulse */
+ if (cur_delta >= HPD_DEBOUNCE_IRQ && level)
+ hpd_possible_irq = 1;
+
+ /* store current time */
+ hpd_prev_ts = now.val;
+
+ /* All previous hpd level events need to be re-triggered */
+ hook_call_deferred(hpd_lvl_deferred, HPD_DEBOUNCE_LVL);
+}
+
/* Debounce time for voltage buttons */
#define BUTTON_DEBOUNCE_US (100 * MSEC)
@@ -98,9 +170,24 @@ static void set_usbc_action(enum usbc_action act)
}
}
+/* has Pull-up */
+static int prev_dbg20v = 1;
+static void button_dbg20v_deferred(void);
+static void enable_dbg20v_poll(void)
+{
+ hook_call_deferred(button_dbg20v_deferred, 10 * MSEC);
+}
+
/* Handle debounced button press */
static void button_deferred(void)
{
+ if (button_pressed == GPIO_DBG_20V_TO_DUT_L) {
+ enable_dbg20v_poll();
+ if (gpio_get_level(GPIO_DBG_20V_TO_DUT_L) == prev_dbg20v)
+ return;
+ else
+ prev_dbg20v = !prev_dbg20v;
+ }
/* bounce ? */
if (gpio_get_level(button_pressed) != 0)
return;
@@ -140,14 +227,21 @@ void button_event(enum gpio_signal signal)
hook_call_deferred(button_deferred, BUTTON_DEBOUNCE_US);
}
+static void button_dbg20v_deferred(void)
+{
+ if (gpio_get_level(GPIO_DBG_20V_TO_DUT_L) == 0)
+ button_event(GPIO_DBG_20V_TO_DUT_L);
+ else
+ enable_dbg20v_poll();
+}
+DECLARE_DEFERRED(button_dbg20v_deferred);
+
void vbus_event(enum gpio_signal signal)
{
ccprintf("VBUS! =%d\n", gpio_get_level(signal));
task_wake(TASK_ID_PD);
}
-#include "gpio_list.h"
-
/* ADC channels */
const struct adc_t adc_channels[] = {
/* USB PD CC lines sensing. Converted to mV (3300mV/4096). */
@@ -247,17 +341,24 @@ static int sn75dp130_redriver_init(void)
static void board_init(void)
{
+ timestamp_t now = get_time();
+ hpd_prev_level = gpio_get_level(GPIO_DPSRC_HPD);
+ hpd_prev_ts = now.val;
+ gpio_enable_interrupt(GPIO_DPSRC_HPD);
+
/* Enable interrupts on VBUS transitions. */
gpio_enable_interrupt(GPIO_VBUS_WAKE);
/* Enable button interrupts. */
gpio_enable_interrupt(GPIO_DBG_5V_TO_DUT_L);
gpio_enable_interrupt(GPIO_DBG_12V_TO_DUT_L);
- gpio_enable_interrupt(GPIO_DBG_20V_TO_DUT_L);
gpio_enable_interrupt(GPIO_DBG_CHG_TO_DEV_L);
gpio_enable_interrupt(GPIO_DBG_USB_TOGGLE_L);
gpio_enable_interrupt(GPIO_DBG_MUX_FLIP_L);
+ /* TODO(crosbug.com/33761): poll DBG_20V_TO_DUT_L */
+ enable_dbg20v_poll();
+
ina2xx_init(0, 0x399f, INA2XX_CALIB_1MA(10 /* mOhm */));
sn75dp130_redriver_init();
}
diff --git a/board/plankton/board.h b/board/plankton/board.h
index efb1bc7868..7b796b919e 100644
--- a/board/plankton/board.h
+++ b/board/plankton/board.h
@@ -18,7 +18,11 @@
/* Optional features */
#define CONFIG_STM_HWTIMER32
#define CONFIG_USB_POWER_DELIVERY
+#define CONFIG_USB_PD_ALT_MODE
+#define CONFIG_USB_PD_CUSTOM_VDM
#define CONFIG_USB_PD_DUAL_ROLE
+#define CONFIG_USB_PD_IDENTITY_HW_VERS 1
+#define CONFIG_USB_PD_IDENTITY_SW_VERS 1
#define CONFIG_USB_PD_INTERNAL_COMP
#define CONFIG_USB_PD_DYNAMIC_SRC_CAP
#define CONFIG_ADC
@@ -33,6 +37,10 @@
/* I2C ports configuration */
#define I2C_PORT_MASTER 1
+/* USB configuration */
+#define CONFIG_USB_PID 0x500c
+#define CONFIG_USB_BCD_DEV 0x0001 /* v 0.01 */
+
/*
* Allow dangerous commands all the time, since we don't have a write protect
* switch.
diff --git a/board/plankton/gpio.inc b/board/plankton/gpio.inc
index dce01b2d9e..6ee250ebce 100644
--- a/board/plankton/gpio.inc
+++ b/board/plankton/gpio.inc
@@ -7,7 +7,7 @@
/* Inputs with interrupt handlers are first for efficiency */
GPIO_INT(VBUS_WAKE, B, 5, GPIO_INT_BOTH, vbus_event)
-GPIO_INT(DBG_20V_TO_DUT_L, C, 13, GPIO_INT_FALLING, button_event)
+GPIO_INT(DPSRC_HPD, B, 13, GPIO_INT_BOTH, hpd_event)
GPIO_INT(DBG_12V_TO_DUT_L, B, 14, GPIO_INT_FALLING, button_event)
GPIO_INT(DBG_5V_TO_DUT_L, B, 8, GPIO_INT_FALLING, button_event)
GPIO_INT(DBG_CHG_TO_DEV_L, F, 1, GPIO_INT_FALLING, button_event)
@@ -15,6 +15,9 @@ GPIO_INT(DBG_USB_TOGGLE_L, F, 0, GPIO_INT_FALLING, button_event)
GPIO_INT(DBG_CASE_CLOSE_EN_L, B, 12, GPIO_INT_FALLING, button_event)
GPIO_INT(DBG_MUX_FLIP_L, B, 15, GPIO_INT_FALLING, button_event)
+/* TODO(crosbug.com/p/33761) : This interrupt is double booked w/ HPD */
+GPIO(DBG_20V_TO_DUT_L, C, 13, GPIO_INPUT)
+
/* PD RX/TX */
GPIO(USBC_PD_REF, A, 1, GPIO_ANALOG)
GPIO(USBC_CC1_PD, A, 0, GPIO_ANALOG)
@@ -50,9 +53,6 @@ GPIO(CASE_CLOSE_EN, A, 7, GPIO_OUT_LOW)
GPIO(CASE_CLOSE_DFU_L, A, 13, GPIO_OUT_HIGH)
GPIO(DEBUG_TOGGLE, B, 4, GPIO_OUT_LOW)
-/* Display port */
-GPIO(DPSRC_HPD, B, 13, GPIO_INPUT)
-
/* Alternate functions */
#if 0
GPIO(UART_TX, A, 14, GPIO_OUT_LOW)
diff --git a/board/plankton/usb_pd_policy.c b/board/plankton/usb_pd_policy.c
index 59a37c6922..f510dc7268 100644
--- a/board/plankton/usb_pd_policy.c
+++ b/board/plankton/usb_pd_policy.c
@@ -14,6 +14,7 @@
#include "timer.h"
#include "util.h"
#include "usb_pd.h"
+#include "version.h"
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
@@ -45,6 +46,9 @@ const uint32_t pd_snk_pdo[] = {
};
const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo);
+/* Whether alternate mode has been entered or not */
+static int alt_mode;
+
void board_set_source_cap(enum board_src_cap cap)
{
pd_src_pdo_idx = cap;
@@ -155,7 +159,157 @@ void pd_check_dr_role(int port, int dr_role, int flags)
pd_request_data_swap(port);
}
+/* ----------------- Vendor Defined Messages ------------------ */
+const uint32_t vdo_idh = VDO_IDH(0, /* data caps as USB host */
+ 0, /* data caps as USB device */
+ IDH_PTYPE_AMA, /* Alternate mode */
+ 1, /* supports alt modes */
+ USB_VID_GOOGLE);
+
+const uint32_t vdo_product = VDO_PRODUCT(CONFIG_USB_PID, CONFIG_USB_BCD_DEV);
+
+const uint32_t vdo_ama = VDO_AMA(CONFIG_USB_PD_IDENTITY_HW_VERS,
+ CONFIG_USB_PD_IDENTITY_SW_VERS,
+ 0, 0, 0, 0, /* SS[TR][12] */
+ 0, /* Vconn power */
+ 0, /* Vconn power required */
+ 1, /* Vbus power required */
+ AMA_USBSS_BBONLY /* USB SS support */);
+
+static int svdm_response_identity(int port, uint32_t *payload)
+{
+ payload[VDO_I(IDH)] = vdo_idh;
+ payload[VDO_I(CSTAT)] = VDO_CSTAT(0);
+ payload[VDO_I(PRODUCT)] = vdo_product;
+ payload[VDO_I(AMA)] = vdo_ama;
+ return VDO_I(AMA) + 1;
+}
+
+static int svdm_response_svids(int port, uint32_t *payload)
+{
+ payload[1] = VDO_SVID(USB_SID_DISPLAYPORT, 0);
+ return 2;
+}
+
+/*
+ * Will only ever be a single mode for this UFP_D device as it has no real USB
+ * support making it only PIN_E configureable
+ */
+#define MODE_CNT 1
+#define OPOS 1
+
+const uint32_t vdo_dp_mode[MODE_CNT] = {
+ VDO_MODE_DP(0, /* UFP pin cfg supported : none */
+ MODE_DP_PIN_E, /* DFP pin cfg supported */
+ 1, /* no usb2.0 signalling in AMode */
+ CABLE_PLUG, /* its a plug */
+ MODE_DP_V13, /* DPv1.3 Support, no Gen2 */
+ MODE_DP_SNK) /* Its a sink only */
+};
+
+static int svdm_response_modes(int port, uint32_t *payload)
+{
+ if (gpio_get_level(GPIO_USBC_SS_USB_MODE))
+ return 0; /* nak */
+
+ if (PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT)
+ return 0; /* nak */
+
+ memcpy(payload + 1, vdo_dp_mode, sizeof(vdo_dp_mode));
+ return MODE_CNT + 1;
+}
+
+static int dp_status(int port, uint32_t *payload)
+{
+ int opos = PD_VDO_OPOS(payload[0]);
+ int hpd = gpio_get_level(GPIO_DPSRC_HPD);
+ if (opos != OPOS)
+ return 0; /* nak */
+
+ payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */
+ (hpd == 1), /* HPD_HI|LOW */
+ 0, /* request exit DP */
+ 0, /* request exit USB */
+ 0, /* MF pref */
+ !gpio_get_level(GPIO_USBC_SS_USB_MODE),
+ 0, /* power low */
+ 0x2);
+ return 2;
+}
+
+static int dp_config(int port, uint32_t *payload)
+{
+ if (PD_DP_CFG_DPON(payload[1]))
+ gpio_set_level(GPIO_USBC_SS_USB_MODE, 0);
+ return 1;
+}
+
+static int svdm_enter_mode(int port, uint32_t *payload)
+{
+ int usb_mode = gpio_get_level(GPIO_USBC_SS_USB_MODE);
+
+ /* SID & mode request is valid */
+ if ((PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) ||
+ (PD_VDO_OPOS(payload[0]) != OPOS))
+ return 0; /* will generate NAK */
+
+ if (usb_mode) {
+ CPRINTS("Toggle USB_MODE if you want DP & re-connect");
+ return 0;
+ }
+
+ alt_mode = OPOS;
+ return 1;
+}
+
+int pd_alt_mode(int port, uint16_t svid)
+{
+ return alt_mode;
+}
+
+static int svdm_exit_mode(int port, uint32_t *payload)
+{
+ alt_mode = 0;
+ /*
+ * Don't actually toggle GPIO_USBC_SS_USB_MODE since its manually
+ * controlled by operator.
+ */
+ return 1; /* Must return ACK */
+}
+
+static struct amode_fx dp_fx = {
+ .status = &dp_status,
+ .config = &dp_config,
+};
+
+const struct svdm_response svdm_rsp = {
+ .identity = &svdm_response_identity,
+ .svids = &svdm_response_svids,
+ .modes = &svdm_response_modes,
+ .enter_mode = &svdm_enter_mode,
+ .amode = &dp_fx,
+ .exit_mode = &svdm_exit_mode,
+};
+
int pd_custom_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
{
- return 0;
+ int cmd = PD_VDO_CMD(payload[0]);
+ int rsize = 1;
+ CPRINTF("VDM/%d [%d] %08x\n", cnt, cmd, payload[0]);
+
+ *rpayload = payload;
+ switch (cmd) {
+ case VDO_CMD_VERSION:
+ memcpy(payload + 1, &version_data.version, 24);
+ rsize = 7;
+ break;
+ default:
+ rsize = 0;
+ }
+
+ CPRINTS("DONE");
+ /* respond (positively) to the request */
+ payload[0] |= VDO_SRC_RESPONDER;
+
+ return rsize;
}
diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c
index bd0915a50b..96cf970a30 100644
--- a/common/usb_pd_policy.c
+++ b/common/usb_pd_policy.c
@@ -749,7 +749,7 @@ int pd_vdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload)
void pd_usb_billboard_deferred(void)
{
#if defined(CONFIG_USB_PD_ALT_MODE) && !defined(CONFIG_USB_PD_ALT_MODE_DFP) \
- && !defined(CONFIG_USB_PD_SIMPLE_DFP)
+ && !defined(CONFIG_USB_PD_SIMPLE_DFP) && defined(CONFIG_USB_BOS)
/*
* TODO(tbroch)
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 9cf7340d54..08deda0a06 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -3046,7 +3046,7 @@ void pd_send_hpd(int port, enum hpd_event hpd)
0, /* request exit DP */
0, /* request exit USB */
0, /* MF pref */
- gpio_get_level(GPIO_PD_SBU_ENABLE),
+ 1, /* enabled */
0, /* power low */
0x2);
pd_send_vdm(port, USB_SID_DISPLAYPORT,