1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2025-05-20     Chasel       first version
9  *
10  */
11 
12 #include <rtconfig.h>
13 #include <rtdef.h>
14 
15 #ifdef BSP_USING_ON_CHIP_FLASH
16 #include "drv_flash.h"
17 #include <board.h>
18 
19 #if defined(RT_USING_FAL)
20 #include "fal.h"
21 #endif
22 
23 #define DRV_DEBUG
24 #define LOG_TAG                "drv.flash"
25 #include <drv_log.h>
26 
27 #define FLASH_PAGE_SIZE        4096
28 
29 /* @note If there is no down-frequency processing, the timeout time needs to be modified */
30 #ifdef ProgramTimeout
31 #undef ProgramTimeout
32 #define ProgramTimeout             ((uint32_t)0x00010000)
33 #endif
34 
35 
36 /**
37   * @brief  Gets the page of a given address
38   * @param  Addr: Address of the FLASH Memory
39   * @retval The page of a given address
40   */
GetPage(uint32_t addr)41 static uint32_t GetPage(uint32_t addr)
42 {
43     uint32_t page = 0;
44     page = RT_ALIGN_DOWN(addr, FLASH_PAGE_SIZE);
45     return page;
46 }
47 
48 /**
49  * Read data from flash.
50  * @note This operation's units is word.
51  *
52  * @param addr flash address
53  * @param buf buffer to store read data
54  * @param size read bytes size
55  *
56  * @return result
57  */
ch32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)58 int ch32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
59 {
60     size_t i;
61 
62     if ((addr + size) > CH32_FLASH_END_ADDRESS)
63     {
64         LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
65         return -RT_EINVAL;
66     }
67 
68     for (i = 0; i < size; i++, buf++, addr++)
69     {
70         *buf = *(rt_uint8_t *) addr;
71     }
72 
73     return size;
74 }
75 
76 /**
77  * Write data to flash.
78  * @note This operation's units is word.
79  * @note This operation must after erase. @see flash_erase.
80  *
81  * @param addr flash address
82  * @param buf the write data buffer
83  * @param size write bytes size
84  *
85  * @return result
86  */
ch32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,size_t size)87 int ch32_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
88 {
89     rt_err_t result        = RT_EOK;
90     FLASH_Status status    = 0;
91     rt_uint32_t end_addr   = addr + size;
92 
93     if (addr % 4 != 0)
94     {
95         LOG_E("write addr must be 4-byte alignment");
96         return -RT_EINVAL;
97     }
98 
99     if ((end_addr) > CH32_FLASH_END_ADDRESS)
100     {
101         LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
102         return -RT_EINVAL;
103     }
104 
105     if (((addr & 0x000000FF) == 0) && (size & 0xFFFFFF00)) {
106         rt_uint32_t fast_size = (size & 0xFFFFFF00);
107 
108         status = FLASH_ROM_WRITE(addr, (rt_uint32_t *)buf, fast_size);
109         if (status != FLASH_COMPLETE) {
110             LOG_E("FLASH ROM Write Fail\r\n");
111             return -RT_ERROR;
112         }
113 
114         addr += fast_size;
115         buf  += fast_size;
116     }
117     if (addr == end_addr) {
118         return size;
119     }
120 
121     FLASH_Access_Clock_Cfg(FLASH_Access_SYSTEM_HALF);
122     FLASH_Unlock();
123     FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
124 
125     while (addr < end_addr)
126     {
127         status = FLASH_ProgramWord(addr, *((rt_uint32_t *)buf));
128         if (status == FLASH_COMPLETE)
129         {
130             if (*(rt_uint32_t *)addr != *(rt_uint32_t *)buf)
131             {
132                 result = -RT_ERROR;
133                 break;
134             }
135             addr += 4;
136             buf  += 4;
137         }
138         else
139         {
140             result = -RT_ERROR;
141             break;
142         }
143     }
144 
145     FLASH_Lock();
146     FLASH_Access_Clock_Cfg(FLASH_Access_SYSTEM);
147 
148     if (result != RT_EOK)
149     {
150         return result;
151     }
152 
153     return size;
154 }
155 
156 /**
157  * Erase data on flash .
158  * @note This operation is irreversible.
159  * @note This operation's units is different which on many chips.
160  *
161  * @param addr flash address
162  * @param size erase bytes size
163  *
164  * @return result
165  */
ch32_flash_erase(rt_uint32_t addr,size_t size)166 int ch32_flash_erase(rt_uint32_t addr, size_t size)
167 {
168     rt_err_t result = RT_EOK;
169     FLASH_Status status = 0;
170     uint32_t num_page = 0;
171     uint32_t i = 0;
172     rt_uint32_t total_size = size;
173 
174     if ((addr + size) > CH32_FLASH_END_ADDRESS)
175     {
176         LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void *)(addr + size));
177         return -RT_EINVAL;
178     }
179 
180     if (((addr & 0x000000FF) == 0) && (total_size & 0xFFFFFF00)) {
181         rt_uint32_t fast_size = (total_size & 0xFFFFFF00);
182 
183         status = FLASH_ROM_ERASE(addr, fast_size);
184         if (status != FLASH_COMPLETE) {
185             LOG_E("FLASH ROM Erase Fail\r\n");
186             return -RT_ERROR;
187         }
188 
189         addr += fast_size;
190         total_size -= fast_size;
191     }
192 
193     if (0 == total_size) {
194         return size;
195     }
196 
197     FLASH_Access_Clock_Cfg(FLASH_Access_SYSTEM_HALF);
198     FLASH_Unlock();
199     FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
200 
201     num_page = (total_size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
202 
203     FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);
204 
205     for(i = 0; (i < num_page) && (status == FLASH_COMPLETE); i++)
206     {
207         status = FLASH_ErasePage(GetPage(addr + i * FLASH_PAGE_SIZE)); //Erase 4KB
208 
209         if(status != FLASH_COMPLETE)
210         {
211             LOG_E("FLASH Erase Fail\r\n");
212             result = -RT_ERROR;
213             goto __exit;
214         }
215     }
216 
217 __exit:
218     FLASH_Lock();
219     FLASH_Access_Clock_Cfg(FLASH_Access_SYSTEM);
220 
221     if (result != RT_EOK)
222     {
223         return -RT_ERROR;
224     }
225 
226     return size;
227 }
228 
229 
230 #if defined(RT_USING_FAL)
231 
232 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
233 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
234 static int fal_flash_erase(long offset, size_t size);
235 
236 const struct fal_flash_dev ch32_onchip_flash = { "onchip_flash", CH32_FLASH_START_ADRESS, CH32_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase}, 8, {} ,};
237 
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)238 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
239 {
240     return ch32_flash_read(ch32_onchip_flash.addr + offset, buf, size);
241 }
242 
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)243 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
244 {
245     return ch32_flash_write(ch32_onchip_flash.addr + offset, buf, size);
246 }
247 
fal_flash_erase(long offset,size_t size)248 static int fal_flash_erase(long offset, size_t size)
249 {
250     return ch32_flash_erase(ch32_onchip_flash.addr + offset, size);
251 }
252 
253 #endif
254 #endif /* BSP_USING_ON_CHIP_FLASH */
255