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  * 2018-12-5      SummerGift   first version
9  */
10 
11 #include <rtconfig.h>
12 #include <rtdef.h>
13 
14 #ifdef BSP_USING_ON_CHIP_FLASH
15 #include "drv_config.h"
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 /**
28   * @brief  Gets the page of a given address
29   * @param  Addr: Address of the FLASH Memory
30   * @retval The page of a given address
31   */
GetPage(uint32_t Addr)32 static uint32_t GetPage(uint32_t Addr)
33 {
34     uint32_t page = 0;
35 
36     if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))
37     {
38         /* Bank 1 */
39         page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
40     }
41     else
42     {
43         /* Bank 2 */
44         page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
45     }
46 
47     return page;
48 }
49 
50 /**
51   * @brief  Gets the bank of a given address
52   * @param  Addr: Address of the FLASH Memory
53   * @retval The bank of a given address
54   */
GetBank(uint32_t Addr)55 static uint32_t GetBank(uint32_t Addr)
56 {
57     uint32_t bank = 0;
58 #ifndef FLASH_BANK_2
59     bank = FLASH_BANK_1;
60 #else
61     if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0)
62     {
63         /* No Bank swap */
64         if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))
65         {
66             bank = FLASH_BANK_1;
67         }
68         else
69         {
70             bank = FLASH_BANK_2;
71         }
72     }
73     else
74     {
75         /* Bank swap */
76         if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))
77         {
78             bank = FLASH_BANK_2;
79         }
80         else
81         {
82             bank = FLASH_BANK_1;
83         }
84     }
85 #endif
86     return bank;
87 }
88 
89 /**
90  * Read data from flash.
91  * @note This operation's units is word.
92  *
93  * @param addr flash address
94  * @param buf buffer to store read data
95  * @param size read bytes size
96  *
97  * @return result
98  */
stm32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)99 int stm32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
100 {
101     size_t i;
102 
103     if ((addr + size) > STM32_FLASH_END_ADDRESS)
104     {
105         LOG_E("read outrange flash size! addr is (0x%p)", (void*)(addr + size));
106         return -RT_EINVAL;
107     }
108 
109     for (i = 0; i < size; i++, buf++, addr++)
110     {
111         *buf = *(rt_uint8_t *) addr;
112     }
113 
114     return size;
115 }
116 
117 /**
118  * Write data to flash.
119  * @note This operation's units is word.
120  * @note This operation must after erase. @see flash_erase.
121  *
122  * @param addr flash address
123  * @param buf the write data buffer
124  * @param size write bytes size
125  *
126  * @return result
127  */
128 
stm32_flash_write(rt_uint32_t addr,const uint8_t * buf,size_t size)129 int stm32_flash_write(rt_uint32_t addr, const uint8_t *buf, size_t size)
130 {
131     size_t i, j;
132     rt_err_t result = 0;
133     rt_uint64_t write_data = 0, temp_data = 0;
134 
135     if ((addr + size) > STM32_FLASH_END_ADDRESS)
136     {
137         LOG_E("ERROR: write outrange flash size! addr is (0x%p)\n", (void*)(addr + size));
138         return -RT_EINVAL;
139     }
140 
141     if(addr % 8 != 0)
142     {
143         LOG_E("write addr must be 8-byte alignment");
144         return -RT_EINVAL;
145     }
146 
147     HAL_FLASH_Unlock();
148 
149     __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR);
150 
151     if (size < 1)
152     {
153         return -RT_ERROR;
154     }
155 
156     for (i = 0; i < size;)
157     {
158         if ((size - i) < 8)
159         {
160             for (j = 0; (size - i) > 0; i++, j++)
161             {
162                 temp_data = *buf;
163                 write_data = (write_data) | (temp_data << 8 * j);
164                 buf ++;
165             }
166         }
167         else
168         {
169             for (j = 0; j < 8; j++, i++)
170             {
171                 temp_data = *buf;
172                 write_data = (write_data) | (temp_data << 8 * j);
173                 buf ++;
174             }
175         }
176 
177         /* write data */
178         if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, write_data) == HAL_OK)
179         {
180             /* Check the written value */
181             if (*(uint64_t*)addr != write_data)
182             {
183                 LOG_E("ERROR: write data != read data\n");
184                 result = -RT_ERROR;
185                 goto __exit;
186             }
187         }
188         else
189         {
190             result = -RT_ERROR;
191             goto __exit;
192         }
193 
194         temp_data = 0;
195         write_data = 0;
196 
197         addr += 8;
198     }
199 
200 __exit:
201     HAL_FLASH_Lock();
202     if (result != 0)
203     {
204         return result;
205     }
206 
207     return size;
208 }
209 
210 /**
211  * Erase data on flash.
212  * @note This operation is irreversible.
213  * @note This operation's units is different which on many chips.
214  *
215  * @param addr flash address
216  * @param size erase bytes size
217  *
218  * @return result
219  */
stm32_flash_erase(rt_uint32_t addr,size_t size)220 int stm32_flash_erase(rt_uint32_t addr, size_t size)
221 {
222     rt_err_t result = RT_EOK;
223     uint32_t FirstPage = 0, NbOfPages = 0, BankNumber = 0;
224     uint32_t PAGEError = 0;
225 
226     if ((addr + size) > STM32_FLASH_END_ADDRESS)
227     {
228         LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void*)(addr + size));
229         return -RT_EINVAL;
230     }
231 
232     /*Variable used for Erase procedure*/
233     FLASH_EraseInitTypeDef EraseInitStruct;
234     /* Unlock the Flash to enable the flash control register access *************/
235     HAL_FLASH_Unlock();
236 
237     /* Clear OPTVERR bit set on virgin samples */
238     __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR | FLASH_FLAG_PGSERR);
239     /* Get the 1st page to erase */
240     FirstPage = GetPage(addr);
241     /* Get the number of pages to erase from 1st page */
242     NbOfPages = GetPage(addr + size - 1) - FirstPage + 1;
243     /* Get the bank */
244     BankNumber = GetBank(addr);
245     /* Fill EraseInit structure*/
246     EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
247     EraseInitStruct.Banks       = BankNumber;
248     EraseInitStruct.Page        = FirstPage;
249     EraseInitStruct.NbPages     = NbOfPages;
250 
251     if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
252     {
253         result = -RT_ERROR;
254         goto __exit;
255     }
256 
257 __exit:
258     HAL_FLASH_Lock();
259 
260     if (result != RT_EOK)
261     {
262         return result;
263     }
264 
265     LOG_D("erase done: addr (0x%p), size %d", (void*)addr, size);
266     return size;
267 }
268 
269 #if defined(RT_USING_FAL)
270 
271 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
272 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
273 static int fal_flash_erase(long offset, size_t size);
274 
275 const struct fal_flash_dev stm32_onchip_flash = { "onchip_flash", STM32_FLASH_START_ADRESS, STM32_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase} };
276 
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)277 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
278 {
279     return stm32_flash_read(stm32_onchip_flash.addr + offset, buf, size);
280 }
281 
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)282 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
283 {
284     return stm32_flash_write(stm32_onchip_flash.addr + offset, buf, size);
285 }
286 
fal_flash_erase(long offset,size_t size)287 static int fal_flash_erase(long offset, size_t size)
288 {
289     return stm32_flash_erase(stm32_onchip_flash.addr + offset, size);
290 }
291 
292 #endif
293 #endif /* BSP_USING_ON_CHIP_FLASH */
294