blob: 6f16dee280a89ef2c457b5e2714d962cf10bb8ca [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/kernel.h>
2#include <linux/init.h>
3#include <linux/pci.h>
4#include <linux/slab.h>
5#include <asm/oplib.h>
6#include <asm/isa.h>
7
8struct sparc_isa_bridge *isa_chain;
9
10static void __init fatal_err(const char *reason)
11{
12 prom_printf("ISA: fatal error, %s.\n", reason);
13}
14
15static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
16{
17 if (child)
David S. Miller690c8fd2006-06-22 19:12:03 -070018 printk(" (%s)", isa_dev->prom_node->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 else
David S. Miller690c8fd2006-06-22 19:12:03 -070020 printk(" [%s", isa_dev->prom_node->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070021}
22
David S. Miller690c8fd2006-06-22 19:12:03 -070023static struct linux_prom_registers * __init
24isa_dev_get_resource(struct sparc_isa_device *isa_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070025{
David S. Miller690c8fd2006-06-22 19:12:03 -070026 struct linux_prom_registers *pregs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 unsigned long base, len;
28 int prop_len;
29
David S. Miller690c8fd2006-06-22 19:12:03 -070030 pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32 /* Only the first one is interesting. */
33 len = pregs[0].reg_size;
34 base = (((unsigned long)pregs[0].which_io << 32) |
35 (unsigned long)pregs[0].phys_addr);
36 base += isa_dev->bus->parent->io_space.start;
37
38 isa_dev->resource.start = base;
39 isa_dev->resource.end = (base + len - 1UL);
40 isa_dev->resource.flags = IORESOURCE_IO;
David S. Miller690c8fd2006-06-22 19:12:03 -070041 isa_dev->resource.name = isa_dev->prom_node->name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43 request_resource(&isa_dev->bus->parent->io_space,
44 &isa_dev->resource);
David S. Miller690c8fd2006-06-22 19:12:03 -070045
46 return pregs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047}
48
49/* I can't believe they didn't put a real INO in the isa device
50 * interrupts property. The whole point of the OBP properties
51 * is to shield the kernel from IRQ routing details.
52 *
53 * The P1275 standard for ISA devices seems to also have been
54 * totally ignored.
55 *
56 * On later systems, an interrupt-map and interrupt-map-mask scheme
57 * akin to EBUS is used.
58 */
59static struct {
60 int obp_irq;
61 int pci_ino;
62} grover_irq_table[] = {
63 { 1, 0x00 }, /* dma, unknown ino at this point */
64 { 2, 0x27 }, /* floppy */
65 { 3, 0x22 }, /* parallel */
66 { 4, 0x2b }, /* serial */
67 { 5, 0x25 }, /* acpi power management */
68
69 { 0, 0x00 } /* end of table */
70};
71
72static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev,
73 struct sparc_isa_bridge *isa_br,
74 int *interrupt,
David S. Miller9c10a582006-06-22 19:31:11 -070075 struct linux_prom_registers *reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
David S. Miller9c10a582006-06-22 19:31:11 -070077 struct linux_prom_ebus_intmap *imap;
78 struct linux_prom_ebus_intmap *imask;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 unsigned int hi, lo, irq;
David S. Miller9c10a582006-06-22 19:31:11 -070080 int i, len, n_imap;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
David S. Miller9c10a582006-06-22 19:31:11 -070082 imap = of_get_property(isa_br->prom_node, "interrupt-map", &len);
83 if (!imap)
84 return 0;
85 n_imap = len / sizeof(imap[0]);
86
87 imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL);
88 if (!imask)
89 return 0;
90
91 hi = reg->which_io & imask->phys_hi;
92 lo = reg->phys_addr & imask->phys_lo;
93 irq = *interrupt & imask->interrupt;
94 for (i = 0; i < n_imap; i++) {
95 if ((imap[i].phys_hi == hi) &&
96 (imap[i].phys_lo == lo) &&
97 (imap[i].interrupt == irq)) {
98 *interrupt = imap[i].cinterrupt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 return 0;
100 }
101 }
102 return -1;
103}
104
105static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
106 struct linux_prom_registers *pregs)
107{
108 int irq_prop;
109
David S. Miller690c8fd2006-06-22 19:12:03 -0700110 irq_prop = of_getintprop_default(isa_dev->prom_node,
111 "interrupts", -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 if (irq_prop <= 0) {
113 goto no_irq;
114 } else {
115 struct pci_controller_info *pcic;
116 struct pci_pbm_info *pbm;
117 int i;
118
David S. Miller9c10a582006-06-22 19:31:11 -0700119 if (of_find_property(isa_dev->bus->prom_node,
120 "interrupt-map", NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 if (!isa_dev_get_irq_using_imap(isa_dev,
122 isa_dev->bus,
123 &irq_prop,
124 pregs))
125 goto route_irq;
126 }
127
128 for (i = 0; grover_irq_table[i].obp_irq != 0; i++) {
129 if (grover_irq_table[i].obp_irq == irq_prop) {
130 int ino = grover_irq_table[i].pci_ino;
131
132 if (ino == 0)
133 goto no_irq;
134
135 irq_prop = ino;
136 goto route_irq;
137 }
138 }
139 goto no_irq;
140
141route_irq:
142 pbm = isa_dev->bus->parent;
143 pcic = pbm->parent;
144 isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop);
145 return;
146 }
147
148no_irq:
149 isa_dev->irq = PCI_IRQ_NONE;
150}
151
152static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
153{
David S. Miller690c8fd2006-06-22 19:12:03 -0700154 struct device_node *dp = parent_isa_dev->prom_node->child;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
David S. Miller690c8fd2006-06-22 19:12:03 -0700156 if (!dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 return;
158
159 printk(" ->");
David S. Miller690c8fd2006-06-22 19:12:03 -0700160 while (dp) {
161 struct linux_prom_registers *regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 struct sparc_isa_device *isa_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
165 if (!isa_dev) {
166 fatal_err("cannot allocate child isa_dev");
167 prom_halt();
168 }
169
170 memset(isa_dev, 0, sizeof(*isa_dev));
171
172 /* Link it in to parent. */
173 isa_dev->next = parent_isa_dev->child;
174 parent_isa_dev->child = isa_dev;
175
176 isa_dev->bus = parent_isa_dev->bus;
David S. Miller690c8fd2006-06-22 19:12:03 -0700177 isa_dev->prom_node = dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
David S. Miller690c8fd2006-06-22 19:12:03 -0700179 regs = isa_dev_get_resource(isa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 isa_dev_get_irq(isa_dev, regs);
181
182 report_dev(isa_dev, 1);
183
David S. Miller690c8fd2006-06-22 19:12:03 -0700184 dp = dp->sibling;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 }
186}
187
188static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
189{
David S. Miller690c8fd2006-06-22 19:12:03 -0700190 struct device_node *dp = isa_br->prom_node->child;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
David S. Miller690c8fd2006-06-22 19:12:03 -0700192 while (dp) {
193 struct linux_prom_registers *regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 struct sparc_isa_device *isa_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196 isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
197 if (!isa_dev) {
David S. Millera2bd4fd2006-06-23 01:44:10 -0700198 printk(KERN_DEBUG "ISA: cannot allocate isa_dev");
199 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
201
202 memset(isa_dev, 0, sizeof(*isa_dev));
203
David S. Millera2bd4fd2006-06-23 01:44:10 -0700204 isa_dev->ofdev.node = dp;
205 isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
206 isa_dev->ofdev.dev.bus = &isa_bus_type;
207 strcpy(isa_dev->ofdev.dev.bus_id, dp->path_component_name);
208
209 /* Register with core */
210 if (of_device_register(&isa_dev->ofdev) != 0) {
211 printk(KERN_DEBUG "isa: device registration error for %s!\n",
212 isa_dev->ofdev.dev.bus_id);
213 kfree(isa_dev);
214 goto next_sibling;
215 }
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 /* Link it in. */
218 isa_dev->next = NULL;
219 if (isa_br->devices == NULL) {
220 isa_br->devices = isa_dev;
221 } else {
222 struct sparc_isa_device *tmp = isa_br->devices;
223
224 while (tmp->next)
225 tmp = tmp->next;
226
227 tmp->next = isa_dev;
228 }
229
230 isa_dev->bus = isa_br;
David S. Miller690c8fd2006-06-22 19:12:03 -0700231 isa_dev->prom_node = dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
David S. Miller690c8fd2006-06-22 19:12:03 -0700233 regs = isa_dev_get_resource(isa_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 isa_dev_get_irq(isa_dev, regs);
235
236 report_dev(isa_dev, 0);
237
238 isa_fill_children(isa_dev);
239
240 printk("]");
241
David S. Millera2bd4fd2006-06-23 01:44:10 -0700242 next_sibling:
David S. Miller690c8fd2006-06-22 19:12:03 -0700243 dp = dp->sibling;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 }
245}
246
247void __init isa_init(void)
248{
249 struct pci_dev *pdev;
250 unsigned short vendor, device;
251 int index = 0;
252
253 vendor = PCI_VENDOR_ID_AL;
254 device = PCI_DEVICE_ID_AL_M1533;
255
256 pdev = NULL;
257 while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) {
258 struct pcidev_cookie *pdev_cookie;
259 struct pci_pbm_info *pbm;
260 struct sparc_isa_bridge *isa_br;
David S. Millera2bd4fd2006-06-23 01:44:10 -0700261 struct device_node *dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263 pdev_cookie = pdev->sysdata;
264 if (!pdev_cookie) {
265 printk("ISA: Warning, ISA bridge ignored due to "
266 "lack of OBP data.\n");
267 continue;
268 }
269 pbm = pdev_cookie->pbm;
David S. Millera2bd4fd2006-06-23 01:44:10 -0700270 dp = pdev_cookie->prom_node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272 isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
273 if (!isa_br) {
David S. Millera2bd4fd2006-06-23 01:44:10 -0700274 printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge");
275 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 }
277
278 memset(isa_br, 0, sizeof(*isa_br));
279
David S. Millera2bd4fd2006-06-23 01:44:10 -0700280 isa_br->ofdev.node = dp;
281 isa_br->ofdev.dev.parent = &pdev->dev;
282 isa_br->ofdev.dev.bus = &isa_bus_type;
283 strcpy(isa_br->ofdev.dev.bus_id, dp->path_component_name);
284
285 /* Register with core */
286 if (of_device_register(&isa_br->ofdev) != 0) {
287 printk(KERN_DEBUG "isa: device registration error for %s!\n",
288 isa_br->ofdev.dev.bus_id);
289 kfree(isa_br);
290 return;
291 }
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 /* Link it in. */
294 isa_br->next = isa_chain;
295 isa_chain = isa_br;
296
297 isa_br->parent = pbm;
298 isa_br->self = pdev;
299 isa_br->index = index++;
David S. Miller690c8fd2006-06-22 19:12:03 -0700300 isa_br->prom_node = pdev_cookie->prom_node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 printk("isa%d:", isa_br->index);
303
304 isa_fill_devices(isa_br);
305
306 printk("\n");
307 }
308}