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 "trimsir_regs.h" // For BB_SIR2 (ECC) register.
35 #include "mcr_regs.h" // For ECCEN registers.
36
37 //******************************************************************************
MXC_FLC_ME21_Flash_Operation(void)38 void MXC_FLC_ME21_Flash_Operation(void)
39 {
40 /*
41 This function should be called after modifying the contents of flash memory.
42 It flushes the instruction caches and line fill buffer.
43
44 It should be called _afterwards_ because after flash is modified the cache
45 may contain instructions that may no longer be valid. _Before_ the
46 flash modifications the ICC may contain relevant cached instructions related to
47 the incoming flash instructions (especially relevant in the case of external memory),
48 and these instructions will be valid up until the point that the modifications are made.
49
50 The line fill buffer is a FLC-related buffer that also may no longer be valid.
51 It's flushed by reading 2 pages of flash.
52 */
53
54 /* Flush all instruction caches */
55 MXC_GCR->sysctrl |= MXC_F_GCR_SYSCTRL_ICC0_FLUSH;
56
57 /* Wait for flush to complete */
58 while (MXC_GCR->sysctrl & MXC_F_GCR_SYSCTRL_ICC0_FLUSH) {}
59
60 // Clear the line fill buffer by reading 2 pages from flash
61 volatile uint32_t *line_addr;
62 volatile uint32_t __unused line; // __unused attribute removes warning
63 line_addr = (uint32_t *)(MXC_FLASH_MEM_BASE);
64 line = *line_addr;
65 line_addr = (uint32_t *)(MXC_FLASH_MEM_BASE + MXC_FLASH_PAGE_SIZE);
66 line = *line_addr;
67 }
68
69 //******************************************************************************
MXC_FLC_ME21_GetByAddress(mxc_flc_regs_t ** flc,uint32_t addr)70 int MXC_FLC_ME21_GetByAddress(mxc_flc_regs_t **flc, uint32_t addr)
71 {
72 if ((addr >= MXC_FLASH_MEM_BASE) && (addr < (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE))) {
73 *flc = MXC_FLC0;
74 } else if ((addr >= MXC_FLASH1_MEM_BASE) &&
75 (addr < (MXC_FLASH1_MEM_BASE + MXC_FLASH_MEM_SIZE))) {
76 *flc = MXC_FLC1;
77 } else if ((addr >= MXC_INFO_MEM_BASE) && (addr < (MXC_INFO_MEM_BASE + MXC_INFO_MEM_SIZE))) {
78 *flc = MXC_FLC0;
79 } else if ((addr >= MXC_INFO1_MEM_BASE) && (addr < (MXC_INFO1_MEM_BASE + MXC_INFO_MEM_SIZE))) {
80 *flc = MXC_FLC1;
81 } else {
82 return E_BAD_PARAM;
83 }
84
85 return E_NO_ERROR;
86 }
87
88 //******************************************************************************
MXC_FLC_ME21_GetPhysicalAddress(uint32_t addr,uint32_t * result)89 int MXC_FLC_ME21_GetPhysicalAddress(uint32_t addr, uint32_t *result)
90 {
91 if ((addr >= MXC_FLASH0_MEM_BASE) && (addr < (MXC_FLASH0_MEM_BASE + MXC_FLASH_MEM_SIZE))) {
92 *result = addr & (MXC_FLASH_MEM_SIZE - 1);
93 } else if ((addr >= MXC_INFO_MEM_BASE) && (addr < (MXC_INFO_MEM_BASE + MXC_INFO_MEM_SIZE))) {
94 *result = (addr & (MXC_INFO_MEM_SIZE - 1)) + MXC_FLASH_MEM_SIZE;
95 } else if ((addr >= MXC_FLASH1_MEM_BASE) &&
96 (addr < (MXC_FLASH1_MEM_BASE + MXC_FLASH_MEM_SIZE))) {
97 *result = addr & (MXC_FLASH_MEM_SIZE - 1);
98 } else if ((addr >= MXC_INFO1_MEM_BASE) && (addr < (MXC_INFO1_MEM_BASE + MXC_INFO_MEM_SIZE))) {
99 *result = ((addr - MXC_INFO_MEM_SIZE) & (MXC_INFO_MEM_SIZE - 1)) + MXC_FLASH_MEM_SIZE;
100 } else {
101 return E_BAD_PARAM;
102 }
103
104 return E_NO_ERROR;
105 }
106
107 //******************************************************************************
MXC_FLC_Init(void)108 int MXC_FLC_Init(void)
109 {
110 return E_NO_ERROR;
111 }
112
113 //******************************************************************************
114 #if IAR_PRAGMAS
115 #pragma section = ".flashprog"
116 #else
117 __attribute__((section(".flashprog")))
118 #endif
MXC_FLC_Busy(void)119 int MXC_FLC_Busy(void)
120 {
121 return MXC_FLC_RevA_Busy();
122 }
123
124 //******************************************************************************
125 #if IAR_PRAGMAS
126 #pragma section = ".flashprog"
127 #else
128 __attribute__((section(".flashprog")))
129 #endif
MXC_FLC_PageErase(uint32_t address)130 int MXC_FLC_PageErase(uint32_t address)
131 {
132 int err;
133 uint32_t addr;
134 mxc_flc_regs_t *flc = NULL;
135
136 // Get FLC Instance
137 if ((err = MXC_FLC_ME21_GetByAddress(&flc, address)) != E_NO_ERROR) {
138 return err;
139 }
140
141 if ((err = MXC_FLC_ME21_GetPhysicalAddress(address, &addr)) < E_NO_ERROR) {
142 return err;
143 }
144
145 err = MXC_FLC_RevA_PageErase((mxc_flc_reva_regs_t *)flc, addr);
146
147 // Flush the cache
148 MXC_FLC_ME21_Flash_Operation();
149
150 return err;
151 }
152
153 //******************************************************************************
154 #if IAR_PRAGMAS
155 #pragma section = ".flashprog"
156 #else
157 __attribute__((section(".flashprog")))
158 #endif
159 // make sure to disable ICC with ICC_Disable(); before Running this function
MXC_FLC_Write128(uint32_t address,uint32_t * data)160 int MXC_FLC_Write128(uint32_t address, uint32_t *data)
161 {
162 int err;
163 mxc_flc_regs_t *flc = NULL;
164 uint32_t addr;
165
166 // Address checked if it is 128-bit aligned
167 if (address & 0xF) {
168 return E_BAD_PARAM;
169 }
170
171 // Get FLC Instance
172 if ((err = MXC_FLC_ME21_GetByAddress(&flc, address)) != E_NO_ERROR) {
173 return err;
174 }
175
176 if ((err = MXC_FLC_ME21_GetPhysicalAddress(address, &addr)) < E_NO_ERROR) {
177 return err;
178 }
179
180 err = MXC_FLC_RevA_Write128((mxc_flc_reva_regs_t *)flc, addr, data);
181
182 // Flush the cache
183 MXC_FLC_ME21_Flash_Operation();
184
185 if ((err = MXC_FLC_Com_VerifyData(address, 4, data)) != E_NO_ERROR) {
186 return err;
187 }
188
189 return E_NO_ERROR;
190 }
191
192 //******************************************************************************
MXC_FLC_Write32(uint32_t address,uint32_t data)193 int MXC_FLC_Write32(uint32_t address, uint32_t data)
194 {
195 uint32_t addr, aligned;
196 int err;
197 mxc_flc_regs_t *flc = NULL;
198
199 // Address checked if it is byte addressable
200 if (address & 0x3) {
201 return E_BAD_PARAM;
202 }
203
204 // Align address to 128-bit word
205 aligned = address & 0xfffffff0;
206
207 // Get FLC Instance
208 if ((err = MXC_FLC_ME21_GetByAddress(&flc, address)) != E_NO_ERROR) {
209 return err;
210 }
211
212 if ((err = MXC_FLC_ME21_GetPhysicalAddress(aligned, &addr)) < E_NO_ERROR) {
213 return err;
214 }
215
216 // Ensure ECC is disabled for the respective flash bank
217 if (address < MXC_FLASH0_MEM_BASE + MXC_FLASH_MEM_SIZE) {
218 if (MXC_TRIMSIR->bb_sir2 & MXC_F_TRIMSIR_BB_SIR2_FL0ECCEN) {
219 return E_BAD_STATE;
220 }
221 } else if (address < MXC_FLASH1_MEM_BASE + MXC_FLASH_MEM_SIZE) {
222 if (MXC_TRIMSIR->bb_sir2 & MXC_F_TRIMSIR_BB_SIR2_FL1ECCEN) {
223 return E_BAD_STATE;
224 }
225 }
226
227 err = MXC_FLC_RevA_Write32Using128((mxc_flc_reva_regs_t *)flc, address, data, addr);
228
229 // Flush the cache
230 MXC_FLC_ME21_Flash_Operation();
231
232 return err;
233 }
234
235 //******************************************************************************
MXC_FLC_MassErase(void)236 int MXC_FLC_MassErase(void)
237 {
238 int err, i;
239 mxc_flc_regs_t *flc;
240
241 for (i = 0; i < MXC_FLC_INSTANCES; i++) {
242 flc = MXC_FLC_GET_FLC(i);
243 err = MXC_FLC_RevA_MassErase((mxc_flc_reva_regs_t *)flc);
244
245 if (err != E_NO_ERROR) {
246 return err;
247 }
248
249 MXC_FLC_ME21_Flash_Operation();
250 }
251
252 return E_NO_ERROR;
253 }
254
255 //******************************************************************************
MXC_FLC_UnlockInfoBlock(uint32_t address)256 int MXC_FLC_UnlockInfoBlock(uint32_t address)
257 {
258 return E_NOT_SUPPORTED;
259 }
260
261 //******************************************************************************
MXC_FLC_LockInfoBlock(uint32_t address)262 int MXC_FLC_LockInfoBlock(uint32_t address)
263 {
264 int err;
265 mxc_flc_regs_t *flc;
266
267 if ((err = MXC_FLC_ME21_GetByAddress(&flc, address)) != E_NO_ERROR) {
268 return err;
269 }
270
271 return MXC_FLC_RevA_LockInfoBlock((mxc_flc_reva_regs_t *)flc, address);
272 }
273
274 //******************************************************************************
MXC_FLC_Write(uint32_t address,uint32_t length,uint32_t * buffer)275 int MXC_FLC_Write(uint32_t address, uint32_t length, uint32_t *buffer)
276 {
277 return MXC_FLC_Com_Write(address, length, buffer);
278 }
279
280 //******************************************************************************
MXC_FLC_Read(int address,void * buffer,int len)281 void MXC_FLC_Read(int address, void *buffer, int len)
282 {
283 MXC_FLC_Com_Read(address, buffer, len);
284 }
285
286 //******************************************************************************
MXC_FLC_EnableInt(uint32_t flags)287 int MXC_FLC_EnableInt(uint32_t flags)
288 {
289 return MXC_FLC_RevA_EnableInt(flags);
290 }
291
292 //******************************************************************************
MXC_FLC_DisableInt(uint32_t flags)293 int MXC_FLC_DisableInt(uint32_t flags)
294 {
295 return MXC_FLC_RevA_DisableInt(flags);
296 }
297
298 //******************************************************************************
MXC_FLC_GetFlags(void)299 int MXC_FLC_GetFlags(void)
300 {
301 return MXC_FLC_RevA_GetFlags();
302 }
303
304 //******************************************************************************
MXC_FLC_ClearFlags(uint32_t flags)305 int MXC_FLC_ClearFlags(uint32_t flags)
306 {
307 return MXC_FLC_RevA_ClearFlags(flags);
308 }
309
310 //******************************************************************************
MXC_FLC_BlockPageWrite(uint32_t address)311 int MXC_FLC_BlockPageWrite(uint32_t address)
312 {
313 int err;
314 mxc_flc_regs_t *flc;
315
316 if (address < MXC_FLASH0_MEM_BASE ||
317 address > (MXC_FLASH1_MEM_BASE + MXC_FLASH_MEM_SIZE)) { // Check address valid
318 return E_INVALID;
319 }
320
321 if ((err = MXC_FLC_ME21_GetByAddress(&flc, address)) !=
322 E_NO_ERROR) { // Get FLC to be able to pass correct base address
323 return err;
324 }
325
326 switch (MXC_FLC_GET_IDX(flc)) {
327 case 0:
328 err = MXC_FLC_RevA_BlockPageWrite(address, MXC_FLASH0_MEM_BASE);
329 break;
330 case 1:
331 err = MXC_FLC_RevA_BlockPageWrite(address, MXC_FLASH1_MEM_BASE);
332 break;
333 default:
334 return E_INVALID;
335 }
336
337 return err;
338 }
339
340 //******************************************************************************
MXC_FLC_BlockPageRead(uint32_t address)341 int MXC_FLC_BlockPageRead(uint32_t address)
342 {
343 int err;
344 mxc_flc_regs_t *flc;
345
346 if (address < MXC_FLASH0_MEM_BASE ||
347 address > (MXC_FLASH1_MEM_BASE + MXC_FLASH_MEM_SIZE)) { // Check address valid
348 return E_INVALID;
349 }
350
351 if ((err = MXC_FLC_ME21_GetByAddress(&flc, address)) !=
352 E_NO_ERROR) { // Get FLC to be able to pass correct base address
353 return err;
354 }
355
356 switch (MXC_FLC_GET_IDX(flc)) {
357 case 0:
358 err = MXC_FLC_RevA_BlockPageRead(address, MXC_FLASH0_MEM_BASE);
359 break;
360 case 1:
361 err = MXC_FLC_RevA_BlockPageRead(address, MXC_FLASH1_MEM_BASE);
362 break;
363 default:
364 return E_INVALID;
365 }
366
367 return err;
368 }
369
370 //******************************************************************************
MXC_FLC_GetWELR(uint32_t address,uint32_t page_num)371 volatile uint32_t *MXC_FLC_GetWELR(uint32_t address, uint32_t page_num)
372 {
373 uint32_t reg_num;
374 int err;
375 reg_num = page_num >>
376 5; // Divide by 32 to get WELR register number containing the page lock bit
377
378 mxc_flc_regs_t *flc;
379 if ((err = MXC_FLC_ME21_GetByAddress(&flc, address)) != E_NO_ERROR) { // Check address valid
380 return NULL;
381 }
382
383 switch (reg_num) {
384 case 0:
385 return &(flc->welr0);
386 case 1:
387 return &(flc->welr1);
388 }
389
390 return NULL;
391 }
392
393 //******************************************************************************
MXC_FLC_GetRLR(uint32_t address,uint32_t page_num)394 volatile uint32_t *MXC_FLC_GetRLR(uint32_t address, uint32_t page_num)
395 {
396 uint32_t reg_num;
397 int err;
398 reg_num = page_num >> 5; // Divide by 32 to get RLR register number containing the page lock bit
399
400 mxc_flc_regs_t *flc;
401 if ((err = MXC_FLC_ME21_GetByAddress(&flc, address)) != E_NO_ERROR) { // Check address valid
402 return NULL;
403 }
404
405 switch (reg_num) {
406 case 0:
407 return &(flc->rlr0);
408 case 1:
409 return &(flc->rlr1);
410 }
411
412 return NULL;
413 }
414