MAINLINE dfu: mmc: Provide support for eMMC boot partition access
authorLukasz Majewski <l.majewski@samsung.com>
Tue, 18 Feb 2014 15:43:09 +0000 (16:43 +0100)
committerLukasz Majewski <l.majewski@samsung.com>
Tue, 18 Mar 2014 15:48:58 +0000 (16:48 +0100)
Before this patch it was only possible to access only the default eMMC
partition. By partition selection I mean the access to eMMC via ext_csd[179]
register programming.

It sometimes happens that it is necessary to write to other partitions.
This patch adds extra attributes to "mmc" sub type of the dfu_alt_info
variable (e.g. boot-mmc.bin mmc 0 200 mmcpart 1;)

It saves the original boot value and restores it after storing the file.

Such definition will not impact other definitions of the "mmc".

Change-Id: I34069510eb27aa80794189d2d13cdb97e54ba83d
Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
drivers/dfu/dfu_mmc.c
include/dfu.h

index 651cfff..a7224b6 100644 (file)
@@ -18,11 +18,29 @@ static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
                                dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE];
 static long dfu_file_buf_len;
 
+static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part)
+{
+       int ret;
+
+       if (part == mmc->part_num)
+               return 0;
+
+       ret = mmc_switch_part(dfu->dev_num, part);
+       if (ret) {
+               error("Cannot switch to partition %d\n", part);
+               return ret;
+       }
+       mmc->part_num = part;
+
+       return 0;
+}
+
 static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
                        u64 offset, void *buf, long *len)
 {
        struct mmc *mmc = find_mmc_device(dfu->dev_num);
        u32 blk_start, blk_count, n = 0;
+       int ret, part_num_bkp = 0;
 
        /*
         * We must ensure that we work in lba_blk_size chunks, so ALIGN
@@ -39,6 +57,13 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
                return -EINVAL;
        }
 
+       if (dfu->data.mmc.partition_access != DFU_NOT_SUPPORTED) {
+               part_num_bkp = mmc->part_num;
+               ret = mmc_access_part(dfu, mmc, dfu->data.mmc.partition_access);
+               if (ret)
+                       return ret;
+       }
+
        debug("%s: %s dev: %d start: %d cnt: %d buf: 0x%p\n", __func__,
              op == DFU_OP_READ ? "MMC READ" : "MMC WRITE", dfu->dev_num,
              blk_start, blk_count, buf);
@@ -57,9 +82,17 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
 
        if (n != blk_count) {
                error("MMC operation failed");
+               if (dfu->data.mmc.partition_access != DFU_NOT_SUPPORTED)
+                       mmc_access_part(dfu, mmc, part_num_bkp);
                return -EIO;
        }
 
+       if (dfu->data.mmc.partition_access != DFU_NOT_SUPPORTED) {
+               ret = mmc_access_part(dfu, mmc, part_num_bkp);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -193,12 +226,22 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
        char *st;
 
        dfu->dev_type = DFU_DEV_MMC;
+       dfu->data.mmc.partition_access = DFU_NOT_SUPPORTED;
+
        st = strsep(&s, " ");
        if (!strcmp(st, "mmc")) {
                dfu->layout = DFU_RAW_ADDR;
                dfu->data.mmc.lba_start = simple_strtoul(s, &s, 16);
-               dfu->data.mmc.lba_size = simple_strtoul(++s, &s, 16);
+               s++;
+               dfu->data.mmc.lba_size = simple_strtoul(s, &s, 16);
                dfu->data.mmc.lba_blk_size = get_mmc_blk_size(dfu->dev_num);
+               if (*s) {
+                       s++;
+                       st = strsep(&s, " ");
+                       if (!strcmp(st, "mmcpart"))
+                               dfu->data.mmc.partition_access =
+                                       simple_strtoul(s, &s, 0);
+               }
        } else if (!strcmp(st, "fat")) {
                dfu->layout = DFU_FS_FAT;
        } else if (!strcmp(st, "ext4")) {
@@ -236,7 +279,8 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
 
        if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {
                dfu->data.mmc.dev = simple_strtoul(s, &s, 10);
-               dfu->data.mmc.part = simple_strtoul(++s, &s, 10);
+               s++;
+               dfu->data.mmc.part = simple_strtoul(s, &s, 10);
        }
 
        dfu->read_medium = dfu_read_medium_mmc;
index f973426..d014107 100644 (file)
@@ -37,12 +37,17 @@ enum dfu_op {
        DFU_OP_WRITE,
 };
 
+#define DFU_NOT_SUPPORTED -1
+
 struct mmc_internal_data {
        /* RAW programming */
        unsigned int lba_start;
        unsigned int lba_size;
        unsigned int lba_blk_size;
 
+       /* Partition access */
+       int partition_access;
+
        /* FAT/EXT */
        unsigned int dev;
        unsigned int part;