All of lore.kernel.org
 help / color / mirror / Atom feed
From: Julien Grall <julien.grall@linaro.org>
To: Oleksandr Tyshchenko <oleksandr.tyshchenko@globallogic.com>,
	xen-devel@lists.xen.org
Cc: tim@xen.org, ian.campbell@citrix.com, stefano.stabellini@eu.citrix.com
Subject: Re: [PATCH v3 2/3] xen/arm: Add new driver for R-Car Gen2 UART
Date: Fri, 23 Jan 2015 22:40:31 +0000	[thread overview]
Message-ID: <54C2CDDF.7030705@linaro.org> (raw)
In-Reply-To: <1422027220-31423-3-git-send-email-oleksandr.tyshchenko@globallogic.com>

Hi Oleksandr,

On 23/01/2015 15:33, Oleksandr Tyshchenko wrote:
> Signed-off-by: Oleksandr Tyshchenko <oleksandr.tyshchenko@globallogic.com>
> Signed-off-by: Iurii Konovalenko <iurii.konovalenko@globallogic.com>
> CC: Julien Grall <julien.grall@linaro.org>

Reviewed-by: Julien Grall <julien.grall@linaro.org>

Regards,

> ---
>   config/arm32.mk               |   1 +
>   xen/drivers/char/Makefile     |   1 +
>   xen/drivers/char/rcar2-uart.c | 366 ++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 368 insertions(+)
>   create mode 100644 xen/drivers/char/rcar2-uart.c
>
> diff --git a/config/arm32.mk b/config/arm32.mk
> index 4f83a63..6ee5173 100644
> --- a/config/arm32.mk
> +++ b/config/arm32.mk
> @@ -12,6 +12,7 @@ CFLAGS += -marm
>   HAS_PL011 := y
>   HAS_EXYNOS4210 := y
>   HAS_OMAP := y
> +HAS_RCAR2 := y
>   HAS_NS16550 := y
>
>   # Use only if calling $(LD) directly.
> diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile
> index 911b788..64428b7 100644
> --- a/xen/drivers/char/Makefile
> +++ b/xen/drivers/char/Makefile
> @@ -3,6 +3,7 @@ obj-$(HAS_NS16550) += ns16550.o
>   obj-$(HAS_PL011) += pl011.o
>   obj-$(HAS_EXYNOS4210) += exynos4210-uart.o
>   obj-$(HAS_OMAP) += omap-uart.o
> +obj-$(HAS_RCAR2) += rcar2-uart.o
>   obj-$(HAS_EHCI) += ehci-dbgp.o
>   obj-$(CONFIG_ARM) += dt-uart.o
>   obj-y += serial.o
> diff --git a/xen/drivers/char/rcar2-uart.c b/xen/drivers/char/rcar2-uart.c
> new file mode 100644
> index 0000000..7ace6ad
> --- /dev/null
> +++ b/xen/drivers/char/rcar2-uart.c
> @@ -0,0 +1,366 @@
> +/*
> + * xen/drivers/char/rcar2-uart.c
> + *
> + * Driver for R-Car Gen2 UART.
> + *
> + * Oleksandr Tyshchenko <oleksandr.tyshchenko@globallogic.com>
> + * Copyright (C) 2014, Globallogic.
> + *
> + * 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/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/rcar2-uart.h>
> +#include <asm/io.h>
> +
> +#define PARITY_NONE    0
> +#define PARITY_EVEN    1
> +#define PARITY_ODD     2
> +
> +#define rcar2_readb(uart, off)          readb((uart)->regs + (off))
> +#define rcar2_writeb(uart, off, val)    writeb((val), (uart)->regs + (off))
> +
> +#define rcar2_readw(uart, off)          readw((uart)->regs + (off))
> +#define rcar2_writew(uart, off, val)    writew((val), (uart)->regs + (off))
> +
> +static struct rcar2_uart {
> +    unsigned int baud, clock_hz, data_bits, parity, stop_bits;
> +    unsigned int irq;
> +    char __iomem *regs;
> +    struct irqaction irqaction;
> +    struct vuart_info vuart;
> +} rcar2_com = {0};
> +
> +static void rcar2_uart_interrupt(int irq, void *data, struct cpu_user_regs *regs)
> +{
> +    struct serial_port *port = data;
> +    struct rcar2_uart *uart = port->uart;
> +    uint16_t status, ctrl;
> +
> +    ctrl = rcar2_readw(uart, SCIF_SCSCR);
> +    status = rcar2_readw(uart, SCIF_SCFSR) & ~SCFSR_TEND;
> +    /* Ignore next flag if TX Interrupt is disabled */
> +    if ( !(ctrl & SCSCR_TIE) )
> +        status &= ~SCFSR_TDFE;
> +
> +    while ( status != 0 )
> +    {
> +        /* TX Interrupt */
> +        if ( status & SCFSR_TDFE )
> +            serial_tx_interrupt(port, regs);
> +
> +        /* RX Interrupt */
> +        if ( status & (SCFSR_RDF | SCFSR_DR) )
> +            serial_rx_interrupt(port, regs);
> +
> +        /* Error Interrupt */
> +        if ( status & SCIF_ERRORS )
> +            rcar2_writew(uart, SCIF_SCFSR, ~SCIF_ERRORS);
> +        if ( rcar2_readw(uart, SCIF_SCLSR) & SCLSR_ORER )
> +            rcar2_writew(uart, SCIF_SCLSR, 0);
> +
> +        ctrl = rcar2_readw(uart, SCIF_SCSCR);
> +        status = rcar2_readw(uart, SCIF_SCFSR) & ~SCFSR_TEND;
> +        /* Ignore next flag if TX Interrupt is disabled */
> +        if ( !(ctrl & SCSCR_TIE) )
> +            status &= ~SCFSR_TDFE;
> +    }
> +}
> +
> +static void __init rcar2_uart_init_preirq(struct serial_port *port)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +    unsigned int divisor;
> +    uint16_t val;
> +
> +    /*
> +     * Wait until last bit has been transmitted. This is needed for a smooth
> +     * transition when we come from early printk
> +     */
> +    while ( !(rcar2_readw(uart, SCIF_SCFSR) & SCFSR_TEND) );
> +
> +    /* Disable TX/RX parts and all interrupts */
> +    rcar2_writew(uart, SCIF_SCSCR, 0);
> +
> +    /* Reset TX/RX FIFOs */
> +    rcar2_writew(uart, SCIF_SCFCR, SCFCR_RFRST | SCFCR_TFRST);
> +
> +    /* Clear all errors and flags */
> +    rcar2_readw(uart, SCIF_SCFSR);
> +    rcar2_writew(uart, SCIF_SCFSR, 0);
> +    rcar2_readw(uart, SCIF_SCLSR);
> +    rcar2_writew(uart, SCIF_SCLSR, 0);
> +
> +    /* Select Baud rate generator output as a clock source */
> +    rcar2_writew(uart, SCIF_SCSCR, SCSCR_CKE10);
> +
> +    /* Setup protocol format and Baud rate, select Asynchronous mode */
> +    val = 0;
> +    ASSERT( uart->data_bits >= 7 && uart->data_bits <= 8 );
> +    if ( uart->data_bits == 7 )
> +        val |= SCSMR_CHR;
> +    else
> +        val &= ~SCSMR_CHR;
> +
> +    ASSERT( uart->stop_bits >= 1 && uart->stop_bits <= 2 );
> +    if ( uart->stop_bits == 2 )
> +        val |= SCSMR_STOP;
> +    else
> +        val &= ~SCSMR_STOP;
> +
> +    ASSERT( uart->parity >= PARITY_NONE && uart->parity <= PARITY_ODD );
> +    switch ( uart->parity )
> +    {
> +    case PARITY_NONE:
> +        val &= ~SCSMR_PE;
> +        break;
> +
> +    case PARITY_EVEN:
> +        val |= SCSMR_PE;
> +        break;
> +
> +    case PARITY_ODD:
> +        val |= SCSMR_PE | SCSMR_ODD;
> +        break;
> +    }
> +    rcar2_writew(uart, SCIF_SCSMR, val);
> +
> +    ASSERT( uart->clock_hz > 0 );
> +    if ( uart->baud != BAUD_AUTO )
> +    {
> +        /* Setup desired Baud rate */
> +        divisor = uart->clock_hz / (uart->baud << 4);
> +        ASSERT( divisor >= 1 && divisor <= (uint16_t)UINT_MAX );
> +        rcar2_writew(uart, SCIF_DL, (uint16_t)divisor);
> +        /* Selects the frequency divided clock (SC_CLK external input) */
> +        rcar2_writew(uart, SCIF_CKS, 0);
> +        udelay(1000000 / uart->baud + 1);
> +    }
> +    else
> +    {
> +        /* Read current Baud rate */
> +        divisor = rcar2_readw(uart, SCIF_DL);
> +        ASSERT( divisor >= 1 && divisor <= (uint16_t)UINT_MAX );
> +        uart->baud = uart->clock_hz / (divisor << 4);
> +    }
> +
> +    /* Setup trigger level for TX/RX FIFOs */
> +    rcar2_writew(uart, SCIF_SCFCR, SCFCR_RTRG11 | SCFCR_TTRG11);
> +
> +    /* Enable TX/RX parts */
> +    rcar2_writew(uart, SCIF_SCSCR, rcar2_readw(uart, SCIF_SCSCR) |
> +                 SCSCR_TE | SCSCR_RE);
> +}
> +
> +static void __init rcar2_uart_init_postirq(struct serial_port *port)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +    int rc;
> +
> +    uart->irqaction.handler = rcar2_uart_interrupt;
> +    uart->irqaction.name    = "rcar2_uart";
> +    uart->irqaction.dev_id  = port;
> +
> +    if ( (rc = setup_irq(uart->irq, 0, &uart->irqaction)) != 0 )
> +        dprintk(XENLOG_ERR, "Failed to allocated rcar2_uart IRQ %d\n",
> +                uart->irq);
> +
> +    /* Clear all errors */
> +    if ( rcar2_readw(uart, SCIF_SCFSR) & SCIF_ERRORS )
> +        rcar2_writew(uart, SCIF_SCFSR, ~SCIF_ERRORS);
> +    if ( rcar2_readw(uart, SCIF_SCLSR) & SCLSR_ORER )
> +        rcar2_writew(uart, SCIF_SCLSR, 0);
> +
> +    /* Enable TX/RX and Error Interrupts  */
> +    rcar2_writew(uart, SCIF_SCSCR, rcar2_readw(uart, SCIF_SCSCR) |
> +                 SCSCR_TIE | SCSCR_RIE | SCSCR_REIE);
> +}
> +
> +static void rcar2_uart_suspend(struct serial_port *port)
> +{
> +    BUG();
> +}
> +
> +static void rcar2_uart_resume(struct serial_port *port)
> +{
> +    BUG();
> +}
> +
> +static int rcar2_uart_tx_ready(struct serial_port *port)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +    uint16_t cnt;
> +
> +    /* Check for empty space in TX FIFO */
> +    if ( !(rcar2_readw(uart, SCIF_SCFSR) & SCFSR_TDFE) )
> +        return 0;
> +
> +     /* Check number of data bytes stored in TX FIFO */
> +    cnt = rcar2_readw(uart, SCIF_SCFDR) >> 8;
> +    ASSERT( cnt >= 0 && cnt <= SCIF_FIFO_MAX_SIZE );
> +
> +    return (SCIF_FIFO_MAX_SIZE - cnt);
> +}
> +
> +static void rcar2_uart_putc(struct serial_port *port, char c)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +
> +    rcar2_writeb(uart, SCIF_SCFTDR, c);
> +    /* Clear required TX flags */
> +    rcar2_writew(uart, SCIF_SCFSR, rcar2_readw(uart, SCIF_SCFSR) &
> +                 ~(SCFSR_TEND | SCFSR_TDFE));
> +}
> +
> +static int rcar2_uart_getc(struct serial_port *port, char *pc)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +
> +    /* Check for available data bytes in RX FIFO */
> +    if ( !(rcar2_readw(uart, SCIF_SCFSR) & (SCFSR_RDF | SCFSR_DR)) )
> +        return 0;
> +
> +    *pc = rcar2_readb(uart, SCIF_SCFRDR);
> +
> +    /* dummy read */
> +    rcar2_readw(uart, SCIF_SCFSR);
> +    /* Clear required RX flags */
> +    rcar2_writew(uart, SCIF_SCFSR, ~(SCFSR_RDF | SCFSR_DR));
> +
> +    return 1;
> +}
> +
> +static int __init rcar2_uart_irq(struct serial_port *port)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +
> +    return ((uart->irq > 0) ? uart->irq : -1);
> +}
> +
> +static const struct vuart_info *rcar2_vuart_info(struct serial_port *port)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +
> +    return &uart->vuart;
> +}
> +
> +static void rcar2_uart_start_tx(struct serial_port *port)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +
> +    rcar2_writew(uart, SCIF_SCSCR, rcar2_readw(uart, SCIF_SCSCR) | SCSCR_TIE);
> +}
> +
> +static void rcar2_uart_stop_tx(struct serial_port *port)
> +{
> +    struct rcar2_uart *uart = port->uart;
> +
> +    rcar2_writew(uart, SCIF_SCSCR, rcar2_readw(uart, SCIF_SCSCR) & ~SCSCR_TIE);
> +}
> +
> +static struct uart_driver __read_mostly rcar2_uart_driver = {
> +    .init_preirq  = rcar2_uart_init_preirq,
> +    .init_postirq = rcar2_uart_init_postirq,
> +    .endboot      = NULL,
> +    .suspend      = rcar2_uart_suspend,
> +    .resume       = rcar2_uart_resume,
> +    .tx_ready     = rcar2_uart_tx_ready,
> +    .putc         = rcar2_uart_putc,
> +    .getc         = rcar2_uart_getc,
> +    .irq          = rcar2_uart_irq,
> +    .start_tx     = rcar2_uart_start_tx,
> +    .stop_tx      = rcar2_uart_stop_tx,
> +    .vuart_info   = rcar2_vuart_info,
> +};
> +
> +static int __init rcar2_uart_init(struct dt_device_node *dev,
> +                                 const void *data)
> +{
> +    const char *config = data;
> +    struct rcar2_uart *uart;
> +    int res;
> +    u64 addr, size;
> +
> +    if ( strcmp(config, "") )
> +        printk("WARNING: UART configuration is not supported\n");
> +
> +    uart = &rcar2_com;
> +
> +    uart->clock_hz  = SCIF_CLK_FREQ;
> +    uart->baud      = BAUD_AUTO;
> +    uart->data_bits = 8;
> +    uart->parity    = PARITY_NONE;
> +    uart->stop_bits = 1;
> +
> +    res = dt_device_get_address(dev, 0, &addr, &size);
> +    if ( res )
> +    {
> +        printk("rcar2-uart: Unable to retrieve the base"
> +                     " address of the UART\n");
> +        return res;
> +    }
> +
> +    res = platform_get_irq(dev, 0);
> +    if ( res < 0 )
> +    {
> +        printk("rcar2-uart: Unable to retrieve the IRQ\n");
> +        return res;
> +    }
> +    uart->irq = res;
> +
> +    uart->regs = ioremap_nocache(addr, size);
> +    if ( !uart->regs )
> +    {
> +        printk("rcar2-uart: Unable to map the UART memory\n");
> +        return -ENOMEM;
> +    }
> +
> +    uart->vuart.base_addr  = addr;
> +    uart->vuart.size       = size;
> +    uart->vuart.data_off   = SCIF_SCFTDR;
> +    uart->vuart.status_off = SCIF_SCFSR;
> +    uart->vuart.status     = SCFSR_TDFE;
> +
> +    /* Register with generic serial driver */
> +    serial_register_uart(SERHND_DTUART, &rcar2_uart_driver, uart);
> +
> +    dt_device_set_used_by(dev, DOMID_XEN);
> +
> +    return 0;
> +}
> +
> +static const char * const rcar2_uart_dt_compat[] __initconst =
> +{
> +    "renesas,scif",
> +    NULL
> +};
> +
> +DT_DEVICE_START(rcar2_uart, "R-Car Gen2 UART", DEVICE_SERIAL)
> +    .compatible = rcar2_uart_dt_compat,
> +    .init = rcar2_uart_init,
> +DT_DEVICE_END
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
>

-- 
Julien Grall

  reply	other threads:[~2015-01-23 22:40 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-23 15:33 [PATCH v3 0/3] arm: introduce basic Renesas R-Car Gen2 platform support Oleksandr Tyshchenko
2015-01-23 15:33 ` [PATCH v3 1/3] xen/arm: Add R-Car Gen2 support for early printk Oleksandr Tyshchenko
2015-01-23 15:33 ` [PATCH v3 2/3] xen/arm: Add new driver for R-Car Gen2 UART Oleksandr Tyshchenko
2015-01-23 22:40   ` Julien Grall [this message]
2015-01-23 15:33 ` [PATCH v3 3/3] xen/arm: Introduce support for Renesas R-Car Gen2 platform Oleksandr Tyshchenko
2015-01-28 13:26   ` Ian Campbell
2015-01-28 13:48     ` Oleksandr Tyshchenko
2015-01-28 14:16       ` Ian Campbell
2015-01-28 16:16         ` Andrii Anisov
2015-01-30 15:38           ` Oleksandr Tyshchenko
2015-01-30 15:52             ` Julien Grall
2015-01-30 16:44               ` Oleksandr Tyshchenko
2015-01-30 16:52                 ` Julien Grall
2015-02-02 17:10                   ` Ian Campbell
2015-02-02 17:19                     ` Oleksandr Tyshchenko
2015-02-02 17:46                       ` Ian Campbell
2015-01-23 22:36 ` [PATCH v3 0/3] arm: introduce basic Renesas R-Car Gen2 platform support Julien Grall
2015-01-23 23:08   ` Oleksandr Tyshchenko

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=54C2CDDF.7030705@linaro.org \
    --to=julien.grall@linaro.org \
    --cc=ian.campbell@citrix.com \
    --cc=oleksandr.tyshchenko@globallogic.com \
    --cc=stefano.stabellini@eu.citrix.com \
    --cc=tim@xen.org \
    --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 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.