[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/3] drivers: serial: add Qualcomm GENI-based serial driver


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Date: Fri, 29 Mar 2024 00:08:57 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=FENK0lL6QM9oXwz7y7lWBx5Y8WUk5Zaz3Nf7Qc0M+Gk=; b=kmHIVQ8cj3llW00z3Mx1zV+lc7FDvmeBzDmCskyTvYtPpX3L13Mau3y9YHZe1v/xJM6EfBfjDKjz6vkNgNf89FlfmizNYoCqGelOl6G4P+pogjatBZLYF4hyvR8T3wy+mRWNrsQ2KmnfPD74s3J01s8jr2m636sEUzoYG8ElwvD73VilCFPAsmqpycnhwwQo8DjIS/tnvk5vaxxT+WLzQ5sdXOuVNQSE7VOO13xWyDjzzRZx/QGYcG5m1xUX4mXULrqPAODOdw1KzEh8wXazmAVHG7QNjKgqPIw/5EIOdjHO4Wrg+fN/iEXXstdw+eUFvZ7lOY7Mr2hTeKyi/n3WQQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Np3SQsj2d+/ruyrD/CKSIbQIhqW9cd72UNQGcwY4efPfCB+fVfVumXDEEfDfsmiNKQ+cDGbD6sKXKcu54KVtgM0DRzOp+AVgeajsQ1tQYxFeOosPGYetjMnvKtr+9usm0eVAoGHkAW1ul+rbM9TXXKRj1XqxGCTqqPTRt8hAyetLjpIn7qAx9XgcdEyQeDwsbRflAZSuv7+Z+Wv5lWrC8XyGvUSYMSl+i81O32ob+CvsS1wWiNBJ1IrkeTn1migLVf7hbofbdYX8aDa+54eeRfmoxUPTU9Kcag0Uds9rUbS1POY/ZOC4xjthAnWqe31t1XASTV0uMN8KymJcrWys3Q==
  • Cc: Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, George Dunlap <george.dunlap@xxxxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Wei Liu <wl@xxxxxxx>
  • Delivery-date: Fri, 29 Mar 2024 00:09:30 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHagW1LewNbiHn0V0mBfSyHgZWL5Q==
  • Thread-topic: [PATCH 2/3] drivers: serial: add Qualcomm GENI-based serial driver

Generic Interface (GENI) is a newer interface for low speed interfaces
like UART, I2C or SPI. This patch adds the simple driver for the UART
instance of GENI. Code is based on similar drivers in U-Boot and Linux
kernel.

This driver implements only simple synchronous mode, because although
GENI supports FIFO mode, it needs to know number of
characters **before** starting TX transaction. This is a stark
contrast when compared to other UART peripherals, which allow adding
characters to a FIFO while TX operation is running.

The patch adds both normal UART driver and earlyprintk version.

Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
---
 xen/arch/arm/Kconfig.debug           |  19 +-
 xen/arch/arm/arm64/debug-qcom.inc    |  76 +++++++
 xen/arch/arm/include/asm/qcom-uart.h |  48 +++++
 xen/drivers/char/Kconfig             |   8 +
 xen/drivers/char/Makefile            |   1 +
 xen/drivers/char/qcom-uart.c         | 288 +++++++++++++++++++++++++++
 6 files changed, 439 insertions(+), 1 deletion(-)
 create mode 100644 xen/arch/arm/arm64/debug-qcom.inc
 create mode 100644 xen/arch/arm/include/asm/qcom-uart.h
 create mode 100644 xen/drivers/char/qcom-uart.c

diff --git a/xen/arch/arm/Kconfig.debug b/xen/arch/arm/Kconfig.debug
index eec860e88e..f6ab0bb30e 100644
--- a/xen/arch/arm/Kconfig.debug
+++ b/xen/arch/arm/Kconfig.debug
@@ -119,6 +119,19 @@ choice
                        selecting one of the platform specific options below if
                        you know the parameters for the port.
 
+                       This option is preferred over the platform specific
+                       options; the platform specific options are deprecated
+                       and will soon be removed.
+       config EARLY_UART_CHOICE_QCOM
+               select EARLY_UART_QCOM
+               bool "Early printk via Qualcomm debug UART"
+               help
+                       Say Y here if you wish the early printk to direct their
+                       output to a Qualcomm debug UART. You can use this 
option to
+                       provide the parameters for the debug UART rather than
+                       selecting one of the platform specific options below if
+                       you know the parameters for the port.
+
                        This option is preferred over the platform specific
                        options; the platform specific options are deprecated
                        and will soon be removed.
@@ -211,6 +224,9 @@ config EARLY_UART_PL011
 config EARLY_UART_SCIF
        select EARLY_PRINTK
        bool
+config EARLY_UART_QCOM
+       select EARLY_PRINTK
+       bool
 
 config EARLY_PRINTK
        bool
@@ -261,7 +277,7 @@ config EARLY_UART_PL011_MMIO32
          will be done using 32-bit only accessors.
 
 config EARLY_UART_INIT
-       depends on EARLY_UART_PL011 && EARLY_UART_PL011_BAUD_RATE != 0
+       depends on (EARLY_UART_PL011 && EARLY_UART_PL011_BAUD_RATE != 0) || 
EARLY_UART_QCOM
        def_bool y
 
 config EARLY_UART_8250_REG_SHIFT
@@ -308,3 +324,4 @@ config EARLY_PRINTK_INC
        default "debug-mvebu.inc" if EARLY_UART_MVEBU
        default "debug-pl011.inc" if EARLY_UART_PL011
        default "debug-scif.inc" if EARLY_UART_SCIF
+       default "debug-qcom.inc" if EARLY_UART_QCOM
diff --git a/xen/arch/arm/arm64/debug-qcom.inc 
b/xen/arch/arm/arm64/debug-qcom.inc
new file mode 100644
index 0000000000..130d08d6e9
--- /dev/null
+++ b/xen/arch/arm/arm64/debug-qcom.inc
@@ -0,0 +1,76 @@
+/*
+ * xen/arch/arm/arm64/debug-qcom.inc
+ *
+ * Qualcomm debug UART specific debug code
+ *
+ * Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
+ * Copyright (C) 2024, EPAM Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <asm/qcom-uart.h>
+
+.macro early_uart_init xb c
+        mov   w\c, #M_GENI_CMD_ABORT
+        str   w\c, [\xb, #SE_GENI_M_CMD_CTRL_REG]
+1:
+        ldr   w\c, [\xb, #SE_GENI_M_IRQ_STATUS]   /* Load IRQ status */
+        tst   w\c, #M_CMD_ABORT_EN         /* Check TX_FIFI_WATERMARK_EN bit */
+        beq   1b                          /* Wait for the UART to be ready */
+        mov   w\c, #M_CMD_ABORT_EN
+        orr   w\c, w\c, #M_CMD_DONE_EN
+        str   w\c, [\xb, #SE_GENI_M_IRQ_CLEAR]
+
+        mov   w\c, #1
+        str   w\c, [\xb, #SE_UART_TX_TRANS_LEN]         /* write len */
+
+        mov   w\c, #(UART_START_TX << M_OPCODE_SHFT)    /* Prepare cmd  */
+        str   w\c, [\xb, #SE_GENI_M_CMD0]               /* write cmd */
+.endm
+/*
+ * wait for UART to be ready to transmit
+ * xb: register which contains the UART base address
+ * c: scratch register
+ */
+.macro early_uart_ready xb c
+1:
+        ldr   w\c, [\xb, #SE_GENI_M_IRQ_STATUS] /* Load IRQ status */
+        tst   w\c, #M_TX_FIFO_WATERMARK_EN  /* Check TX_FIFI_WATERMARK_EN bit 
*/
+        beq    1b                           /* Wait for the UART to be ready */
+.endm
+
+/*
+ * UART transmit character
+ * xb: register which contains the UART base address
+ * wt: register which contains the character to transmit
+ */
+.macro early_uart_transmit xb wt
+        str   \wt, [\xb, #SE_GENI_TX_FIFOn]             /* Put char to FIFO */
+        mov   \wt, #M_TX_FIFO_WATERMARK_EN              /* Prepare to FIFO */
+        str   \wt, [\xb, #SE_GENI_M_IRQ_CLEAR]          /* Kick FIFO */
+95:
+        ldr   \wt, [\xb, #SE_GENI_M_IRQ_STATUS]         /* Load IRQ status */
+        tst   \wt, #M_CMD_DONE_EN           /* Check TX_FIFO_WATERMARK_EN bit 
*/
+        beq   95b                           /* Wait for the UART to be ready */
+        mov   \wt, #M_CMD_DONE_EN
+        str   \wt, [\xb, #SE_GENI_M_IRQ_CLEAR]
+
+        mov   \wt, #(UART_START_TX << M_OPCODE_SHFT)    /* Prepare next cmd */
+        str   \wt, [\xb, #SE_GENI_M_CMD0]               /* write cmd */
+.endm
+
+/*
+ * Local variables:
+ * mode: ASM
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/include/asm/qcom-uart.h 
b/xen/arch/arm/include/asm/qcom-uart.h
new file mode 100644
index 0000000000..dc9579374c
--- /dev/null
+++ b/xen/arch/arm/include/asm/qcom-uart.h
@@ -0,0 +1,48 @@
+/*
+ * xen/include/asm-arm/qcom-uart.h
+ *
+ * Common constant definition between early printk and the UART driver
+ * for the Qualcomm debug UART
+ *
+ * Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
+ * Copyright (C) 2024, EPAM Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARM_QCOM_UART_H
+#define __ASM_ARM_QCOM_UART_H
+
+#define SE_UART_TX_TRANS_LEN            0x270
+#define SE_GENI_M_CMD0                  0x600
+#define   UART_START_TX                 0x1
+#define   M_OPCODE_SHFT                 27
+
+#define SE_GENI_M_CMD_CTRL_REG          0x604
+#define   M_GENI_CMD_ABORT              BIT(1, U)
+#define SE_GENI_M_IRQ_STATUS            0x610
+#define   M_CMD_DONE_EN                 BIT(0, U)
+#define   M_CMD_ABORT_EN                BIT(5, U)
+#define   M_TX_FIFO_WATERMARK_EN        BIT(30, U)
+#define SE_GENI_M_IRQ_CLEAR             0x618
+#define SE_GENI_TX_FIFOn                0x700
+#define SE_GENI_TX_WATERMARK_REG        0x80c
+
+#endif /* __ASM_ARM_QCOM_UART_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/drivers/char/Kconfig b/xen/drivers/char/Kconfig
index e18ec3788c..52c3934d06 100644
--- a/xen/drivers/char/Kconfig
+++ b/xen/drivers/char/Kconfig
@@ -68,6 +68,14 @@ config HAS_SCIF
          This selects the SuperH SCI(F) UART. If you have a SuperH based board,
          or Renesas R-Car Gen 2/3 based board say Y.
 
+config HAS_QCOM_UART
+       bool "Qualcomm GENI UART driver"
+       default y
+       depends on ARM
+       help
+         This selects the Qualcomm GENI-based UART driver. If you
+         have a Qualcomm-based board board say Y here.
+
 config HAS_EHCI
        bool
        depends on X86
diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile
index e7e374775d..698ad0578c 100644
--- a/xen/drivers/char/Makefile
+++ b/xen/drivers/char/Makefile
@@ -7,6 +7,7 @@ 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
+obj-$(CONFIG_HAS_QCOM_UART) += qcom-uart.o
 obj-$(CONFIG_HAS_EHCI) += ehci-dbgp.o
 obj-$(CONFIG_XHCI) += xhci-dbc.o
 obj-$(CONFIG_HAS_IMX_LPUART) += imx-lpuart.o
diff --git a/xen/drivers/char/qcom-uart.c b/xen/drivers/char/qcom-uart.c
new file mode 100644
index 0000000000..2614051ca0
--- /dev/null
+++ b/xen/drivers/char/qcom-uart.c
@@ -0,0 +1,288 @@
+/*
+ * xen/drivers/char/qcom-uart.c
+ *
+ * Driver for Qualcomm GENI-based UART interface
+ *
+ * Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
+ *
+ * Copyright (C) EPAM Systems 2024
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <xen/console.h>
+#include <xen/const.h>
+#include <xen/errno.h>
+#include <xen/serial.h>
+#include <xen/init.h>
+#include <xen/irq.h>
+#include <xen/mm.h>
+#include <xen/delay.h>
+#include <asm/device.h>
+#include <asm/qcom-uart.h>
+#include <asm/io.h>
+
+#define GENI_FORCE_DEFAULT_REG          0x20
+#define   FORCE_DEFAULT                 BIT(0, U)
+#define   DEF_TX_WM                     2
+#define SE_GENI_TX_PACKING_CFG0         0x260
+#define SE_GENI_TX_PACKING_CFG1         0x264
+#define SE_GENI_RX_PACKING_CFG0         0x284
+#define SE_GENI_RX_PACKING_CFG1         0x288
+#define SE_GENI_M_IRQ_EN                0x614
+#define   M_SEC_IRQ_EN                  BIT(31, U)
+#define   M_RX_FIFO_WATERMARK_EN        BIT(26, U)
+#define   M_RX_FIFO_LAST_EN             BIT(27, U)
+#define SE_GENI_S_CMD0                  0x630
+#define   UART_START_READ               0x1
+#define   S_OPCODE_SHFT                 27
+#define SE_GENI_S_CMD_CTRL_REG          0x634
+#define   S_GENI_CMD_ABORT              BIT(1, U)
+#define SE_GENI_S_IRQ_STATUS            0x640
+#define SE_GENI_S_IRQ_EN                0x644
+#define   S_RX_FIFO_LAST_EN             BIT(27, U)
+#define   S_RX_FIFO_WATERMARK_EN        BIT(26, U)
+#define   S_CMD_ABORT_EN                BIT(5, U)
+#define   S_CMD_DONE_EN                 BIT(0, U)
+#define SE_GENI_S_IRQ_CLEAR             0x648
+#define SE_GENI_RX_FIFOn                0x780
+#define SE_GENI_TX_FIFO_STATUS          0x800
+#define   TX_FIFO_WC                    GENMASK(27, 0)
+#define SE_GENI_RX_FIFO_STATUS          0x804
+#define   RX_LAST                       BIT(31, U)
+#define   RX_LAST_BYTE_VALID_MSK        GENMASK(30, 28)
+#define   RX_LAST_BYTE_VALID_SHFT       28
+#define   RX_FIFO_WC_MSK                GENMASK(24, 0)
+#define SE_GENI_TX_WATERMARK_REG        0x80c
+
+static struct qcom_uart {
+    unsigned int irq;
+    char __iomem *regs;
+    struct irqaction irqaction;
+} qcom_com = {0};
+
+static bool qcom_uart_poll_bit(void *addr, uint32_t mask, bool set)
+{
+    unsigned long timeout_us = 20000;
+    uint32_t reg;
+
+    while ( timeout_us ) {
+        reg = readl(addr);
+        if ( (bool)(reg & mask) == set )
+            return true;
+        udelay(10);
+        timeout_us -= 10;
+    }
+
+    return false;
+}
+
+static void __init qcom_uart_init_preirq(struct serial_port *port)
+{
+    struct qcom_uart *uart = port->uart;
+
+    /* Stop anything in TX that earlyprintk configured and clear all errors */
+    writel(M_GENI_CMD_ABORT, uart->regs + SE_GENI_M_CMD_CTRL_REG);
+    qcom_uart_poll_bit(uart->regs + SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN,
+                       true);
+    writel(M_CMD_ABORT_EN, uart->regs + SE_GENI_M_IRQ_CLEAR);
+
+    /*
+     * Configure FIFO length: 1 byte per FIFO entry. This is terribly
+     * ineffective, as it is possible to cram 4 bytes per FIFO word,
+     * like Linux does. But using one byte per FIFO entry makes this
+     * driver much simpler.
+     */
+    writel(0xf, uart->regs + SE_GENI_TX_PACKING_CFG0);
+    writel(0x0, uart->regs + SE_GENI_TX_PACKING_CFG1);
+    writel(0xf, uart->regs + SE_GENI_RX_PACKING_CFG0);
+    writel(0x0, uart->regs + SE_GENI_RX_PACKING_CFG1);
+
+    /* Reset RX state machine */
+    writel(S_GENI_CMD_ABORT, uart->regs + SE_GENI_S_CMD_CTRL_REG);
+    qcom_uart_poll_bit(uart->regs + SE_GENI_S_CMD_CTRL_REG,
+                       S_GENI_CMD_ABORT, false);
+    writel(S_CMD_DONE_EN | S_CMD_ABORT_EN, uart->regs + SE_GENI_S_IRQ_CLEAR);
+    writel(FORCE_DEFAULT, uart->regs + GENI_FORCE_DEFAULT_REG);
+}
+
+static void qcom_uart_interrupt(int irq, void *data, struct cpu_user_regs 
*regs)
+{
+    struct serial_port *port = data;
+    struct qcom_uart *uart = port->uart;
+    uint32_t m_irq_status, s_irq_status;
+
+    m_irq_status = readl(uart->regs + SE_GENI_M_IRQ_STATUS);
+    s_irq_status = readl(uart->regs + SE_GENI_S_IRQ_STATUS);
+    writel(m_irq_status, uart->regs + SE_GENI_M_IRQ_CLEAR);
+    writel(s_irq_status, uart->regs + SE_GENI_S_IRQ_CLEAR);
+
+    if ( s_irq_status & (S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN) )
+        serial_rx_interrupt(port, regs);
+}
+
+static void __init qcom_uart_init_postirq(struct serial_port *port)
+{
+    struct qcom_uart *uart = port->uart;
+    int rc;
+    uint32_t val;
+
+    uart->irqaction.handler = qcom_uart_interrupt;
+    uart->irqaction.name    = "qcom_uart";
+    uart->irqaction.dev_id  = port;
+
+    if ( (rc = setup_irq(uart->irq, 0, &uart->irqaction)) != 0 )
+        dprintk(XENLOG_ERR, "Failed to allocated qcom_uart IRQ %d\n",
+                uart->irq);
+
+    /* Enable TX/RX and Error Interrupts  */
+    writel(S_GENI_CMD_ABORT, uart->regs + SE_GENI_S_CMD_CTRL_REG);
+    qcom_uart_poll_bit(uart->regs + SE_GENI_S_CMD_CTRL_REG,
+                       S_GENI_CMD_ABORT, false);
+    writel(S_CMD_DONE_EN | S_CMD_ABORT_EN, uart->regs + SE_GENI_S_IRQ_CLEAR);
+    writel(FORCE_DEFAULT, uart->regs + GENI_FORCE_DEFAULT_REG);
+
+    val = readl(uart->regs + SE_GENI_S_IRQ_EN);
+    val = S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
+    writel(val, uart->regs + SE_GENI_S_IRQ_EN);
+
+    val = readl(uart->regs + SE_GENI_M_IRQ_EN);
+    val = M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
+    writel(val, uart->regs + SE_GENI_M_IRQ_EN);
+
+    /* Send RX command */
+    writel(UART_START_READ << S_OPCODE_SHFT, uart->regs + SE_GENI_S_CMD0);
+    qcom_uart_poll_bit(uart->regs + SE_GENI_M_IRQ_STATUS, M_SEC_IRQ_EN,
+                       true);
+}
+
+static void qcom_uart_putc(struct serial_port *port, char c)
+{
+    struct qcom_uart *uart = port->uart;
+    uint32_t irq_clear = M_CMD_DONE_EN;
+    uint32_t m_cmd;
+    bool done;
+
+    /* Setup TX */
+    writel(1, uart->regs + SE_UART_TX_TRANS_LEN);
+
+    writel(DEF_TX_WM, uart->regs + SE_GENI_TX_WATERMARK_REG);
+
+    m_cmd = UART_START_TX << M_OPCODE_SHFT;
+    writel(m_cmd, uart->regs + SE_GENI_M_CMD0);
+
+    qcom_uart_poll_bit(uart->regs + SE_GENI_M_IRQ_STATUS,
+                       M_TX_FIFO_WATERMARK_EN, true);
+
+    writel(c, uart->regs + SE_GENI_TX_FIFOn);
+    writel(M_TX_FIFO_WATERMARK_EN, uart->regs + SE_GENI_M_IRQ_CLEAR);
+
+    /* Check for TX done */
+    done = qcom_uart_poll_bit(uart->regs + SE_GENI_M_IRQ_STATUS, M_CMD_DONE_EN,
+                              true);
+    if ( !done )
+    {
+        writel(M_GENI_CMD_ABORT, uart->regs + SE_GENI_M_CMD_CTRL_REG);
+        irq_clear |= M_CMD_ABORT_EN;
+        qcom_uart_poll_bit(uart->regs + SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN,
+                           true);
+
+    }
+    writel(irq_clear, uart->regs + SE_GENI_M_IRQ_CLEAR);
+}
+
+static int qcom_uart_getc(struct serial_port *port, char *pc)
+{
+    struct qcom_uart *uart = port->uart;
+
+    if ( !readl(uart->regs + SE_GENI_RX_FIFO_STATUS) )
+        return 0;
+
+    *pc = readl(uart->regs + SE_GENI_RX_FIFOn) & 0xFF;
+
+    writel(UART_START_READ << S_OPCODE_SHFT, uart->regs + SE_GENI_S_CMD0);
+    qcom_uart_poll_bit(uart->regs + SE_GENI_M_IRQ_STATUS, M_SEC_IRQ_EN,
+                       true);
+
+    return 1;
+
+}
+
+static struct uart_driver __read_mostly qcom_uart_driver = {
+    .init_preirq  = qcom_uart_init_preirq,
+    .init_postirq = qcom_uart_init_postirq,
+    .putc         = qcom_uart_putc,
+    .getc         = qcom_uart_getc,
+};
+
+static const struct dt_device_match qcom_uart_dt_match[] __initconst =
+{
+    { .compatible = "qcom,geni-debug-uart"},
+    { /* sentinel */ },
+};
+
+static int __init qcom_uart_init(struct dt_device_node *dev,
+                                 const void *data)
+{
+    const char *config = data;
+    struct qcom_uart *uart;
+    int res;
+    paddr_t addr, size;
+
+    if ( strcmp(config, "") )
+        printk("WARNING: UART configuration is not supported\n");
+
+    uart = &qcom_com;
+
+    res = dt_device_get_paddr(dev, 0, &addr, &size);
+    if ( res )
+    {
+        printk("qcom-uart: Unable to retrieve the base"
+               " address of the UART\n");
+        return res;
+    }
+
+    res = platform_get_irq(dev, 0);
+    if ( res < 0 )
+    {
+        printk("qcom-uart: Unable to retrieve the IRQ\n");
+        return res;
+    }
+    uart->irq = res;
+
+    uart->regs = ioremap_nocache(addr, size);
+    if ( !uart->regs )
+    {
+        printk("qcom-uart: Unable to map the UART memory\n");
+        return -ENOMEM;
+    }
+
+    /* Register with generic serial driver */
+    serial_register_uart(SERHND_DTUART, &qcom_uart_driver, uart);
+
+    dt_device_set_used_by(dev, DOMID_XEN);
+
+    return 0;
+}
+
+DT_DEVICE_START(qcom_uart, "QCOM UART", DEVICE_SERIAL)
+    .dt_match = qcom_uart_dt_match,
+    .init = qcom_uart_init,
+DT_DEVICE_END
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.43.0



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.