1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2017 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#define LOG_CATEGORY	LOGC_DT
8
9#include <common.h>
10#include <dm.h>
11#include <fdtdec.h>
12#include <fdt_support.h>
13#include <log.h>
14#include <malloc.h>
15#include <of_live.h>
16#include <linux/libfdt.h>
17#include <dm/of_access.h>
18#include <dm/of_addr.h>
19#include <dm/ofnode.h>
20#include <linux/err.h>
21#include <linux/ioport.h>
22#include <asm/global_data.h>
23
24DECLARE_GLOBAL_DATA_PTR;
25
26#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
27static void *oftree_list[CONFIG_OFNODE_MULTI_TREE_MAX];
28static int oftree_count;
29
30void oftree_reset(void)
31{
32	if (gd->flags & GD_FLG_RELOC) {
33		oftree_count = 0;
34		oftree_list[oftree_count++] = (void *)gd->fdt_blob;
35	}
36}
37
38static int oftree_find(const void *fdt)
39{
40	int i;
41
42	for (i = 0; i < oftree_count; i++) {
43		if (fdt == oftree_list[i])
44			return i;
45	}
46
47	return -1;
48}
49
50static int check_tree_count(void)
51{
52	if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
53		log_warning("Too many registered device trees (max %d)\n",
54			    CONFIG_OFNODE_MULTI_TREE_MAX);
55		return -E2BIG;
56	}
57
58	return 0;
59}
60
61static oftree oftree_ensure(void *fdt)
62{
63	oftree tree;
64	int i;
65
66	if (of_live_active()) {
67		struct device_node *root;
68		int ret;
69
70		ret = unflatten_device_tree(fdt, &root);
71		if (ret) {
72			log_err("Failed to create live tree: err=%d\n", ret);
73			return oftree_null();
74		}
75		tree = oftree_from_np(root);
76
77		return tree;
78	}
79
80	if (gd->flags & GD_FLG_RELOC) {
81		i = oftree_find(fdt);
82		if (i == -1) {
83			if (check_tree_count())
84				return oftree_null();
85
86			if (fdt_check_header(fdt)) {
87				log_err("Invalid device tree blob header\n");
88				return oftree_null();
89			}
90
91			/* register the new tree */
92			i = oftree_count++;
93			oftree_list[i] = fdt;
94			log_debug("oftree: registered tree %d: %p\n", i, fdt);
95		}
96	} else {
97		if (fdt != gd->fdt_blob) {
98			log_debug("Only the control FDT can be accessed before relocation\n");
99			return oftree_null();
100		}
101	}
102
103	tree.fdt = fdt;
104
105	return tree;
106}
107
108int oftree_new(oftree *treep)
109{
110	oftree tree = oftree_null();
111	int ret;
112
113	if (of_live_active()) {
114		struct device_node *root;
115
116		ret = of_live_create_empty(&root);
117		if (ret)
118			return log_msg_ret("liv", ret);
119		tree = oftree_from_np(root);
120	} else {
121		const int size = 1024;
122		void *fdt;
123
124		ret = check_tree_count();
125		if (ret)
126			return log_msg_ret("fla", ret);
127
128		/* register the new tree with a small size */
129		fdt = malloc(size);
130		if (!fdt)
131			return log_msg_ret("fla", -ENOMEM);
132		ret = fdt_create_empty_tree(fdt, size);
133		if (ret)
134			return log_msg_ret("fla", -EINVAL);
135		oftree_list[oftree_count++] = fdt;
136		tree.fdt = fdt;
137	}
138	*treep = tree;
139
140	return 0;
141}
142
143void oftree_dispose(oftree tree)
144{
145	if (of_live_active())
146		of_live_free(tree.np);
147}
148
149void *ofnode_lookup_fdt(ofnode node)
150{
151	if (gd->flags & GD_FLG_RELOC) {
152		uint i = OFTREE_TREE_ID(node.of_offset);
153
154		if (i >= oftree_count) {
155			log_debug("Invalid tree ID %x\n", i);
156			return NULL;
157		}
158
159		return oftree_list[i];
160	} else {
161		return (void *)gd->fdt_blob;
162	}
163}
164
165void *ofnode_to_fdt(ofnode node)
166{
167#ifdef OF_CHECKS
168	if (of_live_active())
169		return NULL;
170#endif
171	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
172		return ofnode_lookup_fdt(node);
173
174	/* Use the control FDT by default */
175	return (void *)gd->fdt_blob;
176}
177
178/**
179 * ofnode_to_offset() - convert an ofnode to a flat DT offset
180 *
181 * This cannot be called if the reference contains a node pointer.
182 *
183 * @node: Reference containing offset (possibly invalid)
184 * Return: DT offset (can be -1)
185 */
186int ofnode_to_offset(ofnode node)
187{
188#ifdef OF_CHECKS
189	if (of_live_active())
190		return -1;
191#endif
192	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
193		return OFTREE_OFFSET(node.of_offset);
194
195	return node.of_offset;
196}
197
198oftree oftree_from_fdt(void *fdt)
199{
200	oftree tree;
201
202	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
203		return oftree_ensure(fdt);
204
205#ifdef OF_CHECKS
206	if (of_live_active())
207		return oftree_null();
208#endif
209	tree.fdt = fdt;
210
211	return tree;
212}
213
214/**
215 * noffset_to_ofnode() - convert a DT offset to an ofnode
216 *
217 * @other_node: Node in the same tree to use as a reference
218 * @of_offset: DT offset (either valid, or -1)
219 * Return: reference to the associated DT offset
220 */
221ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
222{
223	ofnode node;
224
225	if (of_live_active())
226		node.np = NULL;
227	else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
228		 !ofnode_valid(other_node))
229		node.of_offset = of_offset;
230	else
231		node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
232						  of_offset);
233
234	return node;
235}
236
237#else /* !OFNODE_MULTI_TREE */
238
239static inline int oftree_find(const void *fdt)
240{
241	return 0;
242}
243
244int oftree_new(oftree *treep)
245{
246	return -ENOSYS;
247}
248
249#endif /* OFNODE_MULTI_TREE */
250
251int oftree_to_fdt(oftree tree, struct abuf *buf)
252{
253	int ret;
254
255	if (of_live_active()) {
256		ret = of_live_flatten(ofnode_to_np(oftree_root(tree)), buf);
257		if (ret)
258			return log_msg_ret("flt", ret);
259	} else {
260		void *fdt = oftree_lookup_fdt(tree);
261
262		abuf_init(buf);
263		abuf_set(buf, fdt, fdt_totalsize(fdt));
264	}
265
266	return 0;
267}
268
269/**
270 * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
271 *
272 * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
273 * containing the tree ID).
274 *
275 * If @offset is < 0 then this returns an ofnode with that offset and no tree
276 * ID.
277 *
278 * @tree: tree to check
279 * @offset: offset within that tree (can be < 0)
280 * @return node for that offset, with the correct ID
281 */
282static ofnode ofnode_from_tree_offset(oftree tree, int offset)
283{
284	ofnode node;
285
286	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
287		int tree_id = oftree_find(tree.fdt);
288
289		if (tree_id == -1)
290			return ofnode_null();
291		node.of_offset = OFTREE_NODE(tree_id, offset);
292	} else {
293		node.of_offset = offset;
294	}
295
296	return node;
297}
298
299bool ofnode_name_eq(ofnode node, const char *name)
300{
301	const char *node_name;
302	size_t len;
303
304	assert(ofnode_valid(node));
305
306	node_name = ofnode_get_name(node);
307	len = strchrnul(node_name, '@') - node_name;
308
309	return (strlen(name) == len) && !strncmp(node_name, name, len);
310}
311
312int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
313{
314	const u8 *cell;
315	int len;
316
317	assert(ofnode_valid(node));
318	debug("%s: %s: ", __func__, propname);
319
320	if (ofnode_is_np(node))
321		return of_read_u8(ofnode_to_np(node), propname, outp);
322
323	cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
324			   &len);
325	if (!cell || len < sizeof(*cell)) {
326		debug("(not found)\n");
327		return -EINVAL;
328	}
329	*outp = *cell;
330	debug("%#x (%d)\n", *outp, *outp);
331
332	return 0;
333}
334
335u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
336{
337	assert(ofnode_valid(node));
338	ofnode_read_u8(node, propname, &def);
339
340	return def;
341}
342
343int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
344{
345	const fdt16_t *cell;
346	int len;
347
348	assert(ofnode_valid(node));
349	debug("%s: %s: ", __func__, propname);
350
351	if (ofnode_is_np(node))
352		return of_read_u16(ofnode_to_np(node), propname, outp);
353
354	cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
355			   &len);
356	if (!cell || len < sizeof(*cell)) {
357		debug("(not found)\n");
358		return -EINVAL;
359	}
360	*outp = be16_to_cpup(cell);
361	debug("%#x (%d)\n", *outp, *outp);
362
363	return 0;
364}
365
366u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
367{
368	assert(ofnode_valid(node));
369	ofnode_read_u16(node, propname, &def);
370
371	return def;
372}
373
374int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
375{
376	return ofnode_read_u32_index(node, propname, 0, outp);
377}
378
379u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def)
380{
381	assert(ofnode_valid(node));
382	ofnode_read_u32_index(node, propname, 0, &def);
383
384	return def;
385}
386
387int ofnode_read_u32_index(ofnode node, const char *propname, int index,
388			  u32 *outp)
389{
390	const fdt32_t *cell;
391	int len;
392
393	assert(ofnode_valid(node));
394	debug("%s: %s: ", __func__, propname);
395
396	if (ofnode_is_np(node))
397		return of_read_u32_index(ofnode_to_np(node), propname, index,
398					 outp);
399
400	cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
401			   propname, &len);
402	if (!cell) {
403		debug("(not found)\n");
404		return -EINVAL;
405	}
406
407	if (len < (sizeof(int) * (index + 1))) {
408		debug("(not large enough)\n");
409		return -EOVERFLOW;
410	}
411
412	*outp = fdt32_to_cpu(cell[index]);
413	debug("%#x (%d)\n", *outp, *outp);
414
415	return 0;
416}
417
418int ofnode_read_u64_index(ofnode node, const char *propname, int index,
419			  u64 *outp)
420{
421	const fdt64_t *cell;
422	int len;
423
424	assert(ofnode_valid(node));
425
426	if (ofnode_is_np(node))
427		return of_read_u64_index(ofnode_to_np(node), propname, index,
428					 outp);
429
430	cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
431			   propname, &len);
432	if (!cell) {
433		debug("(not found)\n");
434		return -EINVAL;
435	}
436
437	if (len < (sizeof(u64) * (index + 1))) {
438		debug("(not large enough)\n");
439		return -EOVERFLOW;
440	}
441
442	*outp = fdt64_to_cpu(cell[index]);
443	debug("%#llx (%lld)\n", *outp, *outp);
444
445	return 0;
446}
447
448u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
449				  u32 def)
450{
451	assert(ofnode_valid(node));
452	ofnode_read_u32_index(node, propname, index, &def);
453
454	return def;
455}
456
457int ofnode_read_s32_default(ofnode node, const char *propname, s32 def)
458{
459	assert(ofnode_valid(node));
460	ofnode_read_u32(node, propname, (u32 *)&def);
461
462	return def;
463}
464
465int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
466{
467	const unaligned_fdt64_t *cell;
468	int len;
469
470	assert(ofnode_valid(node));
471	debug("%s: %s: ", __func__, propname);
472
473	if (ofnode_is_np(node))
474		return of_read_u64(ofnode_to_np(node), propname, outp);
475
476	cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
477			   propname, &len);
478	if (!cell || len < sizeof(*cell)) {
479		debug("(not found)\n");
480		return -EINVAL;
481	}
482	*outp = fdt64_to_cpu(cell[0]);
483	debug("%#llx (%lld)\n", (unsigned long long)*outp,
484	      (unsigned long long)*outp);
485
486	return 0;
487}
488
489u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
490{
491	assert(ofnode_valid(node));
492	ofnode_read_u64(node, propname, &def);
493
494	return def;
495}
496
497bool ofnode_read_bool(ofnode node, const char *propname)
498{
499	bool prop;
500
501	assert(ofnode_valid(node));
502	debug("%s: %s: ", __func__, propname);
503
504	prop = ofnode_has_property(node, propname);
505
506	debug("%s\n", prop ? "true" : "false");
507
508	return prop ? true : false;
509}
510
511const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep)
512{
513	const char *val = NULL;
514	int len;
515
516	assert(ofnode_valid(node));
517	debug("%s: %s: ", __func__, propname);
518
519	if (ofnode_is_np(node)) {
520		struct property *prop = of_find_property(
521				ofnode_to_np(node), propname, &len);
522
523		if (prop) {
524			val = prop->value;
525			len = prop->length;
526		}
527	} else {
528		val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
529				  propname, &len);
530	}
531	if (!val) {
532		debug("<not found>\n");
533		if (sizep)
534			*sizep = -FDT_ERR_NOTFOUND;
535		return NULL;
536	}
537	if (sizep)
538		*sizep = len;
539
540	return val;
541}
542
543const char *ofnode_read_string(ofnode node, const char *propname)
544{
545	const char *str;
546	int len;
547
548	str = ofnode_read_prop(node, propname, &len);
549	if (!str)
550		return NULL;
551
552	if (strnlen(str, len) >= len) {
553		debug("<invalid>\n");
554		return NULL;
555	}
556	debug("%s\n", str);
557
558	return str;
559}
560
561int ofnode_read_size(ofnode node, const char *propname)
562{
563	int len;
564
565	if (!ofnode_read_prop(node, propname, &len))
566		return -EINVAL;
567
568	return len;
569}
570
571ofnode ofnode_find_subnode(ofnode node, const char *subnode_name)
572{
573	ofnode subnode;
574
575	assert(ofnode_valid(node));
576	debug("%s: %s: ", __func__, subnode_name);
577
578	if (ofnode_is_np(node)) {
579		struct device_node *np = ofnode_to_np(node);
580
581		for (np = np->child; np; np = np->sibling) {
582			if (!strcmp(subnode_name, np->name))
583				break;
584		}
585		subnode = np_to_ofnode(np);
586	} else {
587		int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
588				ofnode_to_offset(node), subnode_name);
589		subnode = noffset_to_ofnode(node, ooffset);
590	}
591	debug("%s\n", ofnode_valid(subnode) ?
592	      ofnode_get_name(subnode) : "<none>");
593
594	return subnode;
595}
596
597int ofnode_read_u32_array(ofnode node, const char *propname,
598			  u32 *out_values, size_t sz)
599{
600	assert(ofnode_valid(node));
601	debug("%s: %s: ", __func__, propname);
602
603	if (ofnode_is_np(node)) {
604		return of_read_u32_array(ofnode_to_np(node), propname,
605					 out_values, sz);
606	} else {
607		int ret;
608
609		ret = fdtdec_get_int_array(ofnode_to_fdt(node),
610					   ofnode_to_offset(node), propname,
611					   out_values, sz);
612
613		/* get the error right, but space is more important in SPL */
614		if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
615			if (ret == -FDT_ERR_NOTFOUND)
616				return -EINVAL;
617			else if (ret == -FDT_ERR_BADLAYOUT)
618				return -EOVERFLOW;
619		}
620		return ret;
621	}
622}
623
624#if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE)
625bool ofnode_is_enabled(ofnode node)
626{
627	if (ofnode_is_np(node)) {
628		return of_device_is_available(ofnode_to_np(node));
629	} else {
630		return fdtdec_get_is_enabled(ofnode_to_fdt(node),
631					     ofnode_to_offset(node));
632	}
633}
634
635ofnode ofnode_first_subnode(ofnode node)
636{
637	assert(ofnode_valid(node));
638	if (ofnode_is_np(node))
639		return np_to_ofnode(node.np->child);
640
641	return noffset_to_ofnode(node,
642		fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
643}
644
645ofnode ofnode_next_subnode(ofnode node)
646{
647	assert(ofnode_valid(node));
648	if (ofnode_is_np(node))
649		return np_to_ofnode(node.np->sibling);
650
651	return noffset_to_ofnode(node,
652		fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
653}
654#endif /* !DM_INLINE_OFNODE */
655
656ofnode ofnode_get_parent(ofnode node)
657{
658	ofnode parent;
659
660	assert(ofnode_valid(node));
661	if (ofnode_is_np(node))
662		parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
663	else
664		parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
665						     ofnode_to_offset(node));
666
667	return parent;
668}
669
670const char *ofnode_get_name(ofnode node)
671{
672	if (!ofnode_valid(node)) {
673		debug("%s node not valid\n", __func__);
674		return NULL;
675	}
676
677	if (ofnode_is_np(node))
678		return node.np->name;
679
680	return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
681}
682
683int ofnode_get_path(ofnode node, char *buf, int buflen)
684{
685	assert(ofnode_valid(node));
686
687	if (ofnode_is_np(node)) {
688		if (strlen(node.np->full_name) >= buflen)
689			return -ENOSPC;
690
691		strcpy(buf, node.np->full_name);
692
693		return 0;
694	} else {
695		int res;
696
697		res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
698				   buflen);
699		if (!res)
700			return res;
701		else if (res == -FDT_ERR_NOSPACE)
702			return -ENOSPC;
703		else
704			return -EINVAL;
705	}
706}
707
708ofnode ofnode_get_by_phandle(uint phandle)
709{
710	ofnode node;
711
712	if (of_live_active())
713		node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
714	else
715		node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
716							    phandle);
717
718	return node;
719}
720
721ofnode oftree_get_by_phandle(oftree tree, uint phandle)
722{
723	ofnode node;
724
725	if (of_live_active())
726		node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
727	else
728		node = ofnode_from_tree_offset(tree,
729			fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
730						   phandle));
731
732	return node;
733}
734
735static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
736					       fdt_size_t *size, bool translate)
737{
738	int na, ns;
739
740	if (size)
741		*size = FDT_SIZE_T_NONE;
742
743	if (ofnode_is_np(node)) {
744		const __be32 *prop_val;
745		u64 size64;
746		uint flags;
747
748		prop_val = of_get_address(ofnode_to_np(node), index, &size64,
749					  &flags);
750		if (!prop_val)
751			return FDT_ADDR_T_NONE;
752
753		if (size)
754			*size = size64;
755
756		ns = of_n_size_cells(ofnode_to_np(node));
757
758		if (translate && IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
759			return of_translate_address(ofnode_to_np(node), prop_val);
760		} else {
761			na = of_n_addr_cells(ofnode_to_np(node));
762			return of_read_number(prop_val, na);
763		}
764	} else {
765		na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
766		ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
767		return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
768						  ofnode_to_offset(node), "reg",
769						  index, na, ns, size,
770						  translate);
771	}
772}
773
774fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
775{
776	return __ofnode_get_addr_size_index(node, index, size, true);
777}
778
779fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
780					      fdt_size_t *size)
781{
782	return __ofnode_get_addr_size_index(node, index, size, false);
783}
784
785fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
786{
787	fdt_size_t size;
788
789	return ofnode_get_addr_size_index(node, index, &size);
790}
791
792fdt_addr_t ofnode_get_addr(ofnode node)
793{
794	return ofnode_get_addr_index(node, 0);
795}
796
797fdt_size_t ofnode_get_size(ofnode node)
798{
799	fdt_size_t size;
800
801	ofnode_get_addr_size_index(node, 0, &size);
802
803	return size;
804}
805
806int ofnode_stringlist_search(ofnode node, const char *property,
807			     const char *string)
808{
809	if (ofnode_is_np(node)) {
810		return of_property_match_string(ofnode_to_np(node),
811						property, string);
812	} else {
813		int ret;
814
815		ret = fdt_stringlist_search(ofnode_to_fdt(node),
816					    ofnode_to_offset(node), property,
817					    string);
818		if (ret == -FDT_ERR_NOTFOUND)
819			return -ENODATA;
820		else if (ret < 0)
821			return -EINVAL;
822
823		return ret;
824	}
825}
826
827int ofnode_read_string_index(ofnode node, const char *property, int index,
828			     const char **outp)
829{
830	if (ofnode_is_np(node)) {
831		return of_property_read_string_index(ofnode_to_np(node),
832						     property, index, outp);
833	} else {
834		int len;
835
836		*outp = fdt_stringlist_get(ofnode_to_fdt(node),
837					   ofnode_to_offset(node),
838					   property, index, &len);
839		if (len < 0)
840			return -EINVAL;
841		return 0;
842	}
843}
844
845int ofnode_read_string_count(ofnode node, const char *property)
846{
847	if (ofnode_is_np(node)) {
848		return of_property_count_strings(ofnode_to_np(node), property);
849	} else {
850		return fdt_stringlist_count(ofnode_to_fdt(node),
851					    ofnode_to_offset(node), property);
852	}
853}
854
855int ofnode_read_string_list(ofnode node, const char *property,
856			    const char ***listp)
857{
858	const char **prop;
859	int count;
860	int i;
861
862	*listp = NULL;
863	count = ofnode_read_string_count(node, property);
864	if (count < 0)
865		return count;
866	if (!count)
867		return 0;
868
869	prop = calloc(count + 1, sizeof(char *));
870	if (!prop)
871		return -ENOMEM;
872
873	for (i = 0; i < count; i++)
874		ofnode_read_string_index(node, property, i, &prop[i]);
875	prop[count] = NULL;
876	*listp = prop;
877
878	return count;
879}
880
881static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
882					    struct ofnode_phandle_args *out)
883{
884	assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
885	out->node = offset_to_ofnode(in->node);
886	out->args_count = in->args_count;
887	memcpy(out->args, in->args, sizeof(out->args));
888}
889
890static void ofnode_from_of_phandle_args(struct of_phandle_args *in,
891					struct ofnode_phandle_args *out)
892{
893	assert(OF_MAX_PHANDLE_ARGS == MAX_PHANDLE_ARGS);
894	out->node = np_to_ofnode(in->np);
895	out->args_count = in->args_count;
896	memcpy(out->args, in->args, sizeof(out->args));
897}
898
899int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
900				   const char *cells_name, int cell_count,
901				   int index,
902				   struct ofnode_phandle_args *out_args)
903{
904	if (ofnode_is_np(node)) {
905		struct of_phandle_args args;
906		int ret;
907
908		ret = of_parse_phandle_with_args(ofnode_to_np(node),
909						 list_name, cells_name,
910						 cell_count, index,
911						 &args);
912		if (ret)
913			return ret;
914		ofnode_from_of_phandle_args(&args, out_args);
915	} else {
916		struct fdtdec_phandle_args args;
917		int ret;
918
919		ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
920						     ofnode_to_offset(node),
921						     list_name, cells_name,
922						     cell_count, index, &args);
923		if (ret)
924			return ret;
925		ofnode_from_fdtdec_phandle_args(&args, out_args);
926	}
927
928	return 0;
929}
930
931int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
932				   const char *cells_name, int cell_count)
933{
934	if (ofnode_is_np(node))
935		return of_count_phandle_with_args(ofnode_to_np(node),
936				list_name, cells_name, cell_count);
937	else
938		return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
939				ofnode_to_offset(node), list_name, cells_name,
940				cell_count, -1, NULL);
941}
942
943ofnode ofnode_path(const char *path)
944{
945	if (of_live_active())
946		return np_to_ofnode(of_find_node_by_path(path));
947	else
948		return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
949}
950
951ofnode oftree_root(oftree tree)
952{
953	if (of_live_active()) {
954		return np_to_ofnode(tree.np);
955	} else {
956		return ofnode_from_tree_offset(tree, 0);
957	}
958}
959
960ofnode oftree_path(oftree tree, const char *path)
961{
962	if (of_live_active()) {
963		return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
964							      NULL));
965	} else if (*path != '/' && tree.fdt != gd->fdt_blob) {
966		return ofnode_null();  /* Aliases only on control FDT */
967	} else {
968		int offset = fdt_path_offset(tree.fdt, path);
969
970		return ofnode_from_tree_offset(tree, offset);
971	}
972}
973
974const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
975{
976	ofnode chosen_node;
977
978	chosen_node = ofnode_path("/chosen");
979
980	return ofnode_read_prop(chosen_node, propname, sizep);
981}
982
983const char *ofnode_read_chosen_string(const char *propname)
984{
985	return ofnode_read_chosen_prop(propname, NULL);
986}
987
988ofnode ofnode_get_chosen_node(const char *name)
989{
990	const char *prop;
991
992	prop = ofnode_read_chosen_prop(name, NULL);
993	if (!prop)
994		return ofnode_null();
995
996	return ofnode_path(prop);
997}
998
999int ofnode_read_baud(void)
1000{
1001	const char *str, *p;
1002	u32 baud;
1003
1004	str = ofnode_read_chosen_string("stdout-path");
1005	if (!str)
1006		return -EINVAL;
1007
1008	/* Parse string serial0:115200n8 */
1009	p = strchr(str, ':');
1010	if (!p)
1011		return -EINVAL;
1012
1013	baud = dectoul(p + 1, NULL);
1014	return baud;
1015}
1016
1017const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
1018{
1019	ofnode node;
1020
1021	node = ofnode_path("/aliases");
1022
1023	return ofnode_read_prop(node, propname, sizep);
1024}
1025
1026ofnode ofnode_get_aliases_node(const char *name)
1027{
1028	const char *prop;
1029
1030	prop = ofnode_read_aliases_prop(name, NULL);
1031	if (!prop)
1032		return ofnode_null();
1033
1034	debug("%s: node_path: %s\n", __func__, prop);
1035
1036	return ofnode_path(prop);
1037}
1038
1039int ofnode_get_child_count(ofnode parent)
1040{
1041	ofnode child;
1042	int num = 0;
1043
1044	ofnode_for_each_subnode(child, parent)
1045		num++;
1046
1047	return num;
1048}
1049
1050static int decode_timing_property(ofnode node, const char *name,
1051				  struct timing_entry *result)
1052{
1053	int length, ret = 0;
1054
1055	length = ofnode_read_size(node, name);
1056	if (length < 0) {
1057		debug("%s: could not find property %s\n",
1058		      ofnode_get_name(node), name);
1059		return length;
1060	}
1061
1062	if (length == sizeof(u32)) {
1063		result->typ = ofnode_read_u32_default(node, name, 0);
1064		result->min = result->typ;
1065		result->max = result->typ;
1066	} else {
1067		ret = ofnode_read_u32_array(node, name, &result->min, 3);
1068	}
1069
1070	return ret;
1071}
1072
1073int ofnode_decode_display_timing(ofnode parent, int index,
1074				 struct display_timing *dt)
1075{
1076	int i;
1077	ofnode timings, node;
1078	u32 val = 0;
1079	int ret = 0;
1080
1081	timings = ofnode_find_subnode(parent, "display-timings");
1082	if (!ofnode_valid(timings))
1083		return -EINVAL;
1084
1085	i = 0;
1086	ofnode_for_each_subnode(node, timings) {
1087		if (i++ == index)
1088			break;
1089	}
1090
1091	if (!ofnode_valid(node))
1092		return -EINVAL;
1093
1094	memset(dt, 0, sizeof(*dt));
1095
1096	ret |= decode_timing_property(node, "hback-porch", &dt->hback_porch);
1097	ret |= decode_timing_property(node, "hfront-porch", &dt->hfront_porch);
1098	ret |= decode_timing_property(node, "hactive", &dt->hactive);
1099	ret |= decode_timing_property(node, "hsync-len", &dt->hsync_len);
1100	ret |= decode_timing_property(node, "vback-porch", &dt->vback_porch);
1101	ret |= decode_timing_property(node, "vfront-porch", &dt->vfront_porch);
1102	ret |= decode_timing_property(node, "vactive", &dt->vactive);
1103	ret |= decode_timing_property(node, "vsync-len", &dt->vsync_len);
1104	ret |= decode_timing_property(node, "clock-frequency", &dt->pixelclock);
1105
1106	dt->flags = 0;
1107	val = ofnode_read_u32_default(node, "vsync-active", -1);
1108	if (val != -1) {
1109		dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1110				DISPLAY_FLAGS_VSYNC_LOW;
1111	}
1112	val = ofnode_read_u32_default(node, "hsync-active", -1);
1113	if (val != -1) {
1114		dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1115				DISPLAY_FLAGS_HSYNC_LOW;
1116	}
1117	val = ofnode_read_u32_default(node, "de-active", -1);
1118	if (val != -1) {
1119		dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1120				DISPLAY_FLAGS_DE_LOW;
1121	}
1122	val = ofnode_read_u32_default(node, "pixelclk-active", -1);
1123	if (val != -1) {
1124		dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1125				DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1126	}
1127
1128	if (ofnode_read_bool(node, "interlaced"))
1129		dt->flags |= DISPLAY_FLAGS_INTERLACED;
1130	if (ofnode_read_bool(node, "doublescan"))
1131		dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1132	if (ofnode_read_bool(node, "doubleclk"))
1133		dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1134
1135	return ret;
1136}
1137
1138int ofnode_decode_panel_timing(ofnode parent,
1139			       struct display_timing *dt)
1140{
1141	ofnode timings;
1142	u32 val = 0;
1143	int ret = 0;
1144
1145	timings = ofnode_find_subnode(parent, "panel-timing");
1146	if (!ofnode_valid(timings))
1147		return -EINVAL;
1148	memset(dt, 0, sizeof(*dt));
1149	ret |= decode_timing_property(timings, "hback-porch", &dt->hback_porch);
1150	ret |= decode_timing_property(timings, "hfront-porch", &dt->hfront_porch);
1151	ret |= decode_timing_property(timings, "hactive", &dt->hactive);
1152	ret |= decode_timing_property(timings, "hsync-len", &dt->hsync_len);
1153	ret |= decode_timing_property(timings, "vback-porch", &dt->vback_porch);
1154	ret |= decode_timing_property(timings, "vfront-porch", &dt->vfront_porch);
1155	ret |= decode_timing_property(timings, "vactive", &dt->vactive);
1156	ret |= decode_timing_property(timings, "vsync-len", &dt->vsync_len);
1157	ret |= decode_timing_property(timings, "clock-frequency", &dt->pixelclock);
1158	dt->flags = 0;
1159	if (!ofnode_read_u32(timings, "vsync-active", &val)) {
1160		dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
1161		    DISPLAY_FLAGS_VSYNC_LOW;
1162	}
1163	if (!ofnode_read_u32(timings, "hsync-active", &val)) {
1164		dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
1165		    DISPLAY_FLAGS_HSYNC_LOW;
1166	}
1167	if (!ofnode_read_u32(timings, "de-active", &val)) {
1168		dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
1169		    DISPLAY_FLAGS_DE_LOW;
1170	}
1171	if (!ofnode_read_u32(timings, "pixelclk-active", &val)) {
1172		dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
1173		DISPLAY_FLAGS_PIXDATA_NEGEDGE;
1174	}
1175	if (ofnode_read_bool(timings, "interlaced"))
1176		dt->flags |= DISPLAY_FLAGS_INTERLACED;
1177	if (ofnode_read_bool(timings, "doublescan"))
1178		dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
1179	if (ofnode_read_bool(timings, "doubleclk"))
1180		dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
1181
1182	return ret;
1183}
1184
1185const void *ofnode_get_property(ofnode node, const char *propname, int *lenp)
1186{
1187	if (ofnode_is_np(node))
1188		return of_get_property(ofnode_to_np(node), propname, lenp);
1189	else
1190		return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1191				   propname, lenp);
1192}
1193
1194bool ofnode_has_property(ofnode node, const char *propname)
1195{
1196	if (ofnode_is_np(node))
1197		return of_find_property(ofnode_to_np(node), propname, NULL);
1198	else
1199		return ofnode_get_property(node, propname, NULL);
1200}
1201
1202int ofnode_first_property(ofnode node, struct ofprop *prop)
1203{
1204	prop->node = node;
1205
1206	if (ofnode_is_np(node)) {
1207		prop->prop = of_get_first_property(ofnode_to_np(prop->node));
1208		if (!prop->prop)
1209			return -FDT_ERR_NOTFOUND;
1210	} else {
1211		prop->offset =
1212			fdt_first_property_offset(ofnode_to_fdt(node),
1213						  ofnode_to_offset(prop->node));
1214		if (prop->offset < 0)
1215			return prop->offset;
1216	}
1217
1218	return 0;
1219}
1220
1221int ofnode_next_property(struct ofprop *prop)
1222{
1223	if (ofnode_is_np(prop->node)) {
1224		prop->prop = of_get_next_property(ofnode_to_np(prop->node),
1225						  prop->prop);
1226		if (!prop->prop)
1227			return -FDT_ERR_NOTFOUND;
1228	} else {
1229		prop->offset =
1230			fdt_next_property_offset(ofnode_to_fdt(prop->node),
1231						 prop->offset);
1232		if (prop->offset  < 0)
1233			return prop->offset;
1234	}
1235
1236	return 0;
1237}
1238
1239const void *ofprop_get_property(const struct ofprop *prop,
1240				const char **propname, int *lenp)
1241{
1242	if (ofnode_is_np(prop->node))
1243		return of_get_property_by_prop(ofnode_to_np(prop->node),
1244					       prop->prop, propname, lenp);
1245	else
1246		return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
1247					     prop->offset,
1248					     propname, lenp);
1249}
1250
1251fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
1252				fdt_size_t *sizep)
1253{
1254	if (ofnode_is_np(node)) {
1255		int na, ns;
1256		int psize;
1257		const struct device_node *np = ofnode_to_np(node);
1258		const __be32 *prop = of_get_property(np, property, &psize);
1259
1260		if (!prop)
1261			return FDT_ADDR_T_NONE;
1262		na = of_n_addr_cells(np);
1263		ns = of_n_size_cells(np);
1264		*sizep = of_read_number(prop + na, ns);
1265
1266		if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
1267			return of_translate_address(np, prop);
1268		else
1269			return of_read_number(prop, na);
1270	} else {
1271		return fdtdec_get_addr_size(ofnode_to_fdt(node),
1272					    ofnode_to_offset(node), property,
1273					    sizep);
1274	}
1275}
1276
1277const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
1278					size_t sz)
1279{
1280	if (ofnode_is_np(node)) {
1281		const struct device_node *np = ofnode_to_np(node);
1282		int psize;
1283		const __be32 *prop = of_get_property(np, propname, &psize);
1284
1285		if (!prop || sz != psize)
1286			return NULL;
1287		return (uint8_t *)prop;
1288
1289	} else {
1290		return fdtdec_locate_byte_array(ofnode_to_fdt(node),
1291				ofnode_to_offset(node), propname, sz);
1292	}
1293}
1294
1295int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
1296			 const char *propname, struct fdt_pci_addr *addr,
1297			 fdt_size_t *size)
1298{
1299	const fdt32_t *cell;
1300	int len;
1301	int ret = -ENOENT;
1302
1303	debug("%s: %s: ", __func__, propname);
1304
1305	/*
1306	 * If we follow the pci bus bindings strictly, we should check
1307	 * the value of the node's parent node's #address-cells and
1308	 * #size-cells. They need to be 3 and 2 accordingly. However,
1309	 * for simplicity we skip the check here.
1310	 */
1311	cell = ofnode_get_property(node, propname, &len);
1312	if (!cell)
1313		goto fail;
1314
1315	if ((len % FDT_PCI_REG_SIZE) == 0) {
1316		int num = len / FDT_PCI_REG_SIZE;
1317		int i;
1318
1319		for (i = 0; i < num; i++) {
1320			debug("pci address #%d: %08lx %08lx %08lx\n", i,
1321			      (ulong)fdt32_to_cpu(cell[0]),
1322			      (ulong)fdt32_to_cpu(cell[1]),
1323			      (ulong)fdt32_to_cpu(cell[2]));
1324			if ((fdt32_to_cpu(*cell) & type) == type) {
1325				const unaligned_fdt64_t *ptr;
1326
1327				addr->phys_hi = fdt32_to_cpu(cell[0]);
1328				addr->phys_mid = fdt32_to_cpu(cell[1]);
1329				addr->phys_lo = fdt32_to_cpu(cell[2]);
1330				ptr = (const unaligned_fdt64_t *)(cell + 3);
1331				if (size)
1332					*size = fdt64_to_cpu(*ptr);
1333				break;
1334			}
1335
1336			cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS;
1337		}
1338
1339		if (i == num) {
1340			ret = -ENXIO;
1341			goto fail;
1342		}
1343
1344		return 0;
1345	}
1346
1347	ret = -EINVAL;
1348
1349fail:
1350	debug("(not found)\n");
1351	return ret;
1352}
1353
1354int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
1355{
1356	const char *list, *end;
1357	int len;
1358
1359	list = ofnode_get_property(node, "compatible", &len);
1360	if (!list)
1361		return -ENOENT;
1362
1363	end = list + len;
1364	while (list < end) {
1365		len = strlen(list);
1366		if (len >= strlen("pciVVVV,DDDD")) {
1367			char *s = strstr(list, "pci");
1368
1369			/*
1370			 * check if the string is something like pciVVVV,DDDD.RR
1371			 * or just pciVVVV,DDDD
1372			 */
1373			if (s && s[7] == ',' &&
1374			    (s[12] == '.' || s[12] == 0)) {
1375				s += 3;
1376				*vendor = simple_strtol(s, NULL, 16);
1377
1378				s += 5;
1379				*device = simple_strtol(s, NULL, 16);
1380
1381				return 0;
1382			}
1383		}
1384		list += (len + 1);
1385	}
1386
1387	return -ENOENT;
1388}
1389
1390int ofnode_read_eth_phy_id(ofnode node, u16 *vendor, u16 *device)
1391{
1392	const char *list, *end;
1393	int len;
1394
1395	list = ofnode_get_property(node, "compatible", &len);
1396
1397	if (!list)
1398		return -ENOENT;
1399
1400	end = list + len;
1401	while (list < end) {
1402		len = strlen(list);
1403
1404		if (len >= strlen("ethernet-phy-idVVVV.DDDD")) {
1405			char *s = strstr(list, "ethernet-phy-id");
1406
1407			/*
1408			 * check if the string is something like
1409			 * ethernet-phy-idVVVV.DDDD
1410			 */
1411			if (s && s[19] == '.') {
1412				s += strlen("ethernet-phy-id");
1413				*vendor = simple_strtol(s, NULL, 16);
1414				s += 5;
1415				*device = simple_strtol(s, NULL, 16);
1416
1417				return 0;
1418			}
1419		}
1420		list += (len + 1);
1421	}
1422
1423	return -ENOENT;
1424}
1425
1426int ofnode_read_addr_cells(ofnode node)
1427{
1428	if (ofnode_is_np(node)) {
1429		return of_n_addr_cells(ofnode_to_np(node));
1430	} else {
1431		int parent = fdt_parent_offset(ofnode_to_fdt(node),
1432					       ofnode_to_offset(node));
1433
1434		return fdt_address_cells(ofnode_to_fdt(node), parent);
1435	}
1436}
1437
1438int ofnode_read_size_cells(ofnode node)
1439{
1440	if (ofnode_is_np(node)) {
1441		return of_n_size_cells(ofnode_to_np(node));
1442	} else {
1443		int parent = fdt_parent_offset(ofnode_to_fdt(node),
1444					       ofnode_to_offset(node));
1445
1446		return fdt_size_cells(ofnode_to_fdt(node), parent);
1447	}
1448}
1449
1450int ofnode_read_simple_addr_cells(ofnode node)
1451{
1452	if (ofnode_is_np(node))
1453		return of_simple_addr_cells(ofnode_to_np(node));
1454	else
1455		return fdt_address_cells(ofnode_to_fdt(node),
1456					 ofnode_to_offset(node));
1457}
1458
1459int ofnode_read_simple_size_cells(ofnode node)
1460{
1461	if (ofnode_is_np(node))
1462		return of_simple_size_cells(ofnode_to_np(node));
1463	else
1464		return fdt_size_cells(ofnode_to_fdt(node),
1465				      ofnode_to_offset(node));
1466}
1467
1468bool ofnode_pre_reloc(ofnode node)
1469{
1470#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
1471	/* for SPL and TPL the remaining nodes after the fdtgrep 1st pass
1472	 * had property bootph-all or bootph-pre-sram/bootph-pre-ram.
1473	 * They are removed in final dtb (fdtgrep 2nd pass)
1474	 */
1475	return true;
1476#else
1477	if (ofnode_read_bool(node, "bootph-all"))
1478		return true;
1479	if (ofnode_read_bool(node, "bootph-some-ram"))
1480		return true;
1481
1482	/*
1483	 * In regular builds individual spl and tpl handling both
1484	 * count as handled pre-relocation for later second init.
1485	 */
1486	if (ofnode_read_bool(node, "bootph-pre-ram") ||
1487	    ofnode_read_bool(node, "bootph-pre-sram"))
1488		return gd->flags & GD_FLG_RELOC;
1489
1490	if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) {
1491		/* detect and handle old tags */
1492		if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") ||
1493		    ofnode_read_bool(node, "u-boot,dm-pre-proper") ||
1494		    ofnode_read_bool(node, "u-boot,dm-spl") ||
1495		    ofnode_read_bool(node, "u-boot,dm-tpl") ||
1496		    ofnode_read_bool(node, "u-boot,dm-vpl")) {
1497			gd->flags |= GD_FLG_OF_TAG_MIGRATE;
1498			return true;
1499		}
1500	}
1501
1502	return false;
1503#endif
1504}
1505
1506int ofnode_read_resource(ofnode node, uint index, struct resource *res)
1507{
1508	if (ofnode_is_np(node)) {
1509		return of_address_to_resource(ofnode_to_np(node), index, res);
1510	} else {
1511		struct fdt_resource fres;
1512		int ret;
1513
1514		ret = fdt_get_resource(ofnode_to_fdt(node),
1515				       ofnode_to_offset(node),
1516				       "reg", index, &fres);
1517		if (ret < 0)
1518			return -EINVAL;
1519		memset(res, '\0', sizeof(*res));
1520		res->start = fres.start;
1521		res->end = fres.end;
1522
1523		return 0;
1524	}
1525}
1526
1527int ofnode_read_resource_byname(ofnode node, const char *name,
1528				struct resource *res)
1529{
1530	int index;
1531
1532	index = ofnode_stringlist_search(node, "reg-names", name);
1533	if (index < 0)
1534		return index;
1535
1536	return ofnode_read_resource(node, index, res);
1537}
1538
1539u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
1540{
1541	if (ofnode_is_np(node))
1542		return of_translate_address(ofnode_to_np(node), in_addr);
1543	else
1544		return fdt_translate_address(ofnode_to_fdt(node),
1545					     ofnode_to_offset(node), in_addr);
1546}
1547
1548u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
1549{
1550	if (ofnode_is_np(node))
1551		return of_translate_dma_address(ofnode_to_np(node), in_addr);
1552	else
1553		return fdt_translate_dma_address(ofnode_to_fdt(node),
1554						 ofnode_to_offset(node), in_addr);
1555}
1556
1557int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
1558{
1559	if (ofnode_is_np(node))
1560		return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
1561	else
1562		return fdt_get_dma_range(ofnode_to_fdt(node),
1563					 ofnode_to_offset(node),
1564					 cpu, bus, size);
1565}
1566
1567int ofnode_device_is_compatible(ofnode node, const char *compat)
1568{
1569	if (ofnode_is_np(node))
1570		return of_device_is_compatible(ofnode_to_np(node), compat,
1571					       NULL, NULL);
1572	else
1573		return !fdt_node_check_compatible(ofnode_to_fdt(node),
1574						  ofnode_to_offset(node),
1575						  compat);
1576}
1577
1578ofnode ofnode_by_compatible(ofnode from, const char *compat)
1579{
1580	if (of_live_active()) {
1581		return np_to_ofnode(of_find_compatible_node(
1582			(struct device_node *)ofnode_to_np(from), NULL,
1583			compat));
1584	} else {
1585		return noffset_to_ofnode(from,
1586			fdt_node_offset_by_compatible(ofnode_to_fdt(from),
1587					ofnode_to_offset(from), compat));
1588	}
1589}
1590
1591ofnode ofnode_by_prop_value(ofnode from, const char *propname,
1592			    const void *propval, int proplen)
1593{
1594	if (of_live_active()) {
1595		return np_to_ofnode(of_find_node_by_prop_value(
1596			(struct device_node *)ofnode_to_np(from), propname,
1597			propval, proplen));
1598	} else {
1599		return noffset_to_ofnode(from,
1600			 fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
1601				ofnode_to_offset(from), propname, propval,
1602				proplen));
1603	}
1604}
1605
1606int ofnode_write_prop(ofnode node, const char *propname, const void *value,
1607		      int len, bool copy)
1608{
1609	if (of_live_active()) {
1610		void *newval;
1611		int ret;
1612
1613		if (copy) {
1614			newval = malloc(len);
1615			if (!newval)
1616				return log_ret(-ENOMEM);
1617			memcpy(newval, value, len);
1618			value = newval;
1619		}
1620		ret = of_write_prop(ofnode_to_np(node), propname, len, value);
1621		if (ret && copy)
1622			free(newval);
1623		return ret;
1624	} else {
1625		return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1626				   propname, value, len);
1627	}
1628}
1629
1630int ofnode_write_string(ofnode node, const char *propname, const char *value)
1631{
1632	assert(ofnode_valid(node));
1633
1634	debug("%s: %s = %s", __func__, propname, value);
1635
1636	return ofnode_write_prop(node, propname, value, strlen(value) + 1,
1637				 false);
1638}
1639
1640int ofnode_write_u32(ofnode node, const char *propname, u32 value)
1641{
1642	fdt32_t *val;
1643
1644	assert(ofnode_valid(node));
1645
1646	log_debug("%s = %x", propname, value);
1647	val = malloc(sizeof(*val));
1648	if (!val)
1649		return -ENOMEM;
1650	*val = cpu_to_fdt32(value);
1651
1652	return ofnode_write_prop(node, propname, val, sizeof(value), true);
1653}
1654
1655int ofnode_write_u64(ofnode node, const char *propname, u64 value)
1656{
1657	fdt64_t *val;
1658
1659	assert(ofnode_valid(node));
1660
1661	log_debug("%s = %llx", propname, (unsigned long long)value);
1662	val = malloc(sizeof(*val));
1663	if (!val)
1664		return -ENOMEM;
1665	*val = cpu_to_fdt64(value);
1666
1667	return ofnode_write_prop(node, propname, val, sizeof(value), true);
1668}
1669
1670int ofnode_write_bool(ofnode node, const char *propname, bool value)
1671{
1672	if (value)
1673		return ofnode_write_prop(node, propname, NULL, 0, false);
1674	else
1675		return ofnode_delete_prop(node, propname);
1676}
1677
1678int ofnode_delete_prop(ofnode node, const char *propname)
1679{
1680	if (ofnode_is_np(node)) {
1681		struct property *prop;
1682		int len;
1683
1684		prop = of_find_property(ofnode_to_np(node), propname, &len);
1685		if (prop)
1686			return of_remove_property(ofnode_to_np(node), prop);
1687		return 0;
1688	} else {
1689		return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node),
1690				   propname);
1691	}
1692}
1693
1694int ofnode_set_enabled(ofnode node, bool value)
1695{
1696	assert(ofnode_valid(node));
1697
1698	if (value)
1699		return ofnode_write_string(node, "status", "okay");
1700	else
1701		return ofnode_write_string(node, "status", "disabled");
1702}
1703
1704bool ofnode_conf_read_bool(const char *prop_name)
1705{
1706	ofnode node;
1707
1708	node = ofnode_path("/config");
1709	if (!ofnode_valid(node))
1710		return false;
1711
1712	return ofnode_read_bool(node, prop_name);
1713}
1714
1715int ofnode_conf_read_int(const char *prop_name, int default_val)
1716{
1717	ofnode node;
1718
1719	node = ofnode_path("/config");
1720	if (!ofnode_valid(node))
1721		return default_val;
1722
1723	return ofnode_read_u32_default(node, prop_name, default_val);
1724}
1725
1726const char *ofnode_conf_read_str(const char *prop_name)
1727{
1728	ofnode node;
1729
1730	node = ofnode_path("/config");
1731	if (!ofnode_valid(node))
1732		return NULL;
1733
1734	return ofnode_read_string(node, prop_name);
1735}
1736
1737int ofnode_read_bootscript_address(u64 *bootscr_address, u64 *bootscr_offset)
1738{
1739	int ret;
1740	ofnode uboot;
1741
1742	*bootscr_address = 0;
1743	*bootscr_offset = 0;
1744
1745	uboot = ofnode_path("/options/u-boot");
1746	if (!ofnode_valid(uboot)) {
1747		debug("%s: Missing /u-boot node\n", __func__);
1748		return -EINVAL;
1749	}
1750
1751	ret = ofnode_read_u64(uboot, "bootscr-address", bootscr_address);
1752	if (ret) {
1753		ret = ofnode_read_u64(uboot, "bootscr-ram-offset",
1754				      bootscr_offset);
1755		if (ret)
1756			return -EINVAL;
1757	}
1758
1759	return 0;
1760}
1761
1762int ofnode_read_bootscript_flash(u64 *bootscr_flash_offset,
1763				 u64 *bootscr_flash_size)
1764{
1765	int ret;
1766	ofnode uboot;
1767
1768	*bootscr_flash_offset = 0;
1769	*bootscr_flash_size = 0;
1770
1771	uboot = ofnode_path("/options/u-boot");
1772	if (!ofnode_valid(uboot)) {
1773		debug("%s: Missing /u-boot node\n", __func__);
1774		return -EINVAL;
1775	}
1776
1777	ret = ofnode_read_u64(uboot, "bootscr-flash-offset",
1778			      bootscr_flash_offset);
1779	if (ret)
1780		return -EINVAL;
1781
1782	ret = ofnode_read_u64(uboot, "bootscr-flash-size",
1783			      bootscr_flash_size);
1784	if (ret)
1785		return -EINVAL;
1786
1787	if (!bootscr_flash_size) {
1788		debug("bootscr-flash-size is zero. Ignoring properties!\n");
1789		*bootscr_flash_offset = 0;
1790		return -EINVAL;
1791	}
1792
1793	return 0;
1794}
1795
1796ofnode ofnode_get_phy_node(ofnode node)
1797{
1798	/* DT node properties that reference a PHY node */
1799	static const char * const phy_handle_str[] = {
1800		"phy-handle", "phy", "phy-device",
1801	};
1802	struct ofnode_phandle_args args = {
1803		.node = ofnode_null()
1804	};
1805	int i;
1806
1807	assert(ofnode_valid(node));
1808
1809	for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
1810		if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
1811						    NULL, 0, 0, &args))
1812			break;
1813
1814	return args.node;
1815}
1816
1817phy_interface_t ofnode_read_phy_mode(ofnode node)
1818{
1819	const char *mode;
1820	int i;
1821
1822	assert(ofnode_valid(node));
1823
1824	mode = ofnode_read_string(node, "phy-mode");
1825	if (!mode)
1826		mode = ofnode_read_string(node, "phy-connection-type");
1827
1828	if (!mode)
1829		return PHY_INTERFACE_MODE_NA;
1830
1831	for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
1832		if (!strcmp(mode, phy_interface_strings[i]))
1833			return i;
1834
1835	debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
1836
1837	return PHY_INTERFACE_MODE_NA;
1838}
1839
1840int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
1841{
1842	ofnode subnode;
1843	int ret = 0;
1844
1845	assert(ofnode_valid(node));
1846
1847	if (ofnode_is_np(node)) {
1848		struct device_node *np, *child;
1849
1850		np = (struct device_node *)ofnode_to_np(node);
1851		ret = of_add_subnode(np, name, -1, &child);
1852		if (ret && ret != -EEXIST)
1853			return ret;
1854		subnode = np_to_ofnode(child);
1855	} else {
1856		void *fdt = ofnode_to_fdt(node);
1857		int poffset = ofnode_to_offset(node);
1858		int offset;
1859
1860		offset = fdt_add_subnode(fdt, poffset, name);
1861		if (offset == -FDT_ERR_EXISTS) {
1862			offset = fdt_subnode_offset(fdt, poffset, name);
1863			ret = -EEXIST;
1864		}
1865		if (offset < 0)
1866			return -EINVAL;
1867		subnode = noffset_to_ofnode(node, offset);
1868	}
1869
1870	*subnodep = subnode;
1871
1872	return ret;	/* 0 or -EEXIST */
1873}
1874
1875int ofnode_delete(ofnode *nodep)
1876{
1877	ofnode node = *nodep;
1878	int ret;
1879
1880	assert(ofnode_valid(node));
1881	if (ofnode_is_np(node)) {
1882		ret = of_remove_node(ofnode_to_np(node));
1883	} else {
1884		void *fdt = ofnode_to_fdt(node);
1885		int offset = ofnode_to_offset(node);
1886
1887		ret = fdt_del_node(fdt, offset);
1888		if (ret)
1889			ret = -EFAULT;
1890	}
1891	if (ret)
1892		return ret;
1893	*nodep = ofnode_null();
1894
1895	return 0;
1896}
1897
1898int ofnode_copy_props(ofnode dst, ofnode src)
1899{
1900	struct ofprop prop;
1901
1902	ofnode_for_each_prop(prop, src) {
1903		const char *name;
1904		const char *val;
1905		int len, ret;
1906
1907		val = ofprop_get_property(&prop, &name, &len);
1908		if (!val) {
1909			log_debug("Cannot read prop (err=%d)\n", len);
1910			return log_msg_ret("get", -EINVAL);
1911		}
1912		ret = ofnode_write_prop(dst, name, val, len, true);
1913		if (ret) {
1914			log_debug("Cannot write prop (err=%d)\n", ret);
1915			return log_msg_ret("wr", -EINVAL);
1916		}
1917	}
1918
1919	return 0;
1920}
1921
1922int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src,
1923		     ofnode *nodep)
1924{
1925	ofnode node;
1926	int ret;
1927
1928	ret = ofnode_add_subnode(dst_parent, name, &node);
1929	if (ret) {
1930		if (ret == -EEXIST)
1931			*nodep = node;
1932		return log_msg_ret("add", ret);
1933	}
1934	ret = ofnode_copy_props(node, src);
1935	if (ret)
1936		return log_msg_ret("cpy", ret);
1937	*nodep = node;
1938
1939	return 0;
1940}
1941