f1d68608e5d883798aea4cc3c44f0e2a671b9c13
[lunaix-os.git] / lunaix-os / hal / devtree / dt.c
1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/syslog.h>
3 #include <lunaix/owloysius.h>
4
5 #include "devtree.h"
6
7 LOG_MODULE("dtb")
8
9 static morph_t* devtree_obj_root;
10 static struct dt_context dtctx;
11
12 void 
13 fdt_itbegin(struct fdt_iter* fdti, struct fdt_header* fdt_hdr)
14 {
15     unsigned int off_struct, off_str;
16     struct fdt_token* tok;
17     const char* str_blk;
18
19     off_str    = le(fdt_hdr->off_dt_strings);
20     off_struct = le(fdt_hdr->off_dt_struct);
21
22     tok = offset_t(fdt_hdr, struct fdt_token, off_struct);
23     str_blk = offset_t(fdt_hdr, const char, off_str);
24     
25     *fdti = (struct fdt_iter) {
26         .pos = tok,
27         .str_block = str_blk
28     };
29 }
30
31 void 
32 fdt_itend(struct fdt_iter* fdti)
33 {
34     fdti->pos = NULL;
35 }
36
37 bool
38 fdt_itnext(struct fdt_iter* fdti)
39 {
40     struct fdt_token *current;
41     struct fdt_prop  *prop;
42
43     current = fdti->pos;
44     if (!current) {
45         return false;
46     }
47
48     do
49     {
50         if (fdt_nope(current)) {
51             continue;
52         }
53
54         if (fdt_prop(current)) {
55             prop    = (struct fdt_prop*) current;
56             current = offset(current, prop->len);
57             continue;
58         }
59         
60         if (fdt_node_end(current)) {
61             fdti->depth--;
62             continue;
63         }
64         
65         // node begin
66
67         fdti->depth++;
68         if (fdti->depth == 1) {
69             // enter root node
70             break;
71         }
72
73         while (!fdt_prop(current) && !fdt_node_end(current)) {
74             current++;
75         }
76
77         if (fdt_prop(current)) {
78             break;
79         }
80         
81         current++;
82         
83     } while (fdt_nope(current) && fdti->depth > 0);
84
85     return fdti->depth > 0;
86 }
87
88 bool 
89 fdt_itnext_at(struct fdt_iter* fdti, int level)
90 {
91     while (fdti->depth != level && fdt_itnext(fdti));
92     
93     return fdti->depth == level;
94 }
95
96 void
97 fdt_memrsvd_itbegin(struct fdt_memrsvd_iter* rsvdi, 
98                     struct fdt_header* fdt_hdr)
99 {
100     size_t off = le(fdt_hdr->off_mem_rsvmap);
101     
102     rsvdi->block = 
103         offset_t(fdt_hdr, typeof(*rsvdi->block), off);
104     
105     rsvdi->block = &rsvdi->block[-1];
106 }
107
108 bool
109 fdt_memrsvd_itnext(struct fdt_memrsvd_iter* rsvdi)
110 {
111     struct fdt_memrsvd_ent* ent;
112
113     ent = rsvdi->block;
114     if (!ent) {
115         return false;
116     }
117
118     rsvdi->block++;
119
120     return ent->addr || ent->size;
121 }
122
123 void
124 fdt_memrsvd_itend(struct fdt_memrsvd_iter* rsvdi)
125 {
126     rsvdi->block = NULL;
127 }
128
129 static bool
130 __parse_stdbase_prop(struct fdt_iter* it, struct dt_node_base* node)
131 {
132     struct fdt_prop* prop;
133
134     prop = it->prop;
135
136     if (propeq(it, "compatible")) {
137         __mkprop_ptr(it, &node->compat);
138     } 
139
140     else if (propeq(it, "phandle")) {
141         node->phandle = __prop_getu32(it);
142     }
143     
144     else if (propeq(it, "#address-cells")) {
145         node->addr_c = (char)__prop_getu32(it);
146     } 
147     
148     else if (propeq(it, "#size-cells")) {
149         node->sz_c = (char)__prop_getu32(it);
150     } 
151     
152     else if (propeq(it, "#interrupt-cells")) {
153         node->intr_c = (char)__prop_getu32(it);
154     } 
155     
156     else if (propeq(it, "status")) {
157         char peek = *(char*)&it->prop[1];
158         if (peek == 'o') {
159             node->status = STATUS_OK;
160         }
161         else if (peek == 'r') {
162             node->status = STATUS_RSVD;
163         }
164         else if (peek == 'd') {
165             node->status = STATUS_DISABLE;
166         }
167         else if (peek == 'f') {
168             node->status = STATUS_FAIL;
169         }
170     }
171
172     else {
173         return false;
174     }
175
176     return true;
177 }
178
179 static bool
180 __parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node)
181 {
182     if (propeq(it, "reg")) {
183         __mkprop_ptr(it, &node->reg);
184     }
185
186     else if (propeq(it, "virtual-reg")) {
187         __mkprop_ptr(it, &node->vreg);
188     }
189
190     else if (propeq(it, "ranges")) {
191         __mkprop_ptr(it, &node->ranges);
192     }
193
194     else if (propeq(it, "dma-ranges")) {
195         __mkprop_ptr(it, &node->dma_ranges);
196     }
197
198     else {
199         return false;
200     }
201
202     return true;
203 }
204
205 static bool
206 __parse_stdflags(struct fdt_iter* it, struct dt_node_base* node)
207 {
208     if (propeq(it, "dma-coherent")) {
209         node->dma_coherent = true;
210     }
211
212     else if (propeq(it, "dma-noncoherent")) {
213         node->dma_ncoherent = true;
214     }
215
216     else if (propeq(it, "interrupt-controller")) {
217         node->intr_controll = true;
218     }
219
220     else {
221         return false;
222     }
223
224     return true;
225 }
226
227 static inline void
228 __dt_node_set_name(struct dt_node_base* node, const char* name)
229 {
230     changeling_setname(&node->mobj, name);
231 }
232
233 static inline void
234 __init_prop_table(struct dt_node_base* node)
235 {
236     struct dt_prop_table* propt;
237
238     propt = valloc(sizeof(*propt));
239     hashtable_init(propt->_op_bucket);
240 }
241
242 #define prop_table_add(node, prop)                                             \
243             hashtable_hash_in( (node)->props->_op_bucket,                      \
244                               &(prop)->ht, (prop)->key.hash);
245
246 static void
247 __parse_other_prop(struct fdt_iter* it, struct dt_node_base* node)
248 {
249     struct dt_prop* prop;
250     const char* key;
251     unsigned int hash;
252
253     prop = valloc(sizeof(*prop));
254     key  = fdtit_prop_key(it);
255
256     prop->key = HSTR(key, strlen(key));
257     __mkprop_ptr(it, &prop->val);
258
259     hstr_rehash(&prop->key, HSTR_FULL_HASH);
260
261     prop_table_add(node, prop);
262 }
263
264 static void
265 __fill_node(struct fdt_iter* it, struct dt_node* node)
266 {
267     if (__parse_stdflags(it, &node->base)) {
268         return;
269     }
270
271     if (__parse_stdbase_prop(it, &node->base)) {
272         return;
273     }
274
275     if (__parse_stdnode_prop(it, node)) {
276         return;
277     }
278
279     if (parse_stdintr_prop(it, &node->intr)) {
280         return;
281     }
282
283     __parse_other_prop(it, &node->base);
284 }
285
286 static void
287 __fill_root(struct fdt_iter* it, struct dt_root* node)
288 {
289     if (__parse_stdflags(it, &node->base)) {
290         return;
291     }
292     
293     if (__parse_stdbase_prop(it, &node->base)) {
294         return;
295     }
296
297     struct fdt_prop* prop;
298
299     prop = it->prop;
300     if (propeq(it, "serial-number")) {
301         node->serial = (const char*)&prop[1];
302     }
303
304     else if (propeq(it, "chassis-type")) {
305         node->chassis = (const char*)&prop[1];
306     }
307
308     __parse_other_prop(it, &node->base);
309 }
310
311 static inline void
312 __init_node(struct dt_node_base* node)
313 {
314     morph_t* parent;
315
316     parent = devtree_obj_root;
317     if (node->parent) {
318         parent = node->mobj.parent;
319         node->_std = node->parent->_std;
320     }
321
322     __init_prop_table(node);
323     changeling_morph_anon(parent, node->mobj, dt_morpher);
324 }
325
326 static inline void
327 __init_node_regular(struct dt_node* node)
328 {
329     __init_node(&node->base);
330     node->intr.parent_hnd = PHND_NULL;
331 }
332
333 static void
334 __expand_extended_intr(struct dt_intr_node* intrupt)
335 {
336     struct dt_prop_iter it;
337     struct dt_prop_val  arr;
338     struct dt_node *node;
339     struct dt_node *master;
340     struct dt_intr_prop* intr_prop;
341
342     if (!intrupt->intr.extended) {
343         return;
344     }
345
346     arr = intrupt->intr.arr;
347     node = INTR_TO_DTNODE(intrupt);
348
349     llist_init_head(&intrupt->intr.values);
350     
351     dt_decode(&it, &node->base, &arr, 1);
352     
353     dt_phnd_t phnd;
354     do {
355         phnd   = dtprop_to_u32(it.prop_loc);
356         master = dt_resolve_phandle(phnd);
357
358         if (!master) {
359             WARN("dtb: (intr_extended) malformed phandle: %d", phnd);
360             continue;
361         }
362
363         intr_prop = valloc(sizeof(*intr_prop));
364         
365         intr_prop->master = &master->intr;
366         intr_prop->val = (struct dt_prop_val) {
367             .encoded = it.prop_loc_next,
368             .size    = master->base.intr_c
369         };
370
371         llist_append(&intrupt->intr.values, &intr_prop->props);
372         dtprop_next_n(&it, intr_prop->val.size);
373         
374     } while(dtprop_next(&it));
375 }
376
377 static void
378 __resolve_phnd_references()
379 {
380     struct dt_node_base *pos, *n;
381     struct dt_node *node, *parent, *default_parent;
382     struct dt_intr_node* intrupt;
383     dt_phnd_t phnd;
384     
385     llist_for_each(pos, n, &dtctx.nodes, nodes)
386     {
387         node = BASE_TO_DTNODE(pos);
388         intrupt = &node->intr;
389
390         if (!node->base.intr_c) {
391             continue;
392         }
393
394         phnd = intrupt->parent_hnd;
395         default_parent = (struct dt_node*)node->base.parent;
396         parent = default_parent;
397
398         if (phnd != PHND_NULL) {
399             parent = dt_resolve_phandle(phnd);
400         }
401
402         if (!parent) {
403             WARN("dtb: (phnd_resolve) malformed phandle: %d", phnd);
404             parent = default_parent;
405         }
406
407         intrupt->parent = &parent->intr;
408
409         __expand_extended_intr(intrupt);
410     }
411 }
412
413 static void
414 __resolve_inter_map()
415 {
416     struct dt_node_base *pos, *n;
417
418     llist_for_each(pos, n, &dtctx.nodes, nodes)
419     {
420         dt_resolve_interrupt_map(BASE_TO_DTNODE(pos));
421     }
422 }
423
424 bool
425 dt_load(ptr_t dtb_dropoff)
426 {
427     dtctx.reloacted_dtb = dtb_dropoff;
428
429     if (dtctx.fdt->magic != FDT_MAGIC) {
430         ERROR("invalid dtb, unexpected magic: 0x%x", dtctx.fdt->magic);
431         return false;
432     }
433
434     size_t str_off = le(dtctx.fdt->size_dt_strings);
435     dtctx.str_block = offset_t(dtb_dropoff, const char, str_off);
436
437     llist_init_head(&dtctx.nodes);
438     hashtable_init(dtctx.phnds_table);
439
440     struct fdt_iter it;
441     struct fdt_token* tok;
442     struct dt_node_base *node, *prev;
443     
444     struct dt_node_base* depth[16];
445     bool is_root_level, filled;
446
447     node = NULL;
448     depth[0] = NULL;
449     fdt_itbegin(&it, dtctx.fdt);
450     
451     while (fdt_itnext(&it)) {
452         is_root_level = it.depth == 1;
453
454         if (it.depth >= 16) {
455             // tree too deep
456             ERROR("strange dtb, too deep to dive.");
457             return false;
458         }
459
460         depth[it.depth] = NULL;
461         node = depth[it.depth - 1];
462
463         if (!node) {
464             // need new node
465             if (unlikely(is_root_level)) {
466                 node = vzalloc(sizeof(struct dt_root));
467                 __init_node(node);
468             }
469             else {
470                 node = vzalloc(sizeof(struct dt_node));
471                 prev = depth[it.depth - 2];
472                 node->parent = prev;
473
474                 __init_node_regular((struct dt_node*)node);
475
476                 llist_append(&dtctx.nodes, &node->nodes);
477             }
478
479             __dt_node_set_name(node, (const char*)&it.pos[1]);
480         }
481
482         if (unlikely(is_root_level)) {
483             __fill_root(&it, (struct dt_root*)node);
484         }
485         else {
486             __fill_node(&it, (struct dt_node*)node);
487         }
488     }
489
490     fdt_itend(&it);
491
492     dtctx.root = (struct dt_root*)depth[0];
493
494     __resolve_phnd_references();
495     __resolve_inter_map();
496
497     INFO("device tree loaded");
498
499     return true;
500 }
501
502 struct dt_node*
503 dt_resolve_phandle(dt_phnd_t phandle)
504 {
505     struct dt_node_base *pos, *n;
506     llist_for_each(pos, n, &dtctx.nodes, nodes)
507     {
508         if (pos->phandle == phandle) {
509             return (struct dt_node*)pos;
510         }
511     }
512
513     return NULL;
514 }
515
516 static bool
517 __byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node)
518 {
519     int i = 0;
520     const char* be_matched = HSTR_VAL(node->mobj.name);
521     const char* name = (const char*)iter->closure;
522
523     while (be_matched[i] && name[i])
524     {
525         if (be_matched[i] != name[i]) {
526             return false;
527         }
528
529         i++;
530     }
531
532     return true;
533 }
534
535 void
536 dt_begin_find_byname(struct dt_node_iter* iter, 
537               struct dt_node* node, const char* name)
538 {
539     dt_begin_find(iter, node, __byname_predicate, name);
540 }
541
542 void
543 dt_begin_find(struct dt_node_iter* iter, struct dt_node* node, 
544               node_predicate_t pred, void* closure)
545 {
546     node = node ? : (struct dt_node*)dtctx.root;
547
548     iter->head = &node->base;
549     iter->matched = NULL;
550     iter->closure = closure;
551     iter->pred = pred;
552
553     morph_t *pos, *n;
554     struct dt_node_base* base;
555     changeling_for_each(pos, n, &node->mobj)
556     {
557         base = &changeling_reveal(pos, dt_morpher)->base;
558         if (pred(iter, base)) {
559             iter->matched = base;
560             break;
561         }
562     }
563 }
564
565 bool
566 dt_find_next(struct dt_node_iter* iter,
567              struct dt_node_base** matched)
568 {
569     if (!dt_found_any(iter)) {
570         return false;
571     }
572
573     struct dt_node *node;
574     morph_t *pos, *head;
575
576     head = dt_mobj(iter->head);
577     pos  = dt_mobj(iter->matched);
578     *matched = iter->matched;
579
580     while (&pos->sibs != &head->subs)
581     {
582         pos = list_next(pos, morph_t, sibs);
583         node = changeling_reveal(pos, dt_morpher);
584
585         if (!iter->pred(iter, &node->base)) {
586             continue;
587         }
588
589         iter->matched = &node->base;
590         return true;
591     }
592
593     return false;
594 }
595
596 struct dt_prop_val*
597 dt_getprop(struct dt_node_base* base, const char* name)
598 {
599     struct hstr hashed_name;
600     struct dt_prop *pos, *n;
601     unsigned int hash;
602
603     hashed_name = HSTR(name, strlen(name));
604     hstr_rehash(&hashed_name, HSTR_FULL_HASH);
605     hash = hashed_name.hash;
606
607     hashtable_hash_foreach(base->props->_op_bucket, hash, pos, n, ht)
608     {
609         if (HSTR_EQ(&pos->key, &hashed_name)) {
610             return &pos->val;
611         }
612     }
613
614     return NULL;
615 }
616
617 struct dt_context*
618 dt_main_context()
619 {
620     return &dtctx;
621 }
622
623 static void
624 __init_devtree()
625 {
626     devtree_obj_root = changeling_spawn(NULL, NULL);
627 }
628 owloysius_fetch_init(__init_devtree, on_sysconf);