tty: serial: uartlite: Support uartlite on big and little endian systems
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>
This commit is contained in:
parent
3240b48d49
commit
6d53c3b71d
|
@ -34,7 +34,7 @@
|
||||||
* Register definitions
|
* Register definitions
|
||||||
*
|
*
|
||||||
* For register details see datasheet:
|
* 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_RX 0x00
|
||||||
|
@ -57,6 +57,54 @@
|
||||||
#define ULITE_CONTROL_RST_RX 0x02
|
#define ULITE_CONTROL_RST_RX 0x02
|
||||||
#define ULITE_CONTROL_IE 0x10
|
#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];
|
static struct uart_port ulite_ports[ULITE_NR_UARTS];
|
||||||
|
|
||||||
|
@ -77,7 +125,7 @@ static int ulite_receive(struct uart_port *port, int stat)
|
||||||
/* stats */
|
/* stats */
|
||||||
if (stat & ULITE_STATUS_RXVALID) {
|
if (stat & ULITE_STATUS_RXVALID) {
|
||||||
port->icount.rx++;
|
port->icount.rx++;
|
||||||
ch = ioread32be(port->membase + ULITE_RX);
|
ch = uart_in32(ULITE_RX, port);
|
||||||
|
|
||||||
if (stat & ULITE_STATUS_PARITY)
|
if (stat & ULITE_STATUS_PARITY)
|
||||||
port->icount.parity++;
|
port->icount.parity++;
|
||||||
|
@ -122,7 +170,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (port->x_char) {
|
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->x_char = 0;
|
||||||
port->icount.tx++;
|
port->icount.tx++;
|
||||||
return 1;
|
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))
|
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||||
return 0;
|
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);
|
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
|
||||||
port->icount.tx++;
|
port->icount.tx++;
|
||||||
|
|
||||||
|
@ -148,7 +196,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id)
|
||||||
int busy, n = 0;
|
int busy, n = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int stat = ioread32be(port->membase + ULITE_STATUS);
|
int stat = uart_in32(ULITE_STATUS, port);
|
||||||
busy = ulite_receive(port, stat);
|
busy = ulite_receive(port, stat);
|
||||||
busy |= ulite_transmit(port, stat);
|
busy |= ulite_transmit(port, stat);
|
||||||
n++;
|
n++;
|
||||||
|
@ -169,7 +217,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port)
|
||||||
unsigned int ret;
|
unsigned int ret;
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
ret = ioread32be(port->membase + ULITE_STATUS);
|
ret = uart_in32(ULITE_STATUS, port);
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
|
|
||||||
return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
|
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)
|
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)
|
static void ulite_stop_rx(struct uart_port *port)
|
||||||
|
@ -220,17 +268,17 @@ static int ulite_startup(struct uart_port *port)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
|
uart_out32(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
|
||||||
port->membase + ULITE_CONTROL);
|
ULITE_CONTROL, port);
|
||||||
iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
|
uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ulite_shutdown(struct uart_port *port)
|
static void ulite_shutdown(struct uart_port *port)
|
||||||
{
|
{
|
||||||
iowrite32be(0, port->membase + ULITE_CONTROL);
|
uart_out32(0, ULITE_CONTROL, port);
|
||||||
ioread32be(port->membase + ULITE_CONTROL); /* dummy */
|
uart_in32(ULITE_CONTROL, port); /* dummy */
|
||||||
free_irq(port->irq, port);
|
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)
|
static int ulite_request_port(struct uart_port *port)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
|
pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
|
||||||
port, (unsigned long long) port->mapbase);
|
port, (unsigned long long) port->mapbase);
|
||||||
|
|
||||||
|
@ -296,6 +346,14 @@ static int ulite_request_port(struct uart_port *port)
|
||||||
return -EBUSY;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,20 +372,19 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||||
#ifdef CONFIG_CONSOLE_POLL
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
static int ulite_get_poll_char(struct uart_port *port)
|
static int ulite_get_poll_char(struct uart_port *port)
|
||||||
{
|
{
|
||||||
if (!(ioread32be(port->membase + ULITE_STATUS)
|
if (!(uart_in32(ULITE_STATUS, port) & ULITE_STATUS_RXVALID))
|
||||||
& ULITE_STATUS_RXVALID))
|
|
||||||
return NO_POLL_CHAR;
|
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)
|
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();
|
cpu_relax();
|
||||||
|
|
||||||
/* write char to device */
|
/* write char to device */
|
||||||
iowrite32be(ch, port->membase + ULITE_TX);
|
uart_out32(ch, ULITE_TX, port);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -366,7 +423,7 @@ static void ulite_console_wait_tx(struct uart_port *port)
|
||||||
|
|
||||||
/* Spin waiting for TX fifo to have space available */
|
/* Spin waiting for TX fifo to have space available */
|
||||||
for (i = 0; i < 100000; i++) {
|
for (i = 0; i < 100000; i++) {
|
||||||
val = ioread32be(port->membase + ULITE_STATUS);
|
val = uart_in32(ULITE_STATUS, port);
|
||||||
if ((val & ULITE_STATUS_TXFULL) == 0)
|
if ((val & ULITE_STATUS_TXFULL) == 0)
|
||||||
break;
|
break;
|
||||||
cpu_relax();
|
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)
|
static void ulite_console_putchar(struct uart_port *port, int ch)
|
||||||
{
|
{
|
||||||
ulite_console_wait_tx(port);
|
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,
|
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);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
|
||||||
/* save and disable interrupt */
|
/* save and disable interrupt */
|
||||||
ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
|
ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE;
|
||||||
iowrite32be(0, port->membase + ULITE_CONTROL);
|
uart_out32(0, ULITE_CONTROL, port);
|
||||||
|
|
||||||
uart_console_write(port, s, count, ulite_console_putchar);
|
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 */
|
/* restore interrupt state */
|
||||||
if (ier)
|
if (ier)
|
||||||
iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
|
uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port);
|
||||||
|
|
||||||
if (locked)
|
if (locked)
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
|
|
Loading…
Reference in New Issue