summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/Makefile7
-rw-r--r--drivers/core/device.c348
-rw-r--r--drivers/core/lists.c155
-rw-r--r--drivers/core/root.c102
-rw-r--r--drivers/core/uclass.c285
-rw-r--r--drivers/core/util.c37
-rw-r--r--drivers/demo/Makefile9
-rw-r--r--drivers/demo/demo-pdata.c47
-rw-r--r--drivers/demo/demo-shape.c127
-rw-r--r--drivers/demo/demo-simple.c47
-rw-r--r--drivers/demo/demo-uclass.c58
-rw-r--r--drivers/fpga/zynqpl.c2
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/at91_gpio.c2
-rw-r--r--drivers/gpio/gpio-uclass.c266
-rw-r--r--drivers/gpio/sandbox.c217
-rw-r--r--drivers/mmc/zynq_sdhci.c29
-rw-r--r--drivers/net/xilinx_emaclite.c17
-rw-r--r--drivers/net/zynq_gem.c42
-rw-r--r--drivers/pci/pcie_imx.c2
-rw-r--r--drivers/serial/serial_zynq.c28
-rw-r--r--drivers/usb/gadget/f_thor.h2
22 files changed, 1741 insertions, 90 deletions
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
new file mode 100644
index 0000000000..90b2a7f068
--- /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 0000000000..55ba281be0
--- /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 0000000000..4f2c12631d
--- /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 0000000000..407bc0d046
--- /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 0000000000..4df5a8bd39
--- /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 0000000000..e01dd06d28
--- /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/drivers/demo/Makefile b/drivers/demo/Makefile
new file mode 100644
index 0000000000..baaa2baa4e
--- /dev/null
+++ b/drivers/demo/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2013 Google, Inc
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_DM_DEMO) += demo-uclass.o demo-pdata.o
+obj-$(CONFIG_DM_DEMO_SIMPLE) += demo-simple.o
+obj-$(CONFIG_DM_DEMO_SHAPE) += demo-shape.o
diff --git a/drivers/demo/demo-pdata.c b/drivers/demo/demo-pdata.c
new file mode 100644
index 0000000000..e92841db69
--- /dev/null
+++ b/drivers/demo/demo-pdata.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm-demo.h>
+
+static const struct dm_demo_pdata red_square = {
+ .colour = "red",
+ .sides = 4.
+};
+static const struct dm_demo_pdata green_triangle = {
+ .colour = "green",
+ .sides = 3.
+};
+static const struct dm_demo_pdata yellow_hexagon = {
+ .colour = "yellow",
+ .sides = 6.
+};
+
+U_BOOT_DEVICE(demo0) = {
+ .name = "demo_shape_drv",
+ .platdata = &red_square,
+};
+
+U_BOOT_DEVICE(demo1) = {
+ .name = "demo_simple_drv",
+ .platdata = &red_square,
+};
+
+U_BOOT_DEVICE(demo2) = {
+ .name = "demo_shape_drv",
+ .platdata = &green_triangle,
+};
+
+U_BOOT_DEVICE(demo3) = {
+ .name = "demo_simple_drv",
+ .platdata = &yellow_hexagon,
+};
+
+U_BOOT_DEVICE(demo4) = {
+ .name = "demo_shape_drv",
+ .platdata = &yellow_hexagon,
+};
diff --git a/drivers/demo/demo-shape.c b/drivers/demo/demo-shape.c
new file mode 100644
index 0000000000..2f0eb96bb6
--- /dev/null
+++ b/drivers/demo/demo-shape.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <dm-demo.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Shape size */
+#define WIDTH 8
+#define HEIGHT 6
+
+struct shape_data {
+ int num_chars; /* Number of non-space characters output so far */
+};
+
+/* Crazy little function to draw shapes on the console */
+static int shape_hello(struct device *dev, int ch)
+{
+ const struct dm_demo_pdata *pdata = dev_get_platdata(dev);
+ struct shape_data *data = dev_get_priv(dev);
+ static const struct shape {
+ int start;
+ int end;
+ int dstart;
+ int dend;
+ } shapes[3] = {
+ { 0, 1, 0, 1 },
+ { 0, WIDTH, 0, 0 },
+ { HEIGHT / 2 - 1, WIDTH - HEIGHT / 2 + 1, -1, 1},
+ };
+ struct shape shape;
+ unsigned int index;
+ int line, pos, inside;
+ const char *colour = pdata->colour;
+ int first = 0;
+
+ if (!ch)
+ ch = pdata->default_char;
+ if (!ch)
+ ch = '@';
+
+ index = (pdata->sides / 2) - 1;
+ if (index >= ARRAY_SIZE(shapes))
+ return -EIO;
+ shape = shapes[index];
+
+ for (line = 0; line < HEIGHT; line++) {
+ first = 1;
+ for (pos = 0; pos < WIDTH; pos++) {
+ inside = pos >= shape.start && pos < shape.end;
+ if (inside) {
+ putc(first ? *colour++ : ch);
+ data->num_chars++;
+ first = 0;
+ if (!*colour)
+ colour = pdata->colour;
+ } else {
+ putc(' ');
+ }
+ }
+ putc('\n');
+ shape.start += shape.dstart;
+ shape.end += shape.dend;
+ if (shape.start < 0) {
+ shape.dstart = -shape.dstart;
+ shape.dend = -shape.dend;
+ shape.start += shape.dstart;
+ shape.end += shape.dend;
+ }
+ }
+
+ return 0;
+}
+
+static int shape_status(struct device *dev, int *status)
+{
+ struct shape_data *data = dev_get_priv(dev);
+
+ *status = data->num_chars;
+ return 0;
+}
+
+static const struct demo_ops shape_ops = {
+ .hello = shape_hello,
+ .status = shape_status,
+};
+
+static int shape_ofdata_to_platdata(struct device *dev)
+{
+ struct dm_demo_pdata *pdata = dev_get_platdata(dev);
+ int ret;
+
+ /* Parse the data that is common with all demo devices */
+ ret = demo_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ /* Parse the data that only we need */
+ pdata->default_char = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "character", '@');
+
+ return 0;
+}
+
+static const struct device_id demo_shape_id[] = {
+ { "demo-shape", 0 },
+ { },
+};
+
+U_BOOT_DRIVER(demo_shape_drv) = {
+ .name = "demo_shape_drv",
+ .of_match = demo_shape_id,
+ .id = UCLASS_DEMO,
+ .ofdata_to_platdata = shape_ofdata_to_platdata,
+ .ops = &shape_ops,
+ .priv_auto_alloc_size = sizeof(struct shape_data),
+ .platdata_auto_alloc_size = sizeof(struct dm_demo_pdata),
+};
diff --git a/drivers/demo/demo-simple.c b/drivers/demo/demo-simple.c
new file mode 100644
index 0000000000..6ba8131728
--- /dev/null
+++ b/drivers/demo/demo-simple.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm-demo.h>
+#include <asm/io.h>
+
+static int simple_hello(struct device *dev, int ch)
+{
+ const struct dm_demo_pdata *pdata = dev_get_platdata(dev);
+
+ printf("Hello from %08x: %s %d\n", map_to_sysmem(dev), pdata->colour,
+ pdata->sides);
+
+ return 0;
+}
+
+static const struct demo_ops simple_ops = {
+ .hello = simple_hello,
+};
+
+static int demo_shape_ofdata_to_platdata(struct device *dev)
+{
+ /* Parse the data that is common with all demo devices */
+ return demo_parse_dt(dev);
+}
+
+static const struct device_id demo_shape_id[] = {
+ { "demo-simple", 0 },
+ { },
+};
+
+U_BOOT_DRIVER(demo_simple_drv) = {
+ .name = "demo_simple_drv",
+ .of_match = demo_shape_id,
+ .id = UCLASS_DEMO,
+ .ofdata_to_platdata = demo_shape_ofdata_to_platdata,
+ .ops = &simple_ops,
+ .platdata_auto_alloc_size = sizeof(struct dm_demo_pdata),
+};
diff --git a/drivers/demo/demo-uclass.c b/drivers/demo/demo-uclass.c
new file mode 100644
index 0000000000..48588be907
--- /dev/null
+++ b/drivers/demo/demo-uclass.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * (C) Copyright 2012
+ * Pavel Herrmann <morpheus.ibis@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm-demo.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/list.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+UCLASS_DRIVER(demo) = {
+ .id = UCLASS_DEMO,
+};
+
+int demo_hello(struct device *dev, int ch)
+{
+ const struct demo_ops *ops = device_get_ops(dev);
+
+ if (!ops->hello)
+ return -ENOSYS;
+
+ return ops->hello(dev, ch);
+}
+
+int demo_status(struct device *dev, int *status)
+{
+ const struct demo_ops *ops = device_get_ops(dev);
+
+ if (!ops->status)
+ return -ENOSYS;
+
+ return ops->status(dev, status);
+}
+
+int demo_parse_dt(struct device *dev)
+{
+ struct dm_demo_pdata *pdata = dev_get_platdata(dev);
+ int dn = dev->of_offset;
+
+ pdata->sides = fdtdec_get_int(gd->fdt_blob, dn, "sides", 0);
+ pdata->colour = fdt_getprop(gd->fdt_blob, dn, "colour", NULL);
+ if (!pdata->sides || !pdata->colour) {
+ debug("%s: Invalid device tree data\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
index 15900c9ef2..923a1586d8 100644
--- a/drivers/fpga/zynqpl.c
+++ b/drivers/fpga/zynqpl.c
@@ -10,7 +10,7 @@
#include <common.h>
#include <asm/io.h>
#include <zynqpl.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sys_proto.h>
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index ed2c0c735b..4e001e12bd 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -5,6 +5,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
+obj-$(CONFIG_DM_GPIO) += gpio-uclass.o
+
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o
diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index 8b766665c6..0b70071871 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -11,7 +11,7 @@
#include <config.h>
#include <common.h>
#include <asm/io.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
#include <asm/arch/hardware.h>
#include <asm/arch/at91_pio.h>
#include <asm/arch/gpio.h>
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
new file mode 100644
index 0000000000..56bfd11466
--- /dev/null
+++ b/drivers/gpio/gpio-uclass.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/gpio.h>
+
+/**
+ * gpio_to_device() - Convert global GPIO number to device, number
+ * gpio: The numeric representation of the GPIO
+ *
+ * Convert the GPIO number to an entry in the list of GPIOs
+ * or GPIO blocks registered with the GPIO controller. Returns
+ * entry on success, NULL on error.
+ */
+static int gpio_to_device(unsigned int gpio, struct device **devp,
+ unsigned int *offset)
+{
+ struct gpio_dev_priv *uc_priv;
+ struct device *dev;
+ int ret;
+
+ for (ret = uclass_first_device(UCLASS_GPIO, &dev);
+ dev;
+ ret = uclass_next_device(&dev)) {
+ uc_priv = dev->uclass_priv;
+ if (gpio >= uc_priv->gpio_base &&
+ gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
+ *devp = dev;
+ *offset = gpio - uc_priv->gpio_base;
+ return 0;
+ }
+ }
+
+ /* No such GPIO */
+ return ret ? ret : -EINVAL;
+}
+
+int gpio_lookup_name(const char *name, struct device **devp,
+ unsigned int *offsetp, unsigned int *gpiop)
+{
+ struct gpio_dev_priv *uc_priv;
+ struct device *dev;
+ int ret;
+
+ if (devp)
+ *devp = NULL;
+ for (ret = uclass_first_device(UCLASS_GPIO, &dev);
+ dev;
+ ret = uclass_next_device(&dev)) {
+ ulong offset;
+ int len;
+
+ uc_priv = dev->uclass_priv;
+ len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0;
+
+ if (!strncmp(name, uc_priv->bank_name, len)) {
+ if (strict_strtoul(name + len, 10, &offset))
+ continue;
+ if (devp)
+ *devp = dev;
+ if (offsetp)
+ *offsetp = offset;
+ if (gpiop)
+ *gpiop = uc_priv->gpio_base + offset;
+ return 0;
+ }
+ }
+
+ return ret ? ret : -EINVAL;
+}
+
+/**
+ * gpio_request() - [COMPAT] Request GPIO
+ * gpio: GPIO number
+ * label: Name for the requested GPIO
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_request(unsigned gpio, const char *label)
+{
+ unsigned int offset;
+ struct device *dev;
+ int ret;
+
+ ret = gpio_to_device(gpio, &dev, &offset);
+ if (ret)
+ return ret;
+
+ if (!gpio_get_ops(dev)->request)
+ return 0;
+
+ return gpio_get_ops(dev)->request(dev, offset, label);
+}
+
+/**
+ * gpio_free() - [COMPAT] Relinquish GPIO
+ * gpio: GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_free(unsigned gpio)
+{
+ unsigned int offset;
+ struct device *dev;
+ int ret;
+
+ ret = gpio_to_device(gpio, &dev, &offset);
+ if (ret)
+ return ret;
+
+ if (!gpio_get_ops(dev)->free)
+ return 0;
+ return gpio_get_ops(dev)->free(dev, offset);
+}
+
+/**
+ * gpio_direction_input() - [COMPAT] Set GPIO direction to input
+ * gpio: GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_direction_input(unsigned gpio)
+{
+ unsigned int offset;
+ struct device *dev;
+ int ret;
+
+ ret = gpio_to_device(gpio, &dev, &offset);
+ if (ret)
+ return ret;
+
+ return gpio_get_ops(dev)->direction_input(dev, offset);
+}
+
+/**
+ * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value
+ * gpio: GPIO number
+ * value: Logical value to be set on the GPIO pin
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_direction_output(unsigned gpio, int value)
+{
+ unsigned int offset;
+ struct device *dev;
+ int ret;
+
+ ret = gpio_to_device(gpio, &dev, &offset);
+ if (ret)
+ return ret;
+
+ return gpio_get_ops(dev)->direction_output(dev, offset, value);
+}
+
+/**
+ * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
+ * gpio: GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns the value of the GPIO pin, or negative value
+ * on error.
+ */
+int gpio_get_value(unsigned gpio)
+{
+ unsigned int offset;
+ struct device *dev;
+ int ret;
+
+ ret = gpio_to_device(gpio, &dev, &offset);
+ if (ret)
+ return ret;
+
+ return gpio_get_ops(dev)->get_value(dev, offset);
+}
+
+/**
+ * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
+ * gpio: GPIO number
+ * value: Logical value to be set on the GPIO pin.
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_set_value(unsigned gpio, int value)
+{
+ unsigned int offset;
+ struct device *dev;
+ int ret;
+
+ ret = gpio_to_device(gpio, &dev, &offset);
+ if (ret)
+ return ret;
+
+ return gpio_get_ops(dev)->set_value(dev, offset, value);
+}
+
+const char *gpio_get_bank_info(struct device *dev, int *bit_count)
+{
+ struct gpio_dev_priv *priv;
+
+ /* Must be called on an active device */
+ priv = dev->uclass_priv;
+ assert(priv);
+
+ *bit_count = priv->gpio_count;
+ return priv->bank_name;
+}
+
+/* We need to renumber the GPIOs when any driver is probed/removed */
+static int gpio_renumber(void)
+{
+ struct gpio_dev_priv *uc_priv;
+ struct device *dev;
+ struct uclass *uc;
+ unsigned base;
+ int ret;
+
+ ret = uclass_get(UCLASS_GPIO, &uc);
+ if (ret)
+ return ret;
+
+ /* Ensure that we have a base for each bank */
+ base = 0;
+ uclass_foreach_dev(dev, uc) {
+ if (device_active(dev)) {
+ uc_priv = dev->uclass_priv;
+ uc_priv->gpio_base = base;
+ base += uc_priv->gpio_count;
+ }
+ }
+
+ return 0;
+}
+
+static int gpio_post_probe(struct device *dev)
+{
+ return gpio_renumber();
+}
+
+static int gpio_pre_remove(struct device *dev)
+{
+ return gpio_renumber();
+}
+
+UCLASS_DRIVER(gpio) = {
+ .id = UCLASS_GPIO,
+ .name = "gpio",
+ .post_probe = gpio_post_probe,
+ .pre_remove = gpio_pre_remove,
+ .per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),
+};
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index 3c6cfec179..22b6a5f794 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -4,8 +4,13 @@
*/
#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <malloc.h>
#include <asm/gpio.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/* Flags for each GPIO */
#define GPIOF_OUTPUT (1 << 0) /* Currently set as an output */
#define GPIOF_HIGH (1 << 1) /* Currently set high */
@@ -16,34 +21,30 @@ struct gpio_state {
u8 flags; /* flags (GPIOF_...) */
};
-/*
- * State of GPIOs
- * TODO: Put this into sandbox state
- */
-static struct gpio_state state[CONFIG_SANDBOX_GPIO_COUNT];
-
/* Access routines for GPIO state */
-static u8 *get_gpio_flags(unsigned gp)
+static u8 *get_gpio_flags(struct device *dev, unsigned offset)
{
- /* assert()'s could be disabled, so make sure we handle that */
- assert(gp < ARRAY_SIZE(state));
- if (gp >= ARRAY_SIZE(state)) {
+ struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_state *state = dev_get_priv(dev);
+
+ if (offset >= uc_priv->gpio_count) {
static u8 invalid_flags;
- printf("sandbox_gpio: error: invalid gpio %u\n", gp);
+ printf("sandbox_gpio: error: invalid gpio %u\n", offset);
return &invalid_flags;
}
- return &state[gp].flags;
+ return &state[offset].flags;
}
-static int get_gpio_flag(unsigned gp, int flag)
+static int get_gpio_flag(struct device *dev, unsigned offset, int flag)
{
- return (*get_gpio_flags(gp) & flag) != 0;
+ return (*get_gpio_flags(dev, offset) & flag) != 0;
}
-static int set_gpio_flag(unsigned gp, int flag, int value)
+static int set_gpio_flag(struct device *dev, unsigned offset, int flag,
+ int value)
{
- u8 *gpio = get_gpio_flags(gp);
+ u8 *gpio = get_gpio_flags(dev, offset);
if (value)
*gpio |= flag;
@@ -53,11 +54,12 @@ static int set_gpio_flag(unsigned gp, int flag, int value)
return 0;
}
-static int check_reserved(unsigned gpio, const char *func)
+static int check_reserved(struct device *dev, unsigned offset,
+ const char *func)
{
- if (!get_gpio_flag(gpio, GPIOF_RESERVED)) {
- printf("sandbox_gpio: %s: error: gpio %u not reserved\n",
- func, gpio);
+ if (!get_gpio_flag(dev, offset, GPIOF_RESERVED)) {
+ printf("sandbox_gpio: %s: error: offset %u not reserved\n",
+ func, offset);
return -1;
}
@@ -68,126 +70,185 @@ static int check_reserved(unsigned gpio, const char *func)
* Back-channel sandbox-internal-only access to GPIO state
*/
-int sandbox_gpio_get_value(unsigned gp)
+int sandbox_gpio_get_value(struct device *dev, unsigned offset)
{
- if (get_gpio_flag(gp, GPIOF_OUTPUT))
- debug("sandbox_gpio: get_value on output gpio %u\n", gp);
- return get_gpio_flag(gp, GPIOF_HIGH);
+ if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
+ debug("sandbox_gpio: get_value on output gpio %u\n", offset);
+ return get_gpio_flag(dev, offset, GPIOF_HIGH);
}
-int sandbox_gpio_set_value(unsigned gp, int value)
+int sandbox_gpio_set_value(struct device *dev, unsigned offset, int value)
{
- return set_gpio_flag(gp, GPIOF_HIGH, value);
+ return set_gpio_flag(dev, offset, GPIOF_HIGH, value);
}
-int sandbox_gpio_get_direction(unsigned gp)
+int sandbox_gpio_get_direction(struct device *dev, unsigned offset)
{
- return get_gpio_flag(gp, GPIOF_OUTPUT);
+ return get_gpio_flag(dev, offset, GPIOF_OUTPUT);
}
-int sandbox_gpio_set_direction(unsigned gp, int output)
+int sandbox_gpio_set_direction(struct device *dev, unsigned offset, int output)
{
- return set_gpio_flag(gp, GPIOF_OUTPUT, output);
+ return set_gpio_flag(dev, offset, GPIOF_OUTPUT, output);
}
/*
* These functions implement the public interface within U-Boot
*/
-/* set GPIO port 'gp' as an input */
-int gpio_direction_input(unsigned gp)
+/* set GPIO port 'offset' as an input */
+static int sb_gpio_direction_input(struct device *dev, unsigned offset)
{
- debug("%s: gp:%u\n", __func__, gp);
+ debug("%s: offset:%u\n", __func__, offset);
- if (check_reserved(gp, __func__))
+ if (check_reserved(dev, offset, __func__))
return -1;
- return sandbox_gpio_set_direction(gp, 0);
+ return sandbox_gpio_set_direction(dev, offset, 0);
}
-/* set GPIO port 'gp' as an output, with polarity 'value' */
-int gpio_direction_output(unsigned gp, int value)
+/* set GPIO port 'offset' as an output, with polarity 'value' */
+static int sb_gpio_direction_output(struct device *dev, unsigned offset,
+ int value)
{
- debug("%s: gp:%u, value = %d\n", __func__, gp, value);
+ debug("%s: offset:%u, value = %d\n", __func__, offset, value);
- if (check_reserved(gp, __func__))
+ if (check_reserved(dev, offset, __func__))
return -1;
- return sandbox_gpio_set_direction(gp, 1) |
- sandbox_gpio_set_value(gp, value);
+ return sandbox_gpio_set_direction(dev, offset, 1) |
+ sandbox_gpio_set_value(dev, offset, value);
}
-/* read GPIO IN value of port 'gp' */
-int gpio_get_value(unsigned gp)
+/* read GPIO IN value of port 'offset' */
+static int sb_gpio_get_value(struct device *dev, unsigned offset)
{
- debug("%s: gp:%u\n", __func__, gp);
+ debug("%s: offset:%u\n", __func__, offset);
- if (check_reserved(gp, __func__))
+ if (check_reserved(dev, offset, __func__))
return -1;
- return sandbox_gpio_get_value(gp);
+ return sandbox_gpio_get_value(dev, offset);
}
-/* write GPIO OUT value to port 'gp' */
-int gpio_set_value(unsigned gp, int value)
+/* write GPIO OUT value to port 'offset' */
+static int sb_gpio_set_value(struct device *dev, unsigned offset, int value)
{
- debug("%s: gp:%u, value = %d\n", __func__, gp, value);
+ debug("%s: offset:%u, value = %d\n", __func__, offset, value);
- if (check_reserved(gp, __func__))
+ if (check_reserved(dev, offset, __func__))
return -1;
- if (!sandbox_gpio_get_direction(gp)) {
- printf("sandbox_gpio: error: set_value on input gpio %u\n", gp);
+ if (!sandbox_gpio_get_direction(dev, offset)) {
+ printf("sandbox_gpio: error: set_value on input gpio %u\n",
+ offset);
return -1;
}
- return sandbox_gpio_set_value(gp, value);
+ return sandbox_gpio_set_value(dev, offset, value);
}
-int gpio_request(unsigned gp, const char *label)
+static int sb_gpio_request(struct device *dev, unsigned offset,
+ const char *label)
{
- debug("%s: gp:%u, label:%s\n", __func__, gp, label);
+ struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_state *state = dev_get_priv(dev);
+
+ debug("%s: offset:%u, label:%s\n", __func__, offset, label);
- if (gp >= ARRAY_SIZE(state)) {
- printf("sandbox_gpio: error: invalid gpio %u\n", gp);
+ if (offset >= uc_priv->gpio_count) {
+ printf("sandbox_gpio: error: invalid gpio %u\n", offset);
return -1;
}
- if (get_gpio_flag(gp, GPIOF_RESERVED)) {
- printf("sandbox_gpio: error: gpio %u already reserved\n", gp);
+ if (get_gpio_flag(dev, offset, GPIOF_RESERVED)) {
+ printf("sandbox_gpio: error: gpio %u already reserved\n",
+ offset);
return -1;
}
- state[gp].label = label;
- return set_gpio_flag(gp, GPIOF_RESERVED, 1);
+ state[offset].label = label;
+ return set_gpio_flag(dev, offset, GPIOF_RESERVED, 1);
}
-int gpio_free(unsigned gp)
+static int sb_gpio_free(struct device *dev, unsigned offset)
{
- debug("%s: gp:%u\n", __func__, gp);
+ struct gpio_state *state = dev_get_priv(dev);
+
+ debug("%s: offset:%u\n", __func__, offset);
- if (check_reserved(gp, __func__))
+ if (check_reserved(dev, offset, __func__))
return -1;
- state[gp].label = NULL;
- return set_gpio_flag(gp, GPIOF_RESERVED, 0);
+ state[offset].label = NULL;
+ return set_gpio_flag(dev, offset, GPIOF_RESERVED, 0);
}
-/* Display GPIO information */
-void gpio_info(void)
+static int sb_gpio_get_state(struct device *dev, unsigned int offset,
+ char *buf, int bufsize)
{
- unsigned gpio;
+ struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+ struct gpio_state *state = dev_get_priv(dev);
+ const char *label;
+
+ label = state[offset].label;
+ snprintf(buf, bufsize, "%s%d: %s: %d [%c]%s%s",
+ uc_priv->bank_name ? uc_priv->bank_name : "", offset,
+ sandbox_gpio_get_direction(dev, offset) ? "out" : " in",
+ sandbox_gpio_get_value(dev, offset),
+ get_gpio_flag(dev, offset, GPIOF_RESERVED) ? 'x' : ' ',
+ label ? " " : "",
+ label ? label : "");
- puts("Sandbox GPIOs\n");
+ return 0;
+}
+
+static const struct dm_gpio_ops gpio_sandbox_ops = {
+ .request = sb_gpio_request,
+ .free = sb_gpio_free,
+ .direction_input = sb_gpio_direction_input,
+ .direction_output = sb_gpio_direction_output,
+ .get_value = sb_gpio_get_value,
+ .set_value = sb_gpio_set_value,
+ .get_state = sb_gpio_get_state,
+};
+
+static int sandbox_gpio_ofdata_to_platdata(struct device *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev->uclass_priv;
- for (gpio = 0; gpio < ARRAY_SIZE(state); ++gpio) {
- const char *label = state[gpio].label;
+ uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "num-gpios", 0);
+ uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset,
+ "gpio-bank-name", NULL);
- printf("%4d: %s: %d [%c] %s\n",
- gpio,
- sandbox_gpio_get_direction(gpio) ? "out" : " in",
- sandbox_gpio_get_value(gpio),
- get_gpio_flag(gpio, GPIOF_RESERVED) ? 'x' : ' ',
- label ? label : "");
+ return 0;
+}
+
+static int gpio_sandbox_probe(struct device *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+
+ if (dev->of_offset == -1) {
+ /* Tell the uclass how many GPIOs we have */
+ uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
}
+
+ dev->priv = calloc(sizeof(struct gpio_state), uc_priv->gpio_count);
+
+ return 0;
}
+
+static const struct device_id sandbox_gpio_ids[] = {
+ { .compatible = "sandbox,gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(gpio_sandbox) = {
+ .name = "gpio_sandbox",
+ .id = UCLASS_GPIO,
+ .of_match = sandbox_gpio_ids,
+ .ofdata_to_platdata = sandbox_gpio_ofdata_to_platdata,
+ .probe = gpio_sandbox_probe,
+ .ops = &gpio_sandbox_ops,
+};
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 72a272f2ba..fdce2c2c10 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -7,6 +7,8 @@
*/
#include <common.h>
+#include <fdtdec.h>
+#include <libfdt.h>
#include <malloc.h>
#include <sdhci.h>
#include <asm/arch/sys_proto.h>
@@ -32,3 +34,30 @@ int zynq_sdhci_init(u32 regbase)
add_sdhci(host, 52000000, 52000000 >> 9);
return 0;
}
+
+#ifdef CONFIG_OF_CONTROL
+int zynq_sdhci_of_init(const void *blob)
+{
+ int offset = 0;
+ u32 ret = 0;
+ u32 reg;
+
+ debug("ZYNQ SDHCI: Initialization\n");
+
+ do {
+ offset = fdt_node_offset_by_compatible(blob, offset,
+ "arasan,sdhci-8.9a");
+ if (offset != -1) {
+ reg = fdtdec_get_addr(blob, offset, "reg");
+ if (reg != FDT_ADDR_T_NONE) {
+ ret |= zynq_sdhci_init(reg);
+ } else {
+ debug("ZYNQ SDHCI: Can't get base address\n");
+ return -1;
+ }
+ }
+ } while (offset != -1);
+
+ return ret;
+}
+#endif
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 0a5209d2f8..2a5cc44553 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -14,8 +14,6 @@
#include <asm/io.h>
#include <fdtdec.h>
-DECLARE_GLOBAL_DATA_PTR;
-
#undef DEBUG
#define ENET_ADDR_LENGTH 6
@@ -364,24 +362,27 @@ int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr,
}
#ifdef CONFIG_OF_CONTROL
-int xilinx_emaclite_init(bd_t *bis)
+int xilinx_emaclite_of_init(const void *blob)
{
int offset = 0;
u32 ret = 0;
u32 reg;
do {
- offset = fdt_node_offset_by_compatible(gd->fdt_blob, offset,
+ offset = fdt_node_offset_by_compatible(blob, offset,
"xlnx,xps-ethernetlite-1.00.a");
if (offset != -1) {
- reg = fdtdec_get_addr(gd->fdt_blob, offset, "reg");
+ reg = fdtdec_get_addr(blob, offset, "reg");
if (reg != FDT_ADDR_T_NONE) {
- u32 rxpp = fdtdec_get_int(gd->fdt_blob, offset,
+ u32 rxpp = fdtdec_get_int(blob, offset,
"xlnx,rx-ping-pong", 0);
- u32 txpp = fdtdec_get_int(gd->fdt_blob, offset,
+ u32 txpp = fdtdec_get_int(blob, offset,
"xlnx,tx-ping-pong", 0);
- ret |= xilinx_emaclite_initialize(bis, reg,
+ ret |= xilinx_emaclite_initialize(NULL, reg,
txpp, rxpp);
+ } else {
+ debug("EMACLITE: Can't get base address\n");
+ return -1;
}
}
} while (offset != -1);
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 6d4001b017..101489c994 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -12,6 +12,8 @@
#include <common.h>
#include <net.h>
#include <config.h>
+#include <fdtdec.h>
+#include <libfdt.h>
#include <malloc.h>
#include <asm/io.h>
#include <phy.h>
@@ -534,3 +536,43 @@ int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio)
return 1;
}
+
+#ifdef CONFIG_OF_CONTROL
+int zynq_gem_of_init(const void *blob)
+{
+ int offset = 0;
+ u32 ret = 0;
+ u32 reg, phy_reg;
+
+ debug("ZYNQ GEM: Initialization\n");
+
+ do {
+ offset = fdt_node_offset_by_compatible(blob, offset,
+ "xlnx,ps7-ethernet-1.00.a");
+ if (offset != -1) {
+ reg = fdtdec_get_addr(blob, offset, "reg");
+ if (reg != FDT_ADDR_T_NONE) {
+ offset = fdtdec_lookup_phandle(blob, offset,
+ "phy-handle");
+ if (offset != -1)
+ phy_reg = fdtdec_get_addr(blob, offset,
+ "reg");
+ else
+ phy_reg = 0;
+
+ debug("ZYNQ GEM: addr %x, phyaddr %x\n",
+ reg, phy_reg);
+
+ ret |= zynq_gem_initialize(NULL, reg,
+ phy_reg, 0);
+
+ } else {
+ debug("ZYNQ GEM: Can't get base address\n");
+ return -1;
+ }
+ }
+ } while (offset != -1);
+
+ return ret;
+}
+#endif
diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c
index 34377e90bd..1f600aaec4 100644
--- a/drivers/pci/pcie_imx.c
+++ b/drivers/pci/pcie_imx.c
@@ -17,7 +17,7 @@
#include <asm/arch/crm_regs.h>
#include <asm/gpio.h>
#include <asm/io.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
#include <errno.h>
#define PCI_ACCESS_READ 0
diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c
index 22c6bf099c..53a8af02d6 100644
--- a/drivers/serial/serial_zynq.c
+++ b/drivers/serial/serial_zynq.c
@@ -6,6 +6,7 @@
*/
#include <common.h>
+#include <fdtdec.h>
#include <watchdog.h>
#include <asm/io.h>
#include <linux/compiler.h>
@@ -13,6 +14,8 @@
#include <asm/arch/clk.h>
#include <asm/arch/hardware.h>
+DECLARE_GLOBAL_DATA_PTR;
+
#define ZYNQ_UART_SR_TXFULL 0x00000010 /* TX FIFO full */
#define ZYNQ_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
@@ -182,6 +185,30 @@ DECLARE_PSSERIAL_FUNCTIONS(1);
struct serial_device uart_zynq_serial1_device =
INIT_PSSERIAL_STRUCTURE(1, "ttyPS1");
+#ifdef CONFIG_OF_CONTROL
+__weak struct serial_device *default_serial_console(void)
+{
+ const void *blob = gd->fdt_blob;
+ int node;
+ unsigned int base_addr;
+
+ node = fdt_path_offset(blob, "serial0");
+ if (node < 0)
+ return NULL;
+
+ base_addr = fdtdec_get_addr(blob, node, "reg");
+ if (base_addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ if (base_addr == ZYNQ_SERIAL_BASEADDR0)
+ return &uart_zynq_serial0_device;
+
+ if (base_addr == ZYNQ_SERIAL_BASEADDR1)
+ return &uart_zynq_serial1_device;
+
+ return NULL;
+}
+#else
__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_ZYNQ_SERIAL_UART0)
@@ -194,6 +221,7 @@ __weak struct serial_device *default_serial_console(void)
#endif
return NULL;
}
+#endif
void zynq_serial_initalize(void)
{
diff --git a/drivers/usb/gadget/f_thor.h b/drivers/usb/gadget/f_thor.h
index 04ee9a2438..833a9d24ae 100644
--- a/drivers/usb/gadget/f_thor.h
+++ b/drivers/usb/gadget/f_thor.h
@@ -11,7 +11,7 @@
#define _USB_THOR_H_
#include <linux/compiler.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
/* THOR Composite Gadget */
#define STRING_MANUFACTURER_IDX 0