atsamv: add support for user signature partition write
Embedded flash also has a user signature area. This is a 512 bytes large page whose data are not erased by asserting ERASE pin or by software ERASE command. It may be used to store configuration, keys, trimming values etc. This commit adds option to access this area from OpenOCD. Change-Id: If870aa85938b9cccd94f958dd1f3d93dbdf779f0 Signed-off-by: Michal Lenc <michallenc@seznam.cz> Reviewed-on: https://review.openocd.org/c/openocd/+/8302 Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Tested-by: jenkins
This commit is contained in:
@@ -12,6 +12,9 @@
|
||||
* atsamv, atsams, and atsame support
|
||||
* Copyright (C) 2015 Morgan Quigley
|
||||
*
|
||||
* atsamv extension of user signature area
|
||||
* Copyright (C) 2024-2025 Elektroline Inc.
|
||||
*
|
||||
* Some of the lower level code was based on code supplied by
|
||||
* ATMEL under BSD-Source-Code License and this copyright.
|
||||
* ATMEL Microcontroller Software Support
|
||||
@@ -24,6 +27,7 @@
|
||||
|
||||
#include "imp.h"
|
||||
#include <helper/time_support.h>
|
||||
#include <helper/bits.h>
|
||||
|
||||
#define REG_NAME_WIDTH (12)
|
||||
|
||||
@@ -40,18 +44,39 @@
|
||||
#define SAMV_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */
|
||||
#define SAMV_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */
|
||||
#define SAMV_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */
|
||||
#define SAMV_EFC_FCMD_WUS (0x12) /* (EFC) Write User Signature */
|
||||
#define SAMV_EFC_FCMD_EUS (0x13) /* (EFC) Erase User Signature */
|
||||
#define SAMV_EFC_FCMD_STUS (0x14) /* (EFC) Start Read User Signature */
|
||||
#define SAMV_EFC_FCMD_SPUS (0x15) /* (EFC) Stop Read User Signature */
|
||||
|
||||
#define SAMV_EFC_FMR_SCOD BIT(16) /* Sequantial Code Optimalization Disable */
|
||||
|
||||
#define SAMV_EFC_FSR_FRDY_SET 1
|
||||
#define SAMV_EFC_FRS_FRDY_CLR 0
|
||||
|
||||
#define OFFSET_EFC_FMR 0
|
||||
#define OFFSET_EFC_FCR 4
|
||||
#define OFFSET_EFC_FSR 8
|
||||
#define OFFSET_EFC_FRR 12
|
||||
|
||||
#define TIMEOUT_MS_FRS_CHANGE 10 /* Timeout for FRS ready bit change */
|
||||
#define TIMEOUT_MS_CMD_DEFAULT 50 /* Default timeout for command */
|
||||
#define TIMEOUT_MS_CMD_ERASE 24000 /* Timeout for erase commands */
|
||||
|
||||
#define SAMV_CHIPID_CIDR (0x400E0940)
|
||||
#define SAMV_NUM_GPNVM_BITS 9
|
||||
#define SAMV_CONTROLLER_ADDR (0x400e0c00)
|
||||
#define SAMV_SECTOR_SIZE 16384
|
||||
#define SAMV_PAGE_SIZE 512
|
||||
#define SAMV_FLASH_BASE 0x00400000
|
||||
/* This is a workaround. Flash Signature area is actually located at the
|
||||
* beginning of the flash memory at the address range overlapping the
|
||||
* first page of program flash. Since OpenOCD does not support write to
|
||||
* a bank outside of address range, we use address above maximum 32-bit
|
||||
* address space.
|
||||
*/
|
||||
#define SAMV_FLASH_SIGNATURE_BASE 0x100000000
|
||||
#define SAMV_FLASH_SIGNATURE_SIZE SAMV_PAGE_SIZE
|
||||
|
||||
struct samv_flash_bank {
|
||||
bool probed;
|
||||
@@ -59,6 +84,7 @@ struct samv_flash_bank {
|
||||
unsigned int gpnvm[SAMV_NUM_GPNVM_BITS];
|
||||
};
|
||||
|
||||
|
||||
/* The actual sector size of the SAMV7 flash memory is 128K bytes.
|
||||
* 16 sectors for a 2048KB device. The lock regions are 16KB per lock
|
||||
* region, with a 2048KB device having 128 lock regions.
|
||||
@@ -72,6 +98,36 @@ static int samv_efc_get_status(struct target *target, uint32_t *v)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_efc_wait_status(struct target *target, uint8_t desired,
|
||||
int64_t timeout, uint32_t *status)
|
||||
{
|
||||
uint32_t v;
|
||||
int64_t ms_now, ms_end;
|
||||
int r;
|
||||
|
||||
if (status)
|
||||
*status = 0;
|
||||
|
||||
ms_end = timeout + timeval_ms();
|
||||
|
||||
do {
|
||||
r = samv_efc_get_status(target, &v);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
|
||||
if (status)
|
||||
*status = v;
|
||||
ms_now = timeval_ms();
|
||||
if (ms_now > ms_end) {
|
||||
/* error */
|
||||
LOG_ERROR("Command timeout");
|
||||
return ERROR_FLASH_BUSY;
|
||||
}
|
||||
} while ((v & 1) != desired);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int samv_efc_get_result(struct target *target, uint32_t *v)
|
||||
{
|
||||
uint32_t rv;
|
||||
@@ -81,15 +137,20 @@ static int samv_efc_get_result(struct target *target, uint32_t *v)
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int samv_efc_get_mode(struct target *target, uint32_t *v)
|
||||
{
|
||||
return target_read_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FMR, v);
|
||||
}
|
||||
|
||||
static inline int samv_efc_set_mode(struct target *target, uint32_t v)
|
||||
{
|
||||
return target_write_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FMR, v);
|
||||
}
|
||||
|
||||
static int samv_efc_start_command(struct target *target,
|
||||
unsigned int command, unsigned int argument)
|
||||
uint8_t command, unsigned int argument)
|
||||
{
|
||||
uint32_t v;
|
||||
samv_efc_get_status(target, &v);
|
||||
if (!(v & 1)) {
|
||||
LOG_ERROR("flash controller is not ready");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
v = (0x5A << 24) | (argument << 8) | command;
|
||||
LOG_DEBUG("starting flash command: 0x%08x", (unsigned int)(v));
|
||||
@@ -100,32 +161,33 @@ static int samv_efc_start_command(struct target *target,
|
||||
}
|
||||
|
||||
static int samv_efc_perform_command(struct target *target,
|
||||
unsigned int command, unsigned int argument, uint32_t *status)
|
||||
uint8_t command, unsigned int argument, uint32_t *status)
|
||||
{
|
||||
int r;
|
||||
uint32_t v;
|
||||
int64_t ms_now, ms_end;
|
||||
int64_t timeout;
|
||||
|
||||
if (status)
|
||||
*status = 0;
|
||||
|
||||
r = samv_efc_get_status(target, &v);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
if ((v & 1) != 0x1)
|
||||
return ERROR_FAIL;
|
||||
r = samv_efc_start_command(target, command, argument);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
|
||||
ms_end = 10000 + timeval_ms();
|
||||
if (command == SAMV_EFC_FCMD_EA || command == SAMV_EFC_FCMD_EPA ||
|
||||
command == SAMV_EFC_FCMD_EUS)
|
||||
timeout = TIMEOUT_MS_CMD_ERASE;
|
||||
else
|
||||
timeout = TIMEOUT_MS_CMD_DEFAULT;
|
||||
|
||||
do {
|
||||
r = samv_efc_get_status(target, &v);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
ms_now = timeval_ms();
|
||||
if (ms_now > ms_end) {
|
||||
/* error */
|
||||
LOG_ERROR("Command timeout");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} while ((v & 1) == 0);
|
||||
r = samv_efc_wait_status(target, SAMV_EFC_FSR_FRDY_SET, timeout, &v);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
|
||||
/* if requested, copy the flash controller error bits back to the caller */
|
||||
if (status)
|
||||
@@ -133,6 +195,51 @@ static int samv_efc_perform_command(struct target *target,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int samv_efc_read_sequence(struct target *target, uint8_t start_cmd,
|
||||
uint8_t stop_cmd, uint8_t *buf, size_t read_size)
|
||||
{
|
||||
uint32_t v;
|
||||
uint32_t addr = SAMV_FLASH_BASE;
|
||||
int r;
|
||||
|
||||
samv_efc_get_mode(target, &v);
|
||||
v |= SAMV_EFC_FMR_SCOD;
|
||||
samv_efc_set_mode(target, v);
|
||||
|
||||
r = samv_efc_start_command(target, start_cmd, 0);
|
||||
if (r != ERROR_OK) {
|
||||
samv_efc_start_command(target, stop_cmd, 0);
|
||||
goto rs_finish;
|
||||
}
|
||||
|
||||
r = samv_efc_wait_status(target, SAMV_EFC_FRS_FRDY_CLR,
|
||||
TIMEOUT_MS_FRS_CHANGE, NULL);
|
||||
if (r != ERROR_OK)
|
||||
goto rs_finish;
|
||||
|
||||
r = target_read_memory(target, addr, sizeof(uint32_t),
|
||||
read_size / sizeof(uint32_t), buf);
|
||||
if (r != ERROR_OK) {
|
||||
LOG_ERROR("flash program failed to read page @ 0x%" PRIx32 "", addr);
|
||||
goto rs_finish;
|
||||
}
|
||||
|
||||
r = samv_efc_start_command(target, stop_cmd, 0);
|
||||
if (r != ERROR_OK)
|
||||
goto rs_finish;
|
||||
|
||||
r = samv_efc_wait_status(target, SAMV_EFC_FSR_FRDY_SET,
|
||||
TIMEOUT_MS_FRS_CHANGE, NULL);
|
||||
if (r != ERROR_OK)
|
||||
goto rs_finish;
|
||||
|
||||
rs_finish:
|
||||
v &= ~SAMV_EFC_FMR_SCOD;
|
||||
samv_efc_set_mode(target, v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_erase_pages(struct target *target,
|
||||
int first_page, int num_pages, uint32_t *status)
|
||||
{
|
||||
@@ -230,6 +337,17 @@ static int samv_set_gpnvm(struct target *target, unsigned int gpnvm)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_erase_user_signature(struct target *target)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = samv_efc_perform_command(target, SAMV_EFC_FCMD_EUS, 0, NULL);
|
||||
if (r != ERROR_OK)
|
||||
LOG_ERROR("error performing user signature write");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_flash_unlock(struct target *target,
|
||||
unsigned int start_sector, unsigned int end_sector)
|
||||
{
|
||||
@@ -306,6 +424,14 @@ static int samv_get_device_id(struct flash_bank *bank, uint32_t *device_id)
|
||||
|
||||
static int samv_probe(struct flash_bank *bank)
|
||||
{
|
||||
if (bank->base == SAMV_FLASH_SIGNATURE_BASE) {
|
||||
bank->size = SAMV_FLASH_SIGNATURE_SIZE;
|
||||
bank->num_sectors = 1;
|
||||
bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector));
|
||||
bank->sectors[0].size = SAMV_FLASH_SIGNATURE_SIZE;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
uint32_t device_id;
|
||||
int r = samv_get_device_id(bank, &device_id);
|
||||
if (r != ERROR_OK)
|
||||
@@ -377,6 +503,9 @@ static int samv_erase(struct flash_bank *bank, unsigned int first,
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
|
||||
if (bank->base == SAMV_FLASH_SIGNATURE_BASE)
|
||||
return samv_erase_user_signature(bank->target);
|
||||
|
||||
/* easy case: we've been requested to erase the entire flash */
|
||||
if ((first == 0) && ((last + 1) == bank->num_sectors))
|
||||
return samv_efc_perform_command(bank->target, SAMV_EFC_FCMD_EA, 0, NULL);
|
||||
@@ -418,45 +547,134 @@ static int samv_protect(struct flash_bank *bank, int set, unsigned int first,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_page_read(struct target *target,
|
||||
static int samv_read_standard_page(struct target *target,
|
||||
unsigned int page_num, uint8_t *buf)
|
||||
{
|
||||
uint32_t addr = SAMV_FLASH_BASE + page_num * SAMV_PAGE_SIZE;
|
||||
int r = target_read_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf);
|
||||
if (r != ERROR_OK)
|
||||
LOG_ERROR("flash program failed to read page @ 0x%08x",
|
||||
(unsigned int)(addr));
|
||||
LOG_ERROR("flash program failed to read page @ 0x%08" PRIx32 "",
|
||||
addr);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_page_write(struct target *target,
|
||||
static int samv_read_user_signature(struct target *target, uint8_t *buf)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = samv_efc_read_sequence(target, SAMV_EFC_FCMD_STUS, SAMV_EFC_FCMD_SPUS,
|
||||
buf, SAMV_PAGE_SIZE);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_page_read(struct target *target,
|
||||
target_addr_t base, unsigned int page_num, uint8_t *buf)
|
||||
{
|
||||
int r;
|
||||
if (base == SAMV_FLASH_SIGNATURE_BASE)
|
||||
r = samv_read_user_signature(target, buf);
|
||||
else
|
||||
r = samv_read_standard_page(target, page_num, buf);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_write_user_signature(struct target *target,
|
||||
unsigned int pagenum, const uint8_t *buf)
|
||||
{
|
||||
const uint32_t addr = SAMV_FLASH_BASE;
|
||||
int r;
|
||||
|
||||
r = target_write_memory(target, addr, sizeof(uint32_t),
|
||||
SAMV_PAGE_SIZE / sizeof(uint32_t), buf);
|
||||
if (r != ERROR_OK) {
|
||||
LOG_ERROR("failed to buffer page at 0x%08" PRIx32 "", addr);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = samv_efc_perform_command(target, SAMV_EFC_FCMD_WUS, 0, NULL);
|
||||
if (r != ERROR_OK)
|
||||
LOG_ERROR("error performing user signature write");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_write_standard_page(struct target *target,
|
||||
unsigned int pagenum, const uint8_t *buf)
|
||||
{
|
||||
uint32_t status;
|
||||
const uint32_t addr = SAMV_FLASH_BASE + pagenum * SAMV_PAGE_SIZE;
|
||||
int r;
|
||||
|
||||
LOG_DEBUG("write page %u at address 0x%08x", pagenum, (unsigned int)addr);
|
||||
LOG_DEBUG("write page %u at address 0x%08" PRIx32 "", pagenum, addr);
|
||||
r = target_write_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf);
|
||||
if (r != ERROR_OK) {
|
||||
LOG_ERROR("failed to buffer page at 0x%08x", (unsigned int)addr);
|
||||
LOG_ERROR("failed to buffer page at 0x%08" PRIx32 "", addr);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = samv_efc_perform_command(target, SAMV_EFC_FCMD_WP, pagenum, &status);
|
||||
if (r != ERROR_OK)
|
||||
LOG_ERROR("error performing write page at 0x%08x", (unsigned int)addr);
|
||||
LOG_ERROR("error performing write page at 0x%08" PRIx32 "", addr);
|
||||
if (status & (1 << 2)) {
|
||||
LOG_ERROR("page at 0x%08x is locked", (unsigned int)addr);
|
||||
LOG_ERROR("page at 0x%08" PRIx32 " is locked", addr);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (status & (1 << 1)) {
|
||||
LOG_ERROR("flash command error at 0x%08x", (unsigned int)addr);
|
||||
LOG_ERROR("flash command error at 0x%08" PRIx32 "", addr);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int samv_page_write(struct target *target,
|
||||
target_addr_t base, unsigned int pagenum, const uint8_t *buf)
|
||||
{
|
||||
int r;
|
||||
if (base == SAMV_FLASH_SIGNATURE_BASE)
|
||||
r = samv_write_user_signature(target, pagenum, buf);
|
||||
else
|
||||
r = samv_write_standard_page(target, pagenum, buf);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int samv_read(struct flash_bank *bank, uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
int r;
|
||||
uint8_t pagebuffer[SAMV_PAGE_SIZE] = {0};
|
||||
struct target *target = bank->target;
|
||||
|
||||
LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32 "", offset, count);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (offset + count > bank->size) {
|
||||
LOG_WARNING("Reads past end of flash. Extra data discarded.");
|
||||
count = bank->size - offset;
|
||||
}
|
||||
|
||||
LOG_DEBUG("offset: 0x%08" PRIx32 ", count: 0x%08" PRIx32 "", offset, count);
|
||||
|
||||
if (bank->base == SAMV_FLASH_SIGNATURE_BASE) {
|
||||
r = samv_read_user_signature(target, pagebuffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
memcpy(buffer, pagebuffer + offset, count);
|
||||
} else {
|
||||
r = target_read_memory(target, offset, 1, count, buffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
@@ -470,10 +688,10 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
|
||||
if ((offset + count) > bank->size) {
|
||||
LOG_ERROR("flash write error - past end of bank");
|
||||
LOG_ERROR(" offset: 0x%08x, count 0x%08x, bank end: 0x%08x",
|
||||
(unsigned int)(offset),
|
||||
(unsigned int)(count),
|
||||
(unsigned int)(bank->size));
|
||||
LOG_ERROR(" offset: 0x%08" PRIx32 ", count 0x%08" PRIx32 ", bank end: 0x%08" PRIx32 "",
|
||||
offset,
|
||||
count,
|
||||
bank->size);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
@@ -481,9 +699,8 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
uint32_t page_cur = offset / SAMV_PAGE_SIZE;
|
||||
uint32_t page_end = (offset + count - 1) / SAMV_PAGE_SIZE;
|
||||
|
||||
LOG_DEBUG("offset: 0x%08x, count: 0x%08x",
|
||||
(unsigned int)(offset), (unsigned int)(count));
|
||||
LOG_DEBUG("page start: %d, page end: %d", (int)(page_cur), (int)(page_end));
|
||||
LOG_DEBUG("offset: 0x%08" PRIx32 ", count: 0x%08" PRIx32 "", offset, count);
|
||||
LOG_DEBUG("page start: %" PRIu32 ", page end: %" PRIu32 "", page_cur, page_end);
|
||||
|
||||
/* Special case: all one page */
|
||||
/* Otherwise: */
|
||||
@@ -497,14 +714,14 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
/* handle special case - all one page. */
|
||||
if (page_cur == page_end) {
|
||||
LOG_DEBUG("special case, all in one page");
|
||||
r = samv_page_read(bank->target, page_cur, pagebuffer);
|
||||
r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
|
||||
page_offset = offset & (SAMV_PAGE_SIZE-1);
|
||||
page_offset = offset & (SAMV_PAGE_SIZE - 1);
|
||||
memcpy(pagebuffer + page_offset, buffer, count);
|
||||
|
||||
r = samv_page_write(bank->target, page_cur, pagebuffer);
|
||||
r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
return ERROR_OK;
|
||||
@@ -515,7 +732,7 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
if (page_offset) {
|
||||
LOG_DEBUG("non-aligned start");
|
||||
/* read the partial page */
|
||||
r = samv_page_read(bank->target, page_cur, pagebuffer);
|
||||
r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
|
||||
@@ -523,11 +740,11 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
uint32_t n = SAMV_PAGE_SIZE - page_offset;
|
||||
memcpy(pagebuffer + page_offset, buffer, n);
|
||||
|
||||
r = samv_page_write(bank->target, page_cur, pagebuffer);
|
||||
r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
|
||||
count -= n;
|
||||
count -= n;
|
||||
offset += n;
|
||||
buffer += n;
|
||||
page_cur++;
|
||||
@@ -537,11 +754,11 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
assert(offset % SAMV_PAGE_SIZE == 0);
|
||||
|
||||
/* step 2) handle the full pages */
|
||||
LOG_DEBUG("full page loop: cur=%d, end=%d, count = 0x%08x",
|
||||
(int)page_cur, (int)page_end, (unsigned int)(count));
|
||||
LOG_DEBUG("full page loop: cur=%" PRIu32 ", end=%" PRIu32 ", count = 0x%08" PRIx32 "",
|
||||
page_cur, page_end, count);
|
||||
|
||||
while ((page_cur < page_end) && (count >= SAMV_PAGE_SIZE)) {
|
||||
r = samv_page_write(bank->target, page_cur, buffer);
|
||||
r = samv_page_write(bank->target, bank->base, page_cur, buffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
count -= SAMV_PAGE_SIZE;
|
||||
@@ -551,13 +768,13 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
|
||||
/* step 3) write final page, if it's partial (otherwise it's already done) */
|
||||
if (count) {
|
||||
LOG_DEBUG("final partial page, count = 0x%08x", (unsigned int)(count));
|
||||
LOG_DEBUG("final partial page, count = 0x%08" PRIx32 "", count);
|
||||
/* we have a partial page */
|
||||
r = samv_page_read(bank->target, page_cur, pagebuffer);
|
||||
r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
memcpy(pagebuffer, buffer, count); /* data goes at start of page */
|
||||
r = samv_page_write(bank->target, page_cur, pagebuffer);
|
||||
r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer);
|
||||
if (r != ERROR_OK)
|
||||
return r;
|
||||
}
|
||||
@@ -691,7 +908,7 @@ const struct flash_driver atsamv_flash = {
|
||||
.erase = samv_erase,
|
||||
.protect = samv_protect,
|
||||
.write = samv_write,
|
||||
.read = default_flash_read,
|
||||
.read = samv_read,
|
||||
.probe = samv_probe,
|
||||
.auto_probe = samv_auto_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
|
||||
Reference in New Issue
Block a user