aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-09 12:58:19 -0400
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2008-12-04 08:02:19 -0500
commit84d727a109081684c2e01b811cb0d6dc3b9380ca (patch)
tree632400e37b327dc9ca1aca6f796b41b835f2f8c8 /arch/powerpc/sysdev
parent9d2421e8345602675132421fdaf4179af4705f5c (diff)
powerpc/4xx: Add support for ISA holes on 4xx PCI/X/E
This adds support for ISA memory holes on the PCI, PCI-X and PCI-E busses of the 4xx platforms. The patch includes changes to the Bamboo and Canyonlands device-trees to add such a hole, others can be updated separately. The ISA memory hole is an additional outbound window configured in the bridge to generate PCI cycles in the low memory addresses, thus allowing to access things such as the hard-decoded VGA aperture at 0xa0000..0xbffff or other similar things. It's made accessible to userspace via the new legacy_mem file in sysfs for which support was added by a previous patch. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c306
1 files changed, 208 insertions, 98 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index d3e4d61030b5..77fae5f64f2e 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -194,11 +194,41 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
194 * 4xx PCI 2.x part 194 * 4xx PCI 2.x part
195 */ 195 */
196 196
197static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose,
198 void __iomem *reg,
199 u64 plb_addr,
200 u64 pci_addr,
201 u64 size,
202 unsigned int flags,
203 int index)
204{
205 u32 ma, pcila, pciha;
206
207 if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) ||
208 size < 0x1000 || (plb_addr & (size - 1)) != 0) {
209 printk(KERN_WARNING "%s: Resource out of range\n",
210 hose->dn->full_name);
211 return -1;
212 }
213 ma = (0xffffffffu << ilog2(size)) | 1;
214 if (flags & IORESOURCE_PREFETCH)
215 ma |= 2;
216
217 pciha = RES_TO_U32_HIGH(pci_addr);
218 pcila = RES_TO_U32_LOW(pci_addr);
219
220 writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index));
221 writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index));
222 writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index));
223 writel(ma, reg + PCIL0_PMM0MA + (0x10 * index));
224
225 return 0;
226}
227
197static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, 228static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
198 void __iomem *reg) 229 void __iomem *reg)
199{ 230{
200 u32 la, ma, pcila, pciha; 231 int i, j, found_isa_hole = 0;
201 int i, j;
202 232
203 /* Setup outbound memory windows */ 233 /* Setup outbound memory windows */
204 for (i = j = 0; i < 3; i++) { 234 for (i = j = 0; i < 3; i++) {
@@ -213,28 +243,29 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
213 break; 243 break;
214 } 244 }
215 245
216 /* Calculate register values */ 246 /* Configure the resource */
217 la = res->start; 247 if (ppc4xx_setup_one_pci_PMM(hose, reg,
218 pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); 248 res->start,
219 pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); 249 res->start - hose->pci_mem_offset,
220 250 res->end + 1 - res->start,
221 ma = res->end + 1 - res->start; 251 res->flags,
222 if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { 252 j) == 0) {
223 printk(KERN_WARNING "%s: Resource out of range\n", 253 j++;
224 hose->dn->full_name); 254
225 continue; 255 /* If the resource PCI address is 0 then we have our
256 * ISA memory hole
257 */
258 if (res->start == hose->pci_mem_offset)
259 found_isa_hole = 1;
226 } 260 }
227 ma = (0xffffffffu << ilog2(ma)) | 0x1;
228 if (res->flags & IORESOURCE_PREFETCH)
229 ma |= 0x2;
230
231 /* Program register values */
232 writel(la, reg + PCIL0_PMM0LA + (0x10 * j));
233 writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j));
234 writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j));
235 writel(ma, reg + PCIL0_PMM0MA + (0x10 * j));
236 j++;
237 } 261 }
262
263 /* Handle ISA memory hole if not already covered */
264 if (j <= 2 && !found_isa_hole && hose->isa_mem_size)
265 if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0,
266 hose->isa_mem_size, 0, j) == 0)
267 printk(KERN_INFO "%s: Legacy ISA memory support enabled\n",
268 hose->dn->full_name);
238} 269}
239 270
240static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, 271static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose,
@@ -352,11 +383,52 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np)
352 * 4xx PCI-X part 383 * 4xx PCI-X part
353 */ 384 */
354 385
386static int __init ppc4xx_setup_one_pcix_POM(struct pci_controller *hose,
387 void __iomem *reg,
388 u64 plb_addr,
389 u64 pci_addr,
390 u64 size,
391 unsigned int flags,
392 int index)
393{
394 u32 lah, lal, pciah, pcial, sa;
395
396 if (!is_power_of_2(size) || size < 0x1000 ||
397 (plb_addr & (size - 1)) != 0) {
398 printk(KERN_WARNING "%s: Resource out of range\n",
399 hose->dn->full_name);
400 return -1;
401 }
402
403 /* Calculate register values */
404 lah = RES_TO_U32_HIGH(plb_addr);
405 lal = RES_TO_U32_LOW(plb_addr);
406 pciah = RES_TO_U32_HIGH(pci_addr);
407 pcial = RES_TO_U32_LOW(pci_addr);
408 sa = (0xffffffffu << ilog2(size)) | 0x1;
409
410 /* Program register values */
411 if (index == 0) {
412 writel(lah, reg + PCIX0_POM0LAH);
413 writel(lal, reg + PCIX0_POM0LAL);
414 writel(pciah, reg + PCIX0_POM0PCIAH);
415 writel(pcial, reg + PCIX0_POM0PCIAL);
416 writel(sa, reg + PCIX0_POM0SA);
417 } else {
418 writel(lah, reg + PCIX0_POM1LAH);
419 writel(lal, reg + PCIX0_POM1LAL);
420 writel(pciah, reg + PCIX0_POM1PCIAH);
421 writel(pcial, reg + PCIX0_POM1PCIAL);
422 writel(sa, reg + PCIX0_POM1SA);
423 }
424
425 return 0;
426}
427
355static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, 428static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
356 void __iomem *reg) 429 void __iomem *reg)
357{ 430{
358 u32 lah, lal, pciah, pcial, sa; 431 int i, j, found_isa_hole = 0;
359 int i, j;
360 432
361 /* Setup outbound memory windows */ 433 /* Setup outbound memory windows */
362 for (i = j = 0; i < 3; i++) { 434 for (i = j = 0; i < 3; i++) {
@@ -371,36 +443,29 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
371 break; 443 break;
372 } 444 }
373 445
374 /* Calculate register values */ 446 /* Configure the resource */
375 lah = RES_TO_U32_HIGH(res->start); 447 if (ppc4xx_setup_one_pcix_POM(hose, reg,
376 lal = RES_TO_U32_LOW(res->start); 448 res->start,
377 pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); 449 res->start - hose->pci_mem_offset,
378 pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); 450 res->end + 1 - res->start,
379 sa = res->end + 1 - res->start; 451 res->flags,
380 if (!is_power_of_2(sa) || sa < 0x100000 || 452 j) == 0) {
381 sa > 0xffffffffu) { 453 j++;
382 printk(KERN_WARNING "%s: Resource out of range\n", 454
383 hose->dn->full_name); 455 /* If the resource PCI address is 0 then we have our
384 continue; 456 * ISA memory hole
457 */
458 if (res->start == hose->pci_mem_offset)
459 found_isa_hole = 1;
385 } 460 }
386 sa = (0xffffffffu << ilog2(sa)) | 0x1;
387
388 /* Program register values */
389 if (j == 0) {
390 writel(lah, reg + PCIX0_POM0LAH);
391 writel(lal, reg + PCIX0_POM0LAL);
392 writel(pciah, reg + PCIX0_POM0PCIAH);
393 writel(pcial, reg + PCIX0_POM0PCIAL);
394 writel(sa, reg + PCIX0_POM0SA);
395 } else {
396 writel(lah, reg + PCIX0_POM1LAH);
397 writel(lal, reg + PCIX0_POM1LAL);
398 writel(pciah, reg + PCIX0_POM1PCIAH);
399 writel(pcial, reg + PCIX0_POM1PCIAL);
400 writel(sa, reg + PCIX0_POM1SA);
401 }
402 j++;
403 } 461 }
462
463 /* Handle ISA memory hole if not already covered */
464 if (j <= 1 && !found_isa_hole && hose->isa_mem_size)
465 if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0,
466 hose->isa_mem_size, 0, j) == 0)
467 printk(KERN_INFO "%s: Legacy ISA memory support enabled\n",
468 hose->dn->full_name);
404} 469}
405 470
406static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, 471static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose,
@@ -1317,12 +1382,72 @@ static struct pci_ops ppc4xx_pciex_pci_ops =
1317 .write = ppc4xx_pciex_write_config, 1382 .write = ppc4xx_pciex_write_config,
1318}; 1383};
1319 1384
1385static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port,
1386 struct pci_controller *hose,
1387 void __iomem *mbase,
1388 u64 plb_addr,
1389 u64 pci_addr,
1390 u64 size,
1391 unsigned int flags,
1392 int index)
1393{
1394 u32 lah, lal, pciah, pcial, sa;
1395
1396 if (!is_power_of_2(size) ||
1397 (index < 2 && size < 0x100000) ||
1398 (index == 2 && size < 0x100) ||
1399 (plb_addr & (size - 1)) != 0) {
1400 printk(KERN_WARNING "%s: Resource out of range\n",
1401 hose->dn->full_name);
1402 return -1;
1403 }
1404
1405 /* Calculate register values */
1406 lah = RES_TO_U32_HIGH(plb_addr);
1407 lal = RES_TO_U32_LOW(plb_addr);
1408 pciah = RES_TO_U32_HIGH(pci_addr);
1409 pcial = RES_TO_U32_LOW(pci_addr);
1410 sa = (0xffffffffu << ilog2(size)) | 0x1;
1411
1412 /* Program register values */
1413 switch (index) {
1414 case 0:
1415 out_le32(mbase + PECFG_POM0LAH, pciah);
1416 out_le32(mbase + PECFG_POM0LAL, pcial);
1417 dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah);
1418 dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal);
1419 dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff);
1420 /* Note that 3 here means enabled | single region */
1421 dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3);
1422 break;
1423 case 1:
1424 out_le32(mbase + PECFG_POM1LAH, pciah);
1425 out_le32(mbase + PECFG_POM1LAL, pcial);
1426 dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah);
1427 dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal);
1428 dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff);
1429 /* Note that 3 here means enabled | single region */
1430 dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3);
1431 break;
1432 case 2:
1433 out_le32(mbase + PECFG_POM2LAH, pciah);
1434 out_le32(mbase + PECFG_POM2LAL, pcial);
1435 dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah);
1436 dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal);
1437 dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff);
1438 /* Note that 3 here means enabled | IO space !!! */
1439 dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3);
1440 break;
1441 }
1442
1443 return 0;
1444}
1445
1320static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, 1446static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
1321 struct pci_controller *hose, 1447 struct pci_controller *hose,
1322 void __iomem *mbase) 1448 void __iomem *mbase)
1323{ 1449{
1324 u32 lah, lal, pciah, pcial, sa; 1450 int i, j, found_isa_hole = 0;
1325 int i, j;
1326 1451
1327 /* Setup outbound memory windows */ 1452 /* Setup outbound memory windows */
1328 for (i = j = 0; i < 3; i++) { 1453 for (i = j = 0; i < 3; i++) {
@@ -1337,53 +1462,38 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
1337 break; 1462 break;
1338 } 1463 }
1339 1464
1340 /* Calculate register values */ 1465 /* Configure the resource */
1341 lah = RES_TO_U32_HIGH(res->start); 1466 if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
1342 lal = RES_TO_U32_LOW(res->start); 1467 res->start,
1343 pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); 1468 res->start - hose->pci_mem_offset,
1344 pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); 1469 res->end + 1 - res->start,
1345 sa = res->end + 1 - res->start; 1470 res->flags,
1346 if (!is_power_of_2(sa) || sa < 0x100000 || 1471 j) == 0) {
1347 sa > 0xffffffffu) { 1472 j++;
1348 printk(KERN_WARNING "%s: Resource out of range\n", 1473
1349 port->node->full_name); 1474 /* If the resource PCI address is 0 then we have our
1350 continue; 1475 * ISA memory hole
1351 } 1476 */
1352 sa = (0xffffffffu << ilog2(sa)) | 0x1; 1477 if (res->start == hose->pci_mem_offset)
1353 1478 found_isa_hole = 1;
1354 /* Program register values */
1355 switch (j) {
1356 case 0:
1357 out_le32(mbase + PECFG_POM0LAH, pciah);
1358 out_le32(mbase + PECFG_POM0LAL, pcial);
1359 dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah);
1360 dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal);
1361 dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff);
1362 dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3);
1363 break;
1364 case 1:
1365 out_le32(mbase + PECFG_POM1LAH, pciah);
1366 out_le32(mbase + PECFG_POM1LAL, pcial);
1367 dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah);
1368 dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal);
1369 dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff);
1370 dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3);
1371 break;
1372 } 1479 }
1373 j++;
1374 } 1480 }
1375 1481
1376 /* Configure IO, always 64K starting at 0 */ 1482 /* Handle ISA memory hole if not already covered */
1377 if (hose->io_resource.flags & IORESOURCE_IO) { 1483 if (j <= 1 && !found_isa_hole && hose->isa_mem_size)
1378 lah = RES_TO_U32_HIGH(hose->io_base_phys); 1484 if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
1379 lal = RES_TO_U32_LOW(hose->io_base_phys); 1485 hose->isa_mem_phys, 0,
1380 out_le32(mbase + PECFG_POM2LAH, 0); 1486 hose->isa_mem_size, 0, j) == 0)
1381 out_le32(mbase + PECFG_POM2LAL, 0); 1487 printk(KERN_INFO "%s: Legacy ISA memory support enabled\n",
1382 dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); 1488 hose->dn->full_name);
1383 dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); 1489
1384 dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); 1490 /* Configure IO, always 64K starting at 0. We hard wire it to 64K !
1385 dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3); 1491 * Note also that it -has- to be region index 2 on this HW
1386 } 1492 */
1493 if (hose->io_resource.flags & IORESOURCE_IO)
1494 ppc4xx_setup_one_pciex_POM(port, hose, mbase,
1495 hose->io_base_phys, 0,
1496 0x10000, IORESOURCE_IO, 2);
1387} 1497}
1388 1498
1389static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, 1499static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,