diff options
Diffstat (limited to 'drivers/core')
-rw-r--r-- | drivers/core/Kconfig | 4 | ||||
-rw-r--r-- | drivers/core/Makefile | 5 | ||||
-rw-r--r-- | drivers/core/device-remove.c | 22 | ||||
-rw-r--r-- | drivers/core/device.c | 34 | ||||
-rw-r--r-- | drivers/core/dump.c | 96 | ||||
-rw-r--r-- | drivers/core/lists.c | 6 | ||||
-rw-r--r-- | drivers/core/regmap.c | 86 | ||||
-rw-r--r-- | drivers/core/syscon-uclass.c | 76 | ||||
-rw-r--r-- | drivers/core/uclass.c | 4 |
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)); |