Commit e6f99a5611e1ff59555f93de88e527070f8548af

Authored by Lei Wen
Committed by Andy Fleming
1 parent 6be95ccf9f

MMC: add erase function to both mmc and sd

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 <leiwen@marvell.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
Acked-by: Mike Frysinger <vapier@gentoo.org>

Showing 4 changed files with 131 additions and 4 deletions Side-by-side Diff

... ... @@ -91,6 +91,7 @@
91 91 MMC_INVALID,
92 92 MMC_READ,
93 93 MMC_WRITE,
  94 + MMC_ERASE,
94 95 };
95 96 static void print_mmcinfo(struct mmc *mmc)
96 97 {
97 98  
98 99  
... ... @@ -252,16 +253,25 @@
252 253 state = MMC_READ;
253 254 else if (strcmp(argv[1], "write") == 0)
254 255 state = MMC_WRITE;
  256 + else if (strcmp(argv[1], "erase") == 0)
  257 + state = MMC_ERASE;
255 258 else
256 259 state = MMC_INVALID;
257 260  
258 261 if (state != MMC_INVALID) {
259 262 struct mmc *mmc = find_mmc_device(curr_device);
260   - void *addr = (void *)simple_strtoul(argv[2], NULL, 16);
261   - u32 blk = simple_strtoul(argv[3], NULL, 16);
262   - u32 cnt = simple_strtoul(argv[4], NULL, 16);
263   - u32 n;
  263 + int idx = 2;
  264 + u32 blk, cnt, n;
  265 + void *addr;
264 266  
  267 + if (state != MMC_ERASE) {
  268 + addr = (void *)simple_strtoul(argv[idx], NULL, 16);
  269 + ++idx;
  270 + } else
  271 + addr = 0;
  272 + blk = simple_strtoul(argv[idx], NULL, 16);
  273 + cnt = simple_strtoul(argv[idx + 1], NULL, 16);
  274 +
265 275 if (!mmc) {
266 276 printf("no mmc device at slot %x\n", curr_device);
267 277 return 1;
... ... @@ -283,6 +293,9 @@
283 293 n = mmc->block_dev.block_write(curr_device, blk,
284 294 cnt, addr);
285 295 break;
  296 + case MMC_ERASE:
  297 + n = mmc->block_dev.block_erase(curr_device, blk, cnt);
  298 + break;
286 299 default:
287 300 BUG();
288 301 }
... ... @@ -300,6 +313,7 @@
300 313 "MMC sub system",
301 314 "read addr blk# cnt\n"
302 315 "mmc write addr blk# cnt\n"
  316 + "mmc erase blk# cnt\n"
303 317 "mmc rescan\n"
304 318 "mmc part - lists available partition on current mmc device\n"
305 319 "mmc dev [dev] [part] - show or set current mmc device [partition]\n"
... ... @@ -174,6 +174,88 @@
174 174 return NULL;
175 175 }
176 176  
  177 +static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
  178 +{
  179 + struct mmc_cmd cmd;
  180 + ulong end;
  181 + int err, start_cmd, end_cmd;
  182 +
  183 + if (mmc->high_capacity)
  184 + end = start + blkcnt - 1;
  185 + else {
  186 + end = (start + blkcnt - 1) * mmc->write_bl_len;
  187 + start *= mmc->write_bl_len;
  188 + }
  189 +
  190 + if (IS_SD(mmc)) {
  191 + start_cmd = SD_CMD_ERASE_WR_BLK_START;
  192 + end_cmd = SD_CMD_ERASE_WR_BLK_END;
  193 + } else {
  194 + start_cmd = MMC_CMD_ERASE_GROUP_START;
  195 + end_cmd = MMC_CMD_ERASE_GROUP_END;
  196 + }
  197 +
  198 + cmd.cmdidx = start_cmd;
  199 + cmd.cmdarg = start;
  200 + cmd.resp_type = MMC_RSP_R1;
  201 + cmd.flags = 0;
  202 +
  203 + err = mmc_send_cmd(mmc, &cmd, NULL);
  204 + if (err)
  205 + goto err_out;
  206 +
  207 + cmd.cmdidx = end_cmd;
  208 + cmd.cmdarg = end;
  209 +
  210 + err = mmc_send_cmd(mmc, &cmd, NULL);
  211 + if (err)
  212 + goto err_out;
  213 +
  214 + cmd.cmdidx = MMC_CMD_ERASE;
  215 + cmd.cmdarg = SECURE_ERASE;
  216 + cmd.resp_type = MMC_RSP_R1b;
  217 +
  218 + err = mmc_send_cmd(mmc, &cmd, NULL);
  219 + if (err)
  220 + goto err_out;
  221 +
  222 + return 0;
  223 +
  224 +err_out:
  225 + puts("mmc erase failed\n");
  226 + return err;
  227 +}
  228 +
  229 +static unsigned long
  230 +mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)
  231 +{
  232 + int err = 0;
  233 + struct mmc *mmc = find_mmc_device(dev_num);
  234 + lbaint_t blk = 0, blk_r = 0;
  235 +
  236 + if (!mmc)
  237 + return -1;
  238 +
  239 + if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
  240 + printf("\n\nCaution! Your devices Erase group is 0x%x\n"
  241 + "The erase range would be change to 0x%lx~0x%lx\n\n",
  242 + mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
  243 + ((start + blkcnt + mmc->erase_grp_size)
  244 + & ~(mmc->erase_grp_size - 1)) - 1);
  245 +
  246 + while (blk < blkcnt) {
  247 + blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
  248 + mmc->erase_grp_size : (blkcnt - blk);
  249 + err = mmc_erase_t(mmc, start + blk, blk_r);
  250 + if (err)
  251 + break;
  252 +
  253 + blk += blk_r;
  254 + }
  255 +
  256 + return blk;
  257 +}
  258 +
177 259 static ulong
178 260 mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
179 261 {
... ... @@ -911,6 +993,10 @@
911 993 return err;
912 994 }
913 995  
  996 + /*
  997 + * For SD, its erase group is always one sector
  998 + */
  999 + mmc->erase_grp_size = 1;
914 1000 mmc->part_config = MMCPART_NOAVAILABLE;
915 1001 if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
916 1002 /* check ext_csd version and capacity */
... ... @@ -921,6 +1007,21 @@
921 1007 mmc->capacity *= 512;
922 1008 }
923 1009  
  1010 + /*
  1011 + * Check whether GROUP_DEF is set, if yes, read out
  1012 + * group size from ext_csd directly, or calculate
  1013 + * the group size from the csd value.
  1014 + */
  1015 + if (ext_csd[175])
  1016 + mmc->erase_grp_size = ext_csd[224] * 512 * 1024;
  1017 + else {
  1018 + int erase_gsz, erase_gmul;
  1019 + erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
  1020 + erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
  1021 + mmc->erase_grp_size = (erase_gsz + 1)
  1022 + * (erase_gmul + 1);
  1023 + }
  1024 +
924 1025 /* store the partition info of emmc */
925 1026 if (ext_csd[160] & PART_SUPPORT)
926 1027 mmc->part_config = ext_csd[179];
... ... @@ -1044,6 +1145,7 @@
1044 1145 mmc->block_dev.removable = 1;
1045 1146 mmc->block_dev.block_read = mmc_bread;
1046 1147 mmc->block_dev.block_write = mmc_bwrite;
  1148 + mmc->block_dev.block_erase = mmc_berase;
1047 1149 if (!mmc->b_max)
1048 1150 mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1049 1151  
... ... @@ -75,6 +75,9 @@
75 75 #define MMC_CMD_READ_MULTIPLE_BLOCK 18
76 76 #define MMC_CMD_WRITE_SINGLE_BLOCK 24
77 77 #define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
  78 +#define MMC_CMD_ERASE_GROUP_START 35
  79 +#define MMC_CMD_ERASE_GROUP_END 36
  80 +#define MMC_CMD_ERASE 38
78 81 #define MMC_CMD_APP_CMD 55
79 82 #define MMC_CMD_SPI_READ_OCR 58
80 83 #define MMC_CMD_SPI_CRC_ON_OFF 59
... ... @@ -84,6 +87,8 @@
84 87 #define SD_CMD_SEND_IF_COND 8
85 88  
86 89 #define SD_CMD_APP_SET_BUS_WIDTH 6
  90 +#define SD_CMD_ERASE_WR_BLK_START 32
  91 +#define SD_CMD_ERASE_WR_BLK_END 33
87 92 #define SD_CMD_APP_SEND_OP_COND 41
88 93 #define SD_CMD_APP_SEND_SCR 51
89 94  
... ... @@ -99,6 +104,8 @@
99 104 #define OCR_VOLTAGE_MASK 0x007FFF80
100 105 #define OCR_ACCESS_MODE 0x60000000
101 106  
  107 +#define SECURE_ERASE 0x80000000
  108 +
102 109 #define MMC_STATUS_MASK (~0x0206BF7F)
103 110 #define MMC_STATUS_RDY_FOR_DATA (1 << 8)
104 111 #define MMC_STATUS_CURR_STATE (0xf << 9)
... ... @@ -285,6 +292,7 @@
285 292 uint tran_speed;
286 293 uint read_bl_len;
287 294 uint write_bl_len;
  295 + uint erase_grp_size;
288 296 u64 capacity;
289 297 block_dev_desc_t block_dev;
290 298 int (*send_cmd)(struct mmc *mmc,
... ... @@ -49,6 +49,9 @@
49 49 unsigned long start,
50 50 lbaint_t blkcnt,
51 51 const void *buffer);
  52 + unsigned long (*block_erase)(int dev,
  53 + unsigned long start,
  54 + lbaint_t blkcnt);
52 55 void *priv; /* driver private struct pointer */
53 56 }block_dev_desc_t;
54 57