diff options
Diffstat (limited to 'arch/ppc/syslib/qspan_pci.c')
-rw-r--r-- | arch/ppc/syslib/qspan_pci.c | 380 |
1 files changed, 0 insertions, 380 deletions
diff --git a/arch/ppc/syslib/qspan_pci.c b/arch/ppc/syslib/qspan_pci.c deleted file mode 100644 index 7a97c7440b30..000000000000 --- a/arch/ppc/syslib/qspan_pci.c +++ /dev/null | |||
@@ -1,380 +0,0 @@ | |||
1 | /* | ||
2 | * QSpan pci routines. | ||
3 | * Most 8xx boards use the QSpan PCI bridge. The config address register | ||
4 | * is located 0x500 from the base of the bridge control/status registers. | ||
5 | * The data register is located at 0x504. | ||
6 | * This is a two step operation. First, the address register is written, | ||
7 | * then the data register is read/written as required. | ||
8 | * I don't know what to do about interrupts (yet). | ||
9 | * | ||
10 | * The RPX Classic implementation shares a chip select for normal | ||
11 | * PCI access and QSpan control register addresses. The selection is | ||
12 | * further selected by a bit setting in a board control register. | ||
13 | * Although it should happen, we disable interrupts during this operation | ||
14 | * to make sure some driver doesn't accidentally access the PCI while | ||
15 | * we have switched the chip select. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/init.h> | ||
23 | |||
24 | #include <asm/io.h> | ||
25 | #include <asm/mpc8xx.h> | ||
26 | #include <asm/system.h> | ||
27 | #include <asm/machdep.h> | ||
28 | #include <asm/pci-bridge.h> | ||
29 | |||
30 | |||
31 | /* | ||
32 | * This blows...... | ||
33 | * When reading the configuration space, if something does not respond | ||
34 | * the bus times out and we get a machine check interrupt. So, the | ||
35 | * good ol' exception tables come to mind to trap it and return some | ||
36 | * value. | ||
37 | * | ||
38 | * On an error we just return a -1, since that is what the caller wants | ||
39 | * returned if nothing is present. I copied this from __get_user_asm, | ||
40 | * with the only difference of returning -1 instead of EFAULT. | ||
41 | * There is an associated hack in the machine check trap code. | ||
42 | * | ||
43 | * The QSPAN is also a big endian device, that is it makes the PCI | ||
44 | * look big endian to us. This presents a problem for the Linux PCI | ||
45 | * functions, which assume little endian. For example, we see the | ||
46 | * first 32-bit word like this: | ||
47 | * ------------------------ | ||
48 | * | Device ID | Vendor ID | | ||
49 | * ------------------------ | ||
50 | * If we read/write as a double word, that's OK. But in our world, | ||
51 | * when read as a word, device ID is at location 0, not location 2 as | ||
52 | * the little endian PCI would believe. We have to switch bits in | ||
53 | * the PCI addresses given to us to get the data to/from the correct | ||
54 | * byte lanes. | ||
55 | * | ||
56 | * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. | ||
57 | * It always forces the MS bit to zero. Therefore, dev_fn values | ||
58 | * greater than 128 are returned as "no device found" errors. | ||
59 | * | ||
60 | * The QSPAN can only perform long word (32-bit) configuration cycles. | ||
61 | * The "offset" must have the two LS bits set to zero. Read operations | ||
62 | * require we read the entire word and then sort out what should be | ||
63 | * returned. Write operations other than long word require that we | ||
64 | * read the long word, update the proper word or byte, then write the | ||
65 | * entire long word back. | ||
66 | * | ||
67 | * PCI Bridge hack. We assume (correctly) that bus 0 is the primary | ||
68 | * PCI bus from the QSPAN. If we are called with a bus number other | ||
69 | * than zero, we create a Type 1 configuration access that a downstream | ||
70 | * PCI bridge will interpret. | ||
71 | */ | ||
72 | |||
73 | #define __get_qspan_pci_config(x, addr, op) \ | ||
74 | __asm__ __volatile__( \ | ||
75 | "1: "op" %0,0(%1)\n" \ | ||
76 | " eieio\n" \ | ||
77 | "2:\n" \ | ||
78 | ".section .fixup,\"ax\"\n" \ | ||
79 | "3: li %0,-1\n" \ | ||
80 | " b 2b\n" \ | ||
81 | ".section __ex_table,\"a\"\n" \ | ||
82 | " .align 2\n" \ | ||
83 | " .long 1b,3b\n" \ | ||
84 | ".text" \ | ||
85 | : "=r"(x) : "r"(addr) : " %0") | ||
86 | |||
87 | #define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) | ||
88 | #define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) | ||
89 | |||
90 | #define mk_config_addr(bus, dev, offset) \ | ||
91 | (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) | ||
92 | |||
93 | #define mk_config_type1(bus, dev, offset) \ | ||
94 | mk_config_addr(bus, dev, offset) | 1; | ||
95 | |||
96 | static DEFINE_SPINLOCK(pcibios_lock); | ||
97 | |||
98 | int qspan_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, | ||
99 | unsigned char offset, unsigned char *val) | ||
100 | { | ||
101 | uint temp; | ||
102 | u_char *cp; | ||
103 | #ifdef CONFIG_RPXCLASSIC | ||
104 | unsigned long flags; | ||
105 | #endif | ||
106 | |||
107 | if ((bus > 7) || (dev_fn > 127)) { | ||
108 | *val = 0xff; | ||
109 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
110 | } | ||
111 | |||
112 | #ifdef CONFIG_RPXCLASSIC | ||
113 | /* disable interrupts */ | ||
114 | spin_lock_irqsave(&pcibios_lock, flags); | ||
115 | *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; | ||
116 | eieio(); | ||
117 | #endif | ||
118 | |||
119 | if (bus == 0) | ||
120 | *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); | ||
121 | else | ||
122 | *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); | ||
123 | __get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz"); | ||
124 | |||
125 | #ifdef CONFIG_RPXCLASSIC | ||
126 | *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; | ||
127 | eieio(); | ||
128 | spin_unlock_irqrestore(&pcibios_lock, flags); | ||
129 | #endif | ||
130 | |||
131 | offset ^= 0x03; | ||
132 | cp = ((u_char *)&temp) + (offset & 0x03); | ||
133 | *val = *cp; | ||
134 | return PCIBIOS_SUCCESSFUL; | ||
135 | } | ||
136 | |||
137 | int qspan_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, | ||
138 | unsigned char offset, unsigned short *val) | ||
139 | { | ||
140 | uint temp; | ||
141 | ushort *sp; | ||
142 | #ifdef CONFIG_RPXCLASSIC | ||
143 | unsigned long flags; | ||
144 | #endif | ||
145 | |||
146 | if ((bus > 7) || (dev_fn > 127)) { | ||
147 | *val = 0xffff; | ||
148 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
149 | } | ||
150 | |||
151 | #ifdef CONFIG_RPXCLASSIC | ||
152 | /* disable interrupts */ | ||
153 | spin_lock_irqsave(&pcibios_lock, flags); | ||
154 | *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; | ||
155 | eieio(); | ||
156 | #endif | ||
157 | |||
158 | if (bus == 0) | ||
159 | *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); | ||
160 | else | ||
161 | *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); | ||
162 | __get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz"); | ||
163 | offset ^= 0x02; | ||
164 | |||
165 | #ifdef CONFIG_RPXCLASSIC | ||
166 | *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; | ||
167 | eieio(); | ||
168 | spin_unlock_irqrestore(&pcibios_lock, flags); | ||
169 | #endif | ||
170 | |||
171 | sp = ((ushort *)&temp) + ((offset >> 1) & 1); | ||
172 | *val = *sp; | ||
173 | return PCIBIOS_SUCCESSFUL; | ||
174 | } | ||
175 | |||
176 | int qspan_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, | ||
177 | unsigned char offset, unsigned int *val) | ||
178 | { | ||
179 | #ifdef CONFIG_RPXCLASSIC | ||
180 | unsigned long flags; | ||
181 | #endif | ||
182 | |||
183 | if ((bus > 7) || (dev_fn > 127)) { | ||
184 | *val = 0xffffffff; | ||
185 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
186 | } | ||
187 | |||
188 | #ifdef CONFIG_RPXCLASSIC | ||
189 | /* disable interrupts */ | ||
190 | spin_lock_irqsave(&pcibios_lock, flags); | ||
191 | *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; | ||
192 | eieio(); | ||
193 | #endif | ||
194 | |||
195 | if (bus == 0) | ||
196 | *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); | ||
197 | else | ||
198 | *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); | ||
199 | __get_qspan_pci_config(*val, QS_CONFIG_DATA, "lwz"); | ||
200 | |||
201 | #ifdef CONFIG_RPXCLASSIC | ||
202 | *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; | ||
203 | eieio(); | ||
204 | spin_unlock_irqrestore(&pcibios_lock, flags); | ||
205 | #endif | ||
206 | |||
207 | return PCIBIOS_SUCCESSFUL; | ||
208 | } | ||
209 | |||
210 | int qspan_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, | ||
211 | unsigned char offset, unsigned char val) | ||
212 | { | ||
213 | uint temp; | ||
214 | u_char *cp; | ||
215 | #ifdef CONFIG_RPXCLASSIC | ||
216 | unsigned long flags; | ||
217 | #endif | ||
218 | |||
219 | if ((bus > 7) || (dev_fn > 127)) | ||
220 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
221 | |||
222 | qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp); | ||
223 | |||
224 | offset ^= 0x03; | ||
225 | cp = ((u_char *)&temp) + (offset & 0x03); | ||
226 | *cp = val; | ||
227 | |||
228 | #ifdef CONFIG_RPXCLASSIC | ||
229 | /* disable interrupts */ | ||
230 | spin_lock_irqsave(&pcibios_lock, flags); | ||
231 | *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; | ||
232 | eieio(); | ||
233 | #endif | ||
234 | |||
235 | if (bus == 0) | ||
236 | *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); | ||
237 | else | ||
238 | *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); | ||
239 | *QS_CONFIG_DATA = temp; | ||
240 | |||
241 | #ifdef CONFIG_RPXCLASSIC | ||
242 | *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; | ||
243 | eieio(); | ||
244 | spin_unlock_irqrestore(&pcibios_lock, flags); | ||
245 | #endif | ||
246 | |||
247 | return PCIBIOS_SUCCESSFUL; | ||
248 | } | ||
249 | |||
250 | int qspan_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, | ||
251 | unsigned char offset, unsigned short val) | ||
252 | { | ||
253 | uint temp; | ||
254 | ushort *sp; | ||
255 | #ifdef CONFIG_RPXCLASSIC | ||
256 | unsigned long flags; | ||
257 | #endif | ||
258 | |||
259 | if ((bus > 7) || (dev_fn > 127)) | ||
260 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
261 | |||
262 | qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp); | ||
263 | |||
264 | offset ^= 0x02; | ||
265 | sp = ((ushort *)&temp) + ((offset >> 1) & 1); | ||
266 | *sp = val; | ||
267 | |||
268 | #ifdef CONFIG_RPXCLASSIC | ||
269 | /* disable interrupts */ | ||
270 | spin_lock_irqsave(&pcibios_lock, flags); | ||
271 | *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; | ||
272 | eieio(); | ||
273 | #endif | ||
274 | |||
275 | if (bus == 0) | ||
276 | *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); | ||
277 | else | ||
278 | *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); | ||
279 | *QS_CONFIG_DATA = temp; | ||
280 | |||
281 | #ifdef CONFIG_RPXCLASSIC | ||
282 | *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; | ||
283 | eieio(); | ||
284 | spin_unlock_irqrestore(&pcibios_lock, flags); | ||
285 | #endif | ||
286 | |||
287 | return PCIBIOS_SUCCESSFUL; | ||
288 | } | ||
289 | |||
290 | int qspan_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, | ||
291 | unsigned char offset, unsigned int val) | ||
292 | { | ||
293 | #ifdef CONFIG_RPXCLASSIC | ||
294 | unsigned long flags; | ||
295 | #endif | ||
296 | |||
297 | if ((bus > 7) || (dev_fn > 127)) | ||
298 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
299 | |||
300 | #ifdef CONFIG_RPXCLASSIC | ||
301 | /* disable interrupts */ | ||
302 | spin_lock_irqsave(&pcibios_lock, flags); | ||
303 | *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; | ||
304 | eieio(); | ||
305 | #endif | ||
306 | |||
307 | if (bus == 0) | ||
308 | *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); | ||
309 | else | ||
310 | *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); | ||
311 | *(unsigned int *)QS_CONFIG_DATA = val; | ||
312 | |||
313 | #ifdef CONFIG_RPXCLASSIC | ||
314 | *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; | ||
315 | eieio(); | ||
316 | spin_unlock_irqrestore(&pcibios_lock, flags); | ||
317 | #endif | ||
318 | |||
319 | return PCIBIOS_SUCCESSFUL; | ||
320 | } | ||
321 | |||
322 | int qspan_pcibios_find_device(unsigned short vendor, unsigned short dev_id, | ||
323 | unsigned short index, unsigned char *bus_ptr, | ||
324 | unsigned char *dev_fn_ptr) | ||
325 | { | ||
326 | int num, devfn; | ||
327 | unsigned int x, vendev; | ||
328 | |||
329 | if (vendor == 0xffff) | ||
330 | return PCIBIOS_BAD_VENDOR_ID; | ||
331 | vendev = (dev_id << 16) + vendor; | ||
332 | num = 0; | ||
333 | for (devfn = 0; devfn < 32; devfn++) { | ||
334 | qspan_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x); | ||
335 | if (x == vendev) { | ||
336 | if (index == num) { | ||
337 | *bus_ptr = 0; | ||
338 | *dev_fn_ptr = devfn<<3; | ||
339 | return PCIBIOS_SUCCESSFUL; | ||
340 | } | ||
341 | ++num; | ||
342 | } | ||
343 | } | ||
344 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
345 | } | ||
346 | |||
347 | int qspan_pcibios_find_class(unsigned int class_code, unsigned short index, | ||
348 | unsigned char *bus_ptr, unsigned char *dev_fn_ptr) | ||
349 | { | ||
350 | int devnr, x, num; | ||
351 | |||
352 | num = 0; | ||
353 | for (devnr = 0; devnr < 32; devnr++) { | ||
354 | qspan_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x); | ||
355 | if ((x>>8) == class_code) { | ||
356 | if (index == num) { | ||
357 | *bus_ptr = 0; | ||
358 | *dev_fn_ptr = devnr<<3; | ||
359 | return PCIBIOS_SUCCESSFUL; | ||
360 | } | ||
361 | ++num; | ||
362 | } | ||
363 | } | ||
364 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
365 | } | ||
366 | |||
367 | void __init | ||
368 | m8xx_pcibios_fixup(void) | ||
369 | { | ||
370 | /* Lots to do here, all board and configuration specific. */ | ||
371 | } | ||
372 | |||
373 | void __init | ||
374 | m8xx_setup_pci_ptrs(void) | ||
375 | { | ||
376 | set_config_access_method(qspan); | ||
377 | |||
378 | ppc_md.pcibios_fixup = m8xx_pcibios_fixup; | ||
379 | } | ||
380 | |||