summaryrefslogtreecommitdiff
path: root/target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch')
-rw-r--r--target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch201
1 files changed, 201 insertions, 0 deletions
diff --git a/target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch b/target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch
new file mode 100644
index 0000000000..1ee8b4c1bf
--- /dev/null
+++ b/target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch
@@ -0,0 +1,201 @@
+From: Andrew Murray <Andrew.Murray@arm.com>
+Subject: [PATCH] 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>
+---
+ drivers/of/address.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/of_address.h | 48 +++++++++++++++++++++++++++++++++
+ 2 files changed, 115 insertions(+)
+
+diff --git a/drivers/of/address.c b/drivers/of/address.c
+index 04da786..fdd0636 100644
+--- a/drivers/of/address.c
++++ b/drivers/of/address.c
+@@ -227,6 +227,73 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
+ return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
+ }
+ EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
++
++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_PCI */
+
+ /*
+diff --git a/include/linux/of_address.h b/include/linux/of_address.h
+index 0506eb5..4c2e6f2 100644
+--- a/include/linux/of_address.h
++++ b/include/linux/of_address.h
+@@ -4,6 +4,36 @@
+ #include <linux/errno.h>
+ #include <linux/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 = res->child = res->sibling = NULL;
++ res->name = np->full_name;
++}
++
+ #ifdef CONFIG_OF_ADDRESS
+ extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
+ extern bool of_can_translate_address(struct device_node *dev);
+@@ -27,6 +57,11 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
+ #define pci_address_to_pio pci_address_to_pio
+ #endif
+
++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 /* CONFIG_OF_ADDRESS */
+ #ifndef of_address_to_resource
+ static inline int of_address_to_resource(struct device_node *dev, int index,
+@@ -53,6 +88,19 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index,
+ {
+ return NULL;
+ }
++
++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_ADDRESS */
+
+
+--
+1.8.4
+