blob: 0a12e9b26f89d0efeadb12527098713213613497 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass1ccaa052017-05-18 20:08:54 -06002/*
3 * Originally from Linux v4.9
4 * Paul Mackerras August 1996.
5 * Copyright (C) 1996-2005 Paul Mackerras.
6 *
7 * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
8 * {engebret|bergner}@us.ibm.com
9 *
10 * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
11 *
12 * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
13 * Grant Likely.
14 *
15 * Modified for U-Boot
16 * Copyright (c) 2017 Google, Inc
17 *
18 * This file follows drivers/of/base.c with functions in the same order as the
19 * Linux version.
Simon Glass1ccaa052017-05-18 20:08:54 -060020 */
21
22#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -060023#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070024#include <malloc.h>
Simon Glassc06c1be2020-05-10 11:40:08 -060025#include <linux/bug.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090026#include <linux/libfdt.h>
Simon Glass1ccaa052017-05-18 20:08:54 -060027#include <dm/of_access.h>
28#include <linux/ctype.h>
29#include <linux/err.h>
30#include <linux/ioport.h>
31
32DECLARE_GLOBAL_DATA_PTR;
33
34/* list of struct alias_prop aliases */
35LIST_HEAD(aliases_lookup);
36
37/* "/aliaes" node */
38static struct device_node *of_aliases;
39
40/* "/chosen" node */
41static struct device_node *of_chosen;
42
43/* node pointed to by the stdout-path alias */
44static struct device_node *of_stdout;
45
46/* pointer to options given after the alias (separated by :) or NULL if none */
47static const char *of_stdout_options;
48
49/**
50 * struct alias_prop - Alias property in 'aliases' node
51 *
52 * The structure represents one alias property of 'aliases' node as
53 * an entry in aliases_lookup list.
54 *
55 * @link: List node to link the structure in aliases_lookup list
56 * @alias: Alias property name
57 * @np: Pointer to device_node that the alias stands for
58 * @id: Index value from end of alias name
59 * @stem: Alias string without the index
60 */
61struct alias_prop {
62 struct list_head link;
63 const char *alias;
64 struct device_node *np;
65 int id;
66 char stem[0];
67};
68
69int of_n_addr_cells(const struct device_node *np)
70{
71 const __be32 *ip;
72
73 do {
74 if (np->parent)
75 np = np->parent;
76 ip = of_get_property(np, "#address-cells", NULL);
77 if (ip)
78 return be32_to_cpup(ip);
79 } while (np->parent);
80
81 /* No #address-cells property for the root node */
82 return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
83}
84
85int of_n_size_cells(const struct device_node *np)
86{
87 const __be32 *ip;
88
89 do {
90 if (np->parent)
91 np = np->parent;
92 ip = of_get_property(np, "#size-cells", NULL);
93 if (ip)
94 return be32_to_cpup(ip);
95 } while (np->parent);
96
97 /* No #size-cells property for the root node */
98 return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
99}
100
Simon Glass4191dc12017-06-12 06:21:31 -0600101int of_simple_addr_cells(const struct device_node *np)
102{
103 const __be32 *ip;
104
105 ip = of_get_property(np, "#address-cells", NULL);
106 if (ip)
107 return be32_to_cpup(ip);
108
109 /* Return a default of 2 to match fdt_address_cells()*/
110 return 2;
111}
112
113int of_simple_size_cells(const struct device_node *np)
114{
115 const __be32 *ip;
116
117 ip = of_get_property(np, "#size-cells", NULL);
118 if (ip)
119 return be32_to_cpup(ip);
120
121 /* Return a default of 2 to match fdt_size_cells()*/
122 return 2;
123}
124
Simon Glass1ccaa052017-05-18 20:08:54 -0600125struct property *of_find_property(const struct device_node *np,
126 const char *name, int *lenp)
127{
128 struct property *pp;
129
130 if (!np)
131 return NULL;
132
133 for (pp = np->properties; pp; pp = pp->next) {
134 if (strcmp(pp->name, name) == 0) {
135 if (lenp)
136 *lenp = pp->length;
137 break;
138 }
139 }
140 if (!pp && lenp)
141 *lenp = -FDT_ERR_NOTFOUND;
142
143 return pp;
144}
145
146struct device_node *of_find_all_nodes(struct device_node *prev)
147{
148 struct device_node *np;
149
150 if (!prev) {
151 np = gd->of_root;
152 } else if (prev->child) {
153 np = prev->child;
154 } else {
155 /*
156 * Walk back up looking for a sibling, or the end of the
157 * structure
158 */
159 np = prev;
160 while (np->parent && !np->sibling)
161 np = np->parent;
162 np = np->sibling; /* Might be null at the end of the tree */
163 }
164
165 return np;
166}
167
168const void *of_get_property(const struct device_node *np, const char *name,
169 int *lenp)
170{
171 struct property *pp = of_find_property(np, name, lenp);
172
173 return pp ? pp->value : NULL;
174}
175
Patrick Delaunaycaee1552020-01-13 11:34:56 +0100176const struct property *of_get_first_property(const struct device_node *np)
177{
178 if (!np)
179 return NULL;
180
181 return np->properties;
182}
183
184const struct property *of_get_next_property(const struct device_node *np,
185 const struct property *property)
186{
187 if (!np)
188 return NULL;
189
190 return property->next;
191}
192
193const void *of_get_property_by_prop(const struct device_node *np,
194 const struct property *property,
195 const char **name,
196 int *lenp)
197{
198 if (!np || !property)
199 return NULL;
200 if (name)
201 *name = property->name;
202 if (lenp)
203 *lenp = property->length;
204
205 return property->value;
206}
207
Simon Glass1ccaa052017-05-18 20:08:54 -0600208static const char *of_prop_next_string(struct property *prop, const char *cur)
209{
210 const void *curv = cur;
211
212 if (!prop)
213 return NULL;
214
215 if (!cur)
216 return prop->value;
217
218 curv += strlen(cur) + 1;
219 if (curv >= prop->value + prop->length)
220 return NULL;
221
222 return curv;
223}
224
225int of_device_is_compatible(const struct device_node *device,
226 const char *compat, const char *type,
227 const char *name)
228{
229 struct property *prop;
230 const char *cp;
231 int index = 0, score = 0;
232
233 /* Compatible match has highest priority */
234 if (compat && compat[0]) {
235 prop = of_find_property(device, "compatible", NULL);
236 for (cp = of_prop_next_string(prop, NULL); cp;
237 cp = of_prop_next_string(prop, cp), index++) {
238 if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
239 score = INT_MAX/2 - (index << 2);
240 break;
241 }
242 }
243 if (!score)
244 return 0;
245 }
246
247 /* Matching type is better than matching name */
248 if (type && type[0]) {
249 if (!device->type || of_node_cmp(type, device->type))
250 return 0;
251 score += 2;
252 }
253
254 /* Matching name is a bit better than not */
255 if (name && name[0]) {
256 if (!device->name || of_node_cmp(name, device->name))
257 return 0;
258 score++;
259 }
260
261 return score;
262}
263
264bool of_device_is_available(const struct device_node *device)
265{
266 const char *status;
267 int statlen;
268
269 if (!device)
270 return false;
271
272 status = of_get_property(device, "status", &statlen);
273 if (status == NULL)
274 return true;
275
276 if (statlen > 0) {
277 if (!strcmp(status, "okay"))
278 return true;
279 }
280
281 return false;
282}
283
284struct device_node *of_get_parent(const struct device_node *node)
285{
286 const struct device_node *np;
287
288 if (!node)
289 return NULL;
290
291 np = of_node_get(node->parent);
292
293 return (struct device_node *)np;
294}
295
296static struct device_node *__of_get_next_child(const struct device_node *node,
297 struct device_node *prev)
298{
299 struct device_node *next;
300
301 if (!node)
302 return NULL;
303
304 next = prev ? prev->sibling : node->child;
Simon Glass3694ac52017-06-07 10:28:45 -0600305 /*
306 * coverity[dead_error_line : FALSE]
307 * Dead code here since our current implementation of of_node_get()
308 * always returns NULL (Coverity CID 163245). But we leave it as is
309 * since we may want to implement get/put later.
310 */
Simon Glass1ccaa052017-05-18 20:08:54 -0600311 for (; next; next = next->sibling)
312 if (of_node_get(next))
313 break;
314 of_node_put(prev);
315 return next;
316}
317
318#define __for_each_child_of_node(parent, child) \
319 for (child = __of_get_next_child(parent, NULL); child != NULL; \
320 child = __of_get_next_child(parent, child))
321
322static struct device_node *__of_find_node_by_path(struct device_node *parent,
323 const char *path)
324{
325 struct device_node *child;
326 int len;
327
328 len = strcspn(path, "/:");
329 if (!len)
330 return NULL;
331
332 __for_each_child_of_node(parent, child) {
333 const char *name = strrchr(child->full_name, '/');
334
335 name++;
336 if (strncmp(path, name, len) == 0 && (strlen(name) == len))
337 return child;
338 }
339 return NULL;
340}
341
342#define for_each_property_of_node(dn, pp) \
343 for (pp = dn->properties; pp != NULL; pp = pp->next)
344
345struct device_node *of_find_node_opts_by_path(const char *path,
346 const char **opts)
347{
348 struct device_node *np = NULL;
349 struct property *pp;
350 const char *separator = strchr(path, ':');
351
352 if (opts)
353 *opts = separator ? separator + 1 : NULL;
354
355 if (strcmp(path, "/") == 0)
356 return of_node_get(gd->of_root);
357
358 /* The path could begin with an alias */
359 if (*path != '/') {
360 int len;
361 const char *p = separator;
362
363 if (!p)
364 p = strchrnul(path, '/');
365 len = p - path;
366
367 /* of_aliases must not be NULL */
368 if (!of_aliases)
369 return NULL;
370
371 for_each_property_of_node(of_aliases, pp) {
372 if (strlen(pp->name) == len && !strncmp(pp->name, path,
373 len)) {
374 np = of_find_node_by_path(pp->value);
375 break;
376 }
377 }
378 if (!np)
379 return NULL;
380 path = p;
381 }
382
383 /* Step down the tree matching path components */
384 if (!np)
385 np = of_node_get(gd->of_root);
386 while (np && *path == '/') {
387 struct device_node *tmp = np;
388
389 path++; /* Increment past '/' delimiter */
390 np = __of_find_node_by_path(np, path);
391 of_node_put(tmp);
392 path = strchrnul(path, '/');
393 if (separator && separator < path)
394 break;
395 }
396
397 return np;
398}
399
400struct device_node *of_find_compatible_node(struct device_node *from,
401 const char *type, const char *compatible)
402{
403 struct device_node *np;
404
405 for_each_of_allnodes_from(from, np)
406 if (of_device_is_compatible(np, compatible, type, NULL) &&
407 of_node_get(np))
408 break;
409 of_node_put(from);
410
411 return np;
412}
413
Jens Wiklander7b68dad2018-08-20 11:09:58 +0200414static int of_device_has_prop_value(const struct device_node *device,
415 const char *propname, const void *propval,
416 int proplen)
417{
418 struct property *prop = of_find_property(device, propname, NULL);
419
420 if (!prop || !prop->value || prop->length != proplen)
421 return 0;
422 return !memcmp(prop->value, propval, proplen);
423}
424
425struct device_node *of_find_node_by_prop_value(struct device_node *from,
426 const char *propname,
427 const void *propval, int proplen)
428{
429 struct device_node *np;
430
431 for_each_of_allnodes_from(from, np) {
432 if (of_device_has_prop_value(np, propname, propval, proplen) &&
433 of_node_get(np))
434 break;
435 }
436 of_node_put(from);
437
438 return np;
439}
440
Simon Glass1ccaa052017-05-18 20:08:54 -0600441struct device_node *of_find_node_by_phandle(phandle handle)
442{
443 struct device_node *np;
444
445 if (!handle)
446 return NULL;
447
448 for_each_of_allnodes(np)
449 if (np->phandle == handle)
450 break;
451 (void)of_node_get(np);
452
453 return np;
454}
455
456/**
457 * of_find_property_value_of_size() - find property of given size
458 *
459 * Search for a property in a device node and validate the requested size.
460 *
461 * @np: device node from which the property value is to be read.
462 * @propname: name of the property to be searched.
463 * @len: requested length of property value
464 *
465 * @return the property value on success, -EINVAL if the property does not
466 * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
467 * property data isn't large enough.
468 */
469static void *of_find_property_value_of_size(const struct device_node *np,
470 const char *propname, u32 len)
471{
472 struct property *prop = of_find_property(np, propname, NULL);
473
474 if (!prop)
475 return ERR_PTR(-EINVAL);
476 if (!prop->value)
477 return ERR_PTR(-ENODATA);
478 if (len > prop->length)
479 return ERR_PTR(-EOVERFLOW);
480
481 return prop->value;
482}
483
484int of_read_u32(const struct device_node *np, const char *propname, u32 *outp)
485{
Dario Binacchib3f1cdd2020-03-29 18:04:42 +0200486 return of_read_u32_index(np, propname, 0, outp);
Simon Glass1ccaa052017-05-18 20:08:54 -0600487}
488
489int of_read_u32_array(const struct device_node *np, const char *propname,
490 u32 *out_values, size_t sz)
491{
492 const __be32 *val;
493
494 debug("%s: %s: ", __func__, propname);
495 val = of_find_property_value_of_size(np, propname,
496 sz * sizeof(*out_values));
497
498 if (IS_ERR(val))
499 return PTR_ERR(val);
500
501 debug("size %zd\n", sz);
502 while (sz--)
503 *out_values++ = be32_to_cpup(val++);
504
505 return 0;
506}
507
Dario Binacchi81d80b52020-03-29 18:04:41 +0200508int of_read_u32_index(const struct device_node *np, const char *propname,
509 int index, u32 *outp)
510{
511 const __be32 *val;
512
513 debug("%s: %s: ", __func__, propname);
514 if (!np)
515 return -EINVAL;
516
517 val = of_find_property_value_of_size(np, propname,
518 sizeof(*outp) * (index + 1));
519 if (IS_ERR(val)) {
520 debug("(not found)\n");
521 return PTR_ERR(val);
522 }
523
524 *outp = be32_to_cpup(val + index);
525 debug("%#x (%d)\n", *outp, *outp);
526
527 return 0;
528}
529
Simon Glass9d54a7a2018-06-11 13:07:10 -0600530int of_read_u64(const struct device_node *np, const char *propname, u64 *outp)
531{
532 const __be64 *val;
533
534 debug("%s: %s: ", __func__, propname);
535 if (!np)
536 return -EINVAL;
537 val = of_find_property_value_of_size(np, propname, sizeof(*outp));
538 if (IS_ERR(val)) {
539 debug("(not found)\n");
540 return PTR_ERR(val);
541 }
542
543 *outp = be64_to_cpup(val);
544 debug("%#llx (%lld)\n", (unsigned long long)*outp,
545 (unsigned long long)*outp);
546
547 return 0;
548}
549
Simon Glass1ccaa052017-05-18 20:08:54 -0600550int of_property_match_string(const struct device_node *np, const char *propname,
551 const char *string)
552{
553 const struct property *prop = of_find_property(np, propname, NULL);
554 size_t l;
555 int i;
556 const char *p, *end;
557
558 if (!prop)
559 return -EINVAL;
560 if (!prop->value)
561 return -ENODATA;
562
563 p = prop->value;
564 end = p + prop->length;
565
566 for (i = 0; p < end; i++, p += l) {
567 l = strnlen(p, end - p) + 1;
568 if (p + l > end)
569 return -EILSEQ;
570 debug("comparing %s with %s\n", string, p);
571 if (strcmp(string, p) == 0)
572 return i; /* Found it; return index */
573 }
574 return -ENODATA;
575}
576
577/**
578 * of_property_read_string_helper() - Utility helper for parsing string properties
579 * @np: device node from which the property value is to be read.
580 * @propname: name of the property to be searched.
581 * @out_strs: output array of string pointers.
582 * @sz: number of array elements to read.
583 * @skip: Number of strings to skip over at beginning of list.
584 *
585 * Don't call this function directly. It is a utility helper for the
586 * of_property_read_string*() family of functions.
587 */
588int of_property_read_string_helper(const struct device_node *np,
589 const char *propname, const char **out_strs,
590 size_t sz, int skip)
591{
592 const struct property *prop = of_find_property(np, propname, NULL);
593 int l = 0, i = 0;
594 const char *p, *end;
595
596 if (!prop)
597 return -EINVAL;
598 if (!prop->value)
599 return -ENODATA;
600 p = prop->value;
601 end = p + prop->length;
602
603 for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) {
604 l = strnlen(p, end - p) + 1;
605 if (p + l > end)
606 return -EILSEQ;
607 if (out_strs && i >= skip)
608 *out_strs++ = p;
609 }
610 i -= skip;
611 return i <= 0 ? -ENODATA : i;
612}
613
614static int __of_parse_phandle_with_args(const struct device_node *np,
615 const char *list_name,
616 const char *cells_name,
617 int cell_count, int index,
618 struct of_phandle_args *out_args)
619{
620 const __be32 *list, *list_end;
621 int rc = 0, cur_index = 0;
Heinrich Schuchardtc13346e2020-02-15 21:46:04 +0100622 uint32_t count;
Simon Glass1ccaa052017-05-18 20:08:54 -0600623 struct device_node *node = NULL;
624 phandle phandle;
625 int size;
626
627 /* Retrieve the phandle list property */
628 list = of_get_property(np, list_name, &size);
629 if (!list)
630 return -ENOENT;
631 list_end = list + size / sizeof(*list);
632
633 /* Loop over the phandles until all the requested entry is found */
634 while (list < list_end) {
635 rc = -EINVAL;
636 count = 0;
637
638 /*
639 * If phandle is 0, then it is an empty entry with no
640 * arguments. Skip forward to the next entry.
641 */
642 phandle = be32_to_cpup(list++);
643 if (phandle) {
644 /*
645 * Find the provider node and parse the #*-cells
646 * property to determine the argument length.
647 *
648 * This is not needed if the cell count is hard-coded
649 * (i.e. cells_name not set, but cell_count is set),
650 * except when we're going to return the found node
651 * below.
652 */
653 if (cells_name || cur_index == index) {
654 node = of_find_node_by_phandle(phandle);
655 if (!node) {
656 debug("%s: could not find phandle\n",
657 np->full_name);
658 goto err;
659 }
660 }
661
662 if (cells_name) {
663 if (of_read_u32(node, cells_name, &count)) {
664 debug("%s: could not get %s for %s\n",
665 np->full_name, cells_name,
666 node->full_name);
667 goto err;
668 }
669 } else {
670 count = cell_count;
671 }
672
673 /*
674 * Make sure that the arguments actually fit in the
675 * remaining property data length
676 */
677 if (list + count > list_end) {
678 debug("%s: arguments longer than property\n",
679 np->full_name);
680 goto err;
681 }
682 }
683
684 /*
685 * All of the error cases above bail out of the loop, so at
686 * this point, the parsing is successful. If the requested
687 * index matches, then fill the out_args structure and return,
688 * or return -ENOENT for an empty entry.
689 */
690 rc = -ENOENT;
691 if (cur_index == index) {
692 if (!phandle)
693 goto err;
694
695 if (out_args) {
696 int i;
697 if (WARN_ON(count > OF_MAX_PHANDLE_ARGS))
698 count = OF_MAX_PHANDLE_ARGS;
699 out_args->np = node;
700 out_args->args_count = count;
701 for (i = 0; i < count; i++)
702 out_args->args[i] =
703 be32_to_cpup(list++);
704 } else {
705 of_node_put(node);
706 }
707
708 /* Found it! return success */
709 return 0;
710 }
711
712 of_node_put(node);
713 node = NULL;
714 list += count;
715 cur_index++;
716 }
717
718 /*
719 * Unlock node before returning result; will be one of:
720 * -ENOENT : index is for empty phandle
721 * -EINVAL : parsing error on data
722 * [1..n] : Number of phandle (count mode; when index = -1)
723 */
724 rc = index < 0 ? cur_index : -ENOENT;
725 err:
726 if (node)
727 of_node_put(node);
728 return rc;
729}
730
731struct device_node *of_parse_phandle(const struct device_node *np,
732 const char *phandle_name, int index)
733{
734 struct of_phandle_args args;
735
736 if (index < 0)
737 return NULL;
738
739 if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0, index,
740 &args))
741 return NULL;
742
743 return args.np;
744}
745
746int of_parse_phandle_with_args(const struct device_node *np,
747 const char *list_name, const char *cells_name,
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200748 int cell_count, int index,
749 struct of_phandle_args *out_args)
Simon Glass1ccaa052017-05-18 20:08:54 -0600750{
751 if (index < 0)
752 return -EINVAL;
753
Patrick Delaunay21e3b042020-09-10 18:26:17 +0200754 return __of_parse_phandle_with_args(np, list_name, cells_name,
755 cell_count, index, out_args);
Simon Glass1ccaa052017-05-18 20:08:54 -0600756}
757
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200758int of_count_phandle_with_args(const struct device_node *np,
Patrick Delaunayd776a842020-09-25 09:41:14 +0200759 const char *list_name, const char *cells_name,
760 int cell_count)
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200761{
Patrick Delaunayd776a842020-09-25 09:41:14 +0200762 return __of_parse_phandle_with_args(np, list_name, cells_name,
763 cell_count, -1, NULL);
Patrice Chotardbe7dd602017-07-18 11:57:08 +0200764}
765
Simon Glass1ccaa052017-05-18 20:08:54 -0600766static void of_alias_add(struct alias_prop *ap, struct device_node *np,
767 int id, const char *stem, int stem_len)
768{
769 ap->np = np;
770 ap->id = id;
771 strncpy(ap->stem, stem, stem_len);
772 ap->stem[stem_len] = 0;
773 list_add_tail(&ap->link, &aliases_lookup);
774 debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
775 ap->alias, ap->stem, ap->id, of_node_full_name(np));
776}
777
778int of_alias_scan(void)
779{
780 struct property *pp;
781
782 of_aliases = of_find_node_by_path("/aliases");
783 of_chosen = of_find_node_by_path("/chosen");
784 if (of_chosen == NULL)
785 of_chosen = of_find_node_by_path("/chosen@0");
786
787 if (of_chosen) {
788 const char *name;
789
790 name = of_get_property(of_chosen, "stdout-path", NULL);
791 if (name)
792 of_stdout = of_find_node_opts_by_path(name,
793 &of_stdout_options);
794 }
795
796 if (!of_aliases)
797 return 0;
798
799 for_each_property_of_node(of_aliases, pp) {
800 const char *start = pp->name;
801 const char *end = start + strlen(start);
802 struct device_node *np;
803 struct alias_prop *ap;
804 ulong id;
805 int len;
806
807 /* Skip those we do not want to proceed */
808 if (!strcmp(pp->name, "name") ||
809 !strcmp(pp->name, "phandle") ||
810 !strcmp(pp->name, "linux,phandle"))
811 continue;
812
813 np = of_find_node_by_path(pp->value);
814 if (!np)
815 continue;
816
817 /*
818 * walk the alias backwards to extract the id and work out
819 * the 'stem' string
820 */
821 while (isdigit(*(end-1)) && end > start)
822 end--;
823 len = end - start;
824
825 if (strict_strtoul(end, 10, &id) < 0)
826 continue;
827
828 /* Allocate an alias_prop with enough space for the stem */
829 ap = malloc(sizeof(*ap) + len + 1);
830 if (!ap)
831 return -ENOMEM;
832 memset(ap, 0, sizeof(*ap) + len + 1);
833 ap->alias = start;
834 of_alias_add(ap, np, id, start, len);
835 }
836
837 return 0;
838}
839
840int of_alias_get_id(const struct device_node *np, const char *stem)
841{
842 struct alias_prop *app;
843 int id = -ENODEV;
844
845 mutex_lock(&of_mutex);
846 list_for_each_entry(app, &aliases_lookup, link) {
847 if (strcmp(app->stem, stem) != 0)
848 continue;
849
850 if (np == app->np) {
851 id = app->id;
852 break;
853 }
854 }
855 mutex_unlock(&of_mutex);
856
857 return id;
858}
859
Michal Simekc6203cb2019-01-31 16:30:57 +0100860int of_alias_get_highest_id(const char *stem)
861{
862 struct alias_prop *app;
863 int id = -1;
864
865 mutex_lock(&of_mutex);
866 list_for_each_entry(app, &aliases_lookup, link) {
867 if (strcmp(app->stem, stem) != 0)
868 continue;
869
870 if (app->id > id)
871 id = app->id;
872 }
873 mutex_unlock(&of_mutex);
874
875 return id;
876}
877
Simon Glass1ccaa052017-05-18 20:08:54 -0600878struct device_node *of_get_stdout(void)
879{
880 return of_stdout;
881}