imx6: use upstream gateworks board names
[openwrt.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 --- a/drivers/of/address.c
49 +++ b/drivers/of/address.c
50 @@ -231,6 +231,73 @@ int of_pci_address_to_resource(struct de
51         return __of_address_to_resource(dev, addrp, size, flags, NULL, r);
52  }
53  EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
54 +
55 +int of_pci_range_parser_init(struct of_pci_range_parser *parser,
56 +                               struct device_node *node)
57 +{
58 +       const int na = 3, ns = 2;
59 +       int rlen;
60 +
61 +       parser->node = node;
62 +       parser->pna = of_n_addr_cells(node);
63 +       parser->np = parser->pna + na + ns;
64 +
65 +       parser->range = of_get_property(node, "ranges", &rlen);
66 +       if (parser->range == NULL)
67 +               return -ENOENT;
68 +
69 +       parser->end = parser->range + rlen / sizeof(__be32);
70 +
71 +       return 0;
72 +}
73 +EXPORT_SYMBOL_GPL(of_pci_range_parser_init);
74 +
75 +struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
76 +                                               struct of_pci_range *range)
77 +{
78 +       const int na = 3, ns = 2;
79 +
80 +       if (!range)
81 +               return NULL;
82 +
83 +       if (!parser->range || parser->range + parser->np > parser->end)
84 +               return NULL;
85 +
86 +       range->pci_space = parser->range[0];
87 +       range->flags = of_bus_pci_get_flags(parser->range);
88 +       range->pci_addr = of_read_number(parser->range + 1, ns);
89 +       range->cpu_addr = of_translate_address(parser->node,
90 +                               parser->range + na);
91 +       range->size = of_read_number(parser->range + parser->pna + na, ns);
92 +
93 +       parser->range += parser->np;
94 +
95 +       /* Now consume following elements while they are contiguous */
96 +       while (parser->range + parser->np <= parser->end) {
97 +               u32 flags, pci_space;
98 +               u64 pci_addr, cpu_addr, size;
99 +
100 +               pci_space = be32_to_cpup(parser->range);
101 +               flags = of_bus_pci_get_flags(parser->range);
102 +               pci_addr = of_read_number(parser->range + 1, ns);
103 +               cpu_addr = of_translate_address(parser->node,
104 +                               parser->range + na);
105 +               size = of_read_number(parser->range + parser->pna + na, ns);
106 +
107 +               if (flags != range->flags)
108 +                       break;
109 +               if (pci_addr != range->pci_addr + range->size ||
110 +                   cpu_addr != range->cpu_addr + range->size)
111 +                       break;
112 +
113 +               range->size += size;
114 +               parser->range += parser->np;
115 +       }
116 +
117 +       return range;
118 +}
119 +EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
120 +
121  #endif /* CONFIG_PCI */
122  
123  /*
124 --- a/include/linux/of_address.h
125 +++ b/include/linux/of_address.h
126 @@ -4,6 +4,36 @@
127  #include <linux/errno.h>
128  #include <linux/of.h>
129  
130 +struct of_pci_range_parser {
131 +       struct device_node *node;
132 +       const __be32 *range;
133 +       const __be32 *end;
134 +       int np;
135 +       int pna;
136 +};
137 +
138 +struct of_pci_range {
139 +       u32 pci_space;
140 +       u64 pci_addr;
141 +       u64 cpu_addr;
142 +       u64 size;
143 +       u32 flags;
144 +};
145 +
146 +#define for_each_of_pci_range(parser, range) \
147 +       for (; of_pci_range_parser_one(parser, range);)
148 +
149 +static inline void of_pci_range_to_resource(struct of_pci_range *range,
150 +                                           struct device_node *np,
151 +                                           struct resource *res)
152 +{
153 +       res->flags = range->flags;
154 +       res->start = range->cpu_addr;
155 +       res->end = range->cpu_addr + range->size - 1;
156 +       res->parent = res->child = res->sibling = NULL;
157 +       res->name = np->full_name;
158 +}
159 +
160  #ifdef CONFIG_OF_ADDRESS
161  extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
162  extern bool of_can_translate_address(struct device_node *dev);
163 @@ -27,6 +57,11 @@ static inline unsigned long pci_address_
164  #define pci_address_to_pio pci_address_to_pio
165  #endif
166  
167 +extern int of_pci_range_parser_init(struct of_pci_range_parser *parser,
168 +                       struct device_node *node);
169 +extern struct of_pci_range *of_pci_range_parser_one(
170 +                                       struct of_pci_range_parser *parser,
171 +                                       struct of_pci_range *range);
172  #else /* CONFIG_OF_ADDRESS */
173  #ifndef of_address_to_resource
174  static inline int of_address_to_resource(struct device_node *dev, int index,
175 @@ -53,6 +88,19 @@ static inline const __be32 *of_get_addre
176  {
177         return NULL;
178  }
179 +
180 +static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser,
181 +                       struct device_node *node)
182 +{
183 +       return -1;
184 +}
185 +
186 +static inline struct of_pci_range *of_pci_range_parser_one(
187 +                                       struct of_pci_range_parser *parser,
188 +                                       struct of_pci_range *range)
189 +{
190 +       return NULL;
191 +}
192  #endif /* CONFIG_OF_ADDRESS */
193  
194