--- /dev/null
+#ifndef __LUNAIX_DEVTREE_INTERNAL_H
+#define __LUNAIX_DEVTREE_INTERNAL_H
+
+#include <hal/devtree.h>
+
+bool
+parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node);
+
+#endif /* __LUNAIX_DEVTREE_H */
#include <klibc/string.h>
-#include <hal/devtree.h>
+#include "devtree.h"
LOG_MODULE("dtb")
return true;
}
-static bool
-__parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node)
-{
- if (propeq(it, "interrupt-map")) {
- __mkprop_ptr(it, &node->intr_map);
- }
-
- else if (propeq(it, "interrupt-map-mask")) {
- __mkprop_ptr(it, &node->intr_map_mask);
- }
-
- else if (propeq(it, "interrupt-parent")) {
- node->parent_hnd = __prop_getu32(it);
- }
-
- else if (propeq(it, "interrupt-extended")) {
- node->intr.extended = true;
- __mkprop_ptr(it, &node->intr.arr);
- }
-
- else if (!node->intr.extended && propeq(it, "interrupts")) {
- __mkprop_ptr(it, &node->intr.arr);
- }
-
- else {
- return false;
- }
-
- return true;
-}
-
static bool
__parse_stdflags(struct fdt_iter* it, struct dt_node_base* node)
{
{
hashtable_init(node->_op_bucket);
llist_init_head(&node->children);
+
+ if (node->parent)
+ node->_std = node->parent->_std;
}
static inline void
}
arr = intrupt->intr.arr;
- node = DT_NODE(intrupt);
+ node = INTR_TO_DTNODE(intrupt);
llist_init_head(&intrupt->intr.values);
dt_decode(&it, &node->base, &arr, 1);
dt_phnd_t phnd;
- while(dtprop_next(&it)) {
+ do {
phnd = dtprop_to_u32(it.prop_loc);
master = dt_resolve_phandle(phnd);
llist_append(&intrupt->intr.values, &intr_prop->props);
dtprop_next_n(&it, intr_prop->val.size);
- }
+
+ } while(dtprop_next(&it));
}
static void
llist_for_each(pos, n, &dtctx.nodes, nodes)
{
- node = (struct dt_node*)pos;
+ node = BASE_TO_DTNODE(pos);
intrupt = &node->intr;
+
if (!node->base.intr_c) {
continue;
}
}
}
+static void
+__resolve_inter_map()
+{
+ struct dt_node_base *pos, *n;
+
+ llist_for_each(pos, n, &dtctx.nodes, nodes)
+ {
+ resolve_interrupt_map(BASE_TO_DTNODE(pos));
+ }
+}
+
bool
dt_load(ptr_t dtb_dropoff)
{
if (!node) {
// need new node
if (unlikely(is_root_level)) {
- node = valloc(sizeof(struct dt_root));
+ node = vzalloc(sizeof(struct dt_root));
__init_node(node);
}
else {
- node = valloc(sizeof(struct dt_node));
+ node = vzalloc(sizeof(struct dt_node));
prev = depth[it.depth - 2];
+ node->parent = prev;
__init_node_regular((struct dt_node*)node);
llist_append(&prev->children, &node->siblings);
- node->parent = prev;
llist_append(&dtctx.nodes, &node->nodes);
}
dtctx.root = (struct dt_root*)depth[0];
__resolve_phnd_references();
+ __resolve_inter_map();
+
+ INFO("device tree loaded");
return true;
}
+struct dt_node*
+dt_resolve_phandle(dt_phnd_t phandle)
+{
+ struct dt_node_base *pos, *n;
+ hashtable_hash_foreach(dtctx.phnds_table, phandle, pos, n, phnd_link)
+ {
+ if (pos->phandle == phandle) {
+ return (struct dt_node*)pos;
+ }
+ }
+
+ return NULL;
+}
+
static bool
-__name_starts_with(struct dt_node_base* node, const char* name)
+__byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node)
{
int i = 0;
const char* be_matched = node->name;
+ const char* name = (const char*)iter->closure;
while (be_matched[i] && name[i])
{
if (be_matched[i] != name[i]) {
return false;
}
+
+ i++;
}
return true;
}
-struct dt_node*
-dt_resolve_phandle(dt_phnd_t phandle)
+void
+dt_begin_find_byname(struct dt_node_iter* iter,
+ struct dt_node* node, const char* name)
{
- struct dt_node_base *pos, *n;
- hashtable_hash_foreach(dtctx.phnds_table, phandle, pos, n, phnd_link)
- {
- if (pos->phandle == phandle) {
- return (struct dt_node*)pos;
- }
- }
-
- return NULL;
+ dt_begin_find(iter, node, __byname_predicate, name);
}
void
-dt_begin_find(struct dt_node_iter* iter,
- struct dt_node* node, const char* name)
+dt_begin_find(struct dt_node_iter* iter, struct dt_node* node,
+ node_predicate_t pred, void* closure)
{
node = node ? : (struct dt_node*)dtctx.root;
iter->head = &node->base;
iter->matched = NULL;
- iter->name = name;
+ iter->closure = closure;
+ iter->pred = pred;
struct dt_node_base *pos, *n;
llist_for_each(pos, n, &node->base.children, siblings)
{
- if (__name_starts_with(pos, name)) {
+ if (pred(iter, pos)) {
iter->matched = pos;
break;
}
{
pos = list_next(pos, struct dt_node_base, siblings);
- if (!__name_starts_with(pos, iter->name)) {
+ if (!iter->pred(iter, pos)) {
continue;
}
}
struct dt_prop_val*
-dt_getprop(struct dt_node* node, const char* name)
+dt_getprop(struct dt_node_base* base, const char* name)
{
struct hstr hashed_name;
struct dt_prop *pos, *n;
hstr_rehash(&hashed_name, HSTR_FULL_HASH);
hash = hashed_name.hash;
- hashtable_hash_foreach(node->base._op_bucket, hash, pos, n, ht)
+ hashtable_hash_foreach(base->_op_bucket, hash, pos, n, ht)
{
if (HSTR_EQ(&pos->key, &hashed_name)) {
return &pos->val;
--- /dev/null
+#include "devtree.h"
+
+#include <lunaix/mm/valloc.h>
+
+#include <klibc/string.h>
+
+static struct dt_intr_map*
+__get_map(struct dt_intr_node* node)
+{
+ if (!node->map) {
+ node->map = valloc(sizeof(struct dt_intr_map));
+
+ node->map->resolved = false;
+ llist_init_head(&node->map->mapent);
+
+ INTR_TO_DTNODE(node)->base.intr_neuxs = true;
+ }
+
+ return node->map;
+}
+
+static void
+__prepare_key(struct dt_intr_mapkey* key,
+ dt_enc_t key_raw, unsigned int keylen)
+{
+ *key = (struct dt_intr_mapkey) {
+ .val = valloc(keylen * sizeof(int)),
+ .size = keylen
+ };
+
+ memcpy(key->val, key_raw, keylen * sizeof(int));
+}
+
+static inline void
+__destory_key(struct dt_intr_mapkey* key)
+{
+ vfree(key->val);
+}
+
+static inline unsigned int
+__interrupt_keysize(struct dt_node_base* base)
+{
+ return base->addr_c + base->intr_c;
+}
+
+static void
+__mask_key(struct dt_intr_mapkey* k, struct dt_intr_mapkey* mask)
+{
+ for (int i = 0; i < k->size; i++)
+ {
+ k->val[i] &= mask->val[i];
+ }
+}
+
+static bool
+__compare_key(struct dt_intr_mapkey* k1, struct dt_intr_mapkey* k2)
+{
+ if (k1->size != k2->size) {
+ return false;
+ }
+
+ for (int i = 0; i < k1->size; i++)
+ {
+ if (k1->val[i] != k2->val[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static struct dt_node_base*
+__get_connected_nexus(struct dt_node_base* base)
+{
+ struct dt_node_base* current;
+
+ current = base;
+ while (current && !current->intr_neuxs) {
+ current = current->parent;
+ }
+
+ return current;
+}
+
+void
+resolve_interrupt_map(struct dt_node* node)
+{
+ struct dt_intr_node* inode;
+ struct dt_intr_map* imap;
+ struct dt_prop_iter iter;
+
+ struct dt_intr_mapent *ent;
+
+ unsigned int keysize, parent_keysize;
+ unsigned int advance;
+ dt_phnd_t parent_hnd;
+
+ inode = &node->intr;
+ if (likely(!inode->map)) {
+ return;
+ }
+
+ imap = inode->map;
+ keysize = __interrupt_keysize(&node->base);
+
+ __prepare_key(&imap->key_mask, imap->raw_mask.encoded, keysize);
+
+ dt_decode(&iter, &node->base, &imap->raw, 1);
+
+ advance = 0;
+ do
+ {
+ advance = keysize;
+ ent = valloc(sizeof(*ent));
+
+ __prepare_key(&ent->key, iter.prop_loc, advance);
+ __mask_key(&ent->key, &imap->key_mask);
+
+ parent_hnd = dtprop_to_phnd(dtprop_extract(&iter, advance));
+ ent->parent = &dt_resolve_phandle(parent_hnd)->base;
+
+ advance++;
+ parent_keysize = __interrupt_keysize(ent->parent);
+
+ ent->parent_props.encoded = dtprop_extract(&iter, advance);
+ ent->parent_props.size = parent_keysize;
+
+ advance += parent_keysize;
+
+ llist_append(&imap->mapent, &ent->ents);
+
+ } while (dtprop_next_n(&iter, advance));
+
+ imap->resolved = true;
+}
+
+struct dt_prop_val*
+resolve_interrupt(struct dt_node* node)
+{
+ struct dt_node_base* nexus;
+ struct dt_intr_node* i_nexus, *i_node;
+ struct dt_intr_mapkey key;
+ unsigned int keylen;
+
+ if (!node->intr.intr.valid) {
+ return NULL;
+ }
+
+ nexus = __get_connected_nexus(&node->base);
+ i_nexus = &BASE_TO_DTNODE(nexus)->intr;
+ i_node = &node->intr;
+
+ if (!nexus) {
+ return &i_node->intr.arr;
+ }
+
+ keylen = nexus->addr_c + nexus->intr_c;
+ key = (struct dt_intr_mapkey) {
+ .val = valloc(keylen * sizeof(int)),
+ .size = keylen
+ };
+
+ memcpy( key.val,
+ node->reg.encoded, nexus->addr_c * sizeof(int));
+
+ memcpy(&key.val[nexus->addr_c],
+ i_node->intr.arr.encoded, nexus->intr_c * sizeof(int));
+
+ __mask_key(&key, &i_nexus->map->key_mask);
+
+ struct dt_intr_mapent *pos, *n;
+
+ llist_for_each(pos, n, &i_nexus->map->mapent, ents) {
+ if (__compare_key(&pos->key, &key))
+ {
+ return &pos->parent_props;
+ }
+ }
+}
+
+bool
+parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node)
+{
+ struct dt_intr_map* map;
+
+ if (propeq(it, "interrupt-map")) {
+ map = __get_map(node);
+ __mkprop_ptr(it, &map->raw);
+ }
+
+ else if (propeq(it, "interrupt-map-mask")) {
+ map = __get_map(node);
+ __mkprop_ptr(it, &map->raw_mask);
+ }
+
+ else if (propeq(it, "interrupt-parent")) {
+ node->parent_hnd = __prop_getu32(it);
+ }
+
+ else if (propeq(it, "interrupt-extended")) {
+ node->intr.extended = true;
+ __mkprop_ptr(it, &node->intr.arr);
+ }
+
+ else if (!node->intr.extended && propeq(it, "interrupts")) {
+ node->intr.valid = true;
+ __mkprop_ptr(it, &node->intr.arr);
+ }
+
+ else {
+ return false;
+ }
+
+ return true;
+}
\ No newline at end of file
typedef unsigned int* dt_enc_t;
typedef unsigned int dt_phnd_t;
+typedef bool (*node_predicate_t)(struct dt_node_iter*, struct dt_node*);
+
#define PHND_NULL ((dt_phnd_t)-1)
bool dma_coherent : 1;
bool dma_ncoherent : 1;
bool intr_controll : 1;
+ bool intr_neuxs : 1;
unsigned int other : 29;
};
unsigned int flags;
struct hbucket other_props[0];
struct hbucket _op_bucket[8];
};
+
+ void* obj;
};
struct dt_root
struct dt_intr_prop;
+struct dt_intr_mapkey
+{
+ unsigned int* val;
+ unsigned int size;
+};
+
+struct dt_intr_mapent
+{
+ struct llist_header ents;
+
+ struct dt_intr_mapkey key;
+
+ struct dt_node_base* parent;
+ struct dt_prop_val parent_props;
+};
+
+struct dt_intr_map
+{
+ struct dt_prop_val raw;
+ struct dt_prop_val raw_mask;
+
+ struct dt_intr_mapkey key_mask;
+ struct llist_header mapent;
+
+ bool resolved;
+};
+
struct dt_intr_node
{
union {
struct {
bool extended;
+ bool valid;
union {
struct dt_prop_val arr;
struct llist_header values;
};
} intr;
- struct dt_prop_val intr_map;
- struct dt_prop_val intr_map_mask;
+ struct dt_intr_map* map;
};
-#define DT_NODE(intr_node) \
+#define INTR_TO_DTNODE(intr_node) \
(container_of(intr_node, struct dt_node, intr))
+#define BASE_TO_DTNODE(base_node) \
+ (container_of(base_node, struct dt_node, base))
struct dt_node
{
{
struct dt_node_base* head;
struct dt_node_base* matched;
- const char *name;
+ void* closure;
+ node_predicate_t pred;
};
#define dtnode_child_foreach(node_base, pos, n) \
dt_resolve_phandle(dt_phnd_t phandle);
struct dt_prop_val*
-dt_getprop(struct dt_node* node, const char* name);
+dt_getprop(struct dt_node_base* base, const char* name);
+
+void
+dt_begin_find_byname(struct dt_node_iter* iter,
+ struct dt_node* node, const char* name);
+
+void
+dt_begin_find(struct dt_node_iter* iter, struct dt_node* node,
+ node_predicate_t pred, void* closure);
+
+struct dt_prop_val*
+resolve_interrupt(struct dt_node* node);
void
-dt_begin_find(struct dt_node_iter* iter,
- struct dt_node* node, const char* name);
+resolve_interrupt_map(struct dt_node* node);
+
+static inline void
+dt_end_find(struct dt_node_iter* iter)
+{
+ // currently do nothing, keep only for semantic
+}
bool
dt_find_next(struct dt_node_iter* iter,
}
+static inline void
+dt_bind_object(struct dt_node_base* base, void* obj)
+{
+ base->obj = obj;
+}
+
+static inline bool
+dt_has_binding(struct dt_node_base* base)
+{
+ return base->obj != NULL;
+}
+
+#define dt_binding_of(node_base, type) \
+ ((type)(node_base)->obj)
+
static inline char*
fdtit_prop_key(struct fdt_iter* fdti)
{
dt_decode(dtpi, &(node)->base, &(node)->field, \
(node)->base.sz_c * 2 + (node)->base.addr_c);
-static inline void
-dt_decode_intrmap(struct dt_prop_iter* dtpi,
- struct dt_intr_node* intr_node)
-{
- unsigned int size;
- struct dt_node* node;
- struct dt_node_base* base;
-
- node = DT_NODE(intr_node);
- base = &node->base;
- size = (base->addr_c + base->intr_c) * 2 + 1;
-
- dt_decode(dtpi, base, &intr_node->intr_map, size);
-}
-
#define dtprop_off(dtpi) \
(unsigned int)(\
__ptr(dtpi->prop_loc_next) - __ptr(dtpi->prop->encoded) \
return le64(*(u64_t*)enc_val);
}
+static inline u32_t
+dtprop_u32_at(struct dt_prop_iter* dtpi, int index)
+{
+ return dtprop_to_u32(dtprop_extract(dtpi, index));
+}
+
+static inline u32_t
+dtprop_u64_at(struct dt_prop_iter* dtpi, int index)
+{
+ return dtprop_to_u64(dtprop_extract(dtpi, index));
+}
+
static inline dt_enc_t
dtprop_reg_addr(struct dt_prop_iter* dtpi)
{
return dtprop_extract(dtpi, dtpi->node->addr_c * 2);
}
-static inline dt_enc_t
-dtprop_intr_cuaddr(struct dt_prop_iter* dtpi)
-{
- return dtprop_extract(dtpi, 0);
-}
-
-static inline dt_enc_t
-dtprop_intr_cispec(struct dt_prop_iter* dtpi)
-{
- return dtprop_extract(dtpi, dtpi->node->addr_c);
-}
-
-static inline struct dt_intr_node*
-dtprop_intr_parent(struct dt_prop_iter* dtpi)
-{
- unsigned off;
- struct dt_node* node;
- dt_enc_t enc_val;
-
- off = dtpi->node->addr_c + dtpi->node->intr_c;
- enc_val = dtprop_extract(dtpi, off);
- node = dt_resolve_phandle(dtprop_to_phnd(enc_val));
-
- return &node->intr;
-}
-
-static inline dt_enc_t
-dtprop_intr_puaddr(struct dt_prop_iter* dtpi)
-{
- unsigned off;
-
- off = dtpi->node->addr_c + dtpi->node->intr_c + 1;
- return dtprop_extract(dtpi, off);
-}
-
-static inline dt_enc_t
-dtprop_intr_pispec(struct dt_prop_iter* dtpi)
-{
- unsigned off;
-
- off = dtpi->node->addr_c * 2 + dtpi->node->intr_c + 1;
- return dtprop_extract(dtpi, off);
-}
-
#endif /* __LUNAIX_DEVTREE_H */