From 6985d4966232bfc7bd1a13b46fe3ccbdf46e62f0 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 17 May 2016 16:36:00 +0200 Subject: [PATCH] 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 Cc: Nadav Haklai Cc: Kostya Porotchkin Cc: Wilson Ding Cc: Victor Gu Cc: Hua Jing Cc: Terry Zhou Cc: Hanna Hawa Cc: Haim Boot --- drivers/serial/Kconfig | 15 +++ drivers/serial/Makefile | 1 + drivers/serial/serial_mvebu_a3700.c | 175 ++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 drivers/serial/serial_mvebu_a3700.c diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ab5df70bfc..541cf2e512 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -147,6 +147,13 @@ config DEBUG_UART_ARM_DCC This port is available at least on ARMv6, ARMv7, ARMv8 and XScale architectures. +config DEBUG_MVEBU_A3700_UART + bool "Marvell Armada 3700" + help + Select this to enable a debug UART using the serial_mvebu driver. You + will need to provide parameters to make this work. The driver will + be available until the real driver-model serial is running. + config DEBUG_UART_ZYNQ bool "Xilinx Zynq" help @@ -295,6 +302,13 @@ config FSL_LPUART Select this to enable a Low Power UART for Freescale VF610 and QorIQ Layerscape devices. +config MVEBU_A3700_UART + bool "UART support for Armada 3700" + default n + help + Choose this option to add support for UART driver on the Marvell + Armada 3700 SoC. The base address is configured via DT. + config PIC32_SERIAL bool "Support for Microchip PIC32 on-chip UART" depends on DM_SERIAL && MACH_PIC32 @@ -371,4 +385,5 @@ config MSM_SERIAL It should support all Qualcomm devices with UARTDM version 1.4, for example APQ8016 and MSM8916. Single baudrate is supported in current implementation (115200). + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 6986d659ab..21b129206a 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o obj-$(CONFIG_STM32X7_SERIAL) += serial_stm32x7.o obj-$(CONFIG_BCM283X_MU_SERIAL) += serial_bcm283x_mu.o obj-$(CONFIG_MSM_SERIAL) += serial_msm.o +obj-$(CONFIG_MVEBU_A3700_UART) += serial_mvebu_a3700.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c new file mode 100644 index 0000000000..192e79a3d3 --- /dev/null +++ b/drivers/serial/serial_mvebu_a3700.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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 + +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 -- 2.25.1