diff options
author | Diego Santa Cruz <Diego.SantaCruz@spinetix.com> | 2014-12-23 10:50:27 +0100 |
---|---|---|
committer | Pantelis Antoniou <pantelis.antoniou@konsulko.com> | 2015-01-19 17:04:48 +0200 |
commit | 8a0cf4901021b09c283f172d4d29d0d05721b0ba (patch) | |
tree | 7ca5956ce0f1187a02c3ae99ad940e65f40ac221 /drivers/mmc/mmc.c | |
parent | b0361526d5dc3b09d16fbb8f36fbf999cc064640 (diff) | |
download | u-boot-8a0cf4901021b09c283f172d4d29d0d05721b0ba.tar.gz u-boot-8a0cf4901021b09c283f172d4d29d0d05721b0ba.tar.xz u-boot-8a0cf4901021b09c283f172d4d29d0d05721b0ba.zip |
mmc: eMMC partitioning data is not effective till partitioning completed
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.
Signed-off-by: Diego Santa Cruz <Diego.SantaCruz@spinetix.com>
Diffstat (limited to 'drivers/mmc/mmc.c')
-rw-r--r-- | drivers/mmc/mmc.c | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 16a7a90398..403843b104 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 */ @@ -1007,12 +1008,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_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 (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; @@ -1021,38 +1031,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_PARTITION_SETTING] & - EXT_CSD_PARTITION_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)) @@ -1076,9 +1090,7 @@ static int mmc_startup(struct mmc *mmc) * SEC_COUNT is valid even if it is smaller than 2 GiB * JEDEC Standard JESD84-B45, 6.2.4 */ - if (mmc->high_capacity && - (ext_csd[EXT_CSD_PARTITION_SETTING] & - EXT_CSD_PARTITION_SETTING_COMPLETED)) { + 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) | |