diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index e266d4fa43..176646d462 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -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 diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index cdf2713bad..1d089a7d11 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -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; } /* diff --git a/include/mmc.h b/include/mmc.h index 5501f5547a..aeacdee309 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -138,6 +138,7 @@ * 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 */ @@ -179,6 +180,9 @@ #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);