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