aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorAndrew Murray <Andrew.Murray@arm.com>2013-05-16 11:55:17 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:01:29 -0400
commitb9ce6737e94a9a69ba66f9abbea33c6b9cc600f7 (patch)
tree5b6fa4333ebc61de39216cc4a227c1ddef8cbd9e /drivers/of
parent9e24d83c1f34dd619192533a760de0df49a08351 (diff)
of/pci: Provide support for parsing PCI DT ranges property
This patch factors out common implementation patterns to reduce overall kernel code and provide a means for host bridge drivers to directly obtain struct resources from the DT's ranges property without relying on architecture specific DT handling. This will make it easier to write archiecture independent host bridge drivers and mitigate against further duplication of DT parsing code. This patch can be used in the following way: struct of_pci_range_parser parser; struct of_pci_range range; if (of_pci_range_parser_init(&parser, np)) ; //no ranges property for_each_of_pci_range(&parser, &range) { /* directly access properties of the address range, e.g.: range.pci_space, range.pci_addr, range.cpu_addr, range.size, range.flags alternatively obtain a struct resource, e.g.: struct resource res; of_pci_range_to_resource(&range, np, &res); */ } Additionally the implementation takes care of adjacent ranges and merges them into a single range (as was the case with powerpc and microblaze). Signed-off-by: Andrew Murray <Andrew.Murray@arm.com> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Reviewed-by: Rob Herring <rob.herring@calxeda.com> Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Tested-by: Linus Walleij <linus.walleij@linaro.org> Tested-by: Jingoo Han <jg1.han@samsung.com> Acked-by: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/address.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 9e69b4f0d204..3c4b2af51611 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -223,6 +223,73 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
223 return __of_address_to_resource(dev, addrp, size, flags, NULL, r); 223 return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
224} 224}
225EXPORT_SYMBOL_GPL(of_pci_address_to_resource); 225EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
226
227int of_pci_range_parser_init(struct of_pci_range_parser *parser,
228 struct device_node *node)
229{
230 const int na = 3, ns = 2;
231 int rlen;
232
233 parser->node = node;
234 parser->pna = of_n_addr_cells(node);
235 parser->np = parser->pna + na + ns;
236
237 parser->range = of_get_property(node, "ranges", &rlen);
238 if (parser->range == NULL)
239 return -ENOENT;
240
241 parser->end = parser->range + rlen / sizeof(__be32);
242
243 return 0;
244}
245EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
246
247struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
248 struct of_pci_range *range)
249{
250 const int na = 3, ns = 2;
251
252 if (!range)
253 return NULL;
254
255 if (!parser->range || parser->range + parser->np > parser->end)
256 return NULL;
257
258 range->pci_space = parser->range[0];
259 range->flags = of_bus_pci_get_flags(parser->range);
260 range->pci_addr = of_read_number(parser->range + 1, ns);
261 range->cpu_addr = of_translate_address(parser->node,
262 parser->range + na);
263 range->size = of_read_number(parser->range + parser->pna + na, ns);
264
265 parser->range += parser->np;
266
267 /* Now consume following elements while they are contiguous */
268 while (parser->range + parser->np <= parser->end) {
269 u32 flags, pci_space;
270 u64 pci_addr, cpu_addr, size;
271
272 pci_space = be32_to_cpup(parser->range);
273 flags = of_bus_pci_get_flags(parser->range);
274 pci_addr = of_read_number(parser->range + 1, ns);
275 cpu_addr = of_translate_address(parser->node,
276 parser->range + na);
277 size = of_read_number(parser->range + parser->pna + na, ns);
278
279 if (flags != range->flags)
280 break;
281 if (pci_addr != range->pci_addr + range->size ||
282 cpu_addr != range->cpu_addr + range->size)
283 break;
284
285 range->size += size;
286 parser->range += parser->np;
287 }
288
289 return range;
290}
291EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
292
226#endif /* CONFIG_PCI */ 293#endif /* CONFIG_PCI */
227 294
228/* 295/*