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