1 /**
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 * Description: Provides sfc driver source \n
16 *
17 * History: \n
18 * 2022-11-29, Create file. \n
19 */
20 #include <stdbool.h>
21 #include <securec.h>
22 #include <tcxo.h>
23 #include <sfc_porting.h>
24 #include <hal_sfc.h>
25 #include "osal_interrupt.h"
26 #include "sfc.h"
27
28 #define BYTES_64_MASK 0x3F
29 #define BYTES_4K_MASK 0xFFF
30 #define BYTES_4_MASK 0x3
31 #define BYTES_64K 0x10000
32 #define BYTES_4K 0x1000
33 #define BYTES_64 0x40
34 #define BYTES_4 0x4
35 #define BYTES_18 0x12
36
37 #define ERASE_CHIP 0
38 #define SFC_READ_TIME_SHIFT_NUM 6
39 #define GREEDY_MIN_ERASE_NUM 2
40
41 static bool g_sfc_inited = false;
42 static bool g_sfc_unknown_flash = false;
43 static flash_spi_ctrl_t g_flash_ctrl;
44
45 #if defined(CONFIG_SFC_ALLOW_ERASE_WRITEBACK)
46 static uint8_t g_first_buffer[4096] = {0};
47 static uint8_t g_last_buffer[4096] = {0};
48 #endif /* CONFIG_SFC_ALLOW_ERASE_WRITEBACK */
49
check_init_param(const sfc_flash_config_t * config)50 STATIC errcode_t check_init_param(const sfc_flash_config_t *config)
51 {
52 uint32_t mapping_size = min(config->mapping_size, g_flash_ctrl.chip_size);
53 if (config->mapping_addr < sfc_port_get_sfc_start_addr() ||
54 config->mapping_addr + mapping_size - 1 > sfc_port_get_sfc_end_addr()) {
55 return ERRCODE_SFC_ADDRESS_OVERSTEP;
56 }
57 g_flash_ctrl.chip_size = mapping_size;
58 return ERRCODE_SUCC;
59 }
60
check_opt_param(uint32_t addr,uint32_t size)61 STATIC errcode_t check_opt_param(uint32_t addr, uint32_t size)
62 {
63 if (unlikely(!g_sfc_inited)) {
64 return ERRCODE_SFC_NOT_INIT;
65 }
66 if ((addr + size) > g_flash_ctrl.chip_size || (addr + size) <= addr || (addr + size) < size) {
67 return ERRCODE_INVALID_PARAM;
68 }
69 return ERRCODE_SUCC;
70 }
71
build_flash_ctrl(const flash_spi_info_t * spi_info,sfc_read_if_t read_type,sfc_write_if_t write_type)72 STATIC errcode_t build_flash_ctrl(const flash_spi_info_t *spi_info, sfc_read_if_t read_type, sfc_write_if_t write_type)
73 {
74 spi_opreation_t read_cmd = spi_info->read_cmds[read_type];
75 spi_opreation_t write_cmd = spi_info->write_cmds[write_type];
76 if (read_cmd.cmd_support != SPI_CMD_SUPPORT || write_cmd.cmd_support != SPI_CMD_SUPPORT) {
77 return ERRCODE_SFC_CMD_NOT_SUPPORT;
78 }
79 g_flash_ctrl.read_opreation = spi_info->read_cmds[read_type];
80 g_flash_ctrl.write_opreation = spi_info->write_cmds[write_type];
81 g_flash_ctrl.erase_opreation_array = spi_info->erase_cmds;
82 g_flash_ctrl.chip_size = spi_info->chip_size;
83 if (spi_info->erase_cmd_num < GREEDY_MIN_ERASE_NUM) {
84 return ERRCODE_SFC_PORT_INVALID_PARAM;
85 }
86 g_flash_ctrl.erase_cmd_num = spi_info->erase_cmd_num;
87 g_flash_ctrl.quad_mode = spi_info->quad_mode;
88 return ERRCODE_SUCC;
89 }
90
build_cmds(uint32_t flash_id,sfc_read_if_t read_type,sfc_write_if_t write_type)91 STATIC errcode_t build_cmds(uint32_t flash_id, sfc_read_if_t read_type, sfc_write_if_t write_type)
92 {
93 flash_spi_info_t *flash_spi_infos = sfc_port_get_flash_spi_infos();
94 uint32_t flash_num = sfc_port_get_flash_num();
95 for (uint32_t i = 0; i < flash_num; i++) {
96 if (flash_id == flash_spi_infos[i].chip_id) {
97 errcode_t ret = build_flash_ctrl(&flash_spi_infos[i], read_type, write_type);
98 return ret;
99 }
100 }
101 flash_spi_infos = sfc_port_get_unknown_flash_info();
102 errcode_t ret = build_flash_ctrl(&flash_spi_infos[0], STANDARD_READ, PAGE_PROGRAM);
103 if (ret == ERRCODE_SUCC) {
104 g_sfc_unknown_flash = true;
105 }
106 return ret;
107 }
108
do_greedy_erase(uint32_t hal_erase_size,uint32_t start_sector)109 STATIC errcode_t do_greedy_erase(uint32_t hal_erase_size, uint32_t start_sector)
110 {
111 uint32_t erase_opt_index;
112 uint32_t temp_size = 0;
113 errcode_t ret = ERRCODE_FAIL;
114 /* All parameters are aligned in 4KB. */
115 uint32_t remain_size = hal_erase_size;
116 uint32_t current_addr = start_sector;
117 spi_opreation_t current_erase_opt = {0};
118
119 while (remain_size > 0) {
120 for (erase_opt_index = 1; erase_opt_index < g_flash_ctrl.erase_cmd_num; erase_opt_index++) {
121 current_erase_opt = g_flash_ctrl.erase_opreation_array[erase_opt_index];
122 temp_size = current_erase_opt.size;
123 if ((remain_size >= temp_size) && ((current_addr & (temp_size - 1)) == 0)) {
124 break;
125 }
126 }
127 /* Generally, the 4K erase is not configured for this branch. Check the erase array at the port layer. */
128 if (erase_opt_index == g_flash_ctrl.erase_cmd_num) {
129 return ERRCODE_SFC_ERASE_FORM_ERROR;
130 }
131 ret = hal_sfc_reg_erase(current_addr, current_erase_opt, false);
132 if (ret != ERRCODE_SUCC) {
133 return ret;
134 }
135 remain_size -= temp_size;
136 current_addr += temp_size;
137 }
138 return ERRCODE_SUCC;
139 }
140
uapi_sfc_init(sfc_flash_config_t * config)141 errcode_t uapi_sfc_init(sfc_flash_config_t *config)
142 {
143 errcode_t ret;
144 if (unlikely(g_sfc_inited)) {
145 return ERRCODE_SUCC;
146 }
147 sfc_port_lock_init();
148
149 uint32_t flash_id;
150 ret = hal_sfc_get_flash_id(&flash_id);
151 if (unlikely(ret != ERRCODE_SUCC)) {
152 return ret;
153 }
154 ret = build_cmds(flash_id, config->read_type, config->write_type);
155 if (unlikely(ret != ERRCODE_SUCC)) {
156 return ret;
157 }
158 ret = check_init_param(config);
159 if (unlikely(ret != ERRCODE_SUCC)) {
160 return ret;
161 }
162 #if !defined(CONFIG_SFC_ALREADY_INIT)
163 flash_spi_ctrl_t *spi_ctrl = &g_flash_ctrl;
164 ret = hal_sfc_init(spi_ctrl, config->mapping_addr, g_flash_ctrl.chip_size);
165 if (ret == ERRCODE_SUCC) {
166 g_sfc_inited = true;
167 ret = g_sfc_unknown_flash ? ERRCODE_SFC_FLASH_NOT_SUPPORT : ERRCODE_SUCC;
168 }
169 return ret;
170 #else
171 g_sfc_inited = true;
172 return ERRCODE_SUCC;
173 #endif
174 }
175
uapi_sfc_init_rom(sfc_flash_config_t * config)176 errcode_t uapi_sfc_init_rom(sfc_flash_config_t *config)
177 {
178 errcode_t ret;
179 if (unlikely(g_sfc_inited)) {
180 return ERRCODE_SUCC;
181 }
182 ret = hal_sfc_regs_init();
183 if (ret != ERRCODE_SUCC) {
184 return ret;
185 }
186
187 flash_spi_info_t *flash_spi_info = sfc_port_get_unknown_flash_info();
188 ret = build_flash_ctrl(&flash_spi_info[0], STANDARD_READ, PAGE_PROGRAM);
189 if (unlikely(ret != ERRCODE_SUCC)) {
190 return ret;
191 }
192 g_sfc_unknown_flash = true;
193 ret = check_init_param(config);
194 if (unlikely(ret != ERRCODE_SUCC)) {
195 return ret;
196 }
197 flash_spi_ctrl_t *spi_ctrl = &g_flash_ctrl;
198 ret = hal_sfc_init(spi_ctrl, config->mapping_addr, g_flash_ctrl.chip_size);
199 if (ret == ERRCODE_SUCC) {
200 g_sfc_inited = true;
201 ret = g_sfc_unknown_flash ? ERRCODE_SFC_DEFAULT_INIT : ERRCODE_SUCC;
202 }
203 return ret;
204 }
205
uapi_sfc_deinit(void)206 void uapi_sfc_deinit(void)
207 {
208 if (unlikely(!g_sfc_inited)) {
209 return;
210 }
211 #if !defined(CONFIG_SFC_ALREADY_INIT)
212 hal_sfc_deinit();
213 #endif
214 g_sfc_inited = false;
215 g_sfc_unknown_flash = false;
216 }
217
218 SFC_SECTION
uapi_sfc_reg_read(uint32_t flash_addr,uint8_t * read_buffer,uint32_t read_size)219 errcode_t uapi_sfc_reg_read(uint32_t flash_addr, uint8_t *read_buffer, uint32_t read_size)
220 {
221 errcode_t ret = check_opt_param(flash_addr, read_size);
222 if (unlikely(ret != ERRCODE_SUCC)) {
223 return ret;
224 }
225 uint32_t current_addr = flash_addr;
226 uint8_t *buffer_ptr = read_buffer;
227 uint32_t remained_size = read_size;
228 /* flash_addr 4 byte misaligned */
229 /* Part1.1: 检查非对齐长度 */
230 uint32_t misaligned_addr = current_addr & BYTES_4_MASK;
231 uint32_t lock_sts = sfc_port_lock();
232 if (misaligned_addr != 0) {
233 current_addr -= misaligned_addr;
234 uint8_t cur_size = (uint8_t)((BYTES_4 - misaligned_addr) > read_size ? read_size :
235 (BYTES_4 - misaligned_addr));
236 /* Part1.2: 使用向前对齐后的地址读取4个字节至临时buffer */
237 uint8_t temp_buf[BYTES_4] = {0};
238 ret = hal_sfc_reg_read(current_addr, temp_buf, BYTES_4, g_flash_ctrl.read_opreation);
239 if (ret != ERRCODE_SUCC || memcpy_s(buffer_ptr, cur_size, temp_buf + misaligned_addr, cur_size) != EOK) {
240 ret = ret == ERRCODE_SUCC ? ERRCODE_MEMCPY : ret;
241 sfc_port_unlock(lock_sts);
242 return ret;
243 }
244 current_addr += BYTES_4; // 以对齐后的地址+4
245 buffer_ptr += cur_size; // 以原地址增加读取到的长度
246 remained_size -= cur_size; // 以原长度减少读取到的长度
247 }
248 /* flash_addr 4 byte aligned */
249 /* Part2: 读取地址及长度对齐部分的数据 */
250 uint32_t aligned_size = remained_size - (remained_size & BYTES_4_MASK);
251 if (likely(ret == ERRCODE_SUCC) && aligned_size != 0) {
252 ret = hal_sfc_reg_read(current_addr, buffer_ptr, aligned_size, g_flash_ctrl.read_opreation);
253 buffer_ptr += aligned_size;
254 current_addr += aligned_size;
255 remained_size -= aligned_size;
256 }
257 /* Part3: 读取长度不对齐部分的数据 */
258 if (likely(ret == ERRCODE_SUCC) && remained_size != 0) {
259 /* 读取4字节,并将非对齐部分拷贝至read_buffer */
260 uint8_t temp_buf[BYTES_4] = {0};
261 ret = hal_sfc_reg_read(current_addr, temp_buf, BYTES_4, g_flash_ctrl.read_opreation);
262 if (memcpy_s(buffer_ptr, remained_size, temp_buf, remained_size) != EOK) {
263 ret = ERRCODE_MEMCPY;
264 }
265 }
266 sfc_port_unlock(lock_sts);
267 return ret;
268 }
269
270 SFC_SECTION
uapi_sfc_reg_write(uint32_t flash_addr,uint8_t * write_data,uint32_t write_size)271 errcode_t uapi_sfc_reg_write(uint32_t flash_addr, uint8_t *write_data, uint32_t write_size)
272 {
273 errcode_t ret = check_opt_param(flash_addr, write_size);
274 if (unlikely(ret != ERRCODE_SUCC)) { return ret; }
275 uint32_t current_addr = flash_addr;
276 uint8_t *buffer_ptr = write_data;
277 uint32_t remained_size = write_size;
278 uint8_t temp_buf[BYTES_4];
279 /* flash_addr 4 byte misaligned */
280 /* Part1.1: 检查非对齐长度 */
281 uint32_t misaligned_addr = current_addr & BYTES_4_MASK;
282 uint32_t lock_sts = sfc_port_write_lock(flash_addr, flash_addr + write_size);
283 if (misaligned_addr != 0) {
284 current_addr -= misaligned_addr;
285 uint8_t cur_size = (uint8_t)((BYTES_4 - misaligned_addr) > remained_size ? remained_size :
286 (BYTES_4 - misaligned_addr));
287 /* Part1.2: 将写入数据非对齐地址开始的数据拷贝至临时buffer */
288 ret = hal_sfc_reg_read(current_addr, temp_buf, BYTES_4, g_flash_ctrl.read_opreation);
289 if (ret != ERRCODE_SUCC || memcpy_s(temp_buf + misaligned_addr, cur_size, buffer_ptr, cur_size) != EOK) {
290 ret = ret == ERRCODE_SUCC ? ERRCODE_MEMCPY : ret;
291 sfc_port_write_unlock(lock_sts);
292 return ret;
293 }
294 /* Part1.3: 使用临时buffer往向前对齐后的地址写入四个字节 */
295 ret = hal_sfc_reg_write(current_addr, temp_buf, BYTES_4, g_flash_ctrl.write_opreation);
296 current_addr += BYTES_4; // 以对齐后的地址+4
297 buffer_ptr += cur_size; // 以原地址增加读取到的长度
298 remained_size -= cur_size; // 以原长度减少读取到的长度
299 }
300 /* flash_addr 4 byte aligned */
301 /* Part2: 写入地址及长度对齐部分的数据 */
302 uint32_t aligned_size = remained_size - (remained_size & BYTES_4_MASK);
303 if (likely(ret == ERRCODE_SUCC) && aligned_size != 0) {
304 ret = hal_sfc_reg_write(current_addr, buffer_ptr, aligned_size, g_flash_ctrl.write_opreation);
305 buffer_ptr += aligned_size;
306 current_addr += aligned_size;
307 remained_size -= aligned_size;
308 }
309 /* Part3: 写入长度不对齐部分的数据 */
310 if (likely(ret == ERRCODE_SUCC) && remained_size != 0) {
311 /* 构造非对齐部分的4字节临时数据 */
312 ret = hal_sfc_reg_read(current_addr, temp_buf, BYTES_4, g_flash_ctrl.read_opreation);
313 if (ret != ERRCODE_SUCC || memcpy_s(temp_buf, BYTES_4, buffer_ptr, remained_size) != EOK) {
314 ret = ret == ERRCODE_SUCC ? ERRCODE_MEMCPY : ret;
315 sfc_port_write_unlock(lock_sts);
316 return ERRCODE_MEMCPY;
317 }
318 ret = hal_sfc_reg_write(current_addr, temp_buf, BYTES_4, g_flash_ctrl.write_opreation);
319 }
320 sfc_port_write_unlock(lock_sts);
321 return ret;
322 }
323
324 #if defined(CONFIG_SFC_SUPPORT_DMA)
325 SFC_SECTION
uapi_sfc_dma_read(uint32_t flash_addr,uint8_t * read_buffer,uint32_t read_size)326 errcode_t uapi_sfc_dma_read(uint32_t flash_addr, uint8_t *read_buffer, uint32_t read_size)
327 {
328 errcode_t ret = check_opt_param(flash_addr, read_size);
329 if (unlikely(ret != ERRCODE_SUCC)) {
330 return ret;
331 }
332 uint32_t lock_sts = sfc_port_lock();
333 ret = hal_sfc_dma_read(flash_addr, read_buffer, read_size);
334 sfc_port_unlock(lock_sts);
335 return ret;
336 }
337
338 SFC_SECTION
uapi_sfc_dma_write(uint32_t flash_addr,uint8_t * write_buffer,uint32_t write_size)339 errcode_t uapi_sfc_dma_write(uint32_t flash_addr, uint8_t *write_buffer, uint32_t write_size)
340 {
341 errcode_t ret = check_opt_param(flash_addr, write_size);
342 if (unlikely(ret != ERRCODE_SUCC)) {
343 return ret;
344 }
345 uint32_t lock_sts = sfc_port_write_lock(flash_addr, flash_addr + write_size);
346 ret = hal_sfc_dma_write(flash_addr, write_buffer, write_size);
347 sfc_port_write_unlock(lock_sts);
348 return ret;
349 }
350 #endif /* CONFIG_SFC_SUPPORT_DMA */
351
352 SFC_SECTION
uapi_sfc_reg_erase(uint32_t flash_addr,uint32_t erase_size)353 errcode_t uapi_sfc_reg_erase(uint32_t flash_addr, uint32_t erase_size)
354 {
355 errcode_t ret = check_opt_param(flash_addr, erase_size);
356 if (unlikely(ret != ERRCODE_SUCC)) {
357 return ret;
358 }
359
360 uint32_t end_addr = flash_addr + erase_size;
361 uint32_t start_sector = flash_addr & ~BYTES_4K_MASK;
362 uint32_t end_sector = (end_addr & BYTES_4K_MASK) == 0 ? end_addr : (end_addr & ~BYTES_4K_MASK) + BYTES_4K;
363 uint32_t hal_erase_size = end_sector - start_sector;
364
365 #if defined(CONFIG_SFC_ALLOW_ERASE_WRITEBACK)
366 /* Backup data to RAM */
367 uint32_t first_size = flash_addr - start_sector;
368 if (likely(first_size != 0)) {
369 uapi_sfc_reg_read(start_sector, g_first_buffer, first_size);
370 }
371 uint32_t last_size = end_sector - end_addr;
372 if (likely(last_size != 0)) {
373 uapi_sfc_reg_read(end_addr, g_last_buffer, last_size);
374 }
375 #else
376 if (flash_addr != start_sector || end_addr != end_sector) {
377 return ERRCODE_INVALID_PARAM;
378 }
379 #endif /* CONFIG_SFC_ALLOW_ERASE_WRITEBACK */
380
381 uint32_t lock_sts = sfc_port_write_lock(flash_addr, flash_addr + erase_size);
382 /* Erasing with greedy algorithms */
383 ret = do_greedy_erase(hal_erase_size, start_sector);
384 sfc_port_write_unlock(lock_sts);
385
386 #if defined(CONFIG_SFC_ALLOW_ERASE_WRITEBACK)
387 /* Write back data from RAM */
388 if (likely(first_size != 0)) {
389 uapi_sfc_reg_write(start_sector, g_first_buffer, first_size);
390 }
391 if (likely(last_size != 0)) {
392 uapi_sfc_reg_write(end_addr, g_last_buffer, last_size);
393 }
394 #endif /* CONFIG_SFC_ALLOW_ERASE_WRITEBACK */
395 return ret;
396 }
397
398 SFC_SECTION
uapi_sfc_reg_erase_chip(void)399 errcode_t uapi_sfc_reg_erase_chip(void)
400 {
401 if (unlikely(!g_sfc_inited)) {
402 return ERRCODE_SFC_NOT_INIT;
403 }
404 uint32_t lock_sts = sfc_port_write_lock(0x0, FLASH_CHIP_PROTECT_END);
405 errcode_t ret = hal_sfc_reg_erase(0x0, g_flash_ctrl.erase_opreation_array[ERASE_CHIP], true);
406 sfc_port_write_unlock(lock_sts);
407 return ret;
408 }
409
410 SFC_SECTION
uapi_sfc_reg_other_flash_opt(sfc_flash_op_t cmd_type,uint8_t cmd,uint8_t * buffer,uint32_t length)411 errcode_t uapi_sfc_reg_other_flash_opt(sfc_flash_op_t cmd_type, uint8_t cmd, uint8_t *buffer, uint32_t length)
412 {
413 if (unlikely(!g_sfc_inited)) {
414 return ERRCODE_SFC_NOT_INIT;
415 }
416 if (unlikely(length > BYTES_18)) {
417 return ERRCODE_INVALID_PARAM;
418 }
419 uint32_t lock_sts = sfc_port_lock();
420 errcode_t ret = hal_sfc_reg_flash_opreations(cmd_type, cmd, buffer, length);
421 sfc_port_unlock(lock_sts);
422 return ret;
423 }
424
425 #if defined(CONFIG_SFC_SUPPORT_LPM)
uapi_sfc_suspend(uintptr_t arg)426 errcode_t uapi_sfc_suspend(uintptr_t arg)
427 {
428 unused(arg);
429 hal_sfc_suspend();
430 return ERRCODE_SUCC;
431 }
432
uapi_sfc_resume(uintptr_t arg)433 errcode_t uapi_sfc_resume(uintptr_t arg)
434 {
435 unused(arg);
436 return hal_sfc_resume(g_flash_ctrl.quad_mode);
437 }
438 #endif /* CONFIG_SFC_SUPPORT_LPM */
439
440 #if defined(CONFIG_SFC_SUPPORT_WRITE_PROTECT)
uapi_sfc_lock_protect(sfc_flash_protect_region_t region)441 errcode_t uapi_sfc_lock_protect(sfc_flash_protect_region_t region)
442 {
443 if (unlikely(!g_sfc_inited)) {
444 return ERRCODE_SFC_NOT_INIT;
445 }
446 uint32_t flash_id = 0;
447 errcode_t ret = hal_sfc_get_flash_id(&flash_id);
448 if (ret != ERRCODE_SUCC || flash_id == 0) {
449 return ERRCODE_FAIL;
450 }
451 uint32_t flag = osal_irq_lock();
452 ret = hal_sfc_lock_protect(flash_id, region);
453 osal_irq_restore(flag);
454 return ret;
455 }
456
uapi_sfc_unlock_protect(void)457 errcode_t uapi_sfc_unlock_protect(void)
458 {
459 if (unlikely(!g_sfc_inited)) {
460 return ERRCODE_SFC_NOT_INIT;
461 }
462 uint32_t flash_id = 0;
463 errcode_t ret = hal_sfc_get_flash_id(&flash_id);
464 if (ret != ERRCODE_SUCC || flash_id == 0) {
465 return ERRCODE_FAIL;
466 }
467 uint32_t flag = osal_irq_lock();
468 ret = hal_sfc_unlock_protect(flash_id);
469 osal_irq_restore(flag);
470 return ret;
471 }
472 #endif
473