Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/drivers/serial/8250_hp300.c
Parent Directory | Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 7846 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 7846 byte(s)
Tag kernel26-2.6.12-alx-r9
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 |
26 | struct hp300_port |
27 | { |
28 | struct hp300_port *next; /* next port */ |
29 | int line; /* line (tty) number */ |
30 | }; |
31 | |
32 | static struct hp300_port *hp300_ports; |
33 | #endif |
34 | |
35 | #ifdef CONFIG_HPDCA |
36 | |
37 | static int __devinit hpdca_init_one(struct dio_dev *d, |
38 | const struct dio_device_id *ent); |
39 | static void __devexit hpdca_remove_one(struct dio_dev *d); |
40 | |
41 | static 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 | |
49 | static 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 | |
58 | extern 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 | */ |
92 | int __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 |
163 | static 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 | |
206 | static 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 |
294 | static 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 | |
307 | static 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 | |
326 | module_init(hp300_8250_init); |
327 | module_exit(hp300_8250_exit); |
328 | MODULE_DESCRIPTION("HP DCA/APCI serial driver"); |
329 | MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>"); |
330 | MODULE_LICENSE("GPL"); |