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> | |
95b80e0a | 13 | #include <linux/mbus.h> |
cc22b4c1 | 14 | #include <video/vga.h> |
ba0cda6d | 15 | #include <asm/irq.h> |
794d15b2 | 16 | #include <asm/mach/pci.h> |
6f088f1d | 17 | #include <plat/pcie.h> |
0b9b18e0 | 18 | #include <mach/mv78xx0.h> |
794d15b2 SS |
19 | #include "common.h" |
20 | ||
21 | struct pcie_port { | |
22 | u8 maj; | |
23 | u8 min; | |
24 | u8 root_bus_nr; | |
25 | void __iomem *base; | |
26 | spinlock_t conf_lock; | |
794d15b2 | 27 | char mem_space_name[16]; |
0b9b18e0 | 28 | struct resource res; |
794d15b2 SS |
29 | }; |
30 | ||
31 | static struct pcie_port pcie_port[8]; | |
32 | static int num_pcie_ports; | |
33 | static struct resource pcie_io_space; | |
794d15b2 | 34 | |
cfdeb637 LB |
35 | void __init mv78xx0_pcie_id(u32 *dev, u32 *rev) |
36 | { | |
383b9961 TP |
37 | *dev = orion_pcie_dev_id(PCIE00_VIRT_BASE); |
38 | *rev = orion_pcie_rev(PCIE00_VIRT_BASE); | |
cfdeb637 LB |
39 | } |
40 | ||
0b9b18e0 RH |
41 | u32 pcie_port_size[8] = { |
42 | 0, | |
43 | 0x30000000, | |
44 | 0x10000000, | |
45 | 0x10000000, | |
46 | 0x08000000, | |
47 | 0x08000000, | |
48 | 0x08000000, | |
49 | 0x04000000, | |
50 | }; | |
51 | ||
794d15b2 SS |
52 | static void __init mv78xx0_pcie_preinit(void) |
53 | { | |
54 | int i; | |
55 | u32 size_each; | |
56 | u32 start; | |
794d15b2 SS |
57 | |
58 | pcie_io_space.name = "PCIe I/O Space"; | |
59 | pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0); | |
60 | pcie_io_space.end = | |
61 | MV78XX0_PCIE_IO_PHYS_BASE(0) + MV78XX0_PCIE_IO_SIZE * 8 - 1; | |
0b9b18e0 | 62 | pcie_io_space.flags = IORESOURCE_MEM; |
794d15b2 SS |
63 | if (request_resource(&iomem_resource, &pcie_io_space)) |
64 | panic("can't allocate PCIe I/O space"); | |
65 | ||
0b9b18e0 RH |
66 | if (num_pcie_ports > 7) |
67 | panic("invalid number of PCIe ports"); | |
68 | ||
69 | size_each = pcie_port_size[num_pcie_ports]; | |
794d15b2 | 70 | |
0b9b18e0 | 71 | start = MV78XX0_PCIE_MEM_PHYS_BASE; |
794d15b2 SS |
72 | for (i = 0; i < num_pcie_ports; i++) { |
73 | struct pcie_port *pp = pcie_port + i; | |
95b80e0a | 74 | char winname[MVEBU_MBUS_MAX_WINNAME_SZ]; |
794d15b2 | 75 | |
794d15b2 SS |
76 | snprintf(pp->mem_space_name, sizeof(pp->mem_space_name), |
77 | "PCIe %d.%d MEM", pp->maj, pp->min); | |
78 | pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0; | |
0b9b18e0 RH |
79 | pp->res.name = pp->mem_space_name; |
80 | pp->res.flags = IORESOURCE_MEM; | |
81 | pp->res.start = start; | |
82 | pp->res.end = start + size_each - 1; | |
794d15b2 | 83 | start += size_each; |
794d15b2 | 84 | |
0b9b18e0 | 85 | if (request_resource(&iomem_resource, &pp->res)) |
794d15b2 | 86 | panic("can't allocate PCIe MEM sub-space"); |
794d15b2 | 87 | |
95b80e0a TP |
88 | snprintf(winname, sizeof(winname), "pcie%d.%d", |
89 | pp->maj, pp->min); | |
90 | ||
91 | mvebu_mbus_add_window_remap_flags(winname, | |
92 | pp->res.start, | |
93 | resource_size(&pp->res), | |
94 | MVEBU_MBUS_NO_REMAP, | |
95 | MVEBU_MBUS_PCI_MEM); | |
96 | mvebu_mbus_add_window_remap_flags(winname, | |
97 | i * SZ_64K, SZ_64K, | |
98 | 0, MVEBU_MBUS_PCI_IO); | |
794d15b2 SS |
99 | } |
100 | } | |
101 | ||
102 | static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys) | |
103 | { | |
104 | struct pcie_port *pp; | |
105 | ||
106 | if (nr >= num_pcie_ports) | |
107 | return 0; | |
108 | ||
109 | pp = &pcie_port[nr]; | |
43ba990b | 110 | sys->private_data = pp; |
794d15b2 SS |
111 | pp->root_bus_nr = sys->busnr; |
112 | ||
113 | /* | |
114 | * Generic PCIe unit setup. | |
115 | */ | |
116 | orion_pcie_set_local_bus_nr(pp->base, sys->busnr); | |
63a9332b | 117 | orion_pcie_setup(pp->base); |
794d15b2 | 118 | |
0b9b18e0 RH |
119 | pci_ioremap_io(nr * SZ_64K, MV78XX0_PCIE_IO_PHYS_BASE(nr)); |
120 | ||
121 | pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset); | |
794d15b2 SS |
122 | |
123 | return 1; | |
124 | } | |
125 | ||
794d15b2 SS |
126 | static int pcie_valid_config(struct pcie_port *pp, int bus, int dev) |
127 | { | |
128 | /* | |
129 | * Don't go out when trying to access nonexisting devices | |
130 | * on the local bus. | |
131 | */ | |
132 | if (bus == pp->root_bus_nr && dev > 1) | |
133 | return 0; | |
134 | ||
135 | return 1; | |
136 | } | |
137 | ||
138 | static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, | |
139 | int size, u32 *val) | |
140 | { | |
43ba990b RK |
141 | struct pci_sys_data *sys = bus->sysdata; |
142 | struct pcie_port *pp = sys->private_data; | |
794d15b2 SS |
143 | unsigned long flags; |
144 | int ret; | |
145 | ||
146 | if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) { | |
147 | *val = 0xffffffff; | |
148 | return PCIBIOS_DEVICE_NOT_FOUND; | |
149 | } | |
150 | ||
151 | spin_lock_irqsave(&pp->conf_lock, flags); | |
152 | ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val); | |
153 | spin_unlock_irqrestore(&pp->conf_lock, flags); | |
154 | ||
155 | return ret; | |
156 | } | |
157 | ||
158 | static int pcie_wr_conf(struct pci_bus *bus, u32 devfn, | |
159 | int where, int size, u32 val) | |
160 | { | |
43ba990b RK |
161 | struct pci_sys_data *sys = bus->sysdata; |
162 | struct pcie_port *pp = sys->private_data; | |
794d15b2 SS |
163 | unsigned long flags; |
164 | int ret; | |
165 | ||
166 | if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) | |
167 | return PCIBIOS_DEVICE_NOT_FOUND; | |
168 | ||
169 | spin_lock_irqsave(&pp->conf_lock, flags); | |
170 | ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val); | |
171 | spin_unlock_irqrestore(&pp->conf_lock, flags); | |
172 | ||
173 | return ret; | |
174 | } | |
175 | ||
176 | static struct pci_ops pcie_ops = { | |
177 | .read = pcie_rd_conf, | |
178 | .write = pcie_wr_conf, | |
179 | }; | |
180 | ||
351a102d | 181 | static void rc_pci_fixup(struct pci_dev *dev) |
794d15b2 SS |
182 | { |
183 | /* | |
184 | * Prevent enumeration of root complex. | |
185 | */ | |
186 | if (dev->bus->parent == NULL && dev->devfn == 0) { | |
187 | int i; | |
188 | ||
189 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | |
190 | dev->resource[i].start = 0; | |
191 | dev->resource[i].end = 0; | |
192 | dev->resource[i].flags = 0; | |
193 | } | |
194 | } | |
195 | } | |
196 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); | |
197 | ||
198 | static struct pci_bus __init * | |
199 | mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys) | |
200 | { | |
201 | struct pci_bus *bus; | |
202 | ||
203 | if (nr < num_pcie_ports) { | |
37d15909 BH |
204 | bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys, |
205 | &sys->resources); | |
794d15b2 SS |
206 | } else { |
207 | bus = NULL; | |
208 | BUG(); | |
209 | } | |
210 | ||
211 | return bus; | |
212 | } | |
213 | ||
d5341942 RB |
214 | static int __init mv78xx0_pcie_map_irq(const struct pci_dev *dev, u8 slot, |
215 | u8 pin) | |
794d15b2 | 216 | { |
43ba990b RK |
217 | struct pci_sys_data *sys = dev->bus->sysdata; |
218 | struct pcie_port *pp = sys->private_data; | |
794d15b2 SS |
219 | |
220 | return IRQ_MV78XX0_PCIE_00 + (pp->maj << 2) + pp->min; | |
221 | } | |
222 | ||
223 | static struct hw_pci mv78xx0_pci __initdata = { | |
224 | .nr_controllers = 8, | |
225 | .preinit = mv78xx0_pcie_preinit, | |
794d15b2 SS |
226 | .setup = mv78xx0_pcie_setup, |
227 | .scan = mv78xx0_pcie_scan_bus, | |
228 | .map_irq = mv78xx0_pcie_map_irq, | |
229 | }; | |
230 | ||
383b9961 | 231 | static void __init add_pcie_port(int maj, int min, void __iomem *base) |
794d15b2 SS |
232 | { |
233 | printk(KERN_INFO "MV78xx0 PCIe port %d.%d: ", maj, min); | |
234 | ||
383b9961 | 235 | if (orion_pcie_link_up(base)) { |
794d15b2 SS |
236 | struct pcie_port *pp = &pcie_port[num_pcie_ports++]; |
237 | ||
238 | printk("link up\n"); | |
239 | ||
240 | pp->maj = maj; | |
241 | pp->min = min; | |
242 | pp->root_bus_nr = -1; | |
383b9961 | 243 | pp->base = base; |
794d15b2 | 244 | spin_lock_init(&pp->conf_lock); |
0b9b18e0 | 245 | memset(&pp->res, 0, sizeof(pp->res)); |
794d15b2 SS |
246 | } else { |
247 | printk("link down, ignoring\n"); | |
248 | } | |
249 | } | |
250 | ||
251 | void __init mv78xx0_pcie_init(int init_port0, int init_port1) | |
252 | { | |
cc22b4c1 RH |
253 | vga_base = MV78XX0_PCIE_MEM_PHYS_BASE; |
254 | ||
794d15b2 SS |
255 | if (init_port0) { |
256 | add_pcie_port(0, 0, PCIE00_VIRT_BASE); | |
383b9961 | 257 | if (!orion_pcie_x4_mode(PCIE00_VIRT_BASE)) { |
794d15b2 SS |
258 | add_pcie_port(0, 1, PCIE01_VIRT_BASE); |
259 | add_pcie_port(0, 2, PCIE02_VIRT_BASE); | |
260 | add_pcie_port(0, 3, PCIE03_VIRT_BASE); | |
261 | } | |
262 | } | |
263 | ||
264 | if (init_port1) { | |
265 | add_pcie_port(1, 0, PCIE10_VIRT_BASE); | |
266 | if (!orion_pcie_x4_mode((void __iomem *)PCIE10_VIRT_BASE)) { | |
267 | add_pcie_port(1, 1, PCIE11_VIRT_BASE); | |
268 | add_pcie_port(1, 2, PCIE12_VIRT_BASE); | |
269 | add_pcie_port(1, 3, PCIE13_VIRT_BASE); | |
270 | } | |
271 | } | |
272 | ||
273 | pci_common_init(&mv78xx0_pci); | |
274 | } |