2 * linux/arch/alpha/kernel/sys_cabriolet.c
4 * Copyright (C) 1995 David A Rusling
5 * Copyright (C) 1996 Jay A Estabrook
6 * Copyright (C) 1998, 1999 Richard Henderson
8 * Code supporting the Cabriolet (AlphaPC64), EB66+, and EB164,
12 #include <linux/config.h>
13 #include <linux/kernel.h>
14 #include <linux/types.h>
16 #include <linux/sched.h>
17 #include <linux/pci.h>
18 #include <linux/init.h>
20 #include <asm/ptrace.h>
21 #include <asm/system.h>
24 #include <asm/bitops.h>
25 #include <asm/mmu_context.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 #include <asm/core_pyxis.h>
36 #include "machvec_impl.h"
39 /* Note mask bit is true for DISABLED irqs. */
40 static unsigned long cached_irq_mask
= ~0UL;
43 cabriolet_update_irq_hw(unsigned int irq
, unsigned long mask
)
45 int ofs
= (irq
- 16) / 8;
46 outb(mask
>> (16 + ofs
*3), 0x804 + ofs
);
50 cabriolet_enable_irq(unsigned int irq
)
52 cabriolet_update_irq_hw(irq
, cached_irq_mask
&= ~(1UL << irq
));
56 cabriolet_disable_irq(unsigned int irq
)
58 cabriolet_update_irq_hw(irq
, cached_irq_mask
|= 1UL << irq
);
62 cabriolet_startup_irq(unsigned int irq
)
64 cabriolet_enable_irq(irq
);
65 return 0; /* never anything pending */
69 cabriolet_end_irq(unsigned int irq
)
71 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
72 cabriolet_enable_irq(irq
);
75 static struct hw_interrupt_type cabriolet_irq_type
= {
76 typename
: "CABRIOLET",
77 startup
: cabriolet_startup_irq
,
78 shutdown
: cabriolet_disable_irq
,
79 enable
: cabriolet_enable_irq
,
80 disable
: cabriolet_disable_irq
,
81 ack
: cabriolet_disable_irq
,
82 end
: cabriolet_end_irq
,
86 cabriolet_device_interrupt(unsigned long v
, struct pt_regs
*r
)
91 /* Read the interrupt summary registers */
92 pld
= inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
95 * Now for every possible bit set, work through them and call
96 * the appropriate interrupt handler.
100 pld
&= pld
- 1; /* clear least bit set */
102 isa_device_interrupt(v
, r
);
104 handle_irq(16 + i
, r
);
110 cabriolet_init_irq(void)
114 if (alpha_using_srm
) {
115 alpha_mv
.device_interrupt
= srm_device_interrupt
;
116 init_srm_irqs(35, 0);
125 for (i
= 16; i
< 35; ++i
) {
126 irq_desc
[i
].status
= IRQ_DISABLED
| IRQ_LEVEL
;
127 irq_desc
[i
].handler
= &cabriolet_irq_type
;
131 common_init_isa_dma();
132 setup_irq(16+4, &isa_cascade_irqaction
);
135 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
137 pc164_device_interrupt(unsigned long v
, struct pt_regs
*r
)
139 /* In theory, the PC164 has the same interrupt hardware as
140 the other Cabriolet based systems. However, something
141 got screwed up late in the development cycle which broke
142 the interrupt masking hardware. Repeat, it is not
143 possible to mask and ack interrupts. At all.
145 In an attempt to work around this, while processing
146 interrupts, we do not allow the IPL to drop below what
147 it is currently. This prevents the possibility of
150 ??? Another option might be to force all PCI devices
151 to use edge triggered rather than level triggered
152 interrupts. That might be too invasive though. */
154 __min_ipl
= getipl();
155 cabriolet_device_interrupt(v
, r
);
161 * The EB66+ is very similar to the EB66 except that it does not have
162 * the on-board NCR and Tulip chips. In the code below, I have used
163 * slot number to refer to the id select line and *not* the slot
164 * number used in the EB66+ documentation. However, in the table,
165 * I've given the slot number, the id select line and the Jxx number
166 * that's printed on the board. The interrupt pins from the PCI slots
167 * are wired into 3 interrupt summary registers at 0x804, 0x805 and
170 * In the table, -1 means don't assign an IRQ number. This is usually
171 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
174 static inline int __init
175 eb66p_map_irq(struct pci_dev
*dev
, u8 slot
, u8 pin
)
177 static char irq_tab
[5][5] __initlocaldata
= {
178 /*INT INTA INTB INTC INTD */
179 {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */
180 {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */
181 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
182 {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */
183 {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */
185 const long min_idsel
= 6, max_idsel
= 10, irqs_per_slot
= 5;
186 return COMMON_TABLE_LOOKUP
;
191 * The AlphaPC64 is very similar to the EB66+ except that its slots
192 * are numbered differently. In the code below, I have used slot
193 * number to refer to the id select line and *not* the slot number
194 * used in the AlphaPC64 documentation. However, in the table, I've
195 * given the slot number, the id select line and the Jxx number that's
196 * printed on the board. The interrupt pins from the PCI slots are
197 * wired into 3 interrupt summary registers at 0x804, 0x805 and 0x806
200 * In the table, -1 means don't assign an IRQ number. This is usually
201 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
204 static inline int __init
205 cabriolet_map_irq(struct pci_dev
*dev
, u8 slot
, u8 pin
)
207 static char irq_tab
[5][5] __initlocaldata
= {
208 /*INT INTA INTB INTC INTD */
209 { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */
210 { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */
211 { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */
212 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
213 { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */
215 const long min_idsel
= 5, max_idsel
= 9, irqs_per_slot
= 5;
216 return COMMON_TABLE_LOOKUP
;
219 static inline void __init
220 cabriolet_init_pci(void)
223 ns87312_enable_ide(0x398);
228 * The PC164 and LX164 have 19 PCI interrupts, four from each of the four
229 * PCI slots, the SIO, PCI/IDE, and USB.
231 * Each of the interrupts can be individually masked. This is
232 * accomplished by setting the appropriate bit in the mask register.
233 * A bit is set by writing a "1" to the desired position in the mask
234 * register and cleared by writing a "0". There are 3 mask registers
235 * located at ISA address 804h, 805h and 806h.
237 * An I/O read at ISA address 804h, 805h, 806h will return the
238 * state of the 11 PCI interrupts and not the state of the MASKED
241 * Note: A write to I/O 804h, 805h, and 806h the mask register will be
246 * ISA +--------------------------------------------------------------+
247 * ADDRESS | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
248 * +==============================================================+
249 * 0x804 | INTB0 | USB | IDE | SIO | INTA3 |INTA2 | INTA1 | INTA0 |
250 * +--------------------------------------------------------------+
251 * 0x805 | INTD0 | INTC3 | INTC2 | INTC1 | INTC0 |INTB3 | INTB2 | INTB1 |
252 * +--------------------------------------------------------------+
253 * 0x806 | Rsrv | Rsrv | Rsrv | Rsrv | Rsrv |INTD3 | INTD2 | INTD1 |
254 * +--------------------------------------------------------------+
255 * * Rsrv = reserved bits
256 * Note: The mask register is write-only.
259 * 5 32 bit PCI option slot 2
260 * 6 64 bit PCI option slot 0
261 * 7 64 bit PCI option slot 1
263 * 9 32 bit PCI option slot 3
269 static inline int __init
270 alphapc164_map_irq(struct pci_dev
*dev
, u8 slot
, u8 pin
)
272 static char irq_tab
[7][5] __initlocaldata
= {
273 /*INT INTA INTB INTC INTD */
274 { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */
275 { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */
276 { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */
277 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
278 { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */
279 { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */
280 { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */
282 const long min_idsel
= 5, max_idsel
= 11, irqs_per_slot
= 5;
283 return COMMON_TABLE_LOOKUP
;
286 static inline void __init
287 alphapc164_init_pci(void)
298 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET)
299 struct alpha_machine_vector cabriolet_mv __initmv
= {
300 vector_name
: "Cabriolet",
305 machine_check
: apecs_machine_check
,
306 max_dma_address
: ALPHA_MAX_DMA_ADDRESS
,
307 min_io_address
: DEFAULT_IO_BASE
,
308 min_mem_address
: APECS_AND_LCA_DEFAULT_MEM_BASE
,
311 device_interrupt
: cabriolet_device_interrupt
,
313 init_arch
: apecs_init_arch
,
314 init_irq
: cabriolet_init_irq
,
315 init_rtc
: common_init_rtc
,
316 init_pci
: cabriolet_init_pci
,
318 pci_map_irq
: cabriolet_map_irq
,
319 pci_swizzle
: common_swizzle
,
324 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164)
325 struct alpha_machine_vector eb164_mv __initmv
= {
326 vector_name
: "EB164",
331 machine_check
: cia_machine_check
,
332 max_dma_address
: ALPHA_MAX_DMA_ADDRESS
,
333 min_io_address
: DEFAULT_IO_BASE
,
334 min_mem_address
: CIA_DEFAULT_MEM_BASE
,
337 device_interrupt
: cabriolet_device_interrupt
,
339 init_arch
: cia_init_arch
,
340 init_irq
: cabriolet_init_irq
,
341 init_rtc
: common_init_rtc
,
342 init_pci
: cabriolet_init_pci
,
343 pci_map_irq
: cabriolet_map_irq
,
344 pci_swizzle
: common_swizzle
,
349 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P)
350 struct alpha_machine_vector eb66p_mv __initmv
= {
351 vector_name
: "EB66+",
356 machine_check
: lca_machine_check
,
357 max_dma_address
: ALPHA_MAX_DMA_ADDRESS
,
358 min_io_address
: DEFAULT_IO_BASE
,
359 min_mem_address
: APECS_AND_LCA_DEFAULT_MEM_BASE
,
362 device_interrupt
: cabriolet_device_interrupt
,
364 init_arch
: lca_init_arch
,
365 init_irq
: cabriolet_init_irq
,
366 init_rtc
: common_init_rtc
,
367 init_pci
: cabriolet_init_pci
,
368 pci_map_irq
: eb66p_map_irq
,
369 pci_swizzle
: common_swizzle
,
374 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164)
375 struct alpha_machine_vector lx164_mv __initmv
= {
376 vector_name
: "LX164",
381 machine_check
: pyxis_machine_check
,
382 max_dma_address
: ALPHA_MAX_DMA_ADDRESS
,
383 min_io_address
: DEFAULT_IO_BASE
,
384 min_mem_address
: DEFAULT_MEM_BASE
,
387 device_interrupt
: cabriolet_device_interrupt
,
389 init_arch
: pyxis_init_arch
,
390 init_irq
: cabriolet_init_irq
,
391 init_rtc
: common_init_rtc
,
392 init_pci
: alphapc164_init_pci
,
393 pci_map_irq
: alphapc164_map_irq
,
394 pci_swizzle
: common_swizzle
,
399 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
400 struct alpha_machine_vector pc164_mv __initmv
= {
401 vector_name
: "PC164",
406 machine_check
: cia_machine_check
,
407 max_dma_address
: ALPHA_MAX_DMA_ADDRESS
,
408 min_io_address
: DEFAULT_IO_BASE
,
409 min_mem_address
: CIA_DEFAULT_MEM_BASE
,
412 device_interrupt
: pc164_device_interrupt
,
414 init_arch
: cia_init_arch
,
415 init_irq
: cabriolet_init_irq
,
416 init_rtc
: common_init_rtc
,
417 init_pci
: alphapc164_init_pci
,
418 pci_map_irq
: alphapc164_map_irq
,
419 pci_swizzle
: common_swizzle
,