From: Pranavkumar Sawargaonkar <psawargaonkar@apm.com>
To: Ian Campbell <ian.campbell@citrix.com>
Cc: Anup Patel <anup.patel@linaro.org>,
patches@linaro.org, xen-devel@lists.xen.org,
julien.grall@citrix.com, stefano.stabellini@citrix.com,
Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
Subject: Re: [PATCH 3/4] xen: drivers: char: Add Device Tree Based NS16550 UART driver.
Date: Fri, 20 Sep 2013 19:25:30 +0530 [thread overview]
Message-ID: <CANFfpkSc+9hm09o1T_U3x8TUhNsnuXBorUNKAEOurAzRXPRVHw@mail.gmail.com> (raw)
In-Reply-To: <1379684438.8994.9.camel@hastur.hellion.org.uk>
Hi Ian,
On Fri, Sep 20, 2013 at 7:10 PM, Ian Campbell <ian.campbell@citrix.com> wrote:
> On Fri, 2013-09-20 at 15:22 +0530, Pranavkumar Sawargaonkar wrote:
>> This patch adds a device tree based driver for ns16550 UART.
>
> I posted patches last week (or the week before) to support the
> cubieboard2 and that series included a patch to enable the existing
> ns16550 driver to be used on DT as well. I think that is better than
> duplicating the majority of the driver just differ in a few probe
> routines.
>
> Does that approach work for you?
We will be happy to try that, when will it be merged in xen git repo any idea ?
>
>>
>> Signed-off-by: Anup Patel <anup.patel@linaro.org>
>> Signed-off-by: Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
>> ---
>> xen/drivers/char/Makefile | 1 +
>> xen/drivers/char/ns16550-dt.c | 302 ++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 303 insertions(+)
>> create mode 100644 xen/drivers/char/ns16550-dt.c
>>
>> diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile
>> index 911b788..7c22a1b 100644
>> --- a/xen/drivers/char/Makefile
>> +++ b/xen/drivers/char/Makefile
>> @@ -5,4 +5,5 @@ obj-$(HAS_EXYNOS4210) += exynos4210-uart.o
>> obj-$(HAS_OMAP) += omap-uart.o
>> obj-$(HAS_EHCI) += ehci-dbgp.o
>> obj-$(CONFIG_ARM) += dt-uart.o
>> +obj-$(HAS_NS16550_DT) += ns16550-dt.o
>> obj-y += serial.o
>> diff --git a/xen/drivers/char/ns16550-dt.c b/xen/drivers/char/ns16550-dt.c
>> new file mode 100644
>> index 0000000..74d2b57
>> --- /dev/null
>> +++ b/xen/drivers/char/ns16550-dt.c
>> @@ -0,0 +1,302 @@
>> +/*
>> + * xen/drivers/char/ns16550.c
>> + *
>> + * Driver for ns16550 UART based on DT bindigs.
>> + *
>> + * Pranavkumar Sawargaonkar <psawargaonkar@apm.com>
>> + * Anup Patel <apatel@apm.com>
>> + * Copyright (c) 2013 Applied Micro.
>> + *
>> + * 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/config.h>
>> +#include <xen/console.h>
>> +#include <xen/serial.h>
>> +#include <xen/init.h>
>> +#include <xen/irq.h>
>> +#include <asm/early_printk.h>
>> +#include <xen/device_tree.h>
>> +#include <xen/errno.h>
>> +#include <asm/device.h>
>> +#include <xen/mm.h>
>> +#include <xen/vmap.h>
>> +#include <xen/8250-uart.h>
>> +
>> +static struct ns16550 {
>> + unsigned int baud, clock_hz, data_bits, parity, stop_bits;
>> + unsigned int fifo_size;
>> + unsigned int reg_align; /* Regs alignement */
>> + struct dt_irq irq;
>> + void __iomem *regs;
>> + /* UART with IRQ line: interrupt-driven I/O. */
>> + struct irqaction irqaction;
>> + struct vuart_info vuart;
>> +} ns16550_com = {0};
>> +
>> +
>> +static char ns16550_read(struct ns16550 *uart, int reg)
>> +{
>> + return ioreadl((uart)->regs + (reg * (uart->reg_align)));
>> +}
>> +
>> +static void ns16550_write(struct ns16550 *uart, int reg, char c)
>> +{
>> + iowritel((uart)->regs + (reg * (uart->reg_align)), c);
>> +}
>> +
>> +static void ns16550_interrupt(int irq, void *data, struct cpu_user_regs *regs)
>> +{
>> + struct serial_port *port = data;
>> + struct ns16550 *uart = port->uart;
>> +
>> + while ( !(ns16550_read(uart, UART_IIR) & UART_IIR_NOINT) )
>> + {
>> + char lsr = ns16550_read(uart, UART_LSR);
>> + if ( lsr & UART_LSR_THRE )
>> + serial_tx_interrupt(port, regs);
>> + if ( lsr & UART_LSR_DR )
>> + serial_rx_interrupt(port, regs);
>> + }
>> +}
>> +
>> +static void ns16550_setup_preirq(struct ns16550 *uart)
>> +{
>> + unsigned char lcr;
>> + unsigned int divisor;
>> +
>> + lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
>> +
>> + /* No interrupts. */
>> + ns16550_write(uart, UART_IER, 0);
>> +
>> + /* Line control and baud-rate generator. */
>> + ns16550_write(uart, UART_LCR, lcr | UART_LCR_DLAB);
>> + if ( uart->baud != BAUD_AUTO )
>> + {
>> + /* Baud rate specified: program it into the divisor latch. */
>> + divisor = uart->clock_hz / (uart->baud << 4);
>> + ns16550_write(uart, UART_DLL, (char)divisor);
>> + ns16550_write(uart, UART_DLM, (char)(divisor >> 8));
>> + }
>> + else
>> + {
>> + /* Baud rate already set: read it out from the divisor latch. */
>> + divisor = ns16550_read(uart, UART_DLL);
>> + divisor |= ns16550_read(uart, UART_DLM) << 8;
>> + uart->baud = uart->clock_hz / (divisor << 4);
>> + }
>> + ns16550_write(uart, UART_LCR, lcr);
>> +
>> + /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
>> + ns16550_write(uart, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
>> +
>> + /* Enable and clear the FIFOs. Set a large trigger threshold. */
>> + ns16550_write(uart, UART_FCR,
>> + UART_FCR_ENABLE | UART_FCR_CLRX | UART_FCR_CLTX | UART_FCR_TRG14);
>> +}
>> +
>> +static void __init ns16550_init_preirq(struct serial_port *port)
>> +{
>> + struct ns16550 *uart = port->uart;
>> +
>> + ns16550_setup_preirq(uart);
>> +
>> + /* Check this really is a 16550+. Otherwise we have no FIFOs. */
>> + if ( ((ns16550_read(uart, UART_IIR) & 0xc0) == 0xc0) &&
>> + ((ns16550_read(uart, UART_FCR) & UART_FCR_TRG14) == UART_FCR_TRG14) )
>> + uart->fifo_size = 16;
>> +}
>> +
>> +static void ns16550_setup_postirq(struct ns16550 *uart)
>> +{
>> + if ( uart->irq.irq > 0 )
>> + {
>> + /* Master interrupt enable; also keep DTR/RTS asserted. */
>> + ns16550_write(uart,
>> + UART_MCR, UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS);
>> +
>> + /* Enable receive and transmit interrupts. */
>> + ns16550_write(uart, UART_IER, UART_IER_ERDAI | UART_IER_ETHREI);
>> + }
>> +}
>> +
>> +static void __init ns16550_init_postirq(struct serial_port *port)
>> +{
>> + struct ns16550 *uart = port->uart;
>> + int rc, bits;
>> +
>> + if ( uart->irq.irq < 0 )
>> + return;
>> +
>> + /* Calculate time to fill RX FIFO and/or empty TX FIFO for polling. */
>> + bits = uart->data_bits + uart->stop_bits + !!uart->parity;
>> +
>> + if ( uart->irq.irq > 0 )
>> + {
>> + uart->irqaction.handler = ns16550_interrupt;
>> + uart->irqaction.name = "ns16550";
>> + uart->irqaction.dev_id = port;
>> + if ( (rc = setup_dt_irq(&uart->irq, &uart->irqaction)) != 0 )
>> + printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq.irq);
>> + }
>> +
>> + ns16550_setup_postirq(uart);
>> +}
>> +
>> +static int ns16550_tx_ready(struct serial_port *port)
>> +{
>> + struct ns16550 *uart = port->uart;
>> +
>> + return ns16550_read(uart, UART_LSR) & UART_LSR_THRE ? uart->fifo_size : 0;
>> +}
>> +
>> +static void ns16550_putc(struct serial_port *port, char c)
>> +{
>> + struct ns16550 *uart = port->uart;
>> +
>> + ns16550_write(uart, UART_THR, c);
>> +}
>> +
>> +static int ns16550_getc(struct serial_port *port, char *pc)
>> +{
>> + struct ns16550 *uart = port->uart;
>> +
>> + if ( !(ns16550_read(uart, UART_LSR) & UART_LSR_DR) )
>> + return 0;
>> +
>> + *pc = ns16550_read(uart, UART_RBR);
>> + return 1;
>> +}
>> +
>> +static void ns16550_suspend(struct serial_port *port)
>> +{
>> + BUG(); // XXX
>> +}
>> +
>> +static void ns16550_resume(struct serial_port *port)
>> +{
>> + BUG(); // XXX
>> +}
>> +
>> +static int __init ns16550_irq(struct serial_port *port)
>> +{
>> + struct ns16550 *uart = port->uart;
>> + return ((uart->irq.irq > 0) ? uart->irq.irq : -1);
>> +}
>> +
>> +static const struct dt_irq __init *ns16550_dt_irq(struct serial_port *port)
>> +{
>> + struct ns16550 *uart = port->uart;
>> +
>> + return &uart->irq;
>> +}
>> +
>> +static const struct vuart_info *ns16550_vuart(struct serial_port *port)
>> +{
>> + struct ns16550 *uart = port->uart;
>> +
>> + return &uart->vuart;
>> +}
>> +
>> +static struct uart_driver __read_mostly ns16550_driver = {
>> + .init_preirq = ns16550_init_preirq,
>> + .init_postirq = ns16550_init_postirq,
>> + .endboot = NULL,
>> + .suspend = ns16550_suspend,
>> + .resume = ns16550_resume,
>> + .tx_ready = ns16550_tx_ready,
>> + .putc = ns16550_putc,
>> + .getc = ns16550_getc,
>> + .irq = ns16550_irq,
>> + .dt_irq_get = ns16550_dt_irq,
>> + .vuart_info = ns16550_vuart,
>> +};
>> +
>> +/* TODO: Parse UART config from the command line */
>> +static int __init ns16550_uart_init(struct dt_device_node *dev,
>> + const void *data)
>> +{
>> + const char *config = data;
>> + struct ns16550 *uart;
>> + int res;
>> + u64 addr, size;
>> +
>> + if ( strcmp(config, "") )
>> + {
>> + early_printk("WARNING: UART configuration is not supported\n");
>> + }
>> +
>> + uart = &ns16550_com;
>> +
>> + uart->clock_hz = 50000000;
>> + uart->baud = 115200;
>> + uart->data_bits = 8;
>> + uart->parity = UART_PARITY_NONE; /* FIXME */
>> + uart->stop_bits = 1;
>> + uart->reg_align = 4;
>> +
>> + res = dt_device_get_address(dev, 0, &addr, &size);
>> + if ( res )
>> + {
>> + early_printk("ns16550: Unable to retrieve the base"
>> + " address of the UART\n");
>> + return res;
>> + }
>> +
>> + uart->regs = ioremap_attr(addr, size, PAGE_HYPERVISOR_NOCACHE);
>> + if ( !uart->regs )
>> + {
>> + early_printk("ns16550: Unable to map the UART memory\n");
>> +
>> + return -ENOMEM;
>> + }
>> +
>> + res = dt_device_get_irq(dev, 0, &uart->irq);
>> + if ( res )
>> + {
>> + early_printk("ns16550: Unable to retrieve the IRQ\n");
>> + return res;
>> + }
>> +
>> + uart->vuart.base_addr = addr;
>> + uart->vuart.size = size;
>> + uart->vuart.data_off = (UART_THR * uart->reg_align) ;
>> + uart->vuart.status_off = (UART_LSR * uart->reg_align);
>> + uart->vuart.status = UART_LSR_THRE;
>> +
>> + /* Register with generic serial driver. */
>> + serial_register_uart(SERHND_DTUART, &ns16550_driver, uart);
>> +
>> + dt_device_set_used_by(dev, DOMID_XEN);
>> +
>> + return 0;
>> +}
>> +
>> +static const char const *ns16550_dt_compat[] __initdata =
>> +{
>> + "ns16550",
>> + NULL
>> +};
>> +
>> +DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
>> + .compatible = ns16550_dt_compat,
>> + .init = ns16550_uart_init,
>> +DT_DEVICE_END
>> +
>> +/*
>> + * Local variables:
>> + * mode: C
>> + * c-file-style: "BSD"
>> + * c-basic-offset: 4
>> + * indent-tabs-mode: nil
>> + * End:
>> + */
>
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
Thanks,
Pranav
next prev parent reply other threads:[~2013-09-20 13:55 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-20 9:52 [PATCH 0/4] Initial patches for ARM64 based APM X-Gene Storm Pranavkumar Sawargaonkar
2013-09-20 9:52 ` [PATCH 1/4] xen: arm64: Add Basic Platform support for " Pranavkumar Sawargaonkar
2013-09-20 12:09 ` Julien Grall
2013-09-20 13:28 ` Pranavkumar Sawargaonkar
2013-09-20 13:38 ` Ian Campbell
2013-09-20 13:59 ` Pranavkumar Sawargaonkar
2013-09-20 14:06 ` Ian Campbell
2013-09-20 13:41 ` Julien Grall
2013-09-20 9:52 ` [PATCH 2/4] xen: arm64: Add APM implementor id to processor implementers Pranavkumar Sawargaonkar
2013-09-20 12:10 ` Julien Grall
2013-09-20 9:52 ` [PATCH 3/4] xen: drivers: char: Add Device Tree Based NS16550 UART driver Pranavkumar Sawargaonkar
2013-09-20 13:40 ` Ian Campbell
2013-09-20 13:55 ` Pranavkumar Sawargaonkar [this message]
2013-09-20 14:08 ` Ian Campbell
2013-09-20 9:52 ` [PATCH 4/4] xen: arm: arm64: Enabling compilation of device tree based ns16550 UART Pranavkumar Sawargaonkar
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=CANFfpkSc+9hm09o1T_U3x8TUhNsnuXBorUNKAEOurAzRXPRVHw@mail.gmail.com \
--to=psawargaonkar@apm.com \
--cc=anup.patel@linaro.org \
--cc=ian.campbell@citrix.com \
--cc=julien.grall@citrix.com \
--cc=patches@linaro.org \
--cc=pranavkumar@linaro.org \
--cc=stefano.stabellini@citrix.com \
--cc=xen-devel@lists.xen.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).