diff options
author | Todd Broch <tbroch@chromium.org> | 2014-11-12 16:32:02 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-05-01 01:08:10 +0000 |
commit | 7cc3136da56eaea8cfa7f9139ebaf6361707ade2 (patch) | |
tree | 9a66caa15bf4a2df6954c592ca6978a1bda1ad11 | |
parent | 56653dec06ede2c62ec35c74f0e133f18dd7ea50 (diff) | |
download | chrome-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.c | 107 | ||||
-rw-r--r-- | board/plankton/board.h | 8 | ||||
-rw-r--r-- | board/plankton/gpio.inc | 8 | ||||
-rw-r--r-- | board/plankton/usb_pd_policy.c | 156 | ||||
-rw-r--r-- | common/usb_pd_policy.c | 2 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 2 |
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, |