1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2021 Tarek BOCHKATI
5 * tarek.bouchkati@st.com
8 #define OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X
11 #include "../../../../src/flash/nor/stm32l4x.h"
13 static inline __attribute__((always_inline))
14 void copy_buffer_u32(uint32_t *dst, uint32_t *src, int len)
16 for (int i = 0; i < len; i++)
20 /* this function is assumes that fifo_size is multiple of flash_word_size
21 * this condition is ensured by target_run_flash_async_algorithm
24 void write(volatile struct stm32l4_work_area *work_area,
26 uint8_t *target_address,
29 volatile uint32_t *flash_sr = (uint32_t *) work_area->params.flash_sr_addr;
30 volatile uint32_t *flash_cr = (uint32_t *) work_area->params.flash_cr_addr;
32 /* optimization to avoid reading from memory each time */
33 uint8_t *rp_cache = work_area->fifo.rp;
35 /* fifo_start is used to wrap when we reach fifo_end */
36 uint8_t *fifo_start = rp_cache;
38 /* enable flash programming */
42 /* optimization to avoid reading from memory each time */
43 uint8_t *wp_cache = work_area->fifo.wp;
45 break; /* aborted by target_run_flash_async_algorithm */
47 int32_t fifo_size = wp_cache - rp_cache;
49 /* consider the linear fifo, we will wrap later */
50 fifo_size = fifo_end - rp_cache;
53 /* wait for at least a flash word */
54 while (fifo_size >= work_area->params.flash_word_size) {
55 copy_buffer_u32((uint32_t *)target_address,
57 work_area->params.flash_word_size / 4);
59 /* update target_address and rp_cache */
60 target_address += work_area->params.flash_word_size;
61 rp_cache += work_area->params.flash_word_size;
63 /* wait for the busy flag */
64 while (*flash_sr & work_area->params.flash_sr_bsy_mask)
67 if (*flash_sr & FLASH_ERROR) {
68 work_area->fifo.rp = 0; /* set rp to zero 0 on error */
72 /* wrap if reach the fifo_end, and update rp in memory */
73 if (rp_cache >= fifo_end)
74 rp_cache = fifo_start;
76 /* flush the rp cache value,
77 * so target_run_flash_async_algorithm can fill the circular fifo */
78 work_area->fifo.rp = rp_cache;
80 /* update fifo_size and count */
81 fifo_size -= work_area->params.flash_word_size;
87 /* disable flash programming */
90 /* soft break the loader */
94 /* by enabling this define 'DEBUG':
95 * the main() function can help help debugging the loader algo
96 * note: the application should be linked into RAM */
101 /* device selector: STM32L5 | STM32U5 | STM32WB | STM32WL | STM32WL_CPU2 | STM32G0Bx | ... */
104 /* when using a secure device, and want to test the secure programming enable this define */
108 # define FLASH_WORD_SIZE 16
110 # define FLASH_WORD_SIZE 8
113 #if defined(STM32WB) || defined(STM32WL)
114 # define FLASH_BASE 0x58004000
116 # define FLASH_BASE 0x40022000
119 #if defined(STM32G0Bx)
120 # define FLASH_BSY_MASK (FLASH_BSY | FLASH_BSY2)
122 # define FLASH_BSY_MASK FLASH_BSY
125 #if defined(STM32L5) || defined(STM32U5)
127 # define FLASH_KEYR_OFFSET 0x0c
128 # define FLASH_SR_OFFSET 0x24
129 # define FLASH_CR_OFFSET 0x2c
131 # define FLASH_KEYR_OFFSET 0x08
132 # define FLASH_SR_OFFSET 0x20
133 # define FLASH_CR_OFFSET 0x28
135 #elif defined(STM32WL_CPU2)
136 # define FLASH_KEYR_OFFSET 0x08
137 # define FLASH_SR_OFFSET 0x60
138 # define FLASH_CR_OFFSET 0x64
140 # define FLASH_KEYR_OFFSET 0x08
141 # define FLASH_SR_OFFSET 0x10
142 # define FLASH_CR_OFFSET 0x14
145 #define FLASH_KEYR (uint32_t *)((FLASH_BASE) + (FLASH_KEYR_OFFSET))
146 #define FLASH_SR (uint32_t *)((FLASH_BASE) + (FLASH_SR_OFFSET))
147 #define FLASH_CR (uint32_t *)((FLASH_BASE) + (FLASH_CR_OFFSET))
151 const uint32_t count = 2;
152 const uint32_t buf_size = count * FLASH_WORD_SIZE;
153 const uint32_t work_area_size = sizeof(struct stm32l4_work_area) + buf_size;
155 uint8_t work_area_buf[work_area_size];
156 struct stm32l4_work_area *workarea = (struct stm32l4_work_area *)work_area_buf;
158 /* fill the workarea struct */
159 workarea->params.flash_sr_addr = (uint32_t)(FLASH_SR);
160 workarea->params.flash_cr_addr = (uint32_t)(FLASH_CR);
161 workarea->params.flash_word_size = FLASH_WORD_SIZE;
162 workarea->params.flash_sr_bsy_mask = FLASH_BSY_MASK;
163 /* note: the workarea->stack is not used, in this configuration */
165 /* programming the existing memory raw content in workarea->fifo.buf */
166 /* feel free to fill the memory with magical values ... */
168 workarea->fifo.wp = (uint8_t *)(&workarea->fifo.buf + buf_size);
169 workarea->fifo.rp = (uint8_t *)&workarea->fifo.buf;
171 /* unlock the flash */
176 *FLASH_CR = FLASH_PER | FLASH_STRT;
177 while (*FLASH_SR & FLASH_BSY)
180 /* flash address, should be aligned to FLASH_WORD_SIZE */
181 uint8_t *target_address = (uint8_t *) 0x8000000;
184 (uint8_t *)(workarea + work_area_size),