Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/platforms/52xx/mpc52xx_pci.c
10818 views
1
/*
2
* PCI code for the Freescale MPC52xx embedded CPU.
3
*
4
* Copyright (C) 2006 Secret Lab Technologies Ltd.
5
* Grant Likely <[email protected]>
6
* Copyright (C) 2004 Sylvain Munaut <[email protected]>
7
*
8
* This file is licensed under the terms of the GNU General Public License
9
* version 2. This program is licensed "as is" without any warranty of any
10
* kind, whether express or implied.
11
*/
12
13
#undef DEBUG
14
15
#include <asm/pci.h>
16
#include <asm/mpc52xx.h>
17
#include <asm/delay.h>
18
#include <asm/machdep.h>
19
#include <linux/kernel.h>
20
21
22
/* ======================================================================== */
23
/* Structures mapping & Defines for PCI Unit */
24
/* ======================================================================== */
25
26
#define MPC52xx_PCI_GSCR_BM 0x40000000
27
#define MPC52xx_PCI_GSCR_PE 0x20000000
28
#define MPC52xx_PCI_GSCR_SE 0x10000000
29
#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000
30
#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24
31
#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000
32
#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16
33
#define MPC52xx_PCI_GSCR_BME 0x00004000
34
#define MPC52xx_PCI_GSCR_PEE 0x00002000
35
#define MPC52xx_PCI_GSCR_SEE 0x00001000
36
#define MPC52xx_PCI_GSCR_PR 0x00000001
37
38
39
#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \
40
( ( (proc_ad) & 0xff000000 ) | \
41
( (((size) - 1) >> 8) & 0x00ff0000 ) | \
42
( ((pci_ad) >> 16) & 0x0000ff00 ) )
43
44
#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \
45
((win1) << 16) | \
46
((win2) << 8))
47
48
#define MPC52xx_PCI_IWCR_DISABLE 0x0
49
#define MPC52xx_PCI_IWCR_ENABLE 0x1
50
#define MPC52xx_PCI_IWCR_READ 0x0
51
#define MPC52xx_PCI_IWCR_READ_LINE 0x2
52
#define MPC52xx_PCI_IWCR_READ_MULTI 0x4
53
#define MPC52xx_PCI_IWCR_MEM 0x0
54
#define MPC52xx_PCI_IWCR_IO 0x8
55
56
#define MPC52xx_PCI_TCR_P 0x01000000
57
#define MPC52xx_PCI_TCR_LD 0x00010000
58
#define MPC52xx_PCI_TCR_WCT8 0x00000008
59
60
#define MPC52xx_PCI_TBATR_DISABLE 0x0
61
#define MPC52xx_PCI_TBATR_ENABLE 0x1
62
63
struct mpc52xx_pci {
64
u32 idr; /* PCI + 0x00 */
65
u32 scr; /* PCI + 0x04 */
66
u32 ccrir; /* PCI + 0x08 */
67
u32 cr1; /* PCI + 0x0C */
68
u32 bar0; /* PCI + 0x10 */
69
u32 bar1; /* PCI + 0x14 */
70
u8 reserved1[16]; /* PCI + 0x18 */
71
u32 ccpr; /* PCI + 0x28 */
72
u32 sid; /* PCI + 0x2C */
73
u32 erbar; /* PCI + 0x30 */
74
u32 cpr; /* PCI + 0x34 */
75
u8 reserved2[4]; /* PCI + 0x38 */
76
u32 cr2; /* PCI + 0x3C */
77
u8 reserved3[32]; /* PCI + 0x40 */
78
u32 gscr; /* PCI + 0x60 */
79
u32 tbatr0; /* PCI + 0x64 */
80
u32 tbatr1; /* PCI + 0x68 */
81
u32 tcr; /* PCI + 0x6C */
82
u32 iw0btar; /* PCI + 0x70 */
83
u32 iw1btar; /* PCI + 0x74 */
84
u32 iw2btar; /* PCI + 0x78 */
85
u8 reserved4[4]; /* PCI + 0x7C */
86
u32 iwcr; /* PCI + 0x80 */
87
u32 icr; /* PCI + 0x84 */
88
u32 isr; /* PCI + 0x88 */
89
u32 arb; /* PCI + 0x8C */
90
u8 reserved5[104]; /* PCI + 0x90 */
91
u32 car; /* PCI + 0xF8 */
92
u8 reserved6[4]; /* PCI + 0xFC */
93
};
94
95
/* MPC5200 device tree match tables */
96
const struct of_device_id mpc52xx_pci_ids[] __initdata = {
97
{ .type = "pci", .compatible = "fsl,mpc5200-pci", },
98
{ .type = "pci", .compatible = "mpc5200-pci", },
99
{}
100
};
101
102
/* ======================================================================== */
103
/* PCI configuration access */
104
/* ======================================================================== */
105
106
static int
107
mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
108
int offset, int len, u32 *val)
109
{
110
struct pci_controller *hose = pci_bus_to_host(bus);
111
u32 value;
112
113
if (ppc_md.pci_exclude_device)
114
if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
115
return PCIBIOS_DEVICE_NOT_FOUND;
116
117
out_be32(hose->cfg_addr,
118
(1 << 31) |
119
(bus->number << 16) |
120
(devfn << 8) |
121
(offset & 0xfc));
122
mb();
123
124
#if defined(CONFIG_PPC_MPC5200_BUGFIX)
125
if (bus->number) {
126
/* workaround for the bug 435 of the MPC5200 (L25R);
127
* Don't do 32 bits config access during type-1 cycles */
128
switch (len) {
129
case 1:
130
value = in_8(((u8 __iomem *)hose->cfg_data) +
131
(offset & 3));
132
break;
133
case 2:
134
value = in_le16(((u16 __iomem *)hose->cfg_data) +
135
((offset>>1) & 1));
136
break;
137
138
default:
139
value = in_le16((u16 __iomem *)hose->cfg_data) |
140
(in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
141
break;
142
}
143
}
144
else
145
#endif
146
{
147
value = in_le32(hose->cfg_data);
148
149
if (len != 4) {
150
value >>= ((offset & 0x3) << 3);
151
value &= 0xffffffff >> (32 - (len << 3));
152
}
153
}
154
155
*val = value;
156
157
out_be32(hose->cfg_addr, 0);
158
mb();
159
160
return PCIBIOS_SUCCESSFUL;
161
}
162
163
static int
164
mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
165
int offset, int len, u32 val)
166
{
167
struct pci_controller *hose = pci_bus_to_host(bus);
168
u32 value, mask;
169
170
if (ppc_md.pci_exclude_device)
171
if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
172
return PCIBIOS_DEVICE_NOT_FOUND;
173
174
out_be32(hose->cfg_addr,
175
(1 << 31) |
176
(bus->number << 16) |
177
(devfn << 8) |
178
(offset & 0xfc));
179
mb();
180
181
#if defined(CONFIG_PPC_MPC5200_BUGFIX)
182
if (bus->number) {
183
/* workaround for the bug 435 of the MPC5200 (L25R);
184
* Don't do 32 bits config access during type-1 cycles */
185
switch (len) {
186
case 1:
187
out_8(((u8 __iomem *)hose->cfg_data) +
188
(offset & 3), val);
189
break;
190
case 2:
191
out_le16(((u16 __iomem *)hose->cfg_data) +
192
((offset>>1) & 1), val);
193
break;
194
195
default:
196
out_le16((u16 __iomem *)hose->cfg_data,
197
(u16)val);
198
out_le16(((u16 __iomem *)hose->cfg_data) + 1,
199
(u16)(val>>16));
200
break;
201
}
202
}
203
else
204
#endif
205
{
206
if (len != 4) {
207
value = in_le32(hose->cfg_data);
208
209
offset = (offset & 0x3) << 3;
210
mask = (0xffffffff >> (32 - (len << 3)));
211
mask <<= offset;
212
213
value &= ~mask;
214
val = value | ((val << offset) & mask);
215
}
216
217
out_le32(hose->cfg_data, val);
218
}
219
mb();
220
221
out_be32(hose->cfg_addr, 0);
222
mb();
223
224
return PCIBIOS_SUCCESSFUL;
225
}
226
227
static struct pci_ops mpc52xx_pci_ops = {
228
.read = mpc52xx_pci_read_config,
229
.write = mpc52xx_pci_write_config
230
};
231
232
233
/* ======================================================================== */
234
/* PCI setup */
235
/* ======================================================================== */
236
237
static void __init
238
mpc52xx_pci_setup(struct pci_controller *hose,
239
struct mpc52xx_pci __iomem *pci_regs, phys_addr_t pci_phys)
240
{
241
struct resource *res;
242
u32 tmp;
243
int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
244
245
pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs);
246
247
/* pci_process_bridge_OF_ranges() found all our addresses for us;
248
* now store them in the right places */
249
hose->cfg_addr = &pci_regs->car;
250
hose->cfg_data = hose->io_base_virt;
251
252
/* Control regs */
253
tmp = in_be32(&pci_regs->scr);
254
tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
255
out_be32(&pci_regs->scr, tmp);
256
257
/* Memory windows */
258
res = &hose->mem_resources[0];
259
if (res->flags) {
260
pr_debug("mem_resource[0] = "
261
"{.start=%llx, .end=%llx, .flags=%llx}\n",
262
(unsigned long long)res->start,
263
(unsigned long long)res->end,
264
(unsigned long long)res->flags);
265
out_be32(&pci_regs->iw0btar,
266
MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
267
res->end - res->start + 1));
268
iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
269
if (res->flags & IORESOURCE_PREFETCH)
270
iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
271
else
272
iwcr0 |= MPC52xx_PCI_IWCR_READ;
273
}
274
275
res = &hose->mem_resources[1];
276
if (res->flags) {
277
pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
278
res->start, res->end, res->flags);
279
out_be32(&pci_regs->iw1btar,
280
MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
281
res->end - res->start + 1));
282
iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
283
if (res->flags & IORESOURCE_PREFETCH)
284
iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
285
else
286
iwcr1 |= MPC52xx_PCI_IWCR_READ;
287
}
288
289
/* IO resources */
290
res = &hose->io_resource;
291
if (!res) {
292
printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
293
return;
294
}
295
pr_debug(".io_resource={.start=%llx,.end=%llx,.flags=%llx} "
296
".io_base_phys=0x%p\n",
297
(unsigned long long)res->start,
298
(unsigned long long)res->end,
299
(unsigned long long)res->flags, (void*)hose->io_base_phys);
300
out_be32(&pci_regs->iw2btar,
301
MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
302
res->start,
303
res->end - res->start + 1));
304
iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
305
306
/* Set all the IWCR fields at once; they're in the same reg */
307
out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
308
309
/* Map IMMR onto PCI bus */
310
pci_phys &= 0xfffc0000; /* bar0 has only 14 significant bits */
311
out_be32(&pci_regs->tbatr0, MPC52xx_PCI_TBATR_ENABLE | pci_phys);
312
out_be32(&pci_regs->bar0, PCI_BASE_ADDRESS_MEM_PREFETCH | pci_phys);
313
314
/* Map memory onto PCI bus */
315
out_be32(&pci_regs->tbatr1, MPC52xx_PCI_TBATR_ENABLE);
316
out_be32(&pci_regs->bar1, PCI_BASE_ADDRESS_MEM_PREFETCH);
317
318
out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD | MPC52xx_PCI_TCR_WCT8);
319
320
tmp = in_be32(&pci_regs->gscr);
321
#if 0
322
/* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
323
/* Not necessary and can be a bad thing if for example the bootloader
324
is displaying a splash screen or ... Just left here for
325
documentation purpose if anyone need it */
326
out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
327
udelay(50);
328
#endif
329
330
/* Make sure the PCI bridge is out of reset */
331
out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
332
}
333
334
static void
335
mpc52xx_pci_fixup_resources(struct pci_dev *dev)
336
{
337
int i;
338
339
pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
340
dev->vendor, dev->device);
341
342
/* We don't rely on boot loader for PCI and resets all
343
devices */
344
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
345
struct resource *res = &dev->resource[i];
346
if (res->end > res->start) { /* Only valid resources */
347
res->end -= res->start;
348
res->start = 0;
349
res->flags |= IORESOURCE_UNSET;
350
}
351
}
352
353
/* The PCI Host bridge of MPC52xx has a prefetch memory resource
354
fixed to 1Gb. Doesn't fit in the resource system so we remove it */
355
if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
356
( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
357
|| dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
358
struct resource *res = &dev->resource[1];
359
res->start = res->end = res->flags = 0;
360
}
361
}
362
363
int __init
364
mpc52xx_add_bridge(struct device_node *node)
365
{
366
int len;
367
struct mpc52xx_pci __iomem *pci_regs;
368
struct pci_controller *hose;
369
const int *bus_range;
370
struct resource rsrc;
371
372
pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name);
373
374
ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
375
376
if (of_address_to_resource(node, 0, &rsrc) != 0) {
377
printk(KERN_ERR "Can't get %s resources\n", node->full_name);
378
return -EINVAL;
379
}
380
381
bus_range = of_get_property(node, "bus-range", &len);
382
if (bus_range == NULL || len < 2 * sizeof(int)) {
383
printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
384
node->full_name);
385
bus_range = NULL;
386
}
387
388
/* There are some PCI quirks on the 52xx, register the hook to
389
* fix them. */
390
ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
391
392
/* Alloc and initialize the pci controller. Values in the device
393
* tree are needed to configure the 52xx PCI controller. Rather
394
* than parse the tree here, let pci_process_bridge_OF_ranges()
395
* do it for us and extract the values after the fact */
396
hose = pcibios_alloc_controller(node);
397
if (!hose)
398
return -ENOMEM;
399
400
hose->first_busno = bus_range ? bus_range[0] : 0;
401
hose->last_busno = bus_range ? bus_range[1] : 0xff;
402
403
hose->ops = &mpc52xx_pci_ops;
404
405
pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
406
if (!pci_regs)
407
return -ENOMEM;
408
409
pci_process_bridge_OF_ranges(hose, node, 1);
410
411
/* Finish setting up PCI using values obtained by
412
* pci_proces_bridge_OF_ranges */
413
mpc52xx_pci_setup(hose, pci_regs, rsrc.start);
414
415
return 0;
416
}
417
418
void __init mpc52xx_setup_pci(void)
419
{
420
struct device_node *pci;
421
422
pci = of_find_matching_node(NULL, mpc52xx_pci_ids);
423
if (!pci)
424
return;
425
426
mpc52xx_add_bridge(pci);
427
of_node_put(pci);
428
}
429
430