X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32l4x.c;h=c67dbf75dc7bf2617fe441a518d933b4acf21101;hb=dbb42ca18d471b6bffddbd441b1da2ffe18d7400;hp=3c055616f5c1cd1a92475b7295a07a8b4a1e3683;hpb=c281c64469de3c92b2fad0933722cb95b710b02a;p=openocd.git diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 3c055616f5..c67dbf75dc 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. @@ -64,16 +54,21 @@ * - for STM32L4P5/Q5x * In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode. * In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode. - * */ /* STM32WBxxx series for reference. * - * RM0434 (STM32WB55) + * RM0434 (STM32WB55/WB35x) * http://www.st.com/resource/en/reference_manual/dm00318631.pdf * - * RM0471 (STM32WB50) + * RM0471 (STM32WB50/WB30x) * http://www.st.com/resource/en/reference_manual/dm00622834.pdf + * + * RM0473 (STM32WB15x) + * http://www.st.com/resource/en/reference_manual/dm00649196.pdf + * + * RM0478 (STM32WB10x) + * http://www.st.com/resource/en/reference_manual/dm00689203.pdf */ /* STM32WLxxx series for reference. @@ -247,7 +242,6 @@ struct stm32l4_flash_bank { uint32_t flash_regs_base; const uint32_t *flash_regs; bool otp_enabled; - bool use_flashloader; enum stm32l4_rdp rdp; bool tzen; uint32_t optr; @@ -271,83 +265,92 @@ 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 struct stm32l4_rev stm32_415_revs[] = { +static const struct stm32l4_rev stm32l47_l48xx_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } }; -static const struct stm32l4_rev stm32_435_revs[] = { +static const struct stm32l4_rev stm32l43_l44xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; -static const struct stm32l4_rev stm32_460_revs[] = { +static const struct stm32l4_rev stm32g05_g06xx_revs[] = { + { 0x1000, "A" }, +}; + +static const struct stm32l4_rev stm32_g07_g08xx_revs[] = { { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" }, }; -static const struct stm32l4_rev stm32_461_revs[] = { +static const struct stm32l4_rev stm32l49_l4axx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, }; -static const struct stm32l4_rev stm32_462_revs[] = { +static const struct stm32l4_rev stm32l45_l46xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; -static const struct stm32l4_rev stm32_464_revs[] = { +static const struct stm32l4_rev stm32l41_l42xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; -static const struct stm32l4_rev stm32_466_revs[] = { +static const struct stm32l4_rev stm32g03_g04xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" }, }; -static const struct stm32l4_rev stm32_467_revs[] = { +static const struct stm32l4_rev stm32g0b_g0cxx_revs[] = { { 0x1000, "A" }, }; -static const struct stm32l4_rev stm32_468_revs[] = { +static const struct stm32l4_rev stm32g43_g44xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; -static const struct stm32l4_rev stm32_469_revs[] = { +static const struct stm32l4_rev stm32g47_g48xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; -static const struct stm32l4_rev stm32_470_revs[] = { +static const struct stm32l4_rev stm32l4r_l4sxx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" }, }; -static const struct stm32l4_rev stm32_471_revs[] = { +static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = { { 0x1001, "Z" }, }; -static const struct stm32l4_rev stm32_472_revs[] = { +static const struct stm32l4_rev stm32l55_l56xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, }; -static const struct stm32l4_rev stm32_479_revs[] = { +static const struct stm32l4_rev stm32g49_g4axx_revs[] = { { 0x1000, "A" }, }; -static const struct stm32l4_rev stm32_482_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 stm32wb1xx_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, }; -static const struct stm32l4_rev stm32_495_revs[] = { +static const struct stm32l4_rev stm32wb5xx_revs[] = { { 0x2001, "2.1" }, }; -static const struct stm32l4_rev stm32_496_revs[] = { +static const struct stm32l4_rev stm32wb3xx_revs[] = { { 0x1000, "A" }, }; -static const struct stm32l4_rev stm32_497_revs[] = { +static const struct stm32l4_rev stm32wle_wl5xx_revs[] = { { 0x1000, "1.0" }, }; static const struct stm32l4_part_info stm32l4_parts[] = { { - .id = 0x415, - .revs = stm32_415_revs, - .num_revs = ARRAY_SIZE(stm32_415_revs), + .id = DEVID_STM32L47_L48XX, + .revs = stm32l47_l48xx_revs, + .num_revs = ARRAY_SIZE(stm32l47_l48xx_revs), .device_str = "STM32L47/L48xx", .max_flash_size_kb = 1024, .flags = F_HAS_DUAL_BANK, @@ -357,9 +360,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x435, - .revs = stm32_435_revs, - .num_revs = ARRAY_SIZE(stm32_435_revs), + .id = DEVID_STM32L43_L44XX, + .revs = stm32l43_l44xx_revs, + .num_revs = ARRAY_SIZE(stm32l43_l44xx_revs), .device_str = "STM32L43/L44xx", .max_flash_size_kb = 256, .flags = F_NONE, @@ -369,9 +372,21 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x460, - .revs = stm32_460_revs, - .num_revs = ARRAY_SIZE(stm32_460_revs), + .id = DEVID_STM32G05_G06XX, + .revs = stm32g05_g06xx_revs, + .num_revs = ARRAY_SIZE(stm32g05_g06xx_revs), + .device_str = "STM32G05/G06xx", + .max_flash_size_kb = 64, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32G07_G08XX, + .revs = stm32_g07_g08xx_revs, + .num_revs = ARRAY_SIZE(stm32_g07_g08xx_revs), .device_str = "STM32G07/G08xx", .max_flash_size_kb = 128, .flags = F_NONE, @@ -381,9 +396,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x461, - .revs = stm32_461_revs, - .num_revs = ARRAY_SIZE(stm32_461_revs), + .id = DEVID_STM32L49_L4AXX, + .revs = stm32l49_l4axx_revs, + .num_revs = ARRAY_SIZE(stm32l49_l4axx_revs), .device_str = "STM32L49/L4Axx", .max_flash_size_kb = 1024, .flags = F_HAS_DUAL_BANK, @@ -393,9 +408,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x462, - .revs = stm32_462_revs, - .num_revs = ARRAY_SIZE(stm32_462_revs), + .id = DEVID_STM32L45_L46XX, + .revs = stm32l45_l46xx_revs, + .num_revs = ARRAY_SIZE(stm32l45_l46xx_revs), .device_str = "STM32L45/L46xx", .max_flash_size_kb = 512, .flags = F_NONE, @@ -405,9 +420,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x464, - .revs = stm32_464_revs, - .num_revs = ARRAY_SIZE(stm32_464_revs), + .id = DEVID_STM32L41_L42XX, + .revs = stm32l41_l42xx_revs, + .num_revs = ARRAY_SIZE(stm32l41_l42xx_revs), .device_str = "STM32L41/L42xx", .max_flash_size_kb = 128, .flags = F_NONE, @@ -417,10 +432,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x466, - .revs = stm32_466_revs, - .num_revs = ARRAY_SIZE(stm32_466_revs), - .device_str = "STM32G03/G04xx", + .id = DEVID_STM32G03_G04XX, + .revs = stm32g03_g04xx_revs, + .num_revs = ARRAY_SIZE(stm32g03_g04xx_revs), + .device_str = "STM32G03x/G04xx", .max_flash_size_kb = 64, .flags = F_NONE, .flash_regs_base = 0x40022000, @@ -429,10 +444,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x467, - .revs = stm32_467_revs, - .num_revs = ARRAY_SIZE(stm32_467_revs), - .device_str = "STM32G0Bx/G0Cx", + .id = DEVID_STM32G0B_G0CXX, + .revs = stm32g0b_g0cxx_revs, + .num_revs = ARRAY_SIZE(stm32g0b_g0cxx_revs), + .device_str = "STM32G0B/G0Cx", .max_flash_size_kb = 512, .flags = F_HAS_DUAL_BANK, .flash_regs_base = 0x40022000, @@ -441,9 +456,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x468, - .revs = stm32_468_revs, - .num_revs = ARRAY_SIZE(stm32_468_revs), + .id = DEVID_STM32G43_G44XX, + .revs = stm32g43_g44xx_revs, + .num_revs = ARRAY_SIZE(stm32g43_g44xx_revs), .device_str = "STM32G43/G44xx", .max_flash_size_kb = 128, .flags = F_NONE, @@ -453,9 +468,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x469, - .revs = stm32_469_revs, - .num_revs = ARRAY_SIZE(stm32_469_revs), + .id = DEVID_STM32G47_G48XX, + .revs = stm32g47_g48xx_revs, + .num_revs = ARRAY_SIZE(stm32g47_g48xx_revs), .device_str = "STM32G47/G48xx", .max_flash_size_kb = 512, .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, @@ -465,9 +480,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x470, - .revs = stm32_470_revs, - .num_revs = ARRAY_SIZE(stm32_470_revs), + .id = DEVID_STM32L4R_L4SXX, + .revs = stm32l4r_l4sxx_revs, + .num_revs = ARRAY_SIZE(stm32l4r_l4sxx_revs), .device_str = "STM32L4R/L4Sxx", .max_flash_size_kb = 2048, .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, @@ -477,10 +492,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x471, - .revs = stm32_471_revs, - .num_revs = ARRAY_SIZE(stm32_471_revs), - .device_str = "STM32L4P5/L4Q5x", + .id = DEVID_STM32L4P_L4QXX, + .revs = stm32l4p_l4qxx_revs, + .num_revs = ARRAY_SIZE(stm32l4p_l4qxx_revs), + .device_str = "STM32L4P/L4Qxx", .max_flash_size_kb = 1024, .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX, .flash_regs_base = 0x40022000, @@ -489,9 +504,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x472, - .revs = stm32_472_revs, - .num_revs = ARRAY_SIZE(stm32_472_revs), + .id = DEVID_STM32L55_L56XX, + .revs = stm32l55_l56xx_revs, + .num_revs = ARRAY_SIZE(stm32l55_l56xx_revs), .device_str = "STM32L55/L56xx", .max_flash_size_kb = 512, .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX | F_HAS_TZ | F_HAS_L5_FLASH_REGS, @@ -501,9 +516,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 512, }, { - .id = 0x479, - .revs = stm32_479_revs, - .num_revs = ARRAY_SIZE(stm32_479_revs), + .id = DEVID_STM32G49_G4AXX, + .revs = stm32g49_g4axx_revs, + .num_revs = ARRAY_SIZE(stm32g49_g4axx_revs), .device_str = "STM32G49/G4Axx", .max_flash_size_kb = 512, .flags = F_NONE, @@ -513,9 +528,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x482, - .revs = stm32_482_revs, - .num_revs = ARRAY_SIZE(stm32_482_revs), + .id = DEVID_STM32U57_U58XX, + .revs = stm32u57_u58xx_revs, + .num_revs = ARRAY_SIZE(stm32u57_u58xx_revs), .device_str = "STM32U57/U58xx", .max_flash_size_kb = 2048, .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, @@ -525,9 +540,21 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 512, }, { - .id = 0x495, - .revs = stm32_495_revs, - .num_revs = ARRAY_SIZE(stm32_495_revs), + .id = DEVID_STM32WB1XX, + .revs = stm32wb1xx_revs, + .num_revs = ARRAY_SIZE(stm32wb1xx_revs), + .device_str = "STM32WB1x", + .max_flash_size_kb = 320, + .flags = F_NONE, + .flash_regs_base = 0x58004000, + .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, + { + .id = DEVID_STM32WB5XX, + .revs = stm32wb5xx_revs, + .num_revs = ARRAY_SIZE(stm32wb5xx_revs), .device_str = "STM32WB5x", .max_flash_size_kb = 1024, .flags = F_NONE, @@ -537,9 +564,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x496, - .revs = stm32_496_revs, - .num_revs = ARRAY_SIZE(stm32_496_revs), + .id = DEVID_STM32WB3XX, + .revs = stm32wb3xx_revs, + .num_revs = ARRAY_SIZE(stm32wb3xx_revs), .device_str = "STM32WB3x", .max_flash_size_kb = 512, .flags = F_NONE, @@ -549,10 +576,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { - .id = 0x497, - .revs = stm32_497_revs, - .num_revs = ARRAY_SIZE(stm32_497_revs), - .device_str = "STM32WLEx/WL5x", + .id = DEVID_STM32WLE_WL5XX, + .revs = stm32wle_wl5xx_revs, + .num_revs = ARRAY_SIZE(stm32wle_wl5xx_revs), + .device_str = "STM32WLE/WL5x", .max_flash_size_kb = 256, .flags = F_NONE, .flash_regs_base = 0x58004000, @@ -582,7 +609,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) stm32l4_info->probed = false; stm32l4_info->otp_enabled = false; stm32l4_info->user_bank_size = bank->size; - stm32l4_info->use_flashloader = true; return ERROR_OK; } @@ -1042,7 +1068,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) @@ -1184,49 +1210,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) @@ -1242,7 +1230,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; @@ -1313,17 +1301,50 @@ 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) { struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[6]; + struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -1345,12 +1366,13 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } - /* memory buffer, size *must* be multiple of stm32l4_info->data_width - * plus one dword for rp and one for wp */ - /* FIXME, currently only STM32U5 devices do have a different data_width, - * but STM32U5 device flash programming does not go through this function - * so temporarily continue to consider the default data_width = 8 */ - buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1); + /* data_width should be multiple of double-word */ + assert(stm32l4_info->data_width % 8 == 0); + const size_t extra_size = sizeof(struct stm32l4_work_area); + uint32_t buffer_size = target_get_working_area_avail(target) - extra_size; + /* buffer_size should be multiple of stm32l4_info->data_width */ + buffer_size &= ~(stm32l4_info->data_width - 1); + if (buffer_size < 256) { LOG_WARNING("large enough working area not available, can't do block memory writes"); target_free_working_area(target, write_algorithm); @@ -1360,7 +1382,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, buffer_size = 16384; } - if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + if (target_alloc_working_area_try(target, buffer_size + extra_size, &source) != ERROR_OK) { LOG_ERROR("allocating working area failed"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1368,31 +1390,52 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ + /* contrib/loaders/flash/stm32/stm32l4x.c:write() arguments */ + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* stm32l4_work_area ptr , status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (double word-64bit) */ - init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash status register */ - init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash control register */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (of stm32l4_info->data_width) */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); - buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX)); - buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX)); + + /* write algo stack pointer */ + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); + buf_set_u32(reg_params[4].value, 0, 32, source->address + + offsetof(struct stm32l4_work_area, stack) + LDR_STACK_SIZE); + + struct stm32l4_loader_params loader_extra_params; + + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_addr, + stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX)); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_cr_addr, + stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX)); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_word_size, + stm32l4_info->data_width); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_bsy_mask, + stm32l4_info->sr_bsy_mask); + + retval = target_write_buffer(target, source->address, sizeof(loader_extra_params), + (uint8_t *) &loader_extra_params); + if (retval != ERROR_OK) + return retval; retval = target_run_flash_async_algorithm(target, buffer, count, stm32l4_info->data_width, 0, NULL, ARRAY_SIZE(reg_params), reg_params, - source->address, source->size, + source->address + offsetof(struct stm32l4_work_area, fifo), + source->size - offsetof(struct stm32l4_work_area, fifo), write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("error executing stm32l4 flash write algorithm"); - uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & FLASH_ERROR; + uint32_t error; + stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &error); + error &= FLASH_ERROR; if (error & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); @@ -1413,7 +1456,6 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); - destroy_reg_param(®_params[5]); return retval; } @@ -1538,37 +1580,21 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto err_lock; - /** - * FIXME update the flash loader to use a custom FLASH_SR_BSY mask - * Workaround for STM32G0Bx/G0Cx devices in dual bank mode, - * as the flash loader does not use the SR_BSY2 - */ - bool use_flashloader = stm32l4_info->use_flashloader; - if ((stm32l4_info->part_info->id == 0x467) && stm32l4_info->dual_bank_mode) { - LOG_INFO("Couldn't use the flash loader in dual-bank mode"); - use_flashloader = false; - } else if (stm32l4_info->part_info->id == 0x482) { - /** - * FIXME the current flashloader does not support writing in quad-words - * which is required for STM32U5 devices. - */ - use_flashloader = false; - } - if (use_flashloader) { - /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5, - * the debug is possible only in non-secure state. - * Thus means the flashloader will run in non-secure mode, - * and the workarea need to be in non-secure RAM */ - if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5)) - LOG_INFO("RDP level is 0.5, the work-area should reside in non-secure RAM"); + /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5, + * the debug is possible only in non-secure state. + * Thus means the flashloader will run in non-secure mode, + * and the workarea need to be in non-secure RAM */ + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5)) + LOG_WARNING("RDP = 0x55, the work-area should be in non-secure RAM (check SAU partitioning)"); - retval = stm32l4_write_block(bank, buffer, offset, - count / stm32l4_info->data_width); - } + /* first try to write using the loader, for better performance */ + retval = stm32l4_write_block(bank, buffer, offset, + count / stm32l4_info->data_width); - if (!use_flashloader || retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { - LOG_INFO("falling back to single memory accesses"); + /* if resources are not available write without a loader */ + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + LOG_WARNING("falling back to programming without a flash loader (slower)"); retval = stm32l4_write_block_without_loader(bank, buffer, offset, count / stm32l4_info->data_width); } @@ -1592,13 +1618,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; } @@ -1607,9 +1634,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; + } - if (cortex_m->core_info->partno == CORTEX_M0P_PARTNO && cortex_m->armv7m.debug_ap->ap_num == 1) { + /* 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_get_partno_safe(target) == CORTEX_M0P_PARTNO && + armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) { uint32_t uid64_ids; /* UID64 is contains @@ -1619,10 +1653,10 @@ 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 0x497 and the REV_ID to unknown */ - *id = 0x00000497; + /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */ + *id = DEVID_STM32WLE_WL5XX; return ERROR_OK; } } @@ -1657,11 +1691,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 */ @@ -1697,9 +1741,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 @@ -1712,7 +1757,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; @@ -1773,11 +1818,13 @@ 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); + const bool is_max_flash_size = flash_size_kb == stm32l4_info->part_info->max_flash_size_kb; + stm32l4_info->bank1_sectors = 0; stm32l4_info->hole_sectors = 0; @@ -1785,14 +1832,13 @@ static int stm32l4_probe(struct flash_bank *bank) int page_size_kb = 0; stm32l4_info->dual_bank_mode = false; - bool use_dbank_bit = false; switch (device_id) { - case 0x415: /* STM32L47/L48xx */ - case 0x461: /* STM32L49/L4Axx */ + case DEVID_STM32L47_L48XX: + case DEVID_STM32L49_L4AXX: /* if flash size is max (1M) the device is always dual bank - * 0x415: has variants with 512K - * 0x461: has variants with 512 and 256 + * STM32L47/L48xx: has variants with 512K + * STM32L49/L4Axx: has variants with 512 and 256 * for these variants: * if DUAL_BANK = 0 -> single bank * else -> dual bank without gap @@ -1802,39 +1848,41 @@ static int stm32l4_probe(struct flash_bank *bank) num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - /* check DUAL_BANK bit[21] if the flash is less than 1M */ - if (flash_size_kb == 1024 || (stm32l4_info->optr & BIT(21))) { + /* check DUAL_BANK option bit if the flash is less than 1M */ + if (is_max_flash_size || (stm32l4_info->optr & FLASH_L4_DUAL_BANK)) { stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x435: /* STM32L43/L44xx */ - case 0x460: /* STM32G07/G08xx */ - case 0x462: /* STM32L45/L46xx */ - case 0x464: /* STM32L41/L42xx */ - case 0x466: /* STM32G03/G04xx */ - case 0x468: /* STM32G43/G44xx */ - case 0x479: /* STM32G49/G4Axx */ + case DEVID_STM32L43_L44XX: + case DEVID_STM32G05_G06XX: + case DEVID_STM32G07_G08XX: + case DEVID_STM32L45_L46XX: + case DEVID_STM32L41_L42XX: + case DEVID_STM32G03_G04XX: + case DEVID_STM32G43_G44XX: + case DEVID_STM32G49_G4AXX: + case DEVID_STM32WB1XX: /* single bank flash */ page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; break; - case 0x467: /* STM32G0B/G0Cxx */ - /* single/dual bank depending on bit(21) */ + case DEVID_STM32G0B_G0CXX: + /* single/dual bank depending on DUAL_BANK option bit */ page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; stm32l4_info->cr_bker_mask = FLASH_BKER_G0; /* check DUAL_BANK bit */ - if (stm32l4_info->optr & BIT(21)) { + if (stm32l4_info->optr & FLASH_G0_DUAL_BANK) { stm32l4_info->sr_bsy_mask = FLASH_BSY | FLASH_BSY2; stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x469: /* STM32G47/G48xx */ + case DEVID_STM32G47_G48XX: /* STM32G47/8 can be single/dual bank: * if DUAL_BANK = 0 -> single bank * else -> dual bank WITH gap @@ -1842,7 +1890,7 @@ static int stm32l4_probe(struct flash_bank *bank) page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - if (stm32l4_info->optr & BIT(22)) { + if (stm32l4_info->optr & FLASH_G4_DUAL_BANK) { stm32l4_info->dual_bank_mode = true; page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; @@ -1853,69 +1901,72 @@ static int stm32l4_probe(struct flash_bank *bank) (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb); } break; - case 0x470: /* STM32L4R/L4Sxx */ - case 0x471: /* STM32L4P5/L4Q5x */ + case DEVID_STM32L4R_L4SXX: + case DEVID_STM32L4P_L4QXX: /* STM32L4R/S can be single/dual bank: - * if size = 2M check DBANK bit(22) - * if size = 1M check DB1M bit(21) + * if size = 2M check DBANK bit + * if size = 1M check DB1M bit * STM32L4P/Q can be single/dual bank - * if size = 1M check DBANK bit(22) - * if size = 512K check DB512K bit(21) + * if size = 1M check DBANK bit + * if size = 512K check DB512K bit (same as DB1M bit) */ page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; - if ((use_dbank_bit && (stm32l4_info->optr & BIT(22))) || - (!use_dbank_bit && (stm32l4_info->optr & BIT(21)))) { + if ((is_max_flash_size && (stm32l4_info->optr & FLASH_L4R_DBANK)) || + (!is_max_flash_size && (stm32l4_info->optr & FLASH_LRR_DB1M))) { stm32l4_info->dual_bank_mode = true; page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x472: /* STM32L55/L56xx */ + case DEVID_STM32L55_L56XX: /* STM32L55/L56xx can be single/dual bank: - * if size = 512K check DBANK bit(22) - * if size = 256K check DB256K bit(21) + * if size = 512K check DBANK bit + * if size = 256K check DB256K bit + * + * default page size is 4kb, if DBANK = 1, the page size is 2kb. */ - page_size_kb = 4; + + page_size_kb = (stm32l4_info->optr & FLASH_L5_DBANK) ? 2 : 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; - if ((use_dbank_bit && (stm32l4_info->optr & BIT(22))) || - (!use_dbank_bit && (stm32l4_info->optr & BIT(21)))) { + + if ((is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DBANK)) || + (!is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DB256))) { stm32l4_info->dual_bank_mode = true; - page_size_kb = 2; - num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x482: /* STM32U57/U58xx */ + case DEVID_STM32U57_U58XX: /* if flash size is max (2M) the device is always dual bank - * otherwise check DUALBANK bit(21) + * otherwise check DUALBANK */ page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - if ((flash_size_kb == part_info->max_flash_size_kb) || (stm32l4_info->optr & BIT(21))) { + if (is_max_flash_size || (stm32l4_info->optr & FLASH_U5_DUALBANK)) { stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x495: /* STM32WB5x */ - case 0x496: /* STM32WB3x */ + case DEVID_STM32WB5XX: + case DEVID_STM32WB3XX: /* single bank flash */ page_size_kb = 4; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; break; - case 0x497: /* STM32WLEx/WL5x */ + case DEVID_STM32WLE_WL5XX: /* single bank flash */ page_size_kb = 2; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - if (armv7m->debug_ap->ap_num == 1) + + /* 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 (armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) stm32l4_info->flash_regs = stm32wl_cpu2_flash_regs; break; default: @@ -1923,6 +1974,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; @@ -1943,10 +2003,8 @@ static int stm32l4_probe(struct flash_bank *bank) /* use *max_flash_size* instead of actual size as the trimmed versions * certainly use the same number of bits - * max_flash_size is always power of two, so max_pages too */ uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb; - assert(IS_PWR_OF_2(max_pages)); /* in dual bank mode number of pages is doubled, but extra bit is bank selection */ stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1); @@ -1984,8 +2042,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; @@ -2219,26 +2288,6 @@ COMMAND_HANDLER(stm32l4_handle_trustzone_command) return stm32l4_perform_obl_launch(bank); } -COMMAND_HANDLER(stm32l4_handle_flashloader_command) -{ - if (CMD_ARGC < 1 || CMD_ARGC > 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (retval != ERROR_OK) - return retval; - - struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - - if (CMD_ARGC == 2) - COMMAND_PARSE_ENABLE(CMD_ARGV[1], stm32l4_info->use_flashloader); - - command_print(CMD, "FlashLoader usage is %s", stm32l4_info->use_flashloader ? "enabled" : "disabled"); - - return ERROR_OK; -} - COMMAND_HANDLER(stm32l4_handle_option_load_command) { if (CMD_ARGC != 1) @@ -2444,13 +2493,6 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .usage = "bank_id", .help = "Unlock entire protected flash device.", }, - { - .name = "flashloader", - .handler = stm32l4_handle_flashloader_command, - .mode = COMMAND_EXEC, - .usage = " [enable|disable]", - .help = "Configure the flashloader usage", - }, { .name = "mass_erase", .handler = stm32l4_handle_mass_erase_command,