xref: /rk3399_rockchip-uboot/scripts/dtc/libfdt/fdt_ro.c (revision d7857e40f2de4c570bb962d517058aeb5fc87ad4)
1*d18719a4STom Rini /*
2*d18719a4STom Rini  * libfdt - Flat Device Tree manipulation
3*d18719a4STom Rini  * Copyright (C) 2006 David Gibson, IBM Corporation.
4*d18719a4STom Rini  *
5*d18719a4STom Rini  * libfdt is dual licensed: you can use it either under the terms of
6*d18719a4STom Rini  * the GPL, or the BSD license, at your option.
7*d18719a4STom Rini  *
8*d18719a4STom Rini  *  a) This library is free software; you can redistribute it and/or
9*d18719a4STom Rini  *     modify it under the terms of the GNU General Public License as
10*d18719a4STom Rini  *     published by the Free Software Foundation; either version 2 of the
11*d18719a4STom Rini  *     License, or (at your option) any later version.
12*d18719a4STom Rini  *
13*d18719a4STom Rini  *     This library is distributed in the hope that it will be useful,
14*d18719a4STom Rini  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
15*d18719a4STom Rini  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*d18719a4STom Rini  *     GNU General Public License for more details.
17*d18719a4STom Rini  *
18*d18719a4STom Rini  *     You should have received a copy of the GNU General Public
19*d18719a4STom Rini  *     License along with this library; if not, write to the Free
20*d18719a4STom Rini  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21*d18719a4STom Rini  *     MA 02110-1301 USA
22*d18719a4STom Rini  *
23*d18719a4STom Rini  * Alternatively,
24*d18719a4STom Rini  *
25*d18719a4STom Rini  *  b) Redistribution and use in source and binary forms, with or
26*d18719a4STom Rini  *     without modification, are permitted provided that the following
27*d18719a4STom Rini  *     conditions are met:
28*d18719a4STom Rini  *
29*d18719a4STom Rini  *     1. Redistributions of source code must retain the above
30*d18719a4STom Rini  *        copyright notice, this list of conditions and the following
31*d18719a4STom Rini  *        disclaimer.
32*d18719a4STom Rini  *     2. Redistributions in binary form must reproduce the above
33*d18719a4STom Rini  *        copyright notice, this list of conditions and the following
34*d18719a4STom Rini  *        disclaimer in the documentation and/or other materials
35*d18719a4STom Rini  *        provided with the distribution.
36*d18719a4STom Rini  *
37*d18719a4STom Rini  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38*d18719a4STom Rini  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39*d18719a4STom Rini  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40*d18719a4STom Rini  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41*d18719a4STom Rini  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42*d18719a4STom Rini  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43*d18719a4STom Rini  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44*d18719a4STom Rini  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45*d18719a4STom Rini  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46*d18719a4STom Rini  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47*d18719a4STom Rini  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48*d18719a4STom Rini  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49*d18719a4STom Rini  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50*d18719a4STom Rini  */
51*d18719a4STom Rini #include "libfdt_env.h"
52*d18719a4STom Rini 
53*d18719a4STom Rini #include <fdt.h>
54*d18719a4STom Rini #include <libfdt.h>
55*d18719a4STom Rini 
56*d18719a4STom Rini #include "libfdt_internal.h"
57*d18719a4STom Rini 
_fdt_nodename_eq(const void * fdt,int offset,const char * s,int len)58*d18719a4STom Rini static int _fdt_nodename_eq(const void *fdt, int offset,
59*d18719a4STom Rini 			    const char *s, int len)
60*d18719a4STom Rini {
61*d18719a4STom Rini 	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
62*d18719a4STom Rini 
63*d18719a4STom Rini 	if (!p)
64*d18719a4STom Rini 		/* short match */
65*d18719a4STom Rini 		return 0;
66*d18719a4STom Rini 
67*d18719a4STom Rini 	if (memcmp(p, s, len) != 0)
68*d18719a4STom Rini 		return 0;
69*d18719a4STom Rini 
70*d18719a4STom Rini 	if (p[len] == '\0')
71*d18719a4STom Rini 		return 1;
72*d18719a4STom Rini 	else if (!memchr(s, '@', len) && (p[len] == '@'))
73*d18719a4STom Rini 		return 1;
74*d18719a4STom Rini 	else
75*d18719a4STom Rini 		return 0;
76*d18719a4STom Rini }
77*d18719a4STom Rini 
fdt_string(const void * fdt,int stroffset)78*d18719a4STom Rini const char *fdt_string(const void *fdt, int stroffset)
79*d18719a4STom Rini {
80*d18719a4STom Rini 	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
81*d18719a4STom Rini }
82*d18719a4STom Rini 
_fdt_string_eq(const void * fdt,int stroffset,const char * s,int len)83*d18719a4STom Rini static int _fdt_string_eq(const void *fdt, int stroffset,
84*d18719a4STom Rini 			  const char *s, int len)
85*d18719a4STom Rini {
86*d18719a4STom Rini 	const char *p = fdt_string(fdt, stroffset);
87*d18719a4STom Rini 
88*d18719a4STom Rini 	return (strlen(p) == len) && (memcmp(p, s, len) == 0);
89*d18719a4STom Rini }
90*d18719a4STom Rini 
fdt_get_max_phandle(const void * fdt)91*d18719a4STom Rini uint32_t fdt_get_max_phandle(const void *fdt)
92*d18719a4STom Rini {
93*d18719a4STom Rini 	uint32_t max_phandle = 0;
94*d18719a4STom Rini 	int offset;
95*d18719a4STom Rini 
96*d18719a4STom Rini 	for (offset = fdt_next_node(fdt, -1, NULL);;
97*d18719a4STom Rini 	     offset = fdt_next_node(fdt, offset, NULL)) {
98*d18719a4STom Rini 		uint32_t phandle;
99*d18719a4STom Rini 
100*d18719a4STom Rini 		if (offset == -FDT_ERR_NOTFOUND)
101*d18719a4STom Rini 			return max_phandle;
102*d18719a4STom Rini 
103*d18719a4STom Rini 		if (offset < 0)
104*d18719a4STom Rini 			return (uint32_t)-1;
105*d18719a4STom Rini 
106*d18719a4STom Rini 		phandle = fdt_get_phandle(fdt, offset);
107*d18719a4STom Rini 		if (phandle == (uint32_t)-1)
108*d18719a4STom Rini 			continue;
109*d18719a4STom Rini 
110*d18719a4STom Rini 		if (phandle > max_phandle)
111*d18719a4STom Rini 			max_phandle = phandle;
112*d18719a4STom Rini 	}
113*d18719a4STom Rini 
114*d18719a4STom Rini 	return 0;
115*d18719a4STom Rini }
116*d18719a4STom Rini 
fdt_get_mem_rsv(const void * fdt,int n,uint64_t * address,uint64_t * size)117*d18719a4STom Rini int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
118*d18719a4STom Rini {
119*d18719a4STom Rini 	FDT_CHECK_HEADER(fdt);
120*d18719a4STom Rini 	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
121*d18719a4STom Rini 	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
122*d18719a4STom Rini 	return 0;
123*d18719a4STom Rini }
124*d18719a4STom Rini 
fdt_num_mem_rsv(const void * fdt)125*d18719a4STom Rini int fdt_num_mem_rsv(const void *fdt)
126*d18719a4STom Rini {
127*d18719a4STom Rini 	int i = 0;
128*d18719a4STom Rini 
129*d18719a4STom Rini 	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
130*d18719a4STom Rini 		i++;
131*d18719a4STom Rini 	return i;
132*d18719a4STom Rini }
133*d18719a4STom Rini 
_nextprop(const void * fdt,int offset)134*d18719a4STom Rini static int _nextprop(const void *fdt, int offset)
135*d18719a4STom Rini {
136*d18719a4STom Rini 	uint32_t tag;
137*d18719a4STom Rini 	int nextoffset;
138*d18719a4STom Rini 
139*d18719a4STom Rini 	do {
140*d18719a4STom Rini 		tag = fdt_next_tag(fdt, offset, &nextoffset);
141*d18719a4STom Rini 
142*d18719a4STom Rini 		switch (tag) {
143*d18719a4STom Rini 		case FDT_END:
144*d18719a4STom Rini 			if (nextoffset >= 0)
145*d18719a4STom Rini 				return -FDT_ERR_BADSTRUCTURE;
146*d18719a4STom Rini 			else
147*d18719a4STom Rini 				return nextoffset;
148*d18719a4STom Rini 
149*d18719a4STom Rini 		case FDT_PROP:
150*d18719a4STom Rini 			return offset;
151*d18719a4STom Rini 		}
152*d18719a4STom Rini 		offset = nextoffset;
153*d18719a4STom Rini 	} while (tag == FDT_NOP);
154*d18719a4STom Rini 
155*d18719a4STom Rini 	return -FDT_ERR_NOTFOUND;
156*d18719a4STom Rini }
157*d18719a4STom Rini 
fdt_subnode_offset_namelen(const void * fdt,int offset,const char * name,int namelen)158*d18719a4STom Rini int fdt_subnode_offset_namelen(const void *fdt, int offset,
159*d18719a4STom Rini 			       const char *name, int namelen)
160*d18719a4STom Rini {
161*d18719a4STom Rini 	int depth;
162*d18719a4STom Rini 
163*d18719a4STom Rini 	FDT_CHECK_HEADER(fdt);
164*d18719a4STom Rini 
165*d18719a4STom Rini 	for (depth = 0;
166*d18719a4STom Rini 	     (offset >= 0) && (depth >= 0);
167*d18719a4STom Rini 	     offset = fdt_next_node(fdt, offset, &depth))
168*d18719a4STom Rini 		if ((depth == 1)
169*d18719a4STom Rini 		    && _fdt_nodename_eq(fdt, offset, name, namelen))
170*d18719a4STom Rini 			return offset;
171*d18719a4STom Rini 
172*d18719a4STom Rini 	if (depth < 0)
173*d18719a4STom Rini 		return -FDT_ERR_NOTFOUND;
174*d18719a4STom Rini 	return offset; /* error */
175*d18719a4STom Rini }
176*d18719a4STom Rini 
fdt_subnode_offset(const void * fdt,int parentoffset,const char * name)177*d18719a4STom Rini int fdt_subnode_offset(const void *fdt, int parentoffset,
178*d18719a4STom Rini 		       const char *name)
179*d18719a4STom Rini {
180*d18719a4STom Rini 	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
181*d18719a4STom Rini }
182*d18719a4STom Rini 
fdt_path_offset_namelen(const void * fdt,const char * path,int namelen)183*d18719a4STom Rini int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
184*d18719a4STom Rini {
185*d18719a4STom Rini 	const char *end = path + namelen;
186*d18719a4STom Rini 	const char *p = path;
187*d18719a4STom Rini 	int offset = 0;
188*d18719a4STom Rini 
189*d18719a4STom Rini 	FDT_CHECK_HEADER(fdt);
190*d18719a4STom Rini 
191*d18719a4STom Rini 	/* see if we have an alias */
192*d18719a4STom Rini 	if (*path != '/') {
193*d18719a4STom Rini 		const char *q = memchr(path, '/', end - p);
194*d18719a4STom Rini 
195*d18719a4STom Rini 		if (!q)
196*d18719a4STom Rini 			q = end;
197*d18719a4STom Rini 
198*d18719a4STom Rini 		p = fdt_get_alias_namelen(fdt, p, q - p);
199*d18719a4STom Rini 		if (!p)
200*d18719a4STom Rini 			return -FDT_ERR_BADPATH;
201*d18719a4STom Rini 		offset = fdt_path_offset(fdt, p);
202*d18719a4STom Rini 
203*d18719a4STom Rini 		p = q;
204*d18719a4STom Rini 	}
205*d18719a4STom Rini 
206*d18719a4STom Rini 	while (p < end) {
207*d18719a4STom Rini 		const char *q;
208*d18719a4STom Rini 
209*d18719a4STom Rini 		while (*p == '/') {
210*d18719a4STom Rini 			p++;
211*d18719a4STom Rini 			if (p == end)
212*d18719a4STom Rini 				return offset;
213*d18719a4STom Rini 		}
214*d18719a4STom Rini 		q = memchr(p, '/', end - p);
215*d18719a4STom Rini 		if (! q)
216*d18719a4STom Rini 			q = end;
217*d18719a4STom Rini 
218*d18719a4STom Rini 		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
219*d18719a4STom Rini 		if (offset < 0)
220*d18719a4STom Rini 			return offset;
221*d18719a4STom Rini 
222*d18719a4STom Rini 		p = q;
223*d18719a4STom Rini 	}
224*d18719a4STom Rini 
225*d18719a4STom Rini 	return offset;
226*d18719a4STom Rini }
227*d18719a4STom Rini 
fdt_path_offset(const void * fdt,const char * path)228*d18719a4STom Rini int fdt_path_offset(const void *fdt, const char *path)
229*d18719a4STom Rini {
230*d18719a4STom Rini 	return fdt_path_offset_namelen(fdt, path, strlen(path));
231*d18719a4STom Rini }
232*d18719a4STom Rini 
fdt_get_name(const void * fdt,int nodeoffset,int * len)233*d18719a4STom Rini const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
234*d18719a4STom Rini {
235*d18719a4STom Rini 	const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
236*d18719a4STom Rini 	int err;
237*d18719a4STom Rini 
238*d18719a4STom Rini 	if (((err = fdt_check_header(fdt)) != 0)
239*d18719a4STom Rini 	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
240*d18719a4STom Rini 			goto fail;
241*d18719a4STom Rini 
242*d18719a4STom Rini 	if (len)
243*d18719a4STom Rini 		*len = strlen(nh->name);
244*d18719a4STom Rini 
245*d18719a4STom Rini 	return nh->name;
246*d18719a4STom Rini 
247*d18719a4STom Rini  fail:
248*d18719a4STom Rini 	if (len)
249*d18719a4STom Rini 		*len = err;
250*d18719a4STom Rini 	return NULL;
251*d18719a4STom Rini }
252*d18719a4STom Rini 
fdt_first_property_offset(const void * fdt,int nodeoffset)253*d18719a4STom Rini int fdt_first_property_offset(const void *fdt, int nodeoffset)
254*d18719a4STom Rini {
255*d18719a4STom Rini 	int offset;
256*d18719a4STom Rini 
257*d18719a4STom Rini 	if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
258*d18719a4STom Rini 		return offset;
259*d18719a4STom Rini 
260*d18719a4STom Rini 	return _nextprop(fdt, offset);
261*d18719a4STom Rini }
262*d18719a4STom Rini 
fdt_next_property_offset(const void * fdt,int offset)263*d18719a4STom Rini int fdt_next_property_offset(const void *fdt, int offset)
264*d18719a4STom Rini {
265*d18719a4STom Rini 	if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
266*d18719a4STom Rini 		return offset;
267*d18719a4STom Rini 
268*d18719a4STom Rini 	return _nextprop(fdt, offset);
269*d18719a4STom Rini }
270*d18719a4STom Rini 
fdt_get_property_by_offset(const void * fdt,int offset,int * lenp)271*d18719a4STom Rini const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
272*d18719a4STom Rini 						      int offset,
273*d18719a4STom Rini 						      int *lenp)
274*d18719a4STom Rini {
275*d18719a4STom Rini 	int err;
276*d18719a4STom Rini 	const struct fdt_property *prop;
277*d18719a4STom Rini 
278*d18719a4STom Rini 	if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
279*d18719a4STom Rini 		if (lenp)
280*d18719a4STom Rini 			*lenp = err;
281*d18719a4STom Rini 		return NULL;
282*d18719a4STom Rini 	}
283*d18719a4STom Rini 
284*d18719a4STom Rini 	prop = _fdt_offset_ptr(fdt, offset);
285*d18719a4STom Rini 
286*d18719a4STom Rini 	if (lenp)
287*d18719a4STom Rini 		*lenp = fdt32_to_cpu(prop->len);
288*d18719a4STom Rini 
289*d18719a4STom Rini 	return prop;
290*d18719a4STom Rini }
291*d18719a4STom Rini 
fdt_get_property_namelen(const void * fdt,int offset,const char * name,int namelen,int * lenp)292*d18719a4STom Rini const struct fdt_property *fdt_get_property_namelen(const void *fdt,
293*d18719a4STom Rini 						    int offset,
294*d18719a4STom Rini 						    const char *name,
295*d18719a4STom Rini 						    int namelen, int *lenp)
296*d18719a4STom Rini {
297*d18719a4STom Rini 	for (offset = fdt_first_property_offset(fdt, offset);
298*d18719a4STom Rini 	     (offset >= 0);
299*d18719a4STom Rini 	     (offset = fdt_next_property_offset(fdt, offset))) {
300*d18719a4STom Rini 		const struct fdt_property *prop;
301*d18719a4STom Rini 
302*d18719a4STom Rini 		if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
303*d18719a4STom Rini 			offset = -FDT_ERR_INTERNAL;
304*d18719a4STom Rini 			break;
305*d18719a4STom Rini 		}
306*d18719a4STom Rini 		if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
307*d18719a4STom Rini 				   name, namelen))
308*d18719a4STom Rini 			return prop;
309*d18719a4STom Rini 	}
310*d18719a4STom Rini 
311*d18719a4STom Rini 	if (lenp)
312*d18719a4STom Rini 		*lenp = offset;
313*d18719a4STom Rini 	return NULL;
314*d18719a4STom Rini }
315*d18719a4STom Rini 
fdt_get_property(const void * fdt,int nodeoffset,const char * name,int * lenp)316*d18719a4STom Rini const struct fdt_property *fdt_get_property(const void *fdt,
317*d18719a4STom Rini 					    int nodeoffset,
318*d18719a4STom Rini 					    const char *name, int *lenp)
319*d18719a4STom Rini {
320*d18719a4STom Rini 	return fdt_get_property_namelen(fdt, nodeoffset, name,
321*d18719a4STom Rini 					strlen(name), lenp);
322*d18719a4STom Rini }
323*d18719a4STom Rini 
fdt_getprop_namelen(const void * fdt,int nodeoffset,const char * name,int namelen,int * lenp)324*d18719a4STom Rini const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
325*d18719a4STom Rini 				const char *name, int namelen, int *lenp)
326*d18719a4STom Rini {
327*d18719a4STom Rini 	const struct fdt_property *prop;
328*d18719a4STom Rini 
329*d18719a4STom Rini 	prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
330*d18719a4STom Rini 	if (!prop)
331*d18719a4STom Rini 		return NULL;
332*d18719a4STom Rini 
333*d18719a4STom Rini 	return prop->data;
334*d18719a4STom Rini }
335*d18719a4STom Rini 
fdt_getprop_by_offset(const void * fdt,int offset,const char ** namep,int * lenp)336*d18719a4STom Rini const void *fdt_getprop_by_offset(const void *fdt, int offset,
337*d18719a4STom Rini 				  const char **namep, int *lenp)
338*d18719a4STom Rini {
339*d18719a4STom Rini 	const struct fdt_property *prop;
340*d18719a4STom Rini 
341*d18719a4STom Rini 	prop = fdt_get_property_by_offset(fdt, offset, lenp);
342*d18719a4STom Rini 	if (!prop)
343*d18719a4STom Rini 		return NULL;
344*d18719a4STom Rini 	if (namep)
345*d18719a4STom Rini 		*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
346*d18719a4STom Rini 	return prop->data;
347*d18719a4STom Rini }
348*d18719a4STom Rini 
fdt_getprop(const void * fdt,int nodeoffset,const char * name,int * lenp)349*d18719a4STom Rini const void *fdt_getprop(const void *fdt, int nodeoffset,
350*d18719a4STom Rini 			const char *name, int *lenp)
351*d18719a4STom Rini {
352*d18719a4STom Rini 	return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
353*d18719a4STom Rini }
354*d18719a4STom Rini 
fdt_get_phandle(const void * fdt,int nodeoffset)355*d18719a4STom Rini uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
356*d18719a4STom Rini {
357*d18719a4STom Rini 	const fdt32_t *php;
358*d18719a4STom Rini 	int len;
359*d18719a4STom Rini 
360*d18719a4STom Rini 	/* FIXME: This is a bit sub-optimal, since we potentially scan
361*d18719a4STom Rini 	 * over all the properties twice. */
362*d18719a4STom Rini 	php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
363*d18719a4STom Rini 	if (!php || (len != sizeof(*php))) {
364*d18719a4STom Rini 		php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
365*d18719a4STom Rini 		if (!php || (len != sizeof(*php)))
366*d18719a4STom Rini 			return 0;
367*d18719a4STom Rini 	}
368*d18719a4STom Rini 
369*d18719a4STom Rini 	return fdt32_to_cpu(*php);
370*d18719a4STom Rini }
371*d18719a4STom Rini 
fdt_get_alias_namelen(const void * fdt,const char * name,int namelen)372*d18719a4STom Rini const char *fdt_get_alias_namelen(const void *fdt,
373*d18719a4STom Rini 				  const char *name, int namelen)
374*d18719a4STom Rini {
375*d18719a4STom Rini 	int aliasoffset;
376*d18719a4STom Rini 
377*d18719a4STom Rini 	aliasoffset = fdt_path_offset(fdt, "/aliases");
378*d18719a4STom Rini 	if (aliasoffset < 0)
379*d18719a4STom Rini 		return NULL;
380*d18719a4STom Rini 
381*d18719a4STom Rini 	return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
382*d18719a4STom Rini }
383*d18719a4STom Rini 
fdt_get_alias(const void * fdt,const char * name)384*d18719a4STom Rini const char *fdt_get_alias(const void *fdt, const char *name)
385*d18719a4STom Rini {
386*d18719a4STom Rini 	return fdt_get_alias_namelen(fdt, name, strlen(name));
387*d18719a4STom Rini }
388*d18719a4STom Rini 
fdt_get_path(const void * fdt,int nodeoffset,char * buf,int buflen)389*d18719a4STom Rini int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
390*d18719a4STom Rini {
391*d18719a4STom Rini 	int pdepth = 0, p = 0;
392*d18719a4STom Rini 	int offset, depth, namelen;
393*d18719a4STom Rini 	const char *name;
394*d18719a4STom Rini 
395*d18719a4STom Rini 	FDT_CHECK_HEADER(fdt);
396*d18719a4STom Rini 
397*d18719a4STom Rini 	if (buflen < 2)
398*d18719a4STom Rini 		return -FDT_ERR_NOSPACE;
399*d18719a4STom Rini 
400*d18719a4STom Rini 	for (offset = 0, depth = 0;
401*d18719a4STom Rini 	     (offset >= 0) && (offset <= nodeoffset);
402*d18719a4STom Rini 	     offset = fdt_next_node(fdt, offset, &depth)) {
403*d18719a4STom Rini 		while (pdepth > depth) {
404*d18719a4STom Rini 			do {
405*d18719a4STom Rini 				p--;
406*d18719a4STom Rini 			} while (buf[p-1] != '/');
407*d18719a4STom Rini 			pdepth--;
408*d18719a4STom Rini 		}
409*d18719a4STom Rini 
410*d18719a4STom Rini 		if (pdepth >= depth) {
411*d18719a4STom Rini 			name = fdt_get_name(fdt, offset, &namelen);
412*d18719a4STom Rini 			if (!name)
413*d18719a4STom Rini 				return namelen;
414*d18719a4STom Rini 			if ((p + namelen + 1) <= buflen) {
415*d18719a4STom Rini 				memcpy(buf + p, name, namelen);
416*d18719a4STom Rini 				p += namelen;
417*d18719a4STom Rini 				buf[p++] = '/';
418*d18719a4STom Rini 				pdepth++;
419*d18719a4STom Rini 			}
420*d18719a4STom Rini 		}
421*d18719a4STom Rini 
422*d18719a4STom Rini 		if (offset == nodeoffset) {
423*d18719a4STom Rini 			if (pdepth < (depth + 1))
424*d18719a4STom Rini 				return -FDT_ERR_NOSPACE;
425*d18719a4STom Rini 
426*d18719a4STom Rini 			if (p > 1) /* special case so that root path is "/", not "" */
427*d18719a4STom Rini 				p--;
428*d18719a4STom Rini 			buf[p] = '\0';
429*d18719a4STom Rini 			return 0;
430*d18719a4STom Rini 		}
431*d18719a4STom Rini 	}
432*d18719a4STom Rini 
433*d18719a4STom Rini 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
434*d18719a4STom Rini 		return -FDT_ERR_BADOFFSET;
435*d18719a4STom Rini 	else if (offset == -FDT_ERR_BADOFFSET)
436*d18719a4STom Rini 		return -FDT_ERR_BADSTRUCTURE;
437*d18719a4STom Rini 
438*d18719a4STom Rini 	return offset; /* error from fdt_next_node() */
439*d18719a4STom Rini }
440*d18719a4STom Rini 
fdt_supernode_atdepth_offset(const void * fdt,int nodeoffset,int supernodedepth,int * nodedepth)441*d18719a4STom Rini int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
442*d18719a4STom Rini 				 int supernodedepth, int *nodedepth)
443*d18719a4STom Rini {
444*d18719a4STom Rini 	int offset, depth;
445*d18719a4STom Rini 	int supernodeoffset = -FDT_ERR_INTERNAL;
446*d18719a4STom Rini 
447*d18719a4STom Rini 	FDT_CHECK_HEADER(fdt);
448*d18719a4STom Rini 
449*d18719a4STom Rini 	if (supernodedepth < 0)
450*d18719a4STom Rini 		return -FDT_ERR_NOTFOUND;
451*d18719a4STom Rini 
452*d18719a4STom Rini 	for (offset = 0, depth = 0;
453*d18719a4STom Rini 	     (offset >= 0) && (offset <= nodeoffset);
454*d18719a4STom Rini 	     offset = fdt_next_node(fdt, offset, &depth)) {
455*d18719a4STom Rini 		if (depth == supernodedepth)
456*d18719a4STom Rini 			supernodeoffset = offset;
457*d18719a4STom Rini 
458*d18719a4STom Rini 		if (offset == nodeoffset) {
459*d18719a4STom Rini 			if (nodedepth)
460*d18719a4STom Rini 				*nodedepth = depth;
461*d18719a4STom Rini 
462*d18719a4STom Rini 			if (supernodedepth > depth)
463*d18719a4STom Rini 				return -FDT_ERR_NOTFOUND;
464*d18719a4STom Rini 			else
465*d18719a4STom Rini 				return supernodeoffset;
466*d18719a4STom Rini 		}
467*d18719a4STom Rini 	}
468*d18719a4STom Rini 
469*d18719a4STom Rini 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
470*d18719a4STom Rini 		return -FDT_ERR_BADOFFSET;
471*d18719a4STom Rini 	else if (offset == -FDT_ERR_BADOFFSET)
472*d18719a4STom Rini 		return -FDT_ERR_BADSTRUCTURE;
473*d18719a4STom Rini 
474*d18719a4STom Rini 	return offset; /* error from fdt_next_node() */
475*d18719a4STom Rini }
476*d18719a4STom Rini 
fdt_node_depth(const void * fdt,int nodeoffset)477*d18719a4STom Rini int fdt_node_depth(const void *fdt, int nodeoffset)
478*d18719a4STom Rini {
479*d18719a4STom Rini 	int nodedepth;
480*d18719a4STom Rini 	int err;
481*d18719a4STom Rini 
482*d18719a4STom Rini 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
483*d18719a4STom Rini 	if (err)
484*d18719a4STom Rini 		return (err < 0) ? err : -FDT_ERR_INTERNAL;
485*d18719a4STom Rini 	return nodedepth;
486*d18719a4STom Rini }
487*d18719a4STom Rini 
fdt_parent_offset(const void * fdt,int nodeoffset)488*d18719a4STom Rini int fdt_parent_offset(const void *fdt, int nodeoffset)
489*d18719a4STom Rini {
490*d18719a4STom Rini 	int nodedepth = fdt_node_depth(fdt, nodeoffset);
491*d18719a4STom Rini 
492*d18719a4STom Rini 	if (nodedepth < 0)
493*d18719a4STom Rini 		return nodedepth;
494*d18719a4STom Rini 	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
495*d18719a4STom Rini 					    nodedepth - 1, NULL);
496*d18719a4STom Rini }
497*d18719a4STom Rini 
fdt_node_offset_by_prop_value(const void * fdt,int startoffset,const char * propname,const void * propval,int proplen)498*d18719a4STom Rini int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
499*d18719a4STom Rini 				  const char *propname,
500*d18719a4STom Rini 				  const void *propval, int proplen)
501*d18719a4STom Rini {
502*d18719a4STom Rini 	int offset;
503*d18719a4STom Rini 	const void *val;
504*d18719a4STom Rini 	int len;
505*d18719a4STom Rini 
506*d18719a4STom Rini 	FDT_CHECK_HEADER(fdt);
507*d18719a4STom Rini 
508*d18719a4STom Rini 	/* FIXME: The algorithm here is pretty horrible: we scan each
509*d18719a4STom Rini 	 * property of a node in fdt_getprop(), then if that didn't
510*d18719a4STom Rini 	 * find what we want, we scan over them again making our way
511*d18719a4STom Rini 	 * to the next node.  Still it's the easiest to implement
512*d18719a4STom Rini 	 * approach; performance can come later. */
513*d18719a4STom Rini 	for (offset = fdt_next_node(fdt, startoffset, NULL);
514*d18719a4STom Rini 	     offset >= 0;
515*d18719a4STom Rini 	     offset = fdt_next_node(fdt, offset, NULL)) {
516*d18719a4STom Rini 		val = fdt_getprop(fdt, offset, propname, &len);
517*d18719a4STom Rini 		if (val && (len == proplen)
518*d18719a4STom Rini 		    && (memcmp(val, propval, len) == 0))
519*d18719a4STom Rini 			return offset;
520*d18719a4STom Rini 	}
521*d18719a4STom Rini 
522*d18719a4STom Rini 	return offset; /* error from fdt_next_node() */
523*d18719a4STom Rini }
524*d18719a4STom Rini 
fdt_node_offset_by_phandle(const void * fdt,uint32_t phandle)525*d18719a4STom Rini int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
526*d18719a4STom Rini {
527*d18719a4STom Rini 	int offset;
528*d18719a4STom Rini 
529*d18719a4STom Rini 	if ((phandle == 0) || (phandle == -1))
530*d18719a4STom Rini 		return -FDT_ERR_BADPHANDLE;
531*d18719a4STom Rini 
532*d18719a4STom Rini 	FDT_CHECK_HEADER(fdt);
533*d18719a4STom Rini 
534*d18719a4STom Rini 	/* FIXME: The algorithm here is pretty horrible: we
535*d18719a4STom Rini 	 * potentially scan each property of a node in
536*d18719a4STom Rini 	 * fdt_get_phandle(), then if that didn't find what
537*d18719a4STom Rini 	 * we want, we scan over them again making our way to the next
538*d18719a4STom Rini 	 * node.  Still it's the easiest to implement approach;
539*d18719a4STom Rini 	 * performance can come later. */
540*d18719a4STom Rini 	for (offset = fdt_next_node(fdt, -1, NULL);
541*d18719a4STom Rini 	     offset >= 0;
542*d18719a4STom Rini 	     offset = fdt_next_node(fdt, offset, NULL)) {
543*d18719a4STom Rini 		if (fdt_get_phandle(fdt, offset) == phandle)
544*d18719a4STom Rini 			return offset;
545*d18719a4STom Rini 	}
546*d18719a4STom Rini 
547*d18719a4STom Rini 	return offset; /* error from fdt_next_node() */
548*d18719a4STom Rini }
549*d18719a4STom Rini 
fdt_stringlist_contains(const char * strlist,int listlen,const char * str)550*d18719a4STom Rini int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
551*d18719a4STom Rini {
552*d18719a4STom Rini 	int len = strlen(str);
553*d18719a4STom Rini 	const char *p;
554*d18719a4STom Rini 
555*d18719a4STom Rini 	while (listlen >= len) {
556*d18719a4STom Rini 		if (memcmp(str, strlist, len+1) == 0)
557*d18719a4STom Rini 			return 1;
558*d18719a4STom Rini 		p = memchr(strlist, '\0', listlen);
559*d18719a4STom Rini 		if (!p)
560*d18719a4STom Rini 			return 0; /* malformed strlist.. */
561*d18719a4STom Rini 		listlen -= (p-strlist) + 1;
562*d18719a4STom Rini 		strlist = p + 1;
563*d18719a4STom Rini 	}
564*d18719a4STom Rini 	return 0;
565*d18719a4STom Rini }
566*d18719a4STom Rini 
fdt_stringlist_count(const void * fdt,int nodeoffset,const char * property)567*d18719a4STom Rini int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
568*d18719a4STom Rini {
569*d18719a4STom Rini 	const char *list, *end;
570*d18719a4STom Rini 	int length, count = 0;
571*d18719a4STom Rini 
572*d18719a4STom Rini 	list = fdt_getprop(fdt, nodeoffset, property, &length);
573*d18719a4STom Rini 	if (!list)
574*d18719a4STom Rini 		return length;
575*d18719a4STom Rini 
576*d18719a4STom Rini 	end = list + length;
577*d18719a4STom Rini 
578*d18719a4STom Rini 	while (list < end) {
579*d18719a4STom Rini 		length = strnlen(list, end - list) + 1;
580*d18719a4STom Rini 
581*d18719a4STom Rini 		/* Abort if the last string isn't properly NUL-terminated. */
582*d18719a4STom Rini 		if (list + length > end)
583*d18719a4STom Rini 			return -FDT_ERR_BADVALUE;
584*d18719a4STom Rini 
585*d18719a4STom Rini 		list += length;
586*d18719a4STom Rini 		count++;
587*d18719a4STom Rini 	}
588*d18719a4STom Rini 
589*d18719a4STom Rini 	return count;
590*d18719a4STom Rini }
591*d18719a4STom Rini 
fdt_stringlist_search(const void * fdt,int nodeoffset,const char * property,const char * string)592*d18719a4STom Rini int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
593*d18719a4STom Rini 			  const char *string)
594*d18719a4STom Rini {
595*d18719a4STom Rini 	int length, len, idx = 0;
596*d18719a4STom Rini 	const char *list, *end;
597*d18719a4STom Rini 
598*d18719a4STom Rini 	list = fdt_getprop(fdt, nodeoffset, property, &length);
599*d18719a4STom Rini 	if (!list)
600*d18719a4STom Rini 		return length;
601*d18719a4STom Rini 
602*d18719a4STom Rini 	len = strlen(string) + 1;
603*d18719a4STom Rini 	end = list + length;
604*d18719a4STom Rini 
605*d18719a4STom Rini 	while (list < end) {
606*d18719a4STom Rini 		length = strnlen(list, end - list) + 1;
607*d18719a4STom Rini 
608*d18719a4STom Rini 		/* Abort if the last string isn't properly NUL-terminated. */
609*d18719a4STom Rini 		if (list + length > end)
610*d18719a4STom Rini 			return -FDT_ERR_BADVALUE;
611*d18719a4STom Rini 
612*d18719a4STom Rini 		if (length == len && memcmp(list, string, length) == 0)
613*d18719a4STom Rini 			return idx;
614*d18719a4STom Rini 
615*d18719a4STom Rini 		list += length;
616*d18719a4STom Rini 		idx++;
617*d18719a4STom Rini 	}
618*d18719a4STom Rini 
619*d18719a4STom Rini 	return -FDT_ERR_NOTFOUND;
620*d18719a4STom Rini }
621*d18719a4STom Rini 
fdt_stringlist_get(const void * fdt,int nodeoffset,const char * property,int idx,int * lenp)622*d18719a4STom Rini const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
623*d18719a4STom Rini 			       const char *property, int idx,
624*d18719a4STom Rini 			       int *lenp)
625*d18719a4STom Rini {
626*d18719a4STom Rini 	const char *list, *end;
627*d18719a4STom Rini 	int length;
628*d18719a4STom Rini 
629*d18719a4STom Rini 	list = fdt_getprop(fdt, nodeoffset, property, &length);
630*d18719a4STom Rini 	if (!list) {
631*d18719a4STom Rini 		if (lenp)
632*d18719a4STom Rini 			*lenp = length;
633*d18719a4STom Rini 
634*d18719a4STom Rini 		return NULL;
635*d18719a4STom Rini 	}
636*d18719a4STom Rini 
637*d18719a4STom Rini 	end = list + length;
638*d18719a4STom Rini 
639*d18719a4STom Rini 	while (list < end) {
640*d18719a4STom Rini 		length = strnlen(list, end - list) + 1;
641*d18719a4STom Rini 
642*d18719a4STom Rini 		/* Abort if the last string isn't properly NUL-terminated. */
643*d18719a4STom Rini 		if (list + length > end) {
644*d18719a4STom Rini 			if (lenp)
645*d18719a4STom Rini 				*lenp = -FDT_ERR_BADVALUE;
646*d18719a4STom Rini 
647*d18719a4STom Rini 			return NULL;
648*d18719a4STom Rini 		}
649*d18719a4STom Rini 
650*d18719a4STom Rini 		if (idx == 0) {
651*d18719a4STom Rini 			if (lenp)
652*d18719a4STom Rini 				*lenp = length - 1;
653*d18719a4STom Rini 
654*d18719a4STom Rini 			return list;
655*d18719a4STom Rini 		}
656*d18719a4STom Rini 
657*d18719a4STom Rini 		list += length;
658*d18719a4STom Rini 		idx--;
659*d18719a4STom Rini 	}
660*d18719a4STom Rini 
661*d18719a4STom Rini 	if (lenp)
662*d18719a4STom Rini 		*lenp = -FDT_ERR_NOTFOUND;
663*d18719a4STom Rini 
664*d18719a4STom Rini 	return NULL;
665*d18719a4STom Rini }
666*d18719a4STom Rini 
fdt_node_check_compatible(const void * fdt,int nodeoffset,const char * compatible)667*d18719a4STom Rini int fdt_node_check_compatible(const void *fdt, int nodeoffset,
668*d18719a4STom Rini 			      const char *compatible)
669*d18719a4STom Rini {
670*d18719a4STom Rini 	const void *prop;
671*d18719a4STom Rini 	int len;
672*d18719a4STom Rini 
673*d18719a4STom Rini 	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
674*d18719a4STom Rini 	if (!prop)
675*d18719a4STom Rini 		return len;
676*d18719a4STom Rini 
677*d18719a4STom Rini 	return !fdt_stringlist_contains(prop, len, compatible);
678*d18719a4STom Rini }
679*d18719a4STom Rini 
fdt_node_offset_by_compatible(const void * fdt,int startoffset,const char * compatible)680*d18719a4STom Rini int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
681*d18719a4STom Rini 				  const char *compatible)
682*d18719a4STom Rini {
683*d18719a4STom Rini 	int offset, err;
684*d18719a4STom Rini 
685*d18719a4STom Rini 	FDT_CHECK_HEADER(fdt);
686*d18719a4STom Rini 
687*d18719a4STom Rini 	/* FIXME: The algorithm here is pretty horrible: we scan each
688*d18719a4STom Rini 	 * property of a node in fdt_node_check_compatible(), then if
689*d18719a4STom Rini 	 * that didn't find what we want, we scan over them again
690*d18719a4STom Rini 	 * making our way to the next node.  Still it's the easiest to
691*d18719a4STom Rini 	 * implement approach; performance can come later. */
692*d18719a4STom Rini 	for (offset = fdt_next_node(fdt, startoffset, NULL);
693*d18719a4STom Rini 	     offset >= 0;
694*d18719a4STom Rini 	     offset = fdt_next_node(fdt, offset, NULL)) {
695*d18719a4STom Rini 		err = fdt_node_check_compatible(fdt, offset, compatible);
696*d18719a4STom Rini 		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
697*d18719a4STom Rini 			return err;
698*d18719a4STom Rini 		else if (err == 0)
699*d18719a4STom Rini 			return offset;
700*d18719a4STom Rini 	}
701*d18719a4STom Rini 
702*d18719a4STom Rini 	return offset; /* error from fdt_next_node() */
703*d18719a4STom Rini }
704