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