1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * arch/arm/mach-mv78xx0/pcie.c |
4 | * |
5 | * PCIe functions for Marvell MV78xx0 SoCs |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/pci.h> |
10 | #include <linux/mbus.h> |
11 | #include <video/vga.h> |
12 | #include <asm/irq.h> |
13 | #include <asm/mach/pci.h> |
14 | #include <plat/pcie.h> |
15 | #include "mv78xx0.h" |
16 | #include "common.h" |
17 | |
18 | #define MV78XX0_MBUS_PCIE_MEM_TARGET(port, lane) ((port) ? 8 : 4) |
19 | #define MV78XX0_MBUS_PCIE_MEM_ATTR(port, lane) (0xf8 & ~(0x10 << (lane))) |
20 | #define MV78XX0_MBUS_PCIE_IO_TARGET(port, lane) ((port) ? 8 : 4) |
21 | #define MV78XX0_MBUS_PCIE_IO_ATTR(port, lane) (0xf0 & ~(0x10 << (lane))) |
22 | |
23 | struct pcie_port { |
24 | u8 maj; |
25 | u8 min; |
26 | u8 root_bus_nr; |
27 | void __iomem *base; |
28 | spinlock_t conf_lock; |
29 | char mem_space_name[20]; |
30 | struct resource res; |
31 | }; |
32 | |
33 | static struct pcie_port pcie_port[8]; |
34 | static int num_pcie_ports; |
35 | static struct resource pcie_io_space; |
36 | |
37 | void __init mv78xx0_pcie_id(u32 *dev, u32 *rev) |
38 | { |
39 | *dev = orion_pcie_dev_id(PCIE00_VIRT_BASE); |
40 | *rev = orion_pcie_rev(PCIE00_VIRT_BASE); |
41 | } |
42 | |
43 | u32 pcie_port_size[8] = { |
44 | 0, |
45 | 0x20000000, |
46 | 0x10000000, |
47 | 0x10000000, |
48 | 0x08000000, |
49 | 0x08000000, |
50 | 0x08000000, |
51 | 0x04000000, |
52 | }; |
53 | |
54 | static void __init mv78xx0_pcie_preinit(void) |
55 | { |
56 | int i; |
57 | u32 size_each; |
58 | u32 start; |
59 | |
60 | pcie_io_space.name = "PCIe I/O Space" ; |
61 | pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0); |
62 | pcie_io_space.end = |
63 | MV78XX0_PCIE_IO_PHYS_BASE(0) + MV78XX0_PCIE_IO_SIZE * 8 - 1; |
64 | pcie_io_space.flags = IORESOURCE_MEM; |
65 | if (request_resource(root: &iomem_resource, new: &pcie_io_space)) |
66 | panic(fmt: "can't allocate PCIe I/O space" ); |
67 | |
68 | if (num_pcie_ports > 7) |
69 | panic(fmt: "invalid number of PCIe ports" ); |
70 | |
71 | size_each = pcie_port_size[num_pcie_ports]; |
72 | |
73 | start = MV78XX0_PCIE_MEM_PHYS_BASE; |
74 | for (i = 0; i < num_pcie_ports; i++) { |
75 | struct pcie_port *pp = pcie_port + i; |
76 | |
77 | snprintf(buf: pp->mem_space_name, size: sizeof(pp->mem_space_name), |
78 | fmt: "PCIe %d.%d MEM" , pp->maj, pp->min); |
79 | pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0; |
80 | pp->res.name = pp->mem_space_name; |
81 | pp->res.flags = IORESOURCE_MEM; |
82 | pp->res.start = start; |
83 | pp->res.end = start + size_each - 1; |
84 | start += size_each; |
85 | |
86 | if (request_resource(root: &iomem_resource, new: &pp->res)) |
87 | panic(fmt: "can't allocate PCIe MEM sub-space" ); |
88 | |
89 | mvebu_mbus_add_window_by_id(MV78XX0_MBUS_PCIE_MEM_TARGET(pp->maj, pp->min), |
90 | MV78XX0_MBUS_PCIE_MEM_ATTR(pp->maj, pp->min), |
91 | pp->res.start, resource_size(res: &pp->res)); |
92 | mvebu_mbus_add_window_remap_by_id(MV78XX0_MBUS_PCIE_IO_TARGET(pp->maj, pp->min), |
93 | MV78XX0_MBUS_PCIE_IO_ATTR(pp->maj, pp->min), |
94 | i * SZ_64K, SZ_64K, 0); |
95 | } |
96 | } |
97 | |
98 | static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys) |
99 | { |
100 | struct pcie_port *pp; |
101 | struct resource realio; |
102 | |
103 | if (nr >= num_pcie_ports) |
104 | return 0; |
105 | |
106 | pp = &pcie_port[nr]; |
107 | sys->private_data = pp; |
108 | pp->root_bus_nr = sys->busnr; |
109 | |
110 | /* |
111 | * Generic PCIe unit setup. |
112 | */ |
113 | orion_pcie_set_local_bus_nr(pp->base, sys->busnr); |
114 | orion_pcie_setup(pp->base); |
115 | |
116 | realio.start = nr * SZ_64K; |
117 | realio.end = realio.start + SZ_64K - 1; |
118 | pci_remap_iospace(res: &realio, MV78XX0_PCIE_IO_PHYS_BASE(nr)); |
119 | |
120 | pci_add_resource_offset(resources: &sys->resources, res: &pp->res, offset: sys->mem_offset); |
121 | |
122 | return 1; |
123 | } |
124 | |
125 | static int pcie_valid_config(struct pcie_port *pp, int bus, int dev) |
126 | { |
127 | /* |
128 | * Don't go out when trying to access nonexisting devices |
129 | * on the local bus. |
130 | */ |
131 | if (bus == pp->root_bus_nr && dev > 1) |
132 | return 0; |
133 | |
134 | return 1; |
135 | } |
136 | |
137 | static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, |
138 | int size, u32 *val) |
139 | { |
140 | struct pci_sys_data *sys = bus->sysdata; |
141 | struct pcie_port *pp = sys->private_data; |
142 | unsigned long flags; |
143 | int ret; |
144 | |
145 | if (pcie_valid_config(pp, bus: bus->number, PCI_SLOT(devfn)) == 0) { |
146 | *val = 0xffffffff; |
147 | return PCIBIOS_DEVICE_NOT_FOUND; |
148 | } |
149 | |
150 | spin_lock_irqsave(&pp->conf_lock, flags); |
151 | ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val); |
152 | spin_unlock_irqrestore(lock: &pp->conf_lock, flags); |
153 | |
154 | return ret; |
155 | } |
156 | |
157 | static int pcie_wr_conf(struct pci_bus *bus, u32 devfn, |
158 | int where, int size, u32 val) |
159 | { |
160 | struct pci_sys_data *sys = bus->sysdata; |
161 | struct pcie_port *pp = sys->private_data; |
162 | unsigned long flags; |
163 | int ret; |
164 | |
165 | if (pcie_valid_config(pp, bus: bus->number, PCI_SLOT(devfn)) == 0) |
166 | return PCIBIOS_DEVICE_NOT_FOUND; |
167 | |
168 | spin_lock_irqsave(&pp->conf_lock, flags); |
169 | ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val); |
170 | spin_unlock_irqrestore(lock: &pp->conf_lock, flags); |
171 | |
172 | return ret; |
173 | } |
174 | |
175 | static struct pci_ops pcie_ops = { |
176 | .read = pcie_rd_conf, |
177 | .write = pcie_wr_conf, |
178 | }; |
179 | |
180 | /* |
181 | * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it |
182 | * is operating as a root complex this needs to be switched to |
183 | * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on |
184 | * the device. Decoding setup is handled by the orion code. |
185 | */ |
186 | static void rc_pci_fixup(struct pci_dev *dev) |
187 | { |
188 | if (dev->bus->parent == NULL && dev->devfn == 0) { |
189 | struct resource *r; |
190 | |
191 | dev->class &= 0xff; |
192 | dev->class |= PCI_CLASS_BRIDGE_HOST << 8; |
193 | pci_dev_for_each_resource(dev, r) { |
194 | r->start = 0; |
195 | r->end = 0; |
196 | r->flags = 0; |
197 | } |
198 | } |
199 | } |
200 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); |
201 | |
202 | static int __init mv78xx0_pcie_scan_bus(int nr, struct pci_host_bridge *bridge) |
203 | { |
204 | struct pci_sys_data *sys = pci_host_bridge_priv(bridge); |
205 | |
206 | if (nr >= num_pcie_ports) { |
207 | BUG(); |
208 | return -EINVAL; |
209 | } |
210 | |
211 | list_splice_init(list: &sys->resources, head: &bridge->windows); |
212 | bridge->dev.parent = NULL; |
213 | bridge->sysdata = sys; |
214 | bridge->busnr = sys->busnr; |
215 | bridge->ops = &pcie_ops; |
216 | |
217 | return pci_scan_root_bus_bridge(bridge); |
218 | } |
219 | |
220 | static int __init mv78xx0_pcie_map_irq(const struct pci_dev *dev, u8 slot, |
221 | u8 pin) |
222 | { |
223 | struct pci_sys_data *sys = dev->bus->sysdata; |
224 | struct pcie_port *pp = sys->private_data; |
225 | |
226 | return IRQ_MV78XX0_PCIE_00 + (pp->maj << 2) + pp->min; |
227 | } |
228 | |
229 | static struct hw_pci mv78xx0_pci __initdata = { |
230 | .nr_controllers = 8, |
231 | .preinit = mv78xx0_pcie_preinit, |
232 | .setup = mv78xx0_pcie_setup, |
233 | .scan = mv78xx0_pcie_scan_bus, |
234 | .map_irq = mv78xx0_pcie_map_irq, |
235 | }; |
236 | |
237 | static void __init add_pcie_port(int maj, int min, void __iomem *base) |
238 | { |
239 | printk(KERN_INFO "MV78xx0 PCIe port %d.%d: " , maj, min); |
240 | |
241 | if (orion_pcie_link_up(base)) { |
242 | struct pcie_port *pp = &pcie_port[num_pcie_ports++]; |
243 | |
244 | printk("link up\n" ); |
245 | |
246 | pp->maj = maj; |
247 | pp->min = min; |
248 | pp->root_bus_nr = -1; |
249 | pp->base = base; |
250 | spin_lock_init(&pp->conf_lock); |
251 | memset(&pp->res, 0, sizeof(pp->res)); |
252 | } else { |
253 | printk("link down, ignoring\n" ); |
254 | } |
255 | } |
256 | |
257 | void __init mv78xx0_pcie_init(int init_port0, int init_port1) |
258 | { |
259 | vga_base = MV78XX0_PCIE_MEM_PHYS_BASE; |
260 | |
261 | if (init_port0) { |
262 | add_pcie_port(maj: 0, min: 0, PCIE00_VIRT_BASE); |
263 | if (!orion_pcie_x4_mode(PCIE00_VIRT_BASE)) { |
264 | add_pcie_port(maj: 0, min: 1, PCIE01_VIRT_BASE); |
265 | add_pcie_port(maj: 0, min: 2, PCIE02_VIRT_BASE); |
266 | add_pcie_port(maj: 0, min: 3, PCIE03_VIRT_BASE); |
267 | } |
268 | } |
269 | |
270 | if (init_port1) { |
271 | add_pcie_port(maj: 1, min: 0, PCIE10_VIRT_BASE); |
272 | if (!orion_pcie_x4_mode((void __iomem *)PCIE10_VIRT_BASE)) { |
273 | add_pcie_port(maj: 1, min: 1, PCIE11_VIRT_BASE); |
274 | add_pcie_port(maj: 1, min: 2, PCIE12_VIRT_BASE); |
275 | add_pcie_port(maj: 1, min: 3, PCIE13_VIRT_BASE); |
276 | } |
277 | } |
278 | |
279 | pci_common_init(&mv78xx0_pci); |
280 | } |
281 | |