summaryrefslogtreecommitdiffstats
path: root/drivers/dfu/dfu_mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dfu/dfu_mmc.c')
-rw-r--r--drivers/dfu/dfu_mmc.c108
1 files changed, 72 insertions, 36 deletions
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index 083d74591b..e2f3978400 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -22,6 +22,7 @@
#include <common.h>
#include <malloc.h>
#include <errno.h>
+#include <div64.h>
#include <dfu.h>
enum dfu_mmc_op {
@@ -29,32 +30,51 @@ enum dfu_mmc_op {
DFU_OP_WRITE,
};
+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_block_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
- void *buf, long *len)
+ u64 offset, void *buf, long *len)
{
char cmd_buf[DFU_CMD_BUF_SIZE];
+ u32 blk_start, blk_count;
+
+ /*
+ * We must ensure that we work in lba_blk_size chunks, so ALIGN
+ * this value.
+ */
+ *len = ALIGN(*len, dfu->data.mmc.lba_blk_size);
+
+ blk_start = dfu->data.mmc.lba_start +
+ (u32)lldiv(offset, dfu->data.mmc.lba_blk_size);
+ blk_count = *len / dfu->data.mmc.lba_blk_size;
+ if (blk_start + blk_count >
+ dfu->data.mmc.lba_start + dfu->data.mmc.lba_size) {
+ puts("Request would exceed designated area!\n");
+ return -EINVAL;
+ }
- sprintf(cmd_buf, "mmc %s 0x%x %x %x",
+ sprintf(cmd_buf, "mmc %s %p %x %x",
op == DFU_OP_READ ? "read" : "write",
- (unsigned int) buf,
- dfu->data.mmc.lba_start,
- dfu->data.mmc.lba_size);
-
- if (op == DFU_OP_READ)
- *len = dfu->data.mmc.lba_blk_size * dfu->data.mmc.lba_size;
+ buf, blk_start, blk_count);
debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf);
return run_command(cmd_buf, 0);
}
-static inline int mmc_block_write(struct dfu_entity *dfu, void *buf, long *len)
+static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len)
{
- return mmc_block_op(DFU_OP_WRITE, dfu, buf, len);
-}
+ if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE) {
+ dfu_file_buf_len = 0;
+ return -EINVAL;
+ }
-static inline int mmc_block_read(struct dfu_entity *dfu, void *buf, long *len)
-{
- return mmc_block_op(DFU_OP_READ, dfu, buf, len);
+ /* Add to the current buffer. */
+ memcpy(dfu_file_buf + dfu_file_buf_len, buf, *len);
+ dfu_file_buf_len += *len;
+
+ return 0;
}
static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
@@ -66,20 +86,23 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
switch (dfu->layout) {
case DFU_FS_FAT:
- sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s %lx",
+ sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s",
op == DFU_OP_READ ? "load" : "write",
dfu->data.mmc.dev, dfu->data.mmc.part,
- (unsigned int) buf, dfu->name, *len);
+ (unsigned int) buf, dfu->name);
+ if (op == DFU_OP_WRITE)
+ sprintf(cmd_buf + strlen(cmd_buf), " %lx", *len);
break;
case DFU_FS_EXT4:
- sprintf(cmd_buf, "ext4%s mmc %d:%d /%s 0x%x %ld",
+ sprintf(cmd_buf, "ext4%s mmc %d:%d 0x%x /%s",
op == DFU_OP_READ ? "load" : "write",
dfu->data.mmc.dev, dfu->data.mmc.part,
- dfu->name, (unsigned int) buf, *len);
+ (unsigned int) buf, dfu->name);
break;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
dfu_get_layout(dfu->layout));
+ return -1;
}
debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf);
@@ -102,27 +125,18 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
return ret;
}
-static inline int mmc_file_write(struct dfu_entity *dfu, void *buf, long *len)
-{
- return mmc_file_op(DFU_OP_WRITE, dfu, buf, len);
-}
-
-static inline int mmc_file_read(struct dfu_entity *dfu, void *buf, long *len)
-{
- return mmc_file_op(DFU_OP_READ, dfu, buf, len);
-}
-
-int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
+int dfu_write_medium_mmc(struct dfu_entity *dfu,
+ u64 offset, void *buf, long *len)
{
int ret = -1;
switch (dfu->layout) {
case DFU_RAW_ADDR:
- ret = mmc_block_write(dfu, buf, len);
+ ret = mmc_block_op(DFU_OP_WRITE, dfu, offset, buf, len);
break;
case DFU_FS_FAT:
case DFU_FS_EXT4:
- ret = mmc_file_write(dfu, buf, len);
+ ret = mmc_file_buffer(dfu, buf, len);
break;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
@@ -132,17 +146,34 @@ int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
return ret;
}
-int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
+int dfu_flush_medium_mmc(struct dfu_entity *dfu)
+{
+ int ret = 0;
+
+ if (dfu->layout != DFU_RAW_ADDR) {
+ /* Do stuff here. */
+ ret = mmc_file_op(DFU_OP_WRITE, dfu, &dfu_file_buf,
+ &dfu_file_buf_len);
+
+ /* Now that we're done */
+ dfu_file_buf_len = 0;
+ }
+
+ return ret;
+}
+
+int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf,
+ long *len)
{
int ret = -1;
switch (dfu->layout) {
case DFU_RAW_ADDR:
- ret = mmc_block_read(dfu, buf, len);
+ ret = mmc_block_op(DFU_OP_READ, dfu, offset, buf, len);
break;
case DFU_FS_FAT:
case DFU_FS_EXT4:
- ret = mmc_file_read(dfu, buf, len);
+ ret = mmc_file_op(DFU_OP_READ, dfu, buf, len);
break;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
@@ -181,14 +212,15 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
mmc = find_mmc_device(dev);
if (mmc == NULL || mmc_init(mmc)) {
- printf("%s: could not find mmc device #%d!\n", __func__, dev);
+ printf("%s: could not find mmc device #%d!\n",
+ __func__, dev);
return -ENODEV;
}
blk_dev = &mmc->block_dev;
if (get_partition_info(blk_dev, part, &partinfo) != 0) {
printf("%s: could not find partition #%d on mmc device #%d!\n",
- __func__, part, dev);
+ __func__, part, dev);
return -ENODEV;
}
@@ -208,6 +240,10 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
dfu->read_medium = dfu_read_medium_mmc;
dfu->write_medium = dfu_write_medium_mmc;
+ dfu->flush_medium = dfu_flush_medium_mmc;
+
+ /* initial state */
+ dfu->inited = 0;
return 0;
}
OpenPOWER on IntegriCloud