X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32l4x.c;h=1ebf833b865dfba9b86e3d671f15a3d210cda8f6;hb=af3575b931b2bbd8b82d64f2f4495bae1741a1b1;hp=8d463ac0593e6f5af11118115524c6fd9fe118c2;hpb=6c1e1a212a8c044ae778c526851fe909bf219e90;p=openocd.git diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 8d463ac059..1ebf833b86 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -133,6 +133,9 @@ #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 ******************************************************/ @@ -236,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; @@ -265,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" } @@ -275,6 +279,10 @@ static const struct stm32l4_rev stm32_435_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; +static const struct stm32l4_rev stm32_456_revs[] = { + { 0x1000, "A" }, +}; + static const struct stm32l4_rev stm32_460_revs[] = { { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" }, }; @@ -323,6 +331,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" }, }; @@ -360,6 +372,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_base = 0x1FFF7000, .otp_size = 1024, }, + { + .id = 0x456, + .revs = stm32_456_revs, + .num_revs = ARRAY_SIZE(stm32_456_revs), + .device_str = "STM32G05/G06xx", + .max_flash_size_kb = 64, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, { .id = 0x460, .revs = stm32_460_revs, @@ -504,6 +528,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, @@ -559,10 +595,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; @@ -1297,16 +1329,16 @@ 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; - uint32_t buffer_size; + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[6]; + struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -1328,17 +1360,23 @@ 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 */ - buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1); + /* data_width should be multiple of double-word */ + assert(stm32l4_info->data_width % 8 == 0); + const size_t extra_size = sizeof(struct stm32l4_work_area); + uint32_t buffer_size = target_get_working_area_avail(target) - extra_size; + /* buffer_size should be multiple of stm32l4_info->data_width */ + buffer_size &= ~(stm32l4_info->data_width - 1); + if (buffer_size < 256) { LOG_WARNING("large enough working area not available, can't do block memory writes"); + target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (buffer_size > 16384) { /* probably won't benefit from more than 16k ... */ buffer_size = 16384; } - if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + if (target_alloc_working_area_try(target, buffer_size + extra_size, &source) != ERROR_OK) { LOG_ERROR("allocating working area failed"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1349,28 +1387,46 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (double word-64bit) */ - init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash status register */ - init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash control register */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (of stm32l4_info->data_width) */ + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); /* write algo stack pointer */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); - 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)); + buf_set_u32(reg_params[4].value, 0, 32, source->address + + offsetof(struct stm32l4_work_area, stack) + LDR_STACK_SIZE); + + struct stm32l4_loader_params loader_extra_params; + + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_addr, + stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX)); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_cr_addr, + stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX)); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_word_size, + stm32l4_info->data_width); + target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_bsy_mask, + stm32l4_info->sr_bsy_mask); + + retval = target_write_buffer(target, source->address, sizeof(loader_extra_params), + (uint8_t *) &loader_extra_params); + if (retval != ERROR_OK) + return retval; - 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, + source->address + offsetof(struct stm32l4_work_area, fifo), + source->size - offsetof(struct stm32l4_work_area, fifo), write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("error executing stm32l4 flash write algorithm"); - uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & FLASH_ERROR; + uint32_t error; + stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &error); + error &= FLASH_ERROR; if (error & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); @@ -1391,15 +1447,15 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); - destroy_reg_param(®_params[5]); 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; @@ -1417,8 +1473,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; @@ -1427,8 +1484,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 */ @@ -1455,10 +1512,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: @@ -1511,18 +1571,7 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto err_lock; - /** - * 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) { + if (stm32l4_info->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, @@ -1530,15 +1579,16 @@ 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) { + if (!stm32l4_info->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, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK); @@ -1657,9 +1707,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; @@ -1770,6 +1825,7 @@ static int stm32l4_probe(struct flash_bank *bank) } break; case 0x435: /* STM32L43/L44xx */ + case 0x456: /* STM32G05/G06xx */ case 0x460: /* STM32G07/G08xx */ case 0x462: /* STM32L45/L46xx */ case 0x464: /* STM32L41/L42xx */ @@ -1852,6 +1908,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 */