mirror of
https://git.code.sf.net/p/openocd/code
synced 2025-02-14 14:48:18 +00:00
382148e4dd
With the old checkpatch we cannot use the correct format for the SPDX tags in the file .c, in fact the C99 comments are not allowed and we had to use the block comment. With the new checkpatch, let's switch to the correct SPDX format. Change created automatically through the command: sed -i \ 's,^/\* *\(SPDX-License-Identifier: .*[^ ]\) *\*/$,// \1,' \ $(find src/ contrib/ -name \*.c) Change-Id: I6da16506baa7af718947562505dd49606d124171 Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/7153 Tested-by: jenkins
192 lines
5.2 KiB
C
192 lines
5.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
/**
|
|
* Copyright (C) 2021 Tarek BOCHKATI
|
|
* tarek.bouchkati@st.com
|
|
*/
|
|
|
|
#define OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X
|
|
|
|
#include <stdint.h>
|
|
#include "../../../../src/flash/nor/stm32l4x.h"
|
|
|
|
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
|
|
*/
|
|
|
|
void write(volatile struct stm32l4_work_area *work_area,
|
|
uint8_t *fifo_end,
|
|
uint8_t *target_address,
|
|
uint32_t count)
|
|
{
|
|
volatile uint32_t *flash_sr = (uint32_t *) work_area->params.flash_sr_addr;
|
|
volatile uint32_t *flash_cr = (uint32_t *) work_area->params.flash_cr_addr;
|
|
|
|
/* optimization to avoid reading from memory each time */
|
|
uint8_t *rp_cache = work_area->fifo.rp;
|
|
|
|
/* fifo_start is used to wrap when we reach fifo_end */
|
|
uint8_t *fifo_start = rp_cache;
|
|
|
|
/* enable flash programming */
|
|
*flash_cr = FLASH_PG;
|
|
|
|
while (count) {
|
|
/* optimization to avoid reading from memory each time */
|
|
uint8_t *wp_cache = work_area->fifo.wp;
|
|
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 >= work_area->params.flash_word_size) {
|
|
copy_buffer_u32((uint32_t *)target_address,
|
|
(uint32_t *)rp_cache,
|
|
work_area->params.flash_word_size / 4);
|
|
|
|
/* update target_address and rp_cache */
|
|
target_address += work_area->params.flash_word_size;
|
|
rp_cache += work_area->params.flash_word_size;
|
|
|
|
/* wait for the busy flag */
|
|
while (*flash_sr & work_area->params.flash_sr_bsy_mask)
|
|
;
|
|
|
|
if (*flash_sr & FLASH_ERROR) {
|
|
work_area->fifo.rp = 0; /* set rp to zero 0 on error */
|
|
goto write_end;
|
|
}
|
|
|
|
/* 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->fifo.rp = rp_cache;
|
|
|
|
/* update fifo_size and count */
|
|
fifo_size -= work_area->params.flash_word_size;
|
|
count--;
|
|
}
|
|
}
|
|
|
|
write_end:
|
|
/* 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
|
|
/* device selector: STM32L5 | STM32U5 | STM32WB | STM32WL | STM32WL_CPU2 | STM32G0Bx | ... */
|
|
#define STM32U5
|
|
|
|
/* when using a secure device, and want to test the secure programming enable this define */
|
|
/* #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(STM32G0Bx)
|
|
# define FLASH_BSY_MASK (FLASH_BSY | FLASH_BSY2)
|
|
#else
|
|
# define FLASH_BSY_MASK FLASH_BSY
|
|
#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 uint32_t count = 2;
|
|
const uint32_t buf_size = count * FLASH_WORD_SIZE;
|
|
const uint32_t work_area_size = sizeof(struct stm32l4_work_area) + buf_size;
|
|
|
|
uint8_t work_area_buf[work_area_size];
|
|
struct stm32l4_work_area *workarea = (struct stm32l4_work_area *)work_area_buf;
|
|
|
|
/* fill the workarea struct */
|
|
workarea->params.flash_sr_addr = (uint32_t)(FLASH_SR);
|
|
workarea->params.flash_cr_addr = (uint32_t)(FLASH_CR);
|
|
workarea->params.flash_word_size = FLASH_WORD_SIZE;
|
|
workarea->params.flash_sr_bsy_mask = FLASH_BSY_MASK;
|
|
/* note: the workarea->stack is not used, in this configuration */
|
|
|
|
/* programming the existing memory raw content in workarea->fifo.buf */
|
|
/* feel free to fill the memory with magical values ... */
|
|
|
|
workarea->fifo.wp = (uint8_t *)(&workarea->fifo.buf + buf_size);
|
|
workarea->fifo.rp = (uint8_t *)&workarea->fifo.buf;
|
|
|
|
/* unlock the flash */
|
|
*FLASH_KEYR = KEY1;
|
|
*FLASH_KEYR = KEY2;
|
|
|
|
/* erase sector 0 */
|
|
*FLASH_CR = FLASH_PER | FLASH_STRT;
|
|
while (*FLASH_SR & FLASH_BSY)
|
|
;
|
|
|
|
/* flash address, should be aligned to FLASH_WORD_SIZE */
|
|
uint8_t *target_address = (uint8_t *) 0x8000000;
|
|
|
|
write(workarea,
|
|
(uint8_t *)(workarea + work_area_size),
|
|
target_address,
|
|
count);
|
|
|
|
while (1)
|
|
;
|
|
}
|
|
#endif /* DEBUG */
|