11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Basic EISA bus support for the SGI Indigo-2. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * (C) 2002 Pascal Dameme <netinet@freesurf.fr> 51da177e4SLinus Torvalds * and Marc Zyngier <mzyngier@freesurf.fr> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This code is released under both the GPL version 2 and BSD 81da177e4SLinus Torvalds * licenses. Either license may be used. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * This code offers a very basic support for this EISA bus present in 111da177e4SLinus Torvalds * the SGI Indigo-2. It currently only supports PIO (forget about DMA 121da177e4SLinus Torvalds * for the time being). This is enough for a low-end ethernet card, 131da177e4SLinus Torvalds * but forget about your favorite SCSI card... 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * TODO : 161da177e4SLinus Torvalds * - Fix bugs... 171da177e4SLinus Torvalds * - Add ISA support 181da177e4SLinus Torvalds * - Add DMA (yeah, right...). 191da177e4SLinus Torvalds * - Fix more bugs. 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <linux/config.h> 231da177e4SLinus Torvalds #include <linux/eisa.h> 241da177e4SLinus Torvalds #include <linux/types.h> 251da177e4SLinus Torvalds #include <linux/init.h> 261da177e4SLinus Torvalds #include <linux/irq.h> 271da177e4SLinus Torvalds #include <linux/kernel_stat.h> 281da177e4SLinus Torvalds #include <linux/signal.h> 291da177e4SLinus Torvalds #include <linux/sched.h> 301da177e4SLinus Torvalds #include <linux/interrupt.h> 311da177e4SLinus Torvalds #include <linux/delay.h> 321da177e4SLinus Torvalds #include <asm/irq.h> 331da177e4SLinus Torvalds #include <asm/mipsregs.h> 341da177e4SLinus Torvalds #include <asm/addrspace.h> 351da177e4SLinus Torvalds #include <asm/processor.h> 361da177e4SLinus Torvalds #include <asm/sgi/ioc.h> 371da177e4SLinus Torvalds #include <asm/sgi/mc.h> 381da177e4SLinus Torvalds #include <asm/sgi/ip22.h> 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds #define EISA_MAX_SLOTS 4 411da177e4SLinus Torvalds #define EISA_MAX_IRQ 16 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds #define EISA_TO_PHYS(x) (0x00080000 | (x)) 441da177e4SLinus Torvalds #define EISA_TO_KSEG1(x) ((void *) KSEG1ADDR(EISA_TO_PHYS((x)))) 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #define EIU_MODE_REG 0x0009ffc0 471da177e4SLinus Torvalds #define EIU_STAT_REG 0x0009ffc4 481da177e4SLinus Torvalds #define EIU_PREMPT_REG 0x0009ffc8 491da177e4SLinus Torvalds #define EIU_QUIET_REG 0x0009ffcc 501da177e4SLinus Torvalds #define EIU_INTRPT_ACK 0x00090004 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds #define EISA_DMA1_STATUS 8 531da177e4SLinus Torvalds #define EISA_INT1_CTRL 0x20 541da177e4SLinus Torvalds #define EISA_INT1_MASK 0x21 551da177e4SLinus Torvalds #define EISA_INT2_CTRL 0xA0 561da177e4SLinus Torvalds #define EISA_INT2_MASK 0xA1 571da177e4SLinus Torvalds #define EISA_DMA2_STATUS 0xD0 581da177e4SLinus Torvalds #define EISA_DMA2_WRITE_SINGLE 0xD4 591da177e4SLinus Torvalds #define EISA_EXT_NMI_RESET_CTRL 0x461 601da177e4SLinus Torvalds #define EISA_INT1_EDGE_LEVEL 0x4D0 611da177e4SLinus Torvalds #define EISA_INT2_EDGE_LEVEL 0x4D1 621da177e4SLinus Torvalds #define EISA_VENDOR_ID_OFFSET 0xC80 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds #define EIU_WRITE_32(x,y) { *((u32 *) KSEG1ADDR(x)) = (u32) (y); mb(); } 651da177e4SLinus Torvalds #define EIU_READ_8(x) *((u8 *) KSEG1ADDR(x)) 661da177e4SLinus Torvalds #define EISA_WRITE_8(x,y) { *((u8 *) EISA_TO_KSEG1(x)) = (u8) (y); mb(); } 671da177e4SLinus Torvalds #define EISA_READ_8(x) *((u8 *) EISA_TO_KSEG1(x)) 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds static char *decode_eisa_sig(u8 * sig) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds static char sig_str[8]; 721da177e4SLinus Torvalds u16 rev; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds if (sig[0] & 0x80) 751da177e4SLinus Torvalds return NULL; 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds sig_str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); 781da177e4SLinus Torvalds sig_str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); 791da177e4SLinus Torvalds sig_str[2] = (sig[1] & 0x1f) + ('A' - 1); 801da177e4SLinus Torvalds rev = (sig[2] << 8) | sig[3]; 811da177e4SLinus Torvalds sprintf(sig_str + 3, "%04X", rev); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds return sig_str; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds static void ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds u8 eisa_irq; 891da177e4SLinus Torvalds u8 dma1, dma2; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds eisa_irq = EIU_READ_8(EIU_INTRPT_ACK); 921da177e4SLinus Torvalds dma1 = EISA_READ_8(EISA_DMA1_STATUS); 931da177e4SLinus Torvalds dma2 = EISA_READ_8(EISA_DMA2_STATUS); 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds if (eisa_irq >= EISA_MAX_IRQ) { 961da177e4SLinus Torvalds /* Oops, Bad Stuff Happened... */ 971da177e4SLinus Torvalds printk(KERN_ERR "eisa_irq %d out of bound\n", eisa_irq); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_CTRL, 0x20); 1001da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_CTRL, 0x20); 1011da177e4SLinus Torvalds } else 1021da177e4SLinus Torvalds do_IRQ(eisa_irq, regs); 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds static void enable_eisa1_irq(unsigned int irq) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds unsigned long flags; 1081da177e4SLinus Torvalds u8 mask; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds local_irq_save(flags); 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds mask = EISA_READ_8(EISA_INT1_MASK); 1131da177e4SLinus Torvalds mask &= ~((u8) (1 << irq)); 1141da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_MASK, mask); 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds local_irq_restore(flags); 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds static unsigned int startup_eisa1_irq(unsigned int irq) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds u8 edge; 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds /* Only use edge interrupts for EISA */ 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds edge = EISA_READ_8(EISA_INT1_EDGE_LEVEL); 1261da177e4SLinus Torvalds edge &= ~((u8) (1 << irq)); 1271da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_EDGE_LEVEL, edge); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds enable_eisa1_irq(irq); 1301da177e4SLinus Torvalds return 0; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static void disable_eisa1_irq(unsigned int irq) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds u8 mask; 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds mask = EISA_READ_8(EISA_INT1_MASK); 1381da177e4SLinus Torvalds mask |= ((u8) (1 << irq)); 1391da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_MASK, mask); 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds #define shutdown_eisa1_irq disable_eisa1_irq 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds static void mask_and_ack_eisa1_irq(unsigned int irq) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds disable_eisa1_irq(irq); 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_CTRL, 0x20); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static void end_eisa1_irq(unsigned int irq) 1521da177e4SLinus Torvalds { 1531da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 1541da177e4SLinus Torvalds enable_eisa1_irq(irq); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds static struct hw_interrupt_type ip22_eisa1_irq_type = { 1581da177e4SLinus Torvalds .typename = "IP22 EISA", 1591da177e4SLinus Torvalds .startup = startup_eisa1_irq, 1601da177e4SLinus Torvalds .shutdown = shutdown_eisa1_irq, 1611da177e4SLinus Torvalds .enable = enable_eisa1_irq, 1621da177e4SLinus Torvalds .disable = disable_eisa1_irq, 1631da177e4SLinus Torvalds .ack = mask_and_ack_eisa1_irq, 1641da177e4SLinus Torvalds .end = end_eisa1_irq, 1651da177e4SLinus Torvalds }; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds static void enable_eisa2_irq(unsigned int irq) 1681da177e4SLinus Torvalds { 1691da177e4SLinus Torvalds unsigned long flags; 1701da177e4SLinus Torvalds u8 mask; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds local_irq_save(flags); 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds mask = EISA_READ_8(EISA_INT2_MASK); 1751da177e4SLinus Torvalds mask &= ~((u8) (1 << (irq - 8))); 1761da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_MASK, mask); 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds local_irq_restore(flags); 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds static unsigned int startup_eisa2_irq(unsigned int irq) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds u8 edge; 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds /* Only use edge interrupts for EISA */ 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds edge = EISA_READ_8(EISA_INT2_EDGE_LEVEL); 1881da177e4SLinus Torvalds edge &= ~((u8) (1 << (irq - 8))); 1891da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_EDGE_LEVEL, edge); 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds enable_eisa2_irq(irq); 1921da177e4SLinus Torvalds return 0; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds static void disable_eisa2_irq(unsigned int irq) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds u8 mask; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds mask = EISA_READ_8(EISA_INT2_MASK); 2001da177e4SLinus Torvalds mask |= ((u8) (1 << (irq - 8))); 2011da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_MASK, mask); 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds #define shutdown_eisa2_irq disable_eisa2_irq 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds static void mask_and_ack_eisa2_irq(unsigned int irq) 2071da177e4SLinus Torvalds { 2081da177e4SLinus Torvalds disable_eisa2_irq(irq); 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_CTRL, 0x20); 2111da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_CTRL, 0x20); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds static void end_eisa2_irq(unsigned int irq) 2151da177e4SLinus Torvalds { 2161da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 2171da177e4SLinus Torvalds enable_eisa2_irq(irq); 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds static struct hw_interrupt_type ip22_eisa2_irq_type = { 2211da177e4SLinus Torvalds .typename = "IP22 EISA", 2221da177e4SLinus Torvalds .startup = startup_eisa2_irq, 2231da177e4SLinus Torvalds .shutdown = shutdown_eisa2_irq, 2241da177e4SLinus Torvalds .enable = enable_eisa2_irq, 2251da177e4SLinus Torvalds .disable = disable_eisa2_irq, 2261da177e4SLinus Torvalds .ack = mask_and_ack_eisa2_irq, 2271da177e4SLinus Torvalds .end = end_eisa2_irq, 2281da177e4SLinus Torvalds }; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds static struct irqaction eisa_action = { 2311da177e4SLinus Torvalds .handler = ip22_eisa_intr, 2321da177e4SLinus Torvalds .name = "EISA", 2331da177e4SLinus Torvalds }; 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds static struct irqaction cascade_action = { 2361da177e4SLinus Torvalds .handler = no_action, 2371da177e4SLinus Torvalds .name = "EISA cascade", 2381da177e4SLinus Torvalds }; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds int __init ip22_eisa_init(void) 2411da177e4SLinus Torvalds { 2421da177e4SLinus Torvalds int i, c; 2431da177e4SLinus Torvalds char *str; 2441da177e4SLinus Torvalds u8 *slot_addr; 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) { 2471da177e4SLinus Torvalds printk(KERN_INFO "EISA: bus not present.\n"); 2481da177e4SLinus Torvalds return 1; 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds printk(KERN_INFO "EISA: Probing bus...\n"); 2521da177e4SLinus Torvalds for (c = 0, i = 1; i <= EISA_MAX_SLOTS; i++) { 2531da177e4SLinus Torvalds slot_addr = 2541da177e4SLinus Torvalds (u8 *) EISA_TO_KSEG1((0x1000 * i) + 2551da177e4SLinus Torvalds EISA_VENDOR_ID_OFFSET); 2561da177e4SLinus Torvalds if ((str = decode_eisa_sig(slot_addr))) { 2571da177e4SLinus Torvalds printk(KERN_INFO "EISA: slot %d : %s detected.\n", 2581da177e4SLinus Torvalds i, str); 2591da177e4SLinus Torvalds c++; 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds printk(KERN_INFO "EISA: Detected %d card%s.\n", c, c < 2 ? "" : "s"); 2631da177e4SLinus Torvalds #ifdef CONFIG_ISA 2641da177e4SLinus Torvalds printk(KERN_INFO "ISA support compiled in.\n"); 2651da177e4SLinus Torvalds #endif 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds /* Warning : BlackMagicAhead(tm). 2681da177e4SLinus Torvalds Please wave your favorite dead chicken over the busses */ 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds /* First say hello to the EIU */ 2711da177e4SLinus Torvalds EIU_WRITE_32(EIU_PREMPT_REG, 0x0000FFFF); 2721da177e4SLinus Torvalds EIU_WRITE_32(EIU_QUIET_REG, 1); 2731da177e4SLinus Torvalds EIU_WRITE_32(EIU_MODE_REG, 0x40f3c07F); 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds /* Now be nice to the EISA chipset */ 2761da177e4SLinus Torvalds EISA_WRITE_8(EISA_EXT_NMI_RESET_CTRL, 1); 2771da177e4SLinus Torvalds for (i = 0; i < 10000; i++); /* Wait long enough for the dust to settle */ 2781da177e4SLinus Torvalds EISA_WRITE_8(EISA_EXT_NMI_RESET_CTRL, 0); 2791da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_CTRL, 0x11); 2801da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_CTRL, 0x11); 2811da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_MASK, 0); 2821da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_MASK, 8); 2831da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_MASK, 4); 2841da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_MASK, 2); 2851da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_MASK, 1); 2861da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_MASK, 1); 2871da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT1_MASK, 0xfb); 2881da177e4SLinus Torvalds EISA_WRITE_8(EISA_INT2_MASK, 0xff); 2891da177e4SLinus Torvalds EISA_WRITE_8(EISA_DMA2_WRITE_SINGLE, 0); 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds for (i = SGINT_EISA; i < (SGINT_EISA + EISA_MAX_IRQ); i++) { 2921da177e4SLinus Torvalds irq_desc[i].status = IRQ_DISABLED; 2931da177e4SLinus Torvalds irq_desc[i].action = 0; 2941da177e4SLinus Torvalds irq_desc[i].depth = 1; 2951da177e4SLinus Torvalds if (i < (SGINT_EISA + 8)) 2961da177e4SLinus Torvalds irq_desc[i].handler = &ip22_eisa1_irq_type; 2971da177e4SLinus Torvalds else 2981da177e4SLinus Torvalds irq_desc[i].handler = &ip22_eisa2_irq_type; 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds /* Cannot use request_irq because of kmalloc not being ready at such 3021da177e4SLinus Torvalds * an early stage. Yes, I've been bitten... */ 3031da177e4SLinus Torvalds setup_irq(SGI_EISA_IRQ, &eisa_action); 3041da177e4SLinus Torvalds setup_irq(SGINT_EISA + 2, &cascade_action); 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds EISA_bus = 1; 3071da177e4SLinus Torvalds return 0; 3081da177e4SLinus Torvalds } 309