aboutsummaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/core')
-rw-r--r--drivers/core/Kconfig14
-rw-r--r--drivers/core/fdtaddr.c6
-rw-r--r--drivers/core/of_access.c65
-rw-r--r--drivers/core/ofnode.c183
-rw-r--r--drivers/core/read.c6
-rw-r--r--drivers/core/util.c2
6 files changed, 252 insertions, 24 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index f0d848f45d..fe5c41d57e 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -14,7 +14,7 @@ config SPL_DM
help
Enable driver model in SPL. You will need to provide a
suitable malloc() implementation. If you are not using the
- full malloc() enabled by CFG_SYS_SPL_MALLOC_START,
+ full malloc() enabled by CFG_SPL_SYS_MALLOC_START,
consider using CONFIG_SPL_SYS_MALLOC_SIMPLE. In that case you
must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size.
In most cases driver model will only allocate a few uclasses
@@ -27,12 +27,12 @@ config TPL_DM
help
Enable driver model in TPL. You will need to provide a
suitable malloc() implementation. If you are not using the
- full malloc() enabled by CFG_SYS_SPL_MALLOC_START,
+ full malloc() enabled by CFG_TPL_SYS_MALLOC_START,
consider using CONFIG_TPL_SYS_MALLOC_SIMPLE. In that case you
- must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size.
+ must provide CONFIG_TPL_SYS_MALLOC_F_LEN to set the size.
In most cases driver model will only allocate a few uclasses
- and devices in SPL, so 1KB should be enough. See
- CONFIG_SPL_SYS_MALLOC_F_LEN for more details on how to enable it.
+ and devices in TPL, so 1KB should be enough. See
+ CONFIG_TPL_SYS_MALLOC_F_LEN for more details on how to enable it.
Disable this for very small implementations.
config VPL_DM
@@ -42,8 +42,8 @@ config VPL_DM
help
Enable driver model in VPL. You will need to provide a
suitable malloc() implementation. If you are not using the
- full malloc() enabled by CFG_SYS_SPL_MALLOC_START,
- consider using CONFIG_SPL_SYS_MALLOC_SIMPLE.
+ full malloc() enabled by CFG_TPL_SYS_MALLOC_START,
+ consider using CONFIG_TPL_SYS_MALLOC_SIMPLE.
config DM_WARN
bool "Enable warnings in driver model"
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
index 546db675aa..b79d138c41 100644
--- a/drivers/core/fdtaddr.c
+++ b/drivers/core/fdtaddr.c
@@ -215,7 +215,7 @@ void *devfdt_map_physmem(const struct udevice *dev, unsigned long size)
return map_physmem(addr, size, MAP_NOCACHE);
}
-fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
+fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep)
{
ulong addr;
@@ -226,12 +226,12 @@ fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
int ret;
ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32,
- "reg", &pci_addr);
+ "reg", &pci_addr, sizep);
if (ret) {
/* try if there is any i/o-mapped register */
ret = ofnode_read_pci_addr(dev_ofnode(dev),
FDT_PCI_SPACE_IO, "reg",
- &pci_addr);
+ &pci_addr, sizep);
if (ret)
return FDT_ADDR_T_NONE;
}
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index 1bb4d8eab7..c8db743f52 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -1040,3 +1040,68 @@ int of_add_subnode(struct device_node *parent, const char *name, int len,
return 0;
}
+
+int __of_remove_property(struct device_node *np, struct property *prop)
+{
+ struct property **next;
+
+ for (next = &np->properties; *next; next = &(*next)->next) {
+ if (*next == prop)
+ break;
+ }
+ if (!*next)
+ return -ENODEV;
+
+ /* found the node */
+ *next = prop->next;
+
+ return 0;
+}
+
+int of_remove_property(struct device_node *np, struct property *prop)
+{
+ int rc;
+
+ mutex_lock(&of_mutex);
+
+ rc = __of_remove_property(np, prop);
+
+ mutex_unlock(&of_mutex);
+
+ return rc;
+}
+
+int of_remove_node(struct device_node *to_remove)
+{
+ struct device_node *parent = to_remove->parent;
+ struct device_node *np, *prev;
+
+ if (!parent)
+ return -EPERM;
+ prev = NULL;
+ __for_each_child_of_node(parent, np) {
+ if (np == to_remove)
+ break;
+ prev = np;
+ }
+ if (!np)
+ return -EFAULT;
+
+ /* if there is a previous node, link it to this one's sibling */
+ if (prev)
+ prev->sibling = np->sibling;
+ else
+ parent->child = np->sibling;
+
+ /*
+ * don't free it, since if this is an unflattened tree, all the memory
+ * was alloced in one block; this pointer will be somewhere in the
+ * middle of that
+ *
+ * TODO(sjg@chromium.org): Consider marking nodes as 'allocated'?
+ *
+ * free(np);
+ */
+
+ return 0;
+}
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;
+}
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 49066b59cd..419013451f 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -405,13 +405,15 @@ int dev_read_alias_highest_id(const char *stem)
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
}
-fdt_addr_t dev_read_addr_pci(const struct udevice *dev)
+fdt_addr_t dev_read_addr_pci(const struct udevice *dev, fdt_size_t *sizep)
{
ulong addr;
addr = dev_read_addr(dev);
+ if (sizep)
+ *sizep = 0;
if (addr == FDT_ADDR_T_NONE && !of_live_active())
- addr = devfdt_get_addr_pci(dev);
+ addr = devfdt_get_addr_pci(dev, sizep);
return addr;
}
diff --git a/drivers/core/util.c b/drivers/core/util.c
index aa60fdd15b..81497df85f 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -30,7 +30,7 @@ int pci_get_devfn(struct udevice *dev)
/* Extract the devfn from fdt_pci_addr */
ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
- "reg", &addr);
+ "reg", &addr, NULL);
if (ret) {
if (ret != -ENOENT)
return -EINVAL;