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