All of lore.kernel.org
 help / color / mirror / Atom feed
From: Amit Singh Tomar <amittomer25@gmail.com>
To: xen-devel@lists.xenproject.org
Cc: andre.przywara@arm.com, julien.grall@arm.com,
	sstabellini@kernel.org, Amit Singh Tomar <amittomer25@gmail.com>
Subject: [PATCH v2 2/3] xen/arm: Add MESON UART driver for Amlogic Meson SoCs
Date: Thu, 21 Mar 2019 15:55:34 +0530	[thread overview]
Message-ID: <1553163935-12862-2-git-send-email-amittomer25@gmail.com> (raw)
In-Reply-To: <1553163935-12862-1-git-send-email-amittomer25@gmail.com>

This patch adds driver for UART controller present on Amlogic Meson
SoCs and it has been tested on Nanopi K2 board based on S905 SoC.

Controller registers defination is taken from Linux 4.20.
https://github.com/torvalds/linux/blob/v4.20-rc1/drivers/tty/serial/meson_uart.c

Signed-off-by: Amit Singh Tomar <amittomer25@gmail.com>
---
Changes since v1:

        * Removed clrsetbits macro.
        * Fixed coding style issue.
        * Updated MAINTAINERS file.

Changes since RFC:

        * Removed S905 reference as other Amlogic SoCs
          have this uart controller.
        * Replaced meson_s905_read/write helper
          with clrsetbit and friends helper.
        * Followed proper UART reset sequence.
        * List all UART compatible strings same as Linux
          driver.
---
 xen/drivers/char/Kconfig      |   8 ++
 xen/drivers/char/Makefile     |   1 +
 xen/drivers/char/meson-uart.c | 276 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 285 insertions(+)
 create mode 100644 xen/drivers/char/meson-uart.c

diff --git a/xen/drivers/char/Kconfig b/xen/drivers/char/Kconfig
index b1f07f8..b572305 100644
--- a/xen/drivers/char/Kconfig
+++ b/xen/drivers/char/Kconfig
@@ -20,6 +20,14 @@ config HAS_MVEBU
 	  This selects the Marvell MVEBU UART. If you have a ARMADA 3700
 	  based board, say Y.
 
+config HAS_MESON
+	bool "Amlogic MESON UART driver"
+	default y
+	depends on ARM_64
+	help
+	  This selects the Amlogic MESON UART. If you have a Amlogic based
+	  board, say Y.
+
 config HAS_PL011
 	bool "ARM PL011 UART driver"
 	default y
diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile
index b68c330..7c646d7 100644
--- a/xen/drivers/char/Makefile
+++ b/xen/drivers/char/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_HAS_NS16550) += ns16550.o
 obj-$(CONFIG_HAS_CADENCE_UART) += cadence-uart.o
 obj-$(CONFIG_HAS_PL011) += pl011.o
 obj-$(CONFIG_HAS_EXYNOS4210) += exynos4210-uart.o
+obj-$(CONFIG_HAS_MESON) += meson-uart.o
 obj-$(CONFIG_HAS_MVEBU) += mvebu-uart.o
 obj-$(CONFIG_HAS_OMAP) += omap-uart.o
 obj-$(CONFIG_HAS_SCIF) += scif-uart.o
diff --git a/xen/drivers/char/meson-uart.c b/xen/drivers/char/meson-uart.c
new file mode 100644
index 0000000..c16c188
--- /dev/null
+++ b/xen/drivers/char/meson-uart.c
@@ -0,0 +1,276 @@
+/*
+ * xen/drivers/char/meson-uart.c
+ *
+ * Driver for Amlogic MESON UART
+ *
+ * Copyright (c) 2019, Amit Singh Tomar <amittomer25@gmail.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms and conditions of the GNU General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/irq.h>
+#include <xen/serial.h>
+#include <xen/vmap.h>
+#include <asm/io.h>
+
+/* Register offsets */
+#define AML_UART_WFIFO_REG              0x00
+#define AML_UART_RFIFO_REG              0x04
+#define AML_UART_CONTROL_REG            0x08
+#define AML_UART_STATUS_REG             0x0c
+#define AML_UART_MISC_REG               0x10
+
+/* UART_CONTROL bits */
+#define AML_UART_TX_RST                 BIT(22)
+#define AML_UART_RX_RST                 BIT(23)
+#define AML_UART_CLEAR_ERR              BIT(24)
+#define AML_UART_RX_INT_EN              BIT(27)
+#define AML_UART_TX_INT_EN              BIT(28)
+
+/* UART_STATUS bits */
+#define AML_UART_RX_FIFO_EMPTY          BIT(20)
+#define AML_UART_TX_FIFO_FULL           BIT(21)
+#define AML_UART_TX_FIFO_EMPTY          BIT(22)
+#define AML_UART_TX_CNT_MASK            GENMASK(14, 8)
+
+/* AML_UART_MISC bits */
+#define AML_UART_XMIT_IRQ(c)            (((c) & 0xff) << 8)
+#define AML_UART_RECV_IRQ(c)            ((c) & 0xff)
+
+#define TX_FIFO_SIZE                    64
+
+#define setbits(addr, set)              writel((readl(addr) | (set)), (addr))
+#define clrbits(addr, clear)            writel((readl(addr) & ~(clear)), (addr))
+
+static struct meson_uart {
+    unsigned int irq;
+    void __iomem *regs;
+    struct irqaction irqaction;
+    struct vuart_info vuart;
+} meson_com;
+
+static void meson_uart_interrupt(int irq, void *data,
+                                 struct cpu_user_regs *regs)
+{
+    struct serial_port *port = data;
+    struct meson_uart *uart = port->uart;
+    uint32_t st = readl(uart->regs + AML_UART_STATUS_REG);
+
+    if ( !(st & AML_UART_RX_FIFO_EMPTY) )
+        serial_rx_interrupt(port, regs);
+
+    if ( !(st & AML_UART_TX_FIFO_FULL) )
+        serial_tx_interrupt(port, regs);
+}
+
+static void __init meson_uart_init_preirq(struct serial_port *port)
+{
+    struct meson_uart *uart = port->uart;
+
+    /* Reset UART */
+    setbits(uart->regs + AML_UART_CONTROL_REG,
+            (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLEAR_ERR));
+
+    clrbits(uart->regs + AML_UART_CONTROL_REG,
+            (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLEAR_ERR));
+
+    /* Disable Rx/Tx interrupts */
+    clrbits(uart->regs + AML_UART_CONTROL_REG,
+               (AML_UART_RX_INT_EN | AML_UART_TX_INT_EN));
+}
+
+static void __init meson_uart_init_postirq(struct serial_port *port)
+{
+    struct meson_uart *uart = port->uart;
+
+    uart->irqaction.handler = meson_uart_interrupt;
+    uart->irqaction.name    = "meson_uart";
+    uart->irqaction.dev_id  = port;
+
+    if ( setup_irq(uart->irq, 0, &uart->irqaction) != 0 )
+    {
+        printk("Failed to allocated Meson UART IRQ %d\n", uart->irq);
+        return;
+    }
+
+    /*
+     * Configure Rx/Tx interrupts based on bytes in FIFO, these bits have
+     * taken from Linux driver
+     */
+    writel((AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(TX_FIFO_SIZE / 2)),
+           uart->regs + AML_UART_MISC_REG);
+
+    /* Make sure Rx/Tx interrupts are enabled now */
+    setbits(uart->regs + AML_UART_CONTROL_REG,
+            (AML_UART_RX_INT_EN | AML_UART_TX_INT_EN));
+}
+
+static void meson_uart_suspend(struct serial_port *port)
+{
+    BUG();
+}
+
+static void meson_uart_resume(struct serial_port *port)
+{
+    BUG();
+}
+
+static void meson_uart_putc(struct serial_port *port, char c)
+{
+    struct meson_uart *uart = port->uart;
+
+    writel(c, uart->regs + AML_UART_WFIFO_REG);
+}
+
+static int meson_uart_getc(struct serial_port *port, char *c)
+{
+    struct meson_uart *uart = port->uart;
+
+    if ( (readl(uart->regs + AML_UART_STATUS_REG) & AML_UART_RX_FIFO_EMPTY) )
+        return 0;
+
+    *c = readl(uart->regs + AML_UART_RFIFO_REG) & 0xff;
+
+    return 1;
+}
+
+static int __init meson_irq(struct serial_port *port)
+{
+    struct meson_uart *uart = port->uart;
+
+    return uart->irq;
+}
+
+static const struct vuart_info *meson_vuart_info(struct serial_port *port)
+{
+    struct meson_uart *uart = port->uart;
+
+    return &uart->vuart;
+}
+
+static void meson_uart_stop_tx(struct serial_port *port)
+{
+    struct meson_uart *uart = port->uart;
+
+    clrbits(uart->regs + AML_UART_CONTROL_REG, AML_UART_TX_INT_EN);
+}
+
+static void meson_uart_start_tx(struct serial_port *port)
+{
+    struct meson_uart *uart = port->uart;
+
+    setbits(uart->regs + AML_UART_CONTROL_REG, AML_UART_TX_INT_EN);
+}
+
+static int meson_uart_tx_ready(struct serial_port *port)
+{
+    struct meson_uart *uart = port->uart;
+    uint32_t reg;
+
+    reg = readl(uart->regs + AML_UART_STATUS_REG);
+
+    if ( reg & AML_UART_TX_FIFO_EMPTY )
+        return TX_FIFO_SIZE;
+    if ( reg & AML_UART_TX_FIFO_FULL )
+        return 0;
+
+    return (reg & AML_UART_TX_CNT_MASK) >> 8;
+}
+
+static struct uart_driver __read_mostly meson_uart_driver = {
+    .init_preirq  = meson_uart_init_preirq,
+    .init_postirq = meson_uart_init_postirq,
+    .endboot      = NULL,
+    .suspend      = meson_uart_suspend,
+    .resume       = meson_uart_resume,
+    .putc         = meson_uart_putc,
+    .getc         = meson_uart_getc,
+    .tx_ready     = meson_uart_tx_ready,
+    .stop_tx      = meson_uart_stop_tx,
+    .start_tx     = meson_uart_start_tx,
+    .irq          = meson_irq,
+    .vuart_info   = meson_vuart_info,
+};
+
+static int __init meson_uart_init(struct dt_device_node *dev, const void *data)
+{
+    const char *config = data;
+    struct meson_uart *uart;
+    int res;
+    u64 addr, size;
+
+    if ( strcmp(config, "") )
+        printk("WARNING: UART configuration is not supported\n");
+
+    uart = &meson_com;
+
+    res = dt_device_get_address(dev, 0, &addr, &size);
+    if ( res )
+    {
+        printk("meson: Unable to retrieve the base address of the UART\n");
+        return res;
+    }
+
+    res = platform_get_irq(dev, 0);
+    if ( res < 0 )
+    {
+        printk("meson: Unable to retrieve the IRQ\n");
+        return -EINVAL;
+    }
+
+    uart->irq  = res;
+
+    uart->regs = ioremap_nocache(addr, size);
+    if ( !uart->regs )
+    {
+        printk("meson: Unable to map the UART\n");
+        return -ENOMEM;
+    }
+
+    uart->vuart.base_addr = addr;
+    uart->vuart.size = size;
+    uart->vuart.data_off = AML_UART_WFIFO_REG;
+    uart->vuart.status_off = AML_UART_STATUS_REG;
+    uart->vuart.status = AML_UART_RX_FIFO_EMPTY | AML_UART_TX_FIFO_EMPTY;
+
+    /* Register with generic serial driver. */
+    serial_register_uart(SERHND_DTUART, &meson_uart_driver, uart);
+
+    dt_device_set_used_by(dev, DOMID_XEN);
+
+    return 0;
+}
+
+static const struct dt_device_match meson_dt_match[] __initconst =
+{
+    DT_MATCH_COMPATIBLE("amlogic,meson-uart"),
+    DT_MATCH_COMPATIBLE("amlogic,meson6-uart"),
+    DT_MATCH_COMPATIBLE("amlogic,meson8-uart"),
+    DT_MATCH_COMPATIBLE("amlogic,meson8b-uart"),
+    DT_MATCH_COMPATIBLE("amlogic,meson-gx-uart"),
+    { /* sentinel */ },
+};
+
+DT_DEVICE_START(meson, "Amlogic UART", DEVICE_SERIAL)
+    .dt_match = meson_dt_match,
+    .init = meson_uart_init,
+DT_DEVICE_END
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+*/
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

  reply	other threads:[~2019-03-21 10:26 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-21 10:25 [PATCH v2 1/3] xen/arm: Add Amlogic Meson SoCs earlyprintk support Amit Singh Tomar
2019-03-21 10:25 ` Amit Singh Tomar [this message]
2019-04-02 20:01   ` [PATCH v2 2/3] xen/arm: Add MESON UART driver for Amlogic Meson SoCs André Przywara
2019-04-09  9:39     ` Julien Grall
2019-04-09  9:39       ` [Xen-devel] " Julien Grall
2019-04-09 10:09       ` Amit Tomer
2019-04-09 10:09         ` [Xen-devel] " Amit Tomer
2019-04-09 10:14         ` Julien Grall
2019-04-09 10:14           ` [Xen-devel] " Julien Grall
2019-03-21 10:25 ` [PATCH v2 3/3] MAINTAINERS: add ARM meson serial driver Amit Singh Tomar
2019-04-02 20:01   ` André Przywara
2019-04-02 10:05 ` [PATCH v2 1/3] xen/arm: Add Amlogic Meson SoCs earlyprintk support Julien Grall
2019-04-02 20:00 ` André Przywara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1553163935-12862-2-git-send-email-amittomer25@gmail.com \
    --to=amittomer25@gmail.com \
    --cc=andre.przywara@arm.com \
    --cc=julien.grall@arm.com \
    --cc=sstabellini@kernel.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.