File: /usr/src/linux/arch/alpha/kernel/sys_cabriolet.c
1 /*
2 * linux/arch/alpha/kernel/sys_cabriolet.c
3 *
4 * Copyright (C) 1995 David A Rusling
5 * Copyright (C) 1996 Jay A Estabrook
6 * Copyright (C) 1998, 1999, 2000 Richard Henderson
7 *
8 * Code supporting the Cabriolet (AlphaPC64), EB66+, and EB164,
9 * PC164 and LX164.
10 */
11
12 #include <linux/config.h>
13 #include <linux/kernel.h>
14 #include <linux/types.h>
15 #include <linux/mm.h>
16 #include <linux/sched.h>
17 #include <linux/pci.h>
18 #include <linux/init.h>
19
20 #include <asm/ptrace.h>
21 #include <asm/system.h>
22 #include <asm/dma.h>
23 #include <asm/irq.h>
24 #include <asm/bitops.h>
25 #include <asm/mmu_context.h>
26 #include <asm/io.h>
27 #include <asm/pgtable.h>
28 #include <asm/core_apecs.h>
29 #include <asm/core_cia.h>
30 #include <asm/core_lca.h>
31
32 #include "proto.h"
33 #include "irq_impl.h"
34 #include "pci_impl.h"
35 #include "machvec_impl.h"
36
37
38 /* Note mask bit is true for DISABLED irqs. */
39 static unsigned long cached_irq_mask = ~0UL;
40
41 static inline void
42 cabriolet_update_irq_hw(unsigned int irq, unsigned long mask)
43 {
44 int ofs = (irq - 16) / 8;
45 outb(mask >> (16 + ofs * 8), 0x804 + ofs);
46 }
47
48 static inline void
49 cabriolet_enable_irq(unsigned int irq)
50 {
51 cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq));
52 }
53
54 static void
55 cabriolet_disable_irq(unsigned int irq)
56 {
57 cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq);
58 }
59
60 static unsigned int
61 cabriolet_startup_irq(unsigned int irq)
62 {
63 cabriolet_enable_irq(irq);
64 return 0; /* never anything pending */
65 }
66
67 static void
68 cabriolet_end_irq(unsigned int irq)
69 {
70 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
71 cabriolet_enable_irq(irq);
72 }
73
74 static struct hw_interrupt_type cabriolet_irq_type = {
75 typename: "CABRIOLET",
76 startup: cabriolet_startup_irq,
77 shutdown: cabriolet_disable_irq,
78 enable: cabriolet_enable_irq,
79 disable: cabriolet_disable_irq,
80 ack: cabriolet_disable_irq,
81 end: cabriolet_end_irq,
82 };
83
84 static void
85 cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
86 {
87 unsigned long pld;
88 unsigned int i;
89
90 /* Read the interrupt summary registers */
91 pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
92
93 /*
94 * Now for every possible bit set, work through them and call
95 * the appropriate interrupt handler.
96 */
97 while (pld) {
98 i = ffz(~pld);
99 pld &= pld - 1; /* clear least bit set */
100 if (i == 4) {
101 isa_device_interrupt(v, r);
102 } else {
103 handle_irq(16 + i, r);
104 }
105 }
106 }
107
108 static void __init
109 cabriolet_init_irq(void)
110 {
111 init_i8259a_irqs();
112
113 if (alpha_using_srm) {
114 alpha_mv.device_interrupt = srm_device_interrupt;
115 init_srm_irqs(35, 0);
116 }
117 else {
118 long i;
119
120 outb(0xff, 0x804);
121 outb(0xff, 0x805);
122 outb(0xff, 0x806);
123
124 for (i = 16; i < 35; ++i) {
125 irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
126 irq_desc[i].handler = &cabriolet_irq_type;
127 }
128 }
129
130 common_init_isa_dma();
131 setup_irq(16+4, &isa_cascade_irqaction);
132 }
133
134 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
135 static void
136 pc164_device_interrupt(unsigned long v, struct pt_regs *r)
137 {
138 /* In theory, the PC164 has the same interrupt hardware as
139 the other Cabriolet based systems. However, something
140 got screwed up late in the development cycle which broke
141 the interrupt masking hardware. Repeat, it is not
142 possible to mask and ack interrupts. At all.
143
144 In an attempt to work around this, while processing
145 interrupts, we do not allow the IPL to drop below what
146 it is currently. This prevents the possibility of
147 recursion.
148
149 ??? Another option might be to force all PCI devices
150 to use edge triggered rather than level triggered
151 interrupts. That might be too invasive though. */
152
153 __min_ipl = getipl();
154 cabriolet_device_interrupt(v, r);
155 __min_ipl = 0;
156 }
157 #endif
158
159 /*
160 * The EB66+ is very similar to the EB66 except that it does not have
161 * the on-board NCR and Tulip chips. In the code below, I have used
162 * slot number to refer to the id select line and *not* the slot
163 * number used in the EB66+ documentation. However, in the table,
164 * I've given the slot number, the id select line and the Jxx number
165 * that's printed on the board. The interrupt pins from the PCI slots
166 * are wired into 3 interrupt summary registers at 0x804, 0x805 and
167 * 0x806 ISA.
168 *
169 * In the table, -1 means don't assign an IRQ number. This is usually
170 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
171 */
172
173 static inline int __init
174 eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
175 {
176 static char irq_tab[5][5] __initdata = {
177 /*INT INTA INTB INTC INTD */
178 {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */
179 {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */
180 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
181 {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */
182 {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */
183 };
184 const long min_idsel = 6, max_idsel = 10, irqs_per_slot = 5;
185 return COMMON_TABLE_LOOKUP;
186 }
187
188
189 /*
190 * The AlphaPC64 is very similar to the EB66+ except that its slots
191 * are numbered differently. In the code below, I have used slot
192 * number to refer to the id select line and *not* the slot number
193 * used in the AlphaPC64 documentation. However, in the table, I've
194 * given the slot number, the id select line and the Jxx number that's
195 * printed on the board. The interrupt pins from the PCI slots are
196 * wired into 3 interrupt summary registers at 0x804, 0x805 and 0x806
197 * ISA.
198 *
199 * In the table, -1 means don't assign an IRQ number. This is usually
200 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
201 */
202
203 static inline int __init
204 cabriolet_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
205 {
206 static char irq_tab[5][5] __initdata = {
207 /*INT INTA INTB INTC INTD */
208 { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */
209 { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */
210 { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */
211 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
212 { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */
213 };
214 const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5;
215 return COMMON_TABLE_LOOKUP;
216 }
217
218 static inline void __init
219 cabriolet_init_pci(void)
220 {
221 common_init_pci();
222 ns87312_enable_ide(0x398);
223 }
224
225 static inline void __init
226 cia_cab_init_pci(void)
227 {
228 cia_init_pci();
229 ns87312_enable_ide(0x398);
230 }
231
232 /*
233 * The PC164 and LX164 have 19 PCI interrupts, four from each of the four
234 * PCI slots, the SIO, PCI/IDE, and USB.
235 *
236 * Each of the interrupts can be individually masked. This is
237 * accomplished by setting the appropriate bit in the mask register.
238 * A bit is set by writing a "1" to the desired position in the mask
239 * register and cleared by writing a "0". There are 3 mask registers
240 * located at ISA address 804h, 805h and 806h.
241 *
242 * An I/O read at ISA address 804h, 805h, 806h will return the
243 * state of the 11 PCI interrupts and not the state of the MASKED
244 * interrupts.
245 *
246 * Note: A write to I/O 804h, 805h, and 806h the mask register will be
247 * updated.
248 *
249 *
250 * ISA DATA<7:0>
251 * ISA +--------------------------------------------------------------+
252 * ADDRESS | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
253 * +==============================================================+
254 * 0x804 | INTB0 | USB | IDE | SIO | INTA3 |INTA2 | INTA1 | INTA0 |
255 * +--------------------------------------------------------------+
256 * 0x805 | INTD0 | INTC3 | INTC2 | INTC1 | INTC0 |INTB3 | INTB2 | INTB1 |
257 * +--------------------------------------------------------------+
258 * 0x806 | Rsrv | Rsrv | Rsrv | Rsrv | Rsrv |INTD3 | INTD2 | INTD1 |
259 * +--------------------------------------------------------------+
260 * * Rsrv = reserved bits
261 * Note: The mask register is write-only.
262 *
263 * IdSel
264 * 5 32 bit PCI option slot 2
265 * 6 64 bit PCI option slot 0
266 * 7 64 bit PCI option slot 1
267 * 8 Saturn I/O
268 * 9 32 bit PCI option slot 3
269 * 10 USB
270 * 11 IDE
271 *
272 */
273
274 static inline int __init
275 alphapc164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
276 {
277 static char irq_tab[7][5] __initdata = {
278 /*INT INTA INTB INTC INTD */
279 { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */
280 { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */
281 { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */
282 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
283 { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */
284 { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */
285 { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */
286 };
287 const long min_idsel = 5, max_idsel = 11, irqs_per_slot = 5;
288 return COMMON_TABLE_LOOKUP;
289 }
290
291 static inline void __init
292 alphapc164_init_pci(void)
293 {
294 cia_init_pci();
295 SMC93x_Init();
296 }
297
298
299 /*
300 * The System Vector
301 */
302
303 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET)
304 struct alpha_machine_vector cabriolet_mv __initmv = {
305 vector_name: "Cabriolet",
306 DO_EV4_MMU,
307 DO_DEFAULT_RTC,
308 DO_APECS_IO,
309 DO_APECS_BUS,
310 machine_check: apecs_machine_check,
311 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
312 min_io_address: DEFAULT_IO_BASE,
313 min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
314
315 nr_irqs: 35,
316 device_interrupt: cabriolet_device_interrupt,
317
318 init_arch: apecs_init_arch,
319 init_irq: cabriolet_init_irq,
320 init_rtc: common_init_rtc,
321 init_pci: cabriolet_init_pci,
322 kill_arch: NULL,
323 pci_map_irq: cabriolet_map_irq,
324 pci_swizzle: common_swizzle,
325 };
326 #ifndef CONFIG_ALPHA_EB64P
327 ALIAS_MV(cabriolet)
328 #endif
329 #endif
330
331 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164)
332 struct alpha_machine_vector eb164_mv __initmv = {
333 vector_name: "EB164",
334 DO_EV5_MMU,
335 DO_DEFAULT_RTC,
336 DO_CIA_IO,
337 DO_CIA_BUS,
338 machine_check: cia_machine_check,
339 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
340 min_io_address: DEFAULT_IO_BASE,
341 min_mem_address: CIA_DEFAULT_MEM_BASE,
342
343 nr_irqs: 35,
344 device_interrupt: cabriolet_device_interrupt,
345
346 init_arch: cia_init_arch,
347 init_irq: cabriolet_init_irq,
348 init_rtc: common_init_rtc,
349 init_pci: cia_cab_init_pci,
350 pci_map_irq: cabriolet_map_irq,
351 pci_swizzle: common_swizzle,
352 };
353 ALIAS_MV(eb164)
354 #endif
355
356 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P)
357 struct alpha_machine_vector eb66p_mv __initmv = {
358 vector_name: "EB66+",
359 DO_EV4_MMU,
360 DO_DEFAULT_RTC,
361 DO_LCA_IO,
362 DO_LCA_BUS,
363 machine_check: lca_machine_check,
364 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
365 min_io_address: DEFAULT_IO_BASE,
366 min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
367
368 nr_irqs: 35,
369 device_interrupt: cabriolet_device_interrupt,
370
371 init_arch: lca_init_arch,
372 init_irq: cabriolet_init_irq,
373 init_rtc: common_init_rtc,
374 init_pci: cabriolet_init_pci,
375 pci_map_irq: eb66p_map_irq,
376 pci_swizzle: common_swizzle,
377 };
378 ALIAS_MV(eb66p)
379 #endif
380
381 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164)
382 struct alpha_machine_vector lx164_mv __initmv = {
383 vector_name: "LX164",
384 DO_EV5_MMU,
385 DO_DEFAULT_RTC,
386 DO_PYXIS_IO,
387 DO_CIA_BUS,
388 machine_check: cia_machine_check,
389 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
390 min_io_address: DEFAULT_IO_BASE,
391 min_mem_address: DEFAULT_MEM_BASE,
392
393 nr_irqs: 35,
394 device_interrupt: cabriolet_device_interrupt,
395
396 init_arch: pyxis_init_arch,
397 init_irq: cabriolet_init_irq,
398 init_rtc: common_init_rtc,
399 init_pci: alphapc164_init_pci,
400 pci_map_irq: alphapc164_map_irq,
401 pci_swizzle: common_swizzle,
402 };
403 ALIAS_MV(lx164)
404 #endif
405
406 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
407 struct alpha_machine_vector pc164_mv __initmv = {
408 vector_name: "PC164",
409 DO_EV5_MMU,
410 DO_DEFAULT_RTC,
411 DO_CIA_IO,
412 DO_CIA_BUS,
413 machine_check: cia_machine_check,
414 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
415 min_io_address: DEFAULT_IO_BASE,
416 min_mem_address: CIA_DEFAULT_MEM_BASE,
417
418 nr_irqs: 35,
419 device_interrupt: pc164_device_interrupt,
420
421 init_arch: cia_init_arch,
422 init_irq: cabriolet_init_irq,
423 init_rtc: common_init_rtc,
424 init_pci: alphapc164_init_pci,
425 pci_map_irq: alphapc164_map_irq,
426 pci_swizzle: common_swizzle,
427 };
428 ALIAS_MV(pc164)
429 #endif
430