diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-09-10 10:25:18 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2013-09-11 22:41:22 +0000 |
commit | af12f2f58c001dfa999591c29b055b7ba95379ba (patch) | |
tree | 48867e99e48a62ae818b177cd45b1519d6ceaf5b /chip/stm32/uart.c | |
parent | 6b1dace9f456d5b1b160402866045c3659e665e0 (diff) | |
download | chrome-ec-af12f2f58c001dfa999591c29b055b7ba95379ba.tar.gz |
stm32: Support DMA-based UART output
This reduces the number of UART interrupts by a factor of 12, and
reduces the overall interrupt rate on STM32 by a factor of 2.
BUG=chrome-os-partner:20485
BRANCH=none (not required for pit branch)
TEST=Boot pit. Ctrl+Q pauses debug output; Ctrl+S resumes it.
'crash divzero' still prints a full crash dump.
And util/makeall.sh passes builds all platforms and passes tests.
Change-Id: I86993e14b436150298dcb2c6d29086cc3c9db418
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/168814
Diffstat (limited to 'chip/stm32/uart.c')
-rw-r--r-- | chip/stm32/uart.c | 63 |
1 files changed, 55 insertions, 8 deletions
diff --git a/chip/stm32/uart.c b/chip/stm32/uart.c index 42461b2a90..c848f0b20c 100644 --- a/chip/stm32/uart.c +++ b/chip/stm32/uart.c @@ -7,6 +7,7 @@ #include "common.h" #include "clock.h" +#include "dma.h" #include "gpio.h" #include "hooks.h" #include "registers.h" @@ -17,6 +18,19 @@ /* Console USART index */ #define UARTN CONFIG_UART_CONSOLE +#ifdef CONFIG_UART_TX_DMA +#define UART_TX_INT_ENABLE STM32_USART_CR1_TCIE + +/* DMA channel options; assumes UART1 */ +static const struct dma_option dma_tx_option = { + STM32_DMAC_USART1_TX, (void *)&STM32_USART_DR(UARTN), + STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT +}; + +#else +#define UART_TX_INT_ENABLE STM32_USART_CR1_TXEIE +#endif + static int init_done; /* Initialization done? */ static int should_stop; /* Last TX control action */ @@ -28,21 +42,21 @@ int uart_init_done(void) void uart_tx_start(void) { disable_sleep(SLEEP_MASK_UART); - STM32_USART_CR1(UARTN) |= STM32_USART_CR1_TXEIE; should_stop = 0; + STM32_USART_CR1(UARTN) |= UART_TX_INT_ENABLE; task_trigger_irq(STM32_IRQ_USART(UARTN)); } void uart_tx_stop(void) { - STM32_USART_CR1(UARTN) &= ~STM32_USART_CR1_TXEIE; + STM32_USART_CR1(UARTN) &= ~UART_TX_INT_ENABLE; should_stop = 1; enable_sleep(SLEEP_MASK_UART); } int uart_tx_stopped(void) { - return !(STM32_USART_CR1(UARTN) & STM32_USART_CR1_TXEIE); + return !(STM32_USART_CR1(UARTN) & UART_TX_INT_ENABLE); } void uart_tx_flush(void) @@ -56,6 +70,27 @@ int uart_tx_ready(void) return STM32_USART_SR(UARTN) & STM32_USART_SR_TXE; } +#ifdef CONFIG_UART_TX_DMA + +int uart_tx_dma_ready(void) +{ + return STM32_USART_SR(UARTN) & STM32_USART_SR_TC; +} + +void uart_tx_dma_start(const char *src, int len) +{ + /* Prepare DMA */ + dma_prepare_tx(&dma_tx_option, len, src); + + /* Force clear TC so we don't re-interrupt */ + STM32_USART_SR(UARTN) &= ~STM32_USART_SR_TC; + + /* Start DMA */ + dma_go(dma_get_channel(dma_tx_option.channel)); +} + +#endif /* CONFIG_UART_TX_DMA */ + int uart_rx_available(void) { return STM32_USART_SR(UARTN) & STM32_USART_SR_RXNE; @@ -63,11 +98,10 @@ int uart_rx_available(void) void uart_write_char(char c) { - /* we normally never wait here since uart_write_char is normally called - * when the buffer is ready, excepted when we insert a carriage return - * before a line feed in the interrupt routine. - */ - while (!uart_tx_ready()) ; + /* Wait for space */ + while (!uart_tx_ready()) + ; + STM32_USART_DR(UARTN) = c; } @@ -89,22 +123,30 @@ void uart_enable_interrupt(void) /* Interrupt handler for console USART */ static void uart_interrupt(void) { +#ifdef CONFIG_UART_TX_DMA + /* Disable transmission complete interrupt if DMA done */ + if (STM32_USART_SR(UARTN) & STM32_USART_SR_TC) + STM32_USART_CR1(UARTN) &= ~STM32_USART_CR1_TCIE; +#else /* * Disable the TX empty interrupt before filling the TX buffer since it * needs an actual write to DR to be cleared. */ STM32_USART_CR1(UARTN) &= ~STM32_USART_CR1_TXEIE; +#endif /* Read input FIFO until empty, then fill output FIFO */ uart_process_input(); uart_process_output(); +#ifndef CONFIG_UART_TX_DMA /* * Re-enable TX empty interrupt only if it was not disabled by * uart_process. */ if (!should_stop) STM32_USART_CR1(UARTN) |= STM32_USART_CR1_TXEIE; +#endif } DECLARE_IRQ(STM32_IRQ_USART(UARTN), uart_interrupt, 2); @@ -162,8 +204,13 @@ void uart_init(void) /* 1 stop bit, no fancy stuff */ STM32_USART_CR2(UARTN) = 0x0000; +#ifdef CONFIG_UART_TX_DMA + /* Enable DMA transmitter */ + STM32_USART_CR3(UARTN) |= STM32_USART_CR3_DMAT; +#else /* DMA disabled, special modes disabled, error interrupt disabled */ STM32_USART_CR3(UARTN) = 0x0000; +#endif #ifdef CHIP_FAMILY_stm32l /* Use single-bit sampling */ |