blob: 3fda5027b3019579012c5c1c1df42a39f70ee0d6 [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
Nick Sanders9d57aa72014-03-05 21:38:54 -080033#define EXT_CSD_SIZE 512
34#define CID_SIZE 16
35
36
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050037int read_extcsd(int fd, __u8 *ext_csd)
38{
39 int ret = 0;
40 struct mmc_ioc_cmd idata;
41 memset(&idata, 0, sizeof(idata));
Nick Sanders9d57aa72014-03-05 21:38:54 -080042 memset(ext_csd, 0, sizeof(__u8) * EXT_CSD_SIZE);
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050043 idata.write_flag = 0;
44 idata.opcode = MMC_SEND_EXT_CSD;
45 idata.arg = 0;
46 idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
Nick Sanders9d57aa72014-03-05 21:38:54 -080047 idata.blksz = EXT_CSD_SIZE;
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050048 idata.blocks = 1;
49 mmc_ioc_cmd_set_data(idata, ext_csd);
50
51 ret = ioctl(fd, MMC_IOC_CMD, &idata);
52 if (ret)
Nick Sanders9d57aa72014-03-05 21:38:54 -080053 perror("ioctl SEND_EXT_CSD");
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050054
55 return ret;
56}
57
58int write_extcsd_value(int fd, __u8 index, __u8 value)
59{
60 int ret = 0;
61 struct mmc_ioc_cmd idata;
62
63 memset(&idata, 0, sizeof(idata));
64 idata.write_flag = 1;
65 idata.opcode = MMC_SWITCH;
66 idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
67 (index << 16) |
68 (value << 8) |
69 EXT_CSD_CMD_SET_NORMAL;
70 idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
71
72 ret = ioctl(fd, MMC_IOC_CMD, &idata);
73 if (ret)
Nick Sanders9d57aa72014-03-05 21:38:54 -080074 perror("ioctl Write EXT CSD");
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050075
76 return ret;
77}
78
Ben Gardiner27c357d2013-05-30 17:12:47 -040079int send_status(int fd, __u32 *response)
80{
81 int ret = 0;
82 struct mmc_ioc_cmd idata;
83
84 memset(&idata, 0, sizeof(idata));
85 idata.opcode = MMC_SEND_STATUS;
86 idata.arg = (1 << 16);
87 idata.flags = MMC_RSP_R1 | MMC_CMD_AC;
88
89 ret = ioctl(fd, MMC_IOC_CMD, &idata);
90 if (ret)
91 perror("ioctl");
92
93 *response = idata.response[0];
94
95 return ret;
96}
97
Chris Ballb9c7a172012-02-20 12:34:25 -050098void print_writeprotect_status(__u8 *ext_csd)
99{
100 __u8 reg;
101 __u8 ext_csd_rev = ext_csd[192];
102
103 /* A43: reserved [174:0] */
104 if (ext_csd_rev >= 5) {
105 printf("Boot write protection status registers"
106 " [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]);
107
108 reg = ext_csd[EXT_CSD_BOOT_WP];
109 printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg);
110 printf(" Power ro locking: ");
111 if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
112 printf("not possible\n");
113 else
114 printf("possible\n");
115
116 printf(" Permanent ro locking: ");
117 if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
118 printf("not possible\n");
119 else
120 printf("possible\n");
121
122 printf(" ro lock status: ");
123 if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
124 printf("locked until next power on\n");
125 else if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
126 printf("locked permanently\n");
127 else
128 printf("not locked\n");
129 }
130}
131
132int do_writeprotect_get(int nargs, char **argv)
133{
Nick Sanders9d57aa72014-03-05 21:38:54 -0800134 __u8 ext_csd[EXT_CSD_SIZE];
Chris Ballb9c7a172012-02-20 12:34:25 -0500135 int fd, ret;
136 char *device;
137
Chris Ball8ba44662012-04-19 13:22:54 -0400138 CHECK(nargs != 2, "Usage: mmc writeprotect get </path/to/mmcblkX>\n",
139 exit(1));
Chris Ballb9c7a172012-02-20 12:34:25 -0500140
141 device = argv[1];
142
143 fd = open(device, O_RDWR);
144 if (fd < 0) {
145 perror("open");
146 exit(1);
147 }
148
149 ret = read_extcsd(fd, ext_csd);
150 if (ret) {
151 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
152 exit(1);
153 }
154
155 print_writeprotect_status(ext_csd);
156
157 return ret;
158}
159
160int do_writeprotect_set(int nargs, char **argv)
161{
Nick Sanders9d57aa72014-03-05 21:38:54 -0800162 __u8 ext_csd[EXT_CSD_SIZE], value;
Chris Ballb9c7a172012-02-20 12:34:25 -0500163 int fd, ret;
164 char *device;
165
Chris Ball8ba44662012-04-19 13:22:54 -0400166 CHECK(nargs != 2, "Usage: mmc writeprotect set </path/to/mmcblkX>\n",
167 exit(1));
Chris Ballb9c7a172012-02-20 12:34:25 -0500168
169 device = argv[1];
170
171 fd = open(device, O_RDWR);
172 if (fd < 0) {
173 perror("open");
174 exit(1);
175 }
176
177 ret = read_extcsd(fd, ext_csd);
178 if (ret) {
179 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
180 exit(1);
181 }
182
183 value = ext_csd[EXT_CSD_BOOT_WP] |
184 EXT_CSD_BOOT_WP_B_PWR_WP_EN;
185 ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value);
186 if (ret) {
187 fprintf(stderr, "Could not write 0x%02x to "
188 "EXT_CSD[%d] in %s\n",
189 value, EXT_CSD_BOOT_WP, device);
190 exit(1);
191 }
192
193 return ret;
194}
195
Saugata Dasb7e25992012-05-17 09:26:34 -0400196int do_disable_512B_emulation(int nargs, char **argv)
197{
Nick Sanders9d57aa72014-03-05 21:38:54 -0800198 __u8 ext_csd[EXT_CSD_SIZE], native_sector_size, data_sector_size, wr_rel_param;
Saugata Dasb7e25992012-05-17 09:26:34 -0400199 int fd, ret;
200 char *device;
201
202 CHECK(nargs != 2, "Usage: mmc disable 512B emulation </path/to/mmcblkX>\n", exit(1));
203 device = argv[1];
204
205 fd = open(device, O_RDWR);
206 if (fd < 0) {
207 perror("open");
208 exit(1);
209 }
210
211 ret = read_extcsd(fd, ext_csd);
212 if (ret) {
213 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
214 exit(1);
215 }
216
217 wr_rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
218 native_sector_size = ext_csd[EXT_CSD_NATIVE_SECTOR_SIZE];
219 data_sector_size = ext_csd[EXT_CSD_DATA_SECTOR_SIZE];
220
221 if (native_sector_size && !data_sector_size &&
222 (wr_rel_param & EN_REL_WR)) {
223 ret = write_extcsd_value(fd, EXT_CSD_USE_NATIVE_SECTOR, 1);
224
225 if (ret) {
226 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
227 1, EXT_CSD_BOOT_WP, device);
228 exit(1);
229 }
230 printf("MMC disable 512B emulation successful. Now reset the device to switch to 4KB native sector mode.\n");
231 } else if (native_sector_size && data_sector_size) {
232 printf("MMC 512B emulation mode is already disabled; doing nothing.\n");
233 } else {
234 printf("MMC does not support disabling 512B emulation mode.\n");
235 }
236
237 return ret;
238}
239
Giuseppe CAVALLARO7bd13202012-04-19 10:58:37 +0200240int do_write_boot_en(int nargs, char **argv)
241{
242 __u8 ext_csd[512];
243 __u8 value = 0;
244 int fd, ret;
245 char *device;
246 int boot_area, send_ack;
247
248 CHECK(nargs != 4, "Usage: mmc bootpart enable <partition_number> "
249 "<send_ack> </path/to/mmcblkX>\n", exit(1));
250
251 /*
252 * If <send_ack> is 1, the device will send acknowledgment
253 * pattern "010" to the host when boot operation begins.
254 * If <send_ack> is 0, it won't.
255 */
256 boot_area = strtol(argv[1], NULL, 10);
257 send_ack = strtol(argv[2], NULL, 10);
258 device = argv[3];
259
260 fd = open(device, O_RDWR);
261 if (fd < 0) {
262 perror("open");
263 exit(1);
264 }
265
266 ret = read_extcsd(fd, ext_csd);
267 if (ret) {
268 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
269 exit(1);
270 }
271
272 value = ext_csd[EXT_CSD_PART_CONFIG];
273
274 switch (boot_area) {
275 case EXT_CSD_PART_CONFIG_ACC_BOOT0:
276 value |= (1 << 3);
277 value &= ~(3 << 4);
278 break;
279 case EXT_CSD_PART_CONFIG_ACC_BOOT1:
280 value |= (1 << 4);
281 value &= ~(1 << 3);
282 value &= ~(1 << 5);
283 break;
284 case EXT_CSD_PART_CONFIG_ACC_USER_AREA:
285 value |= (boot_area << 3);
286 break;
287 default:
288 fprintf(stderr, "Cannot enable the boot area\n");
289 exit(1);
290 }
291 if (send_ack)
292 value |= EXT_CSD_PART_CONFIG_ACC_ACK;
293 else
294 value &= ~EXT_CSD_PART_CONFIG_ACC_ACK;
295
296 ret = write_extcsd_value(fd, EXT_CSD_PART_CONFIG, value);
297 if (ret) {
298 fprintf(stderr, "Could not write 0x%02x to "
299 "EXT_CSD[%d] in %s\n",
300 value, EXT_CSD_PART_CONFIG, device);
301 exit(1);
302 }
303 return ret;
304}
305
Chris Ballf74dfe22012-10-19 16:49:55 -0400306int do_hwreset(int value, int nargs, char **argv)
307{
Nick Sanders9d57aa72014-03-05 21:38:54 -0800308 __u8 ext_csd[EXT_CSD_SIZE];
Chris Ballf74dfe22012-10-19 16:49:55 -0400309 int fd, ret;
310 char *device;
311
312 CHECK(nargs != 2, "Usage: mmc hwreset enable </path/to/mmcblkX>\n",
313 exit(1));
314
315 device = argv[1];
316
317 fd = open(device, O_RDWR);
318 if (fd < 0) {
319 perror("open");
320 exit(1);
321 }
322
323 ret = read_extcsd(fd, ext_csd);
324 if (ret) {
325 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
326 exit(1);
327 }
328
329 if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
330 EXT_CSD_HW_RESET_EN) {
331 fprintf(stderr,
332 "H/W Reset is already permanently enabled on %s\n",
333 device);
334 exit(1);
335 }
336 if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
337 EXT_CSD_HW_RESET_DIS) {
338 fprintf(stderr,
339 "H/W Reset is already permanently disabled on %s\n",
340 device);
341 exit(1);
342 }
343
344 ret = write_extcsd_value(fd, EXT_CSD_RST_N_FUNCTION, value);
345 if (ret) {
346 fprintf(stderr,
347 "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
348 value, EXT_CSD_RST_N_FUNCTION, device);
349 exit(1);
350 }
351
352 return ret;
353}
354
355int do_hwreset_en(int nargs, char **argv)
356{
357 return do_hwreset(EXT_CSD_HW_RESET_EN, nargs, argv);
358}
359
360int do_hwreset_dis(int nargs, char **argv)
361{
362 return do_hwreset(EXT_CSD_HW_RESET_DIS, nargs, argv);
363}
364
Jaehoon Chung86496512012-09-21 10:08:05 +0000365int do_write_bkops_en(int nargs, char **argv)
366{
Nick Sanders9d57aa72014-03-05 21:38:54 -0800367 __u8 ext_csd[EXT_CSD_SIZE], value = 0;
Jaehoon Chung86496512012-09-21 10:08:05 +0000368 int fd, ret;
369 char *device;
370
371 CHECK(nargs != 2, "Usage: mmc bkops enable </path/to/mmcblkX>\n",
372 exit(1));
373
374 device = argv[1];
375
376 fd = open(device, O_RDWR);
377 if (fd < 0) {
378 perror("open");
379 exit(1);
380 }
381
382 ret = read_extcsd(fd, ext_csd);
383 if (ret) {
384 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
385 exit(1);
386 }
387
388 if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
389 fprintf(stderr, "%s doesn't support BKOPS\n", device);
390 exit(1);
391 }
392
393 ret = write_extcsd_value(fd, EXT_CSD_BKOPS_EN, BKOPS_ENABLE);
394 if (ret) {
395 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
396 value, EXT_CSD_BKOPS_EN, device);
397 exit(1);
398 }
399
400 return ret;
401}
402
Ben Gardiner27c357d2013-05-30 17:12:47 -0400403int do_status_get(int nargs, char **argv)
404{
405 __u32 response;
406 int fd, ret;
407 char *device;
408
409 CHECK(nargs != 2, "Usage: mmc status get </path/to/mmcblkX>\n",
410 exit(1));
411
412 device = argv[1];
413
414 fd = open(device, O_RDWR);
415 if (fd < 0) {
416 perror("open");
417 exit(1);
418 }
419
420 ret = send_status(fd, &response);
421 if (ret) {
422 fprintf(stderr, "Could not read response to SEND_STATUS from %s\n", device);
423 exit(1);
424 }
425
426 printf("SEND_STATUS response: 0x%08x\n", response);
427
428 return ret;
429}
430
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800431__u32 get_word_from_ext_csd(__u8 *ext_csd_loc)
432{
433 return (ext_csd_loc[3] << 24) |
434 (ext_csd_loc[2] << 16) |
435 (ext_csd_loc[1] << 8) |
436 ext_csd_loc[0];
437}
438
Ben Gardiner4e850232013-05-30 17:12:49 -0400439unsigned int get_sector_count(__u8 *ext_csd)
440{
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800441 return get_word_from_ext_csd(&ext_csd[EXT_CSD_SEC_COUNT_0]);
Ben Gardiner4e850232013-05-30 17:12:49 -0400442}
443
444int is_blockaddresed(__u8 *ext_csd)
445{
446 unsigned int sectors = get_sector_count(ext_csd);
447
448 return (sectors > (2u * 1024 * 1024 * 1024) / 512);
449}
450
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400451unsigned int get_hc_wp_grp_size(__u8 *ext_csd)
452{
453 return ext_csd[221];
454}
455
456unsigned int get_hc_erase_grp_size(__u8 *ext_csd)
457{
458 return ext_csd[224];
459}
460
Ben Gardinere6e84e92013-09-19 11:14:27 -0400461int set_partitioning_setting_completed(int dry_run, const char * const device,
462 int fd)
463{
464 int ret;
465
466 if (dry_run) {
467 fprintf(stderr, "NOT setting PARTITION_SETTING_COMPLETED\n");
468 fprintf(stderr, "These changes will not take effect neither "
469 "now nor after a power cycle\n");
470 return 1;
471 }
472
473 fprintf(stderr, "setting OTP PARTITION_SETTING_COMPLETED!\n");
474 ret = write_extcsd_value(fd, EXT_CSD_PARTITION_SETTING_COMPLETED, 0x1);
475 if (ret) {
476 fprintf(stderr, "Could not write 0x1 to "
477 "EXT_CSD[%d] in %s\n",
478 EXT_CSD_PARTITION_SETTING_COMPLETED, device);
479 return 1;
480 }
481
482 __u32 response;
483 ret = send_status(fd, &response);
484 if (ret) {
485 fprintf(stderr, "Could not get response to SEND_STATUS "
486 "from %s\n", device);
487 return 1;
488 }
489
490 if (response & R1_SWITCH_ERROR) {
491 fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED "
492 "failed on %s\n", device);
493 return 1;
494 }
495
496 fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED on "
497 "%s SUCCESS\n", device);
498 fprintf(stderr, "Device power cycle needed for settings to "
499 "take effect.\n"
500 "Confirm that PARTITION_SETTING_COMPLETED bit is set "
501 "using 'extcsd read' after power cycle\n");
502
503 return 0;
504}
505
Ben Gardinerd91d3692013-05-30 17:12:51 -0400506int do_enh_area_set(int nargs, char **argv)
507{
508 __u8 value;
Nick Sanders9d57aa72014-03-05 21:38:54 -0800509 __u8 ext_csd[EXT_CSD_SIZE];
Ben Gardinerd91d3692013-05-30 17:12:51 -0400510 int fd, ret;
511 char *device;
512 int dry_run = 1;
513 unsigned int start_kib, length_kib, enh_start_addr, enh_size_mult;
514 unsigned long align;
515
516 CHECK(nargs != 5, "Usage: mmc enh_area set <-y|-n> <start KiB> <length KiB> "
517 "</path/to/mmcblkX>\n", exit(1));
518
519 if (!strcmp("-y", argv[1]))
520 dry_run = 0;
521
522 start_kib = strtol(argv[2], NULL, 10);
523 length_kib = strtol(argv[3], NULL, 10);
524 device = argv[4];
525
526 fd = open(device, O_RDWR);
527 if (fd < 0) {
528 perror("open");
529 exit(1);
530 }
531
532 ret = read_extcsd(fd, ext_csd);
533 if (ret) {
534 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
535 exit(1);
536 }
537
538 /* assert ENH_ATTRIBUTE_EN */
539 if (!(ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & EXT_CSD_ENH_ATTRIBUTE_EN))
540 {
541 printf(" Device cannot have enhanced tech.\n");
542 exit(1);
543 }
544
545 /* assert not PARTITION_SETTING_COMPLETED */
546 if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
547 {
548 printf(" Device is already partitioned\n");
549 exit(1);
550 }
551
552 align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
553
554 enh_size_mult = (length_kib + align/2l) / align;
555
556 enh_start_addr = start_kib * 1024 / (is_blockaddresed(ext_csd) ? 512 : 1);
557 enh_start_addr /= align;
558 enh_start_addr *= align;
559
560 /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
561 ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
562 if (ret) {
563 fprintf(stderr, "Could not write 0x1 to "
564 "EXT_CSD[%d] in %s\n",
565 EXT_CSD_ERASE_GROUP_DEF, device);
566 exit(1);
567 }
568
569 /* write to ENH_START_ADDR and ENH_SIZE_MULT and PARTITIONS_ATTRIBUTE's ENH_USR bit */
570 value = (enh_start_addr >> 24) & 0xff;
571 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_3, value);
572 if (ret) {
573 fprintf(stderr, "Could not write 0x%02x to "
574 "EXT_CSD[%d] in %s\n", value,
575 EXT_CSD_ENH_START_ADDR_3, device);
576 exit(1);
577 }
578 value = (enh_start_addr >> 16) & 0xff;
579 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_2, value);
580 if (ret) {
581 fprintf(stderr, "Could not write 0x%02x to "
582 "EXT_CSD[%d] in %s\n", value,
583 EXT_CSD_ENH_START_ADDR_2, device);
584 exit(1);
585 }
586 value = (enh_start_addr >> 8) & 0xff;
587 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_1, value);
588 if (ret) {
589 fprintf(stderr, "Could not write 0x%02x to "
590 "EXT_CSD[%d] in %s\n", value,
591 EXT_CSD_ENH_START_ADDR_1, device);
592 exit(1);
593 }
594 value = enh_start_addr & 0xff;
595 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_0, value);
596 if (ret) {
597 fprintf(stderr, "Could not write 0x%02x to "
598 "EXT_CSD[%d] in %s\n", value,
599 EXT_CSD_ENH_START_ADDR_0, device);
600 exit(1);
601 }
602
603 value = (enh_size_mult >> 16) & 0xff;
604 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_2, value);
605 if (ret) {
606 fprintf(stderr, "Could not write 0x%02x to "
607 "EXT_CSD[%d] in %s\n", value,
608 EXT_CSD_ENH_SIZE_MULT_2, device);
609 exit(1);
610 }
611 value = (enh_size_mult >> 8) & 0xff;
612 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_1, value);
613 if (ret) {
614 fprintf(stderr, "Could not write 0x%02x to "
615 "EXT_CSD[%d] in %s\n", value,
616 EXT_CSD_ENH_SIZE_MULT_1, device);
617 exit(1);
618 }
619 value = enh_size_mult & 0xff;
620 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_0, value);
621 if (ret) {
622 fprintf(stderr, "Could not write 0x%02x to "
623 "EXT_CSD[%d] in %s\n", value,
624 EXT_CSD_ENH_SIZE_MULT_0, device);
625 exit(1);
626 }
627
628 ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, EXT_CSD_ENH_USR);
629 if (ret) {
630 fprintf(stderr, "Could not write EXT_CSD_ENH_USR to "
631 "EXT_CSD[%d] in %s\n",
632 EXT_CSD_PARTITIONS_ATTRIBUTE, device);
633 exit(1);
634 }
635
Ben Gardinere6e84e92013-09-19 11:14:27 -0400636 printf("Done setting ENH_USR area on %s\n", device);
Ben Gardinerd91d3692013-05-30 17:12:51 -0400637
Ben Gardinere6e84e92013-09-19 11:14:27 -0400638 if (!set_partitioning_setting_completed(dry_run, device, fd))
Ben Gardinerd91d3692013-05-30 17:12:51 -0400639 exit(1);
Ben Gardinerd91d3692013-05-30 17:12:51 -0400640
641 return 0;
642}
643
Ben Gardiner196d0d22013-09-19 11:14:29 -0400644int do_write_reliability_set(int nargs, char **argv)
645{
646 __u8 value;
Nick Sanders9d57aa72014-03-05 21:38:54 -0800647 __u8 ext_csd[EXT_CSD_SIZE];
Ben Gardiner196d0d22013-09-19 11:14:29 -0400648 int fd, ret;
649
650 int dry_run = 1;
651 int partition;
652 char *device;
653
654 CHECK(nargs != 4, "Usage: mmc write_reliability set <-y|-n> "
655 "<partition> </path/to/mmcblkX>\n", exit(1));
656
657 if (!strcmp("-y", argv[1]))
658 dry_run = 0;
659
660 partition = strtol(argv[2], NULL, 10);
661 device = argv[3];
662
663 fd = open(device, O_RDWR);
664 if (fd < 0) {
665 perror("open");
666 exit(1);
667 }
668
669 ret = read_extcsd(fd, ext_csd);
670 if (ret) {
671 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
672 exit(1);
673 }
674
675 /* assert not PARTITION_SETTING_COMPLETED */
676 if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
677 {
678 printf(" Device is already partitioned\n");
679 exit(1);
680 }
681
682 /* assert HS_CTRL_REL */
683 if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & HS_CTRL_REL)) {
684 printf("Cannot set write reliability parameters, WR_REL_SET is "
685 "read-only\n");
686 exit(1);
687 }
688
689 value = ext_csd[EXT_CSD_WR_REL_SET] | (1<<partition);
690 ret = write_extcsd_value(fd, EXT_CSD_WR_REL_SET, value);
691 if (ret) {
692 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
693 value, EXT_CSD_WR_REL_SET, device);
694 exit(1);
695 }
696
697 printf("Done setting EXT_CSD_WR_REL_SET to 0x%02x on %s\n",
698 value, device);
699
700 if (!set_partitioning_setting_completed(dry_run, device, fd))
701 exit(1);
702
703 return 0;
704}
705
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500706int do_read_extcsd(int nargs, char **argv)
707{
Nick Sanders9d57aa72014-03-05 21:38:54 -0800708 __u8 ext_csd[EXT_CSD_SIZE], ext_csd_rev, reg;
Oliver Metz11f2cea2013-09-23 08:40:52 +0200709 __u32 regl;
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500710 int fd, ret;
711 char *device;
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100712 const char *str;
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800713 const char *ver_str[] = {
714 "4.0", /* 0 */
715 "4.1", /* 1 */
716 "4.2", /* 2 */
717 "4.3", /* 3 */
718 "Obsolete", /* 4 */
719 "4.41", /* 5 */
720 "4.5", /* 6 */
721 "5.0", /* 7 */
722 };
723 int boot_access;
724 const char* boot_access_str[] = {
725 "No access to boot partition", /* 0 */
726 "R/W Boot Partition 1", /* 1 */
727 "R/W Boot Partition 2", /* 2 */
728 "R/W Replay Protected Memory Block (RPMB)", /* 3 */
729 };
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500730
Chris Ball8ba44662012-04-19 13:22:54 -0400731 CHECK(nargs != 2, "Usage: mmc extcsd read </path/to/mmcblkX>\n",
732 exit(1));
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500733
734 device = argv[1];
735
736 fd = open(device, O_RDWR);
737 if (fd < 0) {
738 perror("open");
739 exit(1);
740 }
741
742 ret = read_extcsd(fd, ext_csd);
743 if (ret) {
744 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
745 exit(1);
746 }
747
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100748 ext_csd_rev = ext_csd[192];
749
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800750 if ((ext_csd_rev < sizeof(ver_str)/sizeof(char*)) &&
751 (ext_csd_rev != 4))
752 str = ver_str[ext_csd_rev];
753 else
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100754 goto out_free;
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800755
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100756 printf("=============================================\n");
757 printf(" Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
758 printf("=============================================\n\n");
759
760 if (ext_csd_rev < 3)
761 goto out_free; /* No ext_csd */
762
763 /* Parse the Extended CSD registers.
764 * Reserved bit should be read as "0" in case of spec older
765 * than A441.
766 */
767 reg = ext_csd[EXT_CSD_S_CMD_SET];
768 printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg);
769 if (!reg)
Chris Ballb9c7a172012-02-20 12:34:25 -0500770 printf(" - Standard MMC command sets\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100771
772 reg = ext_csd[EXT_CSD_HPI_FEATURE];
773 printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg);
774 if (reg & EXT_CSD_HPI_SUPP) {
775 if (reg & EXT_CSD_HPI_IMPL)
Chris Ballb9c7a172012-02-20 12:34:25 -0500776 printf("implementation based on CMD12\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100777 else
778 printf("implementation based on CMD13\n");
779 }
780
781 printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n",
782 ext_csd[502]);
783
784 if (ext_csd_rev >= 6) {
785 printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n",
786 ext_csd[501]);
787 printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n",
788 ext_csd[500]);
789 printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n",
790 ext_csd[499]);
791
792 printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n",
793 ext_csd[498]);
794 printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n",
795 ext_csd[497]);
796 printf("Context Management Capabilities"
797 " [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]);
798 printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n",
799 ext_csd[495]);
800 printf("Extended partition attribute support"
801 " [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800802 }
803 if (ext_csd_rev >= 7) {
804 int j;
805 int eol_info;
806 char* eol_info_str[] = {
807 "Not Defined", /* 0 */
808 "Normal", /* 1 */
809 "Warning", /* 2 */
810 "Urgent", /* 3 */
811 };
812
813 printf("Supported modes [SUPPORTED_MODES: 0x%02x]\n",
814 ext_csd[493]);
815 printf("FFU features [FFU_FEATURES: 0x%02x]\n",
816 ext_csd[492]);
817 printf("Operation codes timeout"
818 " [OPERATION_CODE_TIMEOUT: 0x%02x]\n",
819 ext_csd[491]);
820 printf("FFU Argument [FFU_ARG: 0x%08x]\n",
821 get_word_from_ext_csd(&ext_csd[487]));
822 printf("Number of FW sectors correctly programmed"
823 " [NUMBER_OF_FW_SECTORS_CORRECTLY_PROGRAMMED: %d]\n",
824 get_word_from_ext_csd(&ext_csd[302]));
825 printf("Vendor proprietary health report:\n");
826 for (j = 301; j >= 270; j--)
827 printf("[VENDOR_PROPRIETARY_HEALTH_REPORT[%d]]:"
828 " 0x%02x\n", j, ext_csd[j]);
829 for (j = 269; j >= 268; j--) {
830 __u8 life_used=ext_csd[j];
Puthikorn Voravootivat6bb37ea2014-03-03 17:55:51 -0800831 char est_type = 'B' + (j - 269);
832 printf("Device life time estimation type %c"
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800833 " [DEVICE_LIFE_TIME_EST_TYP_%c: 0x%02x]\n",
Puthikorn Voravootivat6bb37ea2014-03-03 17:55:51 -0800834 est_type, est_type, life_used);
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800835 if (life_used >= 0x1 && life_used <= 0xa)
836 printf(" i.e. %d%% - %d%% device life time"
837 " used\n",
838 (life_used - 1) * 10, life_used * 10);
839 else if (life_used == 0xb)
840 printf(" i.e. Exceeded its maximum estimated"
841 " device life time\n");
842 }
843 eol_info = ext_csd[267];
844 printf("Pre EOL information [PRE_EOL_INFO: 0x%02x]\n",
845 eol_info);
846 if (eol_info < sizeof(eol_info_str)/sizeof(char*))
847 printf(" i.e. %s\n", eol_info_str[eol_info]);
848 else
849 printf(" i.e. Reserved\n");
850
851 printf("Optimal read size [OPTIMAL_READ_SIZE: 0x%02x]\n",
852 ext_csd[266]);
853 printf("Optimal write size [OPTIMAL_WRITE_SIZE: 0x%02x]\n",
854 ext_csd[265]);
855 printf("Optimal trim unit size"
856 " [OPTIMAL_TRIM_UNIT_SIZE: 0x%02x]\n", ext_csd[264]);
857 printf("Device version [DEVICE_VERSION: 0x%02x - 0x%02x]\n",
858 ext_csd[263], ext_csd[262]);
859 printf("Firmware version:\n");
860 for (j = 261; j >= 254; j--)
861 printf("[FIRMWARE_VERSION[%d]]:"
862 " 0x%02x\n", j, ext_csd[j]);
863
864 printf("Power class for 200MHz, DDR at VCC= 3.6V"
865 " [PWR_CL_DDR_200_360: 0x%02x]\n", ext_csd[253]);
866 }
867 if (ext_csd_rev >= 6) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100868 printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n",
869 ext_csd[248]);
870 printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n",
871 ext_csd[247]);
872 printf("Cache Size [CACHE_SIZE] is %d KiB\n",
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -0800873 get_word_from_ext_csd(&ext_csd[249]));
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100874 }
875
876 /* A441: Reserved [501:247]
877 A43: reserved [246:229] */
878 if (ext_csd_rev >= 5) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100879 printf("Background operations status"
Chris Ballb9c7a172012-02-20 12:34:25 -0500880 " [BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100881
882 /* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */
883
884 printf("1st Initialisation Time after programmed sector"
885 " [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]);
886
887 /* A441: reserved [240] */
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100888 printf("Power class for 52MHz, DDR at 3.6V"
889 " [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]);
890 printf("Power class for 52MHz, DDR at 1.95V"
891 " [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]);
892
893 /* A441: reserved [237-236] */
894
895 if (ext_csd_rev >= 6) {
896 printf("Power class for 200MHz at 3.6V"
897 " [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]);
898 printf("Power class for 200MHz, at 1.95V"
899 " [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]);
900 }
Chris Ballb9c7a172012-02-20 12:34:25 -0500901 printf("Minimum Performance for 8bit at 52MHz in DDR mode:\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100902 printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]);
903 printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]);
904 /* A441: reserved [233] */
905 printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]);
906 printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n",
907 ext_csd[231]);
908 }
909 if (ext_csd_rev == 5) { /* Obsolete in 4.5 */
910 printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n",
911 ext_csd[230]);
912 printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n",
913 ext_csd[229]);
914 }
915 reg = ext_csd[EXT_CSD_BOOT_INFO];
916 printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg);
917 if (reg & EXT_CSD_BOOT_INFO_ALT)
918 printf(" Device supports alternative boot method\n");
919 if (reg & EXT_CSD_BOOT_INFO_DDR_DDR)
920 printf(" Device supports dual data rate during boot\n");
921 if (reg & EXT_CSD_BOOT_INFO_HS_MODE)
922 printf(" Device supports high speed timing during boot\n");
923
924 /* A441/A43: reserved [227] */
925 printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]);
926 printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]);
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400927
928 reg = get_hc_erase_grp_size(ext_csd);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100929 printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400930 reg);
931 printf(" i.e. %u KiB\n", 512 * reg);
932
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100933 printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n",
934 ext_csd[223]);
935 printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n",
936 ext_csd[222]);
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400937
938 reg = get_hc_wp_grp_size(ext_csd);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100939 printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400940 reg);
941 printf(" i.e. %lu KiB\n", 512l * get_hc_erase_grp_size(ext_csd) * reg);
942
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100943 printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]);
944 printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]);
945 /* A441/A43: reserved [218] */
946 printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]);
947 /* A441/A43: reserved [216] */
Ben Gardiner4e850232013-05-30 17:12:49 -0400948
949 unsigned int sectors = get_sector_count(ext_csd);
950 printf("Sector Count [SEC_COUNT: 0x%08x]\n", sectors);
951 if (is_blockaddresed(ext_csd))
952 printf(" Device is block-addressed\n");
953 else
954 printf(" Device is NOT block-addressed\n");
955
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100956 /* A441/A43: reserved [211] */
957 printf("Minimum Write Performance for 8bit:\n");
958 printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]);
959 printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]);
960 printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]);
961 printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]);
962 printf("Minimum Write Performance for 4bit:\n");
963 printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]);
964 printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]);
965 /* A441/A43: reserved [204] */
966 printf("Power classes registers:\n");
967 printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]);
968 printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]);
969 printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]);
970 printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]);
971
972 /* A43: reserved [199:198] */
973 if (ext_csd_rev >= 5) {
974 printf("Partition switching timing "
975 "[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]);
976 printf("Out-of-interrupt busy timing"
977 " [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]);
978 }
979
980 /* A441/A43: reserved [197] [195] [193] [190] [188]
981 * [186] [184] [182] [180] [176] */
982
983 if (ext_csd_rev >= 6)
984 printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n",
985 ext_csd[197]);
986
Oleg Matcovschi64f63a32013-05-23 17:11:07 -0700987 /* DEVICE_TYPE in A45, CARD_TYPE in A441 */
988 reg = ext_csd[196];
989 printf("Card Type [CARD_TYPE: 0x%02x]\n", reg);
990 if (reg & 0x20) printf(" HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n");
991 if (reg & 0x10) printf(" HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n");
992 if (reg & 0x08) printf(" HS Dual Data Rate eMMC @52MHz 1.2VI/O\n");
993 if (reg & 0x04) printf(" HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n");
994 if (reg & 0x02) printf(" HS eMMC @52MHz - at rated device voltage(s)\n");
995 if (reg & 0x01) printf(" HS eMMC @26MHz - at rated device voltage(s)\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100996
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100997 printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
998 /* ext_csd_rev = ext_csd[192] (already done!!!) */
999 printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]);
1000 printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]);
1001 printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]);
1002 printf("High-speed interface timing [HS_TIMING: 0x%02x]\n",
1003 ext_csd[185]);
1004 /* bus_width: ext_csd[183] not readable */
1005 printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n",
1006 ext_csd[181]);
1007 reg = ext_csd[EXT_CSD_BOOT_CFG];
1008 printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg);
Mario Schuknecht8c0c40d2013-05-15 08:28:04 +02001009 switch ((reg & EXT_CSD_BOOT_CFG_EN)>>3) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001010 case 0x0:
1011 printf(" Not boot enable\n");
1012 break;
1013 case 0x1:
1014 printf(" Boot Partition 1 enabled\n");
1015 break;
1016 case 0x2:
1017 printf(" Boot Partition 2 enabled\n");
1018 break;
1019 case 0x7:
1020 printf(" User Area Enabled for boot\n");
1021 break;
1022 }
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -08001023 boot_access = reg & EXT_CSD_BOOT_CFG_ACC;
1024 if (boot_access < sizeof(boot_access_str) / sizeof(char*))
1025 printf(" %s\n", boot_access_str[boot_access]);
1026 else
Mario Schuknecht8c0c40d2013-05-15 08:28:04 +02001027 printf(" Access to General Purpose partition %d\n",
Gwendal Grignou9b8d99c2014-01-28 13:48:05 -08001028 boot_access - 3);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001029
1030 printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
1031 ext_csd[178]);
1032 printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n",
1033 ext_csd[177]);
1034 printf("High-density erase group definition"
Ben Gardinerd91d3692013-05-30 17:12:51 -04001035 " [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[EXT_CSD_ERASE_GROUP_DEF]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001036
Chris Ballb9c7a172012-02-20 12:34:25 -05001037 print_writeprotect_status(ext_csd);
1038
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001039 if (ext_csd_rev >= 5) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001040 /* A441]: reserved [172] */
1041 printf("User area write protection register"
1042 " [USER_WP]: 0x%02x\n", ext_csd[171]);
1043 /* A441]: reserved [170] */
1044 printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]);
1045 printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]);
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001046
1047 reg = ext_csd[EXT_CSD_WR_REL_SET];
1048 const char * const fast = "existing data is at risk if a power "
1049 "failure occurs during a write operation";
1050 const char * const reliable = "the device protects existing "
1051 "data if a power failure occurs during a write "
1052 "operation";
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001053 printf("Write reliability setting register"
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001054 " [WR_REL_SET]: 0x%02x\n", reg);
1055
1056 printf(" user area: %s\n", reg & (1<<0) ? reliable : fast);
1057 int i;
1058 for (i = 1; i <= 4; i++) {
1059 printf(" partition %d: %s\n", i,
1060 reg & (1<<i) ? reliable : fast);
1061 }
1062
1063 reg = ext_csd[EXT_CSD_WR_REL_PARAM];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001064 printf("Write reliability parameter register"
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001065 " [WR_REL_PARAM]: 0x%02x\n", reg);
1066 if (reg & 0x01)
1067 printf(" Device supports writing EXT_CSD_WR_REL_SET\n");
1068 if (reg & 0x04)
1069 printf(" Device supports the enhanced def. of reliable "
1070 "write\n");
1071
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001072 /* sanitize_start ext_csd[165]]: not readable
1073 * bkops_start ext_csd[164]]: only writable */
1074 printf("Enable background operations handshake"
1075 " [BKOPS_EN]: 0x%02x\n", ext_csd[163]);
1076 printf("H/W reset function"
1077 " [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]);
1078 printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]);
Ben Gardiner82bd9502013-06-27 11:04:10 -04001079 reg = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001080 printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
1081 reg);
Ben Gardiner82bd9502013-06-27 11:04:10 -04001082 if (reg & EXT_CSD_PARTITIONING_EN)
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001083 printf(" Device support partitioning feature\n");
1084 else
1085 printf(" Device NOT support partitioning feature\n");
Ben Gardiner82bd9502013-06-27 11:04:10 -04001086 if (reg & EXT_CSD_ENH_ATTRIBUTE_EN)
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001087 printf(" Device can have enhanced tech.\n");
1088 else
1089 printf(" Device cannot have enhanced tech.\n");
1090
Oliver Metz11f2cea2013-09-23 08:40:52 +02001091 regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
Oliver Metz22f26412013-09-23 08:40:51 +02001092 (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
1093 ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
1094
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001095 printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
Oliver Metz11f2cea2013-09-23 08:40:52 +02001096 regl);
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001097 unsigned int wp_sz = get_hc_wp_grp_size(ext_csd);
1098 unsigned int erase_sz = get_hc_erase_grp_size(ext_csd);
Oliver Metz11f2cea2013-09-23 08:40:52 +02001099 printf(" i.e. %lu KiB\n", 512l * regl * wp_sz * erase_sz);
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001100
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001101 printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
Ben Gardinerd91d3692013-05-30 17:12:51 -04001102 ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]);
Ben Gardinera6cd98d2013-05-30 17:12:46 -04001103 reg = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001104 printf("Partitioning Setting"
1105 " [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
Ben Gardinera6cd98d2013-05-30 17:12:46 -04001106 reg);
1107 if (reg)
1108 printf(" Device partition setting complete\n");
1109 else
1110 printf(" Device partition setting NOT complete\n");
1111
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001112 printf("General Purpose Partition Size\n"
1113 " [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) |
1114 (ext_csd[153] << 8) | ext_csd[152]);
1115 printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) |
1116 (ext_csd[150] << 8) | ext_csd[149]);
1117 printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) |
1118 (ext_csd[147] << 8) | ext_csd[146]);
1119 printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) |
1120 (ext_csd[144] << 8) | ext_csd[143]);
1121
Oliver Metz11f2cea2013-09-23 08:40:52 +02001122 regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001123 (ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
1124 ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001125 printf("Enhanced User Data Area Size"
Oliver Metz11f2cea2013-09-23 08:40:52 +02001126 " [ENH_SIZE_MULT]: 0x%06x\n", regl);
1127 printf(" i.e. %lu KiB\n", 512l * regl *
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001128 get_hc_erase_grp_size(ext_csd) *
1129 get_hc_wp_grp_size(ext_csd));
Ben Gardiner68f490b2013-05-30 17:12:48 -04001130
Oliver Metz11f2cea2013-09-23 08:40:52 +02001131 regl = (ext_csd[EXT_CSD_ENH_START_ADDR_3] << 24) |
Ben Gardiner68f490b2013-05-30 17:12:48 -04001132 (ext_csd[EXT_CSD_ENH_START_ADDR_2] << 16) |
1133 (ext_csd[EXT_CSD_ENH_START_ADDR_1] << 8) |
1134 ext_csd[EXT_CSD_ENH_START_ADDR_0];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001135 printf("Enhanced User Data Start Address"
Oliver Metz11f2cea2013-09-23 08:40:52 +02001136 " [ENH_START_ADDR]: 0x%06x\n", regl);
Ben Gardiner4e850232013-05-30 17:12:49 -04001137 printf(" i.e. %lu bytes offset\n", (is_blockaddresed(ext_csd) ?
Oliver Metz11f2cea2013-09-23 08:40:52 +02001138 1l : 512l) * regl);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001139
1140 /* A441]: reserved [135] */
1141 printf("Bad Block Management mode"
1142 " [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]);
1143 /* A441: reserved [133:0] */
1144 }
1145 /* B45 */
1146 if (ext_csd_rev >= 6) {
1147 int j;
1148 /* tcase_support ext_csd[132] not readable */
1149 printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n",
1150 ext_csd[131]);
1151 printf("Program CID/CSD in DDR mode support"
1152 " [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n",
1153 ext_csd[130]);
1154
1155 for (j = 127; j >= 64; j--)
1156 printf("Vendor Specific Fields"
1157 " [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n",
1158 j, ext_csd[j]);
1159
Gwendal Grignoue966e672014-07-07 14:03:13 -07001160 reg = ext_csd[63];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001161 printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n",
Gwendal Grignoue966e672014-07-07 14:03:13 -07001162 reg);
1163 if (reg == 0x00)
1164 printf(" i.e. 512 B\n");
1165 else if (reg == 0x01)
1166 printf(" i.e. 4 KiB\n");
1167 else
1168 printf(" i.e. Reserved\n");
1169
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001170 printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n",
1171 ext_csd[62]);
Gwendal Grignoue966e672014-07-07 14:03:13 -07001172 reg = ext_csd[61];
1173 printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", reg);
1174 if (reg == 0x00)
1175 printf(" i.e. 512 B\n");
1176 else if (reg == 0x01)
1177 printf(" i.e. 4 KiB\n");
1178 else
1179 printf(" i.e. Reserved\n");
1180
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001181 printf("1st initialization after disabling sector"
1182 " size emulation [INI_TIMEOUT_EMU]: 0x%02x\n",
1183 ext_csd[60]);
1184 printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n",
1185 ext_csd[59]);
1186 printf("Number of addressed group to be Released"
1187 "[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]);
1188 printf("Exception events control"
1189 " [EXCEPTION_EVENTS_CTRL]: 0x%04x\n",
1190 (ext_csd[57] << 8) | ext_csd[56]);
1191 printf("Exception events status"
1192 "[EXCEPTION_EVENTS_STATUS]: 0x%04x\n",
1193 (ext_csd[55] << 8) | ext_csd[54]);
1194 printf("Extended Partitions Attribute"
1195 " [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n",
1196 (ext_csd[53] << 8) | ext_csd[52]);
1197
1198 for (j = 51; j >= 37; j--)
1199 printf("Context configuration"
1200 " [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]);
1201
1202 printf("Packed command status"
1203 " [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]);
1204 printf("Packed command failure index"
1205 " [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]);
1206 printf("Power Off Notification"
1207 " [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]);
Oleg Matcovschi64f63a32013-05-23 17:11:07 -07001208 printf("Control to turn the Cache ON/OFF"
1209 " [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001210 /* flush_cache ext_csd[32] not readable */
1211 /*Reserved [31:0] */
1212 }
Gwendal Grignoue966e672014-07-07 14:03:13 -07001213 if (ext_csd_rev >= 7) {
1214 printf("Mode config [MODE_CONFIG: 0x%02x]\n", ext_csd[30]);
1215 printf("Mode operation codes [MODE_OPERATION_CODES: 0x%02x]\n",
1216 ext_csd[29]);
1217
1218 reg = ext_csd[26];
1219 printf("FFU status [FFU_STATUS: 0x%02x]\n", reg);
1220 switch (reg) {
1221 case 0x00:
1222 printf(" Success\n");
1223 break;
1224 case 0x10:
1225 printf(" General error\n");
1226 break;
1227 case 0x11:
1228 printf(" Firmware install error\n");
1229 break;
1230 case 0x12:
1231 printf(" Error in downloading firmware\n");
1232 break;
1233 default:
1234 printf(" Reserved\n");
1235 }
1236 printf("Pre loading data size [PRE_LOADING_DATA_SIZE] is"
1237 " %d sector size\n",
1238 get_word_from_ext_csd(&ext_csd[22]));
1239 printf("Max pre loading data size [MAX_PRE_LOADING_DATA_SIZE] is"
1240 " %d sector size\n",
1241 get_word_from_ext_csd(&ext_csd[18]));
1242 printf("Product state awareness enablement"
1243 " [PRODUCT_STATE_AWARENESS_ENABLEMENT: 0x%02x]\n",
1244 ext_csd[17]);
1245 printf("Secure Removal Type [SECURE_REMOVAL_TYPE: 0x%02x]\n",
1246 ext_csd[16]);
1247 }
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001248
1249out_free:
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -05001250 return ret;
1251}
Yaniv Gardi21bb4732013-05-26 13:25:33 -04001252
Nick Sanders9d57aa72014-03-05 21:38:54 -08001253int do_dump_extcsd(int nargs, char **argv)
1254{
1255 __u8 ext_csd[EXT_CSD_SIZE];
1256 int fd, ret;
1257 char *device;
1258 int i, j;
1259
1260 CHECK(nargs != 2, "Usage: mmc extcsd dump </path/to/mmcblkX>\n",
1261 exit(1));
1262
1263 device = argv[1];
1264
1265 fd = open(device, O_RDWR);
1266 if (fd < 0) {
1267 perror("Failed to open mmc device");
1268 exit(1);
1269 }
1270
1271 ret = read_extcsd(fd, ext_csd);
1272 if (ret) {
1273 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
1274 exit(1);
1275 }
1276
1277 /* Dump all bytes so that any undecoded or proprietary registers */
1278 /* can be acessed. */
1279 printf("EXT_CSD binary dump:\n");
1280 for (i = 0; i < EXT_CSD_SIZE; i+= 16) {
1281 printf(" %3d: %3x: ", i, i);
1282 for (j = 0; (j < 16) && (i + j < EXT_CSD_SIZE); j++) {
1283 printf(" %02x", ext_csd[i+j]);
1284 }
1285 printf("\n");
1286 }
1287
1288 return ret;
1289}
1290
Yaniv Gardi21bb4732013-05-26 13:25:33 -04001291int do_sanitize(int nargs, char **argv)
1292{
1293 int fd, ret;
1294 char *device;
1295
1296 CHECK(nargs != 2, "Usage: mmc sanitize </path/to/mmcblkX>\n",
1297 exit(1));
1298
1299 device = argv[1];
1300
1301 fd = open(device, O_RDWR);
1302 if (fd < 0) {
1303 perror("open");
1304 exit(1);
1305 }
1306
1307 ret = write_extcsd_value(fd, EXT_CSD_SANITIZE_START, 1);
1308 if (ret) {
1309 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
1310 1, EXT_CSD_SANITIZE_START, device);
1311 exit(1);
1312 }
1313
1314 return ret;
1315
1316}
1317