From a0fe6b3b2c13e0284df80c1f56d90486a99dba42 Mon Sep 17 00:00:00 2001
From: Andreas Fritiofson <andreas.fritiofson@unjo.com>
Date: Wed, 12 Jun 2024 18:26:39 +0200
Subject: [PATCH 1/2] Add support for STM32H750

Same as STM32H743 but with only one flash sector of 128K.

Adding a new builtin target because the Keil.STM32H7xx CMSIS Pack flash
loader is broken for at least this sub-family.
---
 pyocd/target/builtin/__init__.py           |   2 +
 pyocd/target/builtin/target_STM32H750xx.py | 341 +++++++++++++++++++++
 2 files changed, 343 insertions(+)
 create mode 100644 pyocd/target/builtin/target_STM32H750xx.py

diff --git a/pyocd/target/builtin/__init__.py b/pyocd/target/builtin/__init__.py
index 7530ccbc7..2d1d00b3c 100644
--- a/pyocd/target/builtin/__init__.py
+++ b/pyocd/target/builtin/__init__.py
@@ -134,6 +134,7 @@
 from . import target_ytm32b1md1
 from . import target_STM32H723xx
 from . import target_STM32H743xx
+from . import target_STM32H750xx
 from . import target_STM32H7B0xx
 from . import target_Air001
 from . import target_Air32F103xx
@@ -225,6 +226,7 @@
           'stm32l031x6' : target_STM32L031x6.STM32L031x6,
           'stm32h723xx' : target_STM32H723xx.STM32H723xx,
           'stm32h743xx' : target_STM32H743xx.STM32H743xx,
+          'stm32h750xx' : target_STM32H750xx.STM32H750xx,
           'stm32h7b0xx' : target_STM32H7B0xx.STM32H7B0xx,
           'w7500': target_w7500.W7500,
           's5js100': target_s5js100.S5JS100,
diff --git a/pyocd/target/builtin/target_STM32H750xx.py b/pyocd/target/builtin/target_STM32H750xx.py
new file mode 100644
index 000000000..3b52790de
--- /dev/null
+++ b/pyocd/target/builtin/target_STM32H750xx.py
@@ -0,0 +1,341 @@
+# pyOCD debugger
+# Copyright (c) 2024 Andreas Fritiofson
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import time
+import logging
+from ...coresight.coresight_target import CoreSightTarget
+from ...core.memory_map import (FlashRegion, RamRegion, MemoryMap)
+from ...coresight.cortex_m import CortexM
+from ...coresight.minimal_mem_ap import MinimalMemAP as MiniAP
+
+LOG = logging.getLogger(__name__)
+
+class DBGMCU:
+
+    # Via APB-ap (AP2)
+    #BASE =   0xe00e1000
+    # via AHB-ap (AP0,1)
+    BASE =   0x5c001000
+
+    IDC =  BASE + 0x000
+    CR =   BASE + 0x004
+    CR_VALUE = (0x3f | # keep running in stop sleep and standby
+               0x07 << 20 | # enable all debug components
+               0x07
+               )
+
+    ABP3 = BASE + 0x034
+
+class FlashPeripheral:
+    def __init__(self, bank=0):
+        assert bank < 1, "only one bank on this device"
+
+        # only per-bank registers are offset
+        offset = 0x100 if bank == 1 else 0
+        self.bank = bank
+        self.flashaddr = 0x2000+0x12000000+0x40000000
+        self.flash_keyr      = self.flashaddr + 0x04 + offset
+        self.flash_optkeyr   = self.flashaddr + 0x08
+        self.flash_optcr     = self.flashaddr + 0x18
+        self.flash_cr        = self.flashaddr + 0x0c + offset
+        self.flash_sr        = self.flashaddr + 0x10 + offset
+        self.flash_optsr_cur = self.flashaddr + 0x1c + offset
+        self.flash_optsr_prg = self.flashaddr + 0x20 + offset
+
+
+
+FLASH_ALGO = {
+    'load_address' : 0x20000000,
+
+    # Flash algorithm as a hex string
+    'instructions': [
+    0xe7fdbe00,
+    0x8f4ff3bf, 0xf64a4770, 0x49fe20aa, 0x10406008, 0x20066008, 0x60081d09, 0x20aaf64a, 0x600849fa,
+    0x60081040, 0x1d092006, 0xf2406008, 0x49f710ff, 0x207f6008, 0x60081f09, 0xb5104770, 0x460c4603,
+    0xf44fb672, 0x49f27080, 0x20076008, 0x600849f1, 0x00def44f, 0xbf006148, 0x690048ee, 0x0004f000,
+    0xd1f92800, 0x68c048eb, 0x0001f000, 0x48eab120, 0x604849e8, 0x604848e9, 0x00def44f, 0x600849e8,
+    0x48e7bf00, 0x68001f00, 0x0004f000, 0xd1f82800, 0x380848e3, 0xf0006800, 0xb1380001, 0x49e048de,
+    0x60083910, 0x49db48dd, 0x0104f8c1, 0xffabf7ff, 0x49d848dc, 0x49da6148, 0x20006008, 0x4601bd10,
+    0x47702000, 0x49d348d8, 0xbf006148, 0x690048d1, 0x0004f000, 0xd1f92800, 0x49d148d3, 0xbf006008,
+    0x1f0048cf, 0xf0006800, 0x28000004, 0xbf00d1f8, 0x690048c8, 0x0004f000, 0xd1f92800, 0x68c048c5,
+    0x0030f020, 0x60c849c3, 0x68c04608, 0x0008f040, 0x460860c8, 0xf04068c0, 0x60c80080, 0x48bdbf00,
+    0xf0006900, 0x28000004, 0x48bad1f9, 0xf02068c0, 0x49b80008, 0xbf0060c8, 0x1f0048b9, 0xf0006800,
+    0x28000004, 0x48b6d1f8, 0x68003808, 0x0030f020, 0xf8c149b0, 0x4608010c, 0x010cf8d0, 0x0008f040,
+    0x010cf8c1, 0xf8d04608, 0xf040010c, 0xf8c10080, 0xbf00010c, 0x1f0048aa, 0xf0006800, 0x28000004,
+    0x48a7d1f8, 0x68003808, 0x0008f020, 0xf8c149a1, 0x2000010c, 0xb5704770, 0x461a4603, 0x3600f503,
+    0xe0922400, 0x4543f3c2, 0x6f00f1b2, 0xf1b2d33f, 0xd23c6f01, 0x69404897, 0x310e499b, 0x49954308,
+    0xe0016148, 0xff1ff7ff, 0x69004892, 0x0004f000, 0xd1f72800, 0x68c0488f, 0x7130f647, 0x498d4388,
+    0xf04460c8, 0xea400004, 0xf0402005, 0x68c90030, 0x49884308, 0x460860c8, 0xf04068c0, 0x60c80080,
+    0xf7ffe001, 0x4883ff00, 0xf0006900, 0x28000004, 0x4880d1f7, 0xf02068c0, 0x497e0004, 0x460860c8,
+    0xf0006900, 0x28000001, 0x2001d04c, 0x487cbd70, 0x497d6800, 0x4308310e, 0xf8c14976, 0xe0010114,
+    0xfee1f7ff, 0x1f004876, 0xf0006800, 0x28000004, 0x4873d1f6, 0x68003808, 0x7130f647, 0x496d4388,
+    0x010cf8c1, 0x0104f044, 0x0008f1a5, 0x2000ea41, 0x0030f040, 0xf8d14967, 0x4308110c, 0xf8c14965,
+    0x4608010c, 0x010cf8d0, 0x0080f040, 0x010cf8c1, 0xf7ffe001, 0x4862feb8, 0x68001f00, 0x0004f000,
+    0xd1f62800, 0x3808485e, 0xf0206800, 0x49590004, 0x010cf8c1, 0x1f00485a, 0xf0006800, 0xb1080001,
+    0xe7b32001, 0x3200f502, 0x42b2bf00, 0xaf6af67f, 0xe7ab2000, 0x4df7e92d, 0x46924605, 0x9c01462f,
+    0x46d0463a, 0xf1b72300, 0xd30a6f00, 0x6f01f1b7, 0x4848d207, 0x494c6940, 0x4308310e, 0x61484945,
+    0x4847e007, 0x49486800, 0x4308310e, 0xf8c14941, 0xe0ae0114, 0xfe77f7ff, 0x6f00f1b2, 0xf1b2d30a,
+    0xd2076f01, 0x68c0483b, 0x7130f647, 0x49394388, 0xe00860c8, 0x3808483a, 0xf6476800, 0x43887130,
+    0xf8c14934, 0xf1b2010c, 0xd3066f00, 0x6f01f1b2, 0x2032d203, 0x60c8492f, 0x2032e003, 0x39084930,
+    0x2c206008, 0x2300d30f, 0xf8d8e009, 0xf8d81000, 0x60110004, 0xf1086050, 0x32080808, 0x2b041c5b,
+    0x3c20dbf3, 0x4616e015, 0x230046c3, 0xf81be004, 0xf8060b01, 0x1c5b0b01, 0xd3f842a3, 0xe0032300,
+    0xf80620ff, 0x1c5b0b01, 0x0020f1c4, 0xd8f74298, 0xf7ff2400, 0xf1b2fe25, 0xd30c6f00, 0x6f01f1b2,
+    0xe001d209, 0xfe1ff7ff, 0x69004812, 0x0004f000, 0xd1f72800, 0xe001e009, 0xfe15f7ff, 0x1f004810,
+    0xf0006800, 0x28000004, 0x480ad1f6, 0x20006900, 0xf1b2b358, 0xd31e6f00, 0x6f01f1b2, 0x4805d21b,
+    0xe01368c0, 0x58004800, 0x58004c00, 0x40002c04, 0x580244d4, 0x52002000, 0x45670123, 0xcdef89ab,
+    0x52002114, 0x0fee0000, 0x0fef0000, 0x0002f020, 0x60c84945, 0x4845e006, 0xf0206800, 0x49420002,
+    0x010cf8c1, 0xe8bd2000, 0xf1b28dfe, 0xd3096f00, 0x6f01f1b2, 0x483cd206, 0xf02068c0, 0x493a0002,
+    0xe00660c8, 0x68004839, 0x0002f020, 0xf8c14936, 0x2c00010c, 0xaf4ef47f, 0xe7e42000, 0x68004834,
+    0x0001f040, 0x60084932, 0x30104831, 0x49316800, 0x492f4008, 0x60083110, 0x6800482d, 0x4008492e,
+    0x6008492b, 0x68004608, 0x2080f420, 0x48286008, 0x68003010, 0x00fef420, 0x31104925, 0x20006008,
+    0x31604923, 0x48226008, 0xf0206800, 0x49200018, 0x481f6008, 0x68003010, 0x3110491d, 0x46086008,
+    0x60086800, 0x68004608, 0x7000f440, 0x05c86008, 0x6008491a, 0xb5004770, 0xf7ff2200, 0x4812fd84,
+    0xe0016902, 0x69024810, 0x0001f002, 0xd1f92800, 0x1d00480e, 0xe0026802, 0x1d00480c, 0xf0026802,
+    0x28000001, 0x4808d1f8, 0xe00168c2, 0x68c24806, 0x28002000, 0x4805d1fa, 0xe0016802, 0x68024803,
+    0x28002000, 0xbd00d1fa, 0x52002000, 0x5200210c, 0x58024400, 0xf87fc00c, 0xfef6ffff, 0xe000ed08,
+    0x00000000
+    ],
+
+    # Relative function addresses
+    'pc_init': 0x2000003f,
+    'pc_unInit': 0x200000c3,
+    'pc_program_page': 0x200002d9,
+    'pc_erase_sector': 0x2000019b,
+    'pc_eraseAll': 0x200000c9,
+
+    'static_base' : 0x20000000 + 0x00000004 + 0x00000560,
+    'begin_stack' : 0x20001d70,
+    'end_stack' : 0x20000d70,
+    'begin_data' : 0x20000000 + 0x1000,
+    'page_size' : 0x400,
+    'analyzer_supported' : False,
+    'analyzer_address' : 0x00000000,
+    # Enable double buffering
+    'page_buffers' : [
+        0x20000570,
+        0x20000970
+    ],
+    'min_program_length' : 0x400,
+
+    # Relative region addresses and sizes
+    'ro_start': 0x4,
+    'ro_size': 0x560,
+    'rw_start': 0x564,
+    'rw_size': 0x4,
+    'zi_start': 0x568,
+    'zi_size': 0x0,
+
+    # Flash information
+    'flash_start': 0x8000000,
+    'flash_size': 0x20000,
+    'sector_sizes': (
+        (0x0, 0x20000),
+    )
+}
+
+
+class STM32H750xx(CoreSightTarget):
+
+    VENDOR = "STMicroelectronics"
+
+    MEMORY_MAP = MemoryMap(
+        FlashRegion( start=0x0800_0000, length=0x2_0000, sector_size=0x2_0000,
+                                                    page_size=0x400,
+                                                    is_boot_memory=True,
+                                                    algo=FLASH_ALGO),
+
+        #ITCM
+        RamRegion(   start=0x00000000, length=0x10000,
+                  is_cachable=False,
+                  access="rwx"),
+        #DTCM
+        RamRegion(   start=0x20000000, length=0x20000,
+                  is_cachable=False,
+                  access="rw"),
+        #sram1
+        RamRegion(   start=0x30000000, length=0x20000,
+                  is_powered_on_boot=False),
+        #sram2
+        RamRegion(   start=0x30020000, length=0x20000,
+                  is_powered_on_boot=False),
+
+        #sram3
+        RamRegion(   start=0x30040000, length=0x8000,
+                  is_powered_on_boot=False),
+        #sram4
+        RamRegion(   start=0x38000000, length=0x10000),
+        )
+
+    def __init__(self, session):
+        super().__init__(session, self.MEMORY_MAP)
+
+    def assert_reset_for_connect(self):
+        self.dp.assert_reset(1)
+
+    def safe_reset_and_halt(self):
+        assert self.dp.is_reset_asserted()
+
+        # At this point we can't access full AP as it is not initialized yet.
+        # Let's create a minimalistic AP and use it.
+        ap = MiniAP(self.dp)
+        ap.init()
+
+        DEMCR_value = ap.read32(CortexM.DEMCR)
+
+        # Halt on reset.
+        ap.write32(CortexM.DEMCR,
+                   CortexM.DEMCR_VC_CORERESET |
+                   CortexM.DEMCR_TRCENA
+                   )
+        ap.write32(CortexM.DHCSR, CortexM.DBGKEY | CortexM.C_DEBUGEN)
+
+        self.dp.assert_reset(0)
+        time.sleep(0.01)
+
+        DEV_ID = ap.read32(DBGMCU.IDC) & 0xfff
+        assert DEV_ID == 0x450, f"IDC.DEV_ID 0x{DEV_ID:03x} did not match expected. 0x450"
+        ap.write32(DBGMCU.CR, DBGMCU.CR_VALUE)
+
+        CR = ap.read32(DBGMCU.CR)
+        LOG.info("CR: 0x%08x", CR)
+
+        # Restore DEMCR original value.
+        ap.write32(CortexM.DEMCR, DEMCR_value)
+
+    def create_init_sequence(self):
+        # this was copied from target_STM32F767xx.py but seems to apply here as well
+        #
+        # STM32 under some low power/broken clock states doesn't allow AHP communication.
+        # Low power modes are quite popular on stm32 (including MBed OS defaults).
+        # 'attach' mode is broken by default, as STM32 can't be connected on low-power mode
+        #  successfully without previous DBGMCU setup (It is not possible to write DBGMCU).
+        # It is also not possible to run full pyOCD discovery code under-reset.
+        #
+        # As a solution we can setup DBGMCU under reset, halt core and release reset.
+        # Unfortunately this code has to be executed _before_ discovery stage
+        # and without discovery stage we don't have access to AP/Core.
+        # As a solution we can create minimalistic AP implementation and use it
+        # to setup core halt.
+        # So the sequence for 'halt' connect mode will look like
+        # -> Assert reset
+        # -> Connect DebugPort
+        # -> Setup MiniAp
+        # -> Setup halt on reset
+        # -> Enable support for debugging in low-power modes
+        # -> Release reset
+        # -> [Core is halted and reset is released]
+        # -> Continue [discovery, create cores, etc]
+        seq = super().create_init_sequence()
+        if self.session.options.get('connect_mode') in ('halt', 'under-reset'):
+            seq.insert_before('dp_init', ('assert_reset_for_connect', self.assert_reset_for_connect))
+            seq.insert_after('dp_init', ('safe_reset_and_halt', self.safe_reset_and_halt))
+
+        return seq
+
+    def _unlock_flash_peripheral(self, flash_banks=[0]):
+
+        banks = [FlashPeripheral(n) for n in flash_banks]
+
+        LOG.info('unlocking flash peripheral')
+        self.reset_and_halt()
+
+        for bank in banks:
+            while self.read32(bank.flash_sr) & 1:
+                time.sleep(0.1)
+
+            if self.read32(bank.flash_cr) & 1 != 0:
+                self.write32(bank.flash_keyr,    0x4567_0123)
+                self.write32(bank.flash_keyr,    0xCDEF_89AB)
+                while self.read32(bank.flash_sr) & 1:
+                    time.sleep(0.1)
+
+        # shared, so only once
+        if self.read32(bank.flash_optcr) & 1 != 0:
+            self.write32(bank.flash_optkeyr, 0x0819_2A3B)
+            self.write32(bank.flash_optkeyr, 0x4C5D_6E7F)
+
+
+    def is_locked(self, flash_banks=[0]):
+        banks = [FlashPeripheral(n) for n in flash_banks]
+
+        # return true if either bank
+        for bank in banks:
+            optsr = self.read32(bank.flash_optsr_prg)
+            rdp = optsr & 0x0000_ff00
+            if rdp == 0xcc00:
+                LOG.warning(f"BANK {bank.bank} permanently locked. No unlock possible")
+            if rdp != 0xaa00:
+                return True
+        return False
+
+    def disable_read_protection(self, flash_banks=[0]):
+        self._unlock_flash_peripheral(flash_banks)
+        banks = [FlashPeripheral(n) for n in flash_banks]
+
+        for bank in banks:
+            while self.read32(bank.flash_sr) & 1:
+                time.sleep(0.1)
+
+            optsr = self.read32(bank.flash_optsr_prg)
+            self.write32(bank.flash_optsr_prg, optsr & 0xffff_00ff | 0x0000_aa00)
+
+        # on trigger on both changes
+        self.write32(bank.flash_optcr, 2)
+        while self.read32(bank.flash_sr) & 1:
+            time.sleep(0.1)
+
+        self.reset_and_halt()
+
+    def read_protect(self, flash_banks=[0]):
+        self._unlock_flash_peripheral(flash_banks)
+        banks = [FlashPeripheral(n) for n in flash_banks]
+
+        for bank in banks:
+            while self.read32(bank.flash_sr) & 1:
+                time.sleep(0.1)
+
+            optsr = self.read32(bank.flash_optsr_prg)
+            self.write32(bank.flash_optsr_prg, optsr & 0xffff_00ff)
+
+        # on trigger on both changes
+        self.write32(bank.flash_optcr, 2)
+        while self.read32(bank.flash_sr) & 1:
+            time.sleep(0.1)
+
+        self.reset_and_halt()
+
+    def mass_erase(self, flash_banks=[0]):
+        self._unlock_flash_peripheral(flash_banks)
+        banks = [FlashPeripheral(n) for n in flash_banks]
+
+        for bank in banks:
+            while self.read32(bank.flash_sr) & 1:
+                time.sleep(0.1)
+
+            self.write32(bank.flash_cr, 1<<3 | 3<<4)
+            self.write32(bank.flash_cr, 1<<3 | 3<<4 | 1<<7)
+            LOG.info("mass_erase banks %i", bank.bank)
+
+        # banks can be erased at the same time
+        # so start both,
+        # then wait for both
+        for bank in banks:
+            while self.read32(bank.flash_sr) & 1:
+                time.sleep(0.1)
+            LOG.info("mass_erase bank %i done", bank.bank)
+
+
+

From c5f7438ef7a78a7f2695517e6854bf192bea3366 Mon Sep 17 00:00:00 2001
From: Andreas Fritiofson <andreas.fritiofson@unjo.com>
Date: Wed, 12 Jun 2024 18:27:37 +0200
Subject: [PATCH 2/2] Fix sector size and RDP check on STM32H743 and H723

---
 pyocd/target/builtin/target_STM32H723xx.py |  6 +++---
 pyocd/target/builtin/target_STM32H743xx.py | 10 +++++-----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/pyocd/target/builtin/target_STM32H723xx.py b/pyocd/target/builtin/target_STM32H723xx.py
index afcf6e874..0c94c1ca4 100644
--- a/pyocd/target/builtin/target_STM32H723xx.py
+++ b/pyocd/target/builtin/target_STM32H723xx.py
@@ -120,7 +120,7 @@ class STM32H723xx(CoreSightTarget):
     VENDOR = "STMicroelectronics"
 
     MEMORY_MAP = MemoryMap(
-        FlashRegion( start=0x08000000, length=0x100000, sector_size=0x8000,
+        FlashRegion( start=0x08000000, length=0x100000, sector_size=0x20000,
                                                         page_size=0x400,
                                                         is_boot_memory=True,
                                                         algo=FLASH_ALGO),
@@ -232,9 +232,9 @@ def is_locked(self):
         bank = FlashPeripheral()
         optsr = self.read32(bank.flash_optsr_prg)
         rdp = optsr & 0x0000_ff00
-        if rdp == 0xaa:
+        if rdp == 0xaa00:
             return False;
-        if rdp == 0xcc:
+        if rdp == 0xcc00:
             LOG.warning("MCU permanently locked. No unlock possible")
         return True
 
diff --git a/pyocd/target/builtin/target_STM32H743xx.py b/pyocd/target/builtin/target_STM32H743xx.py
index 841c4c734..9379b4358 100644
--- a/pyocd/target/builtin/target_STM32H743xx.py
+++ b/pyocd/target/builtin/target_STM32H743xx.py
@@ -142,7 +142,7 @@ def __init__(self, bank=0):
     'flash_start': 0x8000000,
     'flash_size': 0x200000,
     'sector_sizes': (
-        (0x0, 0x2000),
+        (0x0, 0x20000),
     )
 }
 
@@ -152,12 +152,12 @@ class STM32H743xx(CoreSightTarget):
     VENDOR = "STMicroelectronics"
 
     MEMORY_MAP = MemoryMap(
-        FlashRegion( start=0x0800_0000, length=0x10_0000, sector_size=0x8000,
+        FlashRegion( start=0x0800_0000, length=0x10_0000, sector_size=0x2_0000,
                                                     page_size=0x400,
                                                     is_boot_memory=True,
                                                     algo=FLASH_ALGO),
 
-        FlashRegion( start=0x0810_0000, length=0x10_0000, sector_size=0x8000,
+        FlashRegion( start=0x0810_0000, length=0x10_0000, sector_size=0x2_0000,
                                                         page_size=0x400,
                                                         algo=FLASH_ALGO),
         #ITCM
@@ -278,9 +278,9 @@ def is_locked(self, flash_banks=[0,1]):
         for bank in banks:
             optsr = self.read32(bank.flash_optsr_prg)
             rdp = optsr & 0x0000_ff00
-            if rdp == 0xcc:
+            if rdp == 0xcc00:
                 LOG.warning(f"BANK {bank.bank} permanently locked. No unlock possible")
-            if rdp != 0xaa:
+            if rdp != 0xaa00:
                 return True
         return False