Commit e6f99a5611e1ff59555f93de88e527070f8548af
Committed by
Andy Fleming
1 parent
6be95ccf9f
Exists in
master
and in
54 other branches
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
common/cmd_mmc.c
... | ... | @@ -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" |
drivers/mmc/mmc.c
... | ... | @@ -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 |
include/mmc.h
... | ... | @@ -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, |
include/part.h