tty: serial: uartlite: Support uartlite on big and little endian systems
authorMichal Simek <michal.simek@xilinx.com>
Mon, 11 Feb 2013 18:04:34 +0000 (19:04 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Feb 2013 16:38:45 +0000 (08:38 -0800)
Use big and little endian accessors function to reflect system configuration.
Detection is done via control register in ulite_request_port.

Tested on Microblaze LE, BE, PPC440 and Arm zynq.

Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/uartlite.c

index f3b09ee767ff5000b3fed5223bb063953ce15203..5f90ef24d475ff728777c63fe32c7ea97adc6485 100644 (file)
@@ -34,7 +34,7 @@
  * Register definitions
  *
  * For register details see datasheet:
- * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf 
+ * http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
  */
 
 #define ULITE_RX               0x00
 #define ULITE_CONTROL_RST_RX   0x02
 #define ULITE_CONTROL_IE       0x10
 
+struct uartlite_reg_ops {
+       u32 (*in)(void __iomem *addr);
+       void (*out)(u32 val, void __iomem *addr);
+};
+
+static u32 uartlite_inbe32(void __iomem *addr)
+{
+       return ioread32be(addr);
+}
+
+static void uartlite_outbe32(u32 val, void __iomem *addr)
+{
+       iowrite32be(val, addr);
+}
+
+static struct uartlite_reg_ops uartlite_be = {
+       .in = uartlite_inbe32,
+       .out = uartlite_outbe32,
+};
+
+static u32 uartlite_inle32(void __iomem *addr)
+{
+       return ioread32(addr);
+}
+
+static void uartlite_outle32(u32 val, void __iomem *addr)
+{
+       iowrite32(val, addr);
+}
+
+static struct uartlite_reg_ops uartlite_le = {
+       .in = uartlite_inle32,
+       .out = uartlite_outle32,
+};
+
+static inline u32 uart_in32(u32 offset, struct uart_port *port)
+{
+       struct uartlite_reg_ops *reg_ops = port->private_data;
+
+       return reg_ops->in(port->membase + offset);
+}
+
+static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
+{
+       struct uartlite_reg_ops *reg_ops = port->private_data;
+
+       reg_ops->out(val, port->membase + offset);
+}
 
 static struct uart_port ulite_ports[ULITE_NR_UARTS];
 
@@ -77,7 +125,7 @@ static int ulite_receive(struct uart_port *port, int stat)
        /* stats */
        if (stat & ULITE_STATUS_RXVALID) {
                port->icount.rx++;
-               ch = ioread32be(port->membase + ULITE_RX);
+               ch = uart_in32(ULITE_RX, port);
 
                if (stat & ULITE_STATUS_PARITY)
                        port->icount.parity++;
@@ -122,7 +170,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
                return 0;
 
        if (port->x_char) {
-               iowrite32be(port->x_char, port->membase + ULITE_TX);
+               uart_out32(port->x_char, ULITE_TX, port);
                port->x_char = 0;
                port->icount.tx++;
                return 1;
@@ -131,7 +179,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
        if (uart_circ_empty(xmit) || uart_tx_stopped(port))
                return 0;
 
-       iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX);
+       uart_out32(xmit->buf[xmit->tail], ULITE_TX, port);
        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
        port->icount.tx++;
 
@@ -148,7 +196,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id)
        int busy, n = 0;
 
        do {
-               int stat = ioread32be(port->membase + ULITE_STATUS);
+               int stat = uart_in32(ULITE_STATUS, port);
                busy  = ulite_receive(port, stat);
                busy |= ulite_transmit(port, stat);
                n++;
@@ -169,7 +217,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port)
        unsigned int ret;
 
        spin_lock_irqsave(&port->lock, flags);
-       ret = ioread32be(port->membase + ULITE_STATUS);
+       ret = uart_in32(ULITE_STATUS, port);
        spin_unlock_irqrestore(&port->lock, flags);
 
        return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
@@ -192,7 +240,7 @@ static void ulite_stop_tx(struct uart_port *port)
 
 static void ulite_start_tx(struct uart_port *port)
 {
-       ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS));
+       ulite_transmit(port, uart_in32(ULITE_STATUS, port));
 }
 
 static void ulite_stop_rx(struct uart_port *port)
@@ -220,17 +268,17 @@ static int ulite_startup(struct uart_port *port)
        if (ret)
                return ret;
 
-       iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
-              port->membase + ULITE_CONTROL);
-       iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+       uart_out32(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
+               ULITE_CONTROL, port);
+       uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port);
 
        return 0;
 }
 
 static void ulite_shutdown(struct uart_port *port)
 {
-       iowrite32be(0, port->membase + ULITE_CONTROL);
-       ioread32be(port->membase + ULITE_CONTROL); /* dummy */
+       uart_out32(0, ULITE_CONTROL, port);
+       uart_in32(ULITE_CONTROL, port); /* dummy */
        free_irq(port->irq, port);
 }
 
@@ -281,6 +329,8 @@ static void ulite_release_port(struct uart_port *port)
 
 static int ulite_request_port(struct uart_port *port)
 {
+       int ret;
+
        pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
                 port, (unsigned long long) port->mapbase);
 
@@ -296,6 +346,14 @@ static int ulite_request_port(struct uart_port *port)
                return -EBUSY;
        }
 
+       port->private_data = &uartlite_be;
+       ret = uart_in32(ULITE_CONTROL, port);
+       uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port);
+       ret = uart_in32(ULITE_STATUS, port);
+       /* Endianess detection */
+       if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY)
+               port->private_data = &uartlite_le;
+
        return 0;
 }
 
@@ -314,20 +372,19 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
 #ifdef CONFIG_CONSOLE_POLL
 static int ulite_get_poll_char(struct uart_port *port)
 {
-       if (!(ioread32be(port->membase + ULITE_STATUS)
-                                               & ULITE_STATUS_RXVALID))
+       if (!(uart_in32(ULITE_STATUS, port) & ULITE_STATUS_RXVALID))
                return NO_POLL_CHAR;
 
-       return ioread32be(port->membase + ULITE_RX);
+       return uart_in32(ULITE_RX, port);
 }
 
 static void ulite_put_poll_char(struct uart_port *port, unsigned char ch)
 {
-       while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL)
+       while (uart_in32(ULITE_STATUS, port) & ULITE_STATUS_TXFULL)
                cpu_relax();
 
        /* write char to device */
-       iowrite32be(ch, port->membase + ULITE_TX);
+       uart_out32(ch, ULITE_TX, port);
 }
 #endif
 
@@ -366,7 +423,7 @@ static void ulite_console_wait_tx(struct uart_port *port)
 
        /* Spin waiting for TX fifo to have space available */
        for (i = 0; i < 100000; i++) {
-               val = ioread32be(port->membase + ULITE_STATUS);
+               val = uart_in32(ULITE_STATUS, port);
                if ((val & ULITE_STATUS_TXFULL) == 0)
                        break;
                cpu_relax();
@@ -376,7 +433,7 @@ static void ulite_console_wait_tx(struct uart_port *port)
 static void ulite_console_putchar(struct uart_port *port, int ch)
 {
        ulite_console_wait_tx(port);
-       iowrite32be(ch, port->membase + ULITE_TX);
+       uart_out32(ch, ULITE_TX, port);
 }
 
 static void ulite_console_write(struct console *co, const char *s,
@@ -393,8 +450,8 @@ static void ulite_console_write(struct console *co, const char *s,
                spin_lock_irqsave(&port->lock, flags);
 
        /* save and disable interrupt */
-       ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
-       iowrite32be(0, port->membase + ULITE_CONTROL);
+       ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE;
+       uart_out32(0, ULITE_CONTROL, port);
 
        uart_console_write(port, s, count, ulite_console_putchar);
 
@@ -402,7 +459,7 @@ static void ulite_console_write(struct console *co, const char *s,
 
        /* restore interrupt state */
        if (ier)
-               iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
+               uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port);
 
        if (locked)
                spin_unlock_irqrestore(&port->lock, flags);