diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-03-27 14:51:41 -0400 |
---|---|---|
committer | Nicolas Pitre <nico@marvell.com> | 2008-03-27 14:51:41 -0400 |
commit | 9dd0b194bf6804b1998f0fe261b2606ec7b58d72 (patch) | |
tree | c9fd5ab51dc256818c24a8a771dc068d021039e2 /arch/arm/mach-orion5x/pci.c | |
parent | 159ffb3a04f6bc619643af680df406faafd0199d (diff) |
Orion: orion -> orion5x rename
Do a global s/orion/orion5x/ of the Orion 5x-specific bits (i.e.
not the plat-orion bits.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Reviewed-by: Tzachi Perelstein <tzachi@marvell.com>
Acked-by: Saeed Bishara <saeed@marvell.com>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Diffstat (limited to 'arch/arm/mach-orion5x/pci.c')
-rw-r--r-- | arch/arm/mach-orion5x/pci.c | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c new file mode 100644 index 000000000000..27b4afc8f486 --- /dev/null +++ b/arch/arm/mach-orion5x/pci.c | |||
@@ -0,0 +1,559 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/pci.c | ||
3 | * | ||
4 | * PCI and PCIe functions for Marvell Orion System On Chip | ||
5 | * | ||
6 | * Maintainer: Tzachi Perelstein <tzachi@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/mbus.h> | ||
16 | #include <asm/mach/pci.h> | ||
17 | #include <asm/plat-orion/pcie.h> | ||
18 | #include "common.h" | ||
19 | |||
20 | /***************************************************************************** | ||
21 | * Orion has one PCIe controller and one PCI controller. | ||
22 | * | ||
23 | * Note1: The local PCIe bus number is '0'. The local PCI bus number | ||
24 | * follows the scanned PCIe bridged busses, if any. | ||
25 | * | ||
26 | * Note2: It is possible for PCI/PCIe agents to access many subsystem's | ||
27 | * space, by configuring BARs and Address Decode Windows, e.g. flashes on | ||
28 | * device bus, Orion registers, etc. However this code only enable the | ||
29 | * access to DDR banks. | ||
30 | ****************************************************************************/ | ||
31 | |||
32 | |||
33 | /***************************************************************************** | ||
34 | * PCIe controller | ||
35 | ****************************************************************************/ | ||
36 | #define PCIE_BASE ((void __iomem *)ORION5X_PCIE_VIRT_BASE) | ||
37 | |||
38 | void __init orion5x_pcie_id(u32 *dev, u32 *rev) | ||
39 | { | ||
40 | *dev = orion_pcie_dev_id(PCIE_BASE); | ||
41 | *rev = orion_pcie_rev(PCIE_BASE); | ||
42 | } | ||
43 | |||
44 | int orion5x_pcie_local_bus_nr(void) | ||
45 | { | ||
46 | return orion_pcie_get_local_bus_nr(PCIE_BASE); | ||
47 | } | ||
48 | |||
49 | static int pcie_valid_config(int bus, int dev) | ||
50 | { | ||
51 | /* | ||
52 | * Don't go out when trying to access -- | ||
53 | * 1. nonexisting device on local bus | ||
54 | * 2. where there's no device connected (no link) | ||
55 | */ | ||
56 | if (bus == 0 && dev == 0) | ||
57 | return 1; | ||
58 | |||
59 | if (!orion_pcie_link_up(PCIE_BASE)) | ||
60 | return 0; | ||
61 | |||
62 | if (bus == 0 && dev != 1) | ||
63 | return 0; | ||
64 | |||
65 | return 1; | ||
66 | } | ||
67 | |||
68 | |||
69 | /* | ||
70 | * PCIe config cycles are done by programming the PCIE_CONF_ADDR register | ||
71 | * and then reading the PCIE_CONF_DATA register. Need to make sure these | ||
72 | * transactions are atomic. | ||
73 | */ | ||
74 | static DEFINE_SPINLOCK(orion5x_pcie_lock); | ||
75 | |||
76 | static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, | ||
77 | int size, u32 *val) | ||
78 | { | ||
79 | unsigned long flags; | ||
80 | int ret; | ||
81 | |||
82 | if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) { | ||
83 | *val = 0xffffffff; | ||
84 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
85 | } | ||
86 | |||
87 | spin_lock_irqsave(&orion5x_pcie_lock, flags); | ||
88 | ret = orion_pcie_rd_conf(PCIE_BASE, bus, devfn, where, size, val); | ||
89 | spin_unlock_irqrestore(&orion5x_pcie_lock, flags); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static int pcie_rd_conf_wa(struct pci_bus *bus, u32 devfn, | ||
95 | int where, int size, u32 *val) | ||
96 | { | ||
97 | int ret; | ||
98 | |||
99 | if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) { | ||
100 | *val = 0xffffffff; | ||
101 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * We only support access to the non-extended configuration | ||
106 | * space when using the WA access method (or we would have to | ||
107 | * sacrifice 256M of CPU virtual address space.) | ||
108 | */ | ||
109 | if (where >= 0x100) { | ||
110 | *val = 0xffffffff; | ||
111 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
112 | } | ||
113 | |||
114 | ret = orion_pcie_rd_conf_wa((void __iomem *)ORION5X_PCIE_WA_VIRT_BASE, | ||
115 | bus, devfn, where, size, val); | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static int pcie_wr_conf(struct pci_bus *bus, u32 devfn, | ||
121 | int where, int size, u32 val) | ||
122 | { | ||
123 | unsigned long flags; | ||
124 | int ret; | ||
125 | |||
126 | if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) | ||
127 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
128 | |||
129 | spin_lock_irqsave(&orion5x_pcie_lock, flags); | ||
130 | ret = orion_pcie_wr_conf(PCIE_BASE, bus, devfn, where, size, val); | ||
131 | spin_unlock_irqrestore(&orion5x_pcie_lock, flags); | ||
132 | |||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | static struct pci_ops pcie_ops = { | ||
137 | .read = pcie_rd_conf, | ||
138 | .write = pcie_wr_conf, | ||
139 | }; | ||
140 | |||
141 | |||
142 | static int __init pcie_setup(struct pci_sys_data *sys) | ||
143 | { | ||
144 | struct resource *res; | ||
145 | int dev; | ||
146 | |||
147 | /* | ||
148 | * Generic PCIe unit setup. | ||
149 | */ | ||
150 | orion_pcie_setup(PCIE_BASE, &orion5x_mbus_dram_info); | ||
151 | |||
152 | /* | ||
153 | * Check whether to apply Orion-1/Orion-NAS PCIe config | ||
154 | * read transaction workaround. | ||
155 | */ | ||
156 | dev = orion_pcie_dev_id(PCIE_BASE); | ||
157 | if (dev == MV88F5181_DEV_ID || dev == MV88F5182_DEV_ID) { | ||
158 | printk(KERN_NOTICE "Applying Orion-1/Orion-NAS PCIe config " | ||
159 | "read transaction workaround\n"); | ||
160 | pcie_ops.read = pcie_rd_conf_wa; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Request resources. | ||
165 | */ | ||
166 | res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); | ||
167 | if (!res) | ||
168 | panic("pcie_setup unable to alloc resources"); | ||
169 | |||
170 | /* | ||
171 | * IORESOURCE_IO | ||
172 | */ | ||
173 | res[0].name = "PCIe I/O Space"; | ||
174 | res[0].flags = IORESOURCE_IO; | ||
175 | res[0].start = ORION5X_PCIE_IO_BUS_BASE; | ||
176 | res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1; | ||
177 | if (request_resource(&ioport_resource, &res[0])) | ||
178 | panic("Request PCIe IO resource failed\n"); | ||
179 | sys->resource[0] = &res[0]; | ||
180 | |||
181 | /* | ||
182 | * IORESOURCE_MEM | ||
183 | */ | ||
184 | res[1].name = "PCIe Memory Space"; | ||
185 | res[1].flags = IORESOURCE_MEM; | ||
186 | res[1].start = ORION5X_PCIE_MEM_PHYS_BASE; | ||
187 | res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1; | ||
188 | if (request_resource(&iomem_resource, &res[1])) | ||
189 | panic("Request PCIe Memory resource failed\n"); | ||
190 | sys->resource[1] = &res[1]; | ||
191 | |||
192 | sys->resource[2] = NULL; | ||
193 | sys->io_offset = 0; | ||
194 | |||
195 | return 1; | ||
196 | } | ||
197 | |||
198 | /***************************************************************************** | ||
199 | * PCI controller | ||
200 | ****************************************************************************/ | ||
201 | #define PCI_MODE ORION5X_PCI_REG(0xd00) | ||
202 | #define PCI_CMD ORION5X_PCI_REG(0xc00) | ||
203 | #define PCI_P2P_CONF ORION5X_PCI_REG(0x1d14) | ||
204 | #define PCI_CONF_ADDR ORION5X_PCI_REG(0xc78) | ||
205 | #define PCI_CONF_DATA ORION5X_PCI_REG(0xc7c) | ||
206 | |||
207 | /* | ||
208 | * PCI_MODE bits | ||
209 | */ | ||
210 | #define PCI_MODE_64BIT (1 << 2) | ||
211 | #define PCI_MODE_PCIX ((1 << 4) | (1 << 5)) | ||
212 | |||
213 | /* | ||
214 | * PCI_CMD bits | ||
215 | */ | ||
216 | #define PCI_CMD_HOST_REORDER (1 << 29) | ||
217 | |||
218 | /* | ||
219 | * PCI_P2P_CONF bits | ||
220 | */ | ||
221 | #define PCI_P2P_BUS_OFFS 16 | ||
222 | #define PCI_P2P_BUS_MASK (0xff << PCI_P2P_BUS_OFFS) | ||
223 | #define PCI_P2P_DEV_OFFS 24 | ||
224 | #define PCI_P2P_DEV_MASK (0x1f << PCI_P2P_DEV_OFFS) | ||
225 | |||
226 | /* | ||
227 | * PCI_CONF_ADDR bits | ||
228 | */ | ||
229 | #define PCI_CONF_REG(reg) ((reg) & 0xfc) | ||
230 | #define PCI_CONF_FUNC(func) (((func) & 0x3) << 8) | ||
231 | #define PCI_CONF_DEV(dev) (((dev) & 0x1f) << 11) | ||
232 | #define PCI_CONF_BUS(bus) (((bus) & 0xff) << 16) | ||
233 | #define PCI_CONF_ADDR_EN (1 << 31) | ||
234 | |||
235 | /* | ||
236 | * Internal configuration space | ||
237 | */ | ||
238 | #define PCI_CONF_FUNC_STAT_CMD 0 | ||
239 | #define PCI_CONF_REG_STAT_CMD 4 | ||
240 | #define PCIX_STAT 0x64 | ||
241 | #define PCIX_STAT_BUS_OFFS 8 | ||
242 | #define PCIX_STAT_BUS_MASK (0xff << PCIX_STAT_BUS_OFFS) | ||
243 | |||
244 | /* | ||
245 | * PCI Address Decode Windows registers | ||
246 | */ | ||
247 | #define PCI_BAR_SIZE_DDR_CS(n) (((n) == 0) ? ORION5X_PCI_REG(0xc08) : \ | ||
248 | ((n) == 1) ? ORION5X_PCI_REG(0xd08) : \ | ||
249 | ((n) == 2) ? ORION5X_PCI_REG(0xc0c) : \ | ||
250 | ((n) == 3) ? ORION5X_PCI_REG(0xd0c) : 0) | ||
251 | #define PCI_BAR_REMAP_DDR_CS(n) (((n) ==0) ? ORION5X_PCI_REG(0xc48) : \ | ||
252 | ((n) == 1) ? ORION5X_PCI_REG(0xd48) : \ | ||
253 | ((n) == 2) ? ORION5X_PCI_REG(0xc4c) : \ | ||
254 | ((n) == 3) ? ORION5X_PCI_REG(0xd4c) : 0) | ||
255 | #define PCI_BAR_ENABLE ORION5X_PCI_REG(0xc3c) | ||
256 | #define PCI_ADDR_DECODE_CTRL ORION5X_PCI_REG(0xd3c) | ||
257 | |||
258 | /* | ||
259 | * PCI configuration helpers for BAR settings | ||
260 | */ | ||
261 | #define PCI_CONF_FUNC_BAR_CS(n) ((n) >> 1) | ||
262 | #define PCI_CONF_REG_BAR_LO_CS(n) (((n) & 1) ? 0x18 : 0x10) | ||
263 | #define PCI_CONF_REG_BAR_HI_CS(n) (((n) & 1) ? 0x1c : 0x14) | ||
264 | |||
265 | /* | ||
266 | * PCI config cycles are done by programming the PCI_CONF_ADDR register | ||
267 | * and then reading the PCI_CONF_DATA register. Need to make sure these | ||
268 | * transactions are atomic. | ||
269 | */ | ||
270 | static DEFINE_SPINLOCK(orion5x_pci_lock); | ||
271 | |||
272 | int orion5x_pci_local_bus_nr(void) | ||
273 | { | ||
274 | u32 conf = orion5x_read(PCI_P2P_CONF); | ||
275 | return((conf & PCI_P2P_BUS_MASK) >> PCI_P2P_BUS_OFFS); | ||
276 | } | ||
277 | |||
278 | static int orion5x_pci_hw_rd_conf(int bus, int dev, u32 func, | ||
279 | u32 where, u32 size, u32 *val) | ||
280 | { | ||
281 | unsigned long flags; | ||
282 | spin_lock_irqsave(&orion5x_pci_lock, flags); | ||
283 | |||
284 | orion5x_write(PCI_CONF_ADDR, PCI_CONF_BUS(bus) | | ||
285 | PCI_CONF_DEV(dev) | PCI_CONF_REG(where) | | ||
286 | PCI_CONF_FUNC(func) | PCI_CONF_ADDR_EN); | ||
287 | |||
288 | *val = orion5x_read(PCI_CONF_DATA); | ||
289 | |||
290 | if (size == 1) | ||
291 | *val = (*val >> (8*(where & 0x3))) & 0xff; | ||
292 | else if (size == 2) | ||
293 | *val = (*val >> (8*(where & 0x3))) & 0xffff; | ||
294 | |||
295 | spin_unlock_irqrestore(&orion5x_pci_lock, flags); | ||
296 | |||
297 | return PCIBIOS_SUCCESSFUL; | ||
298 | } | ||
299 | |||
300 | static int orion5x_pci_hw_wr_conf(int bus, int dev, u32 func, | ||
301 | u32 where, u32 size, u32 val) | ||
302 | { | ||
303 | unsigned long flags; | ||
304 | int ret = PCIBIOS_SUCCESSFUL; | ||
305 | |||
306 | spin_lock_irqsave(&orion5x_pci_lock, flags); | ||
307 | |||
308 | orion5x_write(PCI_CONF_ADDR, PCI_CONF_BUS(bus) | | ||
309 | PCI_CONF_DEV(dev) | PCI_CONF_REG(where) | | ||
310 | PCI_CONF_FUNC(func) | PCI_CONF_ADDR_EN); | ||
311 | |||
312 | if (size == 4) { | ||
313 | __raw_writel(val, PCI_CONF_DATA); | ||
314 | } else if (size == 2) { | ||
315 | __raw_writew(val, PCI_CONF_DATA + (where & 0x3)); | ||
316 | } else if (size == 1) { | ||
317 | __raw_writeb(val, PCI_CONF_DATA + (where & 0x3)); | ||
318 | } else { | ||
319 | ret = PCIBIOS_BAD_REGISTER_NUMBER; | ||
320 | } | ||
321 | |||
322 | spin_unlock_irqrestore(&orion5x_pci_lock, flags); | ||
323 | |||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | static int orion5x_pci_rd_conf(struct pci_bus *bus, u32 devfn, | ||
328 | int where, int size, u32 *val) | ||
329 | { | ||
330 | /* | ||
331 | * Don't go out for local device | ||
332 | */ | ||
333 | if (bus->number == orion5x_pci_local_bus_nr() && | ||
334 | PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) != 0) { | ||
335 | *val = 0xffffffff; | ||
336 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
337 | } | ||
338 | |||
339 | return orion5x_pci_hw_rd_conf(bus->number, PCI_SLOT(devfn), | ||
340 | PCI_FUNC(devfn), where, size, val); | ||
341 | } | ||
342 | |||
343 | static int orion5x_pci_wr_conf(struct pci_bus *bus, u32 devfn, | ||
344 | int where, int size, u32 val) | ||
345 | { | ||
346 | if (bus->number == orion5x_pci_local_bus_nr() && | ||
347 | PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) != 0) | ||
348 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
349 | |||
350 | return orion5x_pci_hw_wr_conf(bus->number, PCI_SLOT(devfn), | ||
351 | PCI_FUNC(devfn), where, size, val); | ||
352 | } | ||
353 | |||
354 | static struct pci_ops pci_ops = { | ||
355 | .read = orion5x_pci_rd_conf, | ||
356 | .write = orion5x_pci_wr_conf, | ||
357 | }; | ||
358 | |||
359 | static void __init orion5x_pci_set_bus_nr(int nr) | ||
360 | { | ||
361 | u32 p2p = orion5x_read(PCI_P2P_CONF); | ||
362 | |||
363 | if (orion5x_read(PCI_MODE) & PCI_MODE_PCIX) { | ||
364 | /* | ||
365 | * PCI-X mode | ||
366 | */ | ||
367 | u32 pcix_status, bus, dev; | ||
368 | bus = (p2p & PCI_P2P_BUS_MASK) >> PCI_P2P_BUS_OFFS; | ||
369 | dev = (p2p & PCI_P2P_DEV_MASK) >> PCI_P2P_DEV_OFFS; | ||
370 | orion5x_pci_hw_rd_conf(bus, dev, 0, PCIX_STAT, 4, &pcix_status); | ||
371 | pcix_status &= ~PCIX_STAT_BUS_MASK; | ||
372 | pcix_status |= (nr << PCIX_STAT_BUS_OFFS); | ||
373 | orion5x_pci_hw_wr_conf(bus, dev, 0, PCIX_STAT, 4, pcix_status); | ||
374 | } else { | ||
375 | /* | ||
376 | * PCI Conventional mode | ||
377 | */ | ||
378 | p2p &= ~PCI_P2P_BUS_MASK; | ||
379 | p2p |= (nr << PCI_P2P_BUS_OFFS); | ||
380 | orion5x_write(PCI_P2P_CONF, p2p); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | static void __init orion5x_pci_master_slave_enable(void) | ||
385 | { | ||
386 | int bus_nr, func, reg; | ||
387 | u32 val; | ||
388 | |||
389 | bus_nr = orion5x_pci_local_bus_nr(); | ||
390 | func = PCI_CONF_FUNC_STAT_CMD; | ||
391 | reg = PCI_CONF_REG_STAT_CMD; | ||
392 | orion5x_pci_hw_rd_conf(bus_nr, 0, func, reg, 4, &val); | ||
393 | val |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | ||
394 | orion5x_pci_hw_wr_conf(bus_nr, 0, func, reg, 4, val | 0x7); | ||
395 | } | ||
396 | |||
397 | static void __init orion5x_setup_pci_wins(struct mbus_dram_target_info *dram) | ||
398 | { | ||
399 | u32 win_enable; | ||
400 | int bus; | ||
401 | int i; | ||
402 | |||
403 | /* | ||
404 | * First, disable windows. | ||
405 | */ | ||
406 | win_enable = 0xffffffff; | ||
407 | orion5x_write(PCI_BAR_ENABLE, win_enable); | ||
408 | |||
409 | /* | ||
410 | * Setup windows for DDR banks. | ||
411 | */ | ||
412 | bus = orion5x_pci_local_bus_nr(); | ||
413 | |||
414 | for (i = 0; i < dram->num_cs; i++) { | ||
415 | struct mbus_dram_window *cs = dram->cs + i; | ||
416 | u32 func = PCI_CONF_FUNC_BAR_CS(cs->cs_index); | ||
417 | u32 reg; | ||
418 | u32 val; | ||
419 | |||
420 | /* | ||
421 | * Write DRAM bank base address register. | ||
422 | */ | ||
423 | reg = PCI_CONF_REG_BAR_LO_CS(cs->cs_index); | ||
424 | orion5x_pci_hw_rd_conf(bus, 0, func, reg, 4, &val); | ||
425 | val = (cs->base & 0xfffff000) | (val & 0xfff); | ||
426 | orion5x_pci_hw_wr_conf(bus, 0, func, reg, 4, val); | ||
427 | |||
428 | /* | ||
429 | * Write DRAM bank size register. | ||
430 | */ | ||
431 | reg = PCI_CONF_REG_BAR_HI_CS(cs->cs_index); | ||
432 | orion5x_pci_hw_wr_conf(bus, 0, func, reg, 4, 0); | ||
433 | orion5x_write(PCI_BAR_SIZE_DDR_CS(cs->cs_index), | ||
434 | (cs->size - 1) & 0xfffff000); | ||
435 | orion5x_write(PCI_BAR_REMAP_DDR_CS(cs->cs_index), | ||
436 | cs->base & 0xfffff000); | ||
437 | |||
438 | /* | ||
439 | * Enable decode window for this chip select. | ||
440 | */ | ||
441 | win_enable &= ~(1 << cs->cs_index); | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * Re-enable decode windows. | ||
446 | */ | ||
447 | orion5x_write(PCI_BAR_ENABLE, win_enable); | ||
448 | |||
449 | /* | ||
450 | * Disable automatic update of address remaping when writing to BARs. | ||
451 | */ | ||
452 | orion5x_setbits(PCI_ADDR_DECODE_CTRL, 1); | ||
453 | } | ||
454 | |||
455 | static int __init pci_setup(struct pci_sys_data *sys) | ||
456 | { | ||
457 | struct resource *res; | ||
458 | |||
459 | /* | ||
460 | * Point PCI unit MBUS decode windows to DRAM space. | ||
461 | */ | ||
462 | orion5x_setup_pci_wins(&orion5x_mbus_dram_info); | ||
463 | |||
464 | /* | ||
465 | * Master + Slave enable | ||
466 | */ | ||
467 | orion5x_pci_master_slave_enable(); | ||
468 | |||
469 | /* | ||
470 | * Force ordering | ||
471 | */ | ||
472 | orion5x_setbits(PCI_CMD, PCI_CMD_HOST_REORDER); | ||
473 | |||
474 | /* | ||
475 | * Request resources | ||
476 | */ | ||
477 | res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); | ||
478 | if (!res) | ||
479 | panic("pci_setup unable to alloc resources"); | ||
480 | |||
481 | /* | ||
482 | * IORESOURCE_IO | ||
483 | */ | ||
484 | res[0].name = "PCI I/O Space"; | ||
485 | res[0].flags = IORESOURCE_IO; | ||
486 | res[0].start = ORION5X_PCI_IO_BUS_BASE; | ||
487 | res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1; | ||
488 | if (request_resource(&ioport_resource, &res[0])) | ||
489 | panic("Request PCI IO resource failed\n"); | ||
490 | sys->resource[0] = &res[0]; | ||
491 | |||
492 | /* | ||
493 | * IORESOURCE_MEM | ||
494 | */ | ||
495 | res[1].name = "PCI Memory Space"; | ||
496 | res[1].flags = IORESOURCE_MEM; | ||
497 | res[1].start = ORION5X_PCI_MEM_PHYS_BASE; | ||
498 | res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1; | ||
499 | if (request_resource(&iomem_resource, &res[1])) | ||
500 | panic("Request PCI Memory resource failed\n"); | ||
501 | sys->resource[1] = &res[1]; | ||
502 | |||
503 | sys->resource[2] = NULL; | ||
504 | sys->io_offset = 0; | ||
505 | |||
506 | return 1; | ||
507 | } | ||
508 | |||
509 | |||
510 | /***************************************************************************** | ||
511 | * General PCIe + PCI | ||
512 | ****************************************************************************/ | ||
513 | static void __devinit rc_pci_fixup(struct pci_dev *dev) | ||
514 | { | ||
515 | /* | ||
516 | * Prevent enumeration of root complex. | ||
517 | */ | ||
518 | if (dev->bus->parent == NULL && dev->devfn == 0) { | ||
519 | int i; | ||
520 | |||
521 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
522 | dev->resource[i].start = 0; | ||
523 | dev->resource[i].end = 0; | ||
524 | dev->resource[i].flags = 0; | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); | ||
529 | |||
530 | int __init orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys) | ||
531 | { | ||
532 | int ret = 0; | ||
533 | |||
534 | if (nr == 0) { | ||
535 | orion_pcie_set_local_bus_nr(PCIE_BASE, sys->busnr); | ||
536 | ret = pcie_setup(sys); | ||
537 | } else if (nr == 1) { | ||
538 | orion5x_pci_set_bus_nr(sys->busnr); | ||
539 | ret = pci_setup(sys); | ||
540 | } | ||
541 | |||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys) | ||
546 | { | ||
547 | struct pci_bus *bus; | ||
548 | |||
549 | if (nr == 0) { | ||
550 | bus = pci_scan_bus(sys->busnr, &pcie_ops, sys); | ||
551 | } else if (nr == 1) { | ||
552 | bus = pci_scan_bus(sys->busnr, &pci_ops, sys); | ||
553 | } else { | ||
554 | bus = NULL; | ||
555 | BUG(); | ||
556 | } | ||
557 | |||
558 | return bus; | ||
559 | } | ||