Commit | Line | Data |
---|---|---|
794d15b2 SS |
1 | /* |
2 | * arch/arm/mach-mv78xx0/pcie.c | |
3 | * | |
4 | * PCIe functions for Marvell MV78xx0 SoCs | |
5 | * | |
6 | * This file is licensed under the terms of the GNU General Public | |
7 | * License version 2. This program is licensed "as is" without any | |
8 | * warranty of any kind, whether express or implied. | |
9 | */ | |
10 | ||
11 | #include <linux/kernel.h> | |
12 | #include <linux/pci.h> | |
cc22b4c1 | 13 | #include <video/vga.h> |
ba0cda6d | 14 | #include <asm/irq.h> |
794d15b2 | 15 | #include <asm/mach/pci.h> |
6f088f1d | 16 | #include <plat/pcie.h> |
45173d5e | 17 | #include <plat/addr-map.h> |
794d15b2 SS |
18 | #include "common.h" |
19 | ||
20 | struct pcie_port { | |
21 | u8 maj; | |
22 | u8 min; | |
23 | u8 root_bus_nr; | |
24 | void __iomem *base; | |
25 | spinlock_t conf_lock; | |
26 | char io_space_name[16]; | |
27 | char mem_space_name[16]; | |
28 | struct resource res[2]; | |
29 | }; | |
30 | ||
31 | static struct pcie_port pcie_port[8]; | |
32 | static int num_pcie_ports; | |
33 | static struct resource pcie_io_space; | |
34 | static struct resource pcie_mem_space; | |
35 | ||
36 | ||
cfdeb637 LB |
37 | void __init mv78xx0_pcie_id(u32 *dev, u32 *rev) |
38 | { | |
39 | *dev = orion_pcie_dev_id((void __iomem *)PCIE00_VIRT_BASE); | |
40 | *rev = orion_pcie_rev((void __iomem *)PCIE00_VIRT_BASE); | |
41 | } | |
42 | ||
794d15b2 SS |
43 | static void __init mv78xx0_pcie_preinit(void) |
44 | { | |
45 | int i; | |
46 | u32 size_each; | |
47 | u32 start; | |
48 | int win; | |
49 | ||
50 | pcie_io_space.name = "PCIe I/O Space"; | |
51 | pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0); | |
52 | pcie_io_space.end = | |
53 | MV78XX0_PCIE_IO_PHYS_BASE(0) + MV78XX0_PCIE_IO_SIZE * 8 - 1; | |
54 | pcie_io_space.flags = IORESOURCE_IO; | |
55 | if (request_resource(&iomem_resource, &pcie_io_space)) | |
56 | panic("can't allocate PCIe I/O space"); | |
57 | ||
58 | pcie_mem_space.name = "PCIe MEM Space"; | |
59 | pcie_mem_space.start = MV78XX0_PCIE_MEM_PHYS_BASE; | |
60 | pcie_mem_space.end = | |
61 | MV78XX0_PCIE_MEM_PHYS_BASE + MV78XX0_PCIE_MEM_SIZE - 1; | |
62 | pcie_mem_space.flags = IORESOURCE_MEM; | |
63 | if (request_resource(&iomem_resource, &pcie_mem_space)) | |
64 | panic("can't allocate PCIe MEM space"); | |
65 | ||
66 | for (i = 0; i < num_pcie_ports; i++) { | |
67 | struct pcie_port *pp = pcie_port + i; | |
68 | ||
69 | snprintf(pp->io_space_name, sizeof(pp->io_space_name), | |
70 | "PCIe %d.%d I/O", pp->maj, pp->min); | |
71 | pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0; | |
72 | pp->res[0].name = pp->io_space_name; | |
73 | pp->res[0].start = MV78XX0_PCIE_IO_PHYS_BASE(i); | |
74 | pp->res[0].end = pp->res[0].start + MV78XX0_PCIE_IO_SIZE - 1; | |
75 | pp->res[0].flags = IORESOURCE_IO; | |
76 | ||
77 | snprintf(pp->mem_space_name, sizeof(pp->mem_space_name), | |
78 | "PCIe %d.%d MEM", pp->maj, pp->min); | |
79 | pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0; | |
80 | pp->res[1].name = pp->mem_space_name; | |
81 | pp->res[1].flags = IORESOURCE_MEM; | |
82 | } | |
83 | ||
84 | switch (num_pcie_ports) { | |
85 | case 0: | |
86 | size_each = 0; | |
87 | break; | |
88 | ||
89 | case 1: | |
90 | size_each = 0x30000000; | |
91 | break; | |
92 | ||
93 | case 2 ... 3: | |
94 | size_each = 0x10000000; | |
95 | break; | |
96 | ||
97 | case 4 ... 6: | |
98 | size_each = 0x08000000; | |
99 | break; | |
100 | ||
101 | case 7: | |
102 | size_each = 0x04000000; | |
103 | break; | |
104 | ||
105 | default: | |
106 | panic("invalid number of PCIe ports"); | |
107 | } | |
108 | ||
109 | start = MV78XX0_PCIE_MEM_PHYS_BASE; | |
110 | for (i = 0; i < num_pcie_ports; i++) { | |
111 | struct pcie_port *pp = pcie_port + i; | |
112 | ||
113 | pp->res[1].start = start; | |
114 | pp->res[1].end = start + size_each - 1; | |
115 | start += size_each; | |
116 | } | |
117 | ||
118 | for (i = 0; i < num_pcie_ports; i++) { | |
119 | struct pcie_port *pp = pcie_port + i; | |
120 | ||
121 | if (request_resource(&pcie_io_space, &pp->res[0])) | |
122 | panic("can't allocate PCIe I/O sub-space"); | |
123 | ||
124 | if (request_resource(&pcie_mem_space, &pp->res[1])) | |
125 | panic("can't allocate PCIe MEM sub-space"); | |
126 | } | |
127 | ||
128 | win = 0; | |
129 | for (i = 0; i < num_pcie_ports; i++) { | |
130 | struct pcie_port *pp = pcie_port + i; | |
131 | ||
132 | mv78xx0_setup_pcie_io_win(win++, pp->res[0].start, | |
28f65c11 JP |
133 | resource_size(&pp->res[0]), |
134 | pp->maj, pp->min); | |
794d15b2 SS |
135 | |
136 | mv78xx0_setup_pcie_mem_win(win++, pp->res[1].start, | |
28f65c11 JP |
137 | resource_size(&pp->res[1]), |
138 | pp->maj, pp->min); | |
794d15b2 SS |
139 | } |
140 | } | |
141 | ||
142 | static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys) | |
143 | { | |
144 | struct pcie_port *pp; | |
145 | ||
146 | if (nr >= num_pcie_ports) | |
147 | return 0; | |
148 | ||
149 | pp = &pcie_port[nr]; | |
150 | pp->root_bus_nr = sys->busnr; | |
151 | ||
152 | /* | |
153 | * Generic PCIe unit setup. | |
154 | */ | |
155 | orion_pcie_set_local_bus_nr(pp->base, sys->busnr); | |
63a9332b | 156 | orion_pcie_setup(pp->base); |
794d15b2 SS |
157 | |
158 | sys->resource[0] = &pp->res[0]; | |
159 | sys->resource[1] = &pp->res[1]; | |
160 | sys->resource[2] = NULL; | |
161 | ||
162 | return 1; | |
163 | } | |
164 | ||
165 | static struct pcie_port *bus_to_port(int bus) | |
166 | { | |
167 | int i; | |
168 | ||
169 | for (i = num_pcie_ports - 1; i >= 0; i--) { | |
170 | int rbus = pcie_port[i].root_bus_nr; | |
171 | if (rbus != -1 && rbus <= bus) | |
172 | break; | |
173 | } | |
174 | ||
175 | return i >= 0 ? pcie_port + i : NULL; | |
176 | } | |
177 | ||
178 | static int pcie_valid_config(struct pcie_port *pp, int bus, int dev) | |
179 | { | |
180 | /* | |
181 | * Don't go out when trying to access nonexisting devices | |
182 | * on the local bus. | |
183 | */ | |
184 | if (bus == pp->root_bus_nr && dev > 1) | |
185 | return 0; | |
186 | ||
187 | return 1; | |
188 | } | |
189 | ||
190 | static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, | |
191 | int size, u32 *val) | |
192 | { | |
193 | struct pcie_port *pp = bus_to_port(bus->number); | |
194 | unsigned long flags; | |
195 | int ret; | |
196 | ||
197 | if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) { | |
198 | *val = 0xffffffff; | |
199 | return PCIBIOS_DEVICE_NOT_FOUND; | |
200 | } | |
201 | ||
202 | spin_lock_irqsave(&pp->conf_lock, flags); | |
203 | ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val); | |
204 | spin_unlock_irqrestore(&pp->conf_lock, flags); | |
205 | ||
206 | return ret; | |
207 | } | |
208 | ||
209 | static int pcie_wr_conf(struct pci_bus *bus, u32 devfn, | |
210 | int where, int size, u32 val) | |
211 | { | |
212 | struct pcie_port *pp = bus_to_port(bus->number); | |
213 | unsigned long flags; | |
214 | int ret; | |
215 | ||
216 | if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) | |
217 | return PCIBIOS_DEVICE_NOT_FOUND; | |
218 | ||
219 | spin_lock_irqsave(&pp->conf_lock, flags); | |
220 | ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val); | |
221 | spin_unlock_irqrestore(&pp->conf_lock, flags); | |
222 | ||
223 | return ret; | |
224 | } | |
225 | ||
226 | static struct pci_ops pcie_ops = { | |
227 | .read = pcie_rd_conf, | |
228 | .write = pcie_wr_conf, | |
229 | }; | |
230 | ||
231 | static void __devinit rc_pci_fixup(struct pci_dev *dev) | |
232 | { | |
233 | /* | |
234 | * Prevent enumeration of root complex. | |
235 | */ | |
236 | if (dev->bus->parent == NULL && dev->devfn == 0) { | |
237 | int i; | |
238 | ||
239 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | |
240 | dev->resource[i].start = 0; | |
241 | dev->resource[i].end = 0; | |
242 | dev->resource[i].flags = 0; | |
243 | } | |
244 | } | |
245 | } | |
246 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); | |
247 | ||
248 | static struct pci_bus __init * | |
249 | mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys) | |
250 | { | |
251 | struct pci_bus *bus; | |
252 | ||
253 | if (nr < num_pcie_ports) { | |
254 | bus = pci_scan_bus(sys->busnr, &pcie_ops, sys); | |
255 | } else { | |
256 | bus = NULL; | |
257 | BUG(); | |
258 | } | |
259 | ||
260 | return bus; | |
261 | } | |
262 | ||
d5341942 RB |
263 | static int __init mv78xx0_pcie_map_irq(const struct pci_dev *dev, u8 slot, |
264 | u8 pin) | |
794d15b2 SS |
265 | { |
266 | struct pcie_port *pp = bus_to_port(dev->bus->number); | |
267 | ||
268 | return IRQ_MV78XX0_PCIE_00 + (pp->maj << 2) + pp->min; | |
269 | } | |
270 | ||
271 | static struct hw_pci mv78xx0_pci __initdata = { | |
272 | .nr_controllers = 8, | |
273 | .preinit = mv78xx0_pcie_preinit, | |
274 | .swizzle = pci_std_swizzle, | |
275 | .setup = mv78xx0_pcie_setup, | |
276 | .scan = mv78xx0_pcie_scan_bus, | |
277 | .map_irq = mv78xx0_pcie_map_irq, | |
278 | }; | |
279 | ||
280 | static void __init add_pcie_port(int maj, int min, unsigned long base) | |
281 | { | |
282 | printk(KERN_INFO "MV78xx0 PCIe port %d.%d: ", maj, min); | |
283 | ||
284 | if (orion_pcie_link_up((void __iomem *)base)) { | |
285 | struct pcie_port *pp = &pcie_port[num_pcie_ports++]; | |
286 | ||
287 | printk("link up\n"); | |
288 | ||
289 | pp->maj = maj; | |
290 | pp->min = min; | |
291 | pp->root_bus_nr = -1; | |
292 | pp->base = (void __iomem *)base; | |
293 | spin_lock_init(&pp->conf_lock); | |
294 | memset(pp->res, 0, sizeof(pp->res)); | |
295 | } else { | |
296 | printk("link down, ignoring\n"); | |
297 | } | |
298 | } | |
299 | ||
300 | void __init mv78xx0_pcie_init(int init_port0, int init_port1) | |
301 | { | |
cc22b4c1 RH |
302 | vga_base = MV78XX0_PCIE_MEM_PHYS_BASE; |
303 | ||
794d15b2 SS |
304 | if (init_port0) { |
305 | add_pcie_port(0, 0, PCIE00_VIRT_BASE); | |
306 | if (!orion_pcie_x4_mode((void __iomem *)PCIE00_VIRT_BASE)) { | |
307 | add_pcie_port(0, 1, PCIE01_VIRT_BASE); | |
308 | add_pcie_port(0, 2, PCIE02_VIRT_BASE); | |
309 | add_pcie_port(0, 3, PCIE03_VIRT_BASE); | |
310 | } | |
311 | } | |
312 | ||
313 | if (init_port1) { | |
314 | add_pcie_port(1, 0, PCIE10_VIRT_BASE); | |
315 | if (!orion_pcie_x4_mode((void __iomem *)PCIE10_VIRT_BASE)) { | |
316 | add_pcie_port(1, 1, PCIE11_VIRT_BASE); | |
317 | add_pcie_port(1, 2, PCIE12_VIRT_BASE); | |
318 | add_pcie_port(1, 3, PCIE13_VIRT_BASE); | |
319 | } | |
320 | } | |
321 | ||
322 | pci_common_init(&mv78xx0_pci); | |
323 | } |