1 /*
2  * Copyright (c) 2022 hpmicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Change Logs:
7  * Date         Author      Notes
8  * 2022-03-09   hpmicro     First implementation
9  * 2022-08-01   hpmicro     Fixed random crashing during kvdb_init
10  * 2022-08-03   hpmicro     Improved erase speed
11  *
12  */
13 #include <rtthread.h>
14 #include <rthw.h>
15 #ifdef RT_USING_FAL
16 #include "fal.h"
17 #include "hpm_romapi.h"
18 #include "board.h"
19 #include "hpm_l1c_drv.h"
20 
21 #if defined(FLASH_XIP) && (FLASH_XIP == 1)
22 
23 static rt_base_t s_interrupt_level;
24 #define FAL_ENTER_CRITICAL() do {\
25         rt_enter_critical();\
26         fencei();\
27         s_interrupt_level = rt_hw_interrupt_disable();\
28     } while(0)
29 
30 #define FAL_EXIT_CRITICAL() do {\
31         ROM_API_TABLE_ROOT->xpi_driver_if->software_reset(BOARD_APP_XPI_NOR_XPI_BASE);\
32         fencei();\
33         rt_exit_critical();\
34         rt_hw_interrupt_enable(s_interrupt_level);\
35     } while(0)
36 
37 #define FAL_RAMFUNC __attribute__((section(".isr_vector")))
38 
39 #else
40 #define FAL_ENTER_CRITICAL()
41 
42 #define FAL_EXIT_CRITICAL()
43 
44 #define FAL_RAMFUNC
45 
46 #endif
47 
48 /***************************************************************************************************
49  *      FAL Porting Guide
50  *
51  *      1. Most FLASH devices do not support RWW (Read-while-Write), the codes to access the FLASH
52  *         must be placed at RAM or ROM code
53  *      2. During FLASH erase/program, it is recommended to disable the interrupt, or place the
54  *         interrupt related codes to RAM
55  *
56  ***************************************************************************************************/
57 
58 static int init(void);
59 static int read(long offset, rt_uint8_t *buf, rt_size_t size);
60 static int write(long offset, const rt_uint8_t *buf, rt_size_t size);
61 static int erase(long offset, rt_size_t size);
62 
63 static xpi_nor_config_t s_flashcfg;
64 
65 /**
66  * @brief FAL Flash device context
67  */
68 struct fal_flash_dev nor_flash0 =
69     {
70             .name = NOR_FLASH_DEV_NAME,
71             /* If porting this code to the device with FLASH connected to XPI1, the address must be changed to 0x90000000 */
72             .addr = NOR_FLASH_MEM_BASE,
73             .len = 8 * 1024 * 1024,
74             .blk_size = 4096,
75             .ops = { .init = init, .read = read, .write = write, .erase = erase },
76             .write_gran = 1
77     };
78 
79 /**
80  * @brief FAL initialization
81  *        This function probes the FLASH using the ROM API
82  */
init(void)83 FAL_RAMFUNC static int init(void)
84 {
85     int ret = RT_EOK;
86     xpi_nor_config_option_t cfg_option;
87     cfg_option.header.U = BOARD_APP_XPI_NOR_CFG_OPT_HDR;
88     cfg_option.option0.U = BOARD_APP_XPI_NOR_CFG_OPT_OPT0;
89     cfg_option.option1.U = BOARD_APP_XPI_NOR_CFG_OPT_OPT1;
90 
91     FAL_ENTER_CRITICAL();
92     hpm_stat_t status = rom_xpi_nor_auto_config(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, &cfg_option);
93     FAL_EXIT_CRITICAL();
94     if (status != status_success)
95     {
96         ret = -RT_ERROR;
97     }
98     else
99     {
100         /* update the flash chip information */
101         rt_uint32_t sector_size;
102         rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_sector_size, &sector_size);
103         rt_uint32_t flash_size;
104         rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_total_size, &flash_size);
105         nor_flash0.blk_size = sector_size;
106         nor_flash0.len = flash_size;
107     }
108 
109     return ret;
110 }
111 
112 /**
113  * @brief FAL read function
114  *        Read data from FLASH
115  * @param offset FLASH offset
116  * @param buf Buffer to hold data read by this API
117  * @param size Size of data to be read
118  * @return actual read bytes
119  */
read(long offset,rt_uint8_t * buf,rt_size_t size)120 FAL_RAMFUNC static int read(long offset, rt_uint8_t *buf, rt_size_t size)
121 {
122     rt_uint32_t flash_addr = nor_flash0.addr + offset;
123     rt_uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN(flash_addr);
124     rt_uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP(flash_addr + size);
125     rt_uint32_t aligned_size = aligned_end - aligned_start;
126     rt_base_t level = rt_hw_interrupt_disable();
127     l1c_dc_invalidate(aligned_start, aligned_size);
128     rt_hw_interrupt_enable(level);
129 
130     (void) rt_memcpy(buf, (void*) flash_addr, size);
131 
132     return size;
133 }
134 
135 /**
136  * @brief Write unaligned data to the page
137  * @param offset FLASH offset
138  * @param buf Data buffer
139  * @param size Size of data to be written
140  * @return actual size of written data or error code
141  */
write_unaligned_page_data(long offset,const rt_uint32_t * buf,rt_size_t size)142 FAL_RAMFUNC static int write_unaligned_page_data(long offset, const rt_uint32_t *buf, rt_size_t size)
143 {
144     hpm_stat_t status;
145 
146     FAL_ENTER_CRITICAL();
147     status = rom_xpi_nor_program(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_flashcfg, buf, offset, size);
148     FAL_EXIT_CRITICAL();
149 
150     if (status != status_success)
151     {
152         return -RT_ERROR;
153         rt_kprintf("write failed, status=%d\n", status);
154     }
155 
156     return size;
157 }
158 
159 /**
160  * @brief FAL write function
161  *        Write data to specified FLASH address
162  * @param offset FLASH offset
163  * @param buf Data buffer
164  * @param size Size of data to be written
165  * @return actual size of written data or error code
166  */
write(long offset,const rt_uint8_t * buf,rt_size_t size)167 FAL_RAMFUNC static int write(long offset, const rt_uint8_t *buf, rt_size_t size)
168 {
169     rt_uint32_t *src = NULL;
170     rt_uint32_t buf_32[64];
171     rt_uint32_t write_size;
172     rt_size_t remaining_size = size;
173     int ret = (int)size;
174 
175     rt_uint32_t page_size;
176     rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_page_size, &page_size);
177     rt_uint32_t offset_in_page = offset % page_size;
178     if (offset_in_page != 0)
179     {
180         rt_uint32_t write_size_in_page = page_size - offset_in_page;
181         rt_uint32_t write_page_size = MIN(write_size_in_page, size);
182         (void) rt_memcpy(buf_32, buf, write_page_size);
183         write_size = write_unaligned_page_data(offset, buf_32, write_page_size);
184         if (write_size < 0)
185         {
186             ret = -RT_ERROR;
187             goto write_quit;
188         }
189 
190         remaining_size -= write_page_size;
191         offset += write_page_size;
192         buf += write_page_size;
193     }
194 
195     while (remaining_size > 0)
196     {
197         write_size = MIN(remaining_size, sizeof(buf_32));
198         rt_memcpy(buf_32, buf, write_size);
199         src = &buf_32[0];
200 
201         FAL_ENTER_CRITICAL();
202         hpm_stat_t status = rom_xpi_nor_program(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_flashcfg, src,
203                 offset, write_size);
204         FAL_EXIT_CRITICAL();
205 
206         if (status != status_success)
207         {
208             ret = -RT_ERROR;
209             rt_kprintf("write failed, status=%d\n", status);
210             break;
211         }
212 
213         remaining_size -= write_size;
214         buf += write_size;
215         offset += write_size;
216     }
217 
218 write_quit:
219     return ret;
220 }
221 
222 /**
223  * @brief FAL erase function
224  *        Erase specified FLASH region
225  * @param offset the start FLASH address to be erased
226  * @param size size of the region to be erased
227  * @ret RT_EOK Erase operation is successful
228  * @retval -RT_ERROR Erase operation failed
229  */
erase(long offset,rt_size_t size)230 FAL_RAMFUNC static int erase(long offset, rt_size_t size)
231 {
232     rt_uint32_t aligned_size = (size + nor_flash0.blk_size - 1U) & ~(nor_flash0.blk_size - 1U);
233     hpm_stat_t status;
234     int ret = (int)size;
235 
236     rt_uint32_t block_size;
237     rt_uint32_t sector_size;
238     (void) rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_sector_size, &sector_size);
239     (void) rom_xpi_nor_get_property(BOARD_APP_XPI_NOR_XPI_BASE, &s_flashcfg, xpi_nor_property_block_size, &block_size);
240     rt_uint32_t erase_unit;
241     while (aligned_size > 0)
242     {
243         FAL_ENTER_CRITICAL();
244         if ((offset % block_size == 0) && (aligned_size >= block_size))
245         {
246             erase_unit = block_size;
247             status = rom_xpi_nor_erase_block(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_flashcfg, offset);
248         }
249         else
250         {
251             erase_unit = sector_size;
252             status = rom_xpi_nor_erase_sector(BOARD_APP_XPI_NOR_XPI_BASE, xpi_xfer_channel_auto, &s_flashcfg, offset);
253         }
254         FAL_EXIT_CRITICAL();
255 
256         if (status != status_success)
257         {
258             ret = -RT_ERROR;
259             break;
260         }
261         offset += erase_unit;
262         aligned_size -= erase_unit;
263     }
264 
265     return ret;
266 }
267 #endif /* RT_USING_FAL */
268