Decode EXT_CSD of eMMC 5.0 device
Display new attributes in Extended CSD register introduced by eMMC 5.0:
'mmc extcsd read /dev/mmcblk0' returns for eMMC 5.0 device:
=============================================
Extended CSD rev 1.7 (MMC 5.0)
=============================================
Card Supported Command sets [S_CMD_SET: 0x01]
...
Extended partition attribute support [EXT_SUPPORT: 0x03]
Supported modes [SUPPORTED_MODES: 0x01]
FFU features [FFU_FEATURES: 0x00]
Operation codes timeout [OPERATION_CODE_TIMEOUT: 0x00]
FFU Argument [FFU_ARG: 0x00000000]
Number of FW sectors correctly programmed [NUMBER_OF_FW_SECTORS_CORRECTLY_PROGRAMMED: 0]
Vendor proprietary health report:
[VENDOR_PROPRIETARY_HEALTH_REPORT[301]]: 0x00
...
[VENDOR_PROPRIETARY_HEALTH_REPORT[270]]: 0x00
Device life time estimation type B [DEVICE_LIFE_TIME_EST_TYP_B: 0x01]
i.e. 0% - 10% device life time used
Device life time estimation type B [DEVICE_LIFE_TIME_EST_TYP_A: 0x01]
i.e. 0% - 10% device life time used
Pre EOL information [PRE_EOL_INFO: 0x01]
i.e. Normal
Optimal read size [OPTIMAL_READ_SIZE: 0x00]
Optimal write size [OPTIMAL_WRITE_SIZE: 0x10]
Optimal trim unit size [OPTIMAL_TRIM_UNIT_SIZE: 0x01]
Device version [DEVICE_VERSION: 0x00 - 0x00]
Firmware version:
[FIRMWARE_VERSION[261]]: 0x00
...
[FIRMWARE_VERSION[254]]: 0x05
Power class for 200MHz, DDR at VCC= 3.6V [PWR_CL_DDR_200_360: 0x00]
Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x0a]
Power off notification [POWER_OFF_LONG_TIME: 0x3c]
Cache Size [CACHE_SIZE] is 65536 KiB
...
BUG=None
TEST=No impact on pre eMMC 5.0 device
TEST=Decode properly a 5.0 device.
Change-Id: Iac7c6ca672b5932cd4bd25943e4ec8d9690bd2bc
Reviewed-on: https://chromium-review.googlesource.com/184175
Reviewed-by: Grant Grundler <grundler@chromium.org>
Tested-by: Gwendal Grignou <gwendal@chromium.org>
Commit-Queue: Gwendal Grignou <gwendal@chromium.org>
diff --git a/mmc_cmds.c b/mmc_cmds.c
index b8afa74..4b9b12e 100644
--- a/mmc_cmds.c
+++ b/mmc_cmds.c
@@ -424,12 +424,17 @@
return ret;
}
+__u32 get_word_from_ext_csd(__u8 *ext_csd_loc)
+{
+ return (ext_csd_loc[3] << 24) |
+ (ext_csd_loc[2] << 16) |
+ (ext_csd_loc[1] << 8) |
+ ext_csd_loc[0];
+}
+
unsigned int get_sector_count(__u8 *ext_csd)
{
- return (ext_csd[EXT_CSD_SEC_COUNT_3] << 24) |
- (ext_csd[EXT_CSD_SEC_COUNT_2] << 16) |
- (ext_csd[EXT_CSD_SEC_COUNT_1] << 8) |
- ext_csd[EXT_CSD_SEC_COUNT_0];
+ return get_word_from_ext_csd(&ext_csd[EXT_CSD_SEC_COUNT_0]);
}
int is_blockaddresed(__u8 *ext_csd)
@@ -701,6 +706,23 @@
int fd, ret;
char *device;
const char *str;
+ const char *ver_str[] = {
+ "4.0", /* 0 */
+ "4.1", /* 1 */
+ "4.2", /* 2 */
+ "4.3", /* 3 */
+ "Obsolete", /* 4 */
+ "4.41", /* 5 */
+ "4.5", /* 6 */
+ "5.0", /* 7 */
+ };
+ int boot_access;
+ const char* boot_access_str[] = {
+ "No access to boot partition", /* 0 */
+ "R/W Boot Partition 1", /* 1 */
+ "R/W Boot Partition 2", /* 2 */
+ "R/W Replay Protected Memory Block (RPMB)", /* 3 */
+ };
CHECK(nargs != 2, "Usage: mmc extcsd read </path/to/mmcblkX>\n",
exit(1));
@@ -721,28 +743,12 @@
ext_csd_rev = ext_csd[192];
- switch (ext_csd_rev) {
- case 6:
- str = "4.5";
- break;
- case 5:
- str = "4.41";
- break;
- case 3:
- str = "4.3";
- break;
- case 2:
- str = "4.2";
- break;
- case 1:
- str = "4.1";
- break;
- case 0:
- str = "4.0";
- break;
- default:
+ if ((ext_csd_rev < sizeof(ver_str)/sizeof(char*)) &&
+ (ext_csd_rev != 4))
+ str = ver_str[ext_csd_rev];
+ else
goto out_free;
- }
+
printf("=============================================\n");
printf(" Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
printf("=============================================\n\n");
@@ -789,13 +795,77 @@
ext_csd[495]);
printf("Extended partition attribute support"
" [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
+ }
+ if (ext_csd_rev >= 7) {
+ int j;
+ int eol_info;
+ char* eol_info_str[] = {
+ "Not Defined", /* 0 */
+ "Normal", /* 1 */
+ "Warning", /* 2 */
+ "Urgent", /* 3 */
+ };
+
+ printf("Supported modes [SUPPORTED_MODES: 0x%02x]\n",
+ ext_csd[493]);
+ printf("FFU features [FFU_FEATURES: 0x%02x]\n",
+ ext_csd[492]);
+ printf("Operation codes timeout"
+ " [OPERATION_CODE_TIMEOUT: 0x%02x]\n",
+ ext_csd[491]);
+ printf("FFU Argument [FFU_ARG: 0x%08x]\n",
+ get_word_from_ext_csd(&ext_csd[487]));
+ printf("Number of FW sectors correctly programmed"
+ " [NUMBER_OF_FW_SECTORS_CORRECTLY_PROGRAMMED: %d]\n",
+ get_word_from_ext_csd(&ext_csd[302]));
+ printf("Vendor proprietary health report:\n");
+ for (j = 301; j >= 270; j--)
+ printf("[VENDOR_PROPRIETARY_HEALTH_REPORT[%d]]:"
+ " 0x%02x\n", j, ext_csd[j]);
+ for (j = 269; j >= 268; j--) {
+ __u8 life_used=ext_csd[j];
+ printf("Device life time estimation type B"
+ " [DEVICE_LIFE_TIME_EST_TYP_%c: 0x%02x]\n",
+ 'B' + (j - 269), life_used);
+ if (life_used >= 0x1 && life_used <= 0xa)
+ printf(" i.e. %d%% - %d%% device life time"
+ " used\n",
+ (life_used - 1) * 10, life_used * 10);
+ else if (life_used == 0xb)
+ printf(" i.e. Exceeded its maximum estimated"
+ " device life time\n");
+ }
+ eol_info = ext_csd[267];
+ printf("Pre EOL information [PRE_EOL_INFO: 0x%02x]\n",
+ eol_info);
+ if (eol_info < sizeof(eol_info_str)/sizeof(char*))
+ printf(" i.e. %s\n", eol_info_str[eol_info]);
+ else
+ printf(" i.e. Reserved\n");
+
+ printf("Optimal read size [OPTIMAL_READ_SIZE: 0x%02x]\n",
+ ext_csd[266]);
+ printf("Optimal write size [OPTIMAL_WRITE_SIZE: 0x%02x]\n",
+ ext_csd[265]);
+ printf("Optimal trim unit size"
+ " [OPTIMAL_TRIM_UNIT_SIZE: 0x%02x]\n", ext_csd[264]);
+ printf("Device version [DEVICE_VERSION: 0x%02x - 0x%02x]\n",
+ ext_csd[263], ext_csd[262]);
+ printf("Firmware version:\n");
+ for (j = 261; j >= 254; j--)
+ printf("[FIRMWARE_VERSION[%d]]:"
+ " 0x%02x\n", j, ext_csd[j]);
+
+ printf("Power class for 200MHz, DDR at VCC= 3.6V"
+ " [PWR_CL_DDR_200_360: 0x%02x]\n", ext_csd[253]);
+ }
+ if (ext_csd_rev >= 6) {
printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n",
ext_csd[248]);
printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n",
ext_csd[247]);
printf("Cache Size [CACHE_SIZE] is %d KiB\n",
- ext_csd[249] << 0 | (ext_csd[250] << 8) |
- (ext_csd[251] << 16) | (ext_csd[252] << 24));
+ get_word_from_ext_csd(&ext_csd[249]));
}
/* A441: Reserved [501:247]
@@ -945,24 +1015,12 @@
printf(" User Area Enabled for boot\n");
break;
}
- switch (reg & EXT_CSD_BOOT_CFG_ACC) {
- case 0x0:
- printf(" No access to boot partition\n");
- break;
- case 0x1:
- printf(" R/W Boot Partition 1\n");
- break;
- case 0x2:
- printf(" R/W Boot Partition 2\n");
- break;
- case 0x3:
- printf(" R/W Replay Protected Memory Block (RPMB)\n");
- break;
- default:
+ boot_access = reg & EXT_CSD_BOOT_CFG_ACC;
+ if (boot_access < sizeof(boot_access_str) / sizeof(char*))
+ printf(" %s\n", boot_access_str[boot_access]);
+ else
printf(" Access to General Purpose partition %d\n",
- (reg & EXT_CSD_BOOT_CFG_ACC) - 3);
- break;
- }
+ boot_access - 3);
printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
ext_csd[178]);