1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/syslog.h>
3 #include <lunaix/owloysius.h>
9 static morph_t* devtree_obj_root;
10 static struct dt_context dtctx;
13 fdt_itbegin(struct fdt_iter* fdti, struct fdt_header* fdt_hdr)
15 unsigned int off_struct, off_str;
16 struct fdt_token* tok;
19 off_str = le(fdt_hdr->off_dt_strings);
20 off_struct = le(fdt_hdr->off_dt_struct);
22 tok = offset_t(fdt_hdr, struct fdt_token, off_struct);
23 str_blk = offset_t(fdt_hdr, const char, off_str);
25 *fdti = (struct fdt_iter) {
32 fdt_itend(struct fdt_iter* fdti)
38 fdt_itnext(struct fdt_iter* fdti)
40 struct fdt_token *current;
41 struct fdt_prop *prop;
50 if (fdt_nope(current)) {
54 if (fdt_prop(current)) {
55 prop = (struct fdt_prop*) current;
56 current = offset(current, prop->len);
60 if (fdt_node_end(current)) {
68 if (fdti->depth == 1) {
73 while (!fdt_prop(current) && !fdt_node_end(current)) {
77 if (fdt_prop(current)) {
83 } while (fdt_nope(current) && fdti->depth > 0);
85 return fdti->depth > 0;
89 fdt_itnext_at(struct fdt_iter* fdti, int level)
91 while (fdti->depth != level && fdt_itnext(fdti));
93 return fdti->depth == level;
97 fdt_memrsvd_itbegin(struct fdt_memrsvd_iter* rsvdi,
98 struct fdt_header* fdt_hdr)
100 size_t off = le(fdt_hdr->off_mem_rsvmap);
103 offset_t(fdt_hdr, typeof(*rsvdi->block), off);
105 rsvdi->block = &rsvdi->block[-1];
109 fdt_memrsvd_itnext(struct fdt_memrsvd_iter* rsvdi)
111 struct fdt_memrsvd_ent* ent;
120 return ent->addr || ent->size;
124 fdt_memrsvd_itend(struct fdt_memrsvd_iter* rsvdi)
130 __parse_stdbase_prop(struct fdt_iter* it, struct dt_node_base* node)
132 struct fdt_prop* prop;
136 if (propeq(it, "compatible")) {
137 __mkprop_ptr(it, &node->compat);
140 else if (propeq(it, "phandle")) {
141 node->phandle = __prop_getu32(it);
144 else if (propeq(it, "#address-cells")) {
145 node->addr_c = (char)__prop_getu32(it);
148 else if (propeq(it, "#size-cells")) {
149 node->sz_c = (char)__prop_getu32(it);
152 else if (propeq(it, "#interrupt-cells")) {
153 node->intr_c = (char)__prop_getu32(it);
156 else if (propeq(it, "status")) {
157 char peek = *(char*)&it->prop[1];
159 node->status = STATUS_OK;
161 else if (peek == 'r') {
162 node->status = STATUS_RSVD;
164 else if (peek == 'd') {
165 node->status = STATUS_DISABLE;
167 else if (peek == 'f') {
168 node->status = STATUS_FAIL;
180 __parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node)
182 if (propeq(it, "reg")) {
183 __mkprop_ptr(it, &node->reg);
186 else if (propeq(it, "virtual-reg")) {
187 __mkprop_ptr(it, &node->vreg);
190 else if (propeq(it, "ranges")) {
191 __mkprop_ptr(it, &node->ranges);
194 else if (propeq(it, "dma-ranges")) {
195 __mkprop_ptr(it, &node->dma_ranges);
206 __parse_stdflags(struct fdt_iter* it, struct dt_node_base* node)
208 if (propeq(it, "dma-coherent")) {
209 node->dma_coherent = true;
212 else if (propeq(it, "dma-noncoherent")) {
213 node->dma_ncoherent = true;
216 else if (propeq(it, "interrupt-controller")) {
217 node->intr_controll = true;
228 __dt_node_set_name(struct dt_node_base* node, const char* name)
230 changeling_setname(&node->mobj, name);
234 __init_prop_table(struct dt_node_base* node)
236 struct dt_prop_table* propt;
238 propt = valloc(sizeof(*propt));
239 hashtable_init(propt->_op_bucket);
242 #define prop_table_add(node, prop) \
243 hashtable_hash_in( (node)->props->_op_bucket, \
244 &(prop)->ht, (prop)->key.hash);
247 __parse_other_prop(struct fdt_iter* it, struct dt_node_base* node)
249 struct dt_prop* prop;
253 prop = valloc(sizeof(*prop));
254 key = fdtit_prop_key(it);
256 prop->key = HSTR(key, strlen(key));
257 __mkprop_ptr(it, &prop->val);
259 hstr_rehash(&prop->key, HSTR_FULL_HASH);
261 prop_table_add(node, prop);
265 __fill_node(struct fdt_iter* it, struct dt_node* node)
267 if (__parse_stdflags(it, &node->base)) {
271 if (__parse_stdbase_prop(it, &node->base)) {
275 if (__parse_stdnode_prop(it, node)) {
279 if (parse_stdintr_prop(it, &node->intr)) {
283 __parse_other_prop(it, &node->base);
287 __fill_root(struct fdt_iter* it, struct dt_root* node)
289 if (__parse_stdflags(it, &node->base)) {
293 if (__parse_stdbase_prop(it, &node->base)) {
297 struct fdt_prop* prop;
300 if (propeq(it, "serial-number")) {
301 node->serial = (const char*)&prop[1];
304 else if (propeq(it, "chassis-type")) {
305 node->chassis = (const char*)&prop[1];
308 __parse_other_prop(it, &node->base);
312 __init_node(struct dt_node_base* node)
316 parent = devtree_obj_root;
318 parent = node->mobj.parent;
319 node->_std = node->parent->_std;
322 __init_prop_table(node);
323 changeling_morph_anon(parent, node->mobj, dt_morpher);
327 __init_node_regular(struct dt_node* node)
329 __init_node(&node->base);
330 node->intr.parent_hnd = PHND_NULL;
334 __expand_extended_intr(struct dt_intr_node* intrupt)
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;
342 if (!intrupt->intr.extended) {
346 arr = intrupt->intr.arr;
347 node = INTR_TO_DTNODE(intrupt);
349 llist_init_head(&intrupt->intr.values);
351 dt_decode(&it, &node->base, &arr, 1);
355 phnd = dtprop_to_u32(it.prop_loc);
356 master = dt_resolve_phandle(phnd);
359 WARN("dtb: (intr_extended) malformed phandle: %d", phnd);
363 intr_prop = valloc(sizeof(*intr_prop));
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
371 llist_append(&intrupt->intr.values, &intr_prop->props);
372 dtprop_next_n(&it, intr_prop->val.size);
374 } while(dtprop_next(&it));
378 __resolve_phnd_references()
380 struct dt_node_base *pos, *n;
381 struct dt_node *node, *parent, *default_parent;
382 struct dt_intr_node* intrupt;
385 llist_for_each(pos, n, &dtctx.nodes, nodes)
387 node = BASE_TO_DTNODE(pos);
388 intrupt = &node->intr;
390 if (!node->base.intr_c) {
394 phnd = intrupt->parent_hnd;
395 default_parent = (struct dt_node*)node->base.parent;
396 parent = default_parent;
398 if (phnd != PHND_NULL) {
399 parent = dt_resolve_phandle(phnd);
403 WARN("dtb: (phnd_resolve) malformed phandle: %d", phnd);
404 parent = default_parent;
407 intrupt->parent = &parent->intr;
409 __expand_extended_intr(intrupt);
414 __resolve_inter_map()
416 struct dt_node_base *pos, *n;
418 llist_for_each(pos, n, &dtctx.nodes, nodes)
420 dt_resolve_interrupt_map(BASE_TO_DTNODE(pos));
425 dt_load(ptr_t dtb_dropoff)
427 dtctx.reloacted_dtb = dtb_dropoff;
429 if (dtctx.fdt->magic != FDT_MAGIC) {
430 ERROR("invalid dtb, unexpected magic: 0x%x", dtctx.fdt->magic);
434 size_t str_off = le(dtctx.fdt->size_dt_strings);
435 dtctx.str_block = offset_t(dtb_dropoff, const char, str_off);
437 llist_init_head(&dtctx.nodes);
438 hashtable_init(dtctx.phnds_table);
441 struct fdt_token* tok;
442 struct dt_node_base *node, *prev;
444 struct dt_node_base* depth[16];
445 bool is_root_level, filled;
449 fdt_itbegin(&it, dtctx.fdt);
451 while (fdt_itnext(&it)) {
452 is_root_level = it.depth == 1;
454 if (it.depth >= 16) {
456 ERROR("strange dtb, too deep to dive.");
460 depth[it.depth] = NULL;
461 node = depth[it.depth - 1];
465 if (unlikely(is_root_level)) {
466 node = vzalloc(sizeof(struct dt_root));
470 node = vzalloc(sizeof(struct dt_node));
471 prev = depth[it.depth - 2];
474 __init_node_regular((struct dt_node*)node);
476 llist_append(&dtctx.nodes, &node->nodes);
479 __dt_node_set_name(node, (const char*)&it.pos[1]);
482 if (unlikely(is_root_level)) {
483 __fill_root(&it, (struct dt_root*)node);
486 __fill_node(&it, (struct dt_node*)node);
492 dtctx.root = (struct dt_root*)depth[0];
494 __resolve_phnd_references();
495 __resolve_inter_map();
497 INFO("device tree loaded");
503 dt_resolve_phandle(dt_phnd_t phandle)
505 struct dt_node_base *pos, *n;
506 llist_for_each(pos, n, &dtctx.nodes, nodes)
508 if (pos->phandle == phandle) {
509 return (struct dt_node*)pos;
517 __byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node)
520 const char* be_matched = HSTR_VAL(node->mobj.name);
521 const char* name = (const char*)iter->closure;
523 while (be_matched[i] && name[i])
525 if (be_matched[i] != name[i]) {
536 dt_begin_find_byname(struct dt_node_iter* iter,
537 struct dt_node* node, const char* name)
539 dt_begin_find(iter, node, __byname_predicate, name);
543 dt_begin_find(struct dt_node_iter* iter, struct dt_node* node,
544 node_predicate_t pred, void* closure)
546 node = node ? : (struct dt_node*)dtctx.root;
548 iter->head = &node->base;
549 iter->matched = NULL;
550 iter->closure = closure;
554 struct dt_node_base* base;
555 changeling_for_each(pos, n, &node->mobj)
557 base = &changeling_reveal(pos, dt_morpher)->base;
558 if (pred(iter, base)) {
559 iter->matched = base;
566 dt_find_next(struct dt_node_iter* iter,
567 struct dt_node_base** matched)
569 if (!dt_found_any(iter)) {
573 struct dt_node *node;
576 head = dt_mobj(iter->head);
577 pos = dt_mobj(iter->matched);
578 *matched = iter->matched;
580 while (&pos->sibs != &head->subs)
582 pos = list_next(pos, morph_t, sibs);
583 node = changeling_reveal(pos, dt_morpher);
585 if (!iter->pred(iter, &node->base)) {
589 iter->matched = &node->base;
597 dt_getprop(struct dt_node_base* base, const char* name)
599 struct hstr hashed_name;
600 struct dt_prop *pos, *n;
603 hashed_name = HSTR(name, strlen(name));
604 hstr_rehash(&hashed_name, HSTR_FULL_HASH);
605 hash = hashed_name.hash;
607 hashtable_hash_foreach(base->props->_op_bucket, hash, pos, n, ht)
609 if (HSTR_EQ(&pos->key, &hashed_name)) {
626 devtree_obj_root = changeling_spawn(NULL, NULL);
628 owloysius_fetch_init(__init_devtree, on_sysconf);