summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mmc.h16
-rw-r--r--mmc_cmds.c415
2 files changed, 408 insertions, 23 deletions
diff --git a/mmc.h b/mmc.h
index 8540f3d..3af36f1 100644
--- a/mmc.h
+++ b/mmc.h
@@ -29,17 +29,29 @@
/*
* EXT_CSD fields
*/
-#define EXT_CSD_BOOT_WP 173 /* R/W */
-#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
+#define EXT_CSD_S_CMD_SET 504
+#define EXT_CSD_HPI_FEATURE 503
+#define EXT_CSD_BOOT_INFO 228 /* R/W */
+#define EXT_CSD_PART_SWITCH_TIME 199
+#define EXT_CSD_BOOT_CFG 179
+#define EXT_CSD_BOOT_WP 173
/*
* EXT_CSD field definitions
*/
+#define EXT_CSD_HPI_SUPP (1<<0)
+#define EXT_CSD_HPI_IMPL (1<<1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
+#define EXT_CSD_BOOT_INFO_HS_MODE (1<<2)
+#define EXT_CSD_BOOT_INFO_DDR_DDR (1<<1)
+#define EXT_CSD_BOOT_INFO_ALT (1<<0)
+#define EXT_CSD_BOOT_CFG_ACK (1<<6)
+#define EXT_CSD_BOOT_CFG_EN (0x38)
+#define EXT_CSD_BOOT_CFG_ACC (0x03)
/* From kernel linux/mmc/core.h */
#define MMC_RSP_PRESENT (1 << 0)
diff --git a/mmc_cmds.c b/mmc_cmds.c
index dce3ecc..36731e2 100644
--- a/mmc_cmds.c
+++ b/mmc_cmds.c
@@ -74,9 +74,10 @@ int write_extcsd_value(int fd, __u8 index, __u8 value)
int do_read_extcsd(int nargs, char **argv)
{
- __u8 ext_csd[512];
+ __u8 ext_csd[512], ext_csd_rev, reg;
int fd, ret;
char *device;
+ const char *str;
CHECK(nargs != 2, "Usage: mmc </path/to/mmcblkX>\n", exit(1));
@@ -94,26 +95,398 @@ int do_read_extcsd(int nargs, char **argv)
exit(1);
}
- printf("Power ro locking: ");
- if (ext_csd[EXT_CSD_BOOT_WP] & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
- printf("not possible\n");
- else
- printf("possible\n");
-
- printf("Permanent ro locking: ");
- if (ext_csd[EXT_CSD_BOOT_WP] & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
- printf("not possible\n");
- else
- printf("possible\n");
-
- printf("ro lock status: ");
- if (ext_csd[EXT_CSD_BOOT_WP] & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
- printf("locked until next power on\n");
- else if (ext_csd[EXT_CSD_BOOT_WP] &
- EXT_CSD_BOOT_WP_B_PERM_WP_EN)
- printf("locked permanently\n");
- else
- printf("not locked\n");
+ 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:
+ goto out_free;
+ }
+ printf("=============================================\n");
+ printf(" Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
+ printf("=============================================\n\n");
+
+ if (ext_csd_rev < 3)
+ goto out_free; /* No ext_csd */
+
+ /* Parse the Extended CSD registers.
+ * Reserved bit should be read as "0" in case of spec older
+ * than A441.
+ */
+ reg = ext_csd[EXT_CSD_S_CMD_SET];
+ printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg);
+ if (!reg)
+ printf(" - Standard MMC coomand sets\n");
+
+ reg = ext_csd[EXT_CSD_HPI_FEATURE];
+ printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg);
+ if (reg & EXT_CSD_HPI_SUPP) {
+ if (reg & EXT_CSD_HPI_IMPL)
+ printf("implementationbased on CMD12\n");
+ else
+ printf("implementation based on CMD13\n");
+ }
+
+ printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n",
+ ext_csd[502]);
+
+ if (ext_csd_rev >= 6) {
+ printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n",
+ ext_csd[501]);
+ printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n",
+ ext_csd[500]);
+ printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n",
+ ext_csd[499]);
+
+ printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n",
+ ext_csd[498]);
+ printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n",
+ ext_csd[497]);
+ printf("Context Management Capabilities"
+ " [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]);
+ printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n",
+ ext_csd[495]);
+ printf("Extended partition attribute support"
+ " [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
+ 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));
+ }
+
+ /* A441: Reserved [501:247]
+ A43: reserved [246:229] */
+ if (ext_csd_rev >= 5) {
+
+ printf("Background operations status"
+ "[BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
+
+ /* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */
+
+ printf("1st Initialisation Time after programmed sector"
+ " [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]);
+
+ /* A441: reserved [240] */
+
+ printf("Power class for 52MHz, DDR at 3.6V"
+ " [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]);
+ printf("Power class for 52MHz, DDR at 1.95V"
+ " [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]);
+
+ /* A441: reserved [237-236] */
+
+ if (ext_csd_rev >= 6) {
+ printf("Power class for 200MHz at 3.6V"
+ " [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]);
+ printf("Power class for 200MHz, at 1.95V"
+ " [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]);
+ }
+ printf("Minimum Performances for 8bit at 52MHz in DDR mode:\n");
+ printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]);
+ printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]);
+ /* A441: reserved [233] */
+ printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]);
+ printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n",
+ ext_csd[231]);
+ }
+ if (ext_csd_rev == 5) { /* Obsolete in 4.5 */
+ printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n",
+ ext_csd[230]);
+ printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n",
+ ext_csd[229]);
+ }
+ reg = ext_csd[EXT_CSD_BOOT_INFO];
+ printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg);
+ if (reg & EXT_CSD_BOOT_INFO_ALT)
+ printf(" Device supports alternative boot method\n");
+ if (reg & EXT_CSD_BOOT_INFO_DDR_DDR)
+ printf(" Device supports dual data rate during boot\n");
+ if (reg & EXT_CSD_BOOT_INFO_HS_MODE)
+ printf(" Device supports high speed timing during boot\n");
+
+ /* A441/A43: reserved [227] */
+ printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]);
+ printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]);
+ printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
+ ext_csd[224]);
+ printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n",
+ ext_csd[223]);
+ printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n",
+ ext_csd[222]);
+ printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
+ ext_csd[221]);
+ printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]);
+ printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]);
+ /* A441/A43: reserved [218] */
+ printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]);
+ /* A441/A43: reserved [216] */
+ printf("Sector Count [SEC_COUNT: 0x%08x]\n", (ext_csd[215] << 24) |
+ (ext_csd[214] << 16) | (ext_csd[213] << 8) |
+ ext_csd[212]);
+ /* A441/A43: reserved [211] */
+ printf("Minimum Write Performance for 8bit:\n");
+ printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]);
+ printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]);
+ printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]);
+ printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]);
+ printf("Minimum Write Performance for 4bit:\n");
+ printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]);
+ printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]);
+ /* A441/A43: reserved [204] */
+ printf("Power classes registers:\n");
+ printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]);
+ printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]);
+ printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]);
+ printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]);
+
+ /* A43: reserved [199:198] */
+ if (ext_csd_rev >= 5) {
+ printf("Partition switching timing "
+ "[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]);
+ printf("Out-of-interrupt busy timing"
+ " [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]);
+ }
+
+ /* A441/A43: reserved [197] [195] [193] [190] [188]
+ * [186] [184] [182] [180] [176] */
+
+ if (ext_csd_rev >= 6)
+ printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n",
+ ext_csd[197]);
+
+ printf("Card Type [CARD_TYPE: 0x%02x]\n", ext_csd[196]);
+ /* DEVICE_TYPE in A45 */
+ switch (reg) {
+ case 5:
+ printf("HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n");
+ break;
+ case 4:
+ printf("HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n");
+ break;
+ case 3:
+ printf("HS Dual Data Rate eMMC @52MHz 1.2VI/O\n");
+
+ break;
+ case 2:
+ printf("HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n");
+ break;
+ case 1:
+ printf("HS eMMC @52MHz - at rated device voltage(s)\n");
+ break;
+ case 0:
+ printf("HS eMMC @26MHz - at rated device voltage(s)\n");
+ break;
+ }
+ printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
+ /* ext_csd_rev = ext_csd[192] (already done!!!) */
+ printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]);
+ printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]);
+ printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]);
+ printf("High-speed interface timing [HS_TIMING: 0x%02x]\n",
+ ext_csd[185]);
+ /* bus_width: ext_csd[183] not readable */
+ printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n",
+ ext_csd[181]);
+ reg = ext_csd[EXT_CSD_BOOT_CFG];
+ printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg);
+ switch (reg & EXT_CSD_BOOT_CFG_EN) {
+ case 0x0:
+ printf(" Not boot enable\n");
+ break;
+ case 0x1:
+ printf(" Boot Partition 1 enabled\n");
+ break;
+ case 0x2:
+ printf(" Boot Partition 2 enabled\n");
+ break;
+ case 0x7:
+ 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;
+ default:
+ printf(" Access to General Purpuse partition %d\n",
+ (reg & EXT_CSD_BOOT_CFG_ACC) - 3);
+ break;
+ }
+
+ printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
+ ext_csd[178]);
+ printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n",
+ ext_csd[177]);
+ printf("High-density erase group definition"
+ " [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[175]);
+
+ /* A43: reserved [174:0] */
+ if (ext_csd_rev >= 5) {
+ printf("Boot write protection status registers"
+ " [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]);
+
+ reg = ext_csd[EXT_CSD_BOOT_WP];
+ printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg);
+ printf(" Power ro locking: ");
+ if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
+ printf("not possible\n");
+ else
+ printf("possible\n");
+
+ printf(" Permanent ro locking: ");
+ if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
+ printf("not possible\n");
+ else
+ printf("possible\n");
+
+ printf(" ro lock status: ");
+ if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
+ printf("locked until next power on\n");
+ else if (reg &
+ EXT_CSD_BOOT_WP_B_PERM_WP_EN)
+ printf("locked permanently\n");
+ else
+ printf("not locked\n");
+
+ /* A441]: reserved [172] */
+ printf("User area write protection register"
+ " [USER_WP]: 0x%02x\n", ext_csd[171]);
+ /* A441]: reserved [170] */
+ printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]);
+ printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]);
+ printf("Write reliability setting register"
+ " [WR_REL_SET]: 0x%02x\n", ext_csd[167]);
+ printf("Write reliability parameter register"
+ " [WR_REL_PARAM]: 0x%02x\n", ext_csd[166]);
+ /* sanitize_start ext_csd[165]]: not readable
+ * bkops_start ext_csd[164]]: only writable */
+ printf("Enable background operations handshake"
+ " [BKOPS_EN]: 0x%02x\n", ext_csd[163]);
+ printf("H/W reset function"
+ " [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]);
+ printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]);
+ reg = ext_csd[160];
+ printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
+ reg);
+ if (reg & 0x1)
+ printf(" Device support partitioning feature\n");
+ else
+ printf(" Device NOT support partitioning feature\n");
+ if (reg & 0x2)
+ printf(" Device can have enhanced tech.\n");
+ else
+ printf(" Device cannot have enhanced tech.\n");
+
+ printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
+ (ext_csd[159] << 16) | (ext_csd[158] << 8) |
+ ext_csd[157]);
+ printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
+ ext_csd[156]);
+ printf("Partitioning Setting"
+ " [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
+ ext_csd[155]);
+ printf("General Purpose Partition Size\n"
+ " [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) |
+ (ext_csd[153] << 8) | ext_csd[152]);
+ printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) |
+ (ext_csd[150] << 8) | ext_csd[149]);
+ printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) |
+ (ext_csd[147] << 8) | ext_csd[146]);
+ printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) |
+ (ext_csd[144] << 8) | ext_csd[143]);
+
+ printf("Enhanced User Data Area Size"
+ " [ENH_SIZE_MULT]: 0x%06x\n", (ext_csd[142] << 16) |
+ (ext_csd[141] << 8) | ext_csd[140]);
+ printf("Enhanced User Data Start Address"
+ " [ENH_START_ADDR]: 0x%06x\n", (ext_csd[139] << 16) |
+ (ext_csd[138] << 8) | ext_csd[137]);
+
+ /* A441]: reserved [135] */
+ printf("Bad Block Management mode"
+ " [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]);
+ /* A441: reserved [133:0] */
+ }
+ /* B45 */
+ if (ext_csd_rev >= 6) {
+ int j;
+ /* tcase_support ext_csd[132] not readable */
+ printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n",
+ ext_csd[131]);
+ printf("Program CID/CSD in DDR mode support"
+ " [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n",
+ ext_csd[130]);
+
+ for (j = 127; j >= 64; j--)
+ printf("Vendor Specific Fields"
+ " [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n",
+ j, ext_csd[j]);
+
+ printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n",
+ ext_csd[63]);
+ printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n",
+ ext_csd[62]);
+ printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", ext_csd[61]);
+ printf("1st initialization after disabling sector"
+ " size emulation [INI_TIMEOUT_EMU]: 0x%02x\n",
+ ext_csd[60]);
+ printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n",
+ ext_csd[59]);
+ printf("Number of addressed group to be Released"
+ "[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]);
+ printf("Exception events control"
+ " [EXCEPTION_EVENTS_CTRL]: 0x%04x\n",
+ (ext_csd[57] << 8) | ext_csd[56]);
+ printf("Exception events status"
+ "[EXCEPTION_EVENTS_STATUS]: 0x%04x\n",
+ (ext_csd[55] << 8) | ext_csd[54]);
+ printf("Extended Partitions Attribute"
+ " [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n",
+ (ext_csd[53] << 8) | ext_csd[52]);
+
+ for (j = 51; j >= 37; j--)
+ printf("Context configuration"
+ " [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]);
+
+ printf("Packed command status"
+ " [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]);
+ printf("Packed command failure index"
+ " [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]);
+ printf("Power Off Notification"
+ " [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]);
+ printf("Control to turn the Cache ON/OFF"
+ " [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
+ /* flush_cache ext_csd[32] not readable */
+ /*Reserved [31:0] */
+ }
+
+out_free:
return ret;
}