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_ME17_Flash_Operation(void)37 void MXC_FLC_ME17_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_ME17_GetByAddress(mxc_flc_regs_t ** flc,uint32_t addr)69 int MXC_FLC_ME17_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_ME17_GetPhysicalAddress(uint32_t addr,uint32_t * result)83 int MXC_FLC_ME17_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_SIZE - 1);
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_ME17_GetByAddress(&flc, address)) != E_NO_ERROR) {
127 return err;
128 }
129
130 if ((err = MXC_FLC_ME17_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
136 // Flush the cache
137 MXC_FLC_ME17_Flash_Operation();
138
139 return err;
140 }
141
142 //******************************************************************************
143 #if IAR_PRAGMAS
144 #pragma section = ".flashprog"
145 #else
146 __attribute__((section(".flashprog")))
147 #endif
148 // make sure to disable ICC with ICC_Disable(); before Running this function
MXC_FLC_Write128(uint32_t address,uint32_t * data)149 int MXC_FLC_Write128(uint32_t address, uint32_t *data)
150 {
151 int err;
152 mxc_flc_regs_t *flc = NULL;
153 uint32_t addr;
154
155 // Address checked if it is 128-bit aligned
156 if (address & 0xF) {
157 return E_BAD_PARAM;
158 }
159
160 // Get FLC Instance
161 if ((err = MXC_FLC_ME17_GetByAddress(&flc, address)) != E_NO_ERROR) {
162 return err;
163 }
164
165 if ((err = MXC_FLC_ME17_GetPhysicalAddress(address, &addr)) < E_NO_ERROR) {
166 return err;
167 }
168
169 err = MXC_FLC_RevA_Write128((mxc_flc_reva_regs_t *)flc, addr, data);
170
171 // Flush the cache
172 MXC_FLC_ME17_Flash_Operation();
173
174 return err;
175 }
176
177 //******************************************************************************
MXC_FLC_Write32(uint32_t address,uint32_t data)178 int MXC_FLC_Write32(uint32_t address, uint32_t data)
179 {
180 uint32_t addr, aligned;
181 int err;
182 mxc_flc_regs_t *flc = NULL;
183
184 // Address checked if it is byte addressable
185 if (address & 0x3) {
186 return E_BAD_PARAM;
187 }
188
189 // Align address to 128-bit word
190 aligned = address & 0xfffffff0;
191
192 // Get FLC Instance
193 if ((err = MXC_FLC_ME17_GetByAddress(&flc, address)) != E_NO_ERROR) {
194 return err;
195 }
196
197 if ((err = MXC_FLC_ME17_GetPhysicalAddress(aligned, &addr)) < E_NO_ERROR) {
198 return err;
199 }
200
201 err = MXC_FLC_RevA_Write32Using128((mxc_flc_reva_regs_t *)flc, address, data, addr);
202
203 // Flush the cache
204 MXC_FLC_ME17_Flash_Operation();
205
206 return err;
207 }
208
209 //******************************************************************************
MXC_FLC_MassErase(void)210 int MXC_FLC_MassErase(void)
211 {
212 int err, i;
213 mxc_flc_regs_t *flc;
214
215 for (i = 0; i < MXC_FLC_INSTANCES; i++) {
216 flc = MXC_FLC_GET_FLC(i);
217
218 err = MXC_FLC_RevA_MassErase((mxc_flc_reva_regs_t *)flc);
219
220 // Flush the cache
221 MXC_FLC_ME17_Flash_Operation();
222
223 if (err != E_NO_ERROR) {
224 return err;
225 }
226 }
227
228 return E_NO_ERROR;
229 }
230
231 //******************************************************************************
MXC_FLC_UnlockInfoBlock(uint32_t address)232 int MXC_FLC_UnlockInfoBlock(uint32_t address)
233 {
234 int err;
235 mxc_flc_regs_t *flc;
236
237 if ((err = MXC_FLC_ME17_GetByAddress(&flc, address)) != E_NO_ERROR) {
238 return err;
239 }
240
241 return MXC_FLC_RevA_UnlockInfoBlock((mxc_flc_reva_regs_t *)flc, address);
242 }
243
244 //******************************************************************************
MXC_FLC_LockInfoBlock(uint32_t address)245 int MXC_FLC_LockInfoBlock(uint32_t address)
246 {
247 int err;
248 mxc_flc_regs_t *flc;
249
250 if ((err = MXC_FLC_ME17_GetByAddress(&flc, address)) != E_NO_ERROR) {
251 return err;
252 }
253
254 return MXC_FLC_RevA_LockInfoBlock((mxc_flc_reva_regs_t *)flc, address);
255 }
256
257 //******************************************************************************
MXC_FLC_Write(uint32_t address,uint32_t length,uint32_t * buffer)258 int MXC_FLC_Write(uint32_t address, uint32_t length, uint32_t *buffer)
259 {
260 return MXC_FLC_Com_Write(address, length, buffer);
261 }
262
263 //******************************************************************************
MXC_FLC_Read(int address,void * buffer,int len)264 void MXC_FLC_Read(int address, void *buffer, int len)
265 {
266 MXC_FLC_Com_Read(address, buffer, len);
267 }
268
269 //******************************************************************************
MXC_FLC_EnableInt(uint32_t flags)270 int MXC_FLC_EnableInt(uint32_t flags)
271 {
272 return MXC_FLC_RevA_EnableInt(flags);
273 }
274
275 //******************************************************************************
MXC_FLC_DisableInt(uint32_t flags)276 int MXC_FLC_DisableInt(uint32_t flags)
277 {
278 return MXC_FLC_RevA_DisableInt(flags);
279 }
280
281 //******************************************************************************
MXC_FLC_GetFlags(void)282 int MXC_FLC_GetFlags(void)
283 {
284 return MXC_FLC_RevA_GetFlags();
285 }
286
287 //******************************************************************************
MXC_FLC_ClearFlags(uint32_t flags)288 int MXC_FLC_ClearFlags(uint32_t flags)
289 {
290 return MXC_FLC_RevA_ClearFlags(flags);
291 }
292
293 //******************************************************************************
MXC_FLC_BlockPageWrite(uint32_t address)294 int MXC_FLC_BlockPageWrite(uint32_t address)
295 {
296 if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
297 return E_INVALID;
298 }
299
300 return MXC_FLC_RevA_BlockPageWrite(address, MXC_FLASH_MEM_BASE);
301 }
302
303 //******************************************************************************
MXC_FLC_BlockPageRead(uint32_t address)304 int MXC_FLC_BlockPageRead(uint32_t address)
305 {
306 if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
307 return E_INVALID;
308 }
309
310 return MXC_FLC_RevA_BlockPageRead(address, MXC_FLASH_MEM_BASE);
311 }
312
313 //******************************************************************************
MXC_FLC_GetWELR(uint32_t address,uint32_t page_num)314 volatile uint32_t *MXC_FLC_GetWELR(uint32_t address, uint32_t page_num)
315 {
316 uint32_t reg_num;
317 reg_num = page_num >>
318 5; // Divide by 32 to get WELR register number containing the page lock bit
319
320 if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
321 return NULL;
322 }
323
324 switch (reg_num) {
325 case 0:
326 return &(MXC_FLC->welr0);
327 case 1:
328 return &(MXC_FLC->welr1);
329 }
330
331 return NULL;
332 }
333
334 //******************************************************************************
MXC_FLC_GetRLR(uint32_t address,uint32_t page_num)335 volatile uint32_t *MXC_FLC_GetRLR(uint32_t address, uint32_t page_num)
336 {
337 uint32_t reg_num;
338 reg_num = page_num >> 5; // Divide by 32 to get RLR register number containing the page lock bit
339
340 if (address < MXC_FLASH_MEM_BASE || address > (MXC_FLASH_MEM_BASE + MXC_FLASH_MEM_SIZE)) {
341 return NULL;
342 }
343
344 switch (reg_num) {
345 case 0:
346 return &(MXC_FLC->rlr0);
347 case 1:
348 return &(MXC_FLC->rlr1);
349 }
350
351 return NULL;
352 }
353