Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Masahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Masahiro Yamada and committed by
Greg Kroah-Hartman
bd94c407 004e2ed5

+57 -13
+5 -4
Documentation/kernel-parameters.txt
··· 721 721 722 722 uart[8250],io,<addr>[,options] 723 723 uart[8250],mmio,<addr>[,options] 724 + uart[8250],mmio16,<addr>[,options] 724 725 uart[8250],mmio32,<addr>[,options] 725 726 uart[8250],0x<addr>[,options] 726 727 Start an early, polled-mode console on the 8250/16550 727 728 UART at the specified I/O port or MMIO address, 728 729 switching to the matching ttyS device later. 729 730 MMIO inter-register address stride is either 8-bit 730 - (mmio) or 32-bit (mmio32). 731 - If none of [io|mmio|mmio32], <addr> is assumed to be 732 - equivalent to 'mmio'. 'options' are specified in the 733 - same format described for ttyS above; if unspecified, 731 + (mmio), 16-bit (mmio16), or 32-bit (mmio32). 732 + If none of [io|mmio|mmio16|mmio32], <addr> is assumed 733 + to be equivalent to 'mmio'. 'options' are specified in 734 + the same format described for ttyS above; if unspecified, 734 735 the h/w is not re-initialized. 735 736 736 737 hvc<n> Use the hypervisor console device <n>. This is for
+4 -3
drivers/tty/serial/8250/8250_core.c
··· 620 620 * @options: ptr to option string from console command line 621 621 * 622 622 * Only attempts to match console command lines of the form: 623 - * console=uart[8250],io|mmio|mmio32,<addr>[,<options>] 623 + * console=uart[8250],io|mmio|mmio16|mmio32,<addr>[,<options>] 624 624 * console=uart[8250],0x<addr>[,<options>] 625 625 * This form is used to register an initial earlycon boot console and 626 626 * replace it with the serial8250_console at 8250 driver init. ··· 650 650 651 651 if (port->iotype != iotype) 652 652 continue; 653 - if ((iotype == UPIO_MEM || iotype == UPIO_MEM32) && 654 - (port->mapbase != addr)) 653 + if ((iotype == UPIO_MEM || iotype == UPIO_MEM16 || 654 + iotype == UPIO_MEM32 || iotype == UPIO_MEM32BE) 655 + && (port->mapbase != addr)) 655 656 continue; 656 657 if (iotype == UPIO_PORT && port->iobase != addr) 657 658 continue;
+5
drivers/tty/serial/8250/8250_early.c
··· 42 42 switch (port->iotype) { 43 43 case UPIO_MEM: 44 44 return readb(port->membase + offset); 45 + case UPIO_MEM16: 46 + return readw(port->membase + (offset << 1)); 45 47 case UPIO_MEM32: 46 48 return readl(port->membase + (offset << 2)); 47 49 case UPIO_MEM32BE: ··· 60 58 switch (port->iotype) { 61 59 case UPIO_MEM: 62 60 writeb(value, port->membase + offset); 61 + break; 62 + case UPIO_MEM16: 63 + writew(value, port->membase + (offset << 1)); 63 64 break; 64 65 case UPIO_MEM32: 65 66 writel(value, port->membase + (offset << 2));
+20
drivers/tty/serial/8250/8250_port.c
··· 368 368 writeb(value, p->membase + offset); 369 369 } 370 370 371 + static void mem16_serial_out(struct uart_port *p, int offset, int value) 372 + { 373 + offset = offset << p->regshift; 374 + writew(value, p->membase + offset); 375 + } 376 + 377 + static unsigned int mem16_serial_in(struct uart_port *p, int offset) 378 + { 379 + offset = offset << p->regshift; 380 + return readw(p->membase + offset); 381 + } 382 + 371 383 static void mem32_serial_out(struct uart_port *p, int offset, int value) 372 384 { 373 385 offset = offset << p->regshift; ··· 437 425 p->serial_out = mem_serial_out; 438 426 break; 439 427 428 + case UPIO_MEM16: 429 + p->serial_in = mem16_serial_in; 430 + p->serial_out = mem16_serial_out; 431 + break; 432 + 440 433 case UPIO_MEM32: 441 434 p->serial_in = mem32_serial_in; 442 435 p->serial_out = mem32_serial_out; ··· 476 459 { 477 460 switch (p->iotype) { 478 461 case UPIO_MEM: 462 + case UPIO_MEM16: 479 463 case UPIO_MEM32: 480 464 case UPIO_MEM32BE: 481 465 case UPIO_AU: ··· 2480 2462 case UPIO_TSI: 2481 2463 case UPIO_MEM32: 2482 2464 case UPIO_MEM32BE: 2465 + case UPIO_MEM16: 2483 2466 case UPIO_MEM: 2484 2467 if (!port->mapbase) 2485 2468 break; ··· 2518 2499 case UPIO_TSI: 2519 2500 case UPIO_MEM32: 2520 2501 case UPIO_MEM32BE: 2502 + case UPIO_MEM16: 2521 2503 case UPIO_MEM: 2522 2504 if (!port->mapbase) 2523 2505 break;
+11 -4
drivers/tty/serial/earlycon.c
··· 71 71 return -EINVAL; 72 72 73 73 switch (port->iotype) { 74 + case UPIO_MEM: 75 + port->mapbase = addr; 76 + break; 77 + case UPIO_MEM16: 78 + port->regshift = 1; 79 + port->mapbase = addr; 80 + break; 74 81 case UPIO_MEM32: 75 82 case UPIO_MEM32BE: 76 - port->regshift = 2; /* fall-through */ 77 - case UPIO_MEM: 83 + port->regshift = 2; 78 84 port->mapbase = addr; 79 85 break; 80 86 case UPIO_PORT: ··· 97 91 strlcpy(device->options, options, length); 98 92 } 99 93 100 - if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 || 101 - port->iotype == UPIO_MEM32BE) 94 + if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 || 95 + port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE) 102 96 pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", 103 97 (port->iotype == UPIO_MEM) ? "" : 98 + (port->iotype == UPIO_MEM16) ? "16" : 104 99 (port->iotype == UPIO_MEM32) ? "32" : "32be", 105 100 (unsigned long long)port->mapbase, 106 101 device->options);
+3
drivers/tty/serial/of_serial.c
··· 122 122 case 1: 123 123 port->iotype = UPIO_MEM; 124 124 break; 125 + case 2: 126 + port->iotype = UPIO_MEM16; 127 + break; 125 128 case 4: 126 129 port->iotype = of_device_is_big_endian(np) ? 127 130 UPIO_MEM32BE : UPIO_MEM32;
+7 -2
drivers/tty/serial/serial_core.c
··· 1818 1818 * @options: ptr for <options> field; NULL if not present (out) 1819 1819 * 1820 1820 * Decodes earlycon kernel command line parameters of the form 1821 - * earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options> 1822 - * console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options> 1821 + * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> 1822 + * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> 1823 1823 * 1824 1824 * The optional form 1825 1825 * earlycon=<name>,0x<addr>,<options> ··· 1834 1834 if (strncmp(p, "mmio,", 5) == 0) { 1835 1835 *iotype = UPIO_MEM; 1836 1836 p += 5; 1837 + } else if (strncmp(p, "mmio16,", 7) == 0) { 1838 + *iotype = UPIO_MEM16; 1839 + p += 7; 1837 1840 } else if (strncmp(p, "mmio32,", 7) == 0) { 1838 1841 *iotype = UPIO_MEM32; 1839 1842 p += 7; ··· 2189 2186 "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); 2190 2187 break; 2191 2188 case UPIO_MEM: 2189 + case UPIO_MEM16: 2192 2190 case UPIO_MEM32: 2193 2191 case UPIO_MEM32BE: 2194 2192 case UPIO_AU: ··· 2835 2831 return (port1->iobase == port2->iobase) && 2836 2832 (port1->hub6 == port2->hub6); 2837 2833 case UPIO_MEM: 2834 + case UPIO_MEM16: 2838 2835 case UPIO_MEM32: 2839 2836 case UPIO_MEM32BE: 2840 2837 case UPIO_AU:
+1
include/linux/serial_core.h
··· 150 150 #define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */ 151 151 #define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */ 152 152 #define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */ 153 + #define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */ 153 154 154 155 unsigned int read_status_mask; /* driver specific */ 155 156 unsigned int ignore_status_mask; /* driver specific */
+1
include/uapi/linux/serial.h
··· 69 69 #define SERIAL_IO_AU 4 70 70 #define SERIAL_IO_TSI 5 71 71 #define SERIAL_IO_MEM32BE 6 72 + #define SERIAL_IO_MEM16 7 72 73 73 74 #define UART_CLEAR_FIFO 0x01 74 75 #define UART_USE_FIFO 0x02