#include "imp.h"
#include <helper/align.h>
#include <helper/binarybuffer.h>
+#include <helper/bits.h>
#include <target/algorithm.h>
+#include <target/arm_adi_v5.h>
#include <target/cortex_m.h>
-#include "bits.h"
#include "stm32l4x.h"
/* STM32L4xxx series for reference.
if (dev_bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode)
wrp2y_sectors_offset = stm32l4_info->bank1_sectors;
- if (wrp2y_sectors_offset > -1) {
+ if (wrp2y_sectors_offset >= 0) {
/* get WRP2AR */
ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2AR_INDEX, wrp2y_sectors_offset);
if (ret != ERROR_OK)
return retval2;
}
-static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
+static int stm32l4_protect_same_bank(struct flash_bank *bank, enum stm32_bank_id bank_id, int set,
+ unsigned int first, unsigned int last)
{
- struct target *target = bank->target;
- struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
- int ret = ERROR_OK;
unsigned int i;
- if (stm32l4_is_otp(bank)) {
- LOG_ERROR("cannot protect/unprotect OTP memory");
- return ERROR_FLASH_OPER_UNSUPPORTED;
- }
-
- if (target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- /* the requested sectors could be located into bank1 and/or bank2 */
- bool use_bank2 = false;
- if (last >= stm32l4_info->bank1_sectors) {
- if (first < stm32l4_info->bank1_sectors) {
- /* the requested sectors for (un)protection are shared between
- * bank 1 and 2, then split the operation */
-
- /* 1- deal with bank 1 sectors */
- LOG_DEBUG("The requested sectors for %s are shared between bank 1 and 2",
- set ? "protection" : "unprotection");
- ret = stm32l4_protect(bank, set, first, stm32l4_info->bank1_sectors - 1);
- if (ret != ERROR_OK)
- return ret;
-
- /* 2- then continue with bank 2 sectors */
- first = stm32l4_info->bank1_sectors;
- }
-
- use_bank2 = true;
- }
-
- /* refresh the sectors' protection */
- ret = stm32l4_protect_check(bank);
- if (ret != ERROR_OK)
- return ret;
-
/* check if the desired protection is already configured */
for (i = first; i <= last; i++) {
if (bank->sectors[i].is_protected != set)
unsigned int n_wrp;
struct stm32l4_wrp wrpxy[4];
- ret = stm32l4_get_all_wrpxy(bank, use_bank2 ? STM32_BANK2 : STM32_BANK1, wrpxy, &n_wrp);
+ int ret = stm32l4_get_all_wrpxy(bank, bank_id, wrpxy, &n_wrp);
if (ret != ERROR_OK)
return ret;
return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp);
}
+static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
+{
+ struct target *target = bank->target;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+ if (stm32l4_is_otp(bank)) {
+ LOG_ERROR("cannot protect/unprotect OTP memory");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* refresh the sectors' protection */
+ int ret = stm32l4_protect_check(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* the requested sectors could be located into bank1 and/or bank2 */
+ if (last < stm32l4_info->bank1_sectors) {
+ return stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, last);
+ } else if (first >= stm32l4_info->bank1_sectors) {
+ return stm32l4_protect_same_bank(bank, STM32_BANK2, set, first, last);
+ } else {
+ ret = stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, stm32l4_info->bank1_sectors - 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ return stm32l4_protect_same_bank(bank, STM32_BANK2, set, stm32l4_info->bank1_sectors, last);
+ }
+}
+
/* count is the size divided by stm32l4_info->data_width */
static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
{
- int retval;
+ int retval = ERROR_OK;
+ struct target *target = bank->target;
/* try reading possible IDCODE registers, in the following order */
uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5};
for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) {
- retval = target_read_u32(bank->target, dbgmcu_idcode[i], id);
+ retval = target_read_u32(target, dbgmcu_idcode[i], id);
if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff))
return ERROR_OK;
}
* DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1,
* to solve this read the UID64 (IEEE 64-bit unique device ID register) */
- struct cortex_m_common *cortex_m = target_to_cm(bank->target);
+ struct armv7m_common *armv7m = target_to_armv7m_safe(target);
+ if (!armv7m) {
+ LOG_ERROR("Flash requires Cortex-M target");
+ return ERROR_TARGET_INVALID;
+ }
/* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1.
* Using HLA adapters armv7m.debug_ap is null, and checking ap_num triggers a segfault */
- if (cortex_m->core_info->partno == CORTEX_M0P_PARTNO &&
- cortex_m->armv7m.debug_ap && cortex_m->armv7m.debug_ap->ap_num == 1) {
+ if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO &&
+ armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) {
uint32_t uid64_ids;
/* UID64 is contains
*
* read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx
*/
- retval = target_read_u32(bank->target, UID64_IDS, &uid64_ids);
+ retval = target_read_u32(target, UID64_IDS, &uid64_ids);
if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) {
/* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */
*id = DEVID_STM32WLE_WL5XX;
static int stm32l4_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
- struct armv7m_common *armv7m = target_to_armv7m(target);
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
const struct stm32l4_part_info *part_info;
uint16_t flash_size_kb = 0xffff;
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_TARGET_NOT_EXAMINED;
+ }
+
+ struct armv7m_common *armv7m = target_to_armv7m_safe(target);
+ if (!armv7m) {
+ LOG_ERROR("Flash requires Cortex-M target");
+ return ERROR_TARGET_INVALID;
+ }
+
stm32l4_info->probed = false;
/* read stm32 device id registers */
* Ask the flash infrastructure to ensure required alignment */
bank->write_start_alignment = bank->write_end_alignment = stm32l4_info->data_width;
- /* initialise the flash registers layout */
+ /* Initialize the flash registers layout */
if (part_info->flags & F_HAS_L5_FLASH_REGS)
stm32l4_info->flash_regs = stm32l5_ns_flash_regs;
else
stm32l4_sync_rdp_tzen(bank);
- /* for devices with trustzone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */
+ /* for devices with TrustZone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */
if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
if (part_info->flags & F_HAS_L5_FLASH_REGS) {
stm32l4_info->flash_regs_base |= STM32L5_REGS_SEC_OFFSET;
return ERROR_FAIL;
}
+ /* ensure that at least there is 1 flash sector / page */
+ if (num_pages == 0) {
+ if (stm32l4_info->user_bank_size)
+ LOG_ERROR("The specified flash size is less than page size");
+
+ LOG_ERROR("Flash pages count cannot be zero");
+ return ERROR_FAIL;
+ }
+
LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single");
const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb;
if (stm32l4_info->probed) {
uint32_t optr_cur;
+ /* save flash_regs_base */
+ uint32_t saved_flash_regs_base = stm32l4_info->flash_regs_base;
+
+ /* for devices with TrustZone, use NS flash registers to read OPTR */
+ if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS)
+ stm32l4_info->flash_regs_base &= ~STM32L5_REGS_SEC_OFFSET;
+
/* read flash option register and re-probe if optr value is changed */
int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &optr_cur);
+
+ /* restore saved flash_regs_base */
+ stm32l4_info->flash_regs_base = saved_flash_regs_base;
+
if (retval != ERROR_OK)
return retval;