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