From 1a73661bc7a7ad2d741f7d7519872ca18231598c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 29 Feb 2016 15:25:39 -0700 Subject: dm: Add a new header for block devices At present block devices are tied up with partitions. But not all block devices have partitions within them. They are in fact separate concepts. Create a separate blk.h header file for block devices. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Stephen Warren --- include/blk.h | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 include/blk.h (limited to 'include/blk.h') diff --git a/include/blk.h b/include/blk.h new file mode 100644 index 00000000000..1e8334c23a4 --- /dev/null +++ b/include/blk.h @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef BLK_H +#define BLK_H + +#ifdef CONFIG_SYS_64BIT_LBA +typedef uint64_t lbaint_t; +#define LBAFlength "ll" +#else +typedef ulong lbaint_t; +#define LBAFlength "l" +#endif +#define LBAF "%" LBAFlength "x" +#define LBAFU "%" LBAFlength "u" + +/* Interface types: */ +#define IF_TYPE_UNKNOWN 0 +#define IF_TYPE_IDE 1 +#define IF_TYPE_SCSI 2 +#define IF_TYPE_ATAPI 3 +#define IF_TYPE_USB 4 +#define IF_TYPE_DOC 5 +#define IF_TYPE_MMC 6 +#define IF_TYPE_SD 7 +#define IF_TYPE_SATA 8 +#define IF_TYPE_HOST 9 +#define IF_TYPE_MAX 10 /* Max number of IF_TYPE_* supported */ + +struct blk_desc { + int if_type; /* type of the interface */ + int dev; /* device number */ + unsigned char part_type; /* partition type */ + unsigned char target; /* target SCSI ID */ + unsigned char lun; /* target LUN */ + unsigned char hwpart; /* HW partition, e.g. for eMMC */ + unsigned char type; /* device type */ + unsigned char removable; /* removable device */ +#ifdef CONFIG_LBA48 + /* device can use 48bit addr (ATA/ATAPI v7) */ + unsigned char lba48; +#endif + lbaint_t lba; /* number of blocks */ + unsigned long blksz; /* block size */ + int log2blksz; /* for convenience: log2(blksz) */ + char vendor[40+1]; /* IDE model, SCSI Vendor */ + char product[20+1]; /* IDE Serial no, SCSI product */ + char revision[8+1]; /* firmware revision */ + unsigned long (*block_read)(struct blk_desc *block_dev, + lbaint_t start, + lbaint_t blkcnt, + void *buffer); + unsigned long (*block_write)(struct blk_desc *block_dev, + lbaint_t start, + lbaint_t blkcnt, + const void *buffer); + unsigned long (*block_erase)(struct blk_desc *block_dev, + lbaint_t start, + lbaint_t blkcnt); + void *priv; /* driver private struct pointer */ +}; + +#define BLOCK_CNT(size, blk_desc) (PAD_COUNT(size, blk_desc->blksz)) +#define PAD_TO_BLOCKSIZE(size, blk_desc) \ + (PAD_SIZE(size, blk_desc->blksz)) + +#endif -- cgit v1.2.3 From 5ec4f1a5f35dc71881f88c84176c568308133640 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 29 Feb 2016 15:25:40 -0700 Subject: dm: blk: Convert interface type to an enum Since these are sequentially numbered it makes sense to use an enum. It avoids having to maintain the maximum value, and provides a type we can use if it is useful. In fact the maximum value is not used. Rename it to COUNT, since MAX suggests it is the maximum valid value, but it is not. Signed-off-by: Simon Glass Tested-by: Stephen Warren --- include/blk.h | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'include/blk.h') diff --git a/include/blk.h b/include/blk.h index 1e8334c23a4..fd545202eb4 100644 --- a/include/blk.h +++ b/include/blk.h @@ -19,20 +19,23 @@ typedef ulong lbaint_t; #define LBAFU "%" LBAFlength "u" /* Interface types: */ -#define IF_TYPE_UNKNOWN 0 -#define IF_TYPE_IDE 1 -#define IF_TYPE_SCSI 2 -#define IF_TYPE_ATAPI 3 -#define IF_TYPE_USB 4 -#define IF_TYPE_DOC 5 -#define IF_TYPE_MMC 6 -#define IF_TYPE_SD 7 -#define IF_TYPE_SATA 8 -#define IF_TYPE_HOST 9 -#define IF_TYPE_MAX 10 /* Max number of IF_TYPE_* supported */ +enum if_type { + IF_TYPE_UNKNOWN = 0, + IF_TYPE_IDE, + IF_TYPE_SCSI, + IF_TYPE_ATAPI, + IF_TYPE_USB, + IF_TYPE_DOC, + IF_TYPE_MMC, + IF_TYPE_SD, + IF_TYPE_SATA, + IF_TYPE_HOST, + + IF_TYPE_COUNT, /* Number of interface types */ +}; struct blk_desc { - int if_type; /* type of the interface */ + enum if_type if_type; /* type of the interface */ int dev; /* device number */ unsigned char part_type; /* partition type */ unsigned char target; /* target SCSI ID */ -- cgit v1.2.3 From bcce53d048de7f41078d25e39aa2f26d752d3658 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 29 Feb 2016 15:25:51 -0700 Subject: dm: block: Rename device number member dev to devnum This is a device number, and we want to use 'dev' to mean a driver model device. Rename the member. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Stephen Warren --- include/blk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/blk.h') diff --git a/include/blk.h b/include/blk.h index fd545202eb4..9c54842961f 100644 --- a/include/blk.h +++ b/include/blk.h @@ -36,7 +36,7 @@ enum if_type { struct blk_desc { enum if_type if_type; /* type of the interface */ - int dev; /* device number */ + int devnum; /* device number */ unsigned char part_type; /* partition type */ unsigned char target; /* target SCSI ID */ unsigned char lun; /* target LUN */ -- cgit v1.2.3 From 2a981dc2c62c500110aad297fa70503aec36e689 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 29 Feb 2016 15:25:52 -0700 Subject: dm: block: Adjust device calls to go through helpers function To ease conversion to driver model, add helper functions which deal with calling each block device method. With driver model we can reimplement these functions with the same arguments. Use inline functions to avoid increasing code size on some boards. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Stephen Warren --- include/blk.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'include/blk.h') diff --git a/include/blk.h b/include/blk.h index 9c54842961f..7b2e5e286f2 100644 --- a/include/blk.h +++ b/include/blk.h @@ -71,4 +71,33 @@ struct blk_desc { #define PAD_TO_BLOCKSIZE(size, blk_desc) \ (PAD_SIZE(size, blk_desc->blksz)) +/* + * These functions should take struct udevice instead of struct blk_desc, + * but this is convenient for migration to driver model. Add a 'd' prefix + * to the function operations, so that blk_read(), etc. can be reserved for + * functions with the correct arguments. + */ +static inline ulong blk_dread(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, void *buffer) +{ + /* + * We could check if block_read is NULL and return -ENOSYS. But this + * bloats the code slightly (cause some board to fail to build), and + * it would be an error to try an operation that does not exist. + */ + return block_dev->block_read(block_dev, start, blkcnt, buffer); +} + +static inline ulong blk_dwrite(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, const void *buffer) +{ + return block_dev->block_write(block_dev, start, blkcnt, buffer); +} + +static inline ulong blk_derase(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt) +{ + return block_dev->block_erase(block_dev, start, blkcnt); +} + #endif -- cgit v1.2.3 From 09d71aac7b530f03ec29cc9d5787047460a629ca Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 29 Feb 2016 15:25:55 -0700 Subject: dm: blk: Add a block-device uclass Add a uclass for block devices. These provide block-oriented data access, supporting reading, writing and erasing of whole blocks. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Stephen Warren --- include/blk.h | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) (limited to 'include/blk.h') diff --git a/include/blk.h b/include/blk.h index 7b2e5e286f2..e83c144e6c5 100644 --- a/include/blk.h +++ b/include/blk.h @@ -34,7 +34,15 @@ enum if_type { IF_TYPE_COUNT, /* Number of interface types */ }; +/* + * With driver model (CONFIG_BLK) this is uclass platform data, accessible + * with dev_get_uclass_platdata(dev) + */ struct blk_desc { + /* + * TODO: With driver model we should be able to use the parent + * device's uclass instead. + */ enum if_type if_type; /* type of the interface */ int devnum; /* device number */ unsigned char part_type; /* partition type */ @@ -53,6 +61,9 @@ struct blk_desc { char vendor[40+1]; /* IDE model, SCSI Vendor */ char product[20+1]; /* IDE Serial no, SCSI product */ char revision[8+1]; /* firmware revision */ +#ifdef CONFIG_BLK + struct udevice *bdev; +#else unsigned long (*block_read)(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, @@ -65,12 +76,145 @@ struct blk_desc { lbaint_t start, lbaint_t blkcnt); void *priv; /* driver private struct pointer */ +#endif }; #define BLOCK_CNT(size, blk_desc) (PAD_COUNT(size, blk_desc->blksz)) #define PAD_TO_BLOCKSIZE(size, blk_desc) \ (PAD_SIZE(size, blk_desc->blksz)) +#ifdef CONFIG_BLK +struct udevice; + +/* Operations on block devices */ +struct blk_ops { + /** + * read() - read from a block device + * + * @dev: Device to read from + * @start: Start block number to read (0=first) + * @blkcnt: Number of blocks to read + * @buffer: Destination buffer for data read + * @return number of blocks read, or -ve error number (see the + * IS_ERR_VALUE() macro + */ + unsigned long (*read)(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt, void *buffer); + + /** + * write() - write to a block device + * + * @dev: Device to write to + * @start: Start block number to write (0=first) + * @blkcnt: Number of blocks to write + * @buffer: Source buffer for data to write + * @return number of blocks written, or -ve error number (see the + * IS_ERR_VALUE() macro + */ + unsigned long (*write)(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt, const void *buffer); + + /** + * erase() - erase a section of a block device + * + * @dev: Device to (partially) erase + * @start: Start block number to erase (0=first) + * @blkcnt: Number of blocks to erase + * @return number of blocks erased, or -ve error number (see the + * IS_ERR_VALUE() macro + */ + unsigned long (*erase)(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt); +}; + +#define blk_get_ops(dev) ((struct blk_ops *)(dev)->driver->ops) + +/* + * These functions should take struct udevice instead of struct blk_desc, + * but this is convenient for migration to driver model. Add a 'd' prefix + * to the function operations, so that blk_read(), etc. can be reserved for + * functions with the correct arguments. + */ +unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, void *buffer); +unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, const void *buffer); +unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt); + +/** + * blk_get_device() - Find and probe a block device ready for use + * + * @if_type: Interface type (enum if_type_t) + * @devnum: Device number (specific to each interface type) + * @devp: the device, if found + * @return - if found, -ENODEV if no device found, or other -ve error value + */ +int blk_get_device(int if_type, int devnum, struct udevice **devp); + +/** + * blk_first_device() - Find the first device for a given interface + * + * The device is probed ready for use + * + * @devnum: Device number (specific to each interface type) + * @devp: the device, if found + * @return 0 if found, -ENODEV if no device, or other -ve error value + */ +int blk_first_device(int if_type, struct udevice **devp); + +/** + * blk_next_device() - Find the next device for a given interface + * + * This can be called repeatedly after blk_first_device() to iterate through + * all devices of the given interface type. + * + * The device is probed ready for use + * + * @devp: On entry, the previous device returned. On exit, the next + * device, if found + * @return 0 if found, -ENODEV if no device, or other -ve error value + */ +int blk_next_device(struct udevice **devp); + +/** + * blk_create_device() - Create a new block device + * + * @parent: Parent of the new device + * @drv_name: Driver name to use for the block device + * @name: Name for the device + * @if_type: Interface type (enum if_type_t) + * @devnum: Device number, specific to the interface type + * @blksz: Block size of the device in bytes (typically 512) + * @size: Total size of the device in bytes + * @devp: the new device (which has not been probed) + */ +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); + +/** + * blk_prepare_device() - Prepare a block device for use + * + * This reads partition information from the device if supported. + * + * @dev: Device to prepare + * @return 0 if ok, -ve on error + */ +int blk_prepare_device(struct udevice *dev); + +/** + * blk_unbind_all() - Unbind all device of the given interface type + * + * The devices are removed and then unbound. + * + * @if_type: Interface type to unbind + * @return 0 if OK, -ve on error + */ +int blk_unbind_all(int if_type); + +#else +#include /* * These functions should take struct udevice instead of struct blk_desc, * but this is convenient for migration to driver model. Add a 'd' prefix @@ -99,5 +243,6 @@ static inline ulong blk_derase(struct blk_desc *block_dev, lbaint_t start, { return block_dev->block_erase(block_dev, start, blkcnt); } +#endif /* !CONFIG_BLK */ #endif -- cgit v1.2.3