};
struct stm32lx_flash_bank {
- int probed;
+ bool probed;
uint32_t idcode;
uint32_t user_bank_size;
uint32_t flash_base;
{ 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" },
};
static const struct stm32lx_rev stm32_427_revs[] = {
- { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" },
+ { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" },
};
static const struct stm32lx_rev stm32_429_revs[] = {
{ 0x1000, "A" }, { 0x1018, "Z" },
stm32lx_info = calloc(1, sizeof(*stm32lx_info));
/* Check allocation */
- if (stm32lx_info == NULL) {
+ if (!stm32lx_info) {
LOG_ERROR("failed to allocate bank structure");
return ERROR_FAIL;
}
bank->driver_priv = stm32lx_info;
- stm32lx_info->probed = 0;
+ stm32lx_info->probed = false;
stm32lx_info->user_bank_size = bank->size;
/* the stm32l erased value is 0x00 */
COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
{
- int i;
-
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
- if (ERROR_OK != retval)
+ if (retval != ERROR_OK)
return retval;
retval = stm32lx_mass_erase(bank);
- if (retval == ERROR_OK) {
- /* set all sectors as erased */
- for (i = 0; i < bank->num_sectors; i++)
- bank->sectors[i].is_erased = 1;
-
- command_print(CMD_CTX, "stm32lx mass erase complete");
- } else {
- command_print(CMD_CTX, "stm32lx mass erase failed");
- }
+ if (retval == ERROR_OK)
+ command_print(CMD, "stm32lx mass erase complete");
+ else
+ command_print(CMD, "stm32lx mass erase failed");
return retval;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
- if (ERROR_OK != retval)
+ if (retval != ERROR_OK)
return retval;
retval = stm32lx_lock(bank);
if (retval == ERROR_OK)
- command_print(CMD_CTX, "STM32Lx locked, takes effect after power cycle.");
+ command_print(CMD, "STM32Lx locked, takes effect after power cycle.");
else
- command_print(CMD_CTX, "STM32Lx lock failed");
+ command_print(CMD, "STM32Lx lock failed");
return retval;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
- if (ERROR_OK != retval)
+ if (retval != ERROR_OK)
return retval;
retval = stm32lx_unlock(bank);
if (retval == ERROR_OK)
- command_print(CMD_CTX, "STM32Lx unlocked, takes effect after power cycle.");
+ command_print(CMD, "STM32Lx unlocked, takes effect after power cycle.");
else
- command_print(CMD_CTX, "STM32Lx unlock failed");
+ command_print(CMD, "STM32Lx unlock failed");
return retval;
}
if (retval != ERROR_OK)
return retval;
- for (int i = 0; i < bank->num_sectors; i++) {
+ for (unsigned int i = 0; i < bank->num_sectors; i++) {
if (wrpr & (1 << i))
bank->sectors[i].is_protected = 1;
else
return ERROR_OK;
}
-static int stm32lx_erase(struct flash_bank *bank, int first, int last)
+static int stm32lx_erase(struct flash_bank *bank, unsigned int first,
+ unsigned int last)
{
int retval;
/*
* Loop over the selected sectors and erase them
*/
- for (int i = first; i <= last; i++) {
+ for (unsigned int i = first; i <= last; i++) {
retval = stm32lx_erase_sector(bank, i);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
-static int stm32lx_protect(struct flash_bank *bank, int set, int first,
- int last)
-{
- LOG_WARNING("protection of the STM32L flash is not implemented");
- return ERROR_OK;
-}
-
static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
uint32_t hp_nb = stm32lx_info->part_info.page_size / 2;
- uint32_t buffer_size = 16384;
+ uint32_t buffer_size = (16384 / hp_nb) * hp_nb; /* must be multiple of hp_nb */
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
- struct reg_param reg_params[3];
+ struct reg_param reg_params[5];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
- /* see contib/loaders/flash/stm32lx.S for src */
-
static const uint8_t stm32lx_flash_write_code[] = {
- 0x92, 0x00, 0x8A, 0x18, 0x01, 0xE0, 0x08, 0xC9, 0x08, 0xC0, 0x91, 0x42, 0xFB, 0xD1, 0x00, 0xBE
+#include "../../../contrib/loaders/flash/stm32/stm32lx.inc"
};
/* Make sure we're performing a half-page aligned write. */
+ if (offset % hp_nb) {
+ LOG_ERROR("The offset must be %" PRIu32 "B-aligned but it is %" PRIi32 "B)", hp_nb, offset);
+ return ERROR_FAIL;
+ }
if (count % hp_nb) {
- LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIi32 "B)", hp_nb, count);
+ LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIu32 "B)", hp_nb, count);
return ERROR_FAIL;
}
LOG_WARNING("no large enough working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ } else {
+ /* Make sure we're still asking for an integral number of half-pages */
+ buffer_size -= buffer_size % hp_nb;
}
}
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
+ init_reg_param(®_params[4], "r4", 32, PARAM_OUT);
/* Enable half-page write */
retval = stm32lx_enable_write_half_page(bank);
destroy_reg_param(®_params[0]);
destroy_reg_param(®_params[1]);
destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
return retval;
}
struct armv7m_common *armv7m = target_to_armv7m(target);
- if (armv7m == NULL) {
+ if (!armv7m) {
/* something is very wrong if armv7m is NULL */
LOG_ERROR("unable to get armv7m target");
buf_set_u32(reg_params[0].value, 0, 32, address);
/* The source address of the copy (R1) */
buf_set_u32(reg_params[1].value, 0, 32, source->address);
- /* The length of the copy (R2) */
- buf_set_u32(reg_params[2].value, 0, 32, this_count / 4);
+ /* The number of half pages to copy (R2) */
+ buf_set_u32(reg_params[2].value, 0, 32, this_count / hp_nb);
+ /* The size in byes of a half page (R3) */
+ buf_set_u32(reg_params[3].value, 0, 32, hp_nb);
+ /* The flash base address (R4) */
+ buf_set_u32(reg_params[4].value, 0, 32, stm32lx_info->flash_base);
/* 5: Execute the bunch of code */
- retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params)
- / sizeof(*reg_params), reg_params,
+ retval = target_run_algorithm(target, 0, NULL,
+ ARRAY_SIZE(reg_params), reg_params,
write_algorithm->address, 0, 10000, &armv7m_info);
if (retval != ERROR_OK)
break;
destroy_reg_param(®_params[0]);
destroy_reg_param(®_params[1]);
destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
return retval;
}
if (retval != ERROR_OK)
return retval;
- /* first we need to write any unaligned head bytes upto
+ /* first we need to write any unaligned head bytes up to
* the next 128 byte page */
if (offset % hp_nb)
static int stm32lx_read_id_code(struct target *target, uint32_t *id)
{
- /* read stm32 device id register */
- int retval = target_read_u32(target, DBGMCU_IDCODE, id);
- if (retval != ERROR_OK)
- return retval;
-
- /* STM32L0 parts will have 0 there, try reading the L0's location for
- * DBG_IDCODE in case this is an L0 part. */
- if (*id == 0)
+ struct armv7m_common *armv7m = target_to_armv7m(target);
+ int retval;
+ if (armv7m->arm.arch == ARM_ARCH_V6M)
retval = target_read_u32(target, DBGMCU_IDCODE_L0, id);
-
+ else
+ /* read stm32 device id register */
+ retval = target_read_u32(target, DBGMCU_IDCODE, id);
return retval;
}
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
- int i;
uint16_t flash_size_in_kb;
uint32_t device_id;
uint32_t base_address = FLASH_BANK0_ADDRESS;
uint32_t second_bank_base;
unsigned int n;
- stm32lx_info->probed = 0;
+ stm32lx_info->probed = false;
int retval = stm32lx_read_id_code(bank->target, &device_id);
if (retval != ERROR_OK)
}
if (n == ARRAY_SIZE(stm32lx_parts)) {
- LOG_WARNING("Cannot identify target as a STM32L family.");
+ LOG_ERROR("Cannot identify target as an STM32 L0 or L1 family device.");
return ERROR_FAIL;
} else {
LOG_INFO("Device: %s", stm32lx_info->part_info.device_str);
flash_size_in_kb = 256;
}
+ /* 0x429 devices only use the lowest 8 bits of the flash size register */
+ if (retval == ERROR_OK && (device_id & 0xfff) == 0x429) {
+ flash_size_in_kb &= 0xff;
+ }
+
/* Failed reading flash size or flash size invalid (early silicon),
* default to max target family */
if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
/* This is the first bank */
flash_size_in_kb = stm32lx_info->part_info.first_bank_size_kb;
} else {
- LOG_WARNING("STM32L flash bank base address config is incorrect."
- " 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32,
+ LOG_WARNING("STM32L flash bank base address config is incorrect. "
+ TARGET_ADDR_FMT " but should rather be 0x%" PRIx32
+ " or 0x%" PRIx32,
bank->base, base_address, second_bank_base);
return ERROR_FAIL;
}
- LOG_INFO("STM32L flash has dual banks. Bank (%d) size is %dkb, base address is 0x%" PRIx32,
+ LOG_INFO("STM32L flash has dual banks. Bank (%u) size is %dkb, base address is 0x%" PRIx32,
bank->bank_number, flash_size_in_kb, base_address);
} else {
LOG_INFO("STM32L flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address);
}
/* calculate numbers of sectors (4kB per sector) */
- int num_sectors = (flash_size_in_kb * 1024) / FLASH_SECTOR_SIZE;
+ unsigned int num_sectors = (flash_size_in_kb * 1024) / FLASH_SECTOR_SIZE;
- if (bank->sectors) {
- free(bank->sectors);
- bank->sectors = NULL;
- }
+ free(bank->sectors);
bank->size = flash_size_in_kb * 1024;
bank->base = base_address;
bank->num_sectors = num_sectors;
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
- if (bank->sectors == NULL) {
+ if (!bank->sectors) {
LOG_ERROR("failed to allocate bank sectors");
return ERROR_FAIL;
}
- for (i = 0; i < num_sectors; i++) {
+ for (unsigned int i = 0; i < num_sectors; i++) {
bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
bank->sectors[i].size = FLASH_SECTOR_SIZE;
bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = 1;
+ bank->sectors[i].is_protected = -1;
}
- stm32lx_info->probed = 1;
+ stm32lx_info->probed = true;
return ERROR_OK;
}
}
/* This method must return a string displaying information about the bank */
-static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size)
+static int stm32lx_get_info(struct flash_bank *bank, struct command_invocation *cmd)
{
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
const struct stm32lx_part_info *info = &stm32lx_info->part_info;
if (!stm32lx_info->probed) {
int retval = stm32lx_probe(bank);
if (retval != ERROR_OK) {
- snprintf(buf, buf_size,
- "Unable to find bank information.");
+ command_print_sameline(cmd, "Unable to find bank information.");
return retval;
}
}
if (rev_id == info->revs[i].rev)
rev_str = info->revs[i].str;
- if (rev_str != NULL) {
- snprintf(buf, buf_size,
- "%s - Rev: %s",
- info->device_str, rev_str);
+ if (rev_str) {
+ command_print_sameline(cmd, "%s - Rev: %s", info->device_str, rev_str);
} else {
- snprintf(buf, buf_size,
- "%s - Rev: unknown (0x%04x)",
- info->device_str, rev_id);
+ command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)", info->device_str, rev_id);
}
return ERROR_OK;
COMMAND_REGISTRATION_DONE
};
-struct flash_driver stm32lx_flash = {
+const struct flash_driver stm32lx_flash = {
.name = "stm32lx",
.commands = stm32lx_command_handlers,
.flash_bank_command = stm32lx_flash_bank_command,
.erase = stm32lx_erase,
- .protect = stm32lx_protect,
.write = stm32lx_write,
.read = default_flash_read,
.probe = stm32lx_probe,
.erase_check = default_flash_blank_check,
.protect_check = stm32lx_protect_check,
.info = stm32lx_get_info,
+ .free_driver_priv = default_flash_free_driver_priv,
};
/* Static methods implementation */