samd: use new flash interface.
This commit is contained in:
parent
d340053078
commit
54eb3a719f
109
src/samd.c
109
src/samd.c
|
@ -40,9 +40,9 @@
|
||||||
#include "gdb_packet.h"
|
#include "gdb_packet.h"
|
||||||
#include "cortexm.h"
|
#include "cortexm.h"
|
||||||
|
|
||||||
static int samd_flash_erase(target *t, uint32_t addr, size_t len);
|
static int samd_flash_erase(struct target_flash *t, uint32_t addr, size_t len);
|
||||||
static int samd_flash_write(target *t, uint32_t dest,
|
static int samd_flash_write(struct target_flash *f,
|
||||||
const uint8_t *src, size_t len);
|
uint32_t dest, const void *src, size_t len);
|
||||||
|
|
||||||
static bool samd_cmd_erase_all(target *t);
|
static bool samd_cmd_erase_all(target *t);
|
||||||
static bool samd_cmd_lock_flash(target *t);
|
static bool samd_cmd_lock_flash(target *t);
|
||||||
|
@ -63,21 +63,6 @@ const struct command_s samd_cmd_list[] = {
|
||||||
{NULL, NULL, NULL}
|
{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[] = "<?xml version=\"1.0\"?>"
|
|
||||||
/* "<!DOCTYPE memory-map "
|
|
||||||
" PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
|
|
||||||
" \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"*/
|
|
||||||
"<memory-map>"
|
|
||||||
" <memory type=\"flash\" start=\"0x0\" length=\"0x40000\">"
|
|
||||||
" <property name=\"blocksize\">0x100</property>"
|
|
||||||
" </memory>"
|
|
||||||
" <memory type=\"ram\" start=\"0x20000000\" length=\"0x8000\"/>"
|
|
||||||
"</memory-map>";
|
|
||||||
|
|
||||||
/* Non-Volatile Memory Controller (NVMC) Parameters */
|
/* Non-Volatile Memory Controller (NVMC) Parameters */
|
||||||
#define SAMD_ROW_SIZE 256
|
#define SAMD_ROW_SIZE 256
|
||||||
#define SAMD_PAGE_SIZE 64
|
#define SAMD_PAGE_SIZE 64
|
||||||
|
@ -361,6 +346,19 @@ struct samd_descr samd_parse_device_id(uint32_t did)
|
||||||
return samd;
|
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];
|
char variant_string[40];
|
||||||
bool samd_probe(target *t)
|
bool samd_probe(target *t)
|
||||||
|
@ -423,9 +421,8 @@ bool samd_probe(target *t)
|
||||||
t->attach = samd_protected_attach;
|
t->attach = samd_protected_attach;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->xml_mem_map = samd_xml_memory_map;
|
target_add_ram(t, 0x20000000, 0x8000);
|
||||||
t->flash_erase = samd_flash_erase;
|
samd_add_flash(t, 0x00000000, 0x40000);
|
||||||
t->flash_write = samd_flash_write;
|
|
||||||
target_add_commands(t, samd_cmd_list, "SAMD");
|
target_add_commands(t, samd_cmd_list, "SAMD");
|
||||||
|
|
||||||
/* If we're not in reset here */
|
/* If we're not in reset here */
|
||||||
|
@ -463,11 +460,9 @@ static void samd_unlock_current_address(target *t)
|
||||||
/**
|
/**
|
||||||
* Erase flash row by row
|
* 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);
|
target *t = f->t;
|
||||||
len &= ~(SAMD_ROW_SIZE - 1);
|
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
/* Write address of first word in row to erase it */
|
/* Write address of first word in row to erase it */
|
||||||
/* Must be shifted right for 16-bit address, see Datasheet §20.8.8 Address */
|
/* 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 */
|
/* Lock */
|
||||||
samd_lock_current_address(t);
|
samd_lock_current_address(t);
|
||||||
|
|
||||||
addr += SAMD_ROW_SIZE;
|
addr += f->blocksize;
|
||||||
len -= SAMD_ROW_SIZE;
|
len -= f->blocksize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -497,56 +492,28 @@ static int samd_flash_erase(target *t, uint32_t addr, size_t len)
|
||||||
/**
|
/**
|
||||||
* Write flash page by page
|
* Write flash page by page
|
||||||
*/
|
*/
|
||||||
static int samd_flash_write(target *t, uint32_t dest,
|
static int samd_flash_write(struct target_flash *f,
|
||||||
const uint8_t *src, size_t len)
|
uint32_t dest, const void *src, size_t len)
|
||||||
{
|
{
|
||||||
/* Find the size of our 32-bit data buffer */
|
target *t = f->t;
|
||||||
uint32_t offset = dest % 4;
|
|
||||||
uint32_t words = (offset + len + 3) / 4;
|
|
||||||
uint32_t data[words], i = 0;
|
|
||||||
|
|
||||||
/* Populate the data buffer */
|
/* Write within a single page. This may be part or all of the page */
|
||||||
memset((uint8_t *)data, 0xFF, words * 4);
|
target_mem_write(t, dest, src, len);
|
||||||
memcpy((uint8_t *)data + offset, src, len);
|
|
||||||
|
|
||||||
/* The address of the first word involved in the write */
|
/* Unlock */
|
||||||
uint32_t addr = dest & ~0x3;
|
samd_unlock_current_address(t);
|
||||||
/* 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 */
|
/* Issue the write page command */
|
||||||
uint32_t first_page = dest & ~(SAMD_PAGE_SIZE - 1);
|
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
||||||
/* The start address of the last page involved in the write */
|
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEPAGE);
|
||||||
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) {
|
/* Poll for NVM Ready */
|
||||||
next_page = page + SAMD_PAGE_SIZE;
|
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
|
||||||
length = MIN(end + 4, next_page) - addr;
|
if (target_check_error(t))
|
||||||
|
return -1;
|
||||||
|
|
||||||
/* Write within a single page. This may be part or all of the page */
|
/* Lock */
|
||||||
target_mem_write(t, addr, &data[i], length);
|
samd_lock_current_address(t);
|
||||||
addr += length; i += (length >> 2);
|
|
||||||
|
|
||||||
/* If MANW=0 (default) we may have triggered an automatic
|
|
||||||
* write. Ignore this */
|
|
||||||
|
|
||||||
/* Unlock */
|
|
||||||
samd_unlock_current_address(t);
|
|
||||||
|
|
||||||
/* Issue the write page command */
|
|
||||||
target_mem_write32(t, SAMD_NVMC_CTRLA,
|
|
||||||
SAMD_CTRLA_CMD_KEY | SAMD_CTRLA_CMD_WRITEPAGE);
|
|
||||||
|
|
||||||
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue