/* * PCI / PCI-X / PCI-Express support for 4xx parts * * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. * * Most PCI Express code is coming from Stefan Roese implementation for * arch/ppc in the Denx tree, slightly reworked by me. * * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de> * * Some of that comes itself from a previous implementation for 440SPE only * by Roland Dreier: * * Copyright (c) 2005 Cisco Systems. All rights reserved. * Roland Dreier <rolandd@cisco.com> *
*/
staticinlineint ppc440spe_revA(void)
{ /* Catch both 440SPe variants, with and without RAID6 support */ if ((mfspr(SPRN_PVR) & 0xffefffff) == 0x53421890) return 1; else return 0;
}
/* Hide the PCI host BARs from the kernel as their content doesn't * fit well in the resource management
*/
pci_dev_for_each_resource(dev, r) {
r->start = r->end = 0;
r->flags = 0;
}
if (cpu_addr == OF_BAD_ADDR || size == 0) continue;
/* We only care about memory */ if ((pci_space & 0x03000000) != 0x02000000) continue;
/* We currently only support memory at 0, and pci_addr * within 32 bits space
*/ if (cpu_addr != 0 || pci_addr > 0xffffffff) {
printk(KERN_WARNING "%pOF: Ignored unsupported dma range" " 0x%016llx...0x%016llx -> 0x%016llx\n",
hose->dn,
pci_addr, pci_addr + size - 1, cpu_addr); continue;
}
/* Check if not prefetchable */ if (!(pci_space & 0x40000000))
res->flags &= ~IORESOURCE_PREFETCH;
/* Use that */
res->start = pci_addr; /* Beware of 32 bits resources */ if (sizeof(resource_size_t) == sizeof(u32) &&
(pci_addr + size) > 0x100000000ull)
res->end = 0xffffffff; else
res->end = res->start + size - 1; break;
}
/* We only support one global DMA offset */ if (dma_offset_set && pci_dram_offset != res->start) {
printk(KERN_ERR "%pOF: dma-ranges(s) mismatch\n", hose->dn); return -ENXIO;
}
/* Check that we can fit all of memory as we don't support * DMA bounce buffers
*/ if (size < total_memory) {
printk(KERN_ERR "%pOF: dma-ranges too small " "(size=%llx total_memory=%llx)\n",
hose->dn, size, (u64)total_memory); return -ENXIO;
}
/* Check we are a power of 2 size and that base is a multiple of size*/ if ((size & (size - 1)) != 0 ||
(res->start & (size - 1)) != 0) {
printk(KERN_ERR "%pOF: dma-ranges unaligned\n", hose->dn); return -ENXIO;
}
/* Check that we are fully contained within 32 bits space if we are not * running on a 460sx or 476fpe which have 64 bit bus addresses.
*/ if (res->end > 0xffffffff &&
!(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx")
|| of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) {
printk(KERN_ERR "%pOF: dma-ranges outside of 32 bits space\n",
hose->dn); return -ENXIO;
}
out:
dma_offset_set = 1;
pci_dram_offset = res->start;
hose->dma_window_base_cur = res->start;
hose->dma_window_size = resource_size(res);
printk(KERN_INFO "4xx PCI DMA offset set to 0x%08lx\n",
pci_dram_offset);
printk(KERN_INFO "4xx PCI DMA window base to 0x%016llx\n",
(unsignedlonglong)hose->dma_window_base_cur);
printk(KERN_INFO "DMA window size 0x%016llx\n",
(unsignedlonglong)hose->dma_window_size); return 0;
}
/* Hack warning ! The "old" PCI 2.x cell only let us configure the low * 32-bit of incoming PLB addresses. The top 4 bits of the 36-bit * address are actually hard wired to a value that appears to depend * on the specific SoC. For example, it's 0 on 440EP and 1 on 440EPx. * * The trick here is we just crop those top bits and ignore them when * programming the chip. That means the device-tree has to be right * for the specific part used (we don't print a warning if it's wrong * but on the other hand, you'll crash quickly enough), but at least * this code should work whatever the hard coded value is
*/
plb_addr &= 0xffffffffull;
/* Note: Due to the above hack, the test below doesn't actually test * if you address is above 4G, but it tests that address and * (address + size) are both contained in the same 4G
*/ if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) ||
size < 0x1000 || (plb_addr & (size - 1)) != 0) {
printk(KERN_WARNING "%pOF: Resource out of range\n", hose->dn); return -1;
}
ma = (0xffffffffu << ilog2(size)) | 1; if (flags & IORESOURCE_PREFETCH)
ma |= 2;
staticvoid __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, void __iomem *reg)
{ int i, j, found_isa_hole = 0;
/* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { struct resource *res = &hose->mem_resources[i];
resource_size_t offset = hose->mem_offset[i];
/* we only care about memory windows */ if (!(res->flags & IORESOURCE_MEM)) continue; if (j > 2) {
printk(KERN_WARNING "%pOF: Too many ranges\n", hose->dn); break;
}
/* Configure the resource */ if (ppc4xx_setup_one_pci_PMM(hose, reg,
res->start,
res->start - offset,
resource_size(res),
res->flags,
j) == 0) {
j++;
/* If the resource PCI address is 0 then we have our * ISA memory hole
*/ if (res->start == offset)
found_isa_hole = 1;
}
}
/* Handle ISA memory hole if not already covered */ if (j <= 2 && !found_isa_hole && hose->isa_mem_size) if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0,
hose->isa_mem_size, 0, j) == 0)
printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n",
hose->dn);
}
staticvoid __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, void __iomem *reg)
{ int i, j, found_isa_hole = 0;
/* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { struct resource *res = &hose->mem_resources[i];
resource_size_t offset = hose->mem_offset[i];
/* we only care about memory windows */ if (!(res->flags & IORESOURCE_MEM)) continue; if (j > 1) {
printk(KERN_WARNING "%pOF: Too many ranges\n", hose->dn); break;
}
/* Configure the resource */ if (ppc4xx_setup_one_pcix_POM(hose, reg,
res->start,
res->start - offset,
resource_size(res),
res->flags,
j) == 0) {
j++;
/* If the resource PCI address is 0 then we have our * ISA memory hole
*/ if (res->start == offset)
found_isa_hole = 1;
}
}
/* Handle ISA memory hole if not already covered */ if (j <= 1 && !found_isa_hole && hose->isa_mem_size) if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0,
hose->isa_mem_size, 0, j) == 0)
printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n",
hose->dn);
}
/* We don't need the registers anymore */
iounmap(reg); return;
fail: if (hose)
pcibios_free_controller(hose); if (reg)
iounmap(reg);
}
#ifdef CONFIG_PPC4xx_PCI_EXPRESS
/* * 4xx PCI-Express part * * We support 3 parts currently based on the compatible property: * * ibm,plb-pciex-440spe * ibm,plb-pciex-405ex * ibm,plb-pciex-460ex * * Anything else will be rejected for now as they are all subtly * different unfortunately. *
*/
/* Check for card presence detect if supported, if not, just wait for * link unconditionally. * * note that we don't fail if there is no link, we just filter out * config space accesses. That way, it will be easier to implement * hotplug later on.
*/ if (!port->has_ibpre ||
!ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
1 << 28, 1 << 28, 100)) {
printk(KERN_INFO "PCIE%d: Device detected, waiting for link...\n",
port->index); if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
0x1000, 0x1000, 2000))
printk(KERN_WARNING "PCIE%d: Link up failed\n", port->index); else {
printk(KERN_INFO "PCIE%d: link is up !\n", port->index);
port->link = 1;
}
} else
printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
}
#ifdef CONFIG_44x
/* Check various reset bits of the 440SPe PCIe core */ staticint __init ppc440spe_pciex_check_reset(struct device_node *np)
{
u32 valPE0, valPE1, valPE2; int err = 0;
/* SDR0_PEGPLLLCT1 reset */ if (!(mfdcri(SDR0, PESDR0_PLLLCT1) & 0x01000000)) { /* * the PCIe core was probably already initialised * by firmware - let's re-reset RCSSET regs * * -- Shouldn't we also re-reset the whole thing ? -- BenH
*/
pr_debug("PCIE: SDR0_PLLLCT1 already reset.\n");
mtdcri(SDR0, PESDR0_440SPE_RCSSET, 0x01010000);
mtdcri(SDR0, PESDR1_440SPE_RCSSET, 0x01010000);
mtdcri(SDR0, PESDR2_440SPE_RCSSET, 0x01010000);
}
staticint __init ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
{ int rc = ppc440spe_pciex_init_port_hw(port);
port->has_ibpre = 1;
return rc;
}
staticint ppc440speA_pciex_init_utl(struct ppc4xx_pciex_port *port)
{ /* XXX Check what that value means... I hate magic */
dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x68782800);
/* * Do a software reset on PCIe ports. * This code is to fix the issue that pci drivers doesn't re-assign * bus number for PCIE devices after Uboot * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000 * PT quad port, SAS LSI 1064E)
*/
/* * If bifurcation is not enabled, u-boot would have disabled the * third PCIe port
*/ if (((mfdcri(SDR0, PESDR1_460SX_HSSCTLSET) & 0x00000001) ==
0x00000001)) {
printk(KERN_INFO "PCI: PCIE bifurcation setup successfully.\n");
printk(KERN_INFO "PCI: Total 3 PCIE ports are present\n"); return 3;
}
printk(KERN_INFO "PCI: Total 2 PCIE ports are present\n"); return 2;
}
if (mbase == NULL) {
printk(KERN_WARNING "PCIE%d: failed to get cfg space\n",
port->index); return;
}
while (timeout_ms--) {
val = in_le32(mbase + PECFG_TLDLP);
if ((val & mask) == mask) break;
msleep(10);
}
if (val & PECFG_TLDLP_PRESENT) {
printk(KERN_INFO "PCIE%d: link is up !\n", port->index);
port->link = 1;
} else
printk(KERN_WARNING "PCIE%d: Link up failed\n", port->index);
/* Check that the core has been initied and if not, do it */ staticint __init ppc4xx_pciex_check_core_init(struct device_node *np)
{ staticint core_init; int count = -ENODEV;
if (core_init++) return 0;
#ifdef CONFIG_44x if (of_device_is_compatible(np, "ibm,plb-pciex-440spe")) { if (ppc440spe_revA())
ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops; else
ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops;
} if (of_device_is_compatible(np, "ibm,plb-pciex-460ex"))
ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops; if (of_device_is_compatible(np, "ibm,plb-pciex-460sx"))
ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops; if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx"))
ppc4xx_pciex_hwops = &apm821xx_pcie_hwops; #endif/* CONFIG_44x */ #ifdef CONFIG_476FPE if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe")
|| of_device_is_compatible(np, "ibm,plb-pciex-476gtr"))
ppc4xx_pciex_hwops = &ppc_476fpe_pcie_hwops; #endif if (ppc4xx_pciex_hwops == NULL) {
printk(KERN_WARNING "PCIE: unknown host type %pOF\n", np); return -ENODEV;
}
staticvoid __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port)
{ /* We map PCI Express configuration based on the reg property */
dcr_write(port->dcrs, DCRO_PEGPL_CFGBAH,
RES_TO_U32_HIGH(port->cfg_space.start));
dcr_write(port->dcrs, DCRO_PEGPL_CFGBAL,
RES_TO_U32_LOW(port->cfg_space.start));
/* XXX FIXME: Use size from reg property. For now, map 512M */
dcr_write(port->dcrs, DCRO_PEGPL_CFGMSK, 0xe0000001);
/* We map UTL registers based on the reg property */
dcr_write(port->dcrs, DCRO_PEGPL_REGBAH,
RES_TO_U32_HIGH(port->utl_regs.start));
dcr_write(port->dcrs, DCRO_PEGPL_REGBAL,
RES_TO_U32_LOW(port->utl_regs.start));
/* XXX FIXME: Use size from reg property */
dcr_write(port->dcrs, DCRO_PEGPL_REGMSK, 0x00007001);
/* Disable all other outbound windows */
dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 0);
dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, 0);
dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0);
dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0);
}
staticint __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
{ int rc = 0;
/* Init HW */ if (ppc4xx_pciex_hwops->port_init_hw)
rc = ppc4xx_pciex_hwops->port_init_hw(port); if (rc != 0) return rc;
/* * Initialize mapping: disable all regions and configure * CFG and REG regions based on resources in the device tree
*/
ppc4xx_pciex_port_init_mapping(port);
if (ppc4xx_pciex_hwops->check_link)
ppc4xx_pciex_hwops->check_link(port);
/* Endpoint can not generate upstream(remote) config cycles */ if (port->endpoint && bus->number != port->hose->first_busno) return PCIBIOS_DEVICE_NOT_FOUND;
/* Check we are within the mapped range */ if (bus->number > port->hose->last_busno) { if (!message) {
printk(KERN_WARNING "Warning! Probing bus %u" " out of range !\n", bus->number);
message++;
} return PCIBIOS_DEVICE_NOT_FOUND;
}
/* The root complex has only one device / function */ if (bus->number == port->hose->first_busno && devfn != 0) return PCIBIOS_DEVICE_NOT_FOUND;
/* The other side of the RC has only one device as well */ if (bus->number == (port->hose->first_busno + 1) &&
PCI_SLOT(devfn) != 0) return PCIBIOS_DEVICE_NOT_FOUND;
/* Check if we have a link */ if ((bus->number != port->hose->first_busno) && !port->link) return PCIBIOS_DEVICE_NOT_FOUND;
/* Remove the casts when we finally remove the stupid volatile * in struct pci_controller
*/ if (bus->number == port->hose->first_busno) return (void __iomem *)port->hose->cfg_addr;
/* * Reading from configuration space of non-existing device can * generate transaction errors. For the read duration we suppress * assertion of machine check exceptions to avoid those.
*/
gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG);
dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA);
/* Make sure no CRS is recorded */
out_be32(port->utl_base + PEUTL_RCSTA, 0x00040000);
/* Check for CRS (440SPe rev B does that for us but heh ..) */ if (in_be32(port->utl_base + PEUTL_RCSTA) & 0x00040000) {
pr_debug("Got CRS !\n"); if (len != 4 || offset != 0) return PCIBIOS_DEVICE_NOT_FOUND;
*val = 0xffff0001;
}
/* * Reading from configuration space of non-existing device can * generate transaction errors. For the read duration we suppress * assertion of machine check exceptions to avoid those.
*/
gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG);
dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA);
/* Program register values */ switch (index) { case 0:
out_le32(mbase + PECFG_POM0LAH, pciah);
out_le32(mbase + PECFG_POM0LAL, pcial);
dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah);
dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal);
dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); /*Enabled and single region */ if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx"))
dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT
| DCRO_PEGPL_OMRxMSKL_VAL); elseif (of_device_is_compatible(
port->node, "ibm,plb-pciex-476fpe") ||
of_device_is_compatible(
port->node, "ibm,plb-pciex-476gtr"))
dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
sa | DCRO_PEGPL_476FPE_OMR1MSKL_UOT
| DCRO_PEGPL_OMRxMSKL_VAL); else
dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
sa | DCRO_PEGPL_OMR1MSKL_UOT
| DCRO_PEGPL_OMRxMSKL_VAL); break; case 1:
out_le32(mbase + PECFG_POM1LAH, pciah);
out_le32(mbase + PECFG_POM1LAL, pcial);
dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah);
dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal);
dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff);
dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL,
sa | DCRO_PEGPL_OMRxMSKL_VAL); break; case 2:
out_le32(mbase + PECFG_POM2LAH, pciah);
out_le32(mbase + PECFG_POM2LAL, pcial);
dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah);
dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal);
dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); /* Note that 3 here means enabled | IO space !!! */
dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL,
sa | DCRO_PEGPL_OMR3MSKL_IO
| DCRO_PEGPL_OMRxMSKL_VAL); break;
}
return 0;
}
staticvoid __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, struct pci_controller *hose, void __iomem *mbase)
{ int i, j, found_isa_hole = 0;
/* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { struct resource *res = &hose->mem_resources[i];
resource_size_t offset = hose->mem_offset[i];
/* we only care about memory windows */ if (!(res->flags & IORESOURCE_MEM)) continue; if (j > 1) {
printk(KERN_WARNING "%pOF: Too many ranges\n",
port->node); break;
}
/* Configure the resource */ if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
res->start,
res->start - offset,
resource_size(res),
res->flags,
j) == 0) {
j++;
/* If the resource PCI address is 0 then we have our * ISA memory hole
*/ if (res->start == offset)
found_isa_hole = 1;
}
}
/* Handle ISA memory hole if not already covered */ if (j <= 1 && !found_isa_hole && hose->isa_mem_size) if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
hose->isa_mem_phys, 0,
hose->isa_mem_size, 0, j) == 0)
printk(KERN_INFO "%pOF: Legacy ISA memory support enabled\n",
hose->dn);
/* Configure IO, always 64K starting at 0. We hard wire it to 64K ! * Note also that it -has- to be region index 2 on this HW
*/ if (hose->io_resource.flags & IORESOURCE_IO)
ppc4xx_setup_one_pciex_POM(port, hose, mbase,
hose->io_base_phys, 0,
0x10000, IORESOURCE_IO, 2);
}
/* The setup of the split looks weird to me ... let's see * if it works
*/
out_le32(mbase + PECFG_PIM0LAL, 0x00000000);
out_le32(mbase + PECFG_PIM0LAH, 0x00000000);
out_le32(mbase + PECFG_PIM1LAL, 0x00000000);
out_le32(mbase + PECFG_PIM1LAH, 0x00000000);
out_le32(mbase + PECFG_PIM01SAH, 0xffff0000);
out_le32(mbase + PECFG_PIM01SAL, 0x00000000);
/* Check if primary bridge */
primary = of_property_read_bool(port->node, "primary");
/* Get bus range if any */
bus_range = of_get_property(port->node, "bus-range", NULL);
/* Allocate the host controller data structure */
hose = pcibios_alloc_controller(port->node); if (!hose) goto fail;
/* We stick the port number in "indirect_type" so the config space * ops can retrieve the port data structure easily
*/
hose->indirect_type = port->index;
/* Get bus range */
hose->first_busno = bus_range ? bus_range[0] : 0x0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
/* Because of how big mapping the config space is (1M per bus), we * limit how many busses we support. In the long run, we could replace * that with something akin to kmap_atomic instead. We set aside 1 bus * for the host itself too.
*/
busses = hose->last_busno - hose->first_busno; /* This is off by 1 */ if (busses > MAX_PCIE_BUS_MAPPED) {
busses = MAX_PCIE_BUS_MAPPED;
hose->last_busno = hose->first_busno + busses;
}
if (!port->endpoint) { /* Only map the external config space in cfg_data for * PCIe root-complexes. External space is 1M per bus
*/
cfg_data = ioremap(port->cfg_space.start +
(hose->first_busno + 1) * 0x100000,
busses * 0x100000); if (cfg_data == NULL) {
printk(KERN_ERR "%pOF: Can't map external config space !",
port->node); goto fail;
}
hose->cfg_data = cfg_data;
}
/* Always map the host config space in cfg_addr. * Internal space is 4K
*/
mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); if (mbase == NULL) {
printk(KERN_ERR "%pOF: Can't map internal config space !",
port->node); goto fail;
}
hose->cfg_addr = mbase;
pr_debug("PCIE %pOF, bus %d..%d\n", port->node,
hose->first_busno, hose->last_busno);
pr_debug(" config space mapped at: root @0x%p, other @0x%p\n",
hose->cfg_addr, hose->cfg_data);
/* The root complex doesn't show up if we don't set some vendor * and device IDs into it. The defaults below are the same bogus * one that the initial code in arch/ppc had. This can be * overwritten by setting the "vendor-id/device-id" properties * in the pciex node.
*/
/* Get the (optional) vendor-/device-id from the device-tree */
pval = of_get_property(port->node, "vendor-id", NULL); if (pval) {
val = *pval;
} else { if (!port->endpoint)
val = 0xaaa0 + port->index; else
val = 0xeee0 + port->index;
}
out_le16(mbase + 0x200, val);
pval = of_get_property(port->node, "device-id", NULL); if (pval) {
val = *pval;
} else { if (!port->endpoint)
val = 0xbed0 + port->index; else
val = 0xfed0 + port->index;
}
out_le16(mbase + 0x202, val);
/* Enable Bus master, memory, and io space */ if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx"))
out_le16(mbase + 0x204, 0x7);
if (!port->endpoint) { /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */
out_le32(mbase + 0x208, 0x06040001);
printk(KERN_INFO "PCIE%d: successfully set as root-complex\n",
port->index);
} else { /* Set Class Code to Processor/PPC */
out_le32(mbase + 0x208, 0x0b200001);
printk(KERN_INFO "PCIE%d: successfully set as endpoint\n",
port->index);
}
return;
fail: if (hose)
pcibios_free_controller(hose); if (cfg_data)
iounmap(cfg_data); if (mbase)
iounmap(mbase);
}
/* First, proceed to core initialization as we assume there's * only one PCIe core in the system
*/ if (ppc4xx_pciex_check_core_init(np)) return;
/* Get the port number from the device-tree */
pval = of_get_property(np, "port", NULL); if (pval == NULL) {
printk(KERN_ERR "PCIE: Can't find port number for %pOF\n", np); return;
}
portno = *pval; if (portno >= ppc4xx_pciex_port_count) {
printk(KERN_ERR "PCIE: port number out of range for %pOF\n",
np); return;
}
port = &ppc4xx_pciex_ports[portno];
port->index = portno;
/* * Check if device is enabled
*/ if (!of_device_is_available(np)) {
printk(KERN_INFO "PCIE%d: Port disabled via device-tree\n", port->index); return;
}
port->node = of_node_get(np); if (ppc4xx_pciex_hwops->want_sdr) {
pval = of_get_property(np, "sdr-base", NULL); if (pval == NULL) {
printk(KERN_ERR "PCIE: missing sdr-base for %pOF\n",
np); return;
}
port->sdr_base = *pval;
}
/* Check if device_type property is set to "pci" or "pci-endpoint". * Resulting from this setup this PCIe port will be configured * as root-complex or as endpoint.
*/ if (of_node_is_type(port->node, "pci-endpoint")) {
port->endpoint = 1;
} elseif (of_node_is_type(port->node, "pci")) {
port->endpoint = 0;
} else {
printk(KERN_ERR "PCIE: missing or incorrect device_type for %pOF\n",
np); return;
}
/* Fetch config space registers address */ if (of_address_to_resource(np, 0, &port->cfg_space)) {
printk(KERN_ERR "%pOF: Can't get PCI-E config space !", np); return;
} /* Fetch host bridge internal registers address */ if (of_address_to_resource(np, 1, &port->utl_regs)) {
printk(KERN_ERR "%pOF: Can't get UTL register base !", np); return;
}
/* Map DCRs */
dcrs = dcr_resource_start(np, 0); if (dcrs == 0) {
printk(KERN_ERR "%pOF: Can't get DCR register base !", np); return;
}
port->dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
/* Initialize the port specific registers */ if (ppc4xx_pciex_port_init(port)) {
printk(KERN_WARNING "PCIE%d: Port init failed\n", port->index); return;
}
/* Setup the linux hose data structure */
ppc4xx_pciex_port_setup_hose(port);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.