diff --git a/contrib/loaders/flash/stm32/stm32l4x.S b/contrib/loaders/flash/stm32/stm32l4x.S index e0ce3cb34..9e5c41eba 100644 --- a/contrib/loaders/flash/stm32/stm32l4x.S +++ b/contrib/loaders/flash/stm32/stm32l4x.S @@ -8,6 +8,9 @@ * Copyright (C) 2015 Uwe Bonnes * * bon@elektron.ikp.physik.tu-darmstadt.de * * * + * Copyright (C) 2018 Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -25,68 +28,79 @@ .text .syntax unified - .cpu cortex-m4 + .cpu cortex-m0 .thumb /* * Params : * r0 = workarea start, status (out) - * r1 = workarea end + * r1 = workarea end + 1 * r2 = target address * r3 = count (64bit words) - * r4 = flash base + * r4 = flash status register + * r5 = flash control register * * Clobbered: - * r5 - rp * r6/7 - temp (64-bit) - * r8 - wp, tmp */ -#define STM32_FLASH_CR_OFFSET 0x14 /* offset of CR register in FLASH struct */ -#define STM32_FLASH_SR_OFFSET 0x10 /* offset of SR register in FLASH struct */ - -#define STM32_PROG 0x1 /* PG */ +#include "../../../../src/flash/nor/stm32l4x.h" .thumb_func .global _start + _start: + mov r8, r3 /* copy dword count */ wait_fifo: - ldr r8, [r0, #0] /* read wp */ - cmp r8, #0 /* abort if wp == 0 */ - beq exit - ldr r5, [r0, #4] /* read rp */ - subs r6, r8, r5 /* number of bytes available for read in r6*/ - itt mi /* if wrapped around*/ - addmi r6, r1 /* add size of buffer */ - submi r6, r0 - cmp r6, #8 /* wait until 8 bytes are available */ - bcc wait_fifo + ldr r6, [r0, #0] /* read wp */ + cmp r6, #0 /* if wp == 0, */ + beq exit /* then abort */ + ldr r3, [r0, #4] /* read rp */ + subs r6, r6, r3 /* number of bytes available for read in r6 */ + bpl fifo_stat /* if not wrapped around, skip */ + adds r6, r6, r1 /* add end of buffer */ + subs r6, r6, r0 /* sub start of buffer */ +fifo_stat: + cmp r6, #8 /* wait until at least one dword available */ + bcc wait_fifo - ldr r6, =STM32_PROG - str r6, [r4, #STM32_FLASH_CR_OFFSET] - ldrd r6, [r5], #0x08 /* read one word from src, increment ptr */ - strd r6, [r2], #0x08 /* write one word to dst, increment ptr */ + movs r6, #FLASH_PG /* flash program enable */ + str r6, [r5] /* write to FLASH_CR, start operation */ + ldmia r3!, {r6, r7} /* read one dword from src, increment ptr */ + stmia r2!, {r6, r7} /* write one dword to dst, increment ptr */ dsb + ldr r7, =FLASH_BSY /* FLASH_BSY mask */ busy: - ldr r6, [r4, #STM32_FLASH_SR_OFFSET] - tst r6, #0x10000 /* BSY (bit16) == 1 => operation in progress */ - bne busy /* wait more... */ - tst r6, #0xfa /* PGSERR | SIZERR | PGAERR | WRPERR | PROGERR | OPERR */ - bne error /* fail... */ + ldr r6, [r4] /* get FLASH_SR register */ + tst r6, r7 /* BSY == 1 => operation in progress */ + bne busy /* if still set, wait more ... */ + movs r7, #FLASH_ERROR /* all error bits */ + tst r6, r7 /* check for any error bit */ + bne error /* fail ... */ - cmp r5, r1 /* wrap rp at end of buffer */ - it cs - addcs r5, r0, #8 /* skip loader args */ - str r5, [r0, #4] /* store rp */ - subs r3, r3, #1 /* decrement dword count */ - cbz r3, exit /* loop if not done */ - b wait_fifo -error: - movs r1, #0 - str r1, [r0, #4] /* set rp = 0 on error */ -exit: - mov r0, r6 /* return status in r0 */ - bkpt #0x00 + cmp r3, r1 /* rp at end of buffer? */ + bcc upd_rp /* if no, then skip */ + subs r3, r3, r1 /* sub end of buffer */ + adds r3, r3, r0 /* add start of buffer */ + adds r3, r3, #8 /* skip wp and rp */ +upd_rp: + str r3, [r0, #4] /* store rp */ + mov r7, r8 /* get dword count */ + subs r7, r7, #1 /* decrement dword count */ + mov r8, r7 /* save dword count */ + beq exit /* exit if done */ + b wait_fifo .pool +error: + movs r3, #0 + str r3, [r0, #4] /* set rp = 0 on error */ +exit: + mov r0, r6 /* return status in r0 */ + movs r6, #0 /* flash program disable */ + str r6, [r5] /* write to FLASH_CR */ + movs r6, #FLASH_ERROR /* all error bits */ + str r6, [r4] /* write to FLASH_CR to clear errors */ + bkpt #0x00 + diff --git a/contrib/loaders/flash/stm32/stm32l4x.inc b/contrib/loaders/flash/stm32/stm32l4x.inc index 4065d14ef..df5c7edd1 100644 --- a/contrib/loaders/flash/stm32/stm32l4x.inc +++ b/contrib/loaders/flash/stm32/stm32l4x.inc @@ -1,7 +1,7 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x20,0xd0,0x45,0x68,0xb8,0xeb,0x05,0x06, -0x44,0xbf,0x76,0x18,0x36,0x1a,0x08,0x2e,0xf2,0xd3,0x0d,0x4e,0x66,0x61,0xf5,0xe8, -0x02,0x67,0xe2,0xe8,0x02,0x67,0xbf,0xf3,0x4f,0x8f,0x26,0x69,0x16,0xf4,0x80,0x3f, -0xfb,0xd1,0x16,0xf0,0xfa,0x0f,0x07,0xd1,0x8d,0x42,0x28,0xbf,0x00,0xf1,0x08,0x05, -0x45,0x60,0x01,0x3b,0x13,0xb1,0xdb,0xe7,0x00,0x21,0x41,0x60,0x30,0x46,0x00,0xbe, -0x01,0x00,0x00,0x00, +0x98,0x46,0x06,0x68,0x00,0x2e,0x23,0xd0,0x43,0x68,0xf6,0x1a,0x01,0xd5,0x76,0x18, +0x36,0x1a,0x08,0x2e,0xf5,0xd3,0x01,0x26,0x2e,0x60,0xc0,0xcb,0xc0,0xc2,0xbf,0xf3, +0x4f,0x8f,0x09,0x4f,0x26,0x68,0x3e,0x42,0xfc,0xd1,0xfa,0x27,0x3e,0x42,0x0d,0xd1, +0x8b,0x42,0x02,0xd3,0x5b,0x1a,0x1b,0x18,0x08,0x33,0x43,0x60,0x47,0x46,0x01,0x3f, +0xb8,0x46,0x05,0xd0,0xdd,0xe7,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x23,0x43,0x60, +0x30,0x46,0x00,0x26,0x2e,0x60,0xfa,0x26,0x26,0x60,0x00,0xbe, diff --git a/doc/openocd.texi b/doc/openocd.texi index 711171a34..97c5a728d 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6892,8 +6892,10 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Flash Driver} stm32l4x -All members of the STM32L4 and STM32WB microcontroller families from STMicroelectronics -include internal flash and use ARM Cortex-M4 cores. +All members of the STM32L4, STM32L4+, STM32WB and STM32G4 +microcontroller families from STMicroelectronics include internal flash +and use ARM Cortex-M4 cores. +Additionally this driver supports STM32G0 family with ARM Cortex-M0+ core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @@ -6903,7 +6905,8 @@ flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by -the flash driver. +the flash driver. However, specifying a wrong value might lead to a completely +wrong flash layout, so this feature must be used carefully. @example flash bank $_FLASHNAME stm32l4x 0x08000000 0x40000 0 0 $_TARGETNAME @@ -6960,7 +6963,7 @@ This will effectively write protect all sectors in flash bank 1. @end deffn @deffn Command {stm32l4x option_load} num -Forces a re-load of the option byte registers. Will cause a reset of the device. +Forces a re-load of the option byte registers. Will cause a system reset of the device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 64c4a9079..b95b003df 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -84,4 +84,5 @@ NORHEADERS = \ %D%/non_cfi.h \ %D%/ocl.h \ %D%/spi.h \ + %D%/stm32l4x.h \ %D%/msp432.h diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index abbb75b46..b6f0d714d 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -28,6 +28,7 @@ #include #include #include "bits.h" +#include "stm32l4x.h" /* STM32L4xxx series for reference. * @@ -65,66 +66,44 @@ * */ +/* STM32WBxxx series for reference. + * + * RM0434 (STM32WB55) + * http://www.st.com/resource/en/reference_manual/dm00318631.pdf + * + * RM0471 (STM32WB50) + * http://www.st.com/resource/en/reference_manual/dm00622834.pdf + */ + +/* + * STM32G0xxx series for reference. + * + * RM0444 (STM32G0x1) + * http://www.st.com/resource/en/reference_manual/dm00371828.pdf + * + * RM0454 (STM32G0x0) + * http://www.st.com/resource/en/reference_manual/dm00463896.pdf + */ + +/* + * STM32G4xxx series for reference. + * + * RM0440 (STM32G43x/44x/47x/48x) + * http://www.st.com/resource/en/reference_manual/dm00355726.pdf + * + * Cat. 2 devices have single bank only, page size is 2kByte. + * + * Cat. 3 devices have single and dual bank operating modes, + * Page size is 2kByte (dual mode) or 4kByte (single mode). + * + * Bank mode is controlled by bit 22 (DBANK) in option bytes register. + * Both banks are treated as a single OpenOCD bank. + */ + /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 -/* Flash registers offsets */ -#define STM32_FLASH_ACR 0x00 -#define STM32_FLASH_KEYR 0x08 -#define STM32_FLASH_OPTKEYR 0x0c -#define STM32_FLASH_SR 0x10 -#define STM32_FLASH_CR 0x14 -#define STM32_FLASH_OPTR 0x20 -#define STM32_FLASH_WRP1AR 0x2c -#define STM32_FLASH_WRP1BR 0x30 -#define STM32_FLASH_WRP2AR 0x4c -#define STM32_FLASH_WRP2BR 0x50 - -/* FLASH_CR register bits */ -#define FLASH_PG (1 << 0) -#define FLASH_PER (1 << 1) -#define FLASH_MER1 (1 << 2) -#define FLASH_PAGE_SHIFT 3 -#define FLASH_CR_BKER (1 << 11) -#define FLASH_MER2 (1 << 15) -#define FLASH_STRT (1 << 16) -#define FLASH_OPTSTRT (1 << 17) -#define FLASH_EOPIE (1 << 24) -#define FLASH_ERRIE (1 << 25) -#define FLASH_OBLLAUNCH (1 << 27) -#define FLASH_OPTLOCK (1 << 30) -#define FLASH_LOCK (1 << 31) - -/* FLASH_SR register bits */ -#define FLASH_BSY (1 << 16) -/* Fast programming not used => related errors not used*/ -#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ -#define FLASH_SIZERR (1 << 6) /* Size error */ -#define FLASH_PGAERR (1 << 5) /* Programming alignment error */ -#define FLASH_WRPERR (1 << 4) /* Write protection error */ -#define FLASH_PROGERR (1 << 3) /* Programming error */ -#define FLASH_OPERR (1 << 1) /* Operation error */ -#define FLASH_EOP (1 << 0) /* End of operation */ -#define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR) - -/* register unlock keys */ -#define KEY1 0x45670123 -#define KEY2 0xCDEF89AB - -/* option register unlock key */ -#define OPTKEY1 0x08192A3B -#define OPTKEY2 0x4C5D6E7F - -#define RDP_LEVEL_0 0xAA -#define RDP_LEVEL_1 0xBB -#define RDP_LEVEL_2 0xCC - - -/* other registers */ -#define DBGMCU_IDCODE 0xE0042000 - - struct stm32l4_rev { const uint16_t rev; const char *str; @@ -147,9 +126,14 @@ struct stm32l4_flash_bank { int bank1_sectors; bool dual_bank_mode; int hole_sectors; + uint32_t user_bank_size; + uint32_t wrpxxr_mask; const struct stm32l4_part_info *part_info; }; +/* human readable list of families this drivers supports */ +static const char *device_families = "STM32L4/L4+/WB/G4/G0"; + static const struct stm32l4_rev stm32_415_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } }; @@ -158,16 +142,32 @@ static const struct stm32l4_rev stm32_435_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; +static const struct stm32l4_rev stm32_460_revs[] = { + { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" }, +}; + static const struct stm32l4_rev stm32_461_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, }; static const struct stm32l4_rev stm32_462_revs[] = { - { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, }; static const struct stm32l4_rev stm32_464_revs[] = { - { 0x1000, "A" }, + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" }, +}; + +static const struct stm32l4_rev stm32_466_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" }, +}; + +static const struct stm32l4_rev stm32_468_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, +}; + +static const struct stm32l4_rev stm32_469_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; static const struct stm32l4_rev stm32_470_revs[] = { @@ -203,6 +203,16 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, }, + { + .id = 0x460, + .revs = stm32_460_revs, + .num_revs = ARRAY_SIZE(stm32_460_revs), + .device_str = "STM32G07/G08xx", + .max_flash_size_kb = 128, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, { .id = 0x461, .revs = stm32_461_revs, @@ -233,6 +243,36 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, }, + { + .id = 0x466, + .revs = stm32_466_revs, + .num_revs = ARRAY_SIZE(stm32_466_revs), + .device_str = "STM32G03/G04xx", + .max_flash_size_kb = 64, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x468, + .revs = stm32_468_revs, + .num_revs = ARRAY_SIZE(stm32_468_revs), + .device_str = "STM32G43/G44xx", + .max_flash_size_kb = 128, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, + { + .id = 0x469, + .revs = stm32_469_revs, + .num_revs = ARRAY_SIZE(stm32_469_revs), + .device_str = "STM32G47/G48xx", + .max_flash_size_kb = 512, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, { .id = 0x470, .revs = stm32_470_revs, @@ -283,6 +323,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) bank->write_start_alignment = bank->write_end_alignment = 8; stm32l4_info->probed = false; + stm32l4_info->user_bank_size = bank->size; return ERROR_OK; } @@ -409,7 +450,8 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; } -static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask) +static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, + uint32_t value, uint32_t mask) { uint32_t optiondata; int retval, retval2; @@ -454,17 +496,23 @@ static int stm32l4_protect_check(struct flash_bank *bank) uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br; stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar); stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br); - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar); - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br); + if (stm32l4_info->part_info->has_dual_bank) { + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar); + stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br); + } else { + /* prevent unintialized errors */ + wrp2ar = 0; + wrp2br = 0; + } - const uint8_t wrp1a_start = wrp1ar & 0xFF; - const uint8_t wrp1a_end = (wrp1ar >> 16) & 0xFF; - const uint8_t wrp1b_start = wrp1br & 0xFF; - const uint8_t wrp1b_end = (wrp1br >> 16) & 0xFF; - const uint8_t wrp2a_start = wrp2ar & 0xFF; - const uint8_t wrp2a_end = (wrp2ar >> 16) & 0xFF; - const uint8_t wrp2b_start = wrp2br & 0xFF; - const uint8_t wrp2b_end = (wrp2br >> 16) & 0xFF; + const uint8_t wrp1a_start = wrp1ar & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1a_end = (wrp1ar >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1b_start = wrp1br & stm32l4_info->wrpxxr_mask; + const uint8_t wrp1b_end = (wrp1br >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2a_start = wrp2ar & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2a_end = (wrp2ar >> 16) & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2b_start = wrp2br & stm32l4_info->wrpxxr_mask; + const uint8_t wrp2b_end = (wrp2br >> 16) & stm32l4_info->wrpxxr_mask; for (int i = 0; i < bank->num_sectors; i++) { if (i < stm32l4_info->bank1_sectors) { @@ -476,6 +524,7 @@ static int stm32l4_protect_check(struct flash_bank *bank) else bank->sectors[i].is_protected = 0; } else { + assert(stm32l4_info->part_info->has_dual_bank == true); uint8_t snb; snb = i - stm32l4_info->bank1_sectors; if (((snb >= wrp2a_start) && @@ -496,8 +545,7 @@ static int stm32l4_erase(struct flash_bank *bank, int first, int last) int i; int retval, retval2; - 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"); @@ -512,7 +560,7 @@ static int stm32l4_erase(struct flash_bank *bank, int first, int last) Sector Erase To erase a sector, follow the procedure below: 1. Check that no Flash memory operation is ongoing by - checking the BSY bit in the FLASH_SR register + checking the BSY bit in the FLASH_SR register 2. Set the PER bit and select the page and bank you wish to erase in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register @@ -586,15 +634,15 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last /* Count is in double-words */ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) + uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; - uint32_t buffer_size = 16384; + uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[5]; + struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -616,18 +664,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } - /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != - ERROR_OK) { - buffer_size /= 2; - if (buffer_size <= 256) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm */ - target_free_working_area(target, write_algorithm); + /* 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); + if (buffer_size < 256) { + LOG_WARNING("large enough working area not available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } else if (buffer_size > 16384) { + /* probably won't benefit from more than 16k ... */ + buffer_size = 16384; + } - LOG_WARNING("large enough working area not available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + LOG_ERROR("allocating working area failed"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; @@ -637,17 +686,19 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, 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 regs base */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash status register */ + init_reg_param(®_params[5], "r5", 32, PARAM_OUT); /* flash control register */ 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_info->part_info->flash_regs_base); + buf_set_u32(reg_params[4].value, 0, 32, stm32l4_info->part_info->flash_regs_base + STM32_FLASH_SR); + buf_set_u32(reg_params[5].value, 0, 32, stm32l4_info->part_info->flash_regs_base + STM32_FLASH_CR); retval = target_run_flash_async_algorithm(target, buffer, count, 8, 0, NULL, - 5, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); @@ -676,14 +727,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; } static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) + uint32_t offset, uint32_t count) { - int retval, retval2; + int retval = ERROR_OK, retval2; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -695,6 +747,43 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, assert(offset % 8 == 0); assert(count % 8 == 0); + /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether + * data to be written does not go into a gap: + * suppose buffer is fully contained in bank from sector 0 to sector + * num->sectors - 1 and sectors are ordered according to offset + */ + struct flash_sector *head = &bank->sectors[0]; + struct flash_sector *tail = &bank->sectors[bank->num_sectors - 1]; + + while ((head < tail) && (offset >= (head + 1)->offset)) { + /* buffer does not intersect head nor gap behind head */ + head++; + } + + while ((head < tail) && (offset + count <= (tail - 1)->offset + (tail - 1)->size)) { + /* buffer does not intersect tail nor gap before tail */ + --tail; + } + + LOG_DEBUG("data: 0x%08" PRIx32 " - 0x%08" PRIx32 ", sectors: 0x%08" PRIx32 " - 0x%08" PRIx32, + offset, offset + count - 1, head->offset, tail->offset + tail->size - 1); + + /* Now check that there is no gap from head to tail, this should work + * even for multiple or non-symmetric gaps + */ + while (head < tail) { + if (head->offset + head->size != (head + 1)->offset) { + LOG_ERROR("write into gap from " TARGET_ADDR_FMT " to " TARGET_ADDR_FMT, + bank->base + head->offset + head->size, + bank->base + (head + 1)->offset - 1); + retval = ERROR_FLASH_DST_OUT_OF_BANK; + } + head++; + } + + if (retval != ERROR_OK) + return retval; + retval = stm32l4_unlock_reg(bank); if (retval != ERROR_OK) goto err_lock; @@ -713,9 +802,17 @@ err_lock: static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { - int retval = target_read_u32(bank->target, DBGMCU_IDCODE, id); - if (retval != ERROR_OK) - return retval; + int retval; + + /* try stm32l4/l4+/wb/g4 id register first, then stm32g0 id register */ + retval = target_read_u32(bank->target, DBGMCU_IDCODE_L4_G4, id); + if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { + retval = target_read_u32(bank->target, DBGMCU_IDCODE_G0, id); + if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { + LOG_ERROR("can't get device id"); + return (retval == ERROR_OK) ? ERROR_FAIL : retval; + } + } return retval; } @@ -725,13 +822,13 @@ static int stm32l4_probe(struct flash_bank *bank) struct target *target = bank->target; struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info; - uint16_t flash_size_in_kb = 0xffff; + uint16_t flash_size_kb = 0xffff; uint32_t device_id; uint32_t options; stm32l4_info->probed = false; - /* read stm32 device id register */ + /* read stm32 device id registers */ int retval = stm32l4_read_idcode(bank, &stm32l4_info->idcode); if (retval != ERROR_OK) return retval; @@ -744,7 +841,7 @@ static int stm32l4_probe(struct flash_bank *bank) } if (!stm32l4_info->part_info) { - LOG_WARNING("Cannot identify target as an STM32 L4 or WB family device."); + LOG_WARNING("Cannot identify target as an %s family device.", device_families); return ERROR_FAIL; } @@ -758,21 +855,28 @@ static int stm32l4_probe(struct flash_bank *bank) LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, device_info); /* get flash size from target. */ - retval = target_read_u16(target, part_info->fsize_addr, &flash_size_in_kb); + retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb); /* failed reading flash size or flash size invalid (early silicon), * default to max target family */ - if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0 - || flash_size_in_kb > part_info->max_flash_size_kb) { + if (retval != ERROR_OK || flash_size_kb == 0xffff || flash_size_kb == 0 + || flash_size_kb > part_info->max_flash_size_kb) { LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash", part_info->max_flash_size_kb); - flash_size_in_kb = part_info->max_flash_size_kb; + flash_size_kb = part_info->max_flash_size_kb; } - LOG_INFO("flash size = %dkbytes", flash_size_in_kb); + /* if the user sets the size manually then ignore the probed value + * this allows us to work around devices that have a invalid flash size register value */ + if (stm32l4_info->user_bank_size) { + LOG_WARNING("overriding size register by configured bank size - MAY CAUSE TROUBLE"); + flash_size_kb = stm32l4_info->user_bank_size / 1024; + } + + LOG_INFO("flash size = %dkbytes", flash_size_kb); /* did we assign a flash size? */ - assert((flash_size_in_kb != 0xffff) && flash_size_in_kb); + assert((flash_size_kb != 0xffff) && flash_size_kb); /* read flash option register */ retval = stm32l4_read_flash_reg(bank, STM32_FLASH_OPTR, &options); @@ -783,13 +887,13 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_info->hole_sectors = 0; int num_pages = 0; - int page_size = 0; + int page_size_kb = 0; stm32l4_info->dual_bank_mode = false; switch (device_id) { - case 0x415: - case 0x461: + case 0x415: /* STM32L47/L48xx */ + case 0x461: /* STM32L49/L4Axx */ /* if flash size is max (1M) the device is always dual bank * 0x415: has variants with 512K * 0x461: has variants with 512 and 256 @@ -798,51 +902,71 @@ static int stm32l4_probe(struct flash_bank *bank) * else -> dual bank without gap * note: the page size is invariant */ - page_size = 2048; - num_pages = flash_size_in_kb / 2; + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; /* check DUAL_BANK bit[21] if the flash is less than 1M */ - if (flash_size_in_kb == 1024 || (options & BIT(21))) { + if (flash_size_kb == 1024 || (options & BIT(21))) { stm32l4_info->dual_bank_mode = true; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x435: - case 0x462: - case 0x464: + case 0x435: /* STM32L43/L44xx */ + case 0x460: /* STM32G07/G08xx */ + case 0x462: /* STM32L45/L46xx */ + case 0x464: /* STM32L41/L42xx */ + case 0x466: /* STM32G03/G04xx */ + case 0x468: /* STM32G43/G44xx */ /* single bank flash */ - page_size = 2048; - num_pages = flash_size_in_kb / 2; + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; break; - case 0x470: - case 0x471: + case 0x469: /* STM32G47/G48xx */ + /* STM32G47/8 can be single/dual bank: + * if DUAL_BANK = 0 -> single bank + * else -> dual bank WITH gap + */ + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + if (options & BIT(22)) { + stm32l4_info->dual_bank_mode = true; + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages / 2; + + /* for devices with trimmed flash, there is a gap between both banks */ + stm32l4_info->hole_sectors = + (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb); + } + break; + case 0x470: /* STM32L4R/L4Sxx */ + case 0x471: /* STM32L4P5/L4Q5x */ /* STM32L4R/S can be single/dual bank: * if size = 2M check DBANK bit(22) * if size = 1M check DB1M bit(21) * STM32L4P/Q can be single/dual bank * if size = 1M check DBANK bit(22) * if size = 512K check DB512K bit(21) - * in single bank configuration the page size is 8K - * else (dual bank) the page size is 4K without gap between banks */ - page_size = 8192; - num_pages = flash_size_in_kb / 8; + page_size_kb = 8; + num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - const bool use_dbank_bit = flash_size_in_kb == part_info->max_flash_size_kb; + const bool use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; if ((use_dbank_bit && (options & BIT(22))) || (!use_dbank_bit && (options & BIT(21)))) { stm32l4_info->dual_bank_mode = true; - page_size = 4096; - num_pages = flash_size_in_kb / 4; + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages / 2; } break; - case 0x495: + case 0x495: /* STM32WB5x */ /* single bank flash */ - page_size = 4096; - num_pages = flash_size_in_kb / 4; + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; break; default: @@ -852,21 +976,41 @@ static int stm32l4_probe(struct flash_bank *bank) LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single"); - const int gap_size = stm32l4_info->hole_sectors * page_size; + const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb; - if (stm32l4_info->dual_bank_mode & gap_size) { - LOG_INFO("gap detected starting from %0x08" PRIx32 " to %0x08" PRIx32, - 0x8000000 + stm32l4_info->bank1_sectors * page_size, - 0x8000000 + stm32l4_info->bank1_sectors * page_size + gap_size); + if (gap_size_kb != 0) { + LOG_INFO("gap detected from 0x%08" PRIx32 " to 0x%08" PRIx32, + STM32_FLASH_BANK_BASE + stm32l4_info->bank1_sectors + * page_size_kb * 1024, + STM32_FLASH_BANK_BASE + (stm32l4_info->bank1_sectors + * page_size_kb + gap_size_kb) * 1024 - 1); } + /* number of significant bits in WRPxxR differs per device, + * always right adjusted, on some devices non-implemented + * bits read as '0', on others as '1' ... + * notably G4 Cat. 2 implement only 6 bits, contradicting the RM + */ + + /* use *max_flash_size* instead of actual size as the trimmed versions + * certainly use the same number of bits + * max_flash_size is always power of two, so max_pages too + */ + uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb; + assert((max_pages & (max_pages - 1)) == 0); + + /* in dual bank mode number of pages is doubled, but extra bit is bank selection */ + stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1); + assert((stm32l4_info->wrpxxr_mask & 0xFFFF0000) == 0); + LOG_DEBUG("WRPxxR mask 0x%04" PRIx16, stm32l4_info->wrpxxr_mask); + if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } - bank->size = flash_size_in_kb * 1024 + gap_size; - bank->base = 0x08000000; + bank->size = (flash_size_kb + gap_size_kb) * 1024; + bank->base = STM32_FLASH_BANK_BASE; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (bank->sectors == NULL) { @@ -875,12 +1019,12 @@ static int stm32l4_probe(struct flash_bank *bank) } for (int i = 0; i < bank->num_sectors; i++) { - bank->sectors[i].offset = i * page_size; + bank->sectors[i].offset = i * page_size_kb * 1024; /* in dual bank configuration, if there is a gap between banks * we fix up the sector offset to consider this gap */ if (i >= stm32l4_info->bank1_sectors && stm32l4_info->hole_sectors) - bank->sectors[i].offset += gap_size; - bank->sectors[i].size = page_size; + bank->sectors[i].offset += gap_size_kb * 1024; + bank->sectors[i].size = page_size_kb * 1024; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } @@ -911,18 +1055,20 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size) rev_str = part_info->revs[i].str; if (rev_str != NULL) { - snprintf(buf, buf_size, "%s - Rev: %s", - part_info->device_str, rev_str); + snprintf(buf, buf_size, "%s - Rev: %s%s", + part_info->device_str, rev_str, stm32l4_info->probed ? + (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); return ERROR_OK; } } } - snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)", - part_info->device_str, rev_id); + snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)%s", + part_info->device_str, rev_id, stm32l4_info->probed ? + (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); return ERROR_OK; } else { - snprintf(buf, buf_size, "Cannot identify target as an STM32 L4 or WB device"); + snprintf(buf, buf_size, "Cannot identify target as an %s device", device_families); return ERROR_FAIL; } @@ -1073,10 +1219,19 @@ COMMAND_HANDLER(stm32l4_handle_option_load_command) if (ERROR_OK != retval) return retval; - /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes reload */ - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBLLAUNCH); + /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload, + * but the RMs explicitly do *NOT* list this as power-on reset cause, and: + * "Note: If the read protection is set while the debugger is still + * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset." + */ + retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBL_LAUNCH); + + command_print(CMD, "stm32l4x option load completed. Power-on reset might be required"); + + /* Need to re-probe after change */ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + stm32l4_info->probed = false; - command_print(CMD, "stm32l4x option load (POR) completed."); return retval; } diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h new file mode 100644 index 000000000..abd8010fc --- /dev/null +++ b/src/flash/nor/stm32l4x.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2015 by Uwe Bonnes * + * bon@elektron.ikp.physik.tu-darmstadt.de * + * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * 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, see . * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_STM32L4X +#define OPENOCD_FLASH_NOR_STM32L4X + +/* Flash registers offsets */ +#define STM32_FLASH_ACR 0x00 +#define STM32_FLASH_KEYR 0x08 +#define STM32_FLASH_OPTKEYR 0x0c +#define STM32_FLASH_SR 0x10 +#define STM32_FLASH_CR 0x14 +#define STM32_FLASH_OPTR 0x20 +#define STM32_FLASH_WRP1AR 0x2c +#define STM32_FLASH_WRP1BR 0x30 +#define STM32_FLASH_WRP2AR 0x4c +#define STM32_FLASH_WRP2BR 0x50 + +/* FLASH_CR register bits */ +#define FLASH_PG (1 << 0) +#define FLASH_PER (1 << 1) +#define FLASH_MER1 (1 << 2) +#define FLASH_PAGE_SHIFT 3 +#define FLASH_CR_BKER (1 << 11) +#define FLASH_MER2 (1 << 15) +#define FLASH_STRT (1 << 16) +#define FLASH_OPTSTRT (1 << 17) +#define FLASH_EOPIE (1 << 24) +#define FLASH_ERRIE (1 << 25) +#define FLASH_OBL_LAUNCH (1 << 27) +#define FLASH_OPTLOCK (1 << 30) +#define FLASH_LOCK (1 << 31) + +/* FLASH_SR register bits */ +#define FLASH_BSY (1 << 16) + +/* Fast programming not used => related errors not used*/ +#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ +#define FLASH_SIZERR (1 << 6) /* Size error */ +#define FLASH_PGAERR (1 << 5) /* Programming alignment error */ +#define FLASH_WRPERR (1 << 4) /* Write protection error */ +#define FLASH_PROGERR (1 << 3) /* Programming error */ +#define FLASH_OPERR (1 << 1) /* Operation error */ +#define FLASH_EOP (1 << 0) /* End of operation */ +#define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | \ + FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR) + +/* register unlock keys */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* option register unlock key */ +#define OPTKEY1 0x08192A3B +#define OPTKEY2 0x4C5D6E7F + +#define RDP_LEVEL_0 0xAA +#define RDP_LEVEL_1 0xBB +#define RDP_LEVEL_2 0xCC + +/* other registers */ +#define DBGMCU_IDCODE_G0 0x40015800 +#define DBGMCU_IDCODE_L4_G4 0xE0042000 +#define DBGMCU_IDCODE_L5 0xE0044000 + +#define STM32_FLASH_BANK_BASE 0x08000000 + +#endif diff --git a/tcl/target/stm32g0x.cfg b/tcl/target/stm32g0x.cfg new file mode 100644 index 000000000..50836ea82 --- /dev/null +++ b/tcl/target/stm32g0x.cfg @@ -0,0 +1,88 @@ +# script for stm32g0x family + +# +# stm32g0 devices support SWD transports only. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32g0x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# Smallest proposed target has 8kB ram, use 4kB by default to avoid surprises +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + # Section 37.5.5 - corresponds to Cortex-M0+ + set _CPUTAPID 0x0bc11477 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME + +# reasonable default +adapter speed 2000 + +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 stm32g0x_default_reset_start {} { + # Reset clock is HSI16 (16 MHz) + adapter speed 2000 +} + +proc stm32g0x_default_examine_end {} { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0x40015804 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0x40015808 0x00001800 0 +} + +proc stm32g0x_default_reset_init {} { + # Increase clock to 64 Mhz + mmw 0x40022000 0x00000002 0x00000005 ;# FLASH_ACR: Latency = 2 + mww 0x4002100C 0x30000802 ;# RCC_PLLCFGR = PLLR=/2, PLLN=8, PLLM=/1, PLLSRC=0x2 + mmw 0x40021000 0x01000000 0x00000000 ;# RCC_CR |= PLLON + mmw 0x40021008 0x00000002 0x00000005 ;# RCC_CFGR: SW=PLLRCLK + + # Boost JTAG frequency + adapter speed 4000 +} + +# Default hooks +$_TARGETNAME configure -event examine-end { stm32g0x_default_examine_end } +$_TARGETNAME configure -event reset-start { stm32g0x_default_reset_start } +$_TARGETNAME configure -event reset-init { stm32g0x_default_reset_init } diff --git a/tcl/target/stm32g4x.cfg b/tcl/target/stm32g4x.cfg new file mode 100644 index 000000000..9f144a07e --- /dev/null +++ b/tcl/target/stm32g4x.cfg @@ -0,0 +1,103 @@ +# script for stm32g4x family + +# +# stm32g4 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 stm32g4x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# Smallest current target has 32kB ram, use 16kB by default to avoid surprises +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + # See STM Document RM0440 + # Section 46.6.3 - corresponds to Cortex-M4 r0p1 + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x2ba01477 + } +} + +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 + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME + +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 +} + +# reasonable default +adapter speed 2000 + +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 +} + +$_TARGETNAME configure -event reset-init { + # CPU comes out of reset with HSION | HSIRDY. + # Use HSI 16 MHz clock, compliant even with VOS == 2. + # 1 WS compliant with VOS == 2 and 16 MHz. + mmw 0x40022000 0x00000001 0x0000000E ;# FLASH_ACR: Latency = 1 + mmw 0x40021000 0x00000100 0x00000000 ;# RCC_CR |= HSION + mmw 0x40021008 0x00000001 0x00000002 ;# RCC_CFGR: SW=HSI16 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is HSI (16 MHz) + adapter speed 2000 +} + +$_TARGETNAME configure -event examine-end { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0xE0042004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZR1 |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0042008 0x00001800 0 +} + +$_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 0xE0042004 0x00000020 0 +}