flash/stm32l4x: add support of STM32U57x/U58x
[fw/openocd] / src / flash / nor / stm32l4x.c
index ff804bbaf90b22d092af384c644041f36f74676d..b8635fe75ccd60de828e35757f5b5d82acc10e87 100644 (file)
@@ -27,7 +27,7 @@
 #include <helper/align.h>
 #include <helper/binarybuffer.h>
 #include <target/algorithm.h>
-#include <target/armv7m.h>
+#include <target/cortex_m.h>
 #include "bits.h"
 #include "stm32l4x.h"
 
@@ -80,6 +80,9 @@
  *
  * RM0461 (STM32WLEx)
  * http://www.st.com/resource/en/reference_manual/dm00530369.pdf
+ *
+ * RM0453 (STM32WL5x)
+ * http://www.st.com/resource/en/reference_manual/dm00451556.pdf
  */
 
 /* STM32G0xxx series for reference.
 #define F_HAS_TZ            BIT(2)
 /* this flag indicates if the device has the same flash registers as STM32L5 */
 #define F_HAS_L5_FLASH_REGS BIT(3)
+/* this flag indicates that programming should be done in quad-word
+ * the default programming word size is double-word */
+#define F_QUAD_WORD_PROG    BIT(4)
 /* end of STM32L4 flags ******************************************************/
 
 
@@ -139,6 +145,9 @@ enum stm32l4_flash_reg_index {
        STM32_FLASH_OPTKEYR_INDEX,
        STM32_FLASH_SR_INDEX,
        STM32_FLASH_CR_INDEX,
+       /* for some devices like STM32WL5x, the CPU2 have a dedicated C2CR register w/o LOCKs,
+        * so it uses the C2CR for flash operations and CR for checking locks and locking */
+       STM32_FLASH_CR_WLK_INDEX, /* FLASH_CR_WITH_LOCK */
        STM32_FLASH_OPTR_INDEX,
        STM32_FLASH_WRP1AR_INDEX,
        STM32_FLASH_WRP1BR_INDEX,
@@ -167,6 +176,18 @@ static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
        [STM32_FLASH_WRP2BR_INDEX]   = 0x050,
 };
 
+static const uint32_t stm32wl_cpu2_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
+       [STM32_FLASH_ACR_INDEX]      = 0x000,
+       [STM32_FLASH_KEYR_INDEX]     = 0x008,
+       [STM32_FLASH_OPTKEYR_INDEX]  = 0x010,
+       [STM32_FLASH_SR_INDEX]       = 0x060,
+       [STM32_FLASH_CR_INDEX]       = 0x064,
+       [STM32_FLASH_CR_WLK_INDEX]   = 0x014,
+       [STM32_FLASH_OPTR_INDEX]     = 0x020,
+       [STM32_FLASH_WRP1AR_INDEX]   = 0x02C,
+       [STM32_FLASH_WRP1BR_INDEX]   = 0x030,
+};
+
 static const uint32_t stm32l5_ns_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
        [STM32_FLASH_ACR_INDEX]      = 0x000,
        [STM32_FLASH_KEYR_INDEX]     = 0x008, /* NSKEYR */
@@ -218,6 +239,7 @@ struct stm32l4_flash_bank {
        bool dual_bank_mode;
        int hole_sectors;
        uint32_t user_bank_size;
+       uint32_t data_width;
        uint32_t cr_bker_mask;
        uint32_t sr_bsy_mask;
        uint32_t wrpxxr_mask;
@@ -247,7 +269,7 @@ struct stm32l4_wrp {
 };
 
 /* human readable list of families this drivers supports (sorted alphabetically) */
-static const char *device_families = "STM32G0/G4/L4/L4+/L5/WB/WL";
+static const char *device_families = "STM32G0/G4/L4/L4+/L5/U5/WB/WL";
 
 static const struct stm32l4_rev stm32_415_revs[] = {
        { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
@@ -305,6 +327,10 @@ static const struct stm32l4_rev stm32_479_revs[] = {
        { 0x1000, "A" },
 };
 
+static const struct stm32l4_rev stm32_482_revs[] = {
+       { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" },
+};
+
 static const struct stm32l4_rev stm32_495_revs[] = {
        { 0x2001, "2.1" },
 };
@@ -486,6 +512,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
        },
+       {
+         .id                    = 0x482,
+         .revs                  = stm32_482_revs,
+         .num_revs              = ARRAY_SIZE(stm32_482_revs),
+         .device_str            = "STM32U57/U58xx",
+         .max_flash_size_kb     = 2048,
+         .flags                 = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS,
+         .flash_regs_base       = 0x40022000,
+         .fsize_addr            = 0x0BFA07A0,
+         .otp_base              = 0x0BFA0000,
+         .otp_size              = 512,
+       },
        {
          .id                    = 0x495,
          .revs                  = stm32_495_revs,
@@ -514,7 +552,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .id                    = 0x497,
          .revs                  = stm32_497_revs,
          .num_revs              = ARRAY_SIZE(stm32_497_revs),
-         .device_str            = "STM32WLEx",
+         .device_str            = "STM32WLEx/WL5x",
          .max_flash_size_kb     = 256,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x58004000,
@@ -541,10 +579,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
                return ERROR_FAIL; /* Checkme: What better error to use?*/
        bank->driver_priv = stm32l4_info;
 
-       /* The flash write must be aligned to a double word (8-bytes) boundary.
-        * Ask the flash infrastructure to ensure required alignment */
-       bank->write_start_alignment = bank->write_end_alignment = 8;
-
        stm32l4_info->probed = false;
        stm32l4_info->otp_enabled = false;
        stm32l4_info->user_bank_size = bank->size;
@@ -789,14 +823,22 @@ static int stm32l4_set_secbb(struct flash_bank *bank, uint32_t value)
        return ERROR_OK;
 }
 
+static inline int stm32l4_get_flash_cr_with_lock_index(struct flash_bank *bank)
+{
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       return (stm32l4_info->flash_regs[STM32_FLASH_CR_WLK_INDEX]) ?
+               STM32_FLASH_CR_WLK_INDEX : STM32_FLASH_CR_INDEX;
+}
+
 static int stm32l4_unlock_reg(struct flash_bank *bank)
 {
+       const uint32_t flash_cr_index = stm32l4_get_flash_cr_with_lock_index(bank);
        uint32_t ctrl;
 
        /* first check if not already unlocked
         * otherwise writing on STM32_FLASH_KEYR will fail
         */
-       int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
+       int retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl);
        if (retval != ERROR_OK)
                return retval;
 
@@ -812,7 +854,7 @@ static int stm32l4_unlock_reg(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
-       retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
+       retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl);
        if (retval != ERROR_OK)
                return retval;
 
@@ -826,9 +868,10 @@ static int stm32l4_unlock_reg(struct flash_bank *bank)
 
 static int stm32l4_unlock_option_reg(struct flash_bank *bank)
 {
+       const uint32_t flash_cr_index = stm32l4_get_flash_cr_with_lock_index(bank);
        uint32_t ctrl;
 
-       int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
+       int retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl);
        if (retval != ERROR_OK)
                return retval;
 
@@ -844,7 +887,7 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
-       retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
+       retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl);
        if (retval != ERROR_OK)
                return retval;
 
@@ -884,7 +927,8 @@ static int stm32l4_perform_obl_launch(struct flash_bank *bank)
        stm32l4_info->probed = false;
 
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK | FLASH_OPTLOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank),
+                       FLASH_LOCK | FLASH_OPTLOCK);
 
        if (retval != ERROR_OK)
                return retval;
@@ -930,7 +974,8 @@ static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset,
        retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
 
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK | FLASH_OPTLOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank),
+                       FLASH_LOCK | FLASH_OPTLOCK);
        stm32l4_info->flash_regs = saved_flash_regs;
 
        if (retval != ERROR_OK)
@@ -1124,7 +1169,7 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
        }
 
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
 
        if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
                /* restore all FLASH pages as non-secure */
@@ -1268,11 +1313,12 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
        return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp);
 }
 
-/* Count is in double-words */
+/* count is the size divided by stm32l4_info->data_width */
 static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        uint32_t buffer_size;
        struct working_area *write_algorithm;
        struct working_area *source;
@@ -1299,7 +1345,11 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
                return retval;
        }
 
-       /* memory buffer, size *must* be multiple of dword plus one dword for rp and one for wp */
+       /* memory buffer, size *must* be multiple of stm32l4_info->data_width
+        * plus one dword for rp and one for wp */
+       /* FIXME, currently only STM32U5 devices do have a different data_width,
+        * but STM32U5 device flash programming does not go through this function
+        * so temporarily continue to consider the default data_width = 8 */
        buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1);
        if (buffer_size < 256) {
                LOG_WARNING("large enough working area not available, can't do block memory writes");
@@ -1331,7 +1381,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX));
        buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX));
 
-       retval = target_run_flash_async_algorithm(target, buffer, count, 8,
+       retval = target_run_flash_async_algorithm(target, buffer, count, stm32l4_info->data_width,
                        0, NULL,
                        ARRAY_SIZE(reg_params), reg_params,
                        source->address, source->size,
@@ -1367,10 +1417,11 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        return retval;
 }
 
-/* Count is in double-words */
+/* count is the size divided by stm32l4_info->data_width */
 static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uint8_t *buffer,
                                uint32_t offset, uint32_t count)
 {
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        struct target *target = bank->target;
        uint32_t address = bank->base + offset;
        int retval = ERROR_OK;
@@ -1388,8 +1439,9 @@ static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uin
 
        /* write directly to flash memory */
        const uint8_t *src = buffer;
+       const uint32_t data_width_in_words = stm32l4_info->data_width / 4;
        while (count--) {
-               retval = target_write_memory(target, address, 4, 2, src);
+               retval = target_write_memory(target, address, 4, data_width_in_words, src);
                if (retval != ERROR_OK)
                        return retval;
 
@@ -1398,8 +1450,8 @@ static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uin
                if (retval != ERROR_OK)
                        return retval;
 
-               src += 8;
-               address += 8;
+               src += stm32l4_info->data_width;
+               address += stm32l4_info->data_width;
        }
 
        /* reset PG in FLASH_CR */
@@ -1426,10 +1478,13 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       /* The flash write must be aligned to a double word (8-bytes) boundary.
+       /* ensure that stm32l4_info->data_width is 'at least' a multiple of dword */
+       assert(stm32l4_info->data_width % 8 == 0);
+
+       /* The flash write must be aligned to the 'stm32l4_info->data_width' boundary.
         * The flash infrastructure ensures it, do just a security check */
-       assert(offset % 8 == 0);
-       assert(count % 8 == 0);
+       assert(offset % stm32l4_info->data_width == 0);
+       assert(count % stm32l4_info->data_width == 0);
 
        /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether
         * data to be written does not go into a gap:
@@ -1491,6 +1546,12 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
        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;
+       } else if (stm32l4_info->part_info->id == 0x482) {
+               /**
+                * FIXME the current flashloader does not support writing in quad-words
+                * which is required for STM32U5 devices.
+                */
+               use_flashloader = false;
        }
 
        if (use_flashloader) {
@@ -1501,17 +1562,18 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
                if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5))
                        LOG_INFO("RDP level is 0.5, the work-area should reside in non-secure RAM");
 
-               retval = stm32l4_write_block(bank, buffer, offset, count / 8);
+               retval = stm32l4_write_block(bank, buffer, offset,
+                               count / stm32l4_info->data_width);
        }
 
        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);
+               retval = stm32l4_write_block_without_loader(bank, buffer, offset,
+                               count / stm32l4_info->data_width);
        }
 
-
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
 
        if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
                /* restore all FLASH pages as non-secure */
@@ -1540,6 +1602,30 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
                        return ERROR_OK;
        }
 
+       /* Workaround for STM32WL5x devices:
+        * DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1,
+        * to solve this read the UID64 (IEEE 64-bit unique device ID register) */
+
+       struct cortex_m_common *cortex_m = target_to_cm(bank->target);
+
+       if (cortex_m->core_info->partno == CORTEX_M0P_PARTNO && cortex_m->armv7m.debug_ap->ap_num == 1) {
+               uint32_t uid64_ids;
+
+               /* UID64 is contains
+                *  - Bits 63:32 : DEVNUM (unique device number, different for each individual device)
+                *  - Bits 31:08 : STID (company ID) = 0x0080E1
+                *  - Bits 07:00 : DEVID (device ID) = 0x15
+                *
+                *  read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx
+                */
+               retval = target_read_u32(bank->target, UID64_IDS, &uid64_ids);
+               if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) {
+                       /* force the DEV_ID to 0x497 and the REV_ID to unknown */
+                       *id = 0x00000497;
+                       return ERROR_OK;
+               }
+       }
+
        LOG_ERROR("can't get the device id");
        return (retval == ERROR_OK) ? ERROR_FAIL : retval;
 }
@@ -1570,6 +1656,7 @@ static const char *get_stm32l4_bank_type_str(struct flash_bank *bank)
 static int stm32l4_probe(struct flash_bank *bank)
 {
        struct target *target = bank->target;
+       struct armv7m_common *armv7m = target_to_armv7m(target);
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        const struct stm32l4_part_info *part_info;
        uint16_t flash_size_kb = 0xffff;
@@ -1603,9 +1690,14 @@ 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->data_width = (part_info->flags & F_QUAD_WORD_PROG) ? 16 : 8;
        stm32l4_info->cr_bker_mask = FLASH_BKER;
        stm32l4_info->sr_bsy_mask = FLASH_BSY;
 
+       /* Set flash write alignment boundaries.
+        * Ask the flash infrastructure to ensure required alignment */
+       bank->write_start_alignment = bank->write_end_alignment = stm32l4_info->data_width;
+
        /* initialise the flash registers layout */
        if (part_info->flags & F_HAS_L5_FLASH_REGS)
                stm32l4_info->flash_regs = stm32l5_ns_flash_regs;
@@ -1722,7 +1814,6 @@ static int stm32l4_probe(struct flash_bank *bank)
        case 0x466: /* STM32G03/G04xx */
        case 0x468: /* STM32G43/G44xx */
        case 0x479: /* STM32G49/G4Axx */
-       case 0x497: /* STM32WLEx */
                /* single bank flash */
                page_size_kb = 2;
                num_pages = flash_size_kb / page_size_kb;
@@ -1799,6 +1890,18 @@ static int stm32l4_probe(struct flash_bank *bank)
                        stm32l4_info->bank1_sectors = num_pages / 2;
                }
                break;
+       case 0x482: /* STM32U57/U58xx */
+               /* if flash size is max (2M) the device is always dual bank
+                * otherwise check DUALBANK bit(21)
+                */
+               page_size_kb = 8;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+               if ((flash_size_kb == part_info->max_flash_size_kb) || (stm32l4_info->optr & BIT(21))) {
+                       stm32l4_info->dual_bank_mode = true;
+                       stm32l4_info->bank1_sectors = num_pages / 2;
+               }
+               break;
        case 0x495: /* STM32WB5x */
        case 0x496: /* STM32WB3x */
                /* single bank flash */
@@ -1806,6 +1909,14 @@ static int stm32l4_probe(struct flash_bank *bank)
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
                break;
+       case 0x497: /* STM32WLEx/WL5x */
+               /* single bank flash */
+               page_size_kb = 2;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+               if (armv7m->debug_ap->ap_num == 1)
+                       stm32l4_info->flash_regs = stm32wl_cpu2_flash_regs;
+               break;
        default:
                LOG_ERROR("unsupported device");
                return ERROR_FAIL;
@@ -1953,7 +2064,7 @@ static int stm32l4_mass_erase(struct flash_bank *bank)
        retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
 
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
 
        if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
                /* restore all FLASH pages as non-secure */