|
|
|
@ -123,6 +123,19 @@
|
|
|
|
|
/* Mass erase time can be as high as 32 s in x8 mode. */
|
|
|
|
|
#define FLASH_MASS_ERASE_TIMEOUT 33000
|
|
|
|
|
|
|
|
|
|
#define FLASH_BANK_BASE 0x80000000
|
|
|
|
|
|
|
|
|
|
#define STM32F2_OTP_SIZE 512
|
|
|
|
|
#define STM32F2_OTP_SECTOR_SIZE 32
|
|
|
|
|
#define STM32F2_OTP_BANK_BASE 0x1fff7800
|
|
|
|
|
#define STM32F2_OTP_LOCK_BASE ((STM32F2_OTP_BANK_BASE) + (STM32F2_OTP_SIZE))
|
|
|
|
|
|
|
|
|
|
/* see RM0410 section 3.6 "One-time programmable bytes" */
|
|
|
|
|
#define STM32F7_OTP_SECTOR_SIZE 64
|
|
|
|
|
#define STM32F7_OTP_SIZE 1024
|
|
|
|
|
#define STM32F7_OTP_BANK_BASE 0x1ff0f000
|
|
|
|
|
#define STM32F7_OTP_LOCK_BASE ((STM32F7_OTP_BANK_BASE) + (STM32F7_OTP_SIZE))
|
|
|
|
|
|
|
|
|
|
#define STM32_FLASH_BASE 0x40023c00
|
|
|
|
|
#define STM32_FLASH_ACR 0x40023c00
|
|
|
|
|
#define STM32_FLASH_KEYR 0x40023c04
|
|
|
|
@ -185,7 +198,8 @@ struct stm32x_options {
|
|
|
|
|
|
|
|
|
|
struct stm32x_flash_bank {
|
|
|
|
|
struct stm32x_options option_bytes;
|
|
|
|
|
int probed;
|
|
|
|
|
bool probed;
|
|
|
|
|
bool otp_unlocked;
|
|
|
|
|
bool has_large_mem; /* F42x/43x/469/479/7xx in dual bank mode */
|
|
|
|
|
bool has_extra_options; /* F42x/43x/469/479/7xx */
|
|
|
|
|
bool has_boot_addr; /* F7xx */
|
|
|
|
@ -194,6 +208,49 @@ struct stm32x_flash_bank {
|
|
|
|
|
uint32_t user_bank_size;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static bool stm32x_is_otp(struct flash_bank *bank)
|
|
|
|
|
{
|
|
|
|
|
return bank->base == STM32F2_OTP_BANK_BASE ||
|
|
|
|
|
bank->base == STM32F7_OTP_BANK_BASE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool stm32x_otp_is_f7(struct flash_bank *bank)
|
|
|
|
|
{
|
|
|
|
|
return bank->base == STM32F7_OTP_BANK_BASE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int stm32x_is_otp_unlocked(struct flash_bank *bank)
|
|
|
|
|
{
|
|
|
|
|
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
|
|
|
|
|
|
|
|
|
return stm32x_info->otp_unlocked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int stm32x_otp_disable(struct flash_bank *bank)
|
|
|
|
|
{
|
|
|
|
|
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
|
|
|
|
|
|
|
|
|
LOG_INFO("OTP memory bank #%d is disabled for write commands.",
|
|
|
|
|
bank->bank_number);
|
|
|
|
|
stm32x_info->otp_unlocked = false;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int stm32x_otp_enable(struct flash_bank *bank)
|
|
|
|
|
{
|
|
|
|
|
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
|
|
|
|
|
|
|
|
|
if (!stm32x_info->otp_unlocked) {
|
|
|
|
|
LOG_INFO("OTP memory bank #%d is is enabled for write commands.",
|
|
|
|
|
bank->bank_number);
|
|
|
|
|
stm32x_info->otp_unlocked = true;
|
|
|
|
|
} else {
|
|
|
|
|
LOG_WARNING("OTP memory bank #%d is is already enabled for write commands.",
|
|
|
|
|
bank->bank_number);
|
|
|
|
|
}
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* flash bank stm32x <base> <size> 0 0 <target#>
|
|
|
|
|
*/
|
|
|
|
|
FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
|
|
|
|
@ -206,7 +263,8 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
|
|
|
|
|
stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
|
|
|
|
|
bank->driver_priv = stm32x_info;
|
|
|
|
|
|
|
|
|
|
stm32x_info->probed = 0;
|
|
|
|
|
stm32x_info->probed = false;
|
|
|
|
|
stm32x_info->otp_unlocked = false;
|
|
|
|
|
stm32x_info->user_bank_size = bank->size;
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
@ -460,14 +518,67 @@ static int stm32x_write_options(struct flash_bank *bank)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int stm32x_otp_read_protect(struct flash_bank *bank)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = bank->target;
|
|
|
|
|
uint32_t lock_base;
|
|
|
|
|
int i, retval;
|
|
|
|
|
uint8_t lock;
|
|
|
|
|
|
|
|
|
|
lock_base = stm32x_otp_is_f7(bank) ? STM32F7_OTP_LOCK_BASE
|
|
|
|
|
: STM32F2_OTP_LOCK_BASE;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < bank->num_sectors; i++) {
|
|
|
|
|
retval = target_read_u8(target, lock_base + i, &lock);
|
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
|
return retval;
|
|
|
|
|
bank->sectors[i].is_protected = !lock;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int stm32x_otp_protect(struct flash_bank *bank, int first, int last)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = bank->target;
|
|
|
|
|
uint32_t lock_base;
|
|
|
|
|
int i, retval;
|
|
|
|
|
uint8_t lock;
|
|
|
|
|
|
|
|
|
|
assert((0 <= first) && (first <= last) && (last < bank->num_sectors));
|
|
|
|
|
|
|
|
|
|
lock_base = stm32x_otp_is_f7(bank) ? STM32F7_OTP_LOCK_BASE
|
|
|
|
|
: STM32F2_OTP_LOCK_BASE;
|
|
|
|
|
|
|
|
|
|
for (i = first; first <= last; i++) {
|
|
|
|
|
retval = target_read_u8(target, lock_base + i, &lock);
|
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
|
return retval;
|
|
|
|
|
if (lock)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
lock = 0xff;
|
|
|
|
|
retval = target_write_u8(target, lock_base + i, lock);
|
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int stm32x_protect_check(struct flash_bank *bank)
|
|
|
|
|
{
|
|
|
|
|
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
|
|
|
|
struct flash_sector *prot_blocks;
|
|
|
|
|
int num_prot_blocks;
|
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
|
|
/* if it's the OTP bank, look at the lock bits there */
|
|
|
|
|
if (stm32x_is_otp(bank))
|
|
|
|
|
return stm32x_otp_read_protect(bank);
|
|
|
|
|
|
|
|
|
|
/* read write protection settings */
|
|
|
|
|
int retval = stm32x_read_options(bank);
|
|
|
|
|
retval = stm32x_read_options(bank);
|
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
|
LOG_DEBUG("unable to read option bytes");
|
|
|
|
|
return retval;
|
|
|
|
@ -494,6 +605,11 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
|
|
|
|
|
struct target *target = bank->target;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (stm32x_is_otp(bank)) {
|
|
|
|
|
LOG_ERROR("Cannot erase OTP memory");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert((0 <= first) && (first <= last) && (last < bank->num_sectors));
|
|
|
|
|
|
|
|
|
|
if (bank->target->state != TARGET_HALTED) {
|
|
|
|
@ -553,6 +669,13 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
|
|
|
|
|
return ERROR_TARGET_NOT_HALTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stm32x_is_otp(bank)) {
|
|
|
|
|
if (!set)
|
|
|
|
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
|
|
|
|
|
|
|
|
|
return stm32x_otp_protect(bank, first, last);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* read protection settings */
|
|
|
|
|
int retval = stm32x_read_options(bank);
|
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
@ -590,6 +713,11 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
|
|
|
|
#include "../../../contrib/loaders/flash/stm32/stm32f2x.inc"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (stm32x_is_otp(bank) && !stm32x_is_otp_unlocked(bank)) {
|
|
|
|
|
LOG_ERROR("OTP memory bank is disabled for write commands.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
|
|
|
|
|
&write_algorithm) != ERROR_OK) {
|
|
|
|
|
LOG_WARNING("no working area available, can't do block memory writes");
|
|
|
|
@ -774,7 +902,7 @@ static int setup_sector(struct flash_bank *bank, int start, int num, int size)
|
|
|
|
|
bank->sectors[i].offset = bank->size;
|
|
|
|
|
bank->sectors[i].size = size;
|
|
|
|
|
bank->size += bank->sectors[i].size;
|
|
|
|
|
LOG_DEBUG("sector %d: %dkBytes", i, size >> 10);
|
|
|
|
|
LOG_DEBUG("sector %d: %d kBytes", i, size >> 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return start + num;
|
|
|
|
@ -828,15 +956,17 @@ static int stm32x_probe(struct flash_bank *bank)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = bank->target;
|
|
|
|
|
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
|
|
|
|
int i, num_prot_blocks;
|
|
|
|
|
int i, num_prot_blocks, num_sectors;
|
|
|
|
|
uint16_t flash_size_in_kb;
|
|
|
|
|
uint16_t otp_size_in_b;
|
|
|
|
|
uint16_t otp_sector_size;
|
|
|
|
|
uint32_t flash_size_reg = 0x1FFF7A22;
|
|
|
|
|
uint16_t max_sector_size_in_kb = 128;
|
|
|
|
|
uint16_t max_flash_size_in_kb;
|
|
|
|
|
uint32_t device_id;
|
|
|
|
|
uint32_t base_address = 0x08000000;
|
|
|
|
|
|
|
|
|
|
stm32x_info->probed = 0;
|
|
|
|
|
stm32x_info->probed = false;
|
|
|
|
|
stm32x_info->has_large_mem = false;
|
|
|
|
|
stm32x_info->has_boot_addr = false;
|
|
|
|
|
stm32x_info->has_extra_options = false;
|
|
|
|
@ -856,6 +986,40 @@ static int stm32x_probe(struct flash_bank *bank)
|
|
|
|
|
bank->prot_blocks = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if explicitely called out as OTP bank, short circuit probe */
|
|
|
|
|
if (stm32x_is_otp(bank)) {
|
|
|
|
|
if (stm32x_otp_is_f7(bank)) {
|
|
|
|
|
otp_size_in_b = STM32F7_OTP_SIZE;
|
|
|
|
|
otp_sector_size = STM32F7_OTP_SECTOR_SIZE;
|
|
|
|
|
} else {
|
|
|
|
|
otp_size_in_b = STM32F2_OTP_SIZE;
|
|
|
|
|
otp_sector_size = STM32F2_OTP_SECTOR_SIZE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num_sectors = otp_size_in_b / otp_sector_size;
|
|
|
|
|
LOG_INFO("flash size = %d bytes", otp_size_in_b);
|
|
|
|
|
|
|
|
|
|
assert(num_sectors > 0);
|
|
|
|
|
|
|
|
|
|
bank->num_sectors = num_sectors;
|
|
|
|
|
bank->sectors = calloc(sizeof(struct flash_sector), num_sectors);
|
|
|
|
|
|
|
|
|
|
if (stm32x_otp_is_f7(bank))
|
|
|
|
|
bank->size = STM32F7_OTP_SIZE;
|
|
|
|
|
else
|
|
|
|
|
bank->size = STM32F2_OTP_SIZE;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_sectors; i++) {
|
|
|
|
|
bank->sectors[i].offset = i * otp_sector_size;
|
|
|
|
|
bank->sectors[i].size = otp_sector_size;
|
|
|
|
|
bank->sectors[i].is_erased = 1;
|
|
|
|
|
bank->sectors[i].is_protected = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stm32x_info->probed = true;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* read stm32 device id register */
|
|
|
|
|
int retval = stm32x_get_device_id(bank, &device_id);
|
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
@ -945,7 +1109,7 @@ static int stm32x_probe(struct flash_bank *bank)
|
|
|
|
|
flash_size_in_kb = stm32x_info->user_bank_size / 1024;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
|
|
|
|
|
LOG_INFO("flash size = %d kbytes", flash_size_in_kb);
|
|
|
|
|
|
|
|
|
|
/* did we assign flash size? */
|
|
|
|
|
assert(flash_size_in_kb != 0xffff);
|
|
|
|
@ -1040,7 +1204,7 @@ static int stm32x_probe(struct flash_bank *bank)
|
|
|
|
|
bank->num_prot_blocks = num_prot_blocks;
|
|
|
|
|
assert((bank->size >> 10) == flash_size_in_kb);
|
|
|
|
|
|
|
|
|
|
stm32x_info->probed = 1;
|
|
|
|
|
stm32x_info->probed = true;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1483,7 +1647,7 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command)
|
|
|
|
|
|
|
|
|
|
/* switching between single- and dual-bank modes requires re-probe */
|
|
|
|
|
/* ... and reprogramming of whole flash */
|
|
|
|
|
stm32x_info->probed = 0;
|
|
|
|
|
stm32x_info->probed = false;
|
|
|
|
|
|
|
|
|
|
command_print(CMD_CTX, "stm32f2x write options complete.\n"
|
|
|
|
|
"INFO: a reset or power cycle is required "
|
|
|
|
@ -1533,6 +1697,37 @@ COMMAND_HANDLER(stm32f2x_handle_optcr2_write_command)
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(stm32x_handle_otp_command)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC < 2) {
|
|
|
|
|
command_print(CMD_CTX, "stm32x otp <bank> (enable|disable|show)");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct flash_bank *bank;
|
|
|
|
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
|
|
|
|
if (ERROR_OK != retval)
|
|
|
|
|
return retval;
|
|
|
|
|
if (stm32x_is_otp(bank)) {
|
|
|
|
|
if (strcmp(CMD_ARGV[1], "enable") == 0) {
|
|
|
|
|
stm32x_otp_enable(bank);
|
|
|
|
|
} else if (strcmp(CMD_ARGV[1], "disable") == 0) {
|
|
|
|
|
stm32x_otp_disable(bank);
|
|
|
|
|
} else if (strcmp(CMD_ARGV[1], "show") == 0) {
|
|
|
|
|
command_print(CMD_CTX,
|
|
|
|
|
"OTP memory bank #%d is %s for write commands.",
|
|
|
|
|
bank->bank_number,
|
|
|
|
|
stm32x_is_otp_unlocked(bank) ? "enabled" : "disabled");
|
|
|
|
|
} else {
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
command_print(CMD_CTX, "Failed: not an OTP bank.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct command_registration stm32x_exec_command_handlers[] = {
|
|
|
|
|
{
|
|
|
|
|
.name = "lock",
|
|
|
|
@ -1576,7 +1771,13 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
|
|
|
|
|
.usage = "bank_id optcr2",
|
|
|
|
|
.help = "Write optcr2 word",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
.name = "otp",
|
|
|
|
|
.handler = stm32x_handle_otp_command,
|
|
|
|
|
.mode = COMMAND_EXEC,
|
|
|
|
|
.usage = "bank_id",
|
|
|
|
|
.help = "OTP (One Time Programmable) memory write enable/disable.",
|
|
|
|
|
},
|
|
|
|
|
COMMAND_REGISTRATION_DONE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|