bcad988437acb5fea8e036170b6f8ffc93b82a57
[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 #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 */