summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2010-07-23 16:38:06 +0800
committerJustin Waters <justin.waters@timesys.com>2010-12-13 16:09:42 -0500
commit286fee097a74975c03597b4f2aa99a3ea8503b19 (patch)
tree00861e2f428143fce9f18bcdf800d6de0a14022e
parent76cbbd0bb3e31cacd7e648cb556ffbe1105553d4 (diff)
ENGR00125411 eMMC: Boot Partition switch func used in MFG tool
User can get eMMC partitions info from user space layer in linux OS enviroment. User can do switch operations between the eMMC boot partitions and the user partition. User can access the eMMC boot partitions from user space layer in linux OS enviroment. NOTE:This func had been verified on TOSHIBA eMMC44 card only. Signed-off-by: Richard Zhu <r65037@freescale.com> Signed-off-by: Rob Herring <r.herring@freescale.com>
-rw-r--r--drivers/mmc/core/mmc.c105
-rw-r--r--include/linux/mmc/card.h3
-rw-r--r--include/linux/mmc/mmc.h5
3 files changed, 113 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index bd55760b66cd..1d29985e3a34 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -226,6 +226,9 @@ static int mmc_read_ext_csd(struct mmc_card *card)
mmc_card_set_blockaddr(card);
}
+ card->ext_csd.boot_info = ext_csd[EXT_CSD_BOOT_INFO];
+ card->ext_csd.boot_size_mult = ext_csd[EXT_CSD_BOOT_SIZE_MULT];
+ card->ext_csd.boot_config = ext_csd[EXT_CSD_BOOT_CONFIG];
card->ext_csd.card_type = ext_csd[EXT_CSD_CARD_TYPE];
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
@@ -260,6 +263,102 @@ out:
return err;
}
+/* switch the partitions */
+static ssize_t
+switch_partitions(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ u32 part, new_part;
+ u8 *ext_csd, boot_config;
+ struct mmc_card *card = container_of(dev, struct mmc_card, dev);
+ struct mmc_host *host = card->host;
+
+ BUG_ON(!card);
+
+ mmc_claim_host(card->host);
+ sscanf(buf, "%d\n", &part);
+
+ /* partition must be -
+ * 0 - user area
+ * 1 - boot partition 1
+ * 2 - boot partition 2
+ */
+ if (part > 2) {
+ printk(KERN_ERR "%s: wrong partition id"
+ " 0 (user area), 1 (boot1), 2 (boot2)\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
+ if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
+ printk(KERN_ERR "%s: invalid mmc version"
+ " mmc version is below version 4!)\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
+ /* it's a normal SD/MMC but user request to configure boot partition */
+ if (card->ext_csd.boot_size_mult <= 0) {
+ printk(KERN_ERR "%s: this is a normal SD/MMC card"
+ " but you request to access boot partition!\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ printk(KERN_ERR "%s: could not allocate a buffer to "
+ "receive the ext_csd.\n", mmc_hostname(card->host));
+ return -ENOMEM;
+ }
+
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err) {
+ printk(KERN_ERR "%s: unable to read EXT_CSD.\n",
+ mmc_hostname(card->host));
+ goto err_rtn;
+ }
+
+ /* Send SWITCH command to change partition for access */
+ boot_config = (ext_csd[EXT_CSD_BOOT_CONFIG] &
+ ~EXT_CSD_BOOT_PARTITION_ACCESS_MASK) | part;
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_CONFIG, boot_config);
+ if (err) {
+ printk(KERN_ERR "%s: fail to send SWITCH command"
+ " to card to swich partition for access!\n",
+ mmc_hostname(card->host));
+ goto err_rtn;
+ }
+
+ /* Now check whether it works */
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err) {
+ printk(KERN_ERR "%s: %d unable to read EXT_CSD.\n",
+ mmc_hostname(card->host), err);
+ goto err_rtn;
+ }
+
+ new_part = ext_csd[EXT_CSD_BOOT_CONFIG] &
+ EXT_CSD_BOOT_PARTITION_ACCESS_MASK;
+ if (part != new_part) {
+ printk(KERN_ERR "%s: after SWITCH, current part id %d is not"
+ " same as requested partition %d!\n",
+ mmc_hostname(card->host), new_part, part);
+ goto err_rtn;
+ }
+ card->ext_csd.boot_config = ext_csd[EXT_CSD_BOOT_CONFIG];
+
+err_rtn:
+ mmc_release_host(card->host);
+ kfree(ext_csd);
+ if (err)
+ return err;
+ else
+ return count;
+}
+
MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
card->raw_cid[2], card->raw_cid[3]);
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
@@ -271,6 +370,10 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
+MMC_DEV_ATTR(boot_info, "Info:0x%02x;Size:0x%02xMB;Part:0x%02x\n",
+ card->ext_csd.boot_info, card->ext_csd.boot_size_mult / 8,
+ card->ext_csd.boot_config);
+DEVICE_ATTR(boot_config, S_IWUGO, NULL, switch_partitions);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
@@ -282,6 +385,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_name.attr,
&dev_attr_oemid.attr,
&dev_attr_serial.attr,
+ &dev_attr_boot_info.attr,
+ &dev_attr_boot_config.attr,
NULL,
};
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index abaab31fe845..1d9eceb396d8 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -46,6 +46,9 @@ struct mmc_ext_csd {
unsigned int sectors;
unsigned int card_type;
#define MMC_DDR_MODE_MASK (0x3<<2)
+ unsigned char boot_info;
+ unsigned char boot_size_mult;
+ unsigned char boot_config;
};
struct sd_scr {
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 4d54f3d1ea27..0ffc8fe3da3e 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -251,12 +251,15 @@ struct _mmc_csd {
* EXT_CSD fields
*/
+#define EXT_CSD_BOOT_CONFIG 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 EXT_CSD_REV 192 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217
+#define EXT_CSD_BOOT_SIZE_MULT 226 /* RO, 1 bytes */
+#define EXT_CSD_BOOT_INFO 228 /* RO, 1 bytes */
/*
* EXT_CSD field definitions
@@ -277,6 +280,8 @@ struct _mmc_csd {
#define EXT_CSD_BUS_WIDTH_4_DDR 5 /* Card is in 4 bit ddr mode */
#define EXT_CSD_BUS_WIDTH_8_DDR 6 /* Card is in 8 bit ddr mode */
+#define EXT_CSD_BOOT_PARTITION_ACCESS_MASK (0x3)
+
/*
* MMC_SWITCH access modes
*/