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, §or_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, §or_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