]> git.sur5r.net Git - u-boot/commitdiff
mmc: enable partition switch function for emmc
authorLei Wen <leiwen@marvell.com>
Mon, 2 May 2011 16:26:26 +0000 (16:26 +0000)
committerAndy Fleming <afleming@freescale.com>
Wed, 18 May 2011 19:37:03 +0000 (14:37 -0500)
For emmc, it may have up to 7 partitions: two boot partitions, one
user partition, one RPMB partition and four general purpose partitions.
(Refer to JESD84-A44.pdf/page 154)

As bootloader may need to read out or reflashing images on those

different partitions, it is better to enable the partition switch with
console command support.

Also for partition would be restore to user partition(part 0) when CMD0
is used, so change mmc_init routine to perform normal initialization
only once for each slot, unless use the rescan command to force init
again.

Signed-off-by: Lei Wen <leiwen@marvell.com>
Acked-by: Andy Fleming <afleming@freescale.com>
common/cmd_mmc.c
drivers/mmc/mmc.c
include/mmc.h

index e266d4fa43ffc047134b58ce56ec07ea87ff65db..176646d4627bfa18e5b627d28956629ce78246ef 100644 (file)
@@ -164,6 +164,7 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                        return 1;
                }
 
+               mmc->has_init = 0;
                mmc_init(mmc);
 
                return 0;
@@ -189,14 +190,22 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                print_mmc_devices('\n');
                return 0;
        } else if (strcmp(argv[1], "dev") == 0) {
-               int dev;
+               int dev, part = -1;
                struct mmc *mmc;
 
                if (argc == 2)
                        dev = curr_device;
                else if (argc == 3)
                        dev = simple_strtoul(argv[2], NULL, 10);
-               else
+               else if (argc == 4) {
+                       dev = (int)simple_strtoul(argv[2], NULL, 10);
+                       part = (int)simple_strtoul(argv[3], NULL, 10);
+                       if (part > PART_ACCESS_MASK) {
+                               printf("#part_num shouldn't be larger"
+                                       " than %d\n", PART_ACCESS_MASK);
+                               return 1;
+                       }
+               } else
                        return cmd_usage(cmdtp);
 
                mmc = find_mmc_device(dev);
@@ -205,8 +214,29 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                        return 1;
                }
 
+               mmc_init(mmc);
+               if (part != -1) {
+                       int ret;
+                       if (mmc->part_config == MMCPART_NOAVAILABLE) {
+                               printf("Card doesn't support part_switch\n");
+                               return 1;
+                       }
+
+                       if (part != mmc->part_num) {
+                               ret = mmc_switch_part(dev, part);
+                               if (!ret)
+                                       mmc->part_num = part;
+
+                               printf("switch to partions #%d, %s\n",
+                                               part, (!ret) ? "OK" : "ERROR");
+                       }
+               }
                curr_device = dev;
-               printf("mmc%d is current device\n", curr_device);
+               if (mmc->part_config == MMCPART_NOAVAILABLE)
+                       printf("mmc%d is current device\n", curr_device);
+               else
+                       printf("mmc%d(part %d) is current device\n",
+                               curr_device, mmc->part_num);
 
                return 0;
        } else if (strcmp(argv[1], "read") == 0) {
@@ -269,6 +299,6 @@ U_BOOT_CMD(
        "mmc write addr blk# cnt\n"
        "mmc rescan\n"
        "mmc part - lists available partition on current mmc device\n"
-       "mmc dev [dev] - show or set current mmc device\n"
+       "mmc dev [dev] [part] - show or set current mmc device [partition]\n"
        "mmc list - lists available devices");
 #endif
index cdf2713bad402de98f3a8313e216642eb5d1d158..1d089a7d11e2c3bfa3079e6e83a775e6b3b32e4b 100644 (file)
@@ -577,6 +577,18 @@ int mmc_change_freq(struct mmc *mmc)
        return 0;
 }
 
+int mmc_switch_part(int dev_num, unsigned int part_num)
+{
+       struct mmc *mmc = find_mmc_device(dev_num);
+
+       if (!mmc)
+               return -1;
+
+       return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
+                         (mmc->part_config & ~PART_ACCESS_MASK)
+                         | (part_num & PART_ACCESS_MASK));
+}
+
 int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
 {
        struct mmc_cmd cmd;
@@ -899,6 +911,7 @@ int mmc_startup(struct mmc *mmc)
                        return err;
        }
 
+       mmc->part_config = MMCPART_NOAVAILABLE;
        if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
                /* check  ext_csd version and capacity */
                err = mmc_send_ext_csd(mmc, ext_csd);
@@ -907,6 +920,10 @@ int mmc_startup(struct mmc *mmc)
                                        ext_csd[214] << 16 | ext_csd[215] << 24;
                        mmc->capacity *= 512;
                }
+
+               /* store the partition info of emmc */
+               if (ext_csd[160] & PART_SUPPORT)
+                       mmc->part_config = ext_csd[179];
        }
 
        if (IS_SD(mmc))
@@ -1048,6 +1065,9 @@ int mmc_init(struct mmc *mmc)
 {
        int err;
 
+       if (mmc->has_init)
+               return 0;
+
        err = mmc->init(mmc);
 
        if (err)
@@ -1062,6 +1082,9 @@ int mmc_init(struct mmc *mmc)
        if (err)
                return err;
 
+       /* The internal partition reset to user partition(0) at every CMD0*/
+       mmc->part_num = 0;
+
        /* Test for SD version 2 */
        err = mmc_send_if_cond(mmc);
 
@@ -1078,7 +1101,12 @@ int mmc_init(struct mmc *mmc)
                }
        }
 
-       return mmc_startup(mmc);
+       err = mmc_startup(mmc);
+       if (err)
+               mmc->has_init = 0;
+       else
+               mmc->has_init = 1;
+       return err;
 }
 
 /*
index 5501f5547a47c58e8fe42cc0aa6c7210cc5b0a65..aeacdee3095d8a5356b791b11944ea54587800dd 100644 (file)
  * EXT_CSD fields
  */
 
+#define EXT_CSD_PART_CONF      179     /* R/W */
 #define EXT_CSD_BUS_WIDTH      183     /* R/W */
 #define EXT_CSD_HS_TIMING      185     /* R/W */
 #define EXT_CSD_CARD_TYPE      196     /* RO */
 #define MMC_RSP_R6     (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
 #define MMC_RSP_R7     (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
 
+#define MMCPART_NOAVAILABLE    (0xff)
+#define PART_ACCESS_MASK       (0x7)
+#define PART_SUPPORT           (0x1)
 
 struct mmc_cid {
        unsigned long psn;
@@ -263,6 +267,7 @@ struct mmc {
        void *priv;
        uint voltages;
        uint version;
+       uint has_init;
        uint f_min;
        uint f_max;
        int high_capacity;
@@ -275,6 +280,8 @@ struct mmc {
        uint csd[4];
        uint cid[4];
        ushort rca;
+       char part_config;
+       char part_num;
        uint tran_speed;
        uint read_bl_len;
        uint write_bl_len;
@@ -297,6 +304,7 @@ int mmc_set_dev(int dev_num);
 void print_mmc_devices(char separator);
 int get_mmc_num(void);
 int board_mmc_getcd(u8 *cd, struct mmc *mmc);
+int mmc_switch_part(int dev_num, unsigned int part_num);
 
 #ifdef CONFIG_GENERIC_MMC
 int atmel_mci_init(void *regs);