[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 3/5] xen/arm: Add the new OMAP UART driver.
On 5 August 2013 12:49, Chen Baozi <baozich@xxxxxxxxx> wrote: > TI OMAP UART introduces some features such as register access modes, which > makes its configuration and interrupt handling differs from 8250 compatible > UART. Thus, we seperate this driver from ns16550's implementation. On your previous version of this patch series you use a modified ns16550, why didn't you continue in the same way? > Signed-off-by: Chen Baozi <baozich@xxxxxxxxx> > --- > config/arm32.mk | 1 + > xen/drivers/char/Makefile | 1 + > xen/drivers/char/omap-uart.c | 358 > +++++++++++++++++++++++++++++++++++++++++++ > xen/include/xen/8250-uart.h | 74 ++++++++- > 4 files changed, 431 insertions(+), 3 deletions(-) > create mode 100644 xen/drivers/char/omap-uart.c > > diff --git a/config/arm32.mk b/config/arm32.mk > index 8e21158..76e229d 100644 > --- a/config/arm32.mk > +++ b/config/arm32.mk > @@ -11,6 +11,7 @@ CFLAGS += -marm > > HAS_PL011 := y > HAS_EXYNOS4210 := y > +HAS_OMAP := y > > # Use only if calling $(LD) directly. > LDFLAGS_DIRECT += -EL > diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile > index 37543f0..911b788 100644 > --- a/xen/drivers/char/Makefile > +++ b/xen/drivers/char/Makefile > @@ -2,6 +2,7 @@ obj-y += console.o > obj-$(HAS_NS16550) += ns16550.o > obj-$(HAS_PL011) += pl011.o > 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-y += serial.o > diff --git a/xen/drivers/char/omap-uart.c b/xen/drivers/char/omap-uart.c > new file mode 100644 > index 0000000..a8cbcc7 > --- /dev/null > +++ b/xen/drivers/char/omap-uart.c > @@ -0,0 +1,358 @@ > +/* > + * omap-uart.c > + * Based on drivers/char/ns16550.c > + * > + * Driver for OMAP-UART contorller > + * > + * Copyright (C) 2012, Chen Baozi <baozich@xxxxxxxxx> > + * > + * Note: This driver is made separate from 16550-series UART driver as > + * omap platform has some specific configurations > + */ > + > +#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 <asm/device.h> > +#include <xen/errno.h> > +#include <xen/mm.h> > +#include <xen/vmap.h> > +#include <xen/8250-uart.h> > + > +static struct omap_uart { > + u32 baud, clock_hz, data_bits, parity, stop_bits, fifo_size; > + struct dt_irq irq; > + volatile uint32_t *regs; > + struct irqaction irqaction; > + > + u32 dll; > + u32 ier; > + u32 dlh; > + u32 fcr; > + u32 efr; > + u32 lcr; > + u32 mcr; > + u32 mdr1; > + u32 scr; > + > +} omap_com = {0}; > + > +static void omap_uart_interrupt(int irq, void *data, struct cpu_user_regs > *regs) > +{ > + struct serial_port *port = data; > + struct omap_uart *uart = port->uart; > + u32 lsr; > + > + do > + { Why do you change the while by a do-while? > + lsr = uart->regs[UART_LSR] & 0xff; Please use ioread{l,w,...} instead of uart->regs[...]. Same for everywhere in you driver. > + if (lsr & UART_LSR_THRE) > + serial_tx_interrupt(port, regs); > + if (lsr & UART_LSR_DR) > + serial_rx_interrupt(port, regs); > + > + if ( port->txbufc == port->txbufp ) { Unnecessary bracket. > + uart->regs[UART_IER] = UART_IER_ERDAI | UART_IER_ELSI; > + } > + } while (!(uart->regs[UART_IIR] & UART_IIR_NOINT)); > + > + > +} > + > +static void baud_protocol_setup(struct omap_uart *uart) > +{ > + /* > + * Switch to register configuration mode B to access the UART_OMAP_EFR > + * register. > + */ > + uart->regs[UART_LCR] = UART_LCR_CONF_MODE_B; > + /* > + * Enable access to the UART_IER[7:4] bit field. > + */ > + uart->efr = uart->regs[UART_OMAP_EFR]; > + uart->regs[UART_OMAP_EFR] = uart->efr | UART_OMAP_EFR_ECB; > + /* > + * Switch to register operation mode to access the UART_IER register. > + */ > + uart->regs[UART_LCR] = 0x0; > + /* > + * Clear the UART_IER register (set the UART_IER[4] SLEEP_MODE bit > + * to 0 to change the UART_DLL and UART_DLM register). Set the > + * UART_IER register value to 0x0000. > + */ > + uart->regs[UART_IER] = 0x0; > + /* > + * Switch to register configuartion mode B to access the UART_DLL and > + * UART_DLM registers. > + */ > + uart->regs[UART_LCR] = UART_LCR_CONF_MODE_B; > + /* > + * Load divisor value. > + */ > + uart->regs[UART_DLL] = uart->dll; > + uart->regs[UART_DLM] = uart->dlh; > + /* > + * Restore the UART_OMAP_EFR > + */ > + uart->regs[UART_OMAP_EFR] = uart->efr; > + /* > + * Load the new protocol formatting (parity, stop-bit, character length) > + * and switch to register operational mode. > + */ > + uart->regs[UART_LCR] = uart->lcr; > +} > + > +static void fifo_setup(struct omap_uart *uart) > +{ > + /* > + * Switch to register configuration mode B to access the UART_OMAP_EFR > + * register. > + */ > + uart->lcr = uart->regs[UART_LCR]; > + uart->regs[UART_LCR] = UART_LCR_CONF_MODE_B; > + /* > + * Enable register submode TCR_TLR to access the UART_OMAP_TLR register. > + */ > + uart->efr = uart->regs[UART_OMAP_EFR]; > + uart->regs[UART_OMAP_EFR] = uart->efr | UART_OMAP_EFR_ECB; > + /* > + * Switch to register configuration mode A to access the UART_MCR > + * register. > + */ > + uart->regs[UART_LCR] = UART_LCR_CONF_MODE_A; > + /* > + * Enable register submode TCR_TLR to access the UART_OMAP_TLR register > + */ > + uart->mcr = uart->regs[UART_MCR]; > + uart->regs[UART_MCR] = uart->mcr | UART_MCR_TCRTLR; > + /* > + * Enable the FIFO; load the new FIFO trigger and the new DMA mode. > + */ > + uart->regs[UART_FCR] = uart->fcr; > + /* > + * Switch to register configuration mode B to access the UART_EFR > + * register. > + */ > + uart->regs[UART_LCR] = UART_LCR_CONF_MODE_B; > + /* > + * Load the new FIFO triggers and the new DMA mode bit. > + */ > + uart->regs[UART_OMAP_SCR] = uart->scr; > + /* > + * Restore the UART_OMAP_EFR[4] value. > + */ > + uart->regs[UART_OMAP_EFR] = uart->efr; > + /* > + * Switch to register configuration mode A to access the UART_MCR > + * register. > + */ > + uart->regs[UART_LCR] = UART_LCR_CONF_MODE_A; > + /* > + * Restore UART_MCR[6] value. > + */ > + uart->regs[UART_MCR] = uart->mcr; > + /* > + * Restore UART_LCR value. > + */ > + uart->regs[UART_LCR] = uart->lcr; > +} > + > +static void __init omap_uart_init_preirq(struct serial_port *port) > +{ > + struct omap_uart *uart = port->uart; > + unsigned int divisor; > + > + /* > + * Clear the FIFO buffers. > + */ > + uart->regs[UART_FCR] = UART_FCR_ENABLE; > + uart->regs[UART_FCR] = UART_FCR_ENABLE | UART_FCR_CLRX | UART_FCR_CLTX; > + uart->regs[UART_FCR] = 0; > + > + /* > + * Calculate desired value. > + */ > + divisor = uart->clock_hz / (uart->baud << 4); > + uart->dll = divisor & 0xff; > + uart->dlh = divisor >> 8; > + uart->lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | > uart->parity; > + uart->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_10 | UART_FCR_ENABLE; > + uart->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; > + uart->ier = UART_IER_ERDAI | UART_IER_ETHREI | UART_IER_ELSI; You are wasting space just to store hardcoded value (for fcr, scr, ier). You should use macro. > + > + /* > + * The TRM says the mode should be disabled while UART_DLL and UART_DHL > + * are being changed so we disable before setup, then enable. > + */ > + uart->regs[UART_OMAP_MDR1] = UART_OMAP_MDR1_DISABLE; > + > + /* Baud rate & protocol format setup */ > + baud_protocol_setup(uart); > + > + /* FIFO setup */ > + fifo_setup(uart); > + > + /* No flow control */ > + uart->regs[UART_MCR] = UART_MCR_DTR | UART_MCR_RTS; > + > + uart->regs[UART_OMAP_MDR1] = UART_OMAP_MDR1_16X_MODE; > + > + uart->fifo_size = 64; > +} > + > +static void __init omap_uart_init_postirq(struct serial_port *port) > +{ > + struct omap_uart *uart = port->uart; > + > + uart->irqaction.handler = omap_uart_interrupt; > + uart->irqaction.name = "omap_uart"; > + uart->irqaction.dev_id = port; > + > + if (setup_dt_irq(&uart->irq, &uart->irqaction) != 0) Missing space for the if. if ( a ) ... > + dprintk(XENLOG_ERR, "Failed to allocated omap_uart IRQ %d\n", > + uart->irq.irq); > + > + /* Enable interrupts */ > + uart->regs[UART_IER] = uart->ier; Don't enable IRQ if setup has failed. > +} > + > +static void omap_uart_suspend(struct serial_port *port) > +{ > + BUG(); > +} > + > +static void omap_uart_resume(struct serial_port *port) > +{ > + BUG(); > +} > + > +static unsigned int omap_uart_tx_ready(struct serial_port *port) > +{ > + struct omap_uart *uart = port->uart; > + > + uart->regs[UART_IER] = uart->ier; > + > + return uart->regs[UART_LSR] & UART_LSR_THRE ? uart->fifo_size : 0; > +} > + > +static void omap_uart_putc(struct serial_port *port, char c) > +{ > + struct omap_uart *uart = port->uart; > + > + uart->regs[UART_THR] = (uint32_t)(unsigned char) c; > +} > + > +static int omap_uart_getc(struct serial_port *port, char *pc) > +{ > + struct omap_uart *uart = port->uart; > + > + if (!(uart->regs[UART_LSR] & UART_LSR_DR)) Missing space for the if. > + return 0; > + > + *pc = uart->regs[UART_RBR] & 0xff; > + return 1; > +} > + > +static int __init omap_uart_irq(struct serial_port *port) > +{ > + struct omap_uart *uart = port->uart; > + > + return ((uart->irq.irq > 0) ? uart->irq.irq : -1); > +} > + > +static const struct dt_irq __init *omap_uart_dt_irq(struct serial_port *port) > +{ > + struct omap_uart *uart = port->uart; > + > + return &uart->irq; > +} > + > +static struct uart_driver __read_mostly omap_uart_driver = { > + .init_preirq = omap_uart_init_preirq, > + .init_postirq = omap_uart_init_postirq, > + .endboot = NULL, > + .suspend = omap_uart_suspend, > + .resume = omap_uart_resume, > + .tx_ready = omap_uart_tx_ready, > + .putc = omap_uart_putc, > + .getc = omap_uart_getc, > + .irq = omap_uart_irq, > + .dt_irq_get = omap_uart_dt_irq, > +}; > + > +static int __init omap_uart_init(struct dt_device_node *dev, > + const void *data) > +{ > + const char *config = data; > + struct omap_uart *uart; > + const __be32 *clkspec; > + int res; > + u64 addr, size; > + > + if (strcmp(config, "")) > + early_printk("WARNING: UART configuration is not supported\n"); > + > + uart = &omap_com; > + > + clkspec = dt_get_property(dev, "clock-frequency", NULL); > + if (clkspec == NULL) { > + early_printk("omap-uart: Unable to retrieve the clock frequency\n"); > + return -EINVAL; > + } > + > + uart->clock_hz = be32_to_cpup(clkspec); > + uart->baud = 115200; > + uart->data_bits = 8; > + uart->parity = UART_PARITY_NONE; > + uart->stop_bits = 1; > + > + res = dt_device_get_address(dev, 0, &addr, &size); > + if (res) { The bracket needs to be on a new line. > + early_printk("omap-uart: Unable to retrieve the base" > + " address of the UART\n"); > + return res; > + } > + > + uart->regs = ioremap_attr(addr, size, PAGE_HYPERVISOR_NOCACHE); > + if (!uart->regs) { Missing space and bracket in newline. > + early_printk("omap-uart: Unable to map the UART memory\n"); > + return -ENOMEM; > + } > + > + res = dt_device_get_irq(dev, 0, &uart->irq); > + if (res) { Same here. > + early_printk("omap-uart: Unable to retrieve the IRQ\n"); > + return res; > + } > + > + /* Register with generic serial driver */ > + serial_register_uart(SERHND_DTUART, &omap_uart_driver, uart); > + > + dt_device_set_used_by(dev, DOMID_XEN); > + > + return 0; > +} > + > +static const char const *omap_uart_dt_compat[] __initdata = > +{ > + "ti,omap4-uart", > + NULL > +}; > + > +DT_DEVICE_START(omap_uart, "OMAP UART", DEVICE_SERIAL) > + .compatible = omap_uart_dt_compat, > + .init = omap_uart_init, > +DT_DEVICE_END > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/include/xen/8250-uart.h b/xen/include/xen/8250-uart.h > index 0e6c6bd..a75f36a 100644 > --- a/xen/include/xen/8250-uart.h > +++ b/xen/include/xen/8250-uart.h > @@ -60,19 +60,55 @@ > #define UART_FCR_CLRX 0x02 /* clear Rx FIFO */ > #define UART_FCR_CLTX 0x04 /* clear Tx FIFO */ > #define UART_FCR_DMA 0x10 /* enter DMA mode */ > + > #define UART_FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */ > #define UART_FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */ > #define UART_FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ > #define UART_FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ > > +/* > + * Note: The FIFO trigger levels are chip specific: > + * RX:76 = 00 01 10 11 TX:54 = 00 01 10 11 > + * PC16550D: 1 4 8 14 xx xx xx xx > + * TI16C550A: 1 4 8 14 xx xx xx xx > + * TI16C550C: 1 4 8 14 xx xx xx xx > + * ST16C550: 1 4 8 14 xx xx xx xx > + * ST16C650: 8 16 24 28 16 8 24 30 PORT_16650V2 > + * NS16C552: 1 4 8 14 xx xx xx xx > + * ST16C654: 8 16 56 60 8 16 32 56 PORT_16654 > + * TI16C750: 1 16 32 56 xx xx xx xx PORT_16750 > + * TI16C752: 8 16 56 60 8 16 32 56 > + * Tegra: 1 4 8 14 16 8 4 1 PORT_TEGRA > + */ > +#define UART_FCR_R_TRIG_00 0x00 > +#define UART_FCR_R_TRIG_01 0x40 > +#define UART_FCR_R_TRIG_10 0x80 > +#define UART_FCR_R_TRIG_11 0xc0 > +#define UART_FCR_T_TRIG_00 0x00 > +#define UART_FCR_T_TRIG_01 0x10 > +#define UART_FCR_T_TRIG_10 0x20 > +#define UART_FCR_T_TRIG_11 0x30 > + > /* Line Control Register */ > #define UART_LCR_DLAB 0x80 /* Divisor Latch Access */ > > +/* > + * Access to some registers depends on register access / configuration > + * mode. > + */ > +#define UART_LCR_CONF_MODE_A UART_LCR_DLAB /* Configutation mode A */ > +#define UART_LCR_CONF_MODE_B 0xBF /* Configutation mode B */ > + > /* Modem Control Register */ > -#define UART_MCR_DTR 0x01 /* Data Terminal Ready */ > -#define UART_MCR_RTS 0x02 /* Request to Send */ > -#define UART_MCR_OUT2 0x08 /* OUT2: interrupt mask */ > +#define UART_MCR_CLKSEL 0x80 /* Divide clock by 4 (TI16C752, EFR[4]=1) > */ > +#define UART_MCR_TCRTLR 0x40 /* Access TCR/TLR (TI16C752, EFR[4]=1) */ > +#define UART_MCR_XONANY 0x20 /* Enable Xon Any (TI16C752, EFR[4]=1) */ Don't add unnecessary define. > +#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS > (TI16C550C/TI16C750) */ > #define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ > +#define UART_MCR_OUT2 0x08 /* Out2 complement */ > +#define UART_MCR_OUT1 0x04 /* Out1 complement */ > +#define UART_MCR_RTS 0x02 /* RTS complement */ > +#define UART_MCR_DTR 0x01 /* DTR complement */ > > /* Line Status Register */ > #define UART_LSR_DR 0x01 /* Data ready */ > @@ -98,6 +134,38 @@ > #define RESUME_DELAY MILLISECS(10) > #define RESUME_RETRIES 100 > > +/* Enhanced feature register */ > +#define UART_OMAP_EFR 0x02 > + > +#define UART_OMAP_EFR_CTS 0x80 /* CTS flow control */ > +#define UART_OMAP_EFR_RTS 0x40 /* RTS flow control */ > +#define UART_OMAP_EFR_SCD 0x20 /* Special character detect */ > +#define UART_OMAP_EFR_ECB 0x10 /* Enhanced control bit */ > + > +/* Mode definition register 1 */ > +#define UART_OMAP_MDR1 0x08 > + > +/* > + * These are the definitions for the MDR1 register > + */ > +#define UART_OMAP_MDR1_16X_MODE 0x00 /* UART 16x mode */ > +#define UART_OMAP_MDR1_SIR_MODE 0x01 /* SIR mode */ > +#define UART_OMAP_MDR1_16X_ABAUD_MODE 0x02 /* UART 16x auto-baud */ > +#define UART_OMAP_MDR1_13X_MODE 0x03 /* UART 13x mode */ > +#define UART_OMAP_MDR1_MIR_MODE 0x04 /* MIR mode */ > +#define UART_OMAP_MDR1_FIR_MODE 0x05 /* FIR mode */ > +#define UART_OMAP_MDR1_CIR_MODE 0x06 /* CIR mode */ > +#define UART_OMAP_MDR1_DISABLE 0x07 /* Disable (default state) */ > + > +/* Supplementary control register */ > +#define UART_OMAP_SCR 0x10 > + > +/* SCR register bitmasks */ > +#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7) > +#define OMAP_UART_SCR_TX_TRIG_GRANU1_MASK (1 << 6) > +#define OMAP_UART_SCR_TX_EMPTY (1 << 3) > + > + > #endif /* __XEN_8250_UART_H__ */ > > /* -- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |