diff options
author | Lucas Stach <dev@lynxeye.de> | 2014-10-04 19:40:21 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2014-10-08 08:39:01 +0200 |
commit | 2840294a514231baff2a9ab484b6965519d1eeb3 (patch) | |
tree | a538e43ed86b45dd487c5536fdd723d27001a05d /drivers/of/address.c | |
parent | 7a2255b43ea926970eaf3cae693d015c17cfea1c (diff) | |
download | barebox-2840294a514231baff2a9ab484b6965519d1eeb3.tar.gz barebox-2840294a514231baff2a9ab484b6965519d1eeb3.tar.xz |
of: import pci range parser from linux
Signed-off-by: Lucas Stach <dev@lynxeye.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/of/address.c')
-rw-r--r-- | drivers/of/address.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c index b3cbb15453..8018d78bcb 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -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 */ |