2013-04-19 12:52:36

by Neil Armstrong

[permalink] [raw]
Subject: [PATCH 2/3] Add boot_enable sysfs attribute to select MMC boot operation partition

Add sysfs attribute to select the eMMC boot mode operation according to
the eMMC 4.5 specifications.
Valid values are : 0 for disabled, 1 for first boot partition, 2 for
second boot partition, 7 for user area.

Signed-off-by: Neil Armstrong <[email protected]>
---
drivers/mmc/card/block.c | 72
+++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 71 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 5bab73b..e11c42e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -114,6 +114,7 @@ struct mmc_blk_data {
*/
unsigned int part_curr;
struct device_attribute force_ro;
+ struct device_attribute boot_enable;
struct device_attribute power_ro_lock;
int area_type;
};
@@ -264,6 +265,23 @@ static ssize_t force_ro_show(struct device *dev,
struct device_attribute *attr,
return ret;
}

+static ssize_t boot_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct mmc_card *card;
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+ md = mmc_blk_get(dev_to_disk(dev));
+ card = md->queue.card;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d",
+ (card->ext_csd.part_config &
+ EXT_CSD_PART_CONFIG_EN_MASK) >> 3);
+ mmc_blk_put(md);
+ return ret;
+}
+
static ssize_t force_ro_store(struct device *dev, struct
device_attribute *attr,
const char *buf, size_t count)
{
@@ -283,6 +301,48 @@ out:
return ret;
}

+static ssize_t boot_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ char *end;
+ u8 part_config;
+ struct mmc_card *card;
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ unsigned long set = simple_strtoul(buf, &end, 0);
+ if (end == buf) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ md = mmc_blk_get(dev_to_disk(dev));
+ card = md->queue.card;
+
+ part_config = card->ext_csd.part_config;
+
+ part_config &= EXT_CSD_PART_CONFIG_EN_MASK;
+ part_config |= (set << 3) & EXT_CSD_PART_CONFIG_EN_MASK;
+
+ mmc_claim_host(card->host);
+
+ ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PART_CONFIG, part_config,
+ card->ext_csd.part_time);
+
+ mmc_release_host(card->host);
+
+ if (ret)
+ return ret;
+
+ card->ext_csd.part_config = part_config;
+
+ ret = count;
+out:
+ mmc_blk_put(md);
+ return ret;
+}
+
static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -2202,6 +2262,15 @@ static int mmc_add_disk(struct mmc_blk_data *md)
if (ret)
goto force_ro_fail;

+ md->boot_enable.show = boot_enable_show;
+ md->boot_enable.store = boot_enable_store;
+ sysfs_attr_init(&md->boot_enable.attr);
+ md->boot_enable.attr.name = "boot_enable";
+ md->boot_enable.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(disk_to_dev(md->disk), &md->boot_enable);
+ if (ret)
+ goto boot_enable_fail;
+
if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
card->ext_csd.boot_ro_lockable) {
umode_t mode;
@@ -2225,6 +2294,8 @@ static int mmc_add_disk(struct mmc_blk_data *md)
return ret;

power_ro_lock_fail:
+ device_remove_file(disk_to_dev(md->disk), &md->boot_enable);
+boot_enable_fail:
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
force_ro_fail:
del_gendisk(md->disk);
@@ -2434,4 +2505,3 @@ module_exit(mmc_blk_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
-
--
1.7.0.4