diff options
author | GuanXuetao <gxt@mprc.pku.edu.cn> | 2011-01-15 05:25:14 -0500 |
---|---|---|
committer | GuanXuetao <gxt@mprc.pku.edu.cn> | 2011-03-16 21:19:15 -0400 |
commit | 700598cef866011b878f389c30414d31fa5bb87b (patch) | |
tree | 2b09be08a2099fbf2bce706aa18d0b013e926e2c /arch | |
parent | b08b4f8e63e60a64f81e194269be14afee396f33 (diff) |
unicore32 machine related files: pci bus handling
This patch implements arch-specific pci bus driver.
Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/unicore32/include/asm/pci.h | 46 | ||||
-rw-r--r-- | arch/unicore32/kernel/pci.c | 404 |
2 files changed, 450 insertions, 0 deletions
diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h new file mode 100644 index 000000000000..c5b28b459535 --- /dev/null +++ b/arch/unicore32/include/asm/pci.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/include/asm/pci.h | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #ifndef __UNICORE_PCI_H__ | ||
13 | #define __UNICORE_PCI_H__ | ||
14 | |||
15 | #ifdef __KERNEL__ | ||
16 | #include <asm-generic/pci-dma-compat.h> | ||
17 | #include <asm-generic/pci.h> | ||
18 | #include <mach/hardware.h> /* for PCIBIOS_MIN_* */ | ||
19 | |||
20 | static inline void pcibios_set_master(struct pci_dev *dev) | ||
21 | { | ||
22 | /* No special bus mastering setup handling */ | ||
23 | } | ||
24 | |||
25 | static inline void pcibios_penalize_isa_irq(int irq, int active) | ||
26 | { | ||
27 | /* We don't do dynamic PCI IRQ allocation */ | ||
28 | } | ||
29 | |||
30 | #ifdef CONFIG_PCI | ||
31 | static inline void pci_dma_burst_advice(struct pci_dev *pdev, | ||
32 | enum pci_dma_burst_strategy *strat, | ||
33 | unsigned long *strategy_parameter) | ||
34 | { | ||
35 | *strat = PCI_DMA_BURST_INFINITY; | ||
36 | *strategy_parameter = ~0UL; | ||
37 | } | ||
38 | #endif | ||
39 | |||
40 | #define HAVE_PCI_MMAP | ||
41 | extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | ||
42 | enum pci_mmap_state mmap_state, int write_combine); | ||
43 | |||
44 | #endif /* __KERNEL__ */ | ||
45 | |||
46 | #endif | ||
diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c new file mode 100644 index 000000000000..d4e55e2d2d29 --- /dev/null +++ b/arch/unicore32/kernel/pci.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | * linux/arch/unicore32/kernel/pci.c | ||
3 | * | ||
4 | * Code specific to PKUnity SoC and UniCore ISA | ||
5 | * | ||
6 | * Copyright (C) 2001-2010 GUAN Xue-tao | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * PCI bios-type initialisation for PCI machines | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/io.h> | ||
22 | |||
23 | static int debug_pci; | ||
24 | static int use_firmware; | ||
25 | |||
26 | #define CONFIG_CMD(bus, devfn, where) \ | ||
27 | (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) | ||
28 | |||
29 | static int | ||
30 | puv3_read_config(struct pci_bus *bus, unsigned int devfn, int where, | ||
31 | int size, u32 *value) | ||
32 | { | ||
33 | PCICFG_ADDR = CONFIG_CMD(bus, devfn, where); | ||
34 | switch (size) { | ||
35 | case 1: | ||
36 | *value = (PCICFG_DATA >> ((where & 3) * 8)) & 0xFF; | ||
37 | break; | ||
38 | case 2: | ||
39 | *value = (PCICFG_DATA >> ((where & 2) * 8)) & 0xFFFF; | ||
40 | break; | ||
41 | case 4: | ||
42 | *value = PCICFG_DATA; | ||
43 | break; | ||
44 | } | ||
45 | return PCIBIOS_SUCCESSFUL; | ||
46 | } | ||
47 | |||
48 | static int | ||
49 | puv3_write_config(struct pci_bus *bus, unsigned int devfn, int where, | ||
50 | int size, u32 value) | ||
51 | { | ||
52 | PCICFG_ADDR = CONFIG_CMD(bus, devfn, where); | ||
53 | switch (size) { | ||
54 | case 1: | ||
55 | PCICFG_DATA = (PCICFG_DATA & ~FMASK(8, (where&3)*8)) | ||
56 | | FIELD(value, 8, (where&3)*8); | ||
57 | break; | ||
58 | case 2: | ||
59 | PCICFG_DATA = (PCICFG_DATA & ~FMASK(16, (where&2)*8)) | ||
60 | | FIELD(value, 16, (where&2)*8); | ||
61 | break; | ||
62 | case 4: | ||
63 | PCICFG_DATA = value; | ||
64 | break; | ||
65 | } | ||
66 | return PCIBIOS_SUCCESSFUL; | ||
67 | } | ||
68 | |||
69 | struct pci_ops pci_puv3_ops = { | ||
70 | .read = puv3_read_config, | ||
71 | .write = puv3_write_config, | ||
72 | }; | ||
73 | |||
74 | void pci_puv3_preinit(void) | ||
75 | { | ||
76 | printk(KERN_DEBUG "PCI: PKUnity PCI Controller Initializing ...\n"); | ||
77 | /* config PCI bridge base */ | ||
78 | PCICFG_BRIBASE = PKUNITY_PCIBRI_BASE; | ||
79 | |||
80 | PCIBRI_AHBCTL0 = 0; | ||
81 | PCIBRI_AHBBAR0 = PKUNITY_PCIBRI_BASE | PCIBRI_BARx_MEM; | ||
82 | PCIBRI_AHBAMR0 = 0xFFFF0000; | ||
83 | PCIBRI_AHBTAR0 = 0; | ||
84 | |||
85 | PCIBRI_AHBCTL1 = PCIBRI_CTLx_AT; | ||
86 | PCIBRI_AHBBAR1 = PKUNITY_PCILIO_BASE | PCIBRI_BARx_IO; | ||
87 | PCIBRI_AHBAMR1 = 0xFFFF0000; | ||
88 | PCIBRI_AHBTAR1 = 0x00000000; | ||
89 | |||
90 | PCIBRI_AHBCTL2 = PCIBRI_CTLx_PREF; | ||
91 | PCIBRI_AHBBAR2 = PKUNITY_PCIMEM_BASE | PCIBRI_BARx_MEM; | ||
92 | PCIBRI_AHBAMR2 = 0xF8000000; | ||
93 | PCIBRI_AHBTAR2 = 0; | ||
94 | |||
95 | PCIBRI_BAR1 = PKUNITY_PCIAHB_BASE | PCIBRI_BARx_MEM; | ||
96 | |||
97 | PCIBRI_PCICTL0 = PCIBRI_CTLx_AT | PCIBRI_CTLx_PREF; | ||
98 | PCIBRI_PCIBAR0 = PKUNITY_PCIAHB_BASE | PCIBRI_BARx_MEM; | ||
99 | PCIBRI_PCIAMR0 = 0xF8000000; | ||
100 | PCIBRI_PCITAR0 = PKUNITY_SDRAM_BASE; | ||
101 | |||
102 | PCIBRI_CMD = PCIBRI_CMD | PCIBRI_CMD_IO | PCIBRI_CMD_MEM; | ||
103 | } | ||
104 | |||
105 | static int __init pci_puv3_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
106 | { | ||
107 | if (dev->bus->number == 0) { | ||
108 | #ifdef CONFIG_ARCH_FPGA /* 4 pci slots */ | ||
109 | if (dev->devfn == 0x00) | ||
110 | return IRQ_PCIINTA; | ||
111 | else if (dev->devfn == 0x08) | ||
112 | return IRQ_PCIINTB; | ||
113 | else if (dev->devfn == 0x10) | ||
114 | return IRQ_PCIINTC; | ||
115 | else if (dev->devfn == 0x18) | ||
116 | return IRQ_PCIINTD; | ||
117 | #endif | ||
118 | #ifdef CONFIG_PUV3_DB0913 /* 3 pci slots */ | ||
119 | if (dev->devfn == 0x30) | ||
120 | return IRQ_PCIINTB; | ||
121 | else if (dev->devfn == 0x60) | ||
122 | return IRQ_PCIINTC; | ||
123 | else if (dev->devfn == 0x58) | ||
124 | return IRQ_PCIINTD; | ||
125 | #endif | ||
126 | #if defined(CONFIG_PUV3_NB0916) || defined(CONFIG_PUV3_SMW0919) | ||
127 | /* only support 2 pci devices */ | ||
128 | if (dev->devfn == 0x00) | ||
129 | return IRQ_PCIINTC; /* sata */ | ||
130 | #endif | ||
131 | } | ||
132 | return -1; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Only first 128MB of memory can be accessed via PCI. | ||
137 | * We use GFP_DMA to allocate safe buffers to do map/unmap. | ||
138 | * This is really ugly and we need a better way of specifying | ||
139 | * DMA-capable regions of memory. | ||
140 | */ | ||
141 | void __init puv3_pci_adjust_zones(unsigned long *zone_size, | ||
142 | unsigned long *zhole_size) | ||
143 | { | ||
144 | unsigned int sz = SZ_128M >> PAGE_SHIFT; | ||
145 | |||
146 | /* | ||
147 | * Only adjust if > 128M on current system | ||
148 | */ | ||
149 | if (zone_size[0] <= sz) | ||
150 | return; | ||
151 | |||
152 | zone_size[1] = zone_size[0] - sz; | ||
153 | zone_size[0] = sz; | ||
154 | zhole_size[1] = zhole_size[0]; | ||
155 | zhole_size[0] = 0; | ||
156 | } | ||
157 | |||
158 | void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) | ||
159 | { | ||
160 | if (debug_pci) | ||
161 | printk(KERN_DEBUG "PCI: Assigning IRQ %02d to %s\n", | ||
162 | irq, pci_name(dev)); | ||
163 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * If the bus contains any of these devices, then we must not turn on | ||
168 | * parity checking of any kind. | ||
169 | */ | ||
170 | static inline int pdev_bad_for_parity(struct pci_dev *dev) | ||
171 | { | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * pcibios_fixup_bus - Called after each bus is probed, | ||
177 | * but before its children are examined. | ||
178 | */ | ||
179 | void __devinit pcibios_fixup_bus(struct pci_bus *bus) | ||
180 | { | ||
181 | struct pci_dev *dev; | ||
182 | u16 features = PCI_COMMAND_SERR | ||
183 | | PCI_COMMAND_PARITY | ||
184 | | PCI_COMMAND_FAST_BACK; | ||
185 | |||
186 | bus->resource[0] = &ioport_resource; | ||
187 | bus->resource[1] = &iomem_resource; | ||
188 | |||
189 | /* | ||
190 | * Walk the devices on this bus, working out what we can | ||
191 | * and can't support. | ||
192 | */ | ||
193 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
194 | u16 status; | ||
195 | |||
196 | pci_read_config_word(dev, PCI_STATUS, &status); | ||
197 | |||
198 | /* | ||
199 | * If any device on this bus does not support fast back | ||
200 | * to back transfers, then the bus as a whole is not able | ||
201 | * to support them. Having fast back to back transfers | ||
202 | * on saves us one PCI cycle per transaction. | ||
203 | */ | ||
204 | if (!(status & PCI_STATUS_FAST_BACK)) | ||
205 | features &= ~PCI_COMMAND_FAST_BACK; | ||
206 | |||
207 | if (pdev_bad_for_parity(dev)) | ||
208 | features &= ~(PCI_COMMAND_SERR | ||
209 | | PCI_COMMAND_PARITY); | ||
210 | |||
211 | switch (dev->class >> 8) { | ||
212 | case PCI_CLASS_BRIDGE_PCI: | ||
213 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status); | ||
214 | status |= PCI_BRIDGE_CTL_PARITY | ||
215 | | PCI_BRIDGE_CTL_MASTER_ABORT; | ||
216 | status &= ~(PCI_BRIDGE_CTL_BUS_RESET | ||
217 | | PCI_BRIDGE_CTL_FAST_BACK); | ||
218 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status); | ||
219 | break; | ||
220 | |||
221 | case PCI_CLASS_BRIDGE_CARDBUS: | ||
222 | pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL, | ||
223 | &status); | ||
224 | status |= PCI_CB_BRIDGE_CTL_PARITY | ||
225 | | PCI_CB_BRIDGE_CTL_MASTER_ABORT; | ||
226 | pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL, | ||
227 | status); | ||
228 | break; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Now walk the devices again, this time setting them up. | ||
234 | */ | ||
235 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
236 | u16 cmd; | ||
237 | |||
238 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
239 | cmd |= features; | ||
240 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
241 | |||
242 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, | ||
243 | L1_CACHE_BYTES >> 2); | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Propagate the flags to the PCI bridge. | ||
248 | */ | ||
249 | if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
250 | if (features & PCI_COMMAND_FAST_BACK) | ||
251 | bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK; | ||
252 | if (features & PCI_COMMAND_PARITY) | ||
253 | bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Report what we did for this bus | ||
258 | */ | ||
259 | printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n", | ||
260 | bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); | ||
261 | } | ||
262 | #ifdef CONFIG_HOTPLUG | ||
263 | EXPORT_SYMBOL(pcibios_fixup_bus); | ||
264 | #endif | ||
265 | |||
266 | static int __init pci_common_init(void) | ||
267 | { | ||
268 | struct pci_bus *puv3_bus; | ||
269 | |||
270 | pci_puv3_preinit(); | ||
271 | |||
272 | puv3_bus = pci_scan_bus(0, &pci_puv3_ops, NULL); | ||
273 | |||
274 | if (!puv3_bus) | ||
275 | panic("PCI: unable to scan bus!"); | ||
276 | |||
277 | pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq); | ||
278 | |||
279 | if (!use_firmware) { | ||
280 | /* | ||
281 | * Size the bridge windows. | ||
282 | */ | ||
283 | pci_bus_size_bridges(puv3_bus); | ||
284 | |||
285 | /* | ||
286 | * Assign resources. | ||
287 | */ | ||
288 | pci_bus_assign_resources(puv3_bus); | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Tell drivers about devices found. | ||
293 | */ | ||
294 | pci_bus_add_devices(puv3_bus); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | subsys_initcall(pci_common_init); | ||
299 | |||
300 | char * __devinit pcibios_setup(char *str) | ||
301 | { | ||
302 | if (!strcmp(str, "debug")) { | ||
303 | debug_pci = 1; | ||
304 | return NULL; | ||
305 | } else if (!strcmp(str, "firmware")) { | ||
306 | use_firmware = 1; | ||
307 | return NULL; | ||
308 | } | ||
309 | return str; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * From arch/i386/kernel/pci-i386.c: | ||
314 | * | ||
315 | * We need to avoid collisions with `mirrored' VGA ports | ||
316 | * and other strange ISA hardware, so we always want the | ||
317 | * addresses to be allocated in the 0x000-0x0ff region | ||
318 | * modulo 0x400. | ||
319 | * | ||
320 | * Why? Because some silly external IO cards only decode | ||
321 | * the low 10 bits of the IO address. The 0x00-0xff region | ||
322 | * is reserved for motherboard devices that decode all 16 | ||
323 | * bits, so it's ok to allocate at, say, 0x2800-0x28ff, | ||
324 | * but we want to try to avoid allocating at 0x2900-0x2bff | ||
325 | * which might be mirrored at 0x0100-0x03ff.. | ||
326 | */ | ||
327 | resource_size_t pcibios_align_resource(void *data, const struct resource *res, | ||
328 | resource_size_t size, resource_size_t align) | ||
329 | { | ||
330 | resource_size_t start = res->start; | ||
331 | |||
332 | if (res->flags & IORESOURCE_IO && start & 0x300) | ||
333 | start = (start + 0x3ff) & ~0x3ff; | ||
334 | |||
335 | start = (start + align - 1) & ~(align - 1); | ||
336 | |||
337 | return start; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * pcibios_enable_device - Enable I/O and memory. | ||
342 | * @dev: PCI device to be enabled | ||
343 | */ | ||
344 | int pcibios_enable_device(struct pci_dev *dev, int mask) | ||
345 | { | ||
346 | u16 cmd, old_cmd; | ||
347 | int idx; | ||
348 | struct resource *r; | ||
349 | |||
350 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
351 | old_cmd = cmd; | ||
352 | for (idx = 0; idx < 6; idx++) { | ||
353 | /* Only set up the requested stuff */ | ||
354 | if (!(mask & (1 << idx))) | ||
355 | continue; | ||
356 | |||
357 | r = dev->resource + idx; | ||
358 | if (!r->start && r->end) { | ||
359 | printk(KERN_ERR "PCI: Device %s not available because" | ||
360 | " of resource collisions\n", pci_name(dev)); | ||
361 | return -EINVAL; | ||
362 | } | ||
363 | if (r->flags & IORESOURCE_IO) | ||
364 | cmd |= PCI_COMMAND_IO; | ||
365 | if (r->flags & IORESOURCE_MEM) | ||
366 | cmd |= PCI_COMMAND_MEMORY; | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * Bridges (eg, cardbus bridges) need to be fully enabled | ||
371 | */ | ||
372 | if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) | ||
373 | cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | ||
374 | |||
375 | if (cmd != old_cmd) { | ||
376 | printk("PCI: enabling device %s (%04x -> %04x)\n", | ||
377 | pci_name(dev), old_cmd, cmd); | ||
378 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
379 | } | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | ||
384 | enum pci_mmap_state mmap_state, int write_combine) | ||
385 | { | ||
386 | unsigned long phys; | ||
387 | |||
388 | if (mmap_state == pci_mmap_io) | ||
389 | return -EINVAL; | ||
390 | |||
391 | phys = vma->vm_pgoff; | ||
392 | |||
393 | /* | ||
394 | * Mark this as IO | ||
395 | */ | ||
396 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
397 | |||
398 | if (remap_pfn_range(vma, vma->vm_start, phys, | ||
399 | vma->vm_end - vma->vm_start, | ||
400 | vma->vm_page_prot)) | ||
401 | return -EAGAIN; | ||
402 | |||
403 | return 0; | ||
404 | } | ||