Skip to content

Commit

Permalink
[POWERPC] 4xx: PLB to PCI 2.x support
Browse files Browse the repository at this point in the history
This adds to the previous patch the support for the 4xx PCI 2.x
bridges.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
  • Loading branch information
Benjamin Herrenschmidt authored and Josh Boyer committed Dec 23, 2007
1 parent 5738ec6 commit c839e0e
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 1 deletion.
180 changes: 179 additions & 1 deletion arch/powerpc/sysdev/ppc4xx_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,36 @@ static int dma_offset_set;
/* Move that to a useable header */
extern unsigned long total_memory;

static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev)
{
struct pci_controller *hose;
int i;

if (dev->devfn != 0 || dev->bus->self != NULL)
return;

hose = pci_bus_to_host(dev->bus);
if (hose == NULL)
return;

if (!of_device_is_compatible(hose->dn, "ibm,plb-pciex") &&
!of_device_is_compatible(hose->dn, "ibm,plb-pcix") &&
!of_device_is_compatible(hose->dn, "ibm,plb-pci"))
return;

/* Hide the PCI host BARs from the kernel as their content doesn't
* fit well in the resource management
*/
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
dev->resource[i].start = dev->resource[i].end = 0;
dev->resource[i].flags = 0;
}

printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n",
pci_name(dev));
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge);

static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
void __iomem *reg,
struct resource *res)
Expand Down Expand Up @@ -126,9 +156,157 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
/*
* 4xx PCI 2.x part
*/

static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
void __iomem *reg)
{
u32 la, ma, pcila, pciha;
int i, j;

/* Setup outbound memory windows */
for (i = j = 0; i < 3; i++) {
struct resource *res = &hose->mem_resources[i];

/* we only care about memory windows */
if (!(res->flags & IORESOURCE_MEM))
continue;
if (j > 2) {
printk(KERN_WARNING "%s: Too many ranges\n",
hose->dn->full_name);
break;
}

/* Calculate register values */
la = res->start;
#ifdef CONFIG_RESOURCES_64BIT
pciha = (res->start - hose->pci_mem_offset) >> 32;
pcila = (res->start - hose->pci_mem_offset) & 0xffffffffu;
#else
pciha = 0;
pcila = res->start - hose->pci_mem_offset;
#endif

ma = res->end + 1 - res->start;
if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) {
printk(KERN_WARNING "%s: Resource out of range\n",
hose->dn->full_name);
continue;
}
ma = (0xffffffffu << ilog2(ma)) | 0x1;
if (res->flags & IORESOURCE_PREFETCH)
ma |= 0x2;

/* Program register values */
writel(la, reg + PCIL0_PMM0LA + (0x10 * j));
writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j));
writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j));
writel(ma, reg + PCIL0_PMM0MA + (0x10 * j));
j++;
}
}

static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose,
void __iomem *reg,
const struct resource *res)
{
resource_size_t size = res->end - res->start + 1;
u32 sa;

/* Calculate window size */
sa = (0xffffffffu << ilog2(size)) | 1;
sa |= 0x1;

/* RAM is always at 0 local for now */
writel(0, reg + PCIL0_PTM1LA);
writel(sa, reg + PCIL0_PTM1MS);

/* Map on PCI side */
early_write_config_dword(hose, hose->first_busno, 0,
PCI_BASE_ADDRESS_1, res->start);
early_write_config_dword(hose, hose->first_busno, 0,
PCI_BASE_ADDRESS_2, 0x00000000);
early_write_config_word(hose, hose->first_busno, 0,
PCI_COMMAND, 0x0006);
}

static void __init ppc4xx_probe_pci_bridge(struct device_node *np)
{
/* NYI */
struct resource rsrc_cfg;
struct resource rsrc_reg;
struct resource dma_window;
struct pci_controller *hose = NULL;
void __iomem *reg = NULL;
const int *bus_range;
int primary = 0;

/* Fetch config space registers address */
if (of_address_to_resource(np, 0, &rsrc_cfg)) {
printk(KERN_ERR "%s:Can't get PCI config register base !",
np->full_name);
return;
}
/* Fetch host bridge internal registers address */
if (of_address_to_resource(np, 3, &rsrc_reg)) {
printk(KERN_ERR "%s: Can't get PCI internal register base !",
np->full_name);
return;
}

/* Check if primary bridge */
if (of_get_property(np, "primary", NULL))
primary = 1;

/* Get bus range if any */
bus_range = of_get_property(np, "bus-range", NULL);

/* Map registers */
reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start);
if (reg == NULL) {
printk(KERN_ERR "%s: Can't map registers !", np->full_name);
goto fail;
}

/* Allocate the host controller data structure */
hose = pcibios_alloc_controller(np);
if (!hose)
goto fail;

hose->first_busno = bus_range ? bus_range[0] : 0x0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;

/* Setup config space */
setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 0);

/* Disable all windows */
writel(0, reg + PCIL0_PMM0MA);
writel(0, reg + PCIL0_PMM1MA);
writel(0, reg + PCIL0_PMM2MA);
writel(0, reg + PCIL0_PTM1MS);
writel(0, reg + PCIL0_PTM2MS);

/* Parse outbound mapping resources */
pci_process_bridge_OF_ranges(hose, np, primary);

/* Parse inbound mapping resources */
if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0)
goto fail;

/* Configure outbound ranges POMs */
ppc4xx_configure_pci_PMMs(hose, reg);

/* Configure inbound ranges PIMs */
ppc4xx_configure_pci_PTMs(hose, reg, &dma_window);

/* We don't need the registers anymore */
iounmap(reg);
return;

fail:
if (hose)
pcibios_free_controller(hose);
if (reg)
iounmap(reg);
}

/*
Expand All @@ -155,7 +333,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
}

/* Calculate register values */
#ifdef CONFIG_PTE_64BIT
#ifdef CONFIG_RESOURCES_64BIT
lah = res->start >> 32;
lal = res->start & 0xffffffffu;
pciah = (res->start - hose->pci_mem_offset) >> 32;
Expand Down
19 changes: 19 additions & 0 deletions arch/powerpc/sysdev/ppc4xx_pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,25 @@
#define PCIX0_MSGOH 0x10c
#define PCIX0_IM 0x1f8

/*
* 4xx PCI bridge register definitions
*/
#define PCIL0_PMM0LA 0x00
#define PCIL0_PMM0MA 0x04
#define PCIL0_PMM0PCILA 0x08
#define PCIL0_PMM0PCIHA 0x0c
#define PCIL0_PMM1LA 0x10
#define PCIL0_PMM1MA 0x14
#define PCIL0_PMM1PCILA 0x18
#define PCIL0_PMM1PCIHA 0x1c
#define PCIL0_PMM2LA 0x20
#define PCIL0_PMM2MA 0x24
#define PCIL0_PMM2PCILA 0x28
#define PCIL0_PMM2PCIHA 0x2c
#define PCIL0_PTM1MS 0x30
#define PCIL0_PTM1LA 0x34
#define PCIL0_PTM2MS 0x38
#define PCIL0_PTM2LA 0x3c


#endif /* __PPC4XX_PCI_H__ */

0 comments on commit c839e0e

Please sign in to comment.