flash/stm32l4x: add support of STM32G0Bx/G0Cx devices
authorTarek BOCHKATI <tarek.bouchkati@gmail.com>
Tue, 19 Jan 2021 12:26:48 +0000 (13:26 +0100)
committerOleksij Rempel <linux@rempel-privat.de>
Thu, 26 Aug 2021 06:38:17 +0000 (06:38 +0000)
this device has a dual bank flash architecture up to 512 KB (page 2KB)
reference: RM0444 Rev 5

notes:
 - 128k variant is always single bank
 - 256k variant flash is contiguous (no gap) in dual bank mode
 - BKER is bit 13 vs bit 11 for other devices
   > added cr_bker_mask in stm32l4_flash_bank struct
 - BSY2 for bank 2 operations
   > added sr_bsy_mask in stm32l4_flash_bank struct
   > proposed optimization: always wait for (BSY1 | BSY2) with
     STM32G0Bx/G0Cx devices only (for L4+ devices BSY2=PEMPTY)

TODO: update flashloader to use the proper BSY bits
      temporarily don't use the loader in dual bank mode

Change-Id: I54b0c93b494e7209da818791d15edd8cd42c2732
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6036
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Tested-by: jenkins
src/flash/nor/stm32l4x.c
src/flash/nor/stm32l4x.h

index 32dff35e021c9190ecf2ae4196016a811f875305..ff804bbaf90b22d092af384c644041f36f74676d 100644 (file)
@@ -218,6 +218,8 @@ struct stm32l4_flash_bank {
        bool dual_bank_mode;
        int hole_sectors;
        uint32_t user_bank_size;
+       uint32_t cr_bker_mask;
+       uint32_t sr_bsy_mask;
        uint32_t wrpxxr_mask;
        const struct stm32l4_part_info *part_info;
        uint32_t flash_regs_base;
@@ -275,6 +277,10 @@ static const struct stm32l4_rev stm32_466_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" },
 };
 
+static const struct stm32l4_rev stm32_467_revs[] = {
+       { 0x1000, "A" },
+};
+
 static const struct stm32l4_rev stm32_468_revs[] = {
        { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
 };
@@ -396,6 +402,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
        },
+       {
+         .id                    = 0x467,
+         .revs                  = stm32_467_revs,
+         .num_revs              = ARRAY_SIZE(stm32_467_revs),
+         .device_str            = "STM32G0Bx/G0Cx",
+         .max_flash_size_kb     = 512,
+         .flags                 = F_HAS_DUAL_BANK,
+         .flash_regs_base       = 0x40022000,
+         .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
        {
          .id                    = 0x468,
          .revs                  = stm32_468_revs,
@@ -691,6 +709,7 @@ static inline int stm32l4_write_flash_reg_by_index(struct flash_bank *bank,
 
 static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
 {
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        uint32_t status;
        int retval = ERROR_OK;
 
@@ -700,7 +719,7 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
                if (retval != ERROR_OK)
                        return retval;
                LOG_DEBUG("status: 0x%" PRIx32 "", status);
-               if ((status & FLASH_BSY) == 0)
+               if ((status & stm32l4_info->sr_bsy_mask) == 0)
                        break;
                if (timeout-- <= 0) {
                        LOG_ERROR("timed out waiting for flash");
@@ -1092,7 +1111,7 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
                if (i >= stm32l4_info->bank1_sectors) {
                        uint8_t snb;
                        snb = i - stm32l4_info->bank1_sectors;
-                       erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER;
+                       erase_flags |= snb << FLASH_PAGE_SHIFT | stm32l4_info->cr_bker_mask;
                } else
                        erase_flags |= i << FLASH_PAGE_SHIFT;
                retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, erase_flags);
@@ -1463,7 +1482,18 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
        if (retval != ERROR_OK)
                goto err_lock;
 
-       if (stm32l4_info->use_flashloader) {
+       /**
+        * FIXME update the flash loader to use a custom FLASH_SR_BSY mask
+        * Workaround for STM32G0Bx/G0Cx devices in dual bank mode,
+        * as the flash loader does not use the SR_BSY2
+        */
+       bool use_flashloader = stm32l4_info->use_flashloader;
+       if ((stm32l4_info->part_info->id == 0x467) && stm32l4_info->dual_bank_mode) {
+               LOG_INFO("Couldn't use the flash loader in dual-bank mode");
+               use_flashloader = false;
+       }
+
+       if (use_flashloader) {
                /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5,
                 * the debug is possible only in non-secure state.
                 * Thus means the flashloader will run in non-secure mode,
@@ -1474,7 +1504,7 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
                retval = stm32l4_write_block(bank, buffer, offset, count / 8);
        }
 
-       if (!stm32l4_info->use_flashloader || retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+       if (!use_flashloader || retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
                LOG_INFO("falling back to single memory accesses");
                retval = stm32l4_write_block_without_loader(bank, buffer, offset, count / 8);
        }
@@ -1573,6 +1603,8 @@ static int stm32l4_probe(struct flash_bank *bank)
                        stm32l4_info->idcode, part_info->device_str, rev_str, rev_id);
 
        stm32l4_info->flash_regs_base = stm32l4_info->part_info->flash_regs_base;
+       stm32l4_info->cr_bker_mask = FLASH_BKER;
+       stm32l4_info->sr_bsy_mask = FLASH_BSY;
 
        /* initialise the flash registers layout */
        if (part_info->flags & F_HAS_L5_FLASH_REGS)
@@ -1696,6 +1728,20 @@ static int stm32l4_probe(struct flash_bank *bank)
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
                break;
+       case 0x467: /* STM32G0B/G0Cxx */
+               /* single/dual bank depending on bit(21) */
+               page_size_kb = 2;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+               stm32l4_info->cr_bker_mask = FLASH_BKER_G0;
+
+               /* check DUAL_BANK bit */
+               if (stm32l4_info->optr & BIT(21)) {
+                       stm32l4_info->sr_bsy_mask = FLASH_BSY | FLASH_BSY2;
+                       stm32l4_info->dual_bank_mode = true;
+                       stm32l4_info->bank1_sectors = num_pages / 2;
+               }
+               break;
        case 0x469: /* STM32G47/G48xx */
                /* STM32G47/8 can be single/dual bank:
                 *   if DUAL_BANK = 0 -> single bank
index b8f3d8c5be724277f9b9b16e1720b1d35212e0e6..ba809ff407eaa943370eea718c4fff0e5d2be0ec 100644 (file)
@@ -24,7 +24,8 @@
 #define FLASH_PER                              (1 << 1)
 #define FLASH_MER1                             (1 << 2)
 #define FLASH_PAGE_SHIFT               3
-#define FLASH_CR_BKER                  (1 << 11)
+#define FLASH_BKER                             (1 << 11)
+#define FLASH_BKER_G0                  (1 << 13)
 #define FLASH_MER2                             (1 << 15)
 #define FLASH_STRT                             (1 << 16)
 #define FLASH_OPTSTRT                  (1 << 17)
@@ -36,6 +37,7 @@
 
 /* FLASH_SR register bits */
 #define FLASH_BSY                              (1 << 16)
+#define FLASH_BSY2                             (1 << 17)
 
 /* Fast programming not used => related errors not used*/
 #define FLASH_PGSERR                   (1 << 7) /* Programming sequence error */