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

[SERIAL] Support Au1x00 8250 UARTs using the generic 8250 driver.

The offsets of the registers are in a different place, and
some parts cannot handle a full set of modem control signals.

Signed-off-by: Pantelis Antoniou <pantelis@embeddedalley.ocm>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Pantelis Antoniou and committed by
Russell King
21c614a7 f912696a

+185 -3
+70 -3
drivers/serial/8250.c
··· 251 251 }, 252 252 }; 253 253 254 + #ifdef CONFIG_SERIAL_8250_AU1X00 255 + 256 + /* Au1x00 UART hardware has a weird register layout */ 257 + static const u8 au_io_in_map[] = { 258 + [UART_RX] = 0, 259 + [UART_IER] = 2, 260 + [UART_IIR] = 3, 261 + [UART_LCR] = 5, 262 + [UART_MCR] = 6, 263 + [UART_LSR] = 7, 264 + [UART_MSR] = 8, 265 + }; 266 + 267 + static const u8 au_io_out_map[] = { 268 + [UART_TX] = 1, 269 + [UART_IER] = 2, 270 + [UART_FCR] = 4, 271 + [UART_LCR] = 5, 272 + [UART_MCR] = 6, 273 + }; 274 + 275 + /* sane hardware needs no mapping */ 276 + static inline int map_8250_in_reg(struct uart_8250_port *up, int offset) 277 + { 278 + if (up->port.iotype != UPIO_AU) 279 + return offset; 280 + return au_io_in_map[offset]; 281 + } 282 + 283 + static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) 284 + { 285 + if (up->port.iotype != UPIO_AU) 286 + return offset; 287 + return au_io_out_map[offset]; 288 + } 289 + 290 + #else 291 + 292 + /* sane hardware needs no mapping */ 293 + #define map_8250_in_reg(up, offset) (offset) 294 + #define map_8250_out_reg(up, offset) (offset) 295 + 296 + #endif 297 + 254 298 static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) 255 299 { 256 - offset <<= up->port.regshift; 300 + offset = map_8250_in_reg(up, offset) << up->port.regshift; 257 301 258 302 switch (up->port.iotype) { 259 303 case UPIO_HUB6: ··· 310 266 case UPIO_MEM32: 311 267 return readl(up->port.membase + offset); 312 268 269 + #ifdef CONFIG_SERIAL_8250_AU1X00 270 + case UPIO_AU: 271 + return __raw_readl(up->port.membase + offset); 272 + #endif 273 + 313 274 default: 314 275 return inb(up->port.iobase + offset); 315 276 } ··· 323 274 static _INLINE_ void 324 275 serial_out(struct uart_8250_port *up, int offset, int value) 325 276 { 326 - offset <<= up->port.regshift; 277 + offset = map_8250_out_reg(up, offset) << up->port.regshift; 327 278 328 279 switch (up->port.iotype) { 329 280 case UPIO_HUB6: ··· 338 289 case UPIO_MEM32: 339 290 writel(value, up->port.membase + offset); 340 291 break; 292 + 293 + #ifdef CONFIG_SERIAL_8250_AU1X00 294 + case UPIO_AU: 295 + __raw_writel(value, up->port.membase + offset); 296 + break; 297 + #endif 341 298 342 299 default: 343 300 outb(value, up->port.iobase + offset); ··· 965 910 } 966 911 } 967 912 #endif 913 + 914 + #ifdef CONFIG_SERIAL_8250_AU1X00 915 + /* if access method is AU, it is a 16550 with a quirk */ 916 + if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) 917 + up->bugs |= UART_BUG_NOMSR; 918 + #endif 919 + 968 920 serial_outp(up, UART_LCR, save_lcr); 969 921 970 922 if (up->capabilities != uart_config[up->port.type].flags) { ··· 1118 1056 static void serial8250_enable_ms(struct uart_port *port) 1119 1057 { 1120 1058 struct uart_8250_port *up = (struct uart_8250_port *)port; 1059 + 1060 + /* no MSR capabilities */ 1061 + if (up->bugs & UART_BUG_NOMSR) 1062 + return; 1121 1063 1122 1064 up->ier |= UART_IER_MSI; 1123 1065 serial_out(up, UART_IER, up->ier); ··· 1840 1774 * CTS flow control flag and modem status interrupts 1841 1775 */ 1842 1776 up->ier &= ~UART_IER_MSI; 1843 - if (UART_ENABLE_MS(&up->port, termios->c_cflag)) 1777 + if (!(up->bugs & UART_BUG_NOMSR) && 1778 + UART_ENABLE_MS(&up->port, termios->c_cflag)) 1844 1779 up->ier |= UART_IER_MSI; 1845 1780 if (up->capabilities & UART_CAP_UUE) 1846 1781 up->ier |= UART_IER_UUE | UART_IER_RTOIE;
+1
drivers/serial/8250.h
··· 49 49 50 50 #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ 51 51 #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ 52 + #define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */ 52 53 53 54 #if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) 54 55 #define _INLINE_ inline
+102
drivers/serial/8250_au1x00.c
··· 1 + /* 2 + * Serial Device Initialisation for Au1x00 3 + * 4 + * (C) Copyright Embedded Alley Solutions, Inc 2005 5 + * Author: Pantelis Antoniou <pantelis@embeddedalley.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; either version 2 of the License, or 10 + * (at your option) any later version. 11 + */ 12 + 13 + #include <linux/errno.h> 14 + #include <linux/init.h> 15 + #include <linux/interrupt.h> 16 + #include <linux/ioport.h> 17 + #include <linux/module.h> 18 + #include <linux/serial_core.h> 19 + #include <linux/signal.h> 20 + #include <linux/slab.h> 21 + #include <linux/types.h> 22 + 23 + #include <linux/serial_8250.h> 24 + 25 + #include <asm/mach-au1x00/au1000.h> 26 + 27 + #include "8250.h" 28 + 29 + #define PORT(_base, _irq) \ 30 + { \ 31 + .iobase = _base, \ 32 + .membase = (void __iomem *)_base,\ 33 + .mapbase = _base, \ 34 + .irq = _irq, \ 35 + .uartclk = 0, /* filled */ \ 36 + .regshift = 2, \ 37 + .iotype = UPIO_AU, \ 38 + .flags = UPF_SKIP_TEST | \ 39 + UPF_IOREMAP, \ 40 + } 41 + 42 + static struct plat_serial8250_port au1x00_data[] = { 43 + #if defined(CONFIG_SOC_AU1000) 44 + PORT(UART0_ADDR, AU1000_UART0_INT), 45 + PORT(UART1_ADDR, AU1000_UART1_INT), 46 + PORT(UART2_ADDR, AU1000_UART2_INT), 47 + PORT(UART3_ADDR, AU1000_UART3_INT), 48 + #elif defined(CONFIG_SOC_AU1500) 49 + PORT(UART0_ADDR, AU1500_UART0_INT), 50 + PORT(UART3_ADDR, AU1500_UART3_INT), 51 + #elif defined(CONFIG_SOC_AU1100) 52 + PORT(UART0_ADDR, AU1100_UART0_INT), 53 + PORT(UART1_ADDR, AU1100_UART1_INT), 54 + PORT(UART2_ADDR, AU1100_UART2_INT), 55 + PORT(UART3_ADDR, AU1100_UART3_INT), 56 + #elif defined(CONFIG_SOC_AU1550) 57 + PORT(UART0_ADDR, AU1550_UART0_INT), 58 + PORT(UART1_ADDR, AU1550_UART1_INT), 59 + PORT(UART2_ADDR, AU1550_UART2_INT), 60 + PORT(UART3_ADDR, AU1550_UART3_INT), 61 + #elif defined(CONFIG_SOC_AU1200) 62 + PORT(UART0_ADDR, AU1200_UART0_INT), 63 + PORT(UART1_ADDR, AU1200_UART1_INT), 64 + #endif 65 + { }, 66 + }; 67 + 68 + static struct platform_device au1x00_device = { 69 + .name = "serial8250", 70 + .id = PLAT8250_DEV_AU1X00, 71 + .dev = { 72 + .platform_data = au1x00_data, 73 + }, 74 + }; 75 + 76 + static int __init au1x00_init(void) 77 + { 78 + int i; 79 + unsigned int uartclk; 80 + 81 + /* get uart clock */ 82 + uartclk = get_au1x00_uart_baud_base() * 16; 83 + 84 + /* fill up uartclk */ 85 + for (i = 0; au1x00_data[i].flags ; i++) 86 + au1x00_data[i].uartclk = uartclk; 87 + 88 + return platform_device_register(&au1x00_device); 89 + } 90 + 91 + /* XXX: Yes, I know this doesn't yet work. */ 92 + static void __exit au1x00_exit(void) 93 + { 94 + platform_device_unregister(&au1x00_device); 95 + } 96 + 97 + module_init(au1x00_init); 98 + module_exit(au1x00_exit); 99 + 100 + MODULE_AUTHOR("Pantelis Antoniou <pantelis@embeddedalley.com>"); 101 + MODULE_DESCRIPTION("8250 serial probe module for Au1x000 cards"); 102 + MODULE_LICENSE("GPL");
+8
drivers/serial/Kconfig
··· 207 207 system, say Y to this option. The driver can handle 1, 2, or 3 port 208 208 cards. If unsure, say N. 209 209 210 + config SERIAL_8250_AU1X00 211 + bool "AU1X00 serial port support" 212 + depends on SERIAL_8250 != n && SOC_AU1X00 213 + help 214 + If you have an Au1x00 board and want to use the serial port, say Y 215 + to this option. The driver can handle 1 or 2 serial ports. 216 + If unsure, say N. 217 + 210 218 comment "Non-8250 serial port support" 211 219 212 220 config SERIAL_AMBA_PL010
+1
drivers/serial/Makefile
··· 22 22 obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o 23 23 obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o 24 24 obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o 25 + obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o 25 26 obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o 26 27 obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o 27 28 obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
+1
drivers/serial/serial_core.c
··· 1959 1959 break; 1960 1960 case UPIO_MEM: 1961 1961 case UPIO_MEM32: 1962 + case UPIO_AU: 1962 1963 snprintf(address, sizeof(address), 1963 1964 "MMIO 0x%lx", port->mapbase); 1964 1965 break;
+1
include/linux/serial_8250.h
··· 42 42 PLAT8250_DEV_BOCA, 43 43 PLAT8250_DEV_HUB6, 44 44 PLAT8250_DEV_MCA, 45 + PLAT8250_DEV_AU1X00, 45 46 }; 46 47 47 48 /*
+1
include/linux/serial_core.h
··· 211 211 #define UPIO_HUB6 (1) 212 212 #define UPIO_MEM (2) 213 213 #define UPIO_MEM32 (3) 214 + #define UPIO_AU (4) /* Au1x00 type IO */ 214 215 215 216 unsigned int read_status_mask; /* driver specific */ 216 217 unsigned int ignore_status_mask; /* driver specific */