Commit b334214e authored by Ilpo Järvinen's avatar Ilpo Järvinen Committed by Greg Kroah-Hartman
Browse files

serial: 8250: RT288x/Au1xxx code away from core



A non-trivial amount of RT288x/Au1xxx code is encapsulated into
ifdeffery in 8250_port / 8250_early and some if UPIO_AU blocks.
Create a separate file from them.

Also handle errors properly in the cases where RT288x/Au1xxx code is
not configured.

It seems that 0x1000 mapsize is likely overkill but I've kept it the
same as previously (the value was shrunk to that value in commit
b2b13cdf ("SERIAL 8250: Fixes for Alchemy UARTs.")). Seemingly, the
driver only needs to access register at 0x28 for the divisor latch.

The Kconfig side is a bit tricky. As SERIAL_8250_RT288X is bool it can
only be =y. It is possible to have SERIAL_8250=m + SERIAL_8250_RT288X=y
which required altering when 8250/ is included or the rt288x would not
be built.

Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20230511121029.13128-5-ilpo.jarvinen@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 30c61f53
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -51,9 +51,9 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state,
#define PORT(_base, _irq)					\
	{							\
		.mapbase	= _base,			\
		.mapsize	= 0x1000,			\
		.irq		= _irq,				\
		.regshift	= 2,				\
		.iotype		= UPIO_AU,			\
		.flags		= UPF_SKIP_TEST | UPF_IOREMAP | \
				  UPF_FIXED_TYPE,		\
		.type		= PORT_16550A,			\
@@ -124,8 +124,14 @@ static void __init alchemy_setup_uarts(int ctype)
	au1xx0_uart_device.dev.platform_data = ports;

	/* Fill up uartclk. */
	for (s = 0; s < c; s++)
	for (s = 0; s < c; s++) {
		ports[s].uartclk = uartclk;
		if (au_platform_setup(&ports[s]) < 0) {
			kfree(ports);
			printk(KERN_INFO "Alchemy: missing support for UARTs\n");
			return;
		}
	}
	if (platform_device_register(&au1xx0_uart_device))
		printk(KERN_INFO "Alchemy: failed to register UARTs\n");
}
+0 −21
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@

static unsigned int serial8250_early_in(struct uart_port *port, int offset)
{
	int reg_offset = offset;
	offset <<= port->regshift;

	switch (port->iotype) {
@@ -50,8 +49,6 @@ static unsigned int serial8250_early_in(struct uart_port *port, int offset)
		return ioread32be(port->membase + offset);
	case UPIO_PORT:
		return inb(port->iobase + offset);
	case UPIO_AU:
		return port->serial_in(port, reg_offset);
	default:
		return 0;
	}
@@ -59,7 +56,6 @@ static unsigned int serial8250_early_in(struct uart_port *port, int offset)

static void serial8250_early_out(struct uart_port *port, int offset, int value)
{
	int reg_offset = offset;
	offset <<= port->regshift;

	switch (port->iotype) {
@@ -78,9 +74,6 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value)
	case UPIO_PORT:
		outb(value, port->iobase + offset);
		break;
	case UPIO_AU:
		port->serial_out(port, reg_offset, value);
		break;
	}
}

@@ -199,17 +192,3 @@ OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup);
OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);

#endif

#ifdef CONFIG_SERIAL_8250_RT288X

static int __init early_au_setup(struct earlycon_device *dev, const char *opt)
{
	dev->port.serial_in = au_serial_in;
	dev->port.serial_out = au_serial_out;
	dev->port.iotype = UPIO_AU;
	dev->con->write = early_serial8250_write;
	return 0;
}
OF_EARLYCON_DECLARE(palmchip, "ralink,rt2880-uart", early_au_setup);

#endif
+3 −1
Original line number Diff line number Diff line
@@ -171,7 +171,9 @@ static int of_platform_serial_setup(struct platform_device *ofdev,

	switch (type) {
	case PORT_RT2880:
		port->iotype = UPIO_AU;
		ret = rt288x_setup(port);
		if (ret)
			goto err_unprepare;
		break;
	}

+0 −78
Original line number Diff line number Diff line
@@ -341,66 +341,6 @@ static void default_serial_dl_write(struct uart_8250_port *up, u32 value)
	serial_out(up, UART_DLM, value >> 8 & 0xff);
}

#ifdef CONFIG_SERIAL_8250_RT288X

#define UART_REG_UNMAPPED	-1

/* Au1x00/RT288x UART hardware has a weird register layout */
static const s8 au_io_in_map[8] = {
	[UART_RX]	= 0,
	[UART_IER]	= 2,
	[UART_IIR]	= 3,
	[UART_LCR]	= 5,
	[UART_MCR]	= 6,
	[UART_LSR]	= 7,
	[UART_MSR]	= 8,
	[UART_SCR]	= UART_REG_UNMAPPED,
};

static const s8 au_io_out_map[8] = {
	[UART_TX]	= 1,
	[UART_IER]	= 2,
	[UART_FCR]	= 4,
	[UART_LCR]	= 5,
	[UART_MCR]	= 6,
	[UART_LSR]	= UART_REG_UNMAPPED,
	[UART_MSR]	= UART_REG_UNMAPPED,
	[UART_SCR]	= UART_REG_UNMAPPED,
};

unsigned int au_serial_in(struct uart_port *p, int offset)
{
	if (offset >= ARRAY_SIZE(au_io_in_map))
		return UINT_MAX;
	offset = au_io_in_map[offset];
	if (offset == UART_REG_UNMAPPED)
		return UINT_MAX;
	return __raw_readl(p->membase + (offset << p->regshift));
}

void au_serial_out(struct uart_port *p, int offset, int value)
{
	if (offset >= ARRAY_SIZE(au_io_out_map))
		return;
	offset = au_io_out_map[offset];
	if (offset == UART_REG_UNMAPPED)
		return;
	__raw_writel(value, p->membase + (offset << p->regshift));
}

/* Au1x00 haven't got a standard divisor latch */
static u32 au_serial_dl_read(struct uart_8250_port *up)
{
	return __raw_readl(up->port.membase + 0x28);
}

static void au_serial_dl_write(struct uart_8250_port *up, u32 value)
{
	__raw_writel(value, up->port.membase + 0x28);
}

#endif

static unsigned int hub6_serial_in(struct uart_port *p, int offset)
{
	offset = offset << p->regshift;
@@ -510,15 +450,6 @@ static void set_io_from_upio(struct uart_port *p)
		p->serial_out = mem32be_serial_out;
		break;

#ifdef CONFIG_SERIAL_8250_RT288X
	case UPIO_AU:
		p->serial_in = au_serial_in;
		p->serial_out = au_serial_out;
		up->dl_read = au_serial_dl_read;
		up->dl_write = au_serial_dl_write;
		break;
#endif

	default:
		p->serial_in = io_serial_in;
		p->serial_out = io_serial_out;
@@ -2968,11 +2899,6 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt)
{
	if (pt->port.mapsize)
		return pt->port.mapsize;
	if (pt->port.iotype == UPIO_AU) {
		if (pt->port.type == PORT_RT2880)
			return 0x100;
		return 0x1000;
	}
	if (is_omap1_8250(pt))
		return 0x16 << pt->port.regshift;

@@ -3222,10 +3148,6 @@ static void serial8250_config_port(struct uart_port *port, int flags)
	if (flags & UART_CONFIG_TYPE)
		autoconfig(up);

	/* if access method is AU, it is a 16550 with a quirk */
	if (port->type == PORT_16550A && port->iotype == UPIO_AU)
		up->bugs |= UART_BUG_NOMSR;

	/* HW bugs may trigger IRQ while IIR == NO_INT */
	if (port->type == PORT_TEGRA)
		up->bugs |= UART_BUG_NOMSR;
+142 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * RT288x/Au1xxx driver
 */

#include <linux/module.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>

#include "8250.h"

#define UART_REG_UNMAPPED	-1

/* Au1x00/RT288x UART hardware has a weird register layout */
static const s8 au_io_in_map[8] = {
	[UART_RX]	= 0,
	[UART_IER]	= 2,
	[UART_IIR]	= 3,
	[UART_LCR]	= 5,
	[UART_MCR]	= 6,
	[UART_LSR]	= 7,
	[UART_MSR]	= 8,
	[UART_SCR]	= UART_REG_UNMAPPED,
};

static const s8 au_io_out_map[8] = {
	[UART_TX]	= 1,
	[UART_IER]	= 2,
	[UART_FCR]	= 4,
	[UART_LCR]	= 5,
	[UART_MCR]	= 6,
	[UART_LSR]	= UART_REG_UNMAPPED,
	[UART_MSR]	= UART_REG_UNMAPPED,
	[UART_SCR]	= UART_REG_UNMAPPED,
};

static unsigned int au_serial_in(struct uart_port *p, int offset)
{
	if (offset >= ARRAY_SIZE(au_io_in_map))
		return UINT_MAX;
	offset = au_io_in_map[offset];
	if (offset == UART_REG_UNMAPPED)
		return UINT_MAX;
	return __raw_readl(p->membase + (offset << p->regshift));
}

static void au_serial_out(struct uart_port *p, int offset, int value)
{
	if (offset >= ARRAY_SIZE(au_io_out_map))
		return;
	offset = au_io_out_map[offset];
	if (offset == UART_REG_UNMAPPED)
		return;
	__raw_writel(value, p->membase + (offset << p->regshift));
}

/* Au1x00 haven't got a standard divisor latch */
static u32 au_serial_dl_read(struct uart_8250_port *up)
{
	return __raw_readl(up->port.membase + 0x28);
}

static void au_serial_dl_write(struct uart_8250_port *up, u32 value)
{
	__raw_writel(value, up->port.membase + 0x28);
}

int au_platform_setup(struct plat_serial8250_port *p)
{
	p->iotype = UPIO_AU;

	p->serial_in = au_serial_in;
	p->serial_out = au_serial_out;
	p->dl_read = au_serial_dl_read;
	p->dl_write = au_serial_dl_write;

	p->mapsize = 0x1000;

	p->bugs |= UART_BUG_NOMSR;

	return 0;
}
EXPORT_SYMBOL_GPL(au_platform_setup);

int rt288x_setup(struct uart_port *p)
{
	struct uart_8250_port *up = up_to_u8250p(p);

	p->iotype = UPIO_AU;

	p->serial_in = au_serial_in;
	p->serial_out = au_serial_out;
	up->dl_read = au_serial_dl_read;
	up->dl_write = au_serial_dl_write;

	p->mapsize = 0x100;

	up->bugs |= UART_BUG_NOMSR;

	return 0;
}
EXPORT_SYMBOL_GPL(rt288x_setup);

#ifdef CONFIG_SERIAL_8250_CONSOLE
static void au_putc(struct uart_port *port, unsigned char c)
{
	unsigned int status;

	au_serial_out(port, UART_TX, c);

	for (;;) {
		status = au_serial_in(port, UART_LSR);
		if (uart_lsr_tx_empty(status))
			break;
		cpu_relax();
	}
}

static void au_early_serial8250_write(struct console *console,
				      const char *s, unsigned int count)
{
	struct earlycon_device *device = console->data;
	struct uart_port *port = &device->port;

	uart_console_write(port, s, count, au_putc);
}

static int __init early_au_setup(struct earlycon_device *dev, const char *opt)
{
	rt288x_setup(&dev->port);
	dev->con->write = au_early_serial8250_write;

	return 0;
}
OF_EARLYCON_DECLARE(palmchip, "ralink,rt2880-uart", early_au_setup);
#endif

MODULE_DESCRIPTION("RT288x/Au1xxx UART driver");
MODULE_LICENSE("GPL");
Loading