diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2007-12-09 22:28:39 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-12-10 21:46:13 -0500 |
commit | 1cade99497c881a8c719df561d1bdc96831ff040 (patch) | |
tree | d90f0f9c667c5379f79244d117f4c95299180a05 /arch/powerpc/boot/libfdt | |
parent | b76e5e93982f28666aeef1055264f5eac76311b0 (diff) |
[POWERPC] Merge libfdt upstream source
This incorporates a copy of dtc libfdt into the kernel source, in
arch/powerpc/boot/libfdt. This only imports the upstream sources
verbatim, later patches are needed to actually link it into the kernel
Makefiles.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/boot/libfdt')
-rw-r--r-- | arch/powerpc/boot/libfdt/Makefile.libfdt | 14 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt.c | 156 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt.h | 60 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_ro.c | 583 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_rw.c | 447 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_strerror.c | 96 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_sw.c | 258 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/fdt_wip.c | 144 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/libfdt.h | 721 | ||||
-rw-r--r-- | arch/powerpc/boot/libfdt/libfdt_internal.h | 89 |
10 files changed, 2568 insertions, 0 deletions
diff --git a/arch/powerpc/boot/libfdt/Makefile.libfdt b/arch/powerpc/boot/libfdt/Makefile.libfdt new file mode 100644 index 000000000000..82f9c6a8287b --- /dev/null +++ b/arch/powerpc/boot/libfdt/Makefile.libfdt | |||
@@ -0,0 +1,14 @@ | |||
1 | # Makefile.libfdt | ||
2 | # | ||
3 | # This is not a complete Makefile of itself. Instead, it is designed to | ||
4 | # be easily embeddable into other systems of Makefiles. | ||
5 | # | ||
6 | LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c | ||
7 | LIBFDT_INCLUDES = fdt.h libfdt.h | ||
8 | LIBFDT_EXTRA = libfdt_internal.h | ||
9 | LIBFDT_LIB = libfdt/libfdt.a | ||
10 | |||
11 | LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) | ||
12 | |||
13 | $(LIBFDT_objdir)/$(LIBFDT_LIB): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) | ||
14 | |||
diff --git a/arch/powerpc/boot/libfdt/fdt.c b/arch/powerpc/boot/libfdt/fdt.c new file mode 100644 index 000000000000..586a36136db2 --- /dev/null +++ b/arch/powerpc/boot/libfdt/fdt.c | |||
@@ -0,0 +1,156 @@ | |||
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 | |||
58 | int fdt_check_header(const void *fdt) | ||
59 | { | ||
60 | if (fdt_magic(fdt) == FDT_MAGIC) { | ||
61 | /* Complete tree */ | ||
62 | if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) | ||
63 | return -FDT_ERR_BADVERSION; | ||
64 | if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) | ||
65 | return -FDT_ERR_BADVERSION; | ||
66 | } else if (fdt_magic(fdt) == SW_MAGIC) { | ||
67 | /* Unfinished sequential-write blob */ | ||
68 | if (fdt_size_dt_struct(fdt) == 0) | ||
69 | return -FDT_ERR_BADSTATE; | ||
70 | } else { | ||
71 | return -FDT_ERR_BADMAGIC; | ||
72 | } | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | const void *fdt_offset_ptr(const void *fdt, int offset, int len) | ||
78 | { | ||
79 | const void *p; | ||
80 | |||
81 | if (fdt_version(fdt) >= 0x11) | ||
82 | if (((offset + len) < offset) | ||
83 | || ((offset + len) > fdt_size_dt_struct(fdt))) | ||
84 | return NULL; | ||
85 | |||
86 | p = _fdt_offset_ptr(fdt, offset); | ||
87 | |||
88 | if (p + len < p) | ||
89 | return NULL; | ||
90 | return p; | ||
91 | } | ||
92 | |||
93 | uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) | ||
94 | { | ||
95 | const uint32_t *tagp, *lenp; | ||
96 | uint32_t tag; | ||
97 | const char *p; | ||
98 | |||
99 | if (offset % FDT_TAGSIZE) | ||
100 | return -1; | ||
101 | |||
102 | tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); | ||
103 | if (! tagp) | ||
104 | return FDT_END; /* premature end */ | ||
105 | tag = fdt32_to_cpu(*tagp); | ||
106 | offset += FDT_TAGSIZE; | ||
107 | |||
108 | switch (tag) { | ||
109 | case FDT_BEGIN_NODE: | ||
110 | /* skip name */ | ||
111 | do { | ||
112 | p = fdt_offset_ptr(fdt, offset++, 1); | ||
113 | } while (p && (*p != '\0')); | ||
114 | if (! p) | ||
115 | return FDT_END; | ||
116 | break; | ||
117 | case FDT_PROP: | ||
118 | lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); | ||
119 | if (! lenp) | ||
120 | return FDT_END; | ||
121 | /* skip name offset, length and value */ | ||
122 | offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); | ||
123 | break; | ||
124 | } | ||
125 | |||
126 | if (nextoffset) | ||
127 | *nextoffset = ALIGN(offset, FDT_TAGSIZE); | ||
128 | |||
129 | return tag; | ||
130 | } | ||
131 | |||
132 | const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) | ||
133 | { | ||
134 | int len = strlen(s) + 1; | ||
135 | const char *last = strtab + tabsize - len; | ||
136 | const char *p; | ||
137 | |||
138 | for (p = strtab; p <= last; p++) | ||
139 | if (memeq(p, s, len)) | ||
140 | return p; | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | int fdt_move(const void *fdt, void *buf, int bufsize) | ||
145 | { | ||
146 | int err = fdt_check_header(fdt); | ||
147 | |||
148 | if (err) | ||
149 | return err; | ||
150 | |||
151 | if (fdt_totalsize(fdt) > bufsize) | ||
152 | return -FDT_ERR_NOSPACE; | ||
153 | |||
154 | memmove(buf, fdt, fdt_totalsize(fdt)); | ||
155 | return 0; | ||
156 | } | ||
diff --git a/arch/powerpc/boot/libfdt/fdt.h b/arch/powerpc/boot/libfdt/fdt.h new file mode 100644 index 000000000000..48ccfd910000 --- /dev/null +++ b/arch/powerpc/boot/libfdt/fdt.h | |||
@@ -0,0 +1,60 @@ | |||
1 | #ifndef _FDT_H | ||
2 | #define _FDT_H | ||
3 | |||
4 | #ifndef __ASSEMBLY__ | ||
5 | |||
6 | struct fdt_header { | ||
7 | uint32_t magic; /* magic word FDT_MAGIC */ | ||
8 | uint32_t totalsize; /* total size of DT block */ | ||
9 | uint32_t off_dt_struct; /* offset to structure */ | ||
10 | uint32_t off_dt_strings; /* offset to strings */ | ||
11 | uint32_t off_mem_rsvmap; /* offset to memory reserve map */ | ||
12 | uint32_t version; /* format version */ | ||
13 | uint32_t last_comp_version; /* last compatible version */ | ||
14 | |||
15 | /* version 2 fields below */ | ||
16 | uint32_t boot_cpuid_phys; /* Which physical CPU id we're | ||
17 | booting on */ | ||
18 | /* version 3 fields below */ | ||
19 | uint32_t size_dt_strings; /* size of the strings block */ | ||
20 | |||
21 | /* version 17 fields below */ | ||
22 | uint32_t size_dt_struct; /* size of the structure block */ | ||
23 | }; | ||
24 | |||
25 | struct fdt_reserve_entry { | ||
26 | uint64_t address; | ||
27 | uint64_t size; | ||
28 | }; | ||
29 | |||
30 | struct fdt_node_header { | ||
31 | uint32_t tag; | ||
32 | char name[0]; | ||
33 | }; | ||
34 | |||
35 | struct fdt_property { | ||
36 | uint32_t tag; | ||
37 | uint32_t len; | ||
38 | uint32_t nameoff; | ||
39 | char data[0]; | ||
40 | }; | ||
41 | |||
42 | #endif /* !__ASSEMBLY */ | ||
43 | |||
44 | #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ | ||
45 | #define FDT_TAGSIZE sizeof(uint32_t) | ||
46 | |||
47 | #define FDT_BEGIN_NODE 0x1 /* Start node: full name */ | ||
48 | #define FDT_END_NODE 0x2 /* End node */ | ||
49 | #define FDT_PROP 0x3 /* Property: name off, | ||
50 | size, content */ | ||
51 | #define FDT_NOP 0x4 /* nop */ | ||
52 | #define FDT_END 0x9 | ||
53 | |||
54 | #define FDT_V1_SIZE (7*sizeof(uint32_t)) | ||
55 | #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) | ||
56 | #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) | ||
57 | #define FDT_V16_SIZE FDT_V3_SIZE | ||
58 | #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) | ||
59 | |||
60 | #endif /* _FDT_H */ | ||
diff --git a/arch/powerpc/boot/libfdt/fdt_ro.c b/arch/powerpc/boot/libfdt/fdt_ro.c new file mode 100644 index 000000000000..12a37d59f96e --- /dev/null +++ b/arch/powerpc/boot/libfdt/fdt_ro.c | |||
@@ -0,0 +1,583 @@ | |||
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 | |||
58 | #define CHECK_HEADER(fdt) \ | ||
59 | { \ | ||
60 | int err; \ | ||
61 | if ((err = fdt_check_header(fdt)) != 0) \ | ||
62 | return err; \ | ||
63 | } | ||
64 | |||
65 | static int nodename_eq(const void *fdt, int offset, | ||
66 | const char *s, int len) | ||
67 | { | ||
68 | const char *p = fdt_offset_ptr(fdt, offset, len+1); | ||
69 | |||
70 | if (! p) | ||
71 | /* short match */ | ||
72 | return 0; | ||
73 | |||
74 | if (memcmp(p, s, len) != 0) | ||
75 | return 0; | ||
76 | |||
77 | if (p[len] == '\0') | ||
78 | return 1; | ||
79 | else if (!memchr(s, '@', len) && (p[len] == '@')) | ||
80 | return 1; | ||
81 | else | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | const char *fdt_string(const void *fdt, int stroffset) | ||
86 | { | ||
87 | return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset; | ||
88 | } | ||
89 | |||
90 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) | ||
91 | { | ||
92 | CHECK_HEADER(fdt); | ||
93 | *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); | ||
94 | *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | int fdt_num_mem_rsv(const void *fdt) | ||
99 | { | ||
100 | int i = 0; | ||
101 | |||
102 | while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) | ||
103 | i++; | ||
104 | return i; | ||
105 | } | ||
106 | |||
107 | int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, | ||
108 | const char *name, int namelen) | ||
109 | { | ||
110 | int level = 0; | ||
111 | uint32_t tag; | ||
112 | int offset, nextoffset; | ||
113 | |||
114 | CHECK_HEADER(fdt); | ||
115 | |||
116 | tag = fdt_next_tag(fdt, parentoffset, &nextoffset); | ||
117 | if (tag != FDT_BEGIN_NODE) | ||
118 | return -FDT_ERR_BADOFFSET; | ||
119 | |||
120 | do { | ||
121 | offset = nextoffset; | ||
122 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
123 | |||
124 | switch (tag) { | ||
125 | case FDT_END: | ||
126 | return -FDT_ERR_TRUNCATED; | ||
127 | |||
128 | case FDT_BEGIN_NODE: | ||
129 | level++; | ||
130 | if (level != 1) | ||
131 | continue; | ||
132 | if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen)) | ||
133 | /* Found it! */ | ||
134 | return offset; | ||
135 | break; | ||
136 | |||
137 | case FDT_END_NODE: | ||
138 | level--; | ||
139 | break; | ||
140 | |||
141 | case FDT_PROP: | ||
142 | case FDT_NOP: | ||
143 | break; | ||
144 | |||
145 | default: | ||
146 | return -FDT_ERR_BADSTRUCTURE; | ||
147 | } | ||
148 | } while (level >= 0); | ||
149 | |||
150 | return -FDT_ERR_NOTFOUND; | ||
151 | } | ||
152 | |||
153 | int fdt_subnode_offset(const void *fdt, int parentoffset, | ||
154 | const char *name) | ||
155 | { | ||
156 | return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); | ||
157 | } | ||
158 | |||
159 | int fdt_path_offset(const void *fdt, const char *path) | ||
160 | { | ||
161 | const char *end = path + strlen(path); | ||
162 | const char *p = path; | ||
163 | int offset = 0; | ||
164 | |||
165 | CHECK_HEADER(fdt); | ||
166 | |||
167 | if (*path != '/') | ||
168 | return -FDT_ERR_BADPATH; | ||
169 | |||
170 | while (*p) { | ||
171 | const char *q; | ||
172 | |||
173 | while (*p == '/') | ||
174 | p++; | ||
175 | if (! *p) | ||
176 | return offset; | ||
177 | q = strchr(p, '/'); | ||
178 | if (! q) | ||
179 | q = end; | ||
180 | |||
181 | offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); | ||
182 | if (offset < 0) | ||
183 | return offset; | ||
184 | |||
185 | p = q; | ||
186 | } | ||
187 | |||
188 | return offset; | ||
189 | } | ||
190 | |||
191 | const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) | ||
192 | { | ||
193 | const struct fdt_node_header *nh; | ||
194 | int err; | ||
195 | |||
196 | if ((err = fdt_check_header(fdt)) != 0) | ||
197 | goto fail; | ||
198 | |||
199 | err = -FDT_ERR_BADOFFSET; | ||
200 | nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh)); | ||
201 | if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE)) | ||
202 | goto fail; | ||
203 | |||
204 | if (len) | ||
205 | *len = strlen(nh->name); | ||
206 | |||
207 | return nh->name; | ||
208 | |||
209 | fail: | ||
210 | if (len) | ||
211 | *len = err; | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | const struct fdt_property *fdt_get_property(const void *fdt, | ||
216 | int nodeoffset, | ||
217 | const char *name, int *lenp) | ||
218 | { | ||
219 | uint32_t tag; | ||
220 | const struct fdt_property *prop; | ||
221 | int namestroff; | ||
222 | int offset, nextoffset; | ||
223 | int err; | ||
224 | |||
225 | if ((err = fdt_check_header(fdt)) != 0) | ||
226 | goto fail; | ||
227 | |||
228 | err = -FDT_ERR_BADOFFSET; | ||
229 | if (nodeoffset % FDT_TAGSIZE) | ||
230 | goto fail; | ||
231 | |||
232 | tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); | ||
233 | if (tag != FDT_BEGIN_NODE) | ||
234 | goto fail; | ||
235 | |||
236 | do { | ||
237 | offset = nextoffset; | ||
238 | |||
239 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
240 | switch (tag) { | ||
241 | case FDT_END: | ||
242 | err = -FDT_ERR_TRUNCATED; | ||
243 | goto fail; | ||
244 | |||
245 | case FDT_BEGIN_NODE: | ||
246 | case FDT_END_NODE: | ||
247 | case FDT_NOP: | ||
248 | break; | ||
249 | |||
250 | case FDT_PROP: | ||
251 | err = -FDT_ERR_BADSTRUCTURE; | ||
252 | prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); | ||
253 | if (! prop) | ||
254 | goto fail; | ||
255 | namestroff = fdt32_to_cpu(prop->nameoff); | ||
256 | if (streq(fdt_string(fdt, namestroff), name)) { | ||
257 | /* Found it! */ | ||
258 | int len = fdt32_to_cpu(prop->len); | ||
259 | prop = fdt_offset_ptr(fdt, offset, | ||
260 | sizeof(*prop)+len); | ||
261 | if (! prop) | ||
262 | goto fail; | ||
263 | |||
264 | if (lenp) | ||
265 | *lenp = len; | ||
266 | |||
267 | return prop; | ||
268 | } | ||
269 | break; | ||
270 | |||
271 | default: | ||
272 | err = -FDT_ERR_BADSTRUCTURE; | ||
273 | goto fail; | ||
274 | } | ||
275 | } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); | ||
276 | |||
277 | err = -FDT_ERR_NOTFOUND; | ||
278 | fail: | ||
279 | if (lenp) | ||
280 | *lenp = err; | ||
281 | return NULL; | ||
282 | } | ||
283 | |||
284 | const void *fdt_getprop(const void *fdt, int nodeoffset, | ||
285 | const char *name, int *lenp) | ||
286 | { | ||
287 | const struct fdt_property *prop; | ||
288 | |||
289 | prop = fdt_get_property(fdt, nodeoffset, name, lenp); | ||
290 | if (! prop) | ||
291 | return NULL; | ||
292 | |||
293 | return prop->data; | ||
294 | } | ||
295 | |||
296 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) | ||
297 | { | ||
298 | const uint32_t *php; | ||
299 | int len; | ||
300 | |||
301 | php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); | ||
302 | if (!php || (len != sizeof(*php))) | ||
303 | return 0; | ||
304 | |||
305 | return fdt32_to_cpu(*php); | ||
306 | } | ||
307 | |||
308 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | ||
309 | { | ||
310 | uint32_t tag; | ||
311 | int p = 0, overflow = 0; | ||
312 | int offset, nextoffset, namelen; | ||
313 | const char *name; | ||
314 | |||
315 | CHECK_HEADER(fdt); | ||
316 | |||
317 | tag = fdt_next_tag(fdt, 0, &nextoffset); | ||
318 | if (tag != FDT_BEGIN_NODE) | ||
319 | return -FDT_ERR_BADSTRUCTURE; | ||
320 | |||
321 | if (buflen < 2) | ||
322 | return -FDT_ERR_NOSPACE; | ||
323 | buf[0] = '/'; | ||
324 | p = 1; | ||
325 | |||
326 | while (nextoffset <= nodeoffset) { | ||
327 | offset = nextoffset; | ||
328 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
329 | switch (tag) { | ||
330 | case FDT_END: | ||
331 | return -FDT_ERR_BADOFFSET; | ||
332 | |||
333 | case FDT_BEGIN_NODE: | ||
334 | name = fdt_get_name(fdt, offset, &namelen); | ||
335 | if (!name) | ||
336 | return namelen; | ||
337 | if (overflow || ((p + namelen + 1) > buflen)) { | ||
338 | overflow++; | ||
339 | break; | ||
340 | } | ||
341 | memcpy(buf + p, name, namelen); | ||
342 | p += namelen; | ||
343 | buf[p++] = '/'; | ||
344 | break; | ||
345 | |||
346 | case FDT_END_NODE: | ||
347 | if (overflow) { | ||
348 | overflow--; | ||
349 | break; | ||
350 | } | ||
351 | do { | ||
352 | p--; | ||
353 | } while (buf[p-1] != '/'); | ||
354 | break; | ||
355 | |||
356 | case FDT_PROP: | ||
357 | case FDT_NOP: | ||
358 | break; | ||
359 | |||
360 | default: | ||
361 | return -FDT_ERR_BADSTRUCTURE; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | if (overflow) | ||
366 | return -FDT_ERR_NOSPACE; | ||
367 | |||
368 | if (p > 1) /* special case so that root path is "/", not "" */ | ||
369 | p--; | ||
370 | buf[p] = '\0'; | ||
371 | return p; | ||
372 | } | ||
373 | |||
374 | int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, | ||
375 | int supernodedepth, int *nodedepth) | ||
376 | { | ||
377 | int level = -1; | ||
378 | uint32_t tag; | ||
379 | int offset, nextoffset = 0; | ||
380 | int supernodeoffset = -FDT_ERR_INTERNAL; | ||
381 | |||
382 | CHECK_HEADER(fdt); | ||
383 | |||
384 | if (supernodedepth < 0) | ||
385 | return -FDT_ERR_NOTFOUND; | ||
386 | |||
387 | do { | ||
388 | offset = nextoffset; | ||
389 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
390 | switch (tag) { | ||
391 | case FDT_END: | ||
392 | return -FDT_ERR_BADOFFSET; | ||
393 | |||
394 | case FDT_BEGIN_NODE: | ||
395 | level++; | ||
396 | if (level == supernodedepth) | ||
397 | supernodeoffset = offset; | ||
398 | break; | ||
399 | |||
400 | case FDT_END_NODE: | ||
401 | level--; | ||
402 | break; | ||
403 | |||
404 | case FDT_PROP: | ||
405 | case FDT_NOP: | ||
406 | break; | ||
407 | |||
408 | default: | ||
409 | return -FDT_ERR_BADSTRUCTURE; | ||
410 | } | ||
411 | } while (offset < nodeoffset); | ||
412 | |||
413 | if (nodedepth) | ||
414 | *nodedepth = level; | ||
415 | |||
416 | if (supernodedepth > level) | ||
417 | return -FDT_ERR_NOTFOUND; | ||
418 | return supernodeoffset; | ||
419 | } | ||
420 | |||
421 | int fdt_node_depth(const void *fdt, int nodeoffset) | ||
422 | { | ||
423 | int nodedepth; | ||
424 | int err; | ||
425 | |||
426 | err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); | ||
427 | if (err) | ||
428 | return (err < 0) ? err : -FDT_ERR_INTERNAL; | ||
429 | return nodedepth; | ||
430 | } | ||
431 | |||
432 | int fdt_parent_offset(const void *fdt, int nodeoffset) | ||
433 | { | ||
434 | int nodedepth = fdt_node_depth(fdt, nodeoffset); | ||
435 | |||
436 | if (nodedepth < 0) | ||
437 | return nodedepth; | ||
438 | return fdt_supernode_atdepth_offset(fdt, nodeoffset, | ||
439 | nodedepth - 1, NULL); | ||
440 | } | ||
441 | |||
442 | int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, | ||
443 | const char *propname, | ||
444 | const void *propval, int proplen) | ||
445 | { | ||
446 | uint32_t tag; | ||
447 | int offset, nextoffset; | ||
448 | const void *val; | ||
449 | int len; | ||
450 | |||
451 | CHECK_HEADER(fdt); | ||
452 | |||
453 | if (startoffset >= 0) { | ||
454 | tag = fdt_next_tag(fdt, startoffset, &nextoffset); | ||
455 | if (tag != FDT_BEGIN_NODE) | ||
456 | return -FDT_ERR_BADOFFSET; | ||
457 | } else { | ||
458 | nextoffset = 0; | ||
459 | } | ||
460 | |||
461 | /* FIXME: The algorithm here is pretty horrible: we scan each | ||
462 | * property of a node in fdt_getprop(), then if that didn't | ||
463 | * find what we want, we scan over them again making our way | ||
464 | * to the next node. Still it's the easiest to implement | ||
465 | * approach; performance can come later. */ | ||
466 | do { | ||
467 | offset = nextoffset; | ||
468 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
469 | |||
470 | switch (tag) { | ||
471 | case FDT_BEGIN_NODE: | ||
472 | val = fdt_getprop(fdt, offset, propname, &len); | ||
473 | if (val | ||
474 | && (len == proplen) | ||
475 | && (memcmp(val, propval, len) == 0)) | ||
476 | return offset; | ||
477 | break; | ||
478 | |||
479 | case FDT_PROP: | ||
480 | case FDT_END: | ||
481 | case FDT_END_NODE: | ||
482 | case FDT_NOP: | ||
483 | break; | ||
484 | |||
485 | default: | ||
486 | return -FDT_ERR_BADSTRUCTURE; | ||
487 | } | ||
488 | } while (tag != FDT_END); | ||
489 | |||
490 | return -FDT_ERR_NOTFOUND; | ||
491 | } | ||
492 | |||
493 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) | ||
494 | { | ||
495 | if ((phandle == 0) || (phandle == -1)) | ||
496 | return -FDT_ERR_BADPHANDLE; | ||
497 | phandle = cpu_to_fdt32(phandle); | ||
498 | return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", | ||
499 | &phandle, sizeof(phandle)); | ||
500 | } | ||
501 | |||
502 | int _stringlist_contains(const void *strlist, int listlen, const char *str) | ||
503 | { | ||
504 | int len = strlen(str); | ||
505 | const void *p; | ||
506 | |||
507 | while (listlen >= len) { | ||
508 | if (memcmp(str, strlist, len+1) == 0) | ||
509 | return 1; | ||
510 | p = memchr(strlist, '\0', listlen); | ||
511 | if (!p) | ||
512 | return 0; /* malformed strlist.. */ | ||
513 | listlen -= (p-strlist) + 1; | ||
514 | strlist = p + 1; | ||
515 | } | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | int fdt_node_check_compatible(const void *fdt, int nodeoffset, | ||
520 | const char *compatible) | ||
521 | { | ||
522 | const void *prop; | ||
523 | int len; | ||
524 | |||
525 | prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); | ||
526 | if (!prop) | ||
527 | return len; | ||
528 | if (_stringlist_contains(prop, len, compatible)) | ||
529 | return 0; | ||
530 | else | ||
531 | return 1; | ||
532 | } | ||
533 | |||
534 | int fdt_node_offset_by_compatible(const void *fdt, int startoffset, | ||
535 | const char *compatible) | ||
536 | { | ||
537 | uint32_t tag; | ||
538 | int offset, nextoffset; | ||
539 | int err; | ||
540 | |||
541 | CHECK_HEADER(fdt); | ||
542 | |||
543 | if (startoffset >= 0) { | ||
544 | tag = fdt_next_tag(fdt, startoffset, &nextoffset); | ||
545 | if (tag != FDT_BEGIN_NODE) | ||
546 | return -FDT_ERR_BADOFFSET; | ||
547 | } else { | ||
548 | nextoffset = 0; | ||
549 | } | ||
550 | |||
551 | /* FIXME: The algorithm here is pretty horrible: we scan each | ||
552 | * property of a node in fdt_node_check_compatible(), then if | ||
553 | * that didn't find what we want, we scan over them again | ||
554 | * making our way to the next node. Still it's the easiest to | ||
555 | * implement approach; performance can come later. */ | ||
556 | do { | ||
557 | offset = nextoffset; | ||
558 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
559 | |||
560 | switch (tag) { | ||
561 | case FDT_BEGIN_NODE: | ||
562 | err = fdt_node_check_compatible(fdt, offset, | ||
563 | compatible); | ||
564 | if ((err < 0) | ||
565 | && (err != -FDT_ERR_NOTFOUND)) | ||
566 | return err; | ||
567 | else if (err == 0) | ||
568 | return offset; | ||
569 | break; | ||
570 | |||
571 | case FDT_PROP: | ||
572 | case FDT_END: | ||
573 | case FDT_END_NODE: | ||
574 | case FDT_NOP: | ||
575 | break; | ||
576 | |||
577 | default: | ||
578 | return -FDT_ERR_BADSTRUCTURE; | ||
579 | } | ||
580 | } while (tag != FDT_END); | ||
581 | |||
582 | return -FDT_ERR_NOTFOUND; | ||
583 | } | ||
diff --git a/arch/powerpc/boot/libfdt/fdt_rw.c b/arch/powerpc/boot/libfdt/fdt_rw.c new file mode 100644 index 000000000000..6673f8ec962a --- /dev/null +++ b/arch/powerpc/boot/libfdt/fdt_rw.c | |||
@@ -0,0 +1,447 @@ | |||
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 | |||
58 | static int _blocks_misordered(const void *fdt, | ||
59 | int mem_rsv_size, int struct_size) | ||
60 | { | ||
61 | return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8)) | ||
62 | || (fdt_off_dt_struct(fdt) < | ||
63 | (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) | ||
64 | || (fdt_off_dt_strings(fdt) < | ||
65 | (fdt_off_dt_struct(fdt) + struct_size)) | ||
66 | || (fdt_totalsize(fdt) < | ||
67 | (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); | ||
68 | } | ||
69 | |||
70 | static int rw_check_header(void *fdt) | ||
71 | { | ||
72 | int err; | ||
73 | |||
74 | if ((err = fdt_check_header(fdt))) | ||
75 | return err; | ||
76 | if (fdt_version(fdt) < 17) | ||
77 | return -FDT_ERR_BADVERSION; | ||
78 | if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), | ||
79 | fdt_size_dt_struct(fdt))) | ||
80 | return -FDT_ERR_BADLAYOUT; | ||
81 | if (fdt_version(fdt) > 17) | ||
82 | fdt_set_version(fdt, 17); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | #define RW_CHECK_HEADER(fdt) \ | ||
88 | { \ | ||
89 | int err; \ | ||
90 | if ((err = rw_check_header(fdt)) != 0) \ | ||
91 | return err; \ | ||
92 | } | ||
93 | |||
94 | static inline int _blob_data_size(void *fdt) | ||
95 | { | ||
96 | return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); | ||
97 | } | ||
98 | |||
99 | static int _blob_splice(void *fdt, void *p, int oldlen, int newlen) | ||
100 | { | ||
101 | void *end = fdt + _blob_data_size(fdt); | ||
102 | |||
103 | if (((p + oldlen) < p) || ((p + oldlen) > end)) | ||
104 | return -FDT_ERR_BADOFFSET; | ||
105 | if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt))) | ||
106 | return -FDT_ERR_NOSPACE; | ||
107 | memmove(p + newlen, p + oldlen, end - p - oldlen); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, | ||
112 | int oldn, int newn) | ||
113 | { | ||
114 | int delta = (newn - oldn) * sizeof(*p); | ||
115 | int err; | ||
116 | err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); | ||
117 | if (err) | ||
118 | return err; | ||
119 | fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); | ||
120 | fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int _blob_splice_struct(void *fdt, void *p, | ||
125 | int oldlen, int newlen) | ||
126 | { | ||
127 | int delta = newlen - oldlen; | ||
128 | int err; | ||
129 | |||
130 | if ((err = _blob_splice(fdt, p, oldlen, newlen))) | ||
131 | return err; | ||
132 | |||
133 | fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); | ||
134 | fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int _blob_splice_string(void *fdt, int newlen) | ||
139 | { | ||
140 | void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); | ||
141 | int err; | ||
142 | |||
143 | if ((err = _blob_splice(fdt, p, 0, newlen))) | ||
144 | return err; | ||
145 | |||
146 | fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int _find_add_string(void *fdt, const char *s) | ||
151 | { | ||
152 | char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); | ||
153 | const char *p; | ||
154 | char *new; | ||
155 | int len = strlen(s) + 1; | ||
156 | int err; | ||
157 | |||
158 | p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); | ||
159 | if (p) | ||
160 | /* found it */ | ||
161 | return (p - strtab); | ||
162 | |||
163 | new = strtab + fdt_size_dt_strings(fdt); | ||
164 | err = _blob_splice_string(fdt, len); | ||
165 | if (err) | ||
166 | return err; | ||
167 | |||
168 | memcpy(new, s, len); | ||
169 | return (new - strtab); | ||
170 | } | ||
171 | |||
172 | int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) | ||
173 | { | ||
174 | struct fdt_reserve_entry *re; | ||
175 | int err; | ||
176 | |||
177 | if ((err = rw_check_header(fdt))) | ||
178 | return err; | ||
179 | |||
180 | re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); | ||
181 | err = _blob_splice_mem_rsv(fdt, re, 0, 1); | ||
182 | if (err) | ||
183 | return err; | ||
184 | |||
185 | re->address = cpu_to_fdt64(address); | ||
186 | re->size = cpu_to_fdt64(size); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | int fdt_del_mem_rsv(void *fdt, int n) | ||
191 | { | ||
192 | struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); | ||
193 | int err; | ||
194 | |||
195 | if ((err = rw_check_header(fdt))) | ||
196 | return err; | ||
197 | if (n >= fdt_num_mem_rsv(fdt)) | ||
198 | return -FDT_ERR_NOTFOUND; | ||
199 | |||
200 | err = _blob_splice_mem_rsv(fdt, re, 1, 0); | ||
201 | if (err) | ||
202 | return err; | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int _resize_property(void *fdt, int nodeoffset, const char *name, int len, | ||
207 | struct fdt_property **prop) | ||
208 | { | ||
209 | int oldlen; | ||
210 | int err; | ||
211 | |||
212 | *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); | ||
213 | if (! (*prop)) | ||
214 | return oldlen; | ||
215 | |||
216 | if ((err = _blob_splice_struct(fdt, (*prop)->data, | ||
217 | ALIGN(oldlen, FDT_TAGSIZE), | ||
218 | ALIGN(len, FDT_TAGSIZE)))) | ||
219 | return err; | ||
220 | |||
221 | (*prop)->len = cpu_to_fdt32(len); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int _add_property(void *fdt, int nodeoffset, const char *name, int len, | ||
226 | struct fdt_property **prop) | ||
227 | { | ||
228 | uint32_t tag; | ||
229 | int proplen; | ||
230 | int nextoffset; | ||
231 | int namestroff; | ||
232 | int err; | ||
233 | |||
234 | tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); | ||
235 | if (tag != FDT_BEGIN_NODE) | ||
236 | return -FDT_ERR_BADOFFSET; | ||
237 | |||
238 | namestroff = _find_add_string(fdt, name); | ||
239 | if (namestroff < 0) | ||
240 | return namestroff; | ||
241 | |||
242 | *prop = _fdt_offset_ptr_w(fdt, nextoffset); | ||
243 | proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE); | ||
244 | |||
245 | err = _blob_splice_struct(fdt, *prop, 0, proplen); | ||
246 | if (err) | ||
247 | return err; | ||
248 | |||
249 | (*prop)->tag = cpu_to_fdt32(FDT_PROP); | ||
250 | (*prop)->nameoff = cpu_to_fdt32(namestroff); | ||
251 | (*prop)->len = cpu_to_fdt32(len); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | int fdt_setprop(void *fdt, int nodeoffset, const char *name, | ||
256 | const void *val, int len) | ||
257 | { | ||
258 | struct fdt_property *prop; | ||
259 | int err; | ||
260 | |||
261 | if ((err = rw_check_header(fdt))) | ||
262 | return err; | ||
263 | |||
264 | err = _resize_property(fdt, nodeoffset, name, len, &prop); | ||
265 | if (err == -FDT_ERR_NOTFOUND) | ||
266 | err = _add_property(fdt, nodeoffset, name, len, &prop); | ||
267 | if (err) | ||
268 | return err; | ||
269 | |||
270 | memcpy(prop->data, val, len); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | int fdt_delprop(void *fdt, int nodeoffset, const char *name) | ||
275 | { | ||
276 | struct fdt_property *prop; | ||
277 | int len, proplen; | ||
278 | |||
279 | RW_CHECK_HEADER(fdt); | ||
280 | |||
281 | prop = fdt_get_property_w(fdt, nodeoffset, name, &len); | ||
282 | if (! prop) | ||
283 | return len; | ||
284 | |||
285 | proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE); | ||
286 | return _blob_splice_struct(fdt, prop, proplen, 0); | ||
287 | } | ||
288 | |||
289 | int fdt_add_subnode_namelen(void *fdt, int parentoffset, | ||
290 | const char *name, int namelen) | ||
291 | { | ||
292 | struct fdt_node_header *nh; | ||
293 | int offset, nextoffset; | ||
294 | int nodelen; | ||
295 | int err; | ||
296 | uint32_t tag; | ||
297 | uint32_t *endtag; | ||
298 | |||
299 | RW_CHECK_HEADER(fdt); | ||
300 | |||
301 | offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); | ||
302 | if (offset >= 0) | ||
303 | return -FDT_ERR_EXISTS; | ||
304 | else if (offset != -FDT_ERR_NOTFOUND) | ||
305 | return offset; | ||
306 | |||
307 | /* Try to place the new node after the parent's properties */ | ||
308 | fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ | ||
309 | do { | ||
310 | offset = nextoffset; | ||
311 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
312 | } while (tag == FDT_PROP); | ||
313 | |||
314 | nh = _fdt_offset_ptr_w(fdt, offset); | ||
315 | nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE; | ||
316 | |||
317 | err = _blob_splice_struct(fdt, nh, 0, nodelen); | ||
318 | if (err) | ||
319 | return err; | ||
320 | |||
321 | nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); | ||
322 | memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE)); | ||
323 | memcpy(nh->name, name, namelen); | ||
324 | endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE); | ||
325 | *endtag = cpu_to_fdt32(FDT_END_NODE); | ||
326 | |||
327 | return offset; | ||
328 | } | ||
329 | |||
330 | int fdt_add_subnode(void *fdt, int parentoffset, const char *name) | ||
331 | { | ||
332 | return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); | ||
333 | } | ||
334 | |||
335 | int fdt_del_node(void *fdt, int nodeoffset) | ||
336 | { | ||
337 | int endoffset; | ||
338 | |||
339 | RW_CHECK_HEADER(fdt); | ||
340 | |||
341 | endoffset = _fdt_node_end_offset(fdt, nodeoffset); | ||
342 | if (endoffset < 0) | ||
343 | return endoffset; | ||
344 | |||
345 | return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), | ||
346 | endoffset - nodeoffset, 0); | ||
347 | } | ||
348 | |||
349 | static void _packblocks(const void *fdt, void *buf, | ||
350 | int mem_rsv_size, int struct_size) | ||
351 | { | ||
352 | int mem_rsv_off, struct_off, strings_off; | ||
353 | |||
354 | mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8); | ||
355 | struct_off = mem_rsv_off + mem_rsv_size; | ||
356 | strings_off = struct_off + struct_size; | ||
357 | |||
358 | memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size); | ||
359 | fdt_set_off_mem_rsvmap(buf, mem_rsv_off); | ||
360 | |||
361 | memmove(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size); | ||
362 | fdt_set_off_dt_struct(buf, struct_off); | ||
363 | fdt_set_size_dt_struct(buf, struct_size); | ||
364 | |||
365 | memmove(buf + strings_off, fdt + fdt_off_dt_strings(fdt), | ||
366 | fdt_size_dt_strings(fdt)); | ||
367 | fdt_set_off_dt_strings(buf, strings_off); | ||
368 | fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt)); | ||
369 | } | ||
370 | |||
371 | int fdt_open_into(const void *fdt, void *buf, int bufsize) | ||
372 | { | ||
373 | int err; | ||
374 | int mem_rsv_size, struct_size; | ||
375 | int newsize; | ||
376 | void *tmp; | ||
377 | |||
378 | err = fdt_check_header(fdt); | ||
379 | if (err) | ||
380 | return err; | ||
381 | |||
382 | mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) | ||
383 | * sizeof(struct fdt_reserve_entry); | ||
384 | |||
385 | if (fdt_version(fdt) >= 17) { | ||
386 | struct_size = fdt_size_dt_struct(fdt); | ||
387 | } else { | ||
388 | struct_size = 0; | ||
389 | while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) | ||
390 | ; | ||
391 | } | ||
392 | |||
393 | if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) { | ||
394 | /* no further work necessary */ | ||
395 | err = fdt_move(fdt, buf, bufsize); | ||
396 | if (err) | ||
397 | return err; | ||
398 | fdt_set_version(buf, 17); | ||
399 | fdt_set_size_dt_struct(buf, struct_size); | ||
400 | fdt_set_totalsize(buf, bufsize); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | /* Need to reorder */ | ||
405 | newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size | ||
406 | + struct_size + fdt_size_dt_strings(fdt); | ||
407 | |||
408 | if (bufsize < newsize) | ||
409 | return -FDT_ERR_NOSPACE; | ||
410 | |||
411 | if (((buf + newsize) <= fdt) | ||
412 | || (buf >= (fdt + fdt_totalsize(fdt)))) { | ||
413 | tmp = buf; | ||
414 | } else { | ||
415 | tmp = (void *)fdt + fdt_totalsize(fdt); | ||
416 | if ((tmp + newsize) > (buf + bufsize)) | ||
417 | return -FDT_ERR_NOSPACE; | ||
418 | } | ||
419 | |||
420 | _packblocks(fdt, tmp, mem_rsv_size, struct_size); | ||
421 | memmove(buf, tmp, newsize); | ||
422 | |||
423 | fdt_set_magic(buf, FDT_MAGIC); | ||
424 | fdt_set_totalsize(buf, bufsize); | ||
425 | fdt_set_version(buf, 17); | ||
426 | fdt_set_last_comp_version(buf, 16); | ||
427 | fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | int fdt_pack(void *fdt) | ||
433 | { | ||
434 | int mem_rsv_size; | ||
435 | int err; | ||
436 | |||
437 | err = rw_check_header(fdt); | ||
438 | if (err) | ||
439 | return err; | ||
440 | |||
441 | mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) | ||
442 | * sizeof(struct fdt_reserve_entry); | ||
443 | _packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); | ||
444 | fdt_set_totalsize(fdt, _blob_data_size(fdt)); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
diff --git a/arch/powerpc/boot/libfdt/fdt_strerror.c b/arch/powerpc/boot/libfdt/fdt_strerror.c new file mode 100644 index 000000000000..f9d32ef5360a --- /dev/null +++ b/arch/powerpc/boot/libfdt/fdt_strerror.c | |||
@@ -0,0 +1,96 @@ | |||
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 | |||
58 | struct errtabent { | ||
59 | const char *str; | ||
60 | }; | ||
61 | |||
62 | #define ERRTABENT(val) \ | ||
63 | [(val)] = { .str = #val, } | ||
64 | |||
65 | static struct errtabent errtable[] = { | ||
66 | ERRTABENT(FDT_ERR_NOTFOUND), | ||
67 | ERRTABENT(FDT_ERR_EXISTS), | ||
68 | ERRTABENT(FDT_ERR_NOSPACE), | ||
69 | |||
70 | ERRTABENT(FDT_ERR_BADOFFSET), | ||
71 | ERRTABENT(FDT_ERR_BADPATH), | ||
72 | ERRTABENT(FDT_ERR_BADSTATE), | ||
73 | |||
74 | ERRTABENT(FDT_ERR_TRUNCATED), | ||
75 | ERRTABENT(FDT_ERR_BADMAGIC), | ||
76 | ERRTABENT(FDT_ERR_BADVERSION), | ||
77 | ERRTABENT(FDT_ERR_BADSTRUCTURE), | ||
78 | ERRTABENT(FDT_ERR_BADLAYOUT), | ||
79 | }; | ||
80 | #define ERRTABSIZE (sizeof(errtable) / sizeof(errtable[0])) | ||
81 | |||
82 | const char *fdt_strerror(int errval) | ||
83 | { | ||
84 | if (errval > 0) | ||
85 | return "<valid offset/length>"; | ||
86 | else if (errval == 0) | ||
87 | return "<no error>"; | ||
88 | else if (errval > -ERRTABSIZE) { | ||
89 | const char *s = errtable[-errval].str; | ||
90 | |||
91 | if (s) | ||
92 | return s; | ||
93 | } | ||
94 | |||
95 | return "<unknown error>"; | ||
96 | } | ||
diff --git a/arch/powerpc/boot/libfdt/fdt_sw.c b/arch/powerpc/boot/libfdt/fdt_sw.c new file mode 100644 index 000000000000..dda2de34b2e0 --- /dev/null +++ b/arch/powerpc/boot/libfdt/fdt_sw.c | |||
@@ -0,0 +1,258 @@ | |||
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 | |||
58 | static int check_header_sw(void *fdt) | ||
59 | { | ||
60 | if (fdt_magic(fdt) != SW_MAGIC) | ||
61 | return -FDT_ERR_BADMAGIC; | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void *grab_space(void *fdt, int len) | ||
66 | { | ||
67 | int offset = fdt_size_dt_struct(fdt); | ||
68 | int spaceleft; | ||
69 | |||
70 | spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) | ||
71 | - fdt_size_dt_strings(fdt); | ||
72 | |||
73 | if ((offset + len < offset) || (offset + len > spaceleft)) | ||
74 | return NULL; | ||
75 | |||
76 | fdt_set_size_dt_struct(fdt, offset + len); | ||
77 | return fdt_offset_ptr_w(fdt, offset, len); | ||
78 | } | ||
79 | |||
80 | int fdt_create(void *buf, int bufsize) | ||
81 | { | ||
82 | void *fdt = buf; | ||
83 | |||
84 | if (bufsize < sizeof(struct fdt_header)) | ||
85 | return -FDT_ERR_NOSPACE; | ||
86 | |||
87 | memset(buf, 0, bufsize); | ||
88 | |||
89 | fdt_set_magic(fdt, SW_MAGIC); | ||
90 | fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); | ||
91 | fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); | ||
92 | fdt_set_totalsize(fdt, bufsize); | ||
93 | |||
94 | fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header), | ||
95 | sizeof(struct fdt_reserve_entry))); | ||
96 | fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); | ||
97 | fdt_set_off_dt_strings(fdt, bufsize); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) | ||
103 | { | ||
104 | struct fdt_reserve_entry *re; | ||
105 | int err = check_header_sw(fdt); | ||
106 | int offset; | ||
107 | |||
108 | if (err) | ||
109 | return err; | ||
110 | if (fdt_size_dt_struct(fdt)) | ||
111 | return -FDT_ERR_BADSTATE; | ||
112 | |||
113 | offset = fdt_off_dt_struct(fdt); | ||
114 | if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) | ||
115 | return -FDT_ERR_NOSPACE; | ||
116 | |||
117 | re = (struct fdt_reserve_entry *)(fdt + offset); | ||
118 | re->address = cpu_to_fdt64(addr); | ||
119 | re->size = cpu_to_fdt64(size); | ||
120 | |||
121 | fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | int fdt_finish_reservemap(void *fdt) | ||
127 | { | ||
128 | return fdt_add_reservemap_entry(fdt, 0, 0); | ||
129 | } | ||
130 | |||
131 | int fdt_begin_node(void *fdt, const char *name) | ||
132 | { | ||
133 | struct fdt_node_header *nh; | ||
134 | int err = check_header_sw(fdt); | ||
135 | int namelen = strlen(name) + 1; | ||
136 | |||
137 | if (err) | ||
138 | return err; | ||
139 | |||
140 | nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE)); | ||
141 | if (! nh) | ||
142 | return -FDT_ERR_NOSPACE; | ||
143 | |||
144 | nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); | ||
145 | memcpy(nh->name, name, namelen); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | int fdt_end_node(void *fdt) | ||
150 | { | ||
151 | uint32_t *en; | ||
152 | int err = check_header_sw(fdt); | ||
153 | |||
154 | if (err) | ||
155 | return err; | ||
156 | |||
157 | en = grab_space(fdt, FDT_TAGSIZE); | ||
158 | if (! en) | ||
159 | return -FDT_ERR_NOSPACE; | ||
160 | |||
161 | *en = cpu_to_fdt32(FDT_END_NODE); | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int find_add_string(void *fdt, const char *s) | ||
166 | { | ||
167 | char *strtab = (char *)fdt + fdt_totalsize(fdt); | ||
168 | const char *p; | ||
169 | int strtabsize = fdt_size_dt_strings(fdt); | ||
170 | int len = strlen(s) + 1; | ||
171 | int struct_top, offset; | ||
172 | |||
173 | p = _fdt_find_string(strtab - strtabsize, strtabsize, s); | ||
174 | if (p) | ||
175 | return p - strtab; | ||
176 | |||
177 | /* Add it */ | ||
178 | offset = -strtabsize - len; | ||
179 | struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); | ||
180 | if (fdt_totalsize(fdt) + offset < struct_top) | ||
181 | return 0; /* no more room :( */ | ||
182 | |||
183 | memcpy(strtab + offset, s, len); | ||
184 | fdt_set_size_dt_strings(fdt, strtabsize + len); | ||
185 | return offset; | ||
186 | } | ||
187 | |||
188 | int fdt_property(void *fdt, const char *name, const void *val, int len) | ||
189 | { | ||
190 | struct fdt_property *prop; | ||
191 | int err = check_header_sw(fdt); | ||
192 | int nameoff; | ||
193 | |||
194 | if (err) | ||
195 | return err; | ||
196 | |||
197 | nameoff = find_add_string(fdt, name); | ||
198 | if (nameoff == 0) | ||
199 | return -FDT_ERR_NOSPACE; | ||
200 | |||
201 | prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE)); | ||
202 | if (! prop) | ||
203 | return -FDT_ERR_NOSPACE; | ||
204 | |||
205 | prop->tag = cpu_to_fdt32(FDT_PROP); | ||
206 | prop->nameoff = cpu_to_fdt32(nameoff); | ||
207 | prop->len = cpu_to_fdt32(len); | ||
208 | memcpy(prop->data, val, len); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int fdt_finish(void *fdt) | ||
213 | { | ||
214 | int err = check_header_sw(fdt); | ||
215 | char *p = (char *)fdt; | ||
216 | uint32_t *end; | ||
217 | int oldstroffset, newstroffset; | ||
218 | uint32_t tag; | ||
219 | int offset, nextoffset; | ||
220 | |||
221 | if (err) | ||
222 | return err; | ||
223 | |||
224 | /* Add terminator */ | ||
225 | end = grab_space(fdt, sizeof(*end)); | ||
226 | if (! end) | ||
227 | return -FDT_ERR_NOSPACE; | ||
228 | *end = cpu_to_fdt32(FDT_END); | ||
229 | |||
230 | /* Relocate the string table */ | ||
231 | oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); | ||
232 | newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); | ||
233 | memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); | ||
234 | fdt_set_off_dt_strings(fdt, newstroffset); | ||
235 | |||
236 | /* Walk the structure, correcting string offsets */ | ||
237 | offset = 0; | ||
238 | while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { | ||
239 | if (tag == FDT_PROP) { | ||
240 | struct fdt_property *prop = | ||
241 | fdt_offset_ptr_w(fdt, offset, sizeof(*prop)); | ||
242 | int nameoff; | ||
243 | |||
244 | if (! prop) | ||
245 | return -FDT_ERR_BADSTRUCTURE; | ||
246 | |||
247 | nameoff = fdt32_to_cpu(prop->nameoff); | ||
248 | nameoff += fdt_size_dt_strings(fdt); | ||
249 | prop->nameoff = cpu_to_fdt32(nameoff); | ||
250 | } | ||
251 | offset = nextoffset; | ||
252 | } | ||
253 | |||
254 | /* Finally, adjust the header */ | ||
255 | fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); | ||
256 | fdt_set_magic(fdt, FDT_MAGIC); | ||
257 | return 0; | ||
258 | } | ||
diff --git a/arch/powerpc/boot/libfdt/fdt_wip.c b/arch/powerpc/boot/libfdt/fdt_wip.c new file mode 100644 index 000000000000..88e24b8318f4 --- /dev/null +++ b/arch/powerpc/boot/libfdt/fdt_wip.c | |||
@@ -0,0 +1,144 @@ | |||
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 | |||
58 | int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, | ||
59 | const void *val, int len) | ||
60 | { | ||
61 | void *propval; | ||
62 | int proplen; | ||
63 | |||
64 | propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); | ||
65 | if (! propval) | ||
66 | return proplen; | ||
67 | |||
68 | if (proplen != len) | ||
69 | return -FDT_ERR_NOSPACE; | ||
70 | |||
71 | memcpy(propval, val, len); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static void nop_region(void *start, int len) | ||
76 | { | ||
77 | uint32_t *p; | ||
78 | |||
79 | for (p = start; (void *)p < (start + len); p++) | ||
80 | *p = cpu_to_fdt32(FDT_NOP); | ||
81 | } | ||
82 | |||
83 | int fdt_nop_property(void *fdt, int nodeoffset, const char *name) | ||
84 | { | ||
85 | struct fdt_property *prop; | ||
86 | int len; | ||
87 | |||
88 | prop = fdt_get_property_w(fdt, nodeoffset, name, &len); | ||
89 | if (! prop) | ||
90 | return len; | ||
91 | |||
92 | nop_region(prop, len + sizeof(*prop)); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | int _fdt_node_end_offset(void *fdt, int nodeoffset) | ||
98 | { | ||
99 | int level = 0; | ||
100 | uint32_t tag; | ||
101 | int offset, nextoffset; | ||
102 | |||
103 | tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); | ||
104 | if (tag != FDT_BEGIN_NODE) | ||
105 | return -FDT_ERR_BADOFFSET; | ||
106 | do { | ||
107 | offset = nextoffset; | ||
108 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
109 | |||
110 | switch (tag) { | ||
111 | case FDT_END: | ||
112 | return offset; | ||
113 | |||
114 | case FDT_BEGIN_NODE: | ||
115 | level++; | ||
116 | break; | ||
117 | |||
118 | case FDT_END_NODE: | ||
119 | level--; | ||
120 | break; | ||
121 | |||
122 | case FDT_PROP: | ||
123 | case FDT_NOP: | ||
124 | break; | ||
125 | |||
126 | default: | ||
127 | return -FDT_ERR_BADSTRUCTURE; | ||
128 | } | ||
129 | } while (level >= 0); | ||
130 | |||
131 | return nextoffset; | ||
132 | } | ||
133 | |||
134 | int fdt_nop_node(void *fdt, int nodeoffset) | ||
135 | { | ||
136 | int endoffset; | ||
137 | |||
138 | endoffset = _fdt_node_end_offset(fdt, nodeoffset); | ||
139 | if (endoffset < 0) | ||
140 | return endoffset; | ||
141 | |||
142 | nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset); | ||
143 | return 0; | ||
144 | } | ||
diff --git a/arch/powerpc/boot/libfdt/libfdt.h b/arch/powerpc/boot/libfdt/libfdt.h new file mode 100644 index 000000000000..6b2fb92ea357 --- /dev/null +++ b/arch/powerpc/boot/libfdt/libfdt.h | |||
@@ -0,0 +1,721 @@ | |||
1 | #ifndef _LIBFDT_H | ||
2 | #define _LIBFDT_H | ||
3 | /* | ||
4 | * libfdt - Flat Device Tree manipulation | ||
5 | * Copyright (C) 2006 David Gibson, IBM Corporation. | ||
6 | * | ||
7 | * libfdt is dual licensed: you can use it either under the terms of | ||
8 | * the GPL, or the BSD license, at your option. | ||
9 | * | ||
10 | * a) This library is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation; either version 2 of the | ||
13 | * License, or (at your option) any later version. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public | ||
21 | * License along with this library; if not, write to the Free | ||
22 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | ||
23 | * MA 02110-1301 USA | ||
24 | * | ||
25 | * Alternatively, | ||
26 | * | ||
27 | * b) Redistribution and use in source and binary forms, with or | ||
28 | * without modification, are permitted provided that the following | ||
29 | * conditions are met: | ||
30 | * | ||
31 | * 1. Redistributions of source code must retain the above | ||
32 | * copyright notice, this list of conditions and the following | ||
33 | * disclaimer. | ||
34 | * 2. Redistributions in binary form must reproduce the above | ||
35 | * copyright notice, this list of conditions and the following | ||
36 | * disclaimer in the documentation and/or other materials | ||
37 | * provided with the distribution. | ||
38 | * | ||
39 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | ||
40 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | ||
41 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
42 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
43 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
44 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
45 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
47 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | ||
50 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | ||
51 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
52 | */ | ||
53 | |||
54 | #include <libfdt_env.h> | ||
55 | #include <fdt.h> | ||
56 | |||
57 | #define FDT_FIRST_SUPPORTED_VERSION 0x10 | ||
58 | #define FDT_LAST_SUPPORTED_VERSION 0x11 | ||
59 | |||
60 | /* Error codes: informative error codes */ | ||
61 | #define FDT_ERR_NOTFOUND 1 | ||
62 | /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ | ||
63 | #define FDT_ERR_EXISTS 2 | ||
64 | /* FDT_ERR_EXISTS: Attemped to create a node or property which | ||
65 | * already exists */ | ||
66 | #define FDT_ERR_NOSPACE 3 | ||
67 | /* FDT_ERR_NOSPACE: Operation needed to expand the device | ||
68 | * tree, but its buffer did not have sufficient space to | ||
69 | * contain the expanded tree. Use fdt_open_into() to move the | ||
70 | * device tree to a buffer with more space. */ | ||
71 | |||
72 | /* Error codes: codes for bad parameters */ | ||
73 | #define FDT_ERR_BADOFFSET 4 | ||
74 | /* FDT_ERR_BADOFFSET: Function was passed a structure block | ||
75 | * offset which is out-of-bounds, or which points to an | ||
76 | * unsuitable part of the structure for the operation. */ | ||
77 | #define FDT_ERR_BADPATH 5 | ||
78 | /* FDT_ERR_BADPATH: Function was passed a badly formatted path | ||
79 | * (e.g. missing a leading / for a function which requires an | ||
80 | * absolute path) */ | ||
81 | #define FDT_ERR_BADPHANDLE 6 | ||
82 | /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle | ||
83 | * value. phandle values of 0 and -1 are not permitted. */ | ||
84 | #define FDT_ERR_BADSTATE 7 | ||
85 | /* FDT_ERR_BADSTATE: Function was passed an incomplete device | ||
86 | * tree created by the sequential-write functions, which is | ||
87 | * not sufficiently complete for the requested operation. */ | ||
88 | |||
89 | /* Error codes: codes for bad device tree blobs */ | ||
90 | #define FDT_ERR_TRUNCATED 8 | ||
91 | /* FDT_ERR_TRUNCATED: Structure block of the given device tree | ||
92 | * ends without an FDT_END tag. */ | ||
93 | #define FDT_ERR_BADMAGIC 9 | ||
94 | /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a | ||
95 | * device tree at all - it is missing the flattened device | ||
96 | * tree magic number. */ | ||
97 | #define FDT_ERR_BADVERSION 10 | ||
98 | /* FDT_ERR_BADVERSION: Given device tree has a version which | ||
99 | * can't be handled by the requested operation. For | ||
100 | * read-write functions, this may mean that fdt_open_into() is | ||
101 | * required to convert the tree to the expected version. */ | ||
102 | #define FDT_ERR_BADSTRUCTURE 11 | ||
103 | /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt | ||
104 | * structure block or other serious error (e.g. misnested | ||
105 | * nodes, or subnodes preceding properties). */ | ||
106 | #define FDT_ERR_BADLAYOUT 12 | ||
107 | /* FDT_ERR_BADLAYOUT: For read-write functions, the given | ||
108 | * device tree has it's sub-blocks in an order that the | ||
109 | * function can't handle (memory reserve map, then structure, | ||
110 | * then strings). Use fdt_open_into() to reorganize the tree | ||
111 | * into a form suitable for the read-write operations. */ | ||
112 | |||
113 | /* "Can't happen" error indicating a bug in libfdt */ | ||
114 | #define FDT_ERR_INTERNAL 13 | ||
115 | /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. | ||
116 | * Should never be returned, if it is, it indicates a bug in | ||
117 | * libfdt itself. */ | ||
118 | |||
119 | #define FDT_ERR_MAX 13 | ||
120 | |||
121 | /**********************************************************************/ | ||
122 | /* Low-level functions (you probably don't need these) */ | ||
123 | /**********************************************************************/ | ||
124 | |||
125 | const void *fdt_offset_ptr(const void *fdt, int offset, int checklen); | ||
126 | static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) | ||
127 | { | ||
128 | return (void *)fdt_offset_ptr(fdt, offset, checklen); | ||
129 | } | ||
130 | |||
131 | uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); | ||
132 | |||
133 | /**********************************************************************/ | ||
134 | /* General functions */ | ||
135 | /**********************************************************************/ | ||
136 | |||
137 | #define fdt_get_header(fdt, field) \ | ||
138 | (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) | ||
139 | #define fdt_magic(fdt) (fdt_get_header(fdt, magic)) | ||
140 | #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) | ||
141 | #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) | ||
142 | #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) | ||
143 | #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) | ||
144 | #define fdt_version(fdt) (fdt_get_header(fdt, version)) | ||
145 | #define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) | ||
146 | #define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) | ||
147 | #define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) | ||
148 | #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) | ||
149 | |||
150 | #define __fdt_set_hdr(name) \ | ||
151 | static inline void fdt_set_##name(void *fdt, uint32_t val) \ | ||
152 | { \ | ||
153 | struct fdt_header *fdth = fdt; \ | ||
154 | fdth->name = cpu_to_fdt32(val); \ | ||
155 | } | ||
156 | __fdt_set_hdr(magic); | ||
157 | __fdt_set_hdr(totalsize); | ||
158 | __fdt_set_hdr(off_dt_struct); | ||
159 | __fdt_set_hdr(off_dt_strings); | ||
160 | __fdt_set_hdr(off_mem_rsvmap); | ||
161 | __fdt_set_hdr(version); | ||
162 | __fdt_set_hdr(last_comp_version); | ||
163 | __fdt_set_hdr(boot_cpuid_phys); | ||
164 | __fdt_set_hdr(size_dt_strings); | ||
165 | __fdt_set_hdr(size_dt_struct); | ||
166 | #undef __fdt_set_hdr | ||
167 | |||
168 | /** | ||
169 | * fdt_check_header - sanity check a device tree or possible device tree | ||
170 | * @fdt: pointer to data which might be a flattened device tree | ||
171 | * | ||
172 | * fdt_check_header() checks that the given buffer contains what | ||
173 | * appears to be a flattened device tree with sane information in its | ||
174 | * header. | ||
175 | * | ||
176 | * returns: | ||
177 | * 0, if the buffer appears to contain a valid device tree | ||
178 | * -FDT_ERR_BADMAGIC, | ||
179 | * -FDT_ERR_BADVERSION, | ||
180 | * -FDT_ERR_BADSTATE, standard meanings, as above | ||
181 | */ | ||
182 | int fdt_check_header(const void *fdt); | ||
183 | |||
184 | /** | ||
185 | * fdt_move - move a device tree around in memory | ||
186 | * @fdt: pointer to the device tree to move | ||
187 | * @buf: pointer to memory where the device is to be moved | ||
188 | * @bufsize: size of the memory space at buf | ||
189 | * | ||
190 | * fdt_move() relocates, if possible, the device tree blob located at | ||
191 | * fdt to the buffer at buf of size bufsize. The buffer may overlap | ||
192 | * with the existing device tree blob at fdt. Therefore, | ||
193 | * fdt_move(fdt, fdt, fdt_totalsize(fdt)) | ||
194 | * should always succeed. | ||
195 | * | ||
196 | * returns: | ||
197 | * 0, on success | ||
198 | * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree | ||
199 | * -FDT_ERR_BADMAGIC, | ||
200 | * -FDT_ERR_BADVERSION, | ||
201 | * -FDT_ERR_BADSTATE, standard meanings | ||
202 | */ | ||
203 | int fdt_move(const void *fdt, void *buf, int bufsize); | ||
204 | |||
205 | /**********************************************************************/ | ||
206 | /* Read-only functions */ | ||
207 | /**********************************************************************/ | ||
208 | |||
209 | /** | ||
210 | * fdt_string - retreive a string from the strings block of a device tree | ||
211 | * @fdt: pointer to the device tree blob | ||
212 | * @stroffset: offset of the string within the strings block (native endian) | ||
213 | * | ||
214 | * fdt_string() retrieves a pointer to a single string from the | ||
215 | * strings block of the device tree blob at fdt. | ||
216 | * | ||
217 | * returns: | ||
218 | * a pointer to the string, on success | ||
219 | * NULL, if stroffset is out of bounds | ||
220 | */ | ||
221 | const char *fdt_string(const void *fdt, int stroffset); | ||
222 | |||
223 | /** | ||
224 | * fdt_num_mem_rsv - retreive the number of memory reserve map entries | ||
225 | * @fdt: pointer to the device tree blob | ||
226 | * | ||
227 | * Returns the number of entries in the device tree blob's memory | ||
228 | * reservation map. This does not include the terminating 0,0 entry | ||
229 | * or any other (0,0) entries reserved for expansion. | ||
230 | * | ||
231 | * returns: | ||
232 | * the number of entries | ||
233 | */ | ||
234 | int fdt_num_mem_rsv(const void *fdt); | ||
235 | |||
236 | /** | ||
237 | * fdt_get_mem_rsv - retreive one memory reserve map entry | ||
238 | * @fdt: pointer to the device tree blob | ||
239 | * @address, @size: pointers to 64-bit variables | ||
240 | * | ||
241 | * On success, *address and *size will contain the address and size of | ||
242 | * the n-th reserve map entry from the device tree blob, in | ||
243 | * native-endian format. | ||
244 | * | ||
245 | * returns: | ||
246 | * 0, on success | ||
247 | * -FDT_ERR_BADMAGIC, | ||
248 | * -FDT_ERR_BADVERSION, | ||
249 | * -FDT_ERR_BADSTATE, standard meanings | ||
250 | */ | ||
251 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); | ||
252 | |||
253 | /** | ||
254 | * fdt_subnode_offset_namelen - find a subnode based on substring | ||
255 | * @fdt: pointer to the device tree blob | ||
256 | * @parentoffset: structure block offset of a node | ||
257 | * @name: name of the subnode to locate | ||
258 | * @namelen: number of characters of name to consider | ||
259 | * | ||
260 | * Identical to fdt_subnode_offset(), but only examine the first | ||
261 | * namelen characters of name for matching the subnode name. This is | ||
262 | * useful for finding subnodes based on a portion of a larger string, | ||
263 | * such as a full path. | ||
264 | */ | ||
265 | int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, | ||
266 | const char *name, int namelen); | ||
267 | /** | ||
268 | * fdt_subnode_offset - find a subnode of a given node | ||
269 | * @fdt: pointer to the device tree blob | ||
270 | * @parentoffset: structure block offset of a node | ||
271 | * @name: name of the subnode to locate | ||
272 | * | ||
273 | * fdt_subnode_offset() finds a subnode of the node at structure block | ||
274 | * offset parentoffset with the given name. name may include a unit | ||
275 | * address, in which case fdt_subnode_offset() will find the subnode | ||
276 | * with that unit address, or the unit address may be omitted, in | ||
277 | * which case fdt_subnode_offset() will find an arbitrary subnode | ||
278 | * whose name excluding unit address matches the given name. | ||
279 | * | ||
280 | * returns: | ||
281 | * structure block offset of the requested subnode (>=0), on success | ||
282 | * -FDT_ERR_NOTFOUND, if the requested subnode does not exist | ||
283 | * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag | ||
284 | * -FDT_ERR_BADMAGIC, | ||
285 | * -FDT_ERR_BADVERSION, | ||
286 | * -FDT_ERR_BADSTATE, | ||
287 | * -FDT_ERR_BADSTRUCTURE, | ||
288 | * -FDT_ERR_TRUNCATED, standard meanings. | ||
289 | */ | ||
290 | int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); | ||
291 | |||
292 | /** | ||
293 | * fdt_path_offset - find a tree node by its full path | ||
294 | * @fdt: pointer to the device tree blob | ||
295 | * @path: full path of the node to locate | ||
296 | * | ||
297 | * fdt_path_offset() finds a node of a given path in the device tree. | ||
298 | * Each path component may omit the unit address portion, but the | ||
299 | * results of this are undefined if any such path component is | ||
300 | * ambiguous (that is if there are multiple nodes at the relevant | ||
301 | * level matching the given component, differentiated only by unit | ||
302 | * address). | ||
303 | * | ||
304 | * returns: | ||
305 | * structure block offset of the node with the requested path (>=0), on success | ||
306 | * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid | ||
307 | * -FDT_ERR_NOTFOUND, if the requested node does not exist | ||
308 | * -FDT_ERR_BADMAGIC, | ||
309 | * -FDT_ERR_BADVERSION, | ||
310 | * -FDT_ERR_BADSTATE, | ||
311 | * -FDT_ERR_BADSTRUCTURE, | ||
312 | * -FDT_ERR_TRUNCATED, standard meanings. | ||
313 | */ | ||
314 | int fdt_path_offset(const void *fdt, const char *path); | ||
315 | |||
316 | /** | ||
317 | * fdt_get_name - retreive the name of a given node | ||
318 | * @fdt: pointer to the device tree blob | ||
319 | * @nodeoffset: structure block offset of the starting node | ||
320 | * @lenp: pointer to an integer variable (will be overwritten) or NULL | ||
321 | * | ||
322 | * fdt_get_name() retrieves the name (including unit address) of the | ||
323 | * device tree node at structure block offset nodeoffset. If lenp is | ||
324 | * non-NULL, the length of this name is also returned, in the integer | ||
325 | * pointed to by lenp. | ||
326 | * | ||
327 | * returns: | ||
328 | * pointer to the node's name, on success | ||
329 | * If lenp is non-NULL, *lenp contains the length of that name (>=0) | ||
330 | * NULL, on error | ||
331 | * if lenp is non-NULL *lenp contains an error code (<0): | ||
332 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag | ||
333 | * -FDT_ERR_BADMAGIC, | ||
334 | * -FDT_ERR_BADVERSION, | ||
335 | * -FDT_ERR_BADSTATE, standard meanings | ||
336 | */ | ||
337 | const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); | ||
338 | |||
339 | /** | ||
340 | * fdt_get_property - find a given property in a given node | ||
341 | * @fdt: pointer to the device tree blob | ||
342 | * @nodeoffset: offset of the node whose property to find | ||
343 | * @name: name of the property to find | ||
344 | * @lenp: pointer to an integer variable (will be overwritten) or NULL | ||
345 | * | ||
346 | * fdt_get_property() retrieves a pointer to the fdt_property | ||
347 | * structure within the device tree blob corresponding to the property | ||
348 | * named 'name' of the node at offset nodeoffset. If lenp is | ||
349 | * non-NULL, the length of the property value also returned, in the | ||
350 | * integer pointed to by lenp. | ||
351 | * | ||
352 | * returns: | ||
353 | * pointer to the structure representing the property | ||
354 | * if lenp is non-NULL, *lenp contains the length of the property | ||
355 | * value (>=0) | ||
356 | * NULL, on error | ||
357 | * if lenp is non-NULL, *lenp contains an error code (<0): | ||
358 | * -FDT_ERR_NOTFOUND, node does not have named property | ||
359 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag | ||
360 | * -FDT_ERR_BADMAGIC, | ||
361 | * -FDT_ERR_BADVERSION, | ||
362 | * -FDT_ERR_BADSTATE, | ||
363 | * -FDT_ERR_BADSTRUCTURE, | ||
364 | * -FDT_ERR_TRUNCATED, standard meanings | ||
365 | */ | ||
366 | const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, | ||
367 | const char *name, int *lenp); | ||
368 | static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, | ||
369 | const char *name, | ||
370 | int *lenp) | ||
371 | { | ||
372 | return (struct fdt_property *)fdt_get_property(fdt, nodeoffset, | ||
373 | name, lenp); | ||
374 | } | ||
375 | |||
376 | /** | ||
377 | * fdt_getprop - retrieve the value of a given property | ||
378 | * @fdt: pointer to the device tree blob | ||
379 | * @nodeoffset: offset of the node whose property to find | ||
380 | * @name: name of the property to find | ||
381 | * @lenp: pointer to an integer variable (will be overwritten) or NULL | ||
382 | * | ||
383 | * fdt_getprop() retrieves a pointer to the value of the property | ||
384 | * named 'name' of the node at offset nodeoffset (this will be a | ||
385 | * pointer to within the device blob itself, not a copy of the value). | ||
386 | * If lenp is non-NULL, the length of the property value also | ||
387 | * returned, in the integer pointed to by lenp. | ||
388 | * | ||
389 | * returns: | ||
390 | * pointer to the property's value | ||
391 | * if lenp is non-NULL, *lenp contains the length of the property | ||
392 | * value (>=0) | ||
393 | * NULL, on error | ||
394 | * if lenp is non-NULL, *lenp contains an error code (<0): | ||
395 | * -FDT_ERR_NOTFOUND, node does not have named property | ||
396 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag | ||
397 | * -FDT_ERR_BADMAGIC, | ||
398 | * -FDT_ERR_BADVERSION, | ||
399 | * -FDT_ERR_BADSTATE, | ||
400 | * -FDT_ERR_BADSTRUCTURE, | ||
401 | * -FDT_ERR_TRUNCATED, standard meanings | ||
402 | */ | ||
403 | const void *fdt_getprop(const void *fdt, int nodeoffset, | ||
404 | const char *name, int *lenp); | ||
405 | static inline void *fdt_getprop_w(void *fdt, int nodeoffset, | ||
406 | const char *name, int *lenp) | ||
407 | { | ||
408 | return (void *)fdt_getprop(fdt, nodeoffset, name, lenp); | ||
409 | } | ||
410 | |||
411 | /** | ||
412 | * fdt_get_phandle - retreive the phandle of a given node | ||
413 | * @fdt: pointer to the device tree blob | ||
414 | * @nodeoffset: structure block offset of the node | ||
415 | * | ||
416 | * fdt_get_phandle() retrieves the phandle of the device tree node at | ||
417 | * structure block offset nodeoffset. | ||
418 | * | ||
419 | * returns: | ||
420 | * the phandle of the node at nodeoffset, on succes (!= 0, != -1) | ||
421 | * 0, if the node has no phandle, or another error occurs | ||
422 | */ | ||
423 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); | ||
424 | |||
425 | /** | ||
426 | * fdt_get_path - determine the full path of a node | ||
427 | * @fdt: pointer to the device tree blob | ||
428 | * @nodeoffset: offset of the node whose path to find | ||
429 | * @buf: character buffer to contain the returned path (will be overwritten) | ||
430 | * @buflen: size of the character buffer at buf | ||
431 | * | ||
432 | * fdt_get_path() computes the full path of the node at offset | ||
433 | * nodeoffset, and records that path in the buffer at buf. | ||
434 | * | ||
435 | * NOTE: This function is expensive, as it must scan the device tree | ||
436 | * structure from the start to nodeoffset. | ||
437 | * | ||
438 | * returns: | ||
439 | * 0, on success | ||
440 | * buf contains the absolute path of the node at | ||
441 | * nodeoffset, as a NUL-terminated string. | ||
442 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag | ||
443 | * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) | ||
444 | * characters and will not fit in the given buffer. | ||
445 | * -FDT_ERR_BADMAGIC, | ||
446 | * -FDT_ERR_BADVERSION, | ||
447 | * -FDT_ERR_BADSTATE, | ||
448 | * -FDT_ERR_BADSTRUCTURE, standard meanings | ||
449 | */ | ||
450 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); | ||
451 | |||
452 | /** | ||
453 | * fdt_supernode_atdepth_offset - find a specific ancestor of a node | ||
454 | * @fdt: pointer to the device tree blob | ||
455 | * @nodeoffset: offset of the node whose parent to find | ||
456 | * @supernodedepth: depth of the ancestor to find | ||
457 | * @nodedepth: pointer to an integer variable (will be overwritten) or NULL | ||
458 | * | ||
459 | * fdt_supernode_atdepth_offset() finds an ancestor of the given node | ||
460 | * at a specific depth from the root (where the root itself has depth | ||
461 | * 0, its immediate subnodes depth 1 and so forth). So | ||
462 | * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); | ||
463 | * will always return 0, the offset of the root node. If the node at | ||
464 | * nodeoffset has depth D, then: | ||
465 | * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); | ||
466 | * will return nodeoffset itself. | ||
467 | * | ||
468 | * NOTE: This function is expensive, as it must scan the device tree | ||
469 | * structure from the start to nodeoffset. | ||
470 | * | ||
471 | * returns: | ||
472 | |||
473 | * structure block offset of the node at node offset's ancestor | ||
474 | * of depth supernodedepth (>=0), on success | ||
475 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag | ||
476 | * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset | ||
477 | * -FDT_ERR_BADMAGIC, | ||
478 | * -FDT_ERR_BADVERSION, | ||
479 | * -FDT_ERR_BADSTATE, | ||
480 | * -FDT_ERR_BADSTRUCTURE, standard meanings | ||
481 | */ | ||
482 | int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, | ||
483 | int supernodedepth, int *nodedepth); | ||
484 | |||
485 | /** | ||
486 | * fdt_node_depth - find the depth of a given node | ||
487 | * @fdt: pointer to the device tree blob | ||
488 | * @nodeoffset: offset of the node whose parent to find | ||
489 | * | ||
490 | * fdt_node_depth() finds the depth of a given node. The root node | ||
491 | * has depth 0, its immediate subnodes depth 1 and so forth. | ||
492 | * | ||
493 | * NOTE: This function is expensive, as it must scan the device tree | ||
494 | * structure from the start to nodeoffset. | ||
495 | * | ||
496 | * returns: | ||
497 | * depth of the node at nodeoffset (>=0), on success | ||
498 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag | ||
499 | * -FDT_ERR_BADMAGIC, | ||
500 | * -FDT_ERR_BADVERSION, | ||
501 | * -FDT_ERR_BADSTATE, | ||
502 | * -FDT_ERR_BADSTRUCTURE, standard meanings | ||
503 | */ | ||
504 | int fdt_node_depth(const void *fdt, int nodeoffset); | ||
505 | |||
506 | /** | ||
507 | * fdt_parent_offset - find the parent of a given node | ||
508 | * @fdt: pointer to the device tree blob | ||
509 | * @nodeoffset: offset of the node whose parent to find | ||
510 | * | ||
511 | * fdt_parent_offset() locates the parent node of a given node (that | ||
512 | * is, it finds the offset of the node which contains the node at | ||
513 | * nodeoffset as a subnode). | ||
514 | * | ||
515 | * NOTE: This function is expensive, as it must scan the device tree | ||
516 | * structure from the start to nodeoffset, *twice*. | ||
517 | * | ||
518 | * returns: | ||
519 | * stucture block offset of the parent of the node at nodeoffset | ||
520 | * (>=0), on success | ||
521 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag | ||
522 | * -FDT_ERR_BADMAGIC, | ||
523 | * -FDT_ERR_BADVERSION, | ||
524 | * -FDT_ERR_BADSTATE, | ||
525 | * -FDT_ERR_BADSTRUCTURE, standard meanings | ||
526 | */ | ||
527 | int fdt_parent_offset(const void *fdt, int nodeoffset); | ||
528 | |||
529 | /** | ||
530 | * fdt_node_offset_by_prop_value - find nodes with a given property value | ||
531 | * @fdt: pointer to the device tree blob | ||
532 | * @startoffset: only find nodes after this offset | ||
533 | * @propname: property name to check | ||
534 | * @propval: property value to search for | ||
535 | * @proplen: length of the value in propval | ||
536 | * | ||
537 | * fdt_node_offset_by_prop_value() returns the offset of the first | ||
538 | * node after startoffset, which has a property named propname whose | ||
539 | * value is of length proplen and has value equal to propval; or if | ||
540 | * startoffset is -1, the very first such node in the tree. | ||
541 | * | ||
542 | * To iterate through all nodes matching the criterion, the following | ||
543 | * idiom can be used: | ||
544 | * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, | ||
545 | * propval, proplen); | ||
546 | * while (offset != -FDT_ERR_NOTFOUND) { | ||
547 | * // other code here | ||
548 | * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, | ||
549 | * propval, proplen); | ||
550 | * } | ||
551 | * | ||
552 | * Note the -1 in the first call to the function, if 0 is used here | ||
553 | * instead, the function will never locate the root node, even if it | ||
554 | * matches the criterion. | ||
555 | * | ||
556 | * returns: | ||
557 | * structure block offset of the located node (>= 0, >startoffset), | ||
558 | * on success | ||
559 | * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the | ||
560 | * tree after startoffset | ||
561 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag | ||
562 | * -FDT_ERR_BADMAGIC, | ||
563 | * -FDT_ERR_BADVERSION, | ||
564 | * -FDT_ERR_BADSTATE, | ||
565 | * -FDT_ERR_BADSTRUCTURE, standard meanings | ||
566 | */ | ||
567 | int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, | ||
568 | const char *propname, | ||
569 | const void *propval, int proplen); | ||
570 | |||
571 | /** | ||
572 | * fdt_node_offset_by_phandle - find the node with a given phandle | ||
573 | * @fdt: pointer to the device tree blob | ||
574 | * @phandle: phandle value | ||
575 | * | ||
576 | * fdt_node_offset_by_prop_value() returns the offset of the node | ||
577 | * which has the given phandle value. If there is more than one node | ||
578 | * in the tree with the given phandle (an invalid tree), results are | ||
579 | * undefined. | ||
580 | * | ||
581 | * returns: | ||
582 | * structure block offset of the located node (>= 0), on success | ||
583 | * -FDT_ERR_NOTFOUND, no node with that phandle exists | ||
584 | * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) | ||
585 | * -FDT_ERR_BADMAGIC, | ||
586 | * -FDT_ERR_BADVERSION, | ||
587 | * -FDT_ERR_BADSTATE, | ||
588 | * -FDT_ERR_BADSTRUCTURE, standard meanings | ||
589 | */ | ||
590 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); | ||
591 | |||
592 | /** | ||
593 | * fdt_node_check_compatible: check a node's compatible property | ||
594 | * @fdt: pointer to the device tree blob | ||
595 | * @nodeoffset: offset of a tree node | ||
596 | * @compatible: string to match against | ||
597 | * | ||
598 | * | ||
599 | * fdt_node_check_compatible() returns 0 if the given node contains a | ||
600 | * 'compatible' property with the given string as one of its elements, | ||
601 | * it returns non-zero otherwise, or on error. | ||
602 | * | ||
603 | * returns: | ||
604 | * 0, if the node has a 'compatible' property listing the given string | ||
605 | * 1, if the node has a 'compatible' property, but it does not list | ||
606 | * the given string | ||
607 | * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property | ||
608 | * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag | ||
609 | * -FDT_ERR_BADMAGIC, | ||
610 | * -FDT_ERR_BADVERSION, | ||
611 | * -FDT_ERR_BADSTATE, | ||
612 | * -FDT_ERR_BADSTRUCTURE, standard meanings | ||
613 | */ | ||
614 | int fdt_node_check_compatible(const void *fdt, int nodeoffset, | ||
615 | const char *compatible); | ||
616 | |||
617 | /** | ||
618 | * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value | ||
619 | * @fdt: pointer to the device tree blob | ||
620 | * @startoffset: only find nodes after this offset | ||
621 | * @compatible: 'compatible' string to match against | ||
622 | * | ||
623 | * fdt_node_offset_by_compatible() returns the offset of the first | ||
624 | * node after startoffset, which has a 'compatible' property which | ||
625 | * lists the given compatible string; or if startoffset is -1, the | ||
626 | * very first such node in the tree. | ||
627 | * | ||
628 | * To iterate through all nodes matching the criterion, the following | ||
629 | * idiom can be used: | ||
630 | * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); | ||
631 | * while (offset != -FDT_ERR_NOTFOUND) { | ||
632 | * // other code here | ||
633 | * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); | ||
634 | * } | ||
635 | * | ||
636 | * Note the -1 in the first call to the function, if 0 is used here | ||
637 | * instead, the function will never locate the root node, even if it | ||
638 | * matches the criterion. | ||
639 | * | ||
640 | * returns: | ||
641 | * structure block offset of the located node (>= 0, >startoffset), | ||
642 | * on success | ||
643 | * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the | ||
644 | * tree after startoffset | ||
645 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag | ||
646 | * -FDT_ERR_BADMAGIC, | ||
647 | * -FDT_ERR_BADVERSION, | ||
648 | * -FDT_ERR_BADSTATE, | ||
649 | * -FDT_ERR_BADSTRUCTURE, standard meanings | ||
650 | */ | ||
651 | int fdt_node_offset_by_compatible(const void *fdt, int startoffset, | ||
652 | const char *compatible); | ||
653 | |||
654 | /**********************************************************************/ | ||
655 | /* Write-in-place functions */ | ||
656 | /**********************************************************************/ | ||
657 | |||
658 | int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, | ||
659 | const void *val, int len); | ||
660 | static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, | ||
661 | const char *name, uint32_t val) | ||
662 | { | ||
663 | val = cpu_to_fdt32(val); | ||
664 | return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); | ||
665 | } | ||
666 | |||
667 | int fdt_nop_property(void *fdt, int nodeoffset, const char *name); | ||
668 | int fdt_nop_node(void *fdt, int nodeoffset); | ||
669 | |||
670 | /**********************************************************************/ | ||
671 | /* Sequential write functions */ | ||
672 | /**********************************************************************/ | ||
673 | |||
674 | int fdt_create(void *buf, int bufsize); | ||
675 | int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); | ||
676 | int fdt_finish_reservemap(void *fdt); | ||
677 | int fdt_begin_node(void *fdt, const char *name); | ||
678 | int fdt_property(void *fdt, const char *name, const void *val, int len); | ||
679 | static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) | ||
680 | { | ||
681 | val = cpu_to_fdt32(val); | ||
682 | return fdt_property(fdt, name, &val, sizeof(val)); | ||
683 | } | ||
684 | #define fdt_property_string(fdt, name, str) \ | ||
685 | fdt_property(fdt, name, str, strlen(str)+1) | ||
686 | int fdt_end_node(void *fdt); | ||
687 | int fdt_finish(void *fdt); | ||
688 | |||
689 | /**********************************************************************/ | ||
690 | /* Read-write functions */ | ||
691 | /**********************************************************************/ | ||
692 | |||
693 | int fdt_open_into(const void *fdt, void *buf, int bufsize); | ||
694 | int fdt_pack(void *fdt); | ||
695 | |||
696 | int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); | ||
697 | int fdt_del_mem_rsv(void *fdt, int n); | ||
698 | |||
699 | int fdt_setprop(void *fdt, int nodeoffset, const char *name, | ||
700 | const void *val, int len); | ||
701 | static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, | ||
702 | uint32_t val) | ||
703 | { | ||
704 | val = cpu_to_fdt32(val); | ||
705 | return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); | ||
706 | } | ||
707 | #define fdt_setprop_string(fdt, nodeoffset, name, str) \ | ||
708 | fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) | ||
709 | int fdt_delprop(void *fdt, int nodeoffset, const char *name); | ||
710 | int fdt_add_subnode_namelen(void *fdt, int parentoffset, | ||
711 | const char *name, int namelen); | ||
712 | int fdt_add_subnode(void *fdt, int parentoffset, const char *name); | ||
713 | int fdt_del_node(void *fdt, int nodeoffset); | ||
714 | |||
715 | /**********************************************************************/ | ||
716 | /* Debugging / informational functions */ | ||
717 | /**********************************************************************/ | ||
718 | |||
719 | const char *fdt_strerror(int errval); | ||
720 | |||
721 | #endif /* _LIBFDT_H */ | ||
diff --git a/arch/powerpc/boot/libfdt/libfdt_internal.h b/arch/powerpc/boot/libfdt/libfdt_internal.h new file mode 100644 index 000000000000..1e60936beb5b --- /dev/null +++ b/arch/powerpc/boot/libfdt/libfdt_internal.h | |||
@@ -0,0 +1,89 @@ | |||
1 | #ifndef _LIBFDT_INTERNAL_H | ||
2 | #define _LIBFDT_INTERNAL_H | ||
3 | /* | ||
4 | * libfdt - Flat Device Tree manipulation | ||
5 | * Copyright (C) 2006 David Gibson, IBM Corporation. | ||
6 | * | ||
7 | * libfdt is dual licensed: you can use it either under the terms of | ||
8 | * the GPL, or the BSD license, at your option. | ||
9 | * | ||
10 | * a) This library is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation; either version 2 of the | ||
13 | * License, or (at your option) any later version. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public | ||
21 | * License along with this library; if not, write to the Free | ||
22 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | ||
23 | * MA 02110-1301 USA | ||
24 | * | ||
25 | * Alternatively, | ||
26 | * | ||
27 | * b) Redistribution and use in source and binary forms, with or | ||
28 | * without modification, are permitted provided that the following | ||
29 | * conditions are met: | ||
30 | * | ||
31 | * 1. Redistributions of source code must retain the above | ||
32 | * copyright notice, this list of conditions and the following | ||
33 | * disclaimer. | ||
34 | * 2. Redistributions in binary form must reproduce the above | ||
35 | * copyright notice, this list of conditions and the following | ||
36 | * disclaimer in the documentation and/or other materials | ||
37 | * provided with the distribution. | ||
38 | * | ||
39 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | ||
40 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | ||
41 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
42 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
43 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
44 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
45 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
47 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | ||
50 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | ||
51 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
52 | */ | ||
53 | #include <fdt.h> | ||
54 | |||
55 | #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) | ||
56 | #define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a))) | ||
57 | |||
58 | #define memeq(p, q, n) (memcmp((p), (q), (n)) == 0) | ||
59 | #define streq(p, q) (strcmp((p), (q)) == 0) | ||
60 | |||
61 | uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset); | ||
62 | const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); | ||
63 | int _fdt_node_end_offset(void *fdt, int nodeoffset); | ||
64 | |||
65 | static inline const void *_fdt_offset_ptr(const void *fdt, int offset) | ||
66 | { | ||
67 | return fdt + fdt_off_dt_struct(fdt) + offset; | ||
68 | } | ||
69 | |||
70 | static inline void *_fdt_offset_ptr_w(void *fdt, int offset) | ||
71 | { | ||
72 | return (void *)_fdt_offset_ptr(fdt, offset); | ||
73 | } | ||
74 | |||
75 | static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) | ||
76 | { | ||
77 | const struct fdt_reserve_entry *rsv_table = | ||
78 | fdt + fdt_off_mem_rsvmap(fdt); | ||
79 | |||
80 | return rsv_table + n; | ||
81 | } | ||
82 | static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) | ||
83 | { | ||
84 | return (void *)_fdt_mem_rsv(fdt, n); | ||
85 | } | ||
86 | |||
87 | #define SW_MAGIC (~FDT_MAGIC) | ||
88 | |||
89 | #endif /* _LIBFDT_INTERNAL_H */ | ||