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