1 /*
2 * Copyright (c) 2022 BrainCo Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "flash_gd32.h"
8
9 #include <zephyr/logging/log.h>
10 #include <zephyr/kernel.h>
11 #include <gd32_fmc.h>
12
13 LOG_MODULE_DECLARE(flash_gd32);
14
15 #define GD32_NV_FLASH_V2_NODE DT_INST(0, gd_gd32_nv_flash_v2)
16 #define GD32_NV_FLASH_V2_TIMEOUT DT_PROP(GD32_NV_FLASH_V2_NODE, max_erase_time_ms)
17
18 #if !defined(CONFIG_SOC_GD32A503)
19 /**
20 * @brief GD32 FMC v2 flash memory has 2 banks.
21 * Bank0 holds the first 512KB, bank1 is used give capacity for reset.
22 * The page size is the same within the same bank, but not equal for all banks.
23 */
24 #if (PRE_KB(512) >= SOC_NV_FLASH_SIZE)
25 #define GD32_NV_FLASH_V2_BANK0_SIZE SOC_NV_FLASH_SIZE
26 #define GD32_NV_FLASH_V2_BANK0_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank0_page_size)
27 #else
28 #define GD32_NV_FLASH_V2_BANK0_SIZE KB(512)
29 #define GD32_NV_FLASH_V2_BANK0_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank0_page_size)
30 #define GD32_NV_FLASH_V2_BANK1_SIZE (SOC_NV_FLASH_SIZE - KB(512))
31 #define GD32_NV_FLASH_V2_BANK1_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank1_page_size)
32 #endif
33
34 #elif defined(CONFIG_SOC_GD32A503)
35 /**
36 * @brief GD32A503 series flash memory has 2 banks.
37 * Bank0 holds the first 256KB, bank1 is used give capacity for reset.
38 * The page size is 1KB for all banks.
39 */
40 #if (PRE_KB(256) >= SOC_NV_FLASH_SIZE)
41 #define GD32_NV_FLASH_V2_BANK0_SIZE SOC_NV_FLASH_SIZE
42 #define GD32_NV_FLASH_V2_BANK0_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank0_page_size)
43 #else
44 #define GD32_NV_FLASH_V2_BANK0_SIZE KB(256)
45 #define GD32_NV_FLASH_V2_BANK0_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank0_page_size)
46 #define GD32_NV_FLASH_V2_BANK1_SIZE (SOC_NV_FLASH_SIZE - KB(256))
47 #define GD32_NV_FLASH_V2_BANK1_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank1_page_size)
48 #endif
49 #endif
50
51 #define GD32_FMC_V2_BANK0_WRITE_ERR (FMC_STAT0_PGERR | FMC_STAT0_WPERR)
52 #define GD32_FMC_V2_BANK0_ERASE_ERR FMC_STAT0_WPERR
53
54 #define GD32_FMC_V2_BANK1_WRITE_ERR (FMC_STAT1_PGERR | FMC_STAT1_WPERR)
55 #define GD32_FMC_V2_BANK1_ERASE_ERR FMC_STAT1_WPERR
56
57 #ifdef CONFIG_FLASH_PAGE_LAYOUT
58 static struct flash_pages_layout gd32_fmc_v2_layout[] = {
59 {
60 .pages_size = GD32_NV_FLASH_V2_BANK0_PAGE_SIZE,
61 .pages_count = GD32_NV_FLASH_V2_BANK0_SIZE / GD32_NV_FLASH_V2_BANK0_PAGE_SIZE
62 },
63 #ifdef GD32_NV_FLASH_V2_BANK1_SIZE
64 {
65 .pages_size = GD32_NV_FLASH_V2_BANK1_PAGE_SIZE,
66 .pages_count = GD32_NV_FLASH_V2_BANK1_SIZE / GD32_NV_FLASH_V2_BANK1_PAGE_SIZE
67 }
68 #endif
69 };
70 #endif
71
gd32_fmc_v2_bank0_unlock(void)72 static inline void gd32_fmc_v2_bank0_unlock(void)
73 {
74 FMC_KEY0 = UNLOCK_KEY0;
75 FMC_KEY0 = UNLOCK_KEY1;
76 }
77
gd32_fmc_v2_bank0_lock(void)78 static inline void gd32_fmc_v2_bank0_lock(void)
79 {
80 FMC_CTL0 |= FMC_CTL0_LK;
81 }
82
gd32_fmc_v2_bank0_wait_idle(void)83 static int gd32_fmc_v2_bank0_wait_idle(void)
84 {
85 const int64_t expired_time = k_uptime_get() + GD32_NV_FLASH_V2_TIMEOUT;
86
87 while (FMC_STAT0 & FMC_STAT0_BUSY) {
88 if (k_uptime_get() > expired_time) {
89 return -ETIMEDOUT;
90 }
91 }
92
93 return 0;
94 }
95
gd32_fmc_v2_bank0_write(off_t offset,const void * data,size_t len)96 static int gd32_fmc_v2_bank0_write(off_t offset, const void *data, size_t len)
97 {
98 flash_prg_t *prg_flash = (flash_prg_t *)((uint8_t *)SOC_NV_FLASH_ADDR + offset);
99 flash_prg_t *prg_data = (flash_prg_t *)data;
100 int ret = 0;
101
102 gd32_fmc_v2_bank0_unlock();
103
104 if (FMC_STAT0 & FMC_STAT0_BUSY) {
105 return -EBUSY;
106 }
107
108 FMC_CTL0 |= FMC_CTL0_PG;
109
110 for (size_t i = 0U; i < (len / sizeof(flash_prg_t)); i++) {
111 *prg_flash++ = *prg_data++;
112 }
113
114 ret = gd32_fmc_v2_bank0_wait_idle();
115 if (ret < 0) {
116 goto expired_out;
117 }
118
119 if (FMC_STAT0 & GD32_FMC_V2_BANK0_WRITE_ERR) {
120 ret = -EIO;
121 FMC_STAT0 |= GD32_FMC_V2_BANK0_WRITE_ERR;
122 LOG_ERR("FMC bank0 programming failed");
123 }
124
125 expired_out:
126 FMC_CTL0 &= ~FMC_CTL0_PG;
127
128 gd32_fmc_v2_bank0_lock();
129
130 return ret;
131 }
132
gd32_fmc_v2_bank0_page_erase(uint32_t page_addr)133 static int gd32_fmc_v2_bank0_page_erase(uint32_t page_addr)
134 {
135 int ret = 0;
136
137 gd32_fmc_v2_bank0_unlock();
138
139 if (FMC_STAT0 & FMC_STAT0_BUSY) {
140 return -EBUSY;
141 }
142
143 FMC_CTL0 |= FMC_CTL0_PER;
144
145 FMC_ADDR0 = page_addr;
146
147 FMC_CTL0 |= FMC_CTL0_START;
148
149 ret = gd32_fmc_v2_bank0_wait_idle();
150 if (ret < 0) {
151 goto expired_out;
152 }
153
154 if (FMC_STAT0 & GD32_FMC_V2_BANK0_ERASE_ERR) {
155 ret = -EIO;
156 FMC_STAT0 |= GD32_FMC_V2_BANK0_ERASE_ERR;
157 LOG_ERR("FMC bank0 page %u erase failed", page_addr);
158 }
159
160 expired_out:
161 FMC_CTL0 &= ~FMC_CTL0_PER;
162
163 gd32_fmc_v2_bank0_lock();
164
165 return ret;
166 }
167
gd32_fmc_v2_bank0_erase_block(off_t offset,size_t size)168 static int gd32_fmc_v2_bank0_erase_block(off_t offset, size_t size)
169 {
170 uint32_t page_addr = SOC_NV_FLASH_ADDR + offset;
171 int ret = 0;
172
173 while (size > 0U) {
174 ret = gd32_fmc_v2_bank0_page_erase(page_addr);
175 if (ret < 0) {
176 return ret;
177 }
178
179 size -= GD32_NV_FLASH_V2_BANK0_PAGE_SIZE;
180 page_addr += GD32_NV_FLASH_V2_BANK0_PAGE_SIZE;
181 }
182
183 return 0;
184 }
185
186 #ifdef GD32_NV_FLASH_V2_BANK1_SIZE
gd32_fmc_v2_bank1_unlock(void)187 static inline void gd32_fmc_v2_bank1_unlock(void)
188 {
189 FMC_KEY1 = UNLOCK_KEY0;
190 FMC_KEY1 = UNLOCK_KEY1;
191 }
192
gd32_fmc_v2_bank1_lock(void)193 static inline void gd32_fmc_v2_bank1_lock(void)
194 {
195 FMC_CTL1 |= FMC_CTL1_LK;
196 }
197
gd32_fmc_v2_bank1_wait_idle(void)198 static int gd32_fmc_v2_bank1_wait_idle(void)
199 {
200 const int64_t expired_time = k_uptime_get() + GD32_NV_FLASH_V2_TIMEOUT;
201
202 while (FMC_STAT1 & FMC_STAT1_BUSY) {
203 if (k_uptime_get() > expired_time) {
204 return -ETIMEDOUT;
205 }
206 }
207
208 return 0;
209 }
210
gd32_fmc_v2_bank1_write(off_t offset,const void * data,size_t len)211 static int gd32_fmc_v2_bank1_write(off_t offset, const void *data, size_t len)
212 {
213 flash_prg_t *prg_flash = (flash_prg_t *)((uint8_t *)SOC_NV_FLASH_ADDR + offset);
214 flash_prg_t *prg_data = (flash_prg_t *)data;
215 int ret = 0;
216
217 gd32_fmc_v2_bank1_unlock();
218
219 if (FMC_STAT1 & FMC_STAT1_BUSY) {
220 return -EBUSY;
221 }
222
223 FMC_CTL1 |= FMC_CTL1_PG;
224
225 for (size_t i = 0U; i < (len / sizeof(flash_prg_t)); i++) {
226 *prg_flash++ = *prg_data++;
227 }
228
229 ret = gd32_fmc_v2_bank1_wait_idle();
230 if (ret < 0) {
231 goto expired_out;
232 }
233
234 if (FMC_STAT1 & GD32_FMC_V2_BANK1_WRITE_ERR) {
235 ret = -EIO;
236 FMC_STAT1 |= GD32_FMC_V2_BANK1_WRITE_ERR;
237 LOG_ERR("FMC bank1 programming failed");
238 }
239
240 expired_out:
241 FMC_CTL1 &= ~FMC_CTL1_PG;
242
243 gd32_fmc_v2_bank1_lock();
244
245 return ret;
246 }
247
gd32_fmc_v2_bank1_page_erase(uint32_t page_addr)248 static int gd32_fmc_v2_bank1_page_erase(uint32_t page_addr)
249 {
250 int ret = 0;
251
252 gd32_fmc_v2_bank1_unlock();
253
254 if (FMC_STAT1 & FMC_STAT1_BUSY) {
255 return -EBUSY;
256 }
257
258 FMC_CTL1 |= FMC_CTL1_PER;
259
260 FMC_ADDR1 = page_addr;
261
262 FMC_CTL1 |= FMC_CTL1_START;
263
264 ret = gd32_fmc_v2_bank1_wait_idle();
265 if (ret < 0) {
266 goto expired_out;
267 }
268
269 if (FMC_STAT1 & GD32_FMC_V2_BANK1_ERASE_ERR) {
270 ret = -EIO;
271 FMC_STAT1 |= GD32_FMC_V2_BANK1_ERASE_ERR;
272 LOG_ERR("FMC bank1 page %u erase failed", page_addr);
273 }
274
275 expired_out:
276 FMC_CTL1 &= ~FMC_CTL1_PER;
277
278 gd32_fmc_v2_bank1_lock();
279
280 return ret;
281 }
282
gd32_fmc_v2_bank1_erase_block(off_t offset,size_t size)283 static int gd32_fmc_v2_bank1_erase_block(off_t offset, size_t size)
284 {
285 uint32_t page_addr = SOC_NV_FLASH_ADDR + offset;
286 int ret = 0;
287
288 while (size > 0U) {
289 ret = gd32_fmc_v2_bank1_page_erase(page_addr);
290 if (ret < 0) {
291 return ret;
292 }
293
294 size -= GD32_NV_FLASH_V2_BANK0_SIZE;
295 page_addr += GD32_NV_FLASH_V2_BANK0_SIZE;
296 }
297
298 return 0;
299 }
300 #endif /* GD32_NV_FLASH_V2_BANK1_SIZE */
301
flash_gd32_valid_range(off_t offset,uint32_t len,bool write)302 bool flash_gd32_valid_range(off_t offset, uint32_t len, bool write)
303 {
304 if ((offset > SOC_NV_FLASH_SIZE) ||
305 ((offset + len) > SOC_NV_FLASH_SIZE)) {
306 return false;
307 }
308
309 if (write) {
310 /* Check offset and len is flash_prg_t aligned. */
311 if ((offset % sizeof(flash_prg_t)) ||
312 (len % sizeof(flash_prg_t))) {
313 return false;
314 }
315
316 } else {
317 if (offset < GD32_NV_FLASH_V2_BANK0_SIZE) {
318 if (offset % GD32_NV_FLASH_V2_BANK0_PAGE_SIZE) {
319 return false;
320 }
321
322 if (((offset + len) <= GD32_NV_FLASH_V2_BANK0_SIZE) &&
323 (len % GD32_NV_FLASH_V2_BANK0_PAGE_SIZE)) {
324 return false;
325 }
326 }
327
328 #ifdef GD32_NV_FLASH_V2_BANK1_SIZE
329 /* Remove bank0 info from offset and len. */
330 if ((offset < GD32_NV_FLASH_V2_BANK0_SIZE) &&
331 ((offset + len) > GD32_NV_FLASH_V2_BANK0_SIZE)) {
332 len -= (GD32_NV_FLASH_V2_BANK0_SIZE - offset);
333 offset = GD32_NV_FLASH_V2_BANK0_SIZE;
334 }
335
336 if (offset >= GD32_NV_FLASH_V2_BANK0_SIZE) {
337 if ((offset % GD32_NV_FLASH_V2_BANK1_PAGE_SIZE) ||
338 (len % GD32_NV_FLASH_V2_BANK1_PAGE_SIZE)) {
339 return false;
340 }
341 }
342 #endif
343 }
344
345 return true;
346 }
347
flash_gd32_write_range(off_t offset,const void * data,size_t len)348 int flash_gd32_write_range(off_t offset, const void *data, size_t len)
349 {
350 size_t len0 = 0U;
351 int ret = 0;
352
353 if (offset < GD32_NV_FLASH_V2_BANK0_SIZE) {
354 if ((offset + len) > GD32_NV_FLASH_V2_BANK0_SIZE) {
355 len0 = GD32_NV_FLASH_V2_BANK0_SIZE - offset;
356 } else {
357 len0 = len;
358 }
359
360 ret = gd32_fmc_v2_bank0_write(offset, data, len0);
361 if (ret < 0) {
362 return ret;
363 }
364 }
365
366 #ifdef GD32_NV_FLASH_V2_BANK1_SIZE
367 size_t len1 = len - len0;
368
369 if (len1 == 0U) {
370 return 0;
371 }
372
373 /* Will programming bank1, remove bank0 offset. */
374 if (offset < GD32_NV_FLASH_V2_BANK0_SIZE) {
375 offset = GD32_NV_FLASH_V2_BANK0_SIZE;
376 }
377
378 ret = gd32_fmc_v2_bank1_write(offset, data, len1);
379 if (ret < 0) {
380 return ret;
381 }
382 #endif
383
384 return 0;
385 }
386
flash_gd32_erase_block(off_t offset,size_t size)387 int flash_gd32_erase_block(off_t offset, size_t size)
388 {
389 size_t size0 = 0U;
390 int ret = 0;
391
392 if (offset < GD32_NV_FLASH_V2_BANK0_SIZE) {
393 if ((offset + size0) > GD32_NV_FLASH_V2_BANK0_SIZE) {
394 size0 = GD32_NV_FLASH_V2_BANK0_SIZE - offset;
395 } else {
396 size0 = size;
397 }
398
399 ret = gd32_fmc_v2_bank0_erase_block(offset, size0);
400 if (ret < 0) {
401 return ret;
402 }
403 }
404
405 #ifdef GD32_NV_FLASH_V2_BANK1_SIZE
406 size_t size1 = size - size0;
407
408 if (size1 == 0U) {
409 return 0;
410 }
411
412 /* Will programming bank1, remove bank0 info from offset. */
413 if (offset < GD32_NV_FLASH_V2_BANK0_SIZE) {
414 offset = GD32_NV_FLASH_V2_BANK0_SIZE;
415 }
416
417 ret = gd32_fmc_v2_bank1_erase_block(offset, size1);
418 if (ret < 0) {
419 return ret;
420 }
421 #endif
422
423 return 0;
424 }
425
426 #ifdef CONFIG_FLASH_PAGE_LAYOUT
flash_gd32_pages_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)427 void flash_gd32_pages_layout(const struct device *dev,
428 const struct flash_pages_layout **layout,
429 size_t *layout_size)
430 {
431 ARG_UNUSED(dev);
432
433 *layout = gd32_fmc_v2_layout;
434 *layout_size = ARRAY_SIZE(gd32_fmc_v2_layout);
435
436 }
437 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
438