target_write_u32(target, STM32_FLASH_AR, bank->base + bank->sectors[i].offset);
target_write_u32(target, STM32_FLASH_CR, FLASH_PER | FLASH_STRT);
- status = stm32x_wait_status_busy(bank, 10);
+ status = stm32x_wait_status_busy(bank, 100);
if (status & FLASH_WRPRTERR)
return ERROR_FLASH_OPERATION_FAILED;
return ERROR_TARGET_NOT_HALTED;
}
- if ((first && (first % stm32x_info->ppage_size)) || ((last + 1) && (last + 1) % stm32x_info->ppage_size))
+ if ((first && (first % stm32x_info->ppage_size)) || ((last + 1) &&
+ (last + 1) % stm32x_info->ppage_size))
{
- LOG_WARNING("Error: start and end sectors must be on a %d sector boundary", stm32x_info->ppage_size);
+ LOG_WARNING("Error: start and end sectors must be on a %d sector boundary",
+ stm32x_info->ppage_size);
return ERROR_FLASH_SECTOR_INVALID;
}
return stm32x_write_options(bank);
}
-static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
+ uint32_t offset, uint32_t count)
{
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct target *target = bank->target;
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
- uint8_t stm32x_flash_write_code[] = {
+ static const uint8_t stm32x_flash_write_code[] = {
/* write: */
0xDF, 0xF8, 0x24, 0x40, /* ldr r4, STM32_FLASH_CR */
0x09, 0x4D, /* ldr r5, STM32_FLASH_SR */
0x01, 0xD1, /* bne exit */
0x01, 0x3A, /* subs r2, r2, #1 */
0xED, 0xD1, /* bne write */
- /* exit: */
- 0xFE, 0xE7, /* b exit */
+ 0x00, 0xBE, /* bkpt #0 */
0x10, 0x20, 0x02, 0x40, /* STM32_FLASH_CR: .word 0x40022010 */
0x0C, 0x20, 0x02, 0x40 /* STM32_FLASH_SR: .word 0x4002200C */
};
/* flash write code */
- if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK)
+ if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
+ &stm32x_info->write_algorithm) != ERROR_OK)
{
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
- if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code)) != ERROR_OK)
+ if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address,
+ sizeof(stm32x_flash_write_code),
+ (uint8_t*)stm32x_flash_write_code)) != ERROR_OK)
return retval;
/* memory buffer */
- while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
{
buffer_size /= 2;
if (buffer_size <= 256)
{
- /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
+ /* if we already allocated the writing code, but failed to get a
+ * buffer, free the algorithm */
if (stm32x_info->write_algorithm)
target_free_working_area(target, stm32x_info->write_algorithm);
while (count > 0)
{
- uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
+ uint32_t thisrun_count = (count > (buffer_size / 2)) ?
+ (buffer_size / 2) : count;
- if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer)) != ERROR_OK)
+ if ((retval = target_write_buffer(target, source->address,
+ thisrun_count * 2, buffer)) != ERROR_OK)
break;
buf_set_u32(reg_params[0].value, 0, 32, source->address);
buf_set_u32(reg_params[1].value, 0, 32, address);
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
- if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \
- stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
+ if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
+ stm32x_info->write_algorithm->address,
+ stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10),
+ 10000, &armv7m_info)) != ERROR_OK)
{
LOG_ERROR("error executing stm32x flash write algorithm");
retval = ERROR_FLASH_OPERATION_FAILED;
return retval;
}
-static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
+static int stm32x_write(struct flash_bank *bank, uint8_t *buffer,
+ uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
uint32_t words_remaining = (count / 2);
uint32_t device_id;
int page_size;
- if (bank->target->state != TARGET_HALTED)
- {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
stm32x_info->probed = 0;
/* read stm32 device id register */
num_pages = 256;
}
}
+ else if ((device_id & 0x7ff) == 0x420)
+ {
+ /* value line density - we have 1k pages
+ * 4 pages for a protection area */
+ page_size = 1024;
+ stm32x_info->ppage_size = 4;
+
+ /* check for early silicon */
+ if (num_pages == 0xffff)
+ {
+ /* number of sectors may be incorrrect on early silicon */
+ LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 128k flash");
+ num_pages = 128;
+ }
+ }
else
{
LOG_WARNING("Cannot identify target as a STM32 family.");
/* calculate numbers of pages */
num_pages /= (page_size / 1024);
+ if (bank->sectors)
+ {
+ free(bank->sectors);
+ bank->sectors = NULL;
+ }
+
bank->base = 0x08000000;
bank->size = (num_pages * page_size);
bank->num_sectors = num_pages;
break;
}
}
+ else if ((device_id & 0x7ff) == 0x420)
+ {
+ printed = snprintf(buf, buf_size, "stm32x (Value) - Rev: ");
+ buf += printed;
+ buf_size -= printed;
+
+ switch (device_id >> 16)
+ {
+ case 0x1000:
+ snprintf(buf, buf_size, "A");
+ break;
+
+ case 0x1001:
+ snprintf(buf, buf_size, "Z");
+ break;
+
+ default:
+ snprintf(buf, buf_size, "unknown");
+ break;
+ }
+ }
else
{
snprintf(buf, buf_size, "Cannot identify target as a stm32x\n");
return ERROR_OK;
}
- command_print(CMD_CTX, "stm32x unlocked");
+ command_print(CMD_CTX, "stm32x unlocked.\n"
+ "INFO: a reset or power cycle is required "
+ "for the new settings to take effect.");
return ERROR_OK;
}
return ERROR_TARGET_NOT_HALTED;
}
+ /* REVISIT: ignores some options which we will display...
+ * and doesn't insist on the specified syntax.
+ */
+
+ /* OPT_RDWDGSW */
if (strcmp(CMD_ARGV[1], "SWWDG") == 0)
{
optionbyte |= (1 << 0);
}
- else
+ else /* REVISIT must be "HWWDG" then ... */
{
optionbyte &= ~(1 << 0);
}
+ /* OPT_RDRSTSTDBY */
if (strcmp(CMD_ARGV[2], "NORSTSTNDBY") == 0)
{
optionbyte |= (1 << 1);
}
- else
+ else /* REVISIT must be "RSTSTNDBY" then ... */
{
optionbyte &= ~(1 << 1);
}
+ /* OPT_RDRSTSTOP */
if (strcmp(CMD_ARGV[3], "NORSTSTOP") == 0)
{
optionbyte |= (1 << 2);
}
- else
+ else /* REVISIT must be "RSTSTOP" then ... */
{
optionbyte &= ~(1 << 2);
}
return ERROR_OK;
}
- command_print(CMD_CTX, "stm32x write options complete");
+ command_print(CMD_CTX, "stm32x write options complete.\n"
+ "INFO: a reset or power cycle is required "
+ "for the new settings to take effect.");
return ERROR_OK;
}
target_write_u32(target, STM32_FLASH_CR, FLASH_MER);
target_write_u32(target, STM32_FLASH_CR, FLASH_MER | FLASH_STRT);
- status = stm32x_wait_status_busy(bank, 10);
+ status = stm32x_wait_status_busy(bank, 100);
target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
if (status & FLASH_WRPRTERR)
{
LOG_ERROR("stm32x device protected");
- return ERROR_OK;
+ return ERROR_FLASH_OPERATION_FAILED;
}
if (status & FLASH_PGERR)
{
LOG_ERROR("stm32x device programming failed");
- return ERROR_OK;
+ return ERROR_FLASH_OPERATION_FAILED;
}
return ERROR_OK;
if (ERROR_OK != retval)
return retval;
- if (stm32x_mass_erase(bank) == ERROR_OK)
+ retval = stm32x_mass_erase(bank);
+ if (retval == ERROR_OK)
{
/* set all sectors as erased */
for (i = 0; i < bank->num_sectors; i++)
command_print(CMD_CTX, "stm32x mass erase failed");
}
- return ERROR_OK;
+ return retval;
}
static const struct command_registration stm32x_exec_command_handlers[] = {
{
.name = "lock",
- .handler = &stm32x_handle_lock_command,
+ .handler = stm32x_handle_lock_command,
.mode = COMMAND_EXEC,
- .help = "lock device",
+ .usage = "bank_id",
+ .help = "Lock entire flash device.",
},
{
.name = "unlock",
- .handler = &stm32x_handle_unlock_command,
+ .handler = stm32x_handle_unlock_command,
.mode = COMMAND_EXEC,
- .help = "unlock protected device",
+ .usage = "bank_id",
+ .help = "Unlock entire protected flash device.",
},
{
.name = "mass_erase",
- .handler = &stm32x_handle_mass_erase_command,
+ .handler = stm32x_handle_mass_erase_command,
.mode = COMMAND_EXEC,
- .help = "mass erase device",
+ .usage = "bank_id",
+ .help = "Erase entire flash device.",
},
{
.name = "options_read",
- .handler = &stm32x_handle_options_read_command,
+ .handler = stm32x_handle_options_read_command,
.mode = COMMAND_EXEC,
- .help = "read device option bytes",
+ .usage = "bank_id",
+ .help = "Read and display device option byte.",
},
{
.name = "options_write",
- .handler = &stm32x_handle_options_write_command,
+ .handler = stm32x_handle_options_write_command,
.mode = COMMAND_EXEC,
- .help = "write device option bytes",
+ .usage = "bank_id ('SWWDG'|'HWWDG') "
+ "('RSTSTNDBY'|'NORSTSTNDBY') "
+ "('RSTSTOP'|'NORSTSTOP')",
+ .help = "Replace bits in device option byte.",
},
COMMAND_REGISTRATION_DONE
};
+
static const struct command_registration stm32x_command_handlers[] = {
{
.name = "stm32x",
};
struct flash_driver stm32x_flash = {
- .name = "stm32x",
- .commands = stm32x_command_handlers,
- .flash_bank_command = &stm32x_flash_bank_command,
- .erase = &stm32x_erase,
- .protect = &stm32x_protect,
- .write = &stm32x_write,
- .probe = &stm32x_probe,
- .auto_probe = &stm32x_auto_probe,
- .erase_check = &default_flash_mem_blank_check,
- .protect_check = &stm32x_protect_check,
- .info = &stm32x_info,
- };
+ .name = "stm32x",
+ .commands = stm32x_command_handlers,
+ .flash_bank_command = stm32x_flash_bank_command,
+ .erase = stm32x_erase,
+ .protect = stm32x_protect,
+ .write = stm32x_write,
+ .read = default_flash_read,
+ .probe = stm32x_probe,
+ .auto_probe = stm32x_auto_probe,
+ .erase_check = default_flash_mem_blank_check,
+ .protect_check = stm32x_protect_check,
+ .info = stm32x_info,
+};