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