diff options
-rw-r--r-- | board/firefly/usb_pd_config.h | 13 | ||||
-rw-r--r-- | board/fruitpie/usb_pd_config.h | 11 | ||||
-rw-r--r-- | board/samus_pd/usb_pd_config.h | 16 | ||||
-rw-r--r-- | board/zinger/usb_pd_config.h | 12 | ||||
-rw-r--r-- | chip/stm32/dma.c | 53 | ||||
-rw-r--r-- | chip/stm32/usb_pd_phy.c | 119 |
6 files changed, 173 insertions, 51 deletions
diff --git a/board/firefly/usb_pd_config.h b/board/firefly/usb_pd_config.h index 595b977d48..eea9688842 100644 --- a/board/firefly/usb_pd_config.h +++ b/board/firefly/usb_pd_config.h @@ -44,16 +44,25 @@ static inline void pd_set_pins_speed(void) STM32_GPIO_OSPEEDR(GPIO_B) |= 0x000C0000; } +/* Reset SPI peripheral used for TX */ +static inline void pd_tx_spi_reset(void) +{ + /* Reset SPI1 */ + STM32_RCC_APB2RSTR |= (1 << 12); + STM32_RCC_APB2RSTR &= ~(1 << 12); +} + /* Drive the CC line from the TX block */ static inline void pd_tx_enable(int polarity) { - /* set the low level reference */ - gpio_set_level(polarity ? GPIO_PD_CC2_TX_EN : GPIO_PD_CC1_TX_EN, 0); /* put SPI function on TX pin */ if (polarity) /* PB4 is SPI1 MISO */ gpio_set_alternate_function(GPIO_B, 0x0010, 0); else /* PA6 is SPI1 MISO */ gpio_set_alternate_function(GPIO_A, 0x0040, 0); + + /* set the low level reference */ + gpio_set_level(polarity ? GPIO_PD_CC2_TX_EN : GPIO_PD_CC1_TX_EN, 0); } /* Put the TX driver in Hi-Z state */ diff --git a/board/fruitpie/usb_pd_config.h b/board/fruitpie/usb_pd_config.h index 0f51c87038..685d11af3b 100644 --- a/board/fruitpie/usb_pd_config.h +++ b/board/fruitpie/usb_pd_config.h @@ -43,12 +43,21 @@ static inline void pd_set_pins_speed(void) STM32_GPIO_OSPEEDR(GPIO_B) |= 0x000C0000; } +/* Reset SPI peripheral used for TX */ +static inline void pd_tx_spi_reset(void) +{ + /* 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 polarity) { - gpio_set_level(GPIO_PD_TX_EN, 1); /* TX_DATA on PB14 is now connected to SPI2 */ gpio_set_alternate_function(GPIO_B, 0x4000, 0); + + gpio_set_level(GPIO_PD_TX_EN, 1); } /* Put the TX driver in Hi-Z state */ diff --git a/board/samus_pd/usb_pd_config.h b/board/samus_pd/usb_pd_config.h index 4381e81791..9f09ad5793 100644 --- a/board/samus_pd/usb_pd_config.h +++ b/board/samus_pd/usb_pd_config.h @@ -42,18 +42,26 @@ static inline void pd_set_pins_speed(void) STM32_GPIO_OSPEEDR(GPIO_B) |= 0x0000000C; } +/* Reset SPI peripheral used for TX */ +static inline void pd_tx_spi_reset(void) +{ + /* Reset SPI1 */ + STM32_RCC_APB2RSTR |= (1 << 12); + STM32_RCC_APB2RSTR &= ~(1 << 12); +} + /* Drive the CC line from the TX block */ static inline void pd_tx_enable(int polarity) { - /* set the low level reference */ - gpio_set_level(polarity ? GPIO_USB_C0_CC2_TX_EN : - GPIO_USB_C0_CC1_TX_EN, 1); - /* put SPI function on TX pin */ if (polarity) /* PE14 is SPI1 MISO */ gpio_set_alternate_function(GPIO_E, 0x4000, 1); else /* PB4 is SPI1 MISO */ gpio_set_alternate_function(GPIO_B, 0x0010, 0); + + /* set the low level reference */ + gpio_set_level(polarity ? GPIO_USB_C0_CC2_TX_EN : + GPIO_USB_C0_CC1_TX_EN, 1); } /* Put the TX driver in Hi-Z state */ diff --git a/board/zinger/usb_pd_config.h b/board/zinger/usb_pd_config.h index 4383e24e32..73959ff787 100644 --- a/board/zinger/usb_pd_config.h +++ b/board/zinger/usb_pd_config.h @@ -43,13 +43,21 @@ static inline void pd_set_pins_speed(void) /* Already done in hardware_init() */ } +/* Reset SPI peripheral used for TX */ +static inline void pd_tx_spi_reset(void) +{ + /* Reset SPI1 */ + STM32_RCC_APB2RSTR |= (1 << 12); + STM32_RCC_APB2RSTR &= ~(1 << 12); +} + /* Drive the CC line from the TX block */ static inline void pd_tx_enable(int polarity) { - /* Drive TX GND on PA4 */ - STM32_GPIO_BSRR(GPIO_A) = 1 << (4 + 16 /* Reset */); /* Drive SPI MISO on PA6 by putting it in AF mode */ STM32_GPIO_MODER(GPIO_A) |= 0x2 << (2*6); + /* Drive TX GND on PA4 */ + STM32_GPIO_BSRR(GPIO_A) = 1 << (4 + 16 /* Reset */); } /* Put the TX driver in Hi-Z state */ diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c index e648b7418e..75073b4db6 100644 --- a/chip/stm32/dma.c +++ b/chip/stm32/dma.c @@ -27,7 +27,16 @@ static task_id_t id[STM32_DMAC_COUNT]; */ static int dma_get_irq(enum dma_channel channel) { +#ifdef CHIP_FAMILY_STM32F0 + if (channel == STM32_DMAC_CH1) + return STM32_IRQ_DMA_CHANNEL_1; + + return channel > STM32_DMAC_CH3 ? + STM32_IRQ_DMA_CHANNEL_4_7 : + STM32_IRQ_DMA_CHANNEL_2_3; +#else return STM32_IRQ_DMA_CHANNEL_1 + channel; +#endif } /* @@ -241,7 +250,47 @@ void dma_clear_isr(enum dma_channel channel) dma->ifcr |= STM32_DMA_ISR_ALL(channel); } -#ifndef CHIP_FAMILY_STM32F0 +#ifdef CHIP_FAMILY_STM32F0 +void dma_event_interrupt_channel_1(void) +{ + if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(STM32_DMAC_CH1)) { + dma_clear_isr(STM32_DMAC_CH1); + if (id[STM32_DMAC_CH1] != TASK_ID_INVALID) + task_wake(id[STM32_DMAC_CH1]); + } +} +DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_1, dma_event_interrupt_channel_1, 3); + +void dma_event_interrupt_channel_2_3(void) +{ + int i; + + for (i = STM32_DMAC_CH2; i <= STM32_DMAC_CH3; i++) { + if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(i)) { + dma_clear_isr(i); + if (id[i] != TASK_ID_INVALID) + task_wake(id[i]); + } + } +} +DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_2_3, dma_event_interrupt_channel_2_3, 3); + +void dma_event_interrupt_channel_4_7(void) +{ + int i; + + for (i = STM32_DMAC_CH4; i <= STM32_DMAC_CH7; i++) { + if (STM32_DMA1_REGS->isr & STM32_DMA_ISR_TCIF(i)) { + dma_clear_isr(i); + if (id[i] != TASK_ID_INVALID) + task_wake(id[i]); + } + } +} +DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_4_7, dma_event_interrupt_channel_4_7, 3); + +#else /* !CHIP_FAMILY_STM32F0 */ + void dma_event_interrupt_channel_4(void) { dma_clear_isr(STM32_DMAC_CH4); @@ -273,4 +322,4 @@ void dma_event_interrupt_channel_7(void) task_wake(id[STM32_DMAC_CH7]); } DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_7, dma_event_interrupt_channel_7, 3); -#endif /* !CHIP_FAMILY_STM32F0 */ +#endif /* CHIP_FAMILY_STM32F0 */ 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); |