diff options
author | Alec Berg <alecaberg@chromium.org> | 2014-07-01 11:31:41 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-07-03 05:25:13 +0000 |
commit | 9ba7bd4284eb8aac2347f3a71fc830c59ccbe387 (patch) | |
tree | 3ffb0cbe850452916999032bd0aa58fe23886414 /chip/stm32/usb_pd_phy.c | |
parent | 64733430754848bfb1f67c87c4c9142564270583 (diff) | |
download | chrome-ec-9ba7bd4284eb8aac2347f3a71fc830c59ccbe387.tar.gz |
pd: clean up beg/end transitions of PD comms
Fix the beginning and end of BMC PD communication:
- Initial transmission within 1us of taking control of CC line
- CC line released between 1us and 23us after last edge
- If final bit is a 0, then add two 1 bits to the end
- No garbage after the final bit
BUG=chrome-os-partner:30132
BRANCH=none
TEST=tested with a fruitpie, samus, and zinger.
verified timing on scope.
Change-Id: Ie45695eb367a7554cf5d5b76b6fbdf1e3fc85d29
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/206453
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'chip/stm32/usb_pd_phy.c')
-rw-r--r-- | chip/stm32/usb_pd_phy.c | 119 |
1 files changed, 79 insertions, 40 deletions
diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c index b4fefa8fa4..7d514840a1 100644 --- a/chip/stm32/usb_pd_phy.c +++ b/chip/stm32/usb_pd_phy.c @@ -214,14 +214,20 @@ int pd_write_last_edge(void *ctxt, int bit_off) if (bit_idx == 0) msg[word_idx] = 0; + if (!b_toggle /* last bit was 0 */) { - /* transition to 1, then 0 */ - msg[word_idx] |= 1 << bit_idx; + /* transition to 1, another 1, then 0 */ + if (bit_idx == 31) { + msg[word_idx++] |= 1 << bit_idx; + msg[word_idx] = 1; + } else { + msg[word_idx] |= 3 << bit_idx; + } } /* ensure that the trailer is 0 */ msg[word_idx+1] = 0; - return bit_off + 2; + return bit_off + 3; } #ifdef CONFIG_COMMON_RUNTIME @@ -257,6 +263,35 @@ static struct dma_option dma_tx_option = { STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT }; +void pd_tx_spi_init(void) +{ + stm32_spi_regs_t *spi = SPI_REGS; + + /* Enable Tx DMA for our first transaction */ + spi->cr2 = STM32_SPI_CR2_TXDMAEN | STM32_SPI_CR2_DATASIZE(8); + +#ifdef CONFIG_USB_PD_TX_USES_SPI_MASTER + /* + * Enable the master SPI: LSB first, force NSS, TX only, CPOL and CPHA + * high. + */ + spi->cr1 = STM32_SPI_CR1_LSBFIRST | STM32_SPI_CR1_BIDIMODE + | STM32_SPI_CR1_SSM | STM32_SPI_CR1_SSI + | STM32_SPI_CR1_BIDIOE | STM32_SPI_CR1_MSTR + | STM32_SPI_CR1_BR_DIV64R | STM32_SPI_CR1_SPE + | STM32_SPI_CR1_CPOL | STM32_SPI_CR1_CPHA; + +#if CPU_CLOCK != 38400000 +#error "CPU_CLOCK must be 38.4MHz to use SPI master for USB PD Tx" +#endif +#else + /* Enable the slave SPI: LSB first, force NSS, TX only, CPHA */ + spi->cr1 = STM32_SPI_CR1_SPE | STM32_SPI_CR1_LSBFIRST + | STM32_SPI_CR1_SSM | STM32_SPI_CR1_BIDIMODE + | STM32_SPI_CR1_BIDIOE | STM32_SPI_CR1_CPHA; +#endif +} + void pd_tx_set_circular_mode(void) { dma_tx_option.flags |= STM32_DMA_CCR_CIRC; @@ -266,6 +301,15 @@ void pd_start_tx(void *ctxt, int polarity, int bit_len) { stm32_dma_chan_t *tx = dma_get_channel(DMAC_SPI_TX); + /* Initialize spi peripheral to prepare for transmission. */ + pd_tx_spi_init(); + + /* + * Set timer to one tick before reset so that the first tick causes + * a rising edge on the output. + */ + STM32_TIM_CNT(TIM_TX) = TX_CLOCK_DIV - 1; + /* update DMA configuration */ dma_prepare_tx(&dma_tx_option, DIV_ROUND_UP(bit_len, 8), ctxt); /* Flush data in write buffer so that DMA can get the latest data */ @@ -273,16 +317,23 @@ void pd_start_tx(void *ctxt, int polarity, int bit_len) /* disable RX detection interrupt */ pd_rx_disable_monitoring(); + + /* Kick off the DMA to send the data */ + dma_clear_isr(DMAC_SPI_TX); +#ifdef CONFIG_COMMON_RUNTIME + dma_enable_tc_interrupt(DMAC_SPI_TX); +#endif + dma_go(tx); + /* * Drive the CC line from the TX block : - * - set the low level reference. * - put SPI function on TX pin. + * - set the low level reference. + * Call this last before enabling timer in order to meet spec on + * timing between enabling TX and clocking out bits. */ pd_tx_enable(polarity); - /* Kick off the DMA to send the data */ - dma_go(tx); - #ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER /* Start counting at 300Khz*/ STM32_TIM_CR1(TIM_TX) |= 1; @@ -293,7 +344,12 @@ void pd_tx_done(int polarity) { stm32_spi_regs_t *spi = SPI_REGS; - dma_wait(DMAC_SPI_TX); + /* wait for DMA */ +#ifdef CONFIG_COMMON_RUNTIME + task_wait_event(DMA_TRANSFER_TIMEOUT_US); + dma_disable_tc_interrupt(DMAC_SPI_TX); +#endif + /* wait for real end of transmission */ #ifdef CHIP_FAMILY_STM32F0 while (spi->sr & STM32_SPI_SR_FTLVL) @@ -303,9 +359,6 @@ void pd_tx_done(int polarity) ; /* wait for TXE == 1 */ #endif - while (spi->sr & STM32_SPI_SR_BSY) - ; /* wait for BSY == 0 */ - /* * At the end of transmitting, the last bit is guaranteed by the * protocol to be low, and it is necessary that the TX line stay low @@ -321,14 +374,23 @@ void pd_tx_done(int polarity) #ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER /* ensure that we are not pushing out junk */ *(uint8_t *)&spi->dr = 0; - /* Stop counting */ - STM32_TIM_CR1(TIM_TX) &= ~1; + while (spi->sr & STM32_SPI_SR_FTLVL) + ; /* wait for TX FIFO empty */ +#else + while (spi->sr & STM32_SPI_SR_BSY) + ; /* wait for BSY == 0 */ #endif - /* clear transfer flag */ - dma_clear_isr(DMAC_SPI_TX); /* put TX pins and reference in Hi-Z */ pd_tx_disable(polarity); + +#ifndef CONFIG_USB_PD_TX_USES_SPI_MASTER + /* Stop counting */ + STM32_TIM_CR1(TIM_TX) &= ~1; + + /* Reset SPI to clear remaining data in buffer */ + pd_tx_spi_reset(); +#endif } /* --- RX operation using comparator linked to timer --- */ @@ -405,8 +467,6 @@ void pd_hw_release(void) /* --- Startup initialization --- */ void *pd_hw_init(void) { - stm32_spi_regs_t *spi = SPI_REGS; - /* set 40 MHz pin speed on communication pins */ pd_set_pins_speed(); @@ -418,29 +478,8 @@ void *pd_hw_init(void) /* Initialize TX pins and put them in Hi-Z */ pd_tx_init(); - /* Enable Tx DMA for our first transaction */ - spi->cr2 = STM32_SPI_CR2_TXDMAEN | STM32_SPI_CR2_DATASIZE(8); - -#ifdef CONFIG_USB_PD_TX_USES_SPI_MASTER - /* - * Enable the master SPI: LSB first, force NSS, TX only, CPOL and CPHA - * high. - */ - spi->cr1 = STM32_SPI_CR1_LSBFIRST | STM32_SPI_CR1_BIDIMODE - | STM32_SPI_CR1_SSM | STM32_SPI_CR1_SSI - | STM32_SPI_CR1_BIDIOE | STM32_SPI_CR1_MSTR - | STM32_SPI_CR1_BR_DIV64R | STM32_SPI_CR1_SPE - | STM32_SPI_CR1_CPOL | STM32_SPI_CR1_CPHA; - -#if CPU_CLOCK != 38400000 -#error "CPU_CLOCK must be 38.4MHz to use SPI master for USB PD Tx" -#endif -#else - /* Enable the slave SPI: LSB first, force NSS, TX only */ - spi->cr1 = STM32_SPI_CR1_SPE | STM32_SPI_CR1_LSBFIRST - | STM32_SPI_CR1_SSM | STM32_SPI_CR1_BIDIMODE - | STM32_SPI_CR1_BIDIOE; -#endif + /* Initialize SPI peripheral registers */ + pd_tx_spi_init(); /* configure TX DMA */ dma_prepare_tx(&dma_tx_option, PD_MAX_RAW_SIZE, raw_samples); |