1 /**
2  * @file flc.h
3  * @brief      Flash Controler driver.
4  * @details    This driver can be used to operate on the embedded flash memory.
5  */
6 /******************************************************************************
7  *
8  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
9  * Analog Devices, Inc.),
10  * Copyright (C) 2023-2024 Analog Devices, Inc.
11  *
12  * Licensed under the Apache License, Version 2.0 (the "License");
13  * you may not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  *     http://www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  *
24  ******************************************************************************/
25 
26 /* **** Includes **** */
27 #include <string.h>
28 #include "mxc_device.h"
29 #include "mxc_assert.h"
30 #include "mxc_sys.h"
31 #include "flc.h"
32 #include "flc_reva.h"
33 #include "flc_common.h"
34 #include "mcr_regs.h" // For ECCEN registers.
35 
36 //******************************************************************************
MXC_FLC_ME12_Flash_Operation(void)37 void MXC_FLC_ME12_Flash_Operation(void)
38 {
39     /*
40     This function should be called after modifying the contents of flash memory.
41     It flushes the instruction caches and line fill buffer.
42 
43     It should be called _afterwards_ because after flash is modified the cache
44     may contain instructions that may no longer be valid.  _Before_ the
45     flash modifications the ICC may contain relevant cached instructions related to
46     the incoming flash instructions (especially relevant in the case of external memory),
47     and these instructions will be valid up until the point that the modifications are made.
48 
49     The line fill buffer is a FLC-related buffer that also may no longer be valid.
50     It's flushed by reading 2 pages of flash.
51     */
52 
53     /* Flush all instruction caches */
54     MXC_GCR->sysctrl |= MXC_F_GCR_SYSCTRL_ICC0_FLUSH;
55 
56     /* Wait for flush to complete */
57     while (MXC_GCR->sysctrl & MXC_F_GCR_SYSCTRL_ICC0_FLUSH) {}
58 
59     // Clear the line fill buffer by reading 2 pages from flash
60     volatile uint32_t *line_addr;
61     volatile uint32_t __unused line; // __unused attribute removes warning
62     line_addr = (uint32_t *)(MXC_FLASH_MEM_BASE);
63     line = *line_addr;
64     line_addr = (uint32_t *)(MXC_FLASH_MEM_BASE + MXC_FLASH_PAGE_SIZE);
65     line = *line_addr;
66 }
67 
68 //******************************************************************************
MXC_FLC_ME12_GetByAddress(mxc_flc_regs_t ** flc,uint32_t addr)69 int MXC_FLC_ME12_GetByAddress(mxc_flc_regs_t **flc, uint32_t addr)
70 {
71     if ((addr >= MXC_FLASH_MEM_BASE) && (addr < (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE))) {
72         *flc = MXC_FLC;
73     } else if ((addr >= MXC_INFO_MEM_BASE) &&
74                (addr < (MXC_INFO_MEM_BASE + 2 * MXC_INFO_MEM_SIZE))) {
75         *flc = MXC_FLC;
76     } else {
77         return E_BAD_PARAM;
78     }
79 
80     return E_NO_ERROR;
81 }
82 
83 //******************************************************************************
MXC_FLC_ME12_GetPhysicalAddress(uint32_t addr,uint32_t * result)84 int MXC_FLC_ME12_GetPhysicalAddress(uint32_t addr, uint32_t *result)
85 {
86     if ((addr >= MXC_FLASH_MEM_BASE) && (addr < (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE))) {
87         *result = addr - MXC_FLASH_MEM_BASE;
88     } else if ((addr >= MXC_INFO_MEM_BASE) &&
89                (addr < (MXC_INFO_MEM_BASE + 2 * MXC_INFO_MEM_SIZE))) {
90         /* For ME12, the info block base was located at the next power of 2 address beyond the main flash.
91            The ME12 ends at 0x5FFFF, so the info block starts at 0x80000. */
92         *result = (addr & (2 * MXC_INFO_MEM_SIZE - 1)) + MXC_FLASH_MEM_SIZE;
93     } else {
94         return E_BAD_PARAM;
95     }
96 
97     return E_NO_ERROR;
98 }
99 
100 //******************************************************************************
MXC_FLC_Init(void)101 int MXC_FLC_Init(void)
102 {
103     return E_NO_ERROR;
104 }
105 
106 //******************************************************************************
107 #if IAR_PRAGMAS
108 #pragma section = ".flashprog"
109 #else
110 __attribute__((section(".flashprog")))
111 #endif
MXC_FLC_Busy(void)112 int MXC_FLC_Busy(void)
113 {
114     return MXC_FLC_RevA_Busy();
115 }
116 
117 //******************************************************************************
118 #if IAR_PRAGMAS
119 #pragma section = ".flashprog"
120 #else
121 __attribute__((section(".flashprog")))
122 #endif
MXC_FLC_PageErase(uint32_t address)123 int MXC_FLC_PageErase(uint32_t address)
124 {
125     int err;
126     uint32_t addr;
127     mxc_flc_regs_t *flc = NULL;
128 
129     // Get FLC Instance
130     if ((err = MXC_FLC_ME12_GetByAddress(&flc, address)) != E_NO_ERROR) {
131         return err;
132     }
133 
134     if ((err = MXC_FLC_ME12_GetPhysicalAddress(address, &addr)) < E_NO_ERROR) {
135         return err;
136     }
137 
138     err = MXC_FLC_RevA_PageErase((mxc_flc_reva_regs_t *)flc, addr);
139 
140     // Flush the cache
141     MXC_FLC_ME12_Flash_Operation();
142 
143     return err;
144 }
145 
146 //******************************************************************************
147 #if IAR_PRAGMAS
148 #pragma section = ".flashprog"
149 #else
150 __attribute__((section(".flashprog")))
151 #endif
152 // make sure to disable ICC with ICC_Disable(); before Running this function
MXC_FLC_Write128(uint32_t address,uint32_t * data)153 int MXC_FLC_Write128(uint32_t address, uint32_t *data)
154 {
155     int err;
156     mxc_flc_regs_t *flc = NULL;
157     uint32_t addr;
158 
159     // Address checked if it is 128-bit aligned
160     if (address & 0xF) {
161         return E_BAD_PARAM;
162     }
163 
164     // Get FLC Instance
165     if ((err = MXC_FLC_ME12_GetByAddress(&flc, address)) != E_NO_ERROR) {
166         return err;
167     }
168 
169     if ((err = MXC_FLC_ME12_GetPhysicalAddress(address, &addr)) < E_NO_ERROR) {
170         return err;
171     }
172 
173     if ((err = MXC_FLC_RevA_Write128((mxc_flc_reva_regs_t *)flc, addr, data)) != E_NO_ERROR) {
174         return err;
175     }
176 
177     // Flush the cache
178     MXC_FLC_ME12_Flash_Operation();
179 
180     if ((err = MXC_FLC_Com_VerifyData(address, 4, data)) != E_NO_ERROR) {
181         return err;
182     }
183 
184     return E_NO_ERROR;
185 }
186 
187 //******************************************************************************
MXC_FLC_Write32(uint32_t address,uint32_t data)188 int MXC_FLC_Write32(uint32_t address, uint32_t data)
189 {
190     uint32_t addr, aligned;
191     int err;
192     mxc_flc_regs_t *flc = NULL;
193 
194     // Address checked if it is byte addressable
195     if (address & 0x3) {
196         return E_BAD_PARAM;
197     }
198 
199     // Align address to 128-bit word
200     aligned = address & 0xfffffff0;
201 
202     // Get FLC Instance
203     if ((err = MXC_FLC_ME12_GetByAddress(&flc, address)) != E_NO_ERROR) {
204         return err;
205     }
206 
207     if ((err = MXC_FLC_ME12_GetPhysicalAddress(aligned, &addr)) < E_NO_ERROR) {
208         return err;
209     }
210 
211     err = MXC_FLC_RevA_Write32Using128((mxc_flc_reva_regs_t *)flc, address, data, addr);
212 
213     // Flush the cache
214     MXC_FLC_ME12_Flash_Operation();
215 
216     return err;
217 }
218 
219 //******************************************************************************
MXC_FLC_MassErase(void)220 int MXC_FLC_MassErase(void)
221 {
222     int err, i;
223     mxc_flc_regs_t *flc;
224 
225     for (i = 0; i < MXC_FLC_INSTANCES; i++) {
226         flc = MXC_FLC_GET_FLC(i);
227         err = MXC_FLC_RevA_MassErase((mxc_flc_reva_regs_t *)flc);
228 
229         if (err != E_NO_ERROR) {
230             return err;
231         }
232 
233         MXC_FLC_ME12_Flash_Operation();
234     }
235 
236     return E_NO_ERROR;
237 }
238 
239 //******************************************************************************
MXC_FLC_UnlockInfoBlock(uint32_t address)240 int MXC_FLC_UnlockInfoBlock(uint32_t address)
241 {
242     /* User accessible area in MAX32662 infoblock does not need to be unlocked. */
243     return E_NOT_SUPPORTED;
244 }
245 
246 //******************************************************************************
MXC_FLC_LockInfoBlock(uint32_t address)247 int MXC_FLC_LockInfoBlock(uint32_t address)
248 {
249     int err;
250     mxc_flc_regs_t *flc;
251 
252     if ((err = MXC_FLC_ME12_GetByAddress(&flc, address)) != E_NO_ERROR) {
253         return err;
254     }
255 
256     return MXC_FLC_RevA_LockInfoBlock((mxc_flc_reva_regs_t *)flc, address);
257 }
258 
259 //******************************************************************************
MXC_FLC_Write(uint32_t address,uint32_t length,uint32_t * buffer)260 int MXC_FLC_Write(uint32_t address, uint32_t length, uint32_t *buffer)
261 {
262     return MXC_FLC_Com_Write(address, length, buffer);
263 }
264 
265 //******************************************************************************
MXC_FLC_Read(int address,void * buffer,int len)266 void MXC_FLC_Read(int address, void *buffer, int len)
267 {
268     MXC_FLC_Com_Read(address, buffer, len);
269 }
270 
271 //******************************************************************************
MXC_FLC_EnableInt(uint32_t flags)272 int MXC_FLC_EnableInt(uint32_t flags)
273 {
274     return MXC_FLC_RevA_EnableInt(flags);
275 }
276 
277 //******************************************************************************
MXC_FLC_DisableInt(uint32_t flags)278 int MXC_FLC_DisableInt(uint32_t flags)
279 {
280     return MXC_FLC_RevA_DisableInt(flags);
281 }
282 
283 //******************************************************************************
MXC_FLC_GetFlags(void)284 int MXC_FLC_GetFlags(void)
285 {
286     return MXC_FLC_RevA_GetFlags();
287 }
288 
289 //******************************************************************************
MXC_FLC_ClearFlags(uint32_t flags)290 int MXC_FLC_ClearFlags(uint32_t flags)
291 {
292     return MXC_FLC_RevA_ClearFlags(flags);
293 }
294 
295 //******************************************************************************
MXC_FLC_BlockPageWrite(uint32_t address)296 int MXC_FLC_BlockPageWrite(uint32_t address)
297 {
298     if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
299         return E_INVALID;
300     }
301 
302     return MXC_FLC_RevA_BlockPageWrite(address, MXC_FLASH_MEM_BASE);
303 }
304 
305 //******************************************************************************
MXC_FLC_BlockPageRead(uint32_t address)306 int MXC_FLC_BlockPageRead(uint32_t address)
307 {
308     if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
309         return E_INVALID;
310     }
311 
312     return MXC_FLC_RevA_BlockPageRead(address, MXC_FLASH_MEM_BASE);
313 }
314 
315 //******************************************************************************
MXC_FLC_GetWELR(uint32_t address,uint32_t page_num)316 volatile uint32_t *MXC_FLC_GetWELR(uint32_t address, uint32_t page_num)
317 {
318     uint32_t reg_num;
319     reg_num = page_num >>
320               5; // Divide by 32 to get WELR register number containing the page lock bit
321 
322     if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
323         return NULL;
324     }
325 
326     switch (reg_num) {
327     case 0:
328         return &(MXC_FLC0->welr0);
329     case 1:
330         return &(MXC_FLC0->welr1);
331     }
332 
333     return NULL;
334 }
335 
336 //******************************************************************************
MXC_FLC_GetRLR(uint32_t address,uint32_t page_num)337 volatile uint32_t *MXC_FLC_GetRLR(uint32_t address, uint32_t page_num)
338 {
339     uint32_t reg_num;
340     reg_num = page_num >> 5; // Divide by 32 to get RLR register number containing the page lock bit
341 
342     if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
343         return NULL;
344     }
345 
346     switch (reg_num) {
347     case 0:
348         return &(MXC_FLC0->rlr0);
349     case 1:
350         return &(MXC_FLC0->rlr1);
351     }
352 
353     return NULL;
354 }
355