serial: Add serial_mvebu_a3700 for Armada 3700 SoC
authorStefan Roese <sr@denx.de>
Tue, 17 May 2016 14:36:00 +0000 (16:36 +0200)
committerStefan Roese <sr@denx.de>
Tue, 27 Sep 2016 15:29:52 +0000 (17:29 +0200)
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>
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/serial_mvebu_a3700.c [new file with mode: 0644]

index ab5df70bfc5e5ade49a7da5461ef260270846478..541cf2e512f0b9844e29f32fc7096f09fb3e647a 100644 (file)
@@ -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
index 6986d659ab05e0f7fa29c1bd29733205cfad4354..21b129206adc0f51b2a11259ca1f7399a6eabc1b 100644 (file)
@@ -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 (file)
index 0000000..192e79a
--- /dev/null
@@ -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