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