mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
USART: Add flexibility needed to support DMA
In order to support DMA transfers in one or both directions the usart driver needs to be configurable with producer/consumer operations and interrupt handler functions. These are now packaged up in the usart_rx and usart_tx structs, and versions for interrupt driven RX and TX are provided. Signed-off-by: Anton Staaf <robotboy@chromium.org> BRANCH=None BUG=None TEST=make buildall -j Change-Id: I3fd14c675c90873e903195b8e20d2070d2eda5ac Reviewed-on: https://chromium-review.googlesource.com/285023 Trybot-Ready: Anton Staaf <robotboy@chromium.org> Tested-by: Anton Staaf <robotboy@chromium.org> Reviewed-by: Todd Broch <tbroch@chromium.org> Tested-by: Todd Broch <tbroch@chromium.org> Commit-Queue: Anton Staaf <robotboy@chromium.org>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
88a1790bb7
commit
137959bb88
@@ -112,8 +112,8 @@ BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
|
||||
* Define AP and SH console forwarding queues and associated USART and USB
|
||||
* stream endpoints.
|
||||
*/
|
||||
struct usart_config const ap_usart;
|
||||
struct usart_config const sh_usart;
|
||||
static struct usart_config const ap_usart;
|
||||
static struct usart_config const sh_usart;
|
||||
|
||||
struct usb_stream_config const ap_usb;
|
||||
struct usb_stream_config const sh_usb;
|
||||
@@ -131,8 +131,19 @@ static struct queue const sh_usb_to_usart = QUEUE_DIRECT(64, uint8_t,
|
||||
sh_usb.producer,
|
||||
sh_usart.consumer);
|
||||
|
||||
USART_CONFIG(ap_usart, usart1_hw, 115200, ap_usart_to_usb, ap_usb_to_usart)
|
||||
USART_CONFIG(sh_usart, usart3_hw, 115200, sh_usart_to_usb, sh_usb_to_usart)
|
||||
static struct usart_config const ap_usart = USART_CONFIG(usart1_hw,
|
||||
usart_rx_interrupt,
|
||||
usart_tx_interrupt,
|
||||
115200,
|
||||
ap_usart_to_usb,
|
||||
ap_usb_to_usart);
|
||||
|
||||
static struct usart_config const sh_usart = USART_CONFIG(usart3_hw,
|
||||
usart_rx_interrupt,
|
||||
usart_tx_interrupt,
|
||||
115200,
|
||||
sh_usart_to_usb,
|
||||
sh_usb_to_usart);
|
||||
|
||||
#define AP_USB_STREAM_RX_SIZE 16
|
||||
#define AP_USB_STREAM_TX_SIZE 16
|
||||
|
||||
@@ -111,8 +111,8 @@ BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
|
||||
* Define AP and SH console forwarding queues and associated USART and USB
|
||||
* stream endpoints.
|
||||
*/
|
||||
struct usart_config const ap_usart;
|
||||
struct usart_config const sh_usart;
|
||||
static struct usart_config const ap_usart;
|
||||
static struct usart_config const sh_usart;
|
||||
|
||||
struct usb_stream_config const ap_usb;
|
||||
struct usb_stream_config const sh_usb;
|
||||
@@ -130,8 +130,19 @@ static struct queue const sh_usb_to_usart = QUEUE_DIRECT(64, uint8_t,
|
||||
sh_usb.producer,
|
||||
sh_usart.consumer);
|
||||
|
||||
USART_CONFIG(ap_usart, usart1_hw, 115200, ap_usart_to_usb, ap_usb_to_usart)
|
||||
USART_CONFIG(sh_usart, usart3_hw, 115200, sh_usart_to_usb, sh_usb_to_usart)
|
||||
static struct usart_config const ap_usart = USART_CONFIG(usart1_hw,
|
||||
usart_rx_interrupt,
|
||||
usart_tx_interrupt,
|
||||
115200,
|
||||
ap_usart_to_usb,
|
||||
ap_usb_to_usart);
|
||||
|
||||
static struct usart_config const sh_usart = USART_CONFIG(usart3_hw,
|
||||
usart_rx_interrupt,
|
||||
usart_tx_interrupt,
|
||||
115200,
|
||||
sh_usart_to_usb,
|
||||
sh_usb_to_usart);
|
||||
|
||||
#define AP_USB_STREAM_RX_SIZE 16
|
||||
#define AP_USB_STREAM_TX_SIZE 16
|
||||
|
||||
@@ -35,6 +35,7 @@ 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_USB)+=usb-stream.o
|
||||
chip-$(CONFIG_WATCHDOG)+=watchdog.o
|
||||
chip-$(HAS_TASK_CONSOLE)+=uart.o
|
||||
|
||||
@@ -14,47 +14,6 @@
|
||||
#include "usart.h"
|
||||
#include "util.h"
|
||||
|
||||
static void usart_written(struct consumer const *consumer, size_t count)
|
||||
{
|
||||
struct usart_config const *config =
|
||||
DOWNCAST(consumer, struct usart_config, consumer);
|
||||
|
||||
/*
|
||||
* Enable USART interrupt. This causes the USART interrupt handler to
|
||||
* start fetching from the TX queue if it wasn't already.
|
||||
*/
|
||||
if (count)
|
||||
STM32_USART_CR1(config->hw->base) |= STM32_USART_CR1_TXEIE;
|
||||
}
|
||||
|
||||
static void usart_flush(struct consumer const *consumer)
|
||||
{
|
||||
struct usart_config const *config =
|
||||
DOWNCAST(consumer, struct usart_config, consumer);
|
||||
|
||||
/*
|
||||
* Enable USART interrupt. This causes the USART interrupt handler to
|
||||
* start fetching from the TX queue if it wasn't already.
|
||||
*/
|
||||
STM32_USART_CR1(config->hw->base) |= STM32_USART_CR1_TXEIE;
|
||||
|
||||
while (queue_count(consumer->queue))
|
||||
;
|
||||
}
|
||||
|
||||
struct producer_ops const usart_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,
|
||||
};
|
||||
|
||||
struct consumer_ops const usart_consumer_ops = {
|
||||
.written = usart_written,
|
||||
.flush = usart_flush,
|
||||
};
|
||||
|
||||
void usart_init(struct usart_config const *config)
|
||||
{
|
||||
intptr_t base = config->hw->base;
|
||||
@@ -78,18 +37,18 @@ void usart_init(struct usart_config const *config)
|
||||
gpio_config_module(MODULE_USART, 1);
|
||||
|
||||
/*
|
||||
* 8N1, 16 samples per bit, enable TX and RX (and associated RX
|
||||
* interrupt) DMA, error interrupts, and special modes disabled.
|
||||
* 8N1, 16 samples per bit. error interrupts, and special modes
|
||||
* disabled.
|
||||
*/
|
||||
STM32_USART_CR1(base) = (STM32_USART_CR1_TE |
|
||||
STM32_USART_CR1_RE |
|
||||
STM32_USART_CR1_RXNEIE);
|
||||
STM32_USART_CR1(base) = 0x0000;
|
||||
STM32_USART_CR2(base) = 0x0000;
|
||||
STM32_USART_CR3(base) = STM32_USART_CR3_OVRDIS;
|
||||
|
||||
/*
|
||||
* Enable the variant specific HW.
|
||||
* Enable the RX, TX, and variant specific HW.
|
||||
*/
|
||||
config->rx->init(config);
|
||||
config->tx->init(config);
|
||||
config->hw->ops->enable(config);
|
||||
|
||||
/*
|
||||
@@ -137,51 +96,8 @@ void usart_set_baud_f(struct usart_config const *config, int frequency_hz)
|
||||
STM32_USART_BRR(config->hw->base) = div;
|
||||
}
|
||||
|
||||
static void usart_interrupt_tx(struct usart_config const *config)
|
||||
{
|
||||
intptr_t base = config->hw->base;
|
||||
uint8_t byte;
|
||||
|
||||
if (queue_remove_unit(config->consumer.queue, &byte)) {
|
||||
STM32_USART_TDR(base) = byte;
|
||||
|
||||
/*
|
||||
* Make sure the TXE interrupt is enabled and that we won't go
|
||||
* into deep sleep. This invocation of the USART interrupt
|
||||
* handler may have been manually triggered to start
|
||||
* transmission.
|
||||
*/
|
||||
disable_sleep(SLEEP_MASK_UART);
|
||||
|
||||
STM32_USART_CR1(base) |= STM32_USART_CR1_TXEIE;
|
||||
} else {
|
||||
/*
|
||||
* The TX queue is empty, disable the TXE interrupt and enable
|
||||
* deep sleep mode. The TXE interrupt will remain disabled
|
||||
* until a write call happens.
|
||||
*/
|
||||
enable_sleep(SLEEP_MASK_UART);
|
||||
|
||||
STM32_USART_CR1(base) &= ~STM32_USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
|
||||
static void usart_interrupt_rx(struct usart_config const *config)
|
||||
{
|
||||
intptr_t base = config->hw->base;
|
||||
uint8_t byte = STM32_USART_RDR(base);
|
||||
|
||||
if (!queue_add_unit(config->producer.queue, &byte))
|
||||
atomic_add((uint32_t *) &config->state->rx_dropped, 1);
|
||||
}
|
||||
|
||||
void usart_interrupt(struct usart_config const *config)
|
||||
{
|
||||
intptr_t base = config->hw->base;
|
||||
|
||||
if (STM32_USART_SR(base) & STM32_USART_SR_TXE)
|
||||
usart_interrupt_tx(config);
|
||||
|
||||
if (STM32_USART_SR(base) & STM32_USART_SR_RXNE)
|
||||
usart_interrupt_rx(config);
|
||||
}
|
||||
config->tx->interrupt(config);
|
||||
config->rx->interrupt(config);
|
||||
}
|
||||
@@ -45,6 +45,32 @@ struct usart_hw_ops {
|
||||
void (*disable)(struct usart_config const *config);
|
||||
};
|
||||
|
||||
/*
|
||||
* The usart_rx/usart_tx structures contain functions pointers for the
|
||||
* interrupt handler and producer/consumer operations required to implement a
|
||||
* particular RX/TX strategy.
|
||||
*
|
||||
* These structures are defined by the various RX/TX implementations, and are
|
||||
* used to initialize the usart_config structure to configure the USART driver
|
||||
* for interrupt or DMA based transfer.
|
||||
*/
|
||||
struct usart_rx {
|
||||
void (*init)(struct usart_config const *config);
|
||||
void (*interrupt)(struct usart_config const *config);
|
||||
|
||||
struct producer_ops producer_ops;
|
||||
};
|
||||
|
||||
struct usart_tx {
|
||||
void (*init)(struct usart_config const *config);
|
||||
void (*interrupt)(struct usart_config const *config);
|
||||
|
||||
struct consumer_ops consumer_ops;
|
||||
};
|
||||
|
||||
extern struct usart_rx const usart_rx_interrupt;
|
||||
extern struct usart_tx const usart_tx_interrupt;
|
||||
|
||||
/*
|
||||
* Per-USART hardware configuration stored in flash. Instances of this
|
||||
* structure are provided by each variants driver, one per physical USART.
|
||||
@@ -72,6 +98,9 @@ struct usart_config {
|
||||
*/
|
||||
struct usart_hw_config const *hw;
|
||||
|
||||
struct usart_rx const *rx;
|
||||
struct usart_tx const *tx;
|
||||
|
||||
/*
|
||||
* Pointer to USART state structure. The state structure maintains per
|
||||
* USART information.
|
||||
@@ -87,13 +116,6 @@ struct usart_config {
|
||||
struct producer producer;
|
||||
};
|
||||
|
||||
/*
|
||||
* These function tables are defined by the USART driver and are used to
|
||||
* initialize the consumer and producer in the usart_config.
|
||||
*/
|
||||
extern struct consumer_ops const usart_consumer_ops;
|
||||
extern struct producer_ops const usart_producer_ops;
|
||||
|
||||
/*
|
||||
* Convenience macro for defining USARTs and their associated state and buffers.
|
||||
* NAME is used to construct the names of the usart_state struct, and
|
||||
@@ -111,26 +133,22 @@ extern struct producer_ops const usart_producer_ops;
|
||||
* BUILD_ASSERT(RX_QUEUE.unit_bytes == 1);
|
||||
* BUILD_ASSERT(TX_QUEUE.unit_bytes == 1);
|
||||
*/
|
||||
#define USART_CONFIG(NAME, \
|
||||
HW, \
|
||||
BAUD, \
|
||||
RX_QUEUE, \
|
||||
TX_QUEUE) \
|
||||
\
|
||||
static struct usart_state CONCAT2(NAME, _state); \
|
||||
struct usart_config const NAME = { \
|
||||
#define USART_CONFIG(HW, RX, TX, BAUD, RX_QUEUE, TX_QUEUE) \
|
||||
((struct usart_config const) { \
|
||||
.hw = &HW, \
|
||||
.state = &CONCAT2(NAME, _state), \
|
||||
.rx = &RX, \
|
||||
.tx = &TX, \
|
||||
.state = &((struct usart_state){}), \
|
||||
.baud = BAUD, \
|
||||
.consumer = { \
|
||||
.queue = &TX_QUEUE, \
|
||||
.ops = &usart_consumer_ops, \
|
||||
.ops = &TX.consumer_ops, \
|
||||
}, \
|
||||
.producer = { \
|
||||
.queue = &RX_QUEUE, \
|
||||
.ops = &usart_producer_ops, \
|
||||
.ops = &RX.producer_ops, \
|
||||
}, \
|
||||
};
|
||||
})
|
||||
|
||||
/*
|
||||
* Initialize the given USART. Once init is finished the USART streams are
|
||||
|
||||
48
chip/stm32/usart_rx_interrupt.c
Normal file
48
chip/stm32/usart_rx_interrupt.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/* Copyright (c) 2014 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 STM32 */
|
||||
|
||||
#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;
|
||||
uint8_t byte;
|
||||
|
||||
if (!(STM32_USART_SR(base) & STM32_USART_SR_RXNE))
|
||||
return;
|
||||
|
||||
byte = STM32_USART_RDR(base);
|
||||
|
||||
if (!queue_add_unit(config->producer.queue, &byte))
|
||||
atomic_add((uint32_t *) &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,
|
||||
};
|
||||
90
chip/stm32/usart_tx_interrupt.c
Normal file
90
chip/stm32/usart_tx_interrupt.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2014 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 TX driver for STM32 */
|
||||
|
||||
#include "usart.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "registers.h"
|
||||
#include "system.h"
|
||||
#include "util.h"
|
||||
|
||||
static void usart_tx_init(struct usart_config const *config)
|
||||
{
|
||||
intptr_t base = config->hw->base;
|
||||
|
||||
STM32_USART_CR1(base) |= STM32_USART_CR1_TE;
|
||||
}
|
||||
|
||||
static void usart_written(struct consumer const *consumer, size_t count)
|
||||
{
|
||||
struct usart_config const *config =
|
||||
DOWNCAST(consumer, struct usart_config, consumer);
|
||||
|
||||
/*
|
||||
* Enable USART interrupt. This causes the USART interrupt handler to
|
||||
* start fetching from the TX queue if it wasn't already.
|
||||
*/
|
||||
if (count)
|
||||
STM32_USART_CR1(config->hw->base) |= STM32_USART_CR1_TXEIE;
|
||||
}
|
||||
|
||||
static void usart_flush(struct consumer const *consumer)
|
||||
{
|
||||
struct usart_config const *config =
|
||||
DOWNCAST(consumer, struct usart_config, consumer);
|
||||
|
||||
/*
|
||||
* Enable USART interrupt. This causes the USART interrupt handler to
|
||||
* start fetching from the TX queue if it wasn't already.
|
||||
*/
|
||||
STM32_USART_CR1(config->hw->base) |= STM32_USART_CR1_TXEIE;
|
||||
|
||||
while (queue_count(consumer->queue))
|
||||
;
|
||||
}
|
||||
|
||||
static void usart_tx_interrupt_handler(struct usart_config const *config)
|
||||
{
|
||||
intptr_t base = config->hw->base;
|
||||
uint8_t byte;
|
||||
|
||||
if (!(STM32_USART_SR(base) & STM32_USART_SR_TXE))
|
||||
return;
|
||||
|
||||
if (queue_remove_unit(config->consumer.queue, &byte)) {
|
||||
STM32_USART_TDR(base) = byte;
|
||||
|
||||
/*
|
||||
* Make sure the TXE interrupt is enabled and that we won't go
|
||||
* into deep sleep. This invocation of the USART interrupt
|
||||
* handler may have been manually triggered to start
|
||||
* transmission.
|
||||
*/
|
||||
disable_sleep(SLEEP_MASK_UART);
|
||||
|
||||
STM32_USART_CR1(base) |= STM32_USART_CR1_TXEIE;
|
||||
} else {
|
||||
/*
|
||||
* The TX queue is empty, disable the TXE interrupt and enable
|
||||
* deep sleep mode. The TXE interrupt will remain disabled
|
||||
* until a write call happens.
|
||||
*/
|
||||
enable_sleep(SLEEP_MASK_UART);
|
||||
|
||||
STM32_USART_CR1(base) &= ~STM32_USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
|
||||
struct usart_tx const usart_tx_interrupt = {
|
||||
.consumer_ops = {
|
||||
.written = usart_written,
|
||||
.flush = usart_flush,
|
||||
},
|
||||
|
||||
.init = usart_tx_init,
|
||||
.interrupt = usart_tx_interrupt_handler,
|
||||
};
|
||||
@@ -38,7 +38,7 @@ static inline void print_buffer(uint8_t *buf, int cnt)
|
||||
static inline void print_buffer(uint8_t *buf, int cnt) {}
|
||||
#endif
|
||||
|
||||
struct usart_config const usart_mcdp;
|
||||
static struct usart_config const usart_mcdp;
|
||||
|
||||
struct queue const usart_mcdp_rx_queue = QUEUE_DIRECT(MCDP_INBUF_MAX,
|
||||
uint8_t,
|
||||
@@ -49,11 +49,12 @@ struct queue const usart_mcdp_tx_queue = QUEUE_DIRECT(MCDP_OUTBUF_MAX,
|
||||
null_producer,
|
||||
usart_mcdp.consumer);
|
||||
|
||||
USART_CONFIG(usart_mcdp,
|
||||
CONFIG_MCDP28X0,
|
||||
115200,
|
||||
usart_mcdp_rx_queue,
|
||||
usart_mcdp_tx_queue);
|
||||
static struct usart_config const usart_mcdp = USART_CONFIG(CONFIG_MCDP28X0,
|
||||
usart_rx_interrupt,
|
||||
usart_tx_interrupt,
|
||||
115200,
|
||||
usart_mcdp_rx_queue,
|
||||
usart_mcdp_tx_queue);
|
||||
|
||||
/**
|
||||
* Compute checksum.
|
||||
|
||||
Reference in New Issue
Block a user