+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2015 by Bogdan Kolbov *
* kolbov@niiet.ru *
- * *
- * 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 2 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, write to the *
- * Free Software Foundation, Inc. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#define FCIS_OP_ERROR (1<<1) /* Flag operation error */
/*---- FCIC: CLear status register */
-#define FCIC_CLR_OPCMLT (1<<0) /* Cleare completion flag in register FCIS */
-#define FCIC_CLR_OPERROR (1<<1) /* Cleare error flag in register FCIS */
+#define FCIC_CLR_OPCMLT (1<<0) /* Clear completion flag in register FCIS */
+#define FCIC_CLR_OPERROR (1<<1) /* Clear error flag in register FCIS */
/*-- USERFLASH ---------------------------------------------------------------*/
#define USERFLASH_PAGE_SIZE 256
#define UFCIS_OP_ERROR (1<<1) /* Flag operation error */
/*---- UFCIC: CLear status register */
-#define UFCIC_CLR_OPCMLT (1<<0) /* Cleared completion flag in register FCIS */
-#define UFCIC_CLR_OPERROR (1<<1) /* Cleared error flag in register FCIS */
+#define UFCIC_CLR_OPCMLT (1<<0) /* Clear completion flag in register FCIS */
+#define UFCIC_CLR_OPERROR (1<<1) /* Clear error flag in register FCIS */
/*---- In info userflash address space */
#define INFOWORD0_ADDR 0x00
{
struct target *target = bank->target;
int retval;
- int timeout = 100;
+ int timeout = 5000;
uint32_t flash_status;
retval = target_read_u32(target, FCIS, &flash_status);
{
struct target *target = bank->target;
int retval;
- int timeout = 100;
+ int timeout = 5000;
uint32_t uflash_status;
retval = target_read_u32(target, UFCIS, &uflash_status);
static int niietcm4_dump_uflash_page(struct flash_bank *bank, uint32_t *dump, int page_num, int mem_type)
{
struct target *target = bank->target;
- int i, retval;
+ int i;
+ int retval = ERROR_OK;
uint32_t uflash_cmd;
if (mem_type == INFO_MEM_TYPE)
static int niietcm4_load_uflash_page(struct flash_bank *bank, uint32_t *dump, int page_num, int mem_type)
{
struct target *target = bank->target;
- int i, retval;
+ int i;
+ int retval = ERROR_OK;
uint32_t uflash_cmd;
if (mem_type == INFO_MEM_TYPE)
/**
* Enable or disable protection of userflash pages
*/
-static int niietcm4_uflash_protect(struct flash_bank *bank, int mem_type, int set, int first, int last)
+static int niietcm4_uflash_protect(struct flash_bank *bank, int mem_type,
+ int set, unsigned int first, unsigned int last)
{
int retval;
if (mem_type == INFO_MEM_TYPE) {
if (retval != ERROR_OK)
return retval;
/* modify dump */
- for (int i = first; i <= last; i++) {
+ for (unsigned int i = first; i <= last; i++) {
uint32_t reg_num = i/8;
uint32_t bit_num = i%8;
if (set)
else
return ERROR_COMMAND_SYNTAX_ERROR;
- COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], uflash_addr);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], uflash_addr);
retval = target_write_u32(target, UFMA, uflash_addr);
if (retval != ERROR_OK)
retval = target_read_u32(target, UFMD, &uflash_data);
if (retval != ERROR_OK)
return retval;
- command_print(CMD_CTX, "Read userflash %s region:\n"
- "address = 0x%04x,\n"
- "value = 0x%02x.", CMD_ARGV[0], uflash_addr, uflash_data);
+ command_print(CMD, "Read userflash %s region:\n"
+ "address = 0x%04" PRIx32 ",\n"
+ "value = 0x%02" PRIx32 ".", CMD_ARGV[0], uflash_addr, uflash_data);
return retval;
}
else
return ERROR_COMMAND_SYNTAX_ERROR;
- COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], uflash_addr);
- COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], uflash_data);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], uflash_addr);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], uflash_data);
int page_num = uflash_addr/USERFLASH_PAGE_SIZE;
- command_print(CMD_CTX, "Write userflash %s region:\n"
- "address = 0x%04x,\n"
- "value = 0x%02x.\n"
- "Please wait ... ", CMD_ARGV[0], uflash_addr, uflash_data);
+ command_print(CMD, "Write userflash %s region:\n"
+ "address = 0x%04" PRIx32 ",\n"
+ "value = 0x%02" PRIx32 ".\n"
+ "Please wait ... ", CMD_ARGV[0], uflash_addr, uflash_data);
/* dump */
uint32_t uflash_dump[USERFLASH_PAGE_SIZE];
niietcm4_dump_uflash_page(bank, uflash_dump, page_num, mem_type);
/* write dump to userflash */
niietcm4_load_uflash_page(bank, uflash_dump, page_num, mem_type);
- command_print(CMD_CTX, "done!");
+ command_print(CMD, "done!");
return retval;
}
retval = niietcm4_uopstatus_check(bank);
if (retval != ERROR_OK)
return retval;
- command_print(CMD_CTX, "Userflash full erase done!");
+ command_print(CMD, "Userflash full erase done!");
return retval;
}
return retval;
}
- command_print(CMD_CTX, "Erase %s userflash pages %d through %d done!", CMD_ARGV[0], first, last);
+ command_print(CMD, "Erase %s userflash pages %u through %u done!", CMD_ARGV[0], first, last);
return retval;
}
return retval;
if (uflash_data & INFOWORD3_LOCK_IFB_UF)
- command_print(CMD_CTX, "All sectors of info userflash are not protected!");
+ command_print(CMD, "All sectors of info userflash are not protected!");
else
- command_print(CMD_CTX, "All sectors of info userflash are protected!");
+ command_print(CMD, "All sectors of info userflash are protected!");
} else {
uflash_addr = UF_LOCK_ADDR;
uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB;
for (j = 0; j < 8; j++) {
if (uflash_data & 0x1)
- command_print(CMD_CTX, "Userflash sector #%03d: 0x%04x (0x100) is not protected!",
+ command_print(CMD, "Userflash sector #%03d: 0x%04x (0x100) is not protected!",
i*8+j, (i*8+j)*USERFLASH_PAGE_SIZE);
else
- command_print(CMD_CTX, "Userflash sector #%03d: 0x%04x (0x100) is protected!",
+ command_print(CMD, "Userflash sector #%03d: 0x%04x (0x100) is protected!",
i*8+j, (i*8+j)*USERFLASH_PAGE_SIZE);
uflash_data = uflash_data >> 1;
}
int set;
if (strcmp("on", CMD_ARGV[3]) == 0) {
- command_print(CMD_CTX, "Try to enable %s userflash sectors %d through %d protection. Please wait ... ",
+ command_print(CMD, "Try to enable %s userflash sectors %u through %u protection. Please wait ... ",
CMD_ARGV[0], first, last);
set = 1;
} else if (strcmp("off", CMD_ARGV[3]) == 0) {
- command_print(CMD_CTX, "Try to disable %s userflash sectors %d through %d protection. Please wait ... ",
+ command_print(CMD, "Try to disable %s userflash sectors %u through %u protection. Please wait ... ",
CMD_ARGV[0], first, last);
set = 0;
} else
if (retval != ERROR_OK)
return retval;
- command_print(CMD_CTX, "done!");
+ command_print(CMD, "done!");
return retval;
}
int set;
if (strcmp("on", CMD_ARGV[0]) == 0) {
- command_print(CMD_CTX, "Try to enable bootflash info region remap. Please wait ...");
+ command_print(CMD, "Try to enable bootflash info region remap. Please wait ...");
set = 1;
} else if (strcmp("off", CMD_ARGV[0]) == 0) {
- command_print(CMD_CTX, "Try to disable bootflash info region remap. Please wait ...");
+ command_print(CMD, "Try to disable bootflash info region remap. Please wait ...");
set = 0;
} else
return ERROR_COMMAND_SYNTAX_ERROR;
/* write dump to userflash */
niietcm4_load_uflash_page(bank, uflash_dump, 0, 1);
- command_print(CMD_CTX, "done!");
+ command_print(CMD, "done!");
return retval;
}
return ERROR_COMMAND_SYNTAX_ERROR;
uint32_t pin;
- COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], pin);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pin);
if (pin > 15)
return ERROR_COMMAND_SYNTAX_ERROR;
else
return ERROR_COMMAND_SYNTAX_ERROR;
- command_print(CMD_CTX, "Try to configure external memory boot interface:\n"
- "port = %s\n"
- "pin = %s\n"
- "func = %s\n"
- "Please wait ...", CMD_ARGV[0], CMD_ARGV[1], CMD_ARGV[2]);
+ command_print(CMD, "Try to configure external memory boot interface:\n"
+ "port = %s\n"
+ "pin = %s\n"
+ "func = %s\n"
+ "Please wait ...", CMD_ARGV[0], CMD_ARGV[1], CMD_ARGV[2]);
/* dump */
uint32_t uflash_dump[USERFLASH_PAGE_SIZE];
niietcm4_dump_uflash_page(bank, uflash_dump, 0, 1);
/* write dump to userflash */
niietcm4_load_uflash_page(bank, uflash_dump, 0, 1);
- command_print(CMD_CTX, "done!");
+ command_print(CMD, "done!");
return retval;
}
int set;
if (strcmp("on", CMD_ARGV[0]) == 0) {
- command_print(CMD_CTX, "Try to enable boot from external memory. Please wait ...");
+ command_print(CMD, "Try to enable boot from external memory. Please wait ...");
set = 1;
} else if (strcmp("off", CMD_ARGV[0]) == 0) {
- command_print(CMD_CTX, "Try to disable boot from external memory. Please wait ...");
+ command_print(CMD, "Try to disable boot from external memory. Please wait ...");
set = 0;
} else
return ERROR_COMMAND_SYNTAX_ERROR;
/* write dump to userflash */
niietcm4_load_uflash_page(bank, uflash_dump, 0, 1);
- command_print(CMD_CTX, "done!");
+ command_print(CMD, "done!");
return retval;
}
return retval;
struct target *target = bank->target;
- command_print(CMD_CTX, "Try to perform service mode erase. Please wait ...");
+ command_print(CMD, "Try to perform service mode erase. Please wait ...");
retval = target_write_u32(target, SERVICE_MODE_ERASE_ADDR, 1);
if (retval != ERROR_OK)
}
busy_sleep(1); /* can use busy sleep for short times. */
}
- command_print(CMD_CTX, "done! All data erased.");
+ command_print(CMD, "done! All data erased.");
return retval;
}
if (retval != ERROR_OK)
return retval;
- command_print(CMD_CTX, "niietcm4 flash driver\n"
+ command_print(CMD, "niietcm4 flash driver\n"
"version: %d.%d\n"
"author: Bogdan Kolbov\n"
"mail: kolbov@niiet.ru",
{
struct niietcm4_flash_bank *niietcm4_info;
- if (CMD_ARGC < 7)
+ if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
niietcm4_info = malloc(sizeof(struct niietcm4_flash_bank));
} else {
uflash_addr = BF_LOCK_ADDR;
uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB;
- for (int i = 0; i < bank->num_sectors/8; i++) {
+ for (unsigned int i = 0; i < bank->num_sectors/8; i++) {
retval = target_write_u32(target, UFMA, uflash_addr);
if (retval != ERROR_OK)
return retval;
return retval;
}
-static int niietcm4_erase(struct flash_bank *bank, int first, int last)
+static int niietcm4_erase(struct flash_bank *bank, unsigned int first,
+ unsigned int last)
{
struct target *target = bank->target;
struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv;
/* erasing pages */
unsigned int page_size = bank->size / bank->num_sectors;
- for (int i = first; i <= last; i++) {
+ for (unsigned int i = first; i <= last; i++) {
/* current page addr */
flash_addr = i*page_size;
retval = target_write_u32(target, FMA, flash_addr);
retval = niietcm4_opstatus_check(bank);
if (retval != ERROR_OK)
return retval;
-
- bank->sectors[i].is_erased = 1;
}
return retval;
}
-static int niietcm4_protect(struct flash_bank *bank, int set, int first, int last)
+static int niietcm4_protect(struct flash_bank *bank, int set,
+ unsigned int first, unsigned int last)
{
struct target *target = bank->target;
struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv;
return ERROR_TARGET_NOT_HALTED;
}
- LOG_INFO("Plese wait ..."); /* it`s quite a long process */
+ LOG_INFO("Please wait ..."); /* it`s quite a long process */
/* chose between main bootflash and info bootflash */
if (niietcm4_info->bflash_info_remap) {
/* dump */
if (retval != ERROR_OK)
return retval;
/* modify dump */
- for (int i = first; i <= last; i++) {
+ for (unsigned int i = first; i <= last; i++) {
uint32_t reg_num = i/8;
uint32_t bit_num = i%8;
if (set)
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- };
+ }
retval = target_write_buffer(target, write_algorithm->address,
sizeof(niietcm4_flash_write_code), niietcm4_flash_write_code);
LOG_WARNING("no large enough working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
- };
+ }
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* write_cmd base (in), status (out) */
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (128bit) */
{
struct target *target = bank->target;
struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv;
+ uint8_t *new_buffer = NULL;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- if (offset & 0x3) {
- LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte alignment", offset);
+ if (offset & 0xF) {
+ LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-word alignment", offset);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
+ /* If there's an odd number of words, the data has to be padded. Duplicate
+ * the buffer and use the normal code path with a single block write since
+ * it's probably cheaper than to special case the last odd write using
+ * discrete accesses. */
+
+ int rem = count % 16;
+ if (rem) {
+ new_buffer = malloc(count + 16 - rem);
+ if (!new_buffer) {
+ LOG_ERROR("Odd number of words to write and no memory for padding buffer");
+ return ERROR_FAIL;
+ }
+ LOG_INFO("Odd number of words to write, padding with 0xFFFFFFFF");
+ buffer = memcpy(new_buffer, buffer, count);
+ while (rem < 16) {
+ new_buffer[count++] = 0xff;
+ rem++;
+ }
+ }
+
int retval;
/* try using block write */
/* if block write failed (no sufficient working area),
* we use normal (slow) single halfword accesses */
LOG_WARNING("Can't use block writes, falling back to single memory accesses");
- LOG_INFO("Plese wait ..."); /* it`s quite a long process */
+ LOG_INFO("Please wait ..."); /* it`s quite a long process */
/* chose between main bootflash and info bootflash */
if (niietcm4_info->bflash_info_remap)
/* write 16 bytes per try */
for (unsigned int i = 0; i < count; i += 16) {
/* current addr */
- LOG_INFO("%d byte of %d", i, count);
+ LOG_INFO("%u byte of %" PRIu32, i, count);
flash_addr = offset + i;
retval = target_write_u32(target, FMA, flash_addr);
if (retval != ERROR_OK)
- return retval;
+ goto free_buffer;
- /* if there's an odd number of bytes, the data has to be padded */
- uint8_t padding[16] = { 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff};
- memcpy(padding, buffer + i, MIN(16, count-i));
+ /* Prepare data (4 words) */
+ uint32_t value[4];
+ memcpy(&value, buffer + i*16, 4*sizeof(uint32_t));
/* place in reg 16 bytes of data */
- flash_data = (padding[3]<<24) | (padding[2]<<16) | (padding[1]<<8) | padding[0];
+ flash_data = value[0];
retval = target_write_u32(target, FMD1, flash_data);
if (retval != ERROR_OK)
- return retval;
- flash_data = (padding[7]<<24) | (padding[6]<<16) | (padding[5]<<8) | padding[4];
+ goto free_buffer;
+ flash_data = value[1];
retval = target_write_u32(target, FMD2, flash_data);
if (retval != ERROR_OK)
- return retval;
- flash_data = (padding[11]<<24) | (padding[10]<<16) | (padding[9]<<8) | padding[8];
+ goto free_buffer;
+ flash_data = value[2];
retval = target_write_u32(target, FMD3, flash_data);
if (retval != ERROR_OK)
- return retval;
- flash_data = (padding[15]<<24) | (padding[14]<<16) | (padding[13]<<8) | padding[12];
+ goto free_buffer;
+ flash_data = value[3];
retval = target_write_u32(target, FMD4, flash_data);
if (retval != ERROR_OK)
- return retval;
+ goto free_buffer;
/* write start */
retval = target_write_u32(target, FMC, flash_cmd);
if (retval != ERROR_OK)
- return retval;
+ goto free_buffer;
/* status check */
retval = niietcm4_opstatus_check(bank);
if (retval != ERROR_OK)
- return retval;
+ goto free_buffer;
}
}
+free_buffer:
+ free(new_buffer);
return retval;
}
char info_bootflash_addr_str[64];
if (niietcm4_info->bflash_info_remap)
- snprintf(info_bootflash_addr_str, sizeof(info_bootflash_addr_str), "0x%08x base adress", bank->base);
+ snprintf(info_bootflash_addr_str, sizeof(info_bootflash_addr_str),
+ TARGET_ADDR_FMT " base address", bank->base);
else
- snprintf(info_bootflash_addr_str, sizeof(info_bootflash_addr_str), "not maped to global adress space");
+ snprintf(info_bootflash_addr_str, sizeof(info_bootflash_addr_str),
+ "not mapped to global address space");
snprintf(niietcm4_info->chip_brief,
sizeof(niietcm4_info->chip_brief),
"\n"
"MEMORY CONFIGURATION\n"
"Bootflash :\n"
- " %d kB total\n"
- " %d pages %d kB each\n"
- " 0x%08x base adress\n"
+ " %" PRIu32 " kB total\n"
+ " %" PRIu32 " pages %" PRIu32 " kB each\n"
+ " 0x%08" PRIx32 " base address\n"
"%s"
"Info bootflash :\n"
- " %d kB total\n"
- " %d pages %d kB each\n"
+ " %" PRIu32 " kB total\n"
+ " %" PRIu32 " pages %" PRIu32 " kB each\n"
" %s\n"
"%s"
"Userflash :\n"
- " %d kB total\n"
- " %d pages %d B each\n"
- " %d bit cells\n"
- " not maped to global adress space\n"
+ " %" PRIu32 " kB total\n"
+ " %" PRIu32 " pages %" PRIu32 " B each\n"
+ " %" PRIu32 " bit cells\n"
+ " not mapped to global address space\n"
"Info userflash :\n"
- " %d B total\n"
- " %d pages of %d B each\n"
- " %d bit cells\n"
- " not maped to global adress space\n"
+ " %" PRIu32 " B total\n"
+ " %" PRIu32 " pages of %" PRIu32 " B each\n"
+ " %" PRIu32 " bit cells\n"
+ " not mapped to global address space\n"
"RAM :\n"
" 192 kB total\n"
- " 0x20000000 base adress\n"
+ " 0x20000000 base address\n"
"External memory :\n"
" 8/16 bit address space\n"
- " 0x%08x base adress\n"
+ " 0x%08" PRIx32 " base address\n"
"\n"
"INFOWORD STATUS\n"
"Bootflash info region remap :\n"
"External memory boot port :\n"
" %s\n"
"External memory boot pin :\n"
- " %d\n"
+ " %" PRIu32 "\n"
"External memory interface alternative function :\n"
- " %d\n"
+ " %" PRIu32 "\n"
"Option boot from external memory :\n"
" %s\n",
bflash_size/1024,
niietcm4_info->extmem_boot_pin,
niietcm4_info->extmem_boot_altfunc,
niietcm4_info->extmem_boot ? "enable" : "disable");
- } else{
+ } else {
bank->size = 0x100000;
bank->num_sectors = 128;
struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv;
struct target *target = bank->target;
- if (bank->sectors) {
- free(bank->sectors);
- bank->sectors = NULL;
- }
+ free(bank->sectors);
+ bank->sectors = NULL;
+
uint32_t retval;
uint32_t chipid;
return niietcm4_probe(bank);
}
-static int get_niietcm4_info(struct flash_bank *bank, char *buf, int buf_size)
+static int get_niietcm4_info(struct flash_bank *bank, struct command_invocation *cmd)
{
struct niietcm4_flash_bank *niietcm4_info = bank->driver_priv;
- LOG_INFO("\nNIIET Cortex M4F %s\n%s", niietcm4_info->chip_name, niietcm4_info->chip_brief);
- snprintf(buf, buf_size, " ");
-
+ command_print_sameline(cmd, "\nNIIET Cortex-M4F %s\n%s",
+ niietcm4_info->chip_name, niietcm4_info->chip_brief);
return ERROR_OK;
}
-struct flash_driver niietcm4_flash = {
+const struct flash_driver niietcm4_flash = {
.name = "niietcm4",
.usage = "flash bank <name> niietcm4 <base> <size> 0 0 <target#>",
.commands = niietcm4_command_handlers,
.erase_check = default_flash_blank_check,
.protect_check = niietcm4_protect_check,
.info = get_niietcm4_info,
+ .free_driver_priv = default_flash_free_driver_priv,
};