1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/syslog.h>
4 #include <klibc/string.h>
6 #include <hal/devtree.h>
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 propeq(struct fdt_iter* it, const char* key)
132 return streq(fdtit_prop_key(it), key);
136 __mkprop_val32(struct fdt_iter* it, struct dt_prop_val* val)
138 val->u32_val = le(*(u32_t*)&it->prop[1]);
139 val->size = le(it->prop->len);
143 __mkprop_val64(struct fdt_iter* it, struct dt_prop_val* val)
145 val->u64_val = le64(*(u64_t*)&it->prop[1]);
146 val->size = le(it->prop->len);
150 __mkprop_ptr(struct fdt_iter* it, struct dt_prop_val* val)
152 val->ptr_val = __ptr(&it->prop[1]);
153 val->size = le(it->prop->len);
157 __prop_getu32(struct fdt_iter* it)
159 return le(*(u32_t*)&it->prop[1]);
163 __parse_stdbase_prop(struct fdt_iter* it, struct dt_node_base* node)
165 struct fdt_prop* prop;
169 if (propeq(it, "compatible")) {
170 __mkprop_ptr(it, &node->compat);
173 else if (propeq(it, "model")) {
174 node->model = (const char*)&prop[1];
177 else if (propeq(it, "phandle")) {
178 node->phandle = __prop_getu32(it);
179 hashtable_hash_in(dtctx.phnds_table,
180 &node->phnd_link, node->phandle);
183 else if (propeq(it, "#address-cells")) {
184 node->addr_c = (char)__prop_getu32(it);
187 else if (propeq(it, "#size-cells")) {
188 node->sz_c = (char)__prop_getu32(it);
191 else if (propeq(it, "#interrupt-cells")) {
192 node->intr_c = (char)__prop_getu32(it);
195 else if (propeq(it, "status")) {
196 char peek = *(char*)&it->prop[1];
198 node->status = STATUS_OK;
200 else if (peek == 'r') {
201 node->status = STATUS_RSVD;
203 else if (peek == 'd') {
204 node->status = STATUS_DISABLE;
206 else if (peek == 'f') {
207 node->status = STATUS_FAIL;
219 __parse_stdnode_prop(struct fdt_iter* it, struct dt_node* node)
221 if (propeq(it, "reg")) {
222 __mkprop_ptr(it, &node->reg);
225 else if (propeq(it, "virtual-reg")) {
226 __mkprop_ptr(it, &node->vreg);
229 else if (propeq(it, "ranges")) {
230 __mkprop_ptr(it, &node->ranges);
233 else if (propeq(it, "dma-ranges")) {
234 __mkprop_ptr(it, &node->dma_ranges);
245 __parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node)
247 if (propeq(it, "interrupt-map")) {
248 __mkprop_ptr(it, &node->intr_map);
251 else if (propeq(it, "interrupt-map-mask")) {
252 __mkprop_ptr(it, &node->intr_map_mask);
255 else if (propeq(it, "interrupt-parent")) {
256 node->parent_hnd = __prop_getu32(it);
259 else if (propeq(it, "interrupt-extended")) {
260 node->intr.extended = true;
261 __mkprop_ptr(it, &node->intr.arr);
264 else if (!node->intr.extended && propeq(it, "interrupts")) {
265 __mkprop_ptr(it, &node->intr.arr);
276 __parse_stdflags(struct fdt_iter* it, struct dt_node_base* node)
278 if (propeq(it, "dma-coherent")) {
279 node->dma_coherent = true;
282 else if (propeq(it, "dma-noncoherent")) {
283 node->dma_ncoherent = true;
286 else if (propeq(it, "interrupt-controller")) {
287 node->intr_controll = true;
298 __parse_other_prop(struct fdt_iter* it, struct dt_node_base* node)
300 struct dt_prop* prop;
304 prop = valloc(sizeof(*prop));
305 key = fdtit_prop_key(it);
307 prop->key = HSTR(key, strlen(key));
308 __mkprop_ptr(it, &prop->val);
310 hstr_rehash(&prop->key, HSTR_FULL_HASH);
311 hash = prop->key.hash;
313 hashtable_hash_in(node->_op_bucket, &prop->ht, hash);
317 __fill_node(struct fdt_iter* it, struct dt_node* node)
319 if (__parse_stdflags(it, &node->base)) {
323 if (__parse_stdbase_prop(it, &node->base)) {
327 if (__parse_stdnode_prop(it, node)) {
331 if (__parse_stdintr_prop(it, &node->intr)) {
335 __parse_other_prop(it, &node->base);
339 __fill_root(struct fdt_iter* it, struct dt_root* node)
341 if (__parse_stdflags(it, &node->base)) {
345 if (__parse_stdbase_prop(it, &node->base)) {
349 struct fdt_prop* prop;
352 if (propeq(it, "serial-number")) {
353 node->serial = (const char*)&prop[1];
356 else if (propeq(it, "chassis-type")) {
357 node->chassis = (const char*)&prop[1];
360 __parse_other_prop(it, &node->base);
364 __init_node(struct dt_node_base* node)
366 hashtable_init(node->_op_bucket);
367 llist_init_head(&node->children);
371 __init_node_regular(struct dt_node* node)
373 __init_node(&node->base);
374 node->intr.parent_hnd = PHND_NULL;
378 __expand_extended_intr(struct dt_intr_node* intrupt)
380 struct dt_prop_iter it;
381 struct dt_prop_val arr;
382 struct dt_node *node;
383 struct dt_node *master;
384 struct dt_intr_prop* intr_prop;
386 if (!intrupt->intr.extended) {
390 arr = intrupt->intr.arr;
391 node = DT_NODE(intrupt);
393 llist_init_head(&intrupt->intr.values);
395 dt_decode(&it, &node->base, &arr, 1);
398 while(dtprop_next(&it)) {
399 phnd = dtprop_to_u32(it.prop_loc);
400 master = dt_resolve_phandle(phnd);
403 WARN("dtb: (intr_extended) malformed phandle: %d", phnd);
407 intr_prop = valloc(sizeof(*intr_prop));
409 intr_prop->master = &master->intr;
410 intr_prop->val = (struct dt_prop_val) {
411 .encoded = it.prop_loc_next,
412 .size = master->base.intr_c
415 llist_append(&intrupt->intr.values, &intr_prop->props);
416 dtprop_next_n(&it, intr_prop->val.size);
421 __resolve_phnd_references()
423 struct dt_node_base *pos, *n;
424 struct dt_node *node, *parent, *default_parent;
425 struct dt_intr_node* intrupt;
428 llist_for_each(pos, n, &dtctx.nodes, nodes)
430 node = (struct dt_node*)pos;
431 intrupt = &node->intr;
432 if (!node->base.intr_c) {
436 phnd = intrupt->parent_hnd;
437 default_parent = (struct dt_node*)node->base.parent;
438 parent = default_parent;
440 if (phnd != PHND_NULL) {
441 parent = dt_resolve_phandle(phnd);
445 WARN("dtb: (phnd_resolve) malformed phandle: %d", phnd);
446 parent = default_parent;
449 intrupt->parent = &parent->intr;
451 __expand_extended_intr(intrupt);
456 dt_load(ptr_t dtb_dropoff)
458 dtctx.reloacted_dtb = dtb_dropoff;
460 if (dtctx.fdt->magic != FDT_MAGIC) {
461 ERROR("invalid dtb, unexpected magic: 0x%x", dtctx.fdt->magic);
465 size_t str_off = le(dtctx.fdt->size_dt_strings);
466 dtctx.str_block = offset_t(dtb_dropoff, const char, str_off);
468 llist_init_head(&dtctx.nodes);
469 hashtable_init(dtctx.phnds_table);
472 struct fdt_token* tok;
473 struct dt_node_base *node, *prev;
475 struct dt_node_base* depth[16];
476 bool is_root_level, filled;
480 fdt_itbegin(&it, dtctx.fdt);
482 while (fdt_itnext(&it)) {
483 is_root_level = it.depth == 1;
485 if (it.depth >= 16) {
487 ERROR("strange dtb, too deep to dive.");
491 depth[it.depth] = NULL;
492 node = depth[it.depth - 1];
496 if (unlikely(is_root_level)) {
497 node = valloc(sizeof(struct dt_root));
501 node = valloc(sizeof(struct dt_node));
502 prev = depth[it.depth - 2];
504 __init_node_regular((struct dt_node*)node);
505 llist_append(&prev->children, &node->siblings);
508 llist_append(&dtctx.nodes, &node->nodes);
511 node->name = (const char*)&it.pos[1];
514 if (unlikely(is_root_level)) {
515 __fill_root(&it, (struct dt_root*)node);
518 __fill_node(&it, (struct dt_node*)node);
524 dtctx.root = (struct dt_root*)depth[0];
526 __resolve_phnd_references();
532 __name_starts_with(struct dt_node_base* node, const char* name)
535 const char* be_matched = node->name;
537 while (be_matched[i] && name[i])
539 if (be_matched[i] != name[i]) {
548 dt_resolve_phandle(dt_phnd_t phandle)
550 struct dt_node_base *pos, *n;
551 hashtable_hash_foreach(dtctx.phnds_table, phandle, pos, n, phnd_link)
553 if (pos->phandle == phandle) {
554 return (struct dt_node*)pos;
562 dt_begin_find(struct dt_node_iter* iter,
563 struct dt_node* node, const char* name)
565 node = node ? : (struct dt_node*)dtctx.root;
567 iter->head = &node->base;
568 iter->matched = NULL;
571 struct dt_node_base *pos, *n;
572 llist_for_each(pos, n, &node->base.children, siblings)
574 if (__name_starts_with(pos, name)) {
582 dt_find_next(struct dt_node_iter* iter,
583 struct dt_node_base** matched)
585 if (!dt_found_any(iter)) {
589 struct dt_node_base *pos, *head;
595 while (&pos->siblings != &head->children)
597 pos = list_next(pos, struct dt_node_base, siblings);
599 if (!__name_starts_with(pos, iter->name)) {
611 dt_getprop(struct dt_node* node, const char* name)
613 struct hstr hashed_name;
614 struct dt_prop *pos, *n;
617 hashed_name = HSTR(name, strlen(name));
618 hstr_rehash(&hashed_name, HSTR_FULL_HASH);
619 hash = hashed_name.hash;
621 hashtable_hash_foreach(node->base._op_bucket, hash, pos, n, ht)
623 if (HSTR_EQ(&pos->key, &hashed_name)) {