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