From e5be10270461f2a0199804c3ae33bab2af156f9b Mon Sep 17 00:00:00 2001
From: Rick van Rein <rick@openfortress.nl>
Date: Tue, 24 Oct 2023 16:34:07 +0200
Subject: [PATCH] Write and erase flash when the Internal RC Oscillator is off
 - By first enabling it - This worked for me on STM32F103 - Quite likely not
 the best structure - Willing to take instructions, or hand it over

Fixed the check to include HSIRDY alongside HSION
- When writing HSION, the HSIRDY takes some time to come up
- This may in theory have delays
- It is entirely proper to check the bits together; they are "ist & soll"
---
 inc/stm32.h                   |  1 +
 src/stlink-lib/common_flash.c | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/inc/stm32.h b/inc/stm32.h
index cf9a8a2ad..902977655 100644
--- a/inc/stm32.h
+++ b/inc/stm32.h
@@ -189,6 +189,7 @@ enum stm32_chipids {
 #define STM32WB_DBGMCU_APB1FZR1_WWDG_STOP 11
 #define STM32WB_DBGMCU_APB1FZR1_IWDG_STOP 12
 
+#define STM32F1_RCC_CR 0x40021000
 #define STM32F1_RCC_AHBENR 0x40021014
 #define STM32F1_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
 
diff --git a/src/stlink-lib/common_flash.c b/src/stlink-lib/common_flash.c
index 3038b53e7..4cdaf4916 100644
--- a/src/stlink-lib/common_flash.c
+++ b/src/stlink-lib/common_flash.c
@@ -424,6 +424,9 @@ static void unlock_flash(stlink_t *sl) {
   uint32_t key_reg, key2_reg = 0;
   uint32_t flash_key1 = FLASH_KEY1;
   uint32_t flash_key2 = FLASH_KEY2;
+  uint32_t clk_reg = 0;
+  uint32_t hsion  = 0x00000001;
+  uint32_t hsirdy = 0x00000002;
   /* The unlock sequence consists of 2 write cycles where 2 key values are
    * written to the FLASH_KEYR register. An invalid sequence results in a
    * definitive lock of the FPEC block until next reset.
@@ -431,6 +434,7 @@ static void unlock_flash(stlink_t *sl) {
 
   if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) {
     key_reg = FLASH_KEYR;
+    clk_reg = STM32F1_RCC_CR;
   } else if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
     key_reg = FLASH_KEYR;
     key2_reg = FLASH_KEYR2;
@@ -468,6 +472,22 @@ static void unlock_flash(stlink_t *sl) {
     return;
   }
 
+  /* First make sure that the HSI is running, the internal RC clock.
+   * This is a requisite for flash erase and write.
+   */
+  if (clk_reg) {
+    uint32_t oldcr;
+    stlink_read_debug32 (sl, clk_reg, &oldcr);
+    while (0 != ((hsion | hsirdy) & ~oldcr)) {
+      stlink_write_debug32 (sl, clk_reg, oldcr | hsion);
+      stlink_read_debug32 (sl, clk_reg, &oldcr);
+    }
+  } else {
+    WLOG("unsure about internal oscillator activity, flash write and erase may block\n");
+  }
+
+  /* Now unlock the flash itself.
+   */
   stlink_write_debug32(sl, key_reg, flash_key1);
   stlink_write_debug32(sl, key_reg, flash_key2);