aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGareth McMullin2015-03-26 22:20:47 -0700
committerGareth McMullin2015-04-11 16:05:40 -0700
commit45328ea12498e857262ae571710d01cb38302a9f (patch)
treeab91d46d3761bc929879052f0d14a8937bc3580b
parent36f749fed92597e0469909e5399146359e5fdfdf (diff)
Add buffering support for flash drivers.
Some devices can get a significant boost in performance by writing to flash memories one page at a time. Generic function to do this are provided at the target layer and may be used by flash drivers.
-rw-r--r--src/include/target.h9
-rw-r--r--src/target.c50
2 files changed, 59 insertions, 0 deletions
diff --git a/src/include/target.h b/src/include/target.h
index f49bc58..96b5506 100644
--- a/src/include/target.h
+++ b/src/include/target.h
@@ -133,6 +133,12 @@ struct target_flash {
struct target_flash *next;
int align;
uint8_t erased;
+
+ /* For buffered flash */
+ size_t buf_size;
+ flash_write_func write_buf;
+ uint32_t buf_addr;
+ void *buf;
};
struct target_s {
@@ -215,6 +221,9 @@ void target_add_commands(target *t, const struct command_s *cmds, const char *na
void target_add_ram(target *t, uint32_t start, uint32_t len);
void target_add_flash(target *t, struct target_flash *f);
const char *target_mem_map(target *t);
+int target_flash_write_buffered(struct target_flash *f,
+ uint32_t dest, const void *src, size_t len);
+int target_flash_done_buffered(struct target_flash *f);
static inline uint32_t target_mem_read32(target *t, uint32_t addr)
{
diff --git a/src/target.c b/src/target.c
index 3ab59bc..266c23e 100644
--- a/src/target.c
+++ b/src/target.c
@@ -57,6 +57,8 @@ void target_list_free(void)
}
while (target_list->flash) {
void * next = target_list->flash->next;
+ if (target_list->flash->buf)
+ free(target_list->flash->buf);
free(target_list->flash);
target_list->flash = next;
}
@@ -216,3 +218,51 @@ int target_flash_done(target *t)
return 0;
}
+int target_flash_write_buffered(struct target_flash *f,
+ uint32_t dest, const void *src, size_t len)
+{
+ int ret = 0;
+
+ if (f->buf == NULL) {
+ /* Allocate flash sector buffer */
+ f->buf = malloc(f->buf_size);
+ f->buf_addr = -1;
+ }
+ while (len) {
+ uint32_t offset = dest % f->buf_size;
+ uint32_t base = dest - offset;
+ if (base != f->buf_addr) {
+ if (f->buf_addr != (uint32_t)-1) {
+ /* Write sector to flash if valid */
+ ret |= f->write_buf(f, f->buf_addr,
+ f->buf, f->buf_size);
+ }
+ /* Setup buffer for a new sector */
+ f->buf_addr = base;
+ memset(f->buf, f->erased, f->buf_size);
+ }
+ /* Copy chunk into sector buffer */
+ size_t sectlen = MIN(f->buf_size - offset, len);
+ memcpy(f->buf + offset, src, sectlen);
+ dest += sectlen;
+ src += sectlen;
+ len -= sectlen;
+ }
+ return ret;
+}
+
+int target_flash_done_buffered(struct target_flash *f)
+{
+ int ret = 0;
+ if ((f->buf != NULL) &&(f->buf_addr != (uint32_t)-1)) {
+ /* Write sector to flash if valid */
+ ret = f->write_buf(f, f->buf_addr, f->buf, f->buf_size);
+ f->buf_addr = -1;
+ free(f->buf);
+ f->buf = NULL;
+ }
+
+ return ret;
+}
+
+