@@ -108,4 +108,7 @@
#define EXT_CSD_PART_CONFIG_EN_BOOT0 (0x1 << 3)
#define EXT_CSD_PART_CONFIG_EN_USER (0x7 << 3)
+#define EXT_CSD_BUS_WIDTH_8_MASK 0x4
+#define EXT_CSD_BUS_WIDTH_4_MASK 0x2
+
#endif
@@ -698,6 +698,25 @@ static const uint8_t sd_tuning_block_pattern4[64] = {
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde
};
+static const uint8_t mmc_tuning_block_pattern8[128] = {
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+ 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+ 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+ 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+ 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+ 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+ 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+ 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+ 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+ 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+ 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+ 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+ 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee
+};
+
static int sd_req_crc_validate(SDRequest *req)
{
uint8_t buffer[5];
@@ -1603,6 +1622,26 @@ static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req)
sizeof(sd_tuning_block_pattern4));
}
+/* CMD21 */
+static sd_rsp_type_t emmc_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req)
+{
+ const uint8_t *buf;
+ size_t size;
+
+ if (sd->state != sd_transfer_state) {
+ sd_invalid_state_for_cmd(sd, req);
+ }
+
+ if (sd->ext_csd[EXT_CSD_BUS_WIDTH] & EXT_CSD_BUS_WIDTH_8_MASK) {
+ buf = mmc_tuning_block_pattern8;
+ size = sizeof(mmc_tuning_block_pattern8);
+ } else {
+ buf = sd_tuning_block_pattern4;
+ size = sizeof(sd_tuning_block_pattern4);
+ }
+ return sd_cmd_to_sendingdata(sd, req, 0, buf, size);
+}
+
/* CMD23 */
static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req)
{
@@ -2391,6 +2430,7 @@ uint8_t sd_read_byte(SDState *sd)
case 13: /* ACMD13: SD_STATUS */
case 17: /* CMD17: READ_SINGLE_BLOCK */
case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */
+ case 21: /* CMD21: SEND_TUNING_BLOCK (MMC) */
case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */
case 30: /* CMD30: SEND_WRITE_PROT */
case 51: /* ACMD51: SEND_SCR */
@@ -2573,6 +2613,7 @@ static const SDProto sd_proto_emmc = {
[16] = {2, sd_ac, "SET_BLOCKLEN", sd_cmd_SET_BLOCKLEN},
[17] = {2, sd_adtc, "READ_SINGLE_BLOCK", sd_cmd_READ_SINGLE_BLOCK},
[19] = {0, sd_adtc, "BUSTEST_W", sd_cmd_unimplemented},
+ [21] = {2, sd_adtc, "SEND_TUNING_BLOCK", emmc_cmd_SEND_TUNING_BLOCK},
[23] = {2, sd_ac, "SET_BLOCK_COUNT", sd_cmd_SET_BLOCK_COUNT},
[24] = {4, sd_adtc, "WRITE_SINGLE_BLOCK", sd_cmd_WRITE_SINGLE_BLOCK},
[26] = {4, sd_adtc, "PROGRAM_CID", mmc_cmd_PROGRAM_CID},