diff --git a/Makefile b/Makefile
index ce51b09..3aff42a 100644
--- a/Makefile
+++ b/Makefile
@@ -604,6 +604,7 @@ libs-y += fs/
 libs-y += net/
 libs-y += disk/
 libs-y += drivers/
+libs-$(CONFIG_DM) += drivers/core/
 libs-y += drivers/dma/
 libs-y += drivers/gpio/
 libs-y += drivers/i2c/
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
new file mode 100644
index 0000000..90b2a7f
--- /dev/null
+++ b/drivers/core/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2013 Google, Inc
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_DM)	:= device.o lists.o root.o uclass.o util.o
diff --git a/drivers/core/device.c b/drivers/core/device.c
new file mode 100644
index 0000000..55ba281
--- /dev/null
+++ b/drivers/core/device.c
@@ -0,0 +1,348 @@
+/*
+ * Device manager
+ *
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/platdata.h>
+#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
+#include <dm/util.h>
+#include <linux/err.h>
+#include <linux/list.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 device *dev)
+{
+	struct device *pos, *n;
+	int ret, saved_ret = 0;
+
+	assert(dev);
+
+	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+		ret = device_unbind(pos);
+		if (ret && !saved_ret)
+			saved_ret = ret;
+	}
+
+	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 device *dev)
+{
+	struct device *pos, *n;
+	int ret;
+
+	assert(dev);
+
+	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+		ret = device_remove(pos);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int device_bind(struct device *parent, struct driver *drv, const char *name,
+		void *platdata, int of_offset, struct device **devp)
+{
+	struct device *dev;
+	struct uclass *uc;
+	int ret = 0;
+
+	*devp = NULL;
+	if (!name)
+		return -EINVAL;
+
+	ret = uclass_get(drv->id, &uc);
+	if (ret)
+		return ret;
+
+	dev = calloc(1, sizeof(struct device));
+	if (!dev)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev->sibling_node);
+	INIT_LIST_HEAD(&dev->child_head);
+	INIT_LIST_HEAD(&dev->uclass_node);
+	dev->platdata = platdata;
+	dev->name = name;
+	dev->of_offset = of_offset;
+	dev->parent = parent;
+	dev->driver = drv;
+	dev->uclass = uc;
+	if (!dev->platdata && drv->platdata_auto_alloc_size)
+		dev->flags |= DM_FLAG_ALLOC_PDATA;
+
+	/* put dev into parent's successor list */
+	if (parent)
+		list_add_tail(&dev->sibling_node, &parent->child_head);
+
+	ret = uclass_bind_device(dev);
+	if (ret)
+		goto fail_bind;
+
+	/* if we fail to bind we remove device from successors and free it */
+	if (drv->bind) {
+		ret = drv->bind(dev);
+		if (ret) {
+			if (uclass_unbind_device(dev)) {
+				dm_warn("Failed to unbind dev '%s' on error path\n",
+					dev->name);
+			}
+			goto fail_bind;
+		}
+	}
+	if (parent)
+		dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
+	*devp = dev;
+
+	return 0;
+
+fail_bind:
+	list_del(&dev->sibling_node);
+	free(dev);
+	return ret;
+}
+
+int device_bind_by_name(struct device *parent, const struct driver_info *info,
+			struct device **devp)
+{
+	struct driver *drv;
+
+	drv = lists_driver_lookup_name(info->name);
+	if (!drv)
+		return -ENOENT;
+
+	return device_bind(parent, drv, info->name, (void *)info->platdata,
+			   -1, devp);
+}
+
+int device_unbind(struct device *dev)
+{
+	struct driver *drv;
+	int ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	if (dev->flags & DM_FLAG_ACTIVATED)
+		return -EINVAL;
+
+	drv = dev->driver;
+	assert(drv);
+
+	if (drv->unbind) {
+		ret = drv->unbind(dev);
+		if (ret)
+			return ret;
+	}
+
+	ret = device_chld_unbind(dev);
+	if (ret)
+		return ret;
+
+	ret = uclass_unbind_device(dev);
+	if (ret)
+		return ret;
+
+	if (dev->parent)
+		list_del(&dev->sibling_node);
+	free(dev);
+
+	return 0;
+}
+
+/**
+ * device_free() - Free memory buffers allocated by a device
+ * @dev:	Device that is to be started
+ */
+static void device_free(struct device *dev)
+{
+	int size;
+
+	if (dev->driver->priv_auto_alloc_size) {
+		free(dev->priv);
+		dev->priv = NULL;
+	}
+	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
+		free(dev->platdata);
+		dev->platdata = NULL;
+	}
+	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
+	if (size) {
+		free(dev->uclass_priv);
+		dev->uclass_priv = NULL;
+	}
+}
+
+int device_probe(struct device *dev)
+{
+	struct driver *drv;
+	int size = 0;
+	int ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	if (dev->flags & DM_FLAG_ACTIVATED)
+		return 0;
+
+	drv = dev->driver;
+	assert(drv);
+
+	/* Allocate private data and platdata if requested */
+	if (drv->priv_auto_alloc_size) {
+		dev->priv = calloc(1, drv->priv_auto_alloc_size);
+		if (!dev->priv) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+	}
+	/* Allocate private data if requested */
+	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
+		dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
+		if (!dev->platdata) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+	}
+	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
+	if (size) {
+		dev->uclass_priv = calloc(1, size);
+		if (!dev->uclass_priv) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+	}
+
+	/* Ensure all parents are probed */
+	if (dev->parent) {
+		ret = device_probe(dev->parent);
+		if (ret)
+			goto fail;
+	}
+
+	if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
+		ret = drv->ofdata_to_platdata(dev);
+		if (ret)
+			goto fail;
+	}
+
+	if (drv->probe) {
+		ret = drv->probe(dev);
+		if (ret)
+			goto fail;
+	}
+
+	dev->flags |= DM_FLAG_ACTIVATED;
+
+	ret = uclass_post_probe_device(dev);
+	if (ret) {
+		dev->flags &= ~DM_FLAG_ACTIVATED;
+		goto fail_uclass;
+	}
+
+	return 0;
+fail_uclass:
+	if (device_remove(dev)) {
+		dm_warn("%s: Device '%s' failed to remove on error path\n",
+			__func__, dev->name);
+	}
+fail:
+	device_free(dev);
+
+	return ret;
+}
+
+int device_remove(struct device *dev)
+{
+	struct driver *drv;
+	int ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	if (!(dev->flags & DM_FLAG_ACTIVATED))
+		return 0;
+
+	drv = dev->driver;
+	assert(drv);
+
+	ret = uclass_pre_remove_device(dev);
+	if (ret)
+		return ret;
+
+	ret = device_chld_remove(dev);
+	if (ret)
+		goto err;
+
+	if (drv->remove) {
+		ret = drv->remove(dev);
+		if (ret)
+			goto err_remove;
+	}
+
+	device_free(dev);
+
+	dev->flags &= ~DM_FLAG_ACTIVATED;
+
+	return 0;
+
+err_remove:
+	/* We can't put the children back */
+	dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
+		__func__, dev->name);
+err:
+	ret = uclass_post_probe_device(dev);
+	if (ret) {
+		dm_warn("%s: Device '%s' failed to post_probe on error path\n",
+			__func__, dev->name);
+	}
+
+	return ret;
+}
+
+void *dev_get_platdata(struct device *dev)
+{
+	if (!dev) {
+		dm_warn("%s: null device", __func__);
+		return NULL;
+	}
+
+	return dev->platdata;
+}
+
+void *dev_get_priv(struct device *dev)
+{
+	if (!dev) {
+		dm_warn("%s: null device", __func__);
+		return NULL;
+	}
+
+	return dev->priv;
+}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
new file mode 100644
index 0000000..4f2c126
--- /dev/null
+++ b/drivers/core/lists.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/platdata.h>
+#include <dm/uclass.h>
+#include <dm/util.h>
+#include <linux/compiler.h>
+
+struct driver *lists_driver_lookup_name(const char *name)
+{
+	struct driver *drv =
+		ll_entry_start(struct driver, driver);
+	const int n_ents = ll_entry_count(struct driver, driver);
+	struct driver *entry;
+	int len;
+
+	if (!drv || !n_ents)
+		return NULL;
+
+	len = strlen(name);
+
+	for (entry = drv; entry != drv + n_ents; entry++) {
+		if (strncmp(name, entry->name, len))
+			continue;
+
+		/* Full match */
+		if (len == strlen(entry->name))
+			return entry;
+	}
+
+	/* Not found */
+	return NULL;
+}
+
+struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
+{
+	struct uclass_driver *uclass =
+		ll_entry_start(struct uclass_driver, uclass);
+	const int n_ents = ll_entry_count(struct uclass_driver, uclass);
+	struct uclass_driver *entry;
+
+	if ((id == UCLASS_INVALID) || !uclass)
+		return NULL;
+
+	for (entry = uclass; entry != uclass + n_ents; entry++) {
+		if (entry->id == id)
+			return entry;
+	}
+
+	return NULL;
+}
+
+int lists_bind_drivers(struct device *parent)
+{
+	struct driver_info *info =
+		ll_entry_start(struct driver_info, driver_info);
+	const int n_ents = ll_entry_count(struct driver_info, driver_info);
+	struct driver_info *entry;
+	struct device *dev;
+	int result = 0;
+	int ret;
+
+	for (entry = info; entry != info + n_ents; entry++) {
+		ret = device_bind_by_name(parent, entry, &dev);
+		if (ret) {
+			dm_warn("No match for driver '%s'\n", entry->name);
+			if (!result || ret != -ENOENT)
+				result = ret;
+		}
+	}
+
+	return result;
+}
+
+#ifdef CONFIG_OF_CONTROL
+/**
+ * driver_check_compatible() - Check if a driver is compatible with this node
+ *
+ * @param blob:		Device tree pointer
+ * @param offset:	Offset of node in device tree
+ * @param of_matchL	List of compatible strings to match
+ * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node
+ * does not have a compatible string, other error <0 if there is a device
+ * tree error
+ */
+static int driver_check_compatible(const void *blob, int offset,
+				   const struct device_id *of_match)
+{
+	int ret;
+
+	if (!of_match)
+		return -ENOENT;
+
+	while (of_match->compatible) {
+		ret = fdt_node_check_compatible(blob, offset,
+						of_match->compatible);
+		if (!ret)
+			return 0;
+		else if (ret == -FDT_ERR_NOTFOUND)
+			return -ENODEV;
+		else if (ret < 0)
+			return -EINVAL;
+		of_match++;
+	}
+
+	return -ENOENT;
+}
+
+int lists_bind_fdt(struct device *parent, const void *blob, int offset)
+{
+	struct driver *driver = ll_entry_start(struct driver, driver);
+	const int n_ents = ll_entry_count(struct driver, driver);
+	struct driver *entry;
+	struct device *dev;
+	const char *name;
+	int result = 0;
+	int ret;
+
+	dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL));
+	for (entry = driver; entry != driver + n_ents; entry++) {
+		ret = driver_check_compatible(blob, offset, entry->of_match);
+		if (ret == -ENOENT) {
+			continue;
+		} else if (ret == -ENODEV) {
+			break;
+		} else if (ret) {
+			dm_warn("Device tree error at offset %d\n", offset);
+			if (!result || ret != -ENOENT)
+				result = ret;
+			break;
+		}
+
+		name = fdt_get_name(blob, offset, NULL);
+		dm_dbg("   - found match at '%s'\n", entry->name);
+		ret = device_bind(parent, entry, name, NULL, offset, &dev);
+		if (ret) {
+			dm_warn("No match for driver '%s'\n", entry->name);
+			if (!result || ret != -ENOENT)
+				result = ret;
+		}
+	}
+
+	return result;
+}
+#endif
diff --git a/drivers/core/root.c b/drivers/core/root.c
new file mode 100644
index 0000000..407bc0d
--- /dev/null
+++ b/drivers/core/root.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/platdata.h>
+#include <dm/uclass.h>
+#include <dm/util.h>
+#include <linux/list.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct driver_info root_info = {
+	.name		= "root_driver",
+};
+
+struct device *dm_root(void)
+{
+	if (!gd->dm_root) {
+		dm_warn("Virtual root driver does not exist!\n");
+		return NULL;
+	}
+
+	return gd->dm_root;
+}
+
+int dm_init(void)
+{
+	int ret;
+
+	if (gd->dm_root) {
+		dm_warn("Virtual root driver already exists!\n");
+		return -EINVAL;
+	}
+	INIT_LIST_HEAD(&gd->uclass_root);
+
+	ret = device_bind_by_name(NULL, &root_info, &gd->dm_root);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int dm_scan_platdata(void)
+{
+	int ret;
+
+	ret = lists_bind_drivers(gd->dm_root);
+	if (ret == -ENOENT) {
+		dm_warn("Some drivers were not found\n");
+		ret = 0;
+	}
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+#ifdef CONFIG_OF_CONTROL
+int dm_scan_fdt(const void *blob)
+{
+	int offset = 0;
+	int ret = 0, err;
+	int depth = 0;
+
+	do {
+		offset = fdt_next_node(blob, offset, &depth);
+		if (offset > 0 && depth == 1) {
+			err = lists_bind_fdt(gd->dm_root, blob, offset);
+			if (err && !ret)
+				ret = err;
+		}
+	} while (offset > 0);
+
+	if (ret)
+		dm_warn("Some drivers failed to bind\n");
+
+	return ret;
+}
+#endif
+
+/* This is the root driver - all drivers are children of this */
+U_BOOT_DRIVER(root_driver) = {
+	.name	= "root_driver",
+	.id	= UCLASS_ROOT,
+};
+
+/* This is the root uclass */
+UCLASS_DRIVER(root) = {
+	.name	= "root",
+	.id	= UCLASS_ROOT,
+};
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
new file mode 100644
index 0000000..4df5a8b
--- /dev/null
+++ b/drivers/core/uclass.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <dm/device.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass.h>
+#include <dm/uclass-internal.h>
+#include <dm/util.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct uclass *uclass_find(enum uclass_id key)
+{
+	struct uclass *uc;
+
+	/*
+	 * TODO(sjg@chromium.org): Optimise this, perhaps moving the found
+	 * node to the start of the list, or creating a linear array mapping
+	 * id to node.
+	 */
+	list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
+		if (uc->uc_drv->id == key)
+			return uc;
+	}
+
+	return NULL;
+}
+
+/**
+ * uclass_add() - Create new uclass in list
+ * @id: Id number to create
+ * @ucp: Returns pointer to uclass, or NULL on error
+ * @return 0 on success, -ve on error
+ *
+ * The new uclass is added to the list. There must be only one uclass for
+ * each id.
+ */
+static int uclass_add(enum uclass_id id, struct uclass **ucp)
+{
+	struct uclass_driver *uc_drv;
+	struct uclass *uc;
+	int ret;
+
+	*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);
+		return -ENOENT;
+	}
+	if (uc_drv->ops) {
+		dm_warn("No ops for uclass id %d\n", id);
+		return -EINVAL;
+	}
+	uc = calloc(1, sizeof(*uc));
+	if (!uc)
+		return -ENOMEM;
+	if (uc_drv->priv_auto_alloc_size) {
+		uc->priv = calloc(1, uc_drv->priv_auto_alloc_size);
+		if (!uc->priv) {
+			ret = -ENOMEM;
+			goto fail_mem;
+		}
+	}
+	uc->uc_drv = uc_drv;
+	INIT_LIST_HEAD(&uc->sibling_node);
+	INIT_LIST_HEAD(&uc->dev_head);
+	list_add(&uc->sibling_node, &gd->uclass_root);
+
+	if (uc_drv->init) {
+		ret = uc_drv->init(uc);
+		if (ret)
+			goto fail;
+	}
+
+	*ucp = uc;
+
+	return 0;
+fail:
+	if (uc_drv->priv_auto_alloc_size) {
+		free(uc->priv);
+		uc->priv = NULL;
+	}
+	list_del(&uc->sibling_node);
+fail_mem:
+	free(uc);
+
+	return ret;
+}
+
+int uclass_destroy(struct uclass *uc)
+{
+	struct uclass_driver *uc_drv;
+	struct device *dev, *tmp;
+	int ret;
+
+	list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) {
+		ret = device_remove(dev);
+		if (ret)
+			return ret;
+		ret = device_unbind(dev);
+		if (ret)
+			return ret;
+	}
+
+	uc_drv = uc->uc_drv;
+	if (uc_drv->destroy)
+		uc_drv->destroy(uc);
+	list_del(&uc->sibling_node);
+	if (uc_drv->priv_auto_alloc_size)
+		free(uc->priv);
+	free(uc);
+
+	return 0;
+}
+
+int uclass_get(enum uclass_id id, struct uclass **ucp)
+{
+	struct uclass *uc;
+
+	*ucp = NULL;
+	uc = uclass_find(id);
+	if (!uc)
+		return uclass_add(id, ucp);
+	*ucp = uc;
+
+	return 0;
+}
+
+int uclass_find_device(enum uclass_id id, int index, struct device **devp)
+{
+	struct uclass *uc;
+	struct device *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_get(id, &uc);
+	if (ret)
+		return ret;
+
+	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+		if (!index--) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+int uclass_get_device(enum uclass_id id, int index, struct device **devp)
+{
+	struct device *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_find_device(id, index, &dev);
+	if (ret)
+		return ret;
+
+	ret = device_probe(dev);
+	if (ret)
+		return ret;
+
+	*devp = dev;
+
+	return 0;
+}
+
+int uclass_first_device(enum uclass_id id, struct device **devp)
+{
+	struct uclass *uc;
+	struct device *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_get(id, &uc);
+	if (ret)
+		return ret;
+	if (list_empty(&uc->dev_head))
+		return 0;
+
+	dev = list_first_entry(&uc->dev_head, struct device, uclass_node);
+	ret = device_probe(dev);
+	if (ret)
+		return ret;
+	*devp = dev;
+
+	return 0;
+}
+
+int uclass_next_device(struct device **devp)
+{
+	struct device *dev = *devp;
+	int ret;
+
+	*devp = NULL;
+	if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
+		return 0;
+
+	dev = list_entry(dev->uclass_node.next, struct device, uclass_node);
+	ret = device_probe(dev);
+	if (ret)
+		return ret;
+	*devp = dev;
+
+	return 0;
+}
+
+int uclass_bind_device(struct device *dev)
+{
+	struct uclass *uc;
+	int ret;
+
+	uc = dev->uclass;
+
+	list_add_tail(&dev->uclass_node, &uc->dev_head);
+
+	if (uc->uc_drv->post_bind) {
+		ret = uc->uc_drv->post_bind(dev);
+		if (ret) {
+			list_del(&dev->uclass_node);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int uclass_unbind_device(struct device *dev)
+{
+	struct uclass *uc;
+	int ret;
+
+	uc = dev->uclass;
+	if (uc->uc_drv->pre_unbind) {
+		ret = uc->uc_drv->pre_unbind(dev);
+		if (ret)
+			return ret;
+	}
+
+	list_del(&dev->uclass_node);
+	return 0;
+}
+
+int uclass_post_probe_device(struct device *dev)
+{
+	struct uclass_driver *uc_drv = dev->uclass->uc_drv;
+
+	if (uc_drv->post_probe)
+		return uc_drv->post_probe(dev);
+
+	return 0;
+}
+
+int uclass_pre_remove_device(struct device *dev)
+{
+	struct uclass_driver *uc_drv;
+	struct uclass *uc;
+	int ret;
+
+	uc = dev->uclass;
+	uc_drv = uc->uc_drv;
+	if (uc->uc_drv->pre_remove) {
+		ret = uc->uc_drv->pre_remove(dev);
+		if (ret)
+			return ret;
+	}
+	if (uc_drv->per_device_auto_alloc_size) {
+		free(dev->uclass_priv);
+		dev->uclass_priv = NULL;
+	}
+
+	return 0;
+}
diff --git a/drivers/core/util.c b/drivers/core/util.c
new file mode 100644
index 0000000..e01dd06
--- /dev/null
+++ b/drivers/core/util.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <vsprintf.h>
+
+void dm_warn(const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vprintf(fmt, args);
+	va_end(args);
+}
+
+void dm_dbg(const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vprintf(fmt, args);
+	va_end(args);
+}
+
+int list_count_items(struct list_head *head)
+{
+	struct list_head *node;
+	int count = 0;
+
+	list_for_each(node, head)
+		count++;
+
+	return count;
+}
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 0de0bea..707400e 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -21,6 +21,8 @@
  */
 
 #ifndef __ASSEMBLY__
+#include <linux/list.h>
+
 typedef struct global_data {
 	bd_t *bd;
 	unsigned long flags;
@@ -61,6 +63,12 @@ typedef struct global_data {
 	unsigned long start_addr_sp;	/* start_addr_stackpointer */
 	unsigned long reloc_off;
 	struct global_data *new_gd;	/* relocated global data */
+
+#ifdef CONFIG_DM
+	struct device	*dm_root;	/* Root instance for Driver Model */
+	struct list_head uclass_root;	/* Head of core tree */
+#endif
+
 	const void *fdt_blob;	/* Our device tree, NULL if none */
 	void *new_fdt;		/* Relocated FDT */
 	unsigned long fdt_size;	/* Space reserved for relocated FDT */
diff --git a/include/dm.h b/include/dm.h
new file mode 100644
index 0000000..8bbb21b
--- /dev/null
+++ b/include/dm.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_H_
+#define _DM_H
+
+#include <dm/device.h>
+#include <dm/platdata.h>
+#include <dm/uclass.h>
+
+#endif
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
new file mode 100644
index 0000000..c026e8e
--- /dev/null
+++ b/include/dm/device-internal.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ * Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_DEVICE_INTERNAL_H
+#define _DM_DEVICE_INTERNAL_H
+
+struct device;
+
+/**
+ * device_bind() - Create a device and bind it to a driver
+ *
+ * Called to set up a new device attached to a driver. The device will either
+ * have platdata, or a device tree node which can be used to create the
+ * platdata.
+ *
+ * Once bound a device exists but is not yet active until device_probe() is
+ * called.
+ *
+ * @parent: Pointer to device's parent, under which this driver will exist
+ * @drv: Device's driver
+ * @name: Name of device (e.g. device tree node name)
+ * @platdata: Pointer to data for this device - the structure is device-
+ * specific but may include the device's I/O address, etc.. This is NULL for
+ * devices which use device tree.
+ * @of_offset: Offset of device tree node for this device. This is -1 for
+ * devices which don't use device tree.
+ * @devp: Returns a pointer to the bound device
+ * @return 0 if OK, -ve on error
+ */
+int device_bind(struct device *parent, struct driver *drv,
+		const char *name, void *platdata, int of_offset,
+		struct device **devp);
+
+/**
+ * device_bind_by_name: Create a device and bind it to a driver
+ *
+ * This is a helper function used to bind devices which do not use device
+ * tree.
+ *
+ * @parent: Pointer to device's parent
+ * @info: Name and platdata for this device
+ * @devp: Returns a pointer to the bound device
+ * @return 0 if OK, -ve on error
+ */
+int device_bind_by_name(struct device *parent, const struct driver_info *info,
+			struct device **devp);
+
+/**
+ * device_probe() - Probe a device, activating it
+ *
+ * Activate a device so that it is ready for use. All its parents are probed
+ * first.
+ *
+ * @dev: Pointer to device to probe
+ * @return 0 if OK, -ve on error
+ */
+int device_probe(struct device *dev);
+
+/**
+ * device_remove() - Remove a device, de-activating it
+ *
+ * De-activate a device so that it is no longer ready for use. All its
+ * children are deactivated first.
+ *
+ * @dev: Pointer to device to remove
+ * @return 0 if OK, -ve on error (an error here is normally a very bad thing)
+ */
+int device_remove(struct device *dev);
+
+/**
+ * device_unbind() - Unbind a device, destroying it
+ *
+ * Unbind a device and remove all memory used by it
+ *
+ * @dev: Pointer to device to unbind
+ * @return 0 if OK, -ve on error
+ */
+int device_unbind(struct device *dev);
+
+#endif
diff --git a/include/dm/device.h b/include/dm/device.h
new file mode 100644
index 0000000..4cd38ed
--- /dev/null
+++ b/include/dm/device.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ * Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_DEVICE_H
+#define _DM_DEVICE_H
+
+#include <dm/uclass-id.h>
+#include <linker_lists.h>
+#include <linux/list.h>
+
+struct driver_info;
+
+/* Driver is active (probed). Cleared when it is removed */
+#define DM_FLAG_ACTIVATED	(1 << 0)
+
+/* DM is responsible for allocating and freeing platdata */
+#define DM_FLAG_ALLOC_PDATA	(2 << 0)
+
+/**
+ * struct device - An instance of a driver
+ *
+ * This holds information about a device, which is a driver bound to a
+ * particular port or peripheral (essentially a driver instance).
+ *
+ * A device will come into existence through a 'bind' call, either due to
+ * a U_BOOT_DEVICE() macro (in which case platdata is non-NULL) or a node
+ * in the device tree (in which case of_offset is >= 0). In the latter case
+ * we translate the device tree information into platdata in a function
+ * implemented by the driver ofdata_to_platdata method (called just before the
+ * probe method if the device has a device tree node.
+ *
+ * All three of platdata, priv and uclass_priv can be allocated by the
+ * driver, or you can use the auto_alloc_size members of struct driver and
+ * struct uclass_driver to have driver model do this automatically.
+ *
+ * @driver: The driver used by this device
+ * @name: Name of device, typically the FDT node name
+ * @platdata: Configuration data for this device
+ * @of_offset: Device tree node offset for this device (- for none)
+ * @parent: Parent of this device, or NULL for the top level device
+ * @priv: Private data for this device
+ * @uclass: Pointer to uclass for this device
+ * @uclass_priv: The uclass's private data for this device
+ * @uclass_node: Used by uclass to link its devices
+ * @child_head: List of children of this device
+ * @sibling_node: Next device in list of all devices
+ * @flags: Flags for this device DM_FLAG_...
+ */
+struct device {
+	struct driver *driver;
+	const char *name;
+	void *platdata;
+	int of_offset;
+	struct device *parent;
+	void *priv;
+	struct uclass *uclass;
+	void *uclass_priv;
+	struct list_head uclass_node;
+	struct list_head child_head;
+	struct list_head sibling_node;
+	uint32_t flags;
+};
+
+/* Returns the operations for a device */
+#define device_get_ops(dev)	(dev->driver->ops)
+
+/* Returns non-zero if the device is active (probed and not removed) */
+#define device_active(dev)	((dev)->flags & DM_FLAG_ACTIVATED)
+
+/**
+ * struct device_id - Lists the compatible strings supported by a driver
+ * @compatible: Compatible string
+ * @data: Data for this compatible string
+ */
+struct device_id {
+	const char *compatible;
+	ulong data;
+};
+
+/**
+ * struct driver - A driver for a feature or peripheral
+ *
+ * This holds methods for setting up a new device, and also removing it.
+ * The device needs information to set itself up - this is provided either
+ * by platdata or a device tree node (which we find by looking up
+ * matching compatible strings with of_match).
+ *
+ * Drivers all belong to a uclass, representing a class of devices of the
+ * same type. Common elements of the drivers can be implemented in the uclass,
+ * or the uclass can provide a consistent interface to the drivers within
+ * it.
+ *
+ * @name: Device name
+ * @id: Identiies the uclass we belong to
+ * @of_match: List of compatible strings to match, and any identifying data
+ * for each.
+ * @bind: Called to bind a device to its driver
+ * @probe: Called to probe a device, i.e. activate it
+ * @remove: Called to remove a device, i.e. de-activate it
+ * @unbind: Called to unbind a device from its driver
+ * @ofdata_to_platdata: Called before probe to decode device tree data
+ * @priv_auto_alloc_size: If non-zero this is the size of the private data
+ * to be allocated in the device's ->priv pointer. If zero, then the driver
+ * is responsible for allocating any data required.
+ * @platdata_auto_alloc_size: If non-zero this is the size of the
+ * platform data to be allocated in the device's ->platdata pointer.
+ * This is typically only useful for device-tree-aware drivers (those with
+ * an of_match), since drivers which use platdata will have the data
+ * provided in the U_BOOT_DEVICE() instantiation.
+ * ops: Driver-specific operations. This is typically a list of function
+ * pointers defined by the driver, to implement driver functions required by
+ * the uclass.
+ */
+struct driver {
+	char *name;
+	enum uclass_id id;
+	const struct device_id *of_match;
+	int (*bind)(struct device *dev);
+	int (*probe)(struct device *dev);
+	int (*remove)(struct device *dev);
+	int (*unbind)(struct device *dev);
+	int (*ofdata_to_platdata)(struct device *dev);
+	int priv_auto_alloc_size;
+	int platdata_auto_alloc_size;
+	const void *ops;	/* driver-specific operations */
+};
+
+/* Declare a new U-Boot driver */
+#define U_BOOT_DRIVER(__name)						\
+	ll_entry_declare(struct driver, __name, driver)
+
+/**
+ * dev_get_platdata() - Get the platform data for a device
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev		Device to check
+ * @return platform data, or NULL if none
+ */
+void *dev_get_platdata(struct device *dev);
+
+/**
+ * dev_get_priv() - Get the private data for a device
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev		Device to check
+ * @return private data, or NULL if none
+ */
+void *dev_get_priv(struct device *dev);
+
+#endif
diff --git a/include/dm/lists.h b/include/dm/lists.h
new file mode 100644
index 0000000..0d09f9a
--- /dev/null
+++ b/include/dm/lists.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_LISTS_H_
+#define _DM_LISTS_H_
+
+#include <dm/uclass-id.h>
+
+/**
+ * lists_driver_lookup_name() - Return u_boot_driver corresponding to name
+ *
+ * This function returns a pointer to a driver given its name. This is used
+ * for binding a driver given its name and platdata.
+ *
+ * @name: Name of driver to look up
+ * @return pointer to driver, or NULL if not found
+ */
+struct driver *lists_driver_lookup_name(const char *name);
+
+/**
+ * lists_uclass_lookup() - Return uclass_driver based on ID of the class
+ * id:		ID of the class
+ *
+ * This function returns the pointer to uclass_driver, which is the class's
+ * base structure based on the ID of the class. Returns NULL on error.
+ */
+struct uclass_driver *lists_uclass_lookup(enum uclass_id id);
+
+int lists_bind_drivers(struct device *parent);
+
+int lists_bind_fdt(struct device *parent, const void *blob, int offset);
+
+#endif
diff --git a/include/dm/platdata.h b/include/dm/platdata.h
new file mode 100644
index 0000000..0ef3353
--- /dev/null
+++ b/include/dm/platdata.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ * Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_PLATDATA_H
+#define _DM_PLATDATA_H
+
+struct driver_info {
+	const char	*name;
+	const void	*platdata;
+};
+
+#define U_BOOT_DEVICE(__name)						\
+	ll_entry_declare(struct driver_info, __name, driver_info)
+
+#endif
diff --git a/include/dm/root.h b/include/dm/root.h
new file mode 100644
index 0000000..0ebccda
--- /dev/null
+++ b/include/dm/root.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_ROOT_H_
+#define _DM_ROOT_H_
+
+struct device;
+
+/**
+ * dm_root() - Return pointer to the top of the driver tree
+ *
+ * This function returns pointer to the root node of the driver tree,
+ *
+ * @return pointer to root device, or NULL if not inited yet
+ */
+struct device *dm_root(void);
+
+/**
+ * dm_scan_platdata() - Scan all platform data and bind drivers
+ *
+ * This scans all available platdata and creates drivers for each
+ *
+ * @return 0 if OK, -ve on error
+ */
+int dm_scan_platdata(void);
+
+/**
+ * dm_scan_fdt() - Scan the device tree and bind drivers
+ *
+ * This scans the device tree and creates a driver for each node
+ *
+ * @blob: Pointer to device tree blob
+ * @return 0 if OK, -ve on error
+ */
+int dm_scan_fdt(const void *blob);
+
+/**
+ * dm_init() - Initialize Driver Model structures
+ *
+ * This function will initialize roots of driver tree and class tree.
+ * This needs to be called before anything uses the DM
+ *
+ * @return 0 if OK, -ve on error
+ */
+int dm_init(void);
+
+#endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
new file mode 100644
index 0000000..f0e691c
--- /dev/null
+++ b/include/dm/uclass-id.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_UCLASS_ID_H
+#define _DM_UCLASS_ID_H
+
+/* TODO(sjg@chromium.org): this could be compile-time generated */
+enum uclass_id {
+	/* These are used internally by driver model */
+	UCLASS_ROOT = 0,
+	UCLASS_DEMO,
+	UCLASS_TEST,
+	UCLASS_TEST_FDT,
+
+	/* U-Boot uclasses start here */
+	UCLASS_GPIO,
+
+	UCLASS_COUNT,
+	UCLASS_INVALID = -1,
+};
+
+#endif
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
new file mode 100644
index 0000000..cc65d52
--- /dev/null
+++ b/include/dm/uclass-internal.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_UCLASS_INTERNAL_H
+#define _DM_UCLASS_INTERNAL_H
+
+/**
+ * uclass_find_device() - Return n-th child of uclass
+ * @id:		Id number of the uclass
+ * @index:	Position of the child in uclass's list
+ * #devp:	Returns pointer to device, or NULL on error
+ *
+ * The device is not prepared for use - this is an internal function
+ *
+ * @return the uclass pointer of a child at the given index or
+ * return NULL on error.
+ */
+int uclass_find_device(enum uclass_id id, int index, struct device **devp);
+
+/**
+ * uclass_bind_device() - Associate device with a uclass
+ *
+ * Connect the device into uclass's list of devices.
+ *
+ * @dev:	Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_bind_device(struct device *dev);
+
+/**
+ * uclass_unbind_device() - Deassociate device with a uclass
+ *
+ * Disconnect the device from uclass's list of devices.
+ *
+ * @dev:	Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_unbind_device(struct device *dev);
+
+/**
+ * uclass_post_probe_device() - Deal with a device that has just been probed
+ *
+ * Perform any post-processing of a probed device that is needed by the
+ * uclass.
+ *
+ * @dev:	Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_post_probe_device(struct device *dev);
+
+/**
+ * uclass_pre_remove_device() - Handle a device which is about to be removed
+ *
+ * Perform any pre-processing of a device that is about to be removed.
+ *
+ * @dev:	Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_pre_remove_device(struct device *dev);
+
+/**
+ * uclass_find() - Find uclass by its id
+ *
+ * @id:		Id to serach for
+ * @return pointer to uclass, or NULL if not found
+ */
+struct uclass *uclass_find(enum uclass_id key);
+
+/**
+ * uclass_destroy() - Destroy a uclass
+ *
+ * Destroy a uclass and all its devices
+ *
+ * @uc: uclass to destroy
+ * @return 0 on success, -ve on error
+ */
+int uclass_destroy(struct uclass *uc);
+
+#endif
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
new file mode 100644
index 0000000..cd23cfe
--- /dev/null
+++ b/include/dm/uclass.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _DM_UCLASS_H
+#define _DM_UCLASS_H
+
+#include <dm/uclass-id.h>
+#include <linux/list.h>
+
+/**
+ * struct uclass - a U-Boot drive class, collecting together similar drivers
+ *
+ * A uclass provides an interface to a particular function, which is
+ * implemented by one or more drivers. Every driver belongs to a uclass even
+ * if it is the only driver in that uclass. An example uclass is GPIO, which
+ * provides the ability to change read inputs, set and clear outputs, etc.
+ * There may be drivers for on-chip SoC GPIO banks, I2C GPIO expanders and
+ * PMIC IO lines, all made available in a unified way through the uclass.
+ *
+ * @priv: Private data for this uclass
+ * @uc_drv: The driver for the uclass itself, not to be confused with a
+ * 'struct driver'
+ * dev_head: List of devices in this uclass (devices are attached to their
+ * uclass when their bind method is called)
+ * @sibling_node: Next uclass in the linked list of uclasses
+ */
+struct uclass {
+	void *priv;
+	struct uclass_driver *uc_drv;
+	struct list_head dev_head;
+	struct list_head sibling_node;
+};
+
+struct device;
+
+/**
+ * struct uclass_driver - Driver for the uclass
+ *
+ * A uclass_driver provides a consistent interface to a set of related
+ * drivers.
+ *
+ * @name: Name of uclass driver
+ * @id: ID number of this uclass
+ * @post_bind: Called after a new device is bound to this uclass
+ * @pre_unbind: Called before a device is unbound from this uclass
+ * @post_probe: Called after a new device is probed
+ * @pre_remove: Called before a device is removed
+ * @init: Called to set up the uclass
+ * @destroy: Called to destroy the uclass
+ * @priv_auto_alloc_size: If non-zero this is the size of the private data
+ * to be allocated in the uclass's ->priv pointer. If zero, then the uclass
+ * driver is responsible for allocating any data required.
+ * @per_device_auto_alloc_size: Each device can hold private data owned
+ * by the uclass. If required this will be automatically allocated if this
+ * value is non-zero.
+ * @ops: Uclass operations, providing the consistent interface to devices
+ * within the uclass.
+ */
+struct uclass_driver {
+	const char *name;
+	enum uclass_id id;
+	int (*post_bind)(struct device *dev);
+	int (*pre_unbind)(struct device *dev);
+	int (*post_probe)(struct device *dev);
+	int (*pre_remove)(struct device *dev);
+	int (*init)(struct uclass *class);
+	int (*destroy)(struct uclass *class);
+	int priv_auto_alloc_size;
+	int per_device_auto_alloc_size;
+	const void *ops;
+};
+
+/* Declare a new uclass_driver */
+#define UCLASS_DRIVER(__name)						\
+	ll_entry_declare(struct uclass_driver, __name, uclass)
+
+/**
+ * uclass_get() - Get a uclass based on an ID, creating it if needed
+ *
+ * Every uclass is identified by an ID, a number from 0 to n-1 where n is
+ * the number of uclasses. This function allows looking up a uclass by its
+ * ID.
+ *
+ * @key: ID to look up
+ * @ucp: Returns pointer to uclass (there is only one per ID)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_get(enum uclass_id key, struct uclass **ucp);
+
+/**
+ * uclass_get_device() - Get a uclass device based on an ID and index
+ *
+ * id: ID to look up
+ * @index: Device number within that uclass (0=first)
+ * @ucp: Returns pointer to uclass (there is only one per for each ID)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_get_device(enum uclass_id id, int index, struct device **ucp);
+
+/**
+ * uclass_first_device() - Get the first device in a uclass
+ *
+ * @id: Uclass ID to look up
+ * @devp: Returns pointer to the first device in that uclass, or NULL if none
+ * @return 0 if OK (found or not found), -1 on error
+ */
+int uclass_first_device(enum uclass_id id, struct device **devp);
+
+/**
+ * uclass_next_device() - Get the next device in a uclass
+ *
+ * @devp: On entry, pointer to device to lookup. On exit, returns pointer
+ * to the next device in the same uclass, or NULL if none
+ * @return 0 if OK (found or not found), -1 on error
+ */
+int uclass_next_device(struct device **devp);
+
+/**
+ * uclass_foreach_dev() - Helper function to iteration through devices
+ *
+ * This creates a for() loop which works through the available devices in
+ * a uclass in order from start to end.
+ *
+ * @pos: struct device * to hold the current device. Set to NULL when there
+ * are no more devices.
+ * uc: uclass to scan
+ */
+#define uclass_foreach_dev(pos, uc)					\
+	for (pos = list_entry((&(uc)->dev_head)->next, typeof(*pos),	\
+			uclass_node);					\
+	     prefetch(pos->uclass_node.next),				\
+			&pos->uclass_node != (&(uc)->dev_head);		\
+	     pos = list_entry(pos->uclass_node.next, typeof(*pos),	\
+			uclass_node))
+
+#endif
diff --git a/include/dm/util.h b/include/dm/util.h
new file mode 100644
index 0000000..8be64a9
--- /dev/null
+++ b/include/dm/util.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __DM_UTIL_H
+
+void dm_warn(const char *fmt, ...);
+
+#ifdef DEBUG
+void dm_dbg(const char *fmt, ...);
+#else
+static inline void dm_dbg(const char *fmt, ...)
+{
+}
+#endif
+
+struct list_head;
+
+/**
+ * list_count_items() - Count number of items in a list
+ *
+ * @param head:		Head of list
+ * @return number of items, or 0 if empty
+ */
+int list_count_items(struct list_head *head);
+
+#endif
