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_AI87_Flash_Operation(void)37 void MXC_FLC_AI87_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_AI87_GetByAddress(mxc_flc_regs_t ** flc,uint32_t addr)69 int MXC_FLC_AI87_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_FLC0;
73 } else if ((addr >= MXC_INFO_MEM_BASE) && (addr < (MXC_INFO_MEM_BASE + MXC_INFO_MEM_SIZE))) {
74 *flc = MXC_FLC0;
75 } else {
76 return E_BAD_PARAM;
77 }
78
79 return E_NO_ERROR;
80 }
81
82 //******************************************************************************
MXC_FLC_AI87_GetPhysicalAddress(uint32_t addr,uint32_t * result)83 int MXC_FLC_AI87_GetPhysicalAddress(uint32_t addr, uint32_t *result)
84 {
85 if ((addr >= MXC_FLASH_MEM_BASE) && (addr < (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE))) {
86 *result = addr - MXC_FLASH_MEM_BASE;
87 } else if ((addr >= MXC_INFO_MEM_BASE) && (addr < (MXC_INFO_MEM_BASE + MXC_INFO_MEM_SIZE))) {
88 *result = (addr & (MXC_INFO_MEM_SIZE - 1)) + MXC_FLASH_MEM_SIZE;
89 } else {
90 return E_BAD_PARAM;
91 }
92
93 return E_NO_ERROR;
94 }
95
96 //******************************************************************************
MXC_FLC_Init(void)97 int MXC_FLC_Init(void)
98 {
99 return E_NO_ERROR;
100 }
101
102 //******************************************************************************
103 #if IAR_PRAGMAS
104 #pragma section = ".flashprog"
105 #else
106 __attribute__((section(".flashprog")))
107 #endif
MXC_FLC_Busy(void)108 int MXC_FLC_Busy(void)
109 {
110 return MXC_FLC_RevA_Busy();
111 }
112
113 //******************************************************************************
114 #if IAR_PRAGMAS
115 #pragma section = ".flashprog"
116 #else
117 __attribute__((section(".flashprog")))
118 #endif
MXC_FLC_PageErase(uint32_t address)119 int MXC_FLC_PageErase(uint32_t address)
120 {
121 int err;
122 uint32_t addr;
123 mxc_flc_regs_t *flc = NULL;
124
125 // Get FLC Instance
126 if ((err = MXC_FLC_AI87_GetByAddress(&flc, address)) != E_NO_ERROR) {
127 return err;
128 }
129
130 if ((err = MXC_FLC_AI87_GetPhysicalAddress(address, &addr)) < E_NO_ERROR) {
131 return err;
132 }
133
134 err = MXC_FLC_RevA_PageErase((mxc_flc_reva_regs_t *)flc, addr);
135 // Flush the cache
136 MXC_FLC_AI87_Flash_Operation();
137
138 return err;
139 }
140
141 //******************************************************************************
142 #if IAR_PRAGMAS
143 #pragma section = ".flashprog"
144 #else
145 __attribute__((section(".flashprog")))
146 #endif
147 // make sure to disable ICC with ICC_Disable(); before Running this function
MXC_FLC_Write128(uint32_t address,uint32_t * data)148 int MXC_FLC_Write128(uint32_t address, uint32_t *data)
149 {
150 int err;
151 mxc_flc_regs_t *flc = NULL;
152 uint32_t addr;
153
154 // Address checked if it is 128-bit aligned
155 if (address & 0xF) {
156 return E_BAD_PARAM;
157 }
158
159 // Get FLC Instance
160 if ((err = MXC_FLC_AI87_GetByAddress(&flc, address)) != E_NO_ERROR) {
161 return err;
162 }
163
164 if ((err = MXC_FLC_AI87_GetPhysicalAddress(address, &addr)) < E_NO_ERROR) {
165 return err;
166 }
167
168 err = MXC_FLC_RevA_Write128((mxc_flc_reva_regs_t *)flc, addr, data);
169
170 // Flush the cache
171 MXC_FLC_AI87_Flash_Operation();
172
173 if ((err = MXC_FLC_Com_VerifyData(address, 4, data)) != E_NO_ERROR) {
174 return err;
175 }
176
177 return E_NO_ERROR;
178 }
179
180 //******************************************************************************
MXC_FLC_Write32(uint32_t address,uint32_t data)181 int MXC_FLC_Write32(uint32_t address, uint32_t data)
182 {
183 uint32_t addr, aligned;
184 int err;
185 mxc_flc_regs_t *flc = NULL;
186
187 // Address checked if it is byte addressable
188 if (address & 0x3) {
189 return E_BAD_PARAM;
190 }
191
192 // Align address to 128-bit word
193 aligned = address & 0xfffffff0;
194
195 // Get FLC Instance
196 if ((err = MXC_FLC_AI87_GetByAddress(&flc, address)) != E_NO_ERROR) {
197 return err;
198 }
199
200 if ((err = MXC_FLC_AI87_GetPhysicalAddress(aligned, &addr)) < E_NO_ERROR) {
201 return err;
202 }
203
204 err = MXC_FLC_RevA_Write32Using128((mxc_flc_reva_regs_t *)flc, address, data, addr);
205
206 // Flush the cache
207 MXC_FLC_AI87_Flash_Operation();
208
209 return err;
210 }
211
212 //******************************************************************************
MXC_FLC_MassErase(void)213 int MXC_FLC_MassErase(void)
214 {
215 int err, i;
216 mxc_flc_regs_t *flc;
217
218 for (i = 0; i < MXC_FLC_INSTANCES; i++) {
219 flc = MXC_FLC_GET_FLC(i);
220 err = MXC_FLC_RevA_MassErase((mxc_flc_reva_regs_t *)flc);
221
222 if (err != E_NO_ERROR) {
223 return err;
224 }
225
226 MXC_FLC_AI87_Flash_Operation();
227 }
228
229 return E_NO_ERROR;
230 }
231
232 //******************************************************************************
MXC_FLC_UnlockInfoBlock(uint32_t address)233 int MXC_FLC_UnlockInfoBlock(uint32_t address)
234 {
235 int err;
236 mxc_flc_regs_t *flc;
237
238 if ((err = MXC_FLC_AI87_GetByAddress(&flc, address)) != E_NO_ERROR) {
239 return err;
240 }
241
242 return MXC_FLC_RevA_UnlockInfoBlock((mxc_flc_reva_regs_t *)flc, address);
243 }
244
245 //******************************************************************************
MXC_FLC_LockInfoBlock(uint32_t address)246 int MXC_FLC_LockInfoBlock(uint32_t address)
247 {
248 int err;
249 mxc_flc_regs_t *flc;
250
251 if ((err = MXC_FLC_AI87_GetByAddress(&flc, address)) != E_NO_ERROR) {
252 return err;
253 }
254
255 return MXC_FLC_RevA_LockInfoBlock((mxc_flc_reva_regs_t *)flc, address);
256 }
257
258 //******************************************************************************
MXC_FLC_Write(uint32_t address,uint32_t length,uint32_t * buffer)259 int MXC_FLC_Write(uint32_t address, uint32_t length, uint32_t *buffer)
260 {
261 return MXC_FLC_Com_Write(address, length, buffer);
262 }
263
264 //******************************************************************************
MXC_FLC_Read(int address,void * buffer,int len)265 void MXC_FLC_Read(int address, void *buffer, int len)
266 {
267 MXC_FLC_Com_Read(address, buffer, len);
268 }
269
270 //******************************************************************************
MXC_FLC_EnableInt(uint32_t flags)271 int MXC_FLC_EnableInt(uint32_t flags)
272 {
273 return MXC_FLC_RevA_EnableInt(flags);
274 }
275
276 //******************************************************************************
MXC_FLC_DisableInt(uint32_t flags)277 int MXC_FLC_DisableInt(uint32_t flags)
278 {
279 return MXC_FLC_RevA_DisableInt(flags);
280 }
281
282 //******************************************************************************
MXC_FLC_GetFlags(void)283 int MXC_FLC_GetFlags(void)
284 {
285 return MXC_FLC_RevA_GetFlags();
286 }
287
288 //******************************************************************************
MXC_FLC_ClearFlags(uint32_t flags)289 int MXC_FLC_ClearFlags(uint32_t flags)
290 {
291 return MXC_FLC_RevA_ClearFlags(flags);
292 }
293
294 //******************************************************************************
MXC_FLC_BlockPageWrite(uint32_t address)295 int MXC_FLC_BlockPageWrite(uint32_t address)
296 {
297 if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
298 return E_INVALID;
299 }
300
301 return MXC_FLC_RevA_BlockPageWrite(address, MXC_FLASH_MEM_BASE);
302 }
303
304 //******************************************************************************
MXC_FLC_BlockPageRead(uint32_t address)305 int MXC_FLC_BlockPageRead(uint32_t address)
306 {
307 if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
308 return E_INVALID;
309 }
310
311 return MXC_FLC_RevA_BlockPageRead(address, MXC_FLASH_MEM_BASE);
312 }
313
314 //******************************************************************************
MXC_FLC_GetWELR(uint32_t address,uint32_t page_num)315 volatile uint32_t *MXC_FLC_GetWELR(uint32_t address, uint32_t page_num)
316 {
317 uint32_t reg_num;
318 reg_num = page_num >>
319 5; // Divide by 32 to get WELR register number containing the page lock bit
320
321 if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
322 return NULL;
323 }
324
325 switch (reg_num) {
326 case 0:
327 return &(MXC_FLC0->welr0);
328 case 1:
329 return &(MXC_FLC0->welr1);
330 case 2:
331 return &(MXC_FLC0->welr2);
332 case 3:
333 return &(MXC_FLC0->welr3);
334 case 4:
335 return &(MXC_FLC0->welr4);
336 }
337
338 return NULL;
339 }
340
341 //******************************************************************************
MXC_FLC_GetRLR(uint32_t address,uint32_t page_num)342 volatile uint32_t *MXC_FLC_GetRLR(uint32_t address, uint32_t page_num)
343 {
344 uint32_t reg_num;
345 reg_num = page_num >> 5; // Divide by 32 to get RLR register number containing the page lock bit
346
347 if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
348 return NULL;
349 }
350
351 switch (reg_num) {
352 case 0:
353 return &(MXC_FLC0->rlr0);
354 case 1:
355 return &(MXC_FLC0->rlr1);
356 case 2:
357 return &(MXC_FLC0->rlr2);
358 case 3:
359 return &(MXC_FLC0->rlr3);
360 case 4:
361 return &(MXC_FLC0->rlr4);
362 }
363
364 return NULL;
365 }
366