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
|
@ -63,6 +63,12 @@
|
||||||
#define PCIE_INT_EN0 0x261
|
#define PCIE_INT_EN0 0x261
|
||||||
#define PCIE_INT_EN1 0x262
|
#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 */
|
/* other */
|
||||||
#define PCIE_NLINKS 4
|
#define PCIE_NLINKS 4
|
||||||
|
|
||||||
|
@ -78,8 +84,8 @@
|
||||||
|
|
||||||
#define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r)
|
#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_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v)
|
||||||
#define nlm_get_pcie_base(node, inst) \
|
#define nlm_get_pcie_base(node, inst) nlm_pcicfg_base(cpu_is_xlp9xx() ? \
|
||||||
nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst))
|
XLP9XX_IO_PCIE_OFFSET(node, inst) : XLP_IO_PCIE_OFFSET(node, inst))
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_MSI
|
#ifdef CONFIG_PCI_MSI
|
||||||
void xlp_init_node_msi_irqs(int node, int link);
|
void xlp_init_node_msi_irqs(int node, int link);
|
||||||
|
|
|
@ -84,6 +84,9 @@ void xlp_mmu_init(void);
|
||||||
void nlm_hal_init(void);
|
void nlm_hal_init(void);
|
||||||
int xlp_get_dram_map(int n, uint64_t *dram_map);
|
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 */
|
/* Device tree related */
|
||||||
void xlp_early_init_devtree(void);
|
void xlp_early_init_devtree(void);
|
||||||
void *xlp_dt_init(void *fdtp);
|
void *xlp_dt_init(void *fdtp);
|
||||||
|
|
|
@ -76,6 +76,11 @@ int nlm_irq_to_irt(int irq)
|
||||||
return 133;
|
return 133;
|
||||||
case PIC_UART_1_IRQ:
|
case PIC_UART_1_IRQ:
|
||||||
return 134;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,9 +67,22 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
|
||||||
u32 *cfgaddr;
|
u32 *cfgaddr;
|
||||||
|
|
||||||
where &= ~3;
|
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;
|
return 0xffffffff;
|
||||||
|
}
|
||||||
cfgaddr = (u32 *)(pci_config_base +
|
cfgaddr = (u32 *)(pci_config_base +
|
||||||
pci_cfg_addr(bus->number, devfn, where));
|
pci_cfg_addr(bus->number, devfn, where));
|
||||||
data = *cfgaddr;
|
data = *cfgaddr;
|
||||||
|
@ -167,18 +180,35 @@ struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct pci_bus *bus, *p;
|
struct pci_bus *bus, *p;
|
||||||
|
|
||||||
/* Find the bridge on bus 0 */
|
|
||||||
bus = dev->bus;
|
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)
|
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||||
{
|
{
|
||||||
struct pci_dev *lnkdev;
|
struct pci_dev *lnkdev;
|
||||||
int lnkslot, lnkfunc;
|
int lnkfunc, node;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For XLP PCIe, there is an IRQ per Link, find out which
|
* 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);
|
lnkdev = xlp_get_pcie_link(dev);
|
||||||
if (lnkdev == NULL)
|
if (lnkdev == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
lnkfunc = PCI_FUNC(lnkdev->devfn);
|
lnkfunc = PCI_FUNC(lnkdev->devfn);
|
||||||
lnkslot = PCI_SLOT(lnkdev->devfn);
|
node = xlp_socdev_to_node(lnkdev);
|
||||||
return nlm_irq_to_xirq(lnkslot / 8, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc));
|
|
||||||
|
return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do platform specific device initialization at pci_enable_device() time */
|
/* 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
|
* Enable byte swap in hardware. Program each link's PCIe SWAP regions
|
||||||
* from the link's address ranges.
|
* from the link's address ranges.
|
||||||
*/
|
*/
|
||||||
reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
|
if (cpu_is_xlp9xx()) {
|
||||||
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
|
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);
|
reg = nlm_read_bridge_reg(nbubase,
|
||||||
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
|
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);
|
reg = nlm_read_bridge_reg(nbubase,
|
||||||
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
|
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);
|
reg = nlm_read_bridge_reg(nbubase,
|
||||||
nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
|
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
|
#else
|
||||||
/* Swap configuration not needed in little-endian mode */
|
/* 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 */
|
/* put in intpin and irq - u-boot does not */
|
||||||
reg = nlm_read_pci_reg(pciebase, 0xf);
|
reg = nlm_read_pci_reg(pciebase, 0xf);
|
||||||
reg &= ~0x1fu;
|
reg &= ~0x1ffu;
|
||||||
reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link);
|
reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link);
|
||||||
nlm_write_pci_reg(pciebase, 0xf, reg);
|
nlm_write_pci_reg(pciebase, 0xf, reg);
|
||||||
pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link);
|
pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link);
|
||||||
|
|
Loading…
Reference in a new issue