aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/dtc/libfdt/fdt_ro.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2009-04-30 01:25:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-05-02 19:52:26 -0400
commit9fffb55f66127b52c937ede5196ebfa0c0d50bce (patch)
tree11664fb82734ba8dcde9556b8d47e780451a740a /scripts/dtc/libfdt/fdt_ro.c
parentafc1e702e8e8355faa712d4e90d9afe26a4995a5 (diff)
Move dtc and libfdt sources from arch/powerpc/boot to scripts/dtc
The powerpc kernel always requires an Open Firmware like device tree to supply device information. On systems without OF, this comes from a flattened device tree blob. This blob is usually generated by dtc, a tool which compiles a text description of the device tree into the flattened format used by the kernel. Sometimes, the bootwrapper makes small changes to the pre-compiled device tree blob (e.g. filling in the size of RAM). To do this it uses the libfdt library. Because these are only used on powerpc, the code for both these tools is included under arch/powerpc/boot (these were imported and are periodically updated from the upstream dtc tree). However, the microblaze architecture, currently being prepared for merging to mainline also uses dtc to produce device tree blobs. A few other archs have also mentioned some interest in using dtc. Therefore, this patch moves dtc and libfdt from arch/powerpc into scripts, where it can be used by any architecture. The vast bulk of this patch is a literal move, the rest is adjusting the various Makefiles to use dtc and libfdt correctly from their new locations. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'scripts/dtc/libfdt/fdt_ro.c')
-rw-r--r--scripts/dtc/libfdt/fdt_ro.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
new file mode 100644
index 000000000000..fbbba44fcd0d
--- /dev/null
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -0,0 +1,469 @@
1/*
2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2006 David Gibson, IBM Corporation.
4 *
5 * libfdt is dual licensed: you can use it either under the terms of
6 * the GPL, or the BSD license, at your option.
7 *
8 * a) This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 * MA 02110-1301 USA
22 *
23 * Alternatively,
24 *
25 * b) Redistribution and use in source and binary forms, with or
26 * without modification, are permitted provided that the following
27 * conditions are met:
28 *
29 * 1. Redistributions of source code must retain the above
30 * copyright notice, this list of conditions and the following
31 * disclaimer.
32 * 2. Redistributions in binary form must reproduce the above
33 * copyright notice, this list of conditions and the following
34 * disclaimer in the documentation and/or other materials
35 * provided with the distribution.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 */
51#include "libfdt_env.h"
52
53#include <fdt.h>
54#include <libfdt.h>
55
56#include "libfdt_internal.h"
57
58static int _fdt_nodename_eq(const void *fdt, int offset,
59 const char *s, int len)
60{
61 const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
62
63 if (! p)
64 /* short match */
65 return 0;
66
67 if (memcmp(p, s, len) != 0)
68 return 0;
69
70 if (p[len] == '\0')
71 return 1;
72 else if (!memchr(s, '@', len) && (p[len] == '@'))
73 return 1;
74 else
75 return 0;
76}
77
78const char *fdt_string(const void *fdt, int stroffset)
79{
80 return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
81}
82
83int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
84{
85 FDT_CHECK_HEADER(fdt);
86 *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
87 *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
88 return 0;
89}
90
91int fdt_num_mem_rsv(const void *fdt)
92{
93 int i = 0;
94
95 while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
96 i++;
97 return i;
98}
99
100int fdt_subnode_offset_namelen(const void *fdt, int offset,
101 const char *name, int namelen)
102{
103 int depth;
104
105 FDT_CHECK_HEADER(fdt);
106
107 for (depth = 0, offset = fdt_next_node(fdt, offset, &depth);
108 (offset >= 0) && (depth > 0);
109 offset = fdt_next_node(fdt, offset, &depth)) {
110 if (depth < 0)
111 return -FDT_ERR_NOTFOUND;
112 else if ((depth == 1)
113 && _fdt_nodename_eq(fdt, offset, name, namelen))
114 return offset;
115 }
116
117 if (offset < 0)
118 return offset; /* error */
119 else
120 return -FDT_ERR_NOTFOUND;
121}
122
123int fdt_subnode_offset(const void *fdt, int parentoffset,
124 const char *name)
125{
126 return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
127}
128
129int fdt_path_offset(const void *fdt, const char *path)
130{
131 const char *end = path + strlen(path);
132 const char *p = path;
133 int offset = 0;
134
135 FDT_CHECK_HEADER(fdt);
136
137 if (*path != '/')
138 return -FDT_ERR_BADPATH;
139
140 while (*p) {
141 const char *q;
142
143 while (*p == '/')
144 p++;
145 if (! *p)
146 return offset;
147 q = strchr(p, '/');
148 if (! q)
149 q = end;
150
151 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
152 if (offset < 0)
153 return offset;
154
155 p = q;
156 }
157
158 return offset;
159}
160
161const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
162{
163 const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
164 int err;
165
166 if (((err = fdt_check_header(fdt)) != 0)
167 || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
168 goto fail;
169
170 if (len)
171 *len = strlen(nh->name);
172
173 return nh->name;
174
175 fail:
176 if (len)
177 *len = err;
178 return NULL;
179}
180
181const struct fdt_property *fdt_get_property(const void *fdt,
182 int nodeoffset,
183 const char *name, int *lenp)
184{
185 uint32_t tag;
186 const struct fdt_property *prop;
187 int namestroff;
188 int offset, nextoffset;
189 int err;
190
191 if (((err = fdt_check_header(fdt)) != 0)
192 || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
193 goto fail;
194
195 nextoffset = err;
196 do {
197 offset = nextoffset;
198
199 tag = fdt_next_tag(fdt, offset, &nextoffset);
200 switch (tag) {
201 case FDT_END:
202 err = -FDT_ERR_TRUNCATED;
203 goto fail;
204
205 case FDT_BEGIN_NODE:
206 case FDT_END_NODE:
207 case FDT_NOP:
208 break;
209
210 case FDT_PROP:
211 err = -FDT_ERR_BADSTRUCTURE;
212 prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
213 if (! prop)
214 goto fail;
215 namestroff = fdt32_to_cpu(prop->nameoff);
216 if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
217 /* Found it! */
218 int len = fdt32_to_cpu(prop->len);
219 prop = fdt_offset_ptr(fdt, offset,
220 sizeof(*prop)+len);
221 if (! prop)
222 goto fail;
223
224 if (lenp)
225 *lenp = len;
226
227 return prop;
228 }
229 break;
230
231 default:
232 err = -FDT_ERR_BADSTRUCTURE;
233 goto fail;
234 }
235 } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
236
237 err = -FDT_ERR_NOTFOUND;
238 fail:
239 if (lenp)
240 *lenp = err;
241 return NULL;
242}
243
244const void *fdt_getprop(const void *fdt, int nodeoffset,
245 const char *name, int *lenp)
246{
247 const struct fdt_property *prop;
248
249 prop = fdt_get_property(fdt, nodeoffset, name, lenp);
250 if (! prop)
251 return NULL;
252
253 return prop->data;
254}
255
256uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
257{
258 const uint32_t *php;
259 int len;
260
261 php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
262 if (!php || (len != sizeof(*php)))
263 return 0;
264
265 return fdt32_to_cpu(*php);
266}
267
268int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
269{
270 int pdepth = 0, p = 0;
271 int offset, depth, namelen;
272 const char *name;
273
274 FDT_CHECK_HEADER(fdt);
275
276 if (buflen < 2)
277 return -FDT_ERR_NOSPACE;
278
279 for (offset = 0, depth = 0;
280 (offset >= 0) && (offset <= nodeoffset);
281 offset = fdt_next_node(fdt, offset, &depth)) {
282 if (pdepth < depth)
283 continue; /* overflowed buffer */
284
285 while (pdepth > depth) {
286 do {
287 p--;
288 } while (buf[p-1] != '/');
289 pdepth--;
290 }
291
292 name = fdt_get_name(fdt, offset, &namelen);
293 if (!name)
294 return namelen;
295 if ((p + namelen + 1) <= buflen) {
296 memcpy(buf + p, name, namelen);
297 p += namelen;
298 buf[p++] = '/';
299 pdepth++;
300 }
301
302 if (offset == nodeoffset) {
303 if (pdepth < (depth + 1))
304 return -FDT_ERR_NOSPACE;
305
306 if (p > 1) /* special case so that root path is "/", not "" */
307 p--;
308 buf[p] = '\0';
309 return p;
310 }
311 }
312
313 if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
314 return -FDT_ERR_BADOFFSET;
315 else if (offset == -FDT_ERR_BADOFFSET)
316 return -FDT_ERR_BADSTRUCTURE;
317
318 return offset; /* error from fdt_next_node() */
319}
320
321int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
322 int supernodedepth, int *nodedepth)
323{
324 int offset, depth;
325 int supernodeoffset = -FDT_ERR_INTERNAL;
326
327 FDT_CHECK_HEADER(fdt);
328
329 if (supernodedepth < 0)
330 return -FDT_ERR_NOTFOUND;
331
332 for (offset = 0, depth = 0;
333 (offset >= 0) && (offset <= nodeoffset);
334 offset = fdt_next_node(fdt, offset, &depth)) {
335 if (depth == supernodedepth)
336 supernodeoffset = offset;
337
338 if (offset == nodeoffset) {
339 if (nodedepth)
340 *nodedepth = depth;
341
342 if (supernodedepth > depth)
343 return -FDT_ERR_NOTFOUND;
344 else
345 return supernodeoffset;
346 }
347 }
348
349 if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
350 return -FDT_ERR_BADOFFSET;
351 else if (offset == -FDT_ERR_BADOFFSET)
352 return -FDT_ERR_BADSTRUCTURE;
353
354 return offset; /* error from fdt_next_node() */
355}
356
357int fdt_node_depth(const void *fdt, int nodeoffset)
358{
359 int nodedepth;
360 int err;
361
362 err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
363 if (err)
364 return (err < 0) ? err : -FDT_ERR_INTERNAL;
365 return nodedepth;
366}
367
368int fdt_parent_offset(const void *fdt, int nodeoffset)
369{
370 int nodedepth = fdt_node_depth(fdt, nodeoffset);
371
372 if (nodedepth < 0)
373 return nodedepth;
374 return fdt_supernode_atdepth_offset(fdt, nodeoffset,
375 nodedepth - 1, NULL);
376}
377
378int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
379 const char *propname,
380 const void *propval, int proplen)
381{
382 int offset;
383 const void *val;
384 int len;
385
386 FDT_CHECK_HEADER(fdt);
387
388 /* FIXME: The algorithm here is pretty horrible: we scan each
389 * property of a node in fdt_getprop(), then if that didn't
390 * find what we want, we scan over them again making our way
391 * to the next node. Still it's the easiest to implement
392 * approach; performance can come later. */
393 for (offset = fdt_next_node(fdt, startoffset, NULL);
394 offset >= 0;
395 offset = fdt_next_node(fdt, offset, NULL)) {
396 val = fdt_getprop(fdt, offset, propname, &len);
397 if (val && (len == proplen)
398 && (memcmp(val, propval, len) == 0))
399 return offset;
400 }
401
402 return offset; /* error from fdt_next_node() */
403}
404
405int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
406{
407 if ((phandle == 0) || (phandle == -1))
408 return -FDT_ERR_BADPHANDLE;
409 phandle = cpu_to_fdt32(phandle);
410 return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
411 &phandle, sizeof(phandle));
412}
413
414int _stringlist_contains(const char *strlist, int listlen, const char *str)
415{
416 int len = strlen(str);
417 const char *p;
418
419 while (listlen >= len) {
420 if (memcmp(str, strlist, len+1) == 0)
421 return 1;
422 p = memchr(strlist, '\0', listlen);
423 if (!p)
424 return 0; /* malformed strlist.. */
425 listlen -= (p-strlist) + 1;
426 strlist = p + 1;
427 }
428 return 0;
429}
430
431int fdt_node_check_compatible(const void *fdt, int nodeoffset,
432 const char *compatible)
433{
434 const void *prop;
435 int len;
436
437 prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
438 if (!prop)
439 return len;
440 if (_stringlist_contains(prop, len, compatible))
441 return 0;
442 else
443 return 1;
444}
445
446int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
447 const char *compatible)
448{
449 int offset, err;
450
451 FDT_CHECK_HEADER(fdt);
452
453 /* FIXME: The algorithm here is pretty horrible: we scan each
454 * property of a node in fdt_node_check_compatible(), then if
455 * that didn't find what we want, we scan over them again
456 * making our way to the next node. Still it's the easiest to
457 * implement approach; performance can come later. */
458 for (offset = fdt_next_node(fdt, startoffset, NULL);
459 offset >= 0;
460 offset = fdt_next_node(fdt, offset, NULL)) {
461 err = fdt_node_check_compatible(fdt, offset, compatible);
462 if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
463 return err;
464 else if (err == 0)
465 return offset;
466 }
467
468 return offset; /* error from fdt_next_node() */
469}