X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32l4x.c;h=7a6ec3fd22e3cd5c62e62b564656f21c3f66cea5;hp=3ef8bf894e5a7918597f629cc835c4e0b771b8e2;hb=HEAD;hpb=a0bd3c9924870c3b8f428648410181040dabc33c
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index 3ef8bf894e..039938512b 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -1,22 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2015 by Uwe Bonnes *
* bon@elektron.ikp.physik.tu-darmstadt.de *
* *
* Copyright (C) 2019 by Tarek Bochkati for STMicroelectronics *
* tarek.bouchkati@gmail.com *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see . *
***************************************************************************/
#ifdef HAVE_CONFIG_H
@@ -26,9 +15,10 @@
#include "imp.h"
#include
#include
+#include
#include
+#include
#include
-#include "bits.h"
#include "stm32l4x.h"
/* STM32L4xxx series for reference.
@@ -67,6 +57,9 @@
*/
/* STM32WBxxx series for reference.
+ *
+ * RM0493 (STM32WBA52x)
+ * http://www.st.com/resource/en/reference_manual/dm00821869.pdf
*
* RM0434 (STM32WB55/WB35x)
* http://www.st.com/resource/en/reference_manual/dm00318631.pdf
@@ -90,6 +83,12 @@
* http://www.st.com/resource/en/reference_manual/dm00451556.pdf
*/
+/* STM32C0xxx series for reference.
+ *
+ * RM0490 (STM32C0x1)
+ * http://www.st.com/resource/en/reference_manual/dm00781702.pdf
+ */
+
/* STM32G0xxx series for reference.
*
* RM0444 (STM32G0x1)
@@ -273,7 +272,7 @@ struct stm32l4_wrp {
};
/* human readable list of families this drivers supports (sorted alphabetically) */
-static const char *device_families = "STM32G0/G4/L4/L4+/L5/U5/WB/WL";
+static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U5/WB/WL";
static const struct stm32l4_rev stm32l47_l48xx_revs[] = {
{ 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
@@ -283,6 +282,15 @@ static const struct stm32l4_rev stm32l43_l44xx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
};
+
+static const struct stm32l4_rev stm32c01xx_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" },
+};
+
+static const struct stm32l4_rev stm32c03xx_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" },
+};
+
static const struct stm32l4_rev stm32g05_g06xx_revs[] = {
{ 0x1000, "A" },
};
@@ -299,7 +307,7 @@ static const struct stm32l4_rev stm32l45_l46xx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
};
-static const struct stm32l4_rev stm32l41_L42xx_revs[] = {
+static const struct stm32l4_rev stm32l41_l42xx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
};
@@ -321,6 +329,7 @@ static const struct stm32l4_rev stm32g47_g48xx_revs[] = {
static const struct stm32l4_rev stm32l4r_l4sxx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" },
+ { 0x101F, "V" },
};
static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = {
@@ -328,7 +337,7 @@ static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = {
};
static const struct stm32l4_rev stm32l55_l56xx_revs[] = {
- { 0x1000, "A" }, { 0x2000, "B" },
+ { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
};
static const struct stm32l4_rev stm32g49_g4axx_revs[] = {
@@ -337,6 +346,11 @@ static const struct stm32l4_rev stm32g49_g4axx_revs[] = {
static const struct stm32l4_rev stm32u57_u58xx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" },
+ { 0x2001, "X" }, { 0x3000, "C" },
+};
+
+static const struct stm32l4_rev stm32wba5x_revs[] = {
+ { 0x1000, "A" },
};
static const struct stm32l4_rev stm32wb1xx_revs[] = {
@@ -380,6 +394,30 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.otp_base = 0x1FFF7000,
.otp_size = 1024,
},
+ {
+ .id = DEVID_STM32C01XX,
+ .revs = stm32c01xx_revs,
+ .num_revs = ARRAY_SIZE(stm32c01xx_revs),
+ .device_str = "STM32C01xx",
+ .max_flash_size_kb = 32,
+ .flags = F_NONE,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75A0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
+ },
+ {
+ .id = DEVID_STM32C03XX,
+ .revs = stm32c03xx_revs,
+ .num_revs = ARRAY_SIZE(stm32c03xx_revs),
+ .device_str = "STM32C03xx",
+ .max_flash_size_kb = 32,
+ .flags = F_NONE,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75A0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
+ },
{
.id = DEVID_STM32G05_G06XX,
.revs = stm32g05_g06xx_revs,
@@ -430,8 +468,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
},
{
.id = DEVID_STM32L41_L42XX,
- .revs = stm32l41_L42xx_revs,
- .num_revs = ARRAY_SIZE(stm32l41_L42xx_revs),
+ .revs = stm32l41_l42xx_revs,
+ .num_revs = ARRAY_SIZE(stm32l41_l42xx_revs),
.device_str = "STM32L41/L42xx",
.max_flash_size_kb = 128,
.flags = F_NONE,
@@ -548,6 +586,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.otp_base = 0x0BFA0000,
.otp_size = 512,
},
+ {
+ .id = DEVID_STM32WBA5X,
+ .revs = stm32wba5x_revs,
+ .num_revs = ARRAY_SIZE(stm32wba5x_revs),
+ .device_str = "STM32WBA5x",
+ .max_flash_size_kb = 1024,
+ .flags = F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x0FF907A0,
+ .otp_base = 0x0FF90000,
+ .otp_size = 512,
+ },
{
.id = DEVID_STM32WB1XX,
.revs = stm32wb1xx_revs,
@@ -1077,7 +1127,7 @@ static int stm32l4_get_all_wrpxy(struct flash_bank *bank, enum stm32_bank_id dev
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)
@@ -1219,49 +1269,11 @@ err_lock:
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)
@@ -1277,7 +1289,7 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
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;
@@ -1348,6 +1360,40 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
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)
@@ -1631,13 +1677,14 @@ err_lock:
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;
}
@@ -1646,12 +1693,16 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
* 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_impl_part(target) == CORTEX_M0P_PARTNO &&
+ armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) {
uint32_t uid64_ids;
/* UID64 is contains
@@ -1661,7 +1712,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
*
* 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;
@@ -1699,11 +1750,21 @@ static const char *get_stm32l4_bank_type_str(struct flash_bank *bank)
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 */
@@ -1739,9 +1800,10 @@ static int stm32l4_probe(struct flash_bank *bank)
/* Set flash write alignment boundaries.
* Ask the flash infrastructure to ensure required alignment */
- bank->write_start_alignment = bank->write_end_alignment = stm32l4_info->data_width;
+ bank->write_start_alignment = stm32l4_info->data_width;
+ 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
@@ -1754,7 +1816,7 @@ static int stm32l4_probe(struct flash_bank *bank)
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;
@@ -1815,7 +1877,7 @@ static int stm32l4_probe(struct flash_bank *bank)
flash_size_kb = stm32l4_info->user_bank_size / 1024;
}
- LOG_INFO("flash size = %dkbytes", flash_size_kb);
+ LOG_INFO("flash size = %d KiB", flash_size_kb);
/* did we assign a flash size? */
assert((flash_size_kb != 0xffff) && flash_size_kb);
@@ -1852,6 +1914,8 @@ static int stm32l4_probe(struct flash_bank *bank)
}
break;
case DEVID_STM32L43_L44XX:
+ case DEVID_STM32C01XX:
+ case DEVID_STM32C03XX:
case DEVID_STM32G05_G06XX:
case DEVID_STM32G07_G08XX:
case DEVID_STM32L45_L46XX:
@@ -1948,6 +2012,12 @@ static int stm32l4_probe(struct flash_bank *bank)
stm32l4_info->bank1_sectors = num_pages / 2;
}
break;
+ case DEVID_STM32WBA5X:
+ /* single bank flash */
+ page_size_kb = 8;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ break;
case DEVID_STM32WB5XX:
case DEVID_STM32WB3XX:
/* single bank flash */
@@ -1971,6 +2041,15 @@ static int stm32l4_probe(struct flash_bank *bank)
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;
@@ -2030,8 +2109,19 @@ static int stm32l4_auto_probe(struct flash_bank *bank)
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;
@@ -2128,10 +2218,8 @@ err_lock:
COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
{
- if (CMD_ARGC < 1) {
- command_print(CMD, "stm32l4x mass_erase ");
+ if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
- }
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
@@ -2149,10 +2237,8 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
COMMAND_HANDLER(stm32l4_handle_option_read_command)
{
- if (CMD_ARGC < 2) {
- command_print(CMD, "stm32l4x option_read ");
+ if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
- }
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
@@ -2176,10 +2262,8 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command)
COMMAND_HANDLER(stm32l4_handle_option_write_command)
{
- if (CMD_ARGC < 3) {
- command_print(CMD, "stm32l4x option_write [mask]");
+ if (CMD_ARGC != 3 && CMD_ARGC != 4)
return ERROR_COMMAND_SYNTAX_ERROR;
- }
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
@@ -2291,7 +2375,7 @@ COMMAND_HANDLER(stm32l4_handle_lock_command)
{
struct target *target = NULL;
- if (CMD_ARGC < 1)
+ if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
@@ -2326,7 +2410,7 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command)
{
struct target *target = NULL;
- if (CMD_ARGC < 1)
+ if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
@@ -2430,7 +2514,7 @@ COMMAND_HANDLER(stm32l4_handle_wrp_info_command)
COMMAND_HANDLER(stm32l4_handle_otp_command)
{
- if (CMD_ARGC < 2)
+ if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;