Commit a48cf37a authored by John Crispin's avatar John Crispin Committed by Ralf Baechle

MIPS: pci: parse memory ranges from devicetree

Implement pci_load_of_ranges on MIPS. Due to lack of test hardware only 32bit
bus width is supported. This function is based on pci_process_bridge_OF_ranges
from powerpc.
Signed-off-by: default avatarJohn Crispin <blogic@openwrt.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/3729/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 3572a2c3
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
*/ */
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/of.h>
/* /*
* Each pci channel is a top-level PCI bus seem by CPU. A machine with * Each pci channel is a top-level PCI bus seem by CPU. A machine with
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
struct pci_controller { struct pci_controller {
struct pci_controller *next; struct pci_controller *next;
struct pci_bus *bus; struct pci_bus *bus;
struct device_node *of_node;
struct pci_ops *pci_ops; struct pci_ops *pci_ops;
struct resource *mem_resource; struct resource *mem_resource;
...@@ -142,4 +144,8 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) ...@@ -142,4 +144,8 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
extern char * (*pcibios_plat_setup)(char *str); extern char * (*pcibios_plat_setup)(char *str);
/* this function parses memory ranges from a device node */
extern void __devinit pci_load_of_ranges(struct pci_controller *hose,
struct device_node *node);
#endif /* _ASM_PCI_H */ #endif /* _ASM_PCI_H */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/of_address.h>
#include <asm/cpu-info.h> #include <asm/cpu-info.h>
...@@ -114,9 +115,63 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose) ...@@ -114,9 +115,63 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
pci_bus_assign_resources(bus); pci_bus_assign_resources(bus);
pci_enable_bridges(bus); pci_enable_bridges(bus);
} }
bus->dev.of_node = hose->of_node;
} }
} }
#ifdef CONFIG_OF
void __devinit pci_load_of_ranges(struct pci_controller *hose,
struct device_node *node)
{
const __be32 *ranges;
int rlen;
int pna = of_n_addr_cells(node);
int np = pna + 5;
pr_info("PCI host bridge %s ranges:\n", node->full_name);
ranges = of_get_property(node, "ranges", &rlen);
if (ranges == NULL)
return;
hose->of_node = node;
while ((rlen -= np * 4) >= 0) {
u32 pci_space;
struct resource *res = NULL;
u64 addr, size;
pci_space = be32_to_cpup(&ranges[0]);
addr = of_translate_address(node, ranges + 3);
size = of_read_number(ranges + pna + 3, 2);
ranges += np;
switch ((pci_space >> 24) & 0x3) {
case 1: /* PCI IO space */
pr_info(" IO 0x%016llx..0x%016llx\n",
addr, addr + size - 1);
hose->io_map_base =
(unsigned long)ioremap(addr, size);
res = hose->io_resource;
res->flags = IORESOURCE_IO;
break;
case 2: /* PCI Memory space */
case 3: /* PCI 64 bits Memory space */
pr_info(" MEM 0x%016llx..0x%016llx\n",
addr, addr + size - 1);
res = hose->mem_resource;
res->flags = IORESOURCE_MEM;
break;
}
if (res != NULL) {
res->start = addr;
res->name = node->full_name;
res->end = res->start + size - 1;
res->parent = NULL;
res->sibling = NULL;
res->child = NULL;
}
}
}
#endif
static DEFINE_MUTEX(pci_scan_mutex); static DEFINE_MUTEX(pci_scan_mutex);
void __devinit register_pci_controller(struct pci_controller *hose) void __devinit register_pci_controller(struct pci_controller *hose)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment