MIPS: PCI: Netlogic XLP9XX support

Add PCI support for Netlogic XLP9XX. The PCI registers and
SoC bus numbers have changed in XLP9XX.

Also skip a few (bus,dev,fn) combinations which have issues when
read.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
Signed-off-by: John Crispin <blogic@openwrt.org>
Patchwork: http://patchwork.linux-mips.org/patch/6284/
This commit is contained in:
Jayachandran C 2013-12-21 16:52:27 +05:30 committed by Ralf Baechle
parent 98d4884ca5
commit b6ba1c5294
4 changed files with 87 additions and 20 deletions

View file

@ -63,6 +63,12 @@
#define PCIE_INT_EN0 0x261
#define PCIE_INT_EN1 0x262
/* XLP9XX has basic changes */
#define PCIE_9XX_BYTE_SWAP_MEM_BASE 0x25c
#define PCIE_9XX_BYTE_SWAP_MEM_LIM 0x25d
#define PCIE_9XX_BYTE_SWAP_IO_BASE 0x25e
#define PCIE_9XX_BYTE_SWAP_IO_LIM 0x25f
/* other */
#define PCIE_NLINKS 4
@ -78,8 +84,8 @@
#define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r)
#define nlm_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v)
#define nlm_get_pcie_base(node, inst) \
nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst))
#define nlm_get_pcie_base(node, inst) nlm_pcicfg_base(cpu_is_xlp9xx() ? \
XLP9XX_IO_PCIE_OFFSET(node, inst) : XLP_IO_PCIE_OFFSET(node, inst))
#ifdef CONFIG_PCI_MSI
void xlp_init_node_msi_irqs(int node, int link);

View file

@ -84,6 +84,9 @@ void xlp_mmu_init(void);
void nlm_hal_init(void);
int xlp_get_dram_map(int n, uint64_t *dram_map);
struct pci_dev;
int xlp_socdev_to_node(const struct pci_dev *dev);
/* Device tree related */
void xlp_early_init_devtree(void);
void *xlp_dt_init(void *fdtp);

View file

@ -76,6 +76,11 @@ int nlm_irq_to_irt(int irq)
return 133;
case PIC_UART_1_IRQ:
return 134;
case PIC_PCIE_LINK_LEGACY_IRQ(0):
case PIC_PCIE_LINK_LEGACY_IRQ(1):
case PIC_PCIE_LINK_LEGACY_IRQ(2):
case PIC_PCIE_LINK_LEGACY_IRQ(3):
return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE;
}
return -1;
}

View file

@ -67,9 +67,22 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
u32 *cfgaddr;
where &= ~3;
if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954)
if (cpu_is_xlp9xx()) {
/* be very careful on SoC buses */
if (bus->number == 0) {
/* Scan only existing nodes - uboot bug? */
if (PCI_SLOT(devfn) != 0 ||
!nlm_node_present(PCI_FUNC(devfn)))
return 0xffffffff;
} else if (bus->parent->number == 0) { /* SoC bus */
if (PCI_SLOT(devfn) == 0) /* b.0.0 hangs */
return 0xffffffff;
if (devfn == 44) /* b.5.4 hangs */
return 0xffffffff;
}
} else if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) {
return 0xffffffff;
}
cfgaddr = (u32 *)(pci_config_base +
pci_cfg_addr(bus->number, devfn, where));
data = *cfgaddr;
@ -167,18 +180,35 @@ struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
{
struct pci_bus *bus, *p;
/* Find the bridge on bus 0 */
bus = dev->bus;
for (p = bus->parent; p && p->number != 0; p = p->parent)
bus = p;
return p ? bus->self : NULL;
if (cpu_is_xlp9xx()) {
/* find bus with grand parent number == 0 */
for (p = bus->parent; p && p->parent && p->parent->number != 0;
p = p->parent)
bus = p;
return (p && p->parent) ? bus->self : NULL;
} else {
/* Find the bridge on bus 0 */
for (p = bus->parent; p && p->number != 0; p = p->parent)
bus = p;
return p ? bus->self : NULL;
}
}
int xlp_socdev_to_node(const struct pci_dev *lnkdev)
{
if (cpu_is_xlp9xx())
return PCI_FUNC(lnkdev->bus->self->devfn);
else
return PCI_SLOT(lnkdev->devfn) / 8;
}
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
struct pci_dev *lnkdev;
int lnkslot, lnkfunc;
int lnkfunc, node;
/*
* For XLP PCIe, there is an IRQ per Link, find out which
@ -187,9 +217,11 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
lnkdev = xlp_get_pcie_link(dev);
if (lnkdev == NULL)
return 0;
lnkfunc = PCI_FUNC(lnkdev->devfn);
lnkslot = PCI_SLOT(lnkdev->devfn);
return nlm_irq_to_xirq(lnkslot / 8, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc));
node = xlp_socdev_to_node(lnkdev);
return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc));
}
/* Do platform specific device initialization at pci_enable_device() time */
@ -216,17 +248,38 @@ static void xlp_config_pci_bswap(int node, int link)
* Enable byte swap in hardware. Program each link's PCIe SWAP regions
* from the link's address ranges.
*/
reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
if (cpu_is_xlp9xx()) {
reg = nlm_read_bridge_reg(nbubase,
BRIDGE_9XX_PCIEMEM_BASE0 + link);
nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_MEM_BASE, reg);
reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link);
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
reg = nlm_read_bridge_reg(nbubase,
BRIDGE_9XX_PCIEMEM_LIMIT0 + link);
nlm_write_pci_reg(lnkbase,
PCIE_9XX_BYTE_SWAP_MEM_LIM, reg | 0xfff);
reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link);
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
reg = nlm_read_bridge_reg(nbubase,
BRIDGE_9XX_PCIEIO_BASE0 + link);
nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_IO_BASE, reg);
reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link);
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
reg = nlm_read_bridge_reg(nbubase,
BRIDGE_9XX_PCIEIO_LIMIT0 + link);
nlm_write_pci_reg(lnkbase,
PCIE_9XX_BYTE_SWAP_IO_LIM, reg | 0xfff);
} else {
reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
reg = nlm_read_bridge_reg(nbubase,
BRIDGE_PCIEMEM_LIMIT0 + link);
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link);
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link);
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
}
}
#else
/* Swap configuration not needed in little-endian mode */
@ -260,7 +313,7 @@ static int __init pcibios_init(void)
/* put in intpin and irq - u-boot does not */
reg = nlm_read_pci_reg(pciebase, 0xf);
reg &= ~0x1fu;
reg &= ~0x1ffu;
reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link);
nlm_write_pci_reg(pciebase, 0xf, reg);
pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link);