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