This is an automated email from Gerrit. "Michal Lenc <michall...@seznam.cz>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8302
-- gerrit commit 10904dec8b59995e1fdfb02e0fe88f1f9a2e8705 Author: Michal Lenc <michall...@seznam.cz> Date: Fri May 31 11:27:38 2024 +0200 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 clear and write this area from OpenOCD. Change-Id: If870aa85938b9cccd94f958dd1f3d93dbdf779f0 Signed-off-by: Michal Lenc <michall...@seznam.cz> diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index 24c432cba3..6d812eb827 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -23,6 +23,7 @@ #endif #include "imp.h" +#include <helper/configuration.h> #include <helper/time_support.h> #define REG_NAME_WIDTH (12) @@ -40,6 +41,10 @@ #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_STU (0x14) /* (EFC) Start Read User Signature */ +#define SAMV_EFC_FCMD_SPUS (0x15) /* (EFC) Stop Read User Signature */ #define OFFSET_EFC_FMR 0 #define OFFSET_EFC_FCR 4 @@ -230,6 +235,50 @@ static int samv_set_gpnvm(struct target *target, unsigned 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_set_user_signature(struct target *target, + const uint8_t *buffer, ssize_t size) +{ + const uint32_t addr = SAMV_FLASH_BASE; + int r; + + if (size > SAMV_PAGE_SIZE) + return ERROR_FAIL; + + /* We need to erase user signature before writing it. This is not described + * in the datasheet, but the results are not correct unless erase is done + * prior to write operation. + */ + r = samv_erase_user_signature(target); + if (r != ERROR_OK) { + LOG_ERROR("error performing user signature erase"); + return r; + } + + ssize_t write_size = (size + sizeof(uint32_t) - 1) / sizeof(uint32_t); + r = target_write_memory(target, addr, sizeof(uint32_t), write_size, buffer); + if (r != ERROR_OK) { + LOG_ERROR("failed to buffer page at 0x%08x", (unsigned int)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_flash_unlock(struct target *target, unsigned start_sector, unsigned end_sector) { @@ -660,6 +709,64 @@ showall: return r; } +COMMAND_HANDLER(samv_handle_user_signature_command) +{ + struct flash_bank *bank = get_flash_bank_by_num_noprobe(0); + if (!bank) + return ERROR_FAIL; + struct samv_flash_bank *samv_info = bank->driver_priv; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + FILE *fp; + ssize_t retval; + uint8_t buffer[SAMV_PAGE_SIZE]; + int r; + if (!samv_info->probed) { + r = samv_auto_probe(bank); + if (r != ERROR_OK) + return r; + } + + switch (CMD_ARGC) { + case 0: + command_print(CMD, "[('clr'|'set [filename]')]"); + break; + case 1: + if (!strcmp(CMD_ARGV[0], "clr")) { + samv_erase_user_signature(target); + } else { + command_print(CMD, "[('clr'|'set [filename]')]"); + } + break; + case 2: + if (!strcmp(CMD_ARGV[0], "set")) { + fp = open_file_from_path(CMD_ARGV[1], "r"); + if (fp == NULL) { + r = ERROR_FAIL; + break; + } + retval = fread(buffer, 1, SAMV_PAGE_SIZE, fp); + if (retval < 0) { + r = ERROR_FAIL; + break; + } + + r = samv_set_user_signature(target, buffer, retval); + } else { + command_print(CMD, "[('clr'|'set [filename]')]"); + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + return r; +} + static const struct command_registration atsamv_exec_command_handlers[] = { { .name = "gpnvm", @@ -670,6 +777,16 @@ static const struct command_registration atsamv_exec_command_handlers[] = { "register. Otherwise, clears, sets, or shows one " "General Purpose Non-Volatile Memory (gpnvm) bit.", }, + { + .name = "user_signature", + .handler = samv_handle_user_signature_command, + .mode = COMMAND_EXEC, + .usage = "[('clr'|'set [filename]')]", + .help = "Performs writes and erases on user signature partition." + "Write is performed by argument set and binary file defined in" + "filename parameter. It is possible to write up to 512 bytes" + "to user signature area. Entire area is erased prior to write.", + }, COMMAND_REGISTRATION_DONE }; --