diff options
| author | Stefan Roese <sr@denx.de> | 2008-04-21 10:54:30 -0400 |
|---|---|---|
| committer | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2008-05-06 13:10:43 -0400 |
| commit | 80daac3f86d4f5aafc9d3e79addb90fa118244e2 (patch) | |
| tree | 06d914e7efffd6965eaa5d552f334c50b600c14a | |
| parent | a96df496ed1496f3e52a9b3c860cf967aa48adda (diff) | |
[POWERPC] 4xx: Add endpoint support to 4xx PCIe driver
This patch adds basic endpoint support to the 4xx PCIe driver.
This is done by checking the device_type property of the PCIe
device node ("pci" for root-complex and "pci-endpoint" for endpoint
configuration).
Note: Currently we map a fixed 64MByte window to PLB address 0 (SDRAM).
This should probably be configurable via a dts property.
Signed-off-by: Stefan Roese <sr@denx.de>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
| -rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 180 |
1 files changed, 131 insertions, 49 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 1814adbd2236..b4a54c52e880 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c | |||
| @@ -1387,28 +1387,59 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, | |||
| 1387 | resource_size_t size = res->end - res->start + 1; | 1387 | resource_size_t size = res->end - res->start + 1; |
| 1388 | u64 sa; | 1388 | u64 sa; |
| 1389 | 1389 | ||
| 1390 | /* Calculate window size */ | 1390 | if (port->endpoint) { |
| 1391 | sa = (0xffffffffffffffffull << ilog2(size));; | 1391 | resource_size_t ep_addr = 0; |
| 1392 | if (res->flags & IORESOURCE_PREFETCH) | 1392 | resource_size_t ep_size = 32 << 20; |
| 1393 | sa |= 0x8; | 1393 | |
| 1394 | /* Currently we map a fixed 64MByte window to PLB address | ||
| 1395 | * 0 (SDRAM). This should probably be configurable via a dts | ||
| 1396 | * property. | ||
| 1397 | */ | ||
| 1398 | |||
| 1399 | /* Calculate window size */ | ||
| 1400 | sa = (0xffffffffffffffffull << ilog2(ep_size));; | ||
| 1401 | |||
| 1402 | /* Setup BAR0 */ | ||
| 1403 | out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); | ||
| 1404 | out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa) | | ||
| 1405 | PCI_BASE_ADDRESS_MEM_TYPE_64); | ||
| 1394 | 1406 | ||
| 1395 | out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); | 1407 | /* Disable BAR1 & BAR2 */ |
| 1396 | out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); | 1408 | out_le32(mbase + PECFG_BAR1MPA, 0); |
| 1409 | out_le32(mbase + PECFG_BAR2HMPA, 0); | ||
| 1410 | out_le32(mbase + PECFG_BAR2LMPA, 0); | ||
| 1397 | 1411 | ||
| 1398 | /* The setup of the split looks weird to me ... let's see if it works */ | 1412 | out_le32(mbase + PECFG_PIM01SAH, RES_TO_U32_HIGH(sa)); |
| 1399 | out_le32(mbase + PECFG_PIM0LAL, 0x00000000); | 1413 | out_le32(mbase + PECFG_PIM01SAL, RES_TO_U32_LOW(sa)); |
| 1400 | out_le32(mbase + PECFG_PIM0LAH, 0x00000000); | 1414 | |
| 1401 | out_le32(mbase + PECFG_PIM1LAL, 0x00000000); | 1415 | out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(ep_addr)); |
| 1402 | out_le32(mbase + PECFG_PIM1LAH, 0x00000000); | 1416 | out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr)); |
| 1403 | out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); | 1417 | } else { |
| 1404 | out_le32(mbase + PECFG_PIM01SAL, 0x00000000); | 1418 | /* Calculate window size */ |
| 1419 | sa = (0xffffffffffffffffull << ilog2(size));; | ||
| 1420 | if (res->flags & IORESOURCE_PREFETCH) | ||
| 1421 | sa |= 0x8; | ||
| 1422 | |||
| 1423 | out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); | ||
| 1424 | out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); | ||
| 1425 | |||
| 1426 | /* The setup of the split looks weird to me ... let's see | ||
| 1427 | * if it works | ||
| 1428 | */ | ||
| 1429 | out_le32(mbase + PECFG_PIM0LAL, 0x00000000); | ||
| 1430 | out_le32(mbase + PECFG_PIM0LAH, 0x00000000); | ||
| 1431 | out_le32(mbase + PECFG_PIM1LAL, 0x00000000); | ||
| 1432 | out_le32(mbase + PECFG_PIM1LAH, 0x00000000); | ||
| 1433 | out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); | ||
| 1434 | out_le32(mbase + PECFG_PIM01SAL, 0x00000000); | ||
| 1435 | |||
| 1436 | out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start)); | ||
| 1437 | out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start)); | ||
| 1438 | } | ||
| 1405 | 1439 | ||
| 1406 | /* Enable inbound mapping */ | 1440 | /* Enable inbound mapping */ |
| 1407 | out_le32(mbase + PECFG_PIMEN, 0x1); | 1441 | out_le32(mbase + PECFG_PIMEN, 0x1); |
| 1408 | 1442 | ||
| 1409 | out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start)); | ||
| 1410 | out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start)); | ||
| 1411 | |||
| 1412 | /* Enable I/O, Mem, and Busmaster cycles */ | 1443 | /* Enable I/O, Mem, and Busmaster cycles */ |
| 1413 | out_le16(mbase + PCI_COMMAND, | 1444 | out_le16(mbase + PCI_COMMAND, |
| 1414 | in_le16(mbase + PCI_COMMAND) | | 1445 | in_le16(mbase + PCI_COMMAND) | |
| @@ -1422,13 +1453,8 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | |||
| 1422 | const int *bus_range; | 1453 | const int *bus_range; |
| 1423 | int primary = 0, busses; | 1454 | int primary = 0, busses; |
| 1424 | void __iomem *mbase = NULL, *cfg_data = NULL; | 1455 | void __iomem *mbase = NULL, *cfg_data = NULL; |
| 1425 | 1456 | const u32 *pval; | |
| 1426 | /* XXX FIXME: Handle endpoint mode properly */ | 1457 | u32 val; |
| 1427 | if (port->endpoint) { | ||
| 1428 | printk(KERN_WARNING "PCIE%d: Port in endpoint mode !\n", | ||
| 1429 | port->index); | ||
| 1430 | return; | ||
| 1431 | } | ||
| 1432 | 1458 | ||
| 1433 | /* Check if primary bridge */ | 1459 | /* Check if primary bridge */ |
| 1434 | if (of_get_property(port->node, "primary", NULL)) | 1460 | if (of_get_property(port->node, "primary", NULL)) |
| @@ -1462,21 +1488,30 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | |||
| 1462 | hose->last_busno = hose->first_busno + busses; | 1488 | hose->last_busno = hose->first_busno + busses; |
| 1463 | } | 1489 | } |
| 1464 | 1490 | ||
| 1465 | /* We map the external config space in cfg_data and the host config | 1491 | if (!port->endpoint) { |
| 1466 | * space in cfg_addr. External space is 1M per bus, internal space | 1492 | /* Only map the external config space in cfg_data for |
| 1467 | * is 4K | 1493 | * PCIe root-complexes. External space is 1M per bus |
| 1494 | */ | ||
| 1495 | cfg_data = ioremap(port->cfg_space.start + | ||
| 1496 | (hose->first_busno + 1) * 0x100000, | ||
| 1497 | busses * 0x100000); | ||
| 1498 | if (cfg_data == NULL) { | ||
| 1499 | printk(KERN_ERR "%s: Can't map external config space !", | ||
| 1500 | port->node->full_name); | ||
| 1501 | goto fail; | ||
| 1502 | } | ||
| 1503 | hose->cfg_data = cfg_data; | ||
| 1504 | } | ||
| 1505 | |||
| 1506 | /* Always map the host config space in cfg_addr. | ||
| 1507 | * Internal space is 4K | ||
| 1468 | */ | 1508 | */ |
| 1469 | cfg_data = ioremap(port->cfg_space.start + | ||
| 1470 | (hose->first_busno + 1) * 0x100000, | ||
| 1471 | busses * 0x100000); | ||
| 1472 | mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); | 1509 | mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); |
| 1473 | if (cfg_data == NULL || mbase == NULL) { | 1510 | if (mbase == NULL) { |
| 1474 | printk(KERN_ERR "%s: Can't map config space !", | 1511 | printk(KERN_ERR "%s: Can't map internal config space !", |
| 1475 | port->node->full_name); | 1512 | port->node->full_name); |
| 1476 | goto fail; | 1513 | goto fail; |
| 1477 | } | 1514 | } |
| 1478 | |||
| 1479 | hose->cfg_data = cfg_data; | ||
| 1480 | hose->cfg_addr = mbase; | 1515 | hose->cfg_addr = mbase; |
| 1481 | 1516 | ||
| 1482 | pr_debug("PCIE %s, bus %d..%d\n", port->node->full_name, | 1517 | pr_debug("PCIE %s, bus %d..%d\n", port->node->full_name, |
| @@ -1489,12 +1524,14 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | |||
| 1489 | port->hose = hose; | 1524 | port->hose = hose; |
| 1490 | mbase = (void __iomem *)hose->cfg_addr; | 1525 | mbase = (void __iomem *)hose->cfg_addr; |
| 1491 | 1526 | ||
| 1492 | /* | 1527 | if (!port->endpoint) { |
| 1493 | * Set bus numbers on our root port | 1528 | /* |
| 1494 | */ | 1529 | * Set bus numbers on our root port |
| 1495 | out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); | 1530 | */ |
| 1496 | out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); | 1531 | out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); |
| 1497 | out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); | 1532 | out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); |
| 1533 | out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); | ||
| 1534 | } | ||
| 1498 | 1535 | ||
| 1499 | /* | 1536 | /* |
| 1500 | * OMRs are already reset, also disable PIMs | 1537 | * OMRs are already reset, also disable PIMs |
| @@ -1515,17 +1552,49 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | |||
| 1515 | ppc4xx_configure_pciex_PIMs(port, hose, mbase, &dma_window); | 1552 | ppc4xx_configure_pciex_PIMs(port, hose, mbase, &dma_window); |
| 1516 | 1553 | ||
| 1517 | /* The root complex doesn't show up if we don't set some vendor | 1554 | /* The root complex doesn't show up if we don't set some vendor |
| 1518 | * and device IDs into it. Those are the same bogus one that the | 1555 | * and device IDs into it. The defaults below are the same bogus |
| 1519 | * initial code in arch/ppc add. We might want to change that. | 1556 | * one that the initial code in arch/ppc had. This can be |
| 1557 | * overwritten by setting the "vendor-id/device-id" properties | ||
| 1558 | * in the pciex node. | ||
| 1520 | */ | 1559 | */ |
| 1521 | out_le16(mbase + 0x200, 0xaaa0 + port->index); | ||
| 1522 | out_le16(mbase + 0x202, 0xbed0 + port->index); | ||
| 1523 | 1560 | ||
| 1524 | /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ | 1561 | /* Get the (optional) vendor-/device-id from the device-tree */ |
| 1525 | out_le32(mbase + 0x208, 0x06040001); | 1562 | pval = of_get_property(port->node, "vendor-id", NULL); |
| 1563 | if (pval) { | ||
| 1564 | val = *pval; | ||
| 1565 | } else { | ||
| 1566 | if (!port->endpoint) | ||
| 1567 | val = 0xaaa0 + port->index; | ||
| 1568 | else | ||
| 1569 | val = 0xeee0 + port->index; | ||
| 1570 | } | ||
| 1571 | out_le16(mbase + 0x200, val); | ||
| 1572 | |||
| 1573 | pval = of_get_property(port->node, "device-id", NULL); | ||
| 1574 | if (pval) { | ||
| 1575 | val = *pval; | ||
| 1576 | } else { | ||
| 1577 | if (!port->endpoint) | ||
| 1578 | val = 0xbed0 + port->index; | ||
| 1579 | else | ||
| 1580 | val = 0xfed0 + port->index; | ||
| 1581 | } | ||
| 1582 | out_le16(mbase + 0x202, val); | ||
| 1583 | |||
| 1584 | if (!port->endpoint) { | ||
| 1585 | /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ | ||
| 1586 | out_le32(mbase + 0x208, 0x06040001); | ||
| 1587 | |||
| 1588 | printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", | ||
| 1589 | port->index); | ||
| 1590 | } else { | ||
| 1591 | /* Set Class Code to Processor/PPC */ | ||
| 1592 | out_le32(mbase + 0x208, 0x0b200001); | ||
| 1593 | |||
| 1594 | printk(KERN_INFO "PCIE%d: successfully set as endpoint\n", | ||
| 1595 | port->index); | ||
| 1596 | } | ||
| 1526 | 1597 | ||
| 1527 | printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", | ||
| 1528 | port->index); | ||
| 1529 | return; | 1598 | return; |
| 1530 | fail: | 1599 | fail: |
| 1531 | if (hose) | 1600 | if (hose) |
| @@ -1542,6 +1611,7 @@ static void __init ppc4xx_probe_pciex_bridge(struct device_node *np) | |||
| 1542 | const u32 *pval; | 1611 | const u32 *pval; |
| 1543 | int portno; | 1612 | int portno; |
| 1544 | unsigned int dcrs; | 1613 | unsigned int dcrs; |
| 1614 | const char *val; | ||
| 1545 | 1615 | ||
| 1546 | /* First, proceed to core initialization as we assume there's | 1616 | /* First, proceed to core initialization as we assume there's |
| 1547 | * only one PCIe core in the system | 1617 | * only one PCIe core in the system |
| @@ -1573,8 +1643,20 @@ static void __init ppc4xx_probe_pciex_bridge(struct device_node *np) | |||
| 1573 | } | 1643 | } |
| 1574 | port->sdr_base = *pval; | 1644 | port->sdr_base = *pval; |
| 1575 | 1645 | ||
| 1576 | /* XXX Currently, we only support root complex mode */ | 1646 | /* Check if device_type property is set to "pci" or "pci-endpoint". |
| 1577 | port->endpoint = 0; | 1647 | * Resulting from this setup this PCIe port will be configured |
| 1648 | * as root-complex or as endpoint. | ||
| 1649 | */ | ||
| 1650 | val = of_get_property(port->node, "device_type", NULL); | ||
| 1651 | if (!strcmp(val, "pci-endpoint")) { | ||
| 1652 | port->endpoint = 1; | ||
| 1653 | } else if (!strcmp(val, "pci")) { | ||
| 1654 | port->endpoint = 0; | ||
| 1655 | } else { | ||
| 1656 | printk(KERN_ERR "PCIE: missing or incorrect device_type for %s\n", | ||
| 1657 | np->full_name); | ||
| 1658 | return; | ||
| 1659 | } | ||
| 1578 | 1660 | ||
| 1579 | /* Fetch config space registers address */ | 1661 | /* Fetch config space registers address */ |
| 1580 | if (of_address_to_resource(np, 0, &port->cfg_space)) { | 1662 | if (of_address_to_resource(np, 0, &port->cfg_space)) { |
