Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d53c3b7 authored by Michal Simek's avatar Michal Simek Committed by Greg Kroah-Hartman
Browse files

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: default avatarMichal Simek <michal.simek@xilinx.com>
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3240b48d
Loading
Loading
Loading
Loading
+79 −22
Original line number Diff line number Diff line
@@ -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];

@@ -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);