1 | /* |
2 | * Basic EISA bus support for the SGI Indigo-2. |
3 | * |
4 | * (C) 2002 Pascal Dameme <netinet@freesurf.fr> |
5 | * and Marc Zyngier <mzyngier@freesurf.fr> |
6 | * |
7 | * This code is released under both the GPL version 2 and BSD |
8 | * licenses. Either license may be used. |
9 | * |
10 | * This code offers a very basic support for this EISA bus present in |
11 | * the SGI Indigo-2. It currently only supports PIO (forget about DMA |
12 | * for the time being). This is enough for a low-end ethernet card, |
13 | * but forget about your favorite SCSI card... |
14 | * |
15 | * TODO : |
16 | * - Fix bugs... |
17 | * - Add ISA support |
18 | * - Add DMA (yeah, right...). |
19 | * - Fix more bugs. |
20 | */ |
21 | |
22 | #include <linux/eisa.h> |
23 | #include <linux/types.h> |
24 | #include <linux/init.h> |
25 | #include <linux/irq.h> |
26 | #include <linux/kernel_stat.h> |
27 | #include <linux/signal.h> |
28 | #include <linux/sched.h> |
29 | #include <linux/interrupt.h> |
30 | #include <linux/delay.h> |
31 | #include <asm/io.h> |
32 | #include <asm/irq.h> |
33 | #include <asm/mipsregs.h> |
34 | #include <asm/addrspace.h> |
35 | #include <asm/processor.h> |
36 | #include <asm/sgi/ioc.h> |
37 | #include <asm/sgi/mc.h> |
38 | #include <asm/sgi/ip22.h> |
39 | #include <asm/i8259.h> |
40 | |
41 | /* I2 has four EISA slots. */ |
42 | #define IP22_EISA_MAX_SLOTS 4 |
43 | #define EISA_MAX_IRQ 16 |
44 | |
45 | #define EIU_MODE_REG 0x0001ffc0 |
46 | #define EIU_STAT_REG 0x0001ffc4 |
47 | #define EIU_PREMPT_REG 0x0001ffc8 |
48 | #define EIU_QUIET_REG 0x0001ffcc |
49 | #define EIU_INTRPT_ACK 0x00010004 |
50 | |
51 | static char __init *decode_eisa_sig(unsigned long addr) |
52 | { |
53 | static char sig_str[EISA_SIG_LEN] __initdata; |
54 | u8 sig[4]; |
55 | u16 rev; |
56 | int i; |
57 | |
58 | for (i = 0; i < 4; i++) { |
59 | sig[i] = inb(port: addr + i); |
60 | |
61 | if (!i && (sig[0] & 0x80)) |
62 | return NULL; |
63 | } |
64 | |
65 | sig_str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); |
66 | sig_str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); |
67 | sig_str[2] = (sig[1] & 0x1f) + ('A' - 1); |
68 | rev = (sig[2] << 8) | sig[3]; |
69 | sprintf(buf: sig_str + 3, fmt: "%04X" , rev); |
70 | |
71 | return sig_str; |
72 | } |
73 | |
74 | static irqreturn_t ip22_eisa_intr(int irq, void *dev_id) |
75 | { |
76 | u8 eisa_irq = inb(EIU_INTRPT_ACK); |
77 | |
78 | inb(EISA_DMA1_STATUS); |
79 | inb(EISA_DMA2_STATUS); |
80 | |
81 | if (eisa_irq < EISA_MAX_IRQ) { |
82 | do_IRQ(eisa_irq); |
83 | return IRQ_HANDLED; |
84 | } |
85 | |
86 | /* Oops, Bad Stuff Happened... */ |
87 | printk(KERN_ERR "eisa_irq %d out of bound\n" , eisa_irq); |
88 | |
89 | outb(value: 0x20, EISA_INT2_CTRL); |
90 | outb(value: 0x20, EISA_INT1_CTRL); |
91 | |
92 | return IRQ_NONE; |
93 | } |
94 | |
95 | int __init ip22_eisa_init(void) |
96 | { |
97 | int i, c; |
98 | char *str; |
99 | |
100 | if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) { |
101 | printk(KERN_INFO "EISA: bus not present.\n" ); |
102 | return 1; |
103 | } |
104 | |
105 | printk(KERN_INFO "EISA: Probing bus...\n" ); |
106 | for (c = 0, i = 1; i <= IP22_EISA_MAX_SLOTS; i++) { |
107 | if ((str = decode_eisa_sig(addr: 0x1000 * i + EISA_VENDOR_ID_OFFSET))) { |
108 | printk(KERN_INFO "EISA: slot %d : %s detected.\n" , |
109 | i, str); |
110 | c++; |
111 | } |
112 | } |
113 | printk(KERN_INFO "EISA: Detected %d card%s.\n" , c, c < 2 ? "" : "s" ); |
114 | #ifdef CONFIG_ISA |
115 | printk(KERN_INFO "ISA support compiled in.\n" ); |
116 | #endif |
117 | |
118 | /* Warning : BlackMagicAhead(tm). |
119 | Please wave your favorite dead chicken over the busses */ |
120 | |
121 | /* First say hello to the EIU */ |
122 | outl(value: 0x0000FFFF, EIU_PREMPT_REG); |
123 | outl(value: 1, EIU_QUIET_REG); |
124 | outl(value: 0x40f3c07F, EIU_MODE_REG); |
125 | |
126 | /* Now be nice to the EISA chipset */ |
127 | outb(value: 1, EISA_EXT_NMI_RESET_CTRL); |
128 | udelay(50); /* Wait long enough for the dust to settle */ |
129 | outb(value: 0, EISA_EXT_NMI_RESET_CTRL); |
130 | outb(value: 0, EISA_DMA2_WRITE_SINGLE); |
131 | |
132 | init_i8259_irqs(); |
133 | |
134 | if (request_irq(irq: SGI_EISA_IRQ, handler: ip22_eisa_intr, flags: 0, name: "EISA" , NULL)) |
135 | pr_err("Failed to request irq %d (EISA)\n" , SGI_EISA_IRQ); |
136 | |
137 | EISA_bus = 1; |
138 | return 0; |
139 | } |
140 | |