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