stm32f2x: Increase options write timeout
[openocd.git] / src / flash / nor / stm32f2x.c
index 1dee6230c488d6ce298adfde70f91ae295d8af68..4d750951ca332e237e4fe3224d0a597bb9dad3e3 100644 (file)
@@ -19,9 +19,7 @@
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
  * To reduce testing complexity and dangers of regressions,
  * a seperate file is used for stm32fx2x.
  *
- * 1mByte part with 4 x 16, 1 x 64, 7 x 128kBytes sectors
+ * Sector sizes in kiBytes:
+ * 1 MiByte part with 4 x 16, 1 x 64, 7 x 128.
+ * 2 MiByte part with 4 x 16, 1 x 64, 7 x 128, 4 x 16, 1 x 64, 7 x 128.
+ * 1 MiByte STM32F42x/43x part with DB1M Option set:
+ *                    4 x 16, 1 x 64, 3 x 128, 4 x 16, 1 x 64, 3 x 128.
  *
- * What's the protection page size???
+ * STM32F7[4|5]
+ * 1 MiByte part with 4 x 32, 1 x 128, 3 x 256.
+ *
+ * STM32F7[6|7]
+ * 1 MiByte part in single bank mode with 4 x 32, 1 x 128, 3 x 256.
+ * 1 MiByte part in dual-bank mode two banks with 4 x 16, 1 x 64, 3 x 128 each.
+ * 2 MiByte part in single-bank mode with 4 x 32, 1 x 128, 7 x 256.
+ * 2 MiByte part in dual-bank mode two banks with 4 x 16, 1 x 64, 7 x 128 each.
+ *
+ * Protection size is sector size.
  *
  * Tested with STM3220F-EVAL board.
  *
- * STM32F21xx series for reference.
+ * STM32F4xx series for reference.
  *
- * RM0033
- * http://www.st.com/internet/mcu/product/250192.jsp
+ * RM0090
+ * http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031020.pdf
  *
  * PM0059
  * www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/
  * PROGRAMMING_MANUAL/CD00233952.pdf
  *
+ * STM32F7xx series for reference.
+ *
+ * RM0385
+ * http://www.st.com/web/en/resource/technical/document/reference_manual/DM00124865.pdf
+ *
+ * RM0410
+ * http://www.st.com/resource/en/reference_manual/dm00224583.pdf
+ *
  * STM32F1x series - notice that this code was copy, pasted and knocked
  * into a stm32f2x driver, so in case something has been converted or
  * bugs haven't been fixed, here are the original manuals:
 #define FLASH_ERASE_TIMEOUT 10000
 #define FLASH_WRITE_TIMEOUT 5
 
+/* Mass erase time can be as high as 32 s in x8 mode. */
+#define FLASH_MASS_ERASE_TIMEOUT 33000
+
 #define STM32_FLASH_BASE    0x40023c00
 #define STM32_FLASH_ACR     0x40023c00
 #define STM32_FLASH_KEYR    0x40023c04
 #define STM32_FLASH_OPTCR1  0x40023c18
 
 /* FLASH_CR register bits */
-
 #define FLASH_PG       (1 << 0)
 #define FLASH_SER      (1 << 1)
-#define FLASH_MER      (1 << 2)
-#define FLASH_MER1     (1 << 15)
+#define FLASH_MER      (1 << 2)                /* MER/MER1 for f76x/77x */
+#define FLASH_MER1     (1 << 15)       /* MER2 for f76x/77x, confusing ... */
 #define FLASH_STRT     (1 << 16)
 #define FLASH_PSIZE_8  (0 << 8)
 #define FLASH_PSIZE_16 (1 << 8)
 #define FLASH_LOCK     (1 << 31)
 
 /* FLASH_SR register bits */
-
 #define FLASH_BSY      (1 << 16)
 #define FLASH_PGSERR   (1 << 7) /* Programming sequence error */
 #define FLASH_PGPERR   (1 << 6) /* Programming parallelism error */
 #define FLASH_ERROR (FLASH_PGSERR | FLASH_PGPERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR)
 
 /* STM32_FLASH_OPTCR register bits */
-
-#define OPT_LOCK      (1 << 0)
-#define OPT_START     (1 << 1)
-
-/* STM32_FLASH_OBR bit definitions (reading) */
-
-#define OPT_ERROR      0
-#define OPT_READOUT    1
-#define OPT_RDWDGSW    2
-#define OPT_RDRSTSTOP  3
-#define OPT_RDRSTSTDBY 4
-#define OPT_BFB2       5       /* dual flash bank only */
+#define OPTCR_LOCK     (1 << 0)
+#define OPTCR_START    (1 << 1)
+#define OPTCR_NDBANK   (1 << 29)       /* not dual bank mode */
+#define OPTCR_DB1M     (1 << 30)       /* 1 MiB devices dual flash bank option */
 
 /* register unlock keys */
-
 #define KEY1           0x45670123
 #define KEY2           0xCDEF89AB
 
 
 struct stm32x_options {
        uint8_t RDP;
-       uint8_t user_options;
+       uint16_t user_options;  /* bit 0-7 usual options, bit 8-11 extra options */
        uint32_t protection;
+       uint32_t boot_addr;
 };
 
 struct stm32x_flash_bank {
        struct stm32x_options option_bytes;
        int probed;
-       bool has_large_mem;             /* stm32f42x/stm32f43x family */
+       bool has_large_mem;             /* F42x/43x/469/479/7xx in dual bank mode */
+       bool has_boot_addr;     /* F7xx */
+       bool has_extra_options; /* F42x/43x/469/479/7xx */
        uint32_t user_bank_size;
 };
 
@@ -273,7 +287,7 @@ static int stm32x_unlock_option_reg(struct target *target)
        if (retval != ERROR_OK)
                return retval;
 
-       if ((ctrl & OPT_LOCK) == 0)
+       if ((ctrl & OPTCR_LOCK) == 0)
                return ERROR_OK;
 
        /* unlock option registers */
@@ -289,7 +303,7 @@ static int stm32x_unlock_option_reg(struct target *target)
        if (retval != ERROR_OK)
                return retval;
 
-       if (ctrl & OPT_LOCK) {
+       if (ctrl & OPTCR_LOCK) {
                LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: %" PRIx32, ctrl);
                return ERROR_TARGET_FAILURE;
        }
@@ -310,18 +324,30 @@ static int stm32x_read_options(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
-       stm32x_info->option_bytes.user_options = optiondata & 0xec;
+    /* caution: F2 implements 5 bits (WDG_SW only)
+     * whereas F7 6 bits (IWDG_SW and WWDG_SW) in user_options */
+       stm32x_info->option_bytes.user_options = optiondata & 0xfc;
        stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff;
        stm32x_info->option_bytes.protection = (optiondata >> 16) & 0xfff;
 
-       if (stm32x_info->has_large_mem) {
+       if (stm32x_info->has_extra_options) {
+               /* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */
+               stm32x_info->option_bytes.user_options |= (optiondata >> 20) & 0xf00;
+       }
 
+       if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) {
                retval = target_read_u32(target, STM32_FLASH_OPTCR1, &optiondata);
                if (retval != ERROR_OK)
                        return retval;
 
-               /* append protection bits */
-               stm32x_info->option_bytes.protection |= (optiondata >> 4) & 0x00fff000;
+               /* FLASH_OPTCR1 has quite diffent meanings ... */
+               if (stm32x_info->has_boot_addr) {
+                       /* for F7xx it contains boot0 and boot1 */
+                       stm32x_info->option_bytes.boot_addr = optiondata;
+               } else {
+                       /* for F42x/43x/469/479 it contains 12 additional protection bits */
+                       stm32x_info->option_bytes.protection |= (optiondata >> 4) & 0x00fff000;
+               }
        }
 
        if (stm32x_info->option_bytes.RDP != 0xAA)
@@ -334,7 +360,7 @@ static int stm32x_write_options(struct flash_bank *bank)
 {
        struct stm32x_flash_bank *stm32x_info = NULL;
        struct target *target = bank->target;
-       uint32_t optiondata;
+       uint32_t optiondata, optiondata2;
 
        stm32x_info = bank->driver_priv;
 
@@ -343,36 +369,46 @@ static int stm32x_write_options(struct flash_bank *bank)
                return retval;
 
        /* rebuild option data */
-       optiondata = stm32x_info->option_bytes.user_options;
-       buf_set_u32(&optiondata, 8, 8, stm32x_info->option_bytes.RDP);
-       buf_set_u32(&optiondata, 16, 12, stm32x_info->option_bytes.protection);
+       optiondata = stm32x_info->option_bytes.user_options & 0xfc;
+       optiondata |= stm32x_info->option_bytes.RDP << 8;
+       optiondata |= (stm32x_info->option_bytes.protection & 0x0fff) << 16;
 
-       /* program options */
-       retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata);
-       if (retval != ERROR_OK)
-               return retval;
+       if (stm32x_info->has_extra_options) {
+               /* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */
+               optiondata |= (stm32x_info->option_bytes.user_options & 0xf00) << 20;
+       }
 
-       if (stm32x_info->has_large_mem) {
+       if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) {
+               if (stm32x_info->has_boot_addr) {
+                       /* F7xx uses FLASH_OPTCR1 for boot0 and boot1 ... */
+                       optiondata2 = stm32x_info->option_bytes.boot_addr;
+               } else {
+                       /* F42x/43x/469/479 uses FLASH_OPTCR1 for additional protection bits */
+                       optiondata2 = (stm32x_info->option_bytes.protection & 0x00fff000) << 4;
+               }
 
-               uint32_t optiondata2 = 0;
-               buf_set_u32(&optiondata2, 16, 12, stm32x_info->option_bytes.protection >> 12);
                retval = target_write_u32(target, STM32_FLASH_OPTCR1, optiondata2);
                if (retval != ERROR_OK)
                        return retval;
        }
 
+       /* program options */
+       retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata);
+       if (retval != ERROR_OK)
+               return retval;
+
        /* start programming cycle */
-       retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPT_START);
+       retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPTCR_START);
        if (retval != ERROR_OK)
                return retval;
 
-       /* wait for completion */
-       retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+       /* wait for completion, this might trigger a security erase and take a while */
+       retval = stm32x_wait_status_busy(bank, FLASH_MASS_ERASE_TIMEOUT);
        if (retval != ERROR_OK)
                return retval;
 
        /* relock registers */
-       retval = target_write_u32(target, STM32_FLASH_OPTCR, OPT_LOCK);
+       retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPTCR_LOCK);
        if (retval != ERROR_OK)
                return retval;
 
@@ -390,11 +426,25 @@ static int stm32x_protect_check(struct flash_bank *bank)
                return retval;
        }
 
-       for (int i = 0; i < bank->num_sectors; i++) {
-               if (stm32x_info->option_bytes.protection & (1 << i))
-                       bank->sectors[i].is_protected = 0;
-               else
-                       bank->sectors[i].is_protected = 1;
+       if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) {
+               /* F76x/77x: bit k protects sectors 2*k and 2*k+1 */
+               for (int i = 0; i < (bank->num_sectors >> 1); i++) {
+                       if (stm32x_info->option_bytes.protection & (1 << i)) {
+                               bank->sectors[i << 1].is_protected = 0;
+                               bank->sectors[(i << 1) + 1].is_protected = 0;
+                       } else {
+                               bank->sectors[i << 1].is_protected = 1;
+                               bank->sectors[(i << 1) + 1].is_protected = 1;
+                       }
+               }
+       } else {
+               /* one protection bit per sector */
+               for (int i = 0; i < bank->num_sectors; i++) {
+                       if (stm32x_info->option_bytes.protection & (1 << i))
+                               bank->sectors[i].is_protected = 0;
+                       else
+                               bank->sectors[i].is_protected = 1;
+               }
        }
 
        return ERROR_OK;
@@ -405,8 +455,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
        struct target *target = bank->target;
        int i;
 
-       assert(first < bank->num_sectors);
-       assert(last < bank->num_sectors);
+       assert((0 <= first) && (first <= last) && (last < bank->num_sectors));
 
        if (bank->target->state != TARGET_HALTED) {
                LOG_ERROR("Target not halted");
@@ -466,8 +515,18 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
                return retval;
        }
 
-       for (int i = first; i <= last; i++) {
+       if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) {
+               /* F76x/77x: bit k protects sectors 2*k and 2*k+1 */
+               if ((first & 1) != 0 || (last & 1) != 1) {
+                       LOG_ERROR("sector protection must be double sector aligned");
+                       return ERROR_FAIL;
+               } else {
+                       first >>= 1;
+                       last >>= 1;
+               }
+       }
 
+       for (int i = first; i <= last; i++) {
                if (set)
                        stm32x_info->option_bytes.protection &= ~(1 << i);
                else
@@ -481,7 +540,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
        return ERROR_OK;
 }
 
-static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
+static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
@@ -504,10 +563,11 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
                0x47, 0x45,                                     /* cmp          r7, r8 */
                0xF7, 0xD0,                                     /* beq          wait_fifo */
 
-               0xDF, 0xF8, 0x30, 0x60,         /* ldr          r6, STM32_PROG16 */
+               0xDF, 0xF8, 0x34, 0x60,         /* ldr          r6, STM32_PROG16 */
                0x26, 0x61,                                     /* str          r6, [r4, #STM32_FLASH_CR_OFFSET] */
                0x37, 0xF8, 0x02, 0x6B,         /* ldrh         r6, [r7], #0x02 */
                0x22, 0xF8, 0x02, 0x6B,         /* strh         r6, [r2], #0x02 */
+               0xBF, 0xF3, 0x4F, 0x8F,         /* dsb          sy */
                                                                        /* busy: */
                0xE6, 0x68,                                     /* ldr          r6, [r4, #STM32_FLASH_SR_OFFSET] */
                0x16, 0xF4, 0x80, 0x3F,         /* tst          r6, #0x10000 */
@@ -521,7 +581,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
                0x47, 0x60,                                     /* str          r7, [r0, #4] */
                0x01, 0x3B,                                     /* subs         r3, r3, #1 */
                0x13, 0xB1,                                     /* cbz          r3, exit */
-               0xE1, 0xE7,                                     /* b            wait_fifo */
+               0xDF, 0xE7,                                     /* b            wait_fifo */
                                                                        /* error: */
                0x00, 0x21,                                     /* movs         r1, #0 */
                0x41, 0x60,                                     /* str          r1, [r0, #4] */
@@ -537,11 +597,11 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
                        &write_algorithm) != ERROR_OK) {
                LOG_WARNING("no working area available, can't do block memory writes");
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
+       }
 
        retval = target_write_buffer(target, write_algorithm->address,
                        sizeof(stm32x_flash_write_code),
-                       (uint8_t *)stm32x_flash_write_code);
+                       stm32x_flash_write_code);
        if (retval != ERROR_OK)
                return retval;
 
@@ -556,7 +616,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
                        LOG_WARNING("no large enough working area available, can't do block memory writes");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
-       };
+       }
 
        armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
        armv7m_info.core_mode = ARM_MODE_THREAD;
@@ -608,7 +668,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
        return retval;
 }
 
-static int stm32x_write(struct flash_bank *bank, uint8_t *buffer,
+static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
@@ -707,14 +767,31 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer,
        return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
 }
 
-static void setup_sector(struct flash_bank *bank, int start, int num, int size)
+static int setup_sector(struct flash_bank *bank, int start, int num, int size)
 {
+
        for (int i = start; i < (start + num) ; i++) {
                assert(i < bank->num_sectors);
                bank->sectors[i].offset = bank->size;
                bank->sectors[i].size = size;
                bank->size += bank->sectors[i].size;
+           LOG_DEBUG("sector %d: %dkBytes", i, size >> 10);
        }
+
+       return start + num;
+}
+
+static void setup_bank(struct flash_bank *bank, int start,
+       uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb)
+{
+       int remain;
+
+       start = setup_sector(bank, start, 4, (max_sector_size_in_kb / 8) * 1024);
+       start = setup_sector(bank, start, 1, (max_sector_size_in_kb / 2) * 1024);
+
+       /* remaining sectors all of size max_sector_size_in_kb */
+       remain = (flash_size_in_kb / max_sector_size_in_kb) - 1;
+       start = setup_sector(bank, start, remain, max_sector_size_in_kb * 1024);
 }
 
 static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
@@ -754,12 +831,16 @@ static int stm32x_probe(struct flash_bank *bank)
        struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
        int i;
        uint16_t flash_size_in_kb;
+       uint32_t flash_size_reg = 0x1FFF7A22;
+       uint16_t max_sector_size_in_kb = 128;
        uint16_t max_flash_size_in_kb;
        uint32_t device_id;
        uint32_t base_address = 0x08000000;
 
        stm32x_info->probed = 0;
        stm32x_info->has_large_mem = false;
+       stm32x_info->has_boot_addr = false;
+       stm32x_info->has_extra_options = false;
 
        /* read stm32 device id register */
        int retval = stm32x_get_device_id(bank, &device_id);
@@ -767,25 +848,57 @@ static int stm32x_probe(struct flash_bank *bank)
                return retval;
        LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
 
-       /* set max flash size depending on family */
+       /* set max flash size depending on family, id taken from AN2606 */
        switch (device_id & 0xfff) {
-       case 0x411:
-       case 0x413:
+       case 0x411: /* F20x/21x */
+       case 0x413: /* F40x/41x */
                max_flash_size_in_kb = 1024;
                break;
-       case 0x419:
+
+       case 0x419: /* F42x/43x */
+       case 0x434: /* F469/479 */
+               stm32x_info->has_extra_options = true;
                max_flash_size_in_kb = 2048;
                break;
-       case 0x423:
+
+       case 0x423:     /* F401xB/C */
                max_flash_size_in_kb = 256;
                break;
+
+       case 0x421:     /* F446 */
+       case 0x431: /* F411 */
+       case 0x433: /* F401xD/E */
+       case 0x441: /* F412 */
+               max_flash_size_in_kb = 512;
+               break;
+
+       case 0x458: /* F410 */
+               max_flash_size_in_kb = 128;
+               break;
+
+       case 0x449:     /* F74x/75x */
+               max_flash_size_in_kb = 1024;
+               max_sector_size_in_kb = 256;
+               flash_size_reg = 0x1FF0F442;
+               stm32x_info->has_extra_options = true;
+               stm32x_info->has_boot_addr = true;
+               break;
+
+       case 0x451:     /* F76x/77x */
+               max_flash_size_in_kb = 2048;
+               max_sector_size_in_kb = 256;
+               flash_size_reg = 0x1FF0F442;
+               stm32x_info->has_extra_options = true;
+               stm32x_info->has_boot_addr = true;
+               break;
+
        default:
                LOG_WARNING("Cannot identify target as a STM32 family.");
                return ERROR_FAIL;
        }
 
        /* get flash size from target. */
-       retval = target_read_u16(target, 0x1FFF7A22, &flash_size_in_kb);
+       retval = target_read_u16(target, flash_size_reg, &flash_size_in_kb);
 
        /* failed reading flash size or flash size invalid (early silicon),
         * default to max target family */
@@ -802,24 +915,53 @@ static int stm32x_probe(struct flash_bank *bank)
                flash_size_in_kb = stm32x_info->user_bank_size / 1024;
        }
 
-       /* only devices with > 1024kB have dual banks */
-       if (flash_size_in_kb > 1024)
-               stm32x_info->has_large_mem = true;
-
        LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
 
        /* did we assign flash size? */
        assert(flash_size_in_kb != 0xffff);
 
-       /* calculate numbers of pages */
-       int num_pages = (flash_size_in_kb / 128) + 4;
+       /* Devices with > 1024 kiByte always are dual-banked */
+       if (flash_size_in_kb > 1024)
+               stm32x_info->has_large_mem = true;
 
-       /* check for larger 2048 bytes devices */
-       if (stm32x_info->has_large_mem)
-               num_pages += 4;
+       /* F42x/43x/469/479 1024 kiByte devices have a dual bank option */
+       if ((device_id & 0xfff) == 0x419 || (device_id & 0xfff) == 0x434) {
+               uint32_t optiondata;
+               retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata);
+               if (retval != ERROR_OK) {
+                       LOG_DEBUG("unable to read option bytes");
+                       return retval;
+               }
+               if ((flash_size_in_kb > 1024) || (optiondata & OPTCR_DB1M)) {
+                       stm32x_info->has_large_mem = true;
+                       LOG_INFO("Dual Bank %d kiB STM32F42x/43x/469/479 found", flash_size_in_kb);
+               } else {
+                       stm32x_info->has_large_mem = false;
+                       LOG_INFO("Single Bank %d kiB STM32F42x/43x/469/479 found", flash_size_in_kb);
+               }
+       }
 
-       /* check that calculation result makes sense */
-       assert(num_pages > 0);
+       /* F76x/77x devices have a dual bank option */
+       if ((device_id & 0xfff) == 0x451) {
+               uint32_t optiondata;
+               retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata);
+               if (retval != ERROR_OK) {
+                       LOG_DEBUG("unable to read option bytes");
+                       return retval;
+               }
+               if (optiondata & OPTCR_NDBANK) {
+                       stm32x_info->has_large_mem = false;
+                       LOG_INFO("Single Bank %d kiB STM32F76x/77x found", flash_size_in_kb);
+               } else {
+                       stm32x_info->has_large_mem = true;
+                       max_sector_size_in_kb >>= 1; /* sector size divided by 2 in dual-bank mode */
+                       LOG_INFO("Dual Bank %d kiB STM32F76x/77x found", flash_size_in_kb);
+               }
+       }
+
+       /* calculate numbers of pages */
+       int num_pages = flash_size_in_kb / max_sector_size_in_kb
+               + (stm32x_info->has_large_mem ? 8 : 4);
 
        if (bank->sectors) {
                free(bank->sectors);
@@ -829,32 +971,25 @@ static int stm32x_probe(struct flash_bank *bank)
        bank->base = base_address;
        bank->num_sectors = num_pages;
        bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
-       bank->size = 0;
-
-       /* fixed memory */
-       setup_sector(bank, 0, 4, 16 * 1024);
-       setup_sector(bank, 4, 1, 64 * 1024);
-
-       /* dynamic memory */
-       setup_sector(bank, 4 + 1, MIN(12, num_pages) - 5, 128 * 1024);
-
-       if (stm32x_info->has_large_mem) {
-
-               /* fixed memory for larger devices */
-               setup_sector(bank, 12, 4, 16 * 1024);
-               setup_sector(bank, 16, 1, 64 * 1024);
-
-               /* dynamic memory for larger devices */
-               setup_sector(bank, 16 + 1, num_pages - 5 - 12, 128 * 1024);
-       }
-
        for (i = 0; i < num_pages; i++) {
                bank->sectors[i].is_erased = -1;
                bank->sectors[i].is_protected = 0;
        }
+       bank->size = 0;
+       LOG_DEBUG("allocated %d sectors", num_pages);
 
-       stm32x_info->probed = 1;
+       if (stm32x_info->has_large_mem) {
+               /* dual-bank */
+               setup_bank(bank, 0, flash_size_in_kb >> 1, max_sector_size_in_kb);
+               setup_bank(bank, num_pages >> 1, flash_size_in_kb >> 1,
+                       max_sector_size_in_kb);
+       } else {
+               /* single-bank */
+               setup_bank(bank, 0, flash_size_in_kb, max_sector_size_in_kb);
+       }
+       assert((bank->size >> 10) == flash_size_in_kb);
 
+       stm32x_info->probed = 1;
        return ERROR_OK;
 }
 
@@ -904,11 +1039,24 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
                case 0x2003:
                        rev_str = "X";
                        break;
+
+               case 0x2007:
+                       rev_str = "1";
+                       break;
+
+               case 0x200F:
+                       rev_str = "V";
+                       break;
+
+               case 0x201F:
+                       rev_str = "2";
+                       break;
                }
                break;
 
        case 0x413:
        case 0x419:
+       case 0x434:
                device_str = "STM32F4xx";
 
                switch (rev_id) {
@@ -923,10 +1071,32 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
                case 0x1003:
                        rev_str = "Y";
                        break;
+
+               case 0x1007:
+                       rev_str = "1";
+                       break;
+
+               case 0x2001:
+                       rev_str = "3";
+                       break;
+               }
+               break;
+
+       case 0x421:
+               device_str = "STM32F446";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
                }
                break;
 
        case 0x423:
+       case 0x431:
+       case 0x433:
+       case 0x458:
+       case 0x441:
                device_str = "STM32F4xx (Low Power)";
 
                switch (rev_id) {
@@ -940,8 +1110,32 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
                }
                break;
 
+       case 0x449:
+               device_str = "STM32F7[4|5]x";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+
+               case 0x1001:
+                       rev_str = "Z";
+                       break;
+               }
+               break;
+
+       case 0x451:
+               device_str = "STM32F7[6|7]x";
+
+               switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+               }
+               break;
+
        default:
-               snprintf(buf, buf_size, "Cannot identify target as a STM32F2/4\n");
+               snprintf(buf, buf_size, "Cannot identify target as a STM32F2/4/7\n");
                return ERROR_FAIL;
        }
 
@@ -1037,6 +1231,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
 static int stm32x_mass_erase(struct flash_bank *bank)
 {
        int retval;
+       uint32_t flash_mer;
        struct target *target = bank->target;
        struct stm32x_flash_bank *stm32x_info = NULL;
 
@@ -1053,17 +1248,19 @@ static int stm32x_mass_erase(struct flash_bank *bank)
 
        /* mass erase flash memory */
        if (stm32x_info->has_large_mem)
-               retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_MER1);
+               flash_mer = FLASH_MER | FLASH_MER1;
        else
-               retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER);
+               flash_mer = FLASH_MER;
+
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), flash_mer);
        if (retval != ERROR_OK)
                return retval;
        retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR),
-               FLASH_MER | FLASH_STRT);
+               flash_mer | FLASH_STRT);
        if (retval != ERROR_OK)
                return retval;
 
-       retval = stm32x_wait_status_busy(bank, 30000);
+       retval = stm32x_wait_status_busy(bank, FLASH_MASS_ERASE_TIMEOUT);
        if (retval != ERROR_OK)
                return retval;
 
@@ -1102,6 +1299,107 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
        return retval;
 }
 
+COMMAND_HANDLER(stm32f2x_handle_options_read_command)
+{
+       int retval;
+       struct flash_bank *bank;
+       struct stm32x_flash_bank *stm32x_info = NULL;
+
+       if (CMD_ARGC != 1) {
+               command_print(CMD_CTX, "stm32f2x options_read <bank>");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       retval = stm32x_read_options(bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       stm32x_info = bank->driver_priv;
+       if (stm32x_info->has_extra_options) {
+               if (stm32x_info->has_boot_addr) {
+                       uint32_t boot_addr = stm32x_info->option_bytes.boot_addr;
+
+                       command_print(CMD_CTX, "stm32f2x user_options 0x%03X,"
+                               " boot_add0 0x%04X, boot_add1 0x%04X",
+                               stm32x_info->option_bytes.user_options,
+                               boot_addr & 0xffff, (boot_addr & 0xffff0000) >> 16);
+               } else {
+                       command_print(CMD_CTX, "stm32f2x user_options 0x%03X,",
+                               stm32x_info->option_bytes.user_options);
+               }
+       } else {
+               command_print(CMD_CTX, "stm32f2x user_options 0x%02X",
+                       stm32x_info->option_bytes.user_options);
+
+       }
+
+       return retval;
+}
+
+COMMAND_HANDLER(stm32f2x_handle_options_write_command)
+{
+       int retval;
+       struct flash_bank *bank;
+       struct stm32x_flash_bank *stm32x_info = NULL;
+       uint16_t user_options, boot_addr0, boot_addr1;
+
+       if (CMD_ARGC < 1) {
+               command_print(CMD_CTX, "stm32f2x options_write <bank> ...");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       retval = stm32x_read_options(bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       stm32x_info = bank->driver_priv;
+       if (stm32x_info->has_boot_addr) {
+               if (CMD_ARGC != 4) {
+                       command_print(CMD_CTX, "stm32f2x options_write <bank> <user_options>"
+                               " <boot_addr0> <boot_addr1>");
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+               COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], boot_addr0);
+               COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], boot_addr1);
+               stm32x_info->option_bytes.boot_addr = boot_addr0 | (((uint32_t) boot_addr1) << 16);
+       } else {
+               if (CMD_ARGC != 2) {
+                       command_print(CMD_CTX, "stm32f2x options_write <bank> <user_options>");
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               }
+       }
+
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], user_options);
+       if (user_options & (stm32x_info->has_extra_options ? ~0xffc : ~0xfc)) {
+               command_print(CMD_CTX, "stm32f2x invalid user_options");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       stm32x_info->option_bytes.user_options = user_options;
+
+       if (stm32x_write_options(bank) != ERROR_OK) {
+               command_print(CMD_CTX, "stm32f2x failed to write options");
+               return ERROR_OK;
+       }
+
+       /* switching between single- and dual-bank modes requires re-probe */
+       /* ... and reprogramming of whole flash */
+       stm32x_info->probed = 0;
+
+       command_print(CMD_CTX, "stm32f2x write options complete.\n"
+                               "INFO: a reset or power cycle is required "
+                               "for the new settings to take effect.");
+       return retval;
+}
+
 static const struct command_registration stm32x_exec_command_handlers[] = {
        {
                .name = "lock",
@@ -1124,6 +1422,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
                .usage = "bank_id",
                .help = "Erase entire flash device.",
        },
+       {
+               .name = "options_read",
+               .handler = stm32f2x_handle_options_read_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Read and display device option bytes.",
+       },
+       {
+               .name = "options_write",
+               .handler = stm32f2x_handle_options_write_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id user_options [ boot_add0 boot_add1]",
+               .help = "Write option bytes",
+       },
        COMMAND_REGISTRATION_DONE
 };
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)