Skip to content

Commit

Permalink
tty: serial: uartlite: Support uartlite on big and little endian systems
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Michal Simek authored and Greg Kroah-Hartman committed Feb 13, 2013
1 parent 3240b48 commit 6d53c3b
Showing 1 changed file with 79 additions and 22 deletions.
101 changes: 79 additions & 22 deletions drivers/tty/serial/uartlite.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -57,6 +57,54 @@
#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];

Expand All @@ -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++;
Expand Down Expand Up @@ -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;
Expand All @@ -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++;

Expand All @@ -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++;
Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);

Expand All @@ -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;
}

Expand All @@ -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

Expand Down Expand Up @@ -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();
Expand All @@ -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,
Expand All @@ -393,16 +450,16 @@ 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);

ulite_console_wait_tx(port);

/* 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);
Expand Down

0 comments on commit 6d53c3b

Please sign in to comment.