Commit bd94c407 authored by Masahiro Yamada's avatar Masahiro Yamada Committed by Greg Kroah-Hartman

serial: support 16-bit register interface for console

Currently, 8-bit (MMIO) and 32-bit (MMIO32) register interfaces are
supported for the 8250 console, but the 16-bit (MMIO16) is not.
The 8250 UART device on my board is connected to a 16-bit bus and
my main motivation is to use earlycon with it.
(Refer to arch/arm/boot/dts/uniphier-support-card.dtsi)
Signed-off-by: default avatarMasahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 004e2ed5
...@@ -721,16 +721,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -721,16 +721,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
uart[8250],io,<addr>[,options] uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options] uart[8250],mmio,<addr>[,options]
uart[8250],mmio16,<addr>[,options]
uart[8250],mmio32,<addr>[,options] uart[8250],mmio32,<addr>[,options]
uart[8250],0x<addr>[,options] uart[8250],0x<addr>[,options]
Start an early, polled-mode console on the 8250/16550 Start an early, polled-mode console on the 8250/16550
UART at the specified I/O port or MMIO address, UART at the specified I/O port or MMIO address,
switching to the matching ttyS device later. switching to the matching ttyS device later.
MMIO inter-register address stride is either 8-bit MMIO inter-register address stride is either 8-bit
(mmio) or 32-bit (mmio32). (mmio), 16-bit (mmio16), or 32-bit (mmio32).
If none of [io|mmio|mmio32], <addr> is assumed to be If none of [io|mmio|mmio16|mmio32], <addr> is assumed
equivalent to 'mmio'. 'options' are specified in the to be equivalent to 'mmio'. 'options' are specified in
same format described for ttyS above; if unspecified, the same format described for ttyS above; if unspecified,
the h/w is not re-initialized. the h/w is not re-initialized.
hvc<n> Use the hypervisor console device <n>. This is for hvc<n> Use the hypervisor console device <n>. This is for
......
...@@ -620,7 +620,7 @@ static int univ8250_console_setup(struct console *co, char *options) ...@@ -620,7 +620,7 @@ static int univ8250_console_setup(struct console *co, char *options)
* @options: ptr to option string from console command line * @options: ptr to option string from console command line
* *
* Only attempts to match console command lines of the form: * Only attempts to match console command lines of the form:
* console=uart[8250],io|mmio|mmio32,<addr>[,<options>] * console=uart[8250],io|mmio|mmio16|mmio32,<addr>[,<options>]
* console=uart[8250],0x<addr>[,<options>] * console=uart[8250],0x<addr>[,<options>]
* This form is used to register an initial earlycon boot console and * This form is used to register an initial earlycon boot console and
* replace it with the serial8250_console at 8250 driver init. * replace it with the serial8250_console at 8250 driver init.
...@@ -650,8 +650,9 @@ static int univ8250_console_match(struct console *co, char *name, int idx, ...@@ -650,8 +650,9 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
if (port->iotype != iotype) if (port->iotype != iotype)
continue; continue;
if ((iotype == UPIO_MEM || iotype == UPIO_MEM32) && if ((iotype == UPIO_MEM || iotype == UPIO_MEM16 ||
(port->mapbase != addr)) iotype == UPIO_MEM32 || iotype == UPIO_MEM32BE)
&& (port->mapbase != addr))
continue; continue;
if (iotype == UPIO_PORT && port->iobase != addr) if (iotype == UPIO_PORT && port->iobase != addr)
continue; continue;
......
...@@ -42,6 +42,8 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse ...@@ -42,6 +42,8 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse
switch (port->iotype) { switch (port->iotype) {
case UPIO_MEM: case UPIO_MEM:
return readb(port->membase + offset); return readb(port->membase + offset);
case UPIO_MEM16:
return readw(port->membase + (offset << 1));
case UPIO_MEM32: case UPIO_MEM32:
return readl(port->membase + (offset << 2)); return readl(port->membase + (offset << 2));
case UPIO_MEM32BE: case UPIO_MEM32BE:
...@@ -59,6 +61,9 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int ...@@ -59,6 +61,9 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int
case UPIO_MEM: case UPIO_MEM:
writeb(value, port->membase + offset); writeb(value, port->membase + offset);
break; break;
case UPIO_MEM16:
writew(value, port->membase + (offset << 1));
break;
case UPIO_MEM32: case UPIO_MEM32:
writel(value, port->membase + (offset << 2)); writel(value, port->membase + (offset << 2));
break; break;
......
...@@ -368,6 +368,18 @@ static void mem_serial_out(struct uart_port *p, int offset, int value) ...@@ -368,6 +368,18 @@ static void mem_serial_out(struct uart_port *p, int offset, int value)
writeb(value, p->membase + offset); writeb(value, p->membase + offset);
} }
static void mem16_serial_out(struct uart_port *p, int offset, int value)
{
offset = offset << p->regshift;
writew(value, p->membase + offset);
}
static unsigned int mem16_serial_in(struct uart_port *p, int offset)
{
offset = offset << p->regshift;
return readw(p->membase + offset);
}
static void mem32_serial_out(struct uart_port *p, int offset, int value) static void mem32_serial_out(struct uart_port *p, int offset, int value)
{ {
offset = offset << p->regshift; offset = offset << p->regshift;
...@@ -425,6 +437,11 @@ static void set_io_from_upio(struct uart_port *p) ...@@ -425,6 +437,11 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem_serial_out; p->serial_out = mem_serial_out;
break; break;
case UPIO_MEM16:
p->serial_in = mem16_serial_in;
p->serial_out = mem16_serial_out;
break;
case UPIO_MEM32: case UPIO_MEM32:
p->serial_in = mem32_serial_in; p->serial_in = mem32_serial_in;
p->serial_out = mem32_serial_out; p->serial_out = mem32_serial_out;
...@@ -459,6 +476,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value) ...@@ -459,6 +476,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
{ {
switch (p->iotype) { switch (p->iotype) {
case UPIO_MEM: case UPIO_MEM:
case UPIO_MEM16:
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_MEM32BE: case UPIO_MEM32BE:
case UPIO_AU: case UPIO_AU:
...@@ -2462,6 +2480,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) ...@@ -2462,6 +2480,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_TSI: case UPIO_TSI:
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_MEM32BE: case UPIO_MEM32BE:
case UPIO_MEM16:
case UPIO_MEM: case UPIO_MEM:
if (!port->mapbase) if (!port->mapbase)
break; break;
...@@ -2499,6 +2518,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) ...@@ -2499,6 +2518,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_TSI: case UPIO_TSI:
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_MEM32BE: case UPIO_MEM32BE:
case UPIO_MEM16:
case UPIO_MEM: case UPIO_MEM:
if (!port->mapbase) if (!port->mapbase)
break; break;
......
...@@ -71,10 +71,16 @@ static int __init parse_options(struct earlycon_device *device, char *options) ...@@ -71,10 +71,16 @@ static int __init parse_options(struct earlycon_device *device, char *options)
return -EINVAL; return -EINVAL;
switch (port->iotype) { switch (port->iotype) {
case UPIO_MEM:
port->mapbase = addr;
break;
case UPIO_MEM16:
port->regshift = 1;
port->mapbase = addr;
break;
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_MEM32BE: case UPIO_MEM32BE:
port->regshift = 2; /* fall-through */ port->regshift = 2;
case UPIO_MEM:
port->mapbase = addr; port->mapbase = addr;
break; break;
case UPIO_PORT: case UPIO_PORT:
...@@ -91,10 +97,11 @@ static int __init parse_options(struct earlycon_device *device, char *options) ...@@ -91,10 +97,11 @@ static int __init parse_options(struct earlycon_device *device, char *options)
strlcpy(device->options, options, length); strlcpy(device->options, options, length);
} }
if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 || if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
port->iotype == UPIO_MEM32BE) port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
(port->iotype == UPIO_MEM) ? "" : (port->iotype == UPIO_MEM) ? "" :
(port->iotype == UPIO_MEM16) ? "16" :
(port->iotype == UPIO_MEM32) ? "32" : "32be", (port->iotype == UPIO_MEM32) ? "32" : "32be",
(unsigned long long)port->mapbase, (unsigned long long)port->mapbase,
device->options); device->options);
......
...@@ -122,6 +122,9 @@ static int of_platform_serial_setup(struct platform_device *ofdev, ...@@ -122,6 +122,9 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
case 1: case 1:
port->iotype = UPIO_MEM; port->iotype = UPIO_MEM;
break; break;
case 2:
port->iotype = UPIO_MEM16;
break;
case 4: case 4:
port->iotype = of_device_is_big_endian(np) ? port->iotype = of_device_is_big_endian(np) ?
UPIO_MEM32BE : UPIO_MEM32; UPIO_MEM32BE : UPIO_MEM32;
......
...@@ -1818,8 +1818,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) ...@@ -1818,8 +1818,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
* @options: ptr for <options> field; NULL if not present (out) * @options: ptr for <options> field; NULL if not present (out)
* *
* Decodes earlycon kernel command line parameters of the form * Decodes earlycon kernel command line parameters of the form
* earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options> * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
* console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options> * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
* *
* The optional form * The optional form
* earlycon=<name>,0x<addr>,<options> * earlycon=<name>,0x<addr>,<options>
...@@ -1834,6 +1834,9 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, ...@@ -1834,6 +1834,9 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
if (strncmp(p, "mmio,", 5) == 0) { if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM; *iotype = UPIO_MEM;
p += 5; p += 5;
} else if (strncmp(p, "mmio16,", 7) == 0) {
*iotype = UPIO_MEM16;
p += 7;
} else if (strncmp(p, "mmio32,", 7) == 0) { } else if (strncmp(p, "mmio32,", 7) == 0) {
*iotype = UPIO_MEM32; *iotype = UPIO_MEM32;
p += 7; p += 7;
...@@ -2186,6 +2189,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) ...@@ -2186,6 +2189,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
"I/O 0x%lx offset 0x%x", port->iobase, port->hub6); "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
break; break;
case UPIO_MEM: case UPIO_MEM:
case UPIO_MEM16:
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_MEM32BE: case UPIO_MEM32BE:
case UPIO_AU: case UPIO_AU:
...@@ -2831,6 +2835,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) ...@@ -2831,6 +2835,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
return (port1->iobase == port2->iobase) && return (port1->iobase == port2->iobase) &&
(port1->hub6 == port2->hub6); (port1->hub6 == port2->hub6);
case UPIO_MEM: case UPIO_MEM:
case UPIO_MEM16:
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_MEM32BE: case UPIO_MEM32BE:
case UPIO_AU: case UPIO_AU:
......
...@@ -150,6 +150,7 @@ struct uart_port { ...@@ -150,6 +150,7 @@ struct uart_port {
#define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */ #define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */
#define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */ #define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */
#define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */ #define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */
#define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */
unsigned int read_status_mask; /* driver specific */ unsigned int read_status_mask; /* driver specific */
unsigned int ignore_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */
......
...@@ -69,6 +69,7 @@ struct serial_struct { ...@@ -69,6 +69,7 @@ struct serial_struct {
#define SERIAL_IO_AU 4 #define SERIAL_IO_AU 4
#define SERIAL_IO_TSI 5 #define SERIAL_IO_TSI 5
#define SERIAL_IO_MEM32BE 6 #define SERIAL_IO_MEM32BE 6
#define SERIAL_IO_MEM16 7
#define UART_CLEAR_FIFO 0x01 #define UART_CLEAR_FIFO 0x01
#define UART_USE_FIFO 0x02 #define UART_USE_FIFO 0x02
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment