From 229b3be0549fb8986497d753fbafccd6d105f44d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 17:24:53 +0100 Subject: [PATCH 01/47] stm32f1: Reworked the STM32F1 device identification structure to better re-use the existing code --- src/target/stm32f1.c | 71 +++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index 956dd4df82a..25262cd5a16 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -115,6 +115,10 @@ static bool stm32f1_mass_erase(target_s *target); #define DBGMCU_IDCODE_MM32L0 0x40013400U #define DBGMCU_IDCODE_MM32F3 0x40007080U +#define STM32F1_FLASH_BANK1_BASE 0x08000000U +#define STM32F1_FLASH_BANK2_BASE 0x08080000U +#define STM32F1_SRAM_BASE 0x20000000U + #define STM32F1_TOPT_32BIT_WRITES (1U << 8U) static void stm32f1_add_flash(target_s *target, uint32_t addr, size_t length, size_t erasesize) @@ -519,46 +523,43 @@ bool stm32f1_probe(target_s *target) { const uint16_t device_id = stm32f1_read_idcode(target); - target->mass_erase = stm32f1_mass_erase; + uint32_t ram_size = 0; size_t flash_size = 0; - size_t block_size = 0x400; + size_t block_size = 0; switch (device_id) { case 0x29bU: /* CS clone */ case 0x410U: /* Medium density */ case 0x412U: /* Low density */ case 0x420U: /* Value Line, Low-/Medium density */ - target_add_ram32(target, 0x20000000, 0x5000); - stm32f1_add_flash(target, 0x8000000, 0x20000, 0x400); - target_add_commands(target, stm32f1_cmd_list, "STM32 LD/MD/VL-LD/VL-MD"); - /* Test for clone parts with Core rev 2*/ + ram_size = 0x5000; + flash_size = 0x20000; + block_size = 0x400; + /* Test for clone parts with Core rev 2 */ adiv5_access_port_s *ap = cortex_ap(target); if ((ap->idr >> 28U) > 1U) { - target->driver = "STM32F1 (clone) medium density"; + target->driver = "Clone STM32F1 medium density"; DEBUG_WARN("Detected clone STM32F1\n"); } else - target->driver = "STM32F1 medium density"; - target->part_id = device_id; - return true; + target->driver = "STM32F1 L/M density"; + break; case 0x414U: /* High density */ case 0x418U: /* Connectivity Line */ case 0x428U: /* Value Line, High Density */ - target->driver = "STM32F1 VL density"; - target->part_id = device_id; - target_add_ram32(target, 0x20000000, 0x10000); - stm32f1_add_flash(target, 0x8000000, 0x80000, 0x800); - target_add_commands(target, stm32f1_cmd_list, "STM32 HF/CL/VL-HD"); - return true; + target->driver = "STM32F1 VL density"; + ram_size = 0x10000; + flash_size = 0x80000; + block_size = 0x800; + break; case 0x430U: /* XL-density */ - target->driver = "STM32F1 XL density"; - target->part_id = device_id; - target_add_ram32(target, 0x20000000, 0x18000); - stm32f1_add_flash(target, 0x8000000, 0x80000, 0x800); - stm32f1_add_flash(target, 0x8080000, 0x80000, 0x800); - target_add_commands(target, stm32f1_cmd_list, "STM32 XL/VL-XL"); - return true; + target->driver = "STM32F1 XL density"; + ram_size = 0x18000; + flash_size = 0x80000; + block_size = 0x800; + stm32f1_add_flash(target, STM32F1_FLASH_BANK2_BASE, flash_size, block_size); + break; case 0x438U: /* STM32F303x6/8 and STM32F328 */ case 0x422U: /* STM32F30x */ @@ -569,48 +570,56 @@ bool stm32f1_probe(target_s *target) case 0x432U: /* STM32F37x */ case 0x439U: /* STM32F302C8 */ target->driver = "STM32F3"; - target->part_id = device_id; - target_add_ram32(target, 0x20000000, 0x10000); - stm32f1_add_flash(target, 0x8000000, 0x80000, 0x800); + ram_size = 0x10000; + flash_size = 0x80000; + block_size = 0x800; target_add_commands(target, stm32f1_cmd_list, "STM32F3"); - return true; + break; case 0x444U: /* STM32F03 RM0091 Rev. 7, STM32F030x[4|6] RM0360 Rev. 4 */ target->driver = "STM32F03"; + ram_size = 0x5000; flash_size = 0x8000; + block_size = 0x400; break; case 0x445U: /* STM32F04 RM0091 Rev. 7, STM32F070x6 RM0360 Rev. 4 */ target->driver = "STM32F04/F070x6"; + ram_size = 0x5000; flash_size = 0x8000; + block_size = 0x400; break; case 0x440U: /* STM32F05 RM0091 Rev. 7, STM32F030x8 RM0360 Rev. 4 */ target->driver = "STM32F05/F030x8"; + ram_size = 0x5000; flash_size = 0x10000; + block_size = 0x400; break; case 0x448U: /* STM32F07 RM0091 Rev. 7, STM32F070xb RM0360 Rev. 4 */ target->driver = "STM32F07"; + ram_size = 0x5000; flash_size = 0x20000; block_size = 0x800; break; case 0x442U: /* STM32F09 RM0091 Rev. 7, STM32F030xc RM0360 Rev. 4 */ target->driver = "STM32F09/F030xc"; + ram_size = 0x5000; flash_size = 0x40000; block_size = 0x800; break; default: /* NONE */ - target->mass_erase = NULL; return false; } + target->mass_erase = stm32f1_mass_erase; target->part_id = device_id; - target_add_ram32(target, 0x20000000, 0x5000); - stm32f1_add_flash(target, 0x8000000, flash_size, block_size); - target_add_commands(target, stm32f1_cmd_list, "STM32F0"); + target_add_ram32(target, STM32F1_SRAM_BASE, ram_size); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, flash_size, block_size); + target_add_commands(target, stm32f1_cmd_list, target->driver); return true; } From 889c684b8b2cef986563d2fee44763cd32bf8098 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 17:40:26 +0100 Subject: [PATCH 02/47] stm32f1: Implemented support for halting at least the STM32F1 WDTs when debug halted, and configuring processor debug to work through WFI/WFE --- src/target/stm32f1.c | 55 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index 25262cd5a16..d4fd3fedb9c 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -97,7 +97,16 @@ static bool stm32f1_mass_erase(target_s *target); #define SR_PROG_ERROR 0x04U #define SR_EOP 0x20U -#define DBGMCU_IDCODE 0xe0042000U +#define STM32F1_DBGMCU_BASE 0xe0042000U +#define STM32F1_DBGMCU_IDCODE (STM32F1_DBGMCU_BASE + 0x000U) +#define STM32F1_DBGMCU_CONFIG (STM32F1_DBGMCU_BASE + 0x004U) + +#define STM32F1_DBGMCU_CONFIG_DBG_SLEEP (1U << 0U) +#define STM32F1_DBGMCU_CONFIG_DBG_STOP (1U << 1U) +#define STM32F1_DBGMCU_CONFIG_DBG_STANDBY (1U << 2U) +#define STM32F1_DBGMCU_CONFIG_IWDG_STOP (1U << 8U) +#define STM32F1_DBGMCU_CONFIG_WWDG_STOP (1U << 9U) + #define DBGMCU_IDCODE_F0 0x40015800U #define DBGMCU_IDCODE_GD32E5 0xe0044000U @@ -121,6 +130,11 @@ static bool stm32f1_mass_erase(target_s *target); #define STM32F1_TOPT_32BIT_WRITES (1U << 8U) +typedef struct stm32f1_priv { + target_addr32_t dbgmcu_config_taddr; + uint32_t dbgmcu_config; +} stm32f1_priv_s; + static void stm32f1_add_flash(target_s *target, uint32_t addr, size_t length, size_t erasesize) { target_flash_s *flash = calloc(1, sizeof(*flash)); @@ -139,22 +153,26 @@ static void stm32f1_add_flash(target_s *target, uint32_t addr, size_t length, si target_add_flash(target, flash); } -static uint16_t stm32f1_read_idcode(target_s *const target) +static uint16_t stm32f1_read_idcode(target_s *const target, target_addr32_t *const config_taddr) { if ((target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M0 || - (target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M23) + (target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M23) { return target_mem32_read32(target, DBGMCU_IDCODE_F0) & 0xfffU; + } /* Is this a Cortex-M33 core with STM32F1-style peripherals? (GD32E50x) */ - if ((target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M33) + if ((target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M33) { return target_mem32_read32(target, DBGMCU_IDCODE_GD32E5) & 0xfffU; + } - return target_mem32_read32(target, DBGMCU_IDCODE) & 0xfffU; + *config_taddr = STM32F1_DBGMCU_CONFIG; + return target_mem32_read32(target, STM32F1_DBGMCU_IDCODE) & 0xfffU; } /* Identify GD32F1, GD32F2 and GD32F3 chips */ bool gd32f1_probe(target_s *target) { - const uint16_t device_id = stm32f1_read_idcode(target); + target_addr32_t dbgmcu_config_taddr; + const uint16_t device_id = stm32f1_read_idcode(target, &dbgmcu_config_taddr); size_t block_size = 0x400; switch (device_id) { @@ -220,7 +238,7 @@ bool gd32vf1_probe(target_s *const target) if (target->cpuid != 0x80000022U) return false; /* Then read out the device ID */ - const uint16_t device_id = target_mem32_read32(target, DBGMCU_IDCODE) & 0xfffU; + const uint16_t device_id = target_mem32_read32(target, STM32F1_DBGMCU_IDCODE) & 0xfffU; switch (device_id) { case 0x410U: /* GD32VF103 */ target->driver = "GD32VF1"; @@ -347,7 +365,7 @@ bool at32f40x_probe(target_s *target) return false; // Artery chips use the complete idcode word for identification - const uint32_t idcode = target_mem32_read32(target, DBGMCU_IDCODE); + const uint32_t idcode = target_mem32_read32(target, STM32F1_DBGMCU_IDCODE); const uint32_t series = idcode & AT32F4x_IDCODE_SERIES_MASK; const uint16_t part_id = idcode & AT32F4x_IDCODE_PART_MASK; @@ -521,7 +539,8 @@ bool mm32f3xx_probe(target_s *target) /* Identify real STM32F0/F1/F3 devices */ bool stm32f1_probe(target_s *target) { - const uint16_t device_id = stm32f1_read_idcode(target); + target_addr32_t dbgmcu_config_taddr; + const uint16_t device_id = stm32f1_read_idcode(target, &dbgmcu_config_taddr); uint32_t ram_size = 0; size_t flash_size = 0; @@ -615,11 +634,27 @@ bool stm32f1_probe(target_s *target) return false; } - target->mass_erase = stm32f1_mass_erase; target->part_id = device_id; + + /* Allocate and save private storage */ + stm32f1_priv_s *priv_storage = calloc(1, sizeof(*priv_storage)); + if (!priv_storage) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + priv_storage->dbgmcu_config_taddr = dbgmcu_config_taddr; + priv_storage->dbgmcu_config = target_mem32_read32(target, dbgmcu_config_taddr); + target->target_storage = priv_storage; + + target->mass_erase = stm32f1_mass_erase; target_add_ram32(target, STM32F1_SRAM_BASE, ram_size); stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, flash_size, block_size); target_add_commands(target, stm32f1_cmd_list, target->driver); + + /* Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us */ + target_mem32_write32(target, dbgmcu_config_taddr, + priv_storage->dbgmcu_config | STM32F1_DBGMCU_CONFIG_WWDG_STOP | STM32F1_DBGMCU_CONFIG_IWDG_STOP | + STM32F1_DBGMCU_CONFIG_DBG_STANDBY | STM32F1_DBGMCU_CONFIG_DBG_STOP | STM32F1_DBGMCU_CONFIG_DBG_SLEEP); return true; } From 5d279c560ad5dba5e425b5839780a9c3a0e06412 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 17:40:58 +0100 Subject: [PATCH 03/47] stm32h7: Cleaned up a nomenclature issue in the private structure --- src/target/stm32h7.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/target/stm32h7.c b/src/target/stm32h7.c index 1890e36689d..ec0f9166c57 100644 --- a/src/target/stm32h7.c +++ b/src/target/stm32h7.c @@ -187,7 +187,7 @@ typedef struct stm32h7_flash { } stm32h7_flash_s; typedef struct stm32h7_priv { - uint32_t dbg_cr; + uint32_t dbgmcu_config; char name[STM32H7_NAME_MAX_LENGTH]; } stm32h7_priv_s; @@ -244,7 +244,7 @@ static void stm32h7_add_flash(target_s *target, uint32_t addr, size_t length, si target_add_flash(target, target_flash); } -void stm32h7_configure_wdts(target_s *const target) +static void stm32h7_configure_wdts(target_s *const target) { /* * Feed the watchdogs to ensure things are stable - though note that the DBGMCU writes @@ -277,7 +277,7 @@ bool stm32h7_probe(target_s *target) DEBUG_ERROR("calloc: failed in %s\n", __func__); return false; } - priv_storage->dbg_cr = target_mem32_read32(target, DBGMCU_CONFIG); + priv_storage->dbgmcu_config = target_mem32_read32(target, DBGMCU_CONFIG); target->target_storage = priv_storage; memcpy(priv_storage->name, "STM32", 5U); @@ -311,8 +311,8 @@ bool stm32h7_probe(target_s *target) * debugging through sleep, stop and standby states for domain D1 */ target_mem32_write32(target, DBGMCU_CONFIG, - DBGMCU_CONFIG_DBGSLEEP_D1 | DBGMCU_CONFIG_DBGSTOP_D1 | DBGMCU_CONFIG_DBGSTBY_D1 | DBGMCU_CONFIG_D1DBGCKEN | - DBGMCU_CONFIG_D3DBGCKEN); + priv_storage->dbgmcu_config | DBGMCU_CONFIG_DBGSLEEP_D1 | DBGMCU_CONFIG_DBGSTOP_D1 | DBGMCU_CONFIG_DBGSTBY_D1 | + DBGMCU_CONFIG_D1DBGCKEN | DBGMCU_CONFIG_D3DBGCKEN); stm32h7_configure_wdts(target); /* Build the RAM map */ @@ -421,8 +421,8 @@ static bool stm32h7_attach(target_s *target) static void stm32h7_detach(target_s *target) { - stm32h7_priv_s *ps = (stm32h7_priv_s *)target->target_storage; - target_mem32_write32(target, DBGMCU_CONFIG, ps->dbg_cr); + stm32h7_priv_s *priv = (stm32h7_priv_s *)target->target_storage; + target_mem32_write32(target, DBGMCU_CONFIG, priv->dbgmcu_config); cortexm_detach(target); } From 18e5dadfaf98111d78d074f0d596e5ca36daf2cb Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 18:21:22 +0100 Subject: [PATCH 04/47] stm32f1: Sorted out DBGMCU handling for the GD32E5 parts --- src/target/stm32f1.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index d4fd3fedb9c..b0f94d1a0ac 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -107,8 +107,11 @@ static bool stm32f1_mass_erase(target_s *target); #define STM32F1_DBGMCU_CONFIG_IWDG_STOP (1U << 8U) #define STM32F1_DBGMCU_CONFIG_WWDG_STOP (1U << 9U) -#define DBGMCU_IDCODE_F0 0x40015800U -#define DBGMCU_IDCODE_GD32E5 0xe0044000U +#define DBGMCU_IDCODE_F0 0x40015800U + +#define GD32E5_DBGMCU_BASE 0xe0044000U +#define GD32E5_DBGMCU_IDCODE (GD32E5_DBGMCU_BASE + 0x000U) +#define GD32E5_DBGMCU_CONFIG (GD32E5_DBGMCU_BASE + 0x004U) #define STM32F3_UID_BASE 0x1ffff7acU #define STM32F1_UID_BASE 0x1ffff7e8U @@ -159,9 +162,10 @@ static uint16_t stm32f1_read_idcode(target_s *const target, target_addr32_t *con (target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M23) { return target_mem32_read32(target, DBGMCU_IDCODE_F0) & 0xfffU; } - /* Is this a Cortex-M33 core with STM32F1-style peripherals? (GD32E50x) */ + /* Is this a Cortex-M33 core with STM32F1-style peripherals? (GD32E50x, GD32E51x) */ if ((target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M33) { - return target_mem32_read32(target, DBGMCU_IDCODE_GD32E5) & 0xfffU; + *config_taddr = GD32E5_DBGMCU_CONFIG; + return target_mem32_read32(target, GD32E5_DBGMCU_IDCODE) & 0xfffU; } *config_taddr = STM32F1_DBGMCU_CONFIG; From 65362cfa260fa0992cf2268319ea9ae333ac06f1 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 18:27:25 +0100 Subject: [PATCH 05/47] stm32f1: Fixed and updated all the references for the documentation the target support is built from --- src/target/stm32f1.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index b0f94d1a0ac..cf01a7245ce 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -21,20 +21,20 @@ */ /* - * This file implements STM32 target specific functions for detecting + * This file implements STM32F0/F1 + clones, and GF32E5 target specific functions for detecting * the device, providing the XML memory map and Flash memory programming. * * References: - * ST doc - RM0008 - * Reference manual - STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx - * and STM32F107xx advanced ARM-based 32-bit MCUs - * ST doc - RM0091 - * Reference manual - STM32F0x1/STM32F0x2/STM32F0x8 - * advanced ARM®-based 32-bit MCUs - * ST doc - RM0360 - * Reference manual - STM32F030x4/x6/x8/xC and STM32F070x6/xB - * ST doc - PM0075 - * Programming manual - STM32F10xxx Flash memory microcontrollers + * RM0008 - STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm®-based 32-bit MCUs, Rev. 21 + * https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * RM0091 - STM32F0x1/STM32F0x2/STM32F0x8 advanced ARM®-based 32-bit MCUs + * https://www.st.com/resource/en/reference_manual/rm0091-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * RM0360 - STM32F030x4/x6/x8/xC and STM32F070x6/xB + * https://www.st.com/resource/en/reference_manual/rm0360-stm32f030x4x6x8xc-and-stm32f070x6xb-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * PM0075 - STM32F10xxx Flash memory microcontrollers + * https://www.st.com/resource/en/programming_manual/pm0075-stm32f10xxx-flash-memory-microcontrollers-stmicroelectronics.pdf + * GD32E51x Arm® Cortex®-M33 32-bit MCU User Manual, Rev. 1.2 + * https://www.gigadevice.com.cn/Public/Uploads/uploadfile/files/20240611/GD32E51x_User_Manual_Rev1.2.pdf */ #include "general.h" From 4d084ae93811455d71686c780bb97b89e0d7f5ff Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 18:48:29 +0100 Subject: [PATCH 06/47] stm32f1: Sorted out DBGMCU handling for the STM32F0 parts --- src/target/stm32f1.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index cf01a7245ce..3e055d62853 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -107,7 +107,16 @@ static bool stm32f1_mass_erase(target_s *target); #define STM32F1_DBGMCU_CONFIG_IWDG_STOP (1U << 8U) #define STM32F1_DBGMCU_CONFIG_WWDG_STOP (1U << 9U) -#define DBGMCU_IDCODE_F0 0x40015800U +#define STM32F0_DBGMCU_BASE 0x40015800U +#define STM32F0_DBGMCU_IDCODE (STM32F0_DBGMCU_BASE + 0x000U) +#define STM32F0_DBGMCU_CONFIG (STM32F0_DBGMCU_BASE + 0x004U) +#define STM32F0_DBGMCU_APB1FREEZE (STM32F0_DBGMCU_BASE + 0x008U) +#define STM32F0_DBGMCU_APB2FREEZE (STM32F0_DBGMCU_BASE + 0x00cU) + +#define STM32F0_DBGMCU_CONFIG_DBG_STOP (1U << 1U) +#define STM32F0_DBGMCU_CONFIG_DBG_STANDBY (1U << 2U) +#define STM32F0_DBGMCU_APB1FREEZE_WWDG (1U << 11U) +#define STM32F0_DBGMCU_APB1FREEZE_IWDG (1U << 12U) #define GD32E5_DBGMCU_BASE 0xe0044000U #define GD32E5_DBGMCU_IDCODE (GD32E5_DBGMCU_BASE + 0x000U) @@ -160,7 +169,8 @@ static uint16_t stm32f1_read_idcode(target_s *const target, target_addr32_t *con { if ((target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M0 || (target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M23) { - return target_mem32_read32(target, DBGMCU_IDCODE_F0) & 0xfffU; + *config_taddr = STM32F0_DBGMCU_CONFIG; + return target_mem32_read32(target, STM32F0_DBGMCU_IDCODE) & 0xfffU; } /* Is this a Cortex-M33 core with STM32F1-style peripherals? (GD32E50x, GD32E51x) */ if ((target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M33) { @@ -172,6 +182,28 @@ static uint16_t stm32f1_read_idcode(target_s *const target, target_addr32_t *con return target_mem32_read32(target, STM32F1_DBGMCU_IDCODE) & 0xfffU; } +static void stm32f1_configure_dbgmcu(target_s *const target) +{ + const stm32f1_priv_s *const priv = (stm32f1_priv_s *)target->target_storage; + const target_addr32_t dbgmcu_config_taddr = priv->dbgmcu_config_taddr; + /* Figure out which style of DBGMCU we're working with */ + if (dbgmcu_config_taddr == STM32F0_DBGMCU_CONFIG) { + /* Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us */ + target_mem32_write32( + target, STM32F0_DBGMCU_APB1FREEZE, STM32F0_DBGMCU_APB1FREEZE_IWDG | STM32F0_DBGMCU_APB1FREEZE_WWDG); + /* Then Reconfigure the config register to prevent WFI/WFE from cutting debug access */ + target_mem32_write32( + target, STM32F0_DBGMCU_CONFIG, STM32F0_DBGMCU_CONFIG_DBG_STANDBY | STM32F0_DBGMCU_CONFIG_DBG_STOP); + } else + /* + * Reconfigure the DBGMCU to prevent the WDTs causing havoc and problems + * and WFI/WFE from cutting debug access too + */ + target_mem32_write32(target, dbgmcu_config_taddr, + priv->dbgmcu_config | STM32F1_DBGMCU_CONFIG_WWDG_STOP | STM32F1_DBGMCU_CONFIG_IWDG_STOP | + STM32F1_DBGMCU_CONFIG_DBG_STANDBY | STM32F1_DBGMCU_CONFIG_DBG_STOP | STM32F1_DBGMCU_CONFIG_DBG_SLEEP); +} + /* Identify GD32F1, GD32F2 and GD32F3 chips */ bool gd32f1_probe(target_s *target) { @@ -656,9 +688,7 @@ bool stm32f1_probe(target_s *target) target_add_commands(target, stm32f1_cmd_list, target->driver); /* Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us */ - target_mem32_write32(target, dbgmcu_config_taddr, - priv_storage->dbgmcu_config | STM32F1_DBGMCU_CONFIG_WWDG_STOP | STM32F1_DBGMCU_CONFIG_IWDG_STOP | - STM32F1_DBGMCU_CONFIG_DBG_STANDBY | STM32F1_DBGMCU_CONFIG_DBG_STOP | STM32F1_DBGMCU_CONFIG_DBG_SLEEP); + stm32f1_configure_dbgmcu(target); return true; } From c69bfbc07567374c5a5f5c786c753e88a2650906 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 18:54:15 +0100 Subject: [PATCH 07/47] stm32f1: Made use of the new DBGMCU machinary for the GD32F{1,2,3} parts as well --- src/target/stm32f1.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index 3e055d62853..dabaa30d505 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -182,8 +182,22 @@ static uint16_t stm32f1_read_idcode(target_s *const target, target_addr32_t *con return target_mem32_read32(target, STM32F1_DBGMCU_IDCODE) & 0xfffU; } -static void stm32f1_configure_dbgmcu(target_s *const target) +static bool stm32f1_configure_dbgmcu(target_s *const target, const target_addr32_t dbgmcu_config) { + /* If we're in the probe phase */ + if (target->target_storage == NULL) { + /* Allocate and save private storage */ + stm32f1_priv_s *const priv_storage = calloc(1, sizeof(*priv_storage)); + if (!priv_storage) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + priv_storage->dbgmcu_config_taddr = dbgmcu_config; + /* Get the current value of the debug config register (and store it for later) */ + priv_storage->dbgmcu_config = target_mem32_read32(target, dbgmcu_config); + target->target_storage = priv_storage; + } + const stm32f1_priv_s *const priv = (stm32f1_priv_s *)target->target_storage; const target_addr32_t dbgmcu_config_taddr = priv->dbgmcu_config_taddr; /* Figure out which style of DBGMCU we're working with */ @@ -202,6 +216,7 @@ static void stm32f1_configure_dbgmcu(target_s *const target) target_mem32_write32(target, dbgmcu_config_taddr, priv->dbgmcu_config | STM32F1_DBGMCU_CONFIG_WWDG_STOP | STM32F1_DBGMCU_CONFIG_IWDG_STOP | STM32F1_DBGMCU_CONFIG_DBG_STANDBY | STM32F1_DBGMCU_CONFIG_DBG_STOP | STM32F1_DBGMCU_CONFIG_DBG_SLEEP); + return true; } /* Identify GD32F1, GD32F2 and GD32F3 chips */ @@ -263,7 +278,8 @@ bool gd32f1_probe(target_s *target) target_add_ram32(target, 0x20000000, ram_size * 1024U); target_add_commands(target, stm32f1_cmd_list, target->driver); - return true; + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + return stm32f1_configure_dbgmcu(target, dbgmcu_config_taddr); } #ifdef ENABLE_RISCV @@ -671,25 +687,13 @@ bool stm32f1_probe(target_s *target) } target->part_id = device_id; - - /* Allocate and save private storage */ - stm32f1_priv_s *priv_storage = calloc(1, sizeof(*priv_storage)); - if (!priv_storage) { /* calloc failed: heap exhaustion */ - DEBUG_ERROR("calloc: failed in %s\n", __func__); - return false; - } - priv_storage->dbgmcu_config_taddr = dbgmcu_config_taddr; - priv_storage->dbgmcu_config = target_mem32_read32(target, dbgmcu_config_taddr); - target->target_storage = priv_storage; - target->mass_erase = stm32f1_mass_erase; target_add_ram32(target, STM32F1_SRAM_BASE, ram_size); stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, flash_size, block_size); target_add_commands(target, stm32f1_cmd_list, target->driver); - /* Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us */ - stm32f1_configure_dbgmcu(target); - return true; + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + return stm32f1_configure_dbgmcu(target, dbgmcu_config_taddr); } static bool stm32f1_flash_unlock(target_s *target, uint32_t bank_offset) From 06d51a4f2d791a3e11dbf3150204ce4dee87a8ab Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 18:59:45 +0100 Subject: [PATCH 08/47] stm32f1: Properly handle the WDTs and WFI/WFE state for the DBGMCU when attaching and detaching --- src/target/stm32f1.c | 49 ++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index dabaa30d505..c613bf31f49 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -44,19 +44,6 @@ #include "jep106.h" #include "stm32_common.h" -static bool stm32f1_cmd_option(target_s *target, int argc, const char **argv); -static bool stm32f1_cmd_uid(target_s *target, int argc, const char **argv); - -const command_s stm32f1_cmd_list[] = { - {"option", stm32f1_cmd_option, "Manipulate option bytes"}, - {"uid", stm32f1_cmd_uid, "Print unique device ID"}, - {NULL, NULL, NULL}, -}; - -static bool stm32f1_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); -static bool stm32f1_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool stm32f1_mass_erase(target_s *target); - /* Flash Program ad Erase Controller Register Map */ #define FPEC_BASE 0x40022000U #define FLASH_ACR (FPEC_BASE + 0x00U) @@ -147,6 +134,21 @@ typedef struct stm32f1_priv { uint32_t dbgmcu_config; } stm32f1_priv_s; +static bool stm32f1_cmd_option(target_s *target, int argc, const char **argv); +static bool stm32f1_cmd_uid(target_s *target, int argc, const char **argv); + +const command_s stm32f1_cmd_list[] = { + {"option", stm32f1_cmd_option, "Manipulate option bytes"}, + {"uid", stm32f1_cmd_uid, "Print unique device ID"}, + {NULL, NULL, NULL}, +}; + +static bool stm32f1_attach(target_s *target); +static void stm32f1_detach(target_s *target); +static bool stm32f1_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); +static bool stm32f1_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); +static bool stm32f1_mass_erase(target_s *target); + static void stm32f1_add_flash(target_s *target, uint32_t addr, size_t length, size_t erasesize) { target_flash_s *flash = calloc(1, sizeof(*flash)); @@ -196,6 +198,9 @@ static bool stm32f1_configure_dbgmcu(target_s *const target, const target_addr32 /* Get the current value of the debug config register (and store it for later) */ priv_storage->dbgmcu_config = target_mem32_read32(target, dbgmcu_config); target->target_storage = priv_storage; + + target->attach = stm32f1_attach; + target->detach = stm32f1_detach; } const stm32f1_priv_s *const priv = (stm32f1_priv_s *)target->target_storage; @@ -696,6 +701,24 @@ bool stm32f1_probe(target_s *target) return stm32f1_configure_dbgmcu(target, dbgmcu_config_taddr); } +static bool stm32f1_attach(target_s *const target) +{ + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + return cortexm_attach(target) && stm32f1_configure_dbgmcu(target, 0U); +} + +static void stm32f1_detach(target_s *const target) +{ + const stm32f1_priv_s *const priv = (stm32f1_priv_s *)target->target_storage; + /* Reverse all changes to the DBGMCU config register */ + target_mem32_write32(target, priv->dbgmcu_config_taddr, priv->dbgmcu_config); + /* Now defer to the normal Cortex-M detach routine to complete the detach */ + cortexm_detach(target); +} + static bool stm32f1_flash_unlock(target_s *target, uint32_t bank_offset) { target_mem32_write32(target, FLASH_KEYR + bank_offset, KEY1); From 8f49985735cc0c019675257b317a4b041f9f8885 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 20:35:58 +0100 Subject: [PATCH 09/47] stm32f1: More documentation links for parts supported by this implementation, and handling for the GD32VF103's DBGMCU --- src/target/stm32f1.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index c613bf31f49..513434935a3 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -33,8 +33,12 @@ * https://www.st.com/resource/en/reference_manual/rm0360-stm32f030x4x6x8xc-and-stm32f070x6xb-advanced-armbased-32bit-mcus-stmicroelectronics.pdf * PM0075 - STM32F10xxx Flash memory microcontrollers * https://www.st.com/resource/en/programming_manual/pm0075-stm32f10xxx-flash-memory-microcontrollers-stmicroelectronics.pdf + * GD32E50x Arm® Cortex®-M33 32-bit MCU User Manual, Rev. 1.8 + * https://www.gigadevice.com.cn/Public/Uploads/uploadfile/files/20240407/GD32E50x_User_Manual_Rev1.8.pdf * GD32E51x Arm® Cortex®-M33 32-bit MCU User Manual, Rev. 1.2 * https://www.gigadevice.com.cn/Public/Uploads/uploadfile/files/20240611/GD32E51x_User_Manual_Rev1.2.pdf + * GD32VF103 RISC-V 32-bit MCU User Manual, Rev. 1.5 + * https://www.gigadevice.com.cn/Public/Uploads/uploadfile/files/20240407/GD32VF103_User_Manual_Rev1.5.pdf */ #include "general.h" @@ -224,7 +228,7 @@ static bool stm32f1_configure_dbgmcu(target_s *const target, const target_addr32 return true; } -/* Identify GD32F1, GD32F2 and GD32F3 chips */ +/* Identify GD32F1, GD32F2, GD32F3, GD32E230 and GD32E5 chips */ bool gd32f1_probe(target_s *target) { target_addr32_t dbgmcu_config_taddr; @@ -314,7 +318,8 @@ bool gd32vf1_probe(target_s *const target) stm32f1_add_flash(target, 0x8000000, (size_t)flash_size * 1024U, 0x400U); target_add_commands(target, stm32f1_cmd_list, target->driver); - return true; + /* Now we have a stable debug environment, make sure the WDTs + sleep instructions can't cause problems */ + return stm32f1_configure_dbgmcu(target, STM32F1_DBGMCU_CONFIG); } #endif From 4e857860aa5673c2b202d34e58be2ca298f13be4 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 20:41:24 +0100 Subject: [PATCH 10/47] stm32f1: Added handling for the AT32F40x and AT32F41x parts' DBGMCUs --- src/target/stm32f1.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index 513434935a3..e3a9dadce41 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -378,7 +378,9 @@ static bool at32f40_detect(target_s *target, const uint16_t part_id) target->part_id = part_id; target->target_options |= STM32F1_TOPT_32BIT_WRITES; target->mass_erase = stm32f1_mass_erase; - return true; + + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + return stm32f1_configure_dbgmcu(target, STM32F1_DBGMCU_CONFIG); } static bool at32f41_detect(target_s *target, const uint16_t part_id) @@ -416,7 +418,9 @@ static bool at32f41_detect(target_s *target, const uint16_t part_id) target->part_id = part_id; target->target_options |= STM32F1_TOPT_32BIT_WRITES; target->mass_erase = stm32f1_mass_erase; - return true; + + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + return stm32f1_configure_dbgmcu(target, STM32F1_DBGMCU_CONFIG); } /* Identify AT32F40x "Mainstream" line devices (Cortex-M4) */ From 8c9c2c6d49ebf416cc57587d8164abc8a5e732ff Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 20:41:45 +0100 Subject: [PATCH 11/47] stm32f1: More use of the base address macros to clean up all the magic number spew --- src/target/stm32f1.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index e3a9dadce41..88018b794a8 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -276,15 +276,15 @@ bool gd32f1_probe(target_s *target) */ if (flash_size > 512U) { const uint16_t flash_size_bank1 = flash_size - 512U; - stm32f1_add_flash(target, 0x8000000, 512U * 1024U, block_size); - stm32f1_add_flash(target, 0x8080000, flash_size_bank1 * 1024U, 0x1000U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, 512U * 1024U, block_size); + stm32f1_add_flash(target, STM32F1_FLASH_BANK2_BASE, flash_size_bank1 * 1024U, 0x1000U); } else - stm32f1_add_flash(target, 0x8000000, (size_t)flash_size * 1024U, block_size); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, (size_t)flash_size * 1024U, block_size); target->part_id = device_id; target->target_options |= STM32F1_TOPT_32BIT_WRITES; target->mass_erase = stm32f1_mass_erase; - target_add_ram32(target, 0x20000000, ram_size * 1024U); + target_add_ram32(target, STM32F1_SRAM_BASE, ram_size * 1024U); target_add_commands(target, stm32f1_cmd_list, target->driver); /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ @@ -314,8 +314,8 @@ bool gd32vf1_probe(target_s *const target) target->part_id = device_id; target->mass_erase = stm32f1_mass_erase; - target_add_ram32(target, 0x20000000, ram_size * 1024U); - stm32f1_add_flash(target, 0x8000000, (size_t)flash_size * 1024U, 0x400U); + target_add_ram32(target, STM32F1_SRAM_BASE, ram_size * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, (size_t)flash_size * 1024U, 0x400U); target_add_commands(target, stm32f1_cmd_list, target->driver); /* Now we have a stable debug environment, make sure the WDTs + sleep instructions can't cause problems */ @@ -352,7 +352,7 @@ static bool at32f40_detect(target_s *target, const uint16_t part_id) case 0x024aU: // AT32F407RCT7 / LQFP64 case 0x0254U: // AT32F407AVCT7 / LQFP100 // Flash (C): 256 KiB / 2 KiB per block - stm32f1_add_flash(target, 0x08000000, 256U * 1024U, 2U * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, 256U * 1024U, 2U * 1024U); break; case 0x02cdU: // AT32F403AVET7 / LQFP100 case 0x02ceU: // AT32F403ARET7 / LQFP64 @@ -361,19 +361,19 @@ static bool at32f40_detect(target_s *target, const uint16_t part_id) case 0x02d1U: // AT32F407VET7 / LQFP100 case 0x02d2U: // AT32F407RET7 / LQFP64 // Flash (E): 512 KiB / 2 KiB per block - stm32f1_add_flash(target, 0x08000000, 512U * 1024U, 2U * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, 512U * 1024U, 2U * 1024U); break; default: if (at32f40_is_dual_bank(part_id)) { // Flash (G): 1024 KiB / 2 KiB per block, dual-bank - stm32f1_add_flash(target, 0x08000000, 512U * 1024U, 2U * 1024U); - stm32f1_add_flash(target, 0x08080000, 512U * 1024U, 2U * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, 512U * 1024U, 2U * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK2_BASE, 512U * 1024U, 2U * 1024U); break; } else // Unknown/undocumented return false; } // All parts have 96 KiB SRAM - target_add_ram32(target, 0x20000000, 96U * 1024U); + target_add_ram32(target, STM32F1_SRAM_BASE, 96U * 1024U); target->driver = "AT32F403A/407"; target->part_id = part_id; target->target_options |= STM32F1_TOPT_32BIT_WRITES; @@ -392,7 +392,7 @@ static bool at32f41_detect(target_s *target, const uint16_t part_id) case 0x0243U: // LQFP64_7x7 case 0x024cU: // QFN48_6x6 // Flash (C): 256 KiB / 2 KiB per block - stm32f1_add_flash(target, 0x08000000, 256U * 1024U, 2U * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, 256U * 1024U, 2U * 1024U); break; case 0x01c4U: // LQFP64_10x10 case 0x01c5U: // LQFP48_7x7 @@ -400,20 +400,20 @@ static bool at32f41_detect(target_s *target, const uint16_t part_id) case 0x01c7U: // LQFP64_7x7 case 0x01cdU: // QFN48_6x6 // Flash (B): 128 KiB / 2 KiB per block - stm32f1_add_flash(target, 0x08000000, 128U * 1024U, 2U * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, 128U * 1024U, 2U * 1024U); break; case 0x0108U: // LQFP64_10x10 case 0x0109U: // LQFP48_7x7 case 0x010aU: // QFN32_4x4 // Flash (8): 64 KiB / 2 KiB per block - stm32f1_add_flash(target, 0x08000000, 64U * 1024U, 2U * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, 64U * 1024U, 2U * 1024U); break; // Unknown/undocumented default: return false; } // All parts have 32 KiB SRAM - target_add_ram32(target, 0x20000000, 32U * 1024U); + target_add_ram32(target, STM32F1_SRAM_BASE, 32U * 1024U); target->driver = "AT32F415"; target->part_id = part_id; target->target_options |= STM32F1_TOPT_32BIT_WRITES; @@ -511,7 +511,6 @@ void mm32l0_mem_write_sized(adiv5_access_port_s *ap, target_addr64_t dest, const } /* Identify MM32 devices (Cortex-M0) */ - bool mm32l0xx_probe(target_s *target) { const char *name; @@ -550,8 +549,8 @@ bool mm32l0xx_probe(target_s *target) target->part_id = mm32_id & 0xfffU; target->driver = name; target->mass_erase = stm32f1_mass_erase; - target_add_ram32(target, 0x20000000U, ram_kbyte * 1024U); - stm32f1_add_flash(target, 0x08000000U, flash_kbyte * 1024U, block_size); + target_add_ram32(target, STM32F1_SRAM_BASE, ram_kbyte * 1024U); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, flash_kbyte * 1024U, block_size); target_add_commands(target, stm32f1_cmd_list, name); cortex_ap(target)->dp->mem_write = mm32l0_mem_write_sized; return true; @@ -594,10 +593,10 @@ bool mm32f3xx_probe(target_s *target) target->driver = name; target->mass_erase = stm32f1_mass_erase; if (ram1_kbyte != 0) - target_add_ram32(target, 0x20000000U, ram1_kbyte * 1024U); + target_add_ram32(target, STM32F1_SRAM_BASE, ram1_kbyte * 1024U); if (ram2_kbyte != 0) target_add_ram32(target, 0x30000000U, ram2_kbyte * 1024U); - stm32f1_add_flash(target, 0x08000000U, flash_kbyte * 1024U, block_size); + stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, flash_kbyte * 1024U, block_size); target_add_commands(target, stm32f1_cmd_list, name); return true; } From 24b52d96c5b1e6513d4c3aa84e6ffeb9cea6e3f0 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 20:52:03 +0100 Subject: [PATCH 12/47] stm32f1: Added handling for the MM32L0 parts' DBGMCUs --- src/target/stm32f1.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index 88018b794a8..480260d560c 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -39,6 +39,8 @@ * https://www.gigadevice.com.cn/Public/Uploads/uploadfile/files/20240611/GD32E51x_User_Manual_Rev1.2.pdf * GD32VF103 RISC-V 32-bit MCU User Manual, Rev. 1.5 * https://www.gigadevice.com.cn/Public/Uploads/uploadfile/files/20240407/GD32VF103_User_Manual_Rev1.5.pdf + * MM32L0xx 32-bit Microcontroller Based on ARM Cortex M0 Core, Version 1.15_n + * https://www.mindmotion.com.cn/download/products/UM_MM32L0xx_n_EN.pdf */ #include "general.h" @@ -113,6 +115,10 @@ #define GD32E5_DBGMCU_IDCODE (GD32E5_DBGMCU_BASE + 0x000U) #define GD32E5_DBGMCU_CONFIG (GD32E5_DBGMCU_BASE + 0x004U) +#define MM32L0_DBGMCU_BASE 0x40013400U +#define MM32L0_DBGMCU_IDCODE (MM32L0_DBGMCU_BASE + 0x000U) +#define MM32L0_DBGMCU_CONFIG (MM32L0_DBGMCU_BASE + 0x004U) + #define STM32F3_UID_BASE 0x1ffff7acU #define STM32F1_UID_BASE 0x1ffff7e8U @@ -124,7 +130,6 @@ #define AT32F41_SERIES 0x70030000U #define AT32F40_SERIES 0x70050000U -#define DBGMCU_IDCODE_MM32L0 0x40013400U #define DBGMCU_IDCODE_MM32F3 0x40007080U #define STM32F1_FLASH_BANK1_BASE 0x08000000U @@ -513,29 +518,28 @@ void mm32l0_mem_write_sized(adiv5_access_port_s *ap, target_addr64_t dest, const /* Identify MM32 devices (Cortex-M0) */ bool mm32l0xx_probe(target_s *target) { - const char *name; size_t flash_kbyte = 0; size_t ram_kbyte = 0; size_t block_size = 0x400U; - const uint32_t mm32_id = target_mem32_read32(target, DBGMCU_IDCODE_MM32L0); + const uint32_t mm32_id = target_mem32_read32(target, MM32L0_DBGMCU_IDCODE); if (target_check_error(target)) { - DEBUG_ERROR("%s: read error at 0x%" PRIx32 "\n", __func__, (uint32_t)DBGMCU_IDCODE_MM32L0); + DEBUG_ERROR("%s: read error at 0x%" PRIx32 "\n", __func__, (uint32_t)MM32L0_DBGMCU_IDCODE); return false; } switch (mm32_id) { case 0xcc568091U: - name = "MM32L07x"; + target->driver = "MM32L07x"; flash_kbyte = 128; ram_kbyte = 8; break; case 0xcc4460b1: - name = "MM32SPIN05"; + target->driver = "MM32SPIN05"; flash_kbyte = 32; ram_kbyte = 4; break; case 0xcc56a097U: - name = "MM32SPIN27"; + target->driver = "MM32SPIN27"; flash_kbyte = 128; ram_kbyte = 12; break; @@ -547,13 +551,14 @@ bool mm32l0xx_probe(target_s *target) return false; } target->part_id = mm32_id & 0xfffU; - target->driver = name; target->mass_erase = stm32f1_mass_erase; target_add_ram32(target, STM32F1_SRAM_BASE, ram_kbyte * 1024U); stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, flash_kbyte * 1024U, block_size); - target_add_commands(target, stm32f1_cmd_list, name); + target_add_commands(target, stm32f1_cmd_list, target->driver); cortex_ap(target)->dp->mem_write = mm32l0_mem_write_sized; - return true; + + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + return stm32f1_configure_dbgmcu(target, MM32L0_DBGMCU_CONFIG); } /* Identify MM32 devices (Cortex-M3, Star-MC1) */ From bd8bfe24a69e1ce9792b8056120b317958efd302 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 9 Jul 2024 21:02:07 +0100 Subject: [PATCH 13/47] stm32f1: Added handling for the MM32F3 and MM32F5 parts' DBGMCUs --- src/target/stm32f1.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index 480260d560c..bac86a7860b 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -41,6 +41,10 @@ * https://www.gigadevice.com.cn/Public/Uploads/uploadfile/files/20240407/GD32VF103_User_Manual_Rev1.5.pdf * MM32L0xx 32-bit Microcontroller Based on ARM Cortex M0 Core, Version 1.15_n * https://www.mindmotion.com.cn/download/products/UM_MM32L0xx_n_EN.pdf + * MM32F3270 32-bit Microcontroller Based on Arm®Cortex®-M3 Core, Version 1.04 + * https://www.mindmotion.com.cn/download/products/UM_MM32F3270_EN.pdf + * MM32F5270/MM32F5280 32-bit Microcontrollers based on Arm China STAR-MC1, Version 0.9 + * https://www.mindmotion.com.cn/download/products/UM_MM32F5270_MM32F5280_EN.pdf */ #include "general.h" @@ -119,6 +123,10 @@ #define MM32L0_DBGMCU_IDCODE (MM32L0_DBGMCU_BASE + 0x000U) #define MM32L0_DBGMCU_CONFIG (MM32L0_DBGMCU_BASE + 0x004U) +#define MM32F3_DBGMCU_BASE 0x40007080U +#define MM32F3_DBGMCU_IDCODE (MM32F3_DBGMCU_BASE + 0x000U) +#define MM32F3_DBGMCU_CONFIG (MM32F3_DBGMCU_BASE + 0x004U) + #define STM32F3_UID_BASE 0x1ffff7acU #define STM32F1_UID_BASE 0x1ffff7e8U @@ -130,8 +138,6 @@ #define AT32F41_SERIES 0x70030000U #define AT32F40_SERIES 0x70050000U -#define DBGMCU_IDCODE_MM32F3 0x40007080U - #define STM32F1_FLASH_BANK1_BASE 0x08000000U #define STM32F1_FLASH_BANK2_BASE 0x08080000U #define STM32F1_SRAM_BASE 0x20000000U @@ -564,25 +570,24 @@ bool mm32l0xx_probe(target_s *target) /* Identify MM32 devices (Cortex-M3, Star-MC1) */ bool mm32f3xx_probe(target_s *target) { - const char *name; size_t flash_kbyte = 0; size_t ram1_kbyte = 0; /* ram at 0x20000000 */ size_t ram2_kbyte = 0; /* ram at 0x30000000 */ size_t block_size = 0x400U; - const uint32_t mm32_id = target_mem32_read32(target, DBGMCU_IDCODE_MM32F3); + const uint32_t mm32_id = target_mem32_read32(target, MM32F3_DBGMCU_IDCODE); if (target_check_error(target)) { - DEBUG_ERROR("%s: read error at 0x%" PRIx32 "\n", __func__, (uint32_t)DBGMCU_IDCODE_MM32F3); + DEBUG_ERROR("%s: read error at 0x%" PRIx32 "\n", __func__, (uint32_t)MM32F3_DBGMCU_IDCODE); return false; } switch (mm32_id) { case 0xcc9aa0e7U: - name = "MM32F3273"; + target->driver = "MM32F327"; flash_kbyte = 512; ram1_kbyte = 128; break; case 0x4d4d0800U: - name = "MM32F5277"; + target->driver = "MM32F52"; flash_kbyte = 256; ram1_kbyte = 32; ram2_kbyte = 128; @@ -594,16 +599,18 @@ bool mm32f3xx_probe(target_s *target) DEBUG_WARN("%s: unknown mm32 ID code 0x%" PRIx32 "\n", __func__, mm32_id); return false; } + target->part_id = mm32_id & 0xfffU; - target->driver = name; target->mass_erase = stm32f1_mass_erase; if (ram1_kbyte != 0) target_add_ram32(target, STM32F1_SRAM_BASE, ram1_kbyte * 1024U); if (ram2_kbyte != 0) target_add_ram32(target, 0x30000000U, ram2_kbyte * 1024U); stm32f1_add_flash(target, STM32F1_FLASH_BANK1_BASE, flash_kbyte * 1024U, block_size); - target_add_commands(target, stm32f1_cmd_list, name); - return true; + target_add_commands(target, stm32f1_cmd_list, target->driver); + + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + return stm32f1_configure_dbgmcu(target, MM32F3_DBGMCU_CONFIG); } /* Identify real STM32F0/F1/F3 devices */ From 01baa135a329909bad28d722c928583916b6a0bf Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 10 Jul 2024 18:30:27 +0100 Subject: [PATCH 14/47] stm32f4: General cleanup an docs links for the implementation --- src/target/stm32f4.c | 81 +++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/src/target/stm32f4.c b/src/target/stm32f4.c index 38931815f92..79ce6347c9f 100644 --- a/src/target/stm32f4.c +++ b/src/target/stm32f4.c @@ -27,9 +27,11 @@ * * References: * RM0090 - STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 advanced Arm®-based 32-bit MCUs, Rev. 20 - * https://www.st.com/resource/en/reference_manual/rm0090-stm32f405415-stm32f407417-stm32f427437-and-stm32f429439-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - * RM0401 - STM32F410 advanced Arm®-based 32-bit MCUs - * https://www.st.com/resource/en/reference_manual/rm0401-stm32f410-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * https://www.st.com/resource/en/reference_manual/rm0090-stm32f405415-stm32f407417-stm32f427437-and-stm32f429439-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * RM0401 - STM32F410 advanced Arm®-based 32-bit MCUs, Rev. 3 + * https://www.st.com/resource/en/reference_manual/rm0401-stm32f410-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * GD32F4xx Arm® Cortex®-M4 32-bit MCU User Manual, Rev. 3.0 + * https://www.gigadevice.com.cn/Public/Uploads/uploadfile/files/20240407/GD32F4xx_User_Manual_Rev3.0.pdf */ #include "general.h" @@ -38,23 +40,6 @@ #include "cortexm.h" #include "stm32_common.h" -static bool stm32f4_cmd_option(target_s *target, int argc, const char **argv); -static bool stm32f4_cmd_psize(target_s *target, int argc, const char **argv); -static bool stm32f4_cmd_uid(target_s *target, int argc, const char **argv); - -const command_s stm32f4_cmd_list[] = { - {"option", stm32f4_cmd_option, "Manipulate option bytes"}, - {"psize", stm32f4_cmd_psize, "Configure flash write parallelism: (x8|x16|x32(default)|x64)"}, - {"uid", stm32f4_cmd_uid, "Print unique device ID"}, - {NULL, NULL, NULL}, -}; - -static bool stm32f4_attach(target_s *target); -static void stm32f4_detach(target_s *target); -static bool stm32f4_flash_erase(target_flash_s *target_flash, target_addr_t addr, size_t len); -static bool stm32f4_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool stm32f4_mass_erase(target_s *target); - /* Flash Program and Erase Controller Register Map */ #define FPEC_BASE 0x40023c00U #define FLASH_ACR (FPEC_BASE + 0x00U) @@ -120,17 +105,6 @@ static bool stm32f4_mass_erase(target_s *target); #define STM32F4_DBGMCU_APB1FREEZE_WWDG (1U << 11U) #define STM32F4_DBGMCU_APB1FREEZE_IWDG (1U << 12U) -typedef struct stm32f4_flash { - target_flash_s flash; - uint8_t base_sector; - uint8_t bank_split; -} stm32f4_flash_s; - -typedef struct stm32f4_priv { - uint32_t dbgmcu_cr; - align_e psize; -} stm32f4_priv_s; - #define ID_STM32F20X 0x411U #define ID_STM32F40X 0x413U #define ID_STM32F42X 0x419U @@ -149,6 +123,35 @@ typedef struct stm32f4_priv { #define ID_GD32F470 0xa2eU #define ID_GD32F405 0xfa4U +typedef struct stm32f4_flash { + target_flash_s flash; + uint8_t base_sector; + uint8_t bank_split; +} stm32f4_flash_s; + +typedef struct stm32f4_priv { + uint32_t dbgmcu_cr; + align_e psize; +} stm32f4_priv_s; + +static bool stm32f4_cmd_option(target_s *target, int argc, const char **argv); +static bool stm32f4_cmd_psize(target_s *target, int argc, const char **argv); +static bool stm32f4_cmd_uid(target_s *target, int argc, const char **argv); + +const command_s stm32f4_cmd_list[] = { + {"option", stm32f4_cmd_option, "Manipulate option bytes"}, + {"psize", stm32f4_cmd_psize, "Configure flash write parallelism: (x8|x16|x32(default)|x64)"}, + {"uid", stm32f4_cmd_uid, "Print unique device ID"}, + {NULL, NULL, NULL}, +}; + +static bool stm32f4_attach(target_s *target); +static bool gd32f4_attach(target_s *target); +static void stm32f4_detach(target_s *target); +static bool stm32f4_flash_erase(target_flash_s *target_flash, target_addr_t addr, size_t len); +static bool stm32f4_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); +static bool stm32f4_mass_erase(target_s *target); + static void stm32f4_add_flash(target_s *const target, const uint32_t addr, const size_t length, const size_t blocksize, const uint8_t base_sector, const uint8_t split) { @@ -303,18 +306,18 @@ bool gd32f4_probe(target_s *target) /* TODO implement DBS mode */ const uint8_t split = 12; - /* Bank 1*/ - stm32f4_add_flash(target, 0x8000000, 0x10000, 0x4000, 0, split); /* 4 16K */ - stm32f4_add_flash(target, 0x8010000, 0x10000, 0x10000, 4, split); /* 1 64K */ - stm32f4_add_flash(target, 0x8020000, 0xe0000, 0x20000, 5, split); /* 7 128K */ + /* Bank 1 */ + stm32f4_add_flash(target, 0x08000000, 0x10000, 0x4000, 0, split); /* 4 16K */ + stm32f4_add_flash(target, 0x08010000, 0x10000, 0x10000, 4, split); /* 1 64K */ + stm32f4_add_flash(target, 0x08020000, 0xe0000, 0x20000, 5, split); /* 7 128K */ /* Bank 2 */ - stm32f4_add_flash(target, 0x8100000, 0x10000, 0x4000, 16, split); /* 4 16K */ - stm32f4_add_flash(target, 0x8110000, 0x10000, 0x10000, 20, split); /* 1 64K */ - stm32f4_add_flash(target, 0x8120000, 0xe0000, 0x20000, 21, split); /* 7 128K */ + stm32f4_add_flash(target, 0x08100000, 0x10000, 0x4000, 16, split); /* 4 16K */ + stm32f4_add_flash(target, 0x08110000, 0x10000, 0x10000, 20, split); /* 1 64K */ + stm32f4_add_flash(target, 0x08120000, 0xe0000, 0x20000, 21, split); /* 7 128K */ /* Third MB composed of 4 256 KB sectors, and uses sector values 12-15 */ - stm32f4_add_flash(target, 0x8200000, 0x100000, 0x40000, 12, split); + stm32f4_add_flash(target, 0x08200000, 0x100000, 0x40000, 12, split); return true; } From 105dee0c4b8a5fd2f8700917c7a4d68fe4e398ae Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 10 Jul 2024 18:31:02 +0100 Subject: [PATCH 15/47] stm32f4: Built DBGMCU support for the GD32F4 parts and improved the STM32F4 DBGMCU support --- src/target/stm32f4.c | 90 +++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/src/target/stm32f4.c b/src/target/stm32f4.c index 79ce6347c9f..ce4b3616dff 100644 --- a/src/target/stm32f4.c +++ b/src/target/stm32f4.c @@ -130,7 +130,7 @@ typedef struct stm32f4_flash { } stm32f4_flash_s; typedef struct stm32f4_priv { - uint32_t dbgmcu_cr; + uint32_t dbgmcu_config; align_e psize; } stm32f4_priv_s; @@ -232,6 +232,36 @@ static uint16_t stm32f4_read_idcode(target_s *const target) return idcode; } +static bool stm32f4_configure_dbgmcu(target_s *const target) +{ + /* If we're in the probe phase */ + if (target->target_storage == NULL) { + /* Allocate target-specific storage */ + stm32f4_priv_s *const priv_storage = calloc(1, sizeof(*priv_storage)); + if (!priv_storage) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + target->target_storage = priv_storage; + /* Get the current value of the debug control register (and store it for later) */ + priv_storage->dbgmcu_config = target_mem32_read32(target, STM32F4_DBGMCU_CTRL); + /* Set up the Flash write/erase parallelism to 32-bit */ + priv_storage->psize = ALIGN_32BIT; + + target->detach = stm32f4_detach; + } + + const stm32f4_priv_s *const priv = (stm32f4_priv_s *)target->target_storage; + /* Enable debugging during all low power modes */ + target_mem32_write32(target, STM32F4_DBGMCU_CTRL, + priv->dbgmcu_config | STM32F4_DBGMCU_CTRL_DBG_SLEEP | STM32F4_DBGMCU_CTRL_DBG_STANDBY | + STM32F4_DBGMCU_CTRL_DBG_STOP); + /* And make sure the WDTs stay synchronised to the run state of the processor */ + target_mem32_write32( + target, STM32F4_DBGMCU_APB1FREEZE, STM32F4_DBGMCU_APB1FREEZE_WWDG | STM32F4_DBGMCU_APB1FREEZE_IWDG); + return true; +} + bool stm32f4_probe(target_s *target) { const uint16_t device_id = stm32f4_read_idcode(target); @@ -255,21 +285,11 @@ bool stm32f4_probe(target_s *target) return false; } - /* Allocate target-specific storage */ - stm32f4_priv_s *priv_storage = calloc(1, sizeof(*priv_storage)); - if (!priv_storage) { /* calloc failed: heap exhaustion */ - DEBUG_ERROR("calloc: failed in %s\n", __func__); + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + if (!stm32f4_configure_dbgmcu(target)) return false; - } - target->target_storage = priv_storage; - - /* Get the current value of the debug control register (and store it for later) */ - priv_storage->dbgmcu_cr = target_mem32_read32(target, STM32F4_DBGMCU_CTRL); - /* Set up the Flash write/erase parallelism to 32-bit */ - priv_storage->psize = ALIGN_32BIT; target->attach = stm32f4_attach; - target->detach = stm32f4_detach; target->mass_erase = stm32f4_mass_erase; target->driver = stm32f4_get_chip_name(device_id); target->part_id = device_id; @@ -282,21 +302,11 @@ bool gd32f4_probe(target_s *target) if (target->part_id != ID_GD32F450 && target->part_id != ID_GD32F470 && target->part_id != ID_GD32F405) return false; - /* Allocate target-specific storage */ - stm32f4_priv_s *priv_storage = calloc(1, sizeof(*priv_storage)); - if (!priv_storage) { /* calloc failed: heap exhaustion */ - DEBUG_ERROR("calloc: failed in %s\n", __func__); + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + if (!stm32f4_configure_dbgmcu(target)) return false; - } - target->target_storage = priv_storage; - - /* Get the current value of the debug control register (and store it for later) */ - priv_storage->dbgmcu_cr = target_mem32_read32(target, STM32F4_DBGMCU_CTRL); - /* Set up the Flash write/erase parallelism to 32-bit */ - priv_storage->psize = ALIGN_32BIT; - target->attach = cortexm_attach; - target->detach = cortexm_detach; + target->attach = gd32f4_attach; target->mass_erase = stm32f4_mass_erase; target->driver = stm32f4_get_chip_name(target->part_id); target_add_commands(target, stm32f4_cmd_list, target->driver); @@ -389,8 +399,11 @@ static bool stm32f4_attach(target_s *target) return false; } - /* Try to attach now we've determined it's a part we can work with */ - if (!cortexm_attach(target)) + /* + * Try to attach now we've determined it's a part we can work with, and then ensure the + * WDTs + WFI and WFE instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + if (!cortexm_attach(target) || !stm32f4_configure_dbgmcu(target)) return false; /* And then grab back all the part properties used to configure the memory map */ @@ -399,15 +412,6 @@ static bool stm32f4_attach(target_s *target) const bool is_f7 = stm32f4_device_is_f7(target->part_id); const bool large_sectors = stm32f4_device_has_large_sectors(target->part_id); - stm32f4_priv_s *const priv_storage = target->target_storage; - /* Enable debugging during all low power modes */ - target_mem32_write32(target, STM32F4_DBGMCU_CTRL, - priv_storage->dbgmcu_cr | STM32F4_DBGMCU_CTRL_DBG_SLEEP | STM32F4_DBGMCU_CTRL_DBG_STANDBY | - STM32F4_DBGMCU_CTRL_DBG_STOP); - /* And make sure the WDTs stay synchronised to the run state of the processor */ - target_mem32_write32( - target, STM32F4_DBGMCU_APB1FREEZE, STM32F4_DBGMCU_APB1FREEZE_WWDG | STM32F4_DBGMCU_APB1FREEZE_IWDG); - /* Free any previously built memory map */ target_mem_map_free(target); /* And rebuild the RAM map */ @@ -491,10 +495,20 @@ static bool stm32f4_attach(target_s *target) return true; } +static bool gd32f4_attach(target_s *const target) +{ + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + return cortexm_attach(target) && stm32f4_configure_dbgmcu(target); +} + static void stm32f4_detach(target_s *target) { + const stm32f4_priv_s *const priv = (stm32f4_priv_s *)target->target_storage; /* Reverse all changes to STM32F4_DBGMCU_CTRL */ - target_mem32_write32(target, STM32F4_DBGMCU_CTRL, ((const stm32f4_priv_s *)target->target_storage)->dbgmcu_cr); + target_mem32_write32(target, STM32F4_DBGMCU_CTRL, priv->dbgmcu_config); /* Now defer to the normal Cortex-M detach routine to complete the detach */ cortexm_detach(target); } From 02bdb8f6c5030d5fc8107aa9f2c7780b43909e82 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 10 Jul 2024 21:46:55 +0100 Subject: [PATCH 16/47] stm32h5: Implemented support for halting the WDTs when debug halted, and configuring processor debug to work through WFI/WFE --- src/target/stm32h5.c | 82 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 8 deletions(-) diff --git a/src/target/stm32h5.c b/src/target/stm32h5.c index f65ea24191f..b3728c67c40 100644 --- a/src/target/stm32h5.c +++ b/src/target/stm32h5.c @@ -45,7 +45,7 @@ #include "general.h" #include "target.h" #include "target_internal.h" -#include "cortex.h" +#include "cortexm.h" #include "stm32_common.h" /* Memory map constants for STM32H5xx */ @@ -98,13 +98,23 @@ #define STM32H5_FLASH_BANK_MASK 0x80000000U #define STM32H5_FLASH_SECTOR_COUNT_MASK 0x000000ffU -#define STM32H5_DBGMCU_BASE 0xe0044000 -#define STM32H5_DBGMCU_IDCODE (STM32H5_DBGMCU_BASE + 0x00U) -#define STM32H5_UID_BASE 0x08fff800U - -#define STM32H5_DBGMCU_IDCODE_DEV_MASK 0x00000fffU -#define STM32H5_DBGMCU_IDCODE_REV_MASK 0xffff0000U -#define STM32H5_DBGMCU_IDCODE_REV_SHIFT 16U +#define STM32H5_DBGMCU_BASE 0xe0044000 +#define STM32H5_DBGMCU_IDCODE (STM32H5_DBGMCU_BASE + 0x00U) +#define STM32H5_DBGMCU_CONFIG (STM32H5_DBGMCU_BASE + 0x04U) +#define STM32H5_DBGMCU_APB1LFREEZE (STM32H5_DBGMCU_BASE + 0x08U) +#define STM32H5_DBGMCU_APB1HFREEZE (STM32H5_DBGMCU_BASE + 0x0cU) +#define STM32H5_DBGMCU_APB2FREEZE (STM32H5_DBGMCU_BASE + 0x10U) +#define STM32H5_DBGMCU_APB3FREEZE (STM32H5_DBGMCU_BASE + 0x14U) +#define STM32H5_DBGMCU_AHB1FREEZE (STM32H5_DBGMCU_BASE + 0x20U) +#define STM32H5_UID_BASE 0x08fff800U + +#define STM32H5_DBGMCU_IDCODE_DEV_MASK 0x00000fffU +#define STM32H5_DBGMCU_IDCODE_REV_MASK 0xffff0000U +#define STM32H5_DBGMCU_IDCODE_REV_SHIFT 16U +#define STM32H5_DBGMCU_CONFIG_DBG_STOP (1U << 1U) +#define STM32H5_DBGMCU_CONFIG_DBG_STANDBY (1U << 2U) +#define STM32H5_DBGMCU_APB1LFREEZE_WWDG (1U << 11U) +#define STM32H5_DBGMCU_APB1LFREEZE_IWDG (1U << 12U) /* Taken from DBGMCU_IDCODE in §18.12.4 of RM0481 rev 1, pg3085 */ #define ID_STM32H5xx 0x484U @@ -116,6 +126,10 @@ typedef struct stm32h5_flash { uint32_t bank_and_sector_count; } stm32h5_flash_s; +typedef struct stm32h5_priv { + uint32_t dbgmcu_config; +} stm32h5_priv_s; + static bool stm32h5_cmd_uid(target_s *target, int argc, const char **argv); static bool stm32h5_cmd_rev(target_s *target, int argc, const char **argv); @@ -125,6 +139,8 @@ const command_s stm32h5_cmd_list[] = { {NULL, NULL, NULL}, }; +static bool stm32h5_attach(target_s *target); +static void stm32h5_detach(target_s *target); static bool stm32h5_enter_flash_mode(target_s *target); static bool stm32h5_exit_flash_mode(target_s *target); static bool stm32h5_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); @@ -151,6 +167,34 @@ static void stm32h5_add_flash( flash->bank_and_sector_count = bank_and_sector_count; } +static bool stm32h5_configure_dbgmcu(target_s *const target) +{ + /* If we're in the probe phase */ + if (target->target_storage == NULL) { + /* Allocate target-specific storage */ + stm32h5_priv_s *const priv_storage = calloc(1, sizeof(*priv_storage)); + if (!priv_storage) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + target->target_storage = priv_storage; + /* Get the current value of the debug config register (and store it for later) */ + priv_storage->dbgmcu_config = target_mem32_read32(target, STM32H5_DBGMCU_CONFIG); + + target->attach = stm32h5_attach; + target->detach = stm32h5_detach; + } + + const stm32h5_priv_s *const priv = (stm32h5_priv_s *)target->target_storage; + /* Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us */ + target_mem32_write32( + target, STM32H5_DBGMCU_APB1LFREEZE, STM32H5_DBGMCU_APB1LFREEZE_IWDG | STM32H5_DBGMCU_APB1LFREEZE_WWDG); + /* Then Reconfigure the config register to prevent WFI/WFE from cutting debug access */ + target_mem32_write32(target, STM32H5_DBGMCU_CONFIG, + priv->dbgmcu_config | STM32H5_DBGMCU_CONFIG_DBG_STANDBY | STM32H5_DBGMCU_CONFIG_DBG_STOP); + return true; +} + bool stm32h5_probe(target_s *const target) { const adiv5_access_port_s *const ap = cortex_ap(target); @@ -159,6 +203,10 @@ bool stm32h5_probe(target_s *const target) return false; target->part_id = ap->partno; + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + if (!stm32h5_configure_dbgmcu(target)) + return false; + target->driver = "STM32H5"; target->mass_erase = stm32h5_mass_erase; target->enter_flash_mode = stm32h5_enter_flash_mode; @@ -200,6 +248,24 @@ bool stm32h5_probe(target_s *const target) return true; } +static bool stm32h5_attach(target_s *const target) +{ + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + return cortexm_attach(target) && stm32h5_configure_dbgmcu(target); +} + +static void stm32h5_detach(target_s *target) +{ + const stm32h5_priv_s *const priv = (stm32h5_priv_s *)target->target_storage; + /* Reverse all changes to STM32F4_DBGMCU_CTRL */ + target_mem32_write32(target, STM32H5_DBGMCU_CONFIG, priv->dbgmcu_config); + /* Now defer to the normal Cortex-M detach routine to complete the detach */ + cortexm_detach(target); +} + static bool stm32h5_flash_wait_complete(target_s *const target, platform_timeout_s *const timeout) { uint32_t status = STM32H5_FLASH_STATUS_BUSY; From 0630e721e048a899e393475ce61ec0372f33960a Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 11 Jul 2024 15:37:21 +0100 Subject: [PATCH 17/47] stm32g0: Cleaned up the docs references --- src/target/stm32g0.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/target/stm32g0.c b/src/target/stm32g0.c index b629f6891d9..5e6003e1a51 100644 --- a/src/target/stm32g0.c +++ b/src/target/stm32g0.c @@ -29,20 +29,16 @@ * the device, providing the XML memory map and Flash memory programming. * * References: - * RM0454 - Rev 5 (Value line) - * Reference manual - STM32G0x0 advanced ARM(R)-based 32-bit MCUs - * (STM32G030/STM32G050/STM32G070/STM32G0B0) - * RM0444 - Rev 5 (Access line) - * Reference manual - STM32G0x1 advanced ARM(R)-based 32-bit MCUs - * (STM32G031/STM32G041/STM32G051/STM32G061/ - * STM32G071/STM32G081/STM32G0B1/STM32G0C1) - * RM0490 - Rev 3 - * Reference manual - STM32C0x1 advanced ARM(R)-based 32-bit MCUs - * (STM32C011/STM32C031) - * STM32C0 shares the same technological platform as STM32G0. - * PM0223 - Rev 6 - * Programming manual - Cortex(R)-M0+ programming manual for STM32L0, STM32G0, - * STM32C0, STM32WL and STM32WB Series + * RM0454 - STM32G0x0 advanced Arm®-based 32-bit MCUs, Rev. 5 + * https://www.st.com/resource/en/reference_manual/rm0454-stm32g0x0-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * RM0444 - STM32G0x1 advanced Arm®-based 32-bit MCUs, Rev. 5 + * https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * RM0490 - STM32C0x1 advanced Arm®-based 32-bit MCUs, Rev. 3 + * https://www.st.com/resource/en/reference_manual/rm0490-stm32c0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * PM0223 - STM32 Cortex®-M0+ MCUs programming manual, Rev 6 + * https://www.st.com/resource/en/programming_manual/pm0223-stm32-cortexm0-mcus-programming-manual-stmicroelectronics.pdf + * + * Note: The STM32C0 series shares the same technological platform as the STM32G0 series. */ #include "general.h" @@ -52,7 +48,6 @@ #include "command.h" #include "stm32_common.h" -/* Flash */ #define FLASH_START 0x08000000U #define FLASH_MEMORY_SIZE 0x1fff75e0U #define FLASH_PAGE_SIZE 0x800U @@ -127,7 +122,6 @@ #define FLASH_PCROP2BER (G0_FLASH_BASE + 0x058U) #define FLASH_SECR (G0_FLASH_BASE + 0x080U) -/* RAM */ #define RAM_START 0x20000000U #define RAM_SIZE_G03_4 (8U * 1024U) // 8kiB #define RAM_SIZE_G05_6 (18U * 1024U) // 18kiB @@ -137,12 +131,10 @@ #define RAM_SIZE_C01 (6U * 1024U) // 6kiB #define RAM_SIZE_C03 (12U * 1024U) // 12kiB -/* RCC */ #define G0_RCC_BASE 0x40021000U #define RCC_APBENR1 (G0_RCC_BASE + 0x3cU) #define RCC_APBENR1_DBGEN (1U << 27U) -/* DBG */ #define DBG_BASE 0x40015800U #define DBG_IDCODE (DBG_BASE + 0x00U) #define DBG_CR (DBG_BASE + 0x04U) From a390c63c6e2cd256fdfcf7b82f3344c7eecb7ea8 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 11 Jul 2024 15:38:04 +0100 Subject: [PATCH 18/47] stm32g0: Fixed a bug wit the erase_bank command specifying parameters in the command string, which doesn't work --- src/target/stm32g0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/stm32g0.c b/src/target/stm32g0.c index 5e6003e1a51..dc1b475f809 100644 --- a/src/target/stm32g0.c +++ b/src/target/stm32g0.c @@ -182,7 +182,7 @@ static bool stm32g0_cmd_irreversible(target_s *t, int argc, const char **argv); static bool stm32g0_cmd_uid(target_s *t, int argc, const char **argv); const command_s stm32g0_cmd_list[] = { - {"erase_bank 1|2", stm32g0_cmd_erase_bank, "Erase specified Flash bank"}, + {"erase_bank", stm32g0_cmd_erase_bank, "Erase specified Flash bank"}, {"option", stm32g0_cmd_option, "Manipulate option bytes"}, {"irreversible", stm32g0_cmd_irreversible, "Allow irreversible operations: (enable|disable)"}, {"uid", stm32g0_cmd_uid, "Print unique device ID"}, From 7904cdc92cbe773ff0391d5fe2bf6d356da5cbc9 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 11 Jul 2024 15:51:34 +0100 Subject: [PATCH 19/47] stm32g0: Fixed up the nomenclature for the ID codes to match the other STM32 target support implementations --- src/target/stm32g0.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/target/stm32g0.c b/src/target/stm32g0.c index dc1b475f809..90f0728b714 100644 --- a/src/target/stm32g0.c +++ b/src/target/stm32g0.c @@ -151,12 +151,12 @@ * The underscores in these definitions represent /'s, this means * that STM32G03_4 is supposed to refer to the G03/4 aka the G03 and G04. */ -#define STM32C011 0x443U -#define STM32C031 0x453U -#define STM32G03_4 0x466U -#define STM32G05_6 0x456U -#define STM32G07_8 0x460U -#define STM32G0B_C 0x467U +#define ID_STM32C011 0x443U +#define ID_STM32C031 0x453U +#define ID_STM32G03_4 0x466U +#define ID_STM32G05_6 0x456U +#define ID_STM32G07_8 0x460U +#define ID_STM32G0B_C 0x467U typedef struct stm32g0_saved_regs { uint32_t rcc_apbenr1; @@ -219,22 +219,22 @@ bool stm32g0_probe(target_s *t) size_t flash_size = 0U; switch (t->part_id) { - case STM32G03_4:; + case ID_STM32G03_4:; const uint16_t dev_id = target_mem32_read32(t, DBG_IDCODE) & 0xfffU; switch (dev_id) { - case STM32G03_4: + case ID_STM32G03_4: /* SRAM 8kiB, Flash up to 64kiB */ ram_size = RAM_SIZE_G03_4; flash_size = FLASH_SIZE_MAX_G03_4; t->driver = "STM32G03/4"; break; - case STM32C011: + case ID_STM32C011: /* SRAM 6kiB, Flash up to 32kiB */ ram_size = RAM_SIZE_C01; flash_size = FLASH_SIZE_MAX_C01; t->driver = "STM32C011"; break; - case STM32C031: + case ID_STM32C031: /* SRAM 12kiB, Flash up to 32kiB */ ram_size = RAM_SIZE_C03; flash_size = FLASH_SIZE_MAX_C03; @@ -245,19 +245,19 @@ bool stm32g0_probe(target_s *t) } t->part_id = dev_id; break; - case STM32G05_6: + case ID_STM32G05_6: /* SRAM 18kiB, Flash up to 64kiB */ ram_size = RAM_SIZE_G05_6; flash_size = FLASH_SIZE_MAX_G05_6; t->driver = "STM32G05/6"; break; - case STM32G07_8: + case ID_STM32G07_8: /* SRAM 36kiB, Flash up to 128kiB */ ram_size = RAM_SIZE_G07_8; flash_size = FLASH_SIZE_MAX_G07_8; t->driver = "STM32G07/8"; break; - case STM32G0B_C: + case ID_STM32G0B_C: /* SRAM 144kiB, Flash up to 512kiB */ ram_size = RAM_SIZE_G0B_C; flash_size = target_mem32_read16(t, FLASH_MEMORY_SIZE) * 1024U; @@ -374,7 +374,7 @@ static size_t stm32g0_bank1_end_page(target_flash_s *f) { target_s *const t = f->t; /* If the part is dual banked, compute the end of the first bank */ - if (t->part_id == STM32G0B_C) + if (t->part_id == ID_STM32G0B_C) return ((f->length / 2U) - 1U) / f->blocksize; /* Single banked devices have a fixed bank end */ return FLASH_BANK2_START_PAGE - 1U; @@ -692,7 +692,7 @@ static bool stm32g0_cmd_option(target_s *t, int argc, const char **argv) option_register_s options_req[OPT_REG_COUNT] = {{0}}; if (argc == 2 && strcasecmp(argv[1], "erase") == 0) { - if (t->part_id == STM32C011 || t->part_id == STM32C031) + if (t->part_id == ID_STM32C011 || t->part_id == ID_STM32C031) options_def[OPT_REG_OPTR].val = FLASH_OPTR_C0x1_DEF; if (!stm32g0_option_write(t, options_def)) goto exit_error; @@ -726,7 +726,7 @@ static bool stm32g0_cmd_uid(target_s *t, int argc, const char **argv) (void)argc; (void)argv; target_addr_t uid_base = STM32G0_UID_BASE; - if (t->part_id == STM32C011 || t->part_id == STM32C031) + if (t->part_id == ID_STM32C011 || t->part_id == ID_STM32C031) uid_base = STM32C0_UID_BASE; return stm32_uid(t, uid_base); } From 6d0cedc9247bb515d6f0caab429c085b153fed3e Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 11 Jul 2024 22:16:31 +0100 Subject: [PATCH 20/47] stm32g0: Systematically correced the nomenclature for `target` and `flash` --- src/target/stm32g0.c | 314 +++++++++++++++++++++---------------------- 1 file changed, 157 insertions(+), 157 deletions(-) diff --git a/src/target/stm32g0.c b/src/target/stm32g0.c index 90f0728b714..2f8b20f35ae 100644 --- a/src/target/stm32g0.c +++ b/src/target/stm32g0.c @@ -169,17 +169,17 @@ typedef struct stm32g0_priv { bool irreversible_enabled; } stm32g0_priv_s; -static bool stm32g0_attach(target_s *t); -static void stm32g0_detach(target_s *t); -static bool stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); -static bool stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); -static bool stm32g0_mass_erase(target_s *t); +static bool stm32g0_attach(target_s *target); +static void stm32g0_detach(target_s *target); +static bool stm32g0_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); +static bool stm32g0_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); +static bool stm32g0_mass_erase(target_s *target); /* Custom commands */ -static bool stm32g0_cmd_erase_bank(target_s *t, int argc, const char **argv); -static bool stm32g0_cmd_option(target_s *t, int argc, const char **argv); -static bool stm32g0_cmd_irreversible(target_s *t, int argc, const char **argv); -static bool stm32g0_cmd_uid(target_s *t, int argc, const char **argv); +static bool stm32g0_cmd_erase_bank(target_s *target, int argc, const char **argv); +static bool stm32g0_cmd_option(target_s *target, int argc, const char **argv); +static bool stm32g0_cmd_irreversible(target_s *target, int argc, const char **argv); +static bool stm32g0_cmd_uid(target_s *target, int argc, const char **argv); const command_s stm32g0_cmd_list[] = { {"erase_bank", stm32g0_cmd_erase_bank, "Erase specified Flash bank"}, @@ -189,22 +189,22 @@ const command_s stm32g0_cmd_list[] = { {NULL, NULL, NULL}, }; -static void stm32g0_add_flash(target_s *t, uint32_t addr, size_t length, size_t blocksize) +static void stm32g0_add_flash(target_s *target, uint32_t addr, size_t length, size_t blocksize) { - target_flash_s *f = calloc(1, sizeof(*f)); - if (!f) { /* calloc failed: heap exhaustion */ + target_flash_s *flash = calloc(1, sizeof(*flash)); + if (!flash) { /* calloc failed: heap exhaustion */ DEBUG_ERROR("calloc: failed in %s\n", __func__); return; } - f->start = addr; - f->length = length; - f->blocksize = blocksize; - f->erase = stm32g0_flash_erase; - f->write = stm32g0_flash_write; - f->writesize = blocksize; - f->erased = 0xffU; - target_add_flash(t, f); + flash->start = addr; + flash->length = length; + flash->blocksize = blocksize; + flash->erase = stm32g0_flash_erase; + flash->write = stm32g0_flash_write; + flash->writesize = blocksize; + flash->erased = 0xffU; + target_add_flash(target, flash); } /* @@ -213,68 +213,68 @@ static void stm32g0_add_flash(target_s *t, uint32_t addr, size_t length, size_t * Single bank devices are populated with their maximal flash capacity to allow * users to program devices with more flash than announced. */ -bool stm32g0_probe(target_s *t) +bool stm32g0_probe(target_s *target) { uint32_t ram_size = 0U; size_t flash_size = 0U; - switch (t->part_id) { + switch (target->part_id) { case ID_STM32G03_4:; - const uint16_t dev_id = target_mem32_read32(t, DBG_IDCODE) & 0xfffU; + const uint16_t dev_id = target_mem32_read32(target, DBG_IDCODE) & 0xfffU; switch (dev_id) { case ID_STM32G03_4: /* SRAM 8kiB, Flash up to 64kiB */ ram_size = RAM_SIZE_G03_4; flash_size = FLASH_SIZE_MAX_G03_4; - t->driver = "STM32G03/4"; + target->driver = "STM32G03/4"; break; case ID_STM32C011: /* SRAM 6kiB, Flash up to 32kiB */ ram_size = RAM_SIZE_C01; flash_size = FLASH_SIZE_MAX_C01; - t->driver = "STM32C011"; + target->driver = "STM32C011"; break; case ID_STM32C031: /* SRAM 12kiB, Flash up to 32kiB */ ram_size = RAM_SIZE_C03; flash_size = FLASH_SIZE_MAX_C03; - t->driver = "STM32C031"; + target->driver = "STM32C031"; break; default: return false; } - t->part_id = dev_id; + target->part_id = dev_id; break; case ID_STM32G05_6: /* SRAM 18kiB, Flash up to 64kiB */ ram_size = RAM_SIZE_G05_6; flash_size = FLASH_SIZE_MAX_G05_6; - t->driver = "STM32G05/6"; + target->driver = "STM32G05/6"; break; case ID_STM32G07_8: /* SRAM 36kiB, Flash up to 128kiB */ ram_size = RAM_SIZE_G07_8; flash_size = FLASH_SIZE_MAX_G07_8; - t->driver = "STM32G07/8"; + target->driver = "STM32G07/8"; break; case ID_STM32G0B_C: /* SRAM 144kiB, Flash up to 512kiB */ ram_size = RAM_SIZE_G0B_C; - flash_size = target_mem32_read16(t, FLASH_MEMORY_SIZE) * 1024U; - t->driver = "STM32G0B/C"; + flash_size = target_mem32_read16(target, FLASH_MEMORY_SIZE) * 1024U; + target->driver = "STM32G0B/C"; break; default: return false; } - target_add_ram32(t, RAM_START, ram_size); + target_add_ram32(target, RAM_START, ram_size); /* Even dual Flash bank devices have a contiguous Flash memory space */ - stm32g0_add_flash(t, FLASH_START, flash_size, FLASH_PAGE_SIZE); + stm32g0_add_flash(target, FLASH_START, flash_size, FLASH_PAGE_SIZE); - t->attach = stm32g0_attach; - t->detach = stm32g0_detach; - t->mass_erase = stm32g0_mass_erase; - target_add_commands(t, stm32g0_cmd_list, t->driver); + target->attach = stm32g0_attach; + target->detach = stm32g0_detach; + target->mass_erase = stm32g0_mass_erase; + target_add_commands(target, stm32g0_cmd_list, target->driver); /* Save private storage */ stm32g0_priv_s *priv_storage = calloc(1, sizeof(*priv_storage)); @@ -282,11 +282,11 @@ bool stm32g0_probe(target_s *t) DEBUG_ERROR("calloc: failed in %s\n", __func__); return false; } - t->target_storage = priv_storage; + target->target_storage = priv_storage; priv_storage->irreversible_enabled = false; /* OTP Flash area */ - stm32g0_add_flash(t, FLASH_OTP_START, FLASH_OTP_SIZE, FLASH_OTP_BLOCKSIZE); + stm32g0_add_flash(target, FLASH_OTP_START, FLASH_OTP_SIZE, FLASH_OTP_BLOCKSIZE); return true; } @@ -298,20 +298,20 @@ bool stm32g0_probe(target_s *t) * allows basic Flash operations (erase/write) if the watchdog is started by * hardware or by a previous program without prior power cycle. */ -static bool stm32g0_attach(target_s *t) +static bool stm32g0_attach(target_s *target) { - stm32g0_priv_s *ps = (stm32g0_priv_s *)t->target_storage; + stm32g0_priv_s *priv = (stm32g0_priv_s *)target->target_storage; - if (!cortexm_attach(t)) + if (!cortexm_attach(target)) return false; - ps->saved_regs.rcc_apbenr1 = target_mem32_read32(t, RCC_APBENR1); - target_mem32_write32(t, RCC_APBENR1, ps->saved_regs.rcc_apbenr1 | RCC_APBENR1_DBGEN); - ps->saved_regs.dbg_cr = target_mem32_read32(t, DBG_CR); - target_mem32_write32(t, DBG_CR, ps->saved_regs.dbg_cr | (DBG_CR_DBG_STANDBY | DBG_CR_DBG_STOP)); - ps->saved_regs.dbg_apb_fz1 = target_mem32_read32(t, DBG_APB_FZ1); + priv->saved_regs.rcc_apbenr1 = target_mem32_read32(target, RCC_APBENR1); + target_mem32_write32(target, RCC_APBENR1, priv->saved_regs.rcc_apbenr1 | RCC_APBENR1_DBGEN); + priv->saved_regs.dbg_cr = target_mem32_read32(t, DBG_CR); + target_mem32_write32(target, DBG_CR, priv->saved_regs.dbg_cr | (DBG_CR_DBG_STANDBY | DBG_CR_DBG_STOP)); + priv->saved_regs.dbg_apb_fz1 = target_mem32_read32(t, DBG_APB_FZ1); target_mem32_write32( - t, DBG_APB_FZ1, ps->saved_regs.dbg_apb_fz1 | (DBG_APB_FZ1_DBG_IWDG_STOP | DBG_APB_FZ1_DBG_WWDG_STOP)); + target, DBG_APB_FZ1, priv->saved_regs.dbg_apb_fz1 | (DBG_APB_FZ1_DBG_IWDG_STOP | DBG_APB_FZ1_DBG_WWDG_STOP)); return true; } @@ -321,40 +321,40 @@ static bool stm32g0_attach(target_s *t) * The registers are restored as is to leave the target in the same state as * before attachment. */ -static void stm32g0_detach(target_s *t) +static void stm32g0_detach(target_s *target) { - stm32g0_priv_s *ps = (stm32g0_priv_s *)t->target_storage; + stm32g0_priv_s *priv = (stm32g0_priv_s *)target->target_storage; /* * First re-enable DBGEN clock, in case it got disabled in the meantime * (happens during flash), so that writes to DBG_* registers below succeed. */ - target_mem32_write32(t, RCC_APBENR1, ps->saved_regs.rcc_apbenr1 | RCC_APBENR1_DBGEN); + target_mem32_write32(target, RCC_APBENR1, priv->saved_regs.rcc_apbenr1 | RCC_APBENR1_DBGEN); /* Then restore the DBG_* registers and clock settings. */ - target_mem32_write32(t, DBG_APB_FZ1, ps->saved_regs.dbg_apb_fz1); - target_mem32_write32(t, DBG_CR, ps->saved_regs.dbg_cr); - target_mem32_write32(t, RCC_APBENR1, ps->saved_regs.rcc_apbenr1); + target_mem32_write32(target, DBG_APB_FZ1, priv->saved_regs.dbg_apb_fz1); + target_mem32_write32(target, DBG_CR, priv->saved_regs.dbg_cr); + target_mem32_write32(target, RCC_APBENR1, priv->saved_regs.rcc_apbenr1); - cortexm_detach(t); + cortexm_detach(target); } -static void stm32g0_flash_unlock(target_s *t) +static void stm32g0_flash_unlock(target_s *target) { - target_mem32_write32(t, FLASH_KEYR, FLASH_KEYR_KEY1); - target_mem32_write32(t, FLASH_KEYR, FLASH_KEYR_KEY2); + target_mem32_write32(target, FLASH_KEYR, FLASH_KEYR_KEY1); + target_mem32_write32(target, FLASH_KEYR, FLASH_KEYR_KEY2); } -static void stm32g0_flash_lock(target_s *t) +static void stm32g0_flash_lock(target_s *target) { - const uint32_t ctrl = target_mem32_read32(t, FLASH_CR) | FLASH_CR_LOCK; - target_mem32_write32(t, FLASH_CR, ctrl); + const uint32_t ctrl = target_mem32_read32(target, FLASH_CR) | FLASH_CR_LOCK; + target_mem32_write32(target, FLASH_CR, ctrl); } -static bool stm32g0_wait_busy(target_s *const t, platform_timeout_s *const timeout) +static bool stm32g0_wait_busy(target_s *const target, platform_timeout_s *const timeout) { - while (target_mem32_read32(t, FLASH_SR) & FLASH_SR_BSY_MASK) { - if (target_check_error(t)) + while (target_mem32_read32(target, FLASH_SR) & FLASH_SR_BSY_MASK) { + if (target_check_error(target)) return false; if (timeout) target_print_progress(timeout); @@ -362,48 +362,48 @@ static bool stm32g0_wait_busy(target_s *const t, platform_timeout_s *const timeo return true; } -static void stm32g0_flash_op_finish(target_s *t) +static void stm32g0_flash_op_finish(target_s *target) { - target_mem32_write32(t, FLASH_SR, FLASH_SR_EOP); // Clear EOP + target_mem32_write32(target, FLASH_SR, FLASH_SR_EOP); // Clear EOP /* Clear PG: half-word access not to clear unwanted bits */ - target_mem32_write16(t, FLASH_CR, 0); - stm32g0_flash_lock(t); + target_mem32_write16(target, FLASH_CR, 0); + stm32g0_flash_lock(target); } -static size_t stm32g0_bank1_end_page(target_flash_s *f) +static size_t stm32g0_bank1_end_page(target_flash_s *flash) { - target_s *const t = f->t; + target_s *const target = flash->t; /* If the part is dual banked, compute the end of the first bank */ - if (t->part_id == ID_STM32G0B_C) - return ((f->length / 2U) - 1U) / f->blocksize; + if (target->part_id == ID_STM32G0B_C) + return ((flash->length / 2U) - 1U) / flash->blocksize; /* Single banked devices have a fixed bank end */ return FLASH_BANK2_START_PAGE - 1U; } /* Erase pages of Flash. In the OTP case, this function clears any previous error and returns. */ -static bool stm32g0_flash_erase(target_flash_s *f, const target_addr_t addr, const size_t len) +static bool stm32g0_flash_erase(target_flash_s *flash, const target_addr_t addr, const size_t len) { - target_s *const t = f->t; + target_s *const target = flash->t; /* Wait for Flash ready */ - if (!stm32g0_wait_busy(t, NULL)) { - stm32g0_flash_op_finish(t); + if (!stm32g0_wait_busy(target, NULL)) { + stm32g0_flash_op_finish(target); return false; } /* Clear any previous programming error */ - target_mem32_write32(t, FLASH_SR, target_mem32_read32(t, FLASH_SR)); + target_mem32_write32(target, FLASH_SR, target_mem32_read32(target, FLASH_SR)); if (addr >= FLASH_OTP_START) { - stm32g0_flash_op_finish(t); + stm32g0_flash_op_finish(target); return true; } - const size_t pages_to_erase = ((len - 1U) / f->blocksize) + 1U; - const size_t bank1_end_page = stm32g0_bank1_end_page(f); - uint32_t page = (addr - f->start) / f->blocksize; + const size_t pages_to_erase = ((len - 1U) / flash->blocksize) + 1U; + const size_t bank1_end_page = stm32g0_bank1_end_page(flash); + uint32_t page = (addr - flash->start) / flash->blocksize; - stm32g0_flash_unlock(t); + stm32g0_flash_unlock(target); for (size_t pages_erased = 0U; pages_erased < pages_to_erase; ++pages_erased, ++page) { /* If the page to erase is after the end of bank 1 but not yet in bank 2, skip */ @@ -413,21 +413,21 @@ static bool stm32g0_flash_erase(target_flash_s *f, const target_addr_t addr, con /* Erase the current page */ const uint32_t ctrl = (page << FLASH_CR_PNB_SHIFT) | FLASH_CR_PER | (page >= FLASH_BANK2_START_PAGE ? FLASH_CR_BKER : 0); - target_mem32_write32(t, FLASH_CR, ctrl); - target_mem32_write32(t, FLASH_CR, ctrl | FLASH_CR_START); + target_mem32_write32(target, FLASH_CR, ctrl); + target_mem32_write32(target, FLASH_CR, ctrl | FLASH_CR_START); /* Wait for the operation to finish and report errors */ - if (!stm32g0_wait_busy(t, NULL)) { - stm32g0_flash_op_finish(t); + if (!stm32g0_wait_busy(target, NULL)) { + stm32g0_flash_op_finish(target); return false; } } /* Check for error */ - const uint32_t status = target_mem32_read32(t, FLASH_SR); + const uint32_t status = target_mem32_read32(target, FLASH_SR); if (status & FLASH_SR_ERROR_MASK) DEBUG_ERROR("stm32g0 flash erase error: sr 0x%" PRIx32 "\n", status); - stm32g0_flash_op_finish(t); + stm32g0_flash_op_finish(target); return !(status & FLASH_SR_ERROR_MASK); } @@ -438,66 +438,66 @@ static bool stm32g0_flash_erase(target_flash_s *f, const target_addr_t addr, con * into the main Flash memory without power cycle. * OTP area is programmed as the "program" area. It can be programmed 8-bytes at a time. */ -static bool stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) +static bool stm32g0_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len) { - target_s *const t = f->t; - stm32g0_priv_s *ps = (stm32g0_priv_s *)t->target_storage; + target_s *const target = flash->t; + stm32g0_priv_s *priv = (stm32g0_priv_s *)target->target_storage; - if (f->start == FLASH_OTP_START && !ps->irreversible_enabled) { - tc_printf(t, "Irreversible operations disabled\n"); - stm32g0_flash_op_finish(t); + if (flash->start == FLASH_OTP_START && !priv->irreversible_enabled) { + tc_printf(target, "Irreversible operations disabled\n"); + stm32g0_flash_op_finish(target); return false; } - stm32g0_flash_unlock(t); + stm32g0_flash_unlock(target); /* Write data to Flash */ - target_mem32_write32(t, FLASH_CR, FLASH_CR_PG); - target_mem32_write(t, dest, src, len); + target_mem32_write32(target, FLASH_CR, FLASH_CR_PG); + target_mem32_write(target, dest, src, len); /* Wait for completion or an error */ - if (!stm32g0_wait_busy(t, NULL)) { + if (!stm32g0_wait_busy(target, NULL)) { DEBUG_ERROR("stm32g0 flash write: comm error\n"); - stm32g0_flash_op_finish(t); + stm32g0_flash_op_finish(target); return false; } - const uint32_t status = target_mem32_read32(t, FLASH_SR); + const uint32_t status = target_mem32_read32(target, FLASH_SR); if (status & FLASH_SR_ERROR_MASK) { DEBUG_ERROR("stm32g0 flash write error: sr 0x%" PRIx32 "\n", status); - stm32g0_flash_op_finish(t); + stm32g0_flash_op_finish(target); return false; } - if (dest == FLASH_START && target_mem32_read32(t, FLASH_START) != 0xffffffffU) { - const uint32_t acr = target_mem32_read32(t, FLASH_ACR) & ~FLASH_ACR_EMPTY; - target_mem32_write32(t, FLASH_ACR, acr); + if (dest == FLASH_START && target_mem32_read32(target, FLASH_START) != 0xffffffffU) { + const uint32_t acr = target_mem32_read32(target, FLASH_ACR) & ~FLASH_ACR_EMPTY; + target_mem32_write32(target, FLASH_ACR, acr); } - stm32g0_flash_op_finish(t); + stm32g0_flash_op_finish(target); return true; } -static bool stm32g0_mass_erase(target_s *t) +static bool stm32g0_mass_erase(target_s *target) { const uint32_t ctrl = FLASH_CR_MER1 | FLASH_CR_MER2 | FLASH_CR_START; - stm32g0_flash_unlock(t); - target_mem32_write32(t, FLASH_CR, ctrl); + stm32g0_flash_unlock(target); + target_mem32_write32(target, FLASH_CR, ctrl); platform_timeout_s timeout; platform_timeout_set(&timeout, 500); /* Wait for completion or an error */ - if (!stm32g0_wait_busy(t, &timeout)) { - stm32g0_flash_op_finish(t); + if (!stm32g0_wait_busy(target, &timeout)) { + stm32g0_flash_op_finish(target); return false; } /* Check for error */ - const uint16_t status = target_mem32_read32(t, FLASH_SR); - stm32g0_flash_op_finish(t); + const uint16_t status = target_mem32_read32(target, FLASH_SR); + stm32g0_flash_op_finish(target); return !(status & FLASH_SR_ERROR_MASK); } -static bool stm32g0_cmd_erase_bank(target_s *t, int argc, const char **argv) +static bool stm32g0_cmd_erase_bank(target_s *target, int argc, const char **argv) { uint32_t ctrl = 0U; if (argc == 2) { @@ -512,30 +512,30 @@ static bool stm32g0_cmd_erase_bank(target_s *t, int argc, const char **argv) } if (!ctrl) { - tc_printf(t, "Must specify which bank to erase\n"); + tc_printf(target, "Must specify which bank to erase\n"); return false; } /* Erase the Flash bank requested */ - stm32g0_flash_unlock(t); - target_mem32_write32(t, FLASH_CR, ctrl); + stm32g0_flash_unlock(target); + target_mem32_write32(target, FLASH_CR, ctrl); /* Wait for completion or an error */ - if (!stm32g0_wait_busy(t, NULL)) { - stm32g0_flash_lock(t); + if (!stm32g0_wait_busy(target, NULL)) { + stm32g0_flash_lock(target); return false; } /* Check for error */ - const uint16_t status = target_mem32_read32(t, FLASH_SR); - stm32g0_flash_op_finish(t); + const uint16_t status = target_mem32_read32(target, FLASH_SR); + stm32g0_flash_op_finish(target); return !(status & FLASH_SR_ERROR_MASK); } -static void stm32g0_flash_option_unlock(target_s *t) +static void stm32g0_flash_option_unlock(target_s *target) { - target_mem32_write32(t, FLASH_OPTKEYR, FLASH_OPTKEYR_KEY1); - target_mem32_write32(t, FLASH_OPTKEYR, FLASH_OPTKEYR_KEY2); + target_mem32_write32(target, FLASH_OPTKEYR, FLASH_OPTKEYR_KEY1); + target_mem32_write32(target, FLASH_OPTKEYR, FLASH_OPTKEYR_KEY2); } typedef enum option_bytes_registers { @@ -592,42 +592,42 @@ static option_register_s options_def[OPT_REG_COUNT] = { [OPT_REG_SECR] = {FLASH_SECR, 0x00000000}, }; -static void write_registers(target_s *const t, const option_register_s *const regs, const size_t nb_regs) +static void write_registers(target_s *const target, const option_register_s *const regs, const size_t nb_regs) { for (size_t reg = 0U; reg < nb_regs; ++reg) { if (regs[reg].addr > 0U) - target_mem32_write32(t, regs[reg].addr, regs[reg].val); + target_mem32_write32(target, regs[reg].addr, regs[reg].val); } } /* Program the option bytes. */ -static bool stm32g0_option_write(target_s *const t, const option_register_s *const options_req) +static bool stm32g0_option_write(target_s *const target, const option_register_s *const options_req) { /* Unlock the option bytes Flash */ - stm32g0_flash_unlock(t); - stm32g0_flash_option_unlock(t); + stm32g0_flash_unlock(target); + stm32g0_flash_option_unlock(target); /* Wait for completion or an error */ - if (!stm32g0_wait_busy(t, NULL)) + if (!stm32g0_wait_busy(target, NULL)) goto exit_error; /* Write the new option register values and begin the programming operation */ - write_registers(t, options_req, OPT_REG_COUNT); - target_mem32_write32(t, FLASH_CR, FLASH_CR_OPTSTART); + write_registers(target, options_req, OPT_REG_COUNT); + target_mem32_write32(target, FLASH_CR, FLASH_CR_OPTSTART); /* Wait for completion or an error */ - if (!stm32g0_wait_busy(t, NULL)) + if (!stm32g0_wait_busy(target, NULL)) goto exit_error; /* Ask the device to reload its options bytes */ - target_mem32_write32(t, FLASH_CR, FLASH_CR_OBL_LAUNCH); + target_mem32_write32(target, FLASH_CR, FLASH_CR_OBL_LAUNCH); /* Option bytes loading generates a system reset */ - tc_printf(t, "Scan and attach again\n"); + tc_printf(target, "Scan and attach again\n"); return true; exit_error: /* If we encounter any errors, relock the Flash */ - stm32g0_flash_op_finish(t); + stm32g0_flash_op_finish(target); return false; } @@ -665,20 +665,20 @@ static bool stm32g0_parse_cmdline_registers( } /* Validates option bytes settings. Only allow level 2 device protection if explicitly allowed. */ -static bool stm32g0_validate_options(target_s *t, const option_register_s *options_req) +static bool stm32g0_validate_options(target_s *target, const option_register_s *options_req) { - stm32g0_priv_s *ps = (stm32g0_priv_s *)t->target_storage; - const bool valid = (options_req[OPT_REG_OPTR].val & FLASH_OPTR_RDP_MASK) != 0xccU || ps->irreversible_enabled; + stm32g0_priv_s *priv = (stm32g0_priv_s *)target->target_storage; + const bool valid = (options_req[OPT_REG_OPTR].val & FLASH_OPTR_RDP_MASK) != 0xccU || priv->irreversible_enabled; if (!valid) - tc_printf(t, "Irreversible operations disabled\n"); + tc_printf(target, "Irreversible operations disabled\n"); return valid; } -static void stm32g0_display_registers(target_s *t) +static void stm32g0_display_registers(target_s *target) { for (size_t i = 0; i < OPT_REG_COUNT; ++i) { - const uint32_t val = target_mem32_read32(t, options_def[i].addr); - tc_printf(t, "0x%08X: 0x%08X\n", options_def[i].addr, val); + const uint32_t val = target_mem32_read32(target, options_def[i].addr); + tc_printf(target, "0x%08X: 0x%08X\n", options_def[i].addr, val); } } @@ -687,46 +687,46 @@ static void stm32g0_display_registers(target_s *t) * 1. Increase device protection to level 1 and set PCROP_RDP if not already the case. * 2. Reset to defaults. */ -static bool stm32g0_cmd_option(target_s *t, int argc, const char **argv) +static bool stm32g0_cmd_option(target_s *target, int argc, const char **argv) { option_register_s options_req[OPT_REG_COUNT] = {{0}}; if (argc == 2 && strcasecmp(argv[1], "erase") == 0) { - if (t->part_id == ID_STM32C011 || t->part_id == ID_STM32C031) + if (target->part_id == ID_STM32C011 || target->part_id == ID_STM32C031) options_def[OPT_REG_OPTR].val = FLASH_OPTR_C0x1_DEF; - if (!stm32g0_option_write(t, options_def)) + if (!stm32g0_option_write(target, options_def)) goto exit_error; } else if (argc > 2 && (argc & 1U) == 0U && strcasecmp(argv[1], "write") == 0) { if (!stm32g0_parse_cmdline_registers((uint32_t)argc - 2U, argv + 2U, options_req) || - !stm32g0_validate_options(t, options_req) || !stm32g0_option_write(t, options_req)) + !stm32g0_validate_options(target, options_req) || !stm32g0_option_write(target, options_req)) goto exit_error; } else { - tc_printf(t, "usage: monitor option erase\n"); - tc_printf(t, "usage: monitor option write [ ]...\n"); - stm32g0_display_registers(t); + tc_printf(target, "usage: monitor option erase\n"); + tc_printf(target, "usage: monitor option write [ ]...\n"); + stm32g0_display_registers(target); } return true; exit_error: - tc_printf(t, "Writing options failed!\n"); + tc_printf(target, "Writing options failed!\n"); return false; } /* Enables the irreversible operation that is level 2 device protection. */ -static bool stm32g0_cmd_irreversible(target_s *t, int argc, const char **argv) +static bool stm32g0_cmd_irreversible(target_s *target, int argc, const char **argv) { - stm32g0_priv_s *ps = (stm32g0_priv_s *)t->target_storage; - const bool ret = argc != 2 || parse_enable_or_disable(argv[1], &ps->irreversible_enabled); - tc_printf(t, "Irreversible operations: %s\n", ps->irreversible_enabled ? "enabled" : "disabled"); + stm32g0_priv_s *priv = (stm32g0_priv_s *)target->target_storage; + const bool ret = argc != 2 || parse_enable_or_disable(argv[1], &priv->irreversible_enabled); + tc_printf(target, "Irreversible operations: %s\n", priv->irreversible_enabled ? "enabled" : "disabled"); return ret; } -static bool stm32g0_cmd_uid(target_s *t, int argc, const char **argv) +static bool stm32g0_cmd_uid(target_s *target, int argc, const char **argv) { (void)argc; (void)argv; target_addr_t uid_base = STM32G0_UID_BASE; - if (t->part_id == ID_STM32C011 || t->part_id == ID_STM32C031) + if (target->part_id == ID_STM32C011 || target->part_id == ID_STM32C031) uid_base = STM32C0_UID_BASE; - return stm32_uid(t, uid_base); + return stm32_uid(target, uid_base); } From c17182d9b4b22bdd77a1027cdddcda62612aeba7 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 11 Jul 2024 22:04:34 +0100 Subject: [PATCH 21/47] stm32g0: Refactored the handling for the WDTs and WFI/WFE debugging support --- src/target/stm32g0.c | 129 +++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/src/target/stm32g0.c b/src/target/stm32g0.c index 2f8b20f35ae..77b8d478f9a 100644 --- a/src/target/stm32g0.c +++ b/src/target/stm32g0.c @@ -135,14 +135,15 @@ #define RCC_APBENR1 (G0_RCC_BASE + 0x3cU) #define RCC_APBENR1_DBGEN (1U << 27U) -#define DBG_BASE 0x40015800U -#define DBG_IDCODE (DBG_BASE + 0x00U) -#define DBG_CR (DBG_BASE + 0x04U) -#define DBG_CR_DBG_STANDBY (1U << 2U) -#define DBG_CR_DBG_STOP (1U << 1U) -#define DBG_APB_FZ1 (DBG_BASE + 0x08U) -#define DBG_APB_FZ1_DBG_IWDG_STOP (1U << 12U) -#define DBG_APB_FZ1_DBG_WWDG_STOP (1U << 11U) +#define STM32G0_DBGMCU_BASE 0x40015800U +#define STM32G0_DBGMCU_IDCODE (STM32G0_DBGMCU_BASE + 0x000U) +#define STM32G0_DBGMCU_CONFIG (STM32G0_DBGMCU_BASE + 0x004U) +#define STM32G0_DBGMCU_APBFREEZE1 (STM32G0_DBGMCU_BASE + 0x008U) + +#define STM32G0_DBGMCU_CONFIG_STOP (1U << 1U) +#define STM32G0_DBGMCU_CONFIG_STANDBY (1U << 2U) +#define STM32G0_DBGMCU_APBFREEZE1_WWDG (1U << 11U) +#define STM32G0_DBGMCU_APBFREEZE1_IWDG (1U << 12U) #define STM32C0_UID_BASE 0x1fff7550U #define STM32G0_UID_BASE 0x1fff7590U @@ -158,14 +159,8 @@ #define ID_STM32G07_8 0x460U #define ID_STM32G0B_C 0x467U -typedef struct stm32g0_saved_regs { - uint32_t rcc_apbenr1; - uint32_t dbg_cr; - uint32_t dbg_apb_fz1; -} stm32g0_saved_regs_s; - typedef struct stm32g0_priv { - stm32g0_saved_regs_s saved_regs; + uint32_t dbgmcu_config; bool irreversible_enabled; } stm32g0_priv_s; @@ -207,6 +202,38 @@ static void stm32g0_add_flash(target_s *target, uint32_t addr, size_t length, si target_add_flash(target, flash); } +static bool stm32g0_configure_dbgmcu(target_s *const target) +{ + /* If we're in the probe phase */ + if (target->target_storage == NULL) { + /* Allocate target-specific storage */ + stm32g0_priv_s *const priv_storage = calloc(1, sizeof(*priv_storage)); + if (!priv_storage) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + target->target_storage = priv_storage; + /* Get the current value of the debug control register (and store it for later) */ + priv_storage->dbgmcu_config = target_mem32_read32(target, STM32G0_DBGMCU_CONFIG); + /* Mark irriversible operations disabled */ + priv_storage->irreversible_enabled = false; + + target->attach = stm32g0_attach; + target->detach = stm32g0_detach; + } + + const stm32g0_priv_s *const priv = (stm32g0_priv_s *)target->target_storage; + /* Enable the clock for the DBGMCU if it's not already */ + target_mem32_write32(target, RCC_APBENR1, target_mem32_read32(target, RCC_APBENR1) | RCC_APBENR1_DBGEN); + /* Enable debugging during all low power modes */ + target_mem32_write32(target, STM32G0_DBGMCU_CONFIG, + priv->dbgmcu_config | (STM32G0_DBGMCU_CONFIG_STANDBY | STM32G0_DBGMCU_CONFIG_STOP)); + /* And make sure the WDTs stay synchronised to the run state of the processor */ + target_mem32_write32( + target, STM32G0_DBGMCU_APBFREEZE1, STM32G0_DBGMCU_APBFREEZE1_IWDG | STM32G0_DBGMCU_APBFREEZE1_WWDG); + return true; +} + /* * Probe for a known STM32G0 series part. * Populate the memory map and add custom commands. @@ -220,7 +247,7 @@ bool stm32g0_probe(target_s *target) switch (target->part_id) { case ID_STM32G03_4:; - const uint16_t dev_id = target_mem32_read32(target, DBG_IDCODE) & 0xfffU; + const uint16_t dev_id = target_mem32_read32(target, STM32G0_DBGMCU_IDCODE) & 0xfffU; switch (dev_id) { case ID_STM32G03_4: /* SRAM 8kiB, Flash up to 64kiB */ @@ -267,75 +294,43 @@ bool stm32g0_probe(target_s *target) return false; } + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + if (!stm32g0_configure_dbgmcu(target)) + return false; + target_add_ram32(target, RAM_START, ram_size); /* Even dual Flash bank devices have a contiguous Flash memory space */ stm32g0_add_flash(target, FLASH_START, flash_size, FLASH_PAGE_SIZE); - target->attach = stm32g0_attach; - target->detach = stm32g0_detach; target->mass_erase = stm32g0_mass_erase; target_add_commands(target, stm32g0_cmd_list, target->driver); - /* Save private storage */ - stm32g0_priv_s *priv_storage = calloc(1, sizeof(*priv_storage)); - if (!priv_storage) { /* calloc failed: heap exhaustion */ - DEBUG_ERROR("calloc: failed in %s\n", __func__); - return false; - } - target->target_storage = priv_storage; - priv_storage->irreversible_enabled = false; - /* OTP Flash area */ stm32g0_add_flash(target, FLASH_OTP_START, FLASH_OTP_SIZE, FLASH_OTP_BLOCKSIZE); return true; } -/* - * In addition to attaching the debug core with cortexm_attach(), this function - * keeps the FCLK and HCLK clocks running in Standby and Stop modes while - * debugging. - * The watchdogs (IWDG and WWDG) are stopped when the core is halted. This - * allows basic Flash operations (erase/write) if the watchdog is started by - * hardware or by a previous program without prior power cycle. - */ static bool stm32g0_attach(target_s *target) { - stm32g0_priv_s *priv = (stm32g0_priv_s *)target->target_storage; - - if (!cortexm_attach(target)) - return false; - - priv->saved_regs.rcc_apbenr1 = target_mem32_read32(target, RCC_APBENR1); - target_mem32_write32(target, RCC_APBENR1, priv->saved_regs.rcc_apbenr1 | RCC_APBENR1_DBGEN); - priv->saved_regs.dbg_cr = target_mem32_read32(t, DBG_CR); - target_mem32_write32(target, DBG_CR, priv->saved_regs.dbg_cr | (DBG_CR_DBG_STANDBY | DBG_CR_DBG_STOP)); - priv->saved_regs.dbg_apb_fz1 = target_mem32_read32(t, DBG_APB_FZ1); - target_mem32_write32( - target, DBG_APB_FZ1, priv->saved_regs.dbg_apb_fz1 | (DBG_APB_FZ1_DBG_IWDG_STOP | DBG_APB_FZ1_DBG_WWDG_STOP)); - - return true; + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + return cortexm_attach(target) && stm32g0_configure_dbgmcu(target); } -/* - * Restore the modified registers and detach the debug core. - * The registers are restored as is to leave the target in the same state as - * before attachment. - */ static void stm32g0_detach(target_s *target) { - stm32g0_priv_s *priv = (stm32g0_priv_s *)target->target_storage; - - /* - * First re-enable DBGEN clock, in case it got disabled in the meantime - * (happens during flash), so that writes to DBG_* registers below succeed. - */ - target_mem32_write32(target, RCC_APBENR1, priv->saved_regs.rcc_apbenr1 | RCC_APBENR1_DBGEN); - - /* Then restore the DBG_* registers and clock settings. */ - target_mem32_write32(target, DBG_APB_FZ1, priv->saved_regs.dbg_apb_fz1); - target_mem32_write32(target, DBG_CR, priv->saved_regs.dbg_cr); - target_mem32_write32(target, RCC_APBENR1, priv->saved_regs.rcc_apbenr1); - + const stm32g0_priv_s *const priv = (stm32g0_priv_s *)target->target_storage; + /* Grab the current state of the clock enables */ + const uint32_t apb_en1 = target_mem32_read32(target, RCC_APBENR1) & ~RCC_APBENR1_DBGEN; + /* Ensure that the DBGMCU is still clocked enabled */ + target_mem32_write32(target, RCC_APBENR1, apb_en1 | RCC_APBENR1_DBGEN); + /* Reverse all changes to STM32F4_DBGMCU_CONFIG */ + target_mem32_write32(target, STM32G0_DBGMCU_CONFIG, priv->dbgmcu_config); + /* Disable the DBGMCU clock */ + target_mem32_write32(target, RCC_APBENR1, apb_en1); + /* Now defer to the normal Cortex-M detach routine to complete the detach */ cortexm_detach(target); } From 99ebf84e74c77afbd4a52c1c893006ce8bd30282 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 12 Jul 2024 23:03:44 +0100 Subject: [PATCH 22/47] stm32l4: Bought the copyright/attribution notice into compliance --- src/target/stm32l4.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index c5e77572be1..a92f766de3f 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -1,8 +1,10 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2015, 2017 - 2022 Uwe Bonnes - * + * Copyright (C) 2015, 2017-2022 Uwe Bonnes + * Copyright (C) 2022-2024 1BitSquared + * Written by Uwe Bonnes + * Modified by Rachel Mant * * 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 From 51a32549112f04f305b9d4ec7f3693a5794859e2 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 13 Jul 2024 23:57:21 +0100 Subject: [PATCH 23/47] stm32l4: Systematically correced the nomenclature for `target`, `flash`, and `priv` --- src/target/stm32l4.c | 345 ++++++++++++++++++++++--------------------- 1 file changed, 174 insertions(+), 171 deletions(-) diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index a92f766de3f..034707d16e2 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -56,16 +56,16 @@ #include #include -static bool stm32l4_cmd_erase_bank1(target_s *t, int argc, const char **argv); -static bool stm32l4_cmd_erase_bank2(target_s *t, int argc, const char **argv); -static bool stm32l4_cmd_option(target_s *t, int argc, const char **argv); -static bool stm32l4_cmd_uid(target_s *t, int argc, const char **argv); +static bool stm32l4_cmd_erase_bank1(target_s *target, int argc, const char **argv); +static bool stm32l4_cmd_erase_bank2(target_s *target, int argc, const char **argv); +static bool stm32l4_cmd_option(target_s *target, int argc, const char **argv); +static bool stm32l4_cmd_uid(target_s *target, int argc, const char **argv); -static bool stm32l4_attach(target_s *t); -static void stm32l4_detach(target_s *t); -static bool stm32l4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); -static bool stm32l4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); -static bool stm32l4_mass_erase(target_s *t); +static bool stm32l4_attach(target_s *target); +static void stm32l4_detach(target_s *target); +static bool stm32l4_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); +static bool stm32l4_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); +static bool stm32l4_mass_erase(target_s *target); const command_s stm32l4_cmd_list[] = { {"erase_bank1", stm32l4_cmd_erase_bank1, "Erase entire bank1 flash memory"}, @@ -214,7 +214,7 @@ typedef struct stm32l4_device_info { } stm32l4_device_info_s; typedef struct stm32l4_flash { - target_flash_s f; + target_flash_s flash; uint32_t bank1_start; } stm32l4_flash_s; @@ -507,84 +507,84 @@ static const stm32l4_device_info_s *stm32l4_get_device_info(const uint16_t devic return device_info; } -static inline uint32_t stm32l4_read_flash_size(target_s *const t) +static inline uint32_t stm32l4_read_flash_size(target_s *const target) { - stm32l4_priv_s *ps = (stm32l4_priv_s *)t->target_storage; - const stm32l4_device_info_s *const device = ps->device; - return target_mem32_read16(t, device->flash_size_reg); + stm32l4_priv_s *priv = (stm32l4_priv_s *)target->target_storage; + const stm32l4_device_info_s *const device = priv->device; + return target_mem32_read16(target, device->flash_size_reg); } -static inline uint32_t stm32l4_flash_read32(target_s *const t, const stm32l4_flash_reg_e reg) +static inline uint32_t stm32l4_flash_read32(target_s *const target, const stm32l4_flash_reg_e reg) { - stm32l4_priv_s *ps = (stm32l4_priv_s *)t->target_storage; - const stm32l4_device_info_s *const device = ps->device; - return target_mem32_read32(t, device->flash_regs_map[reg]); + stm32l4_priv_s *priv = (stm32l4_priv_s *)target->target_storage; + const stm32l4_device_info_s *const device = priv->device; + return target_mem32_read32(target, device->flash_regs_map[reg]); } -static inline void stm32l4_flash_write32(target_s *const t, const stm32l4_flash_reg_e reg, const uint32_t value) +static inline void stm32l4_flash_write32(target_s *const target, const stm32l4_flash_reg_e reg, const uint32_t value) { - stm32l4_priv_s *ps = (stm32l4_priv_s *)t->target_storage; - const stm32l4_device_info_s *const device = ps->device; - target_mem32_write32(t, device->flash_regs_map[reg], value); + stm32l4_priv_s *priv = (stm32l4_priv_s *)target->target_storage; + const stm32l4_device_info_s *const device = priv->device; + target_mem32_write32(target, device->flash_regs_map[reg], value); } -static void stm32l4_add_flash( - target_s *const t, const uint32_t addr, const size_t length, const size_t blocksize, const uint32_t bank1_start) +static void stm32l4_add_flash(target_s *const target, const uint32_t addr, const size_t length, const size_t blocksize, + const uint32_t bank1_start) { - stm32l4_flash_s *sf = calloc(1, sizeof(*sf)); - if (!sf) { /* calloc failed: heap exhaustion */ + stm32l4_flash_s *flash = calloc(1, sizeof(*flash)); + if (!flash) { /* calloc failed: heap exhaustion */ DEBUG_ERROR("calloc: failed in %s\n", __func__); return; } - target_flash_s *f = &sf->f; - f->start = addr; - f->length = length; - f->blocksize = blocksize; - f->erase = stm32l4_flash_erase; - f->write = stm32l4_flash_write; - f->writesize = 2048; - f->erased = 0xffU; - sf->bank1_start = bank1_start; - target_add_flash(t, f); + target_flash_s *target_flash = &flash->flash; + target_flash->start = addr; + target_flash->length = length; + target_flash->blocksize = blocksize; + target_flash->erase = stm32l4_flash_erase; + target_flash->write = stm32l4_flash_write; + target_flash->writesize = 2048; + target_flash->erased = 0xffU; + flash->bank1_start = bank1_start; + target_add_flash(target, target_flash); } /* For flash programming, L5 needs to be in VOS 0 or 1 while reset set 2 (or even 3?) */ -static void stm32l5_flash_enable(target_s *t) +static void stm32l5_flash_enable(target_s *const target) { - target_mem32_write32(t, STM32L5_RCC_APB1ENR1, STM32L5_RCC_APB1ENR1_PWREN); - const uint32_t pwr_ctrl1 = target_mem32_read32(t, STM32L5_PWR_CR1) & ~STM32L5_PWR_CR1_VOS; - target_mem32_write32(t, STM32L5_PWR_CR1, pwr_ctrl1); + target_mem32_write32(target, STM32L5_RCC_APB1ENR1, STM32L5_RCC_APB1ENR1_PWREN); + const uint32_t pwr_ctrl1 = target_mem32_read32(target, STM32L5_PWR_CR1) & ~STM32L5_PWR_CR1_VOS; + target_mem32_write32(target, STM32L5_PWR_CR1, pwr_ctrl1); } -static uint32_t stm32l4_idcode_reg_address(target_s *const t) +static uint32_t stm32l4_idcode_reg_address(target_s *const target) { - const stm32l4_priv_s *const priv = (const stm32l4_priv_s *)t->target_storage; + const stm32l4_priv_s *const priv = (const stm32l4_priv_s *)target->target_storage; const stm32l4_device_info_s *const device = priv->device; if (device->family == STM32L4_FAMILY_L55x) { - stm32l5_flash_enable(t); + stm32l5_flash_enable(target); return STM32L5_DBGMCU_IDCODE_PHYS; } return STM32L4_DBGMCU_IDCODE_PHYS; } -static uint32_t stm32l4_main_sram_length(const target_s *const t) +static uint32_t stm32l4_main_sram_length(const target_s *const target) { - const stm32l4_priv_s *const priv = (const stm32l4_priv_s *)t->target_storage; + const stm32l4_priv_s *const priv = (const stm32l4_priv_s *)target->target_storage; const stm32l4_device_info_s *const device = priv->device; /* All L4 beside L47 alias SRAM2 after SRAM1.*/ - if (t->part_id == ID_STM32L47) + if (target->part_id == ID_STM32L47) return device->sram1 * 1024U; return (device->sram1 + device->sram2 + device->sram3) * 1024U; } -bool stm32l4_probe(target_s *const t) +bool stm32l4_probe(target_s *const target) { - adiv5_access_port_s *ap = cortex_ap(t); + adiv5_access_port_s *ap = cortex_ap(target); uint32_t device_id = ap->dp->version >= 2U ? ap->dp->target_partno : ap->partno; /* If the part is DPv0 or DPv1, we must use the L4 ID register, except if we've already identified an L5 part */ if (ap->dp->version < 2U && device_id != ID_STM32L55) - device_id = target_mem32_read32(t, STM32L4_DBGMCU_IDCODE_PHYS) & 0xfffU; + device_id = target_mem32_read32(target, STM32L4_DBGMCU_IDCODE_PHYS) & 0xfffU; DEBUG_INFO("ID Code: %08" PRIx32 "\n", device_id); const stm32l4_device_info_s *device = stm32l4_get_device_info(device_id); @@ -595,16 +595,16 @@ bool stm32l4_probe(target_s *const t) /* Save private storage */ stm32l4_priv_s *priv_storage = calloc(1, sizeof(*priv_storage)); priv_storage->device = device; - t->target_storage = (void *)priv_storage; + target->target_storage = (void *)priv_storage; - t->driver = device->designator; + target->driver = device->designator; switch (device_id) { case ID_STM32WLXX: case ID_STM32WBXX: case ID_STM32WB1X: - if ((stm32l4_flash_read32(t, FLASH_OPTR)) & FLASH_OPTR_ESE) { + if ((stm32l4_flash_read32(target, FLASH_OPTR)) & FLASH_OPTR_ESE) { DEBUG_WARN("STM32W security enabled\n"); - t->driver = device_id == ID_STM32WLXX ? "STM32WLxx (secure)" : "STM32WBxx (secure)"; + target->driver = device_id == ID_STM32WLXX ? "STM32WLxx (secure)" : "STM32WBxx (secure)"; } if (ap->apsel == 0) { /* @@ -612,72 +612,73 @@ bool stm32l4_probe(target_s *const t) * CPU2 does not boot after reset w/o C2BOOT set. * RM0453/RM0434, §6.6.4. PWR control register 4 (PWR_CR4) */ - const uint32_t pwr_ctrl4 = target_mem32_read32(t, PWR_CR4); - target_mem32_write32(t, PWR_CR4, pwr_ctrl4 | PWR_CR4_C2BOOT); + const uint32_t pwr_ctrl4 = target_mem32_read32(target, PWR_CR4); + target_mem32_write32(target, PWR_CR4, pwr_ctrl4 | PWR_CR4_C2BOOT); } break; case ID_STM32L55: - if ((stm32l4_flash_read32(t, FLASH_OPTR)) & STM32L5_FLASH_OPTR_TZEN) { + if ((stm32l4_flash_read32(target, FLASH_OPTR)) & STM32L5_FLASH_OPTR_TZEN) { DEBUG_WARN("STM32L5 Trust Zone enabled\n"); - t->core = "M33+TZ"; + target->core = "M33+TZ"; break; } } - t->mass_erase = stm32l4_mass_erase; - t->attach = stm32l4_attach; - t->detach = stm32l4_detach; - target_add_commands(t, stm32l4_cmd_list, device->designator); + target->mass_erase = stm32l4_mass_erase; + target->attach = stm32l4_attach; + target->detach = stm32l4_detach; + target_add_commands(target, stm32l4_cmd_list, device->designator); return true; } -static bool stm32l4_attach(target_s *const t) +static bool stm32l4_attach(target_s *const target) { - if (!cortexm_attach(t)) + if (!cortexm_attach(target)) return false; /* Retrieve device information, and locate the device ID register */ - const stm32l4_device_info_s *device = stm32l4_get_device_info(t->part_id); - const uint32_t idcode_addr = stm32l4_idcode_reg_address(t); + const stm32l4_device_info_s *device = stm32l4_get_device_info(target->part_id); + const uint32_t idcode_addr = stm32l4_idcode_reg_address(target); /* Save DBGMCU_CR to restore it when detaching */ - stm32l4_priv_s *const priv_storage = (stm32l4_priv_s *)t->target_storage; - priv_storage->dbgmcu_cr = target_mem32_read32(t, DBGMCU_CR(idcode_addr)); + stm32l4_priv_s *const priv_storage = (stm32l4_priv_s *)target->target_storage; + priv_storage->dbgmcu_cr = target_mem32_read32(target, DBGMCU_CR(idcode_addr)); /* Enable debugging during all low power modes */ - target_mem32_write32(t, DBGMCU_CR(idcode_addr), DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STANDBY | DBGMCU_CR_DBG_STOP); + target_mem32_write32( + target, DBGMCU_CR(idcode_addr), DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STANDBY | DBGMCU_CR_DBG_STOP); /* Free any previously built memory map */ - target_mem_map_free(t); + target_mem_map_free(target); /* And rebuild the RAM map */ if (device->family == STM32L4_FAMILY_L55x || device->family == STM32L4_FAMILY_U5xx) - target_add_ram32(t, 0x0a000000, (device->sram1 + device->sram2) * 1024U); + target_add_ram32(target, 0x0a000000, (device->sram1 + device->sram2) * 1024U); else - target_add_ram32(t, 0x10000000, device->sram2 * 1024U); - target_add_ram32(t, 0x20000000, stm32l4_main_sram_length(t)); + target_add_ram32(target, 0x10000000, device->sram2 * 1024U); + target_add_ram32(target, 0x20000000, stm32l4_main_sram_length(target)); - const uint16_t flash_len = stm32l4_read_flash_size(t); - const uint32_t options = stm32l4_flash_read32(t, FLASH_OPTR); + const uint16_t flash_len = stm32l4_read_flash_size(target); + const uint32_t options = stm32l4_flash_read32(target, FLASH_OPTR); /* Now we have a base RAM map, rebuild the Flash map */ if (device->family == STM32L4_FAMILY_WBxx) { if (device->device_id == ID_STM32WB1X) - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, flash_len * 1024U, 0x0800, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, flash_len * 1024U, 0x0800, UINT32_MAX); else - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, flash_len * 1024U, 0x1000, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, flash_len * 1024U, 0x1000, UINT32_MAX); } else if (device->family == STM32L4_FAMILY_L4Rx) { /* RM0432 Rev. 2 does not mention 1MiB devices or explain DB1M.*/ if (options & OR_DBANK) { - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, 0x00100000, 0x1000, 0x08100000); - stm32l4_add_flash(t, 0x08100000, 0x00100000, 0x1000, 0x08100000); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, 0x00100000, 0x1000, 0x08100000); + stm32l4_add_flash(target, 0x08100000, 0x00100000, 0x1000, 0x08100000); } else - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, 0x00200000, 0x2000, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, 0x00200000, 0x2000, UINT32_MAX); } else if (device->family == STM32L4_FAMILY_L55x) { /* FIXME: Test behaviour on 256kiB devices */ if (options & OR_DBANK) { - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, 0x00040000, 0x0800, 0x08040000); - stm32l4_add_flash(t, 0x08040000, 0x00040000, 0x0800, 0x08040000); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, 0x00040000, 0x0800, 0x08040000); + stm32l4_add_flash(target, 0x08040000, 0x00040000, 0x0800, 0x08040000); } else - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, 0x00080000, 0x0800, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, 0x00080000, 0x0800, UINT32_MAX); } else if (device->family == STM32L4_FAMILY_G4xx) { /* * RM0440 describes G43x/G44x as Category 2, G47x/G48x as Category 3 and G49x/G4Ax as Category 4 devices @@ -688,71 +689,73 @@ static bool stm32l4_attach(target_s *const t) */ if (device->device_id == ID_STM32G43) { const uint32_t bank_len = flash_len * 1024U; - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x0800, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x0800, UINT32_MAX); } else if (device->device_id == ID_STM32G49) { /* Announce maximum possible flash length on this device */ - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, FLASH_SIZE_MAX_G4_CAT4, 0x0800, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, FLASH_SIZE_MAX_G4_CAT4, 0x0800, UINT32_MAX); } else { if (options & OR_DBANK) { const uint32_t bank_len = flash_len * 512U; - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x0800, STM32L4_FLASH_BANK_1_BASE + bank_len); stm32l4_add_flash( - t, STM32L4_FLASH_BANK_1_BASE + bank_len, bank_len, 0x0800, STM32L4_FLASH_BANK_1_BASE + bank_len); + target, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x0800, STM32L4_FLASH_BANK_1_BASE + bank_len); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE + bank_len, bank_len, 0x0800, + STM32L4_FLASH_BANK_1_BASE + bank_len); } else { const uint32_t bank_len = flash_len * 1024U; - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x1000, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x1000, UINT32_MAX); } } } else if (device->flags & DUAL_BANK) { if (options & OR_DUALBANK) { const uint32_t bank_len = flash_len * 512U; if (device->family == STM32L4_FAMILY_U5xx) { - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, bank_len, STM32U5_FLASH_BLOCK_SIZE, + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, bank_len, STM32U5_FLASH_BLOCK_SIZE, STM32L4_FLASH_BANK_1_BASE + bank_len); - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE + bank_len, bank_len, STM32U5_FLASH_BLOCK_SIZE, + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE + bank_len, bank_len, STM32U5_FLASH_BLOCK_SIZE, STM32L4_FLASH_BANK_1_BASE + bank_len); } else { - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x0800, STM32L4_FLASH_BANK_1_BASE + bank_len); stm32l4_add_flash( - t, STM32L4_FLASH_BANK_1_BASE + bank_len, bank_len, 0x0800, STM32L4_FLASH_BANK_1_BASE + bank_len); + target, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x0800, STM32L4_FLASH_BANK_1_BASE + bank_len); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE + bank_len, bank_len, 0x0800, + STM32L4_FLASH_BANK_1_BASE + bank_len); } } else { const uint32_t bank_len = flash_len * 1024U; - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x0800, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, bank_len, 0x0800, UINT32_MAX); } } else - stm32l4_add_flash(t, STM32L4_FLASH_BANK_1_BASE, flash_len * 1024U, 0x800, UINT32_MAX); + stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, flash_len * 1024U, 0x800, UINT32_MAX); /* Clear all errors in the status register. */ - stm32l4_flash_write32(t, FLASH_SR, stm32l4_flash_read32(t, FLASH_SR)); + stm32l4_flash_write32(target, FLASH_SR, stm32l4_flash_read32(target, FLASH_SR)); return true; } -static void stm32l4_detach(target_s *const t) +static void stm32l4_detach(target_s *const target) { - const stm32l4_priv_s *const ps = (stm32l4_priv_s *)t->target_storage; + const stm32l4_priv_s *const priv = (stm32l4_priv_s *)target->target_storage; /*reverse all changes to DBGMCU_CR*/ - target_mem32_write32(t, DBGMCU_CR(STM32L4_DBGMCU_IDCODE_PHYS), ps->dbgmcu_cr); - cortexm_detach(t); + target_mem32_write32(target, DBGMCU_CR(STM32L4_DBGMCU_IDCODE_PHYS), priv->dbgmcu_cr); + cortexm_detach(target); } -static void stm32l4_flash_unlock(target_s *const t) +static void stm32l4_flash_unlock(target_s *const target) { - if ((stm32l4_flash_read32(t, FLASH_CR)) & FLASH_CR_LOCK) { + if ((stm32l4_flash_read32(target, FLASH_CR)) & FLASH_CR_LOCK) { /* Enable FPEC controller access */ - stm32l4_flash_write32(t, FLASH_KEYR, KEY1); - stm32l4_flash_write32(t, FLASH_KEYR, KEY2); + stm32l4_flash_write32(target, FLASH_KEYR, KEY1); + stm32l4_flash_write32(target, FLASH_KEYR, KEY2); } } -static bool stm32l4_flash_busy_wait(target_s *const t, platform_timeout_s *timeout) +static bool stm32l4_flash_busy_wait(target_s *const target, platform_timeout_s *timeout) { /* Read FLASH_SR to poll for BSY bit */ uint32_t status = FLASH_SR_BSY; while (status & FLASH_SR_BSY) { - status = stm32l4_flash_read32(t, FLASH_SR); - if ((status & FLASH_SR_ERROR_MASK) || target_check_error(t)) { + status = stm32l4_flash_read32(target, FLASH_SR); + if ((status & FLASH_SR_ERROR_MASK) || target_check_error(target)) { DEBUG_ERROR("stm32l4 Flash error: status 0x%" PRIx32 "\n", status); return false; } @@ -762,119 +765,119 @@ static bool stm32l4_flash_busy_wait(target_s *const t, platform_timeout_s *timeo return true; } -static bool stm32l4_flash_erase(target_flash_s *const f, const target_addr_t addr, const size_t len) +static bool stm32l4_flash_erase(target_flash_s *const flash, const target_addr_t addr, const size_t len) { - target_s *t = f->t; - const stm32l4_flash_s *const sf = (stm32l4_flash_s *)f; + target_s *target = flash->t; + const stm32l4_flash_s *const sf = (stm32l4_flash_s *)flash; /* STM32WBXX ERRATA ES0394 2.2.9: OPTVERR flag is always set after system reset */ - stm32l4_flash_write32(t, FLASH_SR, stm32l4_flash_read32(t, FLASH_SR)); + stm32l4_flash_write32(target, FLASH_SR, stm32l4_flash_read32(target, FLASH_SR)); /* Unlock the Flash and wait for the operation to complete, reporting any errors */ - stm32l4_flash_unlock(t); - if (!stm32l4_flash_busy_wait(t, NULL)) + stm32l4_flash_unlock(target); + if (!stm32l4_flash_busy_wait(target, NULL)) return false; /* Erase the requested chunk of flash, one page at a time. */ - for (size_t offset = 0; offset < len; offset += f->blocksize) { - const uint32_t page = (addr + offset - STM32L4_FLASH_BANK_1_BASE) / f->blocksize; + for (size_t offset = 0; offset < len; offset += flash->blocksize) { + const uint32_t page = (addr + offset - STM32L4_FLASH_BANK_1_BASE) / flash->blocksize; const uint32_t bank_flags = addr + offset >= sf->bank1_start ? FLASH_CR_BKER : 0; const uint32_t ctrl = FLASH_CR_PER | (page << FLASH_CR_PAGE_SHIFT) | bank_flags; /* Flash page erase instruction */ - stm32l4_flash_write32(t, FLASH_CR, ctrl); + stm32l4_flash_write32(target, FLASH_CR, ctrl); /* write address to FMA */ - stm32l4_flash_write32(t, FLASH_CR, ctrl | FLASH_CR_STRT); + stm32l4_flash_write32(target, FLASH_CR, ctrl | FLASH_CR_STRT); /* Wait for completion or an error */ - if (!stm32l4_flash_busy_wait(t, NULL)) + if (!stm32l4_flash_busy_wait(target, NULL)) return false; } return true; } -static bool stm32l4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) +static bool stm32l4_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len) { - target_s *t = f->t; - stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_PG); - target_mem32_write(t, dest, src, len); + target_s *target = flash->t; + stm32l4_flash_write32(target, FLASH_CR, FLASH_CR_PG); + target_mem32_write(target, dest, src, len); /* Wait for completion or an error */ - return stm32l4_flash_busy_wait(t, NULL); + return stm32l4_flash_busy_wait(target, NULL); } -static bool stm32l4_cmd_erase(target_s *const t, const uint32_t action) +static bool stm32l4_cmd_erase(target_s *const target, const uint32_t action) { - stm32l4_flash_unlock(t); + stm32l4_flash_unlock(target); /* Erase time is 25 ms. Timeout logic shouldn't get fired.*/ /* Flash erase action start instruction */ - stm32l4_flash_write32(t, FLASH_CR, action); - stm32l4_flash_write32(t, FLASH_CR, action | FLASH_CR_STRT); + stm32l4_flash_write32(target, FLASH_CR, action); + stm32l4_flash_write32(target, FLASH_CR, action | FLASH_CR_STRT); platform_timeout_s timeout; platform_timeout_set(&timeout, 500); /* Wait for completion or an error */ - return stm32l4_flash_busy_wait(t, &timeout); + return stm32l4_flash_busy_wait(target, &timeout); } -static bool stm32l4_mass_erase(target_s *const t) +static bool stm32l4_mass_erase(target_s *const target) { - return stm32l4_cmd_erase(t, FLASH_CR_MER1 | FLASH_CR_MER2); + return stm32l4_cmd_erase(target, FLASH_CR_MER1 | FLASH_CR_MER2); } -static bool stm32l4_cmd_erase_bank1(target_s *const t, const int argc, const char **const argv) +static bool stm32l4_cmd_erase_bank1(target_s *const target, const int argc, const char **const argv) { (void)argc; (void)argv; - tc_printf(t, "Erasing bank %u: ", 1U); - const bool result = stm32l4_cmd_erase(t, FLASH_CR_MER1); - tc_printf(t, "done\n"); + tc_printf(target, "Erasing bank %u: ", 1U); + const bool result = stm32l4_cmd_erase(target, FLASH_CR_MER1); + tc_printf(target, "done\n"); return result; } -static bool stm32l4_cmd_erase_bank2(target_s *const t, const int argc, const char **const argv) +static bool stm32l4_cmd_erase_bank2(target_s *const target, const int argc, const char **const argv) { (void)argc; (void)argv; - tc_printf(t, "Erasing bank %u: ", 2U); - const bool result = stm32l4_cmd_erase(t, FLASH_CR_MER2); - tc_printf(t, "done\n"); + tc_printf(target, "Erasing bank %u: ", 2U); + const bool result = stm32l4_cmd_erase(target, FLASH_CR_MER2); + tc_printf(target, "done\n"); return result; } -static bool stm32l4_option_write(target_s *const t, const uint32_t *const values, const size_t len, +static bool stm32l4_option_write(target_s *const target, const uint32_t *const values, const size_t len, const uint32_t fpec_base, const uint8_t *const opt_reg_offsets) { /* Unlock the option registers Flash */ - stm32l4_flash_unlock(t); - stm32l4_flash_write32(t, FLASH_OPTKEYR, OPTKEY1); - stm32l4_flash_write32(t, FLASH_OPTKEYR, OPTKEY2); + stm32l4_flash_unlock(target); + stm32l4_flash_write32(target, FLASH_OPTKEYR, OPTKEY1); + stm32l4_flash_write32(target, FLASH_OPTKEYR, OPTKEY2); /* Wait for the operation to complete and report any errors */ - if (!stm32l4_flash_busy_wait(t, NULL)) + if (!stm32l4_flash_busy_wait(target, NULL)) return true; /* Write the new option register values and begin the programming operation */ for (size_t i = 0; i < len; i++) - target_mem32_write32(t, fpec_base + opt_reg_offsets[i], values[i]); - stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_OPTSTRT); + target_mem32_write32(target, fpec_base + opt_reg_offsets[i], values[i]); + stm32l4_flash_write32(target, FLASH_CR, FLASH_CR_OPTSTRT); /* Wait for the operation to complete and report any errors */ - if (!stm32l4_flash_busy_wait(t, NULL)) + if (!stm32l4_flash_busy_wait(target, NULL)) return false; - tc_printf(t, "Scan and attach again\n"); + tc_printf(target, "Scan and attach again\n"); /* Ask the device to reload its options bytes */ - stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_OBL_LAUNCH); - while (stm32l4_flash_read32(t, FLASH_CR) & FLASH_CR_OBL_LAUNCH) { - if (target_check_error(t)) + stm32l4_flash_write32(target, FLASH_CR, FLASH_CR_OBL_LAUNCH); + while (stm32l4_flash_read32(target, FLASH_CR) & FLASH_CR_OBL_LAUNCH) { + if (target_check_error(target)) return true; } /* Re-lock Flash */ - stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_LOCK); + stm32l4_flash_write32(target, FLASH_CR, FLASH_CR_LOCK); return false; } -static uint32_t stm32l4_fpec_base_addr(const target_s *const t) +static uint32_t stm32l4_fpec_base_addr(const target_s *const target) { - if (t->part_id == ID_STM32WLXX) + if (target->part_id == ID_STM32WLXX) return STM32WL_FPEC_BASE; return STM32L4_FPEC_BASE; } @@ -933,23 +936,23 @@ static stm32l4_option_bytes_info_s stm32l4_get_opt_bytes_info(const uint16_t par * 0x1ffff828 0 0 0 0 0x000000ff 0xff00ff00 */ -static bool stm32l4_cmd_option(target_s *t, int argc, const char **argv) +static bool stm32l4_cmd_option(target_s *target, int argc, const char **argv) { - if (t->part_id == ID_STM32L55) { - tc_printf(t, "%s options not implemented!\n", "STM32L5"); + if (target->part_id == ID_STM32L55) { + tc_printf(target, "%s options not implemented!\n", "STM32L5"); return false; } - if (t->part_id == ID_STM32WBXX || t->part_id == ID_STM32WB1X) { - tc_printf(t, "%s options not implemented!\n", "STM32WBxx"); + if (target->part_id == ID_STM32WBXX || target->part_id == ID_STM32WB1X) { + tc_printf(target, "%s options not implemented!\n", "STM32WBxx"); return false; } - if (t->part_id == ID_STM32WLXX) { - tc_printf(t, "%s options not implemented!\n", "STM32WLxx"); + if (target->part_id == ID_STM32WLXX) { + tc_printf(target, "%s options not implemented!\n", "STM32WLxx"); return false; } - const stm32l4_option_bytes_info_s info = stm32l4_get_opt_bytes_info(t->part_id); - const uint32_t fpec_base = stm32l4_fpec_base_addr(t); + const stm32l4_option_bytes_info_s info = stm32l4_get_opt_bytes_info(target->part_id); + const uint32_t fpec_base = stm32l4_fpec_base_addr(target); const uint8_t *const opt_reg_offsets = info.offsets; const size_t word_count = info.word_count; @@ -959,42 +962,42 @@ static bool stm32l4_cmd_option(target_s *t, int argc, const char **argv) bool result = false; if (argc == 2 && strcmp(argv[1], "erase") == 0) - result = stm32l4_option_write(t, values, word_count, fpec_base, opt_reg_offsets); + result = stm32l4_option_write(target, values, word_count, fpec_base, opt_reg_offsets); else if (argc > 2 && strcmp(argv[1], "write") == 0) { const size_t option_words = MIN((size_t)argc - 2U, word_count); for (size_t i = 0; i < option_words; ++i) values[i] = strtoul(argv[i + 2U], NULL, 0); for (size_t i = option_words; i < word_count; ++i) - values[i] = target_mem32_read32(t, fpec_base + opt_reg_offsets[i]); + values[i] = target_mem32_read32(target, fpec_base + opt_reg_offsets[i]); if ((values[0] & 0xffU) == 0xccU) { ++values[0]; - tc_printf(t, "Changing level 2 protection request to level 1!"); + tc_printf(target, "Changing level 2 protection request to level 1!"); } - result = stm32l4_option_write(t, values, word_count, fpec_base, opt_reg_offsets); + result = stm32l4_option_write(target, values, word_count, fpec_base, opt_reg_offsets); } else { - tc_printf(t, "usage: monitor option erase\n"); - tc_printf(t, "usage: monitor option write ...\n"); + tc_printf(target, "usage: monitor option erase\n"); + tc_printf(target, "usage: monitor option write ...\n"); } if (result) { - tc_printf(t, "Writing options failed!\n"); + tc_printf(target, "Writing options failed!\n"); return false; } for (size_t i = 0; i < word_count; ++i) { const uint32_t addr = fpec_base + opt_reg_offsets[i]; - const uint32_t val = target_mem32_read32(t, fpec_base + opt_reg_offsets[i]); - tc_printf(t, "0x%08X: 0x%08X\n", addr, val); + const uint32_t val = target_mem32_read32(target, fpec_base + opt_reg_offsets[i]); + tc_printf(target, "0x%08X: 0x%08X\n", addr, val); } return true; } /* Read and decode Unique Device ID register of L4 and G4 */ -static bool stm32l4_cmd_uid(target_s *t, int argc, const char **argv) +static bool stm32l4_cmd_uid(target_s *target, int argc, const char **argv) { (void)argc; (void)argv; - return stm32_uid(t, STM32L4_UID_BASE); + return stm32_uid(target, STM32L4_UID_BASE); } From b5372e8cbe548cd6e77c1166a8cb6ff826347df4 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 14 Jul 2024 07:21:27 +0100 Subject: [PATCH 24/47] stm32l4: Refactored the handling for the WDTs and WFI/WFE debugging support --- src/target/stm32l4.c | 121 ++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 43 deletions(-) diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index 034707d16e2..0f5cfc469a0 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -127,20 +127,28 @@ const command_s stm32l4_cmd_list[] = { #define SR_ERROR_MASK 0xf2U -/* Used in STM32L47*/ +/* Used in STM32L47 */ #define OR_DUALBANK (1U << 21U) -/* Used in STM32L47R*/ +/* Used in STM32L47R */ #define OR_DB1M (1U << 21U) -/* Used in STM32L47R, STM32G47 and STM32L55*/ +/* Used in STM32L47R, STM32G47 and STM32L55 */ #define OR_DBANK (1U << 22U) -#define DBGMCU_CR(reg_base) ((reg_base) + 0x04U) -#define DBGMCU_CR_DBG_SLEEP (1U << 0U) -#define DBGMCU_CR_DBG_STOP (1U << 1U) -#define DBGMCU_CR_DBG_STANDBY (1U << 2U) +#define STM32L4_DBGMCU_BASE 0xe0042000U +#define STM32L4_DBGMCU_IDCODE (STM32L4_DBGMCU_BASE + 0x000U) +#define STM32L4_DBGMCU_CONFIG (STM32L4_DBGMCU_BASE + 0x004U) +#define STM32L4_DBGMCU_APB1FREEZE1 (STM32L4_DBGMCU_BASE + 0x008U) -#define STM32L4_DBGMCU_IDCODE_PHYS 0xe0042000U -#define STM32L5_DBGMCU_IDCODE_PHYS 0xe0044000U +#define STM32L5_DBGMCU_BASE 0xe0044000U +#define STM32L5_DBGMCU_IDCODE (STM32L5_DBGMCU_BASE + 0x000U) +#define STM32L5_DBGMCU_CONFIG (STM32L5_DBGMCU_BASE + 0x004U) +#define STM32L5_DBGMCU_APB1FREEZE1 (STM32L5_DBGMCU_BASE + 0x008U) + +#define STM32L4_DBGMCU_CONFIG_DBG_SLEEP (1U << 0U) +#define STM32L4_DBGMCU_CONFIG_DBG_STOP (1U << 1U) +#define STM32L4_DBGMCU_CONFIG_DBG_STANDBY (1U << 2U) +#define STM32L4_DBGMCU_APB1FREEZE1_WWDG (1U << 11U) +#define STM32L4_DBGMCU_APB1FREEZE1_IWDG (1U << 12U) #define STM32L4_UID_BASE 0x1fff7590U #define STM32L4_FLASH_SIZE_REG 0x1fff75e0U @@ -220,7 +228,7 @@ typedef struct stm32l4_flash { typedef struct stm32l4_priv { const stm32l4_device_info_s *device; - uint32_t dbgmcu_cr; + uint32_t dbgmcu_config; } stm32l4_priv_s; typedef struct stm32l4_option_bytes_info { @@ -557,17 +565,6 @@ static void stm32l5_flash_enable(target_s *const target) target_mem32_write32(target, STM32L5_PWR_CR1, pwr_ctrl1); } -static uint32_t stm32l4_idcode_reg_address(target_s *const target) -{ - const stm32l4_priv_s *const priv = (const stm32l4_priv_s *)target->target_storage; - const stm32l4_device_info_s *const device = priv->device; - if (device->family == STM32L4_FAMILY_L55x) { - stm32l5_flash_enable(target); - return STM32L5_DBGMCU_IDCODE_PHYS; - } - return STM32L4_DBGMCU_IDCODE_PHYS; -} - static uint32_t stm32l4_main_sram_length(const target_s *const target) { const stm32l4_priv_s *const priv = (const stm32l4_priv_s *)target->target_storage; @@ -578,25 +575,65 @@ static uint32_t stm32l4_main_sram_length(const target_s *const target) return (device->sram1 + device->sram2 + device->sram3) * 1024U; } +static bool stm32l4_configure_dbgmcu(target_s *const target, const stm32l4_device_info_s *device) +{ + /* If we're in the probe phase */ + if (target->target_storage == NULL) { + /* Allocate and save private storage */ + stm32l4_priv_s *const priv_storage = calloc(1, sizeof(*priv_storage)); + if (!priv_storage) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + /* Save the device we're configuring for */ + priv_storage->device = device; + /* Get the current value of the debug config register (and store it for later) */ + const target_addr32_t dbgmcu_config_taddr = + device->family == STM32L4_FAMILY_L55x ? STM32L5_DBGMCU_CONFIG : STM32L4_DBGMCU_CONFIG; + priv_storage->dbgmcu_config = target_mem32_read32(target, dbgmcu_config_taddr); + target->target_storage = priv_storage; + + target->attach = stm32l4_attach; + target->detach = stm32l4_detach; + } + + const stm32l4_priv_s *const priv = (stm32l4_priv_s *)target->target_storage; + /* + * Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us, + * then Reconfigure the config register to prevent WFI/WFE from cutting debug access + */ + if (device->family == STM32L4_FAMILY_L55x) { + target_mem32_write32( + target, STM32L5_DBGMCU_APB1FREEZE1, STM32L4_DBGMCU_APB1FREEZE1_IWDG | STM32L4_DBGMCU_APB1FREEZE1_WWDG); + target_mem32_write32(target, STM32L5_DBGMCU_CONFIG, + priv->dbgmcu_config | STM32L4_DBGMCU_CONFIG_DBG_STANDBY | STM32L4_DBGMCU_CONFIG_DBG_STOP); + } else { + target_mem32_write32( + target, STM32L4_DBGMCU_APB1FREEZE1, STM32L4_DBGMCU_APB1FREEZE1_IWDG | STM32L4_DBGMCU_APB1FREEZE1_WWDG); + target_mem32_write32(target, STM32L4_DBGMCU_CONFIG, + priv->dbgmcu_config | STM32L4_DBGMCU_CONFIG_DBG_STANDBY | STM32L4_DBGMCU_CONFIG_DBG_STOP | + STM32L4_DBGMCU_CONFIG_DBG_SLEEP); + } + return true; +} + bool stm32l4_probe(target_s *const target) { - adiv5_access_port_s *ap = cortex_ap(target); + adiv5_access_port_s *const ap = cortex_ap(target); uint32_t device_id = ap->dp->version >= 2U ? ap->dp->target_partno : ap->partno; /* If the part is DPv0 or DPv1, we must use the L4 ID register, except if we've already identified an L5 part */ if (ap->dp->version < 2U && device_id != ID_STM32L55) - device_id = target_mem32_read32(target, STM32L4_DBGMCU_IDCODE_PHYS) & 0xfffU; + device_id = target_mem32_read32(target, STM32L4_DBGMCU_IDCODE) & 0xfffU; DEBUG_INFO("ID Code: %08" PRIx32 "\n", device_id); const stm32l4_device_info_s *device = stm32l4_get_device_info(device_id); - /* If the call returned the sentinel, it's not a supported L4 device */ - if (!device->device_id) + /* + * If the call returned the sentinel, it's not a supported L4 device. + * Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems + */ + if (!device->device_id || !stm32l4_configure_dbgmcu(target, device)) return false; - /* Save private storage */ - stm32l4_priv_s *priv_storage = calloc(1, sizeof(*priv_storage)); - priv_storage->device = device; - target->target_storage = (void *)priv_storage; - target->driver = device->designator; switch (device_id) { case ID_STM32WLXX: @@ -623,29 +660,25 @@ bool stm32l4_probe(target_s *const target) break; } } + target->mass_erase = stm32l4_mass_erase; - target->attach = stm32l4_attach; - target->detach = stm32l4_detach; target_add_commands(target, stm32l4_cmd_list, device->designator); return true; } static bool stm32l4_attach(target_s *const target) { - if (!cortexm_attach(target)) + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + if (!cortexm_attach(target) || !stm32l4_configure_dbgmcu(target, NULL)) return false; /* Retrieve device information, and locate the device ID register */ const stm32l4_device_info_s *device = stm32l4_get_device_info(target->part_id); - const uint32_t idcode_addr = stm32l4_idcode_reg_address(target); - - /* Save DBGMCU_CR to restore it when detaching */ - stm32l4_priv_s *const priv_storage = (stm32l4_priv_s *)target->target_storage; - priv_storage->dbgmcu_cr = target_mem32_read32(target, DBGMCU_CR(idcode_addr)); - - /* Enable debugging during all low power modes */ - target_mem32_write32( - target, DBGMCU_CR(idcode_addr), DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STANDBY | DBGMCU_CR_DBG_STOP); + if (device->family == STM32L4_FAMILY_L55x) + stm32l5_flash_enable(target); /* Free any previously built memory map */ target_mem_map_free(target); @@ -734,9 +767,11 @@ static bool stm32l4_attach(target_s *const target) static void stm32l4_detach(target_s *const target) { const stm32l4_priv_s *const priv = (stm32l4_priv_s *)target->target_storage; + const stm32l4_device_info_s *const device = priv->device; /*reverse all changes to DBGMCU_CR*/ - target_mem32_write32(target, DBGMCU_CR(STM32L4_DBGMCU_IDCODE_PHYS), priv->dbgmcu_cr); + target_mem32_write32(target, device->family == STM32L4_FAMILY_L55x ? STM32L5_DBGMCU_CONFIG : STM32L4_DBGMCU_CONFIG, + priv->dbgmcu_config); cortexm_detach(target); } From d99beb458571b84da91cf0b7d8159a61c893d46e Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 16 Jul 2024 05:31:42 +0100 Subject: [PATCH 25/47] riscv_debug: Expose `riscv_attach()` and `riscv_detach()` in the architecture header so they can be used by target support --- src/target/riscv_debug.c | 8 +++----- src/target/riscv_debug.h | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/target/riscv_debug.c b/src/target/riscv_debug.c index 7951ea30b26..a4a41cc6f6f 100644 --- a/src/target/riscv_debug.c +++ b/src/target/riscv_debug.c @@ -142,6 +142,7 @@ static const char *const riscv_gpr_names[RV_GPRS_COUNT] = { }; // clang-format on + typedef struct riscv_csr_descriptor { const char *name; const uint32_t csr_number; // fits in 16 bits actually (?) @@ -257,9 +258,6 @@ static uint32_t riscv_hart_discover_isa(riscv_hart_s *hart); static void riscv_hart_discover_triggers(riscv_hart_s *hart); static void riscv_hart_memory_access_type(riscv_hart_s *hart); -static bool riscv_attach(target_s *target); -static void riscv_detach(target_s *target); - static const char *riscv_target_description(target_s *target); static bool riscv_check_error(target_s *target); @@ -811,7 +809,7 @@ bool riscv_config_trigger(riscv_hart_s *const hart, const uint32_t trigger, cons return result; } -static bool riscv_attach(target_s *const target) +bool riscv_attach(target_s *const target) { riscv_hart_s *const hart = riscv_hart_struct(target); /* If the DMI requires special preparation, do that first */ @@ -825,7 +823,7 @@ static bool riscv_attach(target_s *const target) return true; } -static void riscv_detach(target_s *const target) +void riscv_detach(target_s *const target) { riscv_hart_s *const hart = riscv_hart_struct(target); /* Once we get done and the user's asked us to detach, we need to resume the hart */ diff --git a/src/target/riscv_debug.h b/src/target/riscv_debug.h index 173c9840c35..ba1f0e87b3c 100644 --- a/src/target/riscv_debug.h +++ b/src/target/riscv_debug.h @@ -234,6 +234,9 @@ riscv_match_size_e riscv_breakwatch_match_size(size_t size); bool riscv_config_trigger( riscv_hart_s *hart, uint32_t trigger, riscv_trigger_state_e mode, const void *config, const void *address); +bool riscv_attach(target_s *target); +void riscv_detach(target_s *target); + uint8_t riscv_mem_access_width(const riscv_hart_s *hart, target_addr_t address, size_t length); void riscv32_unpack_data(void *dest, uint32_t data, uint8_t access_width); uint32_t riscv32_pack_data(const void *src, uint8_t access_width); From 5c98da4c50f01be4cd34e4cdc1b752e9e42faa03 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 16 Jul 2024 05:36:07 +0100 Subject: [PATCH 26/47] stm32f1: Fixed the GD32VF1 probe routine to use RISC-V suitable and specific attach/detach routines --- src/target/stm32f1.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index bac86a7860b..3534e72953e 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -51,6 +51,9 @@ #include "target.h" #include "target_internal.h" #include "cortexm.h" +#ifdef ENABLE_RISCV +#include "riscv_debug.h" +#endif #include "jep106.h" #include "stm32_common.h" @@ -303,6 +306,9 @@ bool gd32f1_probe(target_s *target) } #ifdef ENABLE_RISCV +static bool gd32vf1_attach(target_s *target); +static void gd32vf1_detach(target_s *target); + /* Identify RISC-V GD32VF1 chips */ bool gd32vf1_probe(target_s *const target) { @@ -330,7 +336,28 @@ bool gd32vf1_probe(target_s *const target) target_add_commands(target, stm32f1_cmd_list, target->driver); /* Now we have a stable debug environment, make sure the WDTs + sleep instructions can't cause problems */ - return stm32f1_configure_dbgmcu(target, STM32F1_DBGMCU_CONFIG); + const bool result = stm32f1_configure_dbgmcu(target, STM32F1_DBGMCU_CONFIG); + target->attach = gd32vf1_attach; + target->detach = gd32vf1_detach; + return result; +} + +static bool gd32vf1_attach(target_s *const target) +{ + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + return riscv_attach(target) && stm32f1_configure_dbgmcu(target, 0U); +} + +static void gd32vf1_detach(target_s *const target) +{ + const stm32f1_priv_s *const priv = (stm32f1_priv_s *)target->target_storage; + /* Reverse all changes to the DBGMCU config register */ + target_mem32_write32(target, priv->dbgmcu_config_taddr, priv->dbgmcu_config); + /* Now defer to the normal Cortex-M detach routine to complete the detach */ + riscv_detach(target); } #endif From 34c5b466be7680b04637e4b88f9aade24ed3dac0 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 16 Jul 2024 07:24:43 +0100 Subject: [PATCH 27/47] stm32mp15: Nomenclature corrections for the DBGMCU definitions --- src/target/stm32mp15.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/target/stm32mp15.c b/src/target/stm32mp15.c index 818cfabc87a..6be2ee16484 100644 --- a/src/target/stm32mp15.c +++ b/src/target/stm32mp15.c @@ -1,7 +1,7 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2023 1BitSquared + * Copyright (C) 2023-2024 1BitSquared * Written by ALTracer * Modified by Rachel Mant * @@ -51,11 +51,12 @@ #define STM32MP15_DBGMCU_BASE 0x50081000U #define STM32MP15_UID_BASE 0x5c005234U -#define DBGMCU_IDCODE (STM32MP15_DBGMCU_BASE + 0x000U) -#define DBGMCU_CTRL (STM32MP15_DBGMCU_BASE + 0x004U) -#define DBGMCU_CTRL_DBGSLEEP (1U << 0U) -#define DBGMCU_CTRL_DBGSTOP (1U << 1U) -#define DBGMCU_CTRL_DBGSTBY (1U << 2U) +#define STM32MP15_DBGMCU_IDCODE (STM32MP15_DBGMCU_BASE + 0x000U) +#define STM32MP15_DBGMCU_CONFIG (STM32MP15_DBGMCU_BASE + 0x004U) + +#define STM32MP15_DBGMCU_CONFIG_DBGSLEEP (1U << 0U) +#define STM32MP15_DBGMCU_CONFIG_DBGSTOP (1U << 1U) +#define STM32MP15_DBGMCU_CONFIG_DBGSTBY (1U << 2U) #define STM32MP15_DBGMCU_IDCODE_DEV_MASK 0x00000fffU #define STM32MP15_DBGMCU_IDCODE_REV_SHIFT 16U @@ -67,7 +68,7 @@ #define ID_STM32MP15x_ERRATA 0x450U typedef struct stm32mp15_priv { - uint32_t dbgmcu_ctrl; + uint32_t dbgmcu_config; } stm32mp15_priv_s; static bool stm32mp15_uid(target_s *target, int argc, const char **argv); @@ -93,9 +94,9 @@ static bool stm32mp15_ident(target_s *const target, const bool cortexm) } /* By now it's established that this is likely an MP15x_CM4, but check that it's not an H74x */ - const uint32_t idcode = target_mem32_read32(target, DBGMCU_IDCODE); + const uint32_t idcode = target_mem32_read32(target, STM32MP15_DBGMCU_IDCODE); const uint16_t dev_id = idcode & STM32MP15_DBGMCU_IDCODE_DEV_MASK; - DEBUG_TARGET("%s: looking at device ID 0x%03x at 0x%08" PRIx32 "\n", __func__, dev_id, DBGMCU_IDCODE); + DEBUG_TARGET("%s: looking at device ID 0x%03x at 0x%08" PRIx32 "\n", __func__, dev_id, STM32MP15_DBGMCU_IDCODE); /* If this probe routine ever runs ahead of stm32h7_probe, skip the H74x. */ if (dev_id != ID_STM32MP15x) return false; @@ -165,10 +166,11 @@ static bool stm32mp15_attach(target_s *const target) /* Save DBGMCU_CR to restore it when detaching */ stm32mp15_priv_s *const priv = (stm32mp15_priv_s *)target->target_storage; - priv->dbgmcu_ctrl = target_mem32_read32(target, DBGMCU_CTRL); + priv->dbgmcu_config = target_mem32_read32(target, STM32MP15_DBGMCU_CONFIG); /* Disable C-Sleep, C-Stop, C-Standby for debugging */ - target_mem32_write32(target, DBGMCU_CTRL, DBGMCU_CTRL_DBGSLEEP | DBGMCU_CTRL_DBGSTOP | DBGMCU_CTRL_DBGSTBY); + target_mem32_write32(target, STM32MP15_DBGMCU_CONFIG, + STM32MP15_DBGMCU_CONFIG_DBGSLEEP | STM32MP15_DBGMCU_CONFIG_DBGSTOP | STM32MP15_DBGMCU_CONFIG_DBGSTBY); return true; } @@ -176,7 +178,7 @@ static bool stm32mp15_attach(target_s *const target) static void stm32mp15_detach(target_s *const target) { stm32mp15_priv_s *priv = (stm32mp15_priv_s *)target->target_storage; - target_mem32_write32(target, DBGMCU_CTRL, priv->dbgmcu_ctrl); + target_mem32_write32(target, STM32MP15_DBGMCU_CONFIG, priv->dbgmcu_config); cortexm_detach(target); } @@ -200,7 +202,7 @@ static bool stm32mp15_cmd_rev(target_s *const target, const int argc, const char (void)argc; (void)argv; /* DBGMCU identity code register */ - const uint32_t dbgmcu_idcode = target_mem32_read32(target, DBGMCU_IDCODE); + const uint32_t dbgmcu_idcode = target_mem32_read32(target, STM32MP15_DBGMCU_IDCODE); const uint16_t rev_id = dbgmcu_idcode >> STM32MP15_DBGMCU_IDCODE_REV_SHIFT; const uint16_t dev_id = dbgmcu_idcode & STM32MP15_DBGMCU_IDCODE_DEV_MASK; From 39d43535c43af0e95cfb58ce3eb827f48b8fa290 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 16 Jul 2024 07:27:31 +0100 Subject: [PATCH 28/47] stm32mp15: Renamed the Cortex-M4 attach and detach functions to disambiguate their purpose and use --- src/target/stm32mp15.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/target/stm32mp15.c b/src/target/stm32mp15.c index 6be2ee16484..2f14f531b14 100644 --- a/src/target/stm32mp15.c +++ b/src/target/stm32mp15.c @@ -80,8 +80,8 @@ const command_s stm32mp15_cmd_list[] = { {NULL, NULL, NULL}, }; -static bool stm32mp15_attach(target_s *target); -static void stm32mp15_detach(target_s *target); +static bool stm32mp15_cm4_attach(target_s *target); +static void stm32mp15_cm4_detach(target_s *target); static bool stm32mp15_ident(target_s *const target, const bool cortexm) { @@ -116,8 +116,8 @@ bool stm32mp15_cm4_probe(target_s *const target) return false; target->driver = "STM32MP15"; - target->attach = stm32mp15_attach; - target->detach = stm32mp15_detach; + target->attach = stm32mp15_cm4_attach; + target->detach = stm32mp15_cm4_detach; target_add_commands(target, stm32mp15_cmd_list, target->driver); /* Allocate private storage */ @@ -159,7 +159,7 @@ bool stm32mp15_ca7_probe(target_s *const target) } #endif -static bool stm32mp15_attach(target_s *const target) +static bool stm32mp15_cm4_attach(target_s *const target) { if (!cortexm_attach(target)) return false; @@ -175,7 +175,7 @@ static bool stm32mp15_attach(target_s *const target) return true; } -static void stm32mp15_detach(target_s *const target) +static void stm32mp15_cm4_detach(target_s *const target) { stm32mp15_priv_s *priv = (stm32mp15_priv_s *)target->target_storage; target_mem32_write32(target, STM32MP15_DBGMCU_CONFIG, priv->dbgmcu_config); From ad21cc5f22c90b4523dfb8975f283d78a99704cf Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 16 Jul 2024 08:00:55 +0100 Subject: [PATCH 29/47] stm32mp15: Refactored the DBGMCU handling and added support for properly freezing the watchdogs --- src/target/stm32mp15.c | 79 +++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/src/target/stm32mp15.c b/src/target/stm32mp15.c index 2f14f531b14..d395adcc65e 100644 --- a/src/target/stm32mp15.c +++ b/src/target/stm32mp15.c @@ -53,10 +53,17 @@ #define STM32MP15_DBGMCU_IDCODE (STM32MP15_DBGMCU_BASE + 0x000U) #define STM32MP15_DBGMCU_CONFIG (STM32MP15_DBGMCU_BASE + 0x004U) - -#define STM32MP15_DBGMCU_CONFIG_DBGSLEEP (1U << 0U) -#define STM32MP15_DBGMCU_CONFIG_DBGSTOP (1U << 1U) -#define STM32MP15_DBGMCU_CONFIG_DBGSTBY (1U << 2U) +#define STM32MP15_DBGMCU_APB1FREEZE1 (STM32MP15_DBGMCU_BASE + 0x034U) +#define STM32MP15_DBGMCU_APB1FREEZE2 (STM32MP15_DBGMCU_BASE + 0x038U) + +#define STM32MP15_DBGMCU_CONFIG_DBGSLEEP (1U << 0U) +#define STM32MP15_DBGMCU_CONFIG_DBGSTOP (1U << 1U) +#define STM32MP15_DBGMCU_CONFIG_DBGSTBY (1U << 2U) +#define STM32MP15_DBGMCU_CONFIG_IWDG1_FREEZE_AND (1U << 24U) +// Freeze for WWDG1 when debugging the Cortex-A7 core +#define STM32MP15_DBGMCU_APB1FREEZE1_WWDG1 (1U << 10U) +// Freeze for WWDG1 when debugging the Cortex-M4 core +#define STM32MP15_DBGMCU_APB1FREEZE2_WWDG1 (1U << 10U) #define STM32MP15_DBGMCU_IDCODE_DEV_MASK 0x00000fffU #define STM32MP15_DBGMCU_IDCODE_REV_SHIFT 16U @@ -110,28 +117,51 @@ static bool stm32mp15_ident(target_s *const target, const bool cortexm) return true; } +static bool stm32mp15_cm4_configure_dbgmcu(target_s *const target) +{ + /* If we're in the probe phase */ + if (target->target_storage == NULL) { + /* Allocate target-specific storage */ + stm32mp15_priv_s *const priv_storage = calloc(1, sizeof(*priv_storage)); + if (!priv_storage) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + target->target_storage = priv_storage; + /* Get the current value of the debug control register (and store it for later) */ + priv_storage->dbgmcu_config = target_mem32_read32(target, STM32MP15_DBGMCU_CONFIG); + + /* Finally set up the attach/detach functions needed */ + target->attach = stm32mp15_cm4_attach; + target->detach = stm32mp15_cm4_detach; + } + + const stm32mp15_priv_s *const priv = (stm32mp15_priv_s *)target->target_storage; + /* Disable C-Sleep, C-Stop, C-Standby for debugging, and make sure IWDG1 freezes when any core is halted */ + target_mem32_write32(target, STM32MP15_DBGMCU_CONFIG, + (priv->dbgmcu_config & ~STM32MP15_DBGMCU_CONFIG_IWDG1_FREEZE_AND) | STM32MP15_DBGMCU_CONFIG_DBGSLEEP | + STM32MP15_DBGMCU_CONFIG_DBGSTOP | STM32MP15_DBGMCU_CONFIG_DBGSTBY); + /* And make sure the WDTs stay synchronised to the run state of the processor */ + target_mem32_write32(target, STM32MP15_DBGMCU_APB1FREEZE2, STM32MP15_DBGMCU_APB1FREEZE2_WWDG1); + return true; +} + bool stm32mp15_cm4_probe(target_s *const target) { + /* Try to identify the part */ if (!stm32mp15_ident(target, true)) return false; + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + if (!stm32mp15_cm4_configure_dbgmcu(target)) + return false; + target->driver = "STM32MP15"; - target->attach = stm32mp15_cm4_attach; - target->detach = stm32mp15_cm4_detach; target_add_commands(target, stm32mp15_cmd_list, target->driver); - /* Allocate private storage */ - stm32mp15_priv_s *priv = calloc(1, sizeof(*priv)); - if (!priv) { /* calloc failed: heap exhaustion */ - DEBUG_ERROR("calloc: failed in %s\n", __func__); - return false; - } - target->target_storage = priv; - /* Figure 4. Memory map from §2.5.2 in RM0436 rev 6, pg158 */ target_add_ram32(target, STM32MP15_CM4_RETRAM_BASE, STM32MP15_RETRAM_SIZE); target_add_ram32(target, STM32MP15_AHBSRAM_BASE, STM32MP15_AHBSRAM_SIZE); - return true; } @@ -161,24 +191,19 @@ bool stm32mp15_ca7_probe(target_s *const target) static bool stm32mp15_cm4_attach(target_s *const target) { - if (!cortexm_attach(target)) - return false; - - /* Save DBGMCU_CR to restore it when detaching */ - stm32mp15_priv_s *const priv = (stm32mp15_priv_s *)target->target_storage; - priv->dbgmcu_config = target_mem32_read32(target, STM32MP15_DBGMCU_CONFIG); - - /* Disable C-Sleep, C-Stop, C-Standby for debugging */ - target_mem32_write32(target, STM32MP15_DBGMCU_CONFIG, - STM32MP15_DBGMCU_CONFIG_DBGSLEEP | STM32MP15_DBGMCU_CONFIG_DBGSTOP | STM32MP15_DBGMCU_CONFIG_DBGSTBY); - - return true; + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + return cortexm_attach(target) && stm32mp15_cm4_configure_dbgmcu(target); } static void stm32mp15_cm4_detach(target_s *const target) { stm32mp15_priv_s *priv = (stm32mp15_priv_s *)target->target_storage; + /* Reverse all changes to the DBGMCU config register */ target_mem32_write32(target, STM32MP15_DBGMCU_CONFIG, priv->dbgmcu_config); + /* Now defer to the normal Cortex-M detach routine to complete the detach */ cortexm_detach(target); } From 603b00a658320047f19c5cc156e36994c6d8e10e Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Jul 2024 04:36:10 +0100 Subject: [PATCH 30/47] stm32l4: Fixed up the consistency of the references the manuals --- src/target/stm32l4.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index 0f5cfc469a0..6d5d67a3d3c 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -27,23 +27,23 @@ * On L4, flash and options are written in DWORDs (8-Byte) only. * * References: - * RM0351 STM32L4x5 and STM32L4x6 advanced ARM®-based 32-bit MCUs Rev 9 + * RM0351 - STM32L4x5 and STM32L4x6 advanced ARM®-based 32-bit MCUs Rev 9 * - https://www.st.com/resource/en/reference_manual/rm0351-stm32l47xxx-stm32l48xxx-stm32l49xxx-and-stm32l4axxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - * RM0394 STM32L43xxx STM32L44xxx STM32L45xxx STM32L46xxxx advanced ARM®-based 32-bit MCUs Rev.4 + * RM0394 - STM32L43xxx STM32L44xxx STM32L45xxx STM32L46xxxx advanced ARM®-based 32-bit MCUs Rev.4 * - https://www.st.com/resource/en/reference_manual/dm00151940-stm32l41xxx42xxx43xxx44xxx45xxx46xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - * RM0432 STM32L4Rxxx and STM32L4Sxxx advanced Arm®-based 32-bit MCU. Rev 9 + * RM0432 - STM32L4Rxxx and STM32L4Sxxx advanced Arm®-based 32-bit MCU. Rev 9 * - https://www.st.com/resource/en/reference_manual/rm0432-stm32l4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - * RM0440 STM32G4 Series advanced Arm®-based 32-bit MCU. Rev 7 + * RM0440 - STM32G4 Series advanced Arm®-based 32-bit MCU. Rev 7 * - https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - * RM0438 STM32L552xx and STM32L562xx advanced Arm®-based 32-bit MCUs Rev 7 + * RM0438 - STM32L552xx and STM32L562xx advanced Arm®-based 32-bit MCUs Rev 7 * - https://www.st.com/resource/en/reference_manual/dm00346336-stm32l552xx-and-stm32l562xx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf - * RM0456 STM32U5 Series Arm®-based 32-bit MCUs - Reference manual Rev 4 + * RM0456 - STM32U5 Series Arm®-based 32-bit MCUs - Reference manual Rev 4 * - https://www.st.com/resource/en/reference_manual/rm0456-stm32u5-series-armbased-32bit-mcus-stmicroelectronics.pdf - * RM0453 STM32WL5x advanced Arm®-based 32-bit MCUs with sub-GHz radio solution Rev 3 + * RM0453 - STM32WL5x advanced Arm®-based 32-bit MCUs with sub-GHz radio solution Rev 3 * - https://www.st.com/resource/en/reference_manual/rm0453-stm32wl5x-advanced-armbased-32bit-mcus-with-subghz-radio-solution-stmicroelectronics.pdf - * RM0461 STM32WLEx advanced Arm®-based 32-bit MCUs with sub-GHz radio solution Rev 5 + * RM0461 - STM32WLEx advanced Arm®-based 32-bit MCUs with sub-GHz radio solution Rev 5 * - https://www.st.com/resource/en/reference_manual/rm0461-stm32wlex-advanced-armbased-32bit-mcus-with-subghz-radio-solution-stmicroelectronics.pdf - * RM0434 Multiprotocol wireless 32-bit MCU Arm®-based Cortex®-M4 with + * RM0434 - Multiprotocol wireless 32-bit MCU Arm®-based Cortex®-M4 with * FPU, Bluetooth® Low-Energy and 802.15.4 radio solution Rev 10 * - https://www.st.com/resource/en/reference_manual/rm0434-multiprotocol-wireless-32bit-mcu-armbased-cortexm4-with-fpu-bluetooth-lowenergy-and-802154-radio-solution-stmicroelectronics.pdf */ From 2bb55af35dd2f1c131ae7e9b14271b5f9cbdd760 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Jul 2024 04:45:07 +0100 Subject: [PATCH 31/47] stm32l0: Updated the attribution notice and reworked the top of file documentation block to bring it into line with the rest of the code base --- src/target/stm32l0.c | 54 +++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index b1ca5db5d5c..b681c64faf3 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -2,6 +2,9 @@ * This file is part of the Black Magic Debug project. * * Copyright (C) 2014,2015 Marc Singer + * Copyright (C) 2022-2024 1BitSquared + * Written by Marc Singer + * Modified by Rachel Mant * * 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 @@ -18,39 +21,24 @@ */ /* - Description - ----------- - - This is an implementation of the target-specific functions for the - STM32L0x[1] and STM32L1x[2] families of ST Microelectronics MCUs, - Cortex M0+ SOCs. The NVM interface is substantially similar to the - STM32L1x parts. This module is written to better generalize the - NVM interface and to provide more features. - - [1] ST Microelectronics Document RM0377 (DocID025942), "Reference - manual for Ultra-low-power STM32L0x1 advanced ARM-based 32-bit - MCUs," April 2014. - (https://www.st.com/resource/en/reference_manual/rm0377-ultralowpower-stm32l0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) - - [2] ST Microelectronics Document RM0038 (DocID15965, "..."Reference - manual for STM32L100xx, STM32L151xx, STM32L152xx and STM32L162xx - advanced ARM®-based 32-bit MCUs, " July 2014 - (https://www.st.com/resource/en/reference_manual/rm0038-stm32l100xx-stm32l151xx-stm32l152xx-and-stm32l162xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) - - NOTES - ===== - - o Errors. We probably should clear SR errors immediately after - detecting them. If we don't then we always must wait for the NVM - module to complete the last operation before we can start another. - - o There are minor inconsistencies between the stm32l0 and the - stm32l1 in when handling NVM operations. - - o On the STM32L1xx, PECR can only be changed when the NVM - hardware is idle. The STM32L0xx allows the PECR to be updated - while an operation is in progress. -*/ + * This file implements STM32L0 and STM32L1 target specific functions for detecting + * the device, providing the XML memory map and Flash memory programming. + * + * References: + * RM0377 - Ultra-low-power STM32L0x1 advanced Arm®-based 32-bit MCUs, Rev. 10 + * - https://www.st.com/resource/en/reference_manual/rm0377-ultralowpower-stm32l0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * RM0038 - STM32L100xx, STM32L151xx, STM32L152xx and STM32L162xx advanced Arm®-based 32-bit MCUs, Rev. 17 + * - https://www.st.com/resource/en/reference_manual/rm0038-stm32l100xx-stm32l151xx-stm32l152xx-and-stm32l162xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + * + * Note: + * This implementation has a few known defficiencies and quirks, these are: + * - Error handling -> We should probably clear Flash controller statusu register errors + * immediately after detecting them. If we don't then we must always wait for the controller + * to complete the previous operatioon before starting the next. + * - Minor inconsistencies between the STM32L0 and STM32L1 Flash controllers that should be handled + * - On the STM32L1, the Flash controller PECR can only be changed when the controller is + * idle, while on the STM32L0 it may be updated while an operation is in progress + */ #include "general.h" #include "target.h" From 7010e9d3370f9bcc993487a1125bf1b2bff27282 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Jul 2024 09:16:37 +0100 Subject: [PATCH 32/47] stm32l0: Nomenclature harmonisation with the other STM32 target support implementations --- src/target/stm32l0.c | 396 +++++++++++++++++++++---------------------- 1 file changed, 198 insertions(+), 198 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index b681c64faf3..128ab0b45b3 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -46,92 +46,91 @@ #include "cortexm.h" #include "stm32_common.h" -#define STM32Lx_NVM_PECR(p) ((p) + 0x04U) -#define STM32Lx_NVM_PEKEYR(p) ((p) + 0x0cU) -#define STM32Lx_NVM_PRGKEYR(p) ((p) + 0x10U) -#define STM32Lx_NVM_OPTKEYR(p) ((p) + 0x14U) -#define STM32Lx_NVM_SR(p) ((p) + 0x18U) -#define STM32Lx_NVM_OPTR(p) ((p) + 0x1cU) - -#define STM32L0_NVM_PHYS UINT32_C(0x40022000) -#define STM32L0_NVM_OPT_SIZE 12U -#define STM32L0_NVM_EEPROM_CAT1_SIZE (1U * 512U) -#define STM32L0_NVM_EEPROM_CAT2_SIZE (1U * 1024U) -#define STM32L0_NVM_EEPROM_CAT3_SIZE (2U * 1024U) -#define STM32L0_NVM_EEPROM_CAT5_SIZE (6U * 1024U) - -#define STM32L1_NVM_PHYS UINT32_C(0x40023c00) -#define STM32L1_NVM_OPT_SIZE 32U -#define STM32L1_NVM_EEPROM_SIZE (16U * 1024U) - -#define STM32Lx_NVM_OPT_PHYS UINT32_C(0x1ff80000) -#define STM32Lx_NVM_EEPROM_PHYS UINT32_C(0x08080000) - -#define STM32Lx_NVM_PEKEY1 UINT32_C(0x89abcdef) -#define STM32Lx_NVM_PEKEY2 UINT32_C(0x02030405) -#define STM32Lx_NVM_PRGKEY1 UINT32_C(0x8c9daebf) -#define STM32Lx_NVM_PRGKEY2 UINT32_C(0x13141516) -#define STM32Lx_NVM_OPTKEY1 UINT32_C(0xfbead9c8) -#define STM32Lx_NVM_OPTKEY2 UINT32_C(0x24252627) - -#define STM32Lx_NVM_PECR_OBL_LAUNCH (1U << 18U) -#define STM32Lx_NVM_PECR_ERRIE (1U << 17U) -#define STM32Lx_NVM_PECR_EOPIE (1U << 16U) -#define STM32Lx_NVM_PECR_FPRG (1U << 10U) -#define STM32Lx_NVM_PECR_ERASE (1U << 9U) -#define STM32Lx_NVM_PECR_FIX (1U << 8U) /* FTDW */ -#define STM32Lx_NVM_PECR_DATA (1U << 4U) -#define STM32Lx_NVM_PECR_PROG (1U << 3U) -#define STM32Lx_NVM_PECR_OPTLOCK (1U << 2U) -#define STM32Lx_NVM_PECR_PRGLOCK (1U << 1U) -#define STM32Lx_NVM_PECR_PELOCK (1U << 0U) - -#define STM32Lx_NVM_SR_NOTZEROERR (1U << 16U) -#define STM32Lx_NVM_SR_SIZERR (1U << 10U) -#define STM32Lx_NVM_SR_PGAERR (1U << 9U) -#define STM32Lx_NVM_SR_WRPERR (1U << 8U) -#define STM32Lx_NVM_SR_EOP (1U << 1U) -#define STM32Lx_NVM_SR_BSY (1U << 0U) -#define STM32Lx_NVM_SR_ERR_M \ - (STM32Lx_NVM_SR_WRPERR | STM32Lx_NVM_SR_PGAERR | STM32Lx_NVM_SR_SIZERR | STM32Lx_NVM_SR_NOTZEROERR) - -#define STM32L0_NVM_OPTR_BOOT1 (1U << 31U) -#define STM32Lx_NVM_OPTR_WDG_SW (1U << 20U) -#define STM32L0_NVM_OPTR_WPRMOD (1U << 8U) -#define STM32Lx_NVM_OPTR_RDPROT_S 0U -#define STM32Lx_NVM_OPTR_RDPROT_M 0xffU -#define STM32Lx_NVM_OPTR_RDPROT_0 0xaaU -#define STM32Lx_NVM_OPTR_RDPROT_2 0xccU - -#define STM32L1_NVM_OPTR_nBFB2 (1U << 23U) -#define STM32L1_NVM_OPTR_nRST_STDBY (1U << 22U) -#define STM32L1_NVM_OPTR_nRST_STOP (1U << 21U) -#define STM32L1_NVM_OPTR_BOR_LEV_S 16U -#define STM32L1_NVM_OPTR_BOR_LEV_M 0xfU -#define STM32L1_NVM_OPTR_SPRMOD (1U << 8U) - -#define STM32L0_DBGMCU_IDCODE_PHYS UINT32_C(0x40015800) -#define STM32L1_DBGMCU_IDCODE_PHYS UINT32_C(0xe0042000) - -static bool stm32lx_nvm_prog_erase(target_flash_s *flash, target_addr_t addr, size_t length); -static bool stm32lx_nvm_prog_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); - -static bool stm32lx_nvm_data_erase(target_flash_s *flash, target_addr_t addr, size_t length); -static bool stm32lx_nvm_data_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); - -static bool stm32lx_protected_attach(target_s *target); -static bool stm32lx_protected_mass_erase(target_s *target); -static bool stm32lx_mass_erase(target_s *target); +#define STM32Lx_FLASH_PECR(flash_base) ((flash_base) + 0x04U) +#define STM32Lx_FLASH_PEKEYR(flash_base) ((flash_base) + 0x0cU) +#define STM32Lx_FLASH_PRGKEYR(flash_base) ((flash_base) + 0x10U) +#define STM32Lx_FLASH_OPTKEYR(flash_base) ((flash_base) + 0x14U) +#define STM32Lx_FLASH_SR(flash_base) ((flash_base) + 0x18U) +#define STM32Lx_FLASH_OPTR(flash_base) ((flash_base) + 0x1cU) + +#define STM32L0_FLASH_BASE UINT32_C(0x40022000) +#define STM32L0_FLASH_OPT_SIZE 12U +#define STM32L0_FLASH_EEPROM_CAT1_SIZE 512U // 512B +#define STM32L0_FLASH_EEPROM_CAT2_SIZE 1024U // 1KiB +#define STM32L0_FLASH_EEPROM_CAT3_SIZE 2048U // 2KiB +#define STM32L0_FLASH_EEPROM_CAT5_SIZE 6144U // 6KiB + +#define STM32L1_FLASH_BASE UINT32_C(0x40023c00) +#define STM32L1_FLASH_OPT_SIZE 32U +#define STM32L1_FLASH_EEPROM_SIZE 16384U // 16KiB + +#define STM32Lx_FLASH_OPT_BASE UINT32_C(0x1ff80000) +#define STM32Lx_FLASH_EEPROM_BASE UINT32_C(0x08080000) + +#define STM32Lx_FLASH_PEKEY1 UINT32_C(0x89abcdef) +#define STM32Lx_FLASH_PEKEY2 UINT32_C(0x02030405) +#define STM32Lx_FLASH_PRGKEY1 UINT32_C(0x8c9daebf) +#define STM32Lx_FLASH_PRGKEY2 UINT32_C(0x13141516) +#define STM32Lx_FLASH_OPTKEY1 UINT32_C(0xfbead9c8) +#define STM32Lx_FLASH_OPTKEY2 UINT32_C(0x24252627) + +#define STM32Lx_FLASH_PECR_OBL_LAUNCH (1U << 18U) +#define STM32Lx_FLASH_PECR_ERRIE (1U << 17U) +#define STM32Lx_FLASH_PECR_EOPIE (1U << 16U) +#define STM32Lx_FLASH_PECR_FPRG (1U << 10U) +#define STM32Lx_FLASH_PECR_ERASE (1U << 9U) +#define STM32Lx_FLASH_PECR_FIX (1U << 8U) /* FTDW */ +#define STM32Lx_FLASH_PECR_DATA (1U << 4U) +#define STM32Lx_FLASH_PECR_PROG (1U << 3U) +#define STM32Lx_FLASH_PECR_OPTLOCK (1U << 2U) +#define STM32Lx_FLASH_PECR_PRGLOCK (1U << 1U) +#define STM32Lx_FLASH_PECR_PELOCK (1U << 0U) + +#define STM32Lx_FLASH_SR_NOTZEROERR (1U << 16U) +#define STM32Lx_FLASH_SR_SIZERR (1U << 10U) +#define STM32Lx_FLASH_SR_PGAERR (1U << 9U) +#define STM32Lx_FLASH_SR_WRPERR (1U << 8U) +#define STM32Lx_FLASH_SR_EOP (1U << 1U) +#define STM32Lx_FLASH_SR_BSY (1U << 0U) +#define STM32Lx_FLASH_SR_ERR_MASK \ + (STM32Lx_FLASH_SR_WRPERR | STM32Lx_FLASH_SR_PGAERR | STM32Lx_FLASH_SR_SIZERR | STM32Lx_FLASH_SR_NOTZEROERR) + +#define STM32L0_FLASH_OPTR_BOOT1 (1U << 31U) +#define STM32Lx_FLASH_OPTR_WDG_SW (1U << 20U) +#define STM32L0_FLASH_OPTR_WPRMOD (1U << 8U) +#define STM32Lx_FLASH_OPTR_RDPROT_SHIFT 0U +#define STM32Lx_FLASH_OPTR_RDPROT_MASK 0xffU +#define STM32Lx_FLASH_OPTR_RDPROT_0 0xaaU +#define STM32Lx_FLASH_OPTR_RDPROT_2 0xccU + +#define STM32L1_FLASH_OPTR_nBFB2 (1U << 23U) +#define STM32L1_FLASH_OPTR_nRST_STDBY (1U << 22U) +#define STM32L1_FLASH_OPTR_nRST_STOP (1U << 21U) +#define STM32L1_FLASH_OPTR_BOR_LEV_SHIFT 16U +#define STM32L1_FLASH_OPTR_BOR_LEV_MASK 0xfU +#define STM32L1_FLASH_OPTR_SPRMOD (1U << 8U) + +#define STM32L0_DBGMCU_BASE UINT32_C(0x40015800) +#define STM32L1_DBGMCU_BASE UINT32_C(0xe0042000) static bool stm32lx_cmd_option(target_s *target, int argc, const char **argv); static bool stm32lx_cmd_eeprom(target_s *target, int argc, const char **argv); static const command_s stm32lx_cmd_list[] = { {"option", stm32lx_cmd_option, "Manipulate option bytes"}, - {"eeprom", stm32lx_cmd_eeprom, "Manipulate EEPROM (NVM data) memory"}, + {"eeprom", stm32lx_cmd_eeprom, "Manipulate EEPROM (FLASH data) memory"}, {NULL, NULL, NULL}, }; +static bool stm32lx_flash_erase(target_flash_s *flash, target_addr_t addr, size_t length); +static bool stm32lx_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); +static bool stm32lx_eeprom_erase(target_flash_s *flash, target_addr_t addr, size_t length); +static bool stm32lx_eeprom_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); +static bool stm32lx_mass_erase(target_s *target); + +static bool stm32lx_protected_attach(target_s *target); +static bool stm32lx_protected_mass_erase(target_s *target); + typedef struct stm32l_priv_s { char stm32l_variant[21]; } stm32l_priv_t; @@ -146,30 +145,30 @@ static uint32_t stm32lx_nvm_eeprom_size(const target_s *const target) { switch (target->part_id) { case 0x457U: /* STM32L0xx Cat1 */ - return STM32L0_NVM_EEPROM_CAT1_SIZE; + return STM32L0_FLASH_EEPROM_CAT1_SIZE; case 0x425U: /* STM32L0xx Cat2 */ - return STM32L0_NVM_EEPROM_CAT2_SIZE; + return STM32L0_FLASH_EEPROM_CAT2_SIZE; case 0x417U: /* STM32L0xx Cat3 */ - return STM32L0_NVM_EEPROM_CAT3_SIZE; + return STM32L0_FLASH_EEPROM_CAT3_SIZE; case 0x447U: /* STM32L0xx Cat5 */ - return STM32L0_NVM_EEPROM_CAT5_SIZE; + return STM32L0_FLASH_EEPROM_CAT5_SIZE; default: /* STM32L1xx */ - return STM32L1_NVM_EEPROM_SIZE; + return STM32L1_FLASH_EEPROM_SIZE; } } -static uint32_t stm32lx_nvm_phys(const target_s *const target) +static target_addr32_t stm32lx_flash_base(const target_s *const target) { if (stm32lx_is_stm32l1(target)) - return STM32L1_NVM_PHYS; - return STM32L0_NVM_PHYS; + return STM32L1_FLASH_BASE; + return STM32L0_FLASH_BASE; } static uint32_t stm32lx_nvm_option_size(const target_s *const target) { if (stm32lx_is_stm32l1(target)) - return STM32L1_NVM_OPT_SIZE; - return STM32L0_NVM_OPT_SIZE; + return STM32L1_FLASH_OPT_SIZE; + return STM32L0_FLASH_OPT_SIZE; } static void stm32l_add_flash(target_s *const target, const uint32_t addr, const size_t length, const size_t erasesize) @@ -183,8 +182,8 @@ static void stm32l_add_flash(target_s *const target, const uint32_t addr, const flash->start = addr; flash->length = length; flash->blocksize = erasesize; - flash->erase = stm32lx_nvm_prog_erase; - flash->write = stm32lx_nvm_prog_write; + flash->erase = stm32lx_flash_erase; + flash->write = stm32lx_flash_write; flash->writesize = erasesize >> 1U; target_add_flash(target, flash); } @@ -200,8 +199,8 @@ static void stm32l_add_eeprom(target_s *const target, const uint32_t addr, const flash->start = addr; flash->length = length; flash->blocksize = 4; - flash->erase = stm32lx_nvm_data_erase; - flash->write = stm32lx_nvm_data_write; + flash->erase = stm32lx_eeprom_erase; + flash->write = stm32lx_eeprom_write; target_add_flash(target, flash); } @@ -243,9 +242,9 @@ bool stm32l0_probe(target_s *const target) } target->target_storage = (void *)priv_storage; - const uint32_t nvm = stm32lx_nvm_phys(target); - const bool protected = - (target_mem32_read32(target, STM32Lx_NVM_OPTR(nvm)) & STM32Lx_NVM_OPTR_RDPROT_M) != STM32Lx_NVM_OPTR_RDPROT_0; + const target_addr32_t flash_base = stm32lx_flash_base(target); + const bool protected = (target_mem32_read32(target, STM32Lx_FLASH_OPTR(flash_base)) & + STM32Lx_FLASH_OPTR_RDPROT_MASK) != STM32Lx_FLASH_OPTR_RDPROT_0; snprintf(priv_storage->stm32l_variant, sizeof(priv_storage->stm32l_variant), "%s%s", target->driver, protected ? " (protected)" : ""); target->driver = priv_storage->stm32l_variant; @@ -259,83 +258,84 @@ bool stm32l0_probe(target_s *const target) return true; } -/* Lock the NVM control registers preventing writes or erases. */ -static void stm32lx_nvm_lock(target_s *const target, const uint32_t nvm) +/* Lock the FLASH control registers preventing writes or erases. */ +static void stm32lx_nvm_lock(target_s *const target, const target_addr32_t flash_base) { - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_PELOCK); } /* - * Unlock the NVM control registers for modifying program or data flash. + * Unlock the FLASH control registers for modifying program or data flash. * Returns true if the unlock succeeds. */ -static bool stm32lx_nvm_prog_data_unlock(target_s *const target, const uint32_t nvm) +static bool stm32lx_nvm_prog_data_unlock(target_s *const target, const target_addr32_t flash_base) { /* Always lock first because that's the only way to know that the unlock can succeed on the STM32L0's. */ - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK); - target_mem32_write32(target, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY1); - target_mem32_write32(target, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY2); - target_mem32_write32(target, STM32Lx_NVM_PRGKEYR(nvm), STM32Lx_NVM_PRGKEY1); - target_mem32_write32(target, STM32Lx_NVM_PRGKEYR(nvm), STM32Lx_NVM_PRGKEY2); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_PELOCK); + target_mem32_write32(target, STM32Lx_FLASH_PEKEYR(flash_base), STM32Lx_FLASH_PEKEY1); + target_mem32_write32(target, STM32Lx_FLASH_PEKEYR(flash_base), STM32Lx_FLASH_PEKEY2); + target_mem32_write32(target, STM32Lx_FLASH_PRGKEYR(flash_base), STM32Lx_FLASH_PRGKEY1); + target_mem32_write32(target, STM32Lx_FLASH_PRGKEYR(flash_base), STM32Lx_FLASH_PRGKEY2); - return !(target_mem32_read32(target, STM32Lx_NVM_PECR(nvm)) & STM32Lx_NVM_PECR_PRGLOCK); + return !(target_mem32_read32(target, STM32Lx_FLASH_PECR(flash_base)) & STM32Lx_FLASH_PECR_PRGLOCK); } /* - * Unlock the NVM control registers for modifying option bytes. + * Unlock the FLASH control registers for modifying option bytes. * Returns true if the unlock succeeds. */ -static bool stm32lx_nvm_opt_unlock(target_s *const target, const uint32_t nvm) +static bool stm32lx_nvm_opt_unlock(target_s *const target, const target_addr32_t flash_base) { /* Always lock first because that's the only way to know that the unlock can succeed on the STM32L0's. */ - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK); - target_mem32_write32(target, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY1); - target_mem32_write32(target, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY2); - target_mem32_write32(target, STM32Lx_NVM_OPTKEYR(nvm), STM32Lx_NVM_OPTKEY1); - target_mem32_write32(target, STM32Lx_NVM_OPTKEYR(nvm), STM32Lx_NVM_OPTKEY2); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_PELOCK); + target_mem32_write32(target, STM32Lx_FLASH_PEKEYR(flash_base), STM32Lx_FLASH_PEKEY1); + target_mem32_write32(target, STM32Lx_FLASH_PEKEYR(flash_base), STM32Lx_FLASH_PEKEY2); + target_mem32_write32(target, STM32Lx_FLASH_OPTKEYR(flash_base), STM32Lx_FLASH_OPTKEY1); + target_mem32_write32(target, STM32Lx_FLASH_OPTKEYR(flash_base), STM32Lx_FLASH_OPTKEY2); - return !(target_mem32_read32(target, STM32Lx_NVM_PECR(nvm)) & STM32Lx_NVM_PECR_OPTLOCK); + return !(target_mem32_read32(target, STM32Lx_FLASH_PECR(flash_base)) & STM32Lx_FLASH_PECR_OPTLOCK); } -static bool stm32lx_nvm_busy_wait(target_s *const target, const uint32_t nvm, platform_timeout_s *const timeout) +static bool stm32lx_nvm_busy_wait( + target_s *const target, const target_addr32_t flash_base, platform_timeout_s *const timeout) { - while (target_mem32_read32(target, STM32Lx_NVM_SR(nvm)) & STM32Lx_NVM_SR_BSY) { + while (target_mem32_read32(target, STM32Lx_FLASH_SR(flash_base)) & STM32Lx_FLASH_SR_BSY) { if (target_check_error(target)) return false; if (timeout) target_print_progress(timeout); } - const uint32_t status = target_mem32_read32(target, STM32Lx_NVM_SR(nvm)); - return !target_check_error(target) && !(status & STM32Lx_NVM_SR_ERR_M); + const uint32_t status = target_mem32_read32(target, STM32Lx_FLASH_SR(flash_base)); + return !target_check_error(target) && !(status & STM32Lx_FLASH_SR_ERR_MASK); } /* * Erase a region of program flash using operations through the debug interface. * This is slower than stubbed versions (see NOTES). * The flash array is erased for all pages from addr to addr + length inclusive. - * The NVM register base is automatically determined based on the target. + * The FLASH register base is automatically determined based on the target. */ -static bool stm32lx_nvm_prog_erase(target_flash_s *const flash, const target_addr_t addr, const size_t length) +static bool stm32lx_flash_erase(target_flash_s *const flash, const target_addr_t addr, const size_t length) { target_s *const target = flash->t; - const uint32_t nvm = stm32lx_nvm_phys(target); + const target_addr32_t flash_base = stm32lx_flash_base(target); const bool full_erase = addr == flash->start && length == flash->length; - if (!stm32lx_nvm_prog_data_unlock(target, nvm)) + if (!stm32lx_nvm_prog_data_unlock(target, flash_base)) return false; /* Flash page erase instruction */ - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_PROG); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_ERASE | STM32Lx_FLASH_PECR_PROG); - const uint32_t pecr = - target_mem32_read32(target, STM32Lx_NVM_PECR(nvm)) & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE); - if (pecr != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) + const uint32_t pecr = target_mem32_read32(target, STM32Lx_FLASH_PECR(flash_base)) & + (STM32Lx_FLASH_PECR_PROG | STM32Lx_FLASH_PECR_ERASE); + if (pecr != (STM32Lx_FLASH_PECR_PROG | STM32Lx_FLASH_PECR_ERASE)) return false; /* * Clear errors. - * Note that this only works when we wait for the NVM block to complete the last operation. + * Note that this only works when we wait for the FLASH block to complete the last operation. */ - target_mem32_write32(target, STM32Lx_NVM_SR(nvm), STM32Lx_NVM_SR_ERR_M); + target_mem32_write32(target, STM32Lx_FLASH_SR(flash_base), STM32Lx_FLASH_SR_ERR_MASK); platform_timeout_s timeout; platform_timeout_set(&timeout, 500); @@ -347,53 +347,53 @@ static bool stm32lx_nvm_prog_erase(target_flash_s *const flash, const target_add } /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(target, nvm); + stm32lx_nvm_lock(target, flash_base); /* Wait for completion or an error */ - return stm32lx_nvm_busy_wait(target, nvm, full_erase ? &timeout : NULL); + return stm32lx_nvm_busy_wait(target, flash_base, full_erase ? &timeout : NULL); } /* Write to program flash using operations through the debug interface. */ -static bool stm32lx_nvm_prog_write( +static bool stm32lx_flash_write( target_flash_s *const flash, const target_addr_t dest, const void *const src, const size_t length) { target_s *const target = flash->t; - const uint32_t nvm = stm32lx_nvm_phys(target); + const target_addr32_t flash_base = stm32lx_flash_base(target); - if (!stm32lx_nvm_prog_data_unlock(target, nvm)) + if (!stm32lx_nvm_prog_data_unlock(target, flash_base)) return false; /* Wait for BSY to clear because we cannot write the PECR until the previous operation completes */ - if (!stm32lx_nvm_busy_wait(target, nvm, NULL)) + if (!stm32lx_nvm_busy_wait(target, flash_base, NULL)) return false; - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_PROG | STM32Lx_FLASH_PECR_FPRG); target_mem32_write(target, dest, src, length); /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(target, nvm); + stm32lx_nvm_lock(target, flash_base); /* Wait for completion or an error */ - return stm32lx_nvm_busy_wait(target, nvm, NULL); + return stm32lx_nvm_busy_wait(target, flash_base, NULL); } /* * Erase a region of data flash using operations through the debug interface. * The flash is erased for all pages from addr to addr + length, inclusive, on a word boundary. - * The NVM register base is automatically determined based on the target. + * The FLASH register base is automatically determined based on the target. */ -static bool stm32lx_nvm_data_erase(target_flash_s *const flash, const target_addr_t addr, const size_t length) +static bool stm32lx_eeprom_erase(target_flash_s *const flash, const target_addr_t addr, const size_t length) { target_s *const target = flash->t; - const uint32_t nvm = stm32lx_nvm_phys(target); - if (!stm32lx_nvm_prog_data_unlock(target, nvm)) + const target_addr32_t flash_base = stm32lx_flash_base(target); + if (!stm32lx_nvm_prog_data_unlock(target, flash_base)) return false; /* Flash data erase instruction */ - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_ERASE | STM32Lx_FLASH_PECR_DATA); - const uint32_t pecr = - target_mem32_read32(target, STM32Lx_NVM_PECR(nvm)) & (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA); - if (pecr != (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA)) + const uint32_t pecr = target_mem32_read32(target, STM32Lx_FLASH_PECR(flash_base)) & + (STM32Lx_FLASH_PECR_ERASE | STM32Lx_FLASH_PECR_DATA); + if (pecr != (STM32Lx_FLASH_PECR_ERASE | STM32Lx_FLASH_PECR_DATA)) return false; const uint32_t aligned_addr = addr & ~3U; @@ -402,28 +402,28 @@ static bool stm32lx_nvm_data_erase(target_flash_s *const flash, const target_add target_mem32_write32(target, aligned_addr + offset, 0U); /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(target, nvm); + stm32lx_nvm_lock(target, flash_base); /* Wait for completion or an error */ - return stm32lx_nvm_busy_wait(target, nvm, NULL); + return stm32lx_nvm_busy_wait(target, flash_base, NULL); } /* * Write to data flash using operations through the debug interface. - * The NVM register base is automatically determined based on the target. + * The FLASH register base is automatically determined based on the target. * Unaligned destination writes are supported (though unaligned sources are not). */ -static bool stm32lx_nvm_data_write( +static bool stm32lx_eeprom_write( target_flash_s *const flash, const target_addr_t dest, const void *const src, const size_t length) { target_s *const target = flash->t; - const uint32_t nvm = stm32lx_nvm_phys(target); + const target_addr32_t flash_base = stm32lx_flash_base(target); const bool is_stm32l1 = stm32lx_is_stm32l1(target); - if (!stm32lx_nvm_prog_data_unlock(target, nvm)) + if (!stm32lx_nvm_prog_data_unlock(target, flash_base)) return false; - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), is_stm32l1 ? 0 : STM32Lx_NVM_PECR_DATA); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), is_stm32l1 ? 0 : STM32Lx_FLASH_PECR_DATA); /* Sling data to the target one uint32_t at a time */ const uint32_t *const data = (const uint32_t *)src; @@ -434,9 +434,9 @@ static bool stm32lx_nvm_data_write( } /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(target, nvm); + stm32lx_nvm_lock(target, flash_base); /* Wait for completion or an error */ - return stm32lx_nvm_busy_wait(target, nvm, NULL); + return stm32lx_nvm_busy_wait(target, flash_base, NULL); } static bool stm32lx_protected_attach(target_s *const target) @@ -448,31 +448,31 @@ static bool stm32lx_protected_attach(target_s *const target) static bool stm32lx_protected_mass_erase(target_s *const target) { - const uint32_t nvm = stm32lx_nvm_phys(target); - if (!stm32lx_nvm_opt_unlock(target, nvm)) + const target_addr32_t flash_base = stm32lx_flash_base(target); + if (!stm32lx_nvm_opt_unlock(target, flash_base)) return false; - target_mem32_write32(target, STM32Lx_NVM_OPT_PHYS, 0xffff0000U); - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_OBL_LAUNCH); - target_mem32_write32(target, STM32Lx_NVM_OPT_PHYS, 0xff5500aaU); - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_OBL_LAUNCH); + target_mem32_write32(target, STM32Lx_FLASH_OPT_BASE, 0xffff0000U); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_OBL_LAUNCH); + target_mem32_write32(target, STM32Lx_FLASH_OPT_BASE, 0xff5500aaU); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_OBL_LAUNCH); platform_timeout_s timeout; platform_timeout_set(&timeout, 500); - while (target_mem32_read32(target, STM32Lx_NVM_SR(nvm)) & STM32Lx_NVM_SR_BSY) + while (target_mem32_read32(target, STM32Lx_FLASH_SR(flash_base)) & STM32Lx_FLASH_SR_BSY) target_print_progress(&timeout); /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(target, nvm); + stm32lx_nvm_lock(target, flash_base); return true; } static bool stm32lx_mass_erase(target_s *const target) { for (target_flash_s *flash = target->flash; flash; flash = flash->next) { - const int result = stm32lx_nvm_prog_erase(flash, flash->start, flash->length); - if (result != 0) + const bool result = stm32lx_flash_erase(flash, flash->start, flash->length); + if (!result) return false; } return true; @@ -488,14 +488,14 @@ static bool stm32lx_mass_erase(target_s *const target) */ static bool stm32lx_option_write(target_s *const target, const uint32_t address, const uint32_t value) { - const uint32_t nvm = stm32lx_nvm_phys(target); + const target_addr32_t flash_base = stm32lx_flash_base(target); /* Erase and program option in one go. */ - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_FIX); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_FIX); target_mem32_write32(target, address, value); /* Wait for completion or an error */ - return stm32lx_nvm_busy_wait(target, nvm, NULL); + return stm32lx_nvm_busy_wait(target, flash_base, NULL); } /* @@ -506,18 +506,18 @@ static bool stm32lx_option_write(target_s *const target, const uint32_t address, * The return value is true if the write succeeded. * FWIW, byte writing isn't supported because the ADIv5 layer doesn't support byte-level operations. */ -static bool stm32lx_eeprom_write( +static bool stm32lx_eeprom_write_one( target_s *const target, const uint32_t address, const size_t block_size, const uint32_t value) { - const uint32_t nvm = stm32lx_nvm_phys(target); + const target_addr32_t flash_base = stm32lx_flash_base(target); const bool is_stm32l1 = stm32lx_is_stm32l1(target); /* Clear errors. */ - target_mem32_write32(target, STM32Lx_NVM_SR(nvm), STM32Lx_NVM_SR_ERR_M); + target_mem32_write32(target, STM32Lx_FLASH_SR(flash_base), STM32Lx_FLASH_SR_ERR_MASK); /* Erase and program option in one go. */ target_mem32_write32( - target, STM32Lx_NVM_PECR(nvm), (is_stm32l1 ? 0 : STM32Lx_NVM_PECR_DATA) | STM32Lx_NVM_PECR_FIX); + target, STM32Lx_FLASH_PECR(flash_base), (is_stm32l1 ? 0 : STM32Lx_FLASH_PECR_DATA) | STM32Lx_FLASH_PECR_FIX); if (block_size == 4) target_mem32_write32(target, address, value); else if (block_size == 2) @@ -528,26 +528,26 @@ static bool stm32lx_eeprom_write( return false; /* Wait for completion or an error */ - return stm32lx_nvm_busy_wait(target, nvm, NULL); + return stm32lx_nvm_busy_wait(target, flash_base, NULL); } static size_t stm32lx_prot_level(const uint32_t options) { - const uint32_t read_protection = (options >> STM32Lx_NVM_OPTR_RDPROT_S) & STM32Lx_NVM_OPTR_RDPROT_M; - if (read_protection == STM32Lx_NVM_OPTR_RDPROT_0) + const uint32_t read_protection = (options >> STM32Lx_FLASH_OPTR_RDPROT_SHIFT) & STM32Lx_FLASH_OPTR_RDPROT_MASK; + if (read_protection == STM32Lx_FLASH_OPTR_RDPROT_0) return 0; - if (read_protection == STM32Lx_NVM_OPTR_RDPROT_2) + if (read_protection == STM32Lx_FLASH_OPTR_RDPROT_2) return 2; return 1; } static bool stm32lx_cmd_option(target_s *const target, const int argc, const char **const argv) { - const uint32_t nvm = stm32lx_nvm_phys(target); + const target_addr32_t flash_base = stm32lx_flash_base(target); const size_t opt_size = stm32lx_nvm_option_size(target); - if (!stm32lx_nvm_opt_unlock(target, nvm)) { - tc_printf(target, "unable to unlock NVM option bytes\n"); + if (!stm32lx_nvm_opt_unlock(target, flash_base)) { + tc_printf(target, "unable to unlock FLASH option bytes\n"); return true; } @@ -556,7 +556,7 @@ static bool stm32lx_cmd_option(target_s *const target, const int argc, const cha const size_t command_len = strlen(argv[1]); if (argc == 2 && strncasecmp(argv[1], "obl_launch", command_len) == 0) - target_mem32_write32(target, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_OBL_LAUNCH); + target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_OBL_LAUNCH); else if (argc == 4) { const bool raw_write = strncasecmp(argv[1], "raw", command_len) == 0; if (!raw_write && strncasecmp(argv[1], "write", command_len) != 0) @@ -568,7 +568,7 @@ static bool stm32lx_cmd_option(target_s *const target, const int argc, const cha val = (val & 0xffffU) | ((~val & 0xffffU) << 16U); tc_printf(target, "%s %08x <- %08x\n", argv[1], addr, val); - if (addr >= STM32Lx_NVM_OPT_PHYS && addr < STM32Lx_NVM_OPT_PHYS + opt_size && (addr & 3U) == 0) { + if (addr >= STM32Lx_FLASH_OPT_BASE && addr < STM32Lx_FLASH_OPT_BASE + opt_size && (addr & 3U) == 0) { if (!stm32lx_option_write(target, addr, val)) tc_printf(target, "option write failed\n"); } else @@ -577,40 +577,40 @@ static bool stm32lx_cmd_option(target_s *const target, const int argc, const cha /* Report the current option values */ for (size_t i = 0; i < opt_size; i += 4U) { - const uint32_t addr = STM32Lx_NVM_OPT_PHYS + i; + const uint32_t addr = STM32Lx_FLASH_OPT_BASE + i; const uint32_t val = target_mem32_read32(target, addr); tc_printf(target, "0x%08" PRIx32 ": 0x%04u 0x%04u %s\n", addr, val & 0xffffU, (val >> 16U) & 0xffffU, (val & 0xffffU) == ((~val >> 16U) & 0xffffU) ? "OK" : "ERR"); } - const uint32_t options = target_mem32_read32(target, STM32Lx_NVM_OPTR(nvm)); + const uint32_t options = target_mem32_read32(target, STM32Lx_FLASH_OPTR(flash_base)); const size_t read_protection = stm32lx_prot_level(options); if (stm32lx_is_stm32l1(target)) { tc_printf(target, "OPTR: 0x%08" PRIx32 ", RDPRT %u, SPRMD %u, BOR %u, WDG_SW %u, nRST_STP %u, nRST_STBY %u, nBFB2 %u\n", - options, read_protection, (options & STM32L1_NVM_OPTR_SPRMOD) ? 1 : 0, - (options >> STM32L1_NVM_OPTR_BOR_LEV_S) & STM32L1_NVM_OPTR_BOR_LEV_M, - (options & STM32Lx_NVM_OPTR_WDG_SW) ? 1 : 0, (options & STM32L1_NVM_OPTR_nRST_STOP) ? 1 : 0, - (options & STM32L1_NVM_OPTR_nRST_STDBY) ? 1 : 0, (options & STM32L1_NVM_OPTR_nBFB2) ? 1 : 0); + options, read_protection, (options & STM32L1_FLASH_OPTR_SPRMOD) ? 1 : 0, + (options >> STM32L1_FLASH_OPTR_BOR_LEV_SHIFT) & STM32L1_FLASH_OPTR_BOR_LEV_MASK, + (options & STM32Lx_FLASH_OPTR_WDG_SW) ? 1 : 0, (options & STM32L1_FLASH_OPTR_nRST_STOP) ? 1 : 0, + (options & STM32L1_FLASH_OPTR_nRST_STDBY) ? 1 : 0, (options & STM32L1_FLASH_OPTR_nBFB2) ? 1 : 0); } else { tc_printf(target, "OPTR: 0x%08" PRIx32 ", RDPROT %u, WPRMOD %u, WDG_SW %u, BOOT1 %u\n", options, - read_protection, (options & STM32L0_NVM_OPTR_WPRMOD) ? 1 : 0, (options & STM32Lx_NVM_OPTR_WDG_SW) ? 1 : 0, - (options & STM32L0_NVM_OPTR_BOOT1) ? 1 : 0); + read_protection, (options & STM32L0_FLASH_OPTR_WPRMOD) ? 1 : 0, + (options & STM32Lx_FLASH_OPTR_WDG_SW) ? 1 : 0, (options & STM32L0_FLASH_OPTR_BOOT1) ? 1 : 0); } goto done; usage: tc_printf(target, "usage: monitor option [ARGS]\n"); - tc_printf(target, " show - Show options in NVM and as loaded\n"); - tc_printf(target, " obl_launch - Reload options from NVM\n"); + tc_printf(target, " show - Show options in FLASH and as loaded\n"); + tc_printf(target, " obl_launch - Reload options from FLASH\n"); tc_printf(target, " write - Set option half-word; complement computed\n"); tc_printf(target, " raw - Set option word\n"); tc_printf(target, "The value of must be 32-bit aligned and from 0x%08" PRIx32 " to +0x%" PRIx32 "\n", - STM32Lx_NVM_OPT_PHYS, STM32Lx_NVM_OPT_PHYS + (uint32_t)(opt_size - 4U)); + STM32Lx_FLASH_OPT_BASE, STM32Lx_FLASH_OPT_BASE + (uint32_t)(opt_size - 4U)); done: - stm32lx_nvm_lock(target, nvm); + stm32lx_nvm_lock(target, flash_base); return true; } @@ -627,9 +627,9 @@ static const char *stm32lx_block_size_str(const size_t block_size) static bool stm32lx_cmd_eeprom(target_s *const target, const int argc, const char **const argv) { - const uint32_t nvm = stm32lx_nvm_phys(target); + const target_addr32_t flash_base = stm32lx_flash_base(target); - if (!stm32lx_nvm_prog_data_unlock(target, nvm)) { + if (!stm32lx_nvm_prog_data_unlock(target, flash_base)) { tc_printf(target, "unable to unlock EEPROM\n"); return true; } @@ -638,7 +638,7 @@ static bool stm32lx_cmd_eeprom(target_s *const target, const int argc, const cha uint32_t addr = strtoul(argv[2], NULL, 0); uint32_t val = strtoul(argv[3], NULL, 0); - if (addr < STM32Lx_NVM_EEPROM_PHYS || addr >= STM32Lx_NVM_EEPROM_PHYS + stm32lx_nvm_eeprom_size(target)) + if (addr < STM32Lx_FLASH_EEPROM_BASE || addr >= STM32Lx_FLASH_EEPROM_BASE + stm32lx_nvm_eeprom_size(target)) goto usage; const size_t command_len = strlen(argv[1]); @@ -664,7 +664,7 @@ static bool stm32lx_cmd_eeprom(target_s *const target, const int argc, const cha tc_printf( target, "writing %s 0x%08" PRIx32 " with 0x%" PRIx32 "\n", stm32lx_block_size_str(block_size), addr, val); - if (!stm32lx_eeprom_write(target, addr, block_size, val)) + if (!stm32lx_eeprom_write_one(target, addr, block_size, val)) tc_printf(target, "eeprom write failed\n"); } else goto usage; @@ -676,10 +676,10 @@ static bool stm32lx_cmd_eeprom(target_s *const target, const int argc, const cha tc_printf(target, " byte - Write a byte\n"); tc_printf(target, " halfword - Write a half-word\n"); tc_printf(target, " word - Write a word\n"); - tc_printf(target, "The value of must in the interval [0x%08x, 0x%x)\n", STM32Lx_NVM_EEPROM_PHYS, - STM32Lx_NVM_EEPROM_PHYS + stm32lx_nvm_eeprom_size(target)); + tc_printf(target, "The value of must in the interval [0x%08x, 0x%x)\n", STM32Lx_FLASH_EEPROM_BASE, + STM32Lx_FLASH_EEPROM_BASE + stm32lx_nvm_eeprom_size(target)); done: - stm32lx_nvm_lock(target, nvm); + stm32lx_nvm_lock(target, flash_base); return true; } From d0db0f32bef5a8e02f70987a95871ed3a0f55bca Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Jul 2024 09:24:30 +0100 Subject: [PATCH 33/47] stm32l0: Defined base address and sizing macros for the Flash and SRAM regions --- src/target/stm32l0.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 128ab0b45b3..9fbd630209f 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -46,6 +46,14 @@ #include "cortexm.h" #include "stm32_common.h" +#define STM32Lx_FLASH_BANK1_BASE 0x08000000U +#define STM32Lx_FLASH_BANK2_BASE 0x08010000U +#define STM32Lx_FLASH_BANK3_BASE 0x08020000U +#define STM32L0_FLASH_BANK_SIZE 0x00010000U +#define STM32Lx_EEPROM_BASE 0x08080000U +#define STM32Lx_SRAM_BASE 0x20000000U +#define STM32L0_SRAM_SIZE 0x00005000U + #define STM32Lx_FLASH_PECR(flash_base) ((flash_base) + 0x04U) #define STM32Lx_FLASH_PEKEYR(flash_base) ((flash_base) + 0x0cU) #define STM32Lx_FLASH_PRGKEYR(flash_base) ((flash_base) + 0x10U) @@ -214,9 +222,9 @@ bool stm32l0_probe(target_s *const target) case 0x436U: /* CAT. 4 device */ case 0x437U: /* CAT. 5 device */ target->driver = "STM32L1x"; - target_add_ram32(target, 0x20000000, 0x14000); - stm32l_add_flash(target, 0x8000000, 0x80000, 0x100); - //stm32l_add_eeprom(t, 0x8080000, 0x4000); + target_add_ram32(target, STM32Lx_SRAM_BASE, 0x14000); + stm32l_add_flash(target, STM32Lx_FLASH_BANK1_BASE, 0x80000, 0x100); + //stm32l_add_eeprom(t, STM32Lx_EEPROM_BASE, 0x4000); target_add_commands(target, stm32lx_cmd_list, "STM32L1x"); break; case 0x457U: /* STM32L0xx Cat1 */ @@ -224,11 +232,11 @@ bool stm32l0_probe(target_s *const target) case 0x417U: /* STM32L0xx Cat3 */ case 0x447U: /* STM32L0xx Cat5 */ target->driver = "STM32L0x"; - target_add_ram32(target, 0x20000000, 0x5000); - stm32l_add_flash(target, 0x8000000, 0x10000, 0x80); - stm32l_add_flash(target, 0x8010000, 0x10000, 0x80); - stm32l_add_flash(target, 0x8020000, 0x10000, 0x80); - stm32l_add_eeprom(target, 0x8080000, 0x1800); + target_add_ram32(target, STM32Lx_SRAM_BASE, STM32L0_SRAM_SIZE); + stm32l_add_flash(target, STM32Lx_FLASH_BANK1_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); + stm32l_add_flash(target, STM32Lx_FLASH_BANK2_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); + stm32l_add_flash(target, STM32Lx_FLASH_BANK3_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); + stm32l_add_eeprom(target, STM32Lx_EEPROM_BASE, 0x1800); target_add_commands(target, stm32lx_cmd_list, "STM32L0x"); break; default: From 3e0679066851c0b9f16b05b0aab9a68a3dbdfdaf Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Jul 2024 10:45:28 +0100 Subject: [PATCH 34/47] stm32l0: Defined part identification macros to name the part ID numbers --- src/target/stm32l0.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 9fbd630209f..5d170ae9364 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -121,6 +121,12 @@ #define STM32L0_DBGMCU_BASE UINT32_C(0x40015800) #define STM32L1_DBGMCU_BASE UINT32_C(0xe0042000) +/* Taken from DBGMCU_IDCODE in §27.4.1 in RM0377 rev 10, pg820 */ +#define ID_STM32L01x 0x457U /* Category 1 */ +#define ID_STM32L03x 0x425U /* Category 2 */ +#define ID_STM32L05x 0x417U /* Category 3 */ +#define ID_STM32L07x 0x447U /* Category 5 */ + static bool stm32lx_cmd_option(target_s *target, int argc, const char **argv); static bool stm32lx_cmd_eeprom(target_s *target, int argc, const char **argv); @@ -225,19 +231,19 @@ bool stm32l0_probe(target_s *const target) target_add_ram32(target, STM32Lx_SRAM_BASE, 0x14000); stm32l_add_flash(target, STM32Lx_FLASH_BANK1_BASE, 0x80000, 0x100); //stm32l_add_eeprom(t, STM32Lx_EEPROM_BASE, 0x4000); - target_add_commands(target, stm32lx_cmd_list, "STM32L1x"); + target_add_commands(target, stm32lx_cmd_list, target->driver); break; - case 0x457U: /* STM32L0xx Cat1 */ - case 0x425U: /* STM32L0xx Cat2 */ - case 0x417U: /* STM32L0xx Cat3 */ - case 0x447U: /* STM32L0xx Cat5 */ - target->driver = "STM32L0x"; + case ID_STM32L01x: + case ID_STM32L03x: + case ID_STM32L05x: + case ID_STM32L07x: + target->driver = "STM32L0"; target_add_ram32(target, STM32Lx_SRAM_BASE, STM32L0_SRAM_SIZE); stm32l_add_flash(target, STM32Lx_FLASH_BANK1_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); stm32l_add_flash(target, STM32Lx_FLASH_BANK2_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); stm32l_add_flash(target, STM32Lx_FLASH_BANK3_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); stm32l_add_eeprom(target, STM32Lx_EEPROM_BASE, 0x1800); - target_add_commands(target, stm32lx_cmd_list, "STM32L0x"); + target_add_commands(target, stm32lx_cmd_list, target->driver); break; default: return false; From 259de5062e98e73166eb46b362277beb53fcdc5a Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Jul 2024 12:16:44 +0100 Subject: [PATCH 35/47] stm32l0: Split the probe function into two - one for L0 and one for L1 parts to simplify map setup and DBGMCU handling --- src/target/cortexm.c | 1 + src/target/stm32l0.c | 77 +++++++++++++++++++++++++++++++------------- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 9beffd3ba7e..1f6e2546819 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -585,6 +585,7 @@ bool cortexm_probe(adiv5_access_port_s *ap) PROBE(stm32h7_probe); PROBE(stm32mp15_cm4_probe); PROBE(stm32l0_probe); + PROBE(stm32l1_probe); PROBE(stm32l4_probe); PROBE(stm32g0_probe); break; diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 5d170ae9364..062513f7fa7 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -46,13 +46,12 @@ #include "cortexm.h" #include "stm32_common.h" -#define STM32Lx_FLASH_BANK1_BASE 0x08000000U -#define STM32Lx_FLASH_BANK2_BASE 0x08010000U -#define STM32Lx_FLASH_BANK3_BASE 0x08020000U -#define STM32L0_FLASH_BANK_SIZE 0x00010000U -#define STM32Lx_EEPROM_BASE 0x08080000U -#define STM32Lx_SRAM_BASE 0x20000000U -#define STM32L0_SRAM_SIZE 0x00005000U +#define STM32Lx_FLASH_BANK_BASE 0x08000000U +#define STM32L0_FLASH_BANK_SIZE 0x00010000U +#define STM32L0_FLASH_PAGE_SIZE 0x00000080U +#define STM32Lx_EEPROM_BASE 0x08080000U +#define STM32Lx_SRAM_BASE 0x20000000U +#define STM32L0_SRAM_SIZE 0x00005000U #define STM32Lx_FLASH_PECR(flash_base) ((flash_base) + 0x04U) #define STM32Lx_FLASH_PEKEYR(flash_base) ((flash_base) + 0x0cU) @@ -118,7 +117,10 @@ #define STM32L1_FLASH_OPTR_BOR_LEV_MASK 0xfU #define STM32L1_FLASH_OPTR_SPRMOD (1U << 8U) -#define STM32L0_DBGMCU_BASE UINT32_C(0x40015800) +#define STM32L0_DBGMCU_BASE UINT32_C(0x40015800) +#define STM32L0_UID_BASE 0x1ff80050U +#define STM32L0_UID_FLASH_SIZE 0x1ff8007cU + #define STM32L1_DBGMCU_BASE UINT32_C(0xe0042000) /* Taken from DBGMCU_IDCODE in §27.4.1 in RM0377 rev 10, pg820 */ @@ -218,36 +220,65 @@ static void stm32l_add_eeprom(target_s *const target, const uint32_t addr, const target_add_flash(target, flash); } -/* Probe for STM32L0xx and STM32L1xx parts. */ bool stm32l0_probe(target_s *const target) { + /* Try to identify the part, make sure it's a STM32L0 */ + if (target->part_id != ID_STM32L01x && target->part_id != ID_STM32L03x && target->part_id != ID_STM32L05x && + target->part_id != ID_STM32L07x) + return false; + + target->driver = "STM32L0"; + target->mass_erase = stm32lx_mass_erase; + target_add_commands(target, stm32lx_cmd_list, target->driver); + + /* Having identified that it's a STM32L0 of some sort, read out how much Flash it has */ + const uint32_t flash_size = target_mem32_read16(target, STM32L0_UID_FLASH_SIZE) * 1024U; + /* There's no good way to tell how much RAM a part has, so use a one-size map */ + target_add_ram32(target, STM32Lx_SRAM_BASE, STM32L0_SRAM_SIZE); + + /* Now fill in the Flash map based on the part category */ switch (target->part_id) { + case ID_STM32L01x: + case ID_STM32L03x: + case ID_STM32L05x: + /* Category 1, 2 and 3 only have one bank */ + stm32l_add_flash(target, STM32Lx_FLASH_BANK_BASE, flash_size, STM32L0_FLASH_PAGE_SIZE); + break; + case ID_STM32L07x: { + /* Category 5 parts have 2 banks, split 50:50 on the total size of the Flash */ + const size_t bank_size = flash_size >> 1U; + const target_addr32_t bank2_base = STM32Lx_FLASH_BANK_BASE + bank_size; + stm32l_add_flash(target, STM32Lx_FLASH_BANK_BASE, bank_size, STM32L0_FLASH_PAGE_SIZE); + stm32l_add_flash(target, bank2_base, bank_size, STM32L0_FLASH_PAGE_SIZE); + break; + } + } + /* There's also no good way to know how much EEPROM the part has, so define a one-size map for that too */ + stm32l_add_eeprom(target, STM32Lx_EEPROM_BASE, 0x1800); + + return true; +} + +bool stm32l1_probe(target_s *const target) +{ + const adiv5_access_port_s *const ap = cortex_ap(target); + /* Use the partno from the AP always to handle the difference between JTAG and SWD */ + switch (ap->partno) { case 0x416U: /* CAT. 1 device */ case 0x429U: /* CAT. 2 device */ case 0x427U: /* CAT. 3 device */ case 0x436U: /* CAT. 4 device */ case 0x437U: /* CAT. 5 device */ - target->driver = "STM32L1x"; + target->driver = "STM32L1"; target_add_ram32(target, STM32Lx_SRAM_BASE, 0x14000); - stm32l_add_flash(target, STM32Lx_FLASH_BANK1_BASE, 0x80000, 0x100); + stm32l_add_flash(target, STM32Lx_FLASH_BANK_BASE, 0x80000, 0x100); //stm32l_add_eeprom(t, STM32Lx_EEPROM_BASE, 0x4000); target_add_commands(target, stm32lx_cmd_list, target->driver); break; - case ID_STM32L01x: - case ID_STM32L03x: - case ID_STM32L05x: - case ID_STM32L07x: - target->driver = "STM32L0"; - target_add_ram32(target, STM32Lx_SRAM_BASE, STM32L0_SRAM_SIZE); - stm32l_add_flash(target, STM32Lx_FLASH_BANK1_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); - stm32l_add_flash(target, STM32Lx_FLASH_BANK2_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); - stm32l_add_flash(target, STM32Lx_FLASH_BANK3_BASE, STM32L0_FLASH_BANK_SIZE, 0x80); - stm32l_add_eeprom(target, STM32Lx_EEPROM_BASE, 0x1800); - target_add_commands(target, stm32lx_cmd_list, target->driver); - break; default: return false; } + target->part_id = ap->partno; stm32l_priv_t *priv_storage = calloc(1, sizeof(*priv_storage)); if (!priv_storage) { From 21b728e3f6a355aed1af7abefabc920ac7593e41 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 20 Jul 2024 06:13:55 +0100 Subject: [PATCH 36/47] stm32l0: Implemented logic for controlling the DBGMCU and handling both WFI/WFE debugging and freezing the WDTs while in debug halt --- src/target/stm32l0.c | 52 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 062513f7fa7..34e3e8eca71 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -117,12 +117,21 @@ #define STM32L1_FLASH_OPTR_BOR_LEV_MASK 0xfU #define STM32L1_FLASH_OPTR_SPRMOD (1U << 8U) -#define STM32L0_DBGMCU_BASE UINT32_C(0x40015800) -#define STM32L0_UID_BASE 0x1ff80050U -#define STM32L0_UID_FLASH_SIZE 0x1ff8007cU +#define STM32L0_DBGMCU_BASE UINT32_C(0x40015800) +#define STM32L0_DBGMCU_IDCODE (STM32L0_DBGMCU_BASE + 0x000U) +#define STM32L0_DBGMCU_CONFIG (STM32L0_DBGMCU_BASE + 0x004U) +#define STM32L0_DBGMCU_APB1FREEZE (STM32L0_DBGMCU_BASE + 0x008U) +#define STM32L0_UID_BASE 0x1ff80050U +#define STM32L0_UID_FLASH_SIZE 0x1ff8007cU #define STM32L1_DBGMCU_BASE UINT32_C(0xe0042000) +#define STM32Lx_DBGMCU_CONFIG_DBG_SLEEP (1U << 0U) +#define STM32Lx_DBGMCU_CONFIG_DBG_STOP (1U << 1U) +#define STM32Lx_DBGMCU_CONFIG_DBG_STANDBY (1U << 2U) +#define STM32Lx_DBGMCU_APB1FREEZE_WWDG (1U << 11U) +#define STM32Lx_DBGMCU_APB1FREEZE_IWDG (1U << 12U) + /* Taken from DBGMCU_IDCODE in §27.4.1 in RM0377 rev 10, pg820 */ #define ID_STM32L01x 0x457U /* Category 1 */ #define ID_STM32L03x 0x425U /* Category 2 */ @@ -138,6 +147,8 @@ static const command_s stm32lx_cmd_list[] = { {NULL, NULL, NULL}, }; +static bool stm32l0_attach(target_s *target); +static void stm32l0_detach(target_s *target); static bool stm32lx_flash_erase(target_flash_s *flash, target_addr_t addr, size_t length); static bool stm32lx_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); static bool stm32lx_eeprom_erase(target_flash_s *flash, target_addr_t addr, size_t length); @@ -220,6 +231,16 @@ static void stm32l_add_eeprom(target_s *const target, const uint32_t addr, const target_add_flash(target, flash); } +static void stm32l0_configure_dbgmcu(target_s *const target) +{ + /* Enable debugging during all low power modes */ + target_mem32_write32(target, STM32L0_DBGMCU_CONFIG, + STM32Lx_DBGMCU_CONFIG_DBG_SLEEP | STM32Lx_DBGMCU_CONFIG_DBG_STANDBY | STM32Lx_DBGMCU_CONFIG_DBG_STOP); + /* And make sure the WDTs stay synchronised to the run state of the processor */ + target_mem32_write32( + target, STM32L0_DBGMCU_APB1FREEZE, STM32Lx_DBGMCU_APB1FREEZE_WWDG | STM32Lx_DBGMCU_APB1FREEZE_IWDG); +} + bool stm32l0_probe(target_s *const target) { /* Try to identify the part, make sure it's a STM32L0 */ @@ -227,7 +248,12 @@ bool stm32l0_probe(target_s *const target) target->part_id != ID_STM32L07x) return false; + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + stm32l0_configure_dbgmcu(target); + target->driver = "STM32L0"; + target->attach = stm32l0_attach; + target->detach = stm32l0_detach; target->mass_erase = stm32lx_mass_erase; target_add_commands(target, stm32lx_cmd_list, target->driver); @@ -303,6 +329,26 @@ bool stm32l1_probe(target_s *const target) return true; } +static bool stm32l0_attach(target_s *const target) +{ + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + if (!cortexm_attach(target)) + return false; + stm32l0_configure_dbgmcu(target); + return true; +} + +static void stm32l0_detach(target_s *target) +{ + /* Reverse all changes to STM32L0_DBGMCU_CONFIG */ + target_mem32_write32(target, STM32L0_DBGMCU_CONFIG, 0U); + /* Now defer to the normal Cortex-M detach routine to complete the detach */ + cortexm_detach(target); +} + /* Lock the FLASH control registers preventing writes or erases. */ static void stm32lx_nvm_lock(target_s *const target, const target_addr32_t flash_base) { From a4b5d8ff3478d1662e3d10e4b0024c87c64baf04 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 21 Jul 2024 11:32:34 +0100 Subject: [PATCH 37/47] stm32l0: Tidied up the logic for determining if a part is an L0 or an L1 --- src/target/stm32l0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 34e3e8eca71..ec86e8fb312 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -164,8 +164,8 @@ typedef struct stm32l_priv_s { static bool stm32lx_is_stm32l1(const target_s *const target) { - return target->part_id != 0x457U /* STM32L0xx Cat1 */ && target->part_id != 0x425U /* STM32L0xx Cat2 */ && - target->part_id != 0x417U /* STM32L0xx Cat3 */ && target->part_id != 0x447U /* STM32L0xx Cat5 */; + return target->part_id != ID_STM32L01x && target->part_id != ID_STM32L03x && target->part_id != ID_STM32L05x && + target->part_id != ID_STM32L07x; } static uint32_t stm32lx_nvm_eeprom_size(const target_s *const target) From ad4f34185f9df927694906f7f0d6984e89d26e18 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 21 Jul 2024 11:37:01 +0100 Subject: [PATCH 38/47] stm32l0: Begun refactoring the L1 probe code --- src/target/stm32l0.c | 88 ++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index ec86e8fb312..7fd890cce22 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -52,6 +52,7 @@ #define STM32Lx_EEPROM_BASE 0x08080000U #define STM32Lx_SRAM_BASE 0x20000000U #define STM32L0_SRAM_SIZE 0x00005000U +#define STM32L1_SRAM_SIZE 0x00014000U #define STM32Lx_FLASH_PECR(flash_base) ((flash_base) + 0x04U) #define STM32Lx_FLASH_PEKEYR(flash_base) ((flash_base) + 0x0cU) @@ -124,7 +125,20 @@ #define STM32L0_UID_BASE 0x1ff80050U #define STM32L0_UID_FLASH_SIZE 0x1ff8007cU -#define STM32L1_DBGMCU_BASE UINT32_C(0xe0042000) +/* + * NB: The L1 has two different UID and Flash size register base addresses! + * The L1xxxB ones are for Category 1 & 2 devices only. The L1xxxx ones + * are for Category 3, 4, 5 and 6 as the devices have two different memory maps + * that depend on the category code. + */ +#define STM32L1_DBGMCU_BASE UINT32_C(0xe0042000) +#define STM32L1_DBGMCU_IDCODE (STM32L1_DBGMCU_BASE + 0x000U) +#define STM32L1_DBGMCU_CONFIG (STM32L1_DBGMCU_BASE + 0x004U) +#define STM32L1_DBGMCU_APB1FREEZE (STM32L1_DBGMCU_BASE + 0x008U) +#define STM32L1xxxB_UID_BASE 0x1ff80050U +#define STM32L1xxxB_UID_FLASH_SIZE 0x1ff8004cU +#define STM32L1xxxx_UID_BASE 0x1ff800d0U +#define STM32L1xxxx_UID_FLASH_SIZE 0x1ff800ccU #define STM32Lx_DBGMCU_CONFIG_DBG_SLEEP (1U << 0U) #define STM32Lx_DBGMCU_CONFIG_DBG_STOP (1U << 1U) @@ -138,6 +152,13 @@ #define ID_STM32L05x 0x417U /* Category 3 */ #define ID_STM32L07x 0x447U /* Category 5 */ +/* Taken from DBGMCU_IDCODE in §30.6.1 in RM0038 rev 17, pg861 */ +#define ID_STM32L1xxxB 0x416U /* Category 1 */ +#define ID_STM32L1xxxBxA 0x429U /* Category 2 */ +#define ID_STM32L1xxxC 0x427U /* Category 3 */ +#define ID_STM32L1xxxD 0x436U /* Category 3/4 */ +#define ID_STM32L1xxxE 0x437U /* Category 5/6 */ + static bool stm32lx_cmd_option(target_s *target, int argc, const char **argv); static bool stm32lx_cmd_eeprom(target_s *target, int argc, const char **argv); @@ -158,9 +179,10 @@ static bool stm32lx_mass_erase(target_s *target); static bool stm32lx_protected_attach(target_s *target); static bool stm32lx_protected_mass_erase(target_s *target); -typedef struct stm32l_priv_s { +typedef struct stm32l_priv { + uint32_t dbgmcu_config; char stm32l_variant[21]; -} stm32l_priv_t; +} stm32l_priv_s; static bool stm32lx_is_stm32l1(const target_s *const target) { @@ -285,46 +307,42 @@ bool stm32l0_probe(target_s *const target) return true; } +static bool stm32l1_configure_dbgmcu(target_s *const target) +{ + /* If we're in the probe phase */ + if (target->target_storage == NULL) { + /* Allocate and save private storage */ + stm32l_priv_s *const priv_storage = calloc(1, sizeof(*priv_storage)); + if (!priv_storage) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + /* Get the current value of the debug config register (and store it for later) */ + priv_storage->dbgmcu_config = target_mem32_read32(target, STM32L1_DBGMCU_CONFIG); + target->target_storage = priv_storage; + } + return true; +} + bool stm32l1_probe(target_s *const target) { + /* Try to identify the part, make sure it's a STM32L1 */ const adiv5_access_port_s *const ap = cortex_ap(target); /* Use the partno from the AP always to handle the difference between JTAG and SWD */ - switch (ap->partno) { - case 0x416U: /* CAT. 1 device */ - case 0x429U: /* CAT. 2 device */ - case 0x427U: /* CAT. 3 device */ - case 0x436U: /* CAT. 4 device */ - case 0x437U: /* CAT. 5 device */ - target->driver = "STM32L1"; - target_add_ram32(target, STM32Lx_SRAM_BASE, 0x14000); - stm32l_add_flash(target, STM32Lx_FLASH_BANK_BASE, 0x80000, 0x100); - //stm32l_add_eeprom(t, STM32Lx_EEPROM_BASE, 0x4000); - target_add_commands(target, stm32lx_cmd_list, target->driver); - break; - default: + if (ap->partno != ID_STM32L1xxxB && ap->partno != ID_STM32L1xxxBxA && ap->partno != ID_STM32L1xxxC && + ap->partno != ID_STM32L1xxxD && ap->partno != ID_STM32L1xxxE) return false; - } target->part_id = ap->partno; - stm32l_priv_t *priv_storage = calloc(1, sizeof(*priv_storage)); - if (!priv_storage) { - DEBUG_ERROR("calloc: failed in %s\n", __func__); - return false; - } - target->target_storage = (void *)priv_storage; + /* Now we have a stable debug environment, make sure the WDTs + WFI and WFE instructions can't cause problems */ + stm32l1_configure_dbgmcu(target); + + target->driver = "STM32L1"; + target->mass_erase = stm32lx_mass_erase; + target_add_commands(target, stm32lx_cmd_list, target->driver); + /* There's no good way to tell how much RAM a part has, so use a one-size map */ + target_add_ram32(target, STM32Lx_SRAM_BASE, STM32L1_SRAM_SIZE); - const target_addr32_t flash_base = stm32lx_flash_base(target); - const bool protected = (target_mem32_read32(target, STM32Lx_FLASH_OPTR(flash_base)) & - STM32Lx_FLASH_OPTR_RDPROT_MASK) != STM32Lx_FLASH_OPTR_RDPROT_0; - snprintf(priv_storage->stm32l_variant, sizeof(priv_storage->stm32l_variant), "%s%s", target->driver, - protected ? " (protected)" : ""); - target->driver = priv_storage->stm32l_variant; - - if (protected) { - target->attach = stm32lx_protected_attach; - target->mass_erase = stm32lx_protected_mass_erase; - } else - target->mass_erase = stm32lx_mass_erase; return true; } From 1b9ccb288f07c761e47c952ce3a98812eb80c6fd Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 21 Jul 2024 11:37:57 +0100 Subject: [PATCH 39/47] stm32l0: Implemented logic for properly determining the Flash size of an L1 part --- src/target/stm32l0.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 7fd890cce22..a32ccb271a8 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -180,6 +180,7 @@ static bool stm32lx_protected_attach(target_s *target); static bool stm32lx_protected_mass_erase(target_s *target); typedef struct stm32l_priv { + target_addr32_t uid_taddr; uint32_t dbgmcu_config; char stm32l_variant[21]; } stm32l_priv_s; @@ -343,6 +344,33 @@ bool stm32l1_probe(target_s *const target) /* There's no good way to tell how much RAM a part has, so use a one-size map */ target_add_ram32(target, STM32Lx_SRAM_BASE, STM32L1_SRAM_SIZE); + /* Having identified that it's a STM32L1 of some sort, dispatch Flash map setup based on the category */ + target_addr32_t flash_size_taddr = 0U; + stm32l_priv_s *const priv = (stm32l_priv_s *)target->target_storage; + switch (target->part_id) { + case ID_STM32L1xxxB: + case ID_STM32L1xxxBxA: + flash_size_taddr = STM32L1xxxB_UID_FLASH_SIZE; + priv->uid_taddr = STM32L1xxxB_UID_BASE; + break; + case ID_STM32L1xxxC: + case ID_STM32L1xxxD: + case ID_STM32L1xxxE: + flash_size_taddr = STM32L1xxxx_UID_FLASH_SIZE; + priv->uid_taddr = STM32L1xxxx_UID_BASE; + break; + } + /* Read out the appropriate Flash size register value */ + uint32_t flash_size = target_mem32_read16(target, flash_size_taddr); + /* Having read out the Flash size register, deal with two special cases before converting to an actual Flash size */ + if (target->part_id == ID_STM32L1xxxBxA) + /* Only the lowest byte is valid on category 2 parts */ + flash_size &= 0xffU; + else if (target->part_id == ID_STM32L1xxxD) + /* Cat 3/4 parts have values of 0 or 1, convert to actual Flash sizes for these parts (384KiB or 256KiB) */ + flash_size = flash_size == 0U ? 384U : 256U; + /* Finally, now all that's done.. convert the Flash size value to bytes */ + flash_size *= 1024U; return true; } From d655daa4014a0a09452356eb25cc69558152c463 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 21 Jul 2024 11:38:34 +0100 Subject: [PATCH 40/47] stm32l0: Implemented logic for properly halting the WDTs and enabling debug through WFI/WFE --- src/target/stm32l0.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index a32ccb271a8..912ff6d06bf 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -322,6 +322,15 @@ static bool stm32l1_configure_dbgmcu(target_s *const target) priv_storage->dbgmcu_config = target_mem32_read32(target, STM32L1_DBGMCU_CONFIG); target->target_storage = priv_storage; } + + const stm32l_priv_s *const priv = (stm32l_priv_s *)target->target_storage; + /* Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us */ + target_mem32_write32( + target, STM32L1_DBGMCU_APB1FREEZE, STM32Lx_DBGMCU_APB1FREEZE_WWDG | STM32Lx_DBGMCU_APB1FREEZE_IWDG); + /* Then Reconfigure the config register to prevent WFI/WFE from cutting debug access */ + target_mem32_write32(target, STM32L1_DBGMCU_CONFIG, + priv->dbgmcu_config | STM32Lx_DBGMCU_CONFIG_DBG_SLEEP | STM32Lx_DBGMCU_CONFIG_DBG_STANDBY | + STM32Lx_DBGMCU_CONFIG_DBG_STOP); return true; } From 2bff033ff935fc7644e9e41e8a453886c69c09f7 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 21 Jul 2024 11:39:18 +0100 Subject: [PATCH 41/47] stm32l0: Stripped out the protected attach/mass-erase implementations as these things can be achieved with the options bytes command --- src/target/stm32l0.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 912ff6d06bf..6856c44fa63 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -176,9 +176,6 @@ static bool stm32lx_eeprom_erase(target_flash_s *flash, target_addr_t addr, size static bool stm32lx_eeprom_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); static bool stm32lx_mass_erase(target_s *target); -static bool stm32lx_protected_attach(target_s *target); -static bool stm32lx_protected_mass_erase(target_s *target); - typedef struct stm32l_priv { target_addr32_t uid_taddr; uint32_t dbgmcu_config; @@ -585,35 +582,6 @@ static bool stm32lx_eeprom_write( return stm32lx_nvm_busy_wait(target, flash_base, NULL); } -static bool stm32lx_protected_attach(target_s *const target) -{ - tc_printf(target, "Attached in protected mode, please issue 'monitor erase_mass' to regain chip access\n"); - target->attach = cortexm_attach; - return true; -} - -static bool stm32lx_protected_mass_erase(target_s *const target) -{ - const target_addr32_t flash_base = stm32lx_flash_base(target); - if (!stm32lx_nvm_opt_unlock(target, flash_base)) - return false; - - target_mem32_write32(target, STM32Lx_FLASH_OPT_BASE, 0xffff0000U); - target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_OBL_LAUNCH); - target_mem32_write32(target, STM32Lx_FLASH_OPT_BASE, 0xff5500aaU); - target_mem32_write32(target, STM32Lx_FLASH_PECR(flash_base), STM32Lx_FLASH_PECR_OBL_LAUNCH); - - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); - - while (target_mem32_read32(target, STM32Lx_FLASH_SR(flash_base)) & STM32Lx_FLASH_SR_BSY) - target_print_progress(&timeout); - - /* Disable further programming by locking PECR */ - stm32lx_nvm_lock(target, flash_base); - return true; -} - static bool stm32lx_mass_erase(target_s *const target) { for (target_flash_s *flash = target->flash; flash; flash = flash->next) { From 8fa3386f8f7ef12e0e51a4db4efd6d18c4e9f92b Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 21 Jul 2024 11:39:44 +0100 Subject: [PATCH 42/47] stm32l0: Implemented the attach/detach logic for the L1's to deal with the DBGMCU properly --- src/target/stm32l0.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 6856c44fa63..25fd7082fc8 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -169,7 +169,9 @@ static const command_s stm32lx_cmd_list[] = { }; static bool stm32l0_attach(target_s *target); +static bool stm32l1_attach(target_s *target); static void stm32l0_detach(target_s *target); +static void stm32l1_detach(target_s *target); static bool stm32lx_flash_erase(target_flash_s *flash, target_addr_t addr, size_t length); static bool stm32lx_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); static bool stm32lx_eeprom_erase(target_flash_s *flash, target_addr_t addr, size_t length); @@ -318,6 +320,9 @@ static bool stm32l1_configure_dbgmcu(target_s *const target) /* Get the current value of the debug config register (and store it for later) */ priv_storage->dbgmcu_config = target_mem32_read32(target, STM32L1_DBGMCU_CONFIG); target->target_storage = priv_storage; + + target->attach = stm32l1_attach; + target->detach = stm32l1_detach; } const stm32l_priv_s *const priv = (stm32l_priv_s *)target->target_storage; @@ -401,6 +406,24 @@ static void stm32l0_detach(target_s *target) cortexm_detach(target); } +static bool stm32l1_attach(target_s *const target) +{ + /* + * Try to attach to the part, and then ensure that the WDTs + WFI and WFE + * instructions can't cause problems (this is duplicated as it's undone by detach.) + */ + return cortexm_attach(target) && stm32l1_configure_dbgmcu(target); +} + +static void stm32l1_detach(target_s *target) +{ + const stm32l_priv_s *const priv = (stm32l_priv_s *)target->target_storage; + /* Reverse all changes to STM32L1_DBGMCU_CONFIG */ + target_mem32_write32(target, STM32L1_DBGMCU_CONFIG, priv->dbgmcu_config); + /* Now defer to the normal Cortex-M detach routine to complete the detach */ + cortexm_detach(target); +} + /* Lock the FLASH control registers preventing writes or erases. */ static void stm32lx_nvm_lock(target_s *const target, const target_addr32_t flash_base) { From 231584bc0a48a8ee0a24bce860f6c5a81c99f569 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 28 Jul 2024 05:15:30 +0100 Subject: [PATCH 43/47] stm32l0: Implemented proper Flash registration tables for the L1 series parts --- src/target/stm32l0.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 25fd7082fc8..09092f249b7 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -49,6 +49,7 @@ #define STM32Lx_FLASH_BANK_BASE 0x08000000U #define STM32L0_FLASH_BANK_SIZE 0x00010000U #define STM32L0_FLASH_PAGE_SIZE 0x00000080U +#define STM32L1_FLASH_PAGE_SIZE 0x00000100U #define STM32Lx_EEPROM_BASE 0x08080000U #define STM32Lx_SRAM_BASE 0x20000000U #define STM32L0_SRAM_SIZE 0x00005000U @@ -383,6 +384,59 @@ bool stm32l1_probe(target_s *const target) /* Finally, now all that's done.. convert the Flash size value to bytes */ flash_size *= 1024U; + /* Dispatch again on the category to complete Flash map setup */ + switch (target->part_id) { + case ID_STM32L1xxxB: + case ID_STM32L1xxxBxA: + case ID_STM32L1xxxC: + case ID_STM32L1xxxD: { + /* + * Category 1, 2, and 3 only have one bank. This bank is split into up-to 64 4KiB sectors of 256 byte pages. + * Sectors are the write protection primitive, pages are the erase size primitive. The manual displays these + * as split with 1KiB of 256 byte pages, 3KiB of 1KiB pages, up to 124KiB of 4KiB pages, and then finally + * the rest of the Flash as 64KiB pages. However this is inaccurate. + * Category 4 has 2 banks but the first bank is laid out exactly the same as the first 3 categories. + * Category 4's second bank starts at the 192KiB mark and looks like it extends with a 128KiB page and a + * 64KiB page for another 192KiB for 384KiB of Flash. This bank, however, works the same as the first. + * This is documented in §3.2, tables 8, 9, and 10 on pg53 of RM0038, rev 17 + */ + const bool category4 = flash_size == 0x00060000U; + /* + * Determine bank 1's size. Category 4 parts have their 384KiB of Flash split evenly between the two + * banks, while the others all have their entire Flash on the first bank only. + */ + const uint32_t bank_size = category4 ? flash_size >> 1U : flash_size; + stm32l_add_flash(target, STM32Lx_FLASH_BANK_BASE, bank_size, STM32L1_FLASH_PAGE_SIZE); + /* Now deal with the second bank on Category 4 parts */ + if (category4) + stm32l_add_flash(target, STM32Lx_FLASH_BANK_BASE + 0x00030000U, bank_size, STM32L1_FLASH_PAGE_SIZE); + break; + } + case ID_STM32L1xxxE: { + /* + * Category 5 has 2 banks, documented in §3.2, table 11 on pg56 of RM0038, rev 17. + * These banks are split up into sectors and pages the same as any other for the L1 series. + * The manual displays this as first bank being split into 1KiB of 256 byte pages, 3KiB of 1KiB pages, + * 124KiB of 4KiB pages, and a 128KiB page for 256KiB. It then shows the second bank is split into two + * 128KiB pages for a second 256KiB. However this is inaccurate. + * This gives a total of 512KiB of Flash, which is the only way to tell these parts apart from category 6. + * + * Category 6 has 2 banks as well, documented in §3.2, table 12 on pg58 of RM0038, rev 17. + * The manual displays this as the first bank starting the same as a Category 5 device, right up until 128KiB + * in, after which it shows the bank being concluded by a single 64KiB page for 192KiB. Bank 2 is then shown as + * 1 128KiB page and one 64KiB page for another 192KiB, giving a total of 384KiB of Flash same as Category 4 + * parts. While the total amount is accurate, this is an inaccurate representation. These too use + * the same sectors and pages arrangements as the other L1 parts, however the bank split location for + * the Category 5 and 6 parts is the same 256KiB mark, causing the Category 6 parts to have a small hole + * between the two banks, unlike Category 4 where the banks are contiguous. + */ + const uint32_t bank_size = flash_size >> 1U; + stm32l_add_flash(target, STM32Lx_FLASH_BANK_BASE, bank_size, STM32L1_FLASH_PAGE_SIZE); + stm32l_add_flash(target, STM32Lx_FLASH_BANK_BASE + 0x00040000U, bank_size, STM32L1_FLASH_PAGE_SIZE); + break; + } + } + return true; } From c2f0b06303fa62eb6be0c877b1fb371d27e1a586 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 1 Aug 2024 08:11:30 +0100 Subject: [PATCH 44/47] stm32l4: Device ID nomenclature corrections --- src/target/stm32l4.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index 6d5d67a3d3c..6208ce70f45 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -186,12 +186,12 @@ typedef enum stm32l4_device_id { * The references after the values are the sections to look at in the respective reference manuals. */ ID_STM32U535 = 0x4550U, /* STM32U535/545 from RM0456, Rev.4 $75.3.3 DP_TARGETIDR pg.3497 Not Tested */ - ID_STM32U5FX = 0x4760U, /* STM32U5Fx/5Gx from RM0456, Rev.4 $75.3.3 DP_TARGETIDR pg.3497 Not Tested */ - ID_STM32U59X = 0x4810U, /* STM32U59x/5Ax from RM0456, Rev.4 $75.3.3 DP_TARGETIDR pg.3497 Not Tested */ + ID_STM32U5Fx = 0x4760U, /* STM32U5Fx/5Gx from RM0456, Rev.4 $75.3.3 DP_TARGETIDR pg.3497 Not Tested */ + ID_STM32U59x = 0x4810U, /* STM32U59x/5Ax from RM0456, Rev.4 $75.3.3 DP_TARGETIDR pg.3497 Not Tested */ ID_STM32U575 = 0x4820U, /* STM32U575/585 from RM0456, Rev.4 $75.3.3 DP_TARGETIDR pg.3497 Tested on U575 */ - ID_STM32WLXX = 0x4970U, /* from RM0461, Rev.5 §36.4.5, and RM0453, Rev.3 §38.4.5 */ - ID_STM32WBXX = 0x4950U, /* from RM0434, Rev.10 §41.4.8 */ - ID_STM32WB1X = 0x4940U, /* from RM0473, Rev.7 §33.4.8 and RM0478 Rev.5 §31.4.8 */ + ID_STM32WLxx = 0x4970U, /* from RM0461, Rev.5 §36.4.5, and RM0453, Rev.3 §38.4.5 */ + ID_STM32WBxx = 0x4950U, /* from RM0434, Rev.10 §41.4.8 */ + ID_STM32WB1x = 0x4940U, /* from RM0473, Rev.7 §33.4.8 and RM0478 Rev.5 §31.4.8 */ } stm32l4_device_id_e; typedef enum stm32l4_family { @@ -398,7 +398,7 @@ static stm32l4_device_info_s const stm32l4_device_info[] = { .flash_size_reg = STM32U5_FLASH_SIZE_REG, }, { - .device_id = ID_STM32U59X, + .device_id = ID_STM32U59x, .family = STM32L4_FAMILY_U5xx, .designator = "STM32U59x/5Ax", .sram1 = 786U + 64U + 832U + 832U, /* SRAM1+2+3+5 continuous */ @@ -407,7 +407,7 @@ static stm32l4_device_info_s const stm32l4_device_info[] = { .flash_size_reg = STM32U5_FLASH_SIZE_REG, }, { - .device_id = ID_STM32U5FX, + .device_id = ID_STM32U5Fx, .family = STM32L4_FAMILY_U5xx, .designator = "STM32U5Fx/5Gx", .sram1 = 786U + 64U + 832U + 832U + 512U, /* SRAM1+2+3+5+6 continuous */ @@ -416,7 +416,7 @@ static stm32l4_device_info_s const stm32l4_device_info[] = { .flash_size_reg = STM32U5_FLASH_SIZE_REG, }, { - .device_id = ID_STM32WLXX, + .device_id = ID_STM32WLxx, .family = STM32L4_FAMILY_WLxx, .designator = "STM32WLxx", .sram1 = 32U, @@ -426,7 +426,7 @@ static stm32l4_device_info_s const stm32l4_device_info[] = { .flash_size_reg = STM32L4_FLASH_SIZE_REG, }, { - .device_id = ID_STM32WBXX, + .device_id = ID_STM32WBxx, .family = STM32L4_FAMILY_WBxx, .designator = "STM32WBxx", .sram1 = 192U, @@ -436,7 +436,7 @@ static stm32l4_device_info_s const stm32l4_device_info[] = { .flash_size_reg = STM32L4_FLASH_SIZE_REG, }, { - .device_id = ID_STM32WB1X, + .device_id = ID_STM32WB1x, .family = STM32L4_FAMILY_WBxx, .designator = "STM32WB1x", .sram1 = 12U, @@ -636,12 +636,12 @@ bool stm32l4_probe(target_s *const target) target->driver = device->designator; switch (device_id) { - case ID_STM32WLXX: - case ID_STM32WBXX: - case ID_STM32WB1X: + case ID_STM32WLxx: + case ID_STM32WBxx: + case ID_STM32WB1x: if ((stm32l4_flash_read32(target, FLASH_OPTR)) & FLASH_OPTR_ESE) { DEBUG_WARN("STM32W security enabled\n"); - target->driver = device_id == ID_STM32WLXX ? "STM32WLxx (secure)" : "STM32WBxx (secure)"; + target->driver = device_id == ID_STM32WLxx ? "STM32WLxx (secure)" : "STM32WBxx (secure)"; } if (ap->apsel == 0) { /* @@ -694,7 +694,7 @@ static bool stm32l4_attach(target_s *const target) /* Now we have a base RAM map, rebuild the Flash map */ if (device->family == STM32L4_FAMILY_WBxx) { - if (device->device_id == ID_STM32WB1X) + if (device->device_id == ID_STM32WB1x) stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, flash_len * 1024U, 0x0800, UINT32_MAX); else stm32l4_add_flash(target, STM32L4_FLASH_BANK_1_BASE, flash_len * 1024U, 0x1000, UINT32_MAX); @@ -912,7 +912,7 @@ static bool stm32l4_option_write(target_s *const target, const uint32_t *const v static uint32_t stm32l4_fpec_base_addr(const target_s *const target) { - if (target->part_id == ID_STM32WLXX) + if (target->part_id == ID_STM32WLxx) return STM32WL_FPEC_BASE; return STM32L4_FPEC_BASE; } @@ -939,7 +939,7 @@ static stm32l4_option_bytes_info_s stm32l4_get_opt_bytes_info(const uint16_t par .offsets = stm32g4_opt_reg_offsets, .default_values = stm32g4_default_options_values, }; - case ID_STM32WLXX: + case ID_STM32WLxx: return (stm32l4_option_bytes_info_s){ .word_count = ARRAY_LENGTH(stm32wl_default_options_values), .offsets = stm32wl_opt_reg_offsets, @@ -977,11 +977,11 @@ static bool stm32l4_cmd_option(target_s *target, int argc, const char **argv) tc_printf(target, "%s options not implemented!\n", "STM32L5"); return false; } - if (target->part_id == ID_STM32WBXX || target->part_id == ID_STM32WB1X) { + if (target->part_id == ID_STM32WBxx || target->part_id == ID_STM32WB1x) { tc_printf(target, "%s options not implemented!\n", "STM32WBxx"); return false; } - if (target->part_id == ID_STM32WLXX) { + if (target->part_id == ID_STM32WLxx) { tc_printf(target, "%s options not implemented!\n", "STM32WLxx"); return false; } From 62d7ffdc1f503bb52c63ef64de673215cd18394a Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 1 Aug 2024 08:15:12 +0100 Subject: [PATCH 45/47] stm32l4: Corrected the STM32U5 handling to pull the device ID from the correct location to get a valid identification on the part --- src/target/stm32l4.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index 6208ce70f45..85032bff40f 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -620,11 +620,14 @@ static bool stm32l4_configure_dbgmcu(target_s *const target, const stm32l4_devic bool stm32l4_probe(target_s *const target) { adiv5_access_port_s *const ap = cortex_ap(target); - uint32_t device_id = ap->dp->version >= 2U ? ap->dp->target_partno : ap->partno; - /* If the part is DPv0 or DPv1, we must use the L4 ID register, except if we've already identified an L5 part */ - if (ap->dp->version < 2U && device_id != ID_STM32L55) + uint16_t device_id = ap->dp->version >= 2U ? ap->dp->target_partno : ap->partno; + /* + * If the part is DPv0 or DPv1, we must use the L4 ID register, except if we've already identified + * a L5 part or a U5 part of some sort (there are 4 IDs for these parts) + */ + if (ap->dp->version < 2U && device_id != ID_STM32L55 && device_id != ID_STM32U535 && device_id != ID_STM32U575 && + device_id != ID_STM32U59x && device_id != ID_STM32U5Fx) device_id = target_mem32_read32(target, STM32L4_DBGMCU_IDCODE) & 0xfffU; - DEBUG_INFO("ID Code: %08" PRIx32 "\n", device_id); const stm32l4_device_info_s *device = stm32l4_get_device_info(device_id); /* @@ -634,6 +637,7 @@ bool stm32l4_probe(target_s *const target) if (!device->device_id || !stm32l4_configure_dbgmcu(target, device)) return false; + target->part_id = device_id; target->driver = device->designator; switch (device_id) { case ID_STM32WLxx: From 559bb7f5a5f3b9e0c0a3f2ddd22a2114e7b3fb7d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 1 Aug 2024 08:25:26 +0100 Subject: [PATCH 46/47] stm32l4: Correct handling of STM32U5 family devices for their DBGMCU register pokes --- src/target/stm32l4.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index 85032bff40f..da028c0b3bc 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -589,7 +589,8 @@ static bool stm32l4_configure_dbgmcu(target_s *const target, const stm32l4_devic priv_storage->device = device; /* Get the current value of the debug config register (and store it for later) */ const target_addr32_t dbgmcu_config_taddr = - device->family == STM32L4_FAMILY_L55x ? STM32L5_DBGMCU_CONFIG : STM32L4_DBGMCU_CONFIG; + (device->family == STM32L4_FAMILY_L55x || device->family == STM32L4_FAMILY_U5xx) ? STM32L5_DBGMCU_CONFIG : + STM32L4_DBGMCU_CONFIG; priv_storage->dbgmcu_config = target_mem32_read32(target, dbgmcu_config_taddr); target->target_storage = priv_storage; @@ -602,7 +603,7 @@ static bool stm32l4_configure_dbgmcu(target_s *const target, const stm32l4_devic * Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us, * then Reconfigure the config register to prevent WFI/WFE from cutting debug access */ - if (device->family == STM32L4_FAMILY_L55x) { + if (device->family == STM32L4_FAMILY_L55x || device->family == STM32L4_FAMILY_U5xx) { target_mem32_write32( target, STM32L5_DBGMCU_APB1FREEZE1, STM32L4_DBGMCU_APB1FREEZE1_IWDG | STM32L4_DBGMCU_APB1FREEZE1_WWDG); target_mem32_write32(target, STM32L5_DBGMCU_CONFIG, @@ -773,8 +774,10 @@ static void stm32l4_detach(target_s *const target) const stm32l4_priv_s *const priv = (stm32l4_priv_s *)target->target_storage; const stm32l4_device_info_s *const device = priv->device; - /*reverse all changes to DBGMCU_CR*/ - target_mem32_write32(target, device->family == STM32L4_FAMILY_L55x ? STM32L5_DBGMCU_CONFIG : STM32L4_DBGMCU_CONFIG, + /* Reverse all changes to the appropriate STM32Lx_DBGMCU_CONFIG */ + target_mem32_write32(target, + device->family == STM32L4_FAMILY_L55x || device->family == STM32L4_FAMILY_U5xx ? STM32L5_DBGMCU_CONFIG : + STM32L4_DBGMCU_CONFIG, priv->dbgmcu_config); cortexm_detach(target); } From c4785d056b9553c5a7d5f6c18c2bbcef99870d13 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 6 Aug 2024 19:01:41 +0100 Subject: [PATCH 47/47] stm32h7: Nomenclature corrections for the DBGMCU definitions --- src/target/stm32h7.c | 56 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/target/stm32h7.c b/src/target/stm32h7.c index ec0f9166c57..143e2a30b3d 100644 --- a/src/target/stm32h7.c +++ b/src/target/stm32h7.c @@ -134,21 +134,21 @@ * Base address for the DBGMCU peripehral for access from the processor * address space. For access via AP2, use base address 0xe00e1000. */ -#define DBGMCU_BASE 0x5c001000U -#define DBGMCU_IDCODE (DBGMCU_BASE + 0x000U) -#define DBGMCU_CONFIG (DBGMCU_BASE + 0x004U) -#define DBGMCU_APB3FREEZE (DBGMCU_BASE + 0x034U) -#define DBGMCU_APB4FREEZE (DBGMCU_BASE + 0x054U) - -#define DBGMCU_CONFIG_DBGSLEEP_D1 (1U << 0U) -#define DBGMCU_CONFIG_DBGSTOP_D1 (1U << 1U) -#define DBGMCU_CONFIG_DBGSTBY_D1 (1U << 2U) -#define DBGMCU_CONFIG_DBGSTOP_D3 (1U << 7U) -#define DBGMCU_CONFIG_DBGSTBY_D3 (1U << 8U) -#define DBGMCU_CONFIG_D1DBGCKEN (1U << 21U) -#define DBGMCU_CONFIG_D3DBGCKEN (1U << 22U) -#define DBGMCU_APB3FREEZE_WWDG1 (1U << 6U) -#define DBGMCU_APB4FREEZE_IWDG1 (1U << 18U) +#define STM32H7_DBGMCU_BASE 0x5c001000U +#define STM32H7_DBGMCU_IDCODE (STM32H7_DBGMCU_BASE + 0x000U) +#define STM32H7_DBGMCU_CONFIG (STM32H7_DBGMCU_BASE + 0x004U) +#define STM32H7_DBGMCU_APB3FREEZE (STM32H7_DBGMCU_BASE + 0x034U) +#define STM32H7_DBGMCU_APB4FREEZE (STM32H7_DBGMCU_BASE + 0x054U) + +#define STM32H7_DBGMCU_CONFIG_DBGSLEEP_D1 (1U << 0U) +#define STM32H7_DBGMCU_CONFIG_DBGSTOP_D1 (1U << 1U) +#define STM32H7_DBGMCU_CONFIG_DBGSTBY_D1 (1U << 2U) +#define STM32H7_DBGMCU_CONFIG_DBGSTOP_D3 (1U << 7U) +#define STM32H7_DBGMCU_CONFIG_DBGSTBY_D3 (1U << 8U) +#define STM32H7_DBGMCU_CONFIG_D1DBGCKEN (1U << 21U) +#define STM32H7_DBGMCU_CONFIG_D3DBGCKEN (1U << 22U) +#define STM32H7_DBGMCU_APB3FREEZE_WWDG1 (1U << 6U) +#define STM32H7_DBGMCU_APB4FREEZE_IWDG1 (1U << 18U) #define STM32H7_DBGMCU_IDCODE_DEV_MASK 0x00000fffU #define STM32H7_DBGMCU_IDCODE_REV_SHIFT 16U @@ -262,9 +262,9 @@ bool stm32h7_probe(target_s *target) return false; /* By now it's established that this is likely an H7, but check that it's not an MP15x_CM4 with an errata in AP part code */ - const uint32_t idcode = target_mem32_read32(target, DBGMCU_IDCODE); + const uint32_t idcode = target_mem32_read32(target, STM32H7_DBGMCU_IDCODE); const uint16_t dev_id = idcode & STM32H7_DBGMCU_IDCODE_DEV_MASK; - DEBUG_TARGET("%s: looking at device ID 0x%03x at 0x%08" PRIx32 "\n", __func__, dev_id, DBGMCU_IDCODE); + DEBUG_TARGET("%s: looking at device ID 0x%03x at 0x%08" PRIx32 "\n", __func__, dev_id, STM32H7_DBGMCU_IDCODE); /* MP15x_CM4 errata: has a partno of 0x450. SoC DBGMCU says 0x500. */ if (dev_id != ID_STM32H72x && dev_id != ID_STM32H74x && dev_id != ID_STM32H7Bx) return false; @@ -277,7 +277,7 @@ bool stm32h7_probe(target_s *target) DEBUG_ERROR("calloc: failed in %s\n", __func__); return false; } - priv_storage->dbgmcu_config = target_mem32_read32(target, DBGMCU_CONFIG); + priv_storage->dbgmcu_config = target_mem32_read32(target, STM32H7_DBGMCU_CONFIG); target->target_storage = priv_storage; memcpy(priv_storage->name, "STM32", 5U); @@ -304,15 +304,15 @@ bool stm32h7_probe(target_s *target) target_add_commands(target, stm32h7_cmd_list, target->driver); /* Now we have a stable debug environment, make sure the WDTs can't bonk the processor out from under us */ - target_mem32_write32(target, DBGMCU_APB3FREEZE, DBGMCU_APB3FREEZE_WWDG1); - target_mem32_write32(target, DBGMCU_APB4FREEZE, DBGMCU_APB4FREEZE_IWDG1); + target_mem32_write32(target, STM32H7_DBGMCU_APB3FREEZE, STM32H7_DBGMCU_APB3FREEZE_WWDG1); + target_mem32_write32(target, STM32H7_DBGMCU_APB4FREEZE, STM32H7_DBGMCU_APB4FREEZE_IWDG1); /* * Make sure that both domain D1 and D3 debugging are enabled and that we can keep * debugging through sleep, stop and standby states for domain D1 */ - target_mem32_write32(target, DBGMCU_CONFIG, - priv_storage->dbgmcu_config | DBGMCU_CONFIG_DBGSLEEP_D1 | DBGMCU_CONFIG_DBGSTOP_D1 | DBGMCU_CONFIG_DBGSTBY_D1 | - DBGMCU_CONFIG_D1DBGCKEN | DBGMCU_CONFIG_D3DBGCKEN); + target_mem32_write32(target, STM32H7_DBGMCU_CONFIG, + priv_storage->dbgmcu_config | STM32H7_DBGMCU_CONFIG_DBGSLEEP_D1 | STM32H7_DBGMCU_CONFIG_DBGSTOP_D1 | + STM32H7_DBGMCU_CONFIG_DBGSTBY_D1 | STM32H7_DBGMCU_CONFIG_D1DBGCKEN | STM32H7_DBGMCU_CONFIG_D3DBGCKEN); stm32h7_configure_wdts(target); /* Build the RAM map */ @@ -412,9 +412,9 @@ static bool stm32h7_attach(target_s *target) * Make sure that both domain D1 and D3 debugging are enabled and that we can keep * debugging through sleep, stop and standby states for domain D1 - this is duplicated as it's undone by detach. */ - target_mem32_write32(target, DBGMCU_CONFIG, - DBGMCU_CONFIG_DBGSLEEP_D1 | DBGMCU_CONFIG_DBGSTOP_D1 | DBGMCU_CONFIG_DBGSTBY_D1 | DBGMCU_CONFIG_D1DBGCKEN | - DBGMCU_CONFIG_D3DBGCKEN); + target_mem32_write32(target, STM32H7_DBGMCU_CONFIG, + STM32H7_DBGMCU_CONFIG_DBGSLEEP_D1 | STM32H7_DBGMCU_CONFIG_DBGSTOP_D1 | STM32H7_DBGMCU_CONFIG_DBGSTBY_D1 | + STM32H7_DBGMCU_CONFIG_D1DBGCKEN | STM32H7_DBGMCU_CONFIG_D3DBGCKEN); stm32h7_configure_wdts(target); return true; } @@ -422,7 +422,7 @@ static bool stm32h7_attach(target_s *target) static void stm32h7_detach(target_s *target) { stm32h7_priv_s *priv = (stm32h7_priv_s *)target->target_storage; - target_mem32_write32(target, DBGMCU_CONFIG, priv->dbgmcu_config); + target_mem32_write32(target, STM32H7_DBGMCU_CONFIG, priv->dbgmcu_config); cortexm_detach(target); } @@ -733,7 +733,7 @@ static bool stm32h7_cmd_rev(target_s *target, int argc, const char **argv) { (void)argc; (void)argv; - const uint32_t idcode = target_mem32_read32(target, DBGMCU_IDCODE); + const uint32_t idcode = target_mem32_read32(target, STM32H7_DBGMCU_IDCODE); const uint16_t rev_id = idcode >> STM32H7_DBGMCU_IDCODE_REV_SHIFT; const uint16_t dev_id = idcode & STM32H7_DBGMCU_IDCODE_DEV_MASK;