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