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

Configure Feed

Select the types of activity you want to include in your feed.

at 77b2555b52a894a2e39a42e43d993df875c46a6a 330 lines 7.8 kB view raw
1/* 2 * Driver for the 98626/98644/internal serial interface on hp300/hp400 3 * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs) 4 * 5 * Ported from 2.2 and modified to use the normal 8250 driver 6 * by Kars de Jong <jongk@linux-m68k.org>, May 2004. 7 */ 8#include <linux/module.h> 9#include <linux/init.h> 10#include <linux/string.h> 11#include <linux/kernel.h> 12#include <linux/serial.h> 13#include <linux/serial_core.h> 14#include <linux/delay.h> 15#include <linux/dio.h> 16#include <linux/console.h> 17#include <asm/io.h> 18 19#include "8250.h" 20 21#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI) 22#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure? 23#endif 24 25#ifdef CONFIG_HPAPCI 26struct hp300_port 27{ 28 struct hp300_port *next; /* next port */ 29 int line; /* line (tty) number */ 30}; 31 32static struct hp300_port *hp300_ports; 33#endif 34 35#ifdef CONFIG_HPDCA 36 37static int __devinit hpdca_init_one(struct dio_dev *d, 38 const struct dio_device_id *ent); 39static void __devexit hpdca_remove_one(struct dio_dev *d); 40 41static struct dio_device_id hpdca_dio_tbl[] = { 42 { DIO_ID_DCA0 }, 43 { DIO_ID_DCA0REM }, 44 { DIO_ID_DCA1 }, 45 { DIO_ID_DCA1REM }, 46 { 0 } 47}; 48 49static struct dio_driver hpdca_driver = { 50 .name = "hpdca", 51 .id_table = hpdca_dio_tbl, 52 .probe = hpdca_init_one, 53 .remove = __devexit_p(hpdca_remove_one), 54}; 55 56#endif 57 58extern int hp300_uart_scode; 59 60/* Offset to UART registers from base of DCA */ 61#define UART_OFFSET 17 62 63#define DCA_ID 0x01 /* ID (read), reset (write) */ 64#define DCA_IC 0x03 /* Interrupt control */ 65 66/* Interrupt control */ 67#define DCA_IC_IE 0x80 /* Master interrupt enable */ 68 69#define HPDCA_BAUD_BASE 153600 70 71/* Base address of the Frodo part */ 72#define FRODO_BASE (0x41c000) 73 74/* 75 * Where we find the 8250-like APCI ports, and how far apart they are. 76 */ 77#define FRODO_APCIBASE 0x0 78#define FRODO_APCISPACE 0x20 79#define FRODO_APCI_OFFSET(x) (FRODO_APCIBASE + ((x) * FRODO_APCISPACE)) 80 81#define HPAPCI_BAUD_BASE 500400 82 83#ifdef CONFIG_SERIAL_8250_CONSOLE 84/* 85 * Parse the bootinfo to find descriptions for headless console and 86 * debug serial ports and register them with the 8250 driver. 87 * This function should be called before serial_console_init() is called 88 * to make sure the serial console will be available for use. IA-64 kernel 89 * calls this function from setup_arch() after the EFI and ACPI tables have 90 * been parsed. 91 */ 92int __init hp300_setup_serial_console(void) 93{ 94 int scode; 95 struct uart_port port; 96 97 memset(&port, 0, sizeof(port)); 98 99 if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX) 100 return 0; 101 102 if (DIO_SCINHOLE(hp300_uart_scode)) 103 return 0; 104 105 scode = hp300_uart_scode; 106 107 /* Memory mapped I/O */ 108 port.iotype = UPIO_MEM; 109 port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; 110 port.type = PORT_UNKNOWN; 111 112 /* Check for APCI console */ 113 if (scode == 256) { 114#ifdef CONFIG_HPAPCI 115 printk(KERN_INFO "Serial console is HP APCI 1\n"); 116 117 port.uartclk = HPAPCI_BAUD_BASE * 16; 118 port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1)); 119 port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); 120 port.regshift = 2; 121 add_preferred_console("ttyS", port.line, "9600n8"); 122#else 123 printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n"); 124 return 0; 125#endif 126 } 127 else { 128#ifdef CONFIG_HPDCA 129 unsigned long pa = dio_scodetophysaddr(scode); 130 if (!pa) { 131 return 0; 132 } 133 134 printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode); 135 136 port.uartclk = HPDCA_BAUD_BASE * 16; 137 port.mapbase = (pa + UART_OFFSET); 138 port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); 139 port.regshift = 1; 140 port.irq = DIO_IPL(pa + DIO_VIRADDRBASE); 141 142 /* Enable board-interrupts */ 143 out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); 144 145 if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) { 146 add_preferred_console("ttyS", port.line, "9600n8"); 147 } 148#else 149 printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n"); 150 return 0; 151#endif 152 } 153 154 if (early_serial_setup(&port) < 0) { 155 printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n"); 156 } 157 158 return 0; 159} 160#endif /* CONFIG_SERIAL_8250_CONSOLE */ 161 162#ifdef CONFIG_HPDCA 163static int __devinit hpdca_init_one(struct dio_dev *d, 164 const struct dio_device_id *ent) 165{ 166 struct uart_port port; 167 int line; 168 169#ifdef CONFIG_SERIAL_8250_CONSOLE 170 if (hp300_uart_scode == d->scode) { 171 /* Already got it. */ 172 return 0; 173 } 174#endif 175 memset(&port, 0, sizeof(struct uart_port)); 176 177 /* Memory mapped I/O */ 178 port.iotype = UPIO_MEM; 179 port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; 180 port.irq = d->ipl; 181 port.uartclk = HPDCA_BAUD_BASE * 16; 182 port.mapbase = (d->resource.start + UART_OFFSET); 183 port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); 184 port.regshift = 1; 185 port.dev = &d->dev; 186 line = serial8250_register_port(&port); 187 188 if (line < 0) { 189 printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" 190 " irq %d failed\n", d->scode, port.irq); 191 return -ENOMEM; 192 } 193 194 /* Enable board-interrupts */ 195 out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); 196 dio_set_drvdata(d, (void *)line); 197 198 /* Reset the DCA */ 199 out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff); 200 udelay(100); 201 202 return 0; 203} 204#endif 205 206static int __init hp300_8250_init(void) 207{ 208 static int called = 0; 209 int num_ports; 210#ifdef CONFIG_HPAPCI 211 int line; 212 unsigned long base; 213 struct uart_port uport; 214 struct hp300_port *port; 215 int i; 216#endif 217 if (called) 218 return -ENODEV; 219 called = 1; 220 221 if (!MACH_IS_HP300) 222 return -ENODEV; 223 224 num_ports = 0; 225 226#ifdef CONFIG_HPDCA 227 if (dio_module_init(&hpdca_driver) == 0) 228 num_ports++; 229#endif 230#ifdef CONFIG_HPAPCI 231 if (hp300_model < HP_400) { 232 if (!num_ports) 233 return -ENODEV; 234 return 0; 235 } 236 /* These models have the Frodo chip. 237 * Port 0 is reserved for the Apollo Domain keyboard. 238 * Port 1 is either the console or the DCA. 239 */ 240 for (i = 1; i < 4; i++) { 241 /* Port 1 is the console on a 425e, on other machines it's mapped to 242 * DCA. 243 */ 244#ifdef CONFIG_SERIAL_8250_CONSOLE 245 if (i == 1) { 246 continue; 247 } 248#endif 249 250 /* Create new serial device */ 251 port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL); 252 if (!port) 253 return -ENOMEM; 254 255 memset(&uport, 0, sizeof(struct uart_port)); 256 257 base = (FRODO_BASE + FRODO_APCI_OFFSET(i)); 258 259 /* Memory mapped I/O */ 260 uport.iotype = UPIO_MEM; 261 uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; 262 /* XXX - no interrupt support yet */ 263 uport.irq = 0; 264 uport.uartclk = HPAPCI_BAUD_BASE * 16; 265 uport.mapbase = base; 266 uport.membase = (char *)(base + DIO_VIRADDRBASE); 267 uport.regshift = 2; 268 269 line = serial8250_register_port(&uport); 270 271 if (line < 0) { 272 printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d" 273 " irq %d failed\n", i, uport.irq); 274 kfree(port); 275 continue; 276 } 277 278 port->line = line; 279 port->next = hp300_ports; 280 hp300_ports = port; 281 282 num_ports++; 283 } 284#endif 285 286 /* Any boards found? */ 287 if (!num_ports) 288 return -ENODEV; 289 290 return 0; 291} 292 293#ifdef CONFIG_HPDCA 294static void __devexit hpdca_remove_one(struct dio_dev *d) 295{ 296 int line; 297 298 line = (int) dio_get_drvdata(d); 299 if (d->resource.start) { 300 /* Disable board-interrupts */ 301 out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0); 302 } 303 serial8250_unregister_port(line); 304} 305#endif 306 307static void __exit hp300_8250_exit(void) 308{ 309#ifdef CONFIG_HPAPCI 310 struct hp300_port *port, *to_free; 311 312 for (port = hp300_ports; port; ) { 313 serial8250_unregister_port(port->line); 314 to_free = port; 315 port = port->next; 316 kfree(to_free); 317 } 318 319 hp300_ports = NULL; 320#endif 321#ifdef CONFIG_HPDCA 322 dio_unregister_driver(&hpdca_driver); 323#endif 324} 325 326module_init(hp300_8250_init); 327module_exit(hp300_8250_exit); 328MODULE_DESCRIPTION("HP DCA/APCI serial driver"); 329MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>"); 330MODULE_LICENSE("GPL");