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. */ 39static unsigned long cached_irq_mask = ~0UL; 40 41static inline void 42cabriolet_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 48static inline void 49cabriolet_enable_irq(unsigned int irq) 50{ 51 cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq)); 52} 53 54static void 55cabriolet_disable_irq(unsigned int irq) 56{ 57 cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq); 58} 59 60static unsigned int 61cabriolet_startup_irq(unsigned int irq) 62{ 63 cabriolet_enable_irq(irq); 64 return 0; /* never anything pending */ 65} 66 67static void 68cabriolet_end_irq(unsigned int irq) 69{ 70 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 71 cabriolet_enable_irq(irq); 72} 73 74static 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 84static void 85cabriolet_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 108static void __init 109common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r)) 110{ 111 init_i8259a_irqs(); 112 113 if (alpha_using_srm) { 114 alpha_mv.device_interrupt = srm_dev_int; 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 134static void __init 135cabriolet_init_irq(void) 136{ 137 common_init_irq(srm_device_interrupt); 138} 139 140#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164) 141/* In theory, the PC164 has the same interrupt hardware as the other 142 Cabriolet based systems. However, something got screwed up late 143 in the development cycle which broke the interrupt masking hardware. 144 Repeat, it is not possible to mask and ack interrupts. At all. 145 146 In an attempt to work around this, while processing interrupts, 147 we do not allow the IPL to drop below what it is currently. This 148 prevents the possibility of recursion. 149 150 ??? Another option might be to force all PCI devices to use edge 151 triggered rather than level triggered interrupts. That might be 152 too invasive though. */ 153 154static void 155pc164_srm_device_interrupt(unsigned long v, struct pt_regs *r) 156{ 157 __min_ipl = getipl(); 158 srm_device_interrupt(v, r); 159 __min_ipl = 0; 160} 161 162static void 163pc164_device_interrupt(unsigned long v, struct pt_regs *r) 164{ 165 __min_ipl = getipl(); 166 cabriolet_device_interrupt(v, r); 167 __min_ipl = 0; 168} 169 170static void __init 171pc164_init_irq(void) 172{ 173 common_init_irq(pc164_srm_device_interrupt); 174} 175#endif 176 177/* 178 * The EB66+ is very similar to the EB66 except that it does not have 179 * the on-board NCR and Tulip chips. In the code below, I have used 180 * slot number to refer to the id select line and *not* the slot 181 * number used in the EB66+ documentation. However, in the table, 182 * I've given the slot number, the id select line and the Jxx number 183 * that's printed on the board. The interrupt pins from the PCI slots 184 * are wired into 3 interrupt summary registers at 0x804, 0x805 and 185 * 0x806 ISA. 186 * 187 * In the table, -1 means don't assign an IRQ number. This is usually 188 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip. 189 */ 190 191static inline int __init 192eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin) 193{ 194 static char irq_tab[5][5] __initdata = { 195 /*INT INTA INTB INTC INTD */ 196 {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */ 197 {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */ 198 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ 199 {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */ 200 {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */ 201 }; 202 const long min_idsel = 6, max_idsel = 10, irqs_per_slot = 5; 203 return COMMON_TABLE_LOOKUP; 204} 205 206 207/* 208 * The AlphaPC64 is very similar to the EB66+ except that its slots 209 * are numbered differently. In the code below, I have used slot 210 * number to refer to the id select line and *not* the slot number 211 * used in the AlphaPC64 documentation. However, in the table, I've 212 * given the slot number, the id select line and the Jxx number that's 213 * printed on the board. The interrupt pins from the PCI slots are 214 * wired into 3 interrupt summary registers at 0x804, 0x805 and 0x806 215 * ISA. 216 * 217 * In the table, -1 means don't assign an IRQ number. This is usually 218 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip. 219 */ 220 221static inline int __init 222cabriolet_map_irq(struct pci_dev *dev, u8 slot, u8 pin) 223{ 224 static char irq_tab[5][5] __initdata = { 225 /*INT INTA INTB INTC INTD */ 226 { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */ 227 { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */ 228 { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */ 229 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ 230 { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */ 231 }; 232 const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5; 233 return COMMON_TABLE_LOOKUP; 234} 235 236static inline void __init 237cabriolet_init_pci(void) 238{ 239 common_init_pci(); 240 ns87312_enable_ide(0x398); 241} 242 243static inline void __init 244cia_cab_init_pci(void) 245{ 246 cia_init_pci(); 247 ns87312_enable_ide(0x398); 248} 249 250/* 251 * The PC164 and LX164 have 19 PCI interrupts, four from each of the four 252 * PCI slots, the SIO, PCI/IDE, and USB. 253 * 254 * Each of the interrupts can be individually masked. This is 255 * accomplished by setting the appropriate bit in the mask register. 256 * A bit is set by writing a "1" to the desired position in the mask 257 * register and cleared by writing a "0". There are 3 mask registers 258 * located at ISA address 804h, 805h and 806h. 259 * 260 * An I/O read at ISA address 804h, 805h, 806h will return the 261 * state of the 11 PCI interrupts and not the state of the MASKED 262 * interrupts. 263 * 264 * Note: A write to I/O 804h, 805h, and 806h the mask register will be 265 * updated. 266 * 267 * 268 * ISA DATA<7:0> 269 * ISA +--------------------------------------------------------------+ 270 * ADDRESS | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 271 * +==============================================================+ 272 * 0x804 | INTB0 | USB | IDE | SIO | INTA3 |INTA2 | INTA1 | INTA0 | 273 * +--------------------------------------------------------------+ 274 * 0x805 | INTD0 | INTC3 | INTC2 | INTC1 | INTC0 |INTB3 | INTB2 | INTB1 | 275 * +--------------------------------------------------------------+ 276 * 0x806 | Rsrv | Rsrv | Rsrv | Rsrv | Rsrv |INTD3 | INTD2 | INTD1 | 277 * +--------------------------------------------------------------+ 278 * * Rsrv = reserved bits 279 * Note: The mask register is write-only. 280 * 281 * IdSel 282 * 5 32 bit PCI option slot 2 283 * 6 64 bit PCI option slot 0 284 * 7 64 bit PCI option slot 1 285 * 8 Saturn I/O 286 * 9 32 bit PCI option slot 3 287 * 10 USB 288 * 11 IDE 289 * 290 */ 291 292static inline int __init 293alphapc164_map_irq(struct pci_dev *dev, u8 slot, u8 pin) 294{ 295 static char irq_tab[7][5] __initdata = { 296 /*INT INTA INTB INTC INTD */ 297 { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */ 298 { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */ 299 { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */ 300 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ 301 { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */ 302 { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */ 303 { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */ 304 }; 305 const long min_idsel = 5, max_idsel = 11, irqs_per_slot = 5; 306 return COMMON_TABLE_LOOKUP; 307} 308 309static inline void __init 310alphapc164_init_pci(void) 311{ 312 cia_init_pci(); 313 SMC93x_Init(); 314} 315 316 317/* 318 * The System Vector 319 */ 320 321#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET) 322struct alpha_machine_vector cabriolet_mv __initmv = { 323 vector_name: "Cabriolet", 324 DO_EV4_MMU, 325 DO_DEFAULT_RTC, 326 DO_APECS_IO, 327 DO_APECS_BUS, 328 machine_check: apecs_machine_check, 329 max_dma_address: ALPHA_MAX_DMA_ADDRESS, 330 min_io_address: DEFAULT_IO_BASE, 331 min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, 332 333 nr_irqs: 35, 334 device_interrupt: cabriolet_device_interrupt, 335 336 init_arch: apecs_init_arch, 337 init_irq: cabriolet_init_irq, 338 init_rtc: common_init_rtc, 339 init_pci: cabriolet_init_pci, 340 kill_arch: NULL, 341 pci_map_irq: cabriolet_map_irq, 342 pci_swizzle: common_swizzle, 343}; 344#ifndef CONFIG_ALPHA_EB64P 345ALIAS_MV(cabriolet) 346#endif 347#endif 348 349#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164) 350struct alpha_machine_vector eb164_mv __initmv = { 351 vector_name: "EB164", 352 DO_EV5_MMU, 353 DO_DEFAULT_RTC, 354 DO_CIA_IO, 355 DO_CIA_BUS, 356 machine_check: cia_machine_check, 357 max_dma_address: ALPHA_MAX_DMA_ADDRESS, 358 min_io_address: DEFAULT_IO_BASE, 359 min_mem_address: CIA_DEFAULT_MEM_BASE, 360 361 nr_irqs: 35, 362 device_interrupt: cabriolet_device_interrupt, 363 364 init_arch: cia_init_arch, 365 init_irq: cabriolet_init_irq, 366 init_rtc: common_init_rtc, 367 init_pci: cia_cab_init_pci, 368 pci_map_irq: cabriolet_map_irq, 369 pci_swizzle: common_swizzle, 370}; 371ALIAS_MV(eb164) 372#endif 373 374#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P) 375struct alpha_machine_vector eb66p_mv __initmv = { 376 vector_name: "EB66+", 377 DO_EV4_MMU, 378 DO_DEFAULT_RTC, 379 DO_LCA_IO, 380 DO_LCA_BUS, 381 machine_check: lca_machine_check, 382 max_dma_address: ALPHA_MAX_DMA_ADDRESS, 383 min_io_address: DEFAULT_IO_BASE, 384 min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, 385 386 nr_irqs: 35, 387 device_interrupt: cabriolet_device_interrupt, 388 389 init_arch: lca_init_arch, 390 init_irq: cabriolet_init_irq, 391 init_rtc: common_init_rtc, 392 init_pci: cabriolet_init_pci, 393 pci_map_irq: eb66p_map_irq, 394 pci_swizzle: common_swizzle, 395}; 396ALIAS_MV(eb66p) 397#endif 398 399#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164) 400struct alpha_machine_vector lx164_mv __initmv = { 401 vector_name: "LX164", 402 DO_EV5_MMU, 403 DO_DEFAULT_RTC, 404 DO_PYXIS_IO, 405 DO_CIA_BUS, 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: DEFAULT_MEM_BASE, 410 pci_dac_offset: PYXIS_DAC_OFFSET, 411 412 nr_irqs: 35, 413 device_interrupt: cabriolet_device_interrupt, 414 415 init_arch: pyxis_init_arch, 416 init_irq: cabriolet_init_irq, 417 init_rtc: common_init_rtc, 418 init_pci: alphapc164_init_pci, 419 pci_map_irq: alphapc164_map_irq, 420 pci_swizzle: common_swizzle, 421}; 422ALIAS_MV(lx164) 423#endif 424 425#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164) 426struct alpha_machine_vector pc164_mv __initmv = { 427 vector_name: "PC164", 428 DO_EV5_MMU, 429 DO_DEFAULT_RTC, 430 DO_CIA_IO, 431 DO_CIA_BUS, 432 machine_check: cia_machine_check, 433 max_dma_address: ALPHA_MAX_DMA_ADDRESS, 434 min_io_address: DEFAULT_IO_BASE, 435 min_mem_address: CIA_DEFAULT_MEM_BASE, 436 437 nr_irqs: 35, 438 device_interrupt: pc164_device_interrupt, 439 440 init_arch: cia_init_arch, 441 init_irq: pc164_init_irq, 442 init_rtc: common_init_rtc, 443 init_pci: alphapc164_init_pci, 444 pci_map_irq: alphapc164_map_irq, 445 pci_swizzle: common_swizzle, 446}; 447ALIAS_MV(pc164) 448#endif 449