bcad988437acb5fea8e036170b6f8ffc93b82a57
[openocd.git] / contrib / loaders / flash / stm32 / stm32l4x.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /**
4 * Copyright (C) 2021 Tarek BOCHKATI
5 * tarek.bouchkati@st.com
6 */
7
8 #include <stdint.h>
9 #include "../../../../src/flash/nor/stm32l4x.h"
10
11 static inline __attribute__((always_inline))
12 void copy_buffer_u32(uint32_t *dst, uint32_t *src, int len)
13 {
14 for (int i = 0; i < len; i++)
15 dst[i] = src[i];
16 }
17
18 /* this function is assumes that fifo_size is multiple of flash_word_size
19 * this condition is ensured by target_run_flash_async_algorithm
20 */
21
22 void write(volatile struct stm32l4_work_area *work_area,
23 uint8_t *fifo_end,
24 uint8_t *target_address,
25 uint32_t count)
26 {
27 volatile uint32_t *flash_sr = (uint32_t *) work_area->params.flash_sr_addr;
28 volatile uint32_t *flash_cr = (uint32_t *) work_area->params.flash_cr_addr;
29
30 /* optimization to avoid reading from memory each time */
31 uint8_t *rp_cache = work_area->fifo.rp;
32
33 /* fifo_start is used to wrap when we reach fifo_end */
34 uint8_t *fifo_start = rp_cache;
35
36 /* enable flash programming */
37 *flash_cr = FLASH_PG;
38
39 while (count) {
40 /* optimization to avoid reading from memory each time */
41 uint8_t *wp_cache = work_area->fifo.wp;
42 if (wp_cache == 0)
43 break; /* aborted by target_run_flash_async_algorithm */
44
45 int32_t fifo_size = wp_cache - rp_cache;
46 if (fifo_size < 0) {
47 /* consider the linear fifo, we will wrap later */
48 fifo_size = fifo_end - rp_cache;
49 }
50
51 /* wait for at least a flash word */
52 while (fifo_size >= work_area->params.flash_word_size) {
53 copy_buffer_u32((uint32_t *)target_address,
54 (uint32_t *)rp_cache,
55 work_area->params.flash_word_size / 4);
56
57 /* update target_address and rp_cache */
58 target_address += work_area->params.flash_word_size;
59 rp_cache += work_area->params.flash_word_size;
60
61 /* wait for the busy flag */
62 while (*flash_sr & work_area->params.flash_sr_bsy_mask)
63 ;
64
65 if (*flash_sr & FLASH_ERROR) {
66 work_area->fifo.rp = 0; /* set rp to zero 0 on error */
67 goto write_end;
68 }
69
70 /* wrap if reach the fifo_end, and update rp in memory */
71 if (rp_cache >= fifo_end)
72 rp_cache = fifo_start;
73
74 /* flush the rp cache value,
75 * so target_run_flash_async_algorithm can fill the circular fifo */
76 work_area->fifo.rp = rp_cache;
77
78 /* update fifo_size and count */
79 fifo_size -= work_area->params.flash_word_size;
80 count--;
81 }
82 }
83
84 write_end:
85 /* disable flash programming */
86 *flash_cr = 0;
87
88 /* soft break the loader */
89 __asm("bkpt 0");
90 }
91
92 /* by enabling this define 'DEBUG':
93 * the main() function can help help debugging the loader algo
94 * note: the application should be linked into RAM */
95
96 /* #define DEBUG */
97
98 #ifdef DEBUG
99 /* device selector: STM32L5 | STM32U5 | STM32WB | STM32WL | STM32WL_CPU2 | STM32G0Bx | ... */
100 #define STM32U5
101
102 /* when using a secure device, and want to test the secure programming enable this define */
103 /* #define SECURE */
104
105 #if defined(STM32U5)
106 # define FLASH_WORD_SIZE 16
107 #else
108 # define FLASH_WORD_SIZE 8
109 #endif
110
111 #if defined(STM32WB) || defined(STM32WL)
112 # define FLASH_BASE 0x58004000
113 #else
114 # define FLASH_BASE 0x40022000
115 #endif
116
117 #if defined(STM32G0Bx)
118 # define FLASH_BSY_MASK (FLASH_BSY | FLASH_BSY2)
119 #else
120 # define FLASH_BSY_MASK FLASH_BSY
121 #endif
122
123 #if defined(STM32L5) || defined(STM32U5)
124 # ifdef SECURE
125 # define FLASH_KEYR_OFFSET 0x0c
126 # define FLASH_SR_OFFSET 0x24
127 # define FLASH_CR_OFFSET 0x2c
128 # else
129 # define FLASH_KEYR_OFFSET 0x08
130 # define FLASH_SR_OFFSET 0x20
131 # define FLASH_CR_OFFSET 0x28
132 # endif
133 #elif defined(STM32WL_CPU2)
134 # define FLASH_KEYR_OFFSET 0x08
135 # define FLASH_SR_OFFSET 0x60
136 # define FLASH_CR_OFFSET 0x64
137 #else
138 # define FLASH_KEYR_OFFSET 0x08
139 # define FLASH_SR_OFFSET 0x10
140 # define FLASH_CR_OFFSET 0x14
141 #endif
142
143 #define FLASH_KEYR (uint32_t *)((FLASH_BASE) + (FLASH_KEYR_OFFSET))
144 #define FLASH_SR (uint32_t *)((FLASH_BASE) + (FLASH_SR_OFFSET))
145 #define FLASH_CR (uint32_t *)((FLASH_BASE) + (FLASH_CR_OFFSET))
146
147 int main()
148 {
149 const uint32_t count = 2;
150 const uint32_t buf_size = count * FLASH_WORD_SIZE;
151 const uint32_t work_area_size = sizeof(struct stm32l4_work_area) + buf_size;
152
153 uint8_t work_area_buf[work_area_size];
154 struct stm32l4_work_area *workarea = (struct stm32l4_work_area *)work_area_buf;
155
156 /* fill the workarea struct */
157 workarea->params.flash_sr_addr = (uint32_t)(FLASH_SR);
158 workarea->params.flash_cr_addr = (uint32_t)(FLASH_CR);
159 workarea->params.flash_word_size = FLASH_WORD_SIZE;
160 workarea->params.flash_sr_bsy_mask = FLASH_BSY_MASK;
161 /* note: the workarea->stack is not used, in this configuration */
162
163 /* programming the existing memory raw content in workarea->fifo.buf */
164 /* feel free to fill the memory with magical values ... */
165
166 workarea->fifo.wp = (uint8_t *)(&workarea->fifo.buf + buf_size);
167 workarea->fifo.rp = (uint8_t *)&workarea->fifo.buf;
168
169 /* unlock the flash */
170 *FLASH_KEYR = KEY1;
171 *FLASH_KEYR = KEY2;
172
173 /* erase sector 0 */
174 *FLASH_CR = FLASH_PER | FLASH_STRT;
175 while (*FLASH_SR & FLASH_BSY)
176 ;
177
178 /* flash address, should be aligned to FLASH_WORD_SIZE */
179 uint8_t *target_address = (uint8_t *) 0x8000000;
180
181 write(workarea,
182 (uint8_t *)(workarea + work_area_size),
183 target_address,
184 count);
185
186 while (1)
187 ;
188 }
189 #endif /* DEBUG */

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)