This is an automated email from Gerrit. Tarek BOCHKATI ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/6108
-- gerrit commit 14fba0af0d0be567fef3c806f93f54c9550e9f14 Author: Tarek BOCHKATI <[email protected]> Date: Tue Mar 16 16:10:59 2021 +0100 flash/stm32l4x: add support of STM32U57x/U58x this device flash registers are quite similar to STM32L5 with this changes : - flash size is up to 2MB - 2MB variants are always dual bank - 1MB and 512KB variants could be dual bank (contiguous addressing) depending on DUALBANK bit(21) - flash data width is 16 bytes (quad-word) Change-Id: Id13c552270ce1071479ad418526e8a39ebe83cb1 Signed-off-by: Tarek BOCHKATI <[email protected]> Reviewed-on: https://gerrit.st.com/c/stm32ide/official/openocd/+/196640 Tested-by: Tarek BOUCHKATI <[email protected]> Reviewed-by: Tarek BOUCHKATI <[email protected]> diff --git a/doc/openocd.texi b/doc/openocd.texi index b659594..6558bc5 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7212,7 +7212,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Flash Driver} stm32l4x -All members of the STM32 G0, G4, L4, L4+, L5, WB and WL +All members of the STM32 G0, G4, L4, L4+, L5, U5, WB and WL microcontroller families from STMicroelectronics include internal flash and use ARM Cortex-M0+, M4 and M33 cores. The driver automatically recognizes a number of these chips using diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 0734c1f..01b512b 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -234,6 +234,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; @@ -319,6 +320,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" }, }; @@ -515,6 +520,19 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .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_HAS_TZ, + .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l5_ns_flash_regs, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, + { .id = 0x495, .revs = stm32_495_revs, .num_revs = ARRAY_SIZE(stm32_495_revs), @@ -572,10 +590,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; @@ -1289,11 +1303,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; @@ -1320,10 +1335,12 @@ 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 */ 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"); + 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 ... */ @@ -1352,7 +1369,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, @@ -1388,10 +1405,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; @@ -1409,8 +1427,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; @@ -1419,8 +1438,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 */ @@ -1447,10 +1466,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: @@ -1515,13 +1537,19 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, */ LOG_INFO("Couldn't use the flash loader in dual-bank mode"); use_loader = false; + } else if (stm32l4_info->part_info->id == 0x482) { + /** + * FIXME for STM32U5 device we get this error and random pointer + * Error: corrupted fifo read pointer 0x200006ec + */ + use_loader = false; } if (use_loader) - retval = stm32l4_write_block(bank, buffer, offset, count / 8); + retval = stm32l4_write_block(bank, buffer, offset, count / stm32l4_info->data_width); else { 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); } @@ -1591,6 +1619,7 @@ static int stm32l4_probe(struct flash_bank *bank) part_info = stm32l4_info->part_info; stm32l4_info->flash_regs = part_info->default_flash_regs; + stm32l4_info->data_width = 8; /* default is double-word */ stm32l4_info->cr_bker_mask = FLASH_BKER; stm32l4_info->sr_bsy_mask = FLASH_BSY; @@ -1783,6 +1812,26 @@ static int stm32l4_probe(struct flash_bank *bank) if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) stm32l4_info->flash_regs = stm32l5_s_flash_regs; 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; + stm32l4_info->data_width = 16; /* programming in quad-words */ + 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; + } + + /** + * by default use the non-secure registers, + * switch secure registers if TZ is enabled and RDP is LEVEL_0 + */ + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) + stm32l4_info->flash_regs = stm32l5_s_flash_regs; + break; case 0x495: /* STM32WB5x */ case 0x496: /* STM32WB3x */ /* single bank flash */ @@ -1833,6 +1882,11 @@ static int stm32l4_probe(struct flash_bank *bank) assert((stm32l4_info->wrpxxr_mask & 0xFFFF0000) == 0); LOG_DEBUG("WRPxxR mask 0x%04" PRIx16, (uint16_t)stm32l4_info->wrpxxr_mask); + /* 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; + + /* Initialize bank->sectors */ free(bank->sectors); bank->size = (flash_size_kb + gap_size_kb) * 1024; diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index 280a059..1a358e1 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -113,10 +113,11 @@ proc stm32f7x args { eval stm32f2x $args } proc stm32l0x args { eval stm32lx $args } proc stm32l1x args { eval stm32lx $args } -# stm32[g0|g4|wb|wl] uses the same flash driver as the stm32l4x +# stm32[g0|g4|l5|u5|wb|wl] uses the same flash driver as the stm32l4x proc stm32g0x args { eval stm32l4x $args } proc stm32g4x args { eval stm32l4x $args } proc stm32l5x args { eval stm32l4x $args } +proc stm32u5x args { eval stm32l4x $args } proc stm32wbx args { eval stm32l4x $args } proc stm32wlx args { eval stm32l4x $args } diff --git a/tcl/target/stm32u5x.cfg b/tcl/target/stm32u5x.cfg new file mode 100644 index 0000000..dc57f17 --- /dev/null +++ b/tcl/target/stm32u5x.cfg @@ -0,0 +1,181 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32u5x family + +# +# stm32u5 devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32u5x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 64kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + # See STM Document RM0438 + # RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers + # Corresponds to Cortex®-M33 JTAG debug port ID code + set _CPUTAPID 0x0ba04477 + } { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x0be12477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if {[using_jtag]} { + jtag newtap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +# use non-secure RAM by default +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# create sec/ns flash and otp memories (sizes will be probed) +flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME + +# Common knowledges tells JTAG speed should be <= F_CPU/6. +# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on +# the safe side. +# +# Note that there is a pretty wide band where things are +# more or less stable, see http://openocd.zylin.com/#/c/3366/ +adapter speed 500 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +proc is_secure {} { + # read Debug Security Control and Status Regsiter (DSCSR) and check CDS (bit 16) + set DSCSR [mrw 0xE000EE08] + return [expr [expr $DSCSR & (1 << 16)] != 0] +} + +proc clock_config_160_mhz {} { + # Mcu clock is at MSI 4MHz after reset, set mcu freq at 160 MHz with PLL + set offset [expr [is_secure] ? 0x10000000 : 0] + + # Enable voltage range 1 for frequency above 100 Mhz + # RCC_AHB3ENR = PWREN + mww [expr 0x46020C94 + $offset] 0x00000004 + # delay for register clock enable (read back reg) + mrw [expr 0x56020C94 + $offset] + # PWR_VOSR : VOS Range 1 + mww [expr 0x4602080C + $offset] 0x00030000 + # delay for register write (read back reg) + mrw [expr 0x4602080C + $offset] + # FLASH_ACR : 4 WS for 160 MHz HCLK + mww [expr 0x40022000 + $offset] 0x00000004 + # RCC_PLL1CFGR => PLL1M=0000=/1, PLL1SRC=MSI 4MHz + mww [expr 0x46020C28 + $offset] 0x00000001 + # RCC_PLL1DIVR => PLL1P=PLL1Q=PLL1R=000001=/2, PLL1N=0x4F=80 + # fVCO = 4 x 80 /1 = 320 + # SYSCLOCK = fVCO/PLL1R = 320/2 = 160 MHz + mmw [expr 0x46020C34 + $offset] 0x0000004F 0 + # RCC_PLL1CFGR => PLL1REN=1 + mmw [expr 0x46020C28 + $offset] 0x00040000 0 + # RCC_CR |= PLL1ON + mmw [expr 0x46020C00 + $offset] 0x01000000 0 + # while !(RCC_CR & PLL1RDY) + while {!([mrw [expr 0x46020C00 + $offset]] & 0x02000000)} {} + # RCC_CFGR1 |= SW_PLL + mmw [expr 0x46020C1C + $offset] 0x00000003 0 + # while ((RCC_CFGR1 & SWS) != PLL) + while {([mrw [expr 0x46020C1C + $offset]] & 0x0C) != 0x0C} {} +} + +proc ahb_ap_non_secure_access {} { + # SPROT=1=Non Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x4B000000 +} + +proc ahb_ap_secure_access {} { + # SPROT=0=Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x0B000000 +} + +$_TARGETNAME configure -event reset-init { + clock_config_160_mhz + # Boost JTAG frequency + adapter speed 4000 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is MSI (4 MHz) + adapter speed 480 +} + +$_TARGETNAME configure -event examine-end { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0xE0044004 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0044008 0x00001800 0 +} + +$_TARGETNAME configure -event halted { + if {[is_secure]} { + echo "CPU in Secure state" + ahb_ap_secure_access + } else { + echo "CPU in Non-Secure state" + ahb_ap_non_secure_access + } +} + +$_TARGETNAME configure -event gdb-flash-erase-start { + # check if FLASH_OPTR.TZEN is enabled + set FLASH_OPTR [mrw 0x40022040] + if {[expr [expr $FLASH_OPTR & (1 << 31)] == 0]} { + echo "TZEN option bit disabled" + ahb_ap_non_secure_access + # use non secure mapping + $_TARGETNAME configure -work-area-phys 0x20000000 + } { + ahb_ap_secure_access + echo "TZEN option bit enabled" + # Use secure mapping + $_TARGETNAME configure -work-area-phys 0x30000000 + } +} + +$_TARGETNAME configure -event trace-config { + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0xE0044004 0x00000020 0 +} -- _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
