diff options
author | Stefan Roese <sr@denx.de> | 2016-05-17 14:36:00 (GMT) |
---|---|---|
committer | Stefan Roese <sr@denx.de> | 2016-09-27 15:29:52 (GMT) |
commit | 6985d4966232bfc7bd1a13b46fe3ccbdf46e62f0 (patch) | |
tree | dd2b5ea2aa46b246488c18dc4dd72159833f2489 /drivers/serial/serial_mvebu_a3700.c | |
parent | 35e3fca7e3ddaa2ae1fe9bd00b22be73e60a6042 (diff) | |
download | u-boot-6985d4966232bfc7bd1a13b46fe3ccbdf46e62f0.tar.xz |
serial: Add serial_mvebu_a3700 for Armada 3700 SoC
The Armada 3700's UART is a simple serial port. It has a 32 bytes
Tx FIFO and a 64 bytes Rx FIFO integrated. This patch adds support
for this UART including the DEBUG UART functions for very early
debug output.
Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Nadav Haklai <nadavh@marvell.com>
Cc: Kostya Porotchkin <kostap@marvell.com>
Cc: Wilson Ding <dingwei@marvell.com>
Cc: Victor Gu <xigu@marvell.com>
Cc: Hua Jing <jinghua@marvell.com>
Cc: Terry Zhou <bjzhou@marvell.com>
Cc: Hanna Hawa <hannah@marvell.com>
Cc: Haim Boot <hayim@marvell.com>
Diffstat (limited to 'drivers/serial/serial_mvebu_a3700.c')
-rw-r--r-- | drivers/serial/serial_mvebu_a3700.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c new file mode 100644 index 0000000..192e79a --- /dev/null +++ b/drivers/serial/serial_mvebu_a3700.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 Stefan Roese <sr@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <serial.h> +#include <asm/io.h> + +struct mvebu_platdata { + void __iomem *base; +}; + +/* + * Register offset + */ +#define UART_RX_REG 0x00 +#define UART_TX_REG 0x04 +#define UART_CTRL_REG 0x08 +#define UART_STATUS_REG 0x0c +#define UART_BAUD_REG 0x10 +#define UART_POSSR_REG 0x14 + +#define UART_STATUS_RX_RDY 0x10 +#define UART_STATUS_TXFIFO_FULL 0x800 + +#define UART_CTRL_RXFIFO_RESET 0x4000 +#define UART_CTRL_TXFIFO_RESET 0x8000 + +#define CONFIG_UART_BASE_CLOCK 25804800 + +static int mvebu_serial_putc(struct udevice *dev, const char ch) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL) + ; + + writel(ch, base + UART_TX_REG); + + return 0; +} + +static int mvebu_serial_getc(struct udevice *dev) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + while (!(readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY)) + ; + + return readl(base + UART_RX_REG) & 0xff; +} + +static int mvebu_serial_pending(struct udevice *dev, bool input) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + if (readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY) + return 1; + + return 0; +} + +static int mvebu_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + /* + * Calculate divider + * baudrate = clock / 16 / divider + */ + writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG); + + /* + * Set Programmable Oversampling Stack to 0, + * UART defaults to 16x scheme + */ + writel(0, base + UART_POSSR_REG); + + return 0; +} + +static int mvebu_serial_probe(struct udevice *dev) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + void __iomem *base = plat->base; + + /* reset FIFOs */ + writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET, + base + UART_CTRL_REG); + + /* No Parity, 1 Stop */ + writel(0, base + UART_CTRL_REG); + + return 0; +} + +static int mvebu_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct mvebu_platdata *plat = dev_get_platdata(dev); + + plat->base = dev_get_addr_ptr(dev); + + return 0; +} + +static const struct dm_serial_ops mvebu_serial_ops = { + .putc = mvebu_serial_putc, + .pending = mvebu_serial_pending, + .getc = mvebu_serial_getc, + .setbrg = mvebu_serial_setbrg, +}; + +static const struct udevice_id mvebu_serial_ids[] = { + { .compatible = "marvell,armada-3700-uart" }, + { } +}; + +U_BOOT_DRIVER(serial_mvebu) = { + .name = "serial_mvebu", + .id = UCLASS_SERIAL, + .of_match = mvebu_serial_ids, + .ofdata_to_platdata = mvebu_serial_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct mvebu_platdata), + .probe = mvebu_serial_probe, + .ops = &mvebu_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +#ifdef CONFIG_DEBUG_MVEBU_A3700_UART + +#include <debug_uart.h> + +static inline void _debug_uart_init(void) +{ + void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; + + /* reset FIFOs */ + writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET, + base + UART_CTRL_REG); + + /* No Parity, 1 Stop */ + writel(0, base + UART_CTRL_REG); + + /* + * Calculate divider + * baudrate = clock / 16 / divider + */ + writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG); + + /* + * Set Programmable Oversampling Stack to 0, + * UART defaults to 16x scheme + */ + writel(0, base + UART_POSSR_REG); +} + +static inline void _debug_uart_putc(int ch) +{ + void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; + + while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL) + ; + + writel(ch, base + UART_TX_REG); +} + +DEBUG_UART_FUNCS +#endif |