target/sam: flash read write return bool

This commit is contained in:
Rafael Silva 2022-08-24 12:38:51 +01:00 committed by Rachel Mant
parent 44f7984c58
commit 67c9f3f6e2
4 changed files with 85 additions and 99 deletions

View File

@ -28,9 +28,9 @@
#include "target.h" #include "target.h"
#include "target_internal.h" #include "target_internal.h"
static int sam_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool sam_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int sam3_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool sam3_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int sam_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool sam_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
static int sam_gpnvm_get(target *t, uint32_t base, uint32_t *gpnvm); static int sam_gpnvm_get(target *t, uint32_t base, uint32_t *gpnvm);
@ -498,24 +498,20 @@ bool sam3x_probe(target *t)
return false; return false;
} }
static int static bool sam_flash_cmd(target *t, uint32_t base, uint8_t cmd, uint16_t arg)
sam_flash_cmd(target *t, uint32_t base, uint8_t cmd, uint16_t arg)
{ {
DEBUG_INFO("%s: base = 0x%08"PRIx32" cmd = 0x%02X, arg = 0x%06X\n", DEBUG_INFO("%s: base = 0x%08" PRIx32 " cmd = 0x%02X, arg = 0x%06X\n", __func__, base, cmd, arg);
__func__, base, cmd, arg);
if(base == 0) if (base == 0)
return -1; return false;
target_mem_write32(t, EEFC_FCR(base), target_mem_write32(t, EEFC_FCR(base), EEFC_FCR_FKEY | cmd | ((uint32_t)arg << 8));
EEFC_FCR_FKEY | cmd | ((uint32_t)arg << 8));
while (!(target_mem_read32(t, EEFC_FSR(base)) & EEFC_FSR_FRDY)) while (!(target_mem_read32(t, EEFC_FSR(base)) & EEFC_FSR_FRDY))
if(target_check_error(t)) if (target_check_error(t))
return -1; return false;
uint32_t sr = target_mem_read32(t, EEFC_FSR(base)); return !(target_mem_read32(t, EEFC_FSR(base)) & EEFC_FSR_ERROR);
return sr & EEFC_FSR_ERROR;
} }
static enum sam_driver sam_driver(target *t) static enum sam_driver sam_driver(target *t)
@ -535,7 +531,7 @@ static enum sam_driver sam_driver(target *t)
return DRIVER_SAMX7X; return DRIVER_SAMX7X;
} }
static int sam_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool sam_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
uint32_t base = ((struct sam_flash *)f)->eefc_base; uint32_t base = ((struct sam_flash *)f)->eefc_base;
@ -549,8 +545,8 @@ static int sam_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
while (len) { while (len) {
int16_t arg = chunk | 0x1; int16_t arg = chunk | 0x1;
if(sam_flash_cmd(t, base, EEFC_FCR_FCMD_EPA, arg)) if(!sam_flash_cmd(t, base, EEFC_FCR_FCMD_EPA, arg))
return -1; return false;
if (len > f->blocksize) if (len > f->blocksize)
len -= f->blocksize; len -= f->blocksize;
@ -558,19 +554,22 @@ static int sam_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
len = 0; len = 0;
chunk += 8; chunk += 8;
} }
return 0; return true;
} }
static int sam3_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool sam3_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
/* The SAM3X/SAM3N don't really have a page erase function. /* The SAM3X/SAM3N don't really have a page erase function.
* We do nothing here and use Erase/Write page in flash_write. * We do nothing here and use Erase/Write page in flash_write.
*/ */
(void)f; (void)addr; (void)len; (void)f;
return 0; (void)addr;
(void)len;
return true;
} }
static int sam_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) static bool sam_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
{ {
target *t = f->t; target *t = f->t;
struct sam_flash *sf = (struct sam_flash *)f; struct sam_flash *sf = (struct sam_flash *)f;
@ -578,15 +577,13 @@ static int sam_flash_write(target_flash_s *f, target_addr_t dest, const void *sr
unsigned chunk = (dest - f->start) / f->writesize; unsigned chunk = (dest - f->start) / f->writesize;
target_mem_write(t, dest, src, len); target_mem_write(t, dest, src, len);
if(sam_flash_cmd(t, base, sf->write_cmd, chunk))
return -1;
return 0; return sam_flash_cmd(t, base, sf->write_cmd, chunk);
} }
static int sam_gpnvm_get(target *t, uint32_t base, uint32_t *gpnvm) static int sam_gpnvm_get(target *t, uint32_t base, uint32_t *gpnvm)
{ {
if(!gpnvm || sam_flash_cmd(t, base, EEFC_FCR_FCMD_GGPB, 0)) if(!gpnvm || !sam_flash_cmd(t, base, EEFC_FCR_FCMD_GGPB, 0))
return -1; return -1;
*gpnvm = target_mem_read32(t, EEFC_FRR(base)); *gpnvm = target_mem_read32(t, EEFC_FRR(base));
@ -652,7 +649,7 @@ static bool sam_cmd_gpnvm(target *t, int argc, const char **argv)
{ {
if (work_mask & 1) { if (work_mask & 1) {
uint8_t cmd = (work_values & 1) ? EEFC_FCR_FCMD_SGPB : EEFC_FCR_FCMD_CGPB; uint8_t cmd = (work_values & 1) ? EEFC_FCR_FCMD_SGPB : EEFC_FCR_FCMD_CGPB;
if(sam_flash_cmd(t, base, cmd, bit)) if(!sam_flash_cmd(t, base, cmd, bit))
return false; return false;
} }
work_mask >>= 1; work_mask >>= 1;

View File

@ -103,8 +103,8 @@
#define FLASHCALW_FGPFRLO (FLASHCALW_BASE + 0x18) #define FLASHCALW_FGPFRLO (FLASHCALW_BASE + 0x18)
static void sam4l_extended_reset(target *t); static void sam4l_extended_reset(target *t);
static int sam4l_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool sam4l_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int sam4l_flash_write_buf(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool sam4l_flash_write_buf(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
/* why Atmel couldn't make it sequential ... */ /* why Atmel couldn't make it sequential ... */
static const size_t __ram_size[16] = { static const size_t __ram_size[16] = {
@ -159,7 +159,7 @@ static const size_t __nvp_size[16] = {
/* Arbitrary time to wait for FLASH controller to be ready */ /* Arbitrary time to wait for FLASH controller to be ready */
#define FLASH_TIMEOUT 10000 #define FLASH_TIMEOUT 1000 /* ms */
/* /*
* Populate a target_flash struct with the necessary function pointers * Populate a target_flash struct with the necessary function pointers
@ -292,63 +292,55 @@ sam4l_extended_reset(target *t)
* Need the target struct to call the mem_read32 and mem_write32 function * Need the target struct to call the mem_read32 and mem_write32 function
* pointers. * pointers.
*/ */
static int static bool sam4l_flash_command(target *t, uint32_t page, uint32_t cmd)
sam4l_flash_command(target *t, uint32_t page, uint32_t cmd)
{ {
uint32_t cmd_reg; DEBUG_INFO(
uint32_t status; "\nSAM4L: sam4l_flash_command: FSR: 0x%08" PRIx32 ", page = %lu, command = %lu\n", FLASHCALW_FSR, page, cmd);
int timeout;
DEBUG_INFO("\nSAM4L: sam4l_flash_command: FSR: 0x%08x, page = %d, "
"command = %d\n", (unsigned int)(FLASHCALW_FSR),
(int) page, (int) cmd);
/* wait for Flash controller ready */ /* wait for Flash controller ready */
for (timeout = 0; timeout < FLASH_TIMEOUT; timeout++) { platform_timeout timeout;
status = target_mem_read32(t, FLASHCALW_FSR); platform_timeout_set(&timeout, FLASH_TIMEOUT);
if (status & FLASHCALW_FSR_FRDY) { while (!(target_mem_read32(t, FLASHCALW_FSR) & FLASHCALW_FSR_FRDY)) {
break; if (platform_timeout_is_expired(&timeout)) {
DEBUG_WARN("\nSAM4L: sam4l_flash_command: Not ready!\n");
return false;
} }
} }
if (timeout == FLASH_TIMEOUT) {
DEBUG_WARN("\nSAM4L: sam4l_flash_command: Not ready! "
"Status = 0x%08x\n", (unsigned int) status);
return -1; /* Failed */
}
/* load up the new command */ /* load up the new command */
cmd_reg = (cmd & FLASHCALW_FCMD_CMD_MASK) | const uint32_t cmd_reg = (cmd & FLASHCALW_FCMD_CMD_MASK) |
((page & FLASHCALW_FCMD_PAGEN_MASK) << FLASHCALW_FCMD_PAGEN_SHIFT) | ((page & FLASHCALW_FCMD_PAGEN_MASK) << FLASHCALW_FCMD_PAGEN_SHIFT) |
(0xA5 << FLASHCALW_FCMD_KEY_SHIFT); (0xA5U << FLASHCALW_FCMD_KEY_SHIFT);
DEBUG_INFO("\nSAM4L: sam4l_flash_command: Wrting command word 0x%08x\n",
(unsigned int) cmd_reg); DEBUG_INFO("\nSAM4L: sam4l_flash_command: Wrting command word 0x%08" PRIx32 "\n", cmd_reg);
/* and kick it off */ /* and kick it off */
target_mem_write32(t, FLASHCALW_FCMD, cmd_reg); target_mem_write32(t, FLASHCALW_FCMD, cmd_reg);
/* don't actually wait for it to finish, the next command will stall if it is not done */ /* don't actually wait for it to finish, the next command will stall if it is not done */
return 0; return true;
} }
/* /*
* Write data from 'src' into flash using the algorithim provided by * Write data from 'src' into flash using the algorithim provided by
* Atmel in their data sheet. * Atmel in their data sheet.
*/ */
static int sam4l_flash_write_buf(target_flash_s *f, target_addr_t addr, const void *src, size_t len) static bool sam4l_flash_write_buf(target_flash_s *f, target_addr_t addr, const void *src, size_t len)
{ {
target *t = f->t; target *t = f->t;
uint32_t *src_data = (uint32_t *)src; uint32_t *src_data = (uint32_t *)src;
uint32_t ndx;
uint16_t page;
DEBUG_INFO("\nSAM4L: sam4l_flash_write_buf: addr = 0x%08lx, len %d\n", DEBUG_INFO("\nSAM4L: sam4l_flash_write_buf: addr = 0x%08" PRIx32 ", len %d\n", addr, len);
(long unsigned int) addr, (int) len);
/* This will fail with unaligned writes, the write_buf version */ /* This will fail with unaligned writes, the write_buf version */
page = addr / SAM4L_PAGE_SIZE; const uint16_t page = addr / SAM4L_PAGE_SIZE;
if (len != SAM4L_PAGE_SIZE) { if (len != SAM4L_PAGE_SIZE)
return -1; return false;
}
/* clear the page buffer */ /* clear the page buffer */
if (sam4l_flash_command(t, 0, FLASH_CMD_CPB)) { if (!sam4l_flash_command(t, 0, FLASH_CMD_CPB))
return -1; return false;
}
/* Now fill page buffer with our 512 bytes of data */ /* Now fill page buffer with our 512 bytes of data */
@ -356,7 +348,7 @@ static int sam4l_flash_write_buf(target_flash_s *f, target_addr_t addr, const vo
* last 64 bits (8 bytes) to be incorrect on even pages (0, 2, 4, ...) * last 64 bits (8 bytes) to be incorrect on even pages (0, 2, 4, ...)
* since it works this way I've not investigated further. * since it works this way I've not investigated further.
*/ */
for (ndx = 0; ndx < SAM4L_PAGE_SIZE; ndx += 4) { for (size_t ndx = 0; ndx < SAM4L_PAGE_SIZE; ndx += 4) {
/* /*
* the page buffer overlaps flash, its only 512 bytes long * the page buffer overlaps flash, its only 512 bytes long
* and no matter where you write it from it goes to the page * and no matter where you write it from it goes to the page
@ -364,26 +356,23 @@ static int sam4l_flash_write_buf(target_flash_s *f, target_addr_t addr, const vo
* instead we just write 0 - pagelen (512) and that fills our * instead we just write 0 - pagelen (512) and that fills our
* buffer correctly. * buffer correctly.
*/ */
target_mem_write32(t, addr+ndx, *src_data); target_mem_write32(t, addr + ndx, *src_data);
src_data++; src_data++;
} }
/* write the page */ /* write the page */
if (sam4l_flash_command(t, page, FLASH_CMD_WP)) { return sam4l_flash_command(t, page, FLASH_CMD_WP);
return -1;
}
return 0;
} }
/* /*
* Erase flash across the addresses specified by addr and len * Erase flash across the addresses specified by addr and len
*/ */
static int sam4l_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool sam4l_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
uint16_t page; uint16_t page;
DEBUG_INFO("SAM4L: flash erase address 0x%08x for %d bytes\n", DEBUG_INFO("SAM4L: flash erase address 0x%08" PRIx32 " for %d bytes\n", addr, len);
(unsigned int) addr, (unsigned int) len);
/* /*
* NB: if addr isn't aligned to a page boundary, or length * NB: if addr isn't aligned to a page boundary, or length
* is not an even multiple of page sizes, we may end up * is not an even multiple of page sizes, we may end up
@ -392,14 +381,15 @@ static int sam4l_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
while (len) { while (len) {
page = addr / SAM4L_PAGE_SIZE; page = addr / SAM4L_PAGE_SIZE;
if (sam4l_flash_command(t, page, FLASH_CMD_EP)) { if (!sam4l_flash_command(t, page, FLASH_CMD_EP))
return -1; return false;
}
if (len > SAM4L_PAGE_SIZE) if (len > SAM4L_PAGE_SIZE)
len -= SAM4L_PAGE_SIZE; len -= SAM4L_PAGE_SIZE;
else else
len = 0; len = 0;
addr += SAM4L_PAGE_SIZE; addr += SAM4L_PAGE_SIZE;
} }
return 0; return true;
} }

View File

@ -39,8 +39,8 @@
#include "target_internal.h" #include "target_internal.h"
#include "cortexm.h" #include "cortexm.h"
static int samd_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool samd_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int samd_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool samd_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
bool samd_mass_erase(target *t); bool samd_mass_erase(target *t);
static bool samd_cmd_lock_flash(target *t, int argc, const char **argv); static bool samd_cmd_lock_flash(target *t, int argc, const char **argv);
@ -579,7 +579,7 @@ static void samd_unlock_current_address(target *t)
/* /*
* Erase flash row by row * Erase flash row by row
*/ */
static int samd_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool samd_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
while (len) { while (len) {
@ -596,7 +596,7 @@ static int samd_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
/* Poll for NVM Ready */ /* Poll for NVM Ready */
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0) while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
if (target_check_error(t)) if (target_check_error(t))
return -1; return false;
/* Lock */ /* Lock */
samd_lock_current_address(t); samd_lock_current_address(t);
@ -608,14 +608,13 @@ static int samd_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
len = 0; len = 0;
} }
return 0; return true;
} }
/* /*
* Write flash page by page * Write flash page by page
*/ */
static int samd_flash_write(target_flash_s *f, static bool samd_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
target_addr_t dest, const void *src, size_t len)
{ {
target *t = f->t; target *t = f->t;
@ -632,12 +631,12 @@ static int samd_flash_write(target_flash_s *f,
/* Poll for NVM Ready */ /* Poll for NVM Ready */
while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0) while ((target_mem_read32(t, SAMD_NVMC_INTFLAG) & SAMD_NVMC_READY) == 0)
if (target_check_error(t)) if (target_check_error(t))
return -1; return false;
/* Lock */ /* Lock */
samd_lock_current_address(t); samd_lock_current_address(t);
return 0; return true;
} }
/* /*

View File

@ -38,8 +38,8 @@
#include "target_internal.h" #include "target_internal.h"
#include "cortexm.h" #include "cortexm.h"
static int samx5x_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool samx5x_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int samx5x_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool samx5x_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
static bool samx5x_cmd_lock_flash(target *t, int argc, const char **argv); static bool samx5x_cmd_lock_flash(target *t, int argc, const char **argv);
static bool samx5x_cmd_unlock_flash(target *t, int argc, const char **argv); static bool samx5x_cmd_unlock_flash(target *t, int argc, const char **argv);
static bool samx5x_cmd_unlock_bootprot(target *t, int argc, const char **argv); static bool samx5x_cmd_unlock_bootprot(target *t, int argc, const char **argv);
@ -496,7 +496,7 @@ static int samx5x_check_nvm_error(target *t)
/** /**
* Erase flash block by block * Erase flash block by block
*/ */
static int samx5x_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool samx5x_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
uint16_t errs = samx5x_read_nvm_error(t); uint16_t errs = samx5x_read_nvm_error(t);
@ -517,12 +517,12 @@ static int samx5x_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
if (addr < (15 - bootprot) * 8192) { if (addr < (15 - bootprot) * 8192) {
DEBUG_WARN("Bootprot\n"); DEBUG_WARN("Bootprot\n");
return -1; return false;
} }
if (~runlock & (1 << addr / lock_region_size)) { if (~runlock & (1 << addr / lock_region_size)) {
DEBUG_WARN("runlock\n"); DEBUG_WARN("runlock\n");
return -1; return false;
} }
while (len) { while (len) {
@ -541,12 +541,12 @@ static int samx5x_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
SAMX5X_STATUS_READY) == 0) SAMX5X_STATUS_READY) == 0)
if (target_check_error(t) || samx5x_check_nvm_error(t)) { if (target_check_error(t) || samx5x_check_nvm_error(t)) {
DEBUG_WARN("NVM Ready\n"); DEBUG_WARN("NVM Ready\n");
return -1; return false;
} }
if (target_check_error(t) || samx5x_check_nvm_error(t)) { if (target_check_error(t) || samx5x_check_nvm_error(t)) {
DEBUG_WARN("Error\n"); DEBUG_WARN("Error\n");
return -1; return false;
} }
/* Lock */ /* Lock */
@ -556,13 +556,13 @@ static int samx5x_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
len -= f->blocksize; len -= f->blocksize;
} }
return 0; return true;
} }
/** /**
* Write flash page by page * Write flash page by page
*/ */
static int samx5x_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) static bool samx5x_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
{ {
target *t = f->t; target *t = f->t;
bool error = false; bool error = false;
@ -595,13 +595,13 @@ static int samx5x_flash_write(target_flash_s *f, target_addr_t dest, const void
if (error || target_check_error(t) || samx5x_check_nvm_error(t)) { if (error || target_check_error(t) || samx5x_check_nvm_error(t)) {
DEBUG_WARN("Error writing flash page at 0x%08"PRIx32 DEBUG_WARN("Error writing flash page at 0x%08"PRIx32
" (len 0x%08zx)\n", dest, len); " (len 0x%08zx)\n", dest, len);
return -1; return false;
} }
/* Lock */ /* Lock */
samx5x_lock_current_address(t); samx5x_lock_current_address(t);
return 0; return true;
} }
/** /**