of: import pci range parser from linux
Signed-off-by: Lucas Stach <dev@lynxeye.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
7a2255b43e
commit
2840294a51
|
@ -30,6 +30,7 @@ config OF_GPIO
|
|||
config OF_PCI
|
||||
bool
|
||||
depends on PCI
|
||||
select OF_ADDRESS_PCI
|
||||
help
|
||||
OpenFirmware PCI bus accessors
|
||||
|
||||
|
|
|
@ -179,6 +179,74 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na)
|
|||
}
|
||||
#endif /* CONFIG_OF_ADDRESS_PCI */
|
||||
|
||||
#ifdef CONFIG_OF_PCI
|
||||
int of_pci_range_parser_init(struct of_pci_range_parser *parser,
|
||||
struct device_node *node)
|
||||
{
|
||||
const int na = 3, ns = 2;
|
||||
int rlen;
|
||||
|
||||
parser->node = node;
|
||||
parser->pna = of_n_addr_cells(node);
|
||||
parser->np = parser->pna + na + ns;
|
||||
|
||||
parser->range = of_get_property(node, "ranges", &rlen);
|
||||
if (parser->range == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
parser->end = parser->range + rlen / sizeof(__be32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
|
||||
|
||||
struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
|
||||
struct of_pci_range *range)
|
||||
{
|
||||
const int na = 3, ns = 2;
|
||||
|
||||
if (!range)
|
||||
return NULL;
|
||||
|
||||
if (!parser->range || parser->range + parser->np > parser->end)
|
||||
return NULL;
|
||||
|
||||
range->pci_space = parser->range[0];
|
||||
range->flags = of_bus_pci_get_flags(parser->range);
|
||||
range->pci_addr = of_read_number(parser->range + 1, ns);
|
||||
range->cpu_addr = of_translate_address(parser->node,
|
||||
parser->range + na);
|
||||
range->size = of_read_number(parser->range + parser->pna + na, ns);
|
||||
|
||||
parser->range += parser->np;
|
||||
|
||||
/* Now consume following elements while they are contiguous */
|
||||
while (parser->range + parser->np <= parser->end) {
|
||||
u32 flags, pci_space;
|
||||
u64 pci_addr, cpu_addr, size;
|
||||
|
||||
pci_space = be32_to_cpup(parser->range);
|
||||
flags = of_bus_pci_get_flags(parser->range);
|
||||
pci_addr = of_read_number(parser->range + 1, ns);
|
||||
cpu_addr = of_translate_address(parser->node,
|
||||
parser->range + na);
|
||||
size = of_read_number(parser->range + parser->pna + na, ns);
|
||||
|
||||
if (flags != range->flags)
|
||||
break;
|
||||
if (pci_addr != range->pci_addr + range->size ||
|
||||
cpu_addr != range->cpu_addr + range->size)
|
||||
break;
|
||||
|
||||
range->size += size;
|
||||
parser->range += parser->np;
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
|
||||
#endif /* CONFIG_OF_PCI */
|
||||
|
||||
/*
|
||||
* Array of bus specific translators
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,38 @@
|
|||
#include <common.h>
|
||||
#include <of.h>
|
||||
|
||||
struct of_pci_range_parser {
|
||||
struct device_node *node;
|
||||
const __be32 *range;
|
||||
const __be32 *end;
|
||||
int np;
|
||||
int pna;
|
||||
};
|
||||
|
||||
struct of_pci_range {
|
||||
u32 pci_space;
|
||||
u64 pci_addr;
|
||||
u64 cpu_addr;
|
||||
u64 size;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
#define for_each_of_pci_range(parser, range) \
|
||||
for (; of_pci_range_parser_one(parser, range);)
|
||||
|
||||
static inline void of_pci_range_to_resource(struct of_pci_range *range,
|
||||
struct device_node *np,
|
||||
struct resource *res)
|
||||
{
|
||||
res->flags = range->flags;
|
||||
res->start = range->cpu_addr;
|
||||
res->end = range->cpu_addr + range->size - 1;
|
||||
res->parent = NULL;
|
||||
INIT_LIST_HEAD(&res->children);
|
||||
INIT_LIST_HEAD(&res->sibling);
|
||||
res->name = np->full_name;
|
||||
}
|
||||
|
||||
#ifndef pci_address_to_pio
|
||||
static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
|
||||
#endif
|
||||
|
@ -69,4 +101,29 @@ static inline void __iomem *of_iomap(struct device_node *np, int index)
|
|||
|
||||
#endif /* CONFIG_OFTREE */
|
||||
|
||||
#ifdef CONFIG_OF_PCI
|
||||
|
||||
extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
|
||||
struct device_node *node);
|
||||
|
||||
extern struct of_pci_range *of_pci_range_parser_one(
|
||||
struct of_pci_range_parser *parser,
|
||||
struct of_pci_range *range);
|
||||
|
||||
#else
|
||||
|
||||
static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
|
||||
struct device_node *node)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline struct of_pci_range *of_pci_range_parser_one(
|
||||
struct of_pci_range_parser *parser,
|
||||
struct of_pci_range *range)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF_PCI */
|
||||
|
||||
#endif /* __OF_ADDRESS_H */
|
||||
|
|
Loading…
Reference in New Issue