mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-10 01:21:49 +00:00
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:
committed by
ChromeOS Commit Bot
parent
56653dec06
commit
7cc3136da5
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user