diff options
| -rw-r--r-- | common/cmd_mmc.c | 22 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 102 | ||||
| -rw-r--r-- | include/mmc.h | 8 | ||||
| -rw-r--r-- | include/part.h | 3 | 
4 files changed, 131 insertions, 4 deletions
| diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index a6458037e..7335cdc75 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -91,6 +91,7 @@ enum mmc_state {  	MMC_INVALID,  	MMC_READ,  	MMC_WRITE, +	MMC_ERASE,  };  static void print_mmcinfo(struct mmc *mmc)  { @@ -252,15 +253,24 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		state = MMC_READ;  	else if (strcmp(argv[1], "write") == 0)  		state = MMC_WRITE; +	else if (strcmp(argv[1], "erase") == 0) +		state = MMC_ERASE;  	else  		state = MMC_INVALID;  	if (state != MMC_INVALID) {  		struct mmc *mmc = find_mmc_device(curr_device); -		void *addr = (void *)simple_strtoul(argv[2], NULL, 16); -		u32 blk = simple_strtoul(argv[3], NULL, 16); -		u32 cnt = simple_strtoul(argv[4], NULL, 16); -		u32 n; +		int idx = 2; +		u32 blk, cnt, n; +		void *addr; + +		if (state != MMC_ERASE) { +			addr = (void *)simple_strtoul(argv[idx], NULL, 16); +			++idx; +		} else +			addr = 0; +		blk = simple_strtoul(argv[idx], NULL, 16); +		cnt = simple_strtoul(argv[idx + 1], NULL, 16);  		if (!mmc) {  			printf("no mmc device at slot %x\n", curr_device); @@ -283,6 +293,9 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  			n = mmc->block_dev.block_write(curr_device, blk,  						      cnt, addr);  			break; +		case MMC_ERASE: +			n = mmc->block_dev.block_erase(curr_device, blk, cnt); +			break;  		default:  			BUG();  		} @@ -300,6 +313,7 @@ U_BOOT_CMD(  	"MMC sub system",  	"read addr blk# cnt\n"  	"mmc write addr blk# cnt\n" +	"mmc erase 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 21aedbaa3..9a1ee3d39 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: +	puts("mmc erase failed\n"); +	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%lx~0x%lx\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 aeacdee30..1c8a36071 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 3cdae0214..524351182 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; |