diff options
Diffstat (limited to 'drivers')
35 files changed, 1951 insertions, 988 deletions
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index e64df4f98d..a409f63770 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -41,7 +41,7 @@ u16 *ataid[AHCI_MAX_PORTS]; #define WAIT_MS_SPINUP 20000 #define WAIT_MS_DATAIO 5000 #define WAIT_MS_FLUSH 5000 -#define WAIT_MS_LINKUP 4 +#define WAIT_MS_LINKUP 40 static inline u32 ahci_port_base(u32 base, u32 port) { @@ -930,6 +930,11 @@ int ahci_init(u32 base) err_out: return rc; } + +void __weak scsi_init(void) +{ +} + #endif /* 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/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 34688e9bef..5510b13c01 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -104,7 +104,6 @@ static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len) *p++ = in_be32((u32 *)(base + NDFC_DATA)); } -#ifndef CONFIG_NAND_SPL /* * Don't use these speedup functions in NAND boot image, since the image * has to fit into 4kByte. @@ -148,8 +147,6 @@ static uint8_t ndfc_read_byte(struct mtd_info *mtd) } -#endif /* #ifndef CONFIG_NAND_SPL */ - void board_nand_select_device(struct nand_chip *nand, int chip) { /* @@ -207,21 +204,11 @@ int board_nand_init(struct nand_chip *nand) nand->options |= NAND_BUSWIDTH_16; #endif -#ifndef CONFIG_NAND_SPL nand->write_buf = ndfc_write_buf; nand->verify_buf = ndfc_verify_buf; nand->read_byte = ndfc_read_byte; chip++; -#else - /* - * Setup EBC (CS0 only right now) - */ - mtebc(EBC0_CFG, CONFIG_SYS_NDFC_EBC0_CFG); - - mtebc(PB0CR, CONFIG_SYS_EBC_PB0CR); - mtebc(PB0AP, CONFIG_SYS_EBC_PB0AP); -#endif return 0; } diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c index 2aa7807f3e..47b1f1bfe2 100644 --- a/drivers/mtd/nand/omap_elm.c +++ b/drivers/mtd/nand/omap_elm.c @@ -16,9 +16,9 @@ #include <common.h> #include <asm/io.h> #include <asm/errno.h> -#include <asm/arch/cpu.h> -#include <asm/omap_gpmc.h> -#include <asm/omap_elm.h> +#include <linux/mtd/omap_gpmc.h> +#include <linux/mtd/omap_elm.h> +#include <asm/arch/hardware.h> #define ELM_DEFAULT_POLY (0) diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index 389c4de59a..881a63618c 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -9,17 +9,24 @@ #include <asm/io.h> #include <asm/errno.h> #include <asm/arch/mem.h> -#include <asm/arch/cpu.h> -#include <asm/omap_gpmc.h> +#include <linux/mtd/omap_gpmc.h> #include <linux/mtd/nand_ecc.h> #include <linux/bch.h> #include <linux/compiler.h> #include <nand.h> -#include <asm/omap_elm.h> +#include <linux/mtd/omap_elm.h> #define BADBLOCK_MARKER_LENGTH 2 #define SECTOR_BYTES 512 +#define ECCCLEAR (0x1 << 8) +#define ECCRESULTREG1 (0x1 << 0) +/* 4 bit padding to make byte aligned, 56 = 52 + 4 */ +#define BCH4_BIT_PAD 4 +#ifdef CONFIG_BCH +static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2, + 0x97, 0x79, 0xe5, 0x24, 0xb5}; +#endif static uint8_t cs; static __maybe_unused struct nand_ecclayout omap_ecclayout; @@ -60,21 +67,6 @@ int omap_spl_dev_ready(struct mtd_info *mtd) } #endif -/* - * omap_hwecc_init - Initialize the Hardware ECC for NAND flash in - * GPMC controller - * @mtd: MTD device structure - * - */ -static void __maybe_unused omap_hwecc_init(struct nand_chip *chip) -{ - /* - * Init ECC Control Register - * Clear all ECC | Enable Reg1 - */ - writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); - writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, &gpmc_cfg->ecc_size_config); -} /* * gen_true_ecc - This function will generate true ECC value, which @@ -156,74 +148,6 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat, } /* - * omap_calculate_ecc - Generate non-inverted ECC bytes. - * - * Using noninverted ECC can be considered ugly since writing a blank - * page ie. padding will clear the ECC bytes. This is no problem as - * long nobody is trying to write data on the seemingly unused page. - * Reading an erased page will produce an ECC mismatch between - * generated and read ECC bytes that has to be dealt with separately. - * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC - * is used, the result of read will be 0x0 while the ECC offsets of the - * spare area will be 0xFF which will result in an ECC mismatch. - * @mtd: MTD structure - * @dat: unused - * @ecc_code: ecc_code buffer - */ -static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd, - const uint8_t *dat, uint8_t *ecc_code) -{ - u_int32_t val; - - /* Start Reading from HW ECC1_Result = 0x200 */ - val = readl(&gpmc_cfg->ecc1_result); - - ecc_code[0] = val & 0xFF; - ecc_code[1] = (val >> 16) & 0xFF; - ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0); - - /* - * Stop reading anymore ECC vals and clear old results - * enable will be called if more reads are required - */ - writel(0x000, &gpmc_cfg->ecc_config); - - return 0; -} - -/* - * omap_enable_ecc - This function enables the hardware ecc functionality - * @mtd: MTD device structure - * @mode: Read/Write mode - */ -static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) -{ - struct nand_chip *chip = mtd->priv; - uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1; - - switch (mode) { - case NAND_ECC_READ: - case NAND_ECC_WRITE: - /* Clear the ecc result registers, select ecc reg as 1 */ - writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); - - /* - * Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes - * tell all regs to generate size0 sized regs - * we just have a single ECC engine for all CS - */ - writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, - &gpmc_cfg->ecc_size_config); - val = (dev_width << 7) | (cs << 1) | (0x1); - writel(val, &gpmc_cfg->ecc_config); - break; - default: - printf("Error: Unrecognized Mode[%d]!\n", mode); - break; - } -} - -/* * Generic BCH interface */ struct nand_bch_priv { @@ -239,12 +163,7 @@ struct nand_bch_priv { #define ECC_BCH8 1 #define ECC_BCH16 2 -/* GPMC ecc engine settings */ -#define BCH_WRAPMODE_1 1 /* BCH wrap mode 1 */ -#define BCH_WRAPMODE_6 6 /* BCH wrap mode 6 */ - /* BCH nibbles for diff bch levels */ -#define NAND_ECC_HW_BCH ((uint8_t)(NAND_ECC_HW_OOB_FIRST) + 1) #define ECC_BCH4_NIBBLES 13 #define ECC_BCH8_NIBBLES 26 #define ECC_BCH16_NIBBLES 52 @@ -256,266 +175,161 @@ struct nand_bch_priv { * When some users with other BCH strength will exists this have to change! */ static __maybe_unused struct nand_bch_priv bch_priv = { - .mode = NAND_ECC_HW_BCH, .type = ECC_BCH8, .nibbles = ECC_BCH8_NIBBLES, .control = NULL }; /* - * omap_hwecc_init_bch - Initialize the BCH Hardware ECC for NAND flash in - * GPMC controller - * @mtd: MTD device structure - * @mode: Read/Write mode - */ -__maybe_unused -static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode) + * omap_reverse_list - re-orders list elements in reverse order [internal] + * @list: pointer to start of list + * @length: length of list +*/ +void omap_reverse_list(u8 *list, unsigned int length) { - uint32_t val; - uint32_t dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1; - uint32_t unused_length = 0; - uint32_t wr_mode = BCH_WRAPMODE_6; - struct nand_bch_priv *bch = chip->priv; - - /* Clear the ecc result registers, select ecc reg as 1 */ - writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); - - if (bch->ecc_scheme == OMAP_ECC_BCH8_CODE_HW) { - wr_mode = BCH_WRAPMODE_1; - - switch (bch->nibbles) { - case ECC_BCH4_NIBBLES: - unused_length = 3; - break; - case ECC_BCH8_NIBBLES: - unused_length = 2; - break; - case ECC_BCH16_NIBBLES: - unused_length = 0; - break; - } - - /* - * This is ecc_size_config for ELM mode. Here we are using - * different settings for read and write access and also - * depending on BCH strength. - */ - switch (mode) { - case NAND_ECC_WRITE: - /* write access only setup eccsize1 config */ - val = ((unused_length + bch->nibbles) << 22); - break; - - case NAND_ECC_READ: - default: - /* - * by default eccsize0 selected for ecc1resultsize - * eccsize0 config. - */ - val = (bch->nibbles << 12); - /* eccsize1 config */ - val |= (unused_length << 22); - break; - } - } else { - /* - * This ecc_size_config setting is for BCH sw library. - * - * Note: we only support BCH8 currently with BCH sw library! - * Should be really easy to adobt to BCH4, however some omap3 - * have flaws with BCH4. - * - * Here we are using wrapping mode 6 both for reading and - * writing, with: - * size0 = 0 (no additional protected byte in spare area) - * size1 = 32 (skip 32 nibbles = 16 bytes per sector in - * spare area) - */ - val = (32 << 22) | (0 << 12); + unsigned int i, j; + unsigned int half_length = length / 2; + u8 tmp; + for (i = 0, j = length - 1; i < half_length; i++, j--) { + tmp = list[i]; + list[i] = list[j]; + list[j] = tmp; } - /* ecc size configuration */ - writel(val, &gpmc_cfg->ecc_size_config); - - /* - * Configure the ecc engine in gpmc - * We assume 512 Byte sector pages for access to NAND. - */ - val = (1 << 16); /* enable BCH mode */ - val |= (bch->type << 12); /* setup BCH type */ - val |= (wr_mode << 8); /* setup wrapping mode */ - val |= (dev_width << 7); /* setup device width (16 or 8 bit) */ - val |= (cs << 1); /* setup chip select to work on */ - debug("set ECC_CONFIG=0x%08x\n", val); - writel(val, &gpmc_cfg->ecc_config); } /* - * omap_enable_ecc_bch - This function enables the bch h/w ecc functionality + * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write * @mtd: MTD device structure * @mode: Read/Write mode */ __maybe_unused -static void omap_enable_ecc_bch(struct mtd_info *mtd, int32_t mode) -{ - struct nand_chip *chip = mtd->priv; - - omap_hwecc_init_bch(chip, mode); - /* enable ecc */ - writel((readl(&gpmc_cfg->ecc_config) | 0x1), &gpmc_cfg->ecc_config); -} - -/* - * omap_ecc_disable - Disable H/W ECC calculation - * - * @mtd: MTD device structure - */ -static void __maybe_unused omap_ecc_disable(struct mtd_info *mtd) +static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) { - writel((readl(&gpmc_cfg->ecc_config) & ~0x1), &gpmc_cfg->ecc_config); + struct nand_chip *nand = mtd->priv; + struct nand_bch_priv *bch = nand->priv; + unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0; + unsigned int ecc_algo = 0; + unsigned int bch_type = 0; + unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00; + u32 ecc_size_config_val = 0; + u32 ecc_config_val = 0; + + /* configure GPMC for specific ecc-scheme */ + switch (bch->ecc_scheme) { + case OMAP_ECC_HAM1_CODE_SW: + return; + case OMAP_ECC_HAM1_CODE_HW: + ecc_algo = 0x0; + bch_type = 0x0; + bch_wrapmode = 0x00; + eccsize0 = 0xFF; + eccsize1 = 0xFF; + break; + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW: + ecc_algo = 0x1; + bch_type = 0x1; + if (mode == NAND_ECC_WRITE) { + bch_wrapmode = 0x01; + eccsize0 = 0; /* extra bits in nibbles per sector */ + eccsize1 = 28; /* OOB bits in nibbles per sector */ + } else { + bch_wrapmode = 0x01; + eccsize0 = 26; /* ECC bits in nibbles per sector */ + eccsize1 = 2; /* non-ECC bits in nibbles per sector */ + } + break; + default: + return; + } + /* Clear ecc and enable bits */ + writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); + /* Configure ecc size for BCH */ + ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12); + writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config); + + /* Configure device details for BCH engine */ + ecc_config_val = ((ecc_algo << 16) | /* HAM1 | BCHx */ + (bch_type << 12) | /* BCH4/BCH8/BCH16 */ + (bch_wrapmode << 8) | /* wrap mode */ + (dev_width << 7) | /* bus width */ + (0x0 << 4) | /* number of sectors */ + (cs << 1) | /* ECC CS */ + (0x1)); /* enable ECC */ + writel(ecc_config_val, &gpmc_cfg->ecc_config); } /* - * BCH support using ELM module - */ -#ifdef CONFIG_NAND_OMAP_ELM -/* - * omap_read_bch8_result - Read BCH result for BCH8 level - * - * @mtd: MTD device structure - * @big_endian: When set read register 3 first - * @ecc_code: Read syndrome from BCH result registers + * omap_calculate_ecc - Read ECC result + * @mtd: MTD structure + * @dat: unused + * @ecc_code: ecc_code buffer + * Using noninverted ECC can be considered ugly since writing a blank + * page ie. padding will clear the ECC bytes. This is no problem as + * long nobody is trying to write data on the seemingly unused page. + * Reading an erased page will produce an ECC mismatch between + * generated and read ECC bytes that has to be dealt with separately. + * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC + * is used, the result of read will be 0x0 while the ECC offsets of the + * spare area will be 0xFF which will result in an ECC mismatch. */ -static void omap_read_bch8_result(struct mtd_info *mtd, uint8_t big_endian, +static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) { - uint32_t *ptr; + struct nand_chip *chip = mtd->priv; + struct nand_bch_priv *bch = chip->priv; + uint32_t *ptr, val = 0; int8_t i = 0, j; - if (big_endian) { + switch (bch->ecc_scheme) { + case OMAP_ECC_HAM1_CODE_HW: + val = readl(&gpmc_cfg->ecc1_result); + ecc_code[0] = val & 0xFF; + ecc_code[1] = (val >> 16) & 0xFF; + ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0); + break; +#ifdef CONFIG_BCH + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: +#endif + case OMAP_ECC_BCH8_CODE_HW: ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3]; - ecc_code[i++] = readl(ptr) & 0xFF; + val = readl(ptr); + ecc_code[i++] = (val >> 0) & 0xFF; ptr--; for (j = 0; j < 3; j++) { - ecc_code[i++] = (readl(ptr) >> 24) & 0xFF; - ecc_code[i++] = (readl(ptr) >> 16) & 0xFF; - ecc_code[i++] = (readl(ptr) >> 8) & 0xFF; - ecc_code[i++] = readl(ptr) & 0xFF; + val = readl(ptr); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; ptr--; } - } else { - ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[0]; - for (j = 0; j < 3; j++) { - ecc_code[i++] = readl(ptr) & 0xFF; - ecc_code[i++] = (readl(ptr) >> 8) & 0xFF; - ecc_code[i++] = (readl(ptr) >> 16) & 0xFF; - ecc_code[i++] = (readl(ptr) >> 24) & 0xFF; - ptr++; - } - ecc_code[i++] = readl(ptr) & 0xFF; - ecc_code[i++] = 0; /* 14th byte is always zero */ + break; + default: + return -EINVAL; } -} - -/* - * omap_rotate_ecc_bch - Rotate the syndrome bytes - * - * @mtd: MTD device structure - * @calc_ecc: ECC read from ECC registers - * @syndrome: Rotated syndrome will be retuned in this array - * - */ -static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc, - uint8_t *syndrome) -{ - struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; - uint8_t n_bytes = 0; - int8_t i, j; - - switch (bch->type) { - case ECC_BCH4: - n_bytes = 8; + /* ECC scheme specific syndrome customizations */ + switch (bch->ecc_scheme) { + case OMAP_ECC_HAM1_CODE_HW: break; +#ifdef CONFIG_BCH + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: - case ECC_BCH16: - n_bytes = 28; + for (i = 0; i < chip->ecc.bytes; i++) + *(ecc_code + i) = *(ecc_code + i) ^ + bch8_polynomial[i]; break; - - case ECC_BCH8: - default: - n_bytes = 13; +#endif + case OMAP_ECC_BCH8_CODE_HW: + ecc_code[chip->ecc.bytes - 1] = 0x00; break; + default: + return -EINVAL; } - - for (i = 0, j = (n_bytes-1); i < n_bytes; i++, j--) - syndrome[i] = calc_ecc[j]; -} - -/* - * omap_calculate_ecc_bch - Read BCH ECC result - * - * @mtd: MTD structure - * @dat: unused - * @ecc_code: ecc_code buffer - */ -static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) -{ - struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; - uint8_t big_endian = 1; - int8_t ret = 0; - - if (bch->type == ECC_BCH8) - omap_read_bch8_result(mtd, big_endian, ecc_code); - else /* BCH4 and BCH16 currently not supported */ - ret = -1; - - /* - * Stop reading anymore ECC vals and clear old results - * enable will be called if more reads are required - */ - omap_ecc_disable(mtd); - - return ret; -} - -/* - * omap_fix_errors_bch - Correct bch error in the data - * - * @mtd: MTD device structure - * @data: Data read from flash - * @error_count:Number of errors in data - * @error_loc: Locations of errors in the data - * - */ -static void omap_fix_errors_bch(struct mtd_info *mtd, uint8_t *data, - uint32_t error_count, uint32_t *error_loc) -{ - struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; - uint8_t count = 0; - uint32_t error_byte_pos; - uint32_t error_bit_mask; - uint32_t last_bit = (bch->nibbles * 4) - 1; - - /* Flip all bits as specified by the error location array. */ - /* FOR( each found error location flip the bit ) */ - for (count = 0; count < error_count; count++) { - if (error_loc[count] > last_bit) { - /* Remove the ECC spare bits from correction. */ - error_loc[count] -= (last_bit + 1); - /* Offset bit in data region */ - error_byte_pos = ((512 * 8) - - (error_loc[count]) - 1) / 8; - /* Error Bit mask */ - error_bit_mask = 0x1 << (error_loc[count] % 8); - /* Toggle the error bit to make the correction. */ - data[error_byte_pos] ^= error_bit_mask; - } - } + return 0; } +#ifdef CONFIG_NAND_OMAP_ELM /* * omap_correct_data_bch - Compares the ecc read from nand spare area * with ECC registers values and corrects one bit error if it has occured @@ -532,40 +346,72 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, { struct nand_chip *chip = mtd->priv; struct nand_bch_priv *bch = chip->priv; - uint8_t syndrome[28]; - uint32_t error_count = 0; + uint32_t eccbytes = chip->ecc.bytes; + uint32_t error_count = 0, error_max; uint32_t error_loc[8]; - uint32_t i, ecc_flag; + uint32_t i, ecc_flag = 0; + uint8_t count, err = 0; + uint32_t byte_pos, bit_pos; + + /* check calculated ecc */ + for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) { + if (calc_ecc[i] != 0x00) + ecc_flag = 1; + } + if (!ecc_flag) + return 0; + /* check for whether its a erased-page */ ecc_flag = 0; - for (i = 0; i < chip->ecc.bytes; i++) + for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) { if (read_ecc[i] != 0xff) ecc_flag = 1; - + } if (!ecc_flag) return 0; - elm_reset(); - elm_config((enum bch_level)(bch->type)); - /* * while reading ECC result we read it in big endian. * Hence while loading to ELM we have rotate to get the right endian. */ - omap_rotate_ecc_bch(mtd, calc_ecc, syndrome); - + switch (bch->ecc_scheme) { + case OMAP_ECC_BCH8_CODE_HW: + omap_reverse_list(calc_ecc, eccbytes - 1); + break; + default: + return -EINVAL; + } /* use elm module to check for errors */ - if (elm_check_error(syndrome, bch->nibbles, &error_count, - error_loc) != 0) { - printf("ECC: uncorrectable.\n"); - return -1; + elm_config((enum bch_level)(bch->type)); + if (elm_check_error(calc_ecc, bch->nibbles, &error_count, error_loc)) { + printf("nand: error: uncorrectable ECC errors\n"); + return -EINVAL; } - /* correct bch error */ - if (error_count > 0) - omap_fix_errors_bch(mtd, dat, error_count, error_loc); - - return 0; + for (count = 0; count < error_count; count++) { + switch (bch->type) { + case ECC_BCH8: + /* 14th byte in ECC is reserved to match ROM layout */ + error_max = SECTOR_BYTES + (eccbytes - 1); + break; + default: + return -EINVAL; + } + byte_pos = error_max - (error_loc[count] / 8) - 1; + bit_pos = error_loc[count] % 8; + if (byte_pos < SECTOR_BYTES) { + dat[byte_pos] ^= 1 << bit_pos; + printf("nand: bit-flip corrected @data=%d\n", byte_pos); + } else if (byte_pos < error_max) { + read_ecc[byte_pos - SECTOR_BYTES] = 1 << bit_pos; + printf("nand: bit-flip corrected @oob=%d\n", byte_pos - + SECTOR_BYTES); + } else { + err = -EBADMSG; + printf("nand: error: invalid bit-flip location\n"); + } + } + return (err) ? err : error_count; } /** @@ -636,57 +482,6 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, * OMAP3 BCH8 support (with BCH library) */ #ifdef CONFIG_BCH -/* - * omap_calculate_ecc_bch_sw - Read BCH ECC result - * - * @mtd: MTD device structure - * @dat: The pointer to data on which ecc is computed (unused here) - * @ecc: The ECC output buffer - */ -static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc) -{ - int ret = 0; - size_t i; - unsigned long nsectors, val1, val2, val3, val4; - - nsectors = ((readl(&gpmc_cfg->ecc_config) >> 4) & 0x7) + 1; - - for (i = 0; i < nsectors; i++) { - /* Read hw-computed remainder */ - val1 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[0]); - val2 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[1]); - val3 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[2]); - val4 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[3]); - - /* - * Add constant polynomial to remainder, in order to get an ecc - * sequence of 0xFFs for a buffer filled with 0xFFs. - */ - *ecc++ = 0xef ^ (val4 & 0xFF); - *ecc++ = 0x51 ^ ((val3 >> 24) & 0xFF); - *ecc++ = 0x2e ^ ((val3 >> 16) & 0xFF); - *ecc++ = 0x09 ^ ((val3 >> 8) & 0xFF); - *ecc++ = 0xed ^ (val3 & 0xFF); - *ecc++ = 0x93 ^ ((val2 >> 24) & 0xFF); - *ecc++ = 0x9a ^ ((val2 >> 16) & 0xFF); - *ecc++ = 0xc2 ^ ((val2 >> 8) & 0xFF); - *ecc++ = 0x97 ^ (val2 & 0xFF); - *ecc++ = 0x79 ^ ((val1 >> 24) & 0xFF); - *ecc++ = 0xe5 ^ ((val1 >> 16) & 0xFF); - *ecc++ = 0x24 ^ ((val1 >> 8) & 0xFF); - *ecc++ = 0xb5 ^ (val1 & 0xFF); - } - - /* - * Stop reading anymore ECC vals and clear old results - * enable will be called if more reads are required - */ - omap_ecc_disable(mtd); - - return ret; -} - /** * omap_correct_data_bch_sw - Decode received data and correct errors * @mtd: MTD device structure @@ -835,9 +630,9 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, nand->ecc.strength = 8; nand->ecc.size = SECTOR_BYTES; nand->ecc.bytes = 13; - nand->ecc.hwctl = omap_enable_ecc_bch; + nand->ecc.hwctl = omap_enable_hwecc; nand->ecc.correct = omap_correct_data_bch_sw; - nand->ecc.calculate = omap_calculate_ecc_bch_sw; + nand->ecc.calculate = omap_calculate_ecc; /* define ecc-layout */ ecclayout->eccbytes = nand->ecc.bytes * eccsteps; ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; @@ -852,7 +647,6 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - BADBLOCK_MARKER_LENGTH; - omap_hwecc_init_bch(nand, NAND_ECC_READ); bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; break; #else @@ -878,9 +672,9 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, nand->ecc.strength = 8; nand->ecc.size = SECTOR_BYTES; nand->ecc.bytes = 14; - nand->ecc.hwctl = omap_enable_ecc_bch; + nand->ecc.hwctl = omap_enable_hwecc; nand->ecc.correct = omap_correct_data_bch; - nand->ecc.calculate = omap_calculate_ecc_bch; + nand->ecc.calculate = omap_calculate_ecc; nand->ecc.read_page = omap_read_page_bch; /* define ecc-layout */ ecclayout->eccbytes = nand->ecc.bytes * eccsteps; diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 5332e1a18f..b80980d552 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -41,7 +41,7 @@ static int ar8035_config(struct phy_device *phydev) static struct phy_driver AR8021_driver = { .name = "AR8021", .uid = 0x4dd040, - .mask = 0x4fffff, + .mask = 0x4ffff0, .features = PHY_GBIT_FEATURES, .config = ar8021_config, .startup = genphy_startup, 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/eth/asix.c b/drivers/usb/eth/asix.c index 659533a8d4..ce133f0069 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -468,8 +468,6 @@ static int asix_send(struct eth_device *eth, void *packet, int length) memcpy(msg, &packet_len, sizeof(packet_len)); memcpy(msg + sizeof(packet_len), (void *)packet, length); - if (length & 1) - length++; err = usb_bulk_msg(dev->pusb_dev, usb_sndbulkpipe(dev->pusb_dev, dev->ep_out), 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 diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 17187caed4..6017090ebe 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -395,6 +395,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0); qh->qh_endpt2 = cpu_to_hc32(endpt); qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); tdp = &qh->qh_overlay.qt_next; @@ -1161,14 +1162,16 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, debug("ehci intr queue: out of memory\n"); goto fail1; } - result->first = memalign(32, sizeof(struct QH) * queuesize); + result->first = memalign(USB_DMA_MINALIGN, + sizeof(struct QH) * queuesize); if (!result->first) { debug("ehci intr queue: out of memory\n"); goto fail2; } result->current = result->first; result->last = result->first + queuesize - 1; - result->tds = memalign(32, sizeof(struct qTD) * queuesize); + result->tds = memalign(USB_DMA_MINALIGN, + sizeof(struct qTD) * queuesize); if (!result->tds) { debug("ehci intr queue: out of memory\n"); goto fail3; @@ -1186,6 +1189,7 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, qh->qh_link = QH_LINK_TERMINATE; qh->qh_overlay.qt_next = (uint32_t)td; + qh->qh_overlay.qt_altnext = QT_NEXT_TERMINATE; qh->qh_endpt1 = (0 << 28) | /* No NAK reload (ehci 4.9) */ (usb_maxpacket(dev, pipe) << 16) | /* MPS */ (1 << 14) | diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5aa190b52d..46e4cee1d0 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -254,105 +254,7 @@ static inline void dump_ptd_data(struct ptd *ptd, u8 * buf, int type) /* --- Virtual Root Hub ---------------------------------------------------- */ -/* Device descriptor */ -static __u8 root_hub_dev_des[] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, /* __u16 bcdUSB; v1.1 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x01, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = { - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ - 0x02, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static unsigned char root_hub_str_index0[] = { - 0x04, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 0x09, /* __u8 lang ID */ - 0x04, /* __u8 lang ID */ -}; - -static unsigned char root_hub_str_index1[] = { - 0x22, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 'I', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'S', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'P', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '1', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '1', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '6', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'x', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'R', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 't', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'u', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'b', /* __u8 Unicode */ - 0, /* __u8 Unicode */ -}; +#include <usbroothubdes.h> /* * Hub class-specific descriptor is constructed dynamically diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 219d18232a..dc0a4e3179 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1094,103 +1094,7 @@ static int dl_done_list(ohci_t *ohci) * Virtual Root Hub *-------------------------------------------------------------------------*/ -/* Device descriptor */ -static __u8 root_hub_dev_des[] = -{ - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, /* __u16 bcdUSB; v1.1 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x01, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static unsigned char root_hub_str_index0[] = -{ - 0x04, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 0x09, /* __u8 lang ID */ - 0x04, /* __u8 lang ID */ -}; - -static unsigned char root_hub_str_index1[] = -{ - 28, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 'O', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'C', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'I', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'R', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 't', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'u', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'b', /* __u8 Unicode */ - 0, /* __u8 Unicode */ -}; +#include <usbroothubdes.h> /* Hub class-specific descriptor is constructed dynamically */ diff --git a/drivers/usb/host/ohci-s3c24xx.c b/drivers/usb/host/ohci-s3c24xx.c index 42e564ef5e..3c659c60c9 100644 --- a/drivers/usb/host/ohci-s3c24xx.c +++ b/drivers/usb/host/ohci-s3c24xx.c @@ -873,100 +873,7 @@ static int dl_done_list(struct ohci *ohci, struct td *td_list) * Virtual Root Hub *-------------------------------------------------------------------------*/ -/* Device descriptor */ -static __u8 root_hub_dev_des[] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, /* __u16 bcdUSB; v1.1 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x01, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = { - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, 6: Self-powered, - 5 Remote-wakwup, 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static unsigned char root_hub_str_index0[] = { - 0x04, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 0x09, /* __u8 lang ID */ - 0x04, /* __u8 lang ID */ -}; - -static unsigned char root_hub_str_index1[] = { - 28, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 'O', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'C', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'I', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'R', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 't', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'u', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'b', /* __u8 Unicode */ - 0, /* __u8 Unicode */ -}; +#include <usbroothubdes.h> /* Hub class-specific descriptor is constructed dynamically */ diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index fd30d6726c..dfe5423b8a 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -557,109 +557,7 @@ static int check_usb_device_connecting(struct r8a66597 *r8a66597) * Virtual Root Hub *-------------------------------------------------------------------------*/ -/* Device descriptor */ -static __u8 root_hub_dev_des[] = -{ - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, /* __u16 bcdUSB; v1.1 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x01, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; */ - - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static unsigned char root_hub_str_index0[] = -{ - 0x04, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 0x09, /* __u8 lang ID */ - 0x04, /* __u8 lang ID */ -}; - -static unsigned char root_hub_str_index1[] = -{ - 34, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 'R', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '8', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'A', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '6', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '6', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '5', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '9', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - '7', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'R', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 't', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'u', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'b', /* __u8 Unicode */ - 0, /* __u8 Unicode */ -}; +#include <usbroothubdes.h> static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, struct devrequest *cmd) diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 799bd30e22..f0ba8aaaa3 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -28,99 +28,8 @@ static const struct musb_epinfo epinfo[3] = { static int rh_devnum; static u32 port_status; -/* Device descriptor */ -static const u8 root_hub_dev_des[] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x00, /* __u16 bcdUSB; v1.1 */ - 0x02, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x01, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* Configuration descriptor */ -static const u8 root_hub_config_des[] = { - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ - 0x02, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; +#include <usbroothubdes.h> -static const unsigned char root_hub_str_index0[] = { - 0x04, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 0x09, /* __u8 lang ID */ - 0x04, /* __u8 lang ID */ -}; - -static const unsigned char root_hub_str_index1[] = { - 0x1c, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 'M', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'U', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'S', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'B', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'R', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 't', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'u', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'b', /* __u8 Unicode */ - 0, /* __u8 Unicode */ -}; #endif /* diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 6db4073596..b52e9edd25 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -1473,7 +1473,11 @@ int video_display_bitmap(ulong bmp_image, int x, int y) printf("Error: malloc in gunzip failed!\n"); return 1; } - if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, + /* + * NB: we need to force offset of +2 + * See doc/README.displaying-bmps + */ + if (gunzip(dst+2, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE-2, (uchar *) bmp_image, &len) != 0) { printf("Error: no valid bmp or bmp.gz image at %lx\n", @@ -1489,7 +1493,7 @@ int video_display_bitmap(ulong bmp_image, int x, int y) /* * Set addr to decompressed image */ - bmp = (bmp_image_t *) dst; + bmp = (bmp_image_t *)(dst+2); if (!((bmp->header.signature[0] == 'B') && (bmp->header.signature[1] == 'M'))) { |