From 663acabdc548216d61a9d2b1f789d4e6606f7a52 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 11:36:07 -0600 Subject: dm: mmc: Add a legacy block interface for MMC Add a legacy block interface for MMC. Signed-off-by: Simon Glass --- drivers/mmc/mmc.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d3c22abfd5..024368c727 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1582,14 +1582,31 @@ void mmc_destroy(struct mmc *mmc) free(mmc); } +static int mmc_get_devp(int dev, struct blk_desc **descp) +{ + struct mmc *mmc = find_mmc_device(dev); + int ret; + + if (!mmc) + return -ENODEV; + ret = mmc_init(mmc); + if (ret) + return ret; + + *descp = &mmc->block_dev; + + return 0; +} + #ifdef CONFIG_PARTITIONS struct blk_desc *mmc_get_dev(int dev) { - struct mmc *mmc = find_mmc_device(dev); - if (!mmc || mmc_init(mmc)) + struct blk_desc *desc; + + if (mmc_get_devp(dev, &desc)) return NULL; - return &mmc->block_dev; + return desc; } #endif @@ -1965,3 +1982,10 @@ int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) enable); } #endif + +U_BOOT_LEGACY_BLK(mmc) = { + .if_typename = "mmc", + .if_type = IF_TYPE_MMC, + .max_devs = -1, + .get_dev = mmc_get_devp, +}; -- cgit v1.2.1 From 3c457f4d2e47cc91385abe15d3c825d0ce1a2b6f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 11:36:15 -0600 Subject: dm: mmc: Drop the get_dev() function This function is implemented by the legacy block functions now. Drop it. Signed-off-by: Simon Glass --- drivers/mmc/mmc.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 024368c727..185d7b2a8e 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1582,7 +1582,7 @@ void mmc_destroy(struct mmc *mmc) free(mmc); } -static int mmc_get_devp(int dev, struct blk_desc **descp) +static int mmc_get_dev(int dev, struct blk_desc **descp) { struct mmc *mmc = find_mmc_device(dev); int ret; @@ -1598,18 +1598,6 @@ static int mmc_get_devp(int dev, struct blk_desc **descp) return 0; } -#ifdef CONFIG_PARTITIONS -struct blk_desc *mmc_get_dev(int dev) -{ - struct blk_desc *desc; - - if (mmc_get_devp(dev, &desc)) - return NULL; - - return desc; -} -#endif - /* board-specific MMC power initializations. */ __weak void board_mmc_power_init(void) { @@ -1987,5 +1975,5 @@ U_BOOT_LEGACY_BLK(mmc) = { .if_typename = "mmc", .if_type = IF_TYPE_MMC, .max_devs = -1, - .get_dev = mmc_get_devp, + .get_dev = mmc_get_dev, }; -- cgit v1.2.1 From ff3882ac23fcfda81284f372924063036bea507b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:25 -0600 Subject: dm: mmc: Move mmc_switch_part() above its callers 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 --- drivers/mmc/mmc.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 185d7b2a8e..2211ac6d99 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) -- cgit v1.2.1 From e17d1143c1a3f6f9bb1b21acb50e5e6a79855023 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:26 -0600 Subject: dm: mmc: Implement the select_hwpart() method Implement this method so that hardware partitions will work correctly with MMC. Signed-off-by: Simon Glass --- drivers/mmc/mmc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2211ac6d99..e270f5f644 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, }; -- cgit v1.2.1 From cb5ec33d9096f1f57c5ccc97d44ca0fb771729f5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:27 -0600 Subject: dm: mmc: Add a function to obtain the block device 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 --- drivers/mmc/mmc.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e270f5f644..49996a891c 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; -- cgit v1.2.1 From 69f45cd53b8ad8bc3afef2cf2410baf58fe75a6f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:29 -0600 Subject: dm: mmc: Use the new select_hwpart() API Avoid calling directly into the MMC code - use the new API call instead. Signed-off-by: Simon Glass --- drivers/mmc/mmc.c | 2 +- drivers/mmc/mmc_write.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 49996a891c..7322f33404 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 7b186f8500..f4d42aaa76 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; -- cgit v1.2.1 From cffe5d86cfe853ae9271d37522f8bc5795cc4c69 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:34 -0600 Subject: dm: mmc: Set up the device pointer when using the MMC uclass Update the existing drivers to set up this new pointer. This will be required by the MMC uclass. Signed-off-by: Simon Glass --- 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 + 6 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 85a832bd42..be34057ea2 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -825,6 +825,7 @@ static int omap_hsmmc_probe(struct udevice *dev) gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN); #endif + mmc->dev = dev; upriv->mmc = mmc; return 0; diff --git a/drivers/mmc/pic32_sdhci.c b/drivers/mmc/pic32_sdhci.c index e03d6dd517..abe74293ed 100644 --- a/drivers/mmc/pic32_sdhci.c +++ b/drivers/mmc/pic32_sdhci.c @@ -41,7 +41,12 @@ static int pic32_sdhci_probe(struct udevice *dev) return ret; } - return add_sdhci(host, f_min_max[1], f_min_max[0]); + ret = add_sdhci(host, f_min_max[1], f_min_max[0]); + if (ret) + return ret; + host->mmc->dev = dev; + + return 0; } static const struct udevice_id pic32_sdhci_ids[] = { diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index cb9e1048d0..0a261c51a8 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -104,6 +104,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev) if (ret) return ret; + host->mmc->dev = dev; upriv->mmc = host->mmc; return 0; diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 097db81b05..6a0e9719b8 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -108,6 +108,7 @@ static int socfpga_dwmmc_probe(struct udevice *dev) return ret; upriv->mmc = host->mmc; + host->mmc->dev = dev; return 0; } diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 81a80cdbc2..4978cca76d 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -725,6 +725,7 @@ int uniphier_sd_probe(struct udevice *dev) return -EIO; upriv->mmc = priv->mmc; + priv->mmc->dev = dev; return 0; } diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index b59feca80b..d405929b64 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -35,6 +35,7 @@ static int arasan_sdhci_probe(struct udevice *dev) CONFIG_ZYNQ_SDHCI_MIN_FREQ); upriv->mmc = host->mmc; + host->mmc->dev = dev; return 0; } -- cgit v1.2.1 From c40fdca6b7db469d3982cc44fd68a269adb41b25 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:35 -0600 Subject: dm: mmc: Move the device list into a separate file 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 --- 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 +- 5 files changed, 172 insertions(+), 117 deletions(-) create mode 100644 drivers/mmc/mmc_legacy.c (limited to 'drivers/mmc') diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 585aaf3115..624164902d 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 7322f33404..48aedc212c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -21,14 +21,6 @@ #include #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 0000000000..3ec649f2b8 --- /dev/null +++ b/drivers/mmc/mmc_legacy.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +static struct list_head mmc_devices; +static int cur_dev_num = -1; + +struct mmc *find_mmc_device(int dev_num) +{ + struct mmc *m; + struct list_head *entry; + + list_for_each(entry, &mmc_devices) { + m = list_entry(entry, struct mmc, link); + + if (m->block_dev.devnum == dev_num) + return m; + } + +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) + printf("MMC Device %d not found\n", dev_num); +#endif + + return NULL; +} + +int mmc_get_next_devnum(void) +{ + return cur_dev_num++; +} + +struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) +{ + return &mmc->block_dev; +} + +int get_mmc_num(void) +{ + return cur_dev_num; +} + +void mmc_do_preinit(void) +{ + struct mmc *m; + struct list_head *entry; + + list_for_each(entry, &mmc_devices) { + m = list_entry(entry, struct mmc, link); + +#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT + mmc_set_preinit(m, 1); +#endif + if (m->preinit) + mmc_start_init(m); + } +} + +void mmc_list_init(void) +{ + INIT_LIST_HEAD(&mmc_devices); + cur_dev_num = 0; +} + +void mmc_list_add(struct mmc *mmc) +{ + INIT_LIST_HEAD(&mmc->link); + + list_add_tail(&mmc->link, &mmc_devices); +} + +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +void print_mmc_devices(char separator) +{ + struct mmc *m; + struct list_head *entry; + char *mmc_type; + + list_for_each(entry, &mmc_devices) { + m = list_entry(entry, struct mmc, link); + + if (m->has_init) + mmc_type = IS_SD(m) ? "SD" : "eMMC"; + else + mmc_type = NULL; + + printf("%s: %d", m->cfg->name, m->block_dev.devnum); + if (mmc_type) + printf(" (%s)", mmc_type); + + if (entry->next != &mmc_devices) { + printf("%c", separator); + if (separator != '\n') + puts(" "); + } + } + + printf("\n"); +} + +#else +void print_mmc_devices(char separator) { } +#endif diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index d3f6bfe123..6ec52fda05 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 f4d42aaa76..bd07b20f5f 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; } -- cgit v1.2.1 From fdbb139f0ce10325b44dd3ec76993f8c8e798395 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:37 -0600 Subject: dm: mmc: Adjust mmc_switch_part() to use a struct mmc 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 --- drivers/mmc/mmc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 48aedc212c..4ba13a14e8 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; -- cgit v1.2.1 From f8b7752e8f42c6f0bb8725f2488e398c849a7bf4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:38 -0600 Subject: dm: sandbox: Only enable the sandbox MMC driver when valid 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 --- drivers/mmc/Makefile | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 624164902d..38a172be3a 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 -- cgit v1.2.1 From 8ef761ed4cda2d078b3d8b098d105472cbad8fb5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:39 -0600 Subject: dm: mmc: Implement the MMC functions for block devices 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 --- drivers/mmc/Makefile | 4 +- drivers/mmc/mmc-uclass.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 38a172be3a..3da4817a18 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 777489f5d8..1b967d982b 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -21,6 +21,112 @@ struct mmc *mmc_get_mmc_dev(struct udevice *dev) return upriv->mmc; } +#ifdef CONFIG_BLK +struct mmc *find_mmc_device(int dev_num) +{ + struct udevice *dev, *mmc_dev; + int ret; + + ret = blk_get_device(IF_TYPE_MMC, dev_num, &dev); + + if (ret) { +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) + printf("MMC Device %d not found\n", dev_num); +#endif + return NULL; + } + + mmc_dev = dev_get_parent(dev); + + return mmc_get_mmc_dev(mmc_dev); +} + +int get_mmc_num(void) +{ + return max(blk_find_max_devnum(IF_TYPE_MMC), 0); +} + +int mmc_get_next_devnum(void) +{ + int ret; + + ret = get_mmc_num(); + if (ret < 0) + return ret; + + return ret + 1; +} + +struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) +{ + struct blk_desc *desc; + struct udevice *dev; + + device_find_first_child(mmc->dev, &dev); + if (!dev) + return NULL; + desc = dev_get_uclass_platdata(dev); + + return desc; +} + +void mmc_do_preinit(void) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_MMC, &uc); + if (ret) + return; + uclass_foreach_dev(dev, uc) { + struct mmc *m = mmc_get_mmc_dev(dev); + + if (!m) + continue; +#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT + mmc_set_preinit(m, 1); +#endif + if (m->preinit) + mmc_start_init(m); + } +} + +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +void print_mmc_devices(char separator) +{ + struct udevice *dev; + char *mmc_type; + bool first = true; + + for (uclass_first_device(UCLASS_MMC, &dev); + dev; + uclass_next_device(&dev)) { + struct mmc *m = mmc_get_mmc_dev(dev); + + if (!first) { + printf("%c", separator); + if (separator != '\n') + puts(" "); + } + if (m->has_init) + mmc_type = IS_SD(m) ? "SD" : "eMMC"; + else + mmc_type = NULL; + + printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum); + if (mmc_type) + printf(" (%s)", mmc_type); + } + + printf("\n"); +} + +#else +void print_mmc_devices(char separator) { } +#endif +#endif /* CONFIG_BLK */ + U_BOOT_DRIVER(mmc) = { .name = "mmc", .id = UCLASS_MMC, -- cgit v1.2.1 From ad27dd5e13436b554f0f3cb9cd3e79634494072d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:40 -0600 Subject: dm: mmc: Add a way to bind MMC devices with driver model 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 --- drivers/mmc/mmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 4ba13a14e8..7183afcff2 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) { -- cgit v1.2.1 From 33fb211dd2706e666db4008801dc0d5903fd82f6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:41 -0600 Subject: dm: mmc: Add support for driver-model block devices 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 --- drivers/mmc/mmc.c | 48 +++++++++++++++++++++++++++++++++++++---------- drivers/mmc/mmc_private.h | 9 +++++++-- drivers/mmc/mmc_write.c | 9 +++++++++ 3 files changed, 54 insertions(+), 12 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 7183afcff2..74b3d68f87 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 6ec52fda05..27b9e5f56f 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -25,8 +25,13 @@ void mmc_adapter_card_type_ident(void); unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt); -unsigned long mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, - lbaint_t blkcnt, const void *src); +#ifdef CONFIG_BLK +ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, + const void *src); +#else +ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, + const void *src); +#endif #else /* CONFIG_SPL_BUILD */ diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index bd07b20f5f..0f8b5c79d7 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -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; -- cgit v1.2.1 From f376a3cbbf34d3114d92789540ba2d2e9e904758 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 1 May 2016 13:52:42 -0600 Subject: dm: mmc: sandbox: Add an SD-card emulation 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 --- drivers/mmc/Kconfig | 11 +++- drivers/mmc/sandbox_mmc.c | 134 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 4d3df11a1b..c80efc39a7 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -2,7 +2,7 @@ menu "MMC Host controller Support" config MMC bool "Enable MMC support" - depends on ARCH_SUNXI + depends on ARCH_SUNXI || SANDBOX help TODO: Move all architectures to use this option @@ -58,4 +58,13 @@ config MMC_UNIPHIER help This selects support for the SD/MMC Host Controller on UniPhier SoCs. +config SANDBOX_MMC + bool "Sandbox MMC support" + depends on MMC && SANDBOX + help + This select a dummy sandbox MMC driver. At present this does nothing + other than allow sandbox to be build with MMC support. This + improves build coverage for sandbox and makes it easier to detect + MMC build errors with sandbox. + endmenu diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c index f4646a824f..7da059c43c 100644 --- a/drivers/mmc/sandbox_mmc.c +++ b/drivers/mmc/sandbox_mmc.c @@ -8,18 +8,150 @@ #include #include #include +#include #include #include 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), }; -- cgit v1.2.1