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_V3_NODE		DT_INST(0, gd_gd32_nv_flash_v3)
16 #define GD32_NV_FLASH_V3_TIMEOUT	DT_PROP(GD32_NV_FLASH_V3_NODE, max_erase_time_ms)
17 
18 /**
19  * @brief GD32 FMC v3 flash memory layout for GD32F4xx series.
20  */
21 #if defined(CONFIG_FLASH_PAGE_LAYOUT) && \
22 	defined(CONFIG_SOC_SERIES_GD32F4XX)
23 #if (PRE_KB(512) == SOC_NV_FLASH_SIZE)
24 static const struct flash_pages_layout gd32_fmc_v3_layout[] = {
25 	{.pages_count = 4, .pages_size = KB(16)},
26 	{.pages_count = 1, .pages_size = KB(64)},
27 	{.pages_count = 3, .pages_size = KB(128)},
28 };
29 #elif (PRE_KB(1024) == SOC_NV_FLASH_SIZE)
30 static const struct flash_pages_layout gd32_fmc_v3_layout[] = {
31 	{.pages_count = 4, .pages_size = KB(16)},
32 	{.pages_count = 1, .pages_size = KB(64)},
33 	{.pages_count = 7, .pages_size = KB(128)},
34 };
35 #elif (PRE_KB(2048) == SOC_NV_FLASH_SIZE)
36 static const struct flash_pages_layout gd32_fmc_v3_layout[] = {
37 	{.pages_count = 4, .pages_size = KB(16)},
38 	{.pages_count = 1, .pages_size = KB(64)},
39 	{.pages_count = 7, .pages_size = KB(128)},
40 	{.pages_count = 4, .pages_size = KB(16)},
41 	{.pages_count = 1, .pages_size = KB(64)},
42 	{.pages_count = 7, .pages_size = KB(128)},
43 };
44 #elif (PRE_KB(3072) == SOC_NV_FLASH_SIZE)
45 static const struct flash_pages_layout gd32_fmc_v3_layout[] = {
46 	{.pages_count = 4, .pages_size = KB(16)},
47 	{.pages_count = 1, .pages_size = KB(64)},
48 	{.pages_count = 7, .pages_size = KB(128)},
49 	{.pages_count = 4, .pages_size = KB(16)},
50 	{.pages_count = 1, .pages_size = KB(64)},
51 	{.pages_count = 7, .pages_size = KB(128)},
52 	{.pages_count = 4, .pages_size = KB(256)},
53 };
54 #else
55 #error "Unknown FMC layout for GD32F4xx series."
56 #endif
57 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
58 
59 #define gd32_fmc_v3_WRITE_ERR (FMC_STAT_PGMERR | FMC_STAT_PGSERR | FMC_STAT_WPERR)
60 #define gd32_fmc_v3_ERASE_ERR FMC_STAT_OPERR
61 
62 /* SN bits in FMC_CTL are not continue values, use table below to map them. */
63 static uint8_t gd32_fmc_v3_sectors[] = {
64 	0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 11U,
65 	16U, 17U, 18U, 19U, 20U, 21U, 22U, 23U, 24U, 25U, 26U, 27U,
66 	12U, 13U, 14U, 15U
67 };
68 
gd32_fmc_v3_unlock(void)69 static inline void gd32_fmc_v3_unlock(void)
70 {
71 	FMC_KEY = UNLOCK_KEY0;
72 	FMC_KEY = UNLOCK_KEY1;
73 }
74 
gd32_fmc_v3_lock(void)75 static inline void gd32_fmc_v3_lock(void)
76 {
77 	FMC_CTL |= FMC_CTL_LK;
78 }
79 
gd32_fmc_v3_wait_idle(void)80 static int gd32_fmc_v3_wait_idle(void)
81 {
82 	const int64_t expired_time = k_uptime_get() + GD32_NV_FLASH_V3_TIMEOUT;
83 
84 	while (FMC_STAT & FMC_STAT_BUSY) {
85 		if (k_uptime_get() > expired_time) {
86 			return -ETIMEDOUT;
87 		}
88 	}
89 
90 	return 0;
91 }
92 
flash_gd32_valid_range(off_t offset,uint32_t len,bool write)93 bool flash_gd32_valid_range(off_t offset, uint32_t len, bool write)
94 {
95 	const struct flash_pages_layout *page_layout;
96 	uint32_t cur = 0U, next = 0U;
97 
98 	if ((offset > SOC_NV_FLASH_SIZE) ||
99 	    ((offset + len) > SOC_NV_FLASH_SIZE)) {
100 		return false;
101 	}
102 
103 	if (write) {
104 		/* Check offset and len aligned to write-block-size. */
105 		if ((offset % sizeof(flash_prg_t)) ||
106 		    (len % sizeof(flash_prg_t))) {
107 			return false;
108 		}
109 
110 	} else {
111 		for (size_t i = 0; i < ARRAY_SIZE(gd32_fmc_v3_layout); i++) {
112 			page_layout = &gd32_fmc_v3_layout[i];
113 
114 			for (size_t j = 0; j < page_layout->pages_count; j++) {
115 				cur = next;
116 
117 				next += page_layout->pages_size;
118 
119 				/* Check bad offset. */
120 				if ((offset > cur) && (offset < next)) {
121 					return false;
122 				}
123 
124 				/* Check bad len. */
125 				if (((offset + len) > cur) &&
126 				    ((offset + len) < next)) {
127 					return false;
128 				}
129 
130 				if ((offset + len) == next) {
131 					return true;
132 				}
133 			}
134 		}
135 	}
136 
137 	return true;
138 }
139 
flash_gd32_write_range(off_t offset,const void * data,size_t len)140 int flash_gd32_write_range(off_t offset, const void *data, size_t len)
141 {
142 	flash_prg_t *prg_flash = (flash_prg_t *)((uint8_t *)SOC_NV_FLASH_ADDR + offset);
143 	flash_prg_t *prg_data = (flash_prg_t *)data;
144 	int ret = 0;
145 
146 	gd32_fmc_v3_unlock();
147 
148 	if (FMC_STAT & FMC_STAT_BUSY) {
149 		return -EBUSY;
150 	}
151 
152 	FMC_CTL |= FMC_CTL_PG;
153 
154 	FMC_CTL &= ~FMC_CTL_PSZ;
155 	FMC_CTL |= CTL_PSZ(sizeof(flash_prg_t) - 1);
156 
157 	for (size_t i = 0U; i < (len / sizeof(flash_prg_t)); i++) {
158 		*prg_flash++ = *prg_data++;
159 	}
160 
161 	ret = gd32_fmc_v3_wait_idle();
162 	if (ret < 0) {
163 		goto expired_out;
164 	}
165 
166 	if (FMC_STAT & gd32_fmc_v3_WRITE_ERR) {
167 		ret = -EIO;
168 		FMC_STAT |= gd32_fmc_v3_WRITE_ERR;
169 		LOG_ERR("FMC programming failed");
170 	}
171 
172 expired_out:
173 	FMC_CTL &= ~FMC_CTL_PG;
174 
175 	gd32_fmc_v3_lock();
176 
177 	return ret;
178 }
179 
gd32_fmc_v3_sector_erase(uint8_t sector)180 static int gd32_fmc_v3_sector_erase(uint8_t sector)
181 {
182 	int ret = 0;
183 
184 	gd32_fmc_v3_unlock();
185 
186 	if (FMC_STAT & FMC_STAT_BUSY) {
187 		return -EBUSY;
188 	}
189 
190 	FMC_CTL |= FMC_CTL_SER;
191 
192 	FMC_CTL &= ~FMC_CTL_SN;
193 	FMC_CTL |= CTL_SN(sector);
194 
195 	FMC_CTL |= FMC_CTL_START;
196 
197 	ret = gd32_fmc_v3_wait_idle();
198 	if (ret < 0) {
199 		goto expired_out;
200 	}
201 
202 	if (FMC_STAT & gd32_fmc_v3_ERASE_ERR) {
203 		ret = -EIO;
204 		FMC_STAT |= gd32_fmc_v3_ERASE_ERR;
205 		LOG_ERR("FMC sector %u erase failed", sector);
206 	}
207 
208 expired_out:
209 	FMC_CTL &= ~FMC_CTL_SER;
210 
211 	gd32_fmc_v3_lock();
212 
213 	return ret;
214 }
215 
flash_gd32_erase_block(off_t offset,size_t size)216 int flash_gd32_erase_block(off_t offset, size_t size)
217 {
218 	const struct flash_pages_layout *page_layout;
219 	uint32_t erase_offset = 0U;
220 	uint8_t counter = 0U;
221 	int ret = 0;
222 
223 	for (size_t i = 0; i < ARRAY_SIZE(gd32_fmc_v3_layout); i++) {
224 		page_layout = &gd32_fmc_v3_layout[i];
225 
226 		for (size_t j = 0; j < page_layout->pages_count; j++) {
227 			if (erase_offset < offset) {
228 				counter++;
229 				erase_offset += page_layout->pages_size;
230 
231 				continue;
232 			}
233 
234 			uint8_t sector = gd32_fmc_v3_sectors[counter++];
235 
236 			ret = gd32_fmc_v3_sector_erase(sector);
237 			if (ret < 0) {
238 				return ret;
239 			}
240 
241 			erase_offset += page_layout->pages_size;
242 
243 			if (erase_offset - offset >= size) {
244 				return 0;
245 			}
246 		}
247 	}
248 
249 	return 0;
250 }
251 
252 #ifdef CONFIG_FLASH_PAGE_LAYOUT
flash_gd32_pages_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)253 void flash_gd32_pages_layout(const struct device *dev,
254 			     const struct flash_pages_layout **layout,
255 			     size_t *layout_size)
256 {
257 	ARG_UNUSED(dev);
258 
259 	*layout = gd32_fmc_v3_layout;
260 	*layout_size = ARRAY_SIZE(gd32_fmc_v3_layout);
261 }
262 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
263