[SPARC64]: Use in-kernel PROM tree for EBUS and ISA.
[cascardo/linux.git] / arch / sparc64 / kernel / isa.c
1 #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
8 struct sparc_isa_bridge *isa_chain;
9
10 static void __init fatal_err(const char *reason)
11 {
12         prom_printf("ISA: fatal error, %s.\n", reason);
13 }
14
15 static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
16 {
17         if (child)
18                 printk(" (%s)", isa_dev->prom_node->name);
19         else
20                 printk(" [%s", isa_dev->prom_node->name);
21 }
22
23 static struct linux_prom_registers * __init
24 isa_dev_get_resource(struct sparc_isa_device *isa_dev)
25 {
26         struct linux_prom_registers *pregs;
27         unsigned long base, len;
28         int prop_len;
29
30         pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);
31
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;
41         isa_dev->resource.name  = isa_dev->prom_node->name;
42
43         request_resource(&isa_dev->bus->parent->io_space,
44                          &isa_dev->resource);
45
46         return pregs;
47 }
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  */
59 static 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
72 static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev,
73                                              struct sparc_isa_bridge *isa_br,
74                                              int *interrupt,
75                                              struct linux_prom_registers *pregs)
76 {
77         unsigned int hi, lo, irq;
78         int i;
79
80         hi = pregs->which_io & isa_br->isa_intmask.phys_hi;
81         lo = pregs->phys_addr & isa_br->isa_intmask.phys_lo;
82         irq = *interrupt & isa_br->isa_intmask.interrupt;
83         for (i = 0; i < isa_br->num_isa_intmap; i++) {
84                 if ((isa_br->isa_intmap[i].phys_hi == hi) &&
85                     (isa_br->isa_intmap[i].phys_lo == lo) &&
86                     (isa_br->isa_intmap[i].interrupt == irq)) {
87                         *interrupt = isa_br->isa_intmap[i].cinterrupt;
88                         return 0;
89                 }
90         }
91         return -1;
92 }
93
94 static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
95                                    struct linux_prom_registers *pregs)
96 {
97         int irq_prop;
98
99         irq_prop = of_getintprop_default(isa_dev->prom_node,
100                                          "interrupts", -1);
101         if (irq_prop <= 0) {
102                 goto no_irq;
103         } else {
104                 struct pci_controller_info *pcic;
105                 struct pci_pbm_info *pbm;
106                 int i;
107
108                 if (isa_dev->bus->num_isa_intmap) {
109                         if (!isa_dev_get_irq_using_imap(isa_dev,
110                                                         isa_dev->bus,
111                                                         &irq_prop,
112                                                         pregs))
113                                 goto route_irq;
114                 }
115
116                 for (i = 0; grover_irq_table[i].obp_irq != 0; i++) {
117                         if (grover_irq_table[i].obp_irq == irq_prop) {
118                                 int ino = grover_irq_table[i].pci_ino;
119
120                                 if (ino == 0)
121                                         goto no_irq;
122  
123                                 irq_prop = ino;
124                                 goto route_irq;
125                         }
126                 }
127                 goto no_irq;
128
129 route_irq:
130                 pbm = isa_dev->bus->parent;
131                 pcic = pbm->parent;
132                 isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop);
133                 return;
134         }
135
136 no_irq:
137         isa_dev->irq = PCI_IRQ_NONE;
138 }
139
140 static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
141 {
142         struct device_node *dp = parent_isa_dev->prom_node->child;
143
144         if (!dp)
145                 return;
146
147         printk(" ->");
148         while (dp) {
149                 struct linux_prom_registers *regs;
150                 struct sparc_isa_device *isa_dev;
151
152                 isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
153                 if (!isa_dev) {
154                         fatal_err("cannot allocate child isa_dev");
155                         prom_halt();
156                 }
157
158                 memset(isa_dev, 0, sizeof(*isa_dev));
159
160                 /* Link it in to parent. */
161                 isa_dev->next = parent_isa_dev->child;
162                 parent_isa_dev->child = isa_dev;
163
164                 isa_dev->bus = parent_isa_dev->bus;
165                 isa_dev->prom_node = dp;
166
167                 regs = isa_dev_get_resource(isa_dev);
168                 isa_dev_get_irq(isa_dev, regs);
169
170                 report_dev(isa_dev, 1);
171
172                 dp = dp->sibling;
173         }
174 }
175
176 static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
177 {
178         struct device_node *dp = isa_br->prom_node->child;
179
180         while (dp) {
181                 struct linux_prom_registers *regs;
182                 struct sparc_isa_device *isa_dev;
183
184                 isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
185                 if (!isa_dev) {
186                         fatal_err("cannot allocate isa_dev");
187                         prom_halt();
188                 }
189
190                 memset(isa_dev, 0, sizeof(*isa_dev));
191
192                 /* Link it in. */
193                 isa_dev->next = NULL;
194                 if (isa_br->devices == NULL) {
195                         isa_br->devices = isa_dev;
196                 } else {
197                         struct sparc_isa_device *tmp = isa_br->devices;
198
199                         while (tmp->next)
200                                 tmp = tmp->next;
201
202                         tmp->next = isa_dev;
203                 }
204
205                 isa_dev->bus = isa_br;
206                 isa_dev->prom_node = dp;
207
208                 regs = isa_dev_get_resource(isa_dev);
209                 isa_dev_get_irq(isa_dev, regs);
210
211                 report_dev(isa_dev, 0);
212
213                 isa_fill_children(isa_dev);
214
215                 printk("]");
216
217                 dp = dp->sibling;
218         }
219 }
220
221 static void __init get_bridge_props(struct sparc_isa_bridge *isa_br)
222 {
223         struct device_node *dp = isa_br->prom_node;
224         void *pval;
225         int len;
226
227         pval = of_get_property(dp, "ranges", &len);
228         if (pval) {
229                 memcpy(isa_br->isa_ranges, pval, len);
230                 isa_br->num_isa_ranges =
231                         len / sizeof(struct linux_prom_isa_ranges);
232         } else {
233                 isa_br->num_isa_ranges = 0;
234         }
235
236         pval = of_get_property(dp, "interrupt-map", &len);
237         if (pval) {
238                 memcpy(isa_br->isa_intmap, pval, len);
239                 isa_br->num_isa_intmap =
240                         (len / sizeof(struct linux_prom_isa_intmap));
241         } else {
242                 isa_br->num_isa_intmap = 0;
243         }
244
245         pval = of_get_property(dp, "interrupt-map-mask", &len);
246         if (pval)
247                 memcpy(&isa_br->isa_intmask, pval,
248                        sizeof(isa_br->isa_intmask));
249 }
250
251 void __init isa_init(void)
252 {
253         struct pci_dev *pdev;
254         unsigned short vendor, device;
255         int index = 0;
256
257         vendor = PCI_VENDOR_ID_AL;
258         device = PCI_DEVICE_ID_AL_M1533;
259
260         pdev = NULL;
261         while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) {
262                 struct pcidev_cookie *pdev_cookie;
263                 struct pci_pbm_info *pbm;
264                 struct sparc_isa_bridge *isa_br;
265
266                 pdev_cookie = pdev->sysdata;
267                 if (!pdev_cookie) {
268                         printk("ISA: Warning, ISA bridge ignored due to "
269                                "lack of OBP data.\n");
270                         continue;
271                 }
272                 pbm = pdev_cookie->pbm;
273
274                 isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
275                 if (!isa_br) {
276                         fatal_err("cannot allocate sparc_isa_bridge");
277                         prom_halt();
278                 }
279
280                 memset(isa_br, 0, sizeof(*isa_br));
281
282                 /* Link it in. */
283                 isa_br->next = isa_chain;
284                 isa_chain = isa_br;
285
286                 isa_br->parent = pbm;
287                 isa_br->self = pdev;
288                 isa_br->index = index++;
289                 isa_br->prom_node = pdev_cookie->prom_node;
290
291                 get_bridge_props(isa_br);
292
293                 printk("isa%d:", isa_br->index);
294
295                 isa_fill_devices(isa_br);
296
297                 printk("\n");
298         }
299 }