blob: 36731e22eaedb4a920a25f613369accb46652b18 [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
75int do_read_extcsd(int nargs, char **argv)
76{
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +010077 __u8 ext_csd[512], ext_csd_rev, reg;
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050078 int fd, ret;
79 char *device;
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +010080 const char *str;
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050081
82 CHECK(nargs != 2, "Usage: mmc </path/to/mmcblkX>\n", exit(1));
83
84 device = argv[1];
85
86 fd = open(device, O_RDWR);
87 if (fd < 0) {
88 perror("open");
89 exit(1);
90 }
91
92 ret = read_extcsd(fd, ext_csd);
93 if (ret) {
94 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
95 exit(1);
96 }
97
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +010098 ext_csd_rev = ext_csd[192];
99
100 switch (ext_csd_rev) {
101 case 6:
102 str = "4.5";
103 break;
104 case 5:
105 str = "4.41";
106 break;
107 case 3:
108 str = "4.3";
109 break;
110 case 2:
111 str = "4.2";
112 break;
113 case 1:
114 str = "4.1";
115 break;
116 case 0:
117 str = "4.0";
118 break;
119 default:
120 goto out_free;
121 }
122 printf("=============================================\n");
123 printf(" Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
124 printf("=============================================\n\n");
125
126 if (ext_csd_rev < 3)
127 goto out_free; /* No ext_csd */
128
129 /* Parse the Extended CSD registers.
130 * Reserved bit should be read as "0" in case of spec older
131 * than A441.
132 */
133 reg = ext_csd[EXT_CSD_S_CMD_SET];
134 printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg);
135 if (!reg)
136 printf(" - Standard MMC coomand sets\n");
137
138 reg = ext_csd[EXT_CSD_HPI_FEATURE];
139 printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg);
140 if (reg & EXT_CSD_HPI_SUPP) {
141 if (reg & EXT_CSD_HPI_IMPL)
142 printf("implementationbased on CMD12\n");
143 else
144 printf("implementation based on CMD13\n");
145 }
146
147 printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n",
148 ext_csd[502]);
149
150 if (ext_csd_rev >= 6) {
151 printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n",
152 ext_csd[501]);
153 printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n",
154 ext_csd[500]);
155 printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n",
156 ext_csd[499]);
157
158 printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n",
159 ext_csd[498]);
160 printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n",
161 ext_csd[497]);
162 printf("Context Management Capabilities"
163 " [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]);
164 printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n",
165 ext_csd[495]);
166 printf("Extended partition attribute support"
167 " [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
168 printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n",
169 ext_csd[248]);
170 printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n",
171 ext_csd[247]);
172 printf("Cache Size [CACHE_SIZE] is %d KiB\n",
173 ext_csd[249] << 0 | (ext_csd[250] << 8) |
174 (ext_csd[251] << 16) | (ext_csd[252] << 24));
175 }
176
177 /* A441: Reserved [501:247]
178 A43: reserved [246:229] */
179 if (ext_csd_rev >= 5) {
180
181 printf("Background operations status"
182 "[BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
183
184 /* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */
185
186 printf("1st Initialisation Time after programmed sector"
187 " [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]);
188
189 /* A441: reserved [240] */
190
191 printf("Power class for 52MHz, DDR at 3.6V"
192 " [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]);
193 printf("Power class for 52MHz, DDR at 1.95V"
194 " [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]);
195
196 /* A441: reserved [237-236] */
197
198 if (ext_csd_rev >= 6) {
199 printf("Power class for 200MHz at 3.6V"
200 " [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]);
201 printf("Power class for 200MHz, at 1.95V"
202 " [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]);
203 }
204 printf("Minimum Performances for 8bit at 52MHz in DDR mode:\n");
205 printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]);
206 printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]);
207 /* A441: reserved [233] */
208 printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]);
209 printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n",
210 ext_csd[231]);
211 }
212 if (ext_csd_rev == 5) { /* Obsolete in 4.5 */
213 printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n",
214 ext_csd[230]);
215 printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n",
216 ext_csd[229]);
217 }
218 reg = ext_csd[EXT_CSD_BOOT_INFO];
219 printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg);
220 if (reg & EXT_CSD_BOOT_INFO_ALT)
221 printf(" Device supports alternative boot method\n");
222 if (reg & EXT_CSD_BOOT_INFO_DDR_DDR)
223 printf(" Device supports dual data rate during boot\n");
224 if (reg & EXT_CSD_BOOT_INFO_HS_MODE)
225 printf(" Device supports high speed timing during boot\n");
226
227 /* A441/A43: reserved [227] */
228 printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]);
229 printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]);
230 printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
231 ext_csd[224]);
232 printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n",
233 ext_csd[223]);
234 printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n",
235 ext_csd[222]);
236 printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
237 ext_csd[221]);
238 printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]);
239 printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]);
240 /* A441/A43: reserved [218] */
241 printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]);
242 /* A441/A43: reserved [216] */
243 printf("Sector Count [SEC_COUNT: 0x%08x]\n", (ext_csd[215] << 24) |
244 (ext_csd[214] << 16) | (ext_csd[213] << 8) |
245 ext_csd[212]);
246 /* A441/A43: reserved [211] */
247 printf("Minimum Write Performance for 8bit:\n");
248 printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]);
249 printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]);
250 printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]);
251 printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]);
252 printf("Minimum Write Performance for 4bit:\n");
253 printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]);
254 printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]);
255 /* A441/A43: reserved [204] */
256 printf("Power classes registers:\n");
257 printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]);
258 printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]);
259 printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]);
260 printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]);
261
262 /* A43: reserved [199:198] */
263 if (ext_csd_rev >= 5) {
264 printf("Partition switching timing "
265 "[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]);
266 printf("Out-of-interrupt busy timing"
267 " [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]);
268 }
269
270 /* A441/A43: reserved [197] [195] [193] [190] [188]
271 * [186] [184] [182] [180] [176] */
272
273 if (ext_csd_rev >= 6)
274 printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n",
275 ext_csd[197]);
276
277 printf("Card Type [CARD_TYPE: 0x%02x]\n", ext_csd[196]);
278 /* DEVICE_TYPE in A45 */
279 switch (reg) {
280 case 5:
281 printf("HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n");
282 break;
283 case 4:
284 printf("HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n");
285 break;
286 case 3:
287 printf("HS Dual Data Rate eMMC @52MHz 1.2VI/O\n");
288
289 break;
290 case 2:
291 printf("HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n");
292 break;
293 case 1:
294 printf("HS eMMC @52MHz - at rated device voltage(s)\n");
295 break;
296 case 0:
297 printf("HS eMMC @26MHz - at rated device voltage(s)\n");
298 break;
299 }
300 printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
301 /* ext_csd_rev = ext_csd[192] (already done!!!) */
302 printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]);
303 printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]);
304 printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]);
305 printf("High-speed interface timing [HS_TIMING: 0x%02x]\n",
306 ext_csd[185]);
307 /* bus_width: ext_csd[183] not readable */
308 printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n",
309 ext_csd[181]);
310 reg = ext_csd[EXT_CSD_BOOT_CFG];
311 printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg);
312 switch (reg & EXT_CSD_BOOT_CFG_EN) {
313 case 0x0:
314 printf(" Not boot enable\n");
315 break;
316 case 0x1:
317 printf(" Boot Partition 1 enabled\n");
318 break;
319 case 0x2:
320 printf(" Boot Partition 2 enabled\n");
321 break;
322 case 0x7:
323 printf(" User Area Enabled for boot\n");
324 break;
325 }
326 switch (reg & EXT_CSD_BOOT_CFG_ACC) {
327 case 0x0:
328 printf(" No access to boot partition\n");
329 break;
330 case 0x1:
331 printf(" R/W Boot Partition 1\n");
332 break;
333 case 0x2:
334 printf(" R/W Boot Partition 2\n");
335 break;
336 default:
337 printf(" Access to General Purpuse partition %d\n",
338 (reg & EXT_CSD_BOOT_CFG_ACC) - 3);
339 break;
340 }
341
342 printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
343 ext_csd[178]);
344 printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n",
345 ext_csd[177]);
346 printf("High-density erase group definition"
347 " [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[175]);
348
349 /* A43: reserved [174:0] */
350 if (ext_csd_rev >= 5) {
351 printf("Boot write protection status registers"
352 " [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]);
353
354 reg = ext_csd[EXT_CSD_BOOT_WP];
355 printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg);
356 printf(" Power ro locking: ");
357 if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
358 printf("not possible\n");
359 else
360 printf("possible\n");
361
362 printf(" Permanent ro locking: ");
363 if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
364 printf("not possible\n");
365 else
366 printf("possible\n");
367
368 printf(" ro lock status: ");
369 if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
370 printf("locked until next power on\n");
371 else if (reg &
372 EXT_CSD_BOOT_WP_B_PERM_WP_EN)
373 printf("locked permanently\n");
374 else
375 printf("not locked\n");
376
377 /* A441]: reserved [172] */
378 printf("User area write protection register"
379 " [USER_WP]: 0x%02x\n", ext_csd[171]);
380 /* A441]: reserved [170] */
381 printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]);
382 printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]);
383 printf("Write reliability setting register"
384 " [WR_REL_SET]: 0x%02x\n", ext_csd[167]);
385 printf("Write reliability parameter register"
386 " [WR_REL_PARAM]: 0x%02x\n", ext_csd[166]);
387 /* sanitize_start ext_csd[165]]: not readable
388 * bkops_start ext_csd[164]]: only writable */
389 printf("Enable background operations handshake"
390 " [BKOPS_EN]: 0x%02x\n", ext_csd[163]);
391 printf("H/W reset function"
392 " [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]);
393 printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]);
394 reg = ext_csd[160];
395 printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
396 reg);
397 if (reg & 0x1)
398 printf(" Device support partitioning feature\n");
399 else
400 printf(" Device NOT support partitioning feature\n");
401 if (reg & 0x2)
402 printf(" Device can have enhanced tech.\n");
403 else
404 printf(" Device cannot have enhanced tech.\n");
405
406 printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
407 (ext_csd[159] << 16) | (ext_csd[158] << 8) |
408 ext_csd[157]);
409 printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
410 ext_csd[156]);
411 printf("Partitioning Setting"
412 " [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
413 ext_csd[155]);
414 printf("General Purpose Partition Size\n"
415 " [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) |
416 (ext_csd[153] << 8) | ext_csd[152]);
417 printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) |
418 (ext_csd[150] << 8) | ext_csd[149]);
419 printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) |
420 (ext_csd[147] << 8) | ext_csd[146]);
421 printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) |
422 (ext_csd[144] << 8) | ext_csd[143]);
423
424 printf("Enhanced User Data Area Size"
425 " [ENH_SIZE_MULT]: 0x%06x\n", (ext_csd[142] << 16) |
426 (ext_csd[141] << 8) | ext_csd[140]);
427 printf("Enhanced User Data Start Address"
428 " [ENH_START_ADDR]: 0x%06x\n", (ext_csd[139] << 16) |
429 (ext_csd[138] << 8) | ext_csd[137]);
430
431 /* A441]: reserved [135] */
432 printf("Bad Block Management mode"
433 " [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]);
434 /* A441: reserved [133:0] */
435 }
436 /* B45 */
437 if (ext_csd_rev >= 6) {
438 int j;
439 /* tcase_support ext_csd[132] not readable */
440 printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n",
441 ext_csd[131]);
442 printf("Program CID/CSD in DDR mode support"
443 " [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n",
444 ext_csd[130]);
445
446 for (j = 127; j >= 64; j--)
447 printf("Vendor Specific Fields"
448 " [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n",
449 j, ext_csd[j]);
450
451 printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n",
452 ext_csd[63]);
453 printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n",
454 ext_csd[62]);
455 printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", ext_csd[61]);
456 printf("1st initialization after disabling sector"
457 " size emulation [INI_TIMEOUT_EMU]: 0x%02x\n",
458 ext_csd[60]);
459 printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n",
460 ext_csd[59]);
461 printf("Number of addressed group to be Released"
462 "[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]);
463 printf("Exception events control"
464 " [EXCEPTION_EVENTS_CTRL]: 0x%04x\n",
465 (ext_csd[57] << 8) | ext_csd[56]);
466 printf("Exception events status"
467 "[EXCEPTION_EVENTS_STATUS]: 0x%04x\n",
468 (ext_csd[55] << 8) | ext_csd[54]);
469 printf("Extended Partitions Attribute"
470 " [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n",
471 (ext_csd[53] << 8) | ext_csd[52]);
472
473 for (j = 51; j >= 37; j--)
474 printf("Context configuration"
475 " [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]);
476
477 printf("Packed command status"
478 " [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]);
479 printf("Packed command failure index"
480 " [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]);
481 printf("Power Off Notification"
482 " [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]);
483 printf("Control to turn the Cache ON/OFF"
484 " [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
485 /* flush_cache ext_csd[32] not readable */
486 /*Reserved [31:0] */
487 }
488
489out_free:
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500490
491 return ret;
492}
493
494int do_write_extcsd(int nargs, char **argv)
495{
496 __u8 ext_csd[512], value;
497 int fd, ret;
498 char *device;
499
500 if (nargs != 2) {
501 fprintf (stderr, "Usage: %s </path/to/mmcblkX>\n",
502 argv[0]);
503 exit (1);
504 }
505 device = argv[1];
506
507 fd = open(device, O_RDWR);
508 if (fd < 0) {
509 perror("open");
510 exit(1);
511 }
512
513 ret = read_extcsd(fd, ext_csd);
514 if (ret) {
515 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
516 exit(1);
517 }
518
519 value = ext_csd[EXT_CSD_BOOT_WP] |
520 EXT_CSD_BOOT_WP_B_PWR_WP_EN;
521 ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value);
522 if (ret) {
523 fprintf(stderr, "Could not write 0x%02x to "
524 "EXT_CSD[%d] in %s\n",
525 value, EXT_CSD_BOOT_WP, device);
526 exit(1);
527 }
528
529 return ret;
530}