• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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