54c88a3355b0062b2bd60a6503acf2311b896753
[fw/openocd] / 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 #define OPENOCD_CONTRIB_LOADERS_FLASH_STM32_STM32L4X
9
10 #include <stdint.h>
11 #include "../../../../src/flash/nor/stm32l4x.h"
12
13 static inline __attribute__((always_inline))
14 void copy_buffer_u32(uint32_t *dst, uint32_t *src, int len)
15 {
16         for (int i = 0; i < len; i++)
17                 dst[i] = src[i];
18 }
19
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
22  */
23
24 void write(volatile struct stm32l4_work_area *work_area,
25                    uint8_t *fifo_end,
26                    uint8_t *target_address,
27                    uint32_t count)
28 {
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;
31
32         /* optimization to avoid reading from memory each time */
33         uint8_t *rp_cache  = work_area->fifo.rp;
34
35         /* fifo_start is used to wrap when we reach fifo_end */
36         uint8_t *fifo_start = rp_cache;
37
38         /* enable flash programming */
39         *flash_cr = FLASH_PG;
40
41         while (count) {
42                 /* optimization to avoid reading from memory each time */
43                 uint8_t *wp_cache  = work_area->fifo.wp;
44                 if (wp_cache == 0)
45                         break; /* aborted by target_run_flash_async_algorithm */
46
47                 int32_t fifo_size = wp_cache - rp_cache;
48                 if (fifo_size < 0) {
49                         /* consider the linear fifo, we will wrap later */
50                         fifo_size = fifo_end - rp_cache;
51                 }
52
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,
56                                         (uint32_t *)rp_cache,
57                                         work_area->params.flash_word_size / 4);
58
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;
62
63                         /* wait for the busy flag */
64                         while (*flash_sr & work_area->params.flash_sr_bsy_mask)
65                                 ;
66
67                         if (*flash_sr & FLASH_ERROR) {
68                                 work_area->fifo.rp = 0; /* set rp to zero 0 on error */
69                                 goto write_end;
70                         }
71
72                         /* wrap if reach the fifo_end, and update rp in memory */
73                         if (rp_cache >= fifo_end)
74                                 rp_cache = fifo_start;
75
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;
79
80                         /* update fifo_size and count */
81                         fifo_size -= work_area->params.flash_word_size;
82                         count--;
83                 }
84         }
85
86 write_end:
87         /* disable flash programming */
88         *flash_cr = 0;
89
90         /* soft break the loader */
91         __asm("bkpt 0");
92 }
93
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 */
97
98 /* #define DEBUG */
99
100 #ifdef DEBUG
101 /* device selector: STM32L5 | STM32U5 | STM32WB | STM32WL | STM32WL_CPU2 | STM32G0Bx | ... */
102 #define STM32U5
103
104 /* when using a secure device, and want to test the secure programming enable this define */
105 /* #define SECURE */
106
107 #if defined(STM32U5)
108 #  define FLASH_WORD_SIZE   16
109 #else
110 #  define FLASH_WORD_SIZE   8
111 #endif
112
113 #if defined(STM32WB) || defined(STM32WL)
114 #  define FLASH_BASE        0x58004000
115 #else
116 #  define FLASH_BASE        0x40022000
117 #endif
118
119 #if defined(STM32G0Bx)
120 #  define FLASH_BSY_MASK      (FLASH_BSY | FLASH_BSY2)
121 #else
122 #  define FLASH_BSY_MASK      FLASH_BSY
123 #endif
124
125 #if defined(STM32L5) || defined(STM32U5)
126 #  ifdef SECURE
127 #    define FLASH_KEYR_OFFSET 0x0c
128 #    define FLASH_SR_OFFSET   0x24
129 #    define FLASH_CR_OFFSET   0x2c
130 #  else
131 #    define FLASH_KEYR_OFFSET 0x08
132 #    define FLASH_SR_OFFSET   0x20
133 #    define FLASH_CR_OFFSET   0x28
134 #  endif
135 #elif defined(STM32WL_CPU2)
136 #  define FLASH_KEYR_OFFSET 0x08
137 #  define FLASH_SR_OFFSET   0x60
138 #  define FLASH_CR_OFFSET   0x64
139 #else
140 #  define FLASH_KEYR_OFFSET 0x08
141 #  define FLASH_SR_OFFSET   0x10
142 #  define FLASH_CR_OFFSET   0x14
143 #endif
144
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))
148
149 int main()
150 {
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;
154
155         uint8_t work_area_buf[work_area_size];
156         struct stm32l4_work_area *workarea = (struct stm32l4_work_area *)work_area_buf;
157
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 */
164
165         /* programming the existing memory raw content in workarea->fifo.buf */
166         /* feel free to fill the memory with magical values ... */
167
168         workarea->fifo.wp =  (uint8_t *)(&workarea->fifo.buf + buf_size);
169         workarea->fifo.rp =  (uint8_t *)&workarea->fifo.buf;
170
171         /* unlock the flash */
172         *FLASH_KEYR = KEY1;
173         *FLASH_KEYR = KEY2;
174
175         /* erase sector 0 */
176         *FLASH_CR = FLASH_PER | FLASH_STRT;
177         while (*FLASH_SR & FLASH_BSY)
178                 ;
179
180         /* flash address, should be aligned to FLASH_WORD_SIZE */
181         uint8_t *target_address = (uint8_t *) 0x8000000;
182
183         write(workarea,
184                   (uint8_t *)(workarea + work_area_size),
185                   target_address,
186                   count);
187
188         while (1)
189                 ;
190 }
191 #endif /* DEBUG */