Commit | Line | Data |
---|---|---|
6f95e60a MSJ |
1 | /* |
2 | * PMC-Sierra MSP board specific pci_ops | |
3 | * | |
4 | * Copyright 2001 MontaVista Software Inc. | |
5 | * Copyright 2005-2007 PMC-Sierra, Inc | |
6 | * | |
7 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | |
8 | * | |
9 | * Much of the code is derived from the original DDB5074 port by | |
5e888e8f | 10 | * Geert Uytterhoeven <geert@linux-m68k.org> |
6f95e60a | 11 | * |
70342287 RB |
12 | * This program is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | |
6f95e60a MSJ |
14 | * Free Software Foundation; either version 2 of the License, or (at your |
15 | * option) any later version. | |
16 | * | |
17 | */ | |
18 | ||
19 | #define PCI_COUNTERS 1 | |
20 | ||
21 | #include <linux/types.h> | |
22 | #include <linux/pci.h> | |
23 | #include <linux/interrupt.h> | |
24 | ||
25 | #if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) | |
26 | #include <linux/proc_fs.h> | |
27 | #include <linux/seq_file.h> | |
28 | #endif /* CONFIG_PROC_FS && PCI_COUNTERS */ | |
29 | ||
30 | #include <linux/kernel.h> | |
31 | #include <linux/init.h> | |
32 | ||
33 | #include <asm/byteorder.h> | |
34 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | |
35 | #include <asm/mipsmtregs.h> | |
36 | #endif | |
37 | ||
38 | #include <msp_prom.h> | |
39 | #include <msp_cic_int.h> | |
40 | #include <msp_pci.h> | |
41 | #include <msp_regs.h> | |
42 | #include <msp_regops.h> | |
43 | ||
44 | #define PCI_ACCESS_READ 0 | |
45 | #define PCI_ACCESS_WRITE 1 | |
46 | ||
47 | #if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) | |
48 | static char proc_init; | |
49 | extern struct proc_dir_entry *proc_bus_pci_dir; | |
50 | unsigned int pci_int_count[32]; | |
51 | ||
52 | static void pci_proc_init(void); | |
53 | ||
54 | /***************************************************************************** | |
55 | * | |
24270156 | 56 | * FUNCTION: show_msp_pci_counts |
6f95e60a MSJ |
57 | * _________________________________________________________________________ |
58 | * | |
59 | * DESCRIPTION: Prints the count of how many times each PCI | |
70342287 RB |
60 | * interrupt has asserted. Can be invoked by the |
61 | * /proc filesystem. | |
6f95e60a | 62 | * |
24270156 DH |
63 | * INPUTS: m - synthetic file construction data |
64 | * v - iterator | |
6f95e60a | 65 | * |
24270156 | 66 | * RETURNS: 0 or error |
6f95e60a MSJ |
67 | * |
68 | ****************************************************************************/ | |
24270156 | 69 | static int show_msp_pci_counts(struct seq_file *m, void *v) |
6f95e60a MSJ |
70 | { |
71 | int i; | |
6f95e60a MSJ |
72 | unsigned int intcount, total = 0; |
73 | ||
74 | for (i = 0; i < 32; ++i) { | |
75 | intcount = pci_int_count[i]; | |
76 | if (intcount != 0) { | |
24270156 | 77 | seq_printf(m, "[%d] = %u\n", i, intcount); |
6f95e60a MSJ |
78 | total += intcount; |
79 | } | |
80 | } | |
81 | ||
24270156 DH |
82 | seq_printf(m, "total = %u\n", total); |
83 | return 0; | |
84 | } | |
6f95e60a | 85 | |
24270156 DH |
86 | static int msp_pci_rd_cnt_open(struct inode *inode, struct file *file) |
87 | { | |
88 | return single_open(file, show_msp_pci_counts, NULL); | |
6f95e60a MSJ |
89 | } |
90 | ||
24270156 DH |
91 | static const struct file_operations msp_pci_rd_cnt_fops = { |
92 | .open = msp_pci_rd_cnt_open, | |
93 | .read = seq_read, | |
94 | .llseek = seq_lseek, | |
acf300dd | 95 | .release = single_release, |
24270156 DH |
96 | }; |
97 | ||
6f95e60a MSJ |
98 | /***************************************************************************** |
99 | * | |
24270156 | 100 | * FUNCTION: gen_pci_cfg_wr_show |
6f95e60a MSJ |
101 | * _________________________________________________________________________ |
102 | * | |
103 | * DESCRIPTION: Generates a configuration write cycle for debug purposes. | |
70342287 RB |
104 | * The IDSEL line asserted and location and data written are |
105 | * immaterial. Just want to be able to prove that a | |
106 | * configuration write can be correctly generated on the | |
107 | * PCI bus. Intent is that this function by invocable from | |
108 | * the /proc filesystem. | |
6f95e60a | 109 | * |
24270156 DH |
110 | * INPUTS: m - synthetic file construction data |
111 | * v - iterator | |
6f95e60a | 112 | * |
24270156 | 113 | * RETURNS: 0 or error |
6f95e60a MSJ |
114 | * |
115 | ****************************************************************************/ | |
24270156 | 116 | static int gen_pci_cfg_wr_show(struct seq_file *m, void *v) |
6f95e60a MSJ |
117 | { |
118 | unsigned char where = 0; /* Write to static Device/Vendor ID */ | |
119 | unsigned char bus_num = 0; /* Bus 0 */ | |
120 | unsigned char dev_fn = 0xF; /* Arbitrary device number */ | |
121 | u32 wr_data = 0xFF00AA00; /* Arbitrary data */ | |
122 | struct msp_pci_regs *preg = (void *)PCI_BASE_REG; | |
6f95e60a MSJ |
123 | unsigned long value; |
124 | int intr; | |
125 | ||
24270156 | 126 | seq_puts(m, "PMC MSP PCI: Beginning\n"); |
6f95e60a MSJ |
127 | |
128 | if (proc_init == 0) { | |
129 | pci_proc_init(); | |
130 | proc_init = ~0; | |
131 | } | |
132 | ||
24270156 | 133 | seq_puts(m, "PMC MSP PCI: Before Cfg Wr\n"); |
6f95e60a MSJ |
134 | |
135 | /* | |
136 | * Generate PCI Configuration Write Cycle | |
137 | */ | |
138 | ||
139 | /* Clear cause register bits */ | |
140 | preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F); | |
141 | ||
142 | /* Setup address that is to appear on PCI bus */ | |
143 | preg->config_addr = BPCI_CFGADDR_ENABLE | | |
144 | (bus_num << BPCI_CFGADDR_BUSNUM_SHF) | | |
145 | (dev_fn << BPCI_CFGADDR_FUNCTNUM_SHF) | | |
146 | (where & 0xFC); | |
147 | ||
148 | value = cpu_to_le32(wr_data); | |
149 | ||
150 | /* Launch the PCI configuration write cycle */ | |
151 | *PCI_CONFIG_SPACE_REG = value; | |
152 | ||
153 | /* | |
154 | * Check if the PCI configuration cycle (rd or wr) succeeded, by | |
155 | * checking the status bits for errors like master or target abort. | |
156 | */ | |
157 | intr = preg->if_status; | |
158 | ||
24270156 DH |
159 | seq_puts(m, "PMC MSP PCI: After Cfg Wr\n"); |
160 | return 0; | |
161 | } | |
6f95e60a | 162 | |
24270156 DH |
163 | static int gen_pci_cfg_wr_open(struct inode *inode, struct file *file) |
164 | { | |
165 | return single_open(file, gen_pci_cfg_wr_show, NULL); | |
6f95e60a MSJ |
166 | } |
167 | ||
24270156 DH |
168 | static const struct file_operations gen_pci_cfg_wr_fops = { |
169 | .open = gen_pci_cfg_wr_open, | |
170 | .read = seq_read, | |
171 | .llseek = seq_lseek, | |
acf300dd | 172 | .release = single_release, |
24270156 DH |
173 | }; |
174 | ||
6f95e60a MSJ |
175 | /***************************************************************************** |
176 | * | |
177 | * FUNCTION: pci_proc_init | |
178 | * _________________________________________________________________________ | |
179 | * | |
180 | * DESCRIPTION: Create entries in the /proc filesystem for debug access. | |
181 | * | |
70342287 | 182 | * INPUTS: none |
6f95e60a | 183 | * |
70342287 | 184 | * OUTPUTS: none |
6f95e60a | 185 | * |
70342287 | 186 | * RETURNS: none |
6f95e60a MSJ |
187 | * |
188 | ****************************************************************************/ | |
189 | static void pci_proc_init(void) | |
190 | { | |
24270156 DH |
191 | proc_create("pmc_msp_pci_rd_cnt", 0, NULL, &msp_pci_rd_cnt_fops); |
192 | proc_create("pmc_msp_pci_cfg_wr", 0, NULL, &gen_pci_cfg_wr_fops); | |
6f95e60a MSJ |
193 | } |
194 | #endif /* CONFIG_PROC_FS && PCI_COUNTERS */ | |
195 | ||
6f95e60a MSJ |
196 | /***************************************************************************** |
197 | * | |
198 | * STRUCT: pci_io_resource | |
199 | * _________________________________________________________________________ | |
200 | * | |
201 | * DESCRIPTION: Defines the address range that pciauto() will use to | |
70342287 RB |
202 | * assign to the I/O BARs of PCI devices. |
203 | * | |
204 | * Use the start and end addresses of the MSP7120 PCI Host | |
205 | * Controller I/O space, in the form that they appear on the | |
206 | * PCI bus AFTER MSP7120 has performed address translation. | |
207 | * | |
208 | * For I/O accesses, MSP7120 ignores OATRAN and maps I/O | |
209 | * accesses into the bottom 0xFFF region of address space, | |
210 | * so that is the range to put into the pci_io_resource | |
211 | * struct. | |
212 | * | |
213 | * In MSP4200, the start address was 0x04 instead of the | |
214 | * expected 0x00. Will just assume there was a good reason | |
215 | * for this! | |
216 | * | |
217 | * NOTES: Linux, by default, will assign I/O space to the lowest | |
218 | * region of address space. Since MSP7120 and Linux, | |
219 | * by default, have no offset in between how they map, the | |
220 | * io_offset element of pci_controller struct should be set | |
221 | * to zero. | |
6f95e60a | 222 | * ELEMENTS: |
70342287 | 223 | * name - String used for a meaningful name. |
6f95e60a | 224 | * |
70342287 RB |
225 | * start - Start address of MSP7120's I/O space, as MSP7120 presents |
226 | * the address on the PCI bus. | |
6f95e60a | 227 | * |
70342287 RB |
228 | * end - End address of MSP7120's I/O space, as MSP7120 presents |
229 | * the address on the PCI bus. | |
6f95e60a | 230 | * |
70342287 RB |
231 | * flags - Attributes indicating the type of resource. In this case, |
232 | * indicate I/O space. | |
6f95e60a MSJ |
233 | * |
234 | ****************************************************************************/ | |
235 | static struct resource pci_io_resource = { | |
236 | .name = "pci IO space", | |
237 | .start = 0x04, | |
238 | .end = 0x0FFF, | |
70342287 | 239 | .flags = IORESOURCE_IO /* I/O space */ |
6f95e60a MSJ |
240 | }; |
241 | ||
242 | /***************************************************************************** | |
243 | * | |
244 | * STRUCT: pci_mem_resource | |
245 | * _________________________________________________________________________ | |
246 | * | |
247 | * DESCRIPTION: Defines the address range that pciauto() will use to | |
70342287 | 248 | * assign to the memory BARs of PCI devices. |
6f95e60a | 249 | * |
70342287 RB |
250 | * The .start and .end values are dependent upon how address |
251 | * translation is performed by the OATRAN regiser. | |
6f95e60a | 252 | * |
70342287 RB |
253 | * The values to use for .start and .end are the values |
254 | * in the form they appear on the PCI bus AFTER MSP7120 has | |
255 | * performed OATRAN address translation. | |
6f95e60a MSJ |
256 | * |
257 | * ELEMENTS: | |
70342287 | 258 | * name - String used for a meaningful name. |
6f95e60a | 259 | * |
70342287 RB |
260 | * start - Start address of MSP7120's memory space, as MSP7120 presents |
261 | * the address on the PCI bus. | |
6f95e60a | 262 | * |
70342287 RB |
263 | * end - End address of MSP7120's memory space, as MSP7120 presents |
264 | * the address on the PCI bus. | |
6f95e60a | 265 | * |
70342287 RB |
266 | * flags - Attributes indicating the type of resource. In this case, |
267 | * indicate memory space. | |
6f95e60a MSJ |
268 | * |
269 | ****************************************************************************/ | |
270 | static struct resource pci_mem_resource = { | |
271 | .name = "pci memory space", | |
272 | .start = MSP_PCI_SPACE_BASE, | |
273 | .end = MSP_PCI_SPACE_END, | |
274 | .flags = IORESOURCE_MEM /* memory space */ | |
275 | }; | |
276 | ||
277 | /***************************************************************************** | |
278 | * | |
279 | * FUNCTION: bpci_interrupt | |
280 | * _________________________________________________________________________ | |
281 | * | |
282 | * DESCRIPTION: PCI status interrupt handler. Updates the count of how | |
70342287 RB |
283 | * many times each status bit has been set, then clears |
284 | * the status bits. If the appropriate macros are defined, | |
285 | * these counts can be viewed via the /proc filesystem. | |
6f95e60a | 286 | * |
70342287 RB |
287 | * INPUTS: irq - unused |
288 | * dev_id - unused | |
289 | * pt_regs - unused | |
6f95e60a | 290 | * |
70342287 | 291 | * OUTPUTS: none |
6f95e60a | 292 | * |
70342287 | 293 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
6f95e60a MSJ |
294 | * |
295 | ****************************************************************************/ | |
a18059ac | 296 | static irqreturn_t bpci_interrupt(int irq, void *dev_id) |
6f95e60a MSJ |
297 | { |
298 | struct msp_pci_regs *preg = (void *)PCI_BASE_REG; | |
299 | unsigned int stat = preg->if_status; | |
300 | ||
301 | #if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) | |
302 | int i; | |
303 | for (i = 0; i < 32; ++i) { | |
304 | if ((1 << i) & stat) | |
305 | ++pci_int_count[i]; | |
306 | } | |
307 | #endif /* PROC_FS && PCI_COUNTERS */ | |
308 | ||
309 | /* printk("PCI ISR: Status=%08X\n", stat); */ | |
310 | ||
311 | /* write to clear all asserted interrupts */ | |
312 | preg->if_status = stat; | |
313 | ||
a18059ac | 314 | return IRQ_HANDLED; |
6f95e60a MSJ |
315 | } |
316 | ||
317 | /***************************************************************************** | |
318 | * | |
319 | * FUNCTION: msp_pcibios_config_access | |
320 | * _________________________________________________________________________ | |
321 | * | |
322 | * DESCRIPTION: Performs a PCI configuration access (rd or wr), then | |
70342287 RB |
323 | * checks that the access succeeded by querying MSP7120's |
324 | * PCI status bits. | |
6f95e60a MSJ |
325 | * |
326 | * INPUTS: | |
70342287 RB |
327 | * access_type - kind of PCI configuration cycle to perform |
328 | * (read or write). Legal values are | |
329 | * PCI_ACCESS_WRITE and PCI_ACCESS_READ. | |
330 | * | |
331 | * bus - pointer to the bus number of the device to | |
332 | * be targeted for the configuration cycle. | |
333 | * The only element of the pci_bus structure | |
334 | * used is bus->number. This argument determines | |
335 | * if the configuration access will be Type 0 or | |
336 | * Type 1. Since MSP7120 assumes itself to be the | |
337 | * PCI Host, any non-zero bus->number generates | |
338 | * a Type 1 access. | |
339 | * | |
340 | * devfn - this is an 8-bit field. The lower three bits | |
341 | * specify the function number of the device to | |
342 | * be targeted for the configuration cycle, with | |
343 | * all three-bit combinations being legal. The | |
344 | * upper five bits specify the device number, | |
345 | * with legal values being 10 to 31. | |
346 | * | |
347 | * where - address within the Configuration Header | |
348 | * space to access. | |
349 | * | |
350 | * data - for write accesses, contains the data to | |
351 | * write. | |
6f95e60a MSJ |
352 | * |
353 | * OUTPUTS: | |
70342287 | 354 | * data - for read accesses, contains the value read. |
6f95e60a | 355 | * |
70342287 RB |
356 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
357 | * -1 - access failure | |
6f95e60a MSJ |
358 | * |
359 | ****************************************************************************/ | |
360 | int msp_pcibios_config_access(unsigned char access_type, | |
361 | struct pci_bus *bus, | |
362 | unsigned int devfn, | |
363 | unsigned char where, | |
364 | u32 *data) | |
365 | { | |
366 | struct msp_pci_regs *preg = (void *)PCI_BASE_REG; | |
367 | unsigned char bus_num = bus->number; | |
368 | unsigned char dev_fn = (unsigned char)devfn; | |
6f95e60a MSJ |
369 | unsigned long intr; |
370 | unsigned long value; | |
371 | static char pciirqflag; | |
97184267 | 372 | int ret; |
6f95e60a MSJ |
373 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) |
374 | unsigned int vpe_status; | |
375 | #endif | |
376 | ||
377 | #if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) | |
378 | if (proc_init == 0) { | |
379 | pci_proc_init(); | |
380 | proc_init = ~0; | |
381 | } | |
382 | #endif /* CONFIG_PROC_FS && PCI_COUNTERS */ | |
383 | ||
384 | /* | |
385 | * Just the first time this function invokes, allocate | |
386 | * an interrupt line for PCI host status interrupts. The | |
387 | * allocation assigns an interrupt handler to the interrupt. | |
388 | */ | |
389 | if (pciirqflag == 0) { | |
97184267 | 390 | ret = request_irq(MSP_INT_PCI,/* Hardcoded internal MSP7120 wiring */ |
6f95e60a | 391 | bpci_interrupt, |
8b5690f8 | 392 | IRQF_SHARED, |
6f95e60a MSJ |
393 | "PMC MSP PCI Host", |
394 | preg); | |
97184267 RK |
395 | if (ret != 0) |
396 | return ret; | |
6f95e60a MSJ |
397 | pciirqflag = ~0; |
398 | } | |
399 | ||
400 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | |
6f95e60a | 401 | vpe_status = dvpe(); |
6f95e60a MSJ |
402 | #endif |
403 | ||
404 | /* | |
405 | * Clear PCI cause register bits. | |
406 | * | |
407 | * In Polo, the PCI Host had a dedicated DMA called the | |
408 | * Block Copy (not to be confused with the general purpose Block | |
409 | * Copy Engine block). There appear to have been special interrupts | |
410 | * for this Block Copy, called Block Copy 0 Fault (BC0F) and | |
411 | * Block Copy 1 Fault (BC1F). MSP4200 and MSP7120 don't have this | |
412 | * dedicated Block Copy block, so these two interrupts are now | |
70342287 | 413 | * marked reserved. In case the Block Copy is resurrected in a |
6f95e60a MSJ |
414 | * future design, maintain the code that treats these two interrupts |
415 | * specially. | |
416 | * | |
417 | * Write to clear all interrupts in the PCI status register, aside | |
418 | * from BC0F and BC1F. | |
419 | */ | |
420 | preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F); | |
421 | ||
422 | /* Setup address that is to appear on PCI bus */ | |
70342287 | 423 | preg->config_addr = BPCI_CFGADDR_ENABLE | |
6f95e60a MSJ |
424 | (bus_num << BPCI_CFGADDR_BUSNUM_SHF) | |
425 | (dev_fn << BPCI_CFGADDR_FUNCTNUM_SHF) | | |
426 | (where & 0xFC); | |
427 | ||
428 | /* IF access is a PCI configuration write */ | |
429 | if (access_type == PCI_ACCESS_WRITE) { | |
430 | value = cpu_to_le32(*data); | |
431 | *PCI_CONFIG_SPACE_REG = value; | |
432 | } else { | |
433 | /* ELSE access is a PCI configuration read */ | |
434 | value = le32_to_cpu(*PCI_CONFIG_SPACE_REG); | |
435 | *data = value; | |
436 | } | |
437 | ||
438 | /* | |
439 | * Check if the PCI configuration cycle (rd or wr) succeeded, by | |
440 | * checking the status bits for errors like master or target abort. | |
441 | */ | |
442 | intr = preg->if_status; | |
443 | ||
444 | /* Clear config access */ | |
445 | preg->config_addr = 0; | |
446 | ||
447 | /* IF error occurred */ | |
448 | if (intr & ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F)) { | |
449 | /* Clear status bits */ | |
450 | preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F); | |
451 | ||
452 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | |
453 | evpe(vpe_status); | |
6f95e60a MSJ |
454 | #endif |
455 | ||
456 | return -1; | |
457 | } | |
458 | ||
459 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | |
460 | evpe(vpe_status); | |
6f95e60a MSJ |
461 | #endif |
462 | ||
463 | return PCIBIOS_SUCCESSFUL; | |
464 | } | |
465 | ||
466 | /***************************************************************************** | |
467 | * | |
468 | * FUNCTION: msp_pcibios_read_config_byte | |
469 | * _________________________________________________________________________ | |
470 | * | |
471 | * DESCRIPTION: Read a byte from PCI configuration address spac | |
70342287 RB |
472 | * Since the hardware can't address 8 bit chunks |
473 | * directly, read a 32-bit chunk, then mask off extraneous | |
474 | * bits. | |
6f95e60a | 475 | * |
70342287 RB |
476 | * INPUTS bus - structure containing attributes for the PCI bus |
477 | * that the read is destined for. | |
478 | * devfn - device/function combination that the read is | |
479 | * destined for. | |
480 | * where - register within the Configuration Header space | |
481 | * to access. | |
6f95e60a | 482 | * |
70342287 | 483 | * OUTPUTS val - read data |
6f95e60a | 484 | * |
70342287 RB |
485 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
486 | * -1 - read access failure | |
6f95e60a MSJ |
487 | * |
488 | ****************************************************************************/ | |
489 | static int | |
490 | msp_pcibios_read_config_byte(struct pci_bus *bus, | |
491 | unsigned int devfn, | |
492 | int where, | |
493 | u32 *val) | |
494 | { | |
495 | u32 data = 0; | |
496 | ||
497 | /* | |
498 | * If the config access did not complete normally (e.g., underwent | |
499 | * master abort) do the PCI compliant thing, which is to supply an | |
500 | * all ones value. | |
501 | */ | |
502 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | |
503 | where, &data)) { | |
504 | *val = 0xFFFFFFFF; | |
505 | return -1; | |
506 | } | |
507 | ||
508 | *val = (data >> ((where & 3) << 3)) & 0x0ff; | |
509 | ||
510 | return PCIBIOS_SUCCESSFUL; | |
511 | } | |
512 | ||
513 | /***************************************************************************** | |
514 | * | |
515 | * FUNCTION: msp_pcibios_read_config_word | |
516 | * _________________________________________________________________________ | |
517 | * | |
518 | * DESCRIPTION: Read a word (16 bits) from PCI configuration address space. | |
70342287 RB |
519 | * Since the hardware can't address 16 bit chunks |
520 | * directly, read a 32-bit chunk, then mask off extraneous | |
521 | * bits. | |
6f95e60a | 522 | * |
70342287 RB |
523 | * INPUTS bus - structure containing attributes for the PCI bus |
524 | * that the read is destined for. | |
525 | * devfn - device/function combination that the read is | |
526 | * destined for. | |
527 | * where - register within the Configuration Header space | |
528 | * to access. | |
6f95e60a | 529 | * |
70342287 | 530 | * OUTPUTS val - read data |
6f95e60a | 531 | * |
70342287 RB |
532 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
533 | * PCIBIOS_BAD_REGISTER_NUMBER - bad register address | |
534 | * -1 - read access failure | |
6f95e60a MSJ |
535 | * |
536 | ****************************************************************************/ | |
537 | static int | |
538 | msp_pcibios_read_config_word(struct pci_bus *bus, | |
539 | unsigned int devfn, | |
540 | int where, | |
541 | u32 *val) | |
542 | { | |
543 | u32 data = 0; | |
544 | ||
545 | /* if (where & 1) */ /* Commented out non-compliant code. | |
546 | * Should allow word access to configuration | |
547 | * registers, with only exception being when | |
548 | * the word access would wrap around into | |
549 | * the next dword. | |
550 | */ | |
551 | if ((where & 3) == 3) { | |
552 | *val = 0xFFFFFFFF; | |
553 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
554 | } | |
555 | ||
556 | /* | |
557 | * If the config access did not complete normally (e.g., underwent | |
558 | * master abort) do the PCI compliant thing, which is to supply an | |
559 | * all ones value. | |
560 | */ | |
561 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | |
562 | where, &data)) { | |
563 | *val = 0xFFFFFFFF; | |
564 | return -1; | |
565 | } | |
566 | ||
567 | *val = (data >> ((where & 3) << 3)) & 0x0ffff; | |
568 | ||
569 | return PCIBIOS_SUCCESSFUL; | |
570 | } | |
571 | ||
572 | /***************************************************************************** | |
573 | * | |
574 | * FUNCTION: msp_pcibios_read_config_dword | |
575 | * _________________________________________________________________________ | |
576 | * | |
577 | * DESCRIPTION: Read a double word (32 bits) from PCI configuration | |
70342287 | 578 | * address space. |
6f95e60a | 579 | * |
70342287 RB |
580 | * INPUTS bus - structure containing attributes for the PCI bus |
581 | * that the read is destined for. | |
582 | * devfn - device/function combination that the read is | |
583 | * destined for. | |
584 | * where - register within the Configuration Header space | |
585 | * to access. | |
6f95e60a | 586 | * |
70342287 | 587 | * OUTPUTS val - read data |
6f95e60a | 588 | * |
70342287 RB |
589 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
590 | * PCIBIOS_BAD_REGISTER_NUMBER - bad register address | |
591 | * -1 - read access failure | |
6f95e60a MSJ |
592 | * |
593 | ****************************************************************************/ | |
594 | static int | |
595 | msp_pcibios_read_config_dword(struct pci_bus *bus, | |
596 | unsigned int devfn, | |
597 | int where, | |
598 | u32 *val) | |
599 | { | |
600 | u32 data = 0; | |
601 | ||
602 | /* Address must be dword aligned. */ | |
603 | if (where & 3) { | |
604 | *val = 0xFFFFFFFF; | |
605 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
606 | } | |
607 | ||
608 | /* | |
609 | * If the config access did not complete normally (e.g., underwent | |
610 | * master abort) do the PCI compliant thing, which is to supply an | |
611 | * all ones value. | |
612 | */ | |
613 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | |
614 | where, &data)) { | |
615 | *val = 0xFFFFFFFF; | |
616 | return -1; | |
617 | } | |
618 | ||
619 | *val = data; | |
620 | ||
621 | return PCIBIOS_SUCCESSFUL; | |
622 | } | |
623 | ||
624 | /***************************************************************************** | |
625 | * | |
626 | * FUNCTION: msp_pcibios_write_config_byte | |
627 | * _________________________________________________________________________ | |
628 | * | |
629 | * DESCRIPTION: Write a byte to PCI configuration address space. | |
70342287 RB |
630 | * Since the hardware can't address 8 bit chunks |
631 | * directly, a read-modify-write is performed. | |
6f95e60a | 632 | * |
70342287 RB |
633 | * INPUTS bus - structure containing attributes for the PCI bus |
634 | * that the write is destined for. | |
635 | * devfn - device/function combination that the write is | |
636 | * destined for. | |
637 | * where - register within the Configuration Header space | |
638 | * to access. | |
639 | * val - value to write | |
6f95e60a | 640 | * |
70342287 | 641 | * OUTPUTS none |
6f95e60a | 642 | * |
70342287 RB |
643 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
644 | * -1 - write access failure | |
6f95e60a MSJ |
645 | * |
646 | ****************************************************************************/ | |
647 | static int | |
648 | msp_pcibios_write_config_byte(struct pci_bus *bus, | |
649 | unsigned int devfn, | |
650 | int where, | |
651 | u8 val) | |
652 | { | |
653 | u32 data = 0; | |
654 | ||
655 | /* read config space */ | |
656 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | |
657 | where, &data)) | |
658 | return -1; | |
659 | ||
660 | /* modify the byte within the dword */ | |
661 | data = (data & ~(0xff << ((where & 3) << 3))) | | |
662 | (val << ((where & 3) << 3)); | |
663 | ||
664 | /* write back the full dword */ | |
665 | if (msp_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, | |
666 | where, &data)) | |
667 | return -1; | |
668 | ||
669 | return PCIBIOS_SUCCESSFUL; | |
670 | } | |
671 | ||
672 | /***************************************************************************** | |
673 | * | |
674 | * FUNCTION: msp_pcibios_write_config_word | |
675 | * _________________________________________________________________________ | |
676 | * | |
677 | * DESCRIPTION: Write a word (16-bits) to PCI configuration address space. | |
70342287 RB |
678 | * Since the hardware can't address 16 bit chunks |
679 | * directly, a read-modify-write is performed. | |
6f95e60a | 680 | * |
70342287 RB |
681 | * INPUTS bus - structure containing attributes for the PCI bus |
682 | * that the write is destined for. | |
683 | * devfn - device/function combination that the write is | |
684 | * destined for. | |
685 | * where - register within the Configuration Header space | |
686 | * to access. | |
687 | * val - value to write | |
6f95e60a | 688 | * |
70342287 | 689 | * OUTPUTS none |
6f95e60a | 690 | * |
70342287 RB |
691 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
692 | * PCIBIOS_BAD_REGISTER_NUMBER - bad register address | |
693 | * -1 - write access failure | |
6f95e60a MSJ |
694 | * |
695 | ****************************************************************************/ | |
696 | static int | |
697 | msp_pcibios_write_config_word(struct pci_bus *bus, | |
698 | unsigned int devfn, | |
699 | int where, | |
700 | u16 val) | |
701 | { | |
702 | u32 data = 0; | |
703 | ||
704 | /* Fixed non-compliance: if (where & 1) */ | |
705 | if ((where & 3) == 3) | |
706 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
707 | ||
708 | /* read config space */ | |
709 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | |
710 | where, &data)) | |
711 | return -1; | |
712 | ||
713 | /* modify the word within the dword */ | |
714 | data = (data & ~(0xffff << ((where & 3) << 3))) | | |
715 | (val << ((where & 3) << 3)); | |
716 | ||
717 | /* write back the full dword */ | |
718 | if (msp_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, | |
719 | where, &data)) | |
720 | return -1; | |
721 | ||
722 | return PCIBIOS_SUCCESSFUL; | |
723 | } | |
724 | ||
725 | /***************************************************************************** | |
726 | * | |
727 | * FUNCTION: msp_pcibios_write_config_dword | |
728 | * _________________________________________________________________________ | |
729 | * | |
730 | * DESCRIPTION: Write a double word (32-bits) to PCI configuration address | |
70342287 | 731 | * space. |
6f95e60a | 732 | * |
70342287 RB |
733 | * INPUTS bus - structure containing attributes for the PCI bus |
734 | * that the write is destined for. | |
735 | * devfn - device/function combination that the write is | |
736 | * destined for. | |
737 | * where - register within the Configuration Header space | |
738 | * to access. | |
739 | * val - value to write | |
6f95e60a | 740 | * |
70342287 | 741 | * OUTPUTS none |
6f95e60a | 742 | * |
70342287 RB |
743 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
744 | * PCIBIOS_BAD_REGISTER_NUMBER - bad register address | |
745 | * -1 - write access failure | |
6f95e60a MSJ |
746 | * |
747 | ****************************************************************************/ | |
748 | static int | |
749 | msp_pcibios_write_config_dword(struct pci_bus *bus, | |
750 | unsigned int devfn, | |
751 | int where, | |
752 | u32 val) | |
753 | { | |
754 | /* check that address is dword aligned */ | |
755 | if (where & 3) | |
756 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
757 | ||
758 | /* perform write */ | |
759 | if (msp_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, | |
760 | where, &val)) | |
761 | return -1; | |
762 | ||
763 | return PCIBIOS_SUCCESSFUL; | |
764 | } | |
765 | ||
766 | /***************************************************************************** | |
767 | * | |
768 | * FUNCTION: msp_pcibios_read_config | |
769 | * _________________________________________________________________________ | |
770 | * | |
771 | * DESCRIPTION: Interface the PCI configuration read request with | |
70342287 RB |
772 | * the appropriate function, based on how many bytes |
773 | * the read request is. | |
6f95e60a | 774 | * |
70342287 RB |
775 | * INPUTS bus - structure containing attributes for the PCI bus |
776 | * that the write is destined for. | |
777 | * devfn - device/function combination that the write is | |
778 | * destined for. | |
779 | * where - register within the Configuration Header space | |
780 | * to access. | |
781 | * size - in units of bytes, should be 1, 2, or 4. | |
6f95e60a | 782 | * |
70342287 RB |
783 | * OUTPUTS val - value read, with any extraneous bytes masked |
784 | * to zero. | |
6f95e60a | 785 | * |
70342287 RB |
786 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
787 | * -1 - failure | |
6f95e60a MSJ |
788 | * |
789 | ****************************************************************************/ | |
790 | int | |
791 | msp_pcibios_read_config(struct pci_bus *bus, | |
792 | unsigned int devfn, | |
793 | int where, | |
794 | int size, | |
795 | u32 *val) | |
796 | { | |
797 | if (size == 1) { | |
798 | if (msp_pcibios_read_config_byte(bus, devfn, where, val)) { | |
799 | return -1; | |
800 | } | |
801 | } else if (size == 2) { | |
802 | if (msp_pcibios_read_config_word(bus, devfn, where, val)) { | |
803 | return -1; | |
804 | } | |
805 | } else if (size == 4) { | |
806 | if (msp_pcibios_read_config_dword(bus, devfn, where, val)) { | |
807 | return -1; | |
808 | } | |
809 | } else { | |
810 | *val = 0xFFFFFFFF; | |
811 | return -1; | |
812 | } | |
813 | ||
814 | return PCIBIOS_SUCCESSFUL; | |
815 | } | |
816 | ||
817 | /***************************************************************************** | |
818 | * | |
819 | * FUNCTION: msp_pcibios_write_config | |
820 | * _________________________________________________________________________ | |
821 | * | |
822 | * DESCRIPTION: Interface the PCI configuration write request with | |
70342287 RB |
823 | * the appropriate function, based on how many bytes |
824 | * the read request is. | |
6f95e60a | 825 | * |
70342287 RB |
826 | * INPUTS bus - structure containing attributes for the PCI bus |
827 | * that the write is destined for. | |
828 | * devfn - device/function combination that the write is | |
829 | * destined for. | |
830 | * where - register within the Configuration Header space | |
831 | * to access. | |
832 | * size - in units of bytes, should be 1, 2, or 4. | |
833 | * val - value to write | |
6f95e60a | 834 | * |
70342287 | 835 | * OUTPUTS: none |
6f95e60a | 836 | * |
70342287 RB |
837 | * RETURNS: PCIBIOS_SUCCESSFUL - success |
838 | * -1 - failure | |
6f95e60a MSJ |
839 | * |
840 | ****************************************************************************/ | |
841 | int | |
842 | msp_pcibios_write_config(struct pci_bus *bus, | |
843 | unsigned int devfn, | |
844 | int where, | |
845 | int size, | |
846 | u32 val) | |
847 | { | |
848 | if (size == 1) { | |
849 | if (msp_pcibios_write_config_byte(bus, devfn, | |
850 | where, (u8)(0xFF & val))) { | |
851 | return -1; | |
852 | } | |
853 | } else if (size == 2) { | |
854 | if (msp_pcibios_write_config_word(bus, devfn, | |
855 | where, (u16)(0xFFFF & val))) { | |
856 | return -1; | |
857 | } | |
858 | } else if (size == 4) { | |
859 | if (msp_pcibios_write_config_dword(bus, devfn, where, val)) { | |
860 | return -1; | |
861 | } | |
862 | } else { | |
863 | return -1; | |
864 | } | |
865 | ||
866 | return PCIBIOS_SUCCESSFUL; | |
867 | } | |
868 | ||
869 | /***************************************************************************** | |
870 | * | |
871 | * STRUCTURE: msp_pci_ops | |
872 | * _________________________________________________________________________ | |
873 | * | |
874 | * DESCRIPTION: structure to abstract the hardware specific PCI | |
70342287 | 875 | * configuration accesses. |
6f95e60a MSJ |
876 | * |
877 | * ELEMENTS: | |
70342287 RB |
878 | * read - function for Linux to generate PCI Configuration reads. |
879 | * write - function for Linux to generate PCI Configuration writes. | |
6f95e60a MSJ |
880 | * |
881 | ****************************************************************************/ | |
882 | struct pci_ops msp_pci_ops = { | |
883 | .read = msp_pcibios_read_config, | |
884 | .write = msp_pcibios_write_config | |
885 | }; | |
886 | ||
887 | /***************************************************************************** | |
888 | * | |
889 | * STRUCTURE: msp_pci_controller | |
890 | * _________________________________________________________________________ | |
891 | * | |
892 | * Describes the attributes of the MSP7120 PCI Host Controller | |
893 | * | |
894 | * ELEMENTS: | |
70342287 RB |
895 | * pci_ops - abstracts the hardware specific PCI configuration |
896 | * accesses. | |
6f95e60a MSJ |
897 | * |
898 | * mem_resource - address range pciauto() uses to assign to PCI device | |
70342287 | 899 | * memory BARs. |
6f95e60a MSJ |
900 | * |
901 | * mem_offset - offset between how MSP7120 outbound PCI memory | |
70342287 RB |
902 | * transaction addresses appear on the PCI bus and how Linux |
903 | * wants to configure memory BARs of the PCI devices. | |
904 | * MSP7120 does nothing funky, so just set to zero. | |
6f95e60a MSJ |
905 | * |
906 | * io_resource - address range pciauto() uses to assign to PCI device | |
70342287 | 907 | * I/O BARs. |
6f95e60a | 908 | * |
70342287 RB |
909 | * io_offset - offset between how MSP7120 outbound PCI I/O |
910 | * transaction addresses appear on the PCI bus and how | |
911 | * Linux defaults to configure I/O BARs of the PCI devices. | |
912 | * MSP7120 maps outbound I/O accesses into the bottom | |
913 | * bottom 4K of PCI address space (and ignores OATRAN). | |
914 | * Since the Linux default is to configure I/O BARs to the | |
915 | * bottom 4K, no special offset is needed. Just set to zero. | |
6f95e60a MSJ |
916 | * |
917 | ****************************************************************************/ | |
918 | static struct pci_controller msp_pci_controller = { | |
919 | .pci_ops = &msp_pci_ops, | |
920 | .mem_resource = &pci_mem_resource, | |
921 | .mem_offset = 0, | |
8faf2e6c | 922 | .io_map_base = MSP_PCI_IOSPACE_BASE, |
6f95e60a MSJ |
923 | .io_resource = &pci_io_resource, |
924 | .io_offset = 0 | |
925 | }; | |
926 | ||
927 | /***************************************************************************** | |
928 | * | |
929 | * FUNCTION: msp_pci_init | |
930 | * _________________________________________________________________________ | |
931 | * | |
932 | * DESCRIPTION: Initialize the PCI Host Controller and register it with | |
70342287 | 933 | * Linux so Linux can seize control of the PCI bus. |
6f95e60a MSJ |
934 | * |
935 | ****************************************************************************/ | |
936 | void __init msp_pci_init(void) | |
937 | { | |
938 | struct msp_pci_regs *preg = (void *)PCI_BASE_REG; | |
939 | u32 id; | |
940 | ||
941 | /* Extract Device ID */ | |
942 | id = read_reg32(PCI_JTAG_DEVID_REG, 0xFFFF) >> 12; | |
943 | ||
944 | /* Check if JTAG ID identifies MSP7120 */ | |
945 | if (!MSP_HAS_PCI(id)) { | |
946 | printk(KERN_WARNING "PCI: No PCI; id reads as %x\n", id); | |
947 | goto no_pci; | |
948 | } | |
949 | ||
950 | /* | |
951 | * Enable flushing of the PCI-SDRAM queue upon a read | |
952 | * of the SDRAM's Memory Configuration Register. | |
953 | */ | |
954 | *(unsigned long *)QFLUSH_REG_1 = 3; | |
955 | ||
956 | /* Configure PCI Host Controller. */ | |
70342287 | 957 | preg->if_status = ~0; /* Clear cause register bits */ |
6f95e60a MSJ |
958 | preg->config_addr = 0; /* Clear config access */ |
959 | preg->oatran = MSP_PCI_OATRAN; /* PCI outbound addr translation */ | |
960 | preg->if_mask = 0xF8BF87C0; /* Enable all PCI status interrupts */ | |
961 | ||
962 | /* configure so inb(), outb(), and family are functional */ | |
963 | set_io_port_base(MSP_PCI_IOSPACE_BASE); | |
964 | ||
965 | /* Tell Linux the details of the MSP7120 PCI Host Controller */ | |
966 | register_pci_controller(&msp_pci_controller); | |
967 | ||
968 | return; | |
969 | ||
970 | no_pci: | |
971 | /* Disable PCI channel */ | |
972 | printk(KERN_WARNING "PCI: no host PCI bus detected\n"); | |
973 | } |