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/6109
-- gerrit commit 4b06e534356314ad2fd998d4321cc0616660894a Author: Tarek BOCHKATI <[email protected]> Date: Sat Mar 6 22:46:35 2021 +0100 flash/stm32l4x: switch to to c loader instead of assembly loader add loader argument for flash_word_size, to permit using the loader with STM32U5. Change-Id: I24cafc2ba637a065593a0506eae787b21080a0ba Signed-off-by: Tarek BOCHKATI <[email protected]> Reviewed-on: https://gerrit.st.com/c/stm32ide/official/openocd/+/197040 Tested-by: CITOOLS <[email protected]> Reviewed-by: Tarek BOUCHKATI <[email protected]> diff --git a/contrib/loaders/flash/stm32/Makefile b/contrib/loaders/flash/stm32/Makefile index b58b412..3c90a87 100644 --- a/contrib/loaders/flash/stm32/Makefile +++ b/contrib/loaders/flash/stm32/Makefile @@ -6,14 +6,19 @@ CC=$(CROSS_COMPILE)gcc OBJCOPY=$(CROSS_COMPILE)objcopy OBJDUMP=$(CROSS_COMPILE)objdump -CFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL + +AFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL +CFLAGS = -c -mthumb -nostdlib -nostartfiles -Os -g -fPIC all: stm32f1x.inc stm32f2x.inc stm32h7x.inc stm32l4x.inc stm32lx.inc .PHONY: clean %.elf: %.S - $(CC) $(CFLAGS) $< -o $@ + $(CC) $(AFLAGS) $< -o $@ + +stm32l4x.elf: stm32l4x.c + $(CC) $(CFLAGS) -mcpu=cortex-m0plus -Wa,-adhln=$(<:.c=.lst) $< -o $@ %.lst: %.elf $(OBJDUMP) -S $< > $@ diff --git a/contrib/loaders/flash/stm32/stm32l4x.S b/contrib/loaders/flash/stm32/stm32l4x.S deleted file mode 100644 index 9923ce7..0000000 --- a/contrib/loaders/flash/stm32/stm32l4x.S +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Spencer Oliver * - * [email protected] * - * * - * Copyright (C) 2011 Øyvind Harboe * - * [email protected] * - * * - * Copyright (C) 2015 Uwe Bonnes * - * [email protected] * - * * - * Copyright (C) 2018 Andreas Bolsch * - * [email protected] * - * * - * 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, write to the * - * Free Software Foundation, Inc. * - ***************************************************************************/ - - .text - .syntax unified - .cpu cortex-m0 - .thumb - -/* - * Params : - * r0 = workarea start, status (out) - * r1 = workarea end + 1 - * r2 = target address - * r3 = count (64bit words) - * r4 = flash status register - * r5 = flash control register - * - * Clobbered: - * r6/7 - temp (64-bit) - */ - -#include "../../../../src/flash/nor/stm32l4x.h" - - .thumb_func - .global _start - -_start: - mov r8, r3 /* copy dword count */ -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 - - 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] /* 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 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.c b/contrib/loaders/flash/stm32/stm32l4x.c new file mode 100644 index 0000000..069760f --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32l4x.c @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** + * Copyright (C) 2021 Tarek BOCHKATI + * [email protected] + */ + +#include <stdint.h> +#include "../../../../src/flash/nor/stm32l4x.h" + +struct work_area { + uint8_t *wp; + uint8_t *rp; +}; + +static inline __attribute__((always_inline)) void copy_buffer_u32(uint32_t *dst, uint32_t *src, int len) +{ + for (int i = 0; i < len; i++) + dst[i] = src[i]; +} + + +/* this function is assumes that fifo_size is multiple of flash_word_size + * this condition is ensured by target_run_flash_async_algorithm + * + * IMPORTANT: + * when updating this loader and re-compiling it, the stack arguments could be placed + * at a different offset from sp register. + * according the AAPCS, only the 4 32-bit first arguments are passed in the registers r0 to r4 + * the arguments starting from number 5 is passed in the stack. + * to make it work, you need to: + * - check the generated listing 'stm32l4x.lst + * - get the highest offset used with sp: + * example: ldr r3, [sp, #48] + * - change the size of 'write_algorithm_sp' working_area to this value + 4 + */ + +#ifndef DEBUG +__attribute__((naked)) +#endif +void write(volatile struct work_area *work_area, + uint8_t *fifo_end, + uint8_t *target_address, + uint32_t count, + volatile uint32_t *flash_sr, + volatile uint32_t *flash_cr, + uint32_t flash_word_size) +{ + uint8_t *rp_cache = work_area->rp; /* optimization to avoid reading from memory each time */ + uint8_t *fifo_start = rp_cache; /* used to wrap when we reach fifo_end */ + + /* enable flash programming */ + *flash_cr = FLASH_PG; + + while (count) { + uint8_t *wp_cache = work_area->wp; /* optimization to avoid reading from memory each time */ + if (wp_cache == 0) + break; /* aborted by target_run_flash_async_algorithm */ + + int32_t fifo_size = wp_cache - rp_cache; + if (fifo_size < 0) { + /* consider the linear fifo, we will wrap later */ + fifo_size = fifo_end - rp_cache; + } + + /* wait for at least a flash word */ + while (fifo_size >= flash_word_size) { /* same as checking for non-zero size */ + copy_buffer_u32((uint32_t *)target_address, (uint32_t *)rp_cache, flash_word_size / 4); + + /* update target_address and rp_cache */ + target_address += flash_word_size; + rp_cache += flash_word_size; + + /* wait for the busy flag */ + while (*flash_sr & FLASH_BSY) + ; + + if (*flash_sr & FLASH_ERROR) { + work_area->rp = 0; /* set rp to zero 0 on error */ + break; + } + + /* wrap if reach the fifo_end, and update rp in memory */ + if (rp_cache >= fifo_end) + rp_cache = fifo_start; + + /* flush the rp cache value, + * so target_run_flash_async_algorithm can fill the circular fifo */ + work_area->rp = rp_cache; + + /* update fifo_size and count */ + fifo_size -= flash_word_size; + count--; + } + } + + /* disable flash programming */ + *flash_cr = 0; + + /* soft break the loader */ + __asm("bkpt 0"); +} + +/* by enabling this define 'DEBUG': + * the main() function can help help debugging the loader algo + * note: the application should be linked into RAM */ + +/* #define DEBUG */ + +#ifdef DEBUG +#define STM32U5 +/* #define SECURE */ + +#if defined(STM32U5) +#define FLASH_WORD_SIZE 16 +#else +#define FLASH_WORD_SIZE 8 +#endif + +#if defined(STM32WB) || defined(STM32WL) +#define FLASH_BASE 0x58004000 +#else +#define FLASH_BASE 0x40022000 +#endif + +#if defined(STM32L5) || defined(STM32U5) +#ifdef SECURE +#define FLASH_KEYR_OFFSET 0x0c +#define FLASH_SR_OFFSET 0x24 +#define FLASH_CR_OFFSET 0x2c +#else +#define FLASH_KEYR_OFFSET 0x08 +#define FLASH_SR_OFFSET 0x20 +#define FLASH_CR_OFFSET 0x28 +#endif +#elif defined(STM32WL_CPU2) +#define FLASH_KEYR_OFFSET 0x08 +#define FLASH_SR_OFFSET 0x60 +#define FLASH_CR_OFFSET 0x64 +#else +#define FLASH_KEYR_OFFSET 0x08 +#define FLASH_SR_OFFSET 0x10 +#define FLASH_CR_OFFSET 0x14 +#endif + +#define FLASH_KEYR (uint32_t *)((FLASH_BASE) + (FLASH_KEYR_OFFSET)) +#define FLASH_SR (uint32_t *)((FLASH_BASE) + (FLASH_SR_OFFSET)) +#define FLASH_CR (uint32_t *)((FLASH_BASE) + (FLASH_CR_OFFSET)) + +int main() +{ + const int count = 2; + uint8_t *target_address = (uint8_t *) 0x8000000; /* flash address, should be aligned to FLASH_WORD_SIZE */ + + uint32_t work_area[(8 + count * FLASH_WORD_SIZE) / 4]; /* wp, rp, and buffer */ + work_area[0] = (uint32_t) &work_area[2] + count * FLASH_WORD_SIZE; /* wp */ + work_area[1] = (uint32_t) &work_area[2]; /* rp */ + + /* unlock the flash */ + *FLASH_KEYR = KEY1; + *FLASH_KEYR = KEY2; + + /* erase sector 0 */ + *FLASH_CR = FLASH_PER | FLASH_STRT; + while (*FLASH_SR & FLASH_BSY) + ; + + write((struct work_area *)work_area, + (uint8_t *)(work_area + 0x22), + target_address, + count, + FLASH_SR, + FLASH_CR, + FLASH_WORD_SIZE); + + while (1) + ; +} +#endif /* DEBUG */ diff --git a/contrib/loaders/flash/stm32/stm32l4x.inc b/contrib/loaders/flash/stm32/stm32l4x.inc index df5c7ed..0d69c05 100644 --- a/contrib/loaders/flash/stm32/stm32l4x.inc +++ b/contrib/loaders/flash/stm32/stm32l4x.inc @@ -1,7 +1,9 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -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, +0x02,0x91,0x41,0x68,0x0c,0x9d,0x01,0x91,0x01,0x21,0x0b,0x9c,0x00,0x93,0x21,0x60, +0xa9,0x08,0x03,0x91,0x01,0x99,0x00,0x9b,0x00,0x2b,0x03,0xd1,0x00,0x23,0x0b,0x9a, +0x13,0x60,0x00,0xbe,0x04,0x68,0x00,0x2c,0xf8,0xd0,0x64,0x1a,0x01,0xd5,0x02,0x9c, +0x64,0x1a,0xa5,0x42,0xef,0xd8,0x00,0x26,0x03,0xe0,0xb7,0x00,0xcb,0x59,0x01,0x36, +0xd3,0x51,0x03,0x9b,0xb3,0x42,0xf8,0xdc,0x52,0x19,0x49,0x19,0x0a,0x9b,0x1e,0x68, +0x80,0x23,0x37,0x00,0x5b,0x02,0x1f,0x40,0x1e,0x42,0xf7,0xd1,0x0a,0x9b,0x1e,0x68, +0xfa,0x23,0x1e,0x42,0x01,0xd0,0x47,0x60,0xd5,0xe7,0x02,0x9b,0x8b,0x42,0x00,0xd8, +0x01,0x99,0x00,0x9b,0x41,0x60,0x01,0x3b,0x64,0x1b,0x00,0x93,0xd9,0xe7, diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 01b512b..656282b 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1311,9 +1311,11 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; uint32_t buffer_size; struct working_area *write_algorithm; + struct working_area *write_algorithm_sp; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[6]; + struct reg_param reg_params[5]; + struct mem_param mem_params[3]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -1335,16 +1337,27 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } + /* write algorithm stack area */ + if (target_alloc_working_area(target, 48 + 4, &write_algorithm_sp) != ERROR_OK) { + LOG_WARNING("no working area for write code stack pointer"); + target_free_working_area(target, write_algorithm); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + /* 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); + * plus one dword for rp and one for wp */ + assert(stm32l4_info->data_width % 8 == 0); /* data_width should be multiple of dword */ + buffer_size = target_get_working_area_avail(target) & ~(stm32l4_info->data_width - 1); + buffer_size = buffer_size - stm32l4_info->data_width + 8; + 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); + target_free_working_area(target, write_algorithm_sp); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } else if (buffer_size > 16384) { - /* probably won't benefit from more than 16k ... */ - buffer_size = 16384; + } else if (buffer_size > 16392) { + /* probably won't benefit from more than 16k + 8 ... */ + buffer_size = 16392; } if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { @@ -1358,19 +1371,35 @@ 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 */ + + /* check the loader generated assembly to get where the first stack argument is stored */ + uint32_t mem_param_addr = write_algorithm_sp->address + write_algorithm_sp->size; + + /* important: loader exceeding arguments in the reversed order */ + /* flash word_len */ + mem_param_addr -= 4; + init_mem_param(&mem_params[2], mem_param_addr, 4, PARAM_OUT); + /* flash control register */ + mem_param_addr -= 4; + init_mem_param(&mem_params[1], mem_param_addr, 4, PARAM_OUT); + /* flash status register */ + mem_param_addr -= 4; + init_mem_param(&mem_params[0], mem_param_addr, 4, PARAM_OUT); 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, write_algorithm_sp->address); + + buf_set_u32(mem_params[0].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX)); + buf_set_u32(mem_params[1].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX)); + buf_set_u32(mem_params[2].value, 0, 32, stm32l4_info->data_width); retval = target_run_flash_async_algorithm(target, buffer, count, stm32l4_info->data_width, - 0, NULL, + ARRAY_SIZE(mem_params), mem_params, ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, @@ -1379,7 +1408,9 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, 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"); @@ -1393,6 +1424,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, } target_free_working_area(target, source); + target_free_working_area(target, write_algorithm_sp); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); @@ -1400,7 +1432,10 @@ 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]); + + destroy_mem_param(&mem_params[0]); + destroy_mem_param(&mem_params[1]); + destroy_mem_param(&mem_params[2]); return retval; } @@ -1537,12 +1572,6 @@ 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) -- _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
