summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Staaf <robotboy@chromium.org>2015-07-28 10:30:44 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-08-10 17:54:17 +0000
commit014d180b1da90a5e23f2ebd4df3d00457bc5fb28 (patch)
treee6ac67ab0e24d86d82e2e93fc811261bddd66568
parent77f68f204f2e27f7ed7e80bcdd1e36280bbcff83 (diff)
downloadchrome-ec-014d180b1da90a5e23f2ebd4df3d00457bc5fb28.tar.gz
USART: Split RX driver between L and F families
The USART peripheral in the L and F families is different enough to need different receive drivers. In particular, the L family USART perihperal has no way of disabling the overflow error bit. So for that family we check and clear the bit, and keep a count of overflows. Signed-off-by: Anton Staaf <robotboy@chromium.org> BRANCH=None BUG=None TEST=make buildall -j Change-Id: Iea26c242d5177afd552a3bd4d6ab1a9c7a65f90e Reviewed-on: https://chromium-review.googlesource.com/288978 Trybot-Ready: Anton Staaf <robotboy@chromium.org> Tested-by: Anton Staaf <robotboy@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org> Commit-Queue: Anton Staaf <robotboy@chromium.org>
-rw-r--r--chip/stm32/build.mk3
-rw-r--r--chip/stm32/registers.h3
-rw-r--r--chip/stm32/usart.c14
-rw-r--r--chip/stm32/usart.h1
l---------chip/stm32/usart_rx_interrupt-stm32f0.c1
l---------chip/stm32/usart_rx_interrupt-stm32f3.c1
-rw-r--r--chip/stm32/usart_rx_interrupt-stm32l.c64
-rw-r--r--chip/stm32/usart_rx_interrupt.c18
8 files changed, 91 insertions, 14 deletions
diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk
index 72be7eb6d4..0cfd72b93f 100644
--- a/chip/stm32/build.mk
+++ b/chip/stm32/build.mk
@@ -35,7 +35,8 @@ chip-$(CONFIG_COMMON_GPIO)+=gpio.o gpio-$(CHIP_FAMILY).o
chip-$(CONFIG_COMMON_TIMER)+=hwtimer$(TIMER_TYPE).o
chip-$(CONFIG_I2C)+=i2c-$(CHIP_FAMILY).o
chip-$(CONFIG_STREAM_USART)+=usart.o usart-$(CHIP_FAMILY).o
-chip-$(CONFIG_STREAM_USART)+=usart_rx_interrupt.o usart_tx_interrupt.o
+chip-$(CONFIG_STREAM_USART)+=usart_rx_interrupt-$(CHIP_FAMILY).o
+chip-$(CONFIG_STREAM_USART)+=usart_tx_interrupt.o
chip-$(CONFIG_STREAM_USART)+=usart_tx_dma.o
chip-$(CONFIG_STREAM_USB)+=usb-stream.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index f9f27f25f5..617abd98f9 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -189,16 +189,19 @@
#define STM32_USART_RQR(base) STM32_USART_REG(base, 0x18)
#define STM32_USART_ISR(base) STM32_USART_REG(base, 0x1C)
#define STM32_USART_ICR(base) STM32_USART_REG(base, 0x20)
+#define STM32_USART_ICR_ORECF (1 << 3)
#define STM32_USART_ICR_TCCF (1 << 6)
#define STM32_USART_RDR(base) STM32_USART_REG(base, 0x24)
#define STM32_USART_TDR(base) STM32_USART_REG(base, 0x28)
/* register alias */
#define STM32_USART_SR(base) STM32_USART_ISR(base)
+#define STM32_USART_SR_ORE (1 << 3)
#define STM32_USART_SR_RXNE (1 << 5)
#define STM32_USART_SR_TC (1 << 6)
#define STM32_USART_SR_TXE (1 << 7)
#else /* !CHIP_FAMILY_STM32F0 */
#define STM32_USART_SR(base) STM32_USART_REG(base, 0x00)
+#define STM32_USART_SR_ORE (1 << 3)
#define STM32_USART_SR_RXNE (1 << 5)
#define STM32_USART_SR_TC (1 << 6)
#define STM32_USART_SR_TXE (1 << 7)
diff --git a/chip/stm32/usart.c b/chip/stm32/usart.c
index 32dbeaf7d0..549769cb48 100644
--- a/chip/stm32/usart.c
+++ b/chip/stm32/usart.c
@@ -42,7 +42,7 @@ void usart_init(struct usart_config const *config)
*/
STM32_USART_CR1(base) = 0x0000;
STM32_USART_CR2(base) = 0x0000;
- STM32_USART_CR3(base) = STM32_USART_CR3_OVRDIS;
+ STM32_USART_CR3(base) = 0x0000;
/*
* Enable the RX, TX, and variant specific HW.
@@ -52,6 +52,12 @@ void usart_init(struct usart_config const *config)
config->hw->ops->enable(config);
/*
+ * Clear error counts.
+ */
+ config->state->rx_overrun = 0;
+ config->state->rx_dropped = 0;
+
+ /*
* Enable the USART, this must be done last since most of the
* configuration bits require that the USART be disabled for writes to
* succeed.
@@ -98,6 +104,6 @@ void usart_set_baud_f(struct usart_config const *config, int frequency_hz)
void usart_interrupt(struct usart_config const *config)
{
- config->tx->interrupt(config);
- config->rx->interrupt(config);
-} \ No newline at end of file
+ config->tx->interrupt(config);
+ config->rx->interrupt(config);
+}
diff --git a/chip/stm32/usart.h b/chip/stm32/usart.h
index c0003c6cb9..a274aa8dce 100644
--- a/chip/stm32/usart.h
+++ b/chip/stm32/usart.h
@@ -24,6 +24,7 @@ struct usart_state {
* in the RX queue.
*/
uint32_t rx_dropped;
+ uint32_t rx_overrun;
};
struct usart_config;
diff --git a/chip/stm32/usart_rx_interrupt-stm32f0.c b/chip/stm32/usart_rx_interrupt-stm32f0.c
new file mode 120000
index 0000000000..a756455f9b
--- /dev/null
+++ b/chip/stm32/usart_rx_interrupt-stm32f0.c
@@ -0,0 +1 @@
+usart_rx_interrupt.c \ No newline at end of file
diff --git a/chip/stm32/usart_rx_interrupt-stm32f3.c b/chip/stm32/usart_rx_interrupt-stm32f3.c
new file mode 120000
index 0000000000..a756455f9b
--- /dev/null
+++ b/chip/stm32/usart_rx_interrupt-stm32f3.c
@@ -0,0 +1 @@
+usart_rx_interrupt.c \ No newline at end of file
diff --git a/chip/stm32/usart_rx_interrupt-stm32l.c b/chip/stm32/usart_rx_interrupt-stm32l.c
new file mode 100644
index 0000000000..e6222d1716
--- /dev/null
+++ b/chip/stm32/usart_rx_interrupt-stm32l.c
@@ -0,0 +1,64 @@
+/* Copyright (c) 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.
+ */
+
+/* Interrupt based USART RX driver for STM32L */
+
+#include "usart.h"
+
+#include "atomic.h"
+#include "common.h"
+#include "queue.h"
+#include "registers.h"
+
+static void usart_rx_init(struct usart_config const *config)
+{
+ intptr_t base = config->hw->base;
+
+ STM32_USART_CR1(base) |= STM32_USART_CR1_RXNEIE;
+ STM32_USART_CR1(base) |= STM32_USART_CR1_RE;
+}
+
+static void usart_rx_interrupt_handler(struct usart_config const *config)
+{
+ intptr_t base = config->hw->base;
+ int32_t status = STM32_USART_SR(base);
+
+ /*
+ * We have to check and clear the overrun error flag on STM32L because
+ * we can't disable it.
+ */
+ if (status & STM32_USART_SR_ORE) {
+ /*
+ * In the unlikely event that the overrun error bit was set but
+ * the RXNE bit was not (possibly because a read was done from
+ * RDR without first reading the status register) we do a read
+ * here to clear the overrun error bit.
+ */
+ if (!(status & STM32_USART_SR_RXNE))
+ (void)STM32_USART_RDR(config->hw->base);
+
+ atomic_add(&config->state->rx_overrun, 1);
+ }
+
+ if (status & STM32_USART_SR_RXNE) {
+ uint8_t byte = STM32_USART_RDR(base);
+
+ if (!queue_add_unit(config->producer.queue, &byte))
+ atomic_add(&config->state->rx_dropped, 1);
+ }
+}
+
+struct usart_rx const usart_rx_interrupt = {
+ .producer_ops = {
+ /*
+ * Nothing to do here, we either had enough space in the queue
+ * when a character came in or we dropped it already.
+ */
+ .read = NULL,
+ },
+
+ .init = usart_rx_init,
+ .interrupt = usart_rx_interrupt_handler,
+};
diff --git a/chip/stm32/usart_rx_interrupt.c b/chip/stm32/usart_rx_interrupt.c
index ea1b4a4c6a..d4fb48f5a0 100644
--- a/chip/stm32/usart_rx_interrupt.c
+++ b/chip/stm32/usart_rx_interrupt.c
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* Interrupt based USART RX driver for STM32 */
+/* Interrupt based USART RX driver for STM32F0 and STM32F3 */
#include "usart.h"
@@ -18,20 +18,20 @@ static void usart_rx_init(struct usart_config const *config)
STM32_USART_CR1(base) |= STM32_USART_CR1_RXNEIE;
STM32_USART_CR1(base) |= STM32_USART_CR1_RE;
+ STM32_USART_CR3(base) |= STM32_USART_CR3_OVRDIS;
}
static void usart_rx_interrupt_handler(struct usart_config const *config)
{
- intptr_t base = config->hw->base;
- uint8_t byte;
-
- if (!(STM32_USART_SR(base) & STM32_USART_SR_RXNE))
- return;
+ intptr_t base = config->hw->base;
+ int32_t status = STM32_USART_SR(base);
- byte = STM32_USART_RDR(base);
+ if (status & STM32_USART_SR_RXNE) {
+ uint8_t byte = STM32_USART_RDR(base);
- if (!queue_add_unit(config->producer.queue, &byte))
- atomic_add(&config->state->rx_dropped, 1);
+ if (!queue_add_unit(config->producer.queue, &byte))
+ atomic_add(&config->state->rx_dropped, 1);
+ }
}
struct usart_rx const usart_rx_interrupt = {