diff mbox

[U-Boot,12/18] mmc: eMMC partitioning data is not effective till partitioning completed

Message ID 1417165845-30960-13-git-send-email-Diego.SantaCruz@spinetix.com
State Superseded
Delegated to: Pantelis Antoniou
Headers show

Commit Message

Diego Santa Cruz Nov. 28, 2014, 9:10 a.m. UTC
The eMMC spec says that partitioning is only effective after the
PARTITION_SETTING_COMPLETED is set in EXT_CSD (and a power cycle was done,
but that we cannot know). Thus the partition sizes and attributes should
be ignored when that bit is not set, otherwise the various capacities
are not coherent (e.g., the user data capacity will be that of the
unpartitioned device while partition sizes would be non-zero).

Prescence of non-zero partitioning data is nevertheless still used to
activate the high-capacity size definitions (EXT_CSD_ERASE_GROUP_DEF)
as it is necessary to set that to write any of the partitioning fields
in EXT_CSD, so having partitioning data means someone previously
activated that and we should keep it activated.
---
 drivers/mmc/mmc.c |   53 ++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 34 insertions(+), 19 deletions(-)
diff mbox

Patch

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 3879899..f545576 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -819,6 +819,7 @@  static int mmc_startup(struct mmc *mmc)
 	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 */
@@ -1004,12 +1005,21 @@  static int mmc_startup(struct mmc *mmc)
 			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_PART_SETTING_COMPLETED] &
+				    PART_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 (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)
+		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;
@@ -1018,37 +1028,42 @@  static int mmc_startup(struct mmc *mmc)
 
 		for (i = 0; i < 4; i++) {
 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
-			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
+			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 (mmc->capacity_gp[i])
-				has_parts = true;
 		}
 
-		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;
+		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;
+		}
 
 		/*
 		 * Host needs to enable ERASE_GRP_DEF bit if device is
 		 * partitioned. This bit will be lost every time after a reset
 		 * or power off. This will affect erase size.
 		 */
-		if (ext_csd[EXT_CSD_PART_SETTING_COMPLETED] & PART_SETTING_COMPLETED)
+		if (part_completed)
 			has_parts = true;
 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))