]> git.karo-electronics.de Git - karo-tx-uboot.git/commitdiff
mmc: eMMC partitioning data is not effective till partitioning completed
authorDiego Santa Cruz <Diego.SantaCruz@spinetix.com>
Tue, 23 Dec 2014 09:50:27 +0000 (10:50 +0100)
committerPantelis Antoniou <pantelis.antoniou@konsulko.com>
Mon, 19 Jan 2015 15:04:48 +0000 (17:04 +0200)
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>
drivers/mmc/mmc.c

index 16a7a90398fa33e1841d36d73088fdb4d8ad8ee0..403843b104dc78fbab40f04bc2e07dc7d00c26f3 100644 (file)
@@ -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) |