Erase is a very basic function since the begin of sd specification is announced. Although we could write a bulk of full 0xff memory to the range to take place of erase, it is more convenient and safe to implement the erase function itself.
Signed-off-by: Lei Wen <lei...@marvell.com> --- common/cmd_mmc.c | 23 ++++++++++++ drivers/mmc/mmc.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 8 ++++ include/part.h | 3 ++ 4 files changed, 136 insertions(+), 0 deletions(-) diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 176646d..a6483ba 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -287,6 +287,28 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR"); return (n == cnt) ? 0 : 1; + } else if (strcmp(argv[1], "erase") == 0) { + u32 cnt = simple_strtoul(argv[3], NULL, 16); + u32 n; + struct mmc *mmc = find_mmc_device(dev); + + int blk = simple_strtoul(argv[2], NULL, 16); + + if (!mmc) { + printf("no mmc device at slot %x\n", curr_device); + return 1; + } + + printf("\nMMC erase: dev # %d, block # %d, count %d ... ", + curr_device, blk, cnt); + + mmc_init(mmc); + + n = mmc->block_dev.block_erase(curr_device, blk, cnt); + + printf("%d blocks erased: %s\n", + n, (n == cnt) ? "OK" : "ERROR"); + return (n == cnt) ? 0 : 1; } return cmd_usage(cmdtp); @@ -297,6 +319,7 @@ U_BOOT_CMD( "MMC sub system", "read addr blk# cnt\n" "mmc write addr blk# cnt\n" + "mmc erase addr blk# cnt\n" "mmc rescan\n" "mmc part - lists available partition on current mmc device\n" "mmc dev [dev] [part] - show or set current mmc device [partition]\n" diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 21aedba..64bb2a8 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -174,6 +174,88 @@ struct mmc *find_mmc_device(int dev_num) return NULL; } +static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) +{ + struct mmc_cmd cmd; + ulong end; + int err, start_cmd, end_cmd; + + if (mmc->high_capacity) + end = start + blkcnt - 1; + else { + end = (start + blkcnt - 1) * mmc->write_bl_len; + start *= mmc->write_bl_len; + } + + if (IS_SD(mmc)) { + start_cmd = SD_CMD_ERASE_WR_BLK_START; + end_cmd = SD_CMD_ERASE_WR_BLK_END; + } else { + start_cmd = MMC_CMD_ERASE_GROUP_START; + end_cmd = MMC_CMD_ERASE_GROUP_END; + } + + cmd.cmdidx = start_cmd; + cmd.cmdarg = start; + cmd.resp_type = MMC_RSP_R1; + cmd.flags = 0; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + goto err_out; + + cmd.cmdidx = end_cmd; + cmd.cmdarg = end; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + goto err_out; + + cmd.cmdidx = MMC_CMD_ERASE; + cmd.cmdarg = SECURE_ERASE; + cmd.resp_type = MMC_RSP_R1b; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) + goto err_out; + + return 0; + +err_out: + printf("mmc erase failed\n\r"); + return err; +} + +static unsigned long +mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt) +{ + int err = 0; + struct mmc *mmc = find_mmc_device(dev_num); + lbaint_t blk = 0, blk_r = 0; + + if (!mmc) + return -1; + + if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) + printf("\n\nCaution! Your devices Erase group is 0x%x\n" + "The erase range would be change to 0x%x~0x%x\n\n", + mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), + ((start + blkcnt + mmc->erase_grp_size) + & ~(mmc->erase_grp_size - 1)) - 1); + + while (blk < blkcnt) { + blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? + mmc->erase_grp_size : (blkcnt - blk); + err = mmc_erase_t(mmc, start + blk, blk_r); + if (err) + break; + + blk += blk_r; + } + + return blk; +} + static ulong mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) { @@ -911,6 +993,10 @@ int mmc_startup(struct mmc *mmc) return err; } + /* + * For SD, its erase group is always one sector + */ + mmc->erase_grp_size = 1; mmc->part_config = MMCPART_NOAVAILABLE; if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { /* check ext_csd version and capacity */ @@ -921,6 +1007,21 @@ int mmc_startup(struct mmc *mmc) mmc->capacity *= 512; } + /* + * Check whether GROUP_DEF is set, if yes, read out + * group size from ext_csd directly, or calculate + * the group size from the csd value. + */ + if (ext_csd[175]) + mmc->erase_grp_size = ext_csd[224] * 512 * 1024; + else { + int erase_gsz, erase_gmul; + erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; + erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; + mmc->erase_grp_size = (erase_gsz + 1) + * (erase_gmul + 1); + } + /* store the partition info of emmc */ if (ext_csd[160] & PART_SUPPORT) mmc->part_config = ext_csd[179]; @@ -1044,6 +1145,7 @@ int mmc_register(struct mmc *mmc) 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; if (!mmc->b_max) mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; diff --git a/include/mmc.h b/include/mmc.h index aeacdee..1c8a360 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -75,6 +75,9 @@ #define MMC_CMD_READ_MULTIPLE_BLOCK 18 #define MMC_CMD_WRITE_SINGLE_BLOCK 24 #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25 +#define MMC_CMD_ERASE_GROUP_START 35 +#define MMC_CMD_ERASE_GROUP_END 36 +#define MMC_CMD_ERASE 38 #define MMC_CMD_APP_CMD 55 #define MMC_CMD_SPI_READ_OCR 58 #define MMC_CMD_SPI_CRC_ON_OFF 59 @@ -84,6 +87,8 @@ #define SD_CMD_SEND_IF_COND 8 #define SD_CMD_APP_SET_BUS_WIDTH 6 +#define SD_CMD_ERASE_WR_BLK_START 32 +#define SD_CMD_ERASE_WR_BLK_END 33 #define SD_CMD_APP_SEND_OP_COND 41 #define SD_CMD_APP_SEND_SCR 51 @@ -99,6 +104,8 @@ #define OCR_VOLTAGE_MASK 0x007FFF80 #define OCR_ACCESS_MODE 0x60000000 +#define SECURE_ERASE 0x80000000 + #define MMC_STATUS_MASK (~0x0206BF7F) #define MMC_STATUS_RDY_FOR_DATA (1 << 8) #define MMC_STATUS_CURR_STATE (0xf << 9) @@ -285,6 +292,7 @@ struct mmc { uint tran_speed; uint read_bl_len; uint write_bl_len; + uint erase_grp_size; u64 capacity; block_dev_desc_t block_dev; int (*send_cmd)(struct mmc *mmc, diff --git a/include/part.h b/include/part.h index 3cdae02..5243511 100644 --- a/include/part.h +++ b/include/part.h @@ -49,6 +49,9 @@ typedef struct block_dev_desc { unsigned long start, lbaint_t blkcnt, const void *buffer); + unsigned long (*block_erase)(int dev, + unsigned long start, + lbaint_t blkcnt); void *priv; /* driver private struct pointer */ }block_dev_desc_t; -- 1.7.0.4 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot