Merge branch 'master' of git://git.denx.de/u-boot-arm
[platform/kernel/u-boot.git] / drivers / mmc / mmc.c
index 0b552f5..c6a1c23 100644 (file)
@@ -15,6 +15,7 @@
 #include <malloc.h>
 #include <linux/list.h>
 #include <div64.h>
+#include "mmc_private.h"
 
 /* Set block count limit because of 16 bit register limit on some hardware*/
 #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
@@ -52,8 +53,7 @@ int __board_mmc_getcd(struct mmc *mmc) {
 int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
        alias("__board_mmc_getcd")));
 
-static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
-                       struct mmc_data *data)
+int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 {
        int ret;
 
@@ -111,7 +111,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
        return ret;
 }
 
-static int mmc_send_status(struct mmc *mmc, int timeout)
+int mmc_send_status(struct mmc *mmc, int timeout)
 {
        struct mmc_cmd cmd;
        int err, retries = 5;
@@ -132,8 +132,10 @@ static int mmc_send_status(struct mmc *mmc, int timeout)
                             MMC_STATE_PRG)
                                break;
                        else if (cmd.response[0] & MMC_STATUS_MASK) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
                                printf("Status Error: 0x%08X\n",
                                        cmd.response[0]);
+#endif
                                return COMM_ERR;
                        }
                } else if (--retries < 0)
@@ -148,14 +150,16 @@ static int mmc_send_status(struct mmc *mmc, int timeout)
        printf("CURR STATE:%d\n", status);
 #endif
        if (timeout <= 0) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
                printf("Timeout waiting card ready\n");
+#endif
                return TIMEOUT;
        }
 
        return 0;
 }
 
-static int mmc_set_blocklen(struct mmc *mmc, int len)
+int mmc_set_blocklen(struct mmc *mmc, int len)
 {
        struct mmc_cmd cmd;
 
@@ -178,179 +182,13 @@ struct mmc *find_mmc_device(int dev_num)
                        return m;
        }
 
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
        printf("MMC Device %d not found\n", dev_num);
+#endif
 
        return NULL;
 }
 
-static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
-{
-       struct mmc_cmd cmd;
-       ulong end;
-       int err, start_cmd, end_cmd;
-
-       if (mmc->high_capacity)
-               end = start + blkcnt - 1;
-       else {
-               end = (start + blkcnt - 1) * mmc->write_bl_len;
-               start *= mmc->write_bl_len;
-       }
-
-       if (IS_SD(mmc)) {
-               start_cmd = SD_CMD_ERASE_WR_BLK_START;
-               end_cmd = SD_CMD_ERASE_WR_BLK_END;
-       } else {
-               start_cmd = MMC_CMD_ERASE_GROUP_START;
-               end_cmd = MMC_CMD_ERASE_GROUP_END;
-       }
-
-       cmd.cmdidx = start_cmd;
-       cmd.cmdarg = start;
-       cmd.resp_type = MMC_RSP_R1;
-
-       err = mmc_send_cmd(mmc, &cmd, NULL);
-       if (err)
-               goto err_out;
-
-       cmd.cmdidx = end_cmd;
-       cmd.cmdarg = end;
-
-       err = mmc_send_cmd(mmc, &cmd, NULL);
-       if (err)
-               goto err_out;
-
-       cmd.cmdidx = MMC_CMD_ERASE;
-       cmd.cmdarg = SECURE_ERASE;
-       cmd.resp_type = MMC_RSP_R1b;
-
-       err = mmc_send_cmd(mmc, &cmd, NULL);
-       if (err)
-               goto err_out;
-
-       return 0;
-
-err_out:
-       puts("mmc erase failed\n");
-       return err;
-}
-
-static unsigned long
-mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
-{
-       int err = 0;
-       struct mmc *mmc = find_mmc_device(dev_num);
-       lbaint_t blk = 0, blk_r = 0;
-       int timeout = 1000;
-
-       if (!mmc)
-               return -1;
-
-       if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
-               printf("\n\nCaution! Your devices Erase group is 0x%x\n"
-                      "The erase range would be change to "
-                      "0x" LBAF "~0x" LBAF "\n\n",
-                      mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
-                      ((start + blkcnt + mmc->erase_grp_size)
-                      & ~(mmc->erase_grp_size - 1)) - 1);
-
-       while (blk < blkcnt) {
-               blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
-                       mmc->erase_grp_size : (blkcnt - blk);
-               err = mmc_erase_t(mmc, start + blk, blk_r);
-               if (err)
-                       break;
-
-               blk += blk_r;
-
-               /* Waiting for the ready status */
-               if (mmc_send_status(mmc, timeout))
-                       return 0;
-       }
-
-       return blk;
-}
-
-static ulong
-mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src)
-{
-       struct mmc_cmd cmd;
-       struct mmc_data data;
-       int timeout = 1000;
-
-       if ((start + blkcnt) > mmc->block_dev.lba) {
-               printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
-                       start + blkcnt, mmc->block_dev.lba);
-               return 0;
-       }
-
-       if (blkcnt == 0)
-               return 0;
-       else if (blkcnt == 1)
-               cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
-       else
-               cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
-
-       if (mmc->high_capacity)
-               cmd.cmdarg = start;
-       else
-               cmd.cmdarg = start * mmc->write_bl_len;
-
-       cmd.resp_type = MMC_RSP_R1;
-
-       data.src = src;
-       data.blocks = blkcnt;
-       data.blocksize = mmc->write_bl_len;
-       data.flags = MMC_DATA_WRITE;
-
-       if (mmc_send_cmd(mmc, &cmd, &data)) {
-               printf("mmc write failed\n");
-               return 0;
-       }
-
-       /* SPI multiblock writes terminate using a special
-        * token, not a STOP_TRANSMISSION request.
-        */
-       if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
-               cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
-               cmd.cmdarg = 0;
-               cmd.resp_type = MMC_RSP_R1b;
-               if (mmc_send_cmd(mmc, &cmd, NULL)) {
-                       printf("mmc fail to send stop cmd\n");
-                       return 0;
-               }
-       }
-
-       /* Waiting for the ready status */
-       if (mmc_send_status(mmc, timeout))
-               return 0;
-
-       return blkcnt;
-}
-
-static ulong
-mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src)
-{
-       lbaint_t cur, blocks_todo = blkcnt;
-
-       struct mmc *mmc = find_mmc_device(dev_num);
-       if (!mmc)
-               return 0;
-
-       if (mmc_set_blocklen(mmc, mmc->write_bl_len))
-               return 0;
-
-       do {
-               cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
-               if(mmc_write_blocks(mmc, start, cur, src) != cur)
-                       return 0;
-               blocks_todo -= cur;
-               start += cur;
-               src += cur * mmc->write_bl_len;
-       } while (blocks_todo > 0);
-
-       return blkcnt;
-}
-
 static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
                           lbaint_t blkcnt)
 {
@@ -382,7 +220,9 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
                cmd.cmdarg = 0;
                cmd.resp_type = MMC_RSP_R1b;
                if (mmc_send_cmd(mmc, &cmd, NULL)) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
                        printf("mmc fail to send stop cmd\n");
+#endif
                        return 0;
                }
        }
@@ -402,8 +242,10 @@ static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
                return 0;
 
        if ((start + blkcnt) > mmc->block_dev.lba) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
                printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
                        start + blkcnt, mmc->block_dev.lba);
+#endif
                return 0;
        }
 
@@ -1035,6 +877,7 @@ static int mmc_startup(struct mmc *mmc)
 
        mmc->tran_speed = freq * mult;
 
+       mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
        mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
 
        if (IS_SD(mmc))
@@ -1065,6 +908,14 @@ static int mmc_startup(struct mmc *mmc)
        if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
                mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
 
+       if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
+               cmd.cmdidx = MMC_CMD_SET_DSR;
+               cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
+               cmd.resp_type = MMC_RSP_NONE;
+               if (mmc_send_cmd(mmc, &cmd, NULL))
+                       printf("MMC: SET_DSR failed\n");
+       }
+
        /* Select the card, and put it into Transfer Mode */
        if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
                cmd.cmdidx = MMC_CMD_SELECT_CARD;
@@ -1118,15 +969,24 @@ static int mmc_startup(struct mmc *mmc)
                }
 
                /*
-                * Check whether GROUP_DEF is set, if yes, read out
-                * group size from ext_csd directly, or calculate
-                * the group size from the csd value.
+                * 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_ERASE_GROUP_DEF]) {
+               if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
+                   (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) {
+                       err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_ERASE_GROUP_DEF, 1);
+
+                       if (err)
+                               return err;
+
+                       /* Read out group size from ext_csd */
                        mmc->erase_grp_size =
                                ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
                                        MMC_MAX_BLOCK_LEN * 1024;
                } else {
+                       /* Calculate the group size from the csd value. */
                        int erase_gsz, erase_gmul;
                        erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
                        erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
@@ -1265,6 +1125,7 @@ static int mmc_startup(struct mmc *mmc)
        mmc->block_dev.blksz = mmc->read_bl_len;
        mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
        mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
        sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
                mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
                (mmc->cid[3] >> 16) & 0xffff);
@@ -1274,6 +1135,11 @@ static int mmc_startup(struct mmc *mmc)
                (mmc->cid[2] >> 24) & 0xff);
        sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
                (mmc->cid[2] >> 16) & 0xf);
+#else
+       mmc->block_dev.vendor[0] = 0;
+       mmc->block_dev.product[0] = 0;
+       mmc->block_dev.revision[0] = 0;
+#endif
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
        init_part(&mmc->block_dev);
 #endif
@@ -1306,6 +1172,9 @@ static int mmc_send_if_cond(struct mmc *mmc)
 
 int mmc_register(struct mmc *mmc)
 {
+       /* Setup dsr related values */
+       mmc->dsr_imp = 0;
+       mmc->dsr = 0xffffffff;
        /* Setup the universal parts of the block interface just once */
        mmc->block_dev.if_type = IF_TYPE_MMC;
        mmc->block_dev.dev = cur_dev_num++;
@@ -1340,7 +1209,9 @@ int mmc_start_init(struct mmc *mmc)
 
        if (mmc_getcd(mmc) == 0) {
                mmc->has_init = 0;
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
                printf("MMC: no card present\n");
+#endif
                return NO_CARD_ERR;
        }
 
@@ -1375,7 +1246,9 @@ int mmc_start_init(struct mmc *mmc)
                err = mmc_send_op_cond(mmc);
 
                if (err && err != IN_PROGRESS) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
                        printf("Card did not respond to voltage select!\n");
+#endif
                        return UNUSABLE_ERR;
                }
        }
@@ -1419,6 +1292,12 @@ int mmc_init(struct mmc *mmc)
        return err;
 }
 
+int mmc_set_dsr(struct mmc *mmc, u16 val)
+{
+       mmc->dsr = val;
+       return 0;
+}
+
 /*
  * CPU and board-specific MMC initializations.  Aliased function
  * signals caller to move on
@@ -1431,6 +1310,8 @@ static int __def_mmc_init(bd_t *bis)
 int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
 int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
 
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+
 void print_mmc_devices(char separator)
 {
        struct mmc *m;
@@ -1448,6 +1329,10 @@ void print_mmc_devices(char separator)
        printf("\n");
 }
 
+#else
+void print_mmc_devices(char separator) { }
+#endif
+
 int get_mmc_num(void)
 {
        return cur_dev_num;