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