blob: c856eb85a5651214e6949b75085dbb074f3024b4 [file] [log] [blame]
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -05001/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/ioctl.h>
21#include <sys/types.h>
22#include <dirent.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <libgen.h>
27#include <limits.h>
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050028#include <ctype.h>
29
30#include "mmc.h"
31#include "mmc_cmds.h"
32
33int read_extcsd(int fd, __u8 *ext_csd)
34{
35 int ret = 0;
36 struct mmc_ioc_cmd idata;
37 memset(&idata, 0, sizeof(idata));
38 memset(ext_csd, 0, sizeof(__u8) * 512);
39 idata.write_flag = 0;
40 idata.opcode = MMC_SEND_EXT_CSD;
41 idata.arg = 0;
42 idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
43 idata.blksz = 512;
44 idata.blocks = 1;
45 mmc_ioc_cmd_set_data(idata, ext_csd);
46
47 ret = ioctl(fd, MMC_IOC_CMD, &idata);
48 if (ret)
49 perror("ioctl");
50
51 return ret;
52}
53
54int write_extcsd_value(int fd, __u8 index, __u8 value)
55{
56 int ret = 0;
57 struct mmc_ioc_cmd idata;
58
59 memset(&idata, 0, sizeof(idata));
60 idata.write_flag = 1;
61 idata.opcode = MMC_SWITCH;
62 idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
63 (index << 16) |
64 (value << 8) |
65 EXT_CSD_CMD_SET_NORMAL;
66 idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
67
68 ret = ioctl(fd, MMC_IOC_CMD, &idata);
69 if (ret)
70 perror("ioctl");
71
72 return ret;
73}
74
Ben Gardiner27c357d2013-05-30 17:12:47 -040075int send_status(int fd, __u32 *response)
76{
77 int ret = 0;
78 struct mmc_ioc_cmd idata;
79
80 memset(&idata, 0, sizeof(idata));
81 idata.opcode = MMC_SEND_STATUS;
82 idata.arg = (1 << 16);
83 idata.flags = MMC_RSP_R1 | MMC_CMD_AC;
84
85 ret = ioctl(fd, MMC_IOC_CMD, &idata);
86 if (ret)
87 perror("ioctl");
88
89 *response = idata.response[0];
90
91 return ret;
92}
93
Chris Ballb9c7a172012-02-20 12:34:25 -050094void print_writeprotect_status(__u8 *ext_csd)
95{
96 __u8 reg;
97 __u8 ext_csd_rev = ext_csd[192];
98
99 /* A43: reserved [174:0] */
100 if (ext_csd_rev >= 5) {
101 printf("Boot write protection status registers"
102 " [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]);
103
104 reg = ext_csd[EXT_CSD_BOOT_WP];
105 printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg);
106 printf(" Power ro locking: ");
107 if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
108 printf("not possible\n");
109 else
110 printf("possible\n");
111
112 printf(" Permanent ro locking: ");
113 if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
114 printf("not possible\n");
115 else
116 printf("possible\n");
117
118 printf(" ro lock status: ");
119 if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
120 printf("locked until next power on\n");
121 else if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
122 printf("locked permanently\n");
123 else
124 printf("not locked\n");
125 }
126}
127
128int do_writeprotect_get(int nargs, char **argv)
129{
130 __u8 ext_csd[512];
131 int fd, ret;
132 char *device;
133
Chris Ball8ba44662012-04-19 13:22:54 -0400134 CHECK(nargs != 2, "Usage: mmc writeprotect get </path/to/mmcblkX>\n",
135 exit(1));
Chris Ballb9c7a172012-02-20 12:34:25 -0500136
137 device = argv[1];
138
139 fd = open(device, O_RDWR);
140 if (fd < 0) {
141 perror("open");
142 exit(1);
143 }
144
145 ret = read_extcsd(fd, ext_csd);
146 if (ret) {
147 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
148 exit(1);
149 }
150
151 print_writeprotect_status(ext_csd);
152
153 return ret;
154}
155
156int do_writeprotect_set(int nargs, char **argv)
157{
158 __u8 ext_csd[512], value;
159 int fd, ret;
160 char *device;
161
Chris Ball8ba44662012-04-19 13:22:54 -0400162 CHECK(nargs != 2, "Usage: mmc writeprotect set </path/to/mmcblkX>\n",
163 exit(1));
Chris Ballb9c7a172012-02-20 12:34:25 -0500164
165 device = argv[1];
166
167 fd = open(device, O_RDWR);
168 if (fd < 0) {
169 perror("open");
170 exit(1);
171 }
172
173 ret = read_extcsd(fd, ext_csd);
174 if (ret) {
175 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
176 exit(1);
177 }
178
179 value = ext_csd[EXT_CSD_BOOT_WP] |
180 EXT_CSD_BOOT_WP_B_PWR_WP_EN;
181 ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value);
182 if (ret) {
183 fprintf(stderr, "Could not write 0x%02x to "
184 "EXT_CSD[%d] in %s\n",
185 value, EXT_CSD_BOOT_WP, device);
186 exit(1);
187 }
188
189 return ret;
190}
191
Saugata Dasb7e25992012-05-17 09:26:34 -0400192int do_disable_512B_emulation(int nargs, char **argv)
193{
194 __u8 ext_csd[512], native_sector_size, data_sector_size, wr_rel_param;
195 int fd, ret;
196 char *device;
197
198 CHECK(nargs != 2, "Usage: mmc disable 512B emulation </path/to/mmcblkX>\n", exit(1));
199 device = argv[1];
200
201 fd = open(device, O_RDWR);
202 if (fd < 0) {
203 perror("open");
204 exit(1);
205 }
206
207 ret = read_extcsd(fd, ext_csd);
208 if (ret) {
209 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
210 exit(1);
211 }
212
213 wr_rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
214 native_sector_size = ext_csd[EXT_CSD_NATIVE_SECTOR_SIZE];
215 data_sector_size = ext_csd[EXT_CSD_DATA_SECTOR_SIZE];
216
217 if (native_sector_size && !data_sector_size &&
218 (wr_rel_param & EN_REL_WR)) {
219 ret = write_extcsd_value(fd, EXT_CSD_USE_NATIVE_SECTOR, 1);
220
221 if (ret) {
222 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
223 1, EXT_CSD_BOOT_WP, device);
224 exit(1);
225 }
226 printf("MMC disable 512B emulation successful. Now reset the device to switch to 4KB native sector mode.\n");
227 } else if (native_sector_size && data_sector_size) {
228 printf("MMC 512B emulation mode is already disabled; doing nothing.\n");
229 } else {
230 printf("MMC does not support disabling 512B emulation mode.\n");
231 }
232
233 return ret;
234}
235
Giuseppe CAVALLARO7bd13202012-04-19 10:58:37 +0200236int do_write_boot_en(int nargs, char **argv)
237{
238 __u8 ext_csd[512];
239 __u8 value = 0;
240 int fd, ret;
241 char *device;
242 int boot_area, send_ack;
243
244 CHECK(nargs != 4, "Usage: mmc bootpart enable <partition_number> "
245 "<send_ack> </path/to/mmcblkX>\n", exit(1));
246
247 /*
248 * If <send_ack> is 1, the device will send acknowledgment
249 * pattern "010" to the host when boot operation begins.
250 * If <send_ack> is 0, it won't.
251 */
252 boot_area = strtol(argv[1], NULL, 10);
253 send_ack = strtol(argv[2], NULL, 10);
254 device = argv[3];
255
256 fd = open(device, O_RDWR);
257 if (fd < 0) {
258 perror("open");
259 exit(1);
260 }
261
262 ret = read_extcsd(fd, ext_csd);
263 if (ret) {
264 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
265 exit(1);
266 }
267
268 value = ext_csd[EXT_CSD_PART_CONFIG];
269
270 switch (boot_area) {
271 case EXT_CSD_PART_CONFIG_ACC_BOOT0:
272 value |= (1 << 3);
273 value &= ~(3 << 4);
274 break;
275 case EXT_CSD_PART_CONFIG_ACC_BOOT1:
276 value |= (1 << 4);
277 value &= ~(1 << 3);
278 value &= ~(1 << 5);
279 break;
280 case EXT_CSD_PART_CONFIG_ACC_USER_AREA:
281 value |= (boot_area << 3);
282 break;
283 default:
284 fprintf(stderr, "Cannot enable the boot area\n");
285 exit(1);
286 }
287 if (send_ack)
288 value |= EXT_CSD_PART_CONFIG_ACC_ACK;
289 else
290 value &= ~EXT_CSD_PART_CONFIG_ACC_ACK;
291
292 ret = write_extcsd_value(fd, EXT_CSD_PART_CONFIG, value);
293 if (ret) {
294 fprintf(stderr, "Could not write 0x%02x to "
295 "EXT_CSD[%d] in %s\n",
296 value, EXT_CSD_PART_CONFIG, device);
297 exit(1);
298 }
299 return ret;
300}
301
Chris Ballf74dfe22012-10-19 16:49:55 -0400302int do_hwreset(int value, int nargs, char **argv)
303{
304 __u8 ext_csd[512];
305 int fd, ret;
306 char *device;
307
308 CHECK(nargs != 2, "Usage: mmc hwreset enable </path/to/mmcblkX>\n",
309 exit(1));
310
311 device = argv[1];
312
313 fd = open(device, O_RDWR);
314 if (fd < 0) {
315 perror("open");
316 exit(1);
317 }
318
319 ret = read_extcsd(fd, ext_csd);
320 if (ret) {
321 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
322 exit(1);
323 }
324
325 if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
326 EXT_CSD_HW_RESET_EN) {
327 fprintf(stderr,
328 "H/W Reset is already permanently enabled on %s\n",
329 device);
330 exit(1);
331 }
332 if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
333 EXT_CSD_HW_RESET_DIS) {
334 fprintf(stderr,
335 "H/W Reset is already permanently disabled on %s\n",
336 device);
337 exit(1);
338 }
339
340 ret = write_extcsd_value(fd, EXT_CSD_RST_N_FUNCTION, value);
341 if (ret) {
342 fprintf(stderr,
343 "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
344 value, EXT_CSD_RST_N_FUNCTION, device);
345 exit(1);
346 }
347
348 return ret;
349}
350
351int do_hwreset_en(int nargs, char **argv)
352{
353 return do_hwreset(EXT_CSD_HW_RESET_EN, nargs, argv);
354}
355
356int do_hwreset_dis(int nargs, char **argv)
357{
358 return do_hwreset(EXT_CSD_HW_RESET_DIS, nargs, argv);
359}
360
Jaehoon Chung86496512012-09-21 10:08:05 +0000361int do_write_bkops_en(int nargs, char **argv)
362{
363 __u8 ext_csd[512], value = 0;
364 int fd, ret;
365 char *device;
366
367 CHECK(nargs != 2, "Usage: mmc bkops enable </path/to/mmcblkX>\n",
368 exit(1));
369
370 device = argv[1];
371
372 fd = open(device, O_RDWR);
373 if (fd < 0) {
374 perror("open");
375 exit(1);
376 }
377
378 ret = read_extcsd(fd, ext_csd);
379 if (ret) {
380 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
381 exit(1);
382 }
383
384 if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
385 fprintf(stderr, "%s doesn't support BKOPS\n", device);
386 exit(1);
387 }
388
389 ret = write_extcsd_value(fd, EXT_CSD_BKOPS_EN, BKOPS_ENABLE);
390 if (ret) {
391 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
392 value, EXT_CSD_BKOPS_EN, device);
393 exit(1);
394 }
395
396 return ret;
397}
398
Ben Gardiner27c357d2013-05-30 17:12:47 -0400399int do_status_get(int nargs, char **argv)
400{
401 __u32 response;
402 int fd, ret;
403 char *device;
404
405 CHECK(nargs != 2, "Usage: mmc status get </path/to/mmcblkX>\n",
406 exit(1));
407
408 device = argv[1];
409
410 fd = open(device, O_RDWR);
411 if (fd < 0) {
412 perror("open");
413 exit(1);
414 }
415
416 ret = send_status(fd, &response);
417 if (ret) {
418 fprintf(stderr, "Could not read response to SEND_STATUS from %s\n", device);
419 exit(1);
420 }
421
422 printf("SEND_STATUS response: 0x%08x\n", response);
423
424 return ret;
425}
426
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800427__u32 get_word_from_ext_csd(__u8 *ext_csd_loc)
428{
429 return (ext_csd_loc[3] << 24) |
430 (ext_csd_loc[2] << 16) |
431 (ext_csd_loc[1] << 8) |
432 ext_csd_loc[0];
433}
434
Ben Gardiner4e850232013-05-30 17:12:49 -0400435unsigned int get_sector_count(__u8 *ext_csd)
436{
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800437 return get_word_from_ext_csd(&ext_csd[EXT_CSD_SEC_COUNT_0]);
Ben Gardiner4e850232013-05-30 17:12:49 -0400438}
439
440int is_blockaddresed(__u8 *ext_csd)
441{
442 unsigned int sectors = get_sector_count(ext_csd);
443
444 return (sectors > (2u * 1024 * 1024 * 1024) / 512);
445}
446
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400447unsigned int get_hc_wp_grp_size(__u8 *ext_csd)
448{
449 return ext_csd[221];
450}
451
452unsigned int get_hc_erase_grp_size(__u8 *ext_csd)
453{
454 return ext_csd[224];
455}
456
Ben Gardinere6e84e92013-09-19 11:14:27 -0400457int set_partitioning_setting_completed(int dry_run, const char * const device,
458 int fd)
459{
460 int ret;
461
462 if (dry_run) {
463 fprintf(stderr, "NOT setting PARTITION_SETTING_COMPLETED\n");
464 fprintf(stderr, "These changes will not take effect neither "
465 "now nor after a power cycle\n");
466 return 1;
467 }
468
469 fprintf(stderr, "setting OTP PARTITION_SETTING_COMPLETED!\n");
470 ret = write_extcsd_value(fd, EXT_CSD_PARTITION_SETTING_COMPLETED, 0x1);
471 if (ret) {
472 fprintf(stderr, "Could not write 0x1 to "
473 "EXT_CSD[%d] in %s\n",
474 EXT_CSD_PARTITION_SETTING_COMPLETED, device);
475 return 1;
476 }
477
478 __u32 response;
479 ret = send_status(fd, &response);
480 if (ret) {
481 fprintf(stderr, "Could not get response to SEND_STATUS "
482 "from %s\n", device);
483 return 1;
484 }
485
486 if (response & R1_SWITCH_ERROR) {
487 fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED "
488 "failed on %s\n", device);
489 return 1;
490 }
491
492 fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED on "
493 "%s SUCCESS\n", device);
494 fprintf(stderr, "Device power cycle needed for settings to "
495 "take effect.\n"
496 "Confirm that PARTITION_SETTING_COMPLETED bit is set "
497 "using 'extcsd read' after power cycle\n");
498
499 return 0;
500}
501
Ben Gardinerd91d3692013-05-30 17:12:51 -0400502int do_enh_area_set(int nargs, char **argv)
503{
504 __u8 value;
505 __u8 ext_csd[512];
506 int fd, ret;
507 char *device;
508 int dry_run = 1;
509 unsigned int start_kib, length_kib, enh_start_addr, enh_size_mult;
510 unsigned long align;
511
512 CHECK(nargs != 5, "Usage: mmc enh_area set <-y|-n> <start KiB> <length KiB> "
513 "</path/to/mmcblkX>\n", exit(1));
514
515 if (!strcmp("-y", argv[1]))
516 dry_run = 0;
517
518 start_kib = strtol(argv[2], NULL, 10);
519 length_kib = strtol(argv[3], NULL, 10);
520 device = argv[4];
521
522 fd = open(device, O_RDWR);
523 if (fd < 0) {
524 perror("open");
525 exit(1);
526 }
527
528 ret = read_extcsd(fd, ext_csd);
529 if (ret) {
530 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
531 exit(1);
532 }
533
534 /* assert ENH_ATTRIBUTE_EN */
535 if (!(ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & EXT_CSD_ENH_ATTRIBUTE_EN))
536 {
537 printf(" Device cannot have enhanced tech.\n");
538 exit(1);
539 }
540
541 /* assert not PARTITION_SETTING_COMPLETED */
542 if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
543 {
544 printf(" Device is already partitioned\n");
545 exit(1);
546 }
547
548 align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
549
550 enh_size_mult = (length_kib + align/2l) / align;
551
552 enh_start_addr = start_kib * 1024 / (is_blockaddresed(ext_csd) ? 512 : 1);
553 enh_start_addr /= align;
554 enh_start_addr *= align;
555
556 /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
557 ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
558 if (ret) {
559 fprintf(stderr, "Could not write 0x1 to "
560 "EXT_CSD[%d] in %s\n",
561 EXT_CSD_ERASE_GROUP_DEF, device);
562 exit(1);
563 }
564
565 /* write to ENH_START_ADDR and ENH_SIZE_MULT and PARTITIONS_ATTRIBUTE's ENH_USR bit */
566 value = (enh_start_addr >> 24) & 0xff;
567 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_3, value);
568 if (ret) {
569 fprintf(stderr, "Could not write 0x%02x to "
570 "EXT_CSD[%d] in %s\n", value,
571 EXT_CSD_ENH_START_ADDR_3, device);
572 exit(1);
573 }
574 value = (enh_start_addr >> 16) & 0xff;
575 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_2, value);
576 if (ret) {
577 fprintf(stderr, "Could not write 0x%02x to "
578 "EXT_CSD[%d] in %s\n", value,
579 EXT_CSD_ENH_START_ADDR_2, device);
580 exit(1);
581 }
582 value = (enh_start_addr >> 8) & 0xff;
583 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_1, value);
584 if (ret) {
585 fprintf(stderr, "Could not write 0x%02x to "
586 "EXT_CSD[%d] in %s\n", value,
587 EXT_CSD_ENH_START_ADDR_1, device);
588 exit(1);
589 }
590 value = enh_start_addr & 0xff;
591 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_0, value);
592 if (ret) {
593 fprintf(stderr, "Could not write 0x%02x to "
594 "EXT_CSD[%d] in %s\n", value,
595 EXT_CSD_ENH_START_ADDR_0, device);
596 exit(1);
597 }
598
599 value = (enh_size_mult >> 16) & 0xff;
600 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_2, value);
601 if (ret) {
602 fprintf(stderr, "Could not write 0x%02x to "
603 "EXT_CSD[%d] in %s\n", value,
604 EXT_CSD_ENH_SIZE_MULT_2, device);
605 exit(1);
606 }
607 value = (enh_size_mult >> 8) & 0xff;
608 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_1, value);
609 if (ret) {
610 fprintf(stderr, "Could not write 0x%02x to "
611 "EXT_CSD[%d] in %s\n", value,
612 EXT_CSD_ENH_SIZE_MULT_1, device);
613 exit(1);
614 }
615 value = enh_size_mult & 0xff;
616 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_0, value);
617 if (ret) {
618 fprintf(stderr, "Could not write 0x%02x to "
619 "EXT_CSD[%d] in %s\n", value,
620 EXT_CSD_ENH_SIZE_MULT_0, device);
621 exit(1);
622 }
623
624 ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, EXT_CSD_ENH_USR);
625 if (ret) {
626 fprintf(stderr, "Could not write EXT_CSD_ENH_USR to "
627 "EXT_CSD[%d] in %s\n",
628 EXT_CSD_PARTITIONS_ATTRIBUTE, device);
629 exit(1);
630 }
631
Ben Gardinere6e84e92013-09-19 11:14:27 -0400632 printf("Done setting ENH_USR area on %s\n", device);
Ben Gardinerd91d3692013-05-30 17:12:51 -0400633
Ben Gardinere6e84e92013-09-19 11:14:27 -0400634 if (!set_partitioning_setting_completed(dry_run, device, fd))
Ben Gardinerd91d3692013-05-30 17:12:51 -0400635 exit(1);
Ben Gardinerd91d3692013-05-30 17:12:51 -0400636
637 return 0;
638}
639
Ben Gardiner196d0d22013-09-19 11:14:29 -0400640int do_write_reliability_set(int nargs, char **argv)
641{
642 __u8 value;
643 __u8 ext_csd[512];
644 int fd, ret;
645
646 int dry_run = 1;
647 int partition;
648 char *device;
649
650 CHECK(nargs != 4, "Usage: mmc write_reliability set <-y|-n> "
651 "<partition> </path/to/mmcblkX>\n", exit(1));
652
653 if (!strcmp("-y", argv[1]))
654 dry_run = 0;
655
656 partition = strtol(argv[2], NULL, 10);
657 device = argv[3];
658
659 fd = open(device, O_RDWR);
660 if (fd < 0) {
661 perror("open");
662 exit(1);
663 }
664
665 ret = read_extcsd(fd, ext_csd);
666 if (ret) {
667 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
668 exit(1);
669 }
670
671 /* assert not PARTITION_SETTING_COMPLETED */
672 if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
673 {
674 printf(" Device is already partitioned\n");
675 exit(1);
676 }
677
678 /* assert HS_CTRL_REL */
679 if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & HS_CTRL_REL)) {
680 printf("Cannot set write reliability parameters, WR_REL_SET is "
681 "read-only\n");
682 exit(1);
683 }
684
685 value = ext_csd[EXT_CSD_WR_REL_SET] | (1<<partition);
686 ret = write_extcsd_value(fd, EXT_CSD_WR_REL_SET, value);
687 if (ret) {
688 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
689 value, EXT_CSD_WR_REL_SET, device);
690 exit(1);
691 }
692
693 printf("Done setting EXT_CSD_WR_REL_SET to 0x%02x on %s\n",
694 value, device);
695
696 if (!set_partitioning_setting_completed(dry_run, device, fd))
697 exit(1);
698
699 return 0;
700}
701
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500702int do_read_extcsd(int nargs, char **argv)
703{
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100704 __u8 ext_csd[512], ext_csd_rev, reg;
Oliver Metz11f2cea2013-09-23 08:40:52 +0200705 __u32 regl;
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500706 int fd, ret;
707 char *device;
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100708 const char *str;
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800709 const char *ver_str[] = {
710 "4.0", /* 0 */
711 "4.1", /* 1 */
712 "4.2", /* 2 */
713 "4.3", /* 3 */
714 "Obsolete", /* 4 */
715 "4.41", /* 5 */
716 "4.5", /* 6 */
717 "5.0", /* 7 */
718 };
719 int boot_access;
720 const char* boot_access_str[] = {
721 "No access to boot partition", /* 0 */
722 "R/W Boot Partition 1", /* 1 */
723 "R/W Boot Partition 2", /* 2 */
724 "R/W Replay Protected Memory Block (RPMB)", /* 3 */
725 };
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500726
Chris Ball8ba44662012-04-19 13:22:54 -0400727 CHECK(nargs != 2, "Usage: mmc extcsd read </path/to/mmcblkX>\n",
728 exit(1));
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500729
730 device = argv[1];
731
732 fd = open(device, O_RDWR);
733 if (fd < 0) {
734 perror("open");
735 exit(1);
736 }
737
738 ret = read_extcsd(fd, ext_csd);
739 if (ret) {
740 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
741 exit(1);
742 }
743
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100744 ext_csd_rev = ext_csd[192];
745
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800746 if ((ext_csd_rev < sizeof(ver_str)/sizeof(char*)) &&
747 (ext_csd_rev != 4))
748 str = ver_str[ext_csd_rev];
749 else
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100750 goto out_free;
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800751
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100752 printf("=============================================\n");
753 printf(" Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
754 printf("=============================================\n\n");
755
756 if (ext_csd_rev < 3)
757 goto out_free; /* No ext_csd */
758
759 /* Parse the Extended CSD registers.
760 * Reserved bit should be read as "0" in case of spec older
761 * than A441.
762 */
763 reg = ext_csd[EXT_CSD_S_CMD_SET];
764 printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg);
765 if (!reg)
Chris Ballb9c7a172012-02-20 12:34:25 -0500766 printf(" - Standard MMC command sets\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100767
768 reg = ext_csd[EXT_CSD_HPI_FEATURE];
769 printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg);
770 if (reg & EXT_CSD_HPI_SUPP) {
771 if (reg & EXT_CSD_HPI_IMPL)
Chris Ballb9c7a172012-02-20 12:34:25 -0500772 printf("implementation based on CMD12\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100773 else
774 printf("implementation based on CMD13\n");
775 }
776
777 printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n",
778 ext_csd[502]);
779
780 if (ext_csd_rev >= 6) {
781 printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n",
782 ext_csd[501]);
783 printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n",
784 ext_csd[500]);
785 printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n",
786 ext_csd[499]);
787
788 printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n",
789 ext_csd[498]);
790 printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n",
791 ext_csd[497]);
792 printf("Context Management Capabilities"
793 " [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]);
794 printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n",
795 ext_csd[495]);
796 printf("Extended partition attribute support"
797 " [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800798 }
799 if (ext_csd_rev >= 7) {
800 int j;
801 int eol_info;
802 char* eol_info_str[] = {
803 "Not Defined", /* 0 */
804 "Normal", /* 1 */
805 "Warning", /* 2 */
806 "Urgent", /* 3 */
807 };
808
809 printf("Supported modes [SUPPORTED_MODES: 0x%02x]\n",
810 ext_csd[493]);
811 printf("FFU features [FFU_FEATURES: 0x%02x]\n",
812 ext_csd[492]);
813 printf("Operation codes timeout"
814 " [OPERATION_CODE_TIMEOUT: 0x%02x]\n",
815 ext_csd[491]);
816 printf("FFU Argument [FFU_ARG: 0x%08x]\n",
817 get_word_from_ext_csd(&ext_csd[487]));
818 printf("Number of FW sectors correctly programmed"
819 " [NUMBER_OF_FW_SECTORS_CORRECTLY_PROGRAMMED: %d]\n",
820 get_word_from_ext_csd(&ext_csd[302]));
821 printf("Vendor proprietary health report:\n");
822 for (j = 301; j >= 270; j--)
823 printf("[VENDOR_PROPRIETARY_HEALTH_REPORT[%d]]:"
824 " 0x%02x\n", j, ext_csd[j]);
825 for (j = 269; j >= 268; j--) {
826 __u8 life_used=ext_csd[j];
Puthikorn Voravootivat6bb37ea2014-03-03 17:55:51 -0800827 char est_type = 'B' + (j - 269);
828 printf("Device life time estimation type %c"
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800829 " [DEVICE_LIFE_TIME_EST_TYP_%c: 0x%02x]\n",
Puthikorn Voravootivat6bb37ea2014-03-03 17:55:51 -0800830 est_type, est_type, life_used);
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800831 if (life_used >= 0x1 && life_used <= 0xa)
832 printf(" i.e. %d%% - %d%% device life time"
833 " used\n",
834 (life_used - 1) * 10, life_used * 10);
835 else if (life_used == 0xb)
836 printf(" i.e. Exceeded its maximum estimated"
837 " device life time\n");
838 }
839 eol_info = ext_csd[267];
840 printf("Pre EOL information [PRE_EOL_INFO: 0x%02x]\n",
841 eol_info);
842 if (eol_info < sizeof(eol_info_str)/sizeof(char*))
843 printf(" i.e. %s\n", eol_info_str[eol_info]);
844 else
845 printf(" i.e. Reserved\n");
846
847 printf("Optimal read size [OPTIMAL_READ_SIZE: 0x%02x]\n",
848 ext_csd[266]);
849 printf("Optimal write size [OPTIMAL_WRITE_SIZE: 0x%02x]\n",
850 ext_csd[265]);
851 printf("Optimal trim unit size"
852 " [OPTIMAL_TRIM_UNIT_SIZE: 0x%02x]\n", ext_csd[264]);
853 printf("Device version [DEVICE_VERSION: 0x%02x - 0x%02x]\n",
854 ext_csd[263], ext_csd[262]);
855 printf("Firmware version:\n");
856 for (j = 261; j >= 254; j--)
857 printf("[FIRMWARE_VERSION[%d]]:"
858 " 0x%02x\n", j, ext_csd[j]);
859
860 printf("Power class for 200MHz, DDR at VCC= 3.6V"
861 " [PWR_CL_DDR_200_360: 0x%02x]\n", ext_csd[253]);
862 }
863 if (ext_csd_rev >= 6) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100864 printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n",
865 ext_csd[248]);
866 printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n",
867 ext_csd[247]);
868 printf("Cache Size [CACHE_SIZE] is %d KiB\n",
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800869 get_word_from_ext_csd(&ext_csd[249]));
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100870 }
871
872 /* A441: Reserved [501:247]
873 A43: reserved [246:229] */
874 if (ext_csd_rev >= 5) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100875 printf("Background operations status"
Chris Ballb9c7a172012-02-20 12:34:25 -0500876 " [BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100877
878 /* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */
879
880 printf("1st Initialisation Time after programmed sector"
881 " [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]);
882
883 /* A441: reserved [240] */
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100884 printf("Power class for 52MHz, DDR at 3.6V"
885 " [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]);
886 printf("Power class for 52MHz, DDR at 1.95V"
887 " [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]);
888
889 /* A441: reserved [237-236] */
890
891 if (ext_csd_rev >= 6) {
892 printf("Power class for 200MHz at 3.6V"
893 " [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]);
894 printf("Power class for 200MHz, at 1.95V"
895 " [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]);
896 }
Chris Ballb9c7a172012-02-20 12:34:25 -0500897 printf("Minimum Performance for 8bit at 52MHz in DDR mode:\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100898 printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]);
899 printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]);
900 /* A441: reserved [233] */
901 printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]);
902 printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n",
903 ext_csd[231]);
904 }
905 if (ext_csd_rev == 5) { /* Obsolete in 4.5 */
906 printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n",
907 ext_csd[230]);
908 printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n",
909 ext_csd[229]);
910 }
911 reg = ext_csd[EXT_CSD_BOOT_INFO];
912 printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg);
913 if (reg & EXT_CSD_BOOT_INFO_ALT)
914 printf(" Device supports alternative boot method\n");
915 if (reg & EXT_CSD_BOOT_INFO_DDR_DDR)
916 printf(" Device supports dual data rate during boot\n");
917 if (reg & EXT_CSD_BOOT_INFO_HS_MODE)
918 printf(" Device supports high speed timing during boot\n");
919
920 /* A441/A43: reserved [227] */
921 printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]);
922 printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]);
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400923
924 reg = get_hc_erase_grp_size(ext_csd);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100925 printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400926 reg);
927 printf(" i.e. %u KiB\n", 512 * reg);
928
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100929 printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n",
930 ext_csd[223]);
931 printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n",
932 ext_csd[222]);
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400933
934 reg = get_hc_wp_grp_size(ext_csd);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100935 printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400936 reg);
937 printf(" i.e. %lu KiB\n", 512l * get_hc_erase_grp_size(ext_csd) * reg);
938
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100939 printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]);
940 printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]);
941 /* A441/A43: reserved [218] */
942 printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]);
943 /* A441/A43: reserved [216] */
Ben Gardiner4e850232013-05-30 17:12:49 -0400944
945 unsigned int sectors = get_sector_count(ext_csd);
946 printf("Sector Count [SEC_COUNT: 0x%08x]\n", sectors);
947 if (is_blockaddresed(ext_csd))
948 printf(" Device is block-addressed\n");
949 else
950 printf(" Device is NOT block-addressed\n");
951
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100952 /* A441/A43: reserved [211] */
953 printf("Minimum Write Performance for 8bit:\n");
954 printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]);
955 printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]);
956 printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]);
957 printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]);
958 printf("Minimum Write Performance for 4bit:\n");
959 printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]);
960 printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]);
961 /* A441/A43: reserved [204] */
962 printf("Power classes registers:\n");
963 printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]);
964 printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]);
965 printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]);
966 printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]);
967
968 /* A43: reserved [199:198] */
969 if (ext_csd_rev >= 5) {
970 printf("Partition switching timing "
971 "[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]);
972 printf("Out-of-interrupt busy timing"
973 " [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]);
974 }
975
976 /* A441/A43: reserved [197] [195] [193] [190] [188]
977 * [186] [184] [182] [180] [176] */
978
979 if (ext_csd_rev >= 6)
980 printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n",
981 ext_csd[197]);
982
Oleg Matcovschi64f63a32013-05-23 17:11:07 -0700983 /* DEVICE_TYPE in A45, CARD_TYPE in A441 */
984 reg = ext_csd[196];
985 printf("Card Type [CARD_TYPE: 0x%02x]\n", reg);
986 if (reg & 0x20) printf(" HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n");
987 if (reg & 0x10) printf(" HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n");
988 if (reg & 0x08) printf(" HS Dual Data Rate eMMC @52MHz 1.2VI/O\n");
989 if (reg & 0x04) printf(" HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n");
990 if (reg & 0x02) printf(" HS eMMC @52MHz - at rated device voltage(s)\n");
991 if (reg & 0x01) printf(" HS eMMC @26MHz - at rated device voltage(s)\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100992
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100993 printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
994 /* ext_csd_rev = ext_csd[192] (already done!!!) */
995 printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]);
996 printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]);
997 printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]);
998 printf("High-speed interface timing [HS_TIMING: 0x%02x]\n",
999 ext_csd[185]);
1000 /* bus_width: ext_csd[183] not readable */
1001 printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n",
1002 ext_csd[181]);
1003 reg = ext_csd[EXT_CSD_BOOT_CFG];
1004 printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg);
Mario Schuknecht8c0c40d2013-05-15 08:28:04 +02001005 switch ((reg & EXT_CSD_BOOT_CFG_EN)>>3) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001006 case 0x0:
1007 printf(" Not boot enable\n");
1008 break;
1009 case 0x1:
1010 printf(" Boot Partition 1 enabled\n");
1011 break;
1012 case 0x2:
1013 printf(" Boot Partition 2 enabled\n");
1014 break;
1015 case 0x7:
1016 printf(" User Area Enabled for boot\n");
1017 break;
1018 }
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -08001019 boot_access = reg & EXT_CSD_BOOT_CFG_ACC;
1020 if (boot_access < sizeof(boot_access_str) / sizeof(char*))
1021 printf(" %s\n", boot_access_str[boot_access]);
1022 else
Mario Schuknecht8c0c40d2013-05-15 08:28:04 +02001023 printf(" Access to General Purpose partition %d\n",
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -08001024 boot_access - 3);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001025
1026 printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
1027 ext_csd[178]);
1028 printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n",
1029 ext_csd[177]);
1030 printf("High-density erase group definition"
Ben Gardinerd91d3692013-05-30 17:12:51 -04001031 " [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[EXT_CSD_ERASE_GROUP_DEF]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001032
Chris Ballb9c7a172012-02-20 12:34:25 -05001033 print_writeprotect_status(ext_csd);
1034
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001035 if (ext_csd_rev >= 5) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001036 /* A441]: reserved [172] */
1037 printf("User area write protection register"
1038 " [USER_WP]: 0x%02x\n", ext_csd[171]);
1039 /* A441]: reserved [170] */
1040 printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]);
1041 printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]);
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001042
1043 reg = ext_csd[EXT_CSD_WR_REL_SET];
1044 const char * const fast = "existing data is at risk if a power "
1045 "failure occurs during a write operation";
1046 const char * const reliable = "the device protects existing "
1047 "data if a power failure occurs during a write "
1048 "operation";
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001049 printf("Write reliability setting register"
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001050 " [WR_REL_SET]: 0x%02x\n", reg);
1051
1052 printf(" user area: %s\n", reg & (1<<0) ? reliable : fast);
1053 int i;
1054 for (i = 1; i <= 4; i++) {
1055 printf(" partition %d: %s\n", i,
1056 reg & (1<<i) ? reliable : fast);
1057 }
1058
1059 reg = ext_csd[EXT_CSD_WR_REL_PARAM];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001060 printf("Write reliability parameter register"
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001061 " [WR_REL_PARAM]: 0x%02x\n", reg);
1062 if (reg & 0x01)
1063 printf(" Device supports writing EXT_CSD_WR_REL_SET\n");
1064 if (reg & 0x04)
1065 printf(" Device supports the enhanced def. of reliable "
1066 "write\n");
1067
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001068 /* sanitize_start ext_csd[165]]: not readable
1069 * bkops_start ext_csd[164]]: only writable */
1070 printf("Enable background operations handshake"
1071 " [BKOPS_EN]: 0x%02x\n", ext_csd[163]);
1072 printf("H/W reset function"
1073 " [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]);
1074 printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]);
Ben Gardiner82bd9502013-06-27 11:04:10 -04001075 reg = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001076 printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
1077 reg);
Ben Gardiner82bd9502013-06-27 11:04:10 -04001078 if (reg & EXT_CSD_PARTITIONING_EN)
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001079 printf(" Device support partitioning feature\n");
1080 else
1081 printf(" Device NOT support partitioning feature\n");
Ben Gardiner82bd9502013-06-27 11:04:10 -04001082 if (reg & EXT_CSD_ENH_ATTRIBUTE_EN)
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001083 printf(" Device can have enhanced tech.\n");
1084 else
1085 printf(" Device cannot have enhanced tech.\n");
1086
Oliver Metz11f2cea2013-09-23 08:40:52 +02001087 regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
Oliver Metz22f26412013-09-23 08:40:51 +02001088 (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
1089 ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
1090
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001091 printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
Oliver Metz11f2cea2013-09-23 08:40:52 +02001092 regl);
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001093 unsigned int wp_sz = get_hc_wp_grp_size(ext_csd);
1094 unsigned int erase_sz = get_hc_erase_grp_size(ext_csd);
Oliver Metz11f2cea2013-09-23 08:40:52 +02001095 printf(" i.e. %lu KiB\n", 512l * regl * wp_sz * erase_sz);
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001096
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001097 printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
Ben Gardinerd91d3692013-05-30 17:12:51 -04001098 ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]);
Ben Gardinera6cd98d2013-05-30 17:12:46 -04001099 reg = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001100 printf("Partitioning Setting"
1101 " [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
Ben Gardinera6cd98d2013-05-30 17:12:46 -04001102 reg);
1103 if (reg)
1104 printf(" Device partition setting complete\n");
1105 else
1106 printf(" Device partition setting NOT complete\n");
1107
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001108 printf("General Purpose Partition Size\n"
1109 " [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) |
1110 (ext_csd[153] << 8) | ext_csd[152]);
1111 printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) |
1112 (ext_csd[150] << 8) | ext_csd[149]);
1113 printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) |
1114 (ext_csd[147] << 8) | ext_csd[146]);
1115 printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) |
1116 (ext_csd[144] << 8) | ext_csd[143]);
1117
Oliver Metz11f2cea2013-09-23 08:40:52 +02001118 regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001119 (ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
1120 ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001121 printf("Enhanced User Data Area Size"
Oliver Metz11f2cea2013-09-23 08:40:52 +02001122 " [ENH_SIZE_MULT]: 0x%06x\n", regl);
1123 printf(" i.e. %lu KiB\n", 512l * regl *
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001124 get_hc_erase_grp_size(ext_csd) *
1125 get_hc_wp_grp_size(ext_csd));
Ben Gardiner68f490b2013-05-30 17:12:48 -04001126
Oliver Metz11f2cea2013-09-23 08:40:52 +02001127 regl = (ext_csd[EXT_CSD_ENH_START_ADDR_3] << 24) |
Ben Gardiner68f490b2013-05-30 17:12:48 -04001128 (ext_csd[EXT_CSD_ENH_START_ADDR_2] << 16) |
1129 (ext_csd[EXT_CSD_ENH_START_ADDR_1] << 8) |
1130 ext_csd[EXT_CSD_ENH_START_ADDR_0];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001131 printf("Enhanced User Data Start Address"
Oliver Metz11f2cea2013-09-23 08:40:52 +02001132 " [ENH_START_ADDR]: 0x%06x\n", regl);
Ben Gardiner4e850232013-05-30 17:12:49 -04001133 printf(" i.e. %lu bytes offset\n", (is_blockaddresed(ext_csd) ?
Oliver Metz11f2cea2013-09-23 08:40:52 +02001134 1l : 512l) * regl);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001135
1136 /* A441]: reserved [135] */
1137 printf("Bad Block Management mode"
1138 " [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]);
1139 /* A441: reserved [133:0] */
1140 }
1141 /* B45 */
1142 if (ext_csd_rev >= 6) {
1143 int j;
1144 /* tcase_support ext_csd[132] not readable */
1145 printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n",
1146 ext_csd[131]);
1147 printf("Program CID/CSD in DDR mode support"
1148 " [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n",
1149 ext_csd[130]);
1150
1151 for (j = 127; j >= 64; j--)
1152 printf("Vendor Specific Fields"
1153 " [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n",
1154 j, ext_csd[j]);
1155
1156 printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n",
1157 ext_csd[63]);
1158 printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n",
1159 ext_csd[62]);
1160 printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", ext_csd[61]);
1161 printf("1st initialization after disabling sector"
1162 " size emulation [INI_TIMEOUT_EMU]: 0x%02x\n",
1163 ext_csd[60]);
1164 printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n",
1165 ext_csd[59]);
1166 printf("Number of addressed group to be Released"
1167 "[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]);
1168 printf("Exception events control"
1169 " [EXCEPTION_EVENTS_CTRL]: 0x%04x\n",
1170 (ext_csd[57] << 8) | ext_csd[56]);
1171 printf("Exception events status"
1172 "[EXCEPTION_EVENTS_STATUS]: 0x%04x\n",
1173 (ext_csd[55] << 8) | ext_csd[54]);
1174 printf("Extended Partitions Attribute"
1175 " [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n",
1176 (ext_csd[53] << 8) | ext_csd[52]);
1177
1178 for (j = 51; j >= 37; j--)
1179 printf("Context configuration"
1180 " [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]);
1181
1182 printf("Packed command status"
1183 " [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]);
1184 printf("Packed command failure index"
1185 " [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]);
1186 printf("Power Off Notification"
1187 " [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]);
Oleg Matcovschi64f63a32013-05-23 17:11:07 -07001188 printf("Control to turn the Cache ON/OFF"
1189 " [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001190 /* flush_cache ext_csd[32] not readable */
1191 /*Reserved [31:0] */
1192 }
1193
1194out_free:
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -05001195 return ret;
1196}
Yaniv Gardi21bb4732013-05-26 13:25:33 -04001197
1198int do_sanitize(int nargs, char **argv)
1199{
1200 int fd, ret;
1201 char *device;
1202
1203 CHECK(nargs != 2, "Usage: mmc sanitize </path/to/mmcblkX>\n",
1204 exit(1));
1205
1206 device = argv[1];
1207
1208 fd = open(device, O_RDWR);
1209 if (fd < 0) {
1210 perror("open");
1211 exit(1);
1212 }
1213
1214 ret = write_extcsd_value(fd, EXT_CSD_SANITIZE_START, 1);
1215 if (ret) {
1216 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
1217 1, EXT_CSD_SANITIZE_START, device);
1218 exit(1);
1219 }
1220
1221 return ret;
1222
1223}
1224