diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 03:43:28 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 03:43:28 -0400 |
commit | 959f85f8a3223c116bbe95dd8a9b207790b5d4d3 (patch) | |
tree | e7da9ccf292f860bfa0ff9cc8b2682cd1d6bad4d /arch/sh/drivers/pci/pci-sh7780.c | |
parent | e108b2ca2349f510ce7d7f910eda89f71d710d84 (diff) |
sh: Consolidated SH7751/SH7780 PCI support.
This cleans up quite a lot of the PCI mess that we
currently have, and attempts to consolidate the
duplication in the SH7780 and SH7751 PCI controllers.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/drivers/pci/pci-sh7780.c')
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7780.c | 270 |
1 files changed, 34 insertions, 236 deletions
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index e09721330ac2..bd3064a82087 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c | |||
@@ -20,197 +20,36 @@ | |||
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/pci.h> | 22 | #include <linux/pci.h> |
23 | #include <linux/sched.h> | ||
24 | #include <linux/ioport.h> | ||
25 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
26 | #include <linux/irq.h> | ||
27 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
28 | 25 | #include "pci-sh4.h" | |
29 | #include <asm/machvec.h> | ||
30 | #include <asm/io.h> | ||
31 | #include "pci-sh7780.h" | ||
32 | |||
33 | static unsigned int pci_probe = PCI_PROBE_CONF1; | ||
34 | extern int pci_fixup_pcic(void); | ||
35 | |||
36 | /* | ||
37 | * Direct access to PCI hardware... | ||
38 | */ | ||
39 | |||
40 | #define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) | ||
41 | |||
42 | /* | ||
43 | * Functions for accessing PCI configuration space with type 1 accesses | ||
44 | */ | ||
45 | static int sh7780_pci_read(struct pci_bus *bus, unsigned int devfn, | ||
46 | int where, int size, u32 *val) | ||
47 | { | ||
48 | unsigned long flags; | ||
49 | u32 data; | ||
50 | |||
51 | /* | ||
52 | * PCIPDR may only be accessed as 32 bit words, | ||
53 | * so we must do byte alignment by hand | ||
54 | */ | ||
55 | local_irq_save(flags); | ||
56 | outl(CONFIG_CMD(bus, devfn, where), PCI_REG(SH7780_PCIPAR)); | ||
57 | data = inl(PCI_REG(SH7780_PCIPDR)); | ||
58 | local_irq_restore(flags); | ||
59 | |||
60 | switch (size) { | ||
61 | case 1: | ||
62 | *val = (data >> ((where & 3) << 3)) & 0xff; | ||
63 | break; | ||
64 | case 2: | ||
65 | *val = (data >> ((where & 2) << 3)) & 0xffff; | ||
66 | break; | ||
67 | case 4: | ||
68 | *val = data; | ||
69 | break; | ||
70 | default: | ||
71 | return PCIBIOS_FUNC_NOT_SUPPORTED; | ||
72 | } | ||
73 | |||
74 | return PCIBIOS_SUCCESSFUL; | ||
75 | } | ||
76 | 26 | ||
77 | /* | 27 | /* |
78 | * Since SH7780 only does 32bit access we'll have to do a read, | 28 | * Initialization. Try all known PCI access methods. Note that we support |
79 | * mask,write operation. | 29 | * using both PCI BIOS and direct access: in such cases, we use I/O ports |
80 | * We'll allow an odd byte offset, though it should be illegal. | 30 | * to access config space. |
31 | * | ||
32 | * Note that the platform specific initialization (BSC registers, and memory | ||
33 | * space mapping) will be called via the platform defined function | ||
34 | * pcibios_init_platform(). | ||
81 | */ | 35 | */ |
82 | static int sh7780_pci_write(struct pci_bus *bus, unsigned int devfn, | 36 | static int __init sh7780_pci_init(void) |
83 | int where, int size, u32 val) | ||
84 | { | 37 | { |
85 | unsigned long flags; | 38 | unsigned int id; |
86 | int shift; | 39 | int ret; |
87 | u32 data; | ||
88 | |||
89 | local_irq_save(flags); | ||
90 | outl(CONFIG_CMD(bus, devfn, where), PCI_REG(SH7780_PCIPAR)); | ||
91 | data = inl(PCI_REG(SH7780_PCIPDR)); | ||
92 | local_irq_restore(flags); | ||
93 | |||
94 | switch (size) { | ||
95 | case 1: | ||
96 | shift = (where & 3) << 3; | ||
97 | data &= ~(0xff << shift); | ||
98 | data |= ((val & 0xff) << shift); | ||
99 | break; | ||
100 | case 2: | ||
101 | shift = (where & 2) << 3; | ||
102 | data &= ~(0xffff << shift); | ||
103 | data |= ((val & 0xffff) << shift); | ||
104 | break; | ||
105 | case 4: | ||
106 | data = val; | ||
107 | break; | ||
108 | default: | ||
109 | return PCIBIOS_FUNC_NOT_SUPPORTED; | ||
110 | } | ||
111 | |||
112 | outl(data, PCI_REG(SH7780_PCIPDR)); | ||
113 | |||
114 | return PCIBIOS_SUCCESSFUL; | ||
115 | } | ||
116 | |||
117 | #undef CONFIG_CMD | ||
118 | |||
119 | struct pci_ops sh7780_pci_ops = { | ||
120 | .read = sh7780_pci_read, | ||
121 | .write = sh7780_pci_write, | ||
122 | }; | ||
123 | 40 | ||
124 | static int __init pci_check_direct(void) | 41 | pr_debug("PCI: Starting intialization.\n"); |
125 | { | ||
126 | unsigned int tmp, id; | ||
127 | 42 | ||
128 | outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */ | 43 | outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */ |
129 | 44 | ||
130 | /* check for SH7780/SH7780R hardware */ | 45 | /* check for SH7780/SH7780R hardware */ |
131 | id = inl(PCI_REG(SH7780_PCIVID)); | 46 | id = pci_read_reg(SH7780_PCIVID); |
132 | if ((id != ((SH7780_DEVICE_ID << 16) | SH7780_VENDOR_ID)) && | 47 | if ((id != ((SH7780_DEVICE_ID << 16) | SH7780_VENDOR_ID)) && |
133 | (id != ((SH7781_DEVICE_ID << 16) | SH7780_VENDOR_ID))) { | 48 | (id != ((SH7781_DEVICE_ID << 16) | SH7780_VENDOR_ID))) { |
134 | printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id); | 49 | printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id); |
135 | return -ENODEV; | 50 | return -ENODEV; |
136 | } | 51 | } |
137 | 52 | ||
138 | /* | ||
139 | * Check if configuration works. | ||
140 | */ | ||
141 | if (pci_probe & PCI_PROBE_CONF1) { | ||
142 | tmp = inl(PCI_REG(SH7780_PCIPAR)); | ||
143 | outl(0x80000000, PCI_REG(SH7780_PCIPAR)); | ||
144 | if (inl(PCI_REG(SH7780_PCIPAR)) == 0x80000000) { | ||
145 | outl(tmp, PCI_REG(SH7780_PCIPAR)); | ||
146 | printk(KERN_INFO "PCI: Using configuration type 1\n"); | ||
147 | request_region(PCI_REG(SH7780_PCIPAR), 8, "PCI conf1"); | ||
148 | return 0; | ||
149 | } | ||
150 | outl(tmp, PCI_REG(SH7780_PCIPAR)); | ||
151 | } | ||
152 | |||
153 | pr_debug("PCI: pci_check_direct failed\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | /***************************************************************************************/ | ||
158 | |||
159 | /* | ||
160 | * Handle bus scanning and fixups .... | ||
161 | */ | ||
162 | |||
163 | static void __init pci_fixup_ide_bases(struct pci_dev *d) | ||
164 | { | ||
165 | int i; | ||
166 | |||
167 | /* | ||
168 | * PCI IDE controllers use non-standard I/O port decoding, respect it. | ||
169 | */ | ||
170 | if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) | ||
171 | return; | ||
172 | pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d)); | ||
173 | for(i=0; i<4; i++) { | ||
174 | struct resource *r = &d->resource[i]; | ||
175 | if ((r->start & ~0x80) == 0x374) { | ||
176 | r->start |= 2; | ||
177 | r->end = r->start; | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); | ||
183 | |||
184 | /* | ||
185 | * Called after each bus is probed, but before its children | ||
186 | * are examined. | ||
187 | */ | ||
188 | |||
189 | void __init pcibios_fixup_bus(struct pci_bus *b) | ||
190 | { | ||
191 | pci_read_bridge_bases(b); | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Initialization. Try all known PCI access methods. Note that we support | ||
196 | * using both PCI BIOS and direct access: in such cases, we use I/O ports | ||
197 | * to access config space. | ||
198 | * | ||
199 | * Note that the platform specific initialization (BSC registers, and memory | ||
200 | * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it | ||
201 | * exists and via the platform defined function pcibios_init_platform(). | ||
202 | * See pci_bigsur.c for implementation; | ||
203 | * | ||
204 | * The BIOS version of the pci functions is not yet implemented but it is left | ||
205 | * in for completeness. Currently an error will be genereated at compile time. | ||
206 | */ | ||
207 | |||
208 | static int __init sh7780_pci_init(void) | ||
209 | { | ||
210 | int ret; | ||
211 | |||
212 | pr_debug("PCI: Starting intialization.\n"); | ||
213 | |||
214 | /* Setup the INTC */ | 53 | /* Setup the INTC */ |
215 | ctrl_outl(0x00200000, INTC_ICR0); /* INTC SH-4 Mode */ | 54 | ctrl_outl(0x00200000, INTC_ICR0); /* INTC SH-4 Mode */ |
216 | ctrl_outl(0x00078000, INTC_INT2MSKCR); /* enable PCIINTA - PCIINTD */ | 55 | ctrl_outl(0x00078000, INTC_INT2MSKCR); /* enable PCIINTA - PCIINTD */ |
@@ -219,15 +58,14 @@ static int __init sh7780_pci_init(void) | |||
219 | ctrl_outl(0x80000000, INTC_INTMSKCLR1); /* enable IRL0-3 Interrupt */ | 58 | ctrl_outl(0x80000000, INTC_INTMSKCLR1); /* enable IRL0-3 Interrupt */ |
220 | ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); /* enable IRL0-3 Interrupt */ | 59 | ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); /* enable IRL0-3 Interrupt */ |
221 | 60 | ||
222 | if ((ret = pci_check_direct()) != 0) | 61 | if ((ret = sh4_pci_check_direct()) != 0) |
223 | return ret; | 62 | return ret; |
224 | 63 | ||
225 | return pcibios_init_platform(); | 64 | return pcibios_init_platform(); |
226 | } | 65 | } |
227 | |||
228 | core_initcall(sh7780_pci_init); | 66 | core_initcall(sh7780_pci_init); |
229 | 67 | ||
230 | int __init sh7780_pcic_init(struct sh7780_pci_address_map *map) | 68 | int __init sh7780_pcic_init(struct sh4_pci_address_map *map) |
231 | { | 69 | { |
232 | u32 word; | 70 | u32 word; |
233 | 71 | ||
@@ -236,25 +74,25 @@ int __init sh7780_pcic_init(struct sh7780_pci_address_map *map) | |||
236 | * bootloader and doing it here means the MAC addresses loaded | 74 | * bootloader and doing it here means the MAC addresses loaded |
237 | * by the bootloader get lost. | 75 | * by the bootloader get lost. |
238 | */ | 76 | */ |
239 | if (!(map->flags & SH7780_PCIC_NO_RESET)) { | 77 | if (!(map->flags & SH4_PCIC_NO_RESET)) { |
240 | /* toggle PCI reset pin */ | 78 | /* toggle PCI reset pin */ |
241 | word = SH7780_PCICR_PREFIX | SH7780_PCICR_PRST; | 79 | word = SH4_PCICR_PREFIX | SH4_PCICR_PRST; |
242 | outl(word,PCI_REG(SH7780_PCICR)); | 80 | pci_write_reg(word, SH4_PCICR); |
243 | /* Wait for a long time... not 1 sec. but long enough */ | 81 | /* Wait for a long time... not 1 sec. but long enough */ |
244 | mdelay(100); | 82 | mdelay(100); |
245 | word = SH7780_PCICR_PREFIX; | 83 | word = SH4_PCICR_PREFIX; |
246 | outl(word,PCI_REG(SH7780_PCICR)); | 84 | pci_write_reg(word, SH4_PCICR); |
247 | } | 85 | } |
248 | 86 | ||
249 | /* set the command/status bits to: | 87 | /* set the command/status bits to: |
250 | * Wait Cycle Control + Parity Enable + Bus Master + | 88 | * Wait Cycle Control + Parity Enable + Bus Master + |
251 | * Mem space enable | 89 | * Mem space enable |
252 | */ | 90 | */ |
253 | outl(0x00000046, PCI_REG(SH7780_PCICMD)); | 91 | pci_write_reg(0x00000046, SH7780_PCICMD); |
254 | 92 | ||
255 | /* define this host as the host bridge */ | 93 | /* define this host as the host bridge */ |
256 | word = SH7780_PCI_HOST_BRIDGE << 24; | 94 | word = PCI_BASE_CLASS_BRIDGE << 24; |
257 | outl(word, PCI_REG(SH7780_PCIRID)); | 95 | pci_write_reg(word, SH7780_PCIRID); |
258 | 96 | ||
259 | /* Set IO and Mem windows to local address | 97 | /* Set IO and Mem windows to local address |
260 | * Make PCI and local address the same for easy 1 to 1 mapping | 98 | * Make PCI and local address the same for easy 1 to 1 mapping |
@@ -262,25 +100,26 @@ int __init sh7780_pcic_init(struct sh7780_pci_address_map *map) | |||
262 | * Window1 = map->window1.size @ cached area base = SDRAM | 100 | * Window1 = map->window1.size @ cached area base = SDRAM |
263 | */ | 101 | */ |
264 | word = ((map->window0.size - 1) & 0x1ff00001) | 0x01; | 102 | word = ((map->window0.size - 1) & 0x1ff00001) | 0x01; |
265 | outl(0x07f00001, PCI_REG(SH7780_PCILSR0)); | 103 | pci_write_reg(0x07f00001, SH4_PCILSR0); |
266 | word = ((map->window1.size - 1) & 0x1ff00001) | 0x01; | 104 | word = ((map->window1.size - 1) & 0x1ff00001) | 0x01; |
267 | outl(0x00000001, PCI_REG(SH7780_PCILSR1)); | 105 | pci_write_reg(0x00000001, SH4_PCILSR1); |
268 | /* Set the values on window 0 PCI config registers */ | 106 | /* Set the values on window 0 PCI config registers */ |
269 | word = P2SEGADDR(map->window0.base); | 107 | word = P2SEGADDR(map->window0.base); |
270 | outl(0xa8000000, PCI_REG(SH7780_PCILAR0)); | 108 | pci_write_reg(0xa8000000, SH4_PCILAR0); |
271 | outl(0x08000000, PCI_REG(SH7780_PCIMBAR0)); | 109 | pci_write_reg(0x08000000, SH7780_PCIMBAR0); |
272 | /* Set the values on window 1 PCI config registers */ | 110 | /* Set the values on window 1 PCI config registers */ |
273 | word = P2SEGADDR(map->window1.base); | 111 | word = P2SEGADDR(map->window1.base); |
274 | outl(0x00000000, PCI_REG(SH7780_PCILAR1)); | 112 | pci_write_reg(0x00000000, SH4_PCILAR1); |
275 | outl(0x00000000, PCI_REG(SH7780_PCIMBAR1)); | 113 | pci_write_reg(0x00000000, SH7780_PCIMBAR1); |
276 | 114 | ||
277 | /* Map IO space into PCI IO window | 115 | /* Map IO space into PCI IO window |
278 | * The IO window is 64K-PCIBIOS_MIN_IO in size | 116 | * The IO window is 64K-PCIBIOS_MIN_IO in size |
279 | * IO addresses will be translated to the | 117 | * IO addresses will be translated to the |
280 | * PCI IO window base address | 118 | * PCI IO window base address |
281 | */ | 119 | */ |
282 | PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO, | 120 | pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", |
283 | (64*1024), SH7780_PCI_IO_BASE+PCIBIOS_MIN_IO); | 121 | PCIBIOS_MIN_IO, (64 << 10), |
122 | SH7780_PCI_IO_BASE + PCIBIOS_MIN_IO); | ||
284 | 123 | ||
285 | /* NOTE: I'm ignoring the PCI error IRQs for now.. | 124 | /* NOTE: I'm ignoring the PCI error IRQs for now.. |
286 | * TODO: add support for the internal error interrupts and | 125 | * TODO: add support for the internal error interrupts and |
@@ -293,49 +132,8 @@ int __init sh7780_pcic_init(struct sh7780_pci_address_map *map) | |||
293 | 132 | ||
294 | /* SH7780 init done, set central function init complete */ | 133 | /* SH7780 init done, set central function init complete */ |
295 | /* use round robin mode to stop a device starving/overruning */ | 134 | /* use round robin mode to stop a device starving/overruning */ |
296 | word = SH7780_PCICR_PREFIX | SH7780_PCICR_CFIN | /* SH7780_PCICR_ARBM |*/ SH7780_PCICR_FTO; | 135 | word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO; |
297 | outl(word, PCI_REG(SH7780_PCICR)); | 136 | pci_write_reg(word, SH4_PCICR); |
298 | 137 | ||
299 | return 1; | 138 | return 1; |
300 | } | 139 | } |
301 | |||
302 | char * __init pcibios_setup(char *str) | ||
303 | { | ||
304 | if (!strcmp(str, "off")) { | ||
305 | pci_probe = 0; | ||
306 | return NULL; | ||
307 | } | ||
308 | |||
309 | return str; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * IRQ functions | ||
314 | */ | ||
315 | static u8 __init sh7780_no_swizzle(struct pci_dev *dev, u8 *pin) | ||
316 | { | ||
317 | /* no swizzling */ | ||
318 | return PCI_SLOT(dev->devfn); | ||
319 | } | ||
320 | |||
321 | static int sh7780_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
322 | { | ||
323 | int irq = -1; | ||
324 | |||
325 | /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ | ||
326 | irq = pcibios_map_platform_irq(slot,pin); | ||
327 | if( irq < 0 ) { | ||
328 | pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); | ||
329 | return irq; | ||
330 | } | ||
331 | |||
332 | pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); | ||
333 | |||
334 | return irq; | ||
335 | } | ||
336 | |||
337 | void __init pcibios_fixup_irqs(void) | ||
338 | { | ||
339 | pci_fixup_irqs(sh7780_no_swizzle, sh7780_pci_lookup_irq); | ||
340 | } | ||
341 | |||