imx6: update PCIe driver
[openwrt/staging/mkresin.git] / target / linux / imx6 / patches-3.10 / 0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch
1 From: Andrew Murray <Andrew.Murray@arm.com>
2 Subject: [PATCH] of/pci: Provide support for parsing PCI DT ranges property
3
4 This patch factors out common implementation patterns to reduce overall kernel
5 code and provide a means for host bridge drivers to directly obtain struct
6 resources from the DT's ranges property without relying on architecture specific
7 DT handling. This will make it easier to write archiecture independent host bridge
8 drivers and mitigate against further duplication of DT parsing code.
9
10 This patch can be used in the following way:
11
12 struct of_pci_range_parser parser;
13 struct of_pci_range range;
14
15 if (of_pci_range_parser_init(&parser, np))
16 ; //no ranges property
17
18 for_each_of_pci_range(&parser, &range) {
19
20 /*
21 directly access properties of the address range, e.g.:
22 range.pci_space, range.pci_addr, range.cpu_addr,
23 range.size, range.flags
24
25 alternatively obtain a struct resource, e.g.:
26 struct resource res;
27 of_pci_range_to_resource(&range, np, &res);
28 */
29 }
30
31 Additionally the implementation takes care of adjacent ranges and merges them
32 into a single range (as was the case with powerpc and microblaze).
33
34 Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
35 Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
36 Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
37 Reviewed-by: Rob Herring <rob.herring@calxeda.com>
38 Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
39 Tested-by: Linus Walleij <linus.walleij@linaro.org>
40 Tested-by: Jingoo Han <jg1.han@samsung.com>
41 Acked-by: Grant Likely <grant.likely@secretlab.ca>
42 Signed-off-by: Jason Cooper <jason@lakedaemon.net>
43 ---
44 drivers/of/address.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++
45 include/linux/of_address.h | 48 +++++++++++++++++++++++++++++++++
46 2 files changed, 115 insertions(+)
47
48 diff --git a/drivers/of/address.c b/drivers/of/address.c
49 index 04da786..fdd0636 100644
50 --- a/drivers/of/address.c
51 +++ b/drivers/of/address.c
52 @@ -227,6 +227,73 @@ int of_pci_address_to_resource(struct device_node *dev, int bar,
53 return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
54 }
55 EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
56 +
57 +int of_pci_range_parser_init(struct of_pci_range_parser *parser,
58 + struct device_node *node)
59 +{
60 + const int na = 3, ns = 2;
61 + int rlen;
62 +
63 + parser->node = node;
64 + parser->pna = of_n_addr_cells(node);
65 + parser->np = parser->pna + na + ns;
66 +
67 + parser->range = of_get_property(node, "ranges", &rlen);
68 + if (parser->range == NULL)
69 + return -ENOENT;
70 +
71 + parser->end = parser->range + rlen / sizeof(__be32);
72 +
73 + return 0;
74 +}
75 +EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
76 +
77 +struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
78 + struct of_pci_range *range)
79 +{
80 + const int na = 3, ns = 2;
81 +
82 + if (!range)
83 + return NULL;
84 +
85 + if (!parser->range || parser->range + parser->np > parser->end)
86 + return NULL;
87 +
88 + range->pci_space = parser->range[0];
89 + range->flags = of_bus_pci_get_flags(parser->range);
90 + range->pci_addr = of_read_number(parser->range + 1, ns);
91 + range->cpu_addr = of_translate_address(parser->node,
92 + parser->range + na);
93 + range->size = of_read_number(parser->range + parser->pna + na, ns);
94 +
95 + parser->range += parser->np;
96 +
97 + /* Now consume following elements while they are contiguous */
98 + while (parser->range + parser->np <= parser->end) {
99 + u32 flags, pci_space;
100 + u64 pci_addr, cpu_addr, size;
101 +
102 + pci_space = be32_to_cpup(parser->range);
103 + flags = of_bus_pci_get_flags(parser->range);
104 + pci_addr = of_read_number(parser->range + 1, ns);
105 + cpu_addr = of_translate_address(parser->node,
106 + parser->range + na);
107 + size = of_read_number(parser->range + parser->pna + na, ns);
108 +
109 + if (flags != range->flags)
110 + break;
111 + if (pci_addr != range->pci_addr + range->size ||
112 + cpu_addr != range->cpu_addr + range->size)
113 + break;
114 +
115 + range->size += size;
116 + parser->range += parser->np;
117 + }
118 +
119 + return range;
120 +}
121 +EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
122 +
123 #endif /* CONFIG_PCI */
124
125 /*
126 diff --git a/include/linux/of_address.h b/include/linux/of_address.h
127 index 0506eb5..4c2e6f2 100644
128 --- a/include/linux/of_address.h
129 +++ b/include/linux/of_address.h
130 @@ -4,6 +4,36 @@
131 #include <linux/errno.h>
132 #include <linux/of.h>
133
134 +struct of_pci_range_parser {
135 + struct device_node *node;
136 + const __be32 *range;
137 + const __be32 *end;
138 + int np;
139 + int pna;
140 +};
141 +
142 +struct of_pci_range {
143 + u32 pci_space;
144 + u64 pci_addr;
145 + u64 cpu_addr;
146 + u64 size;
147 + u32 flags;
148 +};
149 +
150 +#define for_each_of_pci_range(parser, range) \
151 + for (; of_pci_range_parser_one(parser, range);)
152 +
153 +static inline void of_pci_range_to_resource(struct of_pci_range *range,
154 + struct device_node *np,
155 + struct resource *res)
156 +{
157 + res->flags = range->flags;
158 + res->start = range->cpu_addr;
159 + res->end = range->cpu_addr + range->size - 1;
160 + res->parent = res->child = res->sibling = NULL;
161 + res->name = np->full_name;
162 +}
163 +
164 #ifdef CONFIG_OF_ADDRESS
165 extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
166 extern bool of_can_translate_address(struct device_node *dev);
167 @@ -27,6 +57,11 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }
168 #define pci_address_to_pio pci_address_to_pio
169 #endif
170
171 +extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
172 + struct device_node *node);
173 +extern struct of_pci_range *of_pci_range_parser_one(
174 + struct of_pci_range_parser *parser,
175 + struct of_pci_range *range);
176 #else /* CONFIG_OF_ADDRESS */
177 #ifndef of_address_to_resource
178 static inline int of_address_to_resource(struct device_node *dev, int index,
179 @@ -53,6 +88,19 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index,
180 {
181 return NULL;
182 }
183 +
184 +static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
185 + struct device_node *node)
186 +{
187 + return -1;
188 +}
189 +
190 +static inline struct of_pci_range *of_pci_range_parser_one(
191 + struct of_pci_range_parser *parser,
192 + struct of_pci_range *range)
193 +{
194 + return NULL;
195 +}
196 #endif /* CONFIG_OF_ADDRESS */
197
198
199 --
200 1.8.4
201