summaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/core')
-rw-r--r--drivers/core/Kconfig4
-rw-r--r--drivers/core/Makefile5
-rw-r--r--drivers/core/device-remove.c22
-rw-r--r--drivers/core/device.c34
-rw-r--r--drivers/core/dump.c96
-rw-r--r--drivers/core/lists.c6
-rw-r--r--drivers/core/regmap.c86
-rw-r--r--drivers/core/syscon-uclass.c76
-rw-r--r--drivers/core/uclass.c4
9 files changed, 304 insertions, 29 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 2861b430795..e40372dd753 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -38,6 +38,10 @@ config DM_DEVICE_REMOVE
device. This is not normally required in SPL, so by default this
option is disabled for SPL.
+ Note that this may have undesirable results in the USB subsystem as
+ it causes unplugged devices to linger around in the dm-tree, and it
+ causes USB host controllers to not be stopped when booting the OS.
+
config DM_STDIO
bool "Support stdio registration"
depends on DM
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index a3fec385039..5c2ead870b0 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -4,8 +4,11 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-$(CONFIG_DM) += device.o lists.o root.o uclass.o util.o
+obj-y += device.o lists.o root.o uclass.o util.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_OF_CONTROL) += simple-bus.o
endif
obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o
+obj-$(CONFIG_DM) += dump.o
+obj-$(CONFIG_OF_CONTROL) += regmap.o
+obj-$(CONFIG_OF_CONTROL) += syscon-uclass.o
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 6a16b4f690f..6b87f865e40 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -18,16 +18,7 @@
#include <dm/uclass-internal.h>
#include <dm/util.h>
-/**
- * device_chld_unbind() - Unbind all device's children from the device
- *
- * On error, the function continues to unbind all children, and reports the
- * first error.
- *
- * @dev: The device that is to be stripped of its children
- * @return 0 on success, -ve on error
- */
-static int device_chld_unbind(struct udevice *dev)
+int device_unbind_children(struct udevice *dev)
{
struct udevice *pos, *n;
int ret, saved_ret = 0;
@@ -43,12 +34,7 @@ static int device_chld_unbind(struct udevice *dev)
return saved_ret;
}
-/**
- * device_chld_remove() - Stop all device's children
- * @dev: The device whose children are to be removed
- * @return 0 on success, -ve on error
- */
-static int device_chld_remove(struct udevice *dev)
+int device_remove_children(struct udevice *dev)
{
struct udevice *pos, *n;
int ret;
@@ -84,7 +70,7 @@ int device_unbind(struct udevice *dev)
return ret;
}
- ret = device_chld_unbind(dev);
+ ret = device_unbind_children(dev);
if (ret)
return ret;
@@ -159,7 +145,7 @@ int device_remove(struct udevice *dev)
if (ret)
return ret;
- ret = device_chld_remove(dev);
+ ret = device_remove_children(dev);
if (ret)
goto err;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 85fd1fc7350..51b1b44e5b0 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -284,7 +284,6 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
goto fail;
}
- dev->flags |= DM_FLAG_ACTIVATED;
if (drv->probe) {
ret = drv->probe(dev);
if (ret) {
@@ -330,7 +329,7 @@ void *dev_get_platdata(struct udevice *dev)
void *dev_get_parent_platdata(struct udevice *dev)
{
if (!dev) {
- dm_warn("%s: null device", __func__);
+ dm_warn("%s: null device\n", __func__);
return NULL;
}
@@ -340,7 +339,7 @@ void *dev_get_parent_platdata(struct udevice *dev)
void *dev_get_uclass_platdata(struct udevice *dev)
{
if (!dev) {
- dm_warn("%s: null device", __func__);
+ dm_warn("%s: null device\n", __func__);
return NULL;
}
@@ -459,17 +458,42 @@ int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
return -ENODEV;
}
-int device_get_child_by_of_offset(struct udevice *parent, int seq,
+int device_get_child_by_of_offset(struct udevice *parent, int node,
struct udevice **devp)
{
struct udevice *dev;
int ret;
*devp = NULL;
- ret = device_find_child_by_of_offset(parent, seq, &dev);
+ ret = device_find_child_by_of_offset(parent, node, &dev);
return device_get_device_tail(dev, ret, devp);
}
+static struct udevice *_device_find_global_by_of_offset(struct udevice *parent,
+ int of_offset)
+{
+ struct udevice *dev, *found;
+
+ if (parent->of_offset == of_offset)
+ return parent;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ found = _device_find_global_by_of_offset(dev, of_offset);
+ if (found)
+ return found;
+ }
+
+ return NULL;
+}
+
+int device_get_global_by_of_offset(int of_offset, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ dev = _device_find_global_by_of_offset(gd->dm_root, of_offset);
+ return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
+}
+
int device_find_first_child(struct udevice *parent, struct udevice **devp)
{
if (list_empty(&parent->child_head)) {
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
new file mode 100644
index 00000000000..fd4596ee68b
--- /dev/null
+++ b/drivers/core/dump.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <dm/root.h>
+
+static void show_devices(struct udevice *dev, int depth, int last_flag)
+{
+ int i, is_last;
+ struct udevice *child;
+ char class_name[12];
+
+ /* print the first 11 characters to not break the tree-format. */
+ strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name));
+ printf(" %-11s [ %c ] ", class_name,
+ dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ');
+
+ for (i = depth; i >= 0; i--) {
+ is_last = (last_flag >> i) & 1;
+ if (i) {
+ if (is_last)
+ printf(" ");
+ else
+ printf("| ");
+ } else {
+ if (is_last)
+ printf("`-- ");
+ else
+ printf("|-- ");
+ }
+ }
+
+ printf("%s\n", dev->name);
+
+ list_for_each_entry(child, &dev->child_head, sibling_node) {
+ is_last = list_is_last(&child->sibling_node, &dev->child_head);
+ show_devices(child, depth + 1, (last_flag << 1) | is_last);
+ }
+}
+
+void dm_dump_all(void)
+{
+ struct udevice *root;
+
+ root = dm_root();
+ if (root) {
+ printf(" Class Probed Name\n");
+ printf("----------------------------------------\n");
+ show_devices(root, -1, 0);
+ }
+}
+
+/**
+ * dm_display_line() - Display information about a single device
+ *
+ * Displays a single line of information with an option prefix
+ *
+ * @dev: Device to display
+ */
+static void dm_display_line(struct udevice *dev)
+{
+ printf("- %c %s @ %08lx",
+ dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
+ dev->name, (ulong)map_to_sysmem(dev));
+ if (dev->seq != -1 || dev->req_seq != -1)
+ printf(", seq %d, (req %d)", dev->seq, dev->req_seq);
+ puts("\n");
+}
+
+void dm_dump_uclass(void)
+{
+ struct uclass *uc;
+ int ret;
+ int id;
+
+ for (id = 0; id < UCLASS_COUNT; id++) {
+ struct udevice *dev;
+
+ ret = uclass_get(id, &uc);
+ if (ret)
+ continue;
+
+ printf("uclass %d: %s\n", id, uc->uc_drv->name);
+ if (list_empty(&uc->dev_head))
+ continue;
+ list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+ dm_display_line(dev);
+ }
+ puts("\n");
+ }
+}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 0c49d99f47e..2e52500ef25 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -86,13 +86,13 @@ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
drv = lists_driver_lookup_name(drv_name);
if (!drv) {
- printf("Cannot find driver '%s'\n", drv_name);
+ debug("Cannot find driver '%s'\n", drv_name);
return -ENOENT;
}
ret = device_bind(parent, drv, dev_name, NULL, node, devp);
if (ret) {
- printf("Cannot create device named '%s' (err=%d)\n",
- dev_name, ret);
+ debug("Cannot create device named '%s' (err=%d)\n",
+ dev_name, ret);
return ret;
}
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
new file mode 100644
index 00000000000..519832f1733
--- /dev/null
+++ b/drivers/core/regmap.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <regmap.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
+{
+ const void *blob = gd->fdt_blob;
+ struct regmap_range *range;
+ const fdt32_t *cell;
+ struct regmap *map;
+ int count;
+ int addr_len, size_len, both_len;
+ int parent;
+ int len;
+
+ parent = dev->parent->of_offset;
+ addr_len = fdt_address_cells(blob, parent);
+ size_len = fdt_size_cells(blob, parent);
+ both_len = addr_len + size_len;
+
+ cell = fdt_getprop(blob, dev->of_offset, "reg", &len);
+ len /= sizeof(*cell);
+ count = len / both_len;
+ if (!cell || !count)
+ return -EINVAL;
+
+ map = malloc(sizeof(struct regmap));
+ if (!map)
+ return -ENOMEM;
+
+ if (count <= 1) {
+ map->range = &map->base_range;
+ } else {
+ map->range = malloc(count * sizeof(struct regmap_range));
+ if (!map->range) {
+ free(map);
+ return -ENOMEM;
+ }
+ }
+
+ map->base = fdtdec_get_number(cell, addr_len);
+ map->range_count = count;
+
+ for (range = map->range; count > 0;
+ count--, cell += both_len, range++) {
+ range->start = fdtdec_get_number(cell, addr_len);
+ range->size = fdtdec_get_number(cell + addr_len, size_len);
+ }
+
+ *mapp = map;
+
+ return 0;
+}
+
+void *regmap_get_range(struct regmap *map, unsigned int range_num)
+{
+ struct regmap_range *range;
+
+ if (range_num >= map->range_count)
+ return NULL;
+ range = &map->range[range_num];
+
+ return map_sysmem(range->start, range->size);
+}
+
+int regmap_uninit(struct regmap *map)
+{
+ if (map->range_count > 1)
+ free(map->range);
+ free(map);
+
+ return 0;
+}
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
new file mode 100644
index 00000000000..686c32056ec
--- /dev/null
+++ b/drivers/core/syscon-uclass.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <syscon.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/err.h>
+
+struct regmap *syscon_get_regmap(struct udevice *dev)
+{
+ struct syscon_uc_info *priv;
+
+ if (device_get_uclass_id(dev) != UCLASS_SYSCON)
+ return ERR_PTR(-ENOEXEC);
+ priv = dev_get_uclass_priv(dev);
+ return priv->regmap;
+}
+
+static int syscon_pre_probe(struct udevice *dev)
+{
+ struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
+
+ return regmap_init_mem(dev, &priv->regmap);
+}
+
+struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_SYSCON, &uc);
+ if (ret)
+ return ERR_PTR(ret);
+ uclass_foreach_dev(dev, uc) {
+ if (dev->driver_data == driver_data) {
+ struct syscon_uc_info *priv;
+ int ret;
+
+ ret = device_probe(dev);
+ if (ret)
+ return ERR_PTR(ret);
+ priv = dev_get_uclass_priv(dev);
+
+ return priv->regmap;
+ }
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+void *syscon_get_first_range(ulong driver_data)
+{
+ struct regmap *map;
+
+ map = syscon_get_regmap_by_driver_data(driver_data);
+ if (IS_ERR(map))
+ return map;
+ return regmap_get_range(map, 0);
+}
+
+UCLASS_DRIVER(syscon) = {
+ .id = UCLASS_SYSCON,
+ .name = "syscon",
+ .per_device_auto_alloc_size = sizeof(struct syscon_uc_info),
+ .pre_probe = syscon_pre_probe,
+};
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 7de817324b9..aba98801fd4 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -56,8 +56,8 @@ static int uclass_add(enum uclass_id id, struct uclass **ucp)
*ucp = NULL;
uc_drv = lists_uclass_lookup(id);
if (!uc_drv) {
- dm_warn("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
- id);
+ debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
+ id);
return -ENOENT;
}
uc = calloc(1, sizeof(*uc));