@@ -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
};