aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh64/kernel/pci_sh5.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sh64/kernel/pci_sh5.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/sh64/kernel/pci_sh5.c')
-rw-r--r--arch/sh64/kernel/pci_sh5.c541
1 files changed, 541 insertions, 0 deletions
diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c
new file mode 100644
index 000000000000..6197879e8578
--- /dev/null
+++ b/arch/sh64/kernel/pci_sh5.c
@@ -0,0 +1,541 @@
1/*
2 * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
3 * Copyright (C) 2003, 2004 Paul Mundt
4 * Copyright (C) 2004 Richard Curnow
5 *
6 * May be copied or modified under the terms of the GNU General Public
7 * License. See linux/COPYING for more information.
8 *
9 * Support functions for the SH5 PCI hardware.
10 */
11
12#include <linux/config.h>
13#include <linux/kernel.h>
14#include <linux/rwsem.h>
15#include <linux/smp.h>
16#include <linux/smp_lock.h>
17#include <linux/interrupt.h>
18#include <linux/init.h>
19#include <linux/errno.h>
20#include <linux/pci.h>
21#include <linux/delay.h>
22#include <linux/types.h>
23#include <asm/pci.h>
24#include <linux/irq.h>
25
26#include <asm/io.h>
27#include <asm/hardware.h>
28#include "pci_sh5.h"
29
30static unsigned long pcicr_virt;
31unsigned long pciio_virt;
32
33static void __init pci_fixup_ide_bases(struct pci_dev *d)
34{
35 int i;
36
37 /*
38 * PCI IDE controllers use non-standard I/O port decoding, respect it.
39 */
40 if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
41 return;
42 printk("PCI: IDE base address fixup for %s\n", pci_name(d));
43 for(i=0; i<4; i++) {
44 struct resource *r = &d->resource[i];
45 if ((r->start & ~0x80) == 0x374) {
46 r->start |= 2;
47 r->end = r->start;
48 }
49 }
50}
51DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
52
53char * __init pcibios_setup(char *str)
54{
55 return str;
56}
57
58/* Rounds a number UP to the nearest power of two. Used for
59 * sizing the PCI window.
60 */
61static u32 __init r2p2(u32 num)
62{
63 int i = 31;
64 u32 tmp = num;
65
66 if (num == 0)
67 return 0;
68
69 do {
70 if (tmp & (1 << 31))
71 break;
72 i--;
73 tmp <<= 1;
74 } while (i >= 0);
75
76 tmp = 1 << i;
77 /* If the original number isn't a power of 2, round it up */
78 if (tmp != num)
79 tmp <<= 1;
80
81 return tmp;
82}
83
84extern unsigned long long memory_start, memory_end;
85
86int __init sh5pci_init(unsigned memStart, unsigned memSize)
87{
88 u32 lsr0;
89 u32 uval;
90
91 pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR");
92 if (!pcicr_virt) {
93 panic("Unable to remap PCICR\n");
94 }
95
96 pciio_virt = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO");
97 if (!pciio_virt) {
98 panic("Unable to remap PCIIO\n");
99 }
100
101 pr_debug("Register base addres is 0x%08lx\n", pcicr_virt);
102
103 /* Clear snoop registers */
104 SH5PCI_WRITE(CSCR0, 0);
105 SH5PCI_WRITE(CSCR1, 0);
106
107 pr_debug("Wrote to reg\n");
108
109 /* Switch off interrupts */
110 SH5PCI_WRITE(INTM, 0);
111 SH5PCI_WRITE(AINTM, 0);
112 SH5PCI_WRITE(PINTM, 0);
113
114 /* Set bus active, take it out of reset */
115 uval = SH5PCI_READ(CR);
116
117 /* Set command Register */
118 SH5PCI_WRITE(CR, uval | CR_LOCK_MASK | CR_CFINT| CR_FTO | CR_PFE | CR_PFCS | CR_BMAM);
119
120 uval=SH5PCI_READ(CR);
121 pr_debug("CR is actually 0x%08x\n",uval);
122
123 /* Allow it to be a master */
124 /* NB - WE DISABLE I/O ACCESS to stop overlap */
125 /* set WAIT bit to enable stepping, an attempt to improve stability */
126 SH5PCI_WRITE_SHORT(CSR_CMD,
127 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_WAIT);
128
129 /*
130 ** Set translation mapping memory in order to convert the address
131 ** used for the main bus, to the PCI internal address.
132 */
133 SH5PCI_WRITE(MBR,0x40000000);
134
135 /* Always set the max size 512M */
136 SH5PCI_WRITE(MBMR, PCISH5_MEM_SIZCONV(512*1024*1024));
137
138 /*
139 ** I/O addresses are mapped at internal PCI specific address
140 ** as is described into the configuration bridge table.
141 ** These are changed to 0, to allow cards that have legacy
142 ** io such as vga to function correctly. We set the SH5 IOBAR to
143 ** 256K, which is a bit big as we can only have 64K of address space
144 */
145
146 SH5PCI_WRITE(IOBR,0x0);
147
148 pr_debug("PCI:Writing 0x%08x to IOBR\n",0);
149
150 /* Set up a 256K window. Totally pointless waste of address space */
151 SH5PCI_WRITE(IOBMR,0);
152 pr_debug("PCI:Writing 0x%08x to IOBMR\n",0);
153
154 /* The SH5 has a HUGE 256K I/O region, which breaks the PCI spec. Ideally,
155 * we would want to map the I/O region somewhere, but it is so big this is not
156 * that easy!
157 */
158 SH5PCI_WRITE(CSR_IBAR0,~0);
159 /* Set memory size value */
160 memSize = memory_end - memory_start;
161
162 /* Now we set up the mbars so the PCI bus can see the memory of the machine */
163 if (memSize < (1024 * 1024)) {
164 printk(KERN_ERR "PCISH5: Ridiculous memory size of 0x%x?\n", memSize);
165 return -EINVAL;
166 }
167
168 /* Set LSR 0 */
169 lsr0 = (memSize > (512 * 1024 * 1024)) ? 0x1ff00001 : ((r2p2(memSize) - 0x100000) | 0x1);
170 SH5PCI_WRITE(LSR0, lsr0);
171
172 pr_debug("PCI:Writing 0x%08x to LSR0\n",lsr0);
173
174 /* Set MBAR 0 */
175 SH5PCI_WRITE(CSR_MBAR0, memory_start);
176 SH5PCI_WRITE(LAR0, memory_start);
177
178 SH5PCI_WRITE(CSR_MBAR1,0);
179 SH5PCI_WRITE(LAR1,0);
180 SH5PCI_WRITE(LSR1,0);
181
182 pr_debug("PCI:Writing 0x%08llx to CSR_MBAR0\n",memory_start);
183 pr_debug("PCI:Writing 0x%08llx to LAR0\n",memory_start);
184
185 /* Enable the PCI interrupts on the device */
186 SH5PCI_WRITE(INTM, ~0);
187 SH5PCI_WRITE(AINTM, ~0);
188 SH5PCI_WRITE(PINTM, ~0);
189
190 pr_debug("Switching on all error interrupts\n");
191
192 return(0);
193}
194
195static int sh5pci_read(struct pci_bus *bus, unsigned int devfn, int where,
196 int size, u32 *val)
197{
198 SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
199
200 switch (size) {
201 case 1:
202 *val = (u8)SH5PCI_READ_BYTE(PDR + (where & 3));
203 break;
204 case 2:
205 *val = (u16)SH5PCI_READ_SHORT(PDR + (where & 2));
206 break;
207 case 4:
208 *val = SH5PCI_READ(PDR);
209 break;
210 }
211
212 return PCIBIOS_SUCCESSFUL;
213}
214
215static int sh5pci_write(struct pci_bus *bus, unsigned int devfn, int where,
216 int size, u32 val)
217{
218 SH5PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
219
220 switch (size) {
221 case 1:
222 SH5PCI_WRITE_BYTE(PDR + (where & 3), (u8)val);
223 break;
224 case 2:
225 SH5PCI_WRITE_SHORT(PDR + (where & 2), (u16)val);
226 break;
227 case 4:
228 SH5PCI_WRITE(PDR, val);
229 break;
230 }
231
232 return PCIBIOS_SUCCESSFUL;
233}
234
235static struct pci_ops pci_config_ops = {
236 .read = sh5pci_read,
237 .write = sh5pci_write,
238};
239
240/* Everything hangs off this */
241static struct pci_bus *pci_root_bus;
242
243
244static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
245{
246 pr_debug("swizzle for dev %d on bus %d slot %d pin is %d\n",
247 dev->devfn,dev->bus->number, PCI_SLOT(dev->devfn),*pin);
248 return PCI_SLOT(dev->devfn);
249}
250
251static inline u8 bridge_swizzle(u8 pin, u8 slot)
252{
253 return (((pin-1) + slot) % 4) + 1;
254}
255
256u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp)
257{
258 if (dev->bus->number != 0) {
259 u8 pin = *pinp;
260 do {
261 pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
262 /* Move up the chain of bridges. */
263 dev = dev->bus->self;
264 } while (dev->bus->self);
265 *pinp = pin;
266
267 /* The slot is the slot of the last bridge. */
268 }
269
270 return PCI_SLOT(dev->devfn);
271}
272
273/* This needs to be shunted out of here into the board specific bit */
274
275static int __init map_cayman_irq(struct pci_dev *dev, u8 slot, u8 pin)
276{
277 int result = -1;
278
279 /* The complication here is that the PCI IRQ lines from the Cayman's 2
280 5V slots get into the CPU via a different path from the IRQ lines
281 from the 3 3.3V slots. Thus, we have to detect whether the card's
282 interrupts go via the 5V or 3.3V path, i.e. the 'bridge swizzling'
283 at the point where we cross from 5V to 3.3V is not the normal case.
284
285 The added complication is that we don't know that the 5V slots are
286 always bus 2, because a card containing a PCI-PCI bridge may be
287 plugged into a 3.3V slot, and this changes the bus numbering.
288
289 Also, the Cayman has an intermediate PCI bus that goes a custom
290 expansion board header (and to the secondary bridge). This bus has
291 never been used in practice.
292
293 The 1ary onboard PCI-PCI bridge is device 3 on bus 0
294 The 2ary onboard PCI-PCI bridge is device 0 on the 2ary bus of the 1ary bridge.
295 */
296
297 struct slot_pin {
298 int slot;
299 int pin;
300 } path[4];
301 int i=0;
302
303 while (dev->bus->number > 0) {
304
305 slot = path[i].slot = PCI_SLOT(dev->devfn);
306 pin = path[i].pin = bridge_swizzle(pin, slot);
307 dev = dev->bus->self;
308 i++;
309 if (i > 3) panic("PCI path to root bus too long!\n");
310 }
311
312 slot = PCI_SLOT(dev->devfn);
313 /* This is the slot on bus 0 through which the device is eventually
314 reachable. */
315
316 /* Now work back up. */
317 if ((slot < 3) || (i == 0)) {
318 /* Bus 0 (incl. PCI-PCI bridge itself) : perform the final
319 swizzle now. */
320 result = IRQ_INTA + bridge_swizzle(pin, slot) - 1;
321 } else {
322 i--;
323 slot = path[i].slot;
324 pin = path[i].pin;
325 if (slot > 0) {
326 panic("PCI expansion bus device found - not handled!\n");
327 } else {
328 if (i > 0) {
329 /* 5V slots */
330 i--;
331 slot = path[i].slot;
332 pin = path[i].pin;
333 /* 'pin' was swizzled earlier wrt slot, don't do it again. */
334 result = IRQ_P2INTA + (pin - 1);
335 } else {
336 /* IRQ for 2ary PCI-PCI bridge : unused */
337 result = -1;
338 }
339 }
340 }
341
342 return result;
343}
344
345irqreturn_t pcish5_err_irq(int irq, void *dev_id, struct pt_regs *regs)
346{
347 unsigned pci_int, pci_air, pci_cir, pci_aint;
348
349 pci_int = SH5PCI_READ(INT);
350 pci_cir = SH5PCI_READ(CIR);
351 pci_air = SH5PCI_READ(AIR);
352
353 if (pci_int) {
354 printk("PCI INTERRUPT (at %08llx)!\n", regs->pc);
355 printk("PCI INT -> 0x%x\n", pci_int & 0xffff);
356 printk("PCI AIR -> 0x%x\n", pci_air);
357 printk("PCI CIR -> 0x%x\n", pci_cir);
358 SH5PCI_WRITE(INT, ~0);
359 }
360
361 pci_aint = SH5PCI_READ(AINT);
362 if (pci_aint) {
363 printk("PCI ARB INTERRUPT!\n");
364 printk("PCI AINT -> 0x%x\n", pci_aint);
365 printk("PCI AIR -> 0x%x\n", pci_air);
366 printk("PCI CIR -> 0x%x\n", pci_cir);
367 SH5PCI_WRITE(AINT, ~0);
368 }
369
370 return IRQ_HANDLED;
371}
372
373irqreturn_t pcish5_serr_irq(int irq, void *dev_id, struct pt_regs *regs)
374{
375 printk("SERR IRQ\n");
376
377 return IRQ_NONE;
378}
379
380#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
381
382static void __init
383pcibios_size_bridge(struct pci_bus *bus, struct resource *ior,
384 struct resource *memr)
385{
386 struct resource io_res, mem_res;
387 struct pci_dev *dev;
388 struct pci_dev *bridge = bus->self;
389 struct list_head *ln;
390
391 if (!bridge)
392 return; /* host bridge, nothing to do */
393
394 /* set reasonable default locations for pcibios_align_resource */
395 io_res.start = PCIBIOS_MIN_IO;
396 mem_res.start = PCIBIOS_MIN_MEM;
397
398 io_res.end = io_res.start;
399 mem_res.end = mem_res.start;
400
401 /* Collect information about how our direct children are layed out. */
402 for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
403 int i;
404 dev = pci_dev_b(ln);
405
406 /* Skip bridges for now */
407 if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
408 continue;
409
410 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
411 struct resource res;
412 unsigned long size;
413
414 memcpy(&res, &dev->resource[i], sizeof(res));
415 size = res.end - res.start + 1;
416
417 if (res.flags & IORESOURCE_IO) {
418 res.start = io_res.end;
419 pcibios_align_resource(dev, &res, size, 0);
420 io_res.end = res.start + size;
421 } else if (res.flags & IORESOURCE_MEM) {
422 res.start = mem_res.end;
423 pcibios_align_resource(dev, &res, size, 0);
424 mem_res.end = res.start + size;
425 }
426 }
427 }
428
429 /* And for all of the subordinate busses. */
430 for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
431 pcibios_size_bridge(pci_bus_b(ln), &io_res, &mem_res);
432
433 /* turn the ending locations into sizes (subtract start) */
434 io_res.end -= io_res.start;
435 mem_res.end -= mem_res.start;
436
437 /* Align the sizes up by bridge rules */
438 io_res.end = ROUND_UP(io_res.end, 4*1024) - 1;
439 mem_res.end = ROUND_UP(mem_res.end, 1*1024*1024) - 1;
440
441 /* Adjust the bridge's allocation requirements */
442 bridge->resource[0].end = bridge->resource[0].start + io_res.end;
443 bridge->resource[1].end = bridge->resource[1].start + mem_res.end;
444
445 bridge->resource[PCI_BRIDGE_RESOURCES].end =
446 bridge->resource[PCI_BRIDGE_RESOURCES].start + io_res.end;
447 bridge->resource[PCI_BRIDGE_RESOURCES+1].end =
448 bridge->resource[PCI_BRIDGE_RESOURCES+1].start + mem_res.end;
449
450 /* adjust parent's resource requirements */
451 if (ior) {
452 ior->end = ROUND_UP(ior->end, 4*1024);
453 ior->end += io_res.end;
454 }
455
456 if (memr) {
457 memr->end = ROUND_UP(memr->end, 1*1024*1024);
458 memr->end += mem_res.end;
459 }
460}
461
462#undef ROUND_UP
463
464static void __init pcibios_size_bridges(void)
465{
466 struct resource io_res, mem_res;
467
468 memset(&io_res, 0, sizeof(io_res));
469 memset(&mem_res, 0, sizeof(mem_res));
470
471 pcibios_size_bridge(pci_root_bus, &io_res, &mem_res);
472}
473
474static int __init pcibios_init(void)
475{
476 if (request_irq(IRQ_ERR, pcish5_err_irq,
477 SA_INTERRUPT, "PCI Error",NULL) < 0) {
478 printk(KERN_ERR "PCISH5: Cannot hook PCI_PERR interrupt\n");
479 return -EINVAL;
480 }
481
482 if (request_irq(IRQ_SERR, pcish5_serr_irq,
483 SA_INTERRUPT, "PCI SERR interrupt", NULL) < 0) {
484 printk(KERN_ERR "PCISH5: Cannot hook PCI_SERR interrupt\n");
485 return -EINVAL;
486 }
487
488 /* The pci subsytem needs to know where memory is and how much
489 * of it there is. I've simply made these globals. A better mechanism
490 * is probably needed.
491 */
492 sh5pci_init(__pa(memory_start),
493 __pa(memory_end) - __pa(memory_start));
494
495 pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
496 pcibios_size_bridges();
497 pci_assign_unassigned_resources();
498 pci_fixup_irqs(no_swizzle, map_cayman_irq);
499
500 return 0;
501}
502
503subsys_initcall(pcibios_init);
504
505void __init pcibios_fixup_bus(struct pci_bus *bus)
506{
507 struct pci_dev *dev = bus->self;
508 int i;
509
510#if 1
511 if(dev) {
512 for(i=0; i<3; i++) {
513 bus->resource[i] =
514 &dev->resource[PCI_BRIDGE_RESOURCES+i];
515 bus->resource[i]->name = bus->name;
516 }
517 bus->resource[0]->flags |= IORESOURCE_IO;
518 bus->resource[1]->flags |= IORESOURCE_MEM;
519
520 /* For now, propagate host limits to the bus;
521 * we'll adjust them later. */
522
523#if 1
524 bus->resource[0]->end = 64*1024 - 1 ;
525 bus->resource[1]->end = PCIBIOS_MIN_MEM+(256*1024*1024)-1;
526 bus->resource[0]->start = PCIBIOS_MIN_IO;
527 bus->resource[1]->start = PCIBIOS_MIN_MEM;
528#else
529 bus->resource[0]->end = 0
530 bus->resource[1]->end = 0
531 bus->resource[0]->start =0
532 bus->resource[1]->start = 0;
533#endif
534 /* Turn off downstream PF memory address range by default */
535 bus->resource[2]->start = 1024*1024;
536 bus->resource[2]->end = bus->resource[2]->start - 1;
537 }
538#endif
539
540}
541