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/m68knommu/kernel/comempci.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/m68knommu/kernel/comempci.c')
-rw-r--r-- | arch/m68knommu/kernel/comempci.c | 989 |
1 files changed, 989 insertions, 0 deletions
diff --git a/arch/m68knommu/kernel/comempci.c b/arch/m68knommu/kernel/comempci.c new file mode 100644 index 000000000000..8670938f1107 --- /dev/null +++ b/arch/m68knommu/kernel/comempci.c | |||
@@ -0,0 +1,989 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * comemlite.c -- PCI access code for embedded CO-MEM Lite PCI controller. | ||
5 | * | ||
6 | * (C) Copyright 1999-2003, Greg Ungerer (gerg@snapgear.com). | ||
7 | * (C) Copyright 2000, Lineo (www.lineo.com) | ||
8 | */ | ||
9 | |||
10 | /*****************************************************************************/ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/ptrace.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <asm/coldfire.h> | ||
21 | #include <asm/mcfsim.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <asm/anchor.h> | ||
24 | |||
25 | #ifdef CONFIG_eLIA | ||
26 | #include <asm/elia.h> | ||
27 | #endif | ||
28 | |||
29 | /*****************************************************************************/ | ||
30 | |||
31 | /* | ||
32 | * Debug configuration defines. DEBUGRES sets debugging output for | ||
33 | * the resource allocation phase. DEBUGPCI traces on pcibios_ function | ||
34 | * calls, and DEBUGIO traces all accesses to devices on the PCI bus. | ||
35 | */ | ||
36 | /*#define DEBUGRES 1*/ | ||
37 | /*#define DEBUGPCI 1*/ | ||
38 | /*#define DEBUGIO 1*/ | ||
39 | |||
40 | /*****************************************************************************/ | ||
41 | |||
42 | /* | ||
43 | * PCI markers for bus present and active slots. | ||
44 | */ | ||
45 | int pci_bus_is_present = 0; | ||
46 | unsigned long pci_slotmask = 0; | ||
47 | |||
48 | /* | ||
49 | * We may or may not need to swap the bytes of PCI bus tranfers. | ||
50 | * The endianess is re-roder automatically by the CO-MEM, but it | ||
51 | * will get the wrong byte order for a pure data stream. | ||
52 | */ | ||
53 | #define pci_byteswap 0 | ||
54 | |||
55 | |||
56 | /* | ||
57 | * Resource tracking. The CO-MEM part creates a virtual address | ||
58 | * space that all the PCI devices live in - it is not in any way | ||
59 | * directly mapped into the ColdFire address space. So we can | ||
60 | * really assign any resources we like to devices, as long as | ||
61 | * they do not clash with other PCI devices. | ||
62 | */ | ||
63 | unsigned int pci_iobase = PCIBIOS_MIN_IO; /* Arbitrary start address */ | ||
64 | unsigned int pci_membase = PCIBIOS_MIN_MEM; /* Arbitrary start address */ | ||
65 | |||
66 | #define PCI_MINIO 0x100 /* 256 byte minimum I/O */ | ||
67 | #define PCI_MINMEM 0x00010000 /* 64k minimum chunk */ | ||
68 | |||
69 | /* | ||
70 | * The CO-MEM's shared memory segment is visible inside the PCI | ||
71 | * memory address space. We need to keep track of the address that | ||
72 | * this is mapped at, to setup the bus masters pointers. | ||
73 | */ | ||
74 | unsigned int pci_shmemaddr; | ||
75 | |||
76 | /*****************************************************************************/ | ||
77 | |||
78 | void pci_interrupt(int irq, void *id, struct pt_regs *fp); | ||
79 | |||
80 | /*****************************************************************************/ | ||
81 | |||
82 | /* | ||
83 | * Some platforms have custom ways of reseting the PCI bus. | ||
84 | */ | ||
85 | |||
86 | void pci_resetbus(void) | ||
87 | { | ||
88 | #ifdef CONFIG_eLIA | ||
89 | int i; | ||
90 | |||
91 | #ifdef DEBUGPCI | ||
92 | printk(KERN_DEBUG "pci_resetbus()\n"); | ||
93 | #endif | ||
94 | |||
95 | *((volatile unsigned short *) (MCF_MBAR+MCFSIM_PADDR)) |= eLIA_PCIRESET; | ||
96 | for (i = 0; (i < 1000); i++) { | ||
97 | *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = | ||
98 | (ppdata | eLIA_PCIRESET); | ||
99 | } | ||
100 | |||
101 | |||
102 | *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = ppdata; | ||
103 | #endif | ||
104 | } | ||
105 | |||
106 | /*****************************************************************************/ | ||
107 | |||
108 | int pcibios_assign_resource_slot(int slot) | ||
109 | { | ||
110 | volatile unsigned long *rp; | ||
111 | volatile unsigned char *ip; | ||
112 | unsigned int idsel, addr, val, align, i; | ||
113 | int bar; | ||
114 | |||
115 | #ifdef DEBUGPCI | ||
116 | printk(KERN_INFO "pcibios_assign_resource_slot(slot=%x)\n", slot); | ||
117 | #endif | ||
118 | |||
119 | rp = (volatile unsigned long *) COMEM_BASE; | ||
120 | idsel = COMEM_DA_ADDR(0x1 << (slot + 16)); | ||
121 | |||
122 | /* Try to assign resource to each BAR */ | ||
123 | for (bar = 0; (bar < 6); bar++) { | ||
124 | addr = COMEM_PCIBUS + PCI_BASE_ADDRESS_0 + (bar * 4); | ||
125 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; | ||
126 | val = rp[LREG(addr)]; | ||
127 | #ifdef DEBUGRES | ||
128 | printk(KERN_DEBUG "-----------------------------------" | ||
129 | "-------------------------------------\n"); | ||
130 | printk(KERN_DEBUG "BAR[%d]: read=%08x ", bar, val); | ||
131 | #endif | ||
132 | |||
133 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; | ||
134 | rp[LREG(addr)] = 0xffffffff; | ||
135 | |||
136 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; | ||
137 | val = rp[LREG(addr)]; | ||
138 | #ifdef DEBUGRES | ||
139 | printk(KERN_DEBUG "write=%08x ", val); | ||
140 | #endif | ||
141 | if (val == 0) { | ||
142 | #ifdef DEBUGRES | ||
143 | printk(KERN_DEBUG "\n"); | ||
144 | #endif | ||
145 | continue; | ||
146 | } | ||
147 | |||
148 | /* Determine space required by BAR */ | ||
149 | /* FIXME: this should go backwords from 0x80000000... */ | ||
150 | for (i = 0; (i < 32); i++) { | ||
151 | if ((0x1 << i) & (val & 0xfffffffc)) | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | #ifdef DEBUGRES | ||
156 | printk(KERN_DEBUG "size=%08x(%d)\n", (0x1 << i), i); | ||
157 | #endif | ||
158 | i = 0x1 << i; | ||
159 | |||
160 | /* Assign a resource */ | ||
161 | if (val & PCI_BASE_ADDRESS_SPACE_IO) { | ||
162 | if (i < PCI_MINIO) | ||
163 | i = PCI_MINIO; | ||
164 | #ifdef DEBUGRES | ||
165 | printk(KERN_DEBUG "BAR[%d]: IO size=%08x iobase=%08x\n", | ||
166 | bar, i, pci_iobase); | ||
167 | #endif | ||
168 | if (i > 0xffff) { | ||
169 | /* Invalid size?? */ | ||
170 | val = 0 | PCI_BASE_ADDRESS_SPACE_IO; | ||
171 | #ifdef DEBUGRES | ||
172 | printk(KERN_DEBUG "BAR[%d]: too big for IO??\n", bar); | ||
173 | #endif | ||
174 | } else { | ||
175 | /* Check for un-alignment */ | ||
176 | if ((align = pci_iobase % i)) | ||
177 | pci_iobase += (i - align); | ||
178 | val = pci_iobase | PCI_BASE_ADDRESS_SPACE_IO; | ||
179 | pci_iobase += i; | ||
180 | } | ||
181 | } else { | ||
182 | if (i < PCI_MINMEM) | ||
183 | i = PCI_MINMEM; | ||
184 | #ifdef DEBUGRES | ||
185 | printk(KERN_DEBUG "BAR[%d]: MEMORY size=%08x membase=%08x\n", | ||
186 | bar, i, pci_membase); | ||
187 | #endif | ||
188 | /* Check for un-alignment */ | ||
189 | if ((align = pci_membase % i)) | ||
190 | pci_membase += (i - align); | ||
191 | val = pci_membase | PCI_BASE_ADDRESS_SPACE_MEMORY; | ||
192 | pci_membase += i; | ||
193 | } | ||
194 | |||
195 | /* Write resource back into BAR register */ | ||
196 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; | ||
197 | rp[LREG(addr)] = val; | ||
198 | #ifdef DEBUGRES | ||
199 | printk(KERN_DEBUG "BAR[%d]: assigned bar=%08x\n", bar, val); | ||
200 | #endif | ||
201 | } | ||
202 | |||
203 | #ifdef DEBUGRES | ||
204 | printk(KERN_DEBUG "-----------------------------------" | ||
205 | "-------------------------------------\n"); | ||
206 | #endif | ||
207 | |||
208 | /* Assign IRQ if one is wanted... */ | ||
209 | ip = (volatile unsigned char *) (COMEM_BASE + COMEM_PCIBUS); | ||
210 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; | ||
211 | |||
212 | addr = (PCI_INTERRUPT_PIN & 0xfc) + (~PCI_INTERRUPT_PIN & 0x03); | ||
213 | if (ip[addr]) { | ||
214 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; | ||
215 | addr = (PCI_INTERRUPT_LINE & 0xfc)+(~PCI_INTERRUPT_LINE & 0x03); | ||
216 | ip[addr] = 25; | ||
217 | #ifdef DEBUGRES | ||
218 | printk(KERN_DEBUG "IRQ LINE=25\n"); | ||
219 | #endif | ||
220 | } | ||
221 | |||
222 | return(0); | ||
223 | } | ||
224 | |||
225 | /*****************************************************************************/ | ||
226 | |||
227 | int pcibios_enable_slot(int slot) | ||
228 | { | ||
229 | volatile unsigned long *rp; | ||
230 | volatile unsigned short *wp; | ||
231 | unsigned int idsel, addr; | ||
232 | unsigned short cmd; | ||
233 | |||
234 | #ifdef DEBUGPCI | ||
235 | printk(KERN_DEBUG "pcibios_enbale_slot(slot=%x)\n", slot); | ||
236 | #endif | ||
237 | |||
238 | rp = (volatile unsigned long *) COMEM_BASE; | ||
239 | wp = (volatile unsigned short *) COMEM_BASE; | ||
240 | idsel = COMEM_DA_ADDR(0x1 << (slot + 16)); | ||
241 | |||
242 | /* Get current command settings */ | ||
243 | addr = COMEM_PCIBUS + PCI_COMMAND; | ||
244 | addr = (addr & ~0x3) + (~addr & 0x02); | ||
245 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; | ||
246 | cmd = wp[WREG(addr)]; | ||
247 | /*val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);*/ | ||
248 | |||
249 | /* Enable I/O and memory accesses to this device */ | ||
250 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; | ||
251 | cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; | ||
252 | wp[WREG(addr)] = cmd; | ||
253 | |||
254 | return(0); | ||
255 | } | ||
256 | |||
257 | /*****************************************************************************/ | ||
258 | |||
259 | void pcibios_assign_resources(void) | ||
260 | { | ||
261 | volatile unsigned long *rp; | ||
262 | unsigned long sel, id; | ||
263 | int slot; | ||
264 | |||
265 | rp = (volatile unsigned long *) COMEM_BASE; | ||
266 | |||
267 | /* | ||
268 | * Do a quick scan of the PCI bus and see what is here. | ||
269 | */ | ||
270 | for (slot = COMEM_MINDEV; (slot <= COMEM_MAXDEV); slot++) { | ||
271 | sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16)); | ||
272 | rp[LREG(COMEM_DAHBASE)] = sel; | ||
273 | rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */ | ||
274 | id = rp[LREG(COMEM_PCIBUS)]; | ||
275 | if ((id != 0) && ((id & 0xffff0000) != (sel & 0xffff0000))) { | ||
276 | printk(KERN_INFO "PCI: slot=%d id=%08x\n", slot, (int) id); | ||
277 | pci_slotmask |= 0x1 << slot; | ||
278 | pcibios_assign_resource_slot(slot); | ||
279 | pcibios_enable_slot(slot); | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | /*****************************************************************************/ | ||
285 | |||
286 | int pcibios_init(void) | ||
287 | { | ||
288 | volatile unsigned long *rp; | ||
289 | unsigned long sel, id; | ||
290 | int slot; | ||
291 | |||
292 | #ifdef DEBUGPCI | ||
293 | printk(KERN_DEBUG "pcibios_init()\n"); | ||
294 | #endif | ||
295 | |||
296 | pci_resetbus(); | ||
297 | |||
298 | /* | ||
299 | * Do some sort of basic check to see if the CO-MEM part | ||
300 | * is present... This works ok, but I think we really need | ||
301 | * something better... | ||
302 | */ | ||
303 | rp = (volatile unsigned long *) COMEM_BASE; | ||
304 | if ((rp[LREG(COMEM_LBUSCFG)] & 0xff) != 0x50) { | ||
305 | printk(KERN_INFO "PCI: no PCI bus present\n"); | ||
306 | return(0); | ||
307 | } | ||
308 | |||
309 | #ifdef COMEM_BRIDGEDEV | ||
310 | /* | ||
311 | * Setup the PCI bridge device first. It needs resources too, | ||
312 | * so that bus masters can get to its shared memory. | ||
313 | */ | ||
314 | slot = COMEM_BRIDGEDEV; | ||
315 | sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16)); | ||
316 | rp[LREG(COMEM_DAHBASE)] = sel; | ||
317 | rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */ | ||
318 | id = rp[LREG(COMEM_PCIBUS)]; | ||
319 | if ((id == 0) || ((id & 0xffff0000) == (sel & 0xffff0000))) { | ||
320 | printk(KERN_INFO "PCI: no PCI bus bridge present\n"); | ||
321 | return(0); | ||
322 | } | ||
323 | |||
324 | printk(KERN_INFO "PCI: bridge device at slot=%d id=%08x\n", slot, (int) id); | ||
325 | pci_slotmask |= 0x1 << slot; | ||
326 | pci_shmemaddr = pci_membase; | ||
327 | pcibios_assign_resource_slot(slot); | ||
328 | pcibios_enable_slot(slot); | ||
329 | #endif | ||
330 | |||
331 | pci_bus_is_present = 1; | ||
332 | |||
333 | /* Get PCI irq for local vectoring */ | ||
334 | if (request_irq(COMEM_IRQ, pci_interrupt, 0, "PCI bridge", NULL)) { | ||
335 | printk(KERN_WARNING "PCI: failed to acquire interrupt %d\n", COMEM_IRQ); | ||
336 | } else { | ||
337 | mcf_autovector(COMEM_IRQ); | ||
338 | } | ||
339 | |||
340 | pcibios_assign_resources(); | ||
341 | |||
342 | return(0); | ||
343 | } | ||
344 | |||
345 | /*****************************************************************************/ | ||
346 | |||
347 | char *pcibios_setup(char *option) | ||
348 | { | ||
349 | /* Nothing for us to handle. */ | ||
350 | return(option); | ||
351 | } | ||
352 | /*****************************************************************************/ | ||
353 | |||
354 | void pcibios_fixup_bus(struct pci_bus *b) | ||
355 | { | ||
356 | } | ||
357 | |||
358 | /*****************************************************************************/ | ||
359 | |||
360 | void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align) | ||
361 | { | ||
362 | } | ||
363 | |||
364 | /*****************************************************************************/ | ||
365 | |||
366 | int pcibios_enable_device(struct pci_dev *dev, int mask) | ||
367 | { | ||
368 | int slot; | ||
369 | |||
370 | slot = PCI_SLOT(dev->devfn); | ||
371 | if ((dev->bus == 0) && (pci_slotmask & (1 << slot))) | ||
372 | pcibios_enable_slot(slot); | ||
373 | return(0); | ||
374 | } | ||
375 | |||
376 | /*****************************************************************************/ | ||
377 | |||
378 | void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *r, int resource) | ||
379 | { | ||
380 | printk(KERN_WARNING "%s(%d): no support for changing PCI resources...\n", | ||
381 | __FILE__, __LINE__); | ||
382 | } | ||
383 | |||
384 | |||
385 | /*****************************************************************************/ | ||
386 | |||
387 | /* | ||
388 | * Local routines to interrcept the standard I/O and vector handling | ||
389 | * code. Don't include this 'till now - initialization code above needs | ||
390 | * access to the real code too. | ||
391 | */ | ||
392 | #include <asm/mcfpci.h> | ||
393 | |||
394 | /*****************************************************************************/ | ||
395 | |||
396 | void pci_outb(unsigned char val, unsigned int addr) | ||
397 | { | ||
398 | volatile unsigned long *rp; | ||
399 | volatile unsigned char *bp; | ||
400 | |||
401 | #ifdef DEBUGIO | ||
402 | printk(KERN_DEBUG "pci_outb(val=%02x,addr=%x)\n", val, addr); | ||
403 | #endif | ||
404 | |||
405 | rp = (volatile unsigned long *) COMEM_BASE; | ||
406 | bp = (volatile unsigned char *) COMEM_BASE; | ||
407 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); | ||
408 | addr = (addr & ~0x3) + (~addr & 0x03); | ||
409 | bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; | ||
410 | } | ||
411 | |||
412 | /*****************************************************************************/ | ||
413 | |||
414 | void pci_outw(unsigned short val, unsigned int addr) | ||
415 | { | ||
416 | volatile unsigned long *rp; | ||
417 | volatile unsigned short *sp; | ||
418 | |||
419 | #ifdef DEBUGIO | ||
420 | printk(KERN_DEBUG "pci_outw(val=%04x,addr=%x)\n", val, addr); | ||
421 | #endif | ||
422 | |||
423 | rp = (volatile unsigned long *) COMEM_BASE; | ||
424 | sp = (volatile unsigned short *) COMEM_BASE; | ||
425 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); | ||
426 | addr = (addr & ~0x3) + (~addr & 0x02); | ||
427 | if (pci_byteswap) | ||
428 | val = ((val & 0xff) << 8) | ((val >> 8) & 0xff); | ||
429 | sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; | ||
430 | } | ||
431 | |||
432 | /*****************************************************************************/ | ||
433 | |||
434 | void pci_outl(unsigned int val, unsigned int addr) | ||
435 | { | ||
436 | volatile unsigned long *rp; | ||
437 | volatile unsigned int *lp; | ||
438 | |||
439 | #ifdef DEBUGIO | ||
440 | printk(KERN_DEBUG "pci_outl(val=%08x,addr=%x)\n", val, addr); | ||
441 | #endif | ||
442 | |||
443 | rp = (volatile unsigned long *) COMEM_BASE; | ||
444 | lp = (volatile unsigned int *) COMEM_BASE; | ||
445 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); | ||
446 | |||
447 | if (pci_byteswap) | ||
448 | val = (val << 24) | ((val & 0x0000ff00) << 8) | | ||
449 | ((val & 0x00ff0000) >> 8) | (val >> 24); | ||
450 | |||
451 | lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; | ||
452 | } | ||
453 | |||
454 | /*****************************************************************************/ | ||
455 | |||
456 | unsigned long pci_blmask[] = { | ||
457 | 0x000000e0, | ||
458 | 0x000000d0, | ||
459 | 0x000000b0, | ||
460 | 0x00000070 | ||
461 | }; | ||
462 | |||
463 | unsigned char pci_inb(unsigned int addr) | ||
464 | { | ||
465 | volatile unsigned long *rp; | ||
466 | volatile unsigned char *bp; | ||
467 | unsigned long r; | ||
468 | unsigned char val; | ||
469 | |||
470 | #ifdef DEBUGIO | ||
471 | printk(KERN_DEBUG "pci_inb(addr=%x)\n", addr); | ||
472 | #endif | ||
473 | |||
474 | rp = (volatile unsigned long *) COMEM_BASE; | ||
475 | bp = (volatile unsigned char *) COMEM_BASE; | ||
476 | |||
477 | r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_blmask[(addr & 0x3)]; | ||
478 | rp[LREG(COMEM_DAHBASE)] = r; | ||
479 | |||
480 | addr = (addr & ~0x3) + (~addr & 0x3); | ||
481 | val = bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; | ||
482 | return(val); | ||
483 | } | ||
484 | |||
485 | /*****************************************************************************/ | ||
486 | |||
487 | unsigned long pci_bwmask[] = { | ||
488 | 0x000000c0, | ||
489 | 0x000000c0, | ||
490 | 0x00000030, | ||
491 | 0x00000030 | ||
492 | }; | ||
493 | |||
494 | unsigned short pci_inw(unsigned int addr) | ||
495 | { | ||
496 | volatile unsigned long *rp; | ||
497 | volatile unsigned short *sp; | ||
498 | unsigned long r; | ||
499 | unsigned short val; | ||
500 | |||
501 | #ifdef DEBUGIO | ||
502 | printk(KERN_DEBUG "pci_inw(addr=%x)", addr); | ||
503 | #endif | ||
504 | |||
505 | rp = (volatile unsigned long *) COMEM_BASE; | ||
506 | r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_bwmask[(addr & 0x3)]; | ||
507 | rp[LREG(COMEM_DAHBASE)] = r; | ||
508 | |||
509 | sp = (volatile unsigned short *) COMEM_BASE; | ||
510 | addr = (addr & ~0x3) + (~addr & 0x02); | ||
511 | val = sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; | ||
512 | if (pci_byteswap) | ||
513 | val = ((val & 0xff) << 8) | ((val >> 8) & 0xff); | ||
514 | #ifdef DEBUGIO | ||
515 | printk(KERN_DEBUG "=%04x\n", val); | ||
516 | #endif | ||
517 | return(val); | ||
518 | } | ||
519 | |||
520 | /*****************************************************************************/ | ||
521 | |||
522 | unsigned int pci_inl(unsigned int addr) | ||
523 | { | ||
524 | volatile unsigned long *rp; | ||
525 | volatile unsigned int *lp; | ||
526 | unsigned int val; | ||
527 | |||
528 | #ifdef DEBUGIO | ||
529 | printk(KERN_DEBUG "pci_inl(addr=%x)", addr); | ||
530 | #endif | ||
531 | |||
532 | rp = (volatile unsigned long *) COMEM_BASE; | ||
533 | lp = (volatile unsigned int *) COMEM_BASE; | ||
534 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(addr); | ||
535 | val = lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; | ||
536 | |||
537 | if (pci_byteswap) | ||
538 | val = (val << 24) | ((val & 0x0000ff00) << 8) | | ||
539 | ((val & 0x00ff0000) >> 8) | (val >> 24); | ||
540 | |||
541 | #ifdef DEBUGIO | ||
542 | printk(KERN_DEBUG "=%08x\n", val); | ||
543 | #endif | ||
544 | return(val); | ||
545 | } | ||
546 | |||
547 | /*****************************************************************************/ | ||
548 | |||
549 | void pci_outsb(void *addr, void *buf, int len) | ||
550 | { | ||
551 | volatile unsigned long *rp; | ||
552 | volatile unsigned char *bp; | ||
553 | unsigned char *dp = (unsigned char *) buf; | ||
554 | unsigned int a = (unsigned int) addr; | ||
555 | |||
556 | #ifdef DEBUGIO | ||
557 | printk(KERN_DEBUG "pci_outsb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
558 | #endif | ||
559 | |||
560 | rp = (volatile unsigned long *) COMEM_BASE; | ||
561 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); | ||
562 | |||
563 | a = (a & ~0x3) + (~a & 0x03); | ||
564 | bp = (volatile unsigned char *) | ||
565 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
566 | |||
567 | while (len--) | ||
568 | *bp = *dp++; | ||
569 | } | ||
570 | |||
571 | /*****************************************************************************/ | ||
572 | |||
573 | void pci_outsw(void *addr, void *buf, int len) | ||
574 | { | ||
575 | volatile unsigned long *rp; | ||
576 | volatile unsigned short *wp; | ||
577 | unsigned short w, *dp = (unsigned short *) buf; | ||
578 | unsigned int a = (unsigned int) addr; | ||
579 | |||
580 | #ifdef DEBUGIO | ||
581 | printk(KERN_DEBUG "pci_outsw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
582 | #endif | ||
583 | |||
584 | rp = (volatile unsigned long *) COMEM_BASE; | ||
585 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); | ||
586 | |||
587 | a = (a & ~0x3) + (~a & 0x2); | ||
588 | wp = (volatile unsigned short *) | ||
589 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
590 | |||
591 | while (len--) { | ||
592 | w = *dp++; | ||
593 | if (pci_byteswap) | ||
594 | w = ((w & 0xff) << 8) | ((w >> 8) & 0xff); | ||
595 | *wp = w; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /*****************************************************************************/ | ||
600 | |||
601 | void pci_outsl(void *addr, void *buf, int len) | ||
602 | { | ||
603 | volatile unsigned long *rp; | ||
604 | volatile unsigned long *lp; | ||
605 | unsigned long l, *dp = (unsigned long *) buf; | ||
606 | unsigned int a = (unsigned int) addr; | ||
607 | |||
608 | #ifdef DEBUGIO | ||
609 | printk(KERN_DEBUG "pci_outsl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
610 | #endif | ||
611 | |||
612 | rp = (volatile unsigned long *) COMEM_BASE; | ||
613 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); | ||
614 | |||
615 | lp = (volatile unsigned long *) | ||
616 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
617 | |||
618 | while (len--) { | ||
619 | l = *dp++; | ||
620 | if (pci_byteswap) | ||
621 | l = (l << 24) | ((l & 0x0000ff00) << 8) | | ||
622 | ((l & 0x00ff0000) >> 8) | (l >> 24); | ||
623 | *lp = l; | ||
624 | } | ||
625 | } | ||
626 | |||
627 | /*****************************************************************************/ | ||
628 | |||
629 | void pci_insb(void *addr, void *buf, int len) | ||
630 | { | ||
631 | volatile unsigned long *rp; | ||
632 | volatile unsigned char *bp; | ||
633 | unsigned char *dp = (unsigned char *) buf; | ||
634 | unsigned int a = (unsigned int) addr; | ||
635 | |||
636 | #ifdef DEBUGIO | ||
637 | printk(KERN_DEBUG "pci_insb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
638 | #endif | ||
639 | |||
640 | rp = (volatile unsigned long *) COMEM_BASE; | ||
641 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); | ||
642 | |||
643 | a = (a & ~0x3) + (~a & 0x03); | ||
644 | bp = (volatile unsigned char *) | ||
645 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
646 | |||
647 | while (len--) | ||
648 | *dp++ = *bp; | ||
649 | } | ||
650 | |||
651 | /*****************************************************************************/ | ||
652 | |||
653 | void pci_insw(void *addr, void *buf, int len) | ||
654 | { | ||
655 | volatile unsigned long *rp; | ||
656 | volatile unsigned short *wp; | ||
657 | unsigned short w, *dp = (unsigned short *) buf; | ||
658 | unsigned int a = (unsigned int) addr; | ||
659 | |||
660 | #ifdef DEBUGIO | ||
661 | printk(KERN_DEBUG "pci_insw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
662 | #endif | ||
663 | |||
664 | rp = (volatile unsigned long *) COMEM_BASE; | ||
665 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); | ||
666 | |||
667 | a = (a & ~0x3) + (~a & 0x2); | ||
668 | wp = (volatile unsigned short *) | ||
669 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
670 | |||
671 | while (len--) { | ||
672 | w = *wp; | ||
673 | if (pci_byteswap) | ||
674 | w = ((w & 0xff) << 8) | ((w >> 8) & 0xff); | ||
675 | *dp++ = w; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | /*****************************************************************************/ | ||
680 | |||
681 | void pci_insl(void *addr, void *buf, int len) | ||
682 | { | ||
683 | volatile unsigned long *rp; | ||
684 | volatile unsigned long *lp; | ||
685 | unsigned long l, *dp = (unsigned long *) buf; | ||
686 | unsigned int a = (unsigned int) addr; | ||
687 | |||
688 | #ifdef DEBUGIO | ||
689 | printk(KERN_DEBUG "pci_insl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
690 | #endif | ||
691 | |||
692 | rp = (volatile unsigned long *) COMEM_BASE; | ||
693 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); | ||
694 | |||
695 | lp = (volatile unsigned long *) | ||
696 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
697 | |||
698 | while (len--) { | ||
699 | l = *lp; | ||
700 | if (pci_byteswap) | ||
701 | l = (l << 24) | ((l & 0x0000ff00) << 8) | | ||
702 | ((l & 0x00ff0000) >> 8) | (l >> 24); | ||
703 | *dp++ = l; | ||
704 | } | ||
705 | } | ||
706 | |||
707 | /*****************************************************************************/ | ||
708 | |||
709 | struct pci_localirqlist { | ||
710 | void (*handler)(int, void *, struct pt_regs *); | ||
711 | const char *device; | ||
712 | void *dev_id; | ||
713 | }; | ||
714 | |||
715 | struct pci_localirqlist pci_irqlist[COMEM_MAXPCI]; | ||
716 | |||
717 | /*****************************************************************************/ | ||
718 | |||
719 | int pci_request_irq(unsigned int irq, | ||
720 | void (*handler)(int, void *, struct pt_regs *), | ||
721 | unsigned long flags, const char *device, void *dev_id) | ||
722 | { | ||
723 | int i; | ||
724 | |||
725 | #ifdef DEBUGIO | ||
726 | printk(KERN_DEBUG "pci_request_irq(irq=%d,handler=%x,flags=%x,device=%s," | ||
727 | "dev_id=%x)\n", irq, (int) handler, (int) flags, device, | ||
728 | (int) dev_id); | ||
729 | #endif | ||
730 | |||
731 | /* Check if this interrupt handler is already lodged */ | ||
732 | for (i = 0; (i < COMEM_MAXPCI); i++) { | ||
733 | if (pci_irqlist[i].handler == handler) | ||
734 | return(0); | ||
735 | } | ||
736 | |||
737 | /* Find a free spot to put this handler */ | ||
738 | for (i = 0; (i < COMEM_MAXPCI); i++) { | ||
739 | if (pci_irqlist[i].handler == 0) { | ||
740 | pci_irqlist[i].handler = handler; | ||
741 | pci_irqlist[i].device = device; | ||
742 | pci_irqlist[i].dev_id = dev_id; | ||
743 | return(0); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | /* Couldn't fit?? */ | ||
748 | return(1); | ||
749 | } | ||
750 | |||
751 | /*****************************************************************************/ | ||
752 | |||
753 | void pci_free_irq(unsigned int irq, void *dev_id) | ||
754 | { | ||
755 | int i; | ||
756 | |||
757 | #ifdef DEBUGIO | ||
758 | printk(KERN_DEBUG "pci_free_irq(irq=%d,dev_id=%x)\n", irq, (int) dev_id); | ||
759 | #endif | ||
760 | |||
761 | if (dev_id == (void *) NULL) | ||
762 | return; | ||
763 | |||
764 | /* Check if this interrupt handler is lodged */ | ||
765 | for (i = 0; (i < COMEM_MAXPCI); i++) { | ||
766 | if (pci_irqlist[i].dev_id == dev_id) { | ||
767 | pci_irqlist[i].handler = NULL; | ||
768 | pci_irqlist[i].device = NULL; | ||
769 | pci_irqlist[i].dev_id = NULL; | ||
770 | break; | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | |||
775 | /*****************************************************************************/ | ||
776 | |||
777 | void pci_interrupt(int irq, void *id, struct pt_regs *fp) | ||
778 | { | ||
779 | int i; | ||
780 | |||
781 | #ifdef DEBUGIO | ||
782 | printk(KERN_DEBUG "pci_interrupt(irq=%d,id=%x,fp=%x)\n", irq, (int) id, (int) fp); | ||
783 | #endif | ||
784 | |||
785 | for (i = 0; (i < COMEM_MAXPCI); i++) { | ||
786 | if (pci_irqlist[i].handler) | ||
787 | (*pci_irqlist[i].handler)(irq,pci_irqlist[i].dev_id,fp); | ||
788 | } | ||
789 | } | ||
790 | |||
791 | /*****************************************************************************/ | ||
792 | |||
793 | /* | ||
794 | * The shared memory region is broken up into contiguous 512 byte | ||
795 | * regions for easy allocation... This is not an optimal solution | ||
796 | * but it makes allocation and freeing regions really easy. | ||
797 | */ | ||
798 | |||
799 | #define PCI_MEMSLOTSIZE 512 | ||
800 | #define PCI_MEMSLOTS (COMEM_SHMEMSIZE / PCI_MEMSLOTSIZE) | ||
801 | |||
802 | char pci_shmemmap[PCI_MEMSLOTS]; | ||
803 | |||
804 | |||
805 | void *pci_bmalloc(int size) | ||
806 | { | ||
807 | int i, j, nrslots; | ||
808 | |||
809 | #ifdef DEBUGIO | ||
810 | printk(KERN_DEBUG "pci_bmalloc(size=%d)\n", size); | ||
811 | #endif | ||
812 | |||
813 | if (size <= 0) | ||
814 | return((void *) NULL); | ||
815 | |||
816 | nrslots = (size - 1) / PCI_MEMSLOTSIZE; | ||
817 | |||
818 | for (i = 0; (i < (PCI_MEMSLOTS-nrslots)); i++) { | ||
819 | if (pci_shmemmap[i] == 0) { | ||
820 | for (j = i+1; (j < (i+nrslots)); j++) { | ||
821 | if (pci_shmemmap[j]) | ||
822 | goto restart; | ||
823 | } | ||
824 | |||
825 | for (j = i; (j <= i+nrslots); j++) | ||
826 | pci_shmemmap[j] = 1; | ||
827 | break; | ||
828 | } | ||
829 | restart: | ||
830 | } | ||
831 | |||
832 | return((void *) (COMEM_BASE + COMEM_SHMEM + (i * PCI_MEMSLOTSIZE))); | ||
833 | } | ||
834 | |||
835 | /*****************************************************************************/ | ||
836 | |||
837 | void pci_bmfree(void *mp, int size) | ||
838 | { | ||
839 | int i, j, nrslots; | ||
840 | |||
841 | #ifdef DEBUGIO | ||
842 | printk(KERN_DEBUG "pci_bmfree(mp=%x,size=%d)\n", (int) mp, size); | ||
843 | #endif | ||
844 | |||
845 | nrslots = size / PCI_MEMSLOTSIZE; | ||
846 | i = (((unsigned long) mp) - (COMEM_BASE + COMEM_SHMEM)) / | ||
847 | PCI_MEMSLOTSIZE; | ||
848 | |||
849 | for (j = i; (j < (i+nrslots)); j++) | ||
850 | pci_shmemmap[j] = 0; | ||
851 | } | ||
852 | |||
853 | /*****************************************************************************/ | ||
854 | |||
855 | unsigned long pci_virt_to_bus(volatile void *address) | ||
856 | { | ||
857 | unsigned long l; | ||
858 | |||
859 | #ifdef DEBUGIO | ||
860 | printk(KERN_DEBUG "pci_virt_to_bus(address=%x)", (int) address); | ||
861 | #endif | ||
862 | |||
863 | l = ((unsigned long) address) - COMEM_BASE; | ||
864 | #ifdef DEBUGIO | ||
865 | printk(KERN_DEBUG "=%x\n", (int) (l+pci_shmemaddr)); | ||
866 | #endif | ||
867 | return(l + pci_shmemaddr); | ||
868 | } | ||
869 | |||
870 | /*****************************************************************************/ | ||
871 | |||
872 | void *pci_bus_to_virt(unsigned long address) | ||
873 | { | ||
874 | unsigned long l; | ||
875 | |||
876 | #ifdef DEBUGIO | ||
877 | printk(KERN_DEBUG "pci_bus_to_virt(address=%x)", (int) address); | ||
878 | #endif | ||
879 | |||
880 | l = address - pci_shmemaddr; | ||
881 | #ifdef DEBUGIO | ||
882 | printk(KERN_DEBUG "=%x\n", (int) (address + COMEM_BASE)); | ||
883 | #endif | ||
884 | return((void *) (address + COMEM_BASE)); | ||
885 | } | ||
886 | |||
887 | /*****************************************************************************/ | ||
888 | |||
889 | void pci_bmcpyto(void *dst, void *src, int len) | ||
890 | { | ||
891 | unsigned long *dp, *sp, val; | ||
892 | unsigned char *dcp, *scp; | ||
893 | int i, j; | ||
894 | |||
895 | #ifdef DEBUGIO | ||
896 | printk(KERN_DEBUG "pci_bmcpyto(dst=%x,src=%x,len=%d)\n", (int)dst, (int)src, len); | ||
897 | #endif | ||
898 | |||
899 | dp = (unsigned long *) dst; | ||
900 | sp = (unsigned long *) src; | ||
901 | i = len >> 2; | ||
902 | |||
903 | #if 0 | ||
904 | printk(KERN_INFO "DATA:"); | ||
905 | scp = (unsigned char *) sp; | ||
906 | for (i = 0; (i < len); i++) { | ||
907 | if ((i % 16) == 0) printk(KERN_INFO "\n%04x: ", i); | ||
908 | printk(KERN_INFO "%02x ", *scp++); | ||
909 | } | ||
910 | printk(KERN_INFO "\n"); | ||
911 | #endif | ||
912 | |||
913 | for (j = 0; (i >= 0); i--, j++) { | ||
914 | val = *sp++; | ||
915 | val = (val << 24) | ((val & 0x0000ff00) << 8) | | ||
916 | ((val & 0x00ff0000) >> 8) | (val >> 24); | ||
917 | *dp++ = val; | ||
918 | } | ||
919 | |||
920 | if (len & 0x3) { | ||
921 | dcp = (unsigned char *) dp; | ||
922 | scp = ((unsigned char *) sp) + 3; | ||
923 | for (i = 0; (i < (len & 0x3)); i++) | ||
924 | *dcp++ = *scp--; | ||
925 | } | ||
926 | } | ||
927 | |||
928 | /*****************************************************************************/ | ||
929 | |||
930 | void pci_bmcpyfrom(void *dst, void *src, int len) | ||
931 | { | ||
932 | unsigned long *dp, *sp, val; | ||
933 | unsigned char *dcp, *scp; | ||
934 | int i; | ||
935 | |||
936 | #ifdef DEBUGIO | ||
937 | printk(KERN_DEBUG "pci_bmcpyfrom(dst=%x,src=%x,len=%d)\n",(int)dst,(int)src,len); | ||
938 | #endif | ||
939 | |||
940 | dp = (unsigned long *) dst; | ||
941 | sp = (unsigned long *) src; | ||
942 | i = len >> 2; | ||
943 | |||
944 | for (; (i >= 0); i--) { | ||
945 | val = *sp++; | ||
946 | val = (val << 24) | ((val & 0x0000ff00) << 8) | | ||
947 | ((val & 0x00ff0000) >> 8) | (val >> 24); | ||
948 | *dp++ = val; | ||
949 | } | ||
950 | |||
951 | if (len & 0x3) { | ||
952 | dcp = ((unsigned char *) dp) + 3; | ||
953 | scp = (unsigned char *) sp; | ||
954 | for (i = 0; (i < (len & 0x3)); i++) | ||
955 | *dcp++ = *scp--; | ||
956 | } | ||
957 | |||
958 | #if 0 | ||
959 | printk(KERN_INFO "DATA:"); | ||
960 | dcp = (unsigned char *) dst; | ||
961 | for (i = 0; (i < len); i++) { | ||
962 | if ((i % 16) == 0) printk(KERN_INFO "\n%04x: ", i); | ||
963 | printk(KERN_INFO "%02x ", *dcp++); | ||
964 | } | ||
965 | printk(KERN_INFO "\n"); | ||
966 | #endif | ||
967 | } | ||
968 | |||
969 | /*****************************************************************************/ | ||
970 | |||
971 | void *pci_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_addr) | ||
972 | { | ||
973 | void *mp; | ||
974 | if ((mp = pci_bmalloc(size)) != NULL) { | ||
975 | dma_addr = mp - (COMEM_BASE + COMEM_SHMEM); | ||
976 | return(mp); | ||
977 | } | ||
978 | *dma_addr = (dma_addr_t) NULL; | ||
979 | return(NULL); | ||
980 | } | ||
981 | |||
982 | /*****************************************************************************/ | ||
983 | |||
984 | void pci_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr, dma_addr_t dma_addr) | ||
985 | { | ||
986 | pci_bmfree(cpu_addr, size); | ||
987 | } | ||
988 | |||
989 | /*****************************************************************************/ | ||