From patchwork Sat Apr 16 02:17:32 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lei Wen X-Patchwork-Id: 91469 X-Patchwork-Delegate: afleming@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 10BD61007D1 for ; Sat, 16 Apr 2011 12:18:18 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id ABD6528127; Sat, 16 Apr 2011 04:18:11 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3VMsbhk1T0db; Sat, 16 Apr 2011 04:18:11 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 4152928130; Sat, 16 Apr 2011 04:17:58 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 4D8E72811F for ; Sat, 16 Apr 2011 04:17:55 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Aj10N7M1UE0z for ; Sat, 16 Apr 2011 04:17:54 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from dakia2.marvell.com (dakia2.marvell.com [65.219.4.35]) by theia.denx.de (Postfix) with ESMTPS id 1737E28131 for ; Sat, 16 Apr 2011 04:17:53 +0200 (CEST) X-ASG-Debug-ID: 1302920271-082d68fd0001-4l7tJC Received: from maili.marvell.com (maili.marvell.com [10.68.76.51]) by dakia2.marvell.com with ESMTP id pf7XuZbgo6E3Wp7w; Fri, 15 Apr 2011 19:17:51 -0700 (PDT) X-Barracuda-Envelope-From: leiwen@marvell.com Received: from localhost (unknown [10.38.12.124]) by maili.marvell.com (Postfix) with ESMTP id 0D9838A07D; Fri, 15 Apr 2011 19:17:50 -0700 (PDT) From: Lei Wen To: Wolfgang Denk , u-boot@lists.denx.de, Andy Fleming , adrian.wenl@gmail.com X-ASG-Orig-Subj: [PATCH V2 2/2] mmc: enable partition switch fucntion for emmc Date: Fri, 15 Apr 2011 19:17:32 -0700 X-ASG-Orig-Subj: [PATCH V2 2/2] mmc: enable partition switch fucntion for emmc Message-Id: <1302920252-6274-3-git-send-email-leiwen@marvell.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <20110413054941.4E5C1151F83@gemini.denx.de> References: <20110413054941.4E5C1151F83@gemini.denx.de> X-Barracuda-Connect: maili.marvell.com[10.68.76.51] X-Barracuda-Start-Time: 1302920271 X-Barracuda-URL: http://10.68.76.222:80/cgi-mod/mark.cgi X-Barracuda-Spam-Score: -1002.00 X-Barracuda-Spam-Status: No, SCORE=-1002.00 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=1000.0 Subject: [U-Boot] [PATCH V2 2/2] mmc: enable partition switch fucntion for emmc X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de For emmc, it may has upto 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 --- Changelog: V2: change the switch parittion command per Wolfgang's suggestion common/cmd_mmc.c | 35 ++++++++++++++++++++++++++++++++--- drivers/mmc/mmc.c | 30 +++++++++++++++++++++++++++++- include/mmc.h | 8 ++++++++ 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index dd4ee23..333a1ff 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -147,6 +147,7 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (!mmc) return 1; + mmc->has_init = 0; mmc_init(mmc); return 0; @@ -172,7 +173,7 @@ 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 = mmc_cur_dev; + int dev = mmc_cur_dev, part = -1; struct mmc *mmc; if (argc == 2) { @@ -183,6 +184,14 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } else if (argc == 3) { dev = simple_strtoul(argv[2], NULL, 10); + } 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); } @@ -193,8 +202,28 @@ 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"); + } mmc_cur_dev = dev; - printf("mmc%d is current device\n", mmc_cur_dev); + if (mmc->part_config == MMCPART_NOAVAILABLE) + printf("mmc%d is current device\n", mmc_cur_dev); + else + printf("mmc%d(part %d) is current device\n", + mmc_cur_dev, mmc->part_num); return 0; } else if (strcmp(argv[1], "read") == 0) { @@ -253,6 +282,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 377f13a..ae520a1 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -428,6 +428,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; @@ -725,6 +737,7 @@ int mmc_startup(struct mmc *mmc) if (err) 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); @@ -733,6 +746,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)) @@ -872,6 +889,9 @@ int mmc_init(struct mmc *mmc) { int err; + if (mmc->has_init) + return 0; + err = mmc->init(mmc); if (err) @@ -886,6 +906,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); @@ -902,7 +925,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 dd9bf15..44435ac 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -128,6 +128,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 */ @@ -169,6 +170,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; @@ -253,6 +257,7 @@ struct mmc { void *priv; uint voltages; uint version; + uint has_init; uint f_min; uint f_max; int high_capacity; @@ -265,6 +270,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; @@ -288,6 +295,7 @@ struct mmc *find_mmc_device(int dev_num); int mmc_set_dev(int dev_num); void print_mmc_devices(char separator); 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);