aboutsummaryrefslogtreecommitdiff
path: root/drivers/core/ofnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/core/ofnode.c')
-rw-r--r--drivers/core/ofnode.c183
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;
+}