diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/Kconfig | 11 | ||||
-rw-r--r-- | drivers/block/Makefile | 2 | ||||
-rw-r--r-- | drivers/block/blk-uclass.c | 175 | ||||
-rw-r--r-- | drivers/block/dwc_ahsata.c | 4 | ||||
-rw-r--r-- | drivers/block/pata_bfin.c | 2 | ||||
-rw-r--r-- | drivers/block/sandbox.c | 166 | ||||
-rw-r--r-- | drivers/block/systemace.c | 12 |
7 files changed, 337 insertions, 35 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 990f768adb..f35c4d4db7 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -1,3 +1,14 @@ +config BLK + bool "Support block devices" + depends on DM + help + Enable support for block devices, such as SCSI, MMC and USB + flash sticks. These provide a block-level interface which permits + reading, writing and (in some cases) erasing blocks. Block + devices often have a partition table which allows the device to + 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" depends on DM diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 5eb87e0b89..b5c7ae1124 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -5,6 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_BLK) += blk-uclass.o + obj-$(CONFIG_DISK) += disk-uclass.o obj-$(CONFIG_SCSI_AHCI) += ahci.o obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c new file mode 100644 index 0000000000..49df2a6f89 --- /dev/null +++ b/drivers/block/blk-uclass.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <blk.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> + +int blk_first_device(int if_type, struct udevice **devp) +{ + struct blk_desc *desc; + int ret; + + ret = uclass_first_device(UCLASS_BLK, devp); + if (ret) + return ret; + if (!*devp) + return -ENODEV; + do { + desc = dev_get_uclass_platdata(*devp); + if (desc->if_type == if_type) + return 0; + ret = uclass_next_device(devp); + if (ret) + return ret; + } while (*devp); + + return -ENODEV; +} + +int blk_next_device(struct udevice **devp) +{ + struct blk_desc *desc; + int ret, if_type; + + desc = dev_get_uclass_platdata(*devp); + if_type = desc->if_type; + do { + ret = uclass_next_device(devp); + if (ret) + return ret; + if (!*devp) + return -ENODEV; + desc = dev_get_uclass_platdata(*devp); + if (desc->if_type == if_type) + return 0; + } while (1); +} + +int blk_get_device(int if_type, int devnum, struct udevice **devp) +{ + struct uclass *uc; + struct udevice *dev; + 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); + + 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 && desc->devnum == devnum) { + *devp = dev; + return device_probe(dev); + } + } + + return -ENODEV; +} + +unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, void *buffer) +{ + struct udevice *dev = block_dev->bdev; + const struct blk_ops *ops = blk_get_ops(dev); + + if (!ops->read) + return -ENOSYS; + + return ops->read(dev, start, blkcnt, buffer); +} + +unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, const void *buffer) +{ + struct udevice *dev = block_dev->bdev; + const struct blk_ops *ops = blk_get_ops(dev); + + if (!ops->write) + return -ENOSYS; + + return ops->write(dev, start, blkcnt, buffer); +} + +unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt) +{ + struct udevice *dev = block_dev->bdev; + const struct blk_ops *ops = blk_get_ops(dev); + + if (!ops->erase) + return -ENOSYS; + + return ops->erase(dev, start, blkcnt); +} + +int blk_prepare_device(struct udevice *dev) +{ + struct blk_desc *desc = dev_get_uclass_platdata(dev); + + part_init(desc); + + return 0; +} + +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) +{ + struct blk_desc *desc; + struct udevice *dev; + int ret; + + ret = device_bind_driver(parent, drv_name, name, &dev); + if (ret) + return ret; + desc = dev_get_uclass_platdata(dev); + desc->if_type = if_type; + desc->blksz = blksz; + desc->lba = size / blksz; + desc->part_type = PART_TYPE_UNKNOWN; + desc->bdev = dev; + desc->devnum = devnum; + *devp = dev; + + return 0; +} + +int blk_unbind_all(int if_type) +{ + struct uclass *uc; + struct udevice *dev, *next; + int ret; + + ret = uclass_get(UCLASS_BLK, &uc); + if (ret) + return ret; + uclass_foreach_dev_safe(dev, next, uc) { + struct blk_desc *desc = dev_get_uclass_platdata(dev); + + if (desc->if_type == if_type) { + ret = device_remove(dev); + if (ret) + return ret; + ret = device_unbind(dev); + if (ret) + return ret; + } + } + + return 0; +} + +UCLASS_DRIVER(blk) = { + .id = UCLASS_BLK, + .name = "blk", + .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), +}; diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c index bc072f335f..6ec52a9114 100644 --- a/drivers/block/dwc_ahsata.c +++ b/drivers/block/dwc_ahsata.c @@ -620,7 +620,7 @@ int reset_sata(int dev) static void dwc_ahsata_print_info(int dev) { - block_dev_desc_t *pdev = &(sata_dev_desc[dev]); + struct blk_desc *pdev = &(sata_dev_desc[dev]); printf("SATA Device Info:\n\r"); #ifdef CONFIG_SYS_64BIT_LBA @@ -956,7 +956,7 @@ int scan_sata(int dev) struct ahci_probe_ent *probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; u8 port = probe_ent->hard_port_no; - block_dev_desc_t *pdev = &(sata_dev_desc[dev]); + struct blk_desc *pdev = &(sata_dev_desc[dev]); id = (u16 *)memalign(ARCH_DMA_MINALIGN, roundup(ARCH_DMA_MINALIGN, diff --git a/drivers/block/pata_bfin.c b/drivers/block/pata_bfin.c index c2673bd05d..26569d70aa 100644 --- a/drivers/block/pata_bfin.c +++ b/drivers/block/pata_bfin.c @@ -965,7 +965,7 @@ int scan_sata(int dev) /* Probe device and set xfer mode */ bfin_ata_identify(ap, dev%PATA_DEV_NUM_PER_PORT); bfin_ata_set_Feature_cmd(ap, dev%PATA_DEV_NUM_PER_PORT); - init_part(&sata_dev_desc[dev]); + part_init(&sata_dev_desc[dev]); return 0; } diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c index 170f0fa5bf..6d41508d5c 100644 --- a/drivers/block/sandbox.c +++ b/drivers/block/sandbox.c @@ -4,14 +4,20 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include <config.h> #include <common.h> +#include <blk.h> +#include <dm.h> +#include <fdtdec.h> #include <part.h> #include <os.h> #include <malloc.h> #include <sandboxblockdev.h> #include <asm/errno.h> +#include <dm/device-internal.h> +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) @@ -21,48 +27,130 @@ static struct host_block_dev *find_host_device(int dev) return NULL; } +#endif -static unsigned long host_block_read(block_dev_desc_t *block_dev, +#ifdef CONFIG_BLK +static unsigned long host_block_read(struct udevice *dev, unsigned long start, lbaint_t blkcnt, void *buffer) { - int dev = block_dev->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; - if (os_lseek(host_dev->fd, - start * host_dev->blk_dev.blksz, - OS_SEEK_SET) == -1) { - printf("ERROR: Invalid position\n"); +#endif + + if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) == + -1) { + printf("ERROR: Invalid block %lx\n", start); return -1; } - ssize_t len = os_read(host_dev->fd, buffer, - blkcnt * host_dev->blk_dev.blksz); + ssize_t len = os_read(host_dev->fd, buffer, blkcnt * block_dev->blksz); if (len >= 0) - return len / host_dev->blk_dev.blksz; + return len / block_dev->blksz; return -1; } -static unsigned long host_block_write(block_dev_desc_t *block_dev, +#ifdef CONFIG_BLK +static unsigned long host_block_write(struct udevice *dev, unsigned long start, lbaint_t blkcnt, const void *buffer) { - int dev = block_dev->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_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); - if (os_lseek(host_dev->fd, - start * host_dev->blk_dev.blksz, - OS_SEEK_SET) == -1) { - printf("ERROR: Invalid position\n"); +#endif + + if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) == + -1) { + printf("ERROR: Invalid block %lx\n", start); return -1; } - ssize_t len = os_write(host_dev->fd, buffer, blkcnt * - host_dev->blk_dev.blksz); + ssize_t len = os_write(host_dev->fd, buffer, blkcnt * block_dev->blksz); if (len >= 0) - return len / host_dev->blk_dev.blksz; + return len / block_dev->blksz; return -1; } +#ifdef CONFIG_BLK +int host_dev_bind(int devnum, char *filename) +{ + struct host_block_dev *host_dev; + struct udevice *dev; + char dev_name[20], *str, *fname; + int ret, fd; + + /* Remove and unbind the old device, if any */ + ret = blk_get_device(IF_TYPE_HOST, devnum, &dev); + if (ret == 0) { + ret = device_remove(dev); + if (ret) + return ret; + ret = device_unbind(dev); + if (ret) + return ret; + } else if (ret != -ENODEV) { + return ret; + } + + if (!filename) + return 0; + + snprintf(dev_name, sizeof(dev_name), "host%d", devnum); + str = strdup(dev_name); + if (!str) + return -ENOMEM; + fname = strdup(filename); + if (!fname) { + free(str); + return -ENOMEM; + } + + fd = os_open(filename, OS_O_RDWR); + if (fd == -1) { + printf("Failed to access host backing file '%s'\n", filename); + ret = -ENOENT; + goto err; + } + ret = blk_create_device(gd->dm_root, "sandbox_host_blk", str, + IF_TYPE_HOST, devnum, 512, + os_lseek(fd, 0, OS_SEEK_END), &dev); + if (ret) + goto err_file; + ret = device_probe(dev); + if (ret) { + device_unbind(dev); + goto err_file; + } + + host_dev = dev_get_priv(dev); + host_dev->fd = fd; + host_dev->filename = fname; + + return blk_prepare_device(dev); +err_file: + os_close(fd); +err: + free(fname); + free(str); + return ret; +} +#else int host_dev_bind(int dev, char *filename) { struct host_block_dev *host_dev = find_host_device(dev); @@ -89,23 +177,33 @@ int host_dev_bind(int dev, char *filename) return 1; } - block_dev_desc_t *blk_dev = &host_dev->blk_dev; + 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->dev = dev; + blk_dev->devnum = dev; blk_dev->part_type = PART_TYPE_UNKNOWN; - init_part(blk_dev); + part_init(blk_dev); return 0; } +#endif -int host_get_dev_err(int dev, block_dev_desc_t **blk_devp) +int host_get_dev_err(int devnum, struct blk_desc **blk_devp) { - struct host_block_dev *host_dev = find_host_device(dev); +#ifdef CONFIG_BLK + struct udevice *dev; + int ret; + + ret = blk_get_device(IF_TYPE_HOST, devnum, &dev); + if (ret) + return ret; + *blk_devp = dev_get_uclass_platdata(dev); +#else + struct host_block_dev *host_dev = find_host_device(devnum); if (!host_dev) return -ENODEV; @@ -114,15 +212,31 @@ int host_get_dev_err(int dev, block_dev_desc_t **blk_devp) return -ENOENT; *blk_devp = &host_dev->blk_dev; +#endif + return 0; } -block_dev_desc_t *host_get_dev(int dev) +struct blk_desc *host_get_dev(int dev) { - block_dev_desc_t *blk_dev; + struct blk_desc *blk_dev; if (host_get_dev_err(dev, &blk_dev)) return NULL; return blk_dev; } + +#ifdef CONFIG_BLK +static const struct blk_ops sandbox_host_blk_ops = { + .read = host_block_read, + .write = host_block_write, +}; + +U_BOOT_DRIVER(sandbox_host_blk) = { + .name = "sandbox_host_blk", + .id = UCLASS_BLK, + .ops = &sandbox_host_blk_ops, + .priv_auto_alloc_size = sizeof(struct host_block_dev), +}; +#endif diff --git a/drivers/block/systemace.c b/drivers/block/systemace.c index b974e80167..09fe834e22 100644 --- a/drivers/block/systemace.c +++ b/drivers/block/systemace.c @@ -69,11 +69,11 @@ static u16 ace_readw(unsigned off) return in16(base + off); } -static unsigned long systemace_read(block_dev_desc_t *block_dev, +static unsigned long systemace_read(struct blk_desc *block_dev, unsigned long start, lbaint_t blkcnt, void *buffer); -static block_dev_desc_t systemace_dev = { 0 }; +static struct blk_desc systemace_dev = { 0 }; static int get_cf_lock(void) { @@ -105,13 +105,13 @@ static void release_cf_lock(void) } #ifdef CONFIG_PARTITIONS -block_dev_desc_t *systemace_get_dev(int dev) +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.dev = 0; + systemace_dev.devnum = 0; systemace_dev.part_type = PART_TYPE_UNKNOWN; systemace_dev.type = DEV_TYPE_HARDDISK; systemace_dev.blksz = 512; @@ -124,7 +124,7 @@ block_dev_desc_t *systemace_get_dev(int dev) */ ace_writew(width == 8 ? 0 : 0x0001, 0); - init_part(&systemace_dev); + part_init(&systemace_dev); } @@ -137,7 +137,7 @@ block_dev_desc_t *systemace_get_dev(int dev) * the dev_desc) to read blocks of data. The return value is the * number of blocks read. A zero return indicates an error. */ -static unsigned long systemace_read(block_dev_desc_t *block_dev, +static unsigned long systemace_read(struct blk_desc *block_dev, unsigned long start, lbaint_t blkcnt, void *buffer) { |