[U-Boot] [PATCH 00/23] dm: mmc: Add driver-model block-device support to MMC

This series adds support for using CONFIG_BLK with MMC, such that it uses the block interface correctly. The old interface in part.c is removed.
With driver model, when CONFIG_BLK is enabled, MMC devices must have a child block device. A new mmc_bind() function takes care of this. It should be called when new MMC devices are bound.
MMC support is added to sandbox along with a simple driver-model test.
Code size does unfortunately increase slightly in SPL. For example firefly (Thumb 2) adds 128 bytes of code overall due to the new block driver table support. There may be some potential after this series to rationalise the common/spl/ implementations and reduce code size a little, but that remains to be seen.
This series follows on from the previous series which refactored block devices. It is available at u-boot-dm/blkb-working
Simon Glass (23): dm: blk: Fix allocation of block-device numbering dm: core: Allow device names to be freed automatically dm: blk: Free the block device name when unbound dm: mmc: Move mmc_switch_part() above its callers dm: mmc: Implement the select_hwpart() method dm: mmc: Add a function to obtain the block device dm: mmc: spl: Use the legacy block interface in SPL dm: mmc: Use the new select_hwpart() API dm: blk: Add functions to select a hardware partition dm: part: Use the legacy block driver for hardware partition support dm: part: Drop the block_drvr table dm: blk: Add a comment as to why the bdev member is needed dm: mmc: Set up the device pointer when using the MMC uclass dm: mmc: Move the device list into a separate file dm: blk: Use the correct error code for blk_get_device_by_str() dm: mmc: Adjust mmc_switch_part() to use a struct mmc dm: sandbox: Only enable the sandbox MMC driver when valid dm: mmc: Implement the MMC functions for block devices dm: mmc: Add a way to bind MMC devices with driver model dm: mmc: Add support for driver-model block devices dm: mmc: sandbox: Add an SD-card emulation dm: sandbox: mmc: Enable building MMC code for sandbox dm: mmc: test: Add tests for MMC
cmd/mmc.c | 16 ++- common/env_mmc.c | 4 +- common/spl/spl_mmc.c | 2 +- configs/sandbox_defconfig | 10 +- disk/part.c | 81 +++--------- drivers/Makefile | 1 + drivers/block/blk-uclass.c | 59 +++++++-- drivers/core/device-remove.c | 2 + drivers/core/device.c | 6 + drivers/dfu/dfu_mmc.c | 13 +- drivers/mmc/Kconfig | 11 +- drivers/mmc/Makefile | 12 +- drivers/mmc/mmc-uclass.c | 106 ++++++++++++++++ drivers/mmc/mmc.c | 289 ++++++++++++++++++++++-------------------- drivers/mmc/mmc_legacy.c | 108 ++++++++++++++++ drivers/mmc/mmc_private.h | 33 ++++- drivers/mmc/mmc_write.c | 18 ++- drivers/mmc/omap_hsmmc.c | 1 + drivers/mmc/pic32_sdhci.c | 7 +- drivers/mmc/rockchip_dw_mmc.c | 1 + drivers/mmc/sandbox_mmc.c | 134 +++++++++++++++++++- drivers/mmc/socfpga_dw_mmc.c | 1 + drivers/mmc/uniphier-sd.c | 1 + drivers/mmc/zynq_sdhci.c | 1 + include/blk.h | 35 +++++ include/configs/sandbox.h | 2 + include/dm/device.h | 16 +++ include/mmc.h | 38 +++++- include/part.h | 18 --- lib/efi_loader/efi_disk.c | 19 ++- test/dm/blk.c | 4 +- test/dm/mmc.c | 19 +++ 32 files changed, 799 insertions(+), 269 deletions(-) create mode 100644 drivers/mmc/mmc_legacy.c

Due to code ordering the block devices are not numbered sequentially. Fix this.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/block/blk-uclass.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 6ecbff0..f67f9b9 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -439,15 +439,6 @@ int blk_create_device(struct udevice *parent, const char *drv_name, 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; if (devnum == -1) { ret = blk_find_max_devnum(if_type); if (ret == -ENODEV) @@ -457,6 +448,15 @@ int blk_create_device(struct udevice *parent, const char *drv_name, else devnum = ret + 1; } + 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;

Some devices have a name that is stored in allocated memory. At present there is no mechanism to free this memory when the device is unbound.
Add a device flag to track whether a name is allocated and a function to add the flag. Free the memory when the device is unbound.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device-remove.c | 2 ++ drivers/core/device.c | 6 ++++++ include/dm/device.h | 16 ++++++++++++++++ 3 files changed, 24 insertions(+)
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index e1714b2..0e56b23 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 cb24a61..3bdea99 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -682,12 +682,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/include/dm/device.h b/include/dm/device.h index 1cf8150..d54f737 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -41,6 +41,9 @@ struct driver_info; /* Device is bound */ #define DM_FLAG_BOUND (1 << 6)
+/* Device name is allocated and should be freed on unbind() */ +#define DM_NAME_ALLOCED (1 << 7) + /** * struct udevice - An instance of a driver * @@ -501,6 +504,9 @@ bool device_is_last_sibling(struct udevice *dev); * this is unnecessary but for probed devices which don't get a useful name * this function can be helpful. * + * The name is allocated and will be freed automatically when the device is + * unbound. + * * @dev: Device to update * @name: New name (this string is allocated new memory and attached to * the device) @@ -510,6 +516,16 @@ bool device_is_last_sibling(struct udevice *dev); int device_set_name(struct udevice *dev, const char *name);
/** + * device_set_name_alloced() - note that a device name is allocated + * + * This sets the DM_NAME_ALLOCED flag for the device, so that when it is + * unbound the name will be freed. This avoids memory leaks. + * + * @dev: Device to update + */ +void device_set_name_alloced(struct udevice *dev); + +/** * device_is_on_pci_bus - Test if a device is on a PCI bus * * @dev: device to test

Mark the device name as allocated so that it will be freed correctly when the device is unbound.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/block/blk-uclass.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index f67f9b9..a37239e 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -468,14 +468,22 @@ int blk_create_devicef(struct udevice *parent, const char *drv_name, 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;
- return blk_create_device(parent, drv_name, str, if_type, devnum, - blksz, size, devp); + 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)

This function is defined after it is used. In preparation for making it static, move it up a little. Also drop the printf() which should not appear in a driver.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 185d7b2..2211ac6 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -582,30 +582,6 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num) return 0; }
-int mmc_select_hwpart(int dev_num, int hwpart) -{ - struct mmc *mmc = find_mmc_device(dev_num); - int ret; - - if (!mmc) - return -ENODEV; - - if (mmc->block_dev.hwpart == hwpart) - return 0; - - if (mmc->part_config == MMCPART_NOAVAILABLE) { - printf("Card doesn't support part_switch\n"); - return -EMEDIUMTYPE; - } - - ret = mmc_switch_part(dev_num, hwpart); - if (ret) - return ret; - - return 0; -} - - int mmc_switch_part(int dev_num, unsigned int part_num) { struct mmc *mmc = find_mmc_device(dev_num); @@ -630,6 +606,27 @@ int mmc_switch_part(int dev_num, unsigned int part_num) return ret; }
+int mmc_select_hwpart(int dev_num, int hwpart) +{ + struct mmc *mmc = find_mmc_device(dev_num); + int ret; + + if (!mmc) + return -ENODEV; + + if (mmc->block_dev.hwpart == hwpart) + return 0; + + if (mmc->part_config == MMCPART_NOAVAILABLE) + return -EMEDIUMTYPE; + + ret = mmc_switch_part(dev_num, hwpart); + if (ret) + return ret; + + return 0; +} + int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf, enum mmc_hwpart_conf_mode mode)

Implement this method so that hardware partitions will work correctly with MMC.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2211ac6..e270f5f 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -606,6 +606,27 @@ int mmc_switch_part(int dev_num, unsigned int part_num) return ret; }
+static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart) +{ + struct mmc *mmc = find_mmc_device(desc->devnum); + int ret; + + if (!mmc) + return -ENODEV; + + if (mmc->block_dev.hwpart == hwpart) + return 0; + + if (mmc->part_config == MMCPART_NOAVAILABLE) + return -EMEDIUMTYPE; + + ret = mmc_switch_part(desc->devnum, hwpart); + if (ret) + return ret; + + return 0; +} + int mmc_select_hwpart(int dev_num, int hwpart) { struct mmc *mmc = find_mmc_device(dev_num); @@ -1973,4 +1994,5 @@ U_BOOT_LEGACY_BLK(mmc) = { .if_type = IF_TYPE_MMC, .max_devs = -1, .get_dev = mmc_get_dev, + .select_hwpart = mmc_select_hwpartp, };

The MMC block device is contained within struct mmc. But with driver model this will not be the case. Add a function to obtain the block device. We can later implement this for CONFIG_BLK.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc.c | 5 +++++ include/mmc.h | 8 ++++++++ 2 files changed, 13 insertions(+)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e270f5f..49996a8 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -24,6 +24,11 @@ static struct list_head mmc_devices; static int cur_dev_num = -1;
+struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) +{ + return &mmc->block_dev; +} + __weak int board_mmc_getwp(struct mmc *mmc) { return -1; diff --git a/include/mmc.h b/include/mmc.h index cdb56e7..36449c3 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -498,4 +498,12 @@ int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported); #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 #endif
+/** + * mmc_get_blk_desc() - Get the block descriptor for an MMC device + * + * @mmc: MMC device + * @return block device if found, else NULL + */ +struct blk_desc *mmc_get_blk_desc(struct mmc *mmc); + #endif /* _MMC_H_ */

Bring this in for SPL so that we can use generic code for loading from block devices.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/Makefile | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/Makefile b/drivers/Makefile index 696b3ac..99dd07f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -37,6 +37,7 @@ 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

Avoid calling directly into the MMC code - use the new API call instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
cmd/mmc.c | 8 +++++--- common/env_mmc.c | 4 ++-- common/spl/spl_mmc.c | 2 +- drivers/dfu/dfu_mmc.c | 13 +++++++++---- drivers/mmc/mmc.c | 2 +- drivers/mmc/mmc_write.c | 5 +++-- include/mmc.h | 1 - 7 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/cmd/mmc.c b/cmd/mmc.c index 0fed790..3d82ccd 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -314,12 +314,14 @@ static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag, } /* Switch to the RPMB partition */ original_part = mmc->block_dev.part_num; - if (mmc_select_hwpart(curr_device, MMC_PART_RPMB) != 0) + if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, MMC_PART_RPMB) != + 0) return CMD_RET_FAILURE; ret = cp->cmd(cmdtp, flag, argc, argv);
/* Return to original partition */ - if (mmc_select_hwpart(curr_device, original_part) != 0) + if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, original_part) != + 0) return CMD_RET_FAILURE; return ret; } @@ -467,7 +469,7 @@ static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag, if (!mmc) return CMD_RET_FAILURE;
- ret = mmc_select_hwpart(dev, part); + ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part); printf("switch to partitions #%d, %s\n", part, (!ret) ? "OK" : "ERROR"); if (ret) diff --git a/common/env_mmc.c b/common/env_mmc.c index bdb452e..2555f7b 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -87,7 +87,7 @@ static int mmc_set_env_part(struct mmc *mmc) #endif
env_mmc_orig_hwpart = mmc->block_dev.hwpart; - ret = mmc_select_hwpart(dev, part); + ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part); if (ret) puts("MMC partition switch failed\n");
@@ -119,7 +119,7 @@ static void fini_mmc_for_env(struct mmc *mmc) #ifdef CONFIG_SPL_BUILD dev = 0; #endif - mmc_select_hwpart(dev, env_mmc_orig_hwpart); + blk_select_hwpart_devnum(IF_TYPE_MMC, dev, env_mmc_orig_hwpart); #endif }
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 7d3bfc6..4a8de11 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -286,7 +286,7 @@ int spl_mmc_load_image(u32 boot_device) if (part == 7) part = 0;
- err = mmc_switch_part(0, part); + err = blk_dselect_hwpart(mmc_get_blk_desc(mmc), part); if (err) { #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT puts("spl: mmc partition switch failed\n"); diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index faece88..78724e4 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/mmc/mmc.c b/drivers/mmc/mmc.c index 49996a8..7322f334 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -257,7 +257,7 @@ 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;
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 7b186f8..f4d42aa 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -78,7 +78,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;
@@ -182,7 +183,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/include/mmc.h b/include/mmc.h index 36449c3..f01674d 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -415,7 +415,6 @@ struct mmc *find_mmc_device(int dev_num); int mmc_set_dev(int dev_num); void print_mmc_devices(char separator); int get_mmc_num(void); -int mmc_switch_part(int dev_num, unsigned int part_num); int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf, enum mmc_hwpart_conf_mode mode); int mmc_getcd(struct mmc *mmc);

The block device uclass does not currently support selecting a particular hardware partition but this is needed for MMC. Add it so that the blk API can support MMC properly.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/block/blk-uclass.c | 29 +++++++++++++++++++++++++++++ include/blk.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index a37239e..6ba1026 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -165,6 +165,18 @@ static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp) 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; @@ -291,6 +303,23 @@ ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, 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; diff --git a/include/blk.h b/include/blk.h index 19bc6a4..415c3a8 100644 --- a/include/blk.h +++ b/include/blk.h @@ -217,6 +217,25 @@ struct blk_ops { */ unsigned long (*erase)(struct udevice *dev, lbaint_t start, lbaint_t blkcnt); + + /** + * select_hwpart() - select a particular hardware partition + * + * Some devices (e.g. MMC) can support partitioning at the hardware + * level. This is quite separate from the normal idea of + * software-based partitions. MMC hardware partitions must be + * explicitly selected. Once selected only the region of the device + * covered by that partition is accessible. + * + * The MMC standard provides for two boot partitions (numbered 1 and 2), + * rpmb (3), and up to 4 addition general-purpose partitions (4-7). + * + * @desc: Block device to update + * @hwpart: Hardware partition number to select. 0 means the raw + * device, 1 is the first partition, 2 is the second, etc. + * @return 0 if OK, -ve on error + */ + int (*select_hwpart)(struct udevice *dev, int hwpart); };
#define blk_get_ops(dev) ((struct blk_ops *)(dev)->driver->ops) @@ -335,6 +354,17 @@ int blk_unbind_all(int if_type); */ int blk_find_max_devnum(enum if_type if_type);
+/** + * blk_select_hwpart() - select a hardware partition + * + * Select a hardware partition if the device supports it (typically MMC does) + * + * @dev: Device to update + * @hwpart: Partition number to select + * @return 0 if OK, -ve on error + */ +int blk_select_hwpart(struct udevice *dev, int hwpart); + #else #include <errno.h> /*

Drop use of the table in part.c for this feature.
Signed-off-by: Simon Glass sjg@chromium.org ---
disk/part.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/disk/part.c b/disk/part.c index 8d5f028..5d6dc68 100644 --- a/disk/part.c +++ b/disk/part.c @@ -71,9 +71,7 @@ static struct part_driver *part_driver_lookup_type(int part_type) static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) { const struct block_drvr *drvr = block_drvr; - int (*select_hwpart)(int dev_num, int hwpart); char *name; - int ret;
if (!ifname) return NULL; @@ -84,11 +82,8 @@ static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) #endif while (drvr->name) { name = drvr->name; - select_hwpart = drvr->select_hwpart; #ifdef CONFIG_NEEDS_MANUAL_RELOC name += gd->reloc_off; - if (select_hwpart) - select_hwpart += gd->reloc_off; #endif if (strncmp(ifname, name, strlen(name)) == 0) { struct blk_desc *dev_desc; @@ -96,12 +91,7 @@ static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) dev_desc = blk_get_devnum_by_typename(name, dev); if (!dev_desc) return NULL; - if (hwpart == 0 && !select_hwpart) - return dev_desc; - if (!select_hwpart) - return NULL; - ret = select_hwpart(dev_desc->devnum, hwpart); - if (ret < 0) + if (blk_dselect_hwpart(dev_desc, hwpart)) return NULL; return dev_desc; }

This is not needed since we can use the functions provided by the legacy block device support.
Signed-off-by: Simon Glass sjg@chromium.org ---
disk/part.c | 67 ++++++++++------------------------------------- lib/efi_loader/efi_disk.c | 19 +++++++++----- 2 files changed, 26 insertions(+), 60 deletions(-)
diff --git a/disk/part.c b/disk/part.c index 5d6dc68..4b850fa 100644 --- a/disk/part.c +++ b/disk/part.c @@ -21,34 +21,6 @@ #define PRINTF(fmt,args...) #endif
-const struct block_drvr block_drvr[] = { -#if defined(CONFIG_CMD_IDE) - { .name = "ide", }, -#endif -#if defined(CONFIG_CMD_SATA) - {.name = "sata", }, -#endif -#if defined(CONFIG_SCSI) - { .name = "scsi", }, -#endif -#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) - { .name = "usb", }, -#endif -#if defined(CONFIG_MMC) - { - .name = "mmc", - .select_hwpart = mmc_select_hwpart, - }, -#endif -#if defined(CONFIG_SYSTEMACE) - { .name = "ace", }, -#endif -#if defined(CONFIG_SANDBOX) - { .name = "host", }, -#endif - { }, -}; - DECLARE_GLOBAL_DATA_PTR;
#ifdef HAVE_BLOCK_DEVICE @@ -70,34 +42,23 @@ static struct part_driver *part_driver_lookup_type(int part_type)
static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) { - const struct block_drvr *drvr = block_drvr; - char *name; + struct blk_desc *dev_desc; + int ret;
- if (!ifname) + dev_desc = blk_get_devnum_by_typename(ifname, dev); + if (!dev_desc) { + debug("%s: No device for iface '%s', dev %d\n", __func__, + ifname, dev); return NULL; - - name = drvr->name; -#ifdef CONFIG_NEEDS_MANUAL_RELOC - name += gd->reloc_off; -#endif - while (drvr->name) { - name = drvr->name; -#ifdef CONFIG_NEEDS_MANUAL_RELOC - name += gd->reloc_off; -#endif - if (strncmp(ifname, name, strlen(name)) == 0) { - struct blk_desc *dev_desc; - - dev_desc = blk_get_devnum_by_typename(name, dev); - if (!dev_desc) - return NULL; - if (blk_dselect_hwpart(dev_desc, hwpart)) - return NULL; - return dev_desc; - } - drvr++; } - return NULL; + ret = blk_dselect_hwpart(dev_desc, hwpart); + if (ret) { + debug("%s: Failed to select h/w partition: err-%d\n", __func__, + ret); + return NULL; + } + + return dev_desc; }
struct blk_desc *blk_get_dev(const char *ifname, int dev) diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index aaff947..8a8b685 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -7,6 +7,7 @@ */
#include <common.h> +#include <blk.h> #include <efi_loader.h> #include <inttypes.h> #include <part.h> @@ -147,13 +148,17 @@ static const struct efi_block_io block_io_disk_template = { */ int efi_disk_register(void) { - const struct block_drvr *cur_drvr; - int i; + const struct blk_driver *cur_drvr; + int i, if_type; int disks = 0;
/* Search for all available disk devices */ - for (cur_drvr = block_drvr; cur_drvr->name; cur_drvr++) { - printf("Scanning disks on %s...\n", cur_drvr->name); + for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) { + cur_drvr = blk_driver_lookup_type(if_type); + if (!cur_drvr) + continue; + + printf("Scanning disks on %s...\n", cur_drvr->if_typename); for (i = 0; i < 4; i++) { struct blk_desc *desc; struct efi_disk_obj *diskobj; @@ -161,7 +166,7 @@ int efi_disk_register(void) int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); char devname[16] = { 0 }; /* dp->str is u16[16] long */
- desc = blk_get_dev(cur_drvr->name, i); + desc = blk_get_devnum_by_type(if_type, i); if (!desc) continue; if (desc->type == DEV_TYPE_UNKNOWN) @@ -176,7 +181,7 @@ int efi_disk_register(void) diskobj->parent.protocols[1].open = efi_disk_open_dp; diskobj->parent.handle = diskobj; diskobj->ops = block_io_disk_template; - diskobj->ifname = cur_drvr->name; + diskobj->ifname = cur_drvr->if_typename; diskobj->dev_index = i;
/* Fill in EFI IO Media info (for read/write callbacks) */ @@ -194,7 +199,7 @@ int efi_disk_register(void) dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; dp[0].dp.length = sizeof(*dp); snprintf(devname, sizeof(devname), "%s%d", - cur_drvr->name, i); + cur_drvr->if_typename, i); ascii2unicode(dp[0].str, devname);
dp[1].dp.type = DEVICE_PATH_TYPE_END;

This member should be explained, since it is not obvious why it is needed. Add a comment.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/blk.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/blk.h b/include/blk.h index 415c3a8..1b8e72d 100644 --- a/include/blk.h +++ b/include/blk.h @@ -63,6 +63,11 @@ struct blk_desc { char product[20+1]; /* IDE Serial no, SCSI product */ char revision[8+1]; /* firmware revision */ #ifdef CONFIG_BLK + /* + * For now we have a few functions which take struct blk_desc as a + * parameter. This field allows them to look up the associated + * device. Once these functions are removed we can drop this field. + */ struct udevice *bdev; #else unsigned long (*block_read)(struct blk_desc *block_dev,

Update the existing drivers to set up this new pointer. This will be required by the MMC uclass.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/omap_hsmmc.c | 1 + drivers/mmc/pic32_sdhci.c | 7 ++++++- drivers/mmc/rockchip_dw_mmc.c | 1 + drivers/mmc/socfpga_dw_mmc.c | 1 + drivers/mmc/uniphier-sd.c | 1 + drivers/mmc/zynq_sdhci.c | 1 + include/mmc.h | 3 +++ 7 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index afe0b06..d6c2a82 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -819,6 +819,7 @@ static int omap_hsmmc_probe(struct udevice *dev) if (mmc == NULL) return -1;
+ mmc->dev = dev; upriv->mmc = mmc;
return 0; diff --git a/drivers/mmc/pic32_sdhci.c b/drivers/mmc/pic32_sdhci.c index 28da55d..21bd5d9 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 cb9e104..0a261c5 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/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 43a7e7e..06b8582 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -109,6 +109,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 81a80cd..4978cca 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 039ec16..b0f50dd 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/include/mmc.h b/include/mmc.h index f01674d..6d1f05c 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -381,6 +381,9 @@ struct mmc { char init_in_progress; /* 1 if we have done mmc_start_init() */ char preinit; /* start init as early as possible */ int ddr_mode; +#ifdef CONFIG_DM_MMC + struct udevice *dev; /* Device for this MMC controller */ +#endif };
struct mmc_hwpart_conf {

At present the MMC subsystem maintains its own list of MMC devices. This cannot work with driver model, which needs to maintain this itself. Move the list code into a separate 'legacy' file. The core MMC code remains, and will be shared with the driver-model implementation.
Signed-off-by: Simon Glass sjg@chromium.org ---
cmd/mmc.c | 8 +-- drivers/mmc/Makefile | 4 ++ drivers/mmc/mmc.c | 149 +++++++++++----------------------------------- drivers/mmc/mmc_legacy.c | 108 +++++++++++++++++++++++++++++++++ drivers/mmc/mmc_private.h | 24 ++++++++ drivers/mmc/mmc_write.c | 4 +- 6 files changed, 176 insertions(+), 121 deletions(-) create mode 100644 drivers/mmc/mmc_legacy.c
diff --git a/cmd/mmc.c b/cmd/mmc.c index 3d82ccd..ad68fd2 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -348,7 +348,7 @@ static int do_mmc_read(cmd_tbl_t *cmdtp, int flag, printf("\nMMC read: dev # %d, block # %d, count %d ... ", curr_device, blk, cnt);
- n = blk_dread(&mmc->block_dev, blk, cnt, addr); + n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr); /* flush cache after read */ flush_cache((ulong)addr, cnt * 512); /* FIXME */ printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR"); @@ -380,7 +380,7 @@ static int do_mmc_write(cmd_tbl_t *cmdtp, int flag, printf("Error: card is write protected!\n"); return CMD_RET_FAILURE; } - n = blk_dwrite(&mmc->block_dev, blk, cnt, addr); + n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr); printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; @@ -408,7 +408,7 @@ static int do_mmc_erase(cmd_tbl_t *cmdtp, int flag, printf("Error: card is write protected!\n"); return CMD_RET_FAILURE; } - n = blk_derase(&mmc->block_dev, blk, cnt); + n = blk_derase(mmc_get_blk_desc(mmc), blk, cnt); printf("%d blocks erased: %s\n", n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE; @@ -480,7 +480,7 @@ static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag, printf("mmc%d is current device\n", curr_device); else printf("mmc%d(part %d) is current device\n", - curr_device, mmc->block_dev.hwpart); + curr_device, mmc_get_blk_desc(mmc)->hwpart);
return CMD_RET_SUCCESS; } diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 585aaf3..6241649 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -7,6 +7,10 @@
obj-$(CONFIG_DM_MMC) += mmc-uclass.o
+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 obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 7322f334..48aedc2 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -21,14 +21,6 @@ #include <div64.h> #include "mmc_private.h"
-static struct list_head mmc_devices; -static int cur_dev_num = -1; - -struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) -{ - return &mmc->block_dev; -} - __weak int board_mmc_getwp(struct mmc *mmc) { return -1; @@ -183,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) { @@ -261,10 +234,10 @@ static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, 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; } @@ -582,7 +555,7 @@ 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; } @@ -1062,6 +1035,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 */ @@ -1358,7 +1332,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;
@@ -1498,31 +1472,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; @@ -1562,6 +1537,7 @@ int __deprecated mmc_register(struct mmc *mmc)
struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) { + struct blk_desc *bdesc; struct mmc *mmc;
/* quick validation */ @@ -1582,19 +1558,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; } @@ -1664,7 +1638,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); @@ -1744,66 +1718,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) { @@ -1856,9 +1775,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; @@ -1867,7 +1786,7 @@ int mmc_initialize(bd_t *bis) print_mmc_devices(','); #endif
- do_preinit(); + mmc_do_preinit(); return 0; }
diff --git a/drivers/mmc/mmc_legacy.c b/drivers/mmc/mmc_legacy.c new file mode 100644 index 0000000..3ec649f --- /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 d3f6bfe..6ec52fd 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -46,4 +46,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 f4d42aa..bd07b20 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -122,9 +122,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; }

Return -EINVAL instead of -1 in this function, to provide a more meaningful error.
Signed-off-by: Simon Glass sjg@chromium.org ---
disk/part.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/disk/part.c b/disk/part.c index 4b850fa..f5950d0 100644 --- a/disk/part.c +++ b/disk/part.c @@ -349,7 +349,7 @@ int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, if (*ep) { printf("** Bad device specification %s %s **\n", ifname, dev_str); - dev = -1; + dev = -EINVAL; goto cleanup; }
@@ -358,7 +358,7 @@ int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, if (*ep) { printf("** Bad HW partition specification %s %s **\n", ifname, hwpart_str); - dev = -1; + dev = -EINVAL; goto cleanup; } } @@ -366,7 +366,7 @@ int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, *dev_desc = get_dev_hwpart(ifname, dev, hwpart); if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); - dev = -1; + dev = -ENOENT; goto cleanup; }

Instead of looking up the MMC device by number, just pass it in. This makes it possible to use this function with driver model.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 48aedc2..4ba13a1 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -560,14 +560,10 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num) return 0; }
-int mmc_switch_part(int dev_num, unsigned int part_num) +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 -1; - ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, (mmc->part_config & ~PART_ACCESS_MASK) | (part_num & PART_ACCESS_MASK)); @@ -578,7 +574,7 @@ int mmc_switch_part(int dev_num, unsigned int part_num) */ if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { ret = mmc_set_capacity(mmc, part_num); - mmc->block_dev.hwpart = part_num; + mmc_get_blk_desc(mmc)->hwpart = part_num; }
return ret; @@ -598,7 +594,7 @@ static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart) if (mmc->part_config == MMCPART_NOAVAILABLE) return -EMEDIUMTYPE;
- ret = mmc_switch_part(desc->devnum, hwpart); + ret = mmc_switch_part(mmc, hwpart); if (ret) return ret;
@@ -619,7 +615,7 @@ int mmc_select_hwpart(int dev_num, int hwpart) 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;

This driver will require generic MMC and block-device support in a future commit. To avoid test errors, make this change now.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/Makefile | 4 ++++ test/dm/Makefile | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 6241649..38a172b 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -38,7 +38,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/test/dm/Makefile b/test/dm/Makefile index 9a11ae0..8ec391b 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -21,7 +21,9 @@ obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_LED) += led.o -obj-$(CONFIG_DM_MMC) += mmc.o + +# Disable temporarily +# obj-$(CONFIG_DM_MMC) += mmc.o obj-$(CONFIG_DM_PCI) += pci.o obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o

Implement the functions in mmc_legacy.c for driver-model block devices, so that MMC can use driver model for these. This allows CONFIG_BLK to be enabled with DM_MMC.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/Makefile | 4 +- drivers/mmc/mmc-uclass.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 38a172b..3da4817 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -5,7 +5,9 @@ # 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 diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 777489f..1b967d9 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,

Binding an MMC device when CONFIG_BLK is enabled requires that a block device be bound as a child of the MMC device. Add a function to do this. The mmc_create() method will be used only when DM_BLK is disabled.
Add an unbind method also.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 22 ++++++++++++++++++++++ 2 files changed, 70 insertions(+)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 4ba13a1..7183afc 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1531,6 +1531,53 @@ 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->if_type = IF_TYPE_MMC; + 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; @@ -1574,6 +1621,7 @@ void mmc_destroy(struct mmc *mmc) /* only freeing memory for now */ free(mmc); } +#endif
static int mmc_get_dev(int dev, struct blk_desc **descp) { diff --git a/include/mmc.h b/include/mmc.h index 6d1f05c..fb8d9b2 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -409,7 +409,29 @@ enum mmc_hwpart_conf_mode {
int mmc_register(struct mmc *mmc); struct mmc *mmc_create(const struct mmc_config *cfg, void *priv); + +/** + * mmc_bind() - Set up a new MMC device ready for probing + * + * A child block device is bound with the IF_TYPE_MMC interface type. This + * allows the device to be used with CONFIG_BLK + * + * @dev: MMC device to set up + * @mmc: MMC struct + * @cfg: MMC configuration + * @return 0 if OK, -ve on error + */ +int mmc_bind(struct udevice *dev, struct mmc *mmc, + const struct mmc_config *cfg); void mmc_destroy(struct mmc *mmc); + +/** + * mmc_unbind() - Unbind a MMC device's child block device + * + * @dev: MMC device + * @return 0 if OK, -ve on error + */ +int mmc_unbind(struct udevice *dev); int mmc_initialize(bd_t *bis); int mmc_init(struct mmc *mmc); int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size);

Add support for enabling CONFIG_BLK with MMC. This involves changing a few functions to use struct udevice and adding a MMC block device driver.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/mmc.c | 48 +++++++++++++++++++++++++++++++++++++---------- drivers/mmc/mmc_private.h | 9 +++++++-- drivers/mmc/mmc_write.c | 9 +++++++++ include/mmc.h | 4 ++++ include/part.h | 18 ------------------ 5 files changed, 58 insertions(+), 30 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 7183afc..74b3d68 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -216,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; @@ -580,15 +588,15 @@ static int mmc_switch_part(struct mmc *mmc, unsigned int part_num) return ret; }
-static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart) +#ifdef CONFIG_BLK +static int mmc_select_hwpart(struct udevice *bdev, int hwpart) { - struct mmc *mmc = find_mmc_device(desc->devnum); + 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 (!mmc) - return -ENODEV; - - if (mmc->block_dev.hwpart == hwpart) + if (desc->hwpart == hwpart) return 0;
if (mmc->part_config == MMCPART_NOAVAILABLE) @@ -600,10 +608,10 @@ static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
return 0; } - -int mmc_select_hwpart(int dev_num, int hwpart) +#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) @@ -621,6 +629,7 @@ int mmc_select_hwpart(int dev_num, int hwpart)
return 0; } +#endif
int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf, @@ -1554,7 +1563,6 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) mmc->dsr_imp = 0; mmc->dsr = 0xffffffff; /* Setup the universal parts of the block interface just once */ - bdesc->if_type = IF_TYPE_MMC; bdesc->removable = 1;
/* setup initial part type */ @@ -1623,6 +1631,7 @@ void mmc_destroy(struct mmc *mmc) } #endif
+#ifndef CONFIG_BLK static int mmc_get_dev(int dev, struct blk_desc **descp) { struct mmc *mmc = find_mmc_device(dev); @@ -1638,6 +1647,7 @@ static int mmc_get_dev(int dev, struct blk_desc **descp)
return 0; } +#endif
/* board-specific MMC power initializations. */ __weak void board_mmc_power_init(void) @@ -1729,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;
@@ -1957,6 +1971,19 @@ int mmc_set_rst_n_function(struct mmc *mmc, u8 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, @@ -1964,3 +1991,4 @@ U_BOOT_LEGACY_BLK(mmc) = { .get_dev = mmc_get_dev, .select_hwpart = mmc_select_hwpartp, }; +#endif diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index 6ec52fd..27b9e5f 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 */
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index bd07b20..0f8b5c7 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> @@ -172,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; diff --git a/include/mmc.h b/include/mmc.h index fb8d9b2..a5c6573 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -344,7 +344,9 @@ struct mmc_config {
/* TODO struct mmc should be in mmc_private but it's hard to fix right now */ struct mmc { +#ifndef CONFIG_BLK struct list_head link; +#endif const struct mmc_config *cfg; /* provided configuration */ uint version; void *priv; @@ -376,7 +378,9 @@ struct mmc { u64 capacity_gp[4]; u64 enh_user_start; u64 enh_user_size; +#ifndef CONFIG_BLK struct blk_desc block_dev; +#endif char op_cond_pending; /* 1 if we are waiting on an op_cond command */ char init_in_progress; /* 1 if we have done mmc_start_init() */ char preinit; /* start init as early as possible */ diff --git a/include/part.h b/include/part.h index afe5633..6416c63 100644 --- a/include/part.h +++ b/include/part.h @@ -73,23 +73,6 @@ typedef struct disk_partition { */ struct blk_desc *blk_get_dev(const char *ifname, int dev);
-/** - * mmc_select_hwpart() - Select the MMC hardware partiion on an MMC device - * - * MMC devices can support partitioning at the hardware level. This is quite - * separate from the normal idea of software-based partitions. MMC hardware - * partitions must be explicitly selected. Once selected only the region of - * the device covered by that partition is accessible. - * - * The MMC standard provides for two boot partitions (numbered 1 and 2), - * rpmb (3), and up to 4 addition general-purpose partitions (4-7). - * - * @dev_num: Block device number (struct blk_desc->dev value) - * @hwpart: Hardware partition number to select. 0 means the raw device, - * 1 is the first partition, 2 is the second, etc. - * @return 0 if OK, other value for an error - */ -int mmc_select_hwpart(int dev_num, int hwpart); struct blk_desc *mg_disk_get_dev(int dev); int host_get_dev_err(int dev, struct blk_desc **blk_devp);
@@ -167,7 +150,6 @@ extern const struct block_drvr block_drvr[]; #else static inline struct blk_desc *blk_get_dev(const char *ifname, int dev) { return NULL; } -static inline int mmc_select_hwpart(int dev_num, int hwpart) { return -1; } static inline struct blk_desc *mg_disk_get_dev(int dev) { return NULL; }
static inline int part_get_info(struct blk_desc *dev_desc, int part,

Add an emulation of an SD card to sandbox, allowing MMC to be used in tests. The emulation is very simple, supporting only card detection and reading test data.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/Kconfig | 11 +++- drivers/mmc/sandbox_mmc.c | 134 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 4d3df11..c80efc3 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/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c index f4646a8..7da059c 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), };

Enable building the MMC code for sandbox. This increases build coverage for sandbox.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/sandbox_defconfig | 10 ++++++---- include/configs/sandbox.h | 2 ++ test/dm/blk.c | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index bfc8b61..a760561 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -1,4 +1,5 @@ CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_MMC=y CONFIG_PCI=y CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_FIT=y @@ -30,8 +31,8 @@ CONFIG_ADC=y CONFIG_ADC_SANDBOX=y CONFIG_BLK=y CONFIG_CLK=y -CONFIG_SANDBOX_GPIO=y CONFIG_PM8916_GPIO=y +CONFIG_SANDBOX_GPIO=y CONFIG_SYS_I2C_SANDBOX=y CONFIG_CROS_EC_KEYB=y CONFIG_LED=y @@ -41,6 +42,7 @@ CONFIG_CROS_EC=y CONFIG_CROS_EC_SANDBOX=y CONFIG_RESET=y CONFIG_DM_MMC=y +CONFIG_SANDBOX_MMC=y CONFIG_SPI_FLASH_SANDBOX=y CONFIG_SPI_FLASH=y CONFIG_SPI_FLASH_ATMEL=y @@ -59,10 +61,8 @@ CONFIG_PINCTRL=y CONFIG_PINCONF=y CONFIG_PINCTRL_SANDBOX=y CONFIG_DM_PMIC=y -CONFIG_DM_PMIC_SANDBOX=y CONFIG_PMIC_PM8916=y -CONFIG_SPMI=y -CONFIG_SPMI_SANDBOX=y +CONFIG_DM_PMIC_SANDBOX=y CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_SANDBOX=y CONFIG_RAM=y @@ -72,6 +72,8 @@ CONFIG_SANDBOX_SERIAL=y CONFIG_SOUND=y CONFIG_SOUND_SANDBOX=y CONFIG_SANDBOX_SPI=y +CONFIG_SPMI=y +CONFIG_SPMI_SANDBOX=y CONFIG_TIMER=y CONFIG_TIMER_EARLY=y CONFIG_SANDBOX_TIMER=y diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index f0f7cd4..2d43102 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -233,4 +233,6 @@ #define CONFIG_SYS_SYSTEMACE_WIDTH 16 #define CONFIG_SYS_SYSTEMACE_BASE 0
+#define CONFIG_GENERIC_MMC + #endif diff --git a/test/dm/blk.c b/test/dm/blk.c index f4ea32e..012bf4c 100644 --- a/test/dm/blk.c +++ b/test/dm/blk.c @@ -83,12 +83,12 @@ static int dm_test_blk_usb(struct unit_test_state *uts) ut_asserteq_ptr(usb_dev, dev_get_parent(dev));
/* Check we have one block device for each mass storage device */ - ut_asserteq(3, count_blk_devices()); + ut_asserteq(4, count_blk_devices());
/* Now go around again, making sure the old devices were unbound */ ut_assertok(usb_stop()); ut_assertok(usb_init()); - ut_asserteq(3, count_blk_devices()); + ut_asserteq(4, count_blk_devices()); ut_assertok(usb_stop());
return 0;

Add a simple test which checks that a sandbox-emulated SD card can be used correctly. This tests plumbing through the MMC stack's block-device implementaion.
Signed-off-by: Simon Glass sjg@chromium.org ---
test/dm/Makefile | 4 +--- test/dm/mmc.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/test/dm/Makefile b/test/dm/Makefile index 8ec391b..9a11ae0 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -21,9 +21,7 @@ obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_LED) += led.o - -# Disable temporarily -# obj-$(CONFIG_DM_MMC) += mmc.o +obj-$(CONFIG_DM_MMC) += mmc.o obj-$(CONFIG_DM_PCI) += pci.o obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o diff --git a/test/dm/mmc.c b/test/dm/mmc.c index 0461423..5bca4b7 100644 --- a/test/dm/mmc.c +++ b/test/dm/mmc.c @@ -25,3 +25,22 @@ static int dm_test_mmc_base(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_mmc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_mmc_blk(struct unit_test_state *uts) +{ + struct udevice *dev; + struct blk_desc *dev_desc; + char cmp[1024]; + + ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev)); + ut_assertok(blk_get_device_by_str("mmc", "0", &dev_desc)); + + /* Read a few blocks and look for the string we expect */ + ut_asserteq(512, dev_desc->blksz); + memset(cmp, '\0', sizeof(cmp)); + ut_asserteq(2, blk_dread(dev_desc, 0, 2, cmp)); + ut_assertok(strcmp(cmp, "this is a test")); + + return 0; +} +DM_TEST(dm_test_mmc_blk, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
participants (1)
-
Simon Glass