1 /*
2 * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-04-28 CDT First version
9 * 2024-06-14 CDT Fixed sector number calculation
10 * 2024-06-18 CDT Support HC32F460,HC32F448,HC32F472
11 * 2025-07-16 CDT Support HC32F334
12 */
13
14 #include "board.h"
15
16 #if defined(BSP_USING_ON_CHIP_FLASH)
17 #include "drv_config.h"
18 #include "drv_flash.h"
19
20 #if defined(RT_USING_FAL)
21 #include "fal.h"
22 #endif
23
24 //#define DRV_DEBUG
25 #define LOG_TAG "drv.flash"
26 #include <drv_log.h>
27
28 /**
29 * @brief Gets the sector number.
30 * @param addr flash address
31 * @param size erase bytes size
32 * @retval Sector number.
33 */
GetSectorNum(rt_uint32_t addr,size_t size)34 static rt_uint32_t GetSectorNum(rt_uint32_t addr, size_t size)
35 {
36 rt_uint32_t firstSector = 0, lastSector = 0;
37 rt_uint32_t NumOfSectors = 0;
38
39 firstSector = addr / EFM_SECTOR_SIZE;
40 lastSector = (addr + size - 1U) / EFM_SECTOR_SIZE;
41 NumOfSectors = lastSector - firstSector + 1U;
42
43 return NumOfSectors;
44 }
45
46 /**
47 * @brief Read data from flash.
48 * @param addr flash address
49 * @param buf buffer to store read data
50 * @param size read bytes size
51 * @return result
52 */
hc32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)53 int hc32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
54 {
55 if ((addr + size) > HC32_FLASH_END_ADDRESS)
56 {
57 LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
58 return -1;
59 }
60
61 if (LL_OK != EFM_ReadByte(addr, buf, size))
62 {
63 return -RT_ERROR;
64 }
65
66 return size;
67 }
68
69 /**
70 * @brief Write data to flash.
71 * @param addr flash address
72 * @param buf the write data buffer
73 * @param size write bytes size
74 * @return result
75 * @note This operation's units is word.
76 * @note This operation must after erase.
77 */
hc32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,size_t size)78 int hc32_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
79 {
80 uint8_t u8MemBuf[HC32_FLASH_WRITE_GRANULARITY];
81 rt_err_t result = RT_EOK;
82 rt_uint32_t newAddr = addr, offsetVal = 0;
83 rt_uint32_t index = 0, u32Cnt = 0;
84 #if defined (HC32F4A0) || defined (HC32F472) || defined (HC32F448) || defined (HC32F4A8) || defined (HC32F334)
85 rt_uint32_t FirstSector = 0, NumOfSectors = 0;
86 #endif
87
88 if ((addr + size) > HC32_FLASH_END_ADDRESS)
89 {
90 LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
91 return -RT_EINVAL;
92 }
93 if (size < 1)
94 {
95 return -RT_EINVAL;
96 }
97
98 for (u32Cnt = 0; u32Cnt < HC32_FLASH_WRITE_GRANULARITY; u32Cnt++)
99 {
100 u8MemBuf[u32Cnt] = 0xFF;
101 }
102 /* EFM_FWMC write enable */
103 EFM_FWMC_Cmd(ENABLE);
104 #if defined (HC32F4A0) || defined (HC32F472) || defined (HC32F448) || defined (HC32F4A8) || defined (HC32F334)
105 /* calculate sector information */
106 FirstSector = addr / EFM_SECTOR_SIZE,
107 NumOfSectors = GetSectorNum(addr, size);
108 /* Sectors disable write protection */
109 EFM_SequenceSectorOperateCmd(FirstSector, NumOfSectors, ENABLE);
110 #endif
111 /* Word align */
112 if (0U != (addr % HC32_FLASH_WRITE_GRANULARITY))
113 {
114 newAddr = (addr / HC32_FLASH_WRITE_GRANULARITY + 1U) * HC32_FLASH_WRITE_GRANULARITY;
115 offsetVal = newAddr - addr;
116 if (offsetVal >= size)
117 {
118 result = -RT_ERROR;
119 index = HC32_FLASH_WRITE_GRANULARITY - offsetVal;
120 if (LL_OK == EFM_ReadByte(newAddr - HC32_FLASH_WRITE_GRANULARITY, u8MemBuf, index))
121 {
122 for (u32Cnt = 0; u32Cnt < size; u32Cnt++)
123 {
124 u8MemBuf[index + u32Cnt] = buf[u32Cnt];
125 }
126 /* program */
127 if (LL_OK == EFM_Program(newAddr - HC32_FLASH_WRITE_GRANULARITY, u8MemBuf, HC32_FLASH_WRITE_GRANULARITY))
128 {
129 result = RT_EOK;
130 }
131 }
132 goto __exit;
133 }
134 else
135 {
136 size = size - offsetVal;
137 }
138 }
139 /* program */
140 if (LL_OK != EFM_Program(newAddr, (uint8_t *)&buf[offsetVal], size))
141 {
142 result = -RT_ERROR;
143 goto __exit;
144 }
145
146 __exit:
147 #if defined (HC32F4A0) || defined (HC32F472) || defined (HC32F448) || defined (HC32F4A8) || defined (HC32F334)
148 /* Sectors enable write protection */
149 EFM_SequenceSectorOperateCmd(FirstSector, NumOfSectors, DISABLE);
150 #endif
151 EFM_FWMC_Cmd(DISABLE);
152
153 if (result != RT_EOK)
154 {
155 return result;
156 }
157
158 return size;
159 }
160
161 /**
162 * @brief Erase data on flash.
163 * @param addr flash address
164 * @param size erase bytes size
165 * @return result
166 * @note This operation is irreversible.
167 */
hc32_flash_erase(rt_uint32_t addr,size_t size)168 int hc32_flash_erase(rt_uint32_t addr, size_t size)
169 {
170 rt_err_t result = RT_EOK;
171 rt_uint32_t NumOfSectors = 0;
172 rt_uint32_t SectorVal = 0, u32Addr = addr;
173 #if defined (HC32F4A0) || defined (HC32F472) || defined (HC32F448) || defined (HC32F4A8) || defined (HC32F334)
174 rt_uint32_t FirstSector = 0;
175 #endif
176
177 if ((addr + size) > HC32_FLASH_END_ADDRESS)
178 {
179 LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void *)(addr + size));
180 return -RT_EINVAL;
181 }
182 if (size < 1)
183 {
184 return -RT_EINVAL;
185 }
186
187 /* EFM_FWMC write enable */
188 EFM_FWMC_Cmd(ENABLE);
189 /* calculate sector information */
190 NumOfSectors = GetSectorNum(addr, size);
191 #if defined (HC32F4A0) || defined (HC32F472) || defined (HC32F448) || defined (HC32F4A8) || defined (HC32F334)
192 FirstSector = addr / EFM_SECTOR_SIZE,
193 /* Sectors disable write protection */
194 EFM_SequenceSectorOperateCmd(FirstSector, NumOfSectors, ENABLE);
195 #endif
196 /* Erase sector */
197 for (SectorVal = 0U; SectorVal < NumOfSectors; SectorVal++)
198 {
199 if (LL_OK != EFM_SectorErase(u32Addr))
200 {
201 result = -RT_ERROR;
202 break;
203 }
204 u32Addr += EFM_SECTOR_SIZE;
205 }
206 #if defined (HC32F4A0) || defined (HC32F472) || defined (HC32F448) || defined (HC32F4A8) || defined (HC32F334)
207 /* Sectors enable write protection */
208 EFM_SequenceSectorOperateCmd(FirstSector, NumOfSectors, DISABLE);
209 #endif
210 EFM_FWMC_Cmd(DISABLE);
211
212 if (result != RT_EOK)
213 {
214 return result;
215 }
216
217 LOG_D("erase done: addr (0x%p), size %d", (void *)addr, size);
218 return size;
219 }
220
221 #if defined(RT_USING_FAL)
222 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
223 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
224 static int fal_flash_erase(long offset, size_t size);
225
226 const struct fal_flash_dev hc32_onchip_flash =
227 {
228 .name = "onchip_flash",
229 .addr = HC32_FLASH_START_ADDRESS,
230 .len = HC32_FLASH_SIZE,
231 .blk_size = HC32_FLASH_ERASE_GRANULARITY,
232 .ops = {NULL, fal_flash_read, fal_flash_write, fal_flash_erase},
233 .write_gran = HC32_FLASH_WRITE_GRANULARITY
234 };
235
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)236 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
237 {
238 return hc32_flash_read(hc32_onchip_flash.addr + offset, buf, size);
239 }
240
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)241 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
242 {
243 return hc32_flash_write(hc32_onchip_flash.addr + offset, buf, size);
244 }
245
fal_flash_erase(long offset,size_t size)246 static int fal_flash_erase(long offset, size_t size)
247 {
248 return hc32_flash_erase(hc32_onchip_flash.addr + offset, size);
249 }
250 #endif
251
252 #endif /* BSP_USING_ON_CHIP_FLASH */
253