diff options
author | Alec Berg <alecaberg@chromium.org> | 2015-05-18 14:33:21 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-05-30 16:34:40 +0000 |
commit | 52cbad10627d21b6315d9ce301386e58c5d95036 (patch) | |
tree | 8aca39a6546e8e6475ee89677f67dd6b35ba7377 /board/oak_pd | |
parent | 7a54beba504af6177720e52f9c1ff7e35ec17d2e (diff) | |
download | chrome-ec-52cbad10627d21b6315d9ce301386e58c5d95036.tar.gz |
oak: Add PD communication to oak
Add TCPM on EC side and TCPC on PD side to allow PD
communication. Enable PD communication on port 0.
BUG=none
BRANCH=none
TEST=load on oak. plug in hoho on port 0, and make sure
we successfully negotiate a PD contract. (note: you have
to manually enable 5V VBUS right now)
Change-Id: I0ce7c016545bc56c5e10f66b49b73722187f12dc
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/271829
Reviewed-by: Rong Chang <rongchang@chromium.org>
Reviewed-by: Sheng-liang Song <ssl@chromium.org>
Commit-Queue: Sheng-liang Song <ssl@chromium.org>
Diffstat (limited to 'board/oak_pd')
-rw-r--r-- | board/oak_pd/board.c | 5 | ||||
-rw-r--r-- | board/oak_pd/board.h | 9 | ||||
-rw-r--r-- | board/oak_pd/ec.tasklist | 3 | ||||
-rw-r--r-- | board/oak_pd/usb_pd_config.h | 316 |
4 files changed, 329 insertions, 4 deletions
diff --git a/board/oak_pd/board.c b/board/oak_pd/board.c index 4583d9fdc7..261fdf55cf 100644 --- a/board/oak_pd/board.c +++ b/board/oak_pd/board.c @@ -15,6 +15,7 @@ #include "registers.h" #include "system.h" #include "task.h" +#include "usb_pd.h" #include "util.h" #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) @@ -34,9 +35,7 @@ void pd_send_ec_int(void) void vbus0_evt(enum gpio_signal signal) { -#ifdef HAS_TASK_PD_C0 - task_wake(TASK_ID_PD_C0); -#endif + task_wake(TASK_ID_PD); } void vbus1_evt(enum gpio_signal signal) diff --git a/board/oak_pd/board.h b/board/oak_pd/board.h index 15c8cc5f0e..ac3d6eae64 100644 --- a/board/oak_pd/board.h +++ b/board/oak_pd/board.h @@ -53,6 +53,11 @@ #undef CONFIG_UART_TX_DMA #undef CONFIG_UART_RX_DMA #define CONFIG_UART_TX_BUF_SIZE 128 +#define CONFIG_USB_PD_DUAL_ROLE +#define CONFIG_USB_PD_INTERNAL_COMP +#define CONFIG_USB_PD_PORT_COUNT 1 +#define CONFIG_USB_PD_TCPC +#define CONFIG_USBC_VCONN #define CONFIG_VBOOT_HASH #undef CONFIG_WATCHDOG #undef CONFIG_WATCHDOG_HELP @@ -89,6 +94,10 @@ enum adc_channel { ADC_CH_COUNT }; +/* 1.5A Rp */ +#define PD_SRC_VNC PD_SRC_1_5_VNC_MV +#define PD_SRC_RD_THRESHOLD PD_SRC_1_5_RD_THRESH_MV + #endif /* !__ASSEMBLER__ */ #endif /* __BOARD_H */ diff --git a/board/oak_pd/ec.tasklist b/board/oak_pd/ec.tasklist index c5b5933dd8..c001ade46f 100644 --- a/board/oak_pd/ec.tasklist +++ b/board/oak_pd/ec.tasklist @@ -19,4 +19,5 @@ #define CONFIG_TASK_LIST \ TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \ TASK_NOTEST(HOSTCMD, host_command_task, NULL, LARGER_TASK_STACK_SIZE) \ - TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) + TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(PD, pd_task, NULL, LARGER_TASK_STACK_SIZE) diff --git a/board/oak_pd/usb_pd_config.h b/board/oak_pd/usb_pd_config.h new file mode 100644 index 0000000000..2f91727cb8 --- /dev/null +++ b/board/oak_pd/usb_pd_config.h @@ -0,0 +1,316 @@ +/* Copyright 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "adc.h" +#include "chip/stm32/registers.h" +#include "gpio.h" +#include "ec_commands.h" + +/* USB Power delivery board configuration */ + +#ifndef __USB_PD_CONFIG_H +#define __USB_PD_CONFIG_H + +/* Timer selection for baseband PD communication */ +#define TIM_CLOCK_PD_TX_C0 16 +#define TIM_CLOCK_PD_RX_C0 1 +#define TIM_CLOCK_PD_TX_C1 15 +#define TIM_CLOCK_PD_RX_C1 3 + +/* Timer channel */ +#define TIM_TX_CCR_C0 1 +#define TIM_RX_CCR_C0 1 +#define TIM_TX_CCR_C1 2 +#define TIM_RX_CCR_C1 1 + +#define TIM_CLOCK_PD_TX(p) ((p) ? TIM_CLOCK_PD_TX_C1 : TIM_CLOCK_PD_TX_C0) +#define TIM_CLOCK_PD_RX(p) ((p) ? TIM_CLOCK_PD_RX_C1 : TIM_CLOCK_PD_RX_C0) + +/* RX timer capture/compare register */ +#define TIM_CCR_C0 (&STM32_TIM_CCRx(TIM_CLOCK_PD_RX_C0, TIM_RX_CCR_C0)) +#define TIM_CCR_C1 (&STM32_TIM_CCRx(TIM_CLOCK_PD_RX_C1, TIM_RX_CCR_C1)) +#define TIM_RX_CCR_REG(p) ((p) ? TIM_CCR_C1 : TIM_CCR_C0) + +/* TX and RX timer register */ +#define TIM_REG_TX_C0 (STM32_TIM_BASE(TIM_CLOCK_PD_TX_C0)) +#define TIM_REG_RX_C0 (STM32_TIM_BASE(TIM_CLOCK_PD_RX_C0)) +#define TIM_REG_TX_C1 (STM32_TIM_BASE(TIM_CLOCK_PD_TX_C1)) +#define TIM_REG_RX_C1 (STM32_TIM_BASE(TIM_CLOCK_PD_RX_C1)) +#define TIM_REG_TX(p) ((p) ? TIM_REG_TX_C1 : TIM_REG_TX_C0) +#define TIM_REG_RX(p) ((p) ? TIM_REG_RX_C1 : TIM_REG_RX_C0) + +/* use the hardware accelerator for CRC */ +#define CONFIG_HW_CRC + +/* TX uses SPI1 on PB3-4 for port C0, SPI2 on PB 13-14 for port C1 */ +#define SPI_REGS(p) ((p) ? STM32_SPI2_REGS : STM32_SPI1_REGS) +static inline void spi_enable_clock(int port) +{ + if (port == 0) + STM32_RCC_APB2ENR |= STM32_RCC_PB2_SPI1; + else + STM32_RCC_APB1ENR |= STM32_RCC_PB1_SPI2; +} + +/* DMA for transmit uses DMA CH3 for C0 and DMA_CH5 for C1 */ +#define DMAC_SPI_TX(p) ((p) ? STM32_DMAC_CH5 : STM32_DMAC_CH3) + +/* RX uses COMP1 and TIM1 CH1 on port C0 and COMP2 and TIM3_CH1 for port C1*/ +/* C1 RX use CMP1, TIM3_CH1, DMA_CH4 */ +#define CMP1OUTSEL STM32_COMP_CMP1OUTSEL_TIM3_IC1 +/* C0 RX use CMP2, TIM1_CH1, DMA_CH2 */ +#define CMP2OUTSEL STM32_COMP_CMP2OUTSEL_TIM1_IC1 + +#define TIM_TX_CCR_IDX(p) ((p) ? TIM_TX_CCR_C1 : TIM_TX_CCR_C0) +#define TIM_RX_CCR_IDX(p) ((p) ? TIM_RX_CCR_C1 : TIM_RX_CCR_C0) +#define TIM_CCR_CS 1 + +/* + * EXTI line 21 is connected to the CMP1 output, + * EXTI line 22 is connected to the CMP2 output, + * C0 uses CMP2, and C1 uses CMP1. + */ +#define EXTI_COMP_MASK(p) ((p) ? (1<<21) : (1 << 22)) + +#define IRQ_COMP STM32_IRQ_COMP +/* triggers packet detection on comparator falling edge */ +#define EXTI_XTSR STM32_EXTI_FTSR + +/* DMA for receive uses DMA_CH2 for C0 and DMA_CH4 for C1 */ +#define DMAC_TIM_RX(p) ((p) ? STM32_DMAC_CH4 : STM32_DMAC_CH2) + +/* the pins used for communication need to be hi-speed */ +static inline void pd_set_pins_speed(int port) +{ + if (port == 0) { + /* 40 MHz pin speed on SPI PB3&4, + * (USB_C0_TX_CLKIN & USB_C0_CC1_TX_DATA) + */ + STM32_GPIO_OSPEEDR(GPIO_B) |= 0x000003C0; + /* 40 MHz pin speed on TIM16_CH1 (PB8), + * (USB_C0_TX_CLKOUT) + */ + STM32_GPIO_OSPEEDR(GPIO_B) |= 0x00030000; + } else { + /* 40 MHz pin speed on SPI PB13/14, + * (USB_C1_TX_CLKIN & USB_C1_CC1_TX_DATA) + */ + STM32_GPIO_OSPEEDR(GPIO_B) |= 0x3C000000; + /* 40 MHz pin speed on TIM15_CH2 (PB15) */ + STM32_GPIO_OSPEEDR(GPIO_B) |= 0xC0000000; + } +} + +/* Reset SPI peripheral used for TX */ +static inline void pd_tx_spi_reset(int port) +{ + if (port == 0) { + /* Reset SPI1 */ + STM32_RCC_APB2RSTR |= (1 << 12); + STM32_RCC_APB2RSTR &= ~(1 << 12); + } else { + /* Reset SPI2 */ + STM32_RCC_APB1RSTR |= (1 << 14); + STM32_RCC_APB1RSTR &= ~(1 << 14); + } +} + +/* Drive the CC line from the TX block */ +static inline void pd_tx_enable(int port, int polarity) +{ + if (port == 0) { + /* put SPI function on TX pin */ + if (polarity) { + /* USB_C0_CC2_TX_DATA: PA6 is SPI1 MISO */ + gpio_set_alternate_function(GPIO_A, 0x0040, 0); + /* MCU ADC PA4 pin output low */ + STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A) + & ~(3 << (2*4))) /* PA4 disable ADC */ + | (1 << (2*4)); /* Set as GPO */ + gpio_set_level(GPIO_USB_C0_CC2_PD, 0); + } else { + /* USB_C0_CC1_TX_DATA: PB4 is SPI1 MISO */ + gpio_set_alternate_function(GPIO_B, 0x0010, 0); + /* MCU ADC PA2 pin output low */ + STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A) + & ~(3 << (2*2))) /* PA2 disable ADC */ + | (1 << (2*2)); /* Set as GPO */ + gpio_set_level(GPIO_USB_C0_CC1_PD, 0); + } + } else { + /* put SPI function on TX pin */ + /* USB_C1_CCX_TX_DATA: PB14 is SPI1 MISO */ + gpio_set_alternate_function(GPIO_B, 0x4000, 0); + /* TODO: MCU ADC pin output low */ + /* + * There is a pin muxer to select CC1 or CC2 TX_DATA, + * Pin mux is controlled by USB_C1_CC2_TX_SEL pin, + * USB_C1_CC1_TX_DATA will be selected, if polarity is 0, + * USB_C1_CC2_TX_DATA will be selected, if polarity is 1 . + */ + gpio_set_level(GPIO_USB_C1_CC2_TX_SEL, polarity); + } +} + +/* Put the TX driver in Hi-Z state */ +static inline void pd_tx_disable(int port, int polarity) +{ + if (port == 0) { + /* output low on SPI TX to disable the FET */ + if (polarity) {/* PA6 is SPI1 MISO */ + gpio_set_alternate_function(GPIO_A, 0x0040, -1); + /* TODO: Set MCU ADC PA4 pin to ADC function (Hi-Z) */ + STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A) + | (3 << (2*4))) /* PA4 as ADC */ + & ~(1 << (2*4)); /* disable GPO */ + } else {/* PB4 is SPI1 MISO */ + gpio_set_alternate_function(GPIO_B, 0x0010, -1); + /* put the low level reference in Hi-Z */ + /* TODO: Set MCU ADC PA2 pin to ADC function (Hi-Z) */ + STM32_GPIO_MODER(GPIO_A) = (STM32_GPIO_MODER(GPIO_A) + | (3 << (2*2))) /* PA2 disable ADC */ + & ~(1 << (2*2)); /* Set as GPO */ + } + } else { + /* Select the pin according to the polarity */ + gpio_set_level(GPIO_USB_C1_CC2_TX_SEL, polarity); + /* output low on SPI TX to disable the FET */ + /* PB14 is SPI2 MISO */ + STM32_GPIO_MODER(GPIO_B) = (STM32_GPIO_MODER(GPIO_B) + & ~(3 << (2*14))) /* Pin14 disable ADC */ + | (1 << (2*14)); /* Set as GPO */ + /* 00: Input mode (reset state) + * 01: General purpose output mode + * 10: Alternate function mode + * 11: Analog mode + */ + + /* put the low level reference in Hi-Z */ + /* TODO: Set MCU ADC pin to ADC function (Hi-Z) */ + } +} + +/* we know the plug polarity, do the right configuration */ +static inline void pd_select_polarity(int port, int polarity) +{ + uint32_t val = STM32_COMP_CSR; + + /* Use window mode so that COMP1 and COMP2 share non-inverting input */ + val |= STM32_COMP_CMP1EN | STM32_COMP_CMP2EN | STM32_COMP_WNDWEN; + + if (port == 0) { + /* C0 use the right comparator inverted input for COMP2 */ + STM32_COMP_CSR = (val & ~STM32_COMP_CMP2INSEL_MASK) | + (polarity ? STM32_COMP_CMP2INSEL_INM4 /* PA4: C0_CC2 */ + : STM32_COMP_CMP2INSEL_INM6);/* PA2: C0_CC1 */ + } else { + /* C1 use the right comparator inverted input for COMP1 */ + STM32_COMP_CSR = (val & ~STM32_COMP_CMP1INSEL_MASK) | + (polarity ? STM32_COMP_CMP1INSEL_INM5 /* PA5: C1_CC2 */ + : STM32_COMP_CMP1INSEL_INM6);/* PA0: C1_CC1 */ + } +} + +/* Initialize pins used for TX and put them in Hi-Z */ +static inline void pd_tx_init(void) +{ + gpio_config_module(MODULE_USB_PD, 1); +} +static inline void pd_set_host_mode(int port, int enable) +{ + if (port == 0) { + if (enable) { + /* Pull up for host mode */ + gpio_set_flags(GPIO_USB_C0_HOST_HIGH, GPIO_OUTPUT); + gpio_set_level(GPIO_USB_C0_HOST_HIGH, 1); + /* High-Z is used for host mode. */ + gpio_set_level(GPIO_USB_C0_CC1_ODL, 1); + gpio_set_level(GPIO_USB_C0_CC2_ODL, 1); + /* Set TX Hi-Z */ + gpio_set_flags(GPIO_USB_C0_CC1_TX_DATA, GPIO_INPUT); + gpio_set_flags(GPIO_USB_C0_CC2_TX_DATA, GPIO_INPUT); + } else { + /* Set HOST_HIGH to High-Z for device mode. */ + gpio_set_flags(GPIO_USB_C0_HOST_HIGH, GPIO_INPUT); + /* Pull low for device mode. */ + gpio_set_level(GPIO_USB_C0_CC1_ODL, 0); + gpio_set_level(GPIO_USB_C0_CC2_ODL, 0); + } + } else { + if (enable) { + /* Pull up for host mode */ + gpio_set_flags(GPIO_USB_C1_HOST_HIGH, GPIO_OUTPUT); + gpio_set_level(GPIO_USB_C1_HOST_HIGH, 1); + /* High-Z is used for host mode. */ + gpio_set_level(GPIO_USB_C1_CC1_ODL, 1); + gpio_set_level(GPIO_USB_C1_CC2_ODL, 1); + gpio_set_flags(GPIO_USB_C1_CCX_TX_DATA, GPIO_INPUT); + } else { + /* Set HOST_HIGH to High-Z for device mode. */ + gpio_set_flags(GPIO_USB_C1_HOST_HIGH, GPIO_INPUT); + /* Pull low for device mode. */ + gpio_set_level(GPIO_USB_C1_CC1_ODL, 0); + gpio_set_level(GPIO_USB_C1_CC2_ODL, 0); + } + } +} + +/** + * Initialize various GPIOs and interfaces to safe state at start of pd_task. + * + * These include: + * VBUS, charge path based on power role. + * Physical layer CC transmit. + * VCONNs disabled. + * + * @param port USB-C port number + * @param power_role Power role of device + */ +static inline void pd_config_init(int port, uint8_t power_role) +{ + /* + * Set CC pull resistors, and charge_en and vbus_en GPIOs to match + * the initial role. + */ + pd_set_host_mode(port, power_role); + + /* Initialize TX pins and put them in Hi-Z */ + pd_tx_init(); + + if (port == 0) { + gpio_set_level(GPIO_USB_C0_CC1_VCONN1_EN, 0); + gpio_set_level(GPIO_USB_C0_CC2_VCONN1_EN, 0); + } else { + gpio_set_level(GPIO_USB_C1_CC1_VCONN1_EN, 0); + gpio_set_level(GPIO_USB_C1_CC2_VCONN1_EN, 0); + } +} + +static inline int pd_adc_read(int port, int cc) +{ + if (port == 0) + return adc_read_channel(cc ? ADC_C0_CC2_PD : ADC_C0_CC1_PD); + else + return adc_read_channel(cc ? ADC_C1_CC2_PD : ADC_C1_CC1_PD); +} + +static inline void pd_set_vconn(int port, int polarity, int enable) +{ + /* Set VCONN on the opposite CC line from the polarity */ + if (port == 0) { + gpio_set_level(polarity ? GPIO_USB_C0_CC1_VCONN1_EN : + GPIO_USB_C0_CC2_VCONN1_EN, enable); + /* Set TX_DATA pin to Hi-Z */ + gpio_set_flags(polarity ? GPIO_USB_C0_CC1_TX_DATA : + GPIO_USB_C0_CC2_TX_DATA, GPIO_INPUT); + } else { + gpio_set_level(polarity ? GPIO_USB_C1_CC1_VCONN1_EN : + GPIO_USB_C1_CC2_VCONN1_EN, enable); + /* Set TX_DATA pin to Hi-Z */ + gpio_set_flags(GPIO_USB_C1_CCX_TX_DATA, GPIO_INPUT); + } +} + +#endif /* __USB_PD_CONFIG_H */ |