1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2022-08-25     GuEe-GUI     first version
9  */
10 
11 #include <rthw.h>
12 #include <rtthread.h>
13 
14 #include <drivers/ofw.h>
15 #include <drivers/ofw_io.h>
16 #include <drivers/ofw_fdt.h>
17 #include <drivers/ofw_raw.h>
18 
19 #define DBG_TAG "rtdm.ofw"
20 #define DBG_LVL DBG_INFO
21 #include <rtdbg.h>
22 
23 #include "ofw_internal.h"
24 
25 struct rt_ofw_node *ofw_node_root = RT_NULL;
26 struct rt_ofw_node *ofw_node_cpus = RT_NULL;
27 struct rt_ofw_node *ofw_node_chosen = RT_NULL;
28 struct rt_ofw_node *ofw_node_aliases = RT_NULL;
29 struct rt_ofw_node *ofw_node_reserved_memory = RT_NULL;
30 
31 static rt_phandle _phandle_range[2] = { 1, 1 }, _phandle_next = 1;
32 static struct rt_ofw_node **_phandle_hash = RT_NULL;
33 
34 static rt_list_t _aliases_nodes = RT_LIST_OBJECT_INIT(_aliases_nodes);
35 
ofw_phandle_hash_reset(rt_phandle min,rt_phandle max)36 rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max)
37 {
38     rt_err_t err = RT_EOK;
39     rt_phandle next = max;
40     struct rt_ofw_node **hash_ptr = RT_NULL;
41 
42     max = RT_ALIGN(max, OFW_NODE_MIN_HASH);
43 
44     if (max > _phandle_range[1])
45     {
46         rt_size_t size = sizeof(*_phandle_hash) * (max - min);
47 
48         if (!_phandle_hash)
49         {
50             hash_ptr = rt_calloc(1, size);
51         }
52         else
53         {
54             hash_ptr = rt_realloc(_phandle_hash, size);
55 
56             if (hash_ptr)
57             {
58                 rt_size_t old_max = _phandle_range[1];
59 
60                 rt_memset(&hash_ptr[old_max], 0, sizeof(_phandle_hash) * (max - old_max));
61             }
62         }
63     }
64 
65     if (hash_ptr)
66     {
67         /* We always reset min value only once */
68         if (min)
69         {
70             _phandle_range[0] = min;
71         }
72         _phandle_range[1] = max;
73         _phandle_next = next + 1;
74         _phandle_hash = hash_ptr;
75     }
76     else
77     {
78         err = -RT_ENOMEM;
79     }
80 
81     return err;
82 }
83 
ofw_phandle_next(void)84 static rt_phandle ofw_phandle_next(void)
85 {
86     rt_phandle next;
87     static RT_DEFINE_SPINLOCK(op_lock);
88 
89     rt_hw_spin_lock(&op_lock.lock);
90 
91     RT_ASSERT(_phandle_next != OFW_PHANDLE_MAX);
92 
93     if (_phandle_next <= _phandle_range[1])
94     {
95         next = _phandle_next++;
96     }
97     else
98     {
99         rt_err_t err = ofw_phandle_hash_reset(_phandle_range[0], _phandle_next);
100 
101         if (!err)
102         {
103             next = _phandle_next++;
104         }
105         else
106         {
107             next = 0;
108             LOG_E("Expanded phandle hash[%u, %u] fail error = %s",
109                     _phandle_range[0], _phandle_next + 1, rt_strerror(err));
110         }
111     }
112 
113     rt_hw_spin_unlock(&op_lock.lock);
114 
115     return next;
116 }
ofw_prop_destroy(struct rt_ofw_prop * prop)117 static void ofw_prop_destroy(struct rt_ofw_prop *prop)
118 {
119     struct rt_ofw_prop *next;
120 
121     while (prop)
122     {
123         next = prop->next;
124 
125         rt_free(prop);
126 
127         prop = next;
128     }
129 }
130 
ofw_get_next_node(struct rt_ofw_node * prev)131 static struct rt_ofw_node *ofw_get_next_node(struct rt_ofw_node *prev)
132 {
133     struct rt_ofw_node *np;
134 
135     /*
136      * Walk:
137      *
138      *    / { ------------------------ [0] (START) has child, goto child.
139      *
140      *        node0 { ---------------- [1] has child, goto child.
141      *
142      *            node0_0 { ---------- [2] no child, has sibling, goto sibling.
143      *            };
144      *
145      *            node0_1 { ---------- [3] no sibling now.
146      *                                     upward while the parent has sibling.
147      *            };
148      *        };
149      *
150      *        node1 { ---------------- [4] come from node0 who find the sibling:
151      *                                     node1, node1 has child, goto child.
152      *
153      *            node1_0 { ---------- [5] has child, goto child.
154      *
155      *                node1_0_0 { ---- [6] no sibling now.
156      *                                     upward while the parent has sibling.
157      *                                     (END) in the root.
158      *                };
159      *            };
160      *        };
161      *    };
162      */
163 
164     if (!prev)
165     {
166         np = ofw_node_root;
167     }
168     else if (prev->child)
169     {
170         np = prev->child;
171     }
172     else
173     {
174         np = prev;
175 
176         while (np->parent && !np->sibling)
177         {
178             np = np->parent;
179         }
180 
181         np = np->sibling;
182     }
183 
184     return np;
185 }
186 
ofw_node_destroy(struct rt_ofw_node * np)187 static void ofw_node_destroy(struct rt_ofw_node *np)
188 {
189     struct rt_ofw_node *prev;
190 
191     if (np->parent)
192     {
193         /* Ask parent and prev sibling we are destroy. */
194         prev = np->parent->child;
195 
196         if (prev == np)
197         {
198             np->parent->child = RT_NULL;
199         }
200         else
201         {
202             while (prev->sibling != np)
203             {
204                 prev = prev->sibling;
205             }
206 
207             prev->sibling = np->sibling;
208         }
209     }
210 
211     while (np)
212     {
213         if (rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM) == RT_FALSE)
214         {
215             LOG_E("%s is system node", np->full_name);
216             RT_ASSERT(0);
217         }
218 
219         prev = np;
220 
221         np = ofw_get_next_node(np);
222 
223         ofw_prop_destroy(prev->props);
224         rt_free(prev);
225     }
226 }
227 
rt_ofw_node_destroy(struct rt_ofw_node * np)228 rt_err_t rt_ofw_node_destroy(struct rt_ofw_node *np)
229 {
230     rt_err_t err = RT_EOK;
231 
232     if (np)
233     {
234         if (rt_ref_read(&np->ref) <= 1)
235         {
236             ofw_node_destroy(np);
237         }
238         else
239         {
240             err = -RT_EBUSY;
241         }
242     }
243     else
244     {
245         err = -RT_EINVAL;
246     }
247 
248     return err;
249 }
250 
rt_ofw_node_get(struct rt_ofw_node * np)251 struct rt_ofw_node *rt_ofw_node_get(struct rt_ofw_node *np)
252 {
253     if (np)
254     {
255         LOG_D("%s get ref = %d", np->full_name, rt_ref_read(&np->ref));
256         rt_ref_get(&np->ref);
257     }
258 
259     return np;
260 }
261 
ofw_node_release(struct rt_ref * r)262 static void ofw_node_release(struct rt_ref *r)
263 {
264     struct rt_ofw_node *np = rt_container_of(r, struct rt_ofw_node, ref);
265 
266     LOG_E("%s is release", np->full_name);
267     (void)np;
268 
269     RT_ASSERT(0);
270 }
271 
rt_ofw_node_put(struct rt_ofw_node * np)272 void rt_ofw_node_put(struct rt_ofw_node *np)
273 {
274     if (np)
275     {
276         LOG_D("%s put ref = %d", np->full_name, rt_ref_read(&np->ref));
277         rt_ref_put(&np->ref, &ofw_node_release);
278     }
279 }
280 
rt_ofw_node_tag_equ(const struct rt_ofw_node * np,const char * tag)281 rt_bool_t rt_ofw_node_tag_equ(const struct rt_ofw_node *np, const char *tag)
282 {
283     rt_bool_t ret = RT_FALSE;
284 
285     if (np && tag)
286     {
287         const char *node_name = rt_fdt_node_name(np->full_name);
288         rt_size_t tag_len = strchrnul(node_name, '@') - node_name;
289 
290         ret = (rt_strlen(tag) == tag_len && !rt_strncmp(node_name, tag, tag_len));
291     }
292 
293     return ret;
294 }
295 
rt_ofw_node_tag_prefix(const struct rt_ofw_node * np,const char * prefix)296 rt_bool_t rt_ofw_node_tag_prefix(const struct rt_ofw_node *np, const char *prefix)
297 {
298     rt_bool_t ret = RT_FALSE;
299 
300     if (np && prefix)
301     {
302         ret = !rt_strncmp(rt_fdt_node_name(np->full_name), prefix, rt_strlen(prefix));
303     }
304 
305     return ret;
306 }
307 
ofw_prop_index_of_string(struct rt_ofw_prop * prop,const char * string,rt_int32_t (* cmp)(const char * cs,const char * ct))308 static int ofw_prop_index_of_string(struct rt_ofw_prop *prop, const char *string,
309         rt_int32_t (*cmp)(const char *cs, const char *ct))
310 {
311     int index = -1;
312     rt_size_t len = prop->length, slen = 0;
313     const char *value = prop->value;
314 
315     for (int idx = 0; len > 0; ++idx)
316     {
317         /* Add '\0' */
318         slen = rt_strlen(value) + 1;
319 
320         if (!cmp(value, string))
321         {
322             index = idx;
323 
324             break;
325         }
326 
327         len -= slen;
328         value += slen;
329     }
330 
331     return index;
332 }
333 
ofw_strcasecmp(const char * cs,const char * ct)334 static rt_int32_t ofw_strcasecmp(const char *cs, const char *ct)
335 {
336     return rt_strcasecmp(cs, ct);
337 }
338 
ofw_prop_index_of_compatible(struct rt_ofw_prop * prop,const char * compatible)339 static int ofw_prop_index_of_compatible(struct rt_ofw_prop *prop, const char *compatible)
340 {
341     return ofw_prop_index_of_string(prop, compatible, ofw_strcasecmp);
342 }
343 
ofw_node_index_of_compatible(const struct rt_ofw_node * np,const char * compatible)344 static int ofw_node_index_of_compatible(const struct rt_ofw_node *np, const char *compatible)
345 {
346     int idx = -1;
347     struct rt_ofw_prop *prop = rt_ofw_get_prop(np, "compatible", RT_NULL);
348 
349     if (prop)
350     {
351         idx = ofw_prop_index_of_compatible(prop, compatible);
352     }
353 
354     return idx;
355 }
356 
rt_ofw_machine_is_compatible(const char * compatible)357 rt_bool_t rt_ofw_machine_is_compatible(const char *compatible)
358 {
359     return ofw_node_index_of_compatible(ofw_node_root, compatible) >= 0;
360 }
361 
362 /*
363  * Property status:
364  *
365  *  "okay" or "ok":
366  *      Indicates the device is operational.
367  *
368  *  "disabled":
369  *      Indicates that the device is not presently operational, but it might
370  *      become operational in the future (for example, something is not
371  *      plugged in, or switched off).
372  *      Refer to the device binding for details on what disabled means for a
373  *      given device.
374  *
375  *  "reserved":
376  *      Indicates that the device is operational, but should not be used.
377  *      Typically this is used for devices that are controlled by another
378  *      software component, such as platform firmware.
379  *
380  *  "fail":
381  *      Indicates that the device is not operational. A serious error was
382  *      detected in the device, and it is unlikely to become operational
383  *      without repair.
384  *
385  *  "fail-sss":
386  *      Indicates that the device is not operational. A serious error was
387  *      detected in the device and it is unlikely to become operational
388  *      without repair. The sss portion of the value is specific to the
389  *      device and indicates the error condition detected.
390  */
391 
ofw_node_is_fail(const struct rt_ofw_node * np)392 static rt_bool_t ofw_node_is_fail(const struct rt_ofw_node *np)
393 {
394     rt_bool_t res = RT_FALSE;
395     const char *status = rt_ofw_prop_read_raw(np, "status", RT_NULL);
396 
397     if (status)
398     {
399         res = !rt_strcmp(status, "fail") || !rt_strncmp(status, "fail-", 5);
400     }
401 
402     return res;
403 }
404 
ofw_node_is_available(const struct rt_ofw_node * np)405 static rt_bool_t ofw_node_is_available(const struct rt_ofw_node *np)
406 {
407     rt_bool_t res = RT_TRUE;
408     const char *status = rt_ofw_prop_read_raw(np, "status", RT_NULL);
409 
410     if (status)
411     {
412         res = !rt_strcmp(status, "okay") || !rt_strcmp(status, "ok");
413     }
414 
415     return res;
416 }
417 
rt_ofw_node_is_available(const struct rt_ofw_node * np)418 rt_bool_t rt_ofw_node_is_available(const struct rt_ofw_node *np)
419 {
420     return np ? ofw_node_is_available(np) : RT_FALSE;
421 }
422 
rt_ofw_node_is_compatible(const struct rt_ofw_node * np,const char * compatible)423 rt_bool_t rt_ofw_node_is_compatible(const struct rt_ofw_node *np, const char *compatible)
424 {
425     rt_bool_t res = RT_FALSE;
426 
427     if (np)
428     {
429         res = ofw_node_index_of_compatible(np, compatible) >= 0;
430     }
431 
432     return res;
433 }
434 
ofw_prop_match(struct rt_ofw_prop * prop,const struct rt_ofw_node_id * ids)435 static struct rt_ofw_node_id *ofw_prop_match(struct rt_ofw_prop *prop, const struct rt_ofw_node_id *ids)
436 {
437     int best_index = RT_UINT32_MAX >> 1, index;
438     struct rt_ofw_node_id *found_id = RT_NULL, *id;
439 
440     for (id = (struct rt_ofw_node_id *)ids; id->compatible[0]; ++id)
441     {
442         index = ofw_prop_index_of_compatible(prop, id->compatible);
443 
444         if (index >= 0 && index < best_index)
445         {
446             found_id = id;
447             best_index = index;
448         }
449     }
450 
451     return found_id;
452 }
453 
rt_ofw_prop_match(struct rt_ofw_prop * prop,const struct rt_ofw_node_id * ids)454 struct rt_ofw_node_id *rt_ofw_prop_match(struct rt_ofw_prop *prop, const struct rt_ofw_node_id *ids)
455 {
456     struct rt_ofw_node_id *id = RT_NULL;
457 
458     if (prop && ids && !rt_strcmp(prop->name, "compatible"))
459     {
460         id = ofw_prop_match(prop, ids);
461     }
462 
463     return id;
464 }
465 
rt_ofw_node_match(struct rt_ofw_node * np,const struct rt_ofw_node_id * ids)466 struct rt_ofw_node_id *rt_ofw_node_match(struct rt_ofw_node *np, const struct rt_ofw_node_id *ids)
467 {
468     struct rt_ofw_prop *prop;
469     struct rt_ofw_node_id *id = RT_NULL;
470 
471     if (np && ids && (prop = rt_ofw_get_prop(np, "compatible", RT_NULL)))
472     {
473         id = ofw_prop_match(prop, ids);
474     }
475 
476     return id;
477 }
478 
rt_ofw_find_node_by_tag(struct rt_ofw_node * from,const char * tag)479 struct rt_ofw_node *rt_ofw_find_node_by_tag(struct rt_ofw_node *from, const char *tag)
480 {
481     struct rt_ofw_node *np = RT_NULL;
482 
483     if (tag)
484     {
485         rt_ofw_foreach_nodes(from, np)
486         {
487             if (rt_ofw_node_tag_equ(np, tag))
488             {
489                 break;
490             }
491         }
492     }
493 
494     return np;
495 }
496 
rt_ofw_find_node_by_prop_r(struct rt_ofw_node * from,const char * propname,const struct rt_ofw_prop ** out_prop)497 struct rt_ofw_node *rt_ofw_find_node_by_prop_r(struct rt_ofw_node *from, const char *propname,
498         const struct rt_ofw_prop **out_prop)
499 {
500     struct rt_ofw_node *np = RT_NULL;
501 
502     if (propname)
503     {
504         rt_ofw_foreach_nodes(from, np)
505         {
506             struct rt_ofw_prop *prop = rt_ofw_get_prop(np, propname, RT_NULL);
507 
508             if (prop)
509             {
510                 if (out_prop)
511                 {
512                     *out_prop = prop;
513                 }
514 
515                 break;
516             }
517         }
518     }
519 
520     return np;
521 }
522 
rt_ofw_find_node_by_name(struct rt_ofw_node * from,const char * name)523 struct rt_ofw_node *rt_ofw_find_node_by_name(struct rt_ofw_node *from, const char *name)
524 {
525     struct rt_ofw_node *np = RT_NULL;
526 
527     if (name)
528     {
529         rt_ofw_foreach_nodes(from, np)
530         {
531             if (np->name && !rt_strcmp(np->name, name))
532             {
533                 np = rt_ofw_node_get(np);
534                 break;
535             }
536         }
537     }
538 
539     return np;
540 }
541 
rt_ofw_find_node_by_type(struct rt_ofw_node * from,const char * type)542 struct rt_ofw_node *rt_ofw_find_node_by_type(struct rt_ofw_node *from, const char *type)
543 {
544     struct rt_ofw_node *np = RT_NULL;
545 
546     if (type)
547     {
548         rt_ofw_foreach_nodes(from, np)
549         {
550             if (rt_ofw_node_is_type(np, type))
551             {
552                 break;
553             }
554         }
555     }
556 
557     return np;
558 }
559 
rt_ofw_find_node_by_compatible(struct rt_ofw_node * from,const char * compatible)560 struct rt_ofw_node *rt_ofw_find_node_by_compatible(struct rt_ofw_node *from, const char *compatible)
561 {
562     struct rt_ofw_node *np = RT_NULL;
563 
564     if (compatible)
565     {
566         rt_ofw_foreach_nodes(from, np)
567         {
568             if (ofw_node_index_of_compatible(np, compatible) >= 0)
569             {
570                 break;
571             }
572         }
573     }
574 
575     return np;
576 }
577 
rt_ofw_find_node_by_ids_r(struct rt_ofw_node * from,const struct rt_ofw_node_id * ids,const struct rt_ofw_node_id ** out_id)578 struct rt_ofw_node *rt_ofw_find_node_by_ids_r(struct rt_ofw_node *from, const struct rt_ofw_node_id *ids,
579         const struct rt_ofw_node_id **out_id)
580 {
581     struct rt_ofw_node *np = RT_NULL;
582 
583     if (ids)
584     {
585         rt_ofw_foreach_nodes(from, np)
586         {
587             struct rt_ofw_node_id *id = rt_ofw_node_match(np, ids);
588 
589             if (id)
590             {
591                 if (out_id)
592                 {
593                     *out_id = id;
594                 }
595 
596                 break;
597             }
598         }
599     }
600 
601     return np;
602 }
603 
rt_ofw_find_node_by_path(const char * path)604 struct rt_ofw_node *rt_ofw_find_node_by_path(const char *path)
605 {
606     struct rt_ofw_node *np = RT_NULL, *parent, *tmp = RT_NULL;
607 
608     if (path)
609     {
610         if (!rt_strcmp(path, "/"))
611         {
612             np = ofw_node_root;
613         }
614         else
615         {
616             ++path;
617             parent = rt_ofw_node_get(ofw_node_root);
618 
619             while (*path)
620             {
621                 const char *next = strchrnul(path, '/');
622                 rt_size_t len = next - path;
623 
624                 tmp = RT_NULL;
625 
626                 rt_ofw_foreach_child_node(parent, np)
627                 {
628                     if (!rt_strncmp(np->full_name, path, len))
629                     {
630                         rt_ofw_node_put(parent);
631 
632                         parent = np;
633                         tmp = np;
634 
635                         break;
636                     }
637                 }
638 
639                 if (!tmp)
640                 {
641                     rt_ofw_node_put(parent);
642 
643                     break;
644                 }
645 
646                 path += len + !!*next;
647             }
648 
649             np = tmp;
650         }
651 
652         rt_ofw_node_get(np);
653     }
654 
655     return np;
656 }
657 
rt_ofw_find_node_by_phandle(rt_phandle phandle)658 struct rt_ofw_node *rt_ofw_find_node_by_phandle(rt_phandle phandle)
659 {
660     struct rt_ofw_node *np = RT_NULL;
661 
662     if (phandle >= OFW_PHANDLE_MIN && phandle <= OFW_PHANDLE_MAX)
663     {
664         /* rebase from zero */
665         rt_phandle poff = phandle - _phandle_range[0];
666 
667         np = _phandle_hash[poff];
668 
669         if (!np)
670         {
671             rt_ofw_foreach_allnodes(np)
672             {
673                 if (np->phandle == phandle)
674                 {
675                     _phandle_hash[poff] = np;
676 
677                     break;
678                 }
679             }
680         }
681         else
682         {
683             rt_ofw_node_get(np);
684         }
685     }
686 
687     return np;
688 }
689 
rt_ofw_get_parent(const struct rt_ofw_node * np)690 struct rt_ofw_node *rt_ofw_get_parent(const struct rt_ofw_node *np)
691 {
692     if (np)
693     {
694         np = rt_ofw_node_get(np->parent);
695     }
696 
697     return (struct rt_ofw_node *)np;
698 }
699 
rt_ofw_get_child_by_tag(const struct rt_ofw_node * parent,const char * tag)700 struct rt_ofw_node *rt_ofw_get_child_by_tag(const struct rt_ofw_node *parent, const char *tag)
701 {
702     struct rt_ofw_node *child = RT_NULL;
703 
704     if (parent && tag)
705     {
706         rt_ofw_foreach_child_node(parent, child)
707         {
708             if (rt_ofw_node_tag_equ(child, tag))
709             {
710                 break;
711             }
712         }
713     }
714 
715     return child;
716 }
717 
rt_ofw_get_child_by_compatible(const struct rt_ofw_node * parent,const char * compatible)718 struct rt_ofw_node *rt_ofw_get_child_by_compatible(const struct rt_ofw_node *parent, const char *compatible)
719 {
720     struct rt_ofw_node *child = RT_NULL;
721 
722     if (parent && compatible)
723     {
724         rt_ofw_foreach_child_node(parent, child)
725         {
726             if (ofw_node_index_of_compatible(child, compatible) >= 0)
727             {
728                 break;
729             }
730         }
731     }
732 
733     return child;
734 }
735 
rt_ofw_get_child_count(const struct rt_ofw_node * np)736 int rt_ofw_get_child_count(const struct rt_ofw_node *np)
737 {
738     int nr;
739 
740     if (np)
741     {
742         struct rt_ofw_node *child;
743 
744         nr = 0;
745 
746         rt_ofw_foreach_child_node(np, child)
747         {
748             ++nr;
749         }
750     }
751     else
752     {
753         nr = -RT_EINVAL;
754     }
755 
756     return nr;
757 }
758 
rt_ofw_get_available_child_count(const struct rt_ofw_node * np)759 int rt_ofw_get_available_child_count(const struct rt_ofw_node *np)
760 {
761     int nr;
762 
763     if (np)
764     {
765         struct rt_ofw_node *child;
766 
767         nr = 0;
768 
769         rt_ofw_foreach_available_child_node(np, child)
770         {
771             ++nr;
772         }
773     }
774     else
775     {
776         nr = -RT_EINVAL;
777     }
778 
779     return nr;
780 }
781 
rt_ofw_get_next_node(struct rt_ofw_node * prev)782 struct rt_ofw_node *rt_ofw_get_next_node(struct rt_ofw_node *prev)
783 {
784     struct rt_ofw_node *np;
785 
786     np = rt_ofw_node_get(ofw_get_next_node(prev));
787     rt_ofw_node_put(prev);
788 
789     return np;
790 }
791 
rt_ofw_get_next_parent(struct rt_ofw_node * prev)792 struct rt_ofw_node *rt_ofw_get_next_parent(struct rt_ofw_node *prev)
793 {
794     struct rt_ofw_node *next = RT_NULL;
795 
796     if (prev)
797     {
798         next = rt_ofw_node_get(prev->parent);
799         rt_ofw_node_put(prev);
800     }
801 
802     return next;
803 }
804 
rt_ofw_get_next_child(const struct rt_ofw_node * parent,struct rt_ofw_node * prev)805 struct rt_ofw_node *rt_ofw_get_next_child(const struct rt_ofw_node *parent, struct rt_ofw_node *prev)
806 {
807     struct rt_ofw_node *next = RT_NULL;
808 
809     if (parent)
810     {
811         next = prev ? prev->sibling : parent->child;
812         rt_ofw_node_put(prev);
813         rt_ofw_node_get(next);
814     }
815 
816     return next;
817 }
818 
rt_ofw_get_next_available_child(const struct rt_ofw_node * parent,struct rt_ofw_node * prev)819 struct rt_ofw_node *rt_ofw_get_next_available_child(const struct rt_ofw_node *parent, struct rt_ofw_node *prev)
820 {
821     struct rt_ofw_node *next = RT_NULL;
822 
823     if (parent)
824     {
825         next = prev;
826 
827         do {
828             next = rt_ofw_get_next_child(parent, next);
829 
830         } while (next && !ofw_node_is_available(next));
831     }
832 
833     return next;
834 }
835 
rt_ofw_get_cpu_node(int cpu,int * thread,rt_bool_t (* match_cpu_hwid)(int cpu,rt_uint64_t hwid))836 struct rt_ofw_node *rt_ofw_get_cpu_node(int cpu, int *thread, rt_bool_t (*match_cpu_hwid)(int cpu, rt_uint64_t hwid))
837 {
838     const char *propname = "reg";
839     struct rt_ofw_node *cpu_np = RT_NULL;
840 
841     /*
842      * "reg" (some of the obsolete arch may be other names):
843      *  The value of reg is a <prop-encoded-array> that defines a unique
844      *  CPU/thread id for the CPU/threads represented by the CPU node.
845      *
846      *  If a CPU supports more than one thread (i.e. multiple streams of
847      *  execution) the reg property is an array with 1 element per thread. The
848      *  #address-cells on the /cpus node specifies how many cells each element
849      *  of the array takes. Software can determine the number of threads by
850      *  dividing the size of reg by the parent node’s #address-cells:
851      *
852      *      thread-number = reg-cells / address-cells
853      *
854      *  If a CPU/thread can be the target of an external interrupt the reg
855      *  property value must be a unique CPU/thread id that is addressable by the
856      *  interrupt controller.
857      *
858      *  If a CPU/thread cannot be the target of an external interrupt, then reg
859      *  must be unique and out of bounds of the range addressed by the interrupt
860      *  controller
861      *
862      *  If a CPU/thread’s PIR (pending interrupt register) is modifiable, a
863      *  client program should modify PIR to match the reg property value. If PIR
864      *  cannot be modified and the PIR value is distinct from the interrupt
865      *  controller number space, the CPUs binding may define a binding-specific
866      *  representation of PIR values if desired.
867      */
868 
869     rt_ofw_foreach_cpu_node(cpu_np)
870     {
871         rt_ssize_t prop_len = 0;
872         rt_bool_t is_end = RT_FALSE;
873         int tid, addr_cells = rt_ofw_io_addr_cells(cpu_np);
874         const fdt32_t *cell = rt_ofw_prop_read_raw(cpu_np, propname, &prop_len);
875 
876         if (!cell && !addr_cells)
877         {
878             if (match_cpu_hwid && match_cpu_hwid(cpu, 0))
879             {
880                 break;
881             }
882 
883             continue;
884         }
885 
886         if (!match_cpu_hwid)
887         {
888             continue;
889         }
890 
891         prop_len /= sizeof(*cell) * addr_cells;
892 
893         for (tid = 0; tid < prop_len; ++tid)
894         {
895             rt_uint64_t hwid = rt_fdt_read_number(cell, addr_cells);
896 
897             if (match_cpu_hwid(cpu, hwid))
898             {
899                 if (thread)
900                 {
901                     *thread = tid;
902                 }
903 
904                 is_end = RT_TRUE;
905 
906                 break;
907             }
908 
909             cell += addr_cells;
910         }
911 
912         if (is_end)
913         {
914             break;
915         }
916     }
917 
918     return cpu_np;
919 }
920 
rt_ofw_get_next_cpu_node(struct rt_ofw_node * prev)921 struct rt_ofw_node *rt_ofw_get_next_cpu_node(struct rt_ofw_node *prev)
922 {
923     struct rt_ofw_node *cpu_np;
924 
925     if (prev)
926     {
927         cpu_np = prev->sibling;
928         rt_ofw_node_put(prev);
929     }
930     else
931     {
932         cpu_np = ofw_node_cpus->child;
933     }
934 
935     for (; cpu_np; cpu_np = cpu_np->sibling)
936     {
937         if (ofw_node_is_fail(cpu_np))
938         {
939             continue;
940         }
941 
942         if (!(rt_ofw_node_tag_equ(cpu_np, "cpu") || rt_ofw_node_is_type(cpu_np, "cpu")))
943         {
944             continue;
945         }
946 
947         if (rt_ofw_node_get(cpu_np))
948         {
949             break;
950         }
951     }
952 
953     return cpu_np;
954 }
955 
rt_ofw_get_cpu_state_node(struct rt_ofw_node * cpu_np,int index)956 struct rt_ofw_node *rt_ofw_get_cpu_state_node(struct rt_ofw_node *cpu_np, int index)
957 {
958     struct rt_ofw_cell_args args;
959     struct rt_ofw_node *np = RT_NULL, *state_np;
960     rt_err_t err = rt_ofw_parse_phandle_cells(cpu_np, "power-domains", "#power-domain-cells", 0, &args);
961 
962     if (!err)
963     {
964         state_np = rt_ofw_parse_phandle(args.data, "domain-idle-states", index);
965 
966         rt_ofw_node_put(args.data);
967 
968         if (state_np)
969         {
970             np = state_np;
971         }
972     }
973 
974     if (!np)
975     {
976         int count = 0;
977         rt_uint32_t phandle;
978         const fdt32_t *cell;
979         struct rt_ofw_prop *prop;
980 
981         rt_ofw_foreach_prop_u32(cpu_np, "cpu-idle-states", prop, cell, phandle)
982         {
983             if (count == index)
984             {
985                 np = rt_ofw_find_node_by_phandle((rt_phandle)phandle);
986 
987                 break;
988             }
989 
990             ++count;
991         }
992     }
993 
994     return np;
995 }
996 
rt_ofw_get_cpu_id(struct rt_ofw_node * cpu_np)997 rt_uint64_t rt_ofw_get_cpu_id(struct rt_ofw_node *cpu_np)
998 {
999     rt_uint64_t cpuid = ~0ULL;
1000 
1001     if (cpu_np)
1002     {
1003         rt_uint64_t idx = 0;
1004         struct rt_ofw_node *np = ofw_node_cpus->child;
1005 
1006         for (; np; np = np->sibling)
1007         {
1008             if (!(rt_ofw_node_tag_equ(cpu_np, "cpu") || rt_ofw_node_is_type(cpu_np, "cpu")))
1009             {
1010                 continue;
1011             }
1012 
1013             if (cpu_np == np)
1014             {
1015                 cpuid = idx;
1016 
1017                 break;
1018             }
1019 
1020             ++idx;
1021         }
1022 
1023         if ((rt_int64_t)cpuid < 0 && !rt_ofw_prop_read_u64(cpu_np, "rt-thread,cpuid", &idx))
1024         {
1025             cpuid = idx;
1026         }
1027     }
1028 
1029     return cpuid;
1030 }
1031 
rt_ofw_get_cpu_hwid(struct rt_ofw_node * cpu_np,unsigned int thread)1032 rt_uint64_t rt_ofw_get_cpu_hwid(struct rt_ofw_node *cpu_np, unsigned int thread)
1033 {
1034     rt_uint64_t thread_id, hwid = ~0ULL;
1035 
1036     if (cpu_np && thread >= 0 && !rt_ofw_get_address(cpu_np, thread, &thread_id, RT_NULL))
1037     {
1038         hwid = thread_id;
1039     }
1040 
1041     return hwid;
1042 }
1043 
ofw_alias_scan(void)1044 rt_err_t ofw_alias_scan(void)
1045 {
1046     rt_err_t err = RT_EOK;
1047     struct rt_ofw_prop *prop;
1048     struct rt_ofw_node *np = ofw_node_aliases, *tmp;
1049 
1050     rt_ofw_foreach_prop(np, prop)
1051     {
1052         int id = 0;
1053         struct alias_info *info;
1054         const char *name = prop->name, *end, *id_start;
1055 
1056         /* Maybe the bootloader will set the name, or other nodes reference the aliases */
1057         if (!rt_strcmp(name, "name") || !rt_strcmp(name, "phandle"))
1058         {
1059             continue;
1060         }
1061 
1062         if (!(tmp = rt_ofw_find_node_by_path(prop->value)))
1063         {
1064             continue;
1065         }
1066 
1067         end = name + rt_strlen(name);
1068 
1069         while (*(end - 1) && (*(end - 1) >= '0' && *(end - 1) <= '9') && end > name)
1070         {
1071             --end;
1072         }
1073 
1074         id_start = end;
1075         while (*id_start && (*id_start >= '0' && *id_start <= '9'))
1076         {
1077             id *= 10;
1078             id += (*id_start - '0');
1079 
1080             ++id_start;
1081         }
1082 
1083         info = rt_malloc(sizeof(*info));
1084 
1085         if (!info)
1086         {
1087             err = -RT_ENOMEM;
1088             break;
1089         }
1090 
1091         rt_list_init(&info->list);
1092 
1093         info->id = id;
1094         info->tag = name;
1095         info->tag_len = end - name;
1096         info->np = tmp;
1097 
1098         rt_list_insert_after(&_aliases_nodes, &info->list);
1099     }
1100 
1101     return err;
1102 }
1103 
rt_ofw_get_alias_node(const char * tag,int id)1104 struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id)
1105 {
1106     struct alias_info *info;
1107     struct rt_ofw_node *np = RT_NULL;
1108 
1109     if (tag && id >= 0)
1110     {
1111         if (!rt_list_isempty(&_aliases_nodes))
1112         {
1113             rt_list_for_each_entry(info, &_aliases_nodes, list)
1114             {
1115                 if (rt_strncmp(info->tag, tag, info->tag_len))
1116                 {
1117                     continue;
1118                 }
1119 
1120                 if (info->id == id)
1121                 {
1122                     np = info->np;
1123                     break;
1124                 }
1125             }
1126         }
1127     }
1128 
1129     return np;
1130 }
1131 
ofw_alias_node_id(struct rt_ofw_node * np)1132 int ofw_alias_node_id(struct rt_ofw_node *np)
1133 {
1134     int id;
1135     struct alias_info *info = RT_NULL;
1136 
1137     if (np)
1138     {
1139         id = -1;
1140         if (!rt_list_isempty(&_aliases_nodes))
1141         {
1142             rt_list_for_each_entry(info, &_aliases_nodes, list)
1143             {
1144                 if (info->np == np)
1145                 {
1146                     id = info->id;
1147                     break;
1148                 }
1149             }
1150         }
1151     }
1152     else
1153     {
1154         id = -RT_EINVAL;
1155     }
1156 
1157     return id;
1158 }
1159 
rt_ofw_get_alias_id(struct rt_ofw_node * np,const char * tag)1160 int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag)
1161 {
1162     int id;
1163     struct alias_info *info;
1164 
1165     if (np && tag)
1166     {
1167         id = -1;
1168         if (!rt_list_isempty(&_aliases_nodes))
1169         {
1170             rt_list_for_each_entry(info, &_aliases_nodes, list)
1171             {
1172                 if (rt_strncmp(info->tag, tag, info->tag_len))
1173                 {
1174                     continue;
1175                 }
1176 
1177                 if (info->np == np)
1178                 {
1179                     id = info->id;
1180                     break;
1181                 }
1182             }
1183         }
1184     }
1185     else
1186     {
1187         id = -RT_EINVAL;
1188     }
1189 
1190     return id;
1191 }
1192 
rt_ofw_get_alias_last_id(const char * tag)1193 int rt_ofw_get_alias_last_id(const char *tag)
1194 {
1195     int id;
1196     struct alias_info *info;
1197 
1198     if (tag)
1199     {
1200         id = -1;
1201         if (!rt_list_isempty(&_aliases_nodes))
1202         {
1203             rt_list_for_each_entry(info, &_aliases_nodes, list)
1204             {
1205                 if (rt_strncmp(info->tag, tag, info->tag_len))
1206                 {
1207                     continue;
1208                 }
1209 
1210                 if (info->id > id)
1211                 {
1212                     id = info->id;
1213                 }
1214             }
1215         }
1216     }
1217     else
1218     {
1219         id = -RT_EINVAL;
1220     }
1221 
1222     return id;
1223 }
1224 
ofw_map_id(struct rt_ofw_node * np,rt_uint32_t id,const char * map_name,const char * map_mask_name,const fdt32_t * map,rt_ssize_t map_len,struct rt_ofw_node ** ref_np,rt_uint32_t * out_id)1225 static rt_err_t ofw_map_id(struct rt_ofw_node *np, rt_uint32_t id, const char *map_name, const char *map_mask_name,
1226         const fdt32_t *map, rt_ssize_t map_len, struct rt_ofw_node **ref_np, rt_uint32_t *out_id)
1227 {
1228     rt_err_t err = RT_EOK;
1229     rt_uint32_t masked_id, map_mask;
1230 
1231     /* Select all bits default */
1232     map_mask = 0xffffffff;
1233 
1234     if (map_mask_name)
1235     {
1236         rt_ofw_prop_read_u32(np, map_mask_name, &map_mask);
1237     }
1238 
1239     masked_id = map_mask & id;
1240 
1241     for (; map_len > 0; map_len -= 4 * sizeof(*map), map += 4)
1242     {
1243         struct rt_ofw_node *phandle_node;
1244         rt_uint32_t id_base = fdt32_to_cpu(*(map + 0));
1245         rt_uint32_t phandle = fdt32_to_cpu(*(map + 1));
1246         rt_uint32_t out_base = fdt32_to_cpu(*(map + 2));
1247         rt_uint32_t id_len = fdt32_to_cpu(*(map + 3));
1248 
1249         if (id_base & ~map_mask)
1250         {
1251             LOG_E("%s: Invalid %s translation - %s(0x%x) for id-base = 0x%x",
1252                     np->full_name, map_name, map_mask_name, map_mask, id_base);
1253 
1254             err = -RT_ERROR;
1255             break;
1256         }
1257 
1258         if (masked_id < id_base || masked_id >= id_base + id_len)
1259         {
1260             continue;
1261         }
1262 
1263         phandle_node = rt_ofw_find_node_by_phandle((rt_phandle)phandle);
1264 
1265         if (!phandle_node)
1266         {
1267             err = -RT_EEMPTY;
1268             break;
1269         }
1270 
1271         if (ref_np)
1272         {
1273             if (*ref_np)
1274             {
1275                 rt_ofw_node_put(phandle_node);
1276             }
1277             else
1278             {
1279                 *ref_np = phandle_node;
1280             }
1281 
1282             if (*ref_np != phandle_node)
1283             {
1284                 continue;
1285             }
1286         }
1287 
1288         if (out_id)
1289         {
1290             *out_id = masked_id - id_base + out_base;
1291         }
1292 
1293         LOG_D("%s: Get %s translation - %s(0x%x) for id-base = 0x%x, out-base = 0x%x, length = %d, id: 0x%x -> 0x%x",
1294                 np->full_name, map_name, map_mask_name, map_mask,
1295                 id_base, out_base, id_len, id, masked_id - id_base + out_base);
1296 
1297         break;
1298     }
1299 
1300     if (map_len <= 0)
1301     {
1302         LOG_I("%s: No %s translation for id(0x%x) on %s", np->full_name, map_name,
1303                 id, ref_np && *ref_np ? *ref_np : RT_NULL);
1304 
1305         /* Bypasses translation */
1306         if (out_id)
1307         {
1308             *out_id = id;
1309         }
1310     }
1311 
1312     return err;
1313 }
1314 
rt_ofw_map_id(struct rt_ofw_node * np,rt_uint32_t id,const char * map_name,const char * map_mask_name,struct rt_ofw_node ** ref_np,rt_uint32_t * out_id)1315 rt_err_t rt_ofw_map_id(struct rt_ofw_node *np, rt_uint32_t id, const char *map_name, const char *map_mask_name,
1316         struct rt_ofw_node **ref_np, rt_uint32_t *out_id)
1317 {
1318     rt_err_t err;
1319 
1320     if (np && map_name && (ref_np || out_id))
1321     {
1322         rt_ssize_t map_len;
1323         const fdt32_t *map = rt_ofw_prop_read_raw(np, map_name, &map_len);
1324 
1325         if (!map)
1326         {
1327             if (ref_np)
1328             {
1329                 err = -RT_EEMPTY;
1330             }
1331             else
1332             {
1333                 *out_id = id;
1334             }
1335 
1336             err = RT_EOK;
1337         }
1338         else if (!map_len || map_len % (4 * sizeof(*map)))
1339         {
1340             LOG_E("%s: Invalid %s length = %u", np->full_name, map_name, map_len);
1341 
1342             err = -RT_EINVAL;
1343         }
1344         else
1345         {
1346             err = ofw_map_id(np, id, map_name, map_mask_name, map, map_len, ref_np, out_id);
1347         }
1348     }
1349     else
1350     {
1351         err = -RT_EINVAL;
1352     }
1353 
1354     return err;
1355 }
1356 
rt_ofw_append_child(struct rt_ofw_node * parent,const char * full_name)1357 struct rt_ofw_node *rt_ofw_append_child(struct rt_ofw_node *parent, const char *full_name)
1358 {
1359     rt_phandle phandle;
1360     rt_err_t err = RT_EOK;
1361     fdt32_t *phandle_value;
1362     struct rt_ofw_node *np = RT_NULL, *child;
1363 
1364     if (full_name)
1365     {
1366         if ((phandle = ofw_phandle_next()))
1367         {
1368             np = rt_calloc(1, sizeof(*np) + sizeof(*phandle_value));
1369         }
1370     }
1371 
1372     if (np)
1373     {
1374         parent = parent ? : ofw_node_root;
1375 
1376         np->full_name = full_name;
1377         np->phandle = phandle;
1378         np->parent = parent;
1379 
1380         rt_ref_init(&np->ref);
1381 
1382         phandle_value = (void *)np + sizeof(*np);
1383         *phandle_value = cpu_to_fdt32(phandle);
1384 
1385         err = rt_ofw_append_prop(np, "phandle", sizeof(*phandle_value), phandle_value);
1386 
1387         if (!err)
1388         {
1389             if (parent->child)
1390             {
1391                 rt_ofw_foreach_child_node(parent, child)
1392                 {
1393                     if (!child->sibling)
1394                     {
1395                         child->sibling = np;
1396                         rt_ofw_node_put(child);
1397                         break;
1398                     }
1399                 }
1400             }
1401             else
1402             {
1403                 parent->child = np;
1404             }
1405         }
1406         else
1407         {
1408             rt_free(np);
1409             np = RT_NULL;
1410         }
1411     }
1412 
1413     return rt_ofw_node_get(np);
1414 }
1415 
rt_ofw_append_prop(struct rt_ofw_node * np,const char * name,int length,void * value)1416 rt_err_t rt_ofw_append_prop(struct rt_ofw_node *np, const char *name, int length, void *value)
1417 {
1418     rt_err_t err = RT_EOK;
1419 
1420     if (np && name && ((length && value) || (!length && !value)))
1421     {
1422         struct rt_ofw_prop *prop = rt_malloc(sizeof(*prop)), *last_prop;
1423 
1424         if (prop)
1425         {
1426             prop->name = name;
1427             prop->length = length;
1428             prop->value = value;
1429             prop->next = RT_NULL;
1430 
1431             if (np->props)
1432             {
1433                 rt_ofw_foreach_prop(np, last_prop)
1434                 {
1435                     if (!last_prop->next)
1436                     {
1437                         last_prop->next = prop;
1438                         break;
1439                     }
1440                 }
1441             }
1442             else
1443             {
1444                 np->props = prop;
1445             }
1446         }
1447         else
1448         {
1449             err = -RT_ENOMEM;
1450         }
1451     }
1452     else
1453     {
1454         err = -RT_EINVAL;
1455     }
1456 
1457     return err;
1458 }
1459 
rt_ofw_parse_phandle(const struct rt_ofw_node * np,const char * phandle_name,int index)1460 struct rt_ofw_node *rt_ofw_parse_phandle(const struct rt_ofw_node *np, const char *phandle_name, int index)
1461 {
1462     struct rt_ofw_cell_args args;
1463     struct rt_ofw_node *ref_np = RT_NULL;
1464 
1465     if (!rt_ofw_parse_phandle_cells(np, phandle_name, RT_NULL, index, &args))
1466     {
1467         ref_np = args.data;
1468     }
1469 
1470     return ref_np;
1471 }
1472 
ofw_parse_phandle_cells(const struct rt_ofw_node * np,const char * list_name,const char * cells_name,int index,struct rt_ofw_cell_args * out_args)1473 static rt_err_t ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name,
1474         int index, struct rt_ofw_cell_args *out_args)
1475 {
1476     rt_err_t err = -RT_EEMPTY;
1477     rt_uint32_t value;
1478     rt_size_t count = 0;
1479     const fdt32_t *cell;
1480     struct rt_ofw_prop *prop;
1481 
1482     /*
1483      * List:
1484      *
1485      *      phandle1: node1 {
1486      *          #list-cells = <2>;
1487      *      };
1488      *
1489      *      phandle2: node2 {
1490      *          #list-cells = <1>;
1491      *      };
1492      *
1493      *      node3 {
1494      *          list = <&phandle1 0xaa 0xbb>, <&phandle2 0xcc>;
1495      *      };
1496      *
1497      * if call:
1498      *  rt_ofw_parse_phandle_cells(node3, "list", "#list-cells", 0, &args):
1499      *
1500      *      args.data = node1;
1501      *      args.args_count = 2;
1502      *      args.args[0] = 0xaa;
1503      *      args.args[1] = 0xbb;
1504      *
1505      *  rt_ofw_parse_phandle_cells(node3, "list", "#list-cells", 1, &args):
1506      *
1507      *      args.data = node2;
1508      *      args.args_count = 1;
1509      *      args.args[0] = 0xcc;
1510      */
1511 
1512     rt_ofw_foreach_prop_u32(np, list_name, prop, cell, value)
1513     {
1514         rt_uint32_t cells_count = 0;
1515         struct rt_ofw_node *phandle_np = rt_ofw_find_node_by_phandle((rt_phandle)value);
1516 
1517         /* if phandle node is undefined, we assume that the cels_count is 0 */
1518         if (cells_name && phandle_np)
1519         {
1520             rt_ofw_prop_read_u32(phandle_np, cells_name, &cells_count);
1521         }
1522 
1523         if (count++ == index)
1524         {
1525             for (int idx = 0; idx < cells_count; ++idx)
1526             {
1527                 cell = rt_ofw_prop_next_u32(prop, cell, &value);
1528 
1529                 out_args->args[idx] = value;
1530             }
1531 
1532             out_args->args_count = cells_count;
1533             out_args->data = phandle_np;
1534 
1535             if (out_args->data)
1536             {
1537                 err = RT_EOK;
1538             }
1539 
1540             break;
1541         }
1542 
1543         cell += cells_count;
1544     }
1545 
1546     return err;
1547 }
1548 
rt_ofw_parse_phandle_cells(const struct rt_ofw_node * np,const char * list_name,const char * cells_name,int index,struct rt_ofw_cell_args * out_args)1549 rt_err_t rt_ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name,
1550         int index, struct rt_ofw_cell_args *out_args)
1551 {
1552     rt_err_t err;
1553 
1554     if (np && list_name && index >= 0 && out_args)
1555     {
1556         err = ofw_parse_phandle_cells(np, list_name, cells_name, index, out_args);
1557     }
1558     else
1559     {
1560         err = -RT_EINVAL;
1561     }
1562 
1563     return err;
1564 }
1565 
rt_ofw_count_phandle_cells(const struct rt_ofw_node * np,const char * list_name,const char * cells_name)1566 int rt_ofw_count_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name)
1567 {
1568     int count;
1569 
1570     if (np && list_name)
1571     {
1572         count = -1;
1573 
1574         if (!cells_name)
1575         {
1576             rt_ssize_t length;
1577 
1578             if (rt_ofw_get_prop(np, list_name, &length))
1579             {
1580                 count = length / sizeof(fdt32_t);
1581             }
1582         }
1583         else
1584         {
1585             int index = count = 0;
1586             struct rt_ofw_cell_args args;
1587 
1588             while (!ofw_parse_phandle_cells(np, list_name, cells_name, index, &args))
1589             {
1590                 ++index;
1591                 ++count;
1592             }
1593         }
1594     }
1595     else
1596     {
1597         count = -RT_EINVAL;
1598     }
1599 
1600     return count;
1601 }
1602 
ofw_get_prop_fuzzy_name(const struct rt_ofw_node * np,const char * name)1603 static const char *ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name)
1604 {
1605     char *sf, split_field[64];
1606     rt_size_t len = 0, max_ak = 0;
1607     const char *str, *result = RT_NULL;
1608     RT_BITMAP_DECLARE(ak, sizeof(split_field)) = {0};
1609     struct rt_ofw_prop *prop;
1610 
1611     /*
1612      * List:
1613      *
1614      *      node {
1615      *          property;
1616      *          front-prop-rear;
1617      *          front-prop;
1618      *          prop-rear;
1619      *      };
1620      *
1621      * if call:
1622      *  ofw_get_prop_fuzzy_name(node, name):
1623      *      ["prop"] => property
1624      *      ["-prop"] => front-prop-rear
1625      *      ["prop-"] => front-prop-rear
1626      *      ["-prop$"] => front-prop
1627      *      ["^prop-"] => prop-rear
1628      *      ["-prop-"] => front-prop-rear
1629      *      ["front-*-rear"] => front-prop-rear
1630      */
1631 
1632     str = name;
1633     sf = split_field;
1634 
1635     if (str[0] != '^')
1636     {
1637         /* As '*' */
1638         *sf++ = '\0';
1639         rt_bitmap_set_bit(ak, len++);
1640     }
1641     else
1642     {
1643         ++str;
1644     }
1645 
1646     for (; *str && len < sizeof(split_field); ++str, ++sf, ++len)
1647     {
1648         if (*str != '*')
1649         {
1650             *sf = *str;
1651             rt_bitmap_clear_bit(ak, len);
1652         }
1653         else
1654         {
1655             max_ak = len;
1656             *sf = '\0';
1657             rt_bitmap_set_bit(ak, len);
1658         }
1659     }
1660     *sf = '\0';
1661 
1662     if (str[-1] != '$')
1663     {
1664         /* As '*' */
1665         max_ak = len;
1666         rt_bitmap_set_bit(ak, len++);
1667     }
1668     else
1669     {
1670         sf[-1] = '\0';
1671         --len;
1672     }
1673 
1674     sf = split_field;
1675 
1676     if (len >= sizeof(split_field))
1677     {
1678         LOG_W("%s fuzzy name = %s len is %d out of %d", np->full_name, name, rt_strlen(name), sizeof(split_field));
1679     }
1680 
1681     rt_ofw_foreach_prop(np, prop)
1682     {
1683         int prep_ak = 0, next_ak, field;
1684         rt_bool_t match = RT_TRUE;
1685         const char *propname = prop->name, *fuzzy_name = sf;
1686 
1687         if (!rt_bitmap_test_bit(ak, prep_ak))
1688         {
1689             next_ak = rt_bitmap_next_set_bit(ak, prep_ak + 1, max_ak) ? : len;
1690             field = next_ak - prep_ak;
1691 
1692             if (rt_strncmp(propname, fuzzy_name, field))
1693             {
1694                 continue;
1695             }
1696 
1697             propname += field;
1698             fuzzy_name += field;
1699             prep_ak = next_ak;
1700         }
1701 
1702         rt_bitmap_for_each_set_bit_from(ak, prep_ak, next_ak, max_ak)
1703         {
1704             /* Skip the '*' */
1705             if (prep_ak == next_ak)
1706             {
1707                 ++fuzzy_name;
1708 
1709                 next_ak = rt_bitmap_next_set_bit(ak, prep_ak + 1, max_ak);
1710             }
1711 
1712             if (!(str = rt_strstr(propname, fuzzy_name)))
1713             {
1714                 match = RT_FALSE;
1715                 break;
1716             }
1717 
1718             field = next_ak - prep_ak;
1719             propname = str + field - 1;
1720             fuzzy_name += field;
1721             prep_ak = next_ak;
1722         }
1723 
1724         if (match)
1725         {
1726             if ((max_ak || !split_field[0]) && next_ak >= max_ak && len - max_ak > 1)
1727             {
1728                 if (next_ak == max_ak)
1729                 {
1730                     /* Skip the last '*' */
1731                     ++fuzzy_name;
1732                 }
1733 
1734                 if (!(propname = rt_strstr(propname, fuzzy_name)))
1735                 {
1736                     continue;
1737                 }
1738 
1739                 /* Check end flag */
1740                 if (propname[len - max_ak - 1] != '\0')
1741                 {
1742                     continue;
1743                 }
1744             }
1745 
1746             result = prop->name;
1747             break;
1748         }
1749     }
1750 
1751     return result;
1752 }
1753 
rt_ofw_get_prop_fuzzy_name(const struct rt_ofw_node * np,const char * name)1754 const char *rt_ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name)
1755 {
1756     const char *propname = RT_NULL;
1757 
1758     if (np && name)
1759     {
1760         propname = ofw_get_prop_fuzzy_name(np, name);
1761     }
1762 
1763     return propname;
1764 }
1765 
1766 
rt_ofw_get_prop(const struct rt_ofw_node * np,const char * name,rt_ssize_t * out_length)1767 struct rt_ofw_prop *rt_ofw_get_prop(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length)
1768 {
1769     struct rt_ofw_prop *prop = RT_NULL;
1770 
1771     if (np && name)
1772     {
1773         rt_ofw_foreach_prop(np, prop)
1774         {
1775             if (!rt_strcmp(prop->name, name))
1776             {
1777                 if (out_length)
1778                 {
1779                     *out_length = prop->length;
1780                 }
1781 
1782                 break;
1783             }
1784         }
1785     }
1786 
1787     return prop;
1788 }
1789 
1790 #define OFW_PROP_READ_UXX_ARRAY_INDEX(bit)                      \
1791 int rt_ofw_prop_read_u##bit##_array_index(                      \
1792         const struct rt_ofw_node *np, const char *propname,     \
1793         int index, int nr, rt_uint##bit##_t *out_values)        \
1794 {                                                               \
1795     int res, max_nr;                                            \
1796     if (np && propname && index >= 0 && nr >= 0 && out_values)  \
1797     {                                                           \
1798         rt_ssize_t len;                                         \
1799         const fdt##bit##_t *elm;                                \
1800         elm = rt_ofw_prop_read_raw(np, propname, &len);         \
1801         max_nr = len / sizeof(*elm);                            \
1802         if (elm && index < max_nr)                              \
1803         {                                                       \
1804             elm += index;                                       \
1805             max_nr -= index;                                    \
1806             res = nr > max_nr ? max_nr : nr;                    \
1807             for (nr = 0; nr < res; ++nr)                        \
1808             {                                                   \
1809                 *out_values++ = fdt##bit##_to_cpu(*elm++);      \
1810             }                                                   \
1811         }                                                       \
1812         else                                                    \
1813         {                                                       \
1814             res = -RT_EEMPTY;                                   \
1815         }                                                       \
1816     }                                                           \
1817     else                                                        \
1818     {                                                           \
1819         res = -RT_EINVAL;                                       \
1820     }                                                           \
1821     return res;                                                 \
1822 }
1823 
1824 OFW_PROP_READ_UXX_ARRAY_INDEX(8)
1825 OFW_PROP_READ_UXX_ARRAY_INDEX(16)
1826 OFW_PROP_READ_UXX_ARRAY_INDEX(32)
1827 OFW_PROP_READ_UXX_ARRAY_INDEX(64)
1828 
1829 #undef OFW_PROP_READ_UXX_ARRAY_INDEX
1830 
rt_ofw_prop_read_string_array_index(const struct rt_ofw_node * np,const char * propname,int index,int nr,const char ** out_strings)1831 int rt_ofw_prop_read_string_array_index(const struct rt_ofw_node *np, const char *propname,
1832         int index, int nr, const char **out_strings)
1833 {
1834     int res = 0;
1835 
1836     if (np && propname && index >= 0 && nr >= 0 && out_strings)
1837     {
1838         rt_ssize_t len, slen = 0;
1839         const char *value = rt_ofw_prop_read_raw(np, propname, &len);
1840 
1841         if (value)
1842         {
1843             nr += index;
1844 
1845             for (int idx = 0; idx < nr && len > 0; ++idx)
1846             {
1847                 /* Add '\0' */
1848                 slen = rt_strlen(value) + 1;
1849 
1850                 if (idx >= index)
1851                 {
1852                     *out_strings++ = value;
1853 
1854                     ++res;
1855                 }
1856 
1857                 len -= slen;
1858                 value += slen;
1859             }
1860         }
1861         else
1862         {
1863             res = -RT_EEMPTY;
1864         }
1865     }
1866     else
1867     {
1868         res = -RT_EINVAL;
1869     }
1870 
1871     return res;
1872 }
1873 
rt_ofw_prop_count_of_size(const struct rt_ofw_node * np,const char * propname,int size)1874 int rt_ofw_prop_count_of_size(const struct rt_ofw_node *np, const char *propname, int size)
1875 {
1876     int count;
1877 
1878     if (np && propname && size > 0)
1879     {
1880         rt_ssize_t len;
1881 
1882         count = -RT_EEMPTY;
1883 
1884         if (rt_ofw_get_prop(np, propname, &len))
1885         {
1886             count = len / size;
1887         }
1888     }
1889     else
1890     {
1891         count = -RT_EINVAL;
1892     }
1893 
1894     return count;
1895 }
1896 
ofw_strcmp(const char * cs,const char * ct)1897 static rt_int32_t ofw_strcmp(const char *cs, const char *ct)
1898 {
1899     return rt_strcmp(cs, ct);
1900 }
1901 
rt_ofw_prop_index_of_string(const struct rt_ofw_node * np,const char * propname,const char * string)1902 int rt_ofw_prop_index_of_string(const struct rt_ofw_node *np, const char *propname, const char *string)
1903 {
1904     int idx;
1905 
1906     if (np && propname && string)
1907     {
1908         struct rt_ofw_prop *prop = rt_ofw_get_prop(np, propname, RT_NULL);
1909 
1910         idx = -1;
1911 
1912         if (prop)
1913         {
1914             idx = ofw_prop_index_of_string(prop, string, ofw_strcmp);
1915         }
1916     }
1917     else
1918     {
1919         idx = -RT_EINVAL;
1920     }
1921 
1922     return idx;
1923 }
1924 
rt_ofw_prop_next_u32(struct rt_ofw_prop * prop,const fdt32_t * cur,rt_uint32_t * out_value)1925 const fdt32_t *rt_ofw_prop_next_u32(struct rt_ofw_prop *prop, const fdt32_t *cur, rt_uint32_t *out_value)
1926 {
1927     if (prop && out_value)
1928     {
1929         if (cur)
1930         {
1931             ++cur;
1932 
1933             if ((void *)cur >= prop->value + prop->length)
1934             {
1935                 cur = RT_NULL;
1936             }
1937         }
1938         else
1939         {
1940             cur = prop->value;
1941         }
1942 
1943         if (cur)
1944         {
1945             *out_value = fdt32_to_cpu(*cur);
1946         }
1947     }
1948     else
1949     {
1950         cur = RT_NULL;
1951     }
1952 
1953     return cur;
1954 }
1955 
rt_ofw_prop_next_string(struct rt_ofw_prop * prop,const char * cur)1956 const char *rt_ofw_prop_next_string(struct rt_ofw_prop *prop, const char *cur)
1957 {
1958     if (prop)
1959     {
1960         if (cur)
1961         {
1962             cur += rt_strlen(cur) + 1;
1963 
1964             if ((void *)cur >= prop->value + prop->length)
1965             {
1966                 cur = RT_NULL;
1967             }
1968         }
1969         else
1970         {
1971             cur = prop->value;
1972         }
1973     }
1974     else
1975     {
1976         cur = RT_NULL;
1977     }
1978 
1979     return cur;
1980 }
1981