diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-19 06:28:01 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-20 13:08:32 +0200 |
commit | d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc (patch) | |
tree | caa54b4229e86a68c84ab5961af34e087dce5302 /bsps/arm/lpc32xx | |
parent | bsps/powerpc: Move shared btimer support (diff) | |
download | rtems-d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc.tar.bz2 |
bsps: Move console drivers to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps/arm/lpc32xx')
-rw-r--r-- | bsps/arm/lpc32xx/console/console-config.c | 225 | ||||
-rw-r--r-- | bsps/arm/lpc32xx/console/hsu.c | 208 |
2 files changed, 433 insertions, 0 deletions
diff --git a/bsps/arm/lpc32xx/console/console-config.c b/bsps/arm/lpc32xx/console/console-config.c new file mode 100644 index 0000000000..17e6b0af8f --- /dev/null +++ b/bsps/arm/lpc32xx/console/console-config.c @@ -0,0 +1,225 @@ +/** + * @file + * + * @ingroup arm_lpc32xx + * + * @brief Console configuration. + */ + +/* + * Copyright (c) 2009-2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <libchip/ns16550.h> + +#include <bsp.h> +#include <bsp/lpc32xx.h> +#include <bsp/irq.h> +#include <bsp/hsu.h> +#include <bsp/console-termios.h> + +static uint8_t lpc32xx_uart_get_register(uintptr_t addr, uint8_t i) +{ + volatile uint32_t *reg = (volatile uint32_t *) addr; + + return (uint8_t) reg [i]; +} + +static void lpc32xx_uart_set_register(uintptr_t addr, uint8_t i, uint8_t val) +{ + volatile uint32_t *reg = (volatile uint32_t *) addr; + + reg [i] = val; +} + +#ifdef LPC32XX_UART_3_BAUD + static bool lpc32xx_uart_probe_3(rtems_termios_device_context *context) + { + LPC32XX_UARTCLK_CTRL |= BSP_BIT32(0); + LPC32XX_U3CLK = LPC32XX_CONFIG_U3CLK; + LPC32XX_UART_CLKMODE = BSP_FLD32SET(LPC32XX_UART_CLKMODE, 0x2, 4, 5); + + return ns16550_probe(context); + } +#endif + +#ifdef LPC32XX_UART_4_BAUD + static bool lpc32xx_uart_probe_4(rtems_termios_device_context *context) + { + volatile lpc32xx_gpio *gpio = &lpc32xx.gpio; + + /* + * Set GPO_21/U4_TX/LCDVD[3] to U4_TX. This works only if LCD module is + * disabled. + */ + gpio->p2_mux_set = BSP_BIT32(2); + + LPC32XX_UARTCLK_CTRL |= BSP_BIT32(1); + LPC32XX_U4CLK = LPC32XX_CONFIG_U4CLK; + LPC32XX_UART_CLKMODE = BSP_FLD32SET(LPC32XX_UART_CLKMODE, 0x2, 6, 7); + + return ns16550_probe(context); + } +#endif + +#ifdef LPC32XX_UART_6_BAUD + static bool lpc32xx_uart_probe_6(rtems_termios_device_context *context) + { + /* Bypass the IrDA modulator/demodulator */ + LPC32XX_UART_CTRL |= BSP_BIT32(5); + + LPC32XX_UARTCLK_CTRL |= BSP_BIT32(3); + LPC32XX_U6CLK = LPC32XX_CONFIG_U6CLK; + LPC32XX_UART_CLKMODE = BSP_FLD32SET(LPC32XX_UART_CLKMODE, 0x2, 10, 11); + + return ns16550_probe(context); + } +#endif + +/* FIXME: Console selection */ + +#ifdef LPC32XX_UART_5_BAUD +static ns16550_context lpc32xx_uart_context_5 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 5"), + .get_reg = lpc32xx_uart_get_register, + .set_reg = lpc32xx_uart_set_register, + .port = LPC32XX_BASE_UART_5, + .irq = LPC32XX_IRQ_UART_5, + .clock = 16 * LPC32XX_UART_5_BAUD, + .initial_baud = LPC32XX_UART_5_BAUD +}; +#endif + +#ifdef LPC32XX_UART_3_BAUD +static ns16550_context lpc32xx_uart_context_3 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 3"), + .get_reg = lpc32xx_uart_get_register, + .set_reg = lpc32xx_uart_set_register, + .port = LPC32XX_BASE_UART_3, + .irq = LPC32XX_IRQ_UART_3, + .clock = 16 * LPC32XX_UART_3_BAUD, + .initial_baud = LPC32XX_UART_3_BAUD +}; +#endif + +#ifdef LPC32XX_UART_4_BAUD +static ns16550_context lpc32xx_uart_context_4 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 4"), + .get_reg = lpc32xx_uart_get_register, + .set_reg = lpc32xx_uart_set_register, + .port = LPC32XX_BASE_UART_4, + .irq = LPC32XX_IRQ_UART_4, + .clock = 16 * LPC32XX_UART_4_BAUD, + .initial_baud = LPC32XX_UART_4_BAUD +}; +#endif + +#ifdef LPC32XX_UART_6_BAUD +static ns16550_context lpc32xx_uart_context_6 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 6"), + .get_reg = lpc32xx_uart_get_register, + .set_reg = lpc32xx_uart_set_register, + .port = LPC32XX_BASE_UART_6, + .irq = LPC32XX_IRQ_UART_6, + .clock = 16 * LPC32XX_UART_6_BAUD, + .initial_baud = LPC32XX_UART_6_BAUD +}; +#endif + +#ifdef LPC32XX_UART_1_BAUD +static lpc32xx_hsu_context lpc32xx_uart_context_1 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 1"), + .hsu = (volatile lpc32xx_hsu *) LPC32XX_BASE_UART_1, + .irq = LPC32XX_IRQ_UART_1, + .initial_baud = LPC32XX_UART_1_BAUD +}; +#endif + +#ifdef LPC32XX_UART_2_BAUD +static lpc32xx_hsu_context lpc32xx_uart_context_2 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 2"), + .hsu = (volatile lpc32xx_hsu *) LPC32XX_BASE_UART_2, + .irq = LPC32XX_IRQ_UART_2, + .initial_baud = LPC32XX_UART_2_BAUD +}; +#endif + +#ifdef LPC32XX_UART_7_BAUD +static lpc32xx_hsu_context lpc32xx_uart_context_7 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 7"), + .hsu = (volatile lpc32xx_hsu *) LPC32XX_BASE_UART_7, + .irq = LPC32XX_IRQ_UART_7, + .initial_baud = LPC32XX_UART_7_BAUD +}; +#endif + +const console_device console_device_table[] = { + #ifdef LPC32XX_UART_5_BAUD + { + .device_file = "/dev/ttyS5", + .probe = console_device_probe_default, + .handler = &ns16550_handler_interrupt, + .context = &lpc32xx_uart_context_5.base + }, + #endif + #ifdef LPC32XX_UART_3_BAUD + { + .device_file = "/dev/ttyS3", + .probe = lpc32xx_uart_probe_3, + .handler = &ns16550_handler_interrupt, + .context = &lpc32xx_uart_context_3.base + }, + #endif + #ifdef LPC32XX_UART_4_BAUD + { + .device_file = "/dev/ttyS4", + .probe = lpc32xx_uart_probe_4, + .handler = &ns16550_handler_interrupt, + .context = &lpc32xx_uart_context_4.base + }, + #endif + #ifdef LPC32XX_UART_6_BAUD + { + .device_file = "/dev/ttyS6", + .probe = lpc32xx_uart_probe_6, + .handler = &ns16550_handler_interrupt, + .context = &lpc32xx_uart_context_6.base + }, + #endif + #ifdef LPC32XX_UART_1_BAUD + { + .device_file = "/dev/ttyS1", + .probe = lpc32xx_hsu_probe, + .handler = &lpc32xx_hsu_fns, + .context = &lpc32xx_uart_context_1.base + }, + #endif + #ifdef LPC32XX_UART_2_BAUD + { + .device_file = "/dev/ttyS2", + .probe = lpc32xx_hsu_probe, + .handler = &lpc32xx_hsu_fns, + .context = &lpc32xx_uart_context_2.base + }, + #endif + #ifdef LPC32XX_UART_7_BAUD + { + .device_file = "/dev/ttyS7", + .probe = lpc32xx_hsu_probe, + .handler = &lpc32xx_hsu_fns, + .context = &lpc32xx_uart_context_7.base + }, + #endif +}; + +const size_t console_device_count = RTEMS_ARRAY_SIZE(console_device_table); diff --git a/bsps/arm/lpc32xx/console/hsu.c b/bsps/arm/lpc32xx/console/hsu.c new file mode 100644 index 0000000000..b2044e0753 --- /dev/null +++ b/bsps/arm/lpc32xx/console/hsu.c @@ -0,0 +1,208 @@ +/** + * @file + * + * @ingroup arm_lpc32xx + * + * @brief High speed UART driver (14-clock). + */ + +/* + * Copyright (c) 2010-2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <bsp/lpc32xx.h> +#include <bsp/irq.h> +#include <bsp/hsu.h> + +#define HSU_FIFO_SIZE 64 + +#define HSU_LEVEL_RX_MASK 0xffU +#define HSU_LEVEL_TX_MASK 0xff00U +#define HSU_LEVEL_TX_SHIFT 8 + +#define HSU_RX_DATA_MASK 0xffU +#define HSU_RX_EMPTY (1U << 8) +#define HSU_RX_ERROR (1U << 9) +#define HSU_RX_BREAK (1U << 10) + +#define HSU_IIR_TX (1U << 0) +#define HSU_IIR_RX_TRIG (1U << 1) +#define HSU_IIR_RX_TIMEOUT (1U << 2) + +#define HSU_CTRL_INTR_DISABLED 0x1280fU +#define HSU_CTRL_RX_INTR_ENABLED 0x1284fU +#define HSU_CTRL_RX_AND_TX_INTR_ENABLED 0x1286fU + +/* We are interested in RX timeout, RX trigger and TX trigger interrupts */ +#define HSU_IIR_MASK 0x7U + +bool lpc32xx_hsu_probe(rtems_termios_device_context *base) +{ + lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base; + volatile lpc32xx_hsu *hsu = ctx->hsu; + + hsu->ctrl = HSU_CTRL_INTR_DISABLED; + + /* Drain FIFOs */ + while (hsu->level != 0) { + hsu->fifo; + } + + return true; +} + +static void lpc32xx_hsu_interrupt_handler(void *arg) +{ + rtems_termios_tty *tty = arg; + lpc32xx_hsu_context *ctx = rtems_termios_get_device_context(tty); + volatile lpc32xx_hsu *hsu = ctx->hsu; + + /* Iterate until no more interrupts are pending */ + do { + int rv = 0; + int i = 0; + char buf [HSU_FIFO_SIZE]; + + /* Enqueue received characters */ + while (i < HSU_FIFO_SIZE) { + uint32_t in = hsu->fifo; + + if ((in & HSU_RX_EMPTY) == 0) { + if ((in & HSU_RX_BREAK) == 0) { + buf [i] = in & HSU_RX_DATA_MASK; + ++i; + } + } else { + break; + } + } + rtems_termios_enqueue_raw_characters(tty, buf, i); + + /* Dequeue transmitted characters */ + rv = rtems_termios_dequeue_characters(tty, (int) ctx->chars_in_transmission); + if (rv == 0) { + /* Nothing to transmit */ + } + } while ((hsu->iir & HSU_IIR_MASK) != 0); +} + +static bool lpc32xx_hsu_first_open( + struct rtems_termios_tty *tty, + rtems_termios_device_context *base, + struct termios *term, + rtems_libio_open_close_args_t *args +) +{ + lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base; + volatile lpc32xx_hsu *hsu = ctx->hsu; + rtems_status_code sc; + bool ok; + + sc = rtems_interrupt_handler_install( + ctx->irq, + "HSU", + RTEMS_INTERRUPT_UNIQUE, + lpc32xx_hsu_interrupt_handler, + tty + ); + ok = sc == RTEMS_SUCCESSFUL; + + if (ok) { + rtems_termios_set_initial_baud(tty, ctx->initial_baud); + hsu->ctrl = HSU_CTRL_RX_INTR_ENABLED; + } + + return ok; +} + +static void lpc32xx_hsu_last_close( + struct rtems_termios_tty *tty, + rtems_termios_device_context *base, + rtems_libio_open_close_args_t *args +) +{ + lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base; + volatile lpc32xx_hsu *hsu = ctx->hsu; + + hsu->ctrl = HSU_CTRL_INTR_DISABLED; + + rtems_interrupt_handler_remove( + ctx->irq, + lpc32xx_hsu_interrupt_handler, + tty + ); +} + +static void lpc32xx_hsu_write( + rtems_termios_device_context *base, + const char *buf, + size_t len +) +{ + lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base; + volatile lpc32xx_hsu *hsu = ctx->hsu; + size_t tx_level = (hsu->level & HSU_LEVEL_TX_MASK) >> HSU_LEVEL_TX_SHIFT; + size_t tx_free = HSU_FIFO_SIZE - tx_level; + size_t i = 0; + size_t out = len > tx_free ? tx_free : len; + + for (i = 0; i < out; ++i) { + hsu->fifo = buf [i]; + } + + ctx->chars_in_transmission = out; + + if (len > 0) { + hsu->ctrl = HSU_CTRL_RX_AND_TX_INTR_ENABLED; + } else { + hsu->ctrl = HSU_CTRL_RX_INTR_ENABLED; + hsu->iir = HSU_IIR_TX; + } +} + +static bool lpc32xx_hsu_set_attributes( + rtems_termios_device_context *base, + const struct termios *term +) +{ + lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base; + volatile lpc32xx_hsu *hsu = ctx->hsu; + int baud_flags = term->c_ospeed; + + if (baud_flags != 0) { + int32_t baud = rtems_termios_baud_to_number(baud_flags); + + if (baud > 0) { + uint32_t baud_divisor = 14 * (uint32_t) baud; + uint32_t rate = LPC32XX_PERIPH_CLK / baud_divisor; + uint32_t remainder = LPC32XX_PERIPH_CLK - rate * baud_divisor; + + if (2 * remainder >= baud_divisor) { + ++rate; + } + + hsu->rate = rate - 1; + } + } + + return true; +} + +const rtems_termios_device_handler lpc32xx_hsu_fns = { + .first_open = lpc32xx_hsu_first_open, + .last_close = lpc32xx_hsu_last_close, + .write = lpc32xx_hsu_write, + .set_attributes = lpc32xx_hsu_set_attributes, + .mode = TERMIOS_IRQ_DRIVEN +}; |