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>
This commit is contained in:
Todd Broch
2014-11-12 16:32:02 -08:00
committed by ChromeOS Commit Bot
parent 56653dec06
commit 7cc3136da5
6 changed files with 273 additions and 10 deletions

View File

@@ -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();
}

View File

@@ -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.

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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,