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_reva.h"
32 #include "flc.h"
33 
34 /**
35  * @ingroup flc
36  * @{
37  */
38 
39 /* **** Definitions **** */
40 
41 /* **** Globals **** */
42 #ifdef MXC_FLC0
43 static mxc_flc_reva_regs_t *flc_int = (mxc_flc_reva_regs_t *)MXC_FLC0;
44 #else
45 static mxc_flc_reva_regs_t *flc_int = (mxc_flc_reva_regs_t *)MXC_FLC;
46 #endif
47 
48 /* **** Functions **** */
49 
50 //******************************************************************************
51 #if IAR_PRAGMAS
52 #pragma section = ".flashprog"
53 #else
54 __attribute__((section(".flashprog")))
55 #endif
MXC_busy_flc(mxc_flc_reva_regs_t * flc)56 static int MXC_busy_flc(mxc_flc_reva_regs_t *flc)
57 {
58     return (flc->ctrl &
59             (MXC_F_FLC_REVA_CTRL_WR | MXC_F_FLC_REVA_CTRL_ME | MXC_F_FLC_REVA_CTRL_PGE));
60 }
61 
62 //******************************************************************************
63 #if IAR_PRAGMAS
64 #pragma section = ".flashprog"
65 #else
66 __attribute__((section(".flashprog")))
67 #endif
MXC_prepare_flc(mxc_flc_reva_regs_t * flc)68 static int MXC_prepare_flc(mxc_flc_reva_regs_t *flc)
69 {
70     /* Check if the flash controller is busy */
71     if (MXC_busy_flc(flc)) {
72         return E_BUSY;
73     }
74 
75     // Set flash clock divider to generate a 1MHz clock from the APB clock
76     flc->clkdiv = SystemCoreClock / 1000000;
77 
78     /* Clear stale errors */
79     if (flc->intr & MXC_F_FLC_REVA_INTR_AF) {
80         flc->intr &= ~MXC_F_FLC_REVA_INTR_AF;
81     }
82 
83     /* Unlock flash */
84     flc->ctrl = (flc->ctrl & ~MXC_F_FLC_REVA_CTRL_UNLOCK) | MXC_S_FLC_REVA_CTRL_UNLOCK_UNLOCKED;
85 
86     return E_NO_ERROR;
87 }
88 
89 //******************************************************************************
90 #if IAR_PRAGMAS
91 #pragma section = ".flashprog"
92 #else
93 __attribute__((section(".flashprog")))
94 #endif
MXC_FLC_RevA_Busy(void)95 int MXC_FLC_RevA_Busy(void)
96 {
97     uint32_t flc_cn = 0;
98     int i;
99     mxc_flc_reva_regs_t *flc;
100 
101     for (i = 0; i < MXC_FLC_INSTANCES; i++) {
102         flc = (mxc_flc_reva_regs_t *)MXC_FLC_GET_FLC(i);
103         flc_cn = MXC_busy_flc(flc);
104 
105         if (flc_cn != 0) {
106             break;
107         }
108     }
109 
110     return flc_cn;
111 }
112 //******************************************************************************
113 #if IAR_PRAGMAS
114 #pragma section = ".flashprog"
115 #else
116 __attribute__((section(".flashprog")))
117 #endif
MXC_FLC_RevA_MassErase(mxc_flc_reva_regs_t * flc)118 int MXC_FLC_RevA_MassErase(mxc_flc_reva_regs_t *flc)
119 {
120     int err;
121 
122     if ((err = MXC_prepare_flc(flc)) != E_NO_ERROR) {
123         return err;
124     }
125 
126     /* Write mass erase code */
127     flc->ctrl = (flc->ctrl & ~MXC_F_FLC_REVA_CTRL_ERASE_CODE) |
128                 MXC_S_FLC_REVA_CTRL_ERASE_CODE_ERASEALL;
129 
130     /* Issue mass erase command */
131     flc->ctrl |= MXC_F_FLC_REVA_CTRL_ME;
132 
133     /* Wait until flash operation is complete */
134     while (MXC_busy_flc(flc)) {}
135 
136     /* Lock flash */
137     flc->ctrl &= ~MXC_F_FLC_REVA_CTRL_UNLOCK;
138 
139     /* Check access violations */
140     if (flc->intr & MXC_F_FLC_REVA_INTR_AF) {
141         flc->intr &= ~MXC_F_FLC_REVA_INTR_AF;
142         return E_BAD_STATE;
143     }
144 
145     return E_NO_ERROR;
146 }
147 
148 //******************************************************************************
149 #if IAR_PRAGMAS
150 #pragma section = ".flashprog"
151 #else
152 __attribute__((section(".flashprog")))
153 #endif
MXC_FLC_RevA_PageErase(mxc_flc_reva_regs_t * flc,uint32_t addr)154 int MXC_FLC_RevA_PageErase(mxc_flc_reva_regs_t *flc, uint32_t addr)
155 {
156     int err;
157 
158     if ((err = MXC_prepare_flc(flc)) != E_NO_ERROR) {
159         return err;
160     }
161 
162     /* Write page erase code */
163     flc->ctrl = (flc->ctrl & ~MXC_F_FLC_REVA_CTRL_ERASE_CODE) |
164                 MXC_S_FLC_REVA_CTRL_ERASE_CODE_ERASEPAGE;
165     /* Issue page erase command */
166     flc->addr = addr;
167     flc->ctrl |= MXC_F_FLC_REVA_CTRL_PGE;
168 
169     /* Wait until flash operation is complete */
170     while (MXC_busy_flc(flc)) {}
171 
172     /* Lock flash */
173     flc->ctrl &= ~MXC_F_FLC_REVA_CTRL_UNLOCK;
174 
175     /* Check access violations */
176     if (flc->intr & MXC_F_FLC_REVA_INTR_AF) {
177         flc->intr &= ~MXC_F_FLC_REVA_INTR_AF;
178         return E_BAD_STATE;
179     }
180 
181     return E_NO_ERROR;
182 }
183 
184 //******************************************************************************
185 #if IAR_PRAGMAS
186 #pragma section = ".flashprog"
187 #else
188 __attribute__((section(".flashprog")))
189 #endif
190 // make sure to disable ICC with ICC_Disable(); before Running this function
MXC_FLC_RevA_Write32(mxc_flc_reva_regs_t * flc,uint32_t logicAddr,uint32_t data,uint32_t physicalAddr)191 int MXC_FLC_RevA_Write32(mxc_flc_reva_regs_t *flc, uint32_t logicAddr, uint32_t data,
192                          uint32_t physicalAddr)
193 {
194     int err;
195 
196     // Address checked if it is byte addressable
197     if (logicAddr & 0x3) {
198         return E_BAD_PARAM;
199     }
200 
201     // Check if the location trying to be written has 1's in to be written to 0's
202     if ((*(uint32_t *)logicAddr & data) != data) {
203         return E_BAD_STATE;
204     }
205 
206     // Align address to 32-bit word
207     logicAddr = logicAddr & 0xfffffffc;
208 
209     if ((err = MXC_prepare_flc(flc)) != E_NO_ERROR) {
210         return err;
211     }
212 
213     // write 32-bits
214     flc->ctrl |= MXC_F_FLC_REVA_CTRL_WDTH;
215 
216     // write the data
217     flc->addr = logicAddr;
218     flc->data[0] = data;
219     flc->ctrl |= MXC_F_FLC_REVA_CTRL_WR;
220 
221     /* Wait until flash operation is complete */
222     while ((flc->ctrl & MXC_F_FLC_REVA_CTRL_PEND) != 0) {}
223     while (MXC_busy_flc(flc)) {}
224 
225     /* Lock flash */
226     flc->ctrl &= ~MXC_F_FLC_REVA_CTRL_UNLOCK;
227 
228     /* Check access violations */
229     if (flc->intr & MXC_F_FLC_REVA_INTR_AF) {
230         flc->intr &= ~MXC_F_FLC_REVA_INTR_AF;
231         return E_BAD_STATE;
232     }
233 
234     return E_NO_ERROR;
235 }
236 
237 //******************************************************************************
238 #if IAR_PRAGMAS
239 #pragma section = ".flashprog"
240 #else
241 __attribute__((section(".flashprog")))
242 #endif
243 // make sure to disable ICC with ICC_Disable(); before Running this function
MXC_FLC_RevA_Write32Using128(mxc_flc_reva_regs_t * flc,uint32_t logicAddr,uint32_t data,uint32_t physicalAddr)244 int MXC_FLC_RevA_Write32Using128(mxc_flc_reva_regs_t *flc, uint32_t logicAddr, uint32_t data,
245                                  uint32_t physicalAddr)
246 {
247     int err, i = 0;
248     uint32_t byte;
249     volatile uint32_t *ptr;
250     uint32_t current_data[4] = { 0, 0, 0, 0 };
251 
252     // Address checked if it is byte addressable
253     if (logicAddr & 0x3) {
254         return E_BAD_PARAM;
255     }
256 
257     // Check if the location trying to be written has 1's in to be written to 0's
258     if ((*(uint32_t *)logicAddr & data) != data) {
259         return E_BAD_STATE;
260     }
261 
262     // Get byte idx within 128-bit word
263     byte = (logicAddr & 0xf);
264     // Align address to 128-bit word
265     logicAddr = logicAddr & 0xfffffff0;
266 
267     if ((err = MXC_prepare_flc(flc)) != E_NO_ERROR) {
268         return err;
269     }
270 
271     // Get current data stored in flash
272     for (ptr = (uint32_t *)logicAddr; ptr < (uint32_t *)(logicAddr + 16); ptr++, i++) {
273         current_data[i] = *ptr;
274     }
275 
276     // write the data
277     flc->addr = physicalAddr;
278 
279     if (byte < 4) {
280         current_data[0] = data;
281     } else if (byte < 8) {
282         current_data[1] = data;
283     } else if (byte < 12) {
284         current_data[2] = data;
285     } else {
286         current_data[3] = data;
287     }
288 
289     return MXC_FLC_Write128(logicAddr, current_data);
290 }
291 
292 //******************************************************************************
293 #if IAR_PRAGMAS
294 #pragma section = ".flashprog"
295 #else
296 __attribute__((section(".flashprog")))
297 #endif
298 // make sure to disable ICC with ICC_Disable(); before Running this function
MXC_FLC_RevA_Write128(mxc_flc_reva_regs_t * flc,uint32_t addr,uint32_t * data)299 int MXC_FLC_RevA_Write128(mxc_flc_reva_regs_t *flc, uint32_t addr, uint32_t *data)
300 {
301     int err;
302 
303     // Address checked if it is 128-bit aligned
304     if (addr & 0xF) {
305         return E_BAD_PARAM;
306     }
307 
308     if ((err = MXC_prepare_flc(flc)) != E_NO_ERROR) {
309         return err;
310     }
311 
312     // write 128-bits
313     flc->ctrl &= ~MXC_F_FLC_REVA_CTRL_WDTH;
314 
315     // write the data
316     flc->addr = addr;
317     flc->data[0] = data[0];
318     flc->data[1] = data[1];
319     flc->data[2] = data[2];
320     flc->data[3] = data[3];
321     flc->ctrl |= MXC_F_FLC_REVA_CTRL_WR;
322 
323     /* Wait until flash operation is complete */
324     while ((flc->ctrl & MXC_F_FLC_REVA_CTRL_PEND) != 0) {}
325     while (MXC_busy_flc(flc)) {}
326 
327     /* Lock flash */
328     flc->ctrl &= ~MXC_F_FLC_REVA_CTRL_UNLOCK;
329 
330     /* Check access violations */
331     if (flc->intr & MXC_F_FLC_REVA_INTR_AF) {
332         flc->intr &= ~MXC_F_FLC_REVA_INTR_AF;
333         return E_BAD_STATE;
334     }
335 
336     return E_NO_ERROR;
337 }
338 
339 //******************************************************************************
MXC_FLC_RevA_SetFLCInt(mxc_flc_reva_regs_t * flc)340 void MXC_FLC_RevA_SetFLCInt(mxc_flc_reva_regs_t *flc)
341 {
342     flc_int = flc;
343 }
344 
345 //******************************************************************************
MXC_FLC_RevA_GetFLCInt(void)346 mxc_flc_reva_regs_t *MXC_FLC_RevA_GetFLCInt(void)
347 {
348     return flc_int;
349 }
350 
351 //******************************************************************************
MXC_FLC_RevA_EnableInt(uint32_t mask)352 int MXC_FLC_RevA_EnableInt(uint32_t mask)
353 {
354     mask &= (MXC_F_FLC_REVA_INTR_DONEIE | MXC_F_FLC_REVA_INTR_AFIE);
355 
356     if (!mask) {
357         /* No bits set? Wasn't something we can enable. */
358         return E_BAD_PARAM;
359     }
360 
361     /* Apply enables and write back, preserving the flags */
362     flc_int->intr |= mask;
363 
364     return E_NO_ERROR;
365 }
366 
367 //******************************************************************************
MXC_FLC_RevA_DisableInt(uint32_t mask)368 int MXC_FLC_RevA_DisableInt(uint32_t mask)
369 {
370     mask &= (MXC_F_FLC_REVA_INTR_DONEIE | MXC_F_FLC_REVA_INTR_AFIE);
371 
372     if (!mask) {
373         /* No bits set? Wasn't something we can disable. */
374         return E_BAD_PARAM;
375     }
376 
377     /* Apply disables and write back, preserving the flags */
378     flc_int->intr &= ~mask;
379 
380     return E_NO_ERROR;
381 }
382 
383 //******************************************************************************
MXC_FLC_RevA_GetFlags(void)384 int MXC_FLC_RevA_GetFlags(void)
385 {
386     return (flc_int->intr & (MXC_F_FLC_REVA_INTR_DONE | MXC_F_FLC_REVA_INTR_AF));
387 }
388 
389 //******************************************************************************
MXC_FLC_RevA_ClearFlags(uint32_t mask)390 int MXC_FLC_RevA_ClearFlags(uint32_t mask)
391 {
392     mask &= (MXC_F_FLC_REVA_INTR_DONE | MXC_F_FLC_REVA_INTR_AF);
393 
394     if (!mask) {
395         /* No bits set? Wasn't something we can clear. */
396         return E_BAD_PARAM;
397     }
398 
399     /* Both flags are write zero clear */
400     flc_int->intr ^= mask;
401 
402     return E_NO_ERROR;
403 }
404 
405 //******************************************************************************
MXC_FLC_RevA_UnlockInfoBlock(mxc_flc_reva_regs_t * flc,uint32_t address)406 int MXC_FLC_RevA_UnlockInfoBlock(mxc_flc_reva_regs_t *flc, uint32_t address)
407 {
408     if ((address < MXC_INFO_MEM_BASE) ||
409         (address >= (MXC_INFO_MEM_BASE + (MXC_INFO_MEM_SIZE * 2)))) {
410         return E_BAD_PARAM;
411     }
412 
413     /* Make sure the info block is locked */
414     flc->actrl = 0x1234;
415 
416     /* Write the unlock sequence */
417     flc->actrl = 0x3a7f5ca3;
418     flc->actrl = 0xa1e34f20;
419     flc->actrl = 0x9608b2c1;
420 
421     return E_NO_ERROR;
422 }
423 
424 //******************************************************************************
MXC_FLC_RevA_LockInfoBlock(mxc_flc_reva_regs_t * flc,uint32_t address)425 int MXC_FLC_RevA_LockInfoBlock(mxc_flc_reva_regs_t *flc, uint32_t address)
426 {
427     if ((address < MXC_INFO_MEM_BASE) ||
428         (address >= (MXC_INFO_MEM_BASE + (MXC_INFO_MEM_SIZE * 2)))) {
429         return E_BAD_PARAM;
430     }
431 
432     flc->actrl = 0xDEADBEEF;
433     return E_NO_ERROR;
434 }
435 
436 //******************************************************************************
MXC_FLC_RevA_BlockPageWrite(uint32_t address,uint32_t bank_base)437 int MXC_FLC_RevA_BlockPageWrite(uint32_t address, uint32_t bank_base)
438 {
439     uint32_t page_num;
440     page_num = address - bank_base; // Get page number in flash bank
441     page_num /= MXC_FLASH_PAGE_SIZE;
442 
443     volatile uint32_t *welr = MXC_FLC_GetWELR(
444         address, page_num); // Get pointer to WELR register containing corresponding page bit
445 
446     while (page_num > 31) { // Set corresponding bit in WELR register
447         page_num -= 32;
448     }
449     *welr = (1 << page_num);
450 
451     return E_NO_ERROR;
452 }
453 
454 //******************************************************************************
MXC_FLC_RevA_BlockPageRead(uint32_t address,uint32_t bank_base)455 int MXC_FLC_RevA_BlockPageRead(uint32_t address, uint32_t bank_base)
456 {
457     uint32_t page_num;
458     page_num = address - bank_base; // Get page number in flash bank
459     page_num /= MXC_FLASH_PAGE_SIZE;
460 
461     volatile uint32_t *rlr = MXC_FLC_GetRLR(
462         address, page_num); // Get pointer to RLR register containing corresponding page bit
463 
464     while (page_num > 31) { // Set corresponding bit in WELR register
465         page_num -= 32;
466     }
467     *rlr = (1 << page_num);
468 
469     return E_NO_ERROR;
470 }
471 
472 /**@} end of group flc */
473