diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sh/drivers/pci/pci-sh7751.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/sh/drivers/pci/pci-sh7751.c')
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7751.c | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c new file mode 100644 index 000000000000..30b14ac7ae5a --- /dev/null +++ b/arch/sh/drivers/pci/pci-sh7751.c | |||
@@ -0,0 +1,417 @@ | |||
1 | /* | ||
2 | * Low-Level PCI Support for the SH7751 | ||
3 | * | ||
4 | * Dustin McIntire (dustin@sensoria.com) | ||
5 | * Derived from arch/i386/kernel/pci-*.c which bore the message: | ||
6 | * (c) 1999--2000 Martin Mares <mj@ucw.cz> | ||
7 | * | ||
8 | * Ported to the new API by Paul Mundt <lethal@linux-sh.org> | ||
9 | * With cleanup by Paul van Gool <pvangool@mimotech.com> | ||
10 | * | ||
11 | * May be copied or modified under the terms of the GNU General Public | ||
12 | * License. See linux/COPYING for more information. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #undef DEBUG | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/ioport.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/delay.h> | ||
28 | |||
29 | #include <asm/machvec.h> | ||
30 | #include <asm/io.h> | ||
31 | #include "pci-sh7751.h" | ||
32 | |||
33 | static unsigned int pci_probe = PCI_PROBE_CONF1; | ||
34 | extern int pci_fixup_pcic(void); | ||
35 | |||
36 | void pcibios_fixup_irqs(void) __attribute__ ((weak)); | ||
37 | |||
38 | /* | ||
39 | * Direct access to PCI hardware... | ||
40 | */ | ||
41 | |||
42 | #define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) | ||
43 | |||
44 | /* | ||
45 | * Functions for accessing PCI configuration space with type 1 accesses | ||
46 | */ | ||
47 | static int sh7751_pci_read(struct pci_bus *bus, unsigned int devfn, | ||
48 | int where, int size, u32 *val) | ||
49 | { | ||
50 | unsigned long flags; | ||
51 | u32 data; | ||
52 | |||
53 | /* | ||
54 | * PCIPDR may only be accessed as 32 bit words, | ||
55 | * so we must do byte alignment by hand | ||
56 | */ | ||
57 | local_irq_save(flags); | ||
58 | outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); | ||
59 | data = inl(PCI_REG(SH7751_PCIPDR)); | ||
60 | local_irq_restore(flags); | ||
61 | |||
62 | switch (size) { | ||
63 | case 1: | ||
64 | *val = (data >> ((where & 3) << 3)) & 0xff; | ||
65 | break; | ||
66 | case 2: | ||
67 | *val = (data >> ((where & 2) << 3)) & 0xffff; | ||
68 | break; | ||
69 | case 4: | ||
70 | *val = data; | ||
71 | break; | ||
72 | default: | ||
73 | return PCIBIOS_FUNC_NOT_SUPPORTED; | ||
74 | } | ||
75 | |||
76 | return PCIBIOS_SUCCESSFUL; | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Since SH7751 only does 32bit access we'll have to do a read, | ||
81 | * mask,write operation. | ||
82 | * We'll allow an odd byte offset, though it should be illegal. | ||
83 | */ | ||
84 | static int sh7751_pci_write(struct pci_bus *bus, unsigned int devfn, | ||
85 | int where, int size, u32 val) | ||
86 | { | ||
87 | unsigned long flags; | ||
88 | int shift; | ||
89 | u32 data; | ||
90 | |||
91 | local_irq_save(flags); | ||
92 | outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); | ||
93 | data = inl(PCI_REG(SH7751_PCIPDR)); | ||
94 | local_irq_restore(flags); | ||
95 | |||
96 | switch (size) { | ||
97 | case 1: | ||
98 | shift = (where & 3) << 3; | ||
99 | data &= ~(0xff << shift); | ||
100 | data |= ((val & 0xff) << shift); | ||
101 | break; | ||
102 | case 2: | ||
103 | shift = (where & 2) << 3; | ||
104 | data &= ~(0xffff << shift); | ||
105 | data |= ((val & 0xffff) << shift); | ||
106 | break; | ||
107 | case 4: | ||
108 | data = val; | ||
109 | break; | ||
110 | default: | ||
111 | return PCIBIOS_FUNC_NOT_SUPPORTED; | ||
112 | } | ||
113 | |||
114 | outl(data, PCI_REG(SH7751_PCIPDR)); | ||
115 | |||
116 | return PCIBIOS_SUCCESSFUL; | ||
117 | } | ||
118 | |||
119 | #undef CONFIG_CMD | ||
120 | |||
121 | struct pci_ops sh7751_pci_ops = { | ||
122 | .read = sh7751_pci_read, | ||
123 | .write = sh7751_pci_write, | ||
124 | }; | ||
125 | |||
126 | static int __init pci_check_direct(void) | ||
127 | { | ||
128 | unsigned int tmp, id; | ||
129 | |||
130 | /* check for SH7751/SH7751R hardware */ | ||
131 | id = inl(SH7751_PCIREG_BASE+SH7751_PCICONF0); | ||
132 | if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) && | ||
133 | id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) { | ||
134 | pr_debug("PCI: This is not an SH7751(R) (%x)\n", id); | ||
135 | return -ENODEV; | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Check if configuration works. | ||
140 | */ | ||
141 | if (pci_probe & PCI_PROBE_CONF1) { | ||
142 | tmp = inl (PCI_REG(SH7751_PCIPAR)); | ||
143 | outl (0x80000000, PCI_REG(SH7751_PCIPAR)); | ||
144 | if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) { | ||
145 | outl (tmp, PCI_REG(SH7751_PCIPAR)); | ||
146 | printk(KERN_INFO "PCI: Using configuration type 1\n"); | ||
147 | request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1"); | ||
148 | return 0; | ||
149 | } | ||
150 | outl (tmp, PCI_REG(SH7751_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 | * exitst 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 sh7751_pci_init(void) | ||
209 | { | ||
210 | int ret; | ||
211 | |||
212 | pr_debug("PCI: Starting intialization.\n"); | ||
213 | if ((ret = pci_check_direct()) != 0) | ||
214 | return ret; | ||
215 | |||
216 | return pcibios_init_platform(); | ||
217 | } | ||
218 | |||
219 | subsys_initcall(sh7751_pci_init); | ||
220 | |||
221 | static int __init __area_sdram_check(unsigned int area) | ||
222 | { | ||
223 | u32 word; | ||
224 | |||
225 | word = inl(SH7751_BCR1); | ||
226 | /* check BCR for SDRAM in area */ | ||
227 | if(((word >> area) & 1) == 0) { | ||
228 | printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n", | ||
229 | area, word); | ||
230 | return 0; | ||
231 | } | ||
232 | outl(word, PCI_REG(SH7751_PCIBCR1)); | ||
233 | |||
234 | word = (u16)inw(SH7751_BCR2); | ||
235 | /* check BCR2 for 32bit SDRAM interface*/ | ||
236 | if(((word >> (area << 1)) & 0x3) != 0x3) { | ||
237 | printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n", | ||
238 | area, word); | ||
239 | return 0; | ||
240 | } | ||
241 | outl(word, PCI_REG(SH7751_PCIBCR2)); | ||
242 | |||
243 | return 1; | ||
244 | } | ||
245 | |||
246 | int __init sh7751_pcic_init(struct sh7751_pci_address_map *map) | ||
247 | { | ||
248 | u32 reg; | ||
249 | u32 word; | ||
250 | |||
251 | /* Set the BCR's to enable PCI access */ | ||
252 | reg = inl(SH7751_BCR1); | ||
253 | reg |= 0x80000; | ||
254 | outl(reg, SH7751_BCR1); | ||
255 | |||
256 | /* Turn the clocks back on (not done in reset)*/ | ||
257 | outl(0, PCI_REG(SH7751_PCICLKR)); | ||
258 | /* Clear Powerdown IRQ's (not done in reset) */ | ||
259 | word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0; | ||
260 | outl(word, PCI_REG(SH7751_PCIPINT)); | ||
261 | |||
262 | /* | ||
263 | * This code is unused for some boards as it is done in the | ||
264 | * bootloader and doing it here means the MAC addresses loaded | ||
265 | * by the bootloader get lost. | ||
266 | */ | ||
267 | if (!(map->flags & SH7751_PCIC_NO_RESET)) { | ||
268 | /* toggle PCI reset pin */ | ||
269 | word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST; | ||
270 | outl(word,PCI_REG(SH7751_PCICR)); | ||
271 | /* Wait for a long time... not 1 sec. but long enough */ | ||
272 | mdelay(100); | ||
273 | word = SH7751_PCICR_PREFIX; | ||
274 | outl(word,PCI_REG(SH7751_PCICR)); | ||
275 | } | ||
276 | |||
277 | /* set the command/status bits to: | ||
278 | * Wait Cycle Control + Parity Enable + Bus Master + | ||
279 | * Mem space enable | ||
280 | */ | ||
281 | word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | | ||
282 | SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES; | ||
283 | outl(word, PCI_REG(SH7751_PCICONF1)); | ||
284 | |||
285 | /* define this host as the host bridge */ | ||
286 | word = SH7751_PCI_HOST_BRIDGE << 24; | ||
287 | outl(word, PCI_REG(SH7751_PCICONF2)); | ||
288 | |||
289 | /* Set IO and Mem windows to local address | ||
290 | * Make PCI and local address the same for easy 1 to 1 mapping | ||
291 | * Window0 = map->window0.size @ non-cached area base = SDRAM | ||
292 | * Window1 = map->window1.size @ cached area base = SDRAM | ||
293 | */ | ||
294 | word = map->window0.size - 1; | ||
295 | outl(word, PCI_REG(SH7751_PCILSR0)); | ||
296 | word = map->window1.size - 1; | ||
297 | outl(word, PCI_REG(SH7751_PCILSR1)); | ||
298 | /* Set the values on window 0 PCI config registers */ | ||
299 | word = P2SEGADDR(map->window0.base); | ||
300 | outl(word, PCI_REG(SH7751_PCILAR0)); | ||
301 | outl(word, PCI_REG(SH7751_PCICONF5)); | ||
302 | /* Set the values on window 1 PCI config registers */ | ||
303 | word = PHYSADDR(map->window1.base); | ||
304 | outl(word, PCI_REG(SH7751_PCILAR1)); | ||
305 | outl(word, PCI_REG(SH7751_PCICONF6)); | ||
306 | |||
307 | /* Set the local 16MB PCI memory space window to | ||
308 | * the lowest PCI mapped address | ||
309 | */ | ||
310 | word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK; | ||
311 | PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word); | ||
312 | outl(word , PCI_REG(SH7751_PCIMBR)); | ||
313 | |||
314 | /* Map IO space into PCI IO window | ||
315 | * The IO window is 64K-PCIBIOS_MIN_IO in size | ||
316 | * IO addresses will be translated to the | ||
317 | * PCI IO window base address | ||
318 | */ | ||
319 | PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO, | ||
320 | (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO); | ||
321 | |||
322 | /* | ||
323 | * XXX: For now, leave this board-specific. In the event we have other | ||
324 | * boards that need to do similar work, this can be wrapped. | ||
325 | */ | ||
326 | #ifdef CONFIG_SH_BIGSUR | ||
327 | bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0); | ||
328 | #endif | ||
329 | |||
330 | /* Make sure the MSB's of IO window are set to access PCI space correctly */ | ||
331 | word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK; | ||
332 | PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word); | ||
333 | outl(word, PCI_REG(SH7751_PCIIOBR)); | ||
334 | |||
335 | /* Set PCI WCRx, BCRx's, copy from BSC locations */ | ||
336 | |||
337 | /* check BCR for SDRAM in specified area */ | ||
338 | switch (map->window0.base) { | ||
339 | case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(0); break; | ||
340 | case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(1); break; | ||
341 | case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(2); break; | ||
342 | case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(3); break; | ||
343 | case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(4); break; | ||
344 | case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break; | ||
345 | case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break; | ||
346 | } | ||
347 | |||
348 | if (!word) | ||
349 | return 0; | ||
350 | |||
351 | /* configure the wait control registers */ | ||
352 | word = inl(SH7751_WCR1); | ||
353 | outl(word, PCI_REG(SH7751_PCIWCR1)); | ||
354 | word = inl(SH7751_WCR2); | ||
355 | outl(word, PCI_REG(SH7751_PCIWCR2)); | ||
356 | word = inl(SH7751_WCR3); | ||
357 | outl(word, PCI_REG(SH7751_PCIWCR3)); | ||
358 | word = inl(SH7751_MCR); | ||
359 | outl(word, PCI_REG(SH7751_PCIMCR)); | ||
360 | |||
361 | /* NOTE: I'm ignoring the PCI error IRQs for now.. | ||
362 | * TODO: add support for the internal error interrupts and | ||
363 | * DMA interrupts... | ||
364 | */ | ||
365 | |||
366 | #ifdef CONFIG_SH_RTS7751R2D | ||
367 | pci_fixup_pcic(); | ||
368 | #endif | ||
369 | |||
370 | /* SH7751 init done, set central function init complete */ | ||
371 | /* use round robin mode to stop a device starving/overruning */ | ||
372 | word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN | SH7751_PCICR_ARBM; | ||
373 | outl(word,PCI_REG(SH7751_PCICR)); | ||
374 | |||
375 | return 1; | ||
376 | } | ||
377 | |||
378 | char * __init pcibios_setup(char *str) | ||
379 | { | ||
380 | if (!strcmp(str, "off")) { | ||
381 | pci_probe = 0; | ||
382 | return NULL; | ||
383 | } | ||
384 | |||
385 | return str; | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * IRQ functions | ||
390 | */ | ||
391 | static u8 __init sh7751_no_swizzle(struct pci_dev *dev, u8 *pin) | ||
392 | { | ||
393 | /* no swizzling */ | ||
394 | return PCI_SLOT(dev->devfn); | ||
395 | } | ||
396 | |||
397 | static int sh7751_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
398 | { | ||
399 | int irq = -1; | ||
400 | |||
401 | /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ | ||
402 | irq = pcibios_map_platform_irq(slot,pin); | ||
403 | if( irq < 0 ) { | ||
404 | pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); | ||
405 | return irq; | ||
406 | } | ||
407 | |||
408 | pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); | ||
409 | |||
410 | return irq; | ||
411 | } | ||
412 | |||
413 | void __init pcibios_fixup_irqs(void) | ||
414 | { | ||
415 | pci_fixup_irqs(sh7751_no_swizzle, sh7751_pci_lookup_irq); | ||
416 | } | ||
417 | |||