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 58static unsigned int num_ports; 59 60extern int hp300_uart_scode; 61 62/* Offset to UART registers from base of DCA */ 63#define UART_OFFSET 17 64 65#define DCA_ID 0x01 /* ID (read), reset (write) */ 66#define DCA_IC 0x03 /* Interrupt control */ 67 68/* Interrupt control */ 69#define DCA_IC_IE 0x80 /* Master interrupt enable */ 70 71#define HPDCA_BAUD_BASE 153600 72 73/* Base address of the Frodo part */ 74#define FRODO_BASE (0x41c000) 75 76/* 77 * Where we find the 8250-like APCI ports, and how far apart they are. 78 */ 79#define FRODO_APCIBASE 0x0 80#define FRODO_APCISPACE 0x20 81#define FRODO_APCI_OFFSET(x) (FRODO_APCIBASE + ((x) * FRODO_APCISPACE)) 82 83#define HPAPCI_BAUD_BASE 500400 84 85#ifdef CONFIG_SERIAL_8250_CONSOLE 86/* 87 * Parse the bootinfo to find descriptions for headless console and 88 * debug serial ports and register them with the 8250 driver. 89 * This function should be called before serial_console_init() is called 90 * to make sure the serial console will be available for use. IA-64 kernel 91 * calls this function from setup_arch() after the EFI and ACPI tables have 92 * been parsed. 93 */ 94int __init hp300_setup_serial_console(void) 95{ 96 int scode; 97 struct uart_port port; 98 99 memset(&port, 0, sizeof(port)); 100 101 if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX) 102 return 0; 103 104 if (DIO_SCINHOLE(hp300_uart_scode)) 105 return 0; 106 107 scode = hp300_uart_scode; 108 109 /* Memory mapped I/O */ 110 port.iotype = UPIO_MEM; 111 port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; 112 port.type = PORT_UNKNOWN; 113 114 /* Check for APCI console */ 115 if (scode == 256) { 116#ifdef CONFIG_HPAPCI 117 printk(KERN_INFO "Serial console is HP APCI 1\n"); 118 119 port.uartclk = HPAPCI_BAUD_BASE * 16; 120 port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1)); 121 port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); 122 port.regshift = 2; 123 add_preferred_console("ttyS", port.line, "9600n8"); 124#else 125 printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n"); 126 return 0; 127#endif 128 } 129 else { 130#ifdef CONFIG_HPDCA 131 unsigned long pa = dio_scodetophysaddr(scode); 132 if (!pa) { 133 return 0; 134 } 135 136 printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode); 137 138 port.uartclk = HPDCA_BAUD_BASE * 16; 139 port.mapbase = (pa + UART_OFFSET); 140 port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); 141 port.regshift = 1; 142 port.irq = DIO_IPL(pa + DIO_VIRADDRBASE); 143 144 /* Enable board-interrupts */ 145 out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); 146 147 if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) { 148 add_preferred_console("ttyS", port.line, "9600n8"); 149 } 150#else 151 printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n"); 152 return 0; 153#endif 154 } 155 156 if (early_serial_setup(&port) < 0) { 157 printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n"); 158 } 159 160 return 0; 161} 162#endif /* CONFIG_SERIAL_8250_CONSOLE */ 163 164#ifdef CONFIG_HPDCA 165static int __devinit hpdca_init_one(struct dio_dev *d, 166 const struct dio_device_id *ent) 167{ 168 struct uart_port port; 169 int line; 170 171#ifdef CONFIG_SERIAL_8250_CONSOLE 172 if (hp300_uart_scode == d->scode) { 173 /* Already got it. */ 174 return 0; 175 } 176#endif 177 memset(&port, 0, sizeof(struct uart_port)); 178 179 /* Memory mapped I/O */ 180 port.iotype = UPIO_MEM; 181 port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; 182 port.irq = d->ipl; 183 port.uartclk = HPDCA_BAUD_BASE * 16; 184 port.mapbase = (d->resource.start + UART_OFFSET); 185 port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); 186 port.regshift = 1; 187 port.dev = &d->dev; 188 line = serial8250_register_port(&port); 189 190 if (line < 0) { 191 printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" 192 " irq %d failed\n", d->scode, port.irq); 193 return -ENOMEM; 194 } 195 196 /* Enable board-interrupts */ 197 out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); 198 dio_set_drvdata(d, (void *)line); 199 200 /* Reset the DCA */ 201 out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff); 202 udelay(100); 203 204 num_ports++; 205 206 return 0; 207} 208#endif 209 210static int __init hp300_8250_init(void) 211{ 212 static int called = 0; 213#ifdef CONFIG_HPAPCI 214 int line; 215 unsigned long base; 216 struct uart_port uport; 217 struct hp300_port *port; 218 int i; 219#endif 220 if (called) 221 return -ENODEV; 222 called = 1; 223 224 if (!MACH_IS_HP300) 225 return -ENODEV; 226 227#ifdef CONFIG_HPDCA 228 dio_register_driver(&hpdca_driver); 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 uport.irq = 0; 263 uport.uartclk = HPAPCI_BAUD_BASE * 16; 264 uport.mapbase = base; 265 uport.membase = (char *)(base + DIO_VIRADDRBASE); 266 uport.regshift = 2; 267 268 line = serial8250_register_port(&uport); 269 270 if (line < 0) { 271 printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d" 272 " irq %d failed\n", i, uport.irq); 273 kfree(port); 274 continue; 275 } 276 277 port->line = line; 278 port->next = hp300_ports; 279 hp300_ports = port; 280 281 num_ports++; 282 } 283#endif 284 285 /* Any boards found? */ 286 if (!num_ports) 287 return -ENODEV; 288 289 return 0; 290} 291 292#ifdef CONFIG_HPDCA 293static void __devexit hpdca_remove_one(struct dio_dev *d) 294{ 295 int line; 296 297 line = (int) dio_get_drvdata(d); 298 if (d->resource.start) { 299 /* Disable board-interrupts */ 300 out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0); 301 } 302 serial8250_unregister_port(line); 303} 304#endif 305 306static void __exit hp300_8250_exit(void) 307{ 308#ifdef CONFIG_HPAPCI 309 struct hp300_port *port, *to_free; 310 311 for (port = hp300_ports; port; ) { 312 serial8250_unregister_port(port->line); 313 to_free = port; 314 port = port->next; 315 kfree(to_free); 316 } 317 318 hp300_ports = NULL; 319#endif 320#ifdef CONFIG_HPDCA 321 dio_unregister_driver(&hpdca_driver); 322#endif 323} 324 325module_init(hp300_8250_init); 326module_exit(hp300_8250_exit); 327MODULE_DESCRIPTION("HP DCA/APCI serial driver"); 328MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>"); 329MODULE_LICENSE("GPL"); 330