]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/mmc/mmc.c
update to 2015.04-rc1
[karo-tx-uboot.git] / drivers / mmc / mmc.c
index 2a42e503d50e96b81763b5a321d9bef8c7582d2f..85e9509ed19374115421bcc6fc5ba10c380f0a24 100644 (file)
@@ -324,8 +324,7 @@ static int sd_send_op_cond(struct mmc *mmc)
 
                udelay(1000);
        } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
-
-       if (timeout <= 0)
+       if (!(cmd.response[0] & OCR_BUSY))
                return UNUSABLE_ERR;
 
        if (mmc->version != SD_VERSION_2)
@@ -383,7 +382,7 @@ static int mmc_send_op_cond(struct mmc *mmc)
        /* Some cards seem to need this */
        mmc_go_idle(mmc);
 
-       /* Asking to the card its capabilities */
+       /* 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);
@@ -411,9 +410,13 @@ static int mmc_complete_op_cond(struct mmc *mmc)
                if (err)
                        return err;
                if (get_timer(start) > timeout)
-                       return UNUSABLE_ERR;
+                       break;
                udelay(100);
        } while (!(mmc->op_cond_response & OCR_BUSY));
+       if (!(mmc->op_cond_response & OCR_BUSY)) {
+               debug("%s: timeout\n", __func__);
+               return UNUSABLE_ERR;
+       }
 
        if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
                cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
@@ -486,7 +489,7 @@ static int mmc_change_freq(struct mmc *mmc)
        char cardtype;
        int err;
 
-       mmc->card_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
+       mmc->card_caps = 0;
 
        if (mmc_host_is_spi(mmc))
                return 0;
@@ -495,6 +498,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)
@@ -615,6 +620,7 @@ int mmc_hwpart_config(struct mmc *mmc,
        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);
 
@@ -689,6 +695,33 @@ int mmc_hwpart_config(struct mmc *mmc,
                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");
@@ -746,6 +779,17 @@ int mmc_hwpart_config(struct mmc *mmc,
        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
@@ -1267,6 +1311,8 @@ static int mmc_startup(struct mmc *mmc)
                mmc->hc_wp_grp_size = 1024
                        * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
                        * 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);
@@ -1308,7 +1354,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 */
@@ -1339,6 +1386,18 @@ static int mmc_startup(struct mmc *mmc)
                        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 card and controller support
                         * these capabilities