diff options
Diffstat (limited to 'drivers/core/ofnode.c')
-rw-r--r-- | drivers/core/ofnode.c | 183 |
1 files changed, 172 insertions, 11 deletions
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 2cafa7bca5..29a4294510 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -47,6 +47,17 @@ static int oftree_find(const void *fdt) return -1; } +static int check_tree_count(void) +{ + if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) { + log_warning("Too many registered device trees (max %d)\n", + CONFIG_OFNODE_MULTI_TREE_MAX); + return -E2BIG; + } + + return 0; +} + static oftree oftree_ensure(void *fdt) { oftree tree; @@ -69,11 +80,8 @@ static oftree oftree_ensure(void *fdt) if (gd->flags & GD_FLG_RELOC) { i = oftree_find(fdt); if (i == -1) { - if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) { - log_warning("Too many registered device trees (max %d)\n", - CONFIG_OFNODE_MULTI_TREE_MAX); + if (check_tree_count()) return oftree_null(); - } /* register the new tree */ i = oftree_count++; @@ -92,6 +100,41 @@ static oftree oftree_ensure(void *fdt) return tree; } +int oftree_new(oftree *treep) +{ + oftree tree = oftree_null(); + int ret; + + if (of_live_active()) { + struct device_node *root; + + ret = of_live_create_empty(&root); + if (ret) + return log_msg_ret("liv", ret); + tree = oftree_from_np(root); + } else { + const int size = 1024; + void *fdt; + + ret = check_tree_count(); + if (ret) + return log_msg_ret("fla", ret); + + /* register the new tree with a small size */ + fdt = malloc(size); + if (!fdt) + return log_msg_ret("fla", -ENOMEM); + ret = fdt_create_empty_tree(fdt, size); + if (ret) + return log_msg_ret("fla", -EINVAL); + oftree_list[oftree_count++] = fdt; + tree.fdt = fdt; + } + *treep = tree; + + return 0; +} + void oftree_dispose(oftree tree) { if (of_live_active()) @@ -193,8 +236,31 @@ static inline int oftree_find(const void *fdt) return 0; } +int oftree_new(oftree *treep) +{ + return -ENOSYS; +} + #endif /* OFNODE_MULTI_TREE */ +int oftree_to_fdt(oftree tree, struct abuf *buf) +{ + int ret; + + if (of_live_active()) { + ret = of_live_flatten(ofnode_to_np(oftree_root(tree)), buf); + if (ret) + return log_msg_ret("flt", ret); + } else { + void *fdt = oftree_lookup_fdt(tree); + + abuf_init(buf); + abuf_set(buf, fdt, fdt_totalsize(fdt)); + } + + return 0; +} + /** * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree) * @@ -425,12 +491,12 @@ u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def) bool ofnode_read_bool(ofnode node, const char *propname) { - const void *prop; + bool prop; assert(ofnode_valid(node)); debug("%s: %s: ", __func__, propname); - prop = ofnode_get_property(node, propname, NULL); + prop = ofnode_has_property(node, propname); debug("%s\n", prop ? "true" : "false"); @@ -1102,6 +1168,14 @@ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp) propname, lenp); } +bool ofnode_has_property(ofnode node, const char *propname) +{ + if (ofnode_is_np(node)) + return of_find_property(ofnode_to_np(node), propname, NULL); + else + return ofnode_get_property(node, propname, NULL); +} + int ofnode_first_property(ofnode node, struct ofprop *prop) { prop->node = node; @@ -1196,7 +1270,8 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, } int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, - const char *propname, struct fdt_pci_addr *addr) + const char *propname, struct fdt_pci_addr *addr, + fdt_size_t *size) { const fdt32_t *cell; int len; @@ -1224,14 +1299,18 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, (ulong)fdt32_to_cpu(cell[1]), (ulong)fdt32_to_cpu(cell[2])); if ((fdt32_to_cpu(*cell) & type) == type) { + const unaligned_fdt64_t *ptr; + addr->phys_hi = fdt32_to_cpu(cell[0]); addr->phys_mid = fdt32_to_cpu(cell[1]); addr->phys_lo = fdt32_to_cpu(cell[2]); + ptr = (const unaligned_fdt64_t *)(cell + 3); + if (size) + *size = fdt64_to_cpu(*ptr); break; } - cell += (FDT_PCI_ADDR_CELLS + - FDT_PCI_SIZE_CELLS); + cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS; } if (i == num) { @@ -1547,7 +1626,46 @@ int ofnode_write_u32(ofnode node, const char *propname, u32 value) return -ENOMEM; *val = cpu_to_fdt32(value); - return ofnode_write_prop(node, propname, val, sizeof(value), false); + return ofnode_write_prop(node, propname, val, sizeof(value), true); +} + +int ofnode_write_u64(ofnode node, const char *propname, u64 value) +{ + fdt64_t *val; + + assert(ofnode_valid(node)); + + log_debug("%s = %llx", propname, (unsigned long long)value); + val = malloc(sizeof(*val)); + if (!val) + return -ENOMEM; + *val = cpu_to_fdt64(value); + + return ofnode_write_prop(node, propname, val, sizeof(value), true); +} + +int ofnode_write_bool(ofnode node, const char *propname, bool value) +{ + if (value) + return ofnode_write_prop(node, propname, NULL, 0, false); + else + return ofnode_delete_prop(node, propname); +} + +int ofnode_delete_prop(ofnode node, const char *propname) +{ + if (ofnode_is_np(node)) { + struct property *prop; + int len; + + prop = of_find_property(ofnode_to_np(node), propname, &len); + if (prop) + return of_remove_property(ofnode_to_np(node), prop); + return 0; + } else { + return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node), + propname); + } } int ofnode_set_enabled(ofnode node, bool value) @@ -1731,7 +1849,30 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep) return ret; /* 0 or -EEXIST */ } -int ofnode_copy_props(ofnode src, ofnode dst) +int ofnode_delete(ofnode *nodep) +{ + ofnode node = *nodep; + int ret; + + assert(ofnode_valid(node)); + if (ofnode_is_np(node)) { + ret = of_remove_node(ofnode_to_np(node)); + } else { + void *fdt = ofnode_to_fdt(node); + int offset = ofnode_to_offset(node); + + ret = fdt_del_node(fdt, offset); + if (ret) + ret = -EFAULT; + } + if (ret) + return ret; + *nodep = ofnode_null(); + + return 0; +} + +int ofnode_copy_props(ofnode dst, ofnode src) { struct ofprop prop; @@ -1754,3 +1895,23 @@ int ofnode_copy_props(ofnode src, ofnode dst) return 0; } + +int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src, + ofnode *nodep) +{ + ofnode node; + int ret; + + ret = ofnode_add_subnode(dst_parent, name, &node); + if (ret) { + if (ret == -EEXIST) + *nodep = node; + return log_msg_ret("add", ret); + } + ret = ofnode_copy_props(node, src); + if (ret) + return log_msg_ret("cpy", ret); + *nodep = node; + + return 0; +} |