From 0fc635b3f8a961d09a7ac784d7846c785a3345dc Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sun, 22 Mar 2015 22:59:04 -0700 Subject: Add functions for dynamically generating the XML memory map. --- src/include/target.h | 30 ++++++++++++++++++--- src/platforms/native/platform.h | 1 + src/target.c | 58 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/include/target.h b/src/include/target.h index 940a360..5a9a94a 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -112,12 +112,27 @@ target *target_attach(target *t, target_destroy_callback destroy_cb); #define target_regs_size(target) \ ((target)->regs_size) -#define target_mem_map(target) \ - ((target)->xml_mem_map ? (target)->xml_mem_map : "") - #define target_tdesc(target) \ ((target)->tdesc ? (target)->tdesc : "") +struct target_ram { + uint32_t start; + uint32_t length; + struct target_ram *next; +}; + +struct target_flash { + uint32_t start; + uint32_t length; + uint32_t blocksize; + int (*erase)(struct target_flash *f, uint32_t addr, size_t len); + int (*write)(struct target_flash *f, uint32_t dest, + const uint8_t *src, size_t len); + int (*done)(struct target_flash *t); + target *t; + struct target_flash *next; +}; + struct target_s { /* Notify controlling debugger if target is lost */ target_destroy_callback destroy_callback; @@ -158,8 +173,12 @@ struct target_s { unsigned target_options; uint32_t idcode; - /* Flash memory access functions */ + /* Target memory map */ const char *xml_mem_map; + struct target_ram *ram; + struct target_flash *flash; + + /* DEPRECATED: Flash memory access functions */ int (*flash_erase)(target *t, uint32_t addr, size_t len); int (*flash_write)(target *t, uint32_t dest, const uint8_t *src, size_t len); @@ -190,6 +209,9 @@ extern bool connect_assert_srst; target *target_new(unsigned size); void target_list_free(void); void target_add_commands(target *t, const struct command_s *cmds, const char *name); +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); static inline uint32_t target_mem_read32(target *t, uint32_t addr) { diff --git a/src/platforms/native/platform.h b/src/platforms/native/platform.h index 6958585..96d86be 100644 --- a/src/platforms/native/platform.h +++ b/src/platforms/native/platform.h @@ -150,6 +150,7 @@ /* Use newlib provided integer only stdio functions */ #define sscanf siscanf #define sprintf siprintf +#define snprintf sniprintf #define vasprintf vasiprintf #endif diff --git a/src/target.c b/src/target.c index 4299a45..4e10e72 100644 --- a/src/target.c +++ b/src/target.c @@ -80,3 +80,61 @@ target *target_attach(target *t, target_destroy_callback destroy_cb) return t; } +void target_add_ram(target *t, uint32_t start, uint32_t len) +{ + struct target_ram *ram = malloc(sizeof(*ram)); + ram->start = start; + ram->length = len; + ram->next = t->ram; + t->ram = ram; +} + +void target_add_flash(target *t, struct target_flash *f) +{ + f->t = t; + f->next = t->flash; + t->flash = f; +} + +static ssize_t map_ram(char *buf, size_t len, struct target_ram *ram) +{ + return snprintf(buf, len, "", + ram->start, ram->length); +} + +static ssize_t map_flash(char *buf, size_t len, struct target_flash *f) +{ + int i = 0; + i += snprintf(&buf[i], len - i, "", + f->start, f->length); + i += snprintf(&buf[i], len - i, "0x%08"PRIx32 + "", + f->blocksize); + return i; +} + +const char *target_mem_map(target *t) +{ + if (t->xml_mem_map) + return t->xml_mem_map; + + /* FIXME size buffer */ + size_t len = 1024; + char *tmp = malloc(len); + size_t i = 0; + i = snprintf(&tmp[i], len - i, ""); + /* Map each defined RAM */ + for (struct target_ram *r = t->ram; r; r = r->next) + i += map_ram(&tmp[i], len - i, r); + /* Map each defined Flash */ + for (struct target_flash *f = t->flash; f; f = f->next) + i += map_flash(&tmp[i], len - i, f); + i += snprintf(&tmp[i], len - i, ""); + + t->xml_mem_map = tmp; + + return t->xml_mem_map; +} + -- cgit v1.2.3 From 691d21989a6957be728635fe8b56720c21758a3f Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Tue, 24 Mar 2015 20:45:05 -0700 Subject: Add function to add simple flash driver to target. Clean up ram/flash/memory map on target destruction. --- src/include/target.h | 13 +++++++++---- src/target.c | 20 ++++++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/include/target.h b/src/include/target.h index 5a9a94a..7085ff2 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -121,14 +121,18 @@ struct target_ram { struct target_ram *next; }; +struct target_flash; +typedef int (*flash_erase_func)(struct target_flash *f, uint32_t addr, size_t len); +typedef int (*flash_write_func)(struct target_flash *f, uint32_t dest, + const void *src, size_t len); +typedef int (*flash_done_func)(struct target_flash *f); struct target_flash { uint32_t start; uint32_t length; uint32_t blocksize; - int (*erase)(struct target_flash *f, uint32_t addr, size_t len); - int (*write)(struct target_flash *f, uint32_t dest, - const uint8_t *src, size_t len); - int (*done)(struct target_flash *t); + flash_erase_func erase; + flash_write_func write; + flash_done_func done; target *t; struct target_flash *next; }; @@ -175,6 +179,7 @@ struct target_s { /* Target memory map */ const char *xml_mem_map; + char *dyn_mem_map; struct target_ram *ram; struct target_flash *flash; diff --git a/src/target.c b/src/target.c index 4e10e72..86d88ed 100644 --- a/src/target.c +++ b/src/target.c @@ -48,6 +48,18 @@ void target_list_free(void) free(target_list->commands); target_list->commands = tc; } + if (target_list->dyn_mem_map) + free(target_list->dyn_mem_map); + while (target_list->ram) { + void * next = target_list->ram->next; + free(target_list->ram); + target_list->ram = next; + } + while (target_list->flash) { + void * next = target_list->flash->next; + free(target_list->flash); + target_list->flash = next; + } free(target_list); target_list = t; } @@ -117,9 +129,13 @@ static ssize_t map_flash(char *buf, size_t len, struct target_flash *f) const char *target_mem_map(target *t) { + /* Deprecated static const memory map */ if (t->xml_mem_map) return t->xml_mem_map; + if (t->dyn_mem_map) + return t->dyn_mem_map; + /* FIXME size buffer */ size_t len = 1024; char *tmp = malloc(len); @@ -133,8 +149,8 @@ const char *target_mem_map(target *t) i += map_flash(&tmp[i], len - i, f); i += snprintf(&tmp[i], len - i, ""); - t->xml_mem_map = tmp; + t->dyn_mem_map = tmp; - return t->xml_mem_map; + return t->dyn_mem_map; } -- cgit v1.2.3 From 7202db586038843d1d4f01403ce6e1285ac3520c Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Tue, 24 Mar 2015 20:45:59 -0700 Subject: Add new functions to wrap flash driver erase/write/done operations. --- src/include/target.h | 12 ++++-------- src/target.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/include/target.h b/src/include/target.h index 7085ff2..bcabc23 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -95,14 +95,10 @@ target *target_attach(target *t, target_destroy_callback destroy_cb); /* Flash memory access functions */ -#define target_flash_erase(target, addr, len) \ - (target)->flash_erase((target), (addr), (len)) - -#define target_flash_write(target, dest, src, len) \ - (target)->flash_write((target), (dest), (src), (len)) - -#define target_flash_done(target) \ - ((target)->flash_done ? (target)->flash_done(target) : 0) +int target_flash_erase(target *t, uint32_t addr, size_t len); +int target_flash_write(target *t, + uint32_t dest, const void *src, size_t len); +int target_flash_done(target *t); /* Host I/O */ #define target_hostio_reply(target, recode, errcode) \ diff --git a/src/target.c b/src/target.c index 86d88ed..6b05deb 100644 --- a/src/target.c +++ b/src/target.c @@ -154,3 +154,57 @@ const char *target_mem_map(target *t) return t->dyn_mem_map; } +static struct target_flash *flash_for_addr(target *t, uint32_t addr) +{ + for (struct target_flash *f = t->flash; f; f = f->next) + if ((f->start <= addr) && + (addr < (f->start + f->length))) + return f; + return NULL; +} + +int target_flash_erase(target *t, uint32_t addr, size_t len) +{ + if (t->flash_write) + return t->flash_erase(t, addr, len); + + int ret = 0; + while (len) { + struct target_flash *f = flash_for_addr(t, addr); + size_t tmplen = MIN(len, f->length - (addr % f->length)); + ret |= f->erase(f, addr, tmplen); + addr += tmplen; + len -= tmplen; + } + return ret; +} + +int target_flash_write(target *t, + uint32_t dest, const void *src, size_t len) +{ + if (t->flash_write) + return t->flash_write(t, dest, src, len); + + int ret = 0; + while (len) { + struct target_flash *f = flash_for_addr(t, dest); + size_t tmplen = MIN(len, f->length - (dest % f->length)); + ret |= f->write(f, dest, src, tmplen); + src += tmplen; + len -= tmplen; + } + return ret; +} + +int target_flash_done(target *t) +{ + for (struct target_flash *f = t->flash; f; f = f->next) { + if (f->done) { + int tmp = f->done(f); + if (tmp) + return tmp; + } + } + return 0; +} + -- cgit v1.2.3 From 36f749fed92597e0469909e5399146359e5fdfdf Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Thu, 26 Mar 2015 22:18:18 -0700 Subject: Fix flash buffer alignment in target layer. --- src/include/target.h | 2 ++ src/target.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/include/target.h b/src/include/target.h index bcabc23..f49bc58 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -131,6 +131,8 @@ struct target_flash { flash_done_func done; target *t; struct target_flash *next; + int align; + uint8_t erased; }; struct target_s { diff --git a/src/target.c b/src/target.c index 6b05deb..3ab59bc 100644 --- a/src/target.c +++ b/src/target.c @@ -189,7 +189,15 @@ int target_flash_write(target *t, while (len) { struct target_flash *f = flash_for_addr(t, dest); size_t tmplen = MIN(len, f->length - (dest % f->length)); - ret |= f->write(f, dest, src, tmplen); + if (f->align > 1) { + uint32_t offset = dest % f->align; + uint8_t data[ALIGN(offset + len, f->align)]; + memset(data, f->erased, sizeof(data)); + memcpy((uint8_t *)data + offset, src, len); + ret |= f->write(f, dest - offset, data, sizeof(data)); + } else { + ret |= f->write(f, dest, src, tmplen); + } src += tmplen; len -= tmplen; } -- cgit v1.2.3 From 45328ea12498e857262ae571710d01cb38302a9f Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Thu, 26 Mar 2015 22:20:47 -0700 Subject: 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. --- src/include/target.h | 9 +++++++++ src/target.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) 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; +} + + -- cgit v1.2.3 From 3ed4207e8ac0b451ebee5b46e9f7ad18f9db42fb Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 28 Mar 2015 13:04:20 -0700 Subject: stm32l0: Update to use new buffered flash writes. Remove old stubs. --- flashstub/dump-to-array.sh | 11 - flashstub/stm32l05x-nvm-prog-erase.cc | 93 ---- flashstub/stm32l05x-nvm-prog-erase.stub | 67 --- flashstub/stm32l05x-nvm-prog-write.cc | 113 ----- flashstub/stm32l05x-nvm-prog-write.stub | 99 ----- src/stm32l0.c | 723 +++++++++----------------------- 6 files changed, 196 insertions(+), 910 deletions(-) delete mode 100755 flashstub/dump-to-array.sh delete mode 100644 flashstub/stm32l05x-nvm-prog-erase.cc delete mode 100644 flashstub/stm32l05x-nvm-prog-erase.stub delete mode 100644 flashstub/stm32l05x-nvm-prog-write.cc delete mode 100644 flashstub/stm32l05x-nvm-prog-write.stub diff --git a/flashstub/dump-to-array.sh b/flashstub/dump-to-array.sh deleted file mode 100755 index 78584d0..0000000 --- a/flashstub/dump-to-array.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# Convert the output of objdump to an array of half-words that can be -# included into C code to represent the stub. -# -# Invoke with something like this: -# -# objdump -z -d FILE.o | dump-to-array.sh > FILE.stub -# - -sed -E "/^[ ][ ]*[0-9a-fA-F]+:/!d; s/([0-9a-fA-F]+):[ \t]+([0-9a-fA-F]+).*/[0x\1\/2] = 0x\2,/ ; s/0x(....)(....),/0x\2, 0x\1,/" diff --git a/flashstub/stm32l05x-nvm-prog-erase.cc b/flashstub/stm32l05x-nvm-prog-erase.cc deleted file mode 100644 index 58030e3..0000000 --- a/flashstub/stm32l05x-nvm-prog-erase.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* @file stm32l05x-nvm-prog-erase.cc - * - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2014 Woollysoft - * Written by Marc Singer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* ----------- - DESCRIPTION - ----------- - - NVM program flash erase stub for STM32L05x, a Cortex-M0+ core. The - stub uses SRAM to host the code fragment to perform the erase. - - This stub works with the STM32L1xx given a few options. - - If you plan to modify this routine and emit a new stub, make sure - to audit the code. We don't have a stack so we cannot make calls - that save the link pointer. IOW, the inline functions should be be - inlined. - -*/ - -#include -#include -#include "../src/include/stm32lx-nvm.h" - -/* Erase a region of flash. In the event that the erase is misaligned - with respect to pages, it will erase the pages that contain the - requested range of bytes. */ -extern "C" void __attribute((naked)) stm32l05x_nvm_prog_erase() { - // Leave room for INFO at second word of routine - __asm volatile ("b 0f\n\t" - ".align 2\n\t" - ".word 0\n\t" - ".word 0\n\t" - ".word 0\n\t" - ".word 0\n\t" - ".word 0\n\t" - "0:"); - - auto& nvm = Nvm (Info.nvm); - - // Align to the start of the first page so that we make sure to erase - // all of the target pages. - auto remainder = reinterpret_cast (Info.destination) - & (Info.page_size - 1); - Info.size += remainder; - Info.destination -= remainder/sizeof (*Info.destination); - - if (!unlock(nvm)) - goto quit; - - nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors - - // Enable erasing - nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE; - if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) - != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) - goto quit; - - while (Info.size > 0) { - *Info.destination = 0; // Initiate erase - - Info.destination += Info.page_size/sizeof (*Info.destination); - Info.size -= Info.page_size; - } - -quit: - lock(nvm); - __asm volatile ("bkpt"); -} - -/* - Local Variables: - compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-erase.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-erase.lst stm32l05x-nvm-prog-erase.cc ; /opt/arm/arm-none-eabi-objdump -d -z stm32l05x-nvm-prog-erase.o | ./dump-to-array.sh > stm32l05x-nvm-prog-erase.stub" - End: - -*/ diff --git a/flashstub/stm32l05x-nvm-prog-erase.stub b/flashstub/stm32l05x-nvm-prog-erase.stub deleted file mode 100644 index e0fea34..0000000 --- a/flashstub/stm32l05x-nvm-prog-erase.stub +++ /dev/null @@ -1,67 +0,0 @@ - [0x0/2] = 0xe00a, - [0x2/2] = 0x46c0, - [0x4/2] = 0x0000, 0x0000, - [0x8/2] = 0x0000, 0x0000, - [0xc/2] = 0x0000, 0x0000, - [0x10/2] = 0x0000, 0x0000, - [0x14/2] = 0x0000, 0x0000, - [0x18/2] = 0x491a, - [0x1a/2] = 0x8a08, - [0x1c/2] = 0x680c, - [0x1e/2] = 0x684d, - [0x20/2] = 0x1e42, - [0x22/2] = 0x4022, - [0x24/2] = 0x1955, - [0x26/2] = 0x0892, - [0x28/2] = 0x0092, - [0x2a/2] = 0x1aa2, - [0x2c/2] = 0x600a, - [0x2e/2] = 0x2201, - [0x30/2] = 0x68cb, - [0x32/2] = 0x604d, - [0x34/2] = 0x605a, - [0x36/2] = 0x4a14, - [0x38/2] = 0x60da, - [0x3a/2] = 0x4a14, - [0x3c/2] = 0x60da, - [0x3e/2] = 0x4a14, - [0x40/2] = 0x611a, - [0x42/2] = 0x4a14, - [0x44/2] = 0x611a, - [0x46/2] = 0x685a, - [0x48/2] = 0x0792, - [0x4a/2] = 0xd502, - [0x4c/2] = 0x2201, - [0x4e/2] = 0x605a, - [0x50/2] = 0xbe00, - [0x52/2] = 0x4a11, - [0x54/2] = 0x619a, - [0x56/2] = 0x2282, - [0x58/2] = 0x0092, - [0x5a/2] = 0x605a, - [0x5c/2] = 0x685c, - [0x5e/2] = 0x4014, - [0x60/2] = 0x4294, - [0x62/2] = 0xd1f3, - [0x64/2] = 0x0884, - [0x66/2] = 0x00a4, - [0x68/2] = 0x684d, - [0x6a/2] = 0x4a06, - [0x6c/2] = 0x2d00, - [0x6e/2] = 0xdded, - [0x70/2] = 0x2600, - [0x72/2] = 0x6815, - [0x74/2] = 0x602e, - [0x76/2] = 0x6815, - [0x78/2] = 0x192d, - [0x7a/2] = 0x6015, - [0x7c/2] = 0x6855, - [0x7e/2] = 0x1a2d, - [0x80/2] = 0x6055, - [0x82/2] = 0xe7f1, - [0x84/2] = 0x0004, 0x2000, - [0x88/2] = 0xcdef, 0x89ab, - [0x8c/2] = 0x0405, 0x0203, - [0x90/2] = 0xaebf, 0x8c9d, - [0x94/2] = 0x1516, 0x1314, - [0x98/2] = 0x0700, 0x0001, diff --git a/flashstub/stm32l05x-nvm-prog-write.cc b/flashstub/stm32l05x-nvm-prog-write.cc deleted file mode 100644 index e90401e..0000000 --- a/flashstub/stm32l05x-nvm-prog-write.cc +++ /dev/null @@ -1,113 +0,0 @@ -/* @file stm32l05x-nvm-prog-write.cc - * - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2014 Woollysoft - * Written by Marc Singer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* ----------- - DESCRIPTION - ----------- - - NVM program flash writing stub for STM32L05x, a Cortex-M0+ core. - The stub uses SRAM to host the code fragment and source data to - perform a write to flash. - - This stub works with the STM32L1xx given a few options. - - If you plan to modify this routine and emit a new stub, make sure - to audit the code. We don't have a stack so we cannot make calls - that save the link pointer. IOW, the inline functions should be be - inlined. - -*/ - -#include -#include -#include "../src/include/stm32lx-nvm.h" - -/* Write a block of bytes to flash. The called is responsible for - making sure that the address are aligned and that the count is an - even multiple of words. */ -extern "C" void __attribute((naked)) stm32l05x_nvm_prog_write() { - // Leave room for INFO at second word of routine - __asm volatile ("b 0f\n\t" - ".align 2\n\t" - ".word 0\n\t" - ".word 0\n\t" - ".word 0\n\t" - ".word 0\n\t" - ".word 0\n\t" - "0:"); - - auto& nvm = Nvm (Info.nvm); - - if (!unlock(nvm)) - goto quit; - - nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors - - while (Info.size > 0) { - - // Either we're not half-page aligned or we have less - // than a half page to write - if (Info.size < Info.page_size/2 - || (reinterpret_cast (Info.destination) - & (Info.page_size/2 - 1))) { - nvm.pecr = (Info.options & OPT_STM32L1) ? 0 - : STM32Lx_NVM_PECR_PROG; // Word programming - size_t c = Info.page_size/2 - - (reinterpret_cast (Info.destination) - & (Info.page_size/2 - 1)); - if (c > Info.size) - c = Info.size; - Info.size -= c; - c /= 4; - while (c--) { - uint32_t v = *Info.source++; - *Info.destination++ = v; - if (nvm.sr & STM32Lx_NVM_SR_ERR_M) - goto quit; - } - } - // Or we are writing a half-page(s) - else { - nvm.pecr = STM32Lx_NVM_PECR_PROG - | STM32Lx_NVM_PECR_FPRG; // Half-page prg - size_t c = Info.size & ~(Info.page_size/2 - 1); - Info.size -= c; - c /= 4; - while (c--) { - uint32_t v = *Info.source++; - *Info.destination++ = v; - } - if (nvm.sr & STM32Lx_NVM_SR_ERR_M) - goto quit; - } - } - -quit: - lock(nvm); - __asm volatile ("bkpt"); -} - -/* - Local Variables: - compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-write.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-write.lst stm32l05x-nvm-prog-write.cc ; /opt/arm/arm-none-eabi-objdump -d -z stm32l05x-nvm-prog-write.o | ./dump-to-array.sh > stm32l05x-nvm-prog-write.stub" - End: - -*/ diff --git a/flashstub/stm32l05x-nvm-prog-write.stub b/flashstub/stm32l05x-nvm-prog-write.stub deleted file mode 100644 index 7ddbc81..0000000 --- a/flashstub/stm32l05x-nvm-prog-write.stub +++ /dev/null @@ -1,99 +0,0 @@ - [0x0/2] = 0xe00a, - [0x2/2] = 0x46c0, - [0x4/2] = 0x0000, 0x0000, - [0x8/2] = 0x0000, 0x0000, - [0xc/2] = 0x0000, 0x0000, - [0x10/2] = 0x0000, 0x0000, - [0x14/2] = 0x0000, 0x0000, - [0x18/2] = 0x2201, - [0x1a/2] = 0x4b2a, - [0x1c/2] = 0x68d9, - [0x1e/2] = 0x604a, - [0x20/2] = 0x4a29, - [0x22/2] = 0x60ca, - [0x24/2] = 0x4a29, - [0x26/2] = 0x60ca, - [0x28/2] = 0x4a29, - [0x2a/2] = 0x610a, - [0x2c/2] = 0x4a29, - [0x2e/2] = 0x610a, - [0x30/2] = 0x684a, - [0x32/2] = 0x0792, - [0x34/2] = 0xd502, - [0x36/2] = 0x2301, - [0x38/2] = 0x604b, - [0x3a/2] = 0xbe00, - [0x3c/2] = 0x4826, - [0x3e/2] = 0x6188, - [0x40/2] = 0x685d, - [0x42/2] = 0x4e20, - [0x44/2] = 0x2d00, - [0x46/2] = 0xddf6, - [0x48/2] = 0x8a32, - [0x4a/2] = 0x0852, - [0x4c/2] = 0x1e54, - [0x4e/2] = 0x4295, - [0x50/2] = 0xdb02, - [0x52/2] = 0x6837, - [0x54/2] = 0x4227, - [0x56/2] = 0xd01d, - [0x58/2] = 0x2602, - [0x5a/2] = 0x8a5f, - [0x5c/2] = 0x4037, - [0x5e/2] = 0x427e, - [0x60/2] = 0x417e, - [0x62/2] = 0x00f6, - [0x64/2] = 0x604e, - [0x66/2] = 0x681e, - [0x68/2] = 0x4034, - [0x6a/2] = 0x1b12, - [0x6c/2] = 0x42aa, - [0x6e/2] = 0xd900, - [0x70/2] = 0x1c2a, - [0x72/2] = 0x1aad, - [0x74/2] = 0x605d, - [0x76/2] = 0x0892, - [0x78/2] = 0x3a01, - [0x7a/2] = 0xd3e1, - [0x7c/2] = 0x689c, - [0x7e/2] = 0x1d25, - [0x80/2] = 0x609d, - [0x82/2] = 0x6825, - [0x84/2] = 0x681c, - [0x86/2] = 0x1d26, - [0x88/2] = 0x601e, - [0x8a/2] = 0x6025, - [0x8c/2] = 0x698c, - [0x8e/2] = 0x4204, - [0x90/2] = 0xd0f2, - [0x92/2] = 0xe7d0, - [0x94/2] = 0x2481, - [0x96/2] = 0x4252, - [0x98/2] = 0x402a, - [0x9a/2] = 0x1aad, - [0x9c/2] = 0x00e4, - [0x9e/2] = 0x604c, - [0xa0/2] = 0x0892, - [0xa2/2] = 0x6075, - [0xa4/2] = 0x3a01, - [0xa6/2] = 0xd308, - [0xa8/2] = 0x689c, - [0xaa/2] = 0x1d25, - [0xac/2] = 0x609d, - [0xae/2] = 0x6825, - [0xb0/2] = 0x681c, - [0xb2/2] = 0x1d26, - [0xb4/2] = 0x601e, - [0xb6/2] = 0x6025, - [0xb8/2] = 0xe7f4, - [0xba/2] = 0x698a, - [0xbc/2] = 0x4202, - [0xbe/2] = 0xd0bf, - [0xc0/2] = 0xe7b9, - [0xc2/2] = 0x46c0, - [0xc4/2] = 0x0004, 0x2000, - [0xc8/2] = 0xcdef, 0x89ab, - [0xcc/2] = 0x0405, 0x0203, - [0xd0/2] = 0xaebf, 0x8c9d, - [0xd4/2] = 0x1516, 0x1314, - [0xd8/2] = 0x0700, 0x0001, diff --git a/src/stm32l0.c b/src/stm32l0.c index 8193b12..e46ac27 100644 --- a/src/stm32l0.c +++ b/src/stm32l0.c @@ -38,27 +38,6 @@ NOTES ===== - o Stubbed and non-stubbed NVM operation functions. The STM32L0xx - appears to behave differently from other STM32 cores. When it - enters a fault state it will not exit this state without a - reset. However, the reset will immediately enter a fault state - if program flash is erased. When in this state, it will not - permit execution of code in RAM in the way that other cores - will. Changing the PC to the start of RAM and single stepping - will immediately HardFault. - - The stub functions can be both faster and simpler because they - have direct access to the MCU. So, to permit stub operation in - the best circumstances, the NVM operation functions will check - the MCU state and either execute the stub or non-stub version - accordingly. The user can override stubs as well with a command - in case the detection feature fails...which it seems to do in - most cases. - - o Erase would be more efficient if we checked for non-blank-ness - before initiating an erase. This would have to be done in a stub - for efficiency. - o Mass erase unimplemented. The method for performing a mass erase is to set the options for read protection, reload the option bytes, set options for no protection, and then reload the option @@ -88,28 +67,10 @@ o There are minor inconsistencies between the stm32l0 and the stm32l1 in when handling NVM operations. - o When we erase or write individual words (not half-pages) on the - stm32l0, we set the PROG bit. On the stm32l1 the PROG bit is - only set when erasing. This is not documented in the register - summaries, but in the functional quick reference. Argh. - o On the STM32L1xx, PECR can only be changed when the NVM hardware is idle. The STM32L0xx allows the PECR to be updated while an operation is in progress. - o Performance. The throughput for writing is not high. We - suspected it may be possible to improve throughput significantly - by increasing the MCU clock. The code, as is, offers a - simplicity without undue knowledge of the inner workings of the - MCUs. Increasing clock frequencies would require substantial - knowledge of the clock tree. - - FWIW, this was tried. We verified that the system clocks were - changed, but the flash write was no faster. It looks like this - is due to the fact that the emulator performs a target reset - before executing the flash operations, bringing the system back - to the reset state clocking. - */ #include "general.h" @@ -121,31 +82,24 @@ #include "stm32lx-nvm.h" -static int inhibit_stubs; /* Local option to force non-stub flash IO */ - -static int stm32lx_nvm_erase(target *t, uint32_t addr, size_t len); -static int stm32lx_nvm_write(target *t, uint32_t dest, const uint8_t* src, - size_t size); - -static int stm32lx_nvm_prog_erase(target *t, uint32_t addr, size_t len); -static int stm32lx_nvm_prog_write(target *t, uint32_t dest, const uint8_t* src, +static int stm32lx_nvm_prog_erase(struct target_flash* f, + uint32_t addr, size_t len); +static int stm32lx_nvm_prog_write(struct target_flash* f, + uint32_t destination, + const void* src, size_t size); -static int stm32lx_nvm_prog_erase_stubbed(target *t, uint32_t addr, size_t len); -static int stm32lx_nvm_prog_write_stubbed(target *t, uint32_t dest, - const uint8_t* src, size_t size); - -static int stm32lx_nvm_data_erase(target *t, uint32_t addr, size_t len); -static int stm32lx_nvm_data_write(target *t, uint32_t dest, - const uint8_t* src, size_t size); +static int stm32lx_nvm_data_erase(struct target_flash* f, + uint32_t addr, size_t len); +static int stm32lx_nvm_data_write(struct target_flash* f, + uint32_t destination, + const void* source, + size_t size); -static bool stm32lx_cmd_option(target* t, int argc, char** argv); -static bool stm32lx_cmd_eeprom(target* t, int argc, char** argv); -static bool stm32lx_cmd_stubs(target* t, int argc, char** argv); +static bool stm32lx_cmd_option (target* t, int argc, char** argv); +static bool stm32lx_cmd_eeprom (target* t, int argc, char** argv); static const struct command_s stm32lx_cmd_list[] = { - { "stubs", (cmd_handler) stm32lx_cmd_stubs, - "Enable/disable NVM operation stubs" }, { "option", (cmd_handler) stm32lx_cmd_option, "Manipulate option bytes"}, { "eeprom", (cmd_handler) stm32lx_cmd_eeprom, @@ -158,63 +112,7 @@ enum { STM32L1_DBGMCU_IDCODE_PHYS = 0xe0042000, }; -static const char stm32l0_driver_str[] = "STM32L0xx"; - -static const char stm32l0_xml_memory_map[] = "" -/* ""*/ - "" - /* Program flash; ranges up to 64KiB(0x10000). */ - " " - " 0x80" - " " - /* Data(EEPROM) NVRAM; ranges up to 2KiB(0x800). */ - " " - " 0x4" - " " - /* SRAM; ranges up to 8KiB(0x2000). */ - " " - ""; - -static const char stm32l1_driver_str[] = "STM32L1xx"; - -static const char stm32l1_xml_memory_map[] = "" -/* ""*/ - "" - /* Program flash; ranges from 32KiB to 512KiB(0x80000). */ - " " - " 0x100" - " " - /* Data(EEPROM) NVRAM; ranges from 2K to 16KiB(0x4000). */ - " " - " 0x4" - " " - /* SRAM; ranges from 4KiB to 80KiB(0x14000). */ - " " - ""; - -static const uint16_t stm32l0_nvm_prog_write_stub [] = { -#include "../flashstub/stm32l05x-nvm-prog-write.stub" -}; - -static const uint16_t stm32l0_nvm_prog_erase_stub [] = { -#include "../flashstub/stm32l05x-nvm-prog-erase.stub" -}; - -static uint32_t stm32lx_nvm_prog_page_size(target *t) -{ - switch (t->idcode) { - case 0x417: /* STM32L0xx */ - return STM32L0_NVM_PROG_PAGE_SIZE; - default: /* STM32L1xx */ - return STM32L1_NVM_PROG_PAGE_SIZE; - } -} - -static bool stm32lx_is_stm32l1(target *t) +static bool stm32lx_is_stm32l1(target* t) { switch (t->idcode) { case 0x417: /* STM32L0xx */ @@ -244,16 +142,6 @@ static uint32_t stm32lx_nvm_phys(target *t) } } -static uint32_t stm32lx_nvm_data_page_size(target *t) -{ - switch (t->idcode) { - case 0x417: /* STM32L0xx */ - return STM32L0_NVM_DATA_PAGE_SIZE; - default: /* STM32L1xx */ - return STM32L1_NVM_DATA_PAGE_SIZE; - } -} - static uint32_t stm32lx_nvm_option_size(target *t) { switch (t->idcode) { @@ -264,45 +152,69 @@ static uint32_t stm32lx_nvm_option_size(target *t) } } +static void stm32l_add_flash(target *t, + uint32_t addr, size_t length, size_t erasesize) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + f->start = addr; + f->length = length; + f->blocksize = erasesize; + f->erase = stm32lx_nvm_prog_erase; + f->write = target_flash_write_buffered; + f->done = target_flash_done_buffered; + f->write_buf = stm32lx_nvm_prog_write; + f->buf_size = erasesize/2; + target_add_flash(t, f); +} + +static void stm32l_add_eeprom(target *t, uint32_t addr, size_t length) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + f->start = addr; + f->length = length; + f->blocksize = 4; + f->erase = stm32lx_nvm_data_erase; + f->write = stm32lx_nvm_data_write; + f->align = 1; + target_add_flash(t, f); +} + /** Query MCU memory for an indication as to whether or not the currently attached target is served by this module. We detect the STM32L0xx parts as well as the STM32L1xx's. */ -bool stm32l0_probe(target *t) +bool stm32l0_probe(target* t) { - uint32_t idcode; - - idcode = target_mem_read32(t, STM32L1_DBGMCU_IDCODE_PHYS) & 0xfff; - switch (idcode) { - case 0x416: /* CAT. 1 device */ - case 0x429: /* CAT. 2 device */ - case 0x427: /* CAT. 3 device */ - case 0x436: /* CAT. 4 device */ - case 0x437: /* CAT. 5 device */ - t->idcode = idcode; - t->driver = stm32l1_driver_str; - t->xml_mem_map = stm32l1_xml_memory_map; - t->flash_erase = stm32lx_nvm_erase; - t->flash_write = stm32lx_nvm_write; - target_add_commands(t, stm32lx_cmd_list, "STM32L1x"); - return true; - } - - idcode = target_mem_read32(t, STM32L0_DBGMCU_IDCODE_PHYS) & 0xfff; - switch (idcode) { - default: - break; - - case 0x417: /* STM32L0x[123] & probably others */ - t->idcode = idcode; - t->driver = stm32l0_driver_str; - t->xml_mem_map = stm32l0_xml_memory_map; - t->flash_erase = stm32lx_nvm_erase; - t->flash_write = stm32lx_nvm_write; - target_add_commands(t, stm32lx_cmd_list, "STM32L0x"); - return true; - } - - return false; + uint32_t idcode; + + idcode = target_mem_read32(t, STM32L1_DBGMCU_IDCODE_PHYS) & 0xfff; + switch (idcode) { + case 0x416: /* CAT. 1 device */ + case 0x429: /* CAT. 2 device */ + case 0x427: /* CAT. 3 device */ + case 0x436: /* CAT. 4 device */ + case 0x437: /* CAT. 5 device */ + t->idcode = idcode; + t->driver = "STM32L1x"; + target_add_ram(t, 0x20000000, 0x14000); + stm32l_add_flash(t, 0x8000000, 0x80000, 0x100); + //stm32l_add_eeprom(t, 0x8080000, 0x4000); + target_add_commands(t, stm32lx_cmd_list, "STM32L1x"); + return true; + } + + idcode = target_mem_read32(t, STM32L0_DBGMCU_IDCODE_PHYS) & 0xfff; + switch (idcode) { + case 0x417: /* STM32L0x[123] & probably others */ + t->idcode = idcode; + t->driver = "STM32L0x"; + target_add_ram(t, 0x20000000, 0x2000); + stm32l_add_flash(t, 0x8000000, 0x10000, 0x80); + stm32l_add_eeprom(t, 0x8080000, 0x800); + target_add_commands(t, stm32lx_cmd_list, "STM32L0x"); + return true; + } + + return false; } @@ -346,318 +258,96 @@ static bool stm32lx_nvm_opt_unlock(target *t, uint32_t nvm) & STM32Lx_NVM_PECR_OPTLOCK); } - -/** Erase a region of flash using a stub function. This only works - when the MCU hasn't entered a fault state(see NOTES). The flash - array is erased for all pages from addr to addr+len inclusive. */ -static int stm32lx_nvm_prog_erase_stubbed(target *t, - uint32_t addr, size_t size) -{ - struct stm32lx_nvm_stub_info info; - const uint32_t nvm = stm32lx_nvm_phys(t); - - info.nvm = nvm; - info.page_size = stm32lx_nvm_prog_page_size(t); - - /* Load the stub */ - target_mem_write(t, STM32Lx_STUB_PHYS, - &stm32l0_nvm_prog_erase_stub[0], - sizeof(stm32l0_nvm_prog_erase_stub)); - - /* Setup parameters */ - info.destination = addr; - info.size = size; - - /* Copy parameters */ - target_mem_write(t, STM32Lx_STUB_INFO_PHYS, &info, sizeof(info)); - - /* Execute stub */ - cortexm_run_stub(t, STM32Lx_STUB_PHYS, 0, 0, 0, 0); - - if (target_mem_read32(t, STM32Lx_NVM_SR(nvm)) - & STM32Lx_NVM_SR_ERR_M) - return -1; - - - return 0; -} - - -/** Write to program flash using a stub function. This only works - when the MCU hasn't entered a fault state. Once the MCU faults, - this function will not succeed because the MCU will fault before - executing a single instruction in the stub. */ -static int stm32lx_nvm_prog_write_stubbed(target *t, - uint32_t destination, - const uint8_t* source, - size_t size) -{ - struct stm32lx_nvm_stub_info info; - const uint32_t nvm = stm32lx_nvm_phys(t); - const size_t page_size = stm32lx_nvm_prog_page_size(t); - - /* We can only handle word aligned writes and even - word-multiple ranges. The stm32lx's cannot perform - anything smaller than a word write due to the ECC bits. - So, the caller must do the fixup. */ - if ((destination & 3) || (size & 3)) - return -1; - - info.nvm = nvm; - info.page_size = page_size; - - /* Load the stub */ - target_mem_write(t, STM32Lx_STUB_PHYS, - &stm32l0_nvm_prog_write_stub[0], - sizeof(stm32l0_nvm_prog_write_stub)); - - while (size > 0) { - - /* Max transfer size is adjusted in the event that the - destination isn't half-page aligned. This allows - the stub to write the first partial half-page and - then as many half-pages as will fit in the - buffer. */ - size_t max = STM32Lx_STUB_DATA_MAX - - (destination - (destination - & ~(info.page_size/2 - 1))); - size_t cb = size; - if (cb > max) - cb = max; - - /* Setup parameters */ - info.source = STM32Lx_STUB_DATA_PHYS; - info.destination = destination; - info.size = cb; - - /* Copy data to write to flash */ - target_mem_write(t, info.source, source, info.size); - - /* Move pointers early */ - destination += cb; - source += cb; - size -= cb; - - /* Copy parameters */ - target_mem_write(t, STM32Lx_STUB_INFO_PHYS, - &info, sizeof(info)); - - /* Execute stub */ - cortexm_run_stub(t, STM32Lx_STUB_PHYS, 0, 0, 0, 0); - - if (target_mem_read32(t, STM32Lx_NVM_SR(nvm)) - & STM32Lx_NVM_SR_ERR_M) - return -1; - } - - return 0; -} - - -/** Erase a region of NVM for STM32Lx. This is the lead function and - it will invoke an implementation, stubbed or not depending on the - options and the range of addresses. */ -static int stm32lx_nvm_erase(target *t, uint32_t addr, size_t size) -{ - if (addr >= STM32Lx_NVM_EEPROM_PHYS) - return stm32lx_nvm_data_erase(t, addr, size); - - /* Use stub if not inhibited, the MCU is in a non-exceptonal state - and there is stub. */ - volatile uint32_t regs[20]; - target_regs_read(t, ®s); - if (inhibit_stubs || (regs[16] & 0xf)) - return stm32lx_nvm_prog_erase(t, addr, size); - - return stm32lx_nvm_prog_erase_stubbed(t, addr, size); -} - - -/** Write to a region on NVM for STM32Lxxx. This is the lead function - and it will invoke an implementation, stubbed or not depending on - the options and the range of addresses. Data (EEPROM) writes - don't have to care about alignment, but the program flash does. - There is a fixup for unaligned program flash writes. */ -static int stm32lx_nvm_write(target *t, - uint32_t destination, - const uint8_t* source, - size_t size) -{ - if (destination >= STM32Lx_NVM_EEPROM_PHYS) - return stm32lx_nvm_data_write(t, destination, source, - size); - - /* Unaligned destinations. To make this feature simple to - implement, we do a fixup on the source data as well as the - adjusting the write parameters if the caller has asked for - an unaligned operation. Padding of this data is zeros - because the STM32L's are built that way. */ - if ((destination & 3) || (size & 3)) { - size_t size_aligned = size - + (destination & 3) - + (((size + 3) & ~3) - size); - uint8_t* source_aligned = alloca (size_aligned); - memset (source_aligned, 0, size_aligned); - memcpy (source_aligned + (destination & 3), source, size); - source = source_aligned; - destination &= ~3; - size = size_aligned; - } - - /* Skip stub if the MCU is in a questionable state, or if the - user asks us to avoid stubs. */ - volatile uint32_t regs[20]; - target_regs_read(t, ®s); - if (inhibit_stubs || (regs[16] & 0xf)) - return stm32lx_nvm_prog_write(t, destination, source, - size); - - return stm32lx_nvm_prog_write_stubbed(t, destination, source, - size); -} - - /** Erase a region of program flash using operations through the debug interface. This is slower than stubbed versions(see NOTES). The flash array is erased for all pages from addr to addr+len inclusive. NVM register file address chosen from target. */ -static int stm32lx_nvm_prog_erase(target *t, uint32_t addr, size_t len) +static int stm32lx_nvm_prog_erase(struct target_flash* f, + uint32_t addr, size_t len) { - const size_t page_size = stm32lx_nvm_prog_page_size(t); - const uint32_t nvm = stm32lx_nvm_phys(t); - - /* Word align */ - len += (addr & 3); - addr &= ~3; + target *t = f->t; + const size_t page_size = f->blocksize; + const uint32_t nvm = stm32lx_nvm_phys(t); - if (!stm32lx_nvm_prog_data_unlock(t, nvm)) - return -1; + if (!stm32lx_nvm_prog_data_unlock(t, nvm)) + return -1; - /* Flash page erase instruction */ - target_mem_write32(t, STM32Lx_NVM_PECR(nvm), - STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_PROG); + /* Flash page erase instruction */ + target_mem_write32(t, STM32Lx_NVM_PECR(nvm), + STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_PROG); uint32_t pecr = target_mem_read32(t, STM32Lx_NVM_PECR(nvm)); if ((pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) return -1; - /* Clear errors. Note that this only works when we wait for the NVM - block to complete the last operation. */ - target_mem_write32(t, STM32Lx_NVM_SR(nvm), STM32Lx_NVM_SR_ERR_M); + /* Clear errors. Note that this only works when we wait for the NVM + block to complete the last operation. */ + target_mem_write32(t, STM32Lx_NVM_SR(nvm), STM32Lx_NVM_SR_ERR_M); - while (len > 0) { - /* Write first word of page to 0 */ - target_mem_write32(t, addr, 0); + while (len > 0) { + /* Write first word of page to 0 */ + target_mem_write32(t, addr, 0); - len -= page_size; - addr += page_size; - } + len -= page_size; + addr += page_size; + } - /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(t, nvm); + /* Disable further programming by locking PECR */ + stm32lx_nvm_lock(t, nvm); - /* Wait for completion or an error */ - while (1) { - uint32_t sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm)); - if (target_check_error(t)) - return -1; - if (sr & STM32Lx_NVM_SR_BSY) - continue; - if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP)) - return -1; - break; - } + /* Wait for completion or an error */ + uint32_t sr; + do { + sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm)); + } while (sr & STM32Lx_NVM_SR_BSY); + + if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || + target_check_error(t)) + return -1; - return 0; + return 0; } /** Write to program flash using operations through the debug - interface. This is slower than the stubbed write(see NOTES). - NVM register file address chosen from target. */ -static int stm32lx_nvm_prog_write(target *t, - uint32_t destination, - const uint8_t* source_8, + interface. */ +static int stm32lx_nvm_prog_write(struct target_flash *f, + uint32_t dest, + const void* src, size_t size) { - const uint32_t nvm = stm32lx_nvm_phys(t); - const bool is_stm32l1 = stm32lx_is_stm32l1(t); - - /* We can only handle word aligned writes and even - word-multiple ranges. The stm32lx's cannot perform - anything smaller than a word write due to the ECC bits. - So, the caller must do the fixup. */ - if ((destination & 3) || (size & 3)) - return -1; - - if (!stm32lx_nvm_prog_data_unlock(t, nvm)) - return -1; - - const size_t half_page_size = stm32lx_nvm_prog_page_size(t)/2; - uint32_t* source = (uint32_t*) source_8; - - while (size > 0) { - - /* Wait for BSY to clear because we cannot write the PECR until - the previous operation completes on STM32Lxxx. */ - while (target_mem_read32(t, STM32Lx_NVM_SR(nvm)) - & STM32Lx_NVM_SR_BSY) - if (target_check_error(t)) { - return -1; - } - - // Either we're not half-page aligned or we have less - // than a half page to write - if (size < half_page_size - || (destination & (half_page_size - 1))) { - target_mem_write32(t, STM32Lx_NVM_PECR(nvm), - is_stm32l1 - ? 0 - : STM32Lx_NVM_PECR_PROG); - size_t c = half_page_size - (destination - & (half_page_size - 1)); - - if (c > size) - c = size; - size -= c; - - target_mem_write(t, destination, source, c); - source += c/4; - destination += c; - } - // Or we are writing a half-page(s) - else { - target_mem_write32(t, STM32Lx_NVM_PECR(nvm), - STM32Lx_NVM_PECR_PROG - | STM32Lx_NVM_PECR_FPRG); - - size_t c = size & ~(half_page_size - 1); - size -= c; - target_mem_write(t, destination, source, c); - source += c/4; - destination += c; - } - } + target *t = f->t; + const uint32_t nvm = stm32lx_nvm_phys(t); - /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(t, nvm); + if (!stm32lx_nvm_prog_data_unlock(t, nvm)) + return -1; - /* Wait for completion or an error */ - while (1) { - uint32_t sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm)); - if (target_check_error(t)) { - return -1; - } - if (sr & STM32Lx_NVM_SR_BSY) - continue; - if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP)) { - return -1; - } - break; - } + /* Wait for BSY to clear because we cannot write the PECR until + the previous operation completes on STM32Lxxx. */ + while (target_mem_read32(t, STM32Lx_NVM_SR(nvm)) + & STM32Lx_NVM_SR_BSY) + if (target_check_error(t)) + return -1; + + target_mem_write32(t, STM32Lx_NVM_PECR(nvm), + STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG); + target_mem_write(t, dest, src, size); + + /* Disable further programming by locking PECR */ + stm32lx_nvm_lock(t, nvm); + + /* Wait for completion or an error */ + uint32_t sr; + do { + sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm)); + } while (sr & STM32Lx_NVM_SR_BSY); + + if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || + target_check_error(t)) + return -1; - return 0; + return 0; } @@ -665,52 +355,51 @@ static int stm32lx_nvm_prog_write(target *t, interface . The flash is erased for all pages from addr to addr+len, inclusive, on a word boundary. NVM register file address chosen from target. */ -static int stm32lx_nvm_data_erase(target *t, +static int stm32lx_nvm_data_erase(struct target_flash *f, uint32_t addr, size_t len) { - const size_t page_size = stm32lx_nvm_data_page_size(t); - const uint32_t nvm = stm32lx_nvm_phys(t); + target *t = f->t; + const size_t page_size = f->blocksize; + const uint32_t nvm = stm32lx_nvm_phys(t); - /* Word align */ - len += (addr & 3); - addr &= ~3; + /* Word align */ + len += (addr & 3); + addr &= ~3; - if (!stm32lx_nvm_prog_data_unlock(t, nvm)) - return -1; + if (!stm32lx_nvm_prog_data_unlock(t, nvm)) + return -1; - /* Flash data erase instruction */ - target_mem_write32(t, STM32Lx_NVM_PECR(nvm), - STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA); + /* Flash data erase instruction */ + target_mem_write32(t, STM32Lx_NVM_PECR(nvm), + STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA); uint32_t pecr = target_mem_read32(t, STM32Lx_NVM_PECR(nvm)); if ((pecr & (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA)) != (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA)) return -1; - while (len > 0) { - /* Write first word of page to 0 */ - target_mem_write32(t, addr, 0); + while (len > 0) { + /* Write first word of page to 0 */ + target_mem_write32(t, addr, 0); - len -= page_size; - addr += page_size; - } + len -= page_size; + addr += page_size; + } - /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(t, nvm); + /* Disable further programming by locking PECR */ + stm32lx_nvm_lock(t, nvm); - /* Wait for completion or an error */ - while (1) { - uint32_t sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm)); - if (target_check_error(t)) - return -1; - if (sr & STM32Lx_NVM_SR_BSY) - continue; - if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP)) - return -1; - break; - } + /* Wait for completion or an error */ + uint32_t sr; + do { + sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm)); + } while (sr & STM32Lx_NVM_SR_BSY); + + if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || + target_check_error(t)) + return -1; - return 0; + return 0; } @@ -718,47 +407,46 @@ static int stm32lx_nvm_data_erase(target *t, NVM register file address chosen from target. Unaligned destination writes are supported (though unaligned sources are not). */ -static int stm32lx_nvm_data_write(target *t, +static int stm32lx_nvm_data_write(struct target_flash *f, uint32_t destination, - const uint8_t* source_8, + const void* src, size_t size) { - const uint32_t nvm = stm32lx_nvm_phys(t); - const bool is_stm32l1 = stm32lx_is_stm32l1(t); - uint32_t* source = (uint32_t*) source_8; + target *t = f->t; + const uint32_t nvm = stm32lx_nvm_phys(t); + const bool is_stm32l1 = stm32lx_is_stm32l1(t); + uint32_t* source = (uint32_t*) src; - if (!stm32lx_nvm_prog_data_unlock(t, nvm)) - return -1; + if (!stm32lx_nvm_prog_data_unlock(t, nvm)) + return -1; - target_mem_write32(t, STM32Lx_NVM_PECR(nvm), - is_stm32l1 ? 0 : STM32Lx_NVM_PECR_DATA); + target_mem_write32(t, STM32Lx_NVM_PECR(nvm), + is_stm32l1 ? 0 : STM32Lx_NVM_PECR_DATA); - while (size) { - size -= 4; - uint32_t v = *source++; - target_mem_write32(t, destination, v); - destination += 4; + while (size) { + size -= 4; + uint32_t v = *source++; + target_mem_write32(t, destination, v); + destination += 4; - if (target_check_error(t)) - return -1; - } + if (target_check_error(t)) + return -1; + } - /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(t, nvm); + /* Disable further programming by locking PECR */ + stm32lx_nvm_lock(t, nvm); - /* Wait for completion or an error */ - while (1) { - uint32_t sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm)); - if (target_check_error(t)) - return -1; - if (sr & STM32Lx_NVM_SR_BSY) - continue; - if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP)) - return -1; - break; - } + /* Wait for completion or an error */ + uint32_t sr; + do { + sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm)); + } while (sr & STM32Lx_NVM_SR_BSY); + + if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || + target_check_error(t)) + return -1; - return 0; + return 0; } @@ -822,25 +510,6 @@ static bool stm32lx_eeprom_write(target *t, uint32_t address, return !(sr & STM32Lx_NVM_SR_ERR_M); } -static bool stm32lx_cmd_stubs(target* t, - int argc, char** argv) -{ - (void) t; - if (argc == 1) { - gdb_out("usage: mon stubs [enable/disable]\n"); - } - else if (argc == 2) { - size_t cb = strlen(argv[1]); - if (!strncasecmp(argv[1], "enable", cb)) - inhibit_stubs = 0; - if (!strncasecmp(argv[1], "disable", cb)) - inhibit_stubs = 1; - } - gdb_outf("stubs: %sabled\n", inhibit_stubs ? "dis" : "en"); - - return true; -} - static bool stm32lx_cmd_option(target* t, int argc, char** argv) { const uint32_t nvm = stm32lx_nvm_phys(t); -- cgit v1.2.3 From 21c209fd8fa04fe8b312fa357ae0aa5bf38e3ecd Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Wed, 1 Apr 2015 20:21:22 -0700 Subject: sam3x: simplify probe function. --- src/sam3x.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/sam3x.c b/src/sam3x.c index 0566718..05db420 100644 --- a/src/sam3x.c +++ b/src/sam3x.c @@ -122,10 +122,7 @@ static const char sam4s_xml_memory_map[] = "" #define EEFC_FSR_ERROR (EEFC_FSR_FCMDE | EEFC_FSR_FLOCKE) #define SAM3X_CHIPID_CIDR 0x400E0940 -#define SAM3N_CHIPID_CIDR 0x400E0740 -#define SAM3S_CHIPID_CIDR 0x400E0740 -#define SAM3U_CHIPID_CIDR 0x400E0740 -#define SAM4S_CHIPID_CIDR 0x400E0740 +#define SAM34NSU_CHIPID_CIDR 0x400E0740 #define CHIPID_CIDR_VERSION_MASK (0x1F << 0) #define CHIPID_CIDR_EPROC_CM3 (0x03 << 5) @@ -166,7 +163,6 @@ bool sam3x_probe(target *t) { t->idcode = target_mem_read32(t, SAM3X_CHIPID_CIDR); - /* FIXME: Check for all variants with similar flash interface */ switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) { case CHIPID_CIDR_ARCH_SAM3XxC | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3XxE | CHIPID_CIDR_EPROC_CM3: @@ -179,34 +175,20 @@ bool sam3x_probe(target *t) return true; } - t->idcode = target_mem_read32(t, SAM3N_CHIPID_CIDR); + t->idcode = target_mem_read32(t, SAM34NSU_CHIPID_CIDR); switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) { case CHIPID_CIDR_ARCH_SAM3NxA | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3NxB | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3NxC | CHIPID_CIDR_EPROC_CM3: - t->driver = "Atmel SAM3N"; - t->xml_mem_map = sam3n_xml_memory_map; - t->flash_erase = sam3x_flash_erase; - t->flash_write = sam3x_flash_write; - target_add_commands(t, sam3x_cmd_list, "SAM3N"); - return true; - } - - t->idcode = target_mem_read32(t, SAM3S_CHIPID_CIDR); - switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) { case CHIPID_CIDR_ARCH_SAM3SxA | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3SxB | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3SxC | CHIPID_CIDR_EPROC_CM3: - t->driver = "Atmel SAM3S"; + t->driver = "Atmel SAM3N/S"; t->xml_mem_map = sam3n_xml_memory_map; t->flash_erase = sam3x_flash_erase; t->flash_write = sam3x_flash_write; - target_add_commands(t, sam3x_cmd_list, "SAM3S"); + target_add_commands(t, sam3x_cmd_list, "SAM3N"); return true; - } - - t->idcode = target_mem_read32(t, SAM3U_CHIPID_CIDR); - switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) { case CHIPID_CIDR_ARCH_SAM3UxC | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3UxE | CHIPID_CIDR_EPROC_CM3: t->driver = "Atmel SAM3U"; @@ -215,10 +197,6 @@ bool sam3x_probe(target *t) t->flash_write = sam3x_flash_write; target_add_commands(t, sam3x_cmd_list, "SAM3U"); return true; - } - - t->idcode = target_mem_read32(t, SAM4S_CHIPID_CIDR); - switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) { case CHIPID_CIDR_ARCH_SAM4SxA | CHIPID_CIDR_EPROC_CM4: case CHIPID_CIDR_ARCH_SAM4SxB | CHIPID_CIDR_EPROC_CM4: case CHIPID_CIDR_ARCH_SAM4SxC | CHIPID_CIDR_EPROC_CM4: -- cgit v1.2.3 From fc2f266a13c89b17657414e5c6a2b354ee26c8c8 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Wed, 1 Apr 2015 22:45:52 -0700 Subject: sam3x: Update to use new buffered flash interface. --- src/sam3x.c | 359 ++++++++++++++++++++++++------------------------------------ 1 file changed, 140 insertions(+), 219 deletions(-) diff --git a/src/sam3x.c b/src/sam3x.c index 05db420..703bacc 100644 --- a/src/sam3x.c +++ b/src/sam3x.c @@ -1,7 +1,7 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2012 Black Sphere Technologies Ltd. + * Copyright (C) 2015 Black Sphere Technologies Ltd. * Written by Gareth McMullin * * This program is free software: you can redistribute it and/or modify @@ -18,8 +18,10 @@ * along with this program. If not, see . */ -/* This file implements Atmel SAM3X target specific functions for detecting +/* This file implements Atmel SAM3/4 target specific functions for detecting * the device, providing the XML memory map and Flash memory programming. + * + * Supported devices: SAM3N, SAM3S, SAM3U, SAM3X, and SAM4S */ #include "general.h" @@ -28,9 +30,10 @@ #include "command.h" #include "gdb_packet.h" -static int sam3x_flash_erase(target *t, uint32_t addr, size_t len); -static int sam3x_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len); +static int sam4_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int sam3_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int sam3x_flash_write(struct target_flash *f, uint32_t dest, + const void *src, size_t len); static bool sam3x_cmd_gpnvm_get(target *t); static bool sam3x_cmd_gpnvm_set(target *t, int argc, char *argv[]); @@ -41,54 +44,6 @@ const struct command_s sam3x_cmd_list[] = { {NULL, NULL, NULL} }; -static const char sam3x_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x100" - " " - " " - " " - ""; - -static const char sam3n_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x100" - " " - " " - " " - ""; - -static const char sam3u_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x100" - " " - " " - " " - ""; - -static const char sam4s_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x200" - " " - " " - " " - ""; - /* Enhanced Embedded Flash Controller (EEFC) Register Map */ #define SAM3N_EEFC_BASE 0x400E0A00 #define SAM3X_EEFC_BASE(x) (0x400E0A00+((x)*0x400)) @@ -129,6 +84,10 @@ static const char sam4s_xml_memory_map[] = "" #define CHIPID_CIDR_EPROC_CM4 (0x07 << 5) #define CHIPID_CIDR_EPROC_MASK (0x07 << 5) #define CHIPID_CIDR_NVPSIZ_MASK (0x0F << 8) +#define CHIPID_CIDR_NVPSIZ_8K (0x01 << 8) +#define CHIPID_CIDR_NVPSIZ_16K (0x02 << 8) +#define CHIPID_CIDR_NVPSIZ_32K (0x03 << 8) +#define CHIPID_CIDR_NVPSIZ_64K (0x05 << 8) #define CHIPID_CIDR_NVPSIZ_128K (0x07 << 8) #define CHIPID_CIDR_NVPSIZ_256K (0x09 << 8) #define CHIPID_CIDR_NVPSIZ_512K (0x0A << 8) @@ -159,23 +118,92 @@ static const char sam4s_xml_memory_map[] = "" #define SAM3_PAGE_SIZE 256 #define SAM4_PAGE_SIZE 512 +struct sam_flash { + struct target_flash f; + uint32_t eefc_base; + uint8_t write_cmd; +}; + +static void sam3_add_flash(target *t, + uint32_t eefc_base, uint32_t addr, size_t length) +{ + struct sam_flash *sf = calloc(1, sizeof(*sf)); + struct target_flash *f = &sf->f; + f->start = addr; + f->length = length; + f->blocksize = SAM3_PAGE_SIZE; + f->erase = sam3_flash_erase; + f->write = target_flash_write_buffered; + f->done = target_flash_done_buffered; + f->write_buf = sam3x_flash_write; + f->buf_size = SAM3_PAGE_SIZE; + sf->eefc_base = eefc_base; + sf->write_cmd = EEFC_FCR_FCMD_EWP; + target_add_flash(t, f); +} + +static void sam4_add_flash(target *t, + uint32_t eefc_base, uint32_t addr, size_t length) +{ + struct sam_flash *sf = calloc(1, sizeof(*sf)); + struct target_flash *f = &sf->f; + f->start = addr; + f->length = length; + f->blocksize = SAM4_PAGE_SIZE * 8; + f->erase = sam4_flash_erase; + f->write = target_flash_write_buffered; + f->done = target_flash_done_buffered; + f->write_buf = sam3x_flash_write; + f->buf_size = SAM4_PAGE_SIZE; + sf->eefc_base = eefc_base; + sf->write_cmd = EEFC_FCR_FCMD_WP; + target_add_flash(t, f); +} + +static size_t sam_flash_size(uint32_t idcode) +{ + switch (idcode & CHIPID_CIDR_NVPSIZ_MASK) { + case CHIPID_CIDR_NVPSIZ_8K: + return 0x2000; + case CHIPID_CIDR_NVPSIZ_16K: + return 0x4000; + case CHIPID_CIDR_NVPSIZ_32K: + return 0x8000; + case CHIPID_CIDR_NVPSIZ_64K: + return 0x10000; + case CHIPID_CIDR_NVPSIZ_128K: + return 0x20000; + case CHIPID_CIDR_NVPSIZ_256K: + return 0x40000; + case CHIPID_CIDR_NVPSIZ_512K: + return 0x80000; + case CHIPID_CIDR_NVPSIZ_1024K: + return 0x100000; + case CHIPID_CIDR_NVPSIZ_2048K: + return 0x200000; + } + return 0; +} + bool sam3x_probe(target *t) { t->idcode = target_mem_read32(t, SAM3X_CHIPID_CIDR); - + size_t size = sam_flash_size(t->idcode); switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) { case CHIPID_CIDR_ARCH_SAM3XxC | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3XxE | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3XxG | CHIPID_CIDR_EPROC_CM3: t->driver = "Atmel SAM3X"; - t->xml_mem_map = sam3x_xml_memory_map; - t->flash_erase = sam3x_flash_erase; - t->flash_write = sam3x_flash_write; + target_add_ram(t, 0x20000000, 0x200000); + /* 2 Flash memories back-to-back starting at 0x80000 */ + sam3_add_flash(t, SAM3X_EEFC_BASE(0), 0x80000, size/2); + sam3_add_flash(t, SAM3X_EEFC_BASE(1), 0x80000 + size/2, size/2); target_add_commands(t, sam3x_cmd_list, "SAM3X"); return true; } t->idcode = target_mem_read32(t, SAM34NSU_CHIPID_CIDR); + size = sam_flash_size(t->idcode); switch (t->idcode & (CHIPID_CIDR_ARCH_MASK | CHIPID_CIDR_EPROC_MASK)) { case CHIPID_CIDR_ARCH_SAM3NxA | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3NxB | CHIPID_CIDR_EPROC_CM3: @@ -184,26 +212,40 @@ bool sam3x_probe(target *t) case CHIPID_CIDR_ARCH_SAM3SxB | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3SxC | CHIPID_CIDR_EPROC_CM3: t->driver = "Atmel SAM3N/S"; - t->xml_mem_map = sam3n_xml_memory_map; - t->flash_erase = sam3x_flash_erase; - t->flash_write = sam3x_flash_write; - target_add_commands(t, sam3x_cmd_list, "SAM3N"); + target_add_ram(t, 0x20000000, 0x200000); + /* These devices only have a single bank */ + size = sam_flash_size(t->idcode); + sam3_add_flash(t, SAM3N_EEFC_BASE, 0x400000, size); + target_add_commands(t, sam3x_cmd_list, "SAM3N/S"); return true; case CHIPID_CIDR_ARCH_SAM3UxC | CHIPID_CIDR_EPROC_CM3: case CHIPID_CIDR_ARCH_SAM3UxE | CHIPID_CIDR_EPROC_CM3: t->driver = "Atmel SAM3U"; - t->xml_mem_map = sam3u_xml_memory_map; - t->flash_erase = sam3x_flash_erase; - t->flash_write = sam3x_flash_write; + target_add_ram(t, 0x20000000, 0x200000); + /* One flash up to 512K at 0x80000 */ + sam3_add_flash(t, SAM3U_EEFC_BASE(0), 0x80000, MIN(size, 0x80000)); + if (size >= 0x80000) { + /* Larger devices have a second bank at 0x100000 */ + sam3_add_flash(t, SAM3U_EEFC_BASE(1), + 0x100000, 0x80000); + } target_add_commands(t, sam3x_cmd_list, "SAM3U"); return true; case CHIPID_CIDR_ARCH_SAM4SxA | CHIPID_CIDR_EPROC_CM4: case CHIPID_CIDR_ARCH_SAM4SxB | CHIPID_CIDR_EPROC_CM4: case CHIPID_CIDR_ARCH_SAM4SxC | CHIPID_CIDR_EPROC_CM4: t->driver = "Atmel SAM4S"; - t->xml_mem_map = sam4s_xml_memory_map; - t->flash_erase = sam3x_flash_erase; - t->flash_write = sam3x_flash_write; + target_add_ram(t, 0x20000000, 0x400000); + size_t size = sam_flash_size(t->idcode); + if (size <= 0x80000) { + /* Smaller devices have a single bank */ + sam4_add_flash(t, SAM4S_EEFC_BASE(0), 0x400000, size); + } else { + /* Larger devices are split evenly between 2 */ + sam4_add_flash(t, SAM4S_EEFC_BASE(0), 0x400000, size/2); + sam4_add_flash(t, SAM4S_EEFC_BASE(1), + 0x400000 + size/2, size/2); + } target_add_commands(t, sam3x_cmd_list, "SAM4S"); return true; } @@ -227,191 +269,70 @@ sam3x_flash_cmd(target *t, uint32_t base, uint8_t cmd, uint16_t arg) return sr & EEFC_FSR_ERROR; } -static uint32_t -sam3x_flash_base(target *t, uint32_t addr, uint32_t *offset) +static uint32_t sam3x_flash_base(target *t) { if (strcmp(t->driver, "Atmel SAM3X") == 0) { - uint32_t half = -1; - switch (t->idcode & CHIPID_CIDR_NVPSIZ_MASK) { - case CHIPID_CIDR_NVPSIZ_128K: - half = 0x00090000; - break; - case CHIPID_CIDR_NVPSIZ_256K: - half = 0x000A0000; - break; - case CHIPID_CIDR_NVPSIZ_512K: - half = 0x000C0000; - break; - } - if (addr > half) { - if (offset) - *offset = addr - half; - return SAM3X_EEFC_BASE(1); - } else { - if (offset) - *offset = addr - 0x80000; - return SAM3X_EEFC_BASE(0); - } + return SAM3X_EEFC_BASE(0); } - - /* The SAM3U has a constant split between both banks */ if (strcmp(t->driver, "Atmel SAM3U") == 0) { - if (addr >= 0x100000) { - if(offset) - *offset = addr - 0x100000; - - return SAM3U_EEFC_BASE(1); - } else { - if(offset) - *offset = addr - 0x80000; - - return SAM3U_EEFC_BASE(0); - } + return SAM3U_EEFC_BASE(0); } - if (strcmp(t->driver, "Atmel SAM4S") == 0) { - uint32_t half = -1; - switch (t->idcode & CHIPID_CIDR_NVPSIZ_MASK) { - case CHIPID_CIDR_NVPSIZ_128K: - case CHIPID_CIDR_NVPSIZ_256K: - case CHIPID_CIDR_NVPSIZ_512K: - if (offset) - *offset = addr - 0x400000; - return SAM4S_EEFC_BASE(0); - case CHIPID_CIDR_NVPSIZ_1024K: - half = 0x480000; - break; - case CHIPID_CIDR_NVPSIZ_2048K: - half = 0x500000; - break; - } - if (addr >= half) { - if (offset) - *offset = addr - half; - return SAM4S_EEFC_BASE(1); - } else { - if (offset) - *offset = addr - 0x400000; - return SAM4S_EEFC_BASE(0); - } + return SAM4S_EEFC_BASE(0); } - - /* SAM3N device */ - if (offset) - *offset = addr - 0x400000; return SAM3N_EEFC_BASE; } -static int sam3x_flash_erase(target *t, uint32_t addr, size_t len) +static int sam4_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { - uint32_t offset; - uint32_t base = sam3x_flash_base(t, addr, &offset); + target *t = f->t; + uint32_t base = ((struct sam_flash *)f)->eefc_base; + uint32_t offset = addr - f->start; /* The SAM4S is the only supported device with a page erase command. * Erasing is done in 8-page chunks. arg[15:2] contains the page * number and arg[1:0] contains 0x1, indicating 8-page chunks. */ - if (strcmp(t->driver, "Atmel SAM4S") == 0) { - unsigned chunk = offset / SAM4_PAGE_SIZE; + unsigned chunk = offset / SAM4_PAGE_SIZE; - /* Fail if the start address is not 8-page-aligned. */ - if (chunk % 8 != 0) + while (len) { + int16_t arg = chunk | 0x1; + if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_EPA, arg)) return -1; - /* Note that the length might not be a multiple of 8 pages. - * In this case, we will erase a few extra pages at the end. - */ - while (len > 0) { - int16_t arg = chunk | 0x1; - if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_EPA, arg)) - return -1; - - len -= SAM4_PAGE_SIZE * 8; - addr += SAM4_PAGE_SIZE * 8; - chunk += 8; - } - - return 0; + len -= f->blocksize; + chunk += 8; } + return 0; +} +static int sam3_flash_erase(struct target_flash *f, uint32_t addr, size_t len) +{ /* The SAM3X/SAM3N don't really have a page erase function. - * This Erase/Write page is the best we have, so we write with all - * ones. This does waste time, but what can we do? + * We do nothing here and use Erase/Write page in flash_write. */ - unsigned chunk = offset / SAM3_PAGE_SIZE; - uint8_t buf[SAM3_PAGE_SIZE]; - - memset(buf, 0xff, sizeof(buf)); - /* Only do this once, since it doesn't change. */ - target_mem_write(t, addr, buf, SAM3_PAGE_SIZE); - - while (len) { - if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_EWP, chunk)) - return -1; - - len -= SAM3_PAGE_SIZE; - addr += SAM3_PAGE_SIZE; - chunk++; - } - + (void)f; (void)addr; (void)len; return 0; } -static int sam3x_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len) +static int sam3x_flash_write(struct target_flash *f, uint32_t dest, + const void *src, size_t len) { - unsigned page_size; - if (strcmp(t->driver, "Atmel SAM4S") == 0) { - page_size = SAM4_PAGE_SIZE; - } else { - page_size = SAM3_PAGE_SIZE; - } - uint32_t offset; - uint32_t base = sam3x_flash_base(t, dest, &offset); - uint8_t buf[page_size]; - unsigned first_chunk = offset / page_size; - unsigned last_chunk = (offset + len - 1) / page_size; - offset %= page_size; - dest -= offset; - - for (unsigned chunk = first_chunk; chunk <= last_chunk; chunk++) { - - DEBUG("chunk %u len %zu\n", chunk, len); - /* first and last chunk may require special handling */ - if ((chunk == first_chunk) || (chunk == last_chunk)) { - - /* fill with all ff to avoid sector rewrite corrupting other writes */ - memset(buf, 0xff, sizeof(buf)); - - /* copy as much as fits */ - size_t copylen = page_size - offset; - if (copylen > len) - copylen = len; - memcpy(&buf[offset], src, copylen); - - /* update to suit */ - len -= copylen; - src += copylen; - offset = 0; - } else { - - /* interior chunk, must be aligned and full-sized */ - memcpy(buf, src, page_size); - len -= page_size; - src += page_size; - } + target *t = f->t; + struct sam_flash *sf = (struct sam_flash *)f; + uint32_t base = sf->eefc_base; + unsigned chunk = (dest - f->start) / f->buf_size; - target_mem_write(t, dest, buf, page_size); - if(sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_WP, chunk)) - return -1; - } + target_mem_write(t, dest, src, len); + if(sam3x_flash_cmd(t, base, sf->write_cmd, chunk)) + return -1; return 0; } static bool sam3x_cmd_gpnvm_get(target *t) { - uint32_t base = sam3x_flash_base(t, 0, NULL); + uint32_t base = sam3x_flash_base(t); sam3x_flash_cmd(t, base, EEFC_FCR_FCMD_GGPB, 0); gdb_outf("GPNVM: 0x%08X\n", target_mem_read32(t, EEFC_FRR(base))); @@ -422,7 +343,7 @@ static bool sam3x_cmd_gpnvm_get(target *t) static bool sam3x_cmd_gpnvm_set(target *t, int argc, char *argv[]) { uint32_t bit, cmd; - uint32_t base = sam3x_flash_base(t, 0, NULL); + uint32_t base = sam3x_flash_base(t); if (argc != 3) { gdb_out("usage: monitor gpnvm_set \n"); -- cgit v1.2.3 From 1efad1a03a322e82b85c18a6c22c4d96574e6697 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Fri, 3 Apr 2015 17:58:33 -0700 Subject: stm32f4: use new flash interface. --- src/stm32f4.c | 111 +++++++++++++++++++++++----------------------------------- 1 file changed, 44 insertions(+), 67 deletions(-) diff --git a/src/stm32f4.c b/src/stm32f4.c index 03a33f0..7dd4761 100644 --- a/src/stm32f4.c +++ b/src/stm32f4.c @@ -47,39 +47,12 @@ const struct command_s stm32f4_cmd_list[] = { }; -static int stm32f4_flash_erase(target *t, uint32_t addr, size_t len); -static int stm32f4_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len); +static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int stm32f4_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len); static const char stm32f4_driver_str[] = "STM32F4xx"; -static const char stm32f4_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x4000" - " " - " " - " 0x10000" - " " - " " - " 0x20000" - " " - " " - " 0x4000" - " " - " " - " 0x10000" - " " - " " - " 0x20000" - " " - " " - " " - ""; - /* Flash Program ad Erase Controller Register Map */ #define FPEC_BASE 0x40023C00 #define FLASH_ACR (FPEC_BASE+0x00) @@ -127,6 +100,28 @@ static const uint16_t stm32f4_flash_write_stub[] = { #define SRAM_BASE 0x20000000 #define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(stm32f4_flash_write_stub), 4) +struct stm32f4_flash { + struct target_flash f; + uint8_t base_sector; +}; + +static void stm32f4_add_flash(target *t, + uint32_t addr, size_t length, size_t blocksize, + uint8_t base_sector) +{ + struct stm32f4_flash *sf = calloc(1, sizeof(*sf)); + struct target_flash *f = &sf->f; + f->start = addr; + f->length = length; + f->blocksize = blocksize; + f->erase = stm32f4_flash_erase; + f->write = stm32f4_flash_write; + f->align = 4; + f->erased = 0xff; + sf->base_sector = base_sector; + target_add_flash(t, f); +} + bool stm32f4_probe(target *t) { uint32_t idcode; @@ -139,10 +134,12 @@ bool stm32f4_probe(target *t) case 0x423: /* F401 B/C RM0368 Rev.3 */ case 0x431: /* F411 RM0383 Rev.4 */ case 0x433: /* F401 D/E RM0368 Rev.3 */ - t->xml_mem_map = stm32f4_xml_memory_map; t->driver = stm32f4_driver_str; - t->flash_erase = stm32f4_flash_erase; - t->flash_write = stm32f4_flash_write; + target_add_ram(t, 0x10000000, 0x10000); + target_add_ram(t, 0x20000000, 0x30000); + stm32f4_add_flash(t, 0x8000000, 0x10000, 0x4000, 0); + stm32f4_add_flash(t, 0x8010000, 0x10000, 0x10000, 4); + stm32f4_add_flash(t, 0x8020000, 0xE0000, 0x20000, 5); target_add_commands(t, stm32f4_cmd_list, "STM32F4"); return true; } @@ -158,30 +155,18 @@ static void stm32f4_flash_unlock(target *t) } } -static int stm32f4_flash_erase(target *t, uint32_t addr, size_t len) +static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { + target *t = f->t; uint16_t sr; - uint32_t cr; - uint32_t pagesize; - - addr &= 0x07FFC000; + uint8_t sector = ((struct stm32f4_flash *)f)->base_sector + + (addr - f->start)/f->blocksize; stm32f4_flash_unlock(t); while(len) { - if (addr < 0x10000) { /* Sector 0..3 */ - cr = (addr >> 11); - pagesize = 0x4000; - } else if (addr < 0x20000) { /* Sector 4 */ - cr = (4 << 3); - pagesize = 0x10000; - } else if (addr < 0x100000) { /* Sector 5..11 */ - cr = (((addr - 0x20000) >> 14) + 0x28); - pagesize = 0x20000; - } else { /* Sector > 11 ?? */ - return -1; - } - cr |= FLASH_CR_EOPIE | FLASH_CR_ERRIE | FLASH_CR_SER; + uint32_t cr = FLASH_CR_EOPIE | FLASH_CR_ERRIE | FLASH_CR_SER | + (sector << 3); /* Flash page erase instruction */ target_mem_write32(t, FLASH_CR, cr); /* write address to FMA */ @@ -192,8 +177,8 @@ static int stm32f4_flash_erase(target *t, uint32_t addr, size_t len) if(target_check_error(t)) return -1; - len -= pagesize; - addr += pagesize; + len -= f->blocksize; + sector++; } /* Check for error */ @@ -204,23 +189,15 @@ static int stm32f4_flash_erase(target *t, uint32_t addr, size_t len) return 0; } -static int stm32f4_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len) +static int stm32f4_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len) { - uint32_t offset = dest % 4; - uint8_t data[ALIGN(offset + len, 4)]; - - /* Construct data buffer used by stub */ - /* pad partial words with all 1s to avoid damaging overlapping areas */ - memset(data, 0xff, sizeof(data)); - memcpy((uint8_t *)data + offset, src, len); - /* Write buffer to target ram call stub */ - target_mem_write(t, SRAM_BASE, stm32f4_flash_write_stub, + target_mem_write(f->t, SRAM_BASE, stm32f4_flash_write_stub, sizeof(stm32f4_flash_write_stub)); - target_mem_write(t, STUB_BUFFER_BASE, data, sizeof(data)); - return cortexm_run_stub(t, SRAM_BASE, dest - offset, - STUB_BUFFER_BASE, sizeof(data), 0); + target_mem_write(f->t, STUB_BUFFER_BASE, src, len); + return cortexm_run_stub(f->t, SRAM_BASE, dest, + STUB_BUFFER_BASE, len, 0); } static bool stm32f4_cmd_erase_mass(target *t) -- cgit v1.2.3 From 7cd34329940d3032e3c7a09c45eb0dee96659ff1 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Fri, 3 Apr 2015 21:38:43 -0700 Subject: stm32f4: Add second bank for F42x/F43x. --- src/stm32f4.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/stm32f4.c b/src/stm32f4.c index 7dd4761..7b7a92e 100644 --- a/src/stm32f4.c +++ b/src/stm32f4.c @@ -128,9 +128,14 @@ bool stm32f4_probe(target *t) idcode = target_mem_read32(t, DBGMCU_IDCODE); switch(idcode & 0xFFF) { + case 0x419: /* 427/437 */ + /* Second bank for 2M parts. */ + stm32f4_add_flash(t, 0x8100000, 0x10000, 0x4000, 12); + stm32f4_add_flash(t, 0x8110000, 0x10000, 0x10000, 16); + stm32f4_add_flash(t, 0x8120000, 0xE0000, 0x20000, 17); + /* Fall through for stuff common to F40x/F41x */ case 0x411: /* Documented to be 0x413! This is what I read... */ case 0x413: /* F407VGT6 */ - case 0x419: /* 427/437 */ case 0x423: /* F401 B/C RM0368 Rev.3 */ case 0x431: /* F411 RM0383 Rev.4 */ case 0x433: /* F401 D/E RM0368 Rev.3 */ -- cgit v1.2.3 From 622497f7e28142f5f8d5cab7dfd6608bf88ce0de Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Fri, 3 Apr 2015 23:01:11 -0700 Subject: stm32f1: use new flash interface. --- src/stm32f1.c | 139 +++++++++++++++++----------------------------------------- 1 file changed, 40 insertions(+), 99 deletions(-) diff --git a/src/stm32f1.c b/src/stm32f1.c index 459c159..e405aca 100644 --- a/src/stm32f1.c +++ b/src/stm32f1.c @@ -46,43 +46,10 @@ const struct command_s stm32f1_cmd_list[] = { }; -static int stm32md_flash_erase(target *t, uint32_t addr, size_t len); -static int stm32hd_flash_erase(target *t, uint32_t addr, size_t len); -static int stm32f1_flash_erase(target *t, uint32_t addr, size_t len, - uint32_t pagesize); -static int stm32f1_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len); - -static const char stm32f1_driver_str[] = "STM32, Medium density."; -static const char stm32hd_driver_str[] = "STM32, High density."; -static const char stm32f3_driver_str[] = "STM32F3xx"; -static const char stm32f03_driver_str[] = "STM32F03x"; -static const char stm32f04_driver_str[] = "STM32F04x"; -static const char stm32f05_driver_str[] = "STM32F05x"; -static const char stm32f07_driver_str[] = "STM32F07x"; -static const char stm32f09_driver_str[] = "STM32F09x"; - -static const char stm32f1_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x400" - " " - " " - ""; - -static const char stm32hd_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x800" - " " - " " - ""; +static int stm32f1_flash_erase(struct target_flash *f, + uint32_t addr, size_t len); +static int stm32f1_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len); /* Flash Program ad Erase Controller Register Map */ #define FPEC_BASE 0x40022000 @@ -127,6 +94,20 @@ static const uint16_t stm32f1_flash_write_stub[] = { #define SRAM_BASE 0x20000000 #define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(stm32f1_flash_write_stub), 4) +static void stm32f1_add_flash(target *t, + uint32_t addr, size_t length, size_t erasesize) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + f->start = addr; + f->length = length; + f->blocksize = erasesize; + f->erase = stm32f1_flash_erase; + f->write = stm32f1_flash_write; + f->align = 2; + f->erased = 0xff; + target_add_flash(t, f); +} + bool stm32f1_probe(target *t) { t->idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0xfff; @@ -134,27 +115,24 @@ bool stm32f1_probe(target *t) case 0x410: /* Medium density */ case 0x412: /* Low denisty */ case 0x420: /* Value Line, Low-/Medium density */ - t->driver = stm32f1_driver_str; - t->xml_mem_map = stm32f1_xml_memory_map; - t->flash_erase = stm32md_flash_erase; - t->flash_write = stm32f1_flash_write; + t->driver = "STM32F1 medium density"; + target_add_ram(t, 0x20000000, 0x5000); + stm32f1_add_flash(t, 0x8000000, 0x20000, 0x400); target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD"); return true; case 0x414: /* High density */ case 0x418: /* Connectivity Line */ case 0x428: /* Value Line, High Density */ - t->driver = stm32hd_driver_str; - t->xml_mem_map = stm32hd_xml_memory_map; - t->flash_erase = stm32hd_flash_erase; - t->flash_write = stm32f1_flash_write; + t->driver = "STM32F1 high density"; + target_add_ram(t, 0x20000000, 0x10000); + stm32f1_add_flash(t, 0x8000000, 0x80000, 0x800); target_add_commands(t, stm32f1_cmd_list, "STM32 HD/CL"); return true; case 0x422: /* STM32F30x */ case 0x432: /* STM32F37x */ - t->driver = stm32f3_driver_str; - t->xml_mem_map = stm32hd_xml_memory_map; - t->flash_erase = stm32hd_flash_erase; - t->flash_write = stm32f1_flash_write; + t->driver = "STM32F3"; + target_add_ram(t, 0x20000000, 0x10000); + stm32f1_add_flash(t, 0x8000000, 0x80000, 0x800); target_add_commands(t, stm32f1_cmd_list, "STM32F3"); return true; } @@ -166,26 +144,9 @@ bool stm32f1_probe(target *t) case 0x440: /* STM32F05 RM0091 Rev.7 */ case 0x448: /* STM32F07 RM0091 Rev.7 */ case 0x442: /* STM32F09 RM0091 Rev.7 */ - switch(t->idcode) { - case 0x444: /* STM32F03 */ - t->driver = stm32f03_driver_str; - break; - case 0x445: /* STM32F04 */ - t->driver = stm32f04_driver_str; - break; - case 0x440: /* STM32F05 */ - t->driver = stm32f05_driver_str; - break; - case 0x448: /* STM32F07 */ - t->driver = stm32f07_driver_str; - break; - case 0x442: /* STM32F09 */ - t->driver = stm32f09_driver_str; - break; - } - t->xml_mem_map = stm32f1_xml_memory_map; - t->flash_erase = stm32md_flash_erase; - t->flash_write = stm32f1_flash_write; + t->driver = "STM32F0"; + target_add_ram(t, 0x20000000, 0x5000); + stm32f1_add_flash(t, 0x8000000, 0x20000, 0x400); target_add_commands(t, stm32f1_cmd_list, "STM32F0"); return true; } @@ -199,14 +160,12 @@ static void stm32f1_flash_unlock(target *t) target_mem_write32(t, FLASH_KEYR, KEY2); } -static int stm32f1_flash_erase(target *t, uint32_t addr, - size_t len, uint32_t pagesize) +static int stm32f1_flash_erase(struct target_flash *f, + uint32_t addr, size_t len) { + target *t = f->t; uint16_t sr; - addr &= ~(pagesize - 1); - len = (len + pagesize - 1) & ~(pagesize - 1); - stm32f1_flash_unlock(t); while(len) { @@ -222,8 +181,8 @@ static int stm32f1_flash_erase(target *t, uint32_t addr, if(target_check_error(t)) return -1; - len -= pagesize; - addr += pagesize; + len -= f->blocksize; + addr += f->blocksize; } /* Check for error */ @@ -234,33 +193,15 @@ static int stm32f1_flash_erase(target *t, uint32_t addr, return 0; } -static int stm32hd_flash_erase(target *t, uint32_t addr, size_t len) -{ - return stm32f1_flash_erase(t, addr, len, 0x800); -} - -static int stm32md_flash_erase(target *t, uint32_t addr, size_t len) -{ - return stm32f1_flash_erase(t, addr, len, 0x400); -} - -static int stm32f1_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len) +static int stm32f1_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len) { - uint32_t offset = dest % 4; - uint8_t data[ALIGN(offset + len, 4)]; - - /* Construct data buffer used by stub */ - /* pad partial words with all 1s to avoid damaging overlapping areas */ - memset(data, 0xff, sizeof(data)); - memcpy((uint8_t *)data + offset, src, len); - + target *t = f->t; /* Write stub and data to target ram and set PC */ target_mem_write(t, SRAM_BASE, stm32f1_flash_write_stub, sizeof(stm32f1_flash_write_stub)); - target_mem_write(t, STUB_BUFFER_BASE, data, sizeof(data)); - return cortexm_run_stub(t, SRAM_BASE, dest - offset, - STUB_BUFFER_BASE, sizeof(data), 0); + target_mem_write(t, STUB_BUFFER_BASE, src, len); + return cortexm_run_stub(t, SRAM_BASE, dest, STUB_BUFFER_BASE, len, 0); } static bool stm32f1_cmd_erase_mass(target *t) -- cgit v1.2.3 From 9e09ae2e1e5cd8ddee69147e25dfdc96d04fc953 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 4 Apr 2015 08:45:01 -0700 Subject: lmi: use new flash interface. --- src/lmi.c | 64 +++++++++++++++++++++++++++------------------------------------ 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/src/lmi.c b/src/lmi.c index fb425a2..6bf2240 100644 --- a/src/lmi.c +++ b/src/lmi.c @@ -46,65 +46,51 @@ #define LMI_FLASH_FMC_COMT (1 << 3) #define LMI_FLASH_FMC_WRKEY 0xA4420000 -static int lmi_flash_erase(target *t, uint32_t addr, size_t len); -static int lmi_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len); +static int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int lmi_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len); static const char lmi_driver_str[] = "TI Stellaris/Tiva"; -static const char lmi_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x400" - " " - " " - ""; - -static const char tm4c123gh6pm_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x400" - " " - " " - ""; - - static const uint16_t lmi_flash_write_stub[] = { #include "../flashstub/lmi.stub" }; +static void lmi_add_flash(target *t, size_t length) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + f->start = 0; + f->length = length; + f->blocksize = 0x400; + f->erase = lmi_flash_erase; + f->write = lmi_flash_write; + f->align = 4; + f->erased = 0xff; + target_add_flash(t, f); +} + bool lmi_probe(target *t) { uint32_t did1 = target_mem_read32(t, LMI_SCB_DID1); switch (did1 >> 16) { case 0x1049: /* LM3S3748 */ t->driver = lmi_driver_str; - t->xml_mem_map = lmi_xml_memory_map; - t->flash_erase = lmi_flash_erase; - t->flash_write = lmi_flash_write; + target_add_ram(t, 0x20000000, 0x8000); + lmi_add_flash(t, 0x40000); return true; case 0x10A1: /* TM4C123GH6PM */ t->driver = lmi_driver_str; - t->xml_mem_map = tm4c123gh6pm_xml_memory_map; - t->flash_erase = lmi_flash_erase; - t->flash_write = lmi_flash_write; + target_add_ram(t, 0x20000000, 0x10000); + lmi_add_flash(t, 0x80000); return true; } return false; } -int lmi_flash_erase(target *t, uint32_t addr, size_t len) +int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { - addr &= ~(BLOCK_SIZE - 1); - len &= ~(BLOCK_SIZE - 1); - + target *t = f->t; while(len) { target_mem_write32(t, LMI_FLASH_FMA, addr); target_mem_write32(t, LMI_FLASH_FMC, @@ -118,8 +104,12 @@ int lmi_flash_erase(target *t, uint32_t addr, size_t len) return 0; } -int lmi_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len) +int lmi_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len) { + target *t = f->t; + + /* FIXME rewrite stub to use register args */ uint32_t data[(len>>2)+2]; data[0] = dest; data[1] = len >> 2; -- cgit v1.2.3 From 1541f1c7a8a7b741e4374c7062ce4c9e1148342c Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 4 Apr 2015 08:59:51 -0700 Subject: kinetis: use new flash interface. --- src/kinetis.c | 65 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/src/kinetis.c b/src/kinetis.c index 7ccb28d..3e1fa65 100644 --- a/src/kinetis.c +++ b/src/kinetis.c @@ -20,10 +20,12 @@ /* This file implements KL25 target specific functions providing * the XML memory map and Flash memory programming. + * + * According to Freescale doc KL25P80M48SF0RM: + * KL25 Sub-family Reference Manual */ #include "general.h" -#include "adiv5.h" #include "target.h" #define SIM_SDID 0x40048024 @@ -54,21 +56,23 @@ #define KL25_PAGESIZE 0x400 -static int kl25_flash_erase(target *t, uint32_t addr, size_t len); -static int kl25_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len); - -static const char kl25_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x400" - " " - " " - " " - ""; +static int kl25_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int kl25_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len); + +static void kl25_add_flash(target *t, + uint32_t addr, size_t length, size_t erasesize) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + f->start = addr; + f->length = length; + f->blocksize = erasesize; + f->erase = kl25_flash_erase; + f->write = kl25_flash_write; + f->align = 4; + f->erased = 0xff; + target_add_flash(t, f); +} bool kinetis_probe(target *t) { @@ -76,9 +80,9 @@ bool kinetis_probe(target *t) switch (sdid >> 20) { case 0x251: t->driver = "KL25"; - t->xml_mem_map = kl25_xml_memory_map; - t->flash_erase = kl25_flash_erase; - t->flash_write = kl25_flash_write; + target_add_ram(t, 0x1ffff000, 0x1000); + target_add_ram(t, 0x20000000, 0x3000); + kl25_add_flash(t, 0x00000000, 0x20000, 0x400); return true; } return false; @@ -89,11 +93,11 @@ kl25_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8]) { uint8_t fstat; - /* Wait for CCIF to be high */ + /* Wait for CCIF to be high */ do { fstat = target_mem_read8(t, FTFA_FSTAT); /* Check ACCERR and FPVIOL are zero in FSTAT */ - if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL)) + if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL)) return false; } while (!(fstat & FTFA_FSTAT_CCIF)); @@ -113,35 +117,28 @@ kl25_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8]) do { fstat = target_mem_read8(t, FTFA_FSTAT); /* Check ACCERR and FPVIOL are zero in FSTAT */ - if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL)) + if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL)) return false; } while (!(fstat & FTFA_FSTAT_CCIF)); return true; } -static int kl25_flash_erase(target *t, uint32_t addr, size_t len) +static int kl25_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { - addr &= ~(KL25_PAGESIZE - 1); - len = (len + KL25_PAGESIZE - 1) & ~(KL25_PAGESIZE - 1); - while (len) { - kl25_command(t, FTFA_CMD_ERASE_SECTOR, addr, NULL); + kl25_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL); len -= KL25_PAGESIZE; addr += KL25_PAGESIZE; } return 0; } -static int kl25_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len) +static int kl25_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len) { - /* FIXME handle misaligned start and end of sections */ - if ((dest & 3) || (len & 3)) - return -1; - while (len) { - kl25_command(t, FTFA_CMD_PROGRAM_LONGWORD, dest, src); + kl25_command(f->t, FTFA_CMD_PROGRAM_LONGWORD, dest, src); len -= 4; dest += 4; src += 4; -- cgit v1.2.3 From d34005307867230d30fff819faa4ea2580aae625 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 4 Apr 2015 09:14:52 -0700 Subject: nrf51: use new flash interface. --- src/nrf51.c | 69 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/nrf51.c b/src/nrf51.c index e302de7..6aed592 100644 --- a/src/nrf51.c +++ b/src/nrf51.c @@ -28,9 +28,9 @@ #include "gdb_packet.h" #include "cortexm.h" -static int nrf51_flash_erase(target *t, uint32_t addr, size_t len); -static int nrf51_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len); +static int nrf51_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +static int nrf51_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len); static bool nrf51_cmd_erase_all(target *t); static bool nrf51_cmd_read_hwid(target *t); @@ -54,20 +54,6 @@ const struct command_s nrf51_read_cmd_list[] = { {NULL, NULL, NULL} }; -static const char nrf51_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x400" - " " - " " - " 0x400" - " " - " " - ""; - /* Non-Volatile Memory Controller (NVMC) Registers */ #define NRF51_NVMC 0x4001E000 #define NRF51_NVMC_READY (NRF51_NVMC + 0x400) @@ -103,6 +89,20 @@ static const uint16_t nrf51_flash_write_stub[] = { #include "../flashstub/nrf51.stub" }; +static void nrf51_add_flash(target *t, + uint32_t addr, size_t length, size_t erasesize) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + f->start = addr; + f->length = length; + f->blocksize = erasesize; + f->erase = nrf51_flash_erase; + f->write = nrf51_flash_write; + f->align = 4; + f->erased = 0xff; + target_add_flash(t, f); +} + bool nrf51_probe(target *t) { t->idcode = target_mem_read32(t, NRF51_FICR_CONFIGID) & 0xFFFF; @@ -120,9 +120,9 @@ bool nrf51_probe(target *t) case 0x0026: case 0x004C: t->driver = "Nordic nRF51"; - t->xml_mem_map = nrf51_xml_memory_map; - t->flash_erase = nrf51_flash_erase; - t->flash_write = nrf51_flash_write; + target_add_ram(t, 0x20000000, 0x4000); + nrf51_add_flash(t, 0x00000000, 0x40000, NRF51_PAGE_SIZE); + nrf51_add_flash(t, NRF51_UICR, 0x100, 0x100); target_add_commands(t, nrf51_cmd_list, "nRF51"); return true; } @@ -130,11 +130,9 @@ bool nrf51_probe(target *t) return false; } -static int nrf51_flash_erase(target *t, uint32_t addr, size_t len) +static int nrf51_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { - addr &= ~(NRF51_PAGE_SIZE - 1); - len &= ~(NRF51_PAGE_SIZE - 1); - + target *t = f->t; /* Enable erase */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN); @@ -158,8 +156,8 @@ static int nrf51_flash_erase(target *t, uint32_t addr, size_t len) if(target_check_error(t)) return -1; - addr += NRF51_PAGE_SIZE; - len -= NRF51_PAGE_SIZE; + addr += f->blocksize; + len -= f->blocksize; } /* Return to read-only */ @@ -173,19 +171,18 @@ static int nrf51_flash_erase(target *t, uint32_t addr, size_t len) return 0; } -static int nrf51_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len) +static int nrf51_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len) { - uint32_t offset = dest % 4; - uint32_t words = (offset + len + 3) / 4; - uint32_t data[2 + words]; + target *t = f->t; + uint32_t data[2 + len/4]; + + /* FIXME rewrite stub to use register args */ /* Construct data buffer used by stub */ - data[0] = dest - offset; - data[1] = words * 4; /* length must always be a multiple of 4 */ - data[2] = 0xFFFFFFFF; /* pad partial words with all 1s to avoid */ - data[words + 1] = 0xFFFFFFFF; /* damaging overlapping areas */ - memcpy((uint8_t *)&data[2] + offset, src, len); + data[0] = dest; + data[1] = len; /* length must always be a multiple of 4 */ + memcpy((uint8_t *)&data[2], src, len); /* Enable write */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_WEN); -- cgit v1.2.3 From 54eb3a719fc78c66d0fb60944440a830092f69eb Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 4 Apr 2015 15:01:35 -0700 Subject: samd: use new flash interface. --- src/samd.c | 111 ++++++++++++++++++++++--------------------------------------- 1 file changed, 39 insertions(+), 72 deletions(-) diff --git a/src/samd.c b/src/samd.c index c8517aa..ae38255 100644 --- a/src/samd.c +++ b/src/samd.c @@ -40,9 +40,9 @@ #include "gdb_packet.h" #include "cortexm.h" -static int samd_flash_erase(target *t, uint32_t addr, size_t len); -static int samd_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len); +static int samd_flash_erase(struct target_flash *t, uint32_t addr, size_t len); +static int samd_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len); static bool samd_cmd_erase_all(target *t); static bool samd_cmd_lock_flash(target *t); @@ -63,21 +63,6 @@ const struct command_s samd_cmd_list[] = { {NULL, NULL, NULL} }; -/** - * 256KB Flash Max., 32KB RAM Max. The smallest unit of erase is the - * one row = 256 bytes. - */ -static const char samd_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x100" - " " - " " - ""; - /* Non-Volatile Memory Controller (NVMC) Parameters */ #define SAMD_ROW_SIZE 256 #define SAMD_PAGE_SIZE 64 @@ -361,6 +346,19 @@ struct samd_descr samd_parse_device_id(uint32_t did) return samd; } +static void samd_add_flash(target *t, uint32_t addr, size_t length) +{ + struct target_flash *f = calloc(1, sizeof(*f)); + f->start = addr; + f->length = length; + f->blocksize = SAMD_ROW_SIZE; + f->erase = samd_flash_erase; + f->write = target_flash_write_buffered; + f->done = target_flash_done_buffered; + f->write_buf = samd_flash_write; + f->buf_size = SAMD_PAGE_SIZE; + target_add_flash(t, f); +} char variant_string[40]; bool samd_probe(target *t) @@ -423,9 +421,8 @@ bool samd_probe(target *t) t->attach = samd_protected_attach; } - t->xml_mem_map = samd_xml_memory_map; - t->flash_erase = samd_flash_erase; - t->flash_write = samd_flash_write; + target_add_ram(t, 0x20000000, 0x8000); + samd_add_flash(t, 0x00000000, 0x40000); target_add_commands(t, samd_cmd_list, "SAMD"); /* If we're not in reset here */ @@ -463,11 +460,9 @@ static void samd_unlock_current_address(target *t) /** * Erase flash row by row */ -static int samd_flash_erase(target *t, uint32_t addr, size_t len) +static int samd_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { - addr &= ~(SAMD_ROW_SIZE - 1); - len &= ~(SAMD_ROW_SIZE - 1); - + target *t = f->t; while (len) { /* Write address of first word in row to erase it */ /* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */ @@ -487,8 +482,8 @@ static int samd_flash_erase(target *t, uint32_t addr, size_t len) /* Lock */ samd_lock_current_address(t); - addr += SAMD_ROW_SIZE; - len -= SAMD_ROW_SIZE; + addr += f->blocksize; + len -= f->blocksize; } return 0; @@ -497,56 +492,28 @@ static int samd_flash_erase(target *t, uint32_t addr, size_t len) /** * Write flash page by page */ -static int samd_flash_write(target *t, uint32_t dest, - const uint8_t *src, size_t len) +static int samd_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len) { - /* Find the size of our 32-bit data buffer */ - uint32_t offset = dest % 4; - uint32_t words = (offset + len + 3) / 4; - uint32_t data[words], i = 0; - - /* Populate the data buffer */ - memset((uint8_t *)data, 0xFF, words * 4); - memcpy((uint8_t *)data + offset, src, len); - - /* The address of the first word involved in the write */ - uint32_t addr = dest & ~0x3; - /* The address of the last word involved in the write */ - uint32_t end = (dest + len - 1) & ~0x3; - - /* The start address of the first page involved in the write */ - uint32_t first_page = dest & ~(SAMD_PAGE_SIZE - 1); - /* The start address of the last page involved in the write */ - uint32_t last_page = (dest + len - 1) & ~(SAMD_PAGE_SIZE - 1); - uint32_t next_page; - uint32_t length; - - for (uint32_t page = first_page; page <= last_page; page += SAMD_PAGE_SIZE) { - next_page = page + SAMD_PAGE_SIZE; - length = MIN(end + 4, next_page) - addr; - - /* Write within a single page. This may be part or all of the page */ - target_mem_write(t, addr, &data[i], length); - addr += length; i += (length >> 2); - - /* If MANW=0 (default) we may have triggered an automatic - * write. Ignore this */ + target *t = f->t; - /* Unlock */ - samd_unlock_current_address(t); + /* Write within a single page. This may be part or all of the page */ + target_mem_write(t, dest, src, len); - /* Issue the write page command */ - target_mem_write32(t, SAMD_NVMC_CTRLA, - SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEPAGE); + /* Unlock */ + samd_unlock_current_address(t); - /* Poll for NVM Ready */ - while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0) - if (target_check_error(t)) - return -1; + /* Issue the write page command */ + target_mem_write32(t, SAMD_NVMC_CTRLA, + SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEPAGE); - /* Lock */ - samd_lock_current_address(t); - } + /* Poll for NVM Ready */ + while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0) + if (target_check_error(t)) + return -1; + + /* Lock */ + samd_lock_current_address(t); return 0; } -- cgit v1.2.3 From cd5d569d38ea8cc905739bd9189ac5f944de0207 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 4 Apr 2015 12:44:30 -0700 Subject: lpc: Reduce differences between lpc11xx and lpc43xx code. --- src/cortexm.c | 8 --- src/include/cortexm.h | 10 ++++ src/include/lpc_common.h | 83 +++++++++++++++++++++++++++ src/lpc11xx.c | 93 +++++++++++++----------------- src/lpc43xx.c | 144 ++++++++++++----------------------------------- 5 files changed, 168 insertions(+), 170 deletions(-) create mode 100644 src/include/lpc_common.h diff --git a/src/cortexm.c b/src/cortexm.c index ae1c59d..e7bed5b 100644 --- a/src/cortexm.c +++ b/src/cortexm.c @@ -195,14 +195,6 @@ static const char tdesc_cortex_mf[] = " " ""; -#define REG_SP 13 -#define REG_LR 14 -#define REG_PC 15 -#define REG_XPSR 16 -#define REG_MSP 17 -#define REG_PSP 18 -#define REG_SPECIAL 19 - bool cortexm_probe(target *t) { t->driver = cortexm_driver_str; diff --git a/src/include/cortexm.h b/src/include/cortexm.h index f7396bf..0a9c3ae 100644 --- a/src/include/cortexm.h +++ b/src/include/cortexm.h @@ -143,6 +143,16 @@ #define CORTEXM_DWT_FUNC_FUNC_WRITE (6 << 0) #define CORTEXM_DWT_FUNC_FUNC_ACCESS (7 << 0) +#define REG_SP 13 +#define REG_LR 14 +#define REG_PC 15 +#define REG_XPSR 16 +#define REG_MSP 17 +#define REG_PSP 18 +#define REG_SPECIAL 19 + +#define ARM_THUMB_BREAKPOINT 0xBE00 + bool cortexm_attach(target *t); void cortexm_detach(target *t); void cortexm_halt_resume(target *t, bool step); diff --git a/src/include/lpc_common.h b/src/include/lpc_common.h new file mode 100644 index 0000000..45d2964 --- /dev/null +++ b/src/include/lpc_common.h @@ -0,0 +1,83 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2015 Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __LPC_COMMON_H +#define __LPC_COMMON_H + +#define IAP_CMD_INIT 49 +#define IAP_CMD_PREPARE 50 +#define IAP_CMD_PROGRAM 51 +#define IAP_CMD_ERASE 52 +#define IAP_CMD_BLANKCHECK 53 +#define IAP_CMD_SET_ACTIVE_BANK 60 + +#define IAP_STATUS_CMD_SUCCESS 0 +#define IAP_STATUS_INVALID_COMMAND 1 +#define IAP_STATUS_SRC_ADDR_ERROR 2 +#define IAP_STATUS_DST_ADDR_ERROR 3 +#define IAP_STATUS_SRC_ADDR_NOT_MAPPED 4 +#define IAP_STATUS_DST_ADDR_NOT_MAPPED 5 +#define IAP_STATUS_COUNT_ERROR 6 +#define IAP_STATUS_INVALID_SECTOR 7 +#define IAP_STATUS_SECTOR_NOT_BLANK 8 +#define IAP_STATUS_SECTOR_NOT_PREPARED 9 +#define IAP_STATUS_COMPARE_ERROR 10 +#define IAP_STATUS_BUSY 11 + +/* CPU Frequency */ +#define CPU_CLK_KHZ 12000 + +struct flash_param { + uint16_t opcode;/* opcode to return to after calling the ROM */ + uint16_t pad0; + uint32_t command;/* IAP command */ + union { + uint32_t words[5];/* command parameters */ + struct { + uint32_t start_sector; + uint32_t end_sector; + uint32_t flash_bank; + } prepare; + struct { + uint32_t start_sector; + uint32_t end_sector; + uint32_t cpu_clk_khz; + uint32_t flash_bank; + } erase; + struct { + uint32_t dest; + uint32_t source; + uint32_t byte_count; + uint32_t cpu_clk_khz; + } program; + struct { + uint32_t start_sector; + uint32_t end_sector; + uint32_t flash_bank; + } blank_check; + struct { + uint32_t flash_bank; + uint32_t cpu_clk_khz; + } make_active; + }; + uint32_t result[5]; /* result data */ +} __attribute__((aligned(4))); + +#endif + diff --git a/src/lpc11xx.c b/src/lpc11xx.c index 3a85ded..7c6d742 100644 --- a/src/lpc11xx.c +++ b/src/lpc11xx.c @@ -1,6 +1,9 @@ /* * This file is part of the Black Magic Debug project. * + * Copyright (C) 2011 Mike Smith + * Copyright (C) 2015 Gareth McMullin + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -14,26 +17,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include "general.h" -#include "adiv5.h" #include "target.h" +#include "cortexm.h" +#include "lpc_common.h" #define IAP_PGM_CHUNKSIZE 256 /* should fit in RAM on any device */ -struct flash_param { - uint16_t opcodes[2]; /* two opcodes to return to after calling the ROM */ - uint32_t command[5]; /* command operands */ - uint32_t result[4]; /* result data */ -}; - -struct flash_program { - struct flash_param p; - uint8_t data[IAP_PGM_CHUNKSIZE]; -}; - -static struct flash_program flash_pgm; -#define MSP 17 /* Main stack pointer register number */ #define MIN_RAM_SIZE_FOR_LPC8xx 1024 #define MIN_RAM_SIZE_FOR_LPC1xxx 2048 #define RAM_USAGE_FOR_IAP_ROUTINES 32 /* IAP routines use 32 bytes at top of ram */ @@ -41,24 +33,6 @@ static struct flash_program flash_pgm; #define IAP_ENTRYPOINT 0x1fff1ff1 #define IAP_RAM_BASE 0x10000000 -#define IAP_CMD_PREPARE 50 -#define IAP_CMD_PROGRAM 51 -#define IAP_CMD_ERASE 52 -#define IAP_CMD_BLANKCHECK 53 - -#define IAP_STATUS_CMD_SUCCESS 0 -#define IAP_STATUS_INVALID_COMMAND 1 -#define IAP_STATUS_SRC_ADDR_ERROR 2 -#define IAP_STATUS_DST_ADDR_ERROR 3 -#define IAP_STATUS_SRC_ADDR_NOT_MAPPED 4 -#define IAP_STATUS_DST_ADDR_NOT_MAPPED 5 -#define IAP_STATUS_COUNT_ERROR 6 -#define IAP_STATUS_INVALID_SECTOR 7 -#define IAP_STATUS_SECTOR_NOT_BLANK 8 -#define IAP_STATUS_SECTOR_NOT_PREPARED 9 -#define IAP_STATUS_COMPARE_ERROR 10 -#define IAP_STATUS_BUSY 11 - static const char lpc8xx_driver[] = "lpc8xx"; static const char lpc11xx_driver[] = "lpc11xx"; static void lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len); @@ -67,6 +41,11 @@ static int lpc11xx_flash_erase(target *t, uint32_t addr, size_t len); static int lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len); +struct flash_program { + struct flash_param p; + uint8_t data[IAP_PGM_CHUNKSIZE]; +}; + /* * Note that this memory map is actually for the largest of the lpc11xx devices; * There seems to be no good way to decode the part number to determine the RAM @@ -168,8 +147,8 @@ lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len) uint32_t regs[t->regs_size / sizeof(uint32_t)]; /* fill out the remainder of the parameters and copy the structure to RAM */ - param->opcodes[0] = 0xbe00; - param->opcodes[1] = 0x0000; + param->opcode = ARM_THUMB_BREAKPOINT; + param->pad0 = 0x0000; target_mem_write(t, IAP_RAM_BASE, param, param_len); /* set up for the call to the IAP ROM */ @@ -179,11 +158,11 @@ lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len) // stack pointer - top of the smallest ram less 32 for IAP usage if (t->driver == lpc8xx_driver) - regs[MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC8xx - RAM_USAGE_FOR_IAP_ROUTINES; + regs[REG_MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC8xx - RAM_USAGE_FOR_IAP_ROUTINES; else - regs[MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC1xxx - RAM_USAGE_FOR_IAP_ROUTINES; - regs[14] = IAP_RAM_BASE | 1; - regs[15] = IAP_ENTRYPOINT; + regs[REG_MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC1xxx - RAM_USAGE_FOR_IAP_ROUTINES; + regs[REG_LR] = IAP_RAM_BASE | 1; + regs[REG_PC] = IAP_ENTRYPOINT; target_regs_write(t, regs); /* start the target and wait for it to halt again */ @@ -205,11 +184,12 @@ static int flash_page_size(target *t) static int lpc11xx_flash_prepare(target *t, uint32_t addr, int len) { + struct flash_program flash_pgm; /* prepare the sector(s) to be erased */ memset(&flash_pgm.p, 0, sizeof(flash_pgm.p)); - flash_pgm.p.command[0] = IAP_CMD_PREPARE; - flash_pgm.p.command[1] = addr / flash_page_size(t); - flash_pgm.p.command[2] = (addr + len - 1) / flash_page_size(t); + flash_pgm.p.command = IAP_CMD_PREPARE; + flash_pgm.p.prepare.start_sector = addr / flash_page_size(t); + flash_pgm.p.prepare.end_sector = (addr + len - 1) / flash_page_size(t); lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { @@ -222,6 +202,7 @@ lpc11xx_flash_prepare(target *t, uint32_t addr, int len) static int lpc11xx_flash_erase(target *t, uint32_t addr, size_t len) { + struct flash_program flash_pgm; if (addr % flash_page_size(t)) return -1; @@ -231,15 +212,18 @@ lpc11xx_flash_erase(target *t, uint32_t addr, size_t len) return -1; /* and now erase them */ - flash_pgm.p.command[0] = IAP_CMD_ERASE; - flash_pgm.p.command[1] = addr / flash_page_size(t); - flash_pgm.p.command[2] = (addr + len - 1) / flash_page_size(t); - flash_pgm.p.command[3] = 12000; /* XXX safe to assume this? */ + flash_pgm.p.command = IAP_CMD_ERASE; + flash_pgm.p.erase.start_sector = addr / flash_page_size(t); + flash_pgm.p.erase.end_sector = (addr + len - 1) / flash_page_size(t); + flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ; + flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { return -1; } - flash_pgm.p.command[0] = IAP_CMD_BLANKCHECK; + + /* check erase ok */ + flash_pgm.p.command = IAP_CMD_BLANKCHECK; lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { return -1; @@ -255,6 +239,7 @@ lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len) unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE; unsigned chunk_offset = dest % IAP_PGM_CHUNKSIZE; unsigned chunk; + struct flash_program flash_pgm; for (chunk = first_chunk; chunk <= last_chunk; chunk++) { @@ -269,8 +254,8 @@ lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len) size_t copylen = IAP_PGM_CHUNKSIZE - chunk_offset; if (copylen > len) copylen = len; - memcpy(&flash_pgm.data[chunk_offset], src, copylen); + memcpy(flash_pgm.data + chunk_offset, src, copylen); /* if we are programming the vectors, calculate the magic number */ if ((chunk == 0) && (chunk_offset == 0)) { if (copylen < 32) { @@ -290,9 +275,7 @@ lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len) len -= copylen; src += copylen; chunk_offset = 0; - } else { - /* interior chunk, must be aligned and full-sized */ memcpy(flash_pgm.data, src, IAP_PGM_CHUNKSIZE); len -= IAP_PGM_CHUNKSIZE; @@ -304,12 +287,12 @@ lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len) return -1; /* set the destination address and program */ - flash_pgm.p.command[0] = IAP_CMD_PROGRAM; - flash_pgm.p.command[1] = chunk * IAP_PGM_CHUNKSIZE; - flash_pgm.p.command[2] = IAP_RAM_BASE + offsetof(struct flash_program, data); - flash_pgm.p.command[3] = IAP_PGM_CHUNKSIZE; - /* assuming we are running off IRC - safe lower bound */ - flash_pgm.p.command[4] = 12000; /* XXX safe to presume this? */ + flash_pgm.p.command = IAP_CMD_PROGRAM; + flash_pgm.p.program.dest = chunk * IAP_PGM_CHUNKSIZE; + flash_pgm.p.program.source = IAP_RAM_BASE + offsetof(struct flash_program, data); + flash_pgm.p.program.byte_count = IAP_PGM_CHUNKSIZE; + flash_pgm.p.program.cpu_clk_khz = CPU_CLK_KHZ; + flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { return -1; diff --git a/src/lpc43xx.c b/src/lpc43xx.c index 1519306..ad93c8d 100644 --- a/src/lpc43xx.c +++ b/src/lpc43xx.c @@ -1,7 +1,8 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2012 Gareth McMullin + * Copyright (C) 2014 Allen Ibara + * Copyright (C) 2015 Gareth McMullin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,17 +20,13 @@ #include "general.h" #include "command.h" -#include "adiv5.h" #include "target.h" #include "gdb_packet.h" +#include "cortexm.h" +#include "lpc_common.h" #define LPC43XX_CHIPID 0x40043200 #define ARM_CPUID 0xE000ED00 -#define ARM_THUMB_BREAKPOINT 0xBE00 - -#define R_MSP 17 // Main stack pointer register number -#define R_PC 15 // Program counter register number -#define R_LR 14 // Link register number #define IAP_ENTRYPOINT_LOCATION 0x10400100 @@ -47,25 +44,6 @@ #define IAP_PGM_CHUNKSIZE 4096 -#define IAP_CMD_INIT 49 -#define IAP_CMD_PREPARE 50 -#define IAP_CMD_PROGRAM 51 -#define IAP_CMD_ERASE 52 -#define IAP_CMD_BLANKCHECK 53 -#define IAP_CMD_SET_ACTIVE_BANK 60 - -#define IAP_STATUS_CMD_SUCCESS 0 -#define IAP_STATUS_INVALID_COMMAND 1 -#define IAP_STATUS_SRC_ADDR_ERROR 2 -#define IAP_STATUS_DST_ADDR_ERROR 3 -#define IAP_STATUS_SRC_ADDR_NOT_MAPPED 4 -#define IAP_STATUS_DST_ADDR_NOT_MAPPED 5 -#define IAP_STATUS_COUNT_ERROR 6 -#define IAP_STATUS_INVALID_SECTOR 7 -#define IAP_STATUS_SECTOR_NOT_BLANK 8 -#define IAP_STATUS_SECTOR_NOT_PREPARED 9 -#define IAP_STATUS_COMPARE_ERROR 10 -#define IAP_STATUS_BUSY 11 #define FLASH_BANK_A_BASE 0x1A000000 #define FLASH_BANK_A_SIZE 0x80000 @@ -75,45 +53,6 @@ #define FLASH_NUM_SECTOR 15 #define FLASH_LARGE_SECTOR_OFFSET 0x00010000 -/* CPU Frequency */ -#define CPU_CLK_KHZ 12000 - -struct flash_param { - uint16_t opcode; /* opcode to return to after calling the ROM */ - uint16_t pad0; - uint32_t command; /* IAP command */ - union { - uint32_t words[5]; /* command parameters */ - struct { - uint32_t start_sector; - uint32_t end_sector; - uint32_t flash_bank; - } prepare; - struct { - uint32_t start_sector; - uint32_t end_sector; - uint32_t cpu_clk_khz; - uint32_t flash_bank; - } erase; - struct { - uint32_t dest; - uint32_t source; - uint32_t byte_count; - uint32_t cpu_clk_khz; - } program; - struct { - uint32_t start_sector; - uint32_t end_sector; - uint32_t flash_bank; - } blank_check; - struct { - uint32_t flash_bank; - uint32_t cpu_clk_khz; - } make_active; - } params; - uint32_t result[5]; /* result data */ -} __attribute__((aligned(4))); - struct flash_program { struct flash_param p; uint8_t data[IAP_PGM_CHUNKSIZE]; @@ -242,9 +181,9 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]) for (bank = 0; bank < FLASH_NUM_BANK; bank++) { flash_pgm.p.command = IAP_CMD_PREPARE; - flash_pgm.p.params.prepare.start_sector = 0; - flash_pgm.p.params.prepare.end_sector = FLASH_NUM_SECTOR-1; - flash_pgm.p.params.prepare.flash_bank = bank; + flash_pgm.p.prepare.start_sector = 0; + flash_pgm.p.prepare.end_sector = FLASH_NUM_SECTOR-1; + flash_pgm.p.prepare.flash_bank = bank; flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { @@ -252,10 +191,10 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]) } flash_pgm.p.command = IAP_CMD_ERASE; - flash_pgm.p.params.erase.start_sector = 0; - flash_pgm.p.params.prepare.end_sector = FLASH_NUM_SECTOR-1; - flash_pgm.p.params.erase.cpu_clk_khz = CPU_CLK_KHZ; - flash_pgm.p.params.erase.flash_bank = bank; + flash_pgm.p.erase.start_sector = 0; + flash_pgm.p.prepare.end_sector = FLASH_NUM_SECTOR-1; + flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ; + flash_pgm.p.erase.flash_bank = bank; flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) @@ -343,8 +282,8 @@ static void lpc43xx_iap_call(target *t, struct flash_param *param, unsigned para target_mem_read(t, &iap_entry, IAP_ENTRYPOINT_LOCATION, sizeof(iap_entry)); /* fill out the remainder of the parameters and copy the structure to RAM */ - param->opcode = ARM_THUMB_BREAKPOINT; /* breakpoint */ - param->pad0 = 0x0000; /* pad */ + param->opcode = ARM_THUMB_BREAKPOINT; + param->pad0 = 0x0000; target_mem_write(t, IAP_RAM_BASE, param, param_len); /* set up for the call to the IAP ROM */ @@ -352,9 +291,9 @@ static void lpc43xx_iap_call(target *t, struct flash_param *param, unsigned para regs[0] = IAP_RAM_BASE + offsetof(struct flash_param, command); regs[1] = IAP_RAM_BASE + offsetof(struct flash_param, result); - regs[R_MSP] = IAP_RAM_BASE + IAP_RAM_SIZE; - regs[R_LR] = IAP_RAM_BASE | 1; - regs[R_PC] = iap_entry; + regs[REG_MSP] = IAP_RAM_BASE + IAP_RAM_SIZE; + regs[REG_LR] = IAP_RAM_BASE | 1; + regs[REG_PC] = iap_entry; target_regs_write(t, regs); /* start the target and wait for it to halt again */ @@ -370,11 +309,11 @@ static int lpc43xx_flash_prepare(target *t, uint32_t addr, int len) struct flash_program flash_pgm; /* prepare the sector(s) to be erased */ + memset(&flash_pgm.p, 0, sizeof(flash_pgm.p)); flash_pgm.p.command = IAP_CMD_PREPARE; - flash_pgm.p.params.prepare.start_sector = sector_number(addr); - flash_pgm.p.params.prepare.end_sector = sector_number(addr+len); - flash_pgm.p.params.prepare.flash_bank = flash_bank(addr); - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; + flash_pgm.p.prepare.start_sector = sector_number(addr); + flash_pgm.p.prepare.end_sector = sector_number(addr+len); + flash_pgm.p.prepare.flash_bank = flash_bank(addr); lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { @@ -402,10 +341,10 @@ static int lpc43xx_flash_erase(target *t, uint32_t addr, size_t len) /* and now erase them */ flash_pgm.p.command = IAP_CMD_ERASE; - flash_pgm.p.params.erase.start_sector = sector_number(addr); - flash_pgm.p.params.erase.end_sector = sector_number(addr+len); - flash_pgm.p.params.erase.cpu_clk_khz = CPU_CLK_KHZ; - flash_pgm.p.params.erase.flash_bank = flash_bank(addr); + flash_pgm.p.erase.start_sector = sector_number(addr); + flash_pgm.p.erase.end_sector = sector_number(addr+len); + flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ; + flash_pgm.p.erase.flash_bank = flash_bank(addr); flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { @@ -414,9 +353,9 @@ static int lpc43xx_flash_erase(target *t, uint32_t addr, size_t len) /* check erase ok */ flash_pgm.p.command = IAP_CMD_BLANKCHECK; - flash_pgm.p.params.blank_check.start_sector = sector_number(addr); - flash_pgm.p.params.blank_check.end_sector = sector_number(addr+len); - flash_pgm.p.params.blank_check.flash_bank = flash_bank(addr); + flash_pgm.p.blank_check.start_sector = sector_number(addr); + flash_pgm.p.blank_check.end_sector = sector_number(addr+len); + flash_pgm.p.blank_check.flash_bank = flash_bank(addr); flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { @@ -437,17 +376,13 @@ static int lpc43xx_flash_write(target *t, { unsigned first_chunk = dest / IAP_PGM_CHUNKSIZE; unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE; - unsigned chunk_offset; + unsigned chunk_offset = dest % IAP_PGM_CHUNKSIZE; unsigned chunk; struct flash_program flash_pgm; for (chunk = first_chunk; chunk <= last_chunk; chunk++) { - if (chunk == first_chunk) { - chunk_offset = dest % IAP_PGM_CHUNKSIZE; - } else { - chunk_offset = 0; - } + DEBUG("chunk %u len %zu\n", chunk, len); /* first and last chunk may require special handling */ if ((chunk == first_chunk) || (chunk == last_chunk)) { @@ -464,6 +399,7 @@ static int lpc43xx_flash_write(target *t, /* update to suit */ len -= copylen; src += copylen; + chunk_offset = 0; } else { /* interior chunk, must be aligned and full-sized */ memcpy(flash_pgm.data, src, IAP_PGM_CHUNKSIZE); @@ -472,21 +408,15 @@ static int lpc43xx_flash_write(target *t, } /* prepare... */ - if (lpc43xx_flash_prepare(t, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE)) { + if (lpc43xx_flash_prepare(t, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE)) return -1; - } - - /* copy buffer into target memory */ - target_mem_write(t, - IAP_RAM_BASE + offsetof(struct flash_program, data), - flash_pgm.data, sizeof(flash_pgm.data)); /* set the destination address and program */ flash_pgm.p.command = IAP_CMD_PROGRAM; - flash_pgm.p.params.program.dest = chunk * IAP_PGM_CHUNKSIZE; - flash_pgm.p.params.program.source = IAP_RAM_BASE + offsetof(struct flash_program, data); - flash_pgm.p.params.program.byte_count = IAP_PGM_CHUNKSIZE; - flash_pgm.p.params.program.cpu_clk_khz = CPU_CLK_KHZ; + flash_pgm.p.program.dest = chunk * IAP_PGM_CHUNKSIZE; + flash_pgm.p.program.source = IAP_RAM_BASE + offsetof(struct flash_program, data); + flash_pgm.p.program.byte_count = IAP_PGM_CHUNKSIZE; + flash_pgm.p.program.cpu_clk_khz = CPU_CLK_KHZ; flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { @@ -524,8 +454,8 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]) /* special command to compute/write magic vector for signature */ flash_pgm.p.command = IAP_CMD_SET_ACTIVE_BANK; - flash_pgm.p.params.make_active.flash_bank = bank; - flash_pgm.p.params.make_active.cpu_clk_khz = CPU_CLK_KHZ; + flash_pgm.p.make_active.flash_bank = bank; + flash_pgm.p.make_active.cpu_clk_khz = CPU_CLK_KHZ; flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm)); if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { -- cgit v1.2.3 From 3d8b34f180eaa9bfe021186b9e20a8a551b35515 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 4 Apr 2015 19:15:03 -0700 Subject: lpc: split out common code and rewrite to use new interface. --- src/Makefile | 1 + src/include/lpc_common.h | 91 ++++++------- src/lpc11xx.c | 248 +++++----------------------------- src/lpc43xx.c | 337 +++++++---------------------------------------- src/lpc_common.c | 135 +++++++++++++++++++ 5 files changed, 256 insertions(+), 556 deletions(-) create mode 100644 src/lpc_common.c diff --git a/src/Makefile b/src/Makefile index 3d879ef..856baee 100644 --- a/src/Makefile +++ b/src/Makefile @@ -28,6 +28,7 @@ SRC = \ jtag_scan.c \ jtagtap.c \ lmi.c \ + lpc_common.c \ lpc11xx.c \ lpc43xx.c \ kinetis.c \ diff --git a/src/include/lpc_common.h b/src/include/lpc_common.h index 45d2964..4886156 100644 --- a/src/include/lpc_common.h +++ b/src/include/lpc_common.h @@ -20,64 +20,49 @@ #ifndef __LPC_COMMON_H #define __LPC_COMMON_H -#define IAP_CMD_INIT 49 -#define IAP_CMD_PREPARE 50 -#define IAP_CMD_PROGRAM 51 -#define IAP_CMD_ERASE 52 -#define IAP_CMD_BLANKCHECK 53 -#define IAP_CMD_SET_ACTIVE_BANK 60 +enum iap_cmd { + IAP_CMD_INIT = 49, + IAP_CMD_PREPARE = 50, + IAP_CMD_PROGRAM = 51, + IAP_CMD_ERASE = 52, + IAP_CMD_BLANKCHECK = 53, + IAP_CMD_SET_ACTIVE_BANK = 60, +}; -#define IAP_STATUS_CMD_SUCCESS 0 -#define IAP_STATUS_INVALID_COMMAND 1 -#define IAP_STATUS_SRC_ADDR_ERROR 2 -#define IAP_STATUS_DST_ADDR_ERROR 3 -#define IAP_STATUS_SRC_ADDR_NOT_MAPPED 4 -#define IAP_STATUS_DST_ADDR_NOT_MAPPED 5 -#define IAP_STATUS_COUNT_ERROR 6 -#define IAP_STATUS_INVALID_SECTOR 7 -#define IAP_STATUS_SECTOR_NOT_BLANK 8 -#define IAP_STATUS_SECTOR_NOT_PREPARED 9 -#define IAP_STATUS_COMPARE_ERROR 10 -#define IAP_STATUS_BUSY 11 +enum iap_status { + IAP_STATUS_CMD_SUCCESS = 0, + IAP_STATUS_INVALID_COMMAND = 1, + IAP_STATUS_SRC_ADDR_ERROR = 2, + IAP_STATUS_DST_ADDR_ERROR = 3, + IAP_STATUS_SRC_ADDR_NOT_MAPPED = 4, + IAP_STATUS_DST_ADDR_NOT_MAPPED = 5, + IAP_STATUS_COUNT_ERROR = 6, + IAP_STATUS_INVALID_SECTOR = 7, + IAP_STATUS_SECTOR_NOT_BLANK = 8, + IAP_STATUS_SECTOR_NOT_PREPARED = 9, + IAP_STATUS_COMPARE_ERROR = 10, + IAP_STATUS_BUSY = 11, +}; /* CPU Frequency */ #define CPU_CLK_KHZ 12000 -struct flash_param { - uint16_t opcode;/* opcode to return to after calling the ROM */ - uint16_t pad0; - uint32_t command;/* IAP command */ - union { - uint32_t words[5];/* command parameters */ - struct { - uint32_t start_sector; - uint32_t end_sector; - uint32_t flash_bank; - } prepare; - struct { - uint32_t start_sector; - uint32_t end_sector; - uint32_t cpu_clk_khz; - uint32_t flash_bank; - } erase; - struct { - uint32_t dest; - uint32_t source; - uint32_t byte_count; - uint32_t cpu_clk_khz; - } program; - struct { - uint32_t start_sector; - uint32_t end_sector; - uint32_t flash_bank; - } blank_check; - struct { - uint32_t flash_bank; - uint32_t cpu_clk_khz; - } make_active; - }; - uint32_t result[5]; /* result data */ -} __attribute__((aligned(4))); +struct lpc_flash { + struct target_flash f; + uint8_t base_sector; + uint8_t bank; + /* Info filled in by specific driver */ + void (*wdt_kick)(target *t); + uint32_t iap_entry; + uint32_t iap_ram; + uint32_t iap_msp; +}; + +struct lpc_flash *lpc_add_flash(target *t, uint32_t addr, size_t length); +enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...); +int lpc_flash_erase(struct target_flash *f, uint32_t addr, size_t len); +int lpc_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len); #endif diff --git a/src/lpc11xx.c b/src/lpc11xx.c index 7c6d742..09a0622 100644 --- a/src/lpc11xx.c +++ b/src/lpc11xx.c @@ -23,63 +23,27 @@ #include "cortexm.h" #include "lpc_common.h" -#define IAP_PGM_CHUNKSIZE 256 /* should fit in RAM on any device */ +#define IAP_PGM_CHUNKSIZE 512 /* should fit in RAM on any device */ - -#define MIN_RAM_SIZE_FOR_LPC8xx 1024 -#define MIN_RAM_SIZE_FOR_LPC1xxx 2048 +#define MIN_RAM_SIZE 1024 #define RAM_USAGE_FOR_IAP_ROUTINES 32 /* IAP routines use 32 bytes at top of ram */ #define IAP_ENTRYPOINT 0x1fff1ff1 #define IAP_RAM_BASE 0x10000000 -static const char lpc8xx_driver[] = "lpc8xx"; -static const char lpc11xx_driver[] = "lpc11xx"; -static void lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len); -static int lpc11xx_flash_prepare(target *t, uint32_t addr, int len); -static int lpc11xx_flash_erase(target *t, uint32_t addr, size_t len); -static int lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, - size_t len); - -struct flash_program { - struct flash_param p; - uint8_t data[IAP_PGM_CHUNKSIZE]; -}; +static int lpc11xx_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len); -/* - * Note that this memory map is actually for the largest of the lpc11xx devices; - * There seems to be no good way to decode the part number to determine the RAM - * and flash sizes. - */ -static const char lpc11xx_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x1000" - " " - " " - ""; - -/* - * Memory map for the lpc8xx devices, which otherwise look much like the lpc11xx. - * - * We could decode the RAM/flash sizes, but we just encode the largest possible here. - * - * Note that the LPC810 and LPC811 map their flash oddly; see the NXP LPC800 user - * manual (UM10601) for more details. - */ -static const char lpc8xx_xml_memory_map[] = "" -/* ""*/ - "" - " " - " 0x400" - " " - " " - ""; +void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize) +{ + struct lpc_flash *lf = lpc_add_flash(t, addr, len); + lf->f.blocksize = erasesize; + lf->f.buf_size = IAP_PGM_CHUNKSIZE; + lf->f.write_buf = lpc11xx_flash_write; + lf->iap_entry = IAP_ENTRYPOINT; + lf->iap_ram = IAP_RAM_BASE; + lf->iap_msp = IAP_RAM_BASE + MIN_RAM_SIZE - RAM_USAGE_FOR_IAP_ROUTINES; +} bool lpc11xx_probe(target *t) @@ -122,183 +86,33 @@ lpc11xx_probe(target *t) case 0x2972402B: /* lpc11u23/301 */ case 0x2988402B: /* lpc11u24x/301 */ case 0x2980002B: /* lpc11u24x/401 */ - t->driver = lpc11xx_driver; - t->xml_mem_map = lpc11xx_xml_memory_map; - t->flash_erase = lpc11xx_flash_erase; - t->flash_write = lpc11xx_flash_write; - + t->driver = "LPC11xx"; + target_add_ram(t, 0x10000000, 0x2000); + lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000); return true; case 0x1812202b: /* LPC812M101FDH20 */ - t->driver = lpc8xx_driver; - t->xml_mem_map = lpc8xx_xml_memory_map; - t->flash_erase = lpc11xx_flash_erase; - t->flash_write = lpc11xx_flash_write; - + t->driver = "LPC8xx"; + target_add_ram(t, 0x10000000, 0x1000); + lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400); return true; } return false; } -static void -lpc11x_iap_call(target *t, struct flash_param *param, unsigned param_len) +static int lpc11xx_flash_write(struct target_flash *f, + uint32_t dest, const void *src, size_t len) { - uint32_t regs[t->regs_size / sizeof(uint32_t)]; - - /* fill out the remainder of the parameters and copy the structure to RAM */ - param->opcode = ARM_THUMB_BREAKPOINT; - param->pad0 = 0x0000; - target_mem_write(t, IAP_RAM_BASE, param, param_len); - - /* set up for the call to the IAP ROM */ - target_regs_read(t, regs); - regs[0] = IAP_RAM_BASE + offsetof(struct flash_param, command); - regs[1] = IAP_RAM_BASE + offsetof(struct flash_param, result); - - // stack pointer - top of the smallest ram less 32 for IAP usage - if (t->driver == lpc8xx_driver) - regs[REG_MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC8xx - RAM_USAGE_FOR_IAP_ROUTINES; - else - regs[REG_MSP] = IAP_RAM_BASE + MIN_RAM_SIZE_FOR_LPC1xxx - RAM_USAGE_FOR_IAP_ROUTINES; - regs[REG_LR] = IAP_RAM_BASE | 1; - regs[REG_PC] = IAP_ENTRYPOINT; - target_regs_write(t, regs); - - /* start the target and wait for it to halt again */ - target_halt_resume(t, 0); - while (!target_halt_wait(t)); - - /* copy back just the parameters structure */ - target_mem_read(t, param, IAP_RAM_BASE, sizeof(struct flash_param)); -} - -static int flash_page_size(target *t) -{ - if (t->driver == lpc8xx_driver) - return 1024; - else - return 4096; -} - -static int -lpc11xx_flash_prepare(target *t, uint32_t addr, int len) -{ - struct flash_program flash_pgm; - /* prepare the sector(s) to be erased */ - memset(&flash_pgm.p, 0, sizeof(flash_pgm.p)); - flash_pgm.p.command = IAP_CMD_PREPARE; - flash_pgm.p.prepare.start_sector = addr / flash_page_size(t); - flash_pgm.p.prepare.end_sector = (addr + len - 1) / flash_page_size(t); - - lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { - return -1; + if (dest == 0) { + /* Fill in the magic vector to allow booting the flash */ + uint32_t *w = (uint32_t *)src; + uint32_t sum = 0; + + for (unsigned i = 0; i < 7; i++) + sum += w[i]; + w[7] = ~sum + 1; } - - return 0; + return lpc_flash_write(f, dest, src, len); } -static int -lpc11xx_flash_erase(target *t, uint32_t addr, size_t len) -{ - struct flash_program flash_pgm; - - if (addr % flash_page_size(t)) - return -1; - - /* prepare... */ - if (lpc11xx_flash_prepare(t, addr, len)) - return -1; - - /* and now erase them */ - flash_pgm.p.command = IAP_CMD_ERASE; - flash_pgm.p.erase.start_sector = addr / flash_page_size(t); - flash_pgm.p.erase.end_sector = (addr + len - 1) / flash_page_size(t); - flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ; - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { - return -1; - } - - /* check erase ok */ - flash_pgm.p.command = IAP_CMD_BLANKCHECK; - lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { - return -1; - } - - return 0; -} - -static int -lpc11xx_flash_write(target *t, uint32_t dest, const uint8_t *src, size_t len) -{ - unsigned first_chunk = dest / IAP_PGM_CHUNKSIZE; - unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE; - unsigned chunk_offset = dest % IAP_PGM_CHUNKSIZE; - unsigned chunk; - struct flash_program flash_pgm; - - for (chunk = first_chunk; chunk <= last_chunk; chunk++) { - - DEBUG("chunk %u len %zu\n", chunk, len); - /* first and last chunk may require special handling */ - if ((chunk == first_chunk) || (chunk == last_chunk)) { - - /* fill with all ff to avoid sector rewrite corrupting other writes */ - memset(flash_pgm.data, 0xff, sizeof(flash_pgm.data)); - - /* copy as much as fits */ - size_t copylen = IAP_PGM_CHUNKSIZE - chunk_offset; - if (copylen > len) - copylen = len; - - memcpy(flash_pgm.data + chunk_offset, src, copylen); - /* if we are programming the vectors, calculate the magic number */ - if ((chunk == 0) && (chunk_offset == 0)) { - if (copylen < 32) { - /* we have to be programming at least the first 8 vectors... */ - return -1; - } - - uint32_t *w = (uint32_t *)(&flash_pgm.data[0]); - uint32_t sum = 0; - - for (unsigned i = 0; i < 7; i++) - sum += w[i]; - w[7] = ~sum + 1; - } - - /* update to suit */ - len -= copylen; - src += copylen; - chunk_offset = 0; - } else { - /* interior chunk, must be aligned and full-sized */ - memcpy(flash_pgm.data, src, IAP_PGM_CHUNKSIZE); - len -= IAP_PGM_CHUNKSIZE; - src += IAP_PGM_CHUNKSIZE; - } - - /* prepare... */ - if (lpc11xx_flash_prepare(t, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE)) - return -1; - - /* set the destination address and program */ - flash_pgm.p.command = IAP_CMD_PROGRAM; - flash_pgm.p.program.dest = chunk * IAP_PGM_CHUNKSIZE; - flash_pgm.p.program.source = IAP_RAM_BASE + offsetof(struct flash_program, data); - flash_pgm.p.program.byte_count = IAP_PGM_CHUNKSIZE; - flash_pgm.p.program.cpu_clk_khz = CPU_CLK_KHZ; - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc11x_iap_call(t, &flash_pgm.p, sizeof(flash_pgm)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { - return -1; - } - - } - - return 0; -} diff --git a/src/lpc43xx.c b/src/lpc43xx.c index ad93c8d..5181b8b 100644 --- a/src/lpc43xx.c +++ b/src/lpc43xx.c @@ -44,31 +44,14 @@ #define IAP_PGM_CHUNKSIZE 4096 - -#define FLASH_BANK_A_BASE 0x1A000000 -#define FLASH_BANK_A_SIZE 0x80000 -#define FLASH_BANK_B_BASE 0x1B000000 -#define FLASH_BANK_B_SIZE 0x80000 #define FLASH_NUM_BANK 2 #define FLASH_NUM_SECTOR 15 -#define FLASH_LARGE_SECTOR_OFFSET 0x00010000 - -struct flash_program { - struct flash_param p; - uint8_t data[IAP_PGM_CHUNKSIZE]; -}; static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]); static bool lpc43xx_cmd_reset(target *t, int argc, const char *argv[]); static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]); static int lpc43xx_flash_init(target *t); -static void lpc43xx_iap_call(target *t, struct flash_param *param, - unsigned param_len); -static int lpc43xx_flash_prepare(target *t, - uint32_t addr, int len); -static int lpc43xx_flash_erase(target *t, uint32_t addr, size_t len); -static int lpc43xx_flash_write(target *t, - uint32_t dest, const uint8_t *src, size_t len); +static int lpc43xx_flash_erase(struct target_flash *f, uint32_t addr, size_t len); static void lpc43xx_set_internal_clock(target *t); static void lpc43xx_wdt_set_period(target *t); static void lpc43xx_wdt_pet(target *t); @@ -80,34 +63,26 @@ const struct command_s lpc43xx_cmd_list[] = { {NULL, NULL, NULL} }; -/* blocksize is the erasure block size */ -static const char lpc4337_xml_memory_map[] = "" -/* - "" -*/ -"" -" " -" " -" 0x2000" -" " -" " -" 0x10000" -" " -" " -" " -" 0x2000" -" " -" " -" 0x10000" -" " -" " -""; +void lpc43xx_add_flash(target *t, uint32_t iap_entry, + uint8_t bank, uint8_t base_sector, + uint32_t addr, size_t len, size_t erasesize) +{ + struct lpc_flash *lf = lpc_add_flash(t, addr, len); + lf->f.erase = lpc43xx_flash_erase; + lf->f.blocksize = erasesize; + lf->f.buf_size = IAP_PGM_CHUNKSIZE; + lf->bank = bank; + lf->base_sector = base_sector; + lf->iap_entry = iap_entry; + lf->iap_ram = IAP_RAM_BASE; + lf->iap_msp = IAP_RAM_BASE + IAP_RAM_SIZE; + lf->wdt_kick = lpc43xx_wdt_pet; +} bool lpc43xx_probe(target *t) { uint32_t chipid, cpuid; + uint32_t iap_entry; chipid = target_mem_read32(t, LPC43XX_CHIPID); cpuid = target_mem_read32(t, ARM_CPUID); @@ -120,10 +95,20 @@ bool lpc43xx_probe(target *t) if (cpuid == 0x410FC241) { /* LPC4337 */ - t->xml_mem_map = lpc4337_xml_memory_map; - t->flash_erase = lpc43xx_flash_erase; - t->flash_write = lpc43xx_flash_write; + iap_entry = target_mem_read32(t, + IAP_ENTRYPOINT_LOCATION); + target_add_ram(t, 0, 0x1A000000); + lpc43xx_add_flash(t, iap_entry, 0, 0, + 0x1A000000, 0x10000, 0x2000); + lpc43xx_add_flash(t, iap_entry, 0, 8, + 0x1A010000, 0x70000, 0x10000); + target_add_ram(t, 0x1A080000, 0xF80000); + lpc43xx_add_flash(t, iap_entry, 1, 0, + 0x1B000000, 0x10000, 0x2000); + lpc43xx_add_flash(t, iap_entry, 1, 8, + 0x1B010000, 0x70000, 0x10000); target_add_commands(t, lpc43xx_cmd_list, "LPC43xx"); + target_add_ram(t, 0x1B080000, 0xE4F80000UL); } break; case 0x4100C200: @@ -173,34 +158,18 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]) (void)argc; (void)argv; - uint32_t bank = 0; - struct flash_program flash_pgm; - lpc43xx_flash_init(t); - for (bank = 0; bank < FLASH_NUM_BANK; bank++) + for (int bank = 0; bank < FLASH_NUM_BANK; bank++) { - flash_pgm.p.command = IAP_CMD_PREPARE; - flash_pgm.p.prepare.start_sector = 0; - flash_pgm.p.prepare.end_sector = FLASH_NUM_SECTOR-1; - flash_pgm.p.prepare.flash_bank = bank; - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { + struct lpc_flash *f = (struct lpc_flash *)t->flash; + if (lpc_iap_call(f, IAP_CMD_PREPARE, + 0, FLASH_NUM_SECTOR-1, bank)) return false; - } - flash_pgm.p.command = IAP_CMD_ERASE; - flash_pgm.p.erase.start_sector = 0; - flash_pgm.p.prepare.end_sector = FLASH_NUM_SECTOR-1; - flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ; - flash_pgm.p.erase.flash_bank = bank; - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) - { + if (lpc_iap_call(f, IAP_CMD_ERASE, + 0, FLASH_NUM_SECTOR-1, CPU_CLK_KHZ, bank)) return false; - } } gdb_outf("Erase OK.\n"); @@ -216,215 +185,26 @@ static int lpc43xx_flash_init(target *t) /* Force internal clock */ lpc43xx_set_internal_clock(t); - struct flash_program flash_pgm; - /* Initialize flash IAP */ - flash_pgm.p.command = IAP_CMD_INIT; - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) + struct lpc_flash *f = (struct lpc_flash *)t->flash; + if (lpc_iap_call(f, IAP_CMD_INIT)) return -1; return 0; } - - -/** - * @brief find a sector number given linear offset - */ -static int32_t flash_bank(uint32_t addr) +static int lpc43xx_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { - if ((addr >= FLASH_BANK_A_BASE) && - (addr < (FLASH_BANK_A_BASE + FLASH_BANK_A_SIZE))) - return 0; - if ((addr >= FLASH_BANK_B_BASE) && - (addr < (FLASH_BANK_B_BASE + FLASH_BANK_B_SIZE))) - return 1; - - return -1; -} - -/** - * @brief find a sector number given linear offset - */ -static int32_t sector_number(uint32_t addr) -{ - int32_t bank = flash_bank(addr); - - switch (bank) { - case 0: - addr = addr - FLASH_BANK_A_BASE; - break; - case 1: - addr = addr - FLASH_BANK_B_BASE; - break; - default: + if (lpc43xx_flash_init(f->t)) return -1; - } - /* from 47.5 "Sector numbers" (page 1218) UM10503.pdf (Rev 1.6) */ - if (addr < FLASH_LARGE_SECTOR_OFFSET) { - return addr >> 13; - } else { - return 8 + ((addr - FLASH_LARGE_SECTOR_OFFSET) >> 16); - } -} - -static void lpc43xx_iap_call(target *t, struct flash_param *param, unsigned param_len) -{ - uint32_t regs[t->regs_size / sizeof(uint32_t)]; - uint32_t iap_entry; - - /* Pet WDT before each IAP call, if it is on */ - lpc43xx_wdt_pet(t); - - target_mem_read(t, &iap_entry, IAP_ENTRYPOINT_LOCATION, sizeof(iap_entry)); - - /* fill out the remainder of the parameters and copy the structure to RAM */ - param->opcode = ARM_THUMB_BREAKPOINT; - param->pad0 = 0x0000; - target_mem_write(t, IAP_RAM_BASE, param, param_len); - - /* set up for the call to the IAP ROM */ - target_regs_read(t, regs); - regs[0] = IAP_RAM_BASE + offsetof(struct flash_param, command); - regs[1] = IAP_RAM_BASE + offsetof(struct flash_param, result); - - regs[REG_MSP] = IAP_RAM_BASE + IAP_RAM_SIZE; - regs[REG_LR] = IAP_RAM_BASE | 1; - regs[REG_PC] = iap_entry; - target_regs_write(t, regs); - - /* start the target and wait for it to halt again */ - target_halt_resume(t, 0); - while (!target_halt_wait(t)); - - /* copy back just the parameters structure */ - target_mem_read(t, param, IAP_RAM_BASE, sizeof(struct flash_param)); -} - -static int lpc43xx_flash_prepare(target *t, uint32_t addr, int len) -{ - struct flash_program flash_pgm; - - /* prepare the sector(s) to be erased */ - memset(&flash_pgm.p, 0, sizeof(flash_pgm.p)); - flash_pgm.p.command = IAP_CMD_PREPARE; - flash_pgm.p.prepare.start_sector = sector_number(addr); - flash_pgm.p.prepare.end_sector = sector_number(addr+len); - flash_pgm.p.prepare.flash_bank = flash_bank(addr); - - lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { - return -1; - } - - return 0; -} - -static int lpc43xx_flash_erase(target *t, uint32_t addr, size_t len) -{ - struct flash_program flash_pgm; - - /* min block size */ - if (addr % 8192) - return -1; - - /* init */ - if (lpc43xx_flash_init(t)) - return -1; - - /* prepare... */ - if (lpc43xx_flash_prepare(t, addr, len)) - return -1; - - /* and now erase them */ - flash_pgm.p.command = IAP_CMD_ERASE; - flash_pgm.p.erase.start_sector = sector_number(addr); - flash_pgm.p.erase.end_sector = sector_number(addr+len); - flash_pgm.p.erase.cpu_clk_khz = CPU_CLK_KHZ; - flash_pgm.p.erase.flash_bank = flash_bank(addr); - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { - return -1; - } - - /* check erase ok */ - flash_pgm.p.command = IAP_CMD_BLANKCHECK; - flash_pgm.p.blank_check.start_sector = sector_number(addr); - flash_pgm.p.blank_check.end_sector = sector_number(addr+len); - flash_pgm.p.blank_check.flash_bank = flash_bank(addr); - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm.p)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { - return -1; - } - - return 0; + return lpc_flash_erase(f, addr, len); } static void lpc43xx_set_internal_clock(target *t) { const uint32_t val2 = (1 << 11) | (1 << 24); - target_mem_write(t, 0x40050000 + 0x06C, &val2, sizeof(val2)); -} - -static int lpc43xx_flash_write(target *t, - uint32_t dest, const uint8_t *src, size_t len) -{ - unsigned first_chunk = dest / IAP_PGM_CHUNKSIZE; - unsigned last_chunk = (dest + len - 1) / IAP_PGM_CHUNKSIZE; - unsigned chunk_offset = dest % IAP_PGM_CHUNKSIZE; - unsigned chunk; - struct flash_program flash_pgm; - - for (chunk = first_chunk; chunk <= last_chunk; chunk++) { - - DEBUG("chunk %u len %zu\n", chunk, len); - /* first and last chunk may require special handling */ - if ((chunk == first_chunk) || (chunk == last_chunk)) { - - /* fill with all ff to avoid sector rewrite corrupting other writes */ - memset(flash_pgm.data, 0xff, sizeof(flash_pgm.data)); - - /* copy as much as fits */ - size_t copylen = IAP_PGM_CHUNKSIZE - chunk_offset; - if (copylen > len) - copylen = len; - - memcpy(flash_pgm.data + chunk_offset, src, copylen); - - /* update to suit */ - len -= copylen; - src += copylen; - chunk_offset = 0; - } else { - /* interior chunk, must be aligned and full-sized */ - memcpy(flash_pgm.data, src, IAP_PGM_CHUNKSIZE); - len -= IAP_PGM_CHUNKSIZE; - src += IAP_PGM_CHUNKSIZE; - } - - /* prepare... */ - if (lpc43xx_flash_prepare(t, chunk * IAP_PGM_CHUNKSIZE, IAP_PGM_CHUNKSIZE)) - return -1; - - /* set the destination address and program */ - flash_pgm.p.command = IAP_CMD_PROGRAM; - flash_pgm.p.program.dest = chunk * IAP_PGM_CHUNKSIZE; - flash_pgm.p.program.source = IAP_RAM_BASE + offsetof(struct flash_program, data); - flash_pgm.p.program.byte_count = IAP_PGM_CHUNKSIZE; - flash_pgm.p.program.cpu_clk_khz = CPU_CLK_KHZ; - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { - return -1; - } - } - - return 0; + target_mem_write32(t, 0x40050000 + 0x06C, val2); } /* @@ -450,15 +230,10 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]) } lpc43xx_flash_init(t); - struct flash_program flash_pgm; /* special command to compute/write magic vector for signature */ - flash_pgm.p.command = IAP_CMD_SET_ACTIVE_BANK; - flash_pgm.p.make_active.flash_bank = bank; - flash_pgm.p.make_active.cpu_clk_khz = CPU_CLK_KHZ; - flash_pgm.p.result[0] = IAP_STATUS_CMD_SUCCESS; - lpc43xx_iap_call(t, &flash_pgm.p, sizeof(flash_pgm)); - if (flash_pgm.p.result[0] != IAP_STATUS_CMD_SUCCESS) { + struct lpc_flash *f = (struct lpc_flash *)t->flash; + if (lpc_iap_call(f, IAP_CMD_SET_ACTIVE_BANK, bank, CPU_CLK_KHZ)) { gdb_outf("Set bootable failed.\n"); return false; } @@ -469,33 +244,23 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]) static void lpc43xx_wdt_set_period(target *t) { - uint32_t wdt_mode = 0; /* Check if WDT is on */ - target_mem_read(t, &wdt_mode, LPC43XX_WDT_MODE, sizeof(wdt_mode)); + uint32_t wdt_mode = target_mem_read32(t, LPC43XX_WDT_MODE); /* If WDT on, we can't disable it, but we may be able to set a long period */ if (wdt_mode && !(wdt_mode & LPC43XX_WDT_PROTECT)) - { - const uint32_t wdt_period = LPC43XX_WDT_PERIOD_MAX; - - - target_mem_write(t, LPC43XX_WDT_CNT, &wdt_period, sizeof(wdt_period)); - } + target_mem_write32(t, LPC43XX_WDT_CNT, LPC43XX_WDT_PERIOD_MAX); } static void lpc43xx_wdt_pet(target *t) { - uint32_t wdt_mode = 0; /* Check if WDT is on */ - target_mem_read(t, &wdt_mode, LPC43XX_WDT_MODE, sizeof(wdt_mode)); + uint32_t wdt_mode = target_mem_read32(t, LPC43XX_WDT_MODE); /* If WDT on, pet */ - if (wdt_mode) - { - const uint32_t feed1 = 0xAA;; - const uint32_t feed2 = 0x55;; - - target_mem_write(t, LPC43XX_WDT_FEED, &feed1, sizeof(feed1)); - target_mem_write(t, LPC43XX_WDT_FEED, &feed2, sizeof(feed2)); + if (wdt_mode) { + target_mem_write32(t, LPC43XX_WDT_FEED, 0xAA); + target_mem_write32(t, LPC43XX_WDT_FEED, 0xFF); } } + diff --git a/src/lpc_common.c b/src/lpc_common.c new file mode 100644 index 0000000..d9abc76 --- /dev/null +++ b/src/lpc_common.c @@ -0,0 +1,135 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2015 Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "general.h" +#include "target.h" +#include "cortexm.h" +#include "lpc_common.h" + +#include + +struct flash_param { + uint16_t opcode; + uint16_t pad0; + uint32_t command; + uint32_t words[4]; + uint32_t result; +} __attribute__((aligned(4))); + + +struct lpc_flash *lpc_add_flash(target *t, uint32_t addr, size_t length) +{ + struct lpc_flash *lf = calloc(1, sizeof(*lf)); + struct target_flash *f = &lf->f; + f->start = addr; + f->length = length; + f->erase = lpc_flash_erase; + f->write = target_flash_write_buffered; + f->done = target_flash_done_buffered; + f->write_buf = lpc_flash_write; + f->erased = 0xff; + target_add_flash(t, f); + return lf; +} + +enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...) +{ + target *t = f->f.t; + struct flash_param param = { + .opcode = ARM_THUMB_BREAKPOINT, + .command = cmd, + }; + + /* Pet WDT before each IAP call, if it is on */ + if (f->wdt_kick) + f->wdt_kick(t); + + /* fill out the remainder of the parameters */ + va_list ap; + va_start(ap, cmd); + for (int i = 0; i < 4; i++) + param.words[i] = va_arg(ap, uint32_t); + va_end(ap); + + /* copy the structure to RAM */ + target_mem_write(t, f->iap_ram, ¶m, sizeof(param)); + + /* set up for the call to the IAP ROM */ + uint32_t regs[t->regs_size / sizeof(uint32_t)]; + target_regs_read(t, regs); + regs[0] = f->iap_ram + offsetof(struct flash_param, command); + regs[1] = f->iap_ram + offsetof(struct flash_param, result); + regs[REG_MSP] = f->iap_msp; + regs[REG_LR] = f->iap_ram | 1; + regs[REG_PC] = f->iap_entry; + target_regs_write(t, regs); + + /* start the target and wait for it to halt again */ + target_halt_resume(t, false); + while (!target_halt_wait(t)); + + /* copy back just the parameters structure */ + target_mem_read(t, ¶m, f->iap_ram, sizeof(param)); + return param.result; +} + +static uint8_t lpc_sector_for_addr(struct lpc_flash *f, uint32_t addr) +{ + return f->base_sector + (addr - f->f.start) / f->f.blocksize; +} + +int lpc_flash_erase(struct target_flash *tf, uint32_t addr, size_t len) +{ + struct lpc_flash *f = (struct lpc_flash *)tf; + uint32_t start = lpc_sector_for_addr(f, addr); + uint32_t end = lpc_sector_for_addr(f, addr + len - 1); + + if (lpc_iap_call(f, IAP_CMD_PREPARE, start, end, f->bank)) + return -1; + + /* and now erase them */ + if (lpc_iap_call(f, IAP_CMD_ERASE, start, end, CPU_CLK_KHZ, f->bank)) + return -2; + + /* check erase ok */ + if (lpc_iap_call(f, IAP_CMD_BLANKCHECK, start, end, f->bank)) + return -3; + + return 0; +} + +int lpc_flash_write(struct target_flash *tf, + uint32_t dest, const void *src, size_t len) +{ + struct lpc_flash *f = (struct lpc_flash *)tf; + /* prepare... */ + uint32_t sector = lpc_sector_for_addr(f, dest); + if (lpc_iap_call(f, IAP_CMD_PREPARE, sector, sector, f->bank)) + return -1; + + /* Write payload to target ram */ + uint32_t bufaddr = ALIGN(f->iap_ram + sizeof(struct flash_param), 4); + target_mem_write(f->f.t, bufaddr, src, len); + + /* set the destination address and program */ + if (lpc_iap_call(f, IAP_CMD_PROGRAM, dest, bufaddr, len, CPU_CLK_KHZ)) + return -2; + + return 0; +} + -- cgit v1.2.3 From 09b781f1c1593025e6d3157573343f4431f5f5b6 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 4 Apr 2015 19:18:05 -0700 Subject: target: Remove old flash interface. --- src/include/target.h | 7 ------- src/target.c | 10 ---------- 2 files changed, 17 deletions(-) diff --git a/src/include/target.h b/src/include/target.h index 96b5506..f86714b 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -182,17 +182,10 @@ struct target_s { uint32_t idcode; /* Target memory map */ - const char *xml_mem_map; char *dyn_mem_map; struct target_ram *ram; struct target_flash *flash; - /* DEPRECATED: Flash memory access functions */ - int (*flash_erase)(target *t, uint32_t addr, size_t len); - int (*flash_write)(target *t, uint32_t dest, - const uint8_t *src, size_t len); - int (*flash_done)(target *t); - /* Host I/O support */ void (*hostio_reply)(target *t, int32_t retcode, uint32_t errcode); diff --git a/src/target.c b/src/target.c index 266c23e..8f33e70 100644 --- a/src/target.c +++ b/src/target.c @@ -131,10 +131,6 @@ static ssize_t map_flash(char *buf, size_t len, struct target_flash *f) const char *target_mem_map(target *t) { - /* Deprecated static const memory map */ - if (t->xml_mem_map) - return t->xml_mem_map; - if (t->dyn_mem_map) return t->dyn_mem_map; @@ -167,9 +163,6 @@ static struct target_flash *flash_for_addr(target *t, uint32_t addr) int target_flash_erase(target *t, uint32_t addr, size_t len) { - if (t->flash_write) - return t->flash_erase(t, addr, len); - int ret = 0; while (len) { struct target_flash *f = flash_for_addr(t, addr); @@ -184,9 +177,6 @@ int target_flash_erase(target *t, uint32_t addr, size_t len) int target_flash_write(target *t, uint32_t dest, const void *src, size_t len) { - if (t->flash_write) - return t->flash_write(t, dest, src, len); - int ret = 0; while (len) { struct target_flash *f = flash_for_addr(t, dest); -- cgit v1.2.3 From 24122aa31894524867536469c5a9b055c82b25af Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 11 Apr 2015 16:08:25 -0700 Subject: lpc43xx: add chipid for LPC43S37. --- src/lpc43xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lpc43xx.c b/src/lpc43xx.c index 5181b8b..99ceb00 100644 --- a/src/lpc43xx.c +++ b/src/lpc43xx.c @@ -89,6 +89,7 @@ bool lpc43xx_probe(target *t) switch(chipid) { case 0x4906002B: /* Parts with on-chip flash */ + case 0x7906002B: /* LM43S?? - Undocumented? */ switch (cpuid & 0xFF00FFF0) { case 0x4100C240: t->driver = "LPC43xx Cortex-M4"; -- cgit v1.2.3 From 9009ed6581fddbd5c7cc1353aaec7144c4f778f6 Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 11 Apr 2015 16:08:59 -0700 Subject: cortexm: Add target option to inhibit assersion of SRST. --- src/cortexm.c | 6 ++++-- src/include/cortexm.h | 2 ++ src/lpc43xx.c | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cortexm.c b/src/cortexm.c index e7bed5b..028af21 100644 --- a/src/cortexm.c +++ b/src/cortexm.c @@ -418,8 +418,10 @@ static void cortexm_pc_write(target *t, const uint32_t val) * using the core debug registers in the NVIC. */ static void cortexm_reset(target *t) { - jtagtap_srst(true); - jtagtap_srst(false); + if ((t->target_options & CORTEXM_TOPT_INHIBIT_SRST) == 0) { + jtagtap_srst(true); + jtagtap_srst(false); + } /* Read DHCSR here to clear S_RESET_ST bit before reset */ target_mem_read32(t, CORTEXM_DHCSR); diff --git a/src/include/cortexm.h b/src/include/cortexm.h index 0a9c3ae..de57112 100644 --- a/src/include/cortexm.h +++ b/src/include/cortexm.h @@ -153,6 +153,8 @@ #define ARM_THUMB_BREAKPOINT 0xBE00 +#define CORTEXM_TOPT_INHIBIT_SRST (1 << 2) + bool cortexm_attach(target *t); void cortexm_detach(target *t); void cortexm_halt_resume(target *t, bool step); diff --git a/src/lpc43xx.c b/src/lpc43xx.c index 99ceb00..b6c499a 100644 --- a/src/lpc43xx.c +++ b/src/lpc43xx.c @@ -110,6 +110,7 @@ bool lpc43xx_probe(target *t) 0x1B010000, 0x70000, 0x10000); target_add_commands(t, lpc43xx_cmd_list, "LPC43xx"); target_add_ram(t, 0x1B080000, 0xE4F80000UL); + t->target_options |= CORTEXM_TOPT_INHIBIT_SRST; } break; case 0x4100C200: -- cgit v1.2.3 From ca17de624306f08490d4ce4ec33e78692d95da3b Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Sat, 11 Apr 2015 17:23:01 -0700 Subject: lpc11xx: Correctly detect LPC8xx devices. --- src/lpc11xx.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lpc11xx.c b/src/lpc11xx.c index 09a0622..79a574e 100644 --- a/src/lpc11xx.c +++ b/src/lpc11xx.c @@ -31,6 +31,9 @@ #define IAP_ENTRYPOINT 0x1fff1ff1 #define IAP_RAM_BASE 0x10000000 +#define LPC11XX_DEVICE_ID 0x400483F4 +#define LPC8XX_DEVICE_ID 0x400483F8 + static int lpc11xx_flash_write(struct target_flash *f, uint32_t dest, const void *src, size_t len); @@ -51,10 +54,8 @@ lpc11xx_probe(target *t) uint32_t idcode; /* read the device ID register */ - idcode = target_mem_read32(t, 0x400483F4); - + idcode = target_mem_read32(t, LPC11XX_DEVICE_ID); switch (idcode) { - case 0x041E502B: case 0x2516D02B: case 0x0416502B: @@ -90,8 +91,15 @@ lpc11xx_probe(target *t) target_add_ram(t, 0x10000000, 0x2000); lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000); return true; + } - case 0x1812202b: /* LPC812M101FDH20 */ + idcode = target_mem_read32(t, LPC8XX_DEVICE_ID); + switch (idcode) { + case 0x00008100: /* LPC810M021FN8 */ + case 0x00008110: /* LPC811M001JDH16 */ + case 0x00008120: /* LPC812M101JDH16 */ + case 0x00008121: /* LPC812M101JD20 */ + case 0x00008122: /* LPC812M101JDH20 / LPC812M101JTB16 */ t->driver = "LPC8xx"; target_add_ram(t, 0x10000000, 0x1000); lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400); -- cgit v1.2.3 From 4af5c03d75a15e42263cf30f3a6e8228594133ce Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Tue, 21 Apr 2015 20:05:41 +1200 Subject: lmi: Use registers for stub parameters. --- flashstub/lmi.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ flashstub/lmi.s | 42 ------------------------------------------ flashstub/lmi.stub | 2 +- src/lmi.c | 12 +++--------- 4 files changed, 53 insertions(+), 52 deletions(-) create mode 100644 flashstub/lmi.c delete mode 100644 flashstub/lmi.s diff --git a/flashstub/lmi.c b/flashstub/lmi.c new file mode 100644 index 0000000..27f8875 --- /dev/null +++ b/flashstub/lmi.c @@ -0,0 +1,49 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2015 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "stub.h" + +#define LMI_FLASH_BASE ((volatile uint32_t *)0x400FD000) +#define LMI_FLASH_FMA LMI_FLASH_BASE[0] +#define LMI_FLASH_FMD LMI_FLASH_BASE[1] +#define LMI_FLASH_FMC LMI_FLASH_BASE[2] + +#define LMI_FLASH_FMC_WRITE (1 << 0) +#define LMI_FLASH_FMC_ERASE (1 << 1) +#define LMI_FLASH_FMC_MERASE (1 << 2) +#define LMI_FLASH_FMC_COMT (1 << 3) +#define LMI_FLASH_FMC_WRKEY 0xA4420000 + +void __attribute__((naked)) +stm32f1_flash_write_stub(uint32_t *dest, uint32_t *src, uint32_t size) +{ + size /= 4; + for (int i; i < size; i++) { + LMI_FLASH_FMA = (uint32_t)&dest[i]; + LMI_FLASH_FMD = src[i]; + LMI_FLASH_FMC = LMI_FLASH_FMC_WRKEY | LMI_FLASH_FMC_WRITE; + while (LMI_FLASH_FMC & LMI_FLASH_FMC_WRITE) + ; + } + + stub_exit(0); +} + + diff --git a/flashstub/lmi.s b/flashstub/lmi.s deleted file mode 100644 index b3b206e..0000000 --- a/flashstub/lmi.s +++ /dev/null @@ -1,42 +0,0 @@ - -_start: - ldr r0, _flashbase - ldr r1, _addr - mov r2, pc - add r2, #(_data - . - 2) - ldr r3, _size - ldr r5, _flash_write_cmd -_next: - cbz r3, _done - @ Write address to FMA - str r1, [r0] - @ Write data to FMD - ldr r4, [r2] - str r4, [r0, #4] - @ Write WRITE bit to FMC - str r5, [r0, #8] -_wait: @ Wait for WRITE bit to clear - ldr r4, [r0, #8] - mov r6, #1 - tst r4, r6 - bne _wait - - sub r3, #1 - add r1, #4 - add r2, #4 - b _next -_done: - bkpt - -@.align 4 -.org 0x28 -_flashbase: - .word 0x400FD000 -_flash_write_cmd: - .word 0xA4420001 -_addr: - .word 0 -_size: - .word 4 -_data: - .string "Hello World!\n\0\0\0" diff --git a/flashstub/lmi.stub b/flashstub/lmi.stub index afaf939..5f2c696 100644 --- a/flashstub/lmi.stub +++ b/flashstub/lmi.stub @@ -1 +1 @@ -0x4809, 0x490B, 0x467A, 0x3230, 0x4B0A, 0x4D08, 0xB15B, 0x6001, 0x6814, 0x6044, 0x6085, 0x6884, 0x2601, 0x4234, 0xD1FB, 0x3B01, 0x3104, 0x3204, 0xE7F2, 0xBE00, 0xD000, 0x400F, 0x0001, 0xA442, 0x0000, 0x0000, 0x0004, 0x0000, 0x6548, 0x6C6C, 0x206F, 0x6F57, 0x6C72, 0x2164, 0x000A, 0x0000, 0x0000, +0x0892, 0x2300, 0x4293, 0xD20F, 0x4C08, 0x6020, 0xF851, 0x5023, 0x3408, 0xF844, 0x5C04, 0x4D06, 0x6025, 0x6825, 0xF015, 0x0F01, 0xD1FB, 0x3301, 0x3004, 0xE7ED, 0xBE00, 0xBF00, 0xD000, 0x400F, 0x0001, 0xA442, \ No newline at end of file diff --git a/src/lmi.c b/src/lmi.c index 6bf2240..e2d1809 100644 --- a/src/lmi.c +++ b/src/lmi.c @@ -29,7 +29,7 @@ #include "cortexm.h" #define SRAM_BASE 0x20000000 -#define STUB_BUFFER_BASE (SRAM_BASE + 0x30) +#define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(lmi_flash_write_stub), 4) #define BLOCK_SIZE 0x400 @@ -109,15 +109,9 @@ int lmi_flash_write(struct target_flash *f, { target *t = f->t; - /* FIXME rewrite stub to use register args */ - uint32_t data[(len>>2)+2]; - data[0] = dest; - data[1] = len >> 2; - memcpy(&data[2], src, len); - target_mem_write(t, SRAM_BASE, lmi_flash_write_stub, sizeof(lmi_flash_write_stub)); - target_mem_write(t, STUB_BUFFER_BASE, data, len + 8); - return cortexm_run_stub(t, SRAM_BASE, 0, 0, 0, 0); + target_mem_write(t, STUB_BUFFER_BASE, src, len); + return cortexm_run_stub(t, SRAM_BASE, dest, STUB_BUFFER_BASE, len, 0); } -- cgit v1.2.3