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