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