diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/alpha/kernel/sys_sio.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/alpha/kernel/sys_sio.c')
-rw-r--r-- | arch/alpha/kernel/sys_sio.c | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c new file mode 100644 index 000000000000..47df48a6ddb7 --- /dev/null +++ b/arch/alpha/kernel/sys_sio.c | |||
@@ -0,0 +1,438 @@ | |||
1 | /* | ||
2 | * linux/arch/alpha/kernel/sys_sio.c | ||
3 | * | ||
4 | * Copyright (C) 1995 David A Rusling | ||
5 | * Copyright (C) 1996 Jay A Estabrook | ||
6 | * Copyright (C) 1998, 1999 Richard Henderson | ||
7 | * | ||
8 | * Code for all boards that route the PCI interrupts through the SIO | ||
9 | * PCI/ISA bridge. This includes Noname (AXPpci33), Multia (UDB), | ||
10 | * Kenetics's Platform 2000, Avanti (AlphaStation), XL, and AlphaBook1. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/tty.h> | ||
21 | |||
22 | #include <asm/compiler.h> | ||
23 | #include <asm/ptrace.h> | ||
24 | #include <asm/system.h> | ||
25 | #include <asm/dma.h> | ||
26 | #include <asm/irq.h> | ||
27 | #include <asm/mmu_context.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/pgtable.h> | ||
30 | #include <asm/core_apecs.h> | ||
31 | #include <asm/core_lca.h> | ||
32 | #include <asm/tlbflush.h> | ||
33 | |||
34 | #include "proto.h" | ||
35 | #include "irq_impl.h" | ||
36 | #include "pci_impl.h" | ||
37 | #include "machvec_impl.h" | ||
38 | |||
39 | #if defined(ALPHA_RESTORE_SRM_SETUP) | ||
40 | /* Save LCA configuration data as the console had it set up. */ | ||
41 | struct | ||
42 | { | ||
43 | unsigned int orig_route_tab; /* for SAVE/RESTORE */ | ||
44 | } saved_config __attribute((common)); | ||
45 | #endif | ||
46 | |||
47 | |||
48 | static void __init | ||
49 | sio_init_irq(void) | ||
50 | { | ||
51 | if (alpha_using_srm) | ||
52 | alpha_mv.device_interrupt = srm_device_interrupt; | ||
53 | |||
54 | init_i8259a_irqs(); | ||
55 | common_init_isa_dma(); | ||
56 | } | ||
57 | |||
58 | static inline void __init | ||
59 | alphabook1_init_arch(void) | ||
60 | { | ||
61 | /* The AlphaBook1 has LCD video fixed at 800x600, | ||
62 | 37 rows and 100 cols. */ | ||
63 | screen_info.orig_y = 37; | ||
64 | screen_info.orig_video_cols = 100; | ||
65 | screen_info.orig_video_lines = 37; | ||
66 | |||
67 | lca_init_arch(); | ||
68 | } | ||
69 | |||
70 | |||
71 | /* | ||
72 | * sio_route_tab selects irq routing in PCI/ISA bridge so that: | ||
73 | * PIRQ0 -> irq 15 | ||
74 | * PIRQ1 -> irq 9 | ||
75 | * PIRQ2 -> irq 10 | ||
76 | * PIRQ3 -> irq 11 | ||
77 | * | ||
78 | * This probably ought to be configurable via MILO. For | ||
79 | * example, sound boards seem to like using IRQ 9. | ||
80 | * | ||
81 | * This is NOT how we should do it. PIRQ0-X should have | ||
82 | * their own IRQ's, the way intel uses the IO-APIC irq's. | ||
83 | */ | ||
84 | |||
85 | static void __init | ||
86 | sio_pci_route(void) | ||
87 | { | ||
88 | #if defined(ALPHA_RESTORE_SRM_SETUP) | ||
89 | /* First, read and save the original setting. */ | ||
90 | pci_bus_read_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60, | ||
91 | &saved_config.orig_route_tab); | ||
92 | printk("%s: PIRQ original 0x%x new 0x%x\n", __FUNCTION__, | ||
93 | saved_config.orig_route_tab, alpha_mv.sys.sio.route_tab); | ||
94 | #endif | ||
95 | |||
96 | /* Now override with desired setting. */ | ||
97 | pci_bus_write_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60, | ||
98 | alpha_mv.sys.sio.route_tab); | ||
99 | } | ||
100 | |||
101 | static unsigned int __init | ||
102 | sio_collect_irq_levels(void) | ||
103 | { | ||
104 | unsigned int level_bits = 0; | ||
105 | struct pci_dev *dev = NULL; | ||
106 | |||
107 | /* Iterate through the devices, collecting IRQ levels. */ | ||
108 | while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | ||
109 | if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && | ||
110 | (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) | ||
111 | continue; | ||
112 | |||
113 | if (dev->irq) | ||
114 | level_bits |= (1 << dev->irq); | ||
115 | } | ||
116 | return level_bits; | ||
117 | } | ||
118 | |||
119 | static void __init | ||
120 | sio_fixup_irq_levels(unsigned int level_bits) | ||
121 | { | ||
122 | unsigned int old_level_bits; | ||
123 | |||
124 | /* | ||
125 | * Now, make all PCI interrupts level sensitive. Notice: | ||
126 | * these registers must be accessed byte-wise. inw()/outw() | ||
127 | * don't work. | ||
128 | * | ||
129 | * Make sure to turn off any level bits set for IRQs 9,10,11,15, | ||
130 | * so that the only bits getting set are for devices actually found. | ||
131 | * Note that we do preserve the remainder of the bits, which we hope | ||
132 | * will be set correctly by ARC/SRM. | ||
133 | * | ||
134 | * Note: we at least preserve any level-set bits on AlphaBook1 | ||
135 | */ | ||
136 | old_level_bits = inb(0x4d0) | (inb(0x4d1) << 8); | ||
137 | |||
138 | level_bits |= (old_level_bits & 0x71ff); | ||
139 | |||
140 | outb((level_bits >> 0) & 0xff, 0x4d0); | ||
141 | outb((level_bits >> 8) & 0xff, 0x4d1); | ||
142 | } | ||
143 | |||
144 | static inline int __init | ||
145 | noname_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
146 | { | ||
147 | /* | ||
148 | * The Noname board has 5 PCI slots with each of the 4 | ||
149 | * interrupt pins routed to different pins on the PCI/ISA | ||
150 | * bridge (PIRQ0-PIRQ3). The table below is based on | ||
151 | * information available at: | ||
152 | * | ||
153 | * http://ftp.digital.com/pub/DEC/axppci/ref_interrupts.txt | ||
154 | * | ||
155 | * I have no information on the Avanti interrupt routing, but | ||
156 | * the routing seems to be identical to the Noname except | ||
157 | * that the Avanti has an additional slot whose routing I'm | ||
158 | * unsure of. | ||
159 | * | ||
160 | * pirq_tab[0] is a fake entry to deal with old PCI boards | ||
161 | * that have the interrupt pin number hardwired to 0 (meaning | ||
162 | * that they use the default INTA line, if they are interrupt | ||
163 | * driven at all). | ||
164 | */ | ||
165 | static char irq_tab[][5] __initdata = { | ||
166 | /*INT A B C D */ | ||
167 | { 3, 3, 3, 3, 3}, /* idsel 6 (53c810) */ | ||
168 | {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ | ||
169 | { 2, 2, -1, -1, -1}, /* idsel 8 (Hack: slot closest ISA) */ | ||
170 | {-1, -1, -1, -1, -1}, /* idsel 9 (unused) */ | ||
171 | {-1, -1, -1, -1, -1}, /* idsel 10 (unused) */ | ||
172 | { 0, 0, 2, 1, 0}, /* idsel 11 KN25_PCI_SLOT0 */ | ||
173 | { 1, 1, 0, 2, 1}, /* idsel 12 KN25_PCI_SLOT1 */ | ||
174 | { 2, 2, 1, 0, 2}, /* idsel 13 KN25_PCI_SLOT2 */ | ||
175 | { 0, 0, 0, 0, 0}, /* idsel 14 AS255 TULIP */ | ||
176 | }; | ||
177 | const long min_idsel = 6, max_idsel = 14, irqs_per_slot = 5; | ||
178 | int irq = COMMON_TABLE_LOOKUP, tmp; | ||
179 | tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq); | ||
180 | return irq >= 0 ? tmp : -1; | ||
181 | } | ||
182 | |||
183 | static inline int __init | ||
184 | p2k_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
185 | { | ||
186 | static char irq_tab[][5] __initdata = { | ||
187 | /*INT A B C D */ | ||
188 | { 0, 0, -1, -1, -1}, /* idsel 6 (53c810) */ | ||
189 | {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ | ||
190 | { 1, 1, 2, 3, 0}, /* idsel 8 (slot A) */ | ||
191 | { 2, 2, 3, 0, 1}, /* idsel 9 (slot B) */ | ||
192 | {-1, -1, -1, -1, -1}, /* idsel 10 (unused) */ | ||
193 | {-1, -1, -1, -1, -1}, /* idsel 11 (unused) */ | ||
194 | { 3, 3, -1, -1, -1}, /* idsel 12 (CMD0646) */ | ||
195 | }; | ||
196 | const long min_idsel = 6, max_idsel = 12, irqs_per_slot = 5; | ||
197 | int irq = COMMON_TABLE_LOOKUP, tmp; | ||
198 | tmp = __kernel_extbl(alpha_mv.sys.sio.route_tab, irq); | ||
199 | return irq >= 0 ? tmp : -1; | ||
200 | } | ||
201 | |||
202 | static inline void __init | ||
203 | noname_init_pci(void) | ||
204 | { | ||
205 | common_init_pci(); | ||
206 | sio_pci_route(); | ||
207 | sio_fixup_irq_levels(sio_collect_irq_levels()); | ||
208 | ns87312_enable_ide(0x26e); | ||
209 | } | ||
210 | |||
211 | static inline void __init | ||
212 | alphabook1_init_pci(void) | ||
213 | { | ||
214 | struct pci_dev *dev; | ||
215 | unsigned char orig, config; | ||
216 | |||
217 | common_init_pci(); | ||
218 | sio_pci_route(); | ||
219 | |||
220 | /* | ||
221 | * On the AlphaBook1, the PCMCIA chip (Cirrus 6729) | ||
222 | * is sensitive to PCI bus bursts, so we must DISABLE | ||
223 | * burst mode for the NCR 8xx SCSI... :-( | ||
224 | * | ||
225 | * Note that the NCR810 SCSI driver must preserve the | ||
226 | * setting of the bit in order for this to work. At the | ||
227 | * moment (2.0.29), ncr53c8xx.c does NOT do this, but | ||
228 | * 53c7,8xx.c DOES. | ||
229 | */ | ||
230 | |||
231 | dev = NULL; | ||
232 | while ((dev = pci_find_device(PCI_VENDOR_ID_NCR, PCI_ANY_ID, dev))) { | ||
233 | if (dev->device == PCI_DEVICE_ID_NCR_53C810 | ||
234 | || dev->device == PCI_DEVICE_ID_NCR_53C815 | ||
235 | || dev->device == PCI_DEVICE_ID_NCR_53C820 | ||
236 | || dev->device == PCI_DEVICE_ID_NCR_53C825) { | ||
237 | unsigned long io_port; | ||
238 | unsigned char ctest4; | ||
239 | |||
240 | io_port = dev->resource[0].start; | ||
241 | ctest4 = inb(io_port+0x21); | ||
242 | if (!(ctest4 & 0x80)) { | ||
243 | printk("AlphaBook1 NCR init: setting" | ||
244 | " burst disable\n"); | ||
245 | outb(ctest4 | 0x80, io_port+0x21); | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
250 | /* Do not set *ANY* level triggers for AlphaBook1. */ | ||
251 | sio_fixup_irq_levels(0); | ||
252 | |||
253 | /* Make sure that register PR1 indicates 1Mb mem */ | ||
254 | outb(0x0f, 0x3ce); orig = inb(0x3cf); /* read PR5 */ | ||
255 | outb(0x0f, 0x3ce); outb(0x05, 0x3cf); /* unlock PR0-4 */ | ||
256 | outb(0x0b, 0x3ce); config = inb(0x3cf); /* read PR1 */ | ||
257 | if ((config & 0xc0) != 0xc0) { | ||
258 | printk("AlphaBook1 VGA init: setting 1Mb memory\n"); | ||
259 | config |= 0xc0; | ||
260 | outb(0x0b, 0x3ce); outb(config, 0x3cf); /* write PR1 */ | ||
261 | } | ||
262 | outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */ | ||
263 | } | ||
264 | |||
265 | void | ||
266 | sio_kill_arch(int mode) | ||
267 | { | ||
268 | #if defined(ALPHA_RESTORE_SRM_SETUP) | ||
269 | /* Since we cannot read the PCI DMA Window CSRs, we | ||
270 | * cannot restore them here. | ||
271 | * | ||
272 | * However, we CAN read the PIRQ route register, so restore it | ||
273 | * now... | ||
274 | */ | ||
275 | pci_bus_write_config_dword(pci_isa_hose->bus, PCI_DEVFN(7, 0), 0x60, | ||
276 | saved_config.orig_route_tab); | ||
277 | #endif | ||
278 | } | ||
279 | |||
280 | |||
281 | /* | ||
282 | * The System Vectors | ||
283 | */ | ||
284 | |||
285 | #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_BOOK1) | ||
286 | struct alpha_machine_vector alphabook1_mv __initmv = { | ||
287 | .vector_name = "AlphaBook1", | ||
288 | DO_EV4_MMU, | ||
289 | DO_DEFAULT_RTC, | ||
290 | DO_LCA_IO, | ||
291 | .machine_check = lca_machine_check, | ||
292 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | ||
293 | .min_io_address = DEFAULT_IO_BASE, | ||
294 | .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, | ||
295 | |||
296 | .nr_irqs = 16, | ||
297 | .device_interrupt = isa_device_interrupt, | ||
298 | |||
299 | .init_arch = alphabook1_init_arch, | ||
300 | .init_irq = sio_init_irq, | ||
301 | .init_rtc = common_init_rtc, | ||
302 | .init_pci = alphabook1_init_pci, | ||
303 | .kill_arch = sio_kill_arch, | ||
304 | .pci_map_irq = noname_map_irq, | ||
305 | .pci_swizzle = common_swizzle, | ||
306 | |||
307 | .sys = { .sio = { | ||
308 | /* NCR810 SCSI is 14, PCMCIA controller is 15. */ | ||
309 | .route_tab = 0x0e0f0a0a, | ||
310 | }} | ||
311 | }; | ||
312 | ALIAS_MV(alphabook1) | ||
313 | #endif | ||
314 | |||
315 | #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_AVANTI) | ||
316 | struct alpha_machine_vector avanti_mv __initmv = { | ||
317 | .vector_name = "Avanti", | ||
318 | DO_EV4_MMU, | ||
319 | DO_DEFAULT_RTC, | ||
320 | DO_APECS_IO, | ||
321 | .machine_check = apecs_machine_check, | ||
322 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | ||
323 | .min_io_address = DEFAULT_IO_BASE, | ||
324 | .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, | ||
325 | |||
326 | .nr_irqs = 16, | ||
327 | .device_interrupt = isa_device_interrupt, | ||
328 | |||
329 | .init_arch = apecs_init_arch, | ||
330 | .init_irq = sio_init_irq, | ||
331 | .init_rtc = common_init_rtc, | ||
332 | .init_pci = noname_init_pci, | ||
333 | .kill_arch = sio_kill_arch, | ||
334 | .pci_map_irq = noname_map_irq, | ||
335 | .pci_swizzle = common_swizzle, | ||
336 | |||
337 | .sys = { .sio = { | ||
338 | .route_tab = 0x0b0a0e0f, | ||
339 | }} | ||
340 | }; | ||
341 | ALIAS_MV(avanti) | ||
342 | #endif | ||
343 | |||
344 | #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_NONAME) | ||
345 | struct alpha_machine_vector noname_mv __initmv = { | ||
346 | .vector_name = "Noname", | ||
347 | DO_EV4_MMU, | ||
348 | DO_DEFAULT_RTC, | ||
349 | DO_LCA_IO, | ||
350 | .machine_check = lca_machine_check, | ||
351 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | ||
352 | .min_io_address = DEFAULT_IO_BASE, | ||
353 | .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, | ||
354 | |||
355 | .nr_irqs = 16, | ||
356 | .device_interrupt = srm_device_interrupt, | ||
357 | |||
358 | .init_arch = lca_init_arch, | ||
359 | .init_irq = sio_init_irq, | ||
360 | .init_rtc = common_init_rtc, | ||
361 | .init_pci = noname_init_pci, | ||
362 | .kill_arch = sio_kill_arch, | ||
363 | .pci_map_irq = noname_map_irq, | ||
364 | .pci_swizzle = common_swizzle, | ||
365 | |||
366 | .sys = { .sio = { | ||
367 | /* For UDB, the only available PCI slot must not map to IRQ 9, | ||
368 | since that's the builtin MSS sound chip. That PCI slot | ||
369 | will map to PIRQ1 (for INTA at least), so we give it IRQ 15 | ||
370 | instead. | ||
371 | |||
372 | Unfortunately we have to do this for NONAME as well, since | ||
373 | they are co-indicated when the platform type "Noname" is | ||
374 | selected... :-( */ | ||
375 | |||
376 | .route_tab = 0x0b0a0f0d, | ||
377 | }} | ||
378 | }; | ||
379 | ALIAS_MV(noname) | ||
380 | #endif | ||
381 | |||
382 | #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_P2K) | ||
383 | struct alpha_machine_vector p2k_mv __initmv = { | ||
384 | .vector_name = "Platform2000", | ||
385 | DO_EV4_MMU, | ||
386 | DO_DEFAULT_RTC, | ||
387 | DO_LCA_IO, | ||
388 | .machine_check = lca_machine_check, | ||
389 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | ||
390 | .min_io_address = DEFAULT_IO_BASE, | ||
391 | .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, | ||
392 | |||
393 | .nr_irqs = 16, | ||
394 | .device_interrupt = srm_device_interrupt, | ||
395 | |||
396 | .init_arch = lca_init_arch, | ||
397 | .init_irq = sio_init_irq, | ||
398 | .init_rtc = common_init_rtc, | ||
399 | .init_pci = noname_init_pci, | ||
400 | .kill_arch = sio_kill_arch, | ||
401 | .pci_map_irq = p2k_map_irq, | ||
402 | .pci_swizzle = common_swizzle, | ||
403 | |||
404 | .sys = { .sio = { | ||
405 | .route_tab = 0x0b0a090f, | ||
406 | }} | ||
407 | }; | ||
408 | ALIAS_MV(p2k) | ||
409 | #endif | ||
410 | |||
411 | #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_XL) | ||
412 | struct alpha_machine_vector xl_mv __initmv = { | ||
413 | .vector_name = "XL", | ||
414 | DO_EV4_MMU, | ||
415 | DO_DEFAULT_RTC, | ||
416 | DO_APECS_IO, | ||
417 | .machine_check = apecs_machine_check, | ||
418 | .max_isa_dma_address = ALPHA_XL_MAX_ISA_DMA_ADDRESS, | ||
419 | .min_io_address = DEFAULT_IO_BASE, | ||
420 | .min_mem_address = XL_DEFAULT_MEM_BASE, | ||
421 | |||
422 | .nr_irqs = 16, | ||
423 | .device_interrupt = isa_device_interrupt, | ||
424 | |||
425 | .init_arch = apecs_init_arch, | ||
426 | .init_irq = sio_init_irq, | ||
427 | .init_rtc = common_init_rtc, | ||
428 | .init_pci = noname_init_pci, | ||
429 | .kill_arch = sio_kill_arch, | ||
430 | .pci_map_irq = noname_map_irq, | ||
431 | .pci_swizzle = common_swizzle, | ||
432 | |||
433 | .sys = { .sio = { | ||
434 | .route_tab = 0x0b0a090f, | ||
435 | }} | ||
436 | }; | ||
437 | ALIAS_MV(xl) | ||
438 | #endif | ||