eMMC 5.0 on the TK1 MMC controller

The TK1 MMC controller officially supports eMMC 4.51.

Has anyone tried to use an eMMC 5.0 device on their custom board?
Can it work in backward compatibility (not HS400) mode?

Hi Mike,

Normally with the JEDEC standard all eMMC 5.0 shall be backward compatible with eMMC 4.51 (HS200 speed max).
I didn’t try it but maybe in few months :)

Regards,
Ale

eMMC5.x device can be support by TK1 but it will work at max HS200 mode.
The old AVL list have a eMMC list:
Sandisk SDIN9DW4-16G, eMMC5.0 16GB
Samsung KLMAG2GEAC-B031,eMMC5.0 16GB
Toshiba THGBMBG8D4KBAIR,eMMC5.0 32GB

Thanks.

I can confirm we have a working eMMC5.0 Micron chip (in HS200 mode) with the TK1.
It did however require updating the relevant U-Boot code.

Someone requested the changes, so here is a patch.

Basically merges changes from l4t U-Boot 23.2 into 21.4 with some small adaptations for the old version. Using U-Boot from L4T 23.2 on the TK1 directly has some issues which I did not finish investigating.

From: <michael@percepto.co>
Date: Thu, 7 Apr 2016 09:13:42 +0300
Subject: [PATCH] merge changes from upstream (l4t-23.2) u-boot for the MMC
 subsystem, to properly support eMMC5.0

---
 drivers/mmc/mmc.c       | 510 +++++++++++++++++++++++++++++++++++++++---------
 drivers/mmc/tegra_mmc.c |  58 +++---
 include/mmc.h           | 128 +++++++++---
 3 files changed, 552 insertions(+), 144 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index a26f3ce..79e6fee 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -118,7 +118,7 @@ int mmc_send_status(struct mmc *mmc, int timeout)
 	if (!mmc_host_is_spi(mmc))
 		cmd.cmdarg = mmc->rca << 16;
 
-	do {
+	while (1) {
 		err = mmc_send_cmd(mmc, &cmd, NULL);
 		if (!err) {
 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
@@ -135,9 +135,11 @@ int mmc_send_status(struct mmc *mmc, int timeout)
 		} else if (--retries < 0)
 			return err;
 
-		udelay(1000);
+		if (timeout-- <= 0)
+			break;
 
-	} while (timeout--);
+		udelay(1000);
+	}
 
 #ifdef CONFIG_MMC_TRACE
 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
@@ -159,7 +161,7 @@ int mmc_set_blocklen(struct mmc *mmc, int len)
 {
 	struct mmc_cmd cmd;
 
-	if (mmc->card_caps & MMC_MODE_DDR_52MHz)
+	if (mmc->ddr_mode)
 		return 0;
 
 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
@@ -291,7 +293,7 @@ static int sd_send_op_cond(struct mmc *mmc)
 	int err;
 	struct mmc_cmd cmd;
 
-	do {
+	while (1) {
 		cmd.cmdidx = MMC_CMD_APP_CMD;
 		cmd.resp_type = MMC_RSP_R1;
 		cmd.cmdarg = 0;
@@ -322,11 +324,14 @@ static int sd_send_op_cond(struct mmc *mmc)
 		if (err)
 			return err;
 
-		udelay(1000);
-	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
+		if (cmd.response[0] & OCR_BUSY)
+			break;
 
-	if (timeout <= 0)
-		return UNUSABLE_ERR;
+		if (timeout-- <= 0)
+			return UNUSABLE_ERR;
+
+		udelay(1000);
+	}
 
 	if (mmc->version != SD_VERSION_2)
 		mmc->version = SD_VERSION_1_0;
@@ -350,51 +355,46 @@ static int sd_send_op_cond(struct mmc *mmc)
 	return 0;
 }
 
-/* We pass in the cmd since otherwise the init seems to fail */
-static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
-		int use_arg)
+static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
 {
+	struct mmc_cmd cmd;
 	int err;
 
-	cmd->cmdidx = MMC_CMD_SEND_OP_COND;
-	cmd->resp_type = MMC_RSP_R3;
-	cmd->cmdarg = 0;
-	if (use_arg && !mmc_host_is_spi(mmc)) {
-		cmd->cmdarg =
+	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
+	cmd.resp_type = MMC_RSP_R3;
+	cmd.cmdarg = 0;
+	if (use_arg && !mmc_host_is_spi(mmc))
+		cmd.cmdarg = OCR_HCS |
 			(mmc->cfg->voltages &
-			(mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
-			(mmc->op_cond_response & OCR_ACCESS_MODE);
+			(mmc->ocr & OCR_VOLTAGE_MASK)) |
+			(mmc->ocr & OCR_ACCESS_MODE);
 
-		if (mmc->cfg->host_caps & MMC_MODE_HC)
-			cmd->cmdarg |= OCR_HCS;
-	}
-	err = mmc_send_cmd(mmc, cmd, NULL);
+	err = mmc_send_cmd(mmc, &cmd, NULL);
 	if (err)
 		return err;
-	mmc->op_cond_response = cmd->response[0];
+	mmc->ocr = cmd.response[0];
 	return 0;
 }
 
 static int mmc_send_op_cond(struct mmc *mmc)
 {
-	struct mmc_cmd cmd;
 	int err, i;
 
 	/* Some cards seem to need this */
 	mmc_go_idle(mmc);
 
  	/* Asking to the card its capabilities */
-	mmc->op_cond_pending = 1;
 	for (i = 0; i < 2; i++) {
-		err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
+		err = mmc_send_op_cond_iter(mmc, i != 0);
 		if (err)
 			return err;
 
 		/* exit if not busy (flag seems to be inverted) */
-		if (mmc->op_cond_response & OCR_BUSY)
-			return 0;
+		if (mmc->ocr & OCR_BUSY)
+			break;
 	}
-	return IN_PROGRESS;
+	mmc->op_cond_pending = 1;
+	return 0;
 }
 
 static int mmc_complete_op_cond(struct mmc *mmc)
@@ -405,15 +405,19 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	int err;
 
 	mmc->op_cond_pending = 0;
-	start = get_timer(0);
-	do {
-		err = mmc_send_op_cond_iter(mmc, &cmd, 1);
-		if (err)
-			return err;
-		if (get_timer(start) > timeout)
-			return UNUSABLE_ERR;
-		udelay(100);
-	} while (!(mmc->op_cond_response & OCR_BUSY));
+	if (!(mmc->ocr & OCR_BUSY)) {
+		start = get_timer(0);
+		while (1) {
+			err = mmc_send_op_cond_iter(mmc, 1);
+			if (err)
+				return err;
+			if (mmc->ocr & OCR_BUSY)
+				break;
+			if (get_timer(start) > timeout)
+				return UNUSABLE_ERR;
+			udelay(100);
+		}
+	}
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
@@ -424,10 +428,11 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 
 		if (err)
 			return err;
+
+		mmc->ocr = cmd.response[0];
 	}
 
 	mmc->version = MMC_VERSION_UNKNOWN;
-	mmc->ocr = cmd.response[0];
 
 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
 	mmc->rca = 1;
@@ -495,6 +500,8 @@ static int mmc_change_freq(struct mmc *mmc)
 	if (mmc->version < MMC_VERSION_4)
 		return 0;
 
+	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+
 	err = mmc_send_ext_csd(mmc, ext_csd);
 
 	if (err)
@@ -519,7 +526,7 @@ static int mmc_change_freq(struct mmc *mmc)
 
 	/* High Speed is set, there are two types: 52MHz and 26MHz */
 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
-		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
+		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
 	} else {
@@ -594,10 +601,209 @@ int mmc_switch_part(int dev_num, unsigned int part_num)
 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
 			 (mmc->part_config & ~PART_ACCESS_MASK)
 			 | (part_num & PART_ACCESS_MASK));
-	if (ret)
-		return ret;
 
-	return mmc_set_capacity(mmc, part_num);
+	/*
+	 * Set the capacity if the switch succeeded or was intended
+	 * to return to representing the raw device.
+	 */
+	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0)))
+		ret = mmc_set_capacity(mmc, part_num);
+
+	return ret;
+}
+
+int mmc_hwpart_config(struct mmc *mmc,
+		      const struct mmc_hwpart_conf *conf,
+		      enum mmc_hwpart_conf_mode mode)
+{
+	u8 part_attrs = 0;
+	u32 enh_size_mult;
+	u32 enh_start_addr;
+	u32 gp_size_mult[4];
+	u32 max_enh_size_mult;
+	u32 tot_enh_size_mult = 0;
+	u8 wr_rel_set;
+	int i, pidx, err;
+	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
+
+	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
+		return -EINVAL;
+
+	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
+		printf("eMMC >= 4.4 required for enhanced user data area\n");
+		return -EMEDIUMTYPE;
+	}
+
+	if (!(mmc->part_support & PART_SUPPORT)) {
+		printf("Card does not support partitioning\n");
+		return -EMEDIUMTYPE;
+	}
+
+	if (!mmc->hc_wp_grp_size) {
+		printf("Card does not define HC WP group size\n");
+		return -EMEDIUMTYPE;
+	}
+
+	/* check partition alignment and total enhanced size */
+	if (conf->user.enh_size) {
+		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
+		    conf->user.enh_start % mmc->hc_wp_grp_size) {
+			printf("User data enhanced area not HC WP group "
+			       "size aligned\n");
+			return -EINVAL;
+		}
+		part_attrs |= EXT_CSD_ENH_USR;
+		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
+		if (mmc->high_capacity) {
+			enh_start_addr = conf->user.enh_start;
+		} else {
+			enh_start_addr = (conf->user.enh_start << 9);
+		}
+	} else {
+		enh_size_mult = 0;
+		enh_start_addr = 0;
+	}
+	tot_enh_size_mult += enh_size_mult;
+
+	for (pidx = 0; pidx < 4; pidx++) {
+		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
+			printf("GP%i partition not HC WP group size "
+			       "aligned\n", pidx+1);
+			return -EINVAL;
+		}
+		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
+		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
+			part_attrs |= EXT_CSD_ENH_GP(pidx);
+			tot_enh_size_mult += gp_size_mult[pidx];
+		}
+	}
+
+	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
+		printf("Card does not support enhanced attribute\n");
+		return -EMEDIUMTYPE;
+	}
+
+	err = mmc_send_ext_csd(mmc, ext_csd);
+	if (err)
+		return err;
+
+	max_enh_size_mult =
+		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
+		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
+		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
+	if (tot_enh_size_mult > max_enh_size_mult) {
+		printf("Total enhanced size exceeds maximum (%u > %u)\n",
+		       tot_enh_size_mult, max_enh_size_mult);
+		return -EMEDIUMTYPE;
+	}
+
+	/* The default value of EXT_CSD_WR_REL_SET is device
+	 * dependent, the values can only be changed if the
+	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
+	 * changed only once and before partitioning is completed. */
+	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
+	if (conf->user.wr_rel_change) {
+		if (conf->user.wr_rel_set)
+			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
+		else
+			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
+	}
+	for (pidx = 0; pidx < 4; pidx++) {
+		if (conf->gp_part[pidx].wr_rel_change) {
+			if (conf->gp_part[pidx].wr_rel_set)
+				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
+			else
+				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
+		}
+	}
+
+	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
+	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
+		puts("Card does not support host controlled partition write "
+		     "reliability settings\n");
+		return -EMEDIUMTYPE;
+	}
+
+	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
+	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
+		printf("Card already partitioned\n");
+		return -EPERM;
+	}
+
+	if (mode == MMC_HWPART_CONF_CHECK)
+		return 0;
+
+	/* Partitioning requires high-capacity size definitions */
+	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_ERASE_GROUP_DEF, 1);
+
+		if (err)
+			return err;
+
+		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+
+		/* update erase group size to be high-capacity */
+		mmc->erase_grp_size =
+			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
+
+	}
+
+	/* all OK, write the configuration */
+	for (i = 0; i < 4; i++) {
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_ENH_START_ADDR+i,
+				 (enh_start_addr >> (i*8)) & 0xFF);
+		if (err)
+			return err;
+	}
+	for (i = 0; i < 3; i++) {
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_ENH_SIZE_MULT+i,
+				 (enh_size_mult >> (i*8)) & 0xFF);
+		if (err)
+			return err;
+	}
+	for (pidx = 0; pidx < 4; pidx++) {
+		for (i = 0; i < 3; i++) {
+			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
+					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
+			if (err)
+				return err;
+		}
+	}
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
+	if (err)
+		return err;
+
+	if (mode == MMC_HWPART_CONF_SET)
+		return 0;
+
+	/* The WR_REL_SET is a write-once register but shall be
+	 * written before setting PART_SETTING_COMPLETED. As it is
+	 * write-once we can only write it when completing the
+	 * partitioning. */
+	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
+		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_WR_REL_SET, wr_rel_set);
+		if (err)
+			return err;
+	}
+
+	/* Setting PART_SETTING_COMPLETED confirms the partition
+	 * configuration but it only becomes effective after power
+	 * cycle, so we do not adjust the partition related settings
+	 * in the mmc struct. */
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_PARTITION_SETTING,
+			 EXT_CSD_PARTITION_SETTING_COMPLETED);
+	if (err)
+		return err;
+
+	return 0;
 }
 
 int mmc_getcd(struct mmc *mmc)
@@ -813,6 +1019,8 @@ static int mmc_startup(struct mmc *mmc)
 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
 	int timeout = 1000;
+	bool has_parts = false;
+	bool part_completed;
 
 #ifdef CONFIG_MMC_SPI_CRC_ON
 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
@@ -965,7 +1173,9 @@ static int mmc_startup(struct mmc *mmc)
 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
 		/* check  ext_csd version and capacity */
 		err = mmc_send_ext_csd(mmc, ext_csd);
-		if (!err && (ext_csd[EXT_CSD_REV] >= 2)) {
+		if (err)
+			return err;
+		if (ext_csd[EXT_CSD_REV] >= 2) {
 			/*
 			 * According to the JEDEC Standard, the value of
 			 * ext_csd's capacity is valid if the value is more
@@ -996,6 +1206,62 @@ static int mmc_startup(struct mmc *mmc)
 		case 6:
 			mmc->version = MMC_VERSION_4_5;
 			break;
+		case 7:
+			mmc->version = MMC_VERSION_5_0;
+			break;
+		}
+
+		/* The partition data may be non-zero but it is only
+		 * effective if PARTITION_SETTING_COMPLETED is set in
+		 * EXT_CSD, so ignore any data if this bit is not set,
+		 * except for enabling the high-capacity group size
+		 * definition (see below). */
+		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
+				    EXT_CSD_PARTITION_SETTING_COMPLETED);
+
+		/* store the partition info of emmc */
+		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
+		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
+		    ext_csd[EXT_CSD_BOOT_MULT])
+			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+		if (part_completed &&
+		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
+			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
+
+		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
+
+		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
+
+		for (i = 0; i < 4; i++) {
+			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
+			uint mult = (ext_csd[idx + 2] << 16) +
+				(ext_csd[idx + 1] << 8) + ext_csd[idx];
+			if (mult)
+				has_parts = true;
+			if (!part_completed)
+				continue;
+			mmc->capacity_gp[i] = mult;
+			mmc->capacity_gp[i] *=
+				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+			mmc->capacity_gp[i] <<= 19;
+		}
+
+		if (part_completed) {
+			mmc->enh_user_size =
+				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
+				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
+				ext_csd[EXT_CSD_ENH_SIZE_MULT];
+			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+			mmc->enh_user_size <<= 19;
+			mmc->enh_user_start =
+				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
+				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
+				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
+				ext_csd[EXT_CSD_ENH_START_ADDR];
+			if (mmc->high_capacity)
+				mmc->enh_user_start <<= 9;
 		}
 
 		/*
@@ -1003,18 +1269,38 @@ static int mmc_startup(struct mmc *mmc)
 		 * partitioned. This bit will be lost every time after a reset
 		 * or power off. This will affect erase size.
 		 */
+		if (part_completed)
+			has_parts = true;
 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
-		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) {
+		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
+			has_parts = true;
+		if (has_parts) {
 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
 				EXT_CSD_ERASE_GROUP_DEF, 1);
 
 			if (err)
 				return err;
+			else
+				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+		}
 
+		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
 			/* Read out group size from ext_csd */
 			mmc->erase_grp_size =
-				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
-					MMC_MAX_BLOCK_LEN * 1024;
+				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
+			/*
+			 * if high capacity and partition setting completed
+			 * SEC_COUNT is valid even if it is smaller than 2 GiB
+			 * JEDEC Standard JESD84-B45, 6.2.4
+			 */
+			if (mmc->high_capacity && part_completed) {
+				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
+					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
+					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
+					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
+				capacity *= MMC_MAX_BLOCK_LEN;
+				mmc->capacity_user = capacity;
+			}
 		} else {
 			/* Calculate the group size from the csd value. */
 			int erase_gsz, erase_gmul;
@@ -1024,23 +1310,11 @@ static int mmc_startup(struct mmc *mmc)
 				* (erase_gmul + 1);
 		}
 
-		/* store the partition info of emmc */
-		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
-		    ext_csd[EXT_CSD_BOOT_MULT])
-			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+		mmc->hc_wp_grp_size = 1024
+			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
 
-		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
-
-		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
-
-		for (i = 0; i < 4; i++) {
-			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
-			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
-				(ext_csd[idx + 1] << 8) + ext_csd[idx];
-			mmc->capacity_gp[i] *=
-				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
-			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
-		}
+		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
 	}
 
 	err = mmc_set_capacity(mmc, mmc->part_num);
@@ -1082,7 +1356,8 @@ static int mmc_startup(struct mmc *mmc)
 			mmc->tran_speed = 50000000;
 		else
 			mmc->tran_speed = 25000000;
-	} else {
+	} else if (mmc->version >= MMC_VERSION_4) {
+		/* Only version 4 of MMC supports wider bus widths */
 		int idx;
 
 		/* An array of possible bus widths in order of preference */
@@ -1096,8 +1371,10 @@ static int mmc_startup(struct mmc *mmc)
 
 		/* An array to map CSD bus widths to host cap bits */
 		static unsigned ext_to_hostcaps[] = {
-			[EXT_CSD_DDR_BUS_WIDTH_4] = MMC_MODE_DDR_52MHz,
-			[EXT_CSD_DDR_BUS_WIDTH_8] = MMC_MODE_DDR_52MHz,
+			[EXT_CSD_DDR_BUS_WIDTH_4] =
+				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
+			[EXT_CSD_DDR_BUS_WIDTH_8] =
+				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
 		};
@@ -1109,13 +1386,25 @@ static int mmc_startup(struct mmc *mmc)
 
 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
 			unsigned int extw = ext_csd_bits[idx];
+			unsigned int caps = ext_to_hostcaps[extw];
+
+			/*
+			 * If the bus width is still not changed,
+			 * don't try to set the default again.
+			 * Otherwise, recover from switch attempts
+			 * by switching to 1-bit bus width.
+			 */
+			if (extw == EXT_CSD_BUS_WIDTH_1 &&
+					mmc->bus_width == 1) {
+				err = 0;
+				break;
+			}
 
 			/*
-			 * Check to make sure the controller supports
-			 * this bus width, if it's more than 1
+			 * Check to make sure the card and controller support
+			 * these capabilities
 			 */
-			if (extw != EXT_CSD_BUS_WIDTH_1 &&
-					!(mmc->cfg->host_caps & ext_to_hostcaps[extw]))
+			if ((mmc->card_caps & caps) != caps)
 				continue;
 
 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
@@ -1124,25 +1413,33 @@ static int mmc_startup(struct mmc *mmc)
 			if (err)
 				continue;
 
+			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
 			mmc_set_bus_width(mmc, widths[idx]);
 
 			err = mmc_send_ext_csd(mmc, test_csd);
-			if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
-				    == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
-				 && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \
-				    == test_csd[EXT_CSD_ERASE_GROUP_DEF] \
-				 && ext_csd[EXT_CSD_REV] \
-				    == test_csd[EXT_CSD_REV]
-				 && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
-				    == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
-				 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
-					&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
-
-				mmc->card_caps |= ext_to_hostcaps[extw];
+
+			if (err)
+				continue;
+
+			/* Only compare read only fields */
+			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
+				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
+			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
+				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
+			    ext_csd[EXT_CSD_REV]
+				== test_csd[EXT_CSD_REV] &&
+			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
+			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
 				break;
-			}
+			else
+				err = SWITCH_ERR;
 		}
 
+		if (err)
+			return err;
+
 		if (mmc->card_caps & MMC_MODE_HS) {
 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
 				mmc->tran_speed = 52000000;
@@ -1153,6 +1450,12 @@ static int mmc_startup(struct mmc *mmc)
 
 	mmc_set_clock(mmc, mmc->tran_speed);
 
+	/* Fix the block length for DDR mode */
+	if (mmc->ddr_mode) {
+		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
+		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
+	}
+
 	/* fill in device description */
 	mmc->block_dev.lun = 0;
 	mmc->block_dev.type = 0;
@@ -1269,6 +1572,11 @@ block_dev_desc_t *mmc_get_dev(int dev)
 }
 #endif
 
+/* board-specific MMC power initializations. */
+__weak void board_mmc_power_init(void)
+{
+}
+
 int mmc_start_init(struct mmc *mmc)
 {
 	int err;
@@ -1285,12 +1593,18 @@ int mmc_start_init(struct mmc *mmc)
 	if (mmc->has_init)
 		return 0;
 
+#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
+	mmc_adapter_card_type_ident();
+#endif
+	board_mmc_power_init();
+
 	/* made sure it's not NULL earlier */
 	err = mmc->cfg->ops->init(mmc);
 
 	if (err)
 		return err;
 
+	mmc->ddr_mode = 0;
 	mmc_set_bus_width(mmc, 1);
 	mmc_set_clock(mmc, 1);
 
@@ -1313,7 +1627,7 @@ int mmc_start_init(struct mmc *mmc)
 	if (err == TIMEOUT) {
 		err = mmc_send_op_cond(mmc);
 
-		if (err && err != IN_PROGRESS) {
+		if (err) {
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
 			printf("Card did not respond to voltage select!\n");
 #endif
@@ -1321,7 +1635,7 @@ int mmc_start_init(struct mmc *mmc)
 		}
 	}
 
-	if (err == IN_PROGRESS)
+	if (!err)
 		mmc->init_in_progress = 1;
 
 	return err;
@@ -1331,6 +1645,7 @@ static int mmc_complete_init(struct mmc *mmc)
 {
 	int err = 0;
 
+	mmc->init_in_progress = 0;
 	if (mmc->op_cond_pending)
 		err = mmc_complete_op_cond(mmc);
 
@@ -1340,13 +1655,12 @@ static int mmc_complete_init(struct mmc *mmc)
 		mmc->has_init = 0;
 	else
 		mmc->has_init = 1;
-	mmc->init_in_progress = 0;
 	return err;
 }
 
 int mmc_init(struct mmc *mmc)
 {
-	int err = IN_PROGRESS;
+	int err = 0;
 	unsigned start;
 
 	if (mmc->has_init)
@@ -1357,7 +1671,7 @@ int mmc_init(struct mmc *mmc)
 	if (!mmc->init_in_progress)
 		err = mmc_start_init(mmc);
 
-	if (!err || err == IN_PROGRESS)
+	if (!err)
 		err = mmc_complete_init(mmc);
 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
 	return err;
@@ -1387,14 +1701,25 @@ void print_mmc_devices(char separator)
 {
 	struct mmc *m;
 	struct list_head *entry;
+	char *mmc_type;
 
 	list_for_each(entry, &mmc_devices) {
 		m = list_entry(entry, struct mmc, link);
 
+		if (m->has_init)
+			mmc_type = IS_SD(m) ? "SD" : "eMMC";
+		else
+			mmc_type = NULL;
+
 		printf("%s: %d", m->cfg->name, m->block_dev.dev);
+		if (mmc_type)
+			printf(" (%s)", mmc_type);
 
-		if (entry->next != &mmc_devices)
-			printf("%c ", separator);
+		if (entry->next != &mmc_devices) {
+			printf("%c", separator);
+			if (separator != '\n')
+				puts (" ");
+		}
 	}
 
 	printf("\n");
@@ -1422,6 +1747,9 @@ static void do_preinit(void)
 	list_for_each(entry, &mmc_devices) {
 		m = list_entry(entry, struct mmc, link);
 
+#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
+		mmc_set_preinit(m, 1);
+#endif
 		if (m->preinit)
 			mmc_start_init(m);
 	}
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index ca9c4aa..e524276 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -2,7 +2,7 @@
  * (C) Copyright 2009 SAMSUNG Electronics
  * Minkyu Kang <mk7.kang@samsung.com>
  * Jaehoon Chung <jh80.chung@samsung.com>
- * Portions Copyright 2011-2013 NVIDIA Corporation
+ * Portions Copyright 2011-2015 NVIDIA Corporation
  *
  * SPDX-License-Identifier:	GPL-2.0+
  */
@@ -13,6 +13,7 @@
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/mmc.h>
 #include <asm/arch-tegra/tegra_mmc.h>
 #include <mmc.h>
 
@@ -66,7 +67,7 @@ static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data,
 		bbstate->bounce_buffer, bbstate->user_buffer, data->blocks,
 		data->blocksize);
 
-	writel((u32)bbstate->bounce_buffer, &host->reg->sysad);
+	writel((u32)(unsigned long)bbstate->bounce_buffer, &host->reg->sysad);
 	/*
 	 * DMASEL[4:3]
 	 * 00 = Selects SDMA
@@ -232,8 +233,8 @@ static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 		if (cmd->resp_type & MMC_RSP_136) {
 			/* CRC is stripped so we need to do some shifting. */
 			for (i = 0; i < 4; i++) {
-				unsigned int offset =
-					(unsigned int)(&host->reg->rspreg3 - i);
+				unsigned long offset =
+					(unsigned long)(&host->reg->rspreg3 - i);
 				cmd->response[i] = readl(offset) << 8;
 
 				if (i != 3) {
@@ -292,7 +293,7 @@ static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 				/* Transfer Complete */
 				debug("r/w is done\n");
 				break;
-			} else if (get_timer(start) > 2000UL) {
+			} else if (get_timer(start) > 8000UL) {
 				writel(mask, &host->reg->norintsts);
 				printf("%s: MMC Timeout\n"
 				       "    Interrupt status        0x%08x\n"
@@ -508,14 +509,14 @@ static int tegra_mmc_core_init(struct mmc *mmc)
 	return 0;
 }
 
-int tegra_mmc_getcd(struct mmc *mmc)
+static int tegra_mmc_getcd(struct mmc *mmc)
 {
 	struct mmc_host *host = mmc->priv;
 
 	debug("tegra_mmc_getcd called\n");
 
 	if (fdt_gpio_isvalid(&host->cd_gpio))
-		return fdtdec_get_gpio(&host->cd_gpio);
+			return fdtdec_get_gpio(&host->cd_gpio);
 
 	return 1;
 }
@@ -527,7 +528,7 @@ static const struct mmc_ops tegra_mmc_ops = {
 	.getcd		= tegra_mmc_getcd,
 };
 
-static int do_mmc_init(int dev_index)
+static int do_mmc_init(int dev_index, bool removable)
 {
 	struct mmc_host *host;
 	char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */
@@ -538,27 +539,22 @@ static int do_mmc_init(int dev_index)
 	if (!host->enabled)
 		return -1;
 
-	debug(" do_mmc_init: index %d, bus width %d "
-		"pwr_gpio %d cd_gpio %d\n",
-		dev_index, host->width,
-		host->pwr_gpio.gpio, host->cd_gpio.gpio);
-
 	host->clock = 0;
 	clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
 
 	if (fdt_gpio_isvalid(&host->pwr_gpio)) {
-		sprintf(gpusage, "SD/MMC%d PWR", dev_index);
-		gpio_request(host->pwr_gpio.gpio, gpusage);
-		gpio_direction_output(host->pwr_gpio.gpio, 1);
-		debug(" Power GPIO name = %s\n", host->pwr_gpio.name);
-	}
+			sprintf(gpusage, "SD/MMC%d PWR", dev_index);
+			gpio_request(host->pwr_gpio.gpio, gpusage);
+			gpio_direction_output(host->pwr_gpio.gpio, 1);
+			debug(" Power GPIO name = %s\n", host->pwr_gpio.name);
+		}
 
-	if (fdt_gpio_isvalid(&host->cd_gpio)) {
-		sprintf(gpusage, "SD/MMC%d CD", dev_index);
-		gpio_request(host->cd_gpio.gpio, gpusage);
-		gpio_direction_input(host->cd_gpio.gpio);
-		debug(" CD GPIO name = %s\n", host->cd_gpio.name);
-	}
+		if (fdt_gpio_isvalid(&host->cd_gpio)) {
+			sprintf(gpusage, "SD/MMC%d CD", dev_index);
+			gpio_request(host->cd_gpio.gpio, gpusage);
+			gpio_direction_input(host->cd_gpio.gpio);
+			debug(" CD GPIO name = %s\n", host->cd_gpio.name);
+		}
 
 	memset(&host->cfg, 0, sizeof(host->cfg));
 
@@ -571,7 +567,7 @@ static int do_mmc_init(int dev_index)
 		host->cfg.host_caps |= MMC_MODE_8BIT;
 	if (host->width >= 4)
 		host->cfg.host_caps |= MMC_MODE_4BIT;
-	host->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC;
+	host->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
 
 	/*
 	 * min freq is for card identification, and is the highest
@@ -585,6 +581,7 @@ static int do_mmc_init(int dev_index)
 	host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
 
 	mmc = mmc_create(&host->cfg, host);
+	mmc->block_dev.removable = removable;
 	if (mmc == NULL)
 		return -1;
 
@@ -598,7 +595,8 @@ static int do_mmc_init(int dev_index)
  * @param node		Device index (0-3)
  * @param host		Structure to fill in (reg, width, mmc_id)
  */
-static int mmc_get_config(const void *blob, int node, struct mmc_host *host)
+static int mmc_get_config(const void *blob, int node, struct mmc_host *host,
+			  bool *removablep)
 {
 	debug("%s: node = %d\n", __func__, node);
 
@@ -624,11 +622,12 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host)
 	if (!host->width)
 		debug("%s: no sdmmc width found\n", __func__);
 
-	/* These GPIOs are optional */
 	fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
 	fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio);
 	fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio);
 
+	*removablep = !fdtdec_get_bool(blob, node, "non-removable");
+
 	debug("%s: found controller at %p, width = %d, periph_id = %d\n",
 		__func__, host->reg, host->width, host->mmc_id);
 	return 0;
@@ -645,6 +644,7 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host)
 static int process_nodes(const void *blob, int node_list[], int count)
 {
 	struct mmc_host *host;
+	bool removable;
 	int i, node;
 
 	debug("%s: count = %d\n", __func__, count);
@@ -658,11 +658,11 @@ static int process_nodes(const void *blob, int node_list[], int count)
 		host = &mmc_host[i];
 		host->id = i;
 
-		if (mmc_get_config(blob, node, host)) {
+		if (mmc_get_config(blob, node, host, &removable)) {
 			printf("%s: failed to decode dev %d\n",	__func__, i);
 			return -1;
 		}
-		do_mmc_init(i);
+		do_mmc_init(i, removable);
 	}
 	return 0;
 }
diff --git a/include/mmc.h b/include/mmc.h
index 7f5f9bc..dd98b3b 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -14,35 +14,53 @@
 #include <linux/compiler.h>
 #include <part.h>
 
-#define SD_VERSION_SD	0x20000
-#define SD_VERSION_3	(SD_VERSION_SD | 0x300)
-#define SD_VERSION_2	(SD_VERSION_SD | 0x200)
-#define SD_VERSION_1_0	(SD_VERSION_SD | 0x100)
-#define SD_VERSION_1_10	(SD_VERSION_SD | 0x10a)
-#define MMC_VERSION_MMC		0x10000
-#define MMC_VERSION_UNKNOWN	(MMC_VERSION_MMC)
-#define MMC_VERSION_1_2		(MMC_VERSION_MMC | 0x102)
-#define MMC_VERSION_1_4		(MMC_VERSION_MMC | 0x104)
-#define MMC_VERSION_2_2		(MMC_VERSION_MMC | 0x202)
-#define MMC_VERSION_3		(MMC_VERSION_MMC | 0x300)
-#define MMC_VERSION_4		(MMC_VERSION_MMC | 0x400)
-#define MMC_VERSION_4_1		(MMC_VERSION_MMC | 0x401)
-#define MMC_VERSION_4_2		(MMC_VERSION_MMC | 0x402)
-#define MMC_VERSION_4_3		(MMC_VERSION_MMC | 0x403)
-#define MMC_VERSION_4_41	(MMC_VERSION_MMC | 0x429)
-#define MMC_VERSION_4_5		(MMC_VERSION_MMC | 0x405)
+/* SD/MMC version bits; 8 flags, 8 major, 8 minor, 8 change */
+#define SD_VERSION_SD	(1U << 31)
+#define MMC_VERSION_MMC	(1U << 30)
+
+#define MAKE_SDMMC_VERSION(a, b, c)	\
+	((((u32)(a)) << 16) | ((u32)(b) << 8) | (u32)(c))
+#define MAKE_SD_VERSION(a, b, c)	\
+	(SD_VERSION_SD | MAKE_SDMMC_VERSION(a, b, c))
+#define MAKE_MMC_VERSION(a, b, c)	\
+	(MMC_VERSION_MMC | MAKE_SDMMC_VERSION(a, b, c))
+
+#define EXTRACT_SDMMC_MAJOR_VERSION(x)	\
+	(((u32)(x) >> 16) & 0xff)
+#define EXTRACT_SDMMC_MINOR_VERSION(x)	\
+	(((u32)(x) >> 8) & 0xff)
+#define EXTRACT_SDMMC_CHANGE_VERSION(x)	\
+	((u32)(x) & 0xff)
+
+#define SD_VERSION_3		MAKE_SD_VERSION(3, 0, 0)
+#define SD_VERSION_2		MAKE_SD_VERSION(2, 0, 0)
+#define SD_VERSION_1_0		MAKE_SD_VERSION(1, 0, 0)
+#define SD_VERSION_1_10		MAKE_SD_VERSION(1, 10, 0)
+
+#define MMC_VERSION_UNKNOWN	MAKE_MMC_VERSION(0, 0, 0)
+#define MMC_VERSION_1_2		MAKE_MMC_VERSION(1, 2, 0)
+#define MMC_VERSION_1_4		MAKE_MMC_VERSION(1, 4, 0)
+#define MMC_VERSION_2_2		MAKE_MMC_VERSION(2, 2, 0)
+#define MMC_VERSION_3		MAKE_MMC_VERSION(3, 0, 0)
+#define MMC_VERSION_4		MAKE_MMC_VERSION(4, 0, 0)
+#define MMC_VERSION_4_1		MAKE_MMC_VERSION(4, 1, 0)
+#define MMC_VERSION_4_2		MAKE_MMC_VERSION(4, 2, 0)
+#define MMC_VERSION_4_3		MAKE_MMC_VERSION(4, 3, 0)
+#define MMC_VERSION_4_41	MAKE_MMC_VERSION(4, 4, 1)
+#define MMC_VERSION_4_5		MAKE_MMC_VERSION(4, 5, 0)
+#define MMC_VERSION_5_0		MAKE_MMC_VERSION(5, 0, 0)
 
 #define MMC_MODE_HS		(1 << 0)
 #define MMC_MODE_HS_52MHz	(1 << 1)
 #define MMC_MODE_4BIT		(1 << 2)
 #define MMC_MODE_8BIT		(1 << 3)
 #define MMC_MODE_SPI		(1 << 4)
-#define MMC_MODE_HC		(1 << 5)
-#define MMC_MODE_DDR_52MHz	(1 << 6)
+#define MMC_MODE_DDR_52MHz	(1 << 5)
 
 #define SD_DATA_4BIT	0x00040000
 
-#define IS_SD(x) (x->version & SD_VERSION_SD)
+#define IS_SD(x)	((x)->version & SD_VERSION_SD)
+#define IS_MMC(x)	((x)->version & MMC_VERSION_MMC)
 
 #define MMC_DATA_READ		1
 #define MMC_DATA_WRITE		2
@@ -51,8 +69,7 @@
 #define UNUSABLE_ERR		-17 /* Unusable Card */
 #define COMM_ERR		-18 /* Communications Error */
 #define TIMEOUT			-19
-#define IN_PROGRESS		-20 /* operation is in progress */
-#define SWITCH_ERR		-21 /* Card reports failure to switch mode */
+#define SWITCH_ERR		-20 /* Card reports failure to switch mode */
 
 #define MMC_CMD_GO_IDLE_STATE		0
 #define MMC_CMD_SEND_OP_COND		1
@@ -87,6 +104,7 @@
 #define SD_CMD_SEND_RELATIVE_ADDR	3
 #define SD_CMD_SWITCH_FUNC		6
 #define SD_CMD_SEND_IF_COND		8
+#define SD_CMD_SWITCH_UHS18V		11
 
 #define SD_CMD_APP_SET_BUS_WIDTH	6
 #define SD_CMD_ERASE_WR_BLK_START	32
@@ -146,10 +164,16 @@
 /*
  * EXT_CSD fields
  */
+#define EXT_CSD_ENH_START_ADDR		136	/* R/W */
+#define EXT_CSD_ENH_SIZE_MULT		140	/* R/W */
 #define EXT_CSD_GP_SIZE_MULT		143	/* R/W */
+#define EXT_CSD_PARTITION_SETTING	155	/* R/W */
 #define EXT_CSD_PARTITIONS_ATTRIBUTE	156	/* R/W */
+#define EXT_CSD_MAX_ENH_SIZE_MULT	157	/* R */
 #define EXT_CSD_PARTITIONING_SUPPORT	160	/* RO */
 #define EXT_CSD_RST_N_FUNCTION		162	/* R/W */
+#define EXT_CSD_WR_REL_PARAM		166	/* R */
+#define EXT_CSD_WR_REL_SET		167	/* R/W */
 #define EXT_CSD_RPMB_MULT		168	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
 #define EXT_CSD_BOOT_BUS_WIDTH		177
@@ -197,6 +221,16 @@
 #define EXT_CSD_BOOT_BUS_WIDTH_RESET(x)	(x << 2)
 #define EXT_CSD_BOOT_BUS_WIDTH_WIDTH(x)	(x)
 
+#define EXT_CSD_PARTITION_SETTING_COMPLETED	(1 << 0)
+
+#define EXT_CSD_ENH_USR		(1 << 0)	/* user data area is enhanced */
+#define EXT_CSD_ENH_GP(x)	(1 << ((x)+1))	/* GP part (x+1) is enhanced */
+
+#define EXT_CSD_HS_CTRL_REL	(1 << 0)	/* host controlled WR_REL_SET */
+
+#define EXT_CSD_WR_DATA_REL_USR		(1 << 0)	/* user data area WR_REL */
+#define EXT_CSD_WR_DATA_REL_GP(x)	(1 << ((x)+1))	/* GP part (x+1) WR_REL */
+
 #define R1_ILLEGAL_COMMAND		(1 << 22)
 #define R1_APP_CMD			(1 << 5)
 
@@ -220,6 +254,7 @@
 #define MMCPART_NOAVAILABLE	(0xff)
 #define PART_ACCESS_MASK	(0x7)
 #define PART_SUPPORT		(0x1)
+#define ENHNCD_SUPPORT		(0x2)
 #define PART_ENH_ATTRIB		(0x1f)
 
 /* Maximum block size for MMC */
@@ -298,22 +333,49 @@ struct mmc {
 	uint csd[4];
 	uint cid[4];
 	ushort rca;
+	u8 part_support;
+	u8 part_attr;
+	u8 wr_rel_set;
 	char part_config;
 	char part_num;
 	uint tran_speed;
 	uint read_bl_len;
 	uint write_bl_len;
-	uint erase_grp_size;
+	uint erase_grp_size;	/* in 512-byte sectors */
+	uint hc_wp_grp_size;	/* in 512-byte sectors */
 	u64 capacity;
 	u64 capacity_user;
 	u64 capacity_boot;
 	u64 capacity_rpmb;
 	u64 capacity_gp[4];
+	u64 enh_user_start;
+	u64 enh_user_size;
 	block_dev_desc_t block_dev;
 	char op_cond_pending;	/* 1 if we are waiting on an op_cond command */
 	char init_in_progress;	/* 1 if we have done mmc_start_init() */
 	char preinit;		/* start init as early as possible */
-	uint op_cond_response;	/* the response byte from the last op_cond */
+	int ddr_mode;
+};
+
+struct mmc_hwpart_conf {
+	struct {
+		uint enh_start;	/* in 512-byte sectors */
+		uint enh_size;	/* in 512-byte sectors, if 0 no enh area */
+		unsigned wr_rel_change : 1;
+		unsigned wr_rel_set : 1;
+	} user;
+	struct {
+		uint size;	/* in 512-byte sectors */
+		unsigned enhanced : 1;
+		unsigned wr_rel_change : 1;
+		unsigned wr_rel_set : 1;
+	} gp_part[4];
+};
+
+enum mmc_hwpart_conf_mode {
+	MMC_HWPART_CONF_CHECK,
+	MMC_HWPART_CONF_SET,
+	MMC_HWPART_CONF_COMPLETE,
 };
 
 int mmc_register(struct mmc *mmc);
@@ -328,6 +390,8 @@ int mmc_set_dev(int dev_num);
 void print_mmc_devices(char separator);
 int get_mmc_num(void);
 int mmc_switch_part(int dev_num, unsigned int part_num);
+int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf,
+		      enum mmc_hwpart_conf_mode mode);
 int mmc_getcd(struct mmc *mmc);
 int board_mmc_getcd(struct mmc *mmc);
 int mmc_getwp(struct mmc *mmc);
@@ -385,8 +449,24 @@ struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode);
 int mmc_legacy_init(int verbose);
 #endif
 
+void board_mmc_power_init(void);
 int board_mmc_init(bd_t *bis);
 int cpu_mmc_init(bd_t *bis);
+int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr);
+
+struct pci_device_id;
+
+/**
+ * pci_mmc_init() - set up PCI MMC devices
+ *
+ * This finds all the matching PCI IDs and sets them up as MMC devices.
+ *
+ * @name:		Name to use for devices
+ * @mmc_supported:	PCI IDs to search for
+ * @num_ids:		Number of elements in @mmc_supported
+ */
+int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported,
+		 int num_ids);
 
 /* Set block count limit because of 16 bit register limit on some hardware*/
 #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
-- 
2.5.0

hi all

I change the EMMC to SanDisk iNAND 7232 32G(EMMC 5.1).
how do i bring up this EMMC?
I think i need to add this patch from Mike_0b and modify the BCT file.

could everyone provide some suggestion ?

I have change the emmc to a 5.1.1 32GB device THGBMHG8C4LBAIR . The flashing of the board is successful,but it failed to boot,stopping with the message waiting for root device /dev/mmcblk0p1.

could everyone provide some suggestion ? Thanks for your help

Hello,
From software point, if flashing device successfully, please check whether u-boot can boot. if not, please check the log and find out what’s the error. if yes, please try ext4 commands in u-boot and check whether file can be loaded in u-boot.

BCT file contains EMC (DDR) configurations, and that’s not related to EMMC.
jetson-tk1.conf deserves a look, which contains EMMCSIZE/ROOTFSSIZE.
the included gnu_linux_fastboot_emmc_full.cfg describes layout of EMMC.

br
ChenJian

Hi Guys,

We are facing with very strange problem on bootloader. We created custom board based on TK1 CD575M - A1 with SDIN8DE4 - 16G Taiwan made one and SKYHYNIX CFR-PBA 4 rams. We did full SHMOO test successfully and created necessary files. Successfully flashed IMG files in to the system. However, system stops on very early stage of the booting.

It is very strange because when we flash android os on this exact same system it works. Last month, we made 10pcs of exact same sample boards which were working fine. When we flash L4T in to this system, it shows following error. Please help us to sort out this issue guys. Thanks!

Here I attached my log and i have no clue with this problem at all.

U-Boot SPL 2014.10-rc2-g3127911 (Jun 07 2016 - 21:00:01)                        
                                                                                
                                                                                
U-Boot 2014.10-rc2-g3127911 (Jun 07 2016 - 21:00:01)                            
                                                                                
TEGRA124                                                                        
Board: NVIDIA Jetson TK1                                                        
I2C:   ready                                                                    
DRAM:  2 GiB                                                                    
MMC:   Tegra SD/MMC: 0, Tegra SD/MMC: 1                                         
*** Warning - bad CRC, using default environment                                
                                                                                
tegra-pcie: PCI regions:                                                        
tegra-pcie:   I/O: 0x12000000-0x12010000                                        
tegra-pcie:   non-prefetchable memory: 0x13000000-0x20000000                    
tegra-pcie:   prefetchable memory: 0x20000000-0x40000000                        
tegra-pcie: 2x1, 1x1 configuration                                              
ERROR: tegra-pcie: failed to power on PHY: -110                                 
                                                   
at /dvs/git/dirty/git-master_linux/3rdparty/u-boot/drivers/pci/pci_tegra.c:740/)
ERROR: tegra-pcie: failed to enable controller                                  
at /dvs/git/dirty/git-master_linux/3rdparty/u-boot/drivers/pci/pci_tegra.c:1055)
In:    serial                                                                   
Out:   serial                                                                   
Err:   serial                                                                   
Net:   No ethernet found.                                                       
Hit any key to stop autoboot:  0                                                
MMC: no card present                                                            
switch to partitions #0, OK                                                     
mmc0(part 0) is current device                                                  
Scanning mmc 0...                                                               
GPT: last_usable_lba incorrect: 1D58FFF > 1D52000                               
get_partition_info_efi: *** ERROR: Invalid GPT ***                              
GPT: my_lba incorrect: 1D59FFF != 1D51FFF                                       
get_partition_info_efi: *** ERROR: Invalid Backup GPT ***                       
** Invalid partition 1 **                                                       
GPT: last_usable_lba incorrect: 1D58FFF > 1D52000                               
get_partition_info_efi: *** ERROR: Invalid GPT ***                              
GPT: my_lba incorrect: 1D59FFF != 1D51FFF                                       
get_partition_info_efi: *** ERROR: Invalid Backup GPT ***                       
** Invalid partition 1 **                                                       
GPT: last_usable_lba incorrect: 1D58FFF > 1D52000                               
get_partition_info_efi: *** ERROR: Invalid GPT ***                              
GPT: my_lba incorrect: 1D59FFF != 1D51FFF                                       
get_partition_info_efi: *** ERROR: Invalid Backup GPT ***                       
** Invalid partition 1 **                                                       
GPT: last_usable_lba incorrect: 1D58FFF > 1D52000                               
get_partition_info_efi: *** ERROR: Invalid GPT ***                              
GPT: my_lba incorrect: 1D59FFF != 1D51FFF                                       
get_partition_info_efi: *** ERROR: Invalid Backup GPT ***                       
** Invalid partition 1 **                                                       
GPT: last_usable_lba incorrect: 1D58FFF > 1D52000                               
get_partition_info_efi: *** ERROR: Invalid GPT ***                              
GPT: my_lba incorrect: 1D59FFF != 1D51FFF                                       
get_partition_info_efi: *** ERROR: Invalid Backup GPT ***                       
** Invalid partition 1 **                                                       
GPT: last_usable_lba incorrect: 1D58FFF > 1D52000                               
get_partition_info_efi: *** ERROR: Invalid GPT ***                              
GPT: my_lba incorrect: 1D59FFF != 1D51FFF                                       
get_partition_info_efi: *** ERROR: Invalid Backup GPT ***                       
** Invalid partition 1 **                                                       
(Re)start USB...                                                                
USB0:   USB EHCI 1.10                                                           
scanning bus 0 for devices... 1 USB Device(s) found                             
USB1:   USB EHCI 1.10                                                           
scanning bus 1 for devices... 1 USB Device(s) found                             
       scanning usb for storage devices... 0 Storage Device(s) found            
       scanning usb for ethernet devices... 0 Ethernet Device(s) found          
                                                                                
USB device 0: unknown device                                                    
No ethernet found.                                                              
missing environment variable: pxeuuid                                           
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/00000000                                          
No ethernet found.                                                              
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/0000000                                           
No ethernet found.                                                              
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/000000                                            
No ethernet found.                                                              
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/00000                                             
No ethernet found.                                                              
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/0000                                              
No ethernet found.                                                              
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/000                                               
No ethernet found.                                                              
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/00                                                
No ethernet found.                                                              
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/0                                                 
No ethernet found.                                                              
missing environment variable: bootfile                                          
Retrieving file: pxelinux.cfg/default-arm-tegra124                              
No ethernet found.                                                              
missing..