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:
parent
98d4884ca5
commit
b6ba1c5294
4 changed files with 87 additions and 20 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue