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  * 2023-03-16     luobeihai    first version
9  *
10  */
11 
12 #include "board.h"
13 
14 #ifdef BSP_USING_ON_CHIP_FLASH
15 #include "drv_flash.h"
16 
17 #if defined(RT_USING_FAL)
18 #include "fal.h"
19 #endif
20 
21 #define DRV_DEBUG
22 #define LOG_TAG                "drv.flash"
23 #include <drv_log.h>
24 
25 #if (defined(APM32F030x6) || defined(APM32F030x8) || defined(APM32F051))
26 #define FLASH_PAGE_SIZE          0x400U
27 #elif (defined(APM32F030xC) || defined(APM32F070xB) || defined(APM32F071) || defined(APM32F072) || defined(APM32F091))
28 #define FLASH_PAGE_SIZE          0x800U
29 #endif
30 
31 /**
32   * @brief  Gets the page of a given address
33   * @param  Addr: Address of the FLASH Memory
34   * @retval The page of a given address
35   */
GetPage(uint32_t addr)36 static uint32_t GetPage(uint32_t addr)
37 {
38     uint32_t page = 0;
39     page = RT_ALIGN_DOWN(addr, FLASH_PAGE_SIZE);
40     return page;
41 }
42 
43 /**
44  * Read data from flash.
45  * @note This operation's units is word.
46  *
47  * @param addr flash address
48  * @param buf buffer to store read data
49  * @param size read bytes size
50  *
51  * @return result
52  */
apm32_flash_read(rt_uint32_t addr,rt_uint8_t * buf,size_t size)53 int apm32_flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
54 {
55     size_t i;
56 
57     if ((addr + size) > APM32_FLASH_END_ADDRESS)
58     {
59         LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
60         return -RT_EINVAL;
61     }
62 
63     for (i = 0; i < size; i++, buf++, addr++)
64     {
65         *buf = *(rt_uint8_t *) addr;
66     }
67 
68     return size;
69 }
70 
71 /**
72  * Write data to flash.
73  * @note This operation's units is word.
74  * @note This operation must after erase. @see flash_erase.
75  *
76  * @param addr flash address
77  * @param buf the write data buffer
78  * @param size write bytes size
79  *
80  * @return result
81  */
apm32_flash_write(rt_uint32_t addr,const rt_uint8_t * buf,size_t size)82 int apm32_flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
83 {
84     rt_err_t result        = RT_EOK;
85     rt_uint32_t end_addr   = addr + size;
86 
87     if (addr % 4 != 0)
88     {
89         LOG_E("write addr must be 4-byte alignment");
90         return -RT_EINVAL;
91     }
92 
93     if ((end_addr) > APM32_FLASH_END_ADDRESS)
94     {
95         LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
96         return -RT_EINVAL;
97     }
98 
99     FMC_Unlock();
100 
101     while (addr < end_addr)
102     {
103         if (FMC_ProgramWord(addr, *((rt_uint32_t *)buf)) == FMC_STATE_COMPLETE)
104         {
105             if (*(rt_uint32_t *)addr != *(rt_uint32_t *)buf)
106             {
107                 result = -RT_ERROR;
108                 break;
109             }
110             addr += 4;
111             buf  += 4;
112         }
113         else
114         {
115             result = -RT_ERROR;
116             break;
117         }
118     }
119 
120     FMC_Lock();
121 
122     if (result != RT_EOK)
123     {
124         return result;
125     }
126 
127     return size;
128 }
129 
130 /**
131  * @brief erase data on flash .
132  * @note this operation is irreversible.
133  * @note this operation's units is different which on many chips.
134  *
135  * @param addr flash address
136  * @param size erase bytes size
137  *
138  * @return result
139  */
apm32_flash_erase(rt_uint32_t addr,size_t size)140 int apm32_flash_erase(rt_uint32_t addr, size_t size)
141 {
142     rt_err_t result = RT_EOK;
143     rt_uint32_t start_addr = addr;
144     rt_uint32_t end_addr = addr + size;
145     rt_uint32_t page_addr = 0;
146 
147     FMC_Unlock();
148 
149     if ((end_addr) > APM32_FLASH_END_ADDRESS)
150     {
151         LOG_E("erase outrange flash size! addr is (0x%p)", (void *)(addr + size));
152         return -RT_EINVAL;
153     }
154 
155     /* clear program error flag */
156     if (FMC_ReadStatusFlag(FMC_FLAG_PE) == SET)
157     {
158         FMC_ClearStatusFlag(FMC_FLAG_PE);
159     }
160 
161     while(addr < end_addr)
162     {
163         page_addr = GetPage(addr);
164 
165         if(FMC_ErasePage(page_addr) != FMC_STATE_COMPLETE)
166         {
167             result = -RT_ERROR;
168             goto __exit;
169         }
170 
171         addr += FLASH_PAGE_SIZE;
172     }
173 
174 __exit:
175     FMC_Lock();
176 
177     if(result != RT_EOK)
178     {
179         return result;
180     }
181 
182     LOG_D("erase done: addr (0x%p), size %d", (void *)start_addr, size);
183 
184     return size;
185 }
186 
187 
188 #if defined(RT_USING_FAL)
189 
190 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
191 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
192 static int fal_flash_erase(long offset, size_t size);
193 
194 const struct fal_flash_dev apm32_onchip_flash = { "onchip_flash", APM32_FLASH_START_ADRESS, APM32_FLASH_SIZE, FLASH_PAGE_SIZE, {NULL, fal_flash_read, fal_flash_write, fal_flash_erase} };
195 
fal_flash_read(long offset,rt_uint8_t * buf,size_t size)196 static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
197 {
198     return apm32_flash_read(apm32_onchip_flash.addr + offset, buf, size);
199 }
200 
fal_flash_write(long offset,const rt_uint8_t * buf,size_t size)201 static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
202 {
203     return apm32_flash_write(apm32_onchip_flash.addr + offset, buf, size);
204 }
205 
fal_flash_erase(long offset,size_t size)206 static int fal_flash_erase(long offset, size_t size)
207 {
208     return apm32_flash_erase(apm32_onchip_flash.addr + offset, size);
209 }
210 
211 #endif
212 #endif /* BSP_USING_ON_CHIP_FLASH */
213