summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2016-05-17 13:58:27 -0400
committerTom Rini <trini@konsulko.com>2016-05-17 13:58:27 -0400
commit4b6e1fda107e5244e80ebc41865650ac2873dc88 (patch)
treef448089740af77c2987d12e2dd5b753b7659586f /drivers
parent27bec5c12757c80f598b704477c1bc6c250bcb4c (diff)
parent341392dd115f1385c31bb0b034ec15f542730e30 (diff)
downloadtalos-obmc-uboot-4b6e1fda107e5244e80ebc41865650ac2873dc88.tar.gz
talos-obmc-uboot-4b6e1fda107e5244e80ebc41865650ac2873dc88.zip
Merge git://git.denx.de/u-boot-dm
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/block/Kconfig5
-rw-r--r--drivers/block/Makefile8
-rw-r--r--drivers/block/ahci-uclass.c (renamed from drivers/block/disk-uclass.c)6
-rw-r--r--drivers/block/blk-uclass.c361
-rw-r--r--drivers/block/blk_legacy.c261
-rw-r--r--drivers/block/sandbox.c103
-rw-r--r--drivers/block/sandbox_scsi.c29
-rw-r--r--drivers/block/sata_sandbox.c33
-rw-r--r--drivers/block/sym53c8xx.c2
-rw-r--r--drivers/block/systemace.c110
-rw-r--r--drivers/core/device-remove.c2
-rw-r--r--drivers/core/device.c10
-rw-r--r--drivers/core/lists.c4
-rw-r--r--drivers/dfu/dfu_mmc.c13
-rw-r--r--drivers/gpio/74x164_gpio.c193
-rw-r--r--drivers/gpio/Kconfig30
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/gpio-uclass.c30
-rw-r--r--drivers/gpio/intel_broadwell_gpio.c10
-rw-r--r--drivers/gpio/omap_gpio.c11
-rw-r--r--drivers/gpio/pca953x_gpio.c351
-rw-r--r--drivers/gpio/pic32_gpio.c10
-rw-r--r--drivers/gpio/rk_gpio.c11
-rw-r--r--drivers/gpio/s5p_gpio.c11
-rw-r--r--drivers/mmc/Kconfig11
-rw-r--r--drivers/mmc/Makefile12
-rw-r--r--drivers/mmc/mmc-uclass.c106
-rw-r--r--drivers/mmc/mmc.c311
-rw-r--r--drivers/mmc/mmc_legacy.c108
-rw-r--r--drivers/mmc/mmc_private.h33
-rw-r--r--drivers/mmc/mmc_write.c18
-rw-r--r--drivers/mmc/omap_hsmmc.c1
-rw-r--r--drivers/mmc/pic32_sdhci.c7
-rw-r--r--drivers/mmc/rockchip_dw_mmc.c1
-rw-r--r--drivers/mmc/sandbox_mmc.c134
-rw-r--r--drivers/mmc/socfpga_dw_mmc.c1
-rw-r--r--drivers/mmc/uniphier-sd.c1
-rw-r--r--drivers/mmc/zynq_sdhci.c1
-rw-r--r--drivers/pci/pci.c4
-rw-r--r--drivers/serial/mcfuart.c188
-rw-r--r--drivers/spi/soft_spi.c55
-rw-r--r--drivers/spi/spi-uclass.c28
-rw-r--r--drivers/usb/common/Makefile1
-rw-r--r--drivers/usb/common/common.c40
-rw-r--r--drivers/video/tegra.c7
46 files changed, 2338 insertions, 339 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 6900097e79..99dd07fc76 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -36,6 +36,8 @@ obj-$(CONFIG_SPL_WATCHDOG_SUPPORT) += watchdog/
obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += usb/host/
obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/
obj-$(CONFIG_SPL_SATA_SUPPORT) += block/
+obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += block/
+obj-$(CONFIG_SPL_MMC_SUPPORT) += block/
else
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index fcc9ccdd7f..80eea84dc2 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -9,10 +9,9 @@ config BLK
be partitioned into several areas, called 'partitions' in U-Boot.
A filesystem can be placed in each partition.
-config DISK
- bool "Support disk controllers with driver model"
+config AHCI
+ bool "Support SATA controllers with driver model"
depends on DM
- default y if DM
help
This enables a uclass for disk controllers in U-Boot. Various driver
types can use this, such as AHCI/SATA. It does not provide any standard
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index a43492f208..436b79f981 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -7,7 +7,11 @@
obj-$(CONFIG_BLK) += blk-uclass.o
-obj-$(CONFIG_DISK) += disk-uclass.o
+ifndef CONFIG_BLK
+obj-y += blk_legacy.o
+endif
+
+obj-$(CONFIG_AHCI) += ahci-uclass.o
obj-$(CONFIG_SCSI_AHCI) += ahci.o
obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o
obj-$(CONFIG_FSL_SATA) += fsl_sata.o
@@ -22,7 +26,7 @@ obj-$(CONFIG_SATA_MV) += sata_mv.o
obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o
obj-$(CONFIG_SATA_SIL) += sata_sil.o
obj-$(CONFIG_IDE_SIL680) += sil680.o
-obj-$(CONFIG_SANDBOX) += sandbox.o
+obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o sata_sandbox.o
obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
obj-$(CONFIG_SYSTEMACE) += systemace.o
obj-$(CONFIG_BLOCK_CACHE) += blkcache.o
diff --git a/drivers/block/disk-uclass.c b/drivers/block/ahci-uclass.c
index d665b3505a..7b8c32699f 100644
--- a/drivers/block/disk-uclass.c
+++ b/drivers/block/ahci-uclass.c
@@ -8,7 +8,7 @@
#include <common.h>
#include <dm.h>
-UCLASS_DRIVER(disk) = {
- .id = UCLASS_DISK,
- .name = "disk",
+UCLASS_DRIVER(ahci) = {
+ .id = UCLASS_AHCI,
+ .name = "ahci",
};
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index 617db226a2..6ba1026f58 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -11,6 +11,315 @@
#include <dm/device-internal.h>
#include <dm/lists.h>
+static const char *if_typename_str[IF_TYPE_COUNT] = {
+ [IF_TYPE_IDE] = "ide",
+ [IF_TYPE_SCSI] = "scsi",
+ [IF_TYPE_ATAPI] = "atapi",
+ [IF_TYPE_USB] = "usb",
+ [IF_TYPE_DOC] = "doc",
+ [IF_TYPE_MMC] = "mmc",
+ [IF_TYPE_SD] = "sd",
+ [IF_TYPE_SATA] = "sata",
+ [IF_TYPE_HOST] = "host",
+ [IF_TYPE_SYSTEMACE] = "ace",
+};
+
+static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
+ [IF_TYPE_IDE] = UCLASS_INVALID,
+ [IF_TYPE_SCSI] = UCLASS_INVALID,
+ [IF_TYPE_ATAPI] = UCLASS_INVALID,
+ [IF_TYPE_USB] = UCLASS_MASS_STORAGE,
+ [IF_TYPE_DOC] = UCLASS_INVALID,
+ [IF_TYPE_MMC] = UCLASS_MMC,
+ [IF_TYPE_SD] = UCLASS_INVALID,
+ [IF_TYPE_SATA] = UCLASS_AHCI,
+ [IF_TYPE_HOST] = UCLASS_ROOT,
+ [IF_TYPE_SYSTEMACE] = UCLASS_INVALID,
+};
+
+static enum if_type if_typename_to_iftype(const char *if_typename)
+{
+ int i;
+
+ for (i = 0; i < IF_TYPE_COUNT; i++) {
+ if (if_typename_str[i] &&
+ !strcmp(if_typename, if_typename_str[i]))
+ return i;
+ }
+
+ return IF_TYPE_UNKNOWN;
+}
+
+static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
+{
+ return if_type_uclass_id[if_type];
+}
+
+struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
+{
+ struct blk_desc *desc;
+ struct udevice *dev;
+ int ret;
+
+ ret = blk_get_device(if_type, devnum, &dev);
+ if (ret)
+ return NULL;
+ desc = dev_get_uclass_platdata(dev);
+
+ return desc;
+}
+
+/*
+ * This function is complicated with driver model. We look up the interface
+ * name in a local table. This gives us an interface type which we can match
+ * against the uclass of the block device's parent.
+ */
+struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
+{
+ enum uclass_id uclass_id;
+ enum if_type if_type;
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ if_type = if_typename_to_iftype(if_typename);
+ if (if_type == IF_TYPE_UNKNOWN) {
+ debug("%s: Unknown interface type '%s'\n", __func__,
+ if_typename);
+ return NULL;
+ }
+ uclass_id = if_type_to_uclass_id(if_type);
+ if (uclass_id == UCLASS_INVALID) {
+ debug("%s: Unknown uclass for interface type'\n",
+ if_typename_str[if_type]);
+ return NULL;
+ }
+
+ ret = uclass_get(UCLASS_BLK, &uc);
+ if (ret)
+ return NULL;
+ uclass_foreach_dev(dev, uc) {
+ struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+ debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
+ if_type, devnum, dev->name, desc->if_type, desc->devnum);
+ if (desc->devnum != devnum)
+ continue;
+
+ /* Find out the parent device uclass */
+ if (device_get_uclass_id(dev->parent) != uclass_id) {
+ debug("%s: parent uclass %d, this dev %d\n", __func__,
+ device_get_uclass_id(dev->parent), uclass_id);
+ continue;
+ }
+
+ if (device_probe(dev))
+ return NULL;
+
+ debug("%s: Device desc %p\n", __func__, desc);
+ return desc;
+ }
+ debug("%s: No device found\n", __func__);
+
+ return NULL;
+}
+
+/**
+ * get_desc() - Get the block device descriptor for the given device number
+ *
+ * @if_type: Interface type
+ * @devnum: Device number (0 = first)
+ * @descp: Returns block device descriptor on success
+ * @return 0 on success, -ENODEV if there is no such device and no device
+ * with a higher device number, -ENOENT if there is no such device but there
+ * is one with a higher number, or other -ve on other error.
+ */
+static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
+{
+ bool found_more = false;
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ *descp = NULL;
+ ret = uclass_get(UCLASS_BLK, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(dev, uc) {
+ struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+ debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
+ if_type, devnum, dev->name, desc->if_type, desc->devnum);
+ if (desc->if_type == if_type) {
+ if (desc->devnum == devnum) {
+ ret = device_probe(dev);
+ if (ret)
+ return ret;
+
+ } else if (desc->devnum > devnum) {
+ found_more = true;
+ }
+ }
+ }
+
+ return found_more ? -ENOENT : -ENODEV;
+}
+
+int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = blk_get_device(if_type, devnum, &dev);
+ if (ret)
+ return ret;
+
+ return blk_select_hwpart(dev, hwpart);
+}
+
+int blk_list_part(enum if_type if_type)
+{
+ struct blk_desc *desc;
+ int devnum, ok;
+ int ret;
+
+ for (ok = 0, devnum = 0;; ++devnum) {
+ ret = get_desc(if_type, devnum, &desc);
+ if (ret == -ENODEV)
+ break;
+ else if (ret)
+ continue;
+ if (desc->part_type != PART_TYPE_UNKNOWN) {
+ ++ok;
+ if (devnum)
+ putc('\n');
+ part_print(desc);
+ }
+ }
+ if (!ok)
+ return -ENODEV;
+
+ return 0;
+}
+
+int blk_print_part_devnum(enum if_type if_type, int devnum)
+{
+ struct blk_desc *desc;
+ int ret;
+
+ ret = get_desc(if_type, devnum, &desc);
+ if (ret)
+ return ret;
+ if (desc->type == DEV_TYPE_UNKNOWN)
+ return -ENOENT;
+ part_print(desc);
+
+ return 0;
+}
+
+void blk_list_devices(enum if_type if_type)
+{
+ struct blk_desc *desc;
+ int ret;
+ int i;
+
+ for (i = 0;; ++i) {
+ ret = get_desc(if_type, i, &desc);
+ if (ret == -ENODEV)
+ break;
+ else if (ret)
+ continue;
+ if (desc->type == DEV_TYPE_UNKNOWN)
+ continue; /* list only known devices */
+ printf("Device %d: ", i);
+ dev_print(desc);
+ }
+}
+
+int blk_print_device_num(enum if_type if_type, int devnum)
+{
+ struct blk_desc *desc;
+ int ret;
+
+ ret = get_desc(if_type, devnum, &desc);
+ if (ret)
+ return ret;
+ printf("\nIDE device %d: ", devnum);
+ dev_print(desc);
+
+ return 0;
+}
+
+int blk_show_device(enum if_type if_type, int devnum)
+{
+ struct blk_desc *desc;
+ int ret;
+
+ printf("\nDevice %d: ", devnum);
+ ret = get_desc(if_type, devnum, &desc);
+ if (ret == -ENODEV || ret == -ENOENT) {
+ printf("unknown device\n");
+ return -ENODEV;
+ }
+ if (ret)
+ return ret;
+ dev_print(desc);
+
+ if (desc->type == DEV_TYPE_UNKNOWN)
+ return -ENOENT;
+
+ return 0;
+}
+
+ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
+ lbaint_t blkcnt, void *buffer)
+{
+ struct blk_desc *desc;
+ ulong n;
+ int ret;
+
+ ret = get_desc(if_type, devnum, &desc);
+ if (ret)
+ return ret;
+ n = blk_dread(desc, start, blkcnt, buffer);
+ if (IS_ERR_VALUE(n))
+ return n;
+
+ /* flush cache after read */
+ flush_cache((ulong)buffer, blkcnt * desc->blksz);
+
+ return n;
+}
+
+ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ struct blk_desc *desc;
+ int ret;
+
+ ret = get_desc(if_type, devnum, &desc);
+ if (ret)
+ return ret;
+ return blk_dwrite(desc, start, blkcnt, buffer);
+}
+
+int blk_select_hwpart(struct udevice *dev, int hwpart)
+{
+ const struct blk_ops *ops = blk_get_ops(dev);
+
+ if (!ops)
+ return -ENOSYS;
+ if (!ops->select_hwpart)
+ return 0;
+
+ return ops->select_hwpart(dev, hwpart);
+}
+
+int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
+{
+ return blk_select_hwpart(desc->bdev, hwpart);
+}
+
int blk_first_device(int if_type, struct udevice **devp)
{
struct blk_desc *desc;
@@ -131,6 +440,26 @@ int blk_prepare_device(struct udevice *dev)
return 0;
}
+int blk_find_max_devnum(enum if_type if_type)
+{
+ struct udevice *dev;
+ int max_devnum = -ENODEV;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_BLK, &uc);
+ if (ret)
+ return ret;
+ uclass_foreach_dev(dev, uc) {
+ struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+ if (desc->if_type == if_type && desc->devnum > max_devnum)
+ max_devnum = desc->devnum;
+ }
+
+ return max_devnum;
+}
+
int blk_create_device(struct udevice *parent, const char *drv_name,
const char *name, int if_type, int devnum, int blksz,
lbaint_t size, struct udevice **devp)
@@ -139,6 +468,15 @@ int blk_create_device(struct udevice *parent, const char *drv_name,
struct udevice *dev;
int ret;
+ if (devnum == -1) {
+ ret = blk_find_max_devnum(if_type);
+ if (ret == -ENODEV)
+ devnum = 0;
+ else if (ret < 0)
+ return ret;
+ else
+ devnum = ret + 1;
+ }
ret = device_bind_driver(parent, drv_name, name, &dev);
if (ret)
return ret;
@@ -154,6 +492,29 @@ int blk_create_device(struct udevice *parent, const char *drv_name,
return 0;
}
+int blk_create_devicef(struct udevice *parent, const char *drv_name,
+ const char *name, int if_type, int devnum, int blksz,
+ lbaint_t size, struct udevice **devp)
+{
+ char dev_name[30], *str;
+ int ret;
+
+ snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
+ str = strdup(dev_name);
+ if (!str)
+ return -ENOMEM;
+
+ ret = blk_create_device(parent, drv_name, str, if_type, devnum,
+ blksz, size, devp);
+ if (ret) {
+ free(str);
+ return ret;
+ }
+ device_set_name_alloced(*devp);
+
+ return ret;
+}
+
int blk_unbind_all(int if_type)
{
struct uclass *uc;
diff --git a/drivers/block/blk_legacy.c b/drivers/block/blk_legacy.c
new file mode 100644
index 0000000000..7b90a8a6e1
--- /dev/null
+++ b/drivers/block/blk_legacy.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+
+struct blk_driver *blk_driver_lookup_type(int if_type)
+{
+ struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
+ const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
+ struct blk_driver *entry;
+
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ if (if_type == entry->if_type)
+ return entry;
+ }
+
+ /* Not found */
+ return NULL;
+}
+
+static struct blk_driver *blk_driver_lookup_typename(const char *if_typename)
+{
+ struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
+ const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
+ struct blk_driver *entry;
+
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ if (!strcmp(if_typename, entry->if_typename))
+ return entry;
+ }
+
+ /* Not found */
+ return NULL;
+}
+
+/**
+ * get_desc() - Get the block device descriptor for the given device number
+ *
+ * @drv: Legacy block driver
+ * @devnum: Device number (0 = first)
+ * @descp: Returns block device descriptor on success
+ * @return 0 on success, -ENODEV if there is no such device, -ENOSYS if the
+ * driver does not provide a way to find a device, or other -ve on other
+ * error.
+ */
+static int get_desc(struct blk_driver *drv, int devnum, struct blk_desc **descp)
+{
+ if (drv->desc) {
+ if (devnum < 0 || devnum >= drv->max_devs)
+ return -ENODEV;
+ *descp = &drv->desc[devnum];
+ return 0;
+ }
+ if (!drv->get_dev)
+ return -ENOSYS;
+
+ return drv->get_dev(devnum, descp);
+}
+
+#ifdef HAVE_BLOCK_DEVICE
+int blk_list_part(enum if_type if_type)
+{
+ struct blk_driver *drv;
+ struct blk_desc *desc;
+ int devnum, ok;
+ bool first = true;
+
+ drv = blk_driver_lookup_type(if_type);
+ if (!drv)
+ return -ENOSYS;
+ for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) {
+ if (get_desc(drv, devnum, &desc))
+ continue;
+ if (desc->part_type != PART_TYPE_UNKNOWN) {
+ ++ok;
+ if (!first)
+ putc('\n');
+ part_print(desc);
+ first = false;
+ }
+ }
+ if (!ok)
+ return -ENODEV;
+
+ return 0;
+}
+
+int blk_print_part_devnum(enum if_type if_type, int devnum)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(if_type);
+ struct blk_desc *desc;
+ int ret;
+
+ if (!drv)
+ return -ENOSYS;
+ ret = get_desc(drv, devnum, &desc);
+ if (ret)
+ return ret;
+ if (desc->type == DEV_TYPE_UNKNOWN)
+ return -ENOENT;
+ part_print(desc);
+
+ return 0;
+}
+
+void blk_list_devices(enum if_type if_type)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(if_type);
+ struct blk_desc *desc;
+ int i;
+
+ if (!drv)
+ return;
+ for (i = 0; i < drv->max_devs; ++i) {
+ if (get_desc(drv, i, &desc))
+ continue;
+ if (desc->type == DEV_TYPE_UNKNOWN)
+ continue; /* list only known devices */
+ printf("Device %d: ", i);
+ dev_print(desc);
+ }
+}
+
+int blk_print_device_num(enum if_type if_type, int devnum)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(if_type);
+ struct blk_desc *desc;
+ int ret;
+
+ if (!drv)
+ return -ENOSYS;
+ ret = get_desc(drv, devnum, &desc);
+ if (ret)
+ return ret;
+ printf("\n%s device %d: ", drv->if_typename, devnum);
+ dev_print(desc);
+
+ return 0;
+}
+
+int blk_show_device(enum if_type if_type, int devnum)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(if_type);
+ struct blk_desc *desc;
+ int ret;
+
+ if (!drv)
+ return -ENOSYS;
+ printf("\nDevice %d: ", devnum);
+ if (devnum >= drv->max_devs) {
+ puts("unknown device\n");
+ return -ENODEV;
+ }
+ ret = get_desc(drv, devnum, &desc);
+ if (ret)
+ return ret;
+ dev_print(desc);
+
+ if (desc->type == DEV_TYPE_UNKNOWN)
+ return -ENOENT;
+
+ return 0;
+}
+#endif /* HAVE_BLOCK_DEVICE */
+
+struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(if_type);
+ struct blk_desc *desc;
+
+ if (!drv)
+ return NULL;
+
+ if (get_desc(drv, devnum, &desc))
+ return NULL;
+
+ return desc;
+}
+
+int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(desc->if_type);
+
+ if (!drv)
+ return -ENOSYS;
+ if (drv->select_hwpart)
+ return drv->select_hwpart(desc, hwpart);
+
+ return 0;
+}
+
+struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
+{
+ struct blk_driver *drv = blk_driver_lookup_typename(if_typename);
+ struct blk_desc *desc;
+
+ if (!drv)
+ return NULL;
+
+ if (get_desc(drv, devnum, &desc))
+ return NULL;
+
+ return desc;
+}
+
+ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
+ lbaint_t blkcnt, void *buffer)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(if_type);
+ struct blk_desc *desc;
+ ulong n;
+ int ret;
+
+ if (!drv)
+ return -ENOSYS;
+ ret = get_desc(drv, devnum, &desc);
+ if (ret)
+ return ret;
+ n = desc->block_read(desc, start, blkcnt, buffer);
+ if (IS_ERR_VALUE(n))
+ return n;
+
+ /* flush cache after read */
+ flush_cache((ulong)buffer, blkcnt * desc->blksz);
+
+ return n;
+}
+
+ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(if_type);
+ struct blk_desc *desc;
+ int ret;
+
+ if (!drv)
+ return -ENOSYS;
+ ret = get_desc(drv, devnum, &desc);
+ if (ret)
+ return ret;
+ return desc->block_write(desc, start, blkcnt, buffer);
+}
+
+int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
+{
+ struct blk_driver *drv = blk_driver_lookup_type(if_type);
+ struct blk_desc *desc;
+ int ret;
+
+ if (!drv)
+ return -ENOSYS;
+ ret = get_desc(drv, devnum, &desc);
+ if (ret)
+ return ret;
+ return drv->select_hwpart(desc, hwpart);
+}
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
index 2d340efd32..ac28f83472 100644
--- a/drivers/block/sandbox.c
+++ b/drivers/block/sandbox.c
@@ -17,6 +17,19 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_BLK
+static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES];
+
+static struct host_block_dev *find_host_device(int dev)
+{
+ if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES)
+ return &host_devices[dev];
+
+ return NULL;
+}
+#endif
+
+#ifdef CONFIG_BLK
static unsigned long host_block_read(struct udevice *dev,
unsigned long start, lbaint_t blkcnt,
void *buffer)
@@ -24,6 +37,18 @@ static unsigned long host_block_read(struct udevice *dev,
struct host_block_dev *host_dev = dev_get_priv(dev);
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#else
+static unsigned long host_block_read(struct blk_desc *block_dev,
+ unsigned long start, lbaint_t blkcnt,
+ void *buffer)
+{
+ int dev = block_dev->devnum;
+ struct host_block_dev *host_dev = find_host_device(dev);
+
+ if (!host_dev)
+ return -1;
+#endif
+
if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
-1) {
printf("ERROR: Invalid block %lx\n", start);
@@ -35,12 +60,21 @@ static unsigned long host_block_read(struct udevice *dev,
return -1;
}
+#ifdef CONFIG_BLK
static unsigned long host_block_write(struct udevice *dev,
unsigned long start, lbaint_t blkcnt,
const void *buffer)
{
struct host_block_dev *host_dev = dev_get_priv(dev);
struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#else
+static unsigned long host_block_write(struct blk_desc *block_dev,
+ unsigned long start, lbaint_t blkcnt,
+ const void *buffer)
+{
+ int dev = block_dev->devnum;
+ struct host_block_dev *host_dev = find_host_device(dev);
+#endif
if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
-1) {
@@ -53,6 +87,7 @@ static unsigned long host_block_write(struct udevice *dev,
return -1;
}
+#ifdef CONFIG_BLK
int host_dev_bind(int devnum, char *filename)
{
struct host_block_dev *host_dev;
@@ -115,9 +150,51 @@ err:
free(str);
return ret;
}
+#else
+int host_dev_bind(int dev, char *filename)
+{
+ struct host_block_dev *host_dev = find_host_device(dev);
+
+ if (!host_dev)
+ return -1;
+ if (host_dev->blk_dev.priv) {
+ os_close(host_dev->fd);
+ host_dev->blk_dev.priv = NULL;
+ }
+ if (host_dev->filename)
+ free(host_dev->filename);
+ if (filename && *filename) {
+ host_dev->filename = strdup(filename);
+ } else {
+ host_dev->filename = NULL;
+ return 0;
+ }
+
+ host_dev->fd = os_open(host_dev->filename, OS_O_RDWR);
+ if (host_dev->fd == -1) {
+ printf("Failed to access host backing file '%s'\n",
+ host_dev->filename);
+ return 1;
+ }
+
+ struct blk_desc *blk_dev = &host_dev->blk_dev;
+ blk_dev->if_type = IF_TYPE_HOST;
+ blk_dev->priv = host_dev;
+ blk_dev->blksz = 512;
+ blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz;
+ blk_dev->block_read = host_block_read;
+ blk_dev->block_write = host_block_write;
+ blk_dev->devnum = dev;
+ blk_dev->part_type = PART_TYPE_UNKNOWN;
+ part_init(blk_dev);
+
+ return 0;
+}
+#endif
int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
{
+#ifdef CONFIG_BLK
struct udevice *dev;
int ret;
@@ -125,20 +202,22 @@ int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
if (ret)
return ret;
*blk_devp = dev_get_uclass_platdata(dev);
+#else
+ struct host_block_dev *host_dev = find_host_device(devnum);
- return 0;
-}
+ if (!host_dev)
+ return -ENODEV;
-struct blk_desc *host_get_dev(int dev)
-{
- struct blk_desc *blk_dev;
+ if (!host_dev->blk_dev.priv)
+ return -ENOENT;
- if (host_get_dev_err(dev, &blk_dev))
- return NULL;
+ *blk_devp = &host_dev->blk_dev;
+#endif
- return blk_dev;
+ return 0;
}
+#ifdef CONFIG_BLK
static const struct blk_ops sandbox_host_blk_ops = {
.read = host_block_read,
.write = host_block_write,
@@ -150,3 +229,11 @@ U_BOOT_DRIVER(sandbox_host_blk) = {
.ops = &sandbox_host_blk_ops,
.priv_auto_alloc_size = sizeof(struct host_block_dev),
};
+#else
+U_BOOT_LEGACY_BLK(sandbox_host) = {
+ .if_typename = "host",
+ .if_type = IF_TYPE_HOST,
+ .max_devs = CONFIG_HOST_MAX_DEVICES,
+ .get_dev = host_get_dev_err,
+};
+#endif
diff --git a/drivers/block/sandbox_scsi.c b/drivers/block/sandbox_scsi.c
new file mode 100644
index 0000000000..ad961bd225
--- /dev/null
+++ b/drivers/block/sandbox_scsi.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This file contains dummy implementations of SCSI functions requried so
+ * that CONFIG_SCSI can be enabled for sandbox.
+ */
+
+#include <common.h>
+#include <scsi.h>
+
+void scsi_bus_reset(void)
+{
+}
+
+void scsi_init(void)
+{
+}
+
+int scsi_exec(ccb *pccb)
+{
+ return 0;
+}
+
+void scsi_print_error(ccb *pccb)
+{
+}
diff --git a/drivers/block/sata_sandbox.c b/drivers/block/sata_sandbox.c
new file mode 100644
index 0000000000..bd967d290c
--- /dev/null
+++ b/drivers/block/sata_sandbox.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+int init_sata(int dev)
+{
+ return 0;
+}
+
+int reset_sata(int dev)
+{
+ return 0;
+}
+
+int scan_sata(int dev)
+{
+ return 0;
+}
+
+ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
+{
+ return 0;
+}
+
+ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
+{
+ return 0;
+}
diff --git a/drivers/block/sym53c8xx.c b/drivers/block/sym53c8xx.c
index c7c40affae..5daede7279 100644
--- a/drivers/block/sym53c8xx.c
+++ b/drivers/block/sym53c8xx.c
@@ -33,7 +33,7 @@
#define PRINTF(fmt,args...)
#endif
-#if defined(CONFIG_CMD_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
+#if defined(CONFIG_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
#undef SCSI_SINGLE_STEP
/*
diff --git a/drivers/block/systemace.c b/drivers/block/systemace.c
index 09fe834e22..9392beaf05 100644
--- a/drivers/block/systemace.c
+++ b/drivers/block/systemace.c
@@ -27,7 +27,7 @@
#include <common.h>
#include <command.h>
-#include <systemace.h>
+#include <dm.h>
#include <part.h>
#include <asm/io.h>
@@ -69,11 +69,9 @@ static u16 ace_readw(unsigned off)
return in16(base + off);
}
-static unsigned long systemace_read(struct blk_desc *block_dev,
- unsigned long start, lbaint_t blkcnt,
- void *buffer);
-
+#ifndef CONFIG_BLK
static struct blk_desc systemace_dev = { 0 };
+#endif
static int get_cf_lock(void)
{
@@ -104,42 +102,19 @@ static void release_cf_lock(void)
ace_writew((val & 0xffff), 0x18);
}
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *systemace_get_dev(int dev)
-{
- /* The first time through this, the systemace_dev object is
- not yet initialized. In that case, fill it in. */
- if (systemace_dev.blksz == 0) {
- systemace_dev.if_type = IF_TYPE_UNKNOWN;
- systemace_dev.devnum = 0;
- systemace_dev.part_type = PART_TYPE_UNKNOWN;
- systemace_dev.type = DEV_TYPE_HARDDISK;
- systemace_dev.blksz = 512;
- systemace_dev.log2blksz = LOG2(systemace_dev.blksz);
- systemace_dev.removable = 1;
- systemace_dev.block_read = systemace_read;
-
- /*
- * Ensure the correct bus mode (8/16 bits) gets enabled
- */
- ace_writew(width == 8 ? 0 : 0x0001, 0);
-
- part_init(&systemace_dev);
-
- }
-
- return &systemace_dev;
-}
-#endif
-
/*
* This function is called (by dereferencing the block_read pointer in
* the dev_desc) to read blocks of data. The return value is the
* number of blocks read. A zero return indicates an error.
*/
+#ifdef CONFIG_BLK
+static unsigned long systemace_read(struct udevice *dev, unsigned long start,
+ lbaint_t blkcnt, void *buffer)
+#else
static unsigned long systemace_read(struct blk_desc *block_dev,
unsigned long start, lbaint_t blkcnt,
void *buffer)
+#endif
{
int retry;
unsigned blk_countdown;
@@ -257,3 +232,72 @@ static unsigned long systemace_read(struct blk_desc *block_dev,
return blkcnt;
}
+
+#ifdef CONFIG_BLK
+static int systemace_bind(struct udevice *dev)
+{
+ struct blk_desc *bdesc;
+ struct udevice *bdev;
+ int ret;
+
+ ret = blk_create_devicef(dev, "systemace_blk", "blk", IF_TYPE_SYSTEMACE,
+ -1, 512, 0, &bdev);
+ if (ret) {
+ debug("Cannot create block device\n");
+ return ret;
+ }
+ bdesc = dev_get_uclass_platdata(bdev);
+ bdesc->removable = 1;
+ bdesc->part_type = PART_TYPE_UNKNOWN;
+ bdesc->log2blksz = LOG2(bdesc->blksz);
+
+ /* Ensure the correct bus mode (8/16 bits) gets enabled */
+ ace_writew(width == 8 ? 0 : 0x0001, 0);
+
+ return 0;
+}
+
+static const struct blk_ops systemace_blk_ops = {
+ .read = systemace_read,
+};
+
+U_BOOT_DRIVER(systemace_blk) = {
+ .name = "systemace_blk",
+ .id = UCLASS_BLK,
+ .ops = &systemace_blk_ops,
+ .bind = systemace_bind,
+};
+#else
+static int systemace_get_dev(int dev, struct blk_desc **descp)
+{
+ /* The first time through this, the systemace_dev object is
+ not yet initialized. In that case, fill it in. */
+ if (systemace_dev.blksz == 0) {
+ systemace_dev.if_type = IF_TYPE_UNKNOWN;
+ systemace_dev.devnum = 0;
+ systemace_dev.part_type = PART_TYPE_UNKNOWN;
+ systemace_dev.type = DEV_TYPE_HARDDISK;
+ systemace_dev.blksz = 512;
+ systemace_dev.log2blksz = LOG2(systemace_dev.blksz);
+ systemace_dev.removable = 1;
+ systemace_dev.block_read = systemace_read;
+
+ /*
+ * Ensure the correct bus mode (8/16 bits) gets enabled
+ */
+ ace_writew(width == 8 ? 0 : 0x0001, 0);
+
+ part_init(&systemace_dev);
+ }
+ *descp = &systemace_dev;
+
+ return 0;
+}
+
+U_BOOT_LEGACY_BLK(systemace) = {
+ .if_typename = "ace",
+ .if_type = IF_TYPE_SYSTEMACE,
+ .max_devs = 1,
+ .get_dev = systemace_get_dev,
+};
+#endif
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index e1714b2202..0e56b23fbb 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -112,6 +112,8 @@ int device_unbind(struct udevice *dev)
devres_release_all(dev);
+ if (dev->flags & DM_NAME_ALLOCED)
+ free((char *)dev->name);
free(dev);
return 0;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 1322991d6c..5c2dc7021f 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -657,8 +657,8 @@ fdt_addr_t dev_get_addr_name(struct udevice *dev, const char *name)
#if CONFIG_IS_ENABLED(OF_CONTROL)
int index;
- index = fdt_find_string(gd->fdt_blob, dev->parent->of_offset,
- "reg-names", name);
+ index = fdt_find_string(gd->fdt_blob, dev->of_offset, "reg-names",
+ name);
if (index < 0)
return index;
@@ -706,12 +706,18 @@ bool device_is_last_sibling(struct udevice *dev)
return list_is_last(&dev->sibling_node, &parent->child_head);
}
+void device_set_name_alloced(struct udevice *dev)
+{
+ dev->flags |= DM_NAME_ALLOCED;
+}
+
int device_set_name(struct udevice *dev, const char *name)
{
name = strdup(name);
if (!name)
return -ENOMEM;
dev->name = name;
+ device_set_name_alloced(dev);
return 0;
}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index c4fc216340..a72db13a11 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -171,6 +171,10 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
dm_dbg(" - found match at '%s'\n", entry->name);
ret = device_bind(parent, entry, name, NULL, offset, &dev);
+ if (ret == -ENODEV) {
+ dm_dbg("Driver '%s' refuses to bind\n", entry->name);
+ continue;
+ }
if (ret) {
dm_warn("Error binding driver '%s': %d\n", entry->name,
ret);
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index faece8883a..78724e467b 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -50,8 +50,9 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
if (dfu->data.mmc.hw_partition >= 0) {
part_num_bkp = mmc->block_dev.hwpart;
- ret = mmc_select_hwpart(dfu->data.mmc.dev_num,
- dfu->data.mmc.hw_partition);
+ ret = blk_select_hwpart_devnum(IF_TYPE_MMC,
+ dfu->data.mmc.dev_num,
+ dfu->data.mmc.hw_partition);
if (ret)
return ret;
}
@@ -75,12 +76,16 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
if (n != blk_count) {
error("MMC operation failed");
if (dfu->data.mmc.hw_partition >= 0)
- mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
+ blk_select_hwpart_devnum(IF_TYPE_MMC,
+ dfu->data.mmc.dev_num,
+ part_num_bkp);
return -EIO;
}
if (dfu->data.mmc.hw_partition >= 0) {
- ret = mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
+ ret = blk_select_hwpart_devnum(IF_TYPE_MMC,
+ dfu->data.mmc.dev_num,
+ part_num_bkp);
if (ret)
return ret;
}
diff --git a/drivers/gpio/74x164_gpio.c b/drivers/gpio/74x164_gpio.c
new file mode 100644
index 0000000000..9ac10a745d
--- /dev/null
+++ b/drivers/gpio/74x164_gpio.c
@@ -0,0 +1,193 @@
+/*
+ * Take drivers/gpio/gpio-74x164.c as reference.
+ *
+ * 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
+ *
+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <spi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * struct gen_74x164_chip - Data for 74Hx164
+ *
+ * @oe: OE pin
+ * @nregs: number of registers
+ * @buffer: buffer for chained chips
+ */
+#define GEN_74X164_NUMBER_GPIOS 8
+
+struct gen_74x164_priv {
+ struct gpio_desc oe;
+ u32 nregs;
+ /*
+ * Since the nregs are chained, every byte sent will make
+ * the previous byte shift to the next register in the
+ * chain. Thus, the first byte sent will end up in the last
+ * register at the end of the transfer. So, to have a logical
+ * numbering, store the bytes in reverse order.
+ */
+ u8 *buffer;
+};
+
+static int gen_74x164_write_conf(struct udevice *dev)
+{
+ struct gen_74x164_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = dm_spi_claim_bus(dev);
+ if (ret)
+ return ret;
+
+ ret = dm_spi_xfer(dev, priv->nregs * 8, priv->buffer, NULL,
+ SPI_XFER_BEGIN | SPI_XFER_END);
+
+ dm_spi_release_bus(dev);
+
+ return ret;
+}
+
+static int gen_74x164_get_value(struct udevice *dev, unsigned offset)
+{
+ struct gen_74x164_priv *priv = dev_get_priv(dev);
+ uint bank = priv->nregs - 1 - offset / 8;
+ uint pin = offset % 8;
+
+ return (priv->buffer[bank] >> pin) & 0x1;
+}
+
+static int gen_74x164_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct gen_74x164_priv *priv = dev_get_priv(dev);
+ uint bank = priv->nregs - 1 - offset / 8;
+ uint pin = offset % 8;
+ int ret;
+
+ if (value)
+ priv->buffer[bank] |= 1 << pin;
+ else
+ priv->buffer[bank] &= ~(1 << pin);
+
+ ret = gen_74x164_write_conf(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int gen_74x164_direction_input(struct udevice *dev, unsigned offset)
+{
+ return -ENOSYS;
+}
+
+static int gen_74x164_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ return gen_74x164_set_value(dev, offset, value);
+}
+
+static int gen_74x164_get_function(struct udevice *dev, unsigned offset)
+{
+ return GPIOF_OUTPUT;
+}
+
+static int gen_74x164_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct fdtdec_phandle_args *args)
+{
+ desc->offset = args->args[0];
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops gen_74x164_ops = {
+ .direction_input = gen_74x164_direction_input,
+ .direction_output = gen_74x164_direction_output,
+ .get_value = gen_74x164_get_value,
+ .set_value = gen_74x164_set_value,
+ .get_function = gen_74x164_get_function,
+ .xlate = gen_74x164_xlate,
+};
+
+static int gen_74x164_probe(struct udevice *dev)
+{
+ struct gen_74x164_priv *priv = dev_get_priv(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ char *str, name[32];
+ int ret;
+ const void *fdt = gd->fdt_blob;
+ int node = dev->of_offset;
+
+ snprintf(name, sizeof(name), "%s_", dev->name);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+
+ /*
+ * See Linux kernel:
+ * Documentation/devicetree/bindings/gpio/gpio-74x164.txt
+ */
+ priv->nregs = fdtdec_get_int(fdt, node, "registers-number", 1);
+ priv->buffer = calloc(priv->nregs, sizeof(u8));
+ if (!priv->buffer) {
+ ret = -ENOMEM;
+ goto free_str;
+ }
+
+ ret = fdtdec_get_byte_array(fdt, node, "registers-default",
+ priv->buffer, priv->nregs);
+ if (ret)
+ dev_dbg(dev, "No registers-default property\n");
+
+ ret = gpio_request_by_name(dev, "oe-gpios", 0, &priv->oe,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret) {
+ dev_err(dev, "No oe-pins property\n");
+ goto free_buf;
+ }
+
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = priv->nregs * 8;
+
+ ret = gen_74x164_write_conf(dev);
+ if (ret)
+ goto free_buf;
+
+ dev_dbg(dev, "%s is ready\n", dev->name);
+
+ return 0;
+
+free_buf:
+ free(priv->buffer);
+free_str:
+ free(str);
+ return ret;
+}
+
+static const struct udevice_id gen_74x164_ids[] = {
+ { .compatible = "fairchild,74hc595" },
+ { }
+};
+
+U_BOOT_DRIVER(74x164) = {
+ .name = "74x164",
+ .id = UCLASS_GPIO,
+ .ops = &gen_74x164_ops,
+ .probe = gen_74x164_probe,
+ .priv_auto_alloc_size = sizeof(struct gen_74x164_priv),
+ .of_match = gen_74x164_ids,
+};
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 2b4624d7f8..93a7e8c6c2 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -143,4 +143,34 @@ config ZYNQ_GPIO
help
Supports GPIO access on Zynq SoC.
+config DM_74X164
+ bool "74x164 serial-in/parallel-out 8-bits shift register"
+ depends on DM_GPIO
+ help
+ Driver for 74x164 compatible serial-in/parallel-out 8-outputs
+ shift registers, such as 74lv165, 74hc595.
+ This driver can be used to provide access to more gpio outputs.
+
+config DM_PCA953X
+ bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
+ depends on DM_GPIO
+ help
+ Say yes here to provide access to several register-oriented
+ SMBus I/O expanders, made mostly by NXP or TI. Compatible
+ models include:
+
+ 4 bits: pca9536, pca9537
+
+ 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
+ pca9556, pca9557, pca9574, tca6408, xra1202
+
+ 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
+ tca6416
+
+ 24 bits: tca6424
+
+ 40 bits: pca9505, pca9698
+
+ Now, max 24 bits chips and PCA953X compatible chips are
+ supported
endmenu
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4f071c4517..ddec1ef8de 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -11,6 +11,9 @@ obj-$(CONFIG_AXP_GPIO) += axp_gpio.o
endif
obj-$(CONFIG_DM_GPIO) += gpio-uclass.o
+obj-$(CONFIG_DM_PCA953X) += pca953x_gpio.o
+obj-$(CONFIG_DM_74X164) += 74x164_gpio.o
+
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index b58d4e64e8..732b6c2afa 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <dm.h>
+#include <dt-bindings/gpio/gpio.h>
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
@@ -113,19 +114,33 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
return 0;
}
+int gpio_xlate_offs_flags(struct udevice *dev,
+ struct gpio_desc *desc,
+ struct fdtdec_phandle_args *args)
+{
+ if (args->args_count < 1)
+ return -EINVAL;
+
+ desc->offset = args->args[0];
+
+ if (args->args_count < 2)
+ return 0;
+
+ if (args->args[1] & GPIO_ACTIVE_LOW)
+ desc->flags = GPIOD_ACTIVE_LOW;
+
+ return 0;
+}
+
static int gpio_find_and_xlate(struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
{
struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
- /* Use the first argument as the offset by default */
- if (args->args_count > 0)
- desc->offset = args->args[0];
+ if (ops->xlate)
+ return ops->xlate(desc->dev, desc, args);
else
- desc->offset = -1;
- desc->flags = 0;
-
- return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
+ return gpio_xlate_offs_flags(desc->dev, desc, args);
}
int dm_gpio_request(struct gpio_desc *desc, const char *label)
@@ -605,6 +620,7 @@ static int _gpio_request_by_name_nodev(const void *blob, int node,
desc->dev = NULL;
desc->offset = 0;
+ desc->flags = 0;
ret = fdtdec_parse_phandle_with_args(blob, node, list_name,
"#gpio-cells", 0, index, &args);
if (ret) {
diff --git a/drivers/gpio/intel_broadwell_gpio.c b/drivers/gpio/intel_broadwell_gpio.c
index 8cf76f96c2..81ce446e1a 100644
--- a/drivers/gpio/intel_broadwell_gpio.c
+++ b/drivers/gpio/intel_broadwell_gpio.c
@@ -162,15 +162,6 @@ static int broadwell_gpio_ofdata_to_platdata(struct udevice *dev)
return 0;
}
-static int broadwell_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
- struct fdtdec_phandle_args *args)
-{
- desc->offset = args->args[0];
- desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
- return 0;
-}
-
static const struct dm_gpio_ops gpio_broadwell_ops = {
.request = broadwell_gpio_request,
.direction_input = broadwell_gpio_direction_input,
@@ -178,7 +169,6 @@ static const struct dm_gpio_ops gpio_broadwell_ops = {
.get_value = broadwell_gpio_get_value,
.set_value = broadwell_gpio_set_value,
.get_function = broadwell_gpio_get_function,
- .xlate = broadwell_gpio_xlate,
};
static const struct udevice_id intel_broadwell_gpio_ids[] = {
diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c
index 93d18e44a5..cd960dc013 100644
--- a/drivers/gpio/omap_gpio.c
+++ b/drivers/gpio/omap_gpio.c
@@ -25,7 +25,6 @@
#include <asm/io.h>
#include <asm/errno.h>
#include <malloc.h>
-#include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -277,22 +276,12 @@ static int omap_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_INPUT;
}
-static int omap_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
- struct fdtdec_phandle_args *args)
-{
- desc->offset = args->args[0];
- desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
- return 0;
-}
-
static const struct dm_gpio_ops gpio_omap_ops = {
.direction_input = omap_gpio_direction_input,
.direction_output = omap_gpio_direction_output,
.get_value = omap_gpio_get_value,
.set_value = omap_gpio_set_value,
.get_function = omap_gpio_get_function,
- .xlate = omap_gpio_xlate,
};
static int omap_gpio_probe(struct udevice *dev)
diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c
new file mode 100644
index 0000000000..987d10e967
--- /dev/null
+++ b/drivers/gpio/pca953x_gpio.c
@@ -0,0 +1,351 @@
+/*
+ * Take linux kernel driver drivers/gpio/gpio-pca953x.c for reference.
+ *
+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+
+/*
+ * Note:
+ * The driver's compatible table is borrowed from Linux Kernel,
+ * but now max supported gpio pins is 24 and only PCA953X_TYPE
+ * is supported. PCA957X_TYPE is not supported now.
+ * Also the Polarity Inversion feature is not supported now.
+ *
+ * TODO:
+ * 1. Support PCA957X_TYPE
+ * 2. Support max 40 gpio pins
+ * 3. Support Plolarity Inversion
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#define PCA953X_INPUT 0
+#define PCA953X_OUTPUT 1
+#define PCA953X_INVERT 2
+#define PCA953X_DIRECTION 3
+
+#define PCA_GPIO_MASK 0x00FF
+#define PCA_INT 0x0100
+#define PCA953X_TYPE 0x1000
+#define PCA957X_TYPE 0x2000
+#define PCA_TYPE_MASK 0xF000
+#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
+
+enum {
+ PCA953X_DIRECTION_IN,
+ PCA953X_DIRECTION_OUT,
+};
+
+#define MAX_BANK 3
+#define BANK_SZ 8
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * struct pca953x_info - Data for pca953x
+ *
+ * @dev: udevice structure for the device
+ * @addr: i2c slave address
+ * @invert: Polarity inversion or not
+ * @gpio_count: the number of gpio pins that the device supports
+ * @chip_type: indicate the chip type,PCA953X or PCA957X
+ * @bank_count: the number of banks that the device supports
+ * @reg_output: array to hold the value of output registers
+ * @reg_direction: array to hold the value of direction registers
+ */
+struct pca953x_info {
+ struct udevice *dev;
+ int addr;
+ int invert;
+ int gpio_count;
+ int chip_type;
+ int bank_count;
+ u8 reg_output[MAX_BANK];
+ u8 reg_direction[MAX_BANK];
+};
+
+static int pca953x_write_single(struct udevice *dev, int reg, u8 val,
+ int offset)
+{
+ struct pca953x_info *info = dev_get_platdata(dev);
+ int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
+ int off = offset / BANK_SZ;
+ int ret = 0;
+
+ ret = dm_i2c_write(dev, (reg << bank_shift) + off, &val, 1);
+ if (ret) {
+ dev_err(dev, "%s error\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pca953x_read_single(struct udevice *dev, int reg, u8 *val,
+ int offset)
+{
+ struct pca953x_info *info = dev_get_platdata(dev);
+ int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
+ int off = offset / BANK_SZ;
+ int ret;
+ u8 byte;
+
+ ret = dm_i2c_read(dev, (reg << bank_shift) + off, &byte, 1);
+ if (ret) {
+ dev_err(dev, "%s error\n", __func__);
+ return ret;
+ }
+
+ *val = byte;
+
+ return 0;
+}
+
+static int pca953x_read_regs(struct udevice *dev, int reg, u8 *val)
+{
+ struct pca953x_info *info = dev_get_platdata(dev);
+ int ret = 0;
+
+ if (info->gpio_count <= 8) {
+ ret = dm_i2c_read(dev, reg, val, 1);
+ } else if (info->gpio_count <= 16) {
+ ret = dm_i2c_read(dev, reg << 1, val, info->bank_count);
+ } else {
+ dev_err(dev, "Unsupported now\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int pca953x_is_output(struct udevice *dev, int offset)
+{
+ struct pca953x_info *info = dev_get_platdata(dev);
+
+ int bank = offset / BANK_SZ;
+ int off = offset % BANK_SZ;
+
+ /*0: output; 1: input */
+ return !(info->reg_direction[bank] & (1 << off));
+}
+
+static int pca953x_get_value(struct udevice *dev, unsigned offset)
+{
+ int ret;
+ u8 val = 0;
+
+ ret = pca953x_read_single(dev, PCA953X_INPUT, &val, offset);
+ if (ret)
+ return ret;
+
+ return (val >> offset) & 0x1;
+}
+
+static int pca953x_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct pca953x_info *info = dev_get_platdata(dev);
+ int bank = offset / BANK_SZ;
+ int off = offset % BANK_SZ;
+ u8 val;
+ int ret;
+
+ if (value)
+ val = info->reg_output[bank] | (1 << off);
+ else
+ val = info->reg_output[bank] & ~(1 << off);
+
+ ret = pca953x_write_single(dev, PCA953X_OUTPUT, val, offset);
+ if (ret)
+ return ret;
+
+ info->reg_output[bank] = val;
+
+ return 0;
+}
+
+static int pca953x_set_direction(struct udevice *dev, unsigned offset, int dir)
+{
+ struct pca953x_info *info = dev_get_platdata(dev);
+ int bank = offset / BANK_SZ;
+ int off = offset % BANK_SZ;
+ u8 val;
+ int ret;
+
+ if (dir == PCA953X_DIRECTION_IN)
+ val = info->reg_direction[bank] | (1 << off);
+ else
+ val = info->reg_direction[bank] & ~(1 << off);
+
+ ret = pca953x_write_single(dev, PCA953X_DIRECTION, val, offset);
+ if (ret)
+ return ret;
+
+ info->reg_direction[bank] = val;
+
+ return 0;
+}
+
+static int pca953x_direction_input(struct udevice *dev, unsigned offset)
+{
+ return pca953x_set_direction(dev, offset, PCA953X_DIRECTION_IN);
+}
+
+static int pca953x_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ /* Configure output value. */
+ pca953x_set_value(dev, offset, value);
+
+ /* Configure direction as output. */
+ pca953x_set_direction(dev, offset, PCA953X_DIRECTION_OUT);
+
+ return 0;
+}
+
+static int pca953x_get_function(struct udevice *dev, unsigned offset)
+{
+ if (pca953x_is_output(dev, offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static int pca953x_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct fdtdec_phandle_args *args)
+{
+ desc->offset = args->args[0];
+ desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+ return 0;
+}
+
+static const struct dm_gpio_ops pca953x_ops = {
+ .direction_input = pca953x_direction_input,
+ .direction_output = pca953x_direction_output,
+ .get_value = pca953x_get_value,
+ .set_value = pca953x_set_value,
+ .get_function = pca953x_get_function,
+ .xlate = pca953x_xlate,
+};
+
+static int pca953x_probe(struct udevice *dev)
+{
+ struct pca953x_info *info = dev_get_platdata(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+ char name[32], *str;
+ int addr;
+ ulong driver_data;
+ int ret;
+
+ if (!info) {
+ dev_err(dev, "platdata not ready\n");
+ return -ENOMEM;
+ }
+
+ if (!chip) {
+ dev_err(dev, "i2c not ready\n");
+ return -ENODEV;
+ }
+
+ addr = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", 0);
+ if (addr == 0)
+ return -ENODEV;
+
+ info->addr = addr;
+
+ driver_data = dev_get_driver_data(dev);
+
+ info->gpio_count = driver_data & PCA_GPIO_MASK;
+ if (info->gpio_count > MAX_BANK * BANK_SZ) {
+ dev_err(dev, "Max support %d pins now\n", MAX_BANK * BANK_SZ);
+ return -EINVAL;
+ }
+
+ info->chip_type = PCA_CHIP_TYPE(driver_data);
+ if (info->chip_type != PCA953X_TYPE) {
+ dev_err(dev, "Only support PCA953X chip type now.\n");
+ return -EINVAL;
+ }
+
+ info->bank_count = DIV_ROUND_UP(info->gpio_count, BANK_SZ);
+
+ ret = pca953x_read_regs(dev, PCA953X_OUTPUT, info->reg_output);
+ if (ret) {
+ dev_err(dev, "Error reading output register\n");
+ return ret;
+ }
+
+ ret = pca953x_read_regs(dev, PCA953X_DIRECTION, info->reg_direction);
+ if (ret) {
+ dev_err(dev, "Error reading direction register\n");
+ return ret;
+ }
+
+ snprintf(name, sizeof(name), "gpio@%x_", info->addr);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = info->gpio_count;
+
+ dev_dbg(dev, "%s is ready\n", str);
+
+ return 0;
+}
+
+#define OF_953X(__nrgpio, __int) (ulong)(__nrgpio | PCA953X_TYPE | __int)
+#define OF_957X(__nrgpio, __int) (ulong)(__nrgpio | PCA957X_TYPE | __int)
+
+static const struct udevice_id pca953x_ids[] = {
+ { .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
+ { .compatible = "nxp,pca9534", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9536", .data = OF_953X(4, 0), },
+ { .compatible = "nxp,pca9537", .data = OF_953X(4, PCA_INT), },
+ { .compatible = "nxp,pca9538", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "nxp,pca9539", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9554", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "nxp,pca9555", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "nxp,pca9556", .data = OF_953X(8, 0), },
+ { .compatible = "nxp,pca9557", .data = OF_953X(8, 0), },
+ { .compatible = "nxp,pca9574", .data = OF_957X(8, PCA_INT), },
+ { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
+ { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
+
+ { .compatible = "maxim,max7310", .data = OF_953X(8, 0), },
+ { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "maxim,max7315", .data = OF_953X(8, PCA_INT), },
+
+ { .compatible = "ti,pca6107", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "ti,tca6408", .data = OF_953X(8, PCA_INT), },
+ { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
+ { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
+
+ { .compatible = "onsemi,pca9654", .data = OF_953X(8, PCA_INT), },
+
+ { .compatible = "exar,xra1202", .data = OF_953X(8, 0), },
+ { }
+};
+
+U_BOOT_DRIVER(pca953x) = {
+ .name = "pca953x",
+ .id = UCLASS_GPIO,
+ .ops = &pca953x_ops,
+ .probe = pca953x_probe,
+ .platdata_auto_alloc_size = sizeof(struct pca953x_info),
+ .of_match = pca953x_ids,
+};
diff --git a/drivers/gpio/pic32_gpio.c b/drivers/gpio/pic32_gpio.c
index 499b4fa5ad..7a037f3a77 100644
--- a/drivers/gpio/pic32_gpio.c
+++ b/drivers/gpio/pic32_gpio.c
@@ -12,7 +12,6 @@
#include <asm/io.h>
#include <asm/gpio.h>
#include <linux/compat.h>
-#include <dt-bindings/gpio/gpio.h>
#include <mach/pic32.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -99,14 +98,6 @@ static int pic32_gpio_direction_output(struct udevice *dev,
return 0;
}
-static int pic32_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
- struct fdtdec_phandle_args *args)
-{
- desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
- return 0;
-}
-
static int pic32_gpio_get_function(struct udevice *dev, unsigned offset)
{
int ret = GPIOF_UNUSED;
@@ -131,7 +122,6 @@ static const struct dm_gpio_ops gpio_pic32_ops = {
.get_value = pic32_gpio_get_value,
.set_value = pic32_gpio_set_value,
.get_function = pic32_gpio_get_function,
- .xlate = pic32_gpio_xlate,
};
static int pic32_gpio_probe(struct udevice *dev)
diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c
index 40e87bd199..fefe3ca203 100644
--- a/drivers/gpio/rk_gpio.c
+++ b/drivers/gpio/rk_gpio.c
@@ -16,7 +16,6 @@
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <dm/pinctrl.h>
-#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/clock/rk3288-cru.h>
enum {
@@ -98,15 +97,6 @@ static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
#endif
}
-static int rockchip_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
- struct fdtdec_phandle_args *args)
-{
- desc->offset = args->args[0];
- desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
- return 0;
-}
-
static int rockchip_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
@@ -135,7 +125,6 @@ static const struct dm_gpio_ops gpio_rockchip_ops = {
.get_value = rockchip_gpio_get_value,
.set_value = rockchip_gpio_set_value,
.get_function = rockchip_gpio_get_function,
- .xlate = rockchip_gpio_xlate,
};
static const struct udevice_id rockchip_gpio_ids[] = {
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 0f22b238ba..377fed467f 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -13,7 +13,6 @@
#include <asm/io.h>
#include <asm/gpio.h>
#include <dm/device-internal.h>
-#include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -276,22 +275,12 @@ static int exynos_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_FUNC;
}
-static int exynos_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
- struct fdtdec_phandle_args *args)
-{
- desc->offset = args->args[0];
- desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
- return 0;
-}
-
static const struct dm_gpio_ops gpio_exynos_ops = {
.direction_input = exynos_gpio_direction_input,
.direction_output = exynos_gpio_direction_output,
.get_value = exynos_gpio_get_value,
.set_value = exynos_gpio_set_value,
.get_function = exynos_gpio_get_function,
- .xlate = exynos_gpio_xlate,
};
static int gpio_exynos_probe(struct udevice *dev)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4d3df11a1b..c80efc39a7 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -2,7 +2,7 @@ menu "MMC Host controller Support"
config MMC
bool "Enable MMC support"
- depends on ARCH_SUNXI
+ depends on ARCH_SUNXI || SANDBOX
help
TODO: Move all architectures to use this option
@@ -58,4 +58,13 @@ config MMC_UNIPHIER
help
This selects support for the SD/MMC Host Controller on UniPhier SoCs.
+config SANDBOX_MMC
+ bool "Sandbox MMC support"
+ depends on MMC && SANDBOX
+ help
+ This select a dummy sandbox MMC driver. At present this does nothing
+ other than allow sandbox to be build with MMC support. This
+ improves build coverage for sandbox and makes it easier to detect
+ MMC build errors with sandbox.
+
endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 585aaf3115..3da4817a18 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -5,7 +5,13 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-$(CONFIG_DM_MMC) += mmc-uclass.o
+ifdef CONFIG_DM_MMC
+obj-$(CONFIG_GENERIC_MMC) += mmc-uclass.o
+endif
+
+ifndef CONFIG_BLK
+obj-$(CONFIG_GENERIC_MMC) += mmc_legacy.o
+endif
obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
obj-$(CONFIG_ATMEL_SDHCI) += atmel_sdhci.o
@@ -34,7 +40,11 @@ obj-$(CONFIG_ROCKCHIP_DWMMC) += rockchip_dw_mmc.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
+ifdef CONFIG_BLK
+ifdef CONFIG_GENERIC_MMC
obj-$(CONFIG_SANDBOX) += sandbox_mmc.o
+endif
+endif
obj-$(CONFIG_SDHCI) += sdhci.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 777489f5d8..1b967d982b 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -21,6 +21,112 @@ struct mmc *mmc_get_mmc_dev(struct udevice *dev)
return upriv->mmc;
}
+#ifdef CONFIG_BLK
+struct mmc *find_mmc_device(int dev_num)
+{
+ struct udevice *dev, *mmc_dev;
+ int ret;
+
+ ret = blk_get_device(IF_TYPE_MMC, dev_num, &dev);
+
+ if (ret) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+ printf("MMC Device %d not found\n", dev_num);
+#endif
+ return NULL;
+ }
+
+ mmc_dev = dev_get_parent(dev);
+
+ return mmc_get_mmc_dev(mmc_dev);
+}
+
+int get_mmc_num(void)
+{
+ return max(blk_find_max_devnum(IF_TYPE_MMC), 0);
+}
+
+int mmc_get_next_devnum(void)
+{
+ int ret;
+
+ ret = get_mmc_num();
+ if (ret < 0)
+ return ret;
+
+ return ret + 1;
+}
+
+struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
+{
+ struct blk_desc *desc;
+ struct udevice *dev;
+
+ device_find_first_child(mmc->dev, &dev);
+ if (!dev)
+ return NULL;
+ desc = dev_get_uclass_platdata(dev);
+
+ return desc;
+}
+
+void mmc_do_preinit(void)
+{
+ struct udevice *dev;
+ struct uclass *uc;
+ int ret;
+
+ ret = uclass_get(UCLASS_MMC, &uc);
+ if (ret)
+ return;
+ uclass_foreach_dev(dev, uc) {
+ struct mmc *m = mmc_get_mmc_dev(dev);
+
+ if (!m)
+ continue;
+#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
+ mmc_set_preinit(m, 1);
+#endif
+ if (m->preinit)
+ mmc_start_init(m);
+ }
+}
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+void print_mmc_devices(char separator)
+{
+ struct udevice *dev;
+ char *mmc_type;
+ bool first = true;
+
+ for (uclass_first_device(UCLASS_MMC, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ struct mmc *m = mmc_get_mmc_dev(dev);
+
+ if (!first) {
+ printf("%c", separator);
+ if (separator != '\n')
+ puts(" ");
+ }
+ if (m->has_init)
+ mmc_type = IS_SD(m) ? "SD" : "eMMC";
+ else
+ mmc_type = NULL;
+
+ printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum);
+ if (mmc_type)
+ printf(" (%s)", mmc_type);
+ }
+
+ printf("\n");
+}
+
+#else
+void print_mmc_devices(char separator) { }
+#endif
+#endif /* CONFIG_BLK */
+
U_BOOT_DRIVER(mmc) = {
.name = "mmc",
.id = UCLASS_MMC,
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index d3c22abfd5..74b3d68f87 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -21,9 +21,6 @@
#include <div64.h>
#include "mmc_private.h"
-static struct list_head mmc_devices;
-static int cur_dev_num = -1;
-
__weak int board_mmc_getwp(struct mmc *mmc)
{
return -1;
@@ -178,25 +175,6 @@ int mmc_set_blocklen(struct mmc *mmc, int len)
return mmc_send_cmd(mmc, &cmd, NULL);
}
-struct mmc *find_mmc_device(int dev_num)
-{
- struct mmc *m;
- struct list_head *entry;
-
- list_for_each(entry, &mmc_devices) {
- m = list_entry(entry, struct mmc, link);
-
- if (m->block_dev.devnum == dev_num)
- return m;
- }
-
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("MMC Device %d not found\n", dev_num);
-#endif
-
- return NULL;
-}
-
static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
lbaint_t blkcnt)
{
@@ -238,9 +216,17 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
return blkcnt;
}
+#ifdef CONFIG_BLK
+static ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
+ void *dst)
+#else
static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
lbaint_t blkcnt, void *dst)
+#endif
{
+#ifdef CONFIG_BLK
+ struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
int dev_num = block_dev->devnum;
int err;
lbaint_t cur, blocks_todo = blkcnt;
@@ -252,14 +238,14 @@ static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
if (!mmc)
return 0;
- err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+ err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
if (err < 0)
return 0;
- if ((start + blkcnt) > mmc->block_dev.lba) {
+ if ((start + blkcnt) > block_dev->lba) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
- start + blkcnt, mmc->block_dev.lba);
+ start + blkcnt, block_dev->lba);
#endif
return 0;
}
@@ -577,58 +563,73 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
return -1;
}
- mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+ mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
return 0;
}
-int mmc_select_hwpart(int dev_num, int hwpart)
+static int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
{
- struct mmc *mmc = find_mmc_device(dev_num);
int ret;
- if (!mmc)
- return -ENODEV;
+ ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
+ (mmc->part_config & ~PART_ACCESS_MASK)
+ | (part_num & PART_ACCESS_MASK));
- if (mmc->block_dev.hwpart == hwpart)
+ /*
+ * Set the capacity if the switch succeeded or was intended
+ * to return to representing the raw device.
+ */
+ if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
+ ret = mmc_set_capacity(mmc, part_num);
+ mmc_get_blk_desc(mmc)->hwpart = part_num;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_BLK
+static int mmc_select_hwpart(struct udevice *bdev, int hwpart)
+{
+ struct udevice *mmc_dev = dev_get_parent(bdev);
+ struct mmc *mmc = mmc_get_mmc_dev(mmc_dev);
+ struct blk_desc *desc = dev_get_uclass_platdata(bdev);
+ int ret;
+
+ if (desc->hwpart == hwpart)
return 0;
- if (mmc->part_config == MMCPART_NOAVAILABLE) {
- printf("Card doesn't support part_switch\n");
+ if (mmc->part_config == MMCPART_NOAVAILABLE)
return -EMEDIUMTYPE;
- }
- ret = mmc_switch_part(dev_num, hwpart);
+ ret = mmc_switch_part(mmc, hwpart);
if (ret)
return ret;
return 0;
}
-
-
-int mmc_switch_part(int dev_num, unsigned int part_num)
+#else
+static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
{
- struct mmc *mmc = find_mmc_device(dev_num);
+ struct mmc *mmc = find_mmc_device(desc->devnum);
int ret;
if (!mmc)
- return -1;
+ return -ENODEV;
- ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
- (mmc->part_config & ~PART_ACCESS_MASK)
- | (part_num & PART_ACCESS_MASK));
+ if (mmc->block_dev.hwpart == hwpart)
+ return 0;
- /*
- * Set the capacity if the switch succeeded or was intended
- * to return to representing the raw device.
- */
- if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
- ret = mmc_set_capacity(mmc, part_num);
- mmc->block_dev.hwpart = part_num;
- }
+ if (mmc->part_config == MMCPART_NOAVAILABLE)
+ return -EMEDIUMTYPE;
- return ret;
+ ret = mmc_switch_part(mmc, hwpart);
+ if (ret)
+ return ret;
+
+ return 0;
}
+#endif
int mmc_hwpart_config(struct mmc *mmc,
const struct mmc_hwpart_conf *conf,
@@ -1039,6 +1040,7 @@ static int mmc_startup(struct mmc *mmc)
int timeout = 1000;
bool has_parts = false;
bool part_completed;
+ struct blk_desc *bdesc;
#ifdef CONFIG_MMC_SPI_CRC_ON
if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
@@ -1335,7 +1337,7 @@ static int mmc_startup(struct mmc *mmc)
mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
}
- err = mmc_set_capacity(mmc, mmc->block_dev.hwpart);
+ err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
if (err)
return err;
@@ -1475,31 +1477,32 @@ static int mmc_startup(struct mmc *mmc)
}
/* fill in device description */
- mmc->block_dev.lun = 0;
- mmc->block_dev.hwpart = 0;
- mmc->block_dev.type = 0;
- mmc->block_dev.blksz = mmc->read_bl_len;
- mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
- mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+ bdesc = mmc_get_blk_desc(mmc);
+ bdesc->lun = 0;
+ bdesc->hwpart = 0;
+ bdesc->type = 0;
+ bdesc->blksz = mmc->read_bl_len;
+ bdesc->log2blksz = LOG2(bdesc->blksz);
+ bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
#if !defined(CONFIG_SPL_BUILD) || \
(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
!defined(CONFIG_USE_TINY_PRINTF))
- sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
+ sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
(mmc->cid[3] >> 16) & 0xffff);
- sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
+ sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
(mmc->cid[2] >> 24) & 0xff);
- sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
+ sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
(mmc->cid[2] >> 16) & 0xf);
#else
- mmc->block_dev.vendor[0] = 0;
- mmc->block_dev.product[0] = 0;
- mmc->block_dev.revision[0] = 0;
+ bdesc->vendor[0] = 0;
+ bdesc->product[0] = 0;
+ bdesc->revision[0] = 0;
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
- part_init(&mmc->block_dev);
+ part_init(bdesc);
#endif
return 0;
@@ -1537,8 +1540,55 @@ int __deprecated mmc_register(struct mmc *mmc)
return -1;
}
+#ifdef CONFIG_BLK
+int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
+{
+ struct blk_desc *bdesc;
+ struct udevice *bdev;
+ int ret;
+
+ ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512,
+ 0, &bdev);
+ if (ret) {
+ debug("Cannot create block device\n");
+ return ret;
+ }
+ bdesc = dev_get_uclass_platdata(bdev);
+ mmc->cfg = cfg;
+ mmc->priv = dev;
+
+ /* the following chunk was from mmc_register() */
+
+ /* Setup dsr related values */
+ mmc->dsr_imp = 0;
+ mmc->dsr = 0xffffffff;
+ /* Setup the universal parts of the block interface just once */
+ bdesc->removable = 1;
+
+ /* setup initial part type */
+ bdesc->part_type = mmc->cfg->part_type;
+ mmc->dev = dev;
+
+ return 0;
+}
+
+int mmc_unbind(struct udevice *dev)
+{
+ struct udevice *bdev;
+
+ device_find_first_child(dev, &bdev);
+ if (bdev) {
+ device_remove(bdev);
+ device_unbind(bdev);
+ }
+
+ return 0;
+}
+
+#else
struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
{
+ struct blk_desc *bdesc;
struct mmc *mmc;
/* quick validation */
@@ -1559,19 +1609,17 @@ struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
mmc->dsr_imp = 0;
mmc->dsr = 0xffffffff;
/* Setup the universal parts of the block interface just once */
- mmc->block_dev.if_type = IF_TYPE_MMC;
- mmc->block_dev.devnum = cur_dev_num++;
- mmc->block_dev.removable = 1;
- mmc->block_dev.block_read = mmc_bread;
- mmc->block_dev.block_write = mmc_bwrite;
- mmc->block_dev.block_erase = mmc_berase;
+ bdesc = mmc_get_blk_desc(mmc);
+ bdesc->if_type = IF_TYPE_MMC;
+ bdesc->removable = 1;
+ bdesc->devnum = mmc_get_next_devnum();
+ bdesc->block_read = mmc_bread;
+ bdesc->block_write = mmc_bwrite;
+ bdesc->block_erase = mmc_berase;
/* setup initial part type */
- mmc->block_dev.part_type = mmc->cfg->part_type;
-
- INIT_LIST_HEAD(&mmc->link);
-
- list_add_tail(&mmc->link, &mmc_devices);
+ bdesc->part_type = mmc->cfg->part_type;
+ mmc_list_add(mmc);
return mmc;
}
@@ -1581,15 +1629,23 @@ void mmc_destroy(struct mmc *mmc)
/* only freeing memory for now */
free(mmc);
}
+#endif
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *mmc_get_dev(int dev)
+#ifndef CONFIG_BLK
+static int mmc_get_dev(int dev, struct blk_desc **descp)
{
struct mmc *mmc = find_mmc_device(dev);
- if (!mmc || mmc_init(mmc))
- return NULL;
+ int ret;
- return &mmc->block_dev;
+ if (!mmc)
+ return -ENODEV;
+ ret = mmc_init(mmc);
+ if (ret)
+ return ret;
+
+ *descp = &mmc->block_dev;
+
+ return 0;
}
#endif
@@ -1636,7 +1692,7 @@ int mmc_start_init(struct mmc *mmc)
return err;
/* The internal partition reset to user partition(0) at every CMD0*/
- mmc->block_dev.hwpart = 0;
+ mmc_get_blk_desc(mmc)->hwpart = 0;
/* Test for SD version 2 */
err = mmc_send_if_cond(mmc);
@@ -1683,7 +1739,11 @@ int mmc_init(struct mmc *mmc)
{
int err = 0;
unsigned start;
+#ifdef CONFIG_DM_MMC
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
+ upriv->mmc = mmc;
+#endif
if (mmc->has_init)
return 0;
@@ -1716,66 +1776,11 @@ __weak int board_mmc_init(bd_t *bis)
return -1;
}
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
-
-void print_mmc_devices(char separator)
-{
- struct mmc *m;
- struct list_head *entry;
- char *mmc_type;
-
- list_for_each(entry, &mmc_devices) {
- m = list_entry(entry, struct mmc, link);
-
- if (m->has_init)
- mmc_type = IS_SD(m) ? "SD" : "eMMC";
- else
- mmc_type = NULL;
-
- printf("%s: %d", m->cfg->name, m->block_dev.devnum);
- if (mmc_type)
- printf(" (%s)", mmc_type);
-
- if (entry->next != &mmc_devices) {
- printf("%c", separator);
- if (separator != '\n')
- puts (" ");
- }
- }
-
- printf("\n");
-}
-
-#else
-void print_mmc_devices(char separator) { }
-#endif
-
-int get_mmc_num(void)
-{
- return cur_dev_num;
-}
-
void mmc_set_preinit(struct mmc *mmc, int preinit)
{
mmc->preinit = preinit;
}
-static void do_preinit(void)
-{
- struct mmc *m;
- struct list_head *entry;
-
- list_for_each(entry, &mmc_devices) {
- m = list_entry(entry, struct mmc, link);
-
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
- mmc_set_preinit(m, 1);
-#endif
- if (m->preinit)
- mmc_start_init(m);
- }
-}
-
#if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
static int mmc_probe(bd_t *bis)
{
@@ -1828,9 +1833,9 @@ int mmc_initialize(bd_t *bis)
return 0;
initialized = 1;
- INIT_LIST_HEAD (&mmc_devices);
- cur_dev_num = 0;
-
+#ifndef CONFIG_BLK
+ mmc_list_init();
+#endif
ret = mmc_probe(bis);
if (ret)
return ret;
@@ -1839,7 +1844,7 @@ int mmc_initialize(bd_t *bis)
print_mmc_devices(',');
#endif
- do_preinit();
+ mmc_do_preinit();
return 0;
}
@@ -1965,3 +1970,25 @@ int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
enable);
}
#endif
+
+#ifdef CONFIG_BLK
+static const struct blk_ops mmc_blk_ops = {
+ .read = mmc_bread,
+ .write = mmc_bwrite,
+ .select_hwpart = mmc_select_hwpart,
+};
+
+U_BOOT_DRIVER(mmc_blk) = {
+ .name = "mmc_blk",
+ .id = UCLASS_BLK,
+ .ops = &mmc_blk_ops,
+};
+#else
+U_BOOT_LEGACY_BLK(mmc) = {
+ .if_typename = "mmc",
+ .if_type = IF_TYPE_MMC,
+ .max_devs = -1,
+ .get_dev = mmc_get_dev,
+ .select_hwpart = mmc_select_hwpartp,
+};
+#endif
diff --git a/drivers/mmc/mmc_legacy.c b/drivers/mmc/mmc_legacy.c
new file mode 100644
index 0000000000..3ec649f2b8
--- /dev/null
+++ b/drivers/mmc/mmc_legacy.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <mmc.h>
+
+static struct list_head mmc_devices;
+static int cur_dev_num = -1;
+
+struct mmc *find_mmc_device(int dev_num)
+{
+ struct mmc *m;
+ struct list_head *entry;
+
+ list_for_each(entry, &mmc_devices) {
+ m = list_entry(entry, struct mmc, link);
+
+ if (m->block_dev.devnum == dev_num)
+ return m;
+ }
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+ printf("MMC Device %d not found\n", dev_num);
+#endif
+
+ return NULL;
+}
+
+int mmc_get_next_devnum(void)
+{
+ return cur_dev_num++;
+}
+
+struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
+{
+ return &mmc->block_dev;
+}
+
+int get_mmc_num(void)
+{
+ return cur_dev_num;
+}
+
+void mmc_do_preinit(void)
+{
+ struct mmc *m;
+ struct list_head *entry;
+
+ list_for_each(entry, &mmc_devices) {
+ m = list_entry(entry, struct mmc, link);
+
+#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
+ mmc_set_preinit(m, 1);
+#endif
+ if (m->preinit)
+ mmc_start_init(m);
+ }
+}
+
+void mmc_list_init(void)
+{
+ INIT_LIST_HEAD(&mmc_devices);
+ cur_dev_num = 0;
+}
+
+void mmc_list_add(struct mmc *mmc)
+{
+ INIT_LIST_HEAD(&mmc->link);
+
+ list_add_tail(&mmc->link, &mmc_devices);
+}
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+void print_mmc_devices(char separator)
+{
+ struct mmc *m;
+ struct list_head *entry;
+ char *mmc_type;
+
+ list_for_each(entry, &mmc_devices) {
+ m = list_entry(entry, struct mmc, link);
+
+ if (m->has_init)
+ mmc_type = IS_SD(m) ? "SD" : "eMMC";
+ else
+ mmc_type = NULL;
+
+ printf("%s: %d", m->cfg->name, m->block_dev.devnum);
+ if (mmc_type)
+ printf(" (%s)", mmc_type);
+
+ if (entry->next != &mmc_devices) {
+ printf("%c", separator);
+ if (separator != '\n')
+ puts(" ");
+ }
+ }
+
+ printf("\n");
+}
+
+#else
+void print_mmc_devices(char separator) { }
+#endif
diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h
index d3f6bfe123..27b9e5f56f 100644
--- a/drivers/mmc/mmc_private.h
+++ b/drivers/mmc/mmc_private.h
@@ -25,8 +25,13 @@ void mmc_adapter_card_type_ident(void);
unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start,
lbaint_t blkcnt);
-unsigned long mmc_bwrite(struct blk_desc *block_dev, lbaint_t start,
- lbaint_t blkcnt, const void *src);
+#ifdef CONFIG_BLK
+ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
+ const void *src);
+#else
+ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
+ const void *src);
+#endif
#else /* CONFIG_SPL_BUILD */
@@ -46,4 +51,28 @@ static inline ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start,
#endif /* CONFIG_SPL_BUILD */
+/**
+ * mmc_get_next_devnum() - Get the next available MMC device number
+ *
+ * @return next available device number (0 = first), or -ve on error
+ */
+int mmc_get_next_devnum(void);
+
+/**
+ * mmc_do_preinit() - Get an MMC device ready for use
+ */
+void mmc_do_preinit(void);
+
+/**
+ * mmc_list_init() - Set up the list of MMC devices
+ */
+void mmc_list_init(void);
+
+/**
+ * mmc_list_add() - Add a new MMC device to the list of devices
+ *
+ * @mmc: Device to add
+ */
+void mmc_list_add(struct mmc *mmc);
+
#endif /* _MMC_PRIVATE_H_ */
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index 7b186f8500..0f8b5c79d7 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -9,6 +9,7 @@
#include <config.h>
#include <common.h>
+#include <dm.h>
#include <part.h>
#include <div64.h>
#include <linux/math64.h>
@@ -78,7 +79,8 @@ unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start,
if (!mmc)
return -1;
- err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+ err = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_num,
+ block_dev->hwpart);
if (err < 0)
return -1;
@@ -121,9 +123,9 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
struct mmc_data data;
int timeout = 1000;
- if ((start + blkcnt) > mmc->block_dev.lba) {
+ if ((start + blkcnt) > mmc_get_blk_desc(mmc)->lba) {
printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
- start + blkcnt, mmc->block_dev.lba);
+ start + blkcnt, mmc_get_blk_desc(mmc)->lba);
return 0;
}
@@ -171,9 +173,17 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
return blkcnt;
}
+#ifdef CONFIG_BLK
+ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
+ const void *src)
+#else
ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
const void *src)
+#endif
{
+#ifdef CONFIG_BLK
+ struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
int dev_num = block_dev->devnum;
lbaint_t cur, blocks_todo = blkcnt;
int err;
@@ -182,7 +192,7 @@ ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
if (!mmc)
return 0;
- err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+ err = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_num, block_dev->hwpart);
if (err < 0)
return 0;
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index 85a832bd42..be34057ea2 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -825,6 +825,7 @@ static int omap_hsmmc_probe(struct udevice *dev)
gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
#endif
+ mmc->dev = dev;
upriv->mmc = mmc;
return 0;
diff --git a/drivers/mmc/pic32_sdhci.c b/drivers/mmc/pic32_sdhci.c
index e03d6dd517..abe74293ed 100644
--- a/drivers/mmc/pic32_sdhci.c
+++ b/drivers/mmc/pic32_sdhci.c
@@ -41,7 +41,12 @@ static int pic32_sdhci_probe(struct udevice *dev)
return ret;
}
- return add_sdhci(host, f_min_max[1], f_min_max[0]);
+ ret = add_sdhci(host, f_min_max[1], f_min_max[0]);
+ if (ret)
+ return ret;
+ host->mmc->dev = dev;
+
+ return 0;
}
static const struct udevice_id pic32_sdhci_ids[] = {
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index cb9e1048d0..0a261c51a8 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -104,6 +104,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
if (ret)
return ret;
+ host->mmc->dev = dev;
upriv->mmc = host->mmc;
return 0;
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
index f4646a824f..7da059c43c 100644
--- a/drivers/mmc/sandbox_mmc.c
+++ b/drivers/mmc/sandbox_mmc.c
@@ -8,18 +8,150 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
+#include <fdtdec.h>
#include <mmc.h>
#include <asm/test.h>
DECLARE_GLOBAL_DATA_PTR;
+struct sandbox_mmc_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+/**
+ * sandbox_mmc_send_cmd() - Emulate SD commands
+ *
+ * This emulate an SD card version 2. Single-block reads result in zero data.
+ * Multiple-block reads return a test string.
+ */
+static int sandbox_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ switch (cmd->cmdidx) {
+ case MMC_CMD_ALL_SEND_CID:
+ break;
+ case SD_CMD_SEND_RELATIVE_ADDR:
+ cmd->response[0] = 0 << 16; /* mmc->rca */
+ case MMC_CMD_GO_IDLE_STATE:
+ break;
+ case SD_CMD_SEND_IF_COND:
+ cmd->response[0] = 0xaa;
+ break;
+ case MMC_CMD_SEND_STATUS:
+ cmd->response[0] = MMC_STATUS_RDY_FOR_DATA;
+ break;
+ case MMC_CMD_SELECT_CARD:
+ break;
+ case MMC_CMD_SEND_CSD:
+ cmd->response[0] = 0;
+ cmd->response[1] = 10 << 16; /* 1 << block_len */
+ break;
+ case SD_CMD_SWITCH_FUNC: {
+ u32 *resp = (u32 *)data->dest;
+
+ resp[7] = cpu_to_be32(SD_HIGHSPEED_BUSY);
+ break;
+ }
+ case MMC_CMD_READ_SINGLE_BLOCK:
+ memset(data->dest, '\0', data->blocksize);
+ break;
+ case MMC_CMD_READ_MULTIPLE_BLOCK:
+ strcpy(data->dest, "this is a test");
+ break;
+ case MMC_CMD_STOP_TRANSMISSION:
+ break;
+ case SD_CMD_APP_SEND_OP_COND:
+ cmd->response[0] = OCR_BUSY | OCR_HCS;
+ cmd->response[1] = 0;
+ cmd->response[2] = 0;
+ break;
+ case MMC_CMD_APP_CMD:
+ break;
+ case MMC_CMD_SET_BLOCKLEN:
+ debug("block len %d\n", cmd->cmdarg);
+ break;
+ case SD_CMD_APP_SEND_SCR: {
+ u32 *scr = (u32 *)data->dest;
+
+ scr[0] = cpu_to_be32(2 << 24 | 1 << 15); /* SD version 3 */
+ break;
+ }
+ default:
+ debug("%s: Unknown command %d\n", __func__, cmd->cmdidx);
+ break;
+ }
+
+ return 0;
+}
+
+static void sandbox_mmc_set_ios(struct mmc *mmc)
+{
+}
+
+static int sandbox_mmc_init(struct mmc *mmc)
+{
+ return 0;
+}
+
+static int sandbox_mmc_getcd(struct mmc *mmc)
+{
+ return 1;
+}
+
+static const struct mmc_ops sandbox_mmc_ops = {
+ .send_cmd = sandbox_mmc_send_cmd,
+ .set_ios = sandbox_mmc_set_ios,
+ .init = sandbox_mmc_init,
+ .getcd = sandbox_mmc_getcd,
+};
+
+int sandbox_mmc_probe(struct udevice *dev)
+{
+ struct sandbox_mmc_plat *plat = dev_get_platdata(dev);
+
+ return mmc_init(&plat->mmc);
+}
+
+int sandbox_mmc_bind(struct udevice *dev)
+{
+ struct sandbox_mmc_plat *plat = dev_get_platdata(dev);
+ struct mmc_config *cfg = &plat->cfg;
+ int ret;
+
+ cfg->name = dev->name;
+ cfg->ops = &sandbox_mmc_ops;
+ cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_8BIT;
+ cfg->voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
+ cfg->f_min = 1000000;
+ cfg->f_max = 52000000;
+ cfg->b_max = U32_MAX;
+
+ ret = mmc_bind(dev, &plat->mmc, cfg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int sandbox_mmc_unbind(struct udevice *dev)
+{
+ mmc_unbind(dev);
+
+ return 0;
+}
+
static const struct udevice_id sandbox_mmc_ids[] = {
{ .compatible = "sandbox,mmc" },
{ }
};
-U_BOOT_DRIVER(warm_mmc_sandbox) = {
+U_BOOT_DRIVER(mmc_sandbox) = {
.name = "mmc_sandbox",
.id = UCLASS_MMC,
.of_match = sandbox_mmc_ids,
+ .bind = sandbox_mmc_bind,
+ .unbind = sandbox_mmc_unbind,
+ .probe = sandbox_mmc_probe,
+ .platdata_auto_alloc_size = sizeof(struct sandbox_mmc_plat),
};
diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
index 097db81b05..6a0e9719b8 100644
--- a/drivers/mmc/socfpga_dw_mmc.c
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -108,6 +108,7 @@ static int socfpga_dwmmc_probe(struct udevice *dev)
return ret;
upriv->mmc = host->mmc;
+ host->mmc->dev = dev;
return 0;
}
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c
index 81a80cdbc2..4978cca76d 100644
--- a/drivers/mmc/uniphier-sd.c
+++ b/drivers/mmc/uniphier-sd.c
@@ -725,6 +725,7 @@ int uniphier_sd_probe(struct udevice *dev)
return -EIO;
upriv->mmc = priv->mmc;
+ priv->mmc->dev = dev;
return 0;
}
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index b59feca80b..d405929b64 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -35,6 +35,7 @@ static int arasan_sdhci_probe(struct udevice *dev)
CONFIG_ZYNQ_SDHCI_MIN_FREQ);
upriv->mmc = host->mmc;
+ host->mmc->dev = dev;
return 0;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 461908941d..4b73a0ff9c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -175,11 +175,7 @@ pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
int bus;
for (hose = pci_get_hose_head(); hose; hose = hose->next) {
-#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
- for (bus = hose->last_busno; bus >= hose->first_busno; bus--) {
-#else
for (bus = hose->first_busno; bus <= hose->last_busno; bus++) {
-#endif
bdf = pci_hose_find_devices(hose, bus, ids, &index);
if (bdf != -1)
return bdf;
diff --git a/drivers/serial/mcfuart.c b/drivers/serial/mcfuart.c
index 407354fc4c..059cb0fc6e 100644
--- a/drivers/serial/mcfuart.c
+++ b/drivers/serial/mcfuart.c
@@ -2,6 +2,9 @@
* (C) Copyright 2004-2007 Freescale Semiconductor, Inc.
* TsiChung Liew, Tsi-Chung.Liew@freescale.com.
*
+ * Modified to add device model (DM) support
+ * (C) Copyright 2015 Angelo Dureghello <angelo@sysam.it>
+ *
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -11,9 +14,10 @@
*/
#include <common.h>
+#include <dm.h>
+#include <dm/platform_data/serial_coldfire.h>
#include <serial.h>
#include <linux/compiler.h>
-
#include <asm/immap.h>
#include <asm/uart.h>
@@ -21,91 +25,110 @@ DECLARE_GLOBAL_DATA_PTR;
extern void uart_port_conf(int port);
-static int mcf_serial_init(void)
+static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate)
{
- volatile uart_t *uart;
u32 counter;
- uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
-
- uart_port_conf(CONFIG_SYS_UART_PORT);
+ uart_port_conf(port_idx);
/* write to SICR: SIM2 = uart mode,dcd does not affect rx */
- uart->ucr = UART_UCR_RESET_RX;
- uart->ucr = UART_UCR_RESET_TX;
- uart->ucr = UART_UCR_RESET_ERROR;
- uart->ucr = UART_UCR_RESET_MR;
+ writeb(UART_UCR_RESET_RX, &uart->ucr);
+ writeb(UART_UCR_RESET_TX, &uart->ucr);
+ writeb(UART_UCR_RESET_ERROR, &uart->ucr);
+ writeb(UART_UCR_RESET_MR, &uart->ucr);
__asm__("nop");
- uart->uimr = 0;
+ writeb(0, &uart->uimr);
/* write to CSR: RX/TX baud rate from timers */
- uart->ucsr = (UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK);
+ writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr);
- uart->umr = (UART_UMR_BC_8 | UART_UMR_PM_NONE);
- uart->umr = UART_UMR_SB_STOP_BITS_1;
+ writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr);
+ writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr);
/* Setting up BaudRate */
- counter = (u32) ((gd->bus_clk / 32) + (gd->baudrate / 2));
- counter = counter / gd->baudrate;
+ counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
+ counter = counter / baudrate;
/* write to CTUR: divide counter upper byte */
- uart->ubg1 = (u8) ((counter & 0xff00) >> 8);
+ writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1);
/* write to CTLR: divide counter lower byte */
- uart->ubg2 = (u8) (counter & 0x00ff);
+ writeb((u8)(counter & 0x00ff), &uart->ubg2);
- uart->ucr = (UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED);
+ writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
return (0);
}
+static void mcf_serial_setbrg_common(uart_t *uart, int baudrate)
+{
+ u32 counter;
+
+ /* Setting up BaudRate */
+ counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
+ counter = counter / baudrate;
+
+ /* write to CTUR: divide counter upper byte */
+ writeb(((counter & 0xff00) >> 8), &uart->ubg1);
+ /* write to CTLR: divide counter lower byte */
+ writeb((counter & 0x00ff), &uart->ubg2);
+
+ writeb(UART_UCR_RESET_RX, &uart->ucr);
+ writeb(UART_UCR_RESET_TX, &uart->ucr);
+
+ writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
+}
+
+#ifndef CONFIG_DM_SERIAL
+
+static int mcf_serial_init(void)
+{
+ uart_t *uart_base;
+ int port_idx;
+
+ uart_base = (uart_t *)CONFIG_SYS_UART_BASE;
+ port_idx = CONFIG_SYS_UART_PORT;
+
+ return mcf_serial_init_common(uart_base, port_idx, gd->baudrate);
+}
+
static void mcf_serial_putc(const char c)
{
- volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
+ uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
if (c == '\n')
serial_putc('\r');
/* Wait for last character to go. */
- while (!(uart->usr & UART_USR_TXRDY)) ;
+ while (!(readb(&uart->usr) & UART_USR_TXRDY))
+ ;
- uart->utb = c;
+ writeb(c, &uart->utb);
}
static int mcf_serial_getc(void)
{
- volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
+ uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
/* Wait for a character to arrive. */
- while (!(uart->usr & UART_USR_RXRDY)) ;
- return uart->urb;
-}
-
-static int mcf_serial_tstc(void)
-{
- volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
+ while (!(readb(&uart->usr) & UART_USR_RXRDY))
+ ;
- return (uart->usr & UART_USR_RXRDY);
+ return readb(&uart->urb);
}
static void mcf_serial_setbrg(void)
{
- volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
- u32 counter;
-
- /* Setting up BaudRate */
- counter = (u32) ((gd->bus_clk / 32) + (gd->baudrate / 2));
- counter = counter / gd->baudrate;
+ uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
- /* write to CTUR: divide counter upper byte */
- uart->ubg1 = ((counter & 0xff00) >> 8);
- /* write to CTLR: divide counter lower byte */
- uart->ubg2 = (counter & 0x00ff);
+ mcf_serial_setbrg_common(uart, gd->baudrate);
+}
- uart->ucr = UART_UCR_RESET_RX;
- uart->ucr = UART_UCR_RESET_TX;
+static int mcf_serial_tstc(void)
+{
+ uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
- uart->ucr = UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED;
+ return readb(&uart->usr) & UART_USR_RXRDY;
}
static struct serial_device mcf_serial_drv = {
@@ -128,3 +151,80 @@ __weak struct serial_device *default_serial_console(void)
{
return &mcf_serial_drv;
}
+
+#endif
+
+#ifdef CONFIG_DM_SERIAL
+
+static int coldfire_serial_probe(struct udevice *dev)
+{
+ struct coldfire_serial_platdata *plat = dev->platdata;
+
+ return mcf_serial_init_common((uart_t *)plat->base,
+ plat->port, plat->baudrate);
+}
+
+static int coldfire_serial_putc(struct udevice *dev, const char ch)
+{
+ struct coldfire_serial_platdata *plat = dev->platdata;
+ uart_t *uart = (uart_t *)plat->base;
+
+ /* Wait for last character to go. */
+ if (!(readb(&uart->usr) & UART_USR_TXRDY))
+ return -EAGAIN;
+
+ writeb(ch, &uart->utb);
+
+ return 0;
+}
+
+static int coldfire_serial_getc(struct udevice *dev)
+{
+ struct coldfire_serial_platdata *plat = dev->platdata;
+ uart_t *uart = (uart_t *)(plat->base);
+
+ /* Wait for a character to arrive. */
+ if (!(readb(&uart->usr) & UART_USR_RXRDY))
+ return -EAGAIN;
+
+ return readb(&uart->urb);
+}
+
+int coldfire_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct coldfire_serial_platdata *plat = dev->platdata;
+ uart_t *uart = (uart_t *)(plat->base);
+
+ mcf_serial_setbrg_common(uart, baudrate);
+
+ return 0;
+}
+
+static int coldfire_serial_pending(struct udevice *dev, bool input)
+{
+ struct coldfire_serial_platdata *plat = dev->platdata;
+ uart_t *uart = (uart_t *)(plat->base);
+
+ if (input)
+ return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0;
+ else
+ return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1;
+
+ return 0;
+}
+
+static const struct dm_serial_ops coldfire_serial_ops = {
+ .putc = coldfire_serial_putc,
+ .pending = coldfire_serial_pending,
+ .getc = coldfire_serial_getc,
+ .setbrg = coldfire_serial_setbrg,
+};
+
+U_BOOT_DRIVER(serial_coldfire) = {
+ .name = "serial_coldfire",
+ .id = UCLASS_SERIAL,
+ .probe = coldfire_serial_probe,
+ .ops = &coldfire_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+#endif
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index aa4abcc3d2..d23dc81a21 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -26,15 +26,20 @@ struct soft_spi_platdata {
struct gpio_desc mosi;
struct gpio_desc miso;
int spi_delay_us;
+ int flags;
};
+#define SPI_MASTER_NO_RX BIT(0)
+#define SPI_MASTER_NO_TX BIT(1)
+
struct soft_spi_priv {
unsigned int mode;
};
static int soft_spi_scl(struct udevice *dev, int bit)
{
- struct soft_spi_platdata *plat = dev->platdata;
+ struct udevice *bus = dev_get_parent(dev);
+ struct soft_spi_platdata *plat = dev_get_platdata(bus);
dm_gpio_set_value(&plat->sclk, bit);
@@ -43,7 +48,8 @@ static int soft_spi_scl(struct udevice *dev, int bit)
static int soft_spi_sda(struct udevice *dev, int bit)
{
- struct soft_spi_platdata *plat = dev->platdata;
+ struct udevice *bus = dev_get_parent(dev);
+ struct soft_spi_platdata *plat = dev_get_platdata(bus);
dm_gpio_set_value(&plat->mosi, bit);
@@ -52,7 +58,8 @@ static int soft_spi_sda(struct udevice *dev, int bit)
static int soft_spi_cs_activate(struct udevice *dev)
{
- struct soft_spi_platdata *plat = dev->platdata;
+ struct udevice *bus = dev_get_parent(dev);
+ struct soft_spi_platdata *plat = dev_get_platdata(bus);
dm_gpio_set_value(&plat->cs, 0);
dm_gpio_set_value(&plat->sclk, 0);
@@ -63,7 +70,8 @@ static int soft_spi_cs_activate(struct udevice *dev)
static int soft_spi_cs_deactivate(struct udevice *dev)
{
- struct soft_spi_platdata *plat = dev->platdata;
+ struct udevice *bus = dev_get_parent(dev);
+ struct soft_spi_platdata *plat = dev_get_platdata(bus);
dm_gpio_set_value(&plat->cs, 0);
@@ -100,8 +108,9 @@ static int soft_spi_release_bus(struct udevice *dev)
static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
- struct soft_spi_priv *priv = dev_get_priv(dev);
- struct soft_spi_platdata *plat = dev->platdata;
+ struct udevice *bus = dev_get_parent(dev);
+ struct soft_spi_priv *priv = dev_get_priv(bus);
+ struct soft_spi_platdata *plat = dev_get_platdata(bus);
uchar tmpdin = 0;
uchar tmpdout = 0;
const u8 *txd = dout;
@@ -134,14 +143,16 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (!cpha)
soft_spi_scl(dev, 0);
- soft_spi_sda(dev, tmpdout & 0x80);
+ if ((plat->flags & SPI_MASTER_NO_TX) == 0)
+ soft_spi_sda(dev, !!(tmpdout & 0x80));
udelay(plat->spi_delay_us);
if (cpha)
soft_spi_scl(dev, 0);
else
soft_spi_scl(dev, 1);
tmpdin <<= 1;
- tmpdin |= dm_gpio_get_value(&plat->miso);
+ if ((plat->flags & SPI_MASTER_NO_RX) == 0)
+ tmpdin |= dm_gpio_get_value(&plat->miso);
tmpdout <<= 1;
udelay(plat->spi_delay_us);
if (cpha)
@@ -203,24 +214,36 @@ static int soft_spi_probe(struct udevice *dev)
struct spi_slave *slave = dev_get_parent_priv(dev);
struct soft_spi_platdata *plat = dev->platdata;
int cs_flags, clk_flags;
+ int ret;
cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW;
clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0;
- if (gpio_request_by_name(dev, "cs-gpio", 0, &plat->cs,
+
+ if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs,
GPIOD_IS_OUT | cs_flags) ||
- gpio_request_by_name(dev, "sclk-gpio", 0, &plat->sclk,
- GPIOD_IS_OUT | clk_flags) ||
- gpio_request_by_name(dev, "mosi-gpio", 0, &plat->mosi,
- GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE) ||
- gpio_request_by_name(dev, "miso-gpio", 0, &plat->miso,
- GPIOD_IS_IN))
+ gpio_request_by_name(dev, "gpio-sck", 0, &plat->sclk,
+ GPIOD_IS_OUT | clk_flags))
+ return -EINVAL;
+
+ ret = gpio_request_by_name(dev, "gpio-mosi", 0, &plat->mosi,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret)
+ plat->flags |= SPI_MASTER_NO_TX;
+
+ ret = gpio_request_by_name(dev, "gpio-miso", 0, &plat->miso,
+ GPIOD_IS_IN);
+ if (ret)
+ plat->flags |= SPI_MASTER_NO_RX;
+
+ if ((plat->flags & (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX)) ==
+ (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX))
return -EINVAL;
return 0;
}
static const struct udevice_id soft_spi_ids[] = {
- { .compatible = "u-boot,soft-spi" },
+ { .compatible = "spi-gpio" },
{ }
};
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 5561f36762..84b6786517 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -45,12 +45,12 @@ static int spi_set_speed_mode(struct udevice *bus, int speed, int mode)
return 0;
}
-int spi_claim_bus(struct spi_slave *slave)
+int dm_spi_claim_bus(struct udevice *dev)
{
- struct udevice *dev = slave->dev;
struct udevice *bus = dev->parent;
struct dm_spi_ops *ops = spi_get_ops(bus);
struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
+ struct spi_slave *slave = dev_get_parent_priv(dev);
int speed;
int ret;
@@ -73,9 +73,8 @@ int spi_claim_bus(struct spi_slave *slave)
return ops->claim_bus ? ops->claim_bus(dev) : 0;
}
-void spi_release_bus(struct spi_slave *slave)
+void dm_spi_release_bus(struct udevice *dev)
{
- struct udevice *dev = slave->dev;
struct udevice *bus = dev->parent;
struct dm_spi_ops *ops = spi_get_ops(bus);
@@ -83,10 +82,9 @@ void spi_release_bus(struct spi_slave *slave)
ops->release_bus(dev);
}
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
+int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
{
- struct udevice *dev = slave->dev;
struct udevice *bus = dev->parent;
if (bus->uclass->uc_drv->id != UCLASS_SPI)
@@ -95,6 +93,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
}
+int spi_claim_bus(struct spi_slave *slave)
+{
+ return dm_spi_claim_bus(slave->dev);
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ dm_spi_release_bus(slave->dev);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ return dm_spi_xfer(slave->dev, bitlen, dout, din, flags);
+}
+
static int spi_post_bind(struct udevice *dev)
{
/* Scan the bus for devices */
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index 2f3d43d939..2f46d38d2b 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -3,5 +3,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
+obj-$(CONFIG_DM_USB) += common.o
obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o
obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
new file mode 100644
index 0000000000..35c2dc18d9
--- /dev/null
+++ b/drivers/usb/common/common.c
@@ -0,0 +1,40 @@
+/*
+ * Provides code common for host and device side USB.
+ *
+ * (C) Copyright 2016
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <linux/usb/otg.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *const usb_dr_modes[] = {
+ [USB_DR_MODE_UNKNOWN] = "",
+ [USB_DR_MODE_HOST] = "host",
+ [USB_DR_MODE_PERIPHERAL] = "peripheral",
+ [USB_DR_MODE_OTG] = "otg",
+};
+
+enum usb_dr_mode usb_get_dr_mode(int node)
+{
+ const void *fdt = gd->fdt_blob;
+ const char *dr_mode;
+ int i;
+
+ dr_mode = fdt_getprop(fdt, node, "dr_mode", NULL);
+ if (!dr_mode) {
+ error("usb dr_mode not found\n");
+ return USB_DR_MODE_UNKNOWN;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
+ if (!strcmp(dr_mode, usb_dr_modes[i]))
+ return i;
+
+ return USB_DR_MODE_UNKNOWN;
+}
diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c
index 7fd10e6af3..c01809e89e 100644
--- a/drivers/video/tegra.c
+++ b/drivers/video/tegra.c
@@ -620,6 +620,13 @@ static int tegra_lcd_ofdata_to_platdata(struct udevice *dev)
static int tegra_lcd_bind(struct udevice *dev)
{
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
+ int rgb;
+
+ rgb = fdt_subnode_offset(blob, node, "rgb");
+ if ((rgb < 0) || !fdtdec_get_is_enabled(blob, rgb))
+ return -ENODEV;
plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
(1 << LCD_MAX_LOG2_BPP) / 8;
OpenPOWER on IntegriCloud