1 /***************************************************************************//**
2  * @file
3  * @brief Flash controller (MSC) Peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_msc.h"
32 #if defined(MSC_COUNT) && (MSC_COUNT > 0)
33 
34 #include "sl_assert.h"
35 #include "em_cmu.h"
36 #include "sl_common.h"
37 #include "em_core.h"
38 #include "em_system.h"
39 
40 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
41 
42 #if defined(__ICCARM__)
43 /* Suppress warnings originating from use of EFM_ASSERT() with IAR Embedded Workbench */
44 #pragma diag_suppress=Ta022,Ta023
45 #endif
46 
47 #if defined(EM_MSC_RUN_FROM_FLASH) && defined(_EFM32_GECKO_FAMILY)
48 #error "Running Flash write/erase operations from Flash is not supported on EFM32G."
49 #endif
50 
51 /*******************************************************************************
52  ******************************      DEFINES      ******************************
53  ******************************************************************************/
54 #if defined(MSC_WRITECTRL_WDOUBLE)
55 #define WORDS_PER_DATA_PHASE (FLASH_SIZE < (512 * 1024) ? 1 : 2)
56 #else
57 #define WORDS_PER_DATA_PHASE (1)
58 #endif
59 
60 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
61 /* Fix for errata FLASH_E201 - Potential program failure after Power On */
62 #define ERRATA_FIX_FLASH_E201_EN
63 #endif
64 
65 #define FLASH_PAGE_MASK (~(FLASH_PAGE_SIZE - 1U))
66 
67 #if defined(_MSC_ECCCTRL_MASK)          \
68   || defined(_SYSCFG_DMEM0ECCCTRL_MASK) \
69   || defined(_MPAHBRAM_CTRL_MASK)
70 #if defined(_SILICON_LABS_32B_SERIES_1_CONFIG_1)
71 /* On Series 1 Config 1 EFM32GG11, ECC is supported for RAM0 and RAM1
72    banks (not RAM2). It is necessary to figure out which is biggest to
73    calculate the number of DMA descriptors needed. */
74 #define ECC_RAM_SIZE_MAX   (SL_MAX(RAM0_MEM_SIZE, RAM1_MEM_SIZE))
75 
76 #define ECC_RAM0_MEM_BASE  (RAM0_MEM_BASE)
77 #define ECC_RAM0_MEM_SIZE  (RAM0_MEM_SIZE)
78 
79 #define ECC_RAM1_MEM_BASE  (RAM1_MEM_BASE)
80 #define ECC_RAM1_MEM_SIZE  (RAM1_MEM_SIZE)
81 
82 #define ECC_CTRL_REG            (MSC->ECCCTRL)
83 #define ECC_RAM0_SYNDROMES_INIT (MSC_ECCCTRL_RAMECCEWEN)
84 #define ECC_RAM0_CORRECTION_EN  (MSC_ECCCTRL_RAMECCCHKEN)
85 #define ECC_RAM1_SYNDROMES_INIT (MSC_ECCCTRL_RAM1ECCEWEN)
86 #define ECC_RAM1_CORRECTION_EN  (MSC_ECCCTRL_RAM1ECCCHKEN)
87 
88 #define ECC_IFC_REG        (MSC->IFC)
89 #define ECC_IFC_MASK       (MSC_IFC_RAMERR1B | MSC_IFC_RAMERR2B \
90                             | MSC_IFC_RAM1ERR1B | MSC_IFC_RAM1ERR2B)
91 
92 #define ECC_FAULT_CTRL_REG (MSC->CTRL)
93 #define ECC_FAULT_EN       (MSC_CTRL_RAMECCERRFAULTEN)
94 
95 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_106)
96 /* On Series 1 Config 2 EFM32GG12, ECC is supported for RAM0, RAM1 and
97    RAM2 banks. All banks are of equal size. */
98 #define ECC_RAM_SIZE_MAX   (RAM0_MEM_SIZE)
99 
100 #define ECC_RAM0_MEM_BASE  (RAM0_MEM_BASE)
101 #define ECC_RAM0_MEM_SIZE  (RAM0_MEM_SIZE)
102 
103 #define ECC_RAM1_MEM_BASE  (RAM1_MEM_BASE)
104 #define ECC_RAM1_MEM_SIZE  (RAM1_MEM_SIZE)
105 
106 #define ECC_RAM2_MEM_BASE  (RAM2_MEM_BASE)
107 #define ECC_RAM2_MEM_SIZE  (RAM2_MEM_SIZE)
108 
109 #define ECC_CTRL_REG            (MSC->ECCCTRL)
110 #define ECC_RAM0_SYNDROMES_INIT (MSC_ECCCTRL_RAMECCEWEN)
111 #define ECC_RAM0_CORRECTION_EN  (MSC_ECCCTRL_RAMECCCHKEN)
112 #define ECC_RAM1_SYNDROMES_INIT (MSC_ECCCTRL_RAM1ECCEWEN)
113 #define ECC_RAM1_CORRECTION_EN  (MSC_ECCCTRL_RAM1ECCCHKEN)
114 #define ECC_RAM2_SYNDROMES_INIT (MSC_ECCCTRL_RAM2ECCEWEN)
115 #define ECC_RAM2_CORRECTION_EN  (MSC_ECCCTRL_RAM2ECCCHKEN)
116 
117 #define ECC_IFC_REG        (MSC->IFC)
118 #define ECC_IFC_MASK       (MSC_IFC_RAMERR1B | MSC_IFC_RAMERR2B     \
119                             | MSC_IFC_RAM1ERR1B | MSC_IFC_RAM1ERR2B \
120                             | MSC_IFC_RAM2ERR1B | MSC_IFC_RAM2ERR2B)
121 
122 #define ECC_FAULT_CTRL_REG (MSC->CTRL)
123 #define ECC_FAULT_EN       (MSC_CTRL_RAMECCERRFAULTEN)
124 
125 #elif defined(_SILICON_LABS_32B_SERIES_2)
126 
127 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
128 
129 /* On Series 2 Config 1, aka EFR32XG21, ECC is supported for the
130    main DMEM RAM banks which is controlled with one ECC encoder/decoder. */
131 #define ECC_RAM0_SYNDROMES_INIT (SYSCFG_DMEM0ECCCTRL_RAMECCEWEN)
132 #define ECC_RAM0_CORRECTION_EN  (SYSCFG_DMEM0ECCCTRL_RAMECCCHKEN)
133 
134 #elif (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) \
135   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7))
136 
137 /* On Series 2 Config 2, aka EFR32XG22, ECC is supported for the
138    main DMEM RAM banks which is controlled with one ECC encoder/decoder. */
139 #define ECC_RAM0_SYNDROMES_INIT (SYSCFG_DMEM0ECCCTRL_RAMECCEN)
140 #define ECC_RAM0_CORRECTION_EN  (SYSCFG_DMEM0ECCCTRL_RAMECCEWEN)
141 
142 #define ECC_IF_REG         (SYSCFG->IF)
143 #define ECC_IF_1BIT_ERROR  (SYSCFG_IF_RAMERR1B)
144 
145 #elif defined(_MPAHBRAM_CTRL_MASK)
146 
147 /* From Series 2 Config 3, aka EFR32XG23, ECC is now standalone in the
148  * MPAHBRAM module */
149 #define ECC_RAM0_SYNDROMES_INIT (MPAHBRAM_CTRL_ECCWEN)
150 #define ECC_RAM0_CORRECTION_EN  (MPAHBRAM_CTRL_ECCEN)
151 
152 #if defined(DMEM_COUNT) && (DMEM_COUNT == 2)
153 #define ECC_RAM1_SYNDROMES_INIT (MPAHBRAM_CTRL_ECCWEN)
154 #define ECC_RAM1_CORRECTION_EN  (MPAHBRAM_CTRL_ECCEN)
155 #endif
156 
157 #define ECC_IF_REG         (DMEM->IF)
158 /* number of AHB ports is between 1 and 4 */
159 #if defined(MPAHBRAM_IF_AHB3ERR1B)
160 #define ECC_IF_1BIT_ERROR       (MPAHBRAM_IF_AHB0ERR1B | MPAHBRAM_IF_AHB1ERR1B | MPAHBRAM_IF_AHB2ERR1B | MPAHBRAM_IF_AHB3ERR1B)
161 #elif defined(MPAHBRAM_IF_AHB2ERR1B)
162 #define ECC_IF_1BIT_ERROR       (MPAHBRAM_IF_AHB0ERR1B | MPAHBRAM_IF_AHB1ERR1B | MPAHBRAM_IF_AHB2ERR1B)
163 #elif defined(MPAHBRAM_IF_AHB1ERR1B)
164 #define ECC_IF_1BIT_ERROR       (MPAHBRAM_IF_AHB0ERR1B | MPAHBRAM_IF_AHB1ERR1B)
165 #else
166 #define ECC_IF_1BIT_ERROR       (MPAHBRAM_IF_AHB0ERR1B)
167 #endif
168 
169 #else
170 
171 #error "Unknown device"
172 
173 #endif /* #if defined(if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1) */
174 
175 #define ECC_RAM_SIZE_MAX   (RAM_MEM_SIZE)
176 
177 #if defined(DMEM_COUNT) && (DMEM_COUNT == 2)
178 
179 #define ECC_RAM0_MEM_BASE   (DMEM0_RAM0_RAM_MEM_BASE)
180 #define ECC_RAM0_MEM_SIZE   (DMEM0_RAM0_RAM_MEM_SIZE)
181 #define ECC_RAM1_MEM_BASE   (DMEM1_RAM0_RAM_MEM_BASE)
182 #define ECC_RAM1_MEM_SIZE   (DMEM1_RAM0_RAM_MEM_SIZE)
183 
184 #define ECC_CTRL0_REG       (DMEM0->CTRL)
185 #define ECC_CTRL1_REG       (DMEM1->CTRL)
186 
187 #define ECC_IFC0_REG        (DMEM0->IF_CLR)
188 #define ECC_IFC1_REG        (DMEM1->IF_CLR)
189 #define ECC_IFC_MASK        (_MPAHBRAM_IF_MASK)
190 
191 #define ECC_FAULT_CTRL0_REG (DMEM0->CTRL)
192 #define ECC_FAULT_CTRL1_REG (DMEM1->CTRL)
193 #define ECC_FAULT_EN        (MPAHBRAM_CTRL_ECCERRFAULTEN)
194 
195 #else
196 
197 #define ECC_RAM0_MEM_BASE  (SRAM_BASE)
198 #define ECC_RAM0_MEM_SIZE  (SRAM_SIZE)
199 
200 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1) \
201   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) \
202   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7))
203 #define ECC_CTRL_REG       (SYSCFG->DMEM0ECCCTRL)
204 #define ECC_IFC_REG        (SYSCFG->IF_CLR)
205 #define ECC_IFC_MASK       (SYSCFG_IF_RAMERR1B | SYSCFG_IF_RAMERR2B)
206 #define ECC_FAULT_CTRL_REG (SYSCFG->CTRL)
207 #define ECC_FAULT_EN       (SYSCFG_CTRL_RAMECCERRFAULTEN)
208 
209 #elif defined(_MPAHBRAM_CTRL_MASK)
210 #define ECC_CTRL_REG       (DMEM->CTRL)
211 #define ECC_IFC_REG        (DMEM->IF_CLR)
212 #define ECC_IFC_MASK       (_MPAHBRAM_IF_MASK)
213 #define ECC_FAULT_CTRL_REG (DMEM->CTRL)
214 #define ECC_FAULT_EN       (MPAHBRAM_CTRL_ECCERRFAULTEN)
215 #endif
216 
217 #endif /* defined(DMEM_COUNT) && (DMEM_COUNT == 2) */
218 
219 #else
220 
221 #error Unknown device.
222 
223 #endif
224 
225 #define ECC_DMA_MAX_XFERCNT (_LDMA_CH_CTRL_XFERCNT_MASK \
226                              >> _LDMA_CH_CTRL_XFERCNT_SHIFT)
227 #define ECC_DMA_DESC_SIZE   ((ECC_DMA_MAX_XFERCNT + 1) * 4)  /* 4 bytes units */
228 
229 #define ECC_DMA_DESCS       (ECC_RAM_SIZE_MAX / ECC_DMA_DESC_SIZE)
230 
231 #endif /* #if defined(_MSC_ECCCTRL_MASK) */
232 
233 /***************************************************************************//**
234  * @brief
235  *   Get locked status of the MSC registers.
236  *
237  * @detail
238  *   MSC_IS_LOCKED() is implemented as a macro because it's used inside functions
239  *   that can be placed either in flash or in RAM.
240  ******************************************************************************/
241 #if defined(_MSC_STATUS_REGLOCK_MASK)
242 #define MSC_IS_LOCKED()    ((MSC->STATUS & _MSC_STATUS_REGLOCK_MASK) != 0U)
243 #else
244 #define MSC_IS_LOCKED()    ((MSC->LOCK & _MSC_LOCK_MASK) != 0U)
245 #endif
246 
247 /*******************************************************************************
248  ******************************      TYPEDEFS     ******************************
249  ******************************************************************************/
250 
251 #if defined(_MSC_ECCCTRL_MASK)          \
252   || defined(_SYSCFG_DMEM0ECCCTRL_MASK) \
253   || defined(_MPAHBRAM_CTRL_MASK)
254 typedef struct {
255   uint32_t           initSyndromeEnable;
256   uint32_t           correctionEnable;
257   uint32_t           base;
258   uint32_t           size;
259 } MSC_EccBank_Typedef;
260 
261 #endif
262 
263 /*******************************************************************************
264  ******************************      LOCALS      *******************************
265  ******************************************************************************/
266 #if defined(_MSC_ECCCTRL_MASK)          \
267   || defined(_SYSCFG_DMEM0ECCCTRL_MASK) \
268   || defined(_MPAHBRAM_CTRL_MASK)
269 static const MSC_EccBank_Typedef eccBankTbl[MSC_ECC_BANKS] =
270 {
271   {
272     ECC_RAM0_SYNDROMES_INIT, ECC_RAM0_CORRECTION_EN,
273     ECC_RAM0_MEM_BASE, ECC_RAM0_MEM_SIZE
274   },
275 #if MSC_ECC_BANKS > 1
276   {
277     ECC_RAM1_SYNDROMES_INIT, ECC_RAM1_CORRECTION_EN,
278     ECC_RAM1_MEM_BASE, ECC_RAM1_MEM_SIZE
279   },
280 #if MSC_ECC_BANKS > 2
281   {
282     ECC_RAM2_SYNDROMES_INIT, ECC_RAM2_CORRECTION_EN,
283     ECC_RAM2_MEM_BASE, ECC_RAM2_MEM_SIZE
284   },
285 #endif
286 #endif
287 };
288 #endif
289 
290 /*******************************************************************************
291  ******************************     FUNCTIONS     ******************************
292  ******************************************************************************/
293 MSC_RAMFUNC_DECLARATOR MSC_Status_TypeDef
294 MSC_WriteWordI(uint32_t *address,
295                void const *data,
296                uint32_t numBytes);
297 
298 MSC_RAMFUNC_DECLARATOR MSC_Status_TypeDef
299 MSC_LoadWriteData(uint32_t* data,
300                   uint32_t numWords);
301 
302 MSC_RAMFUNC_DECLARATOR MSC_Status_TypeDef
303 MSC_LoadVerifyAddress(uint32_t* address);
304 
305 /** @endcond */
306 
307 /***************************************************************************//**
308  * @addtogroup msc
309  * @{
310  ******************************************************************************/
311 
312 /*******************************************************************************
313  **************************   GLOBAL FUNCTIONS   *******************************
314  ******************************************************************************/
315 
316 #if defined(_SILICON_LABS_32B_SERIES_2)
317 
318 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
319 
320 /***************************************************************************//**
321  * @brief
322  *   Wait for a specified MSC status or timeout.
323  *
324  * @param[in] mask
325  *   MSC->STATUS register mask to apply when testing for specified status.
326  * @param[in] value
327  *   The value the MSC->STATUS test is waiting to see.
328  * @return
329  *   Returns the status of a write or erase operation, @ref MSC_Status_TypeDef
330  * @verbatim
331  *   mscReturnOk - Specified status criteria fulfilled.
332  *   mscReturnInvalidAddr - Operation tried to write or erase a non-flash area.
333  *   flashReturnLocked - MSC registers are locked or the operation tried to
334  *                       write or erase a locked area of the flash.
335  *   flashReturnTimeOut - Operation timed out.
336  * @endverbatim
337  ******************************************************************************/
338 MSC_RAMFUNC_DEFINITION_BEGIN
mscStatusWait(uint32_t mask,uint32_t value)339 msc_Return_TypeDef mscStatusWait(uint32_t mask, uint32_t value)
340 {
341   uint32_t timeOut = MSC_PROGRAM_TIMEOUT;
342 
343   while (timeOut) {
344     uint32_t status = MSC->STATUS;
345 
346     /* if INVADDR is asserted by MSC, BUSY will never go high, can be checked early */
347     if (status & MSC_STATUS_INVADDR) {
348       return mscReturnInvalidAddr;
349     }
350 
351     /*
352      * if requested operation fails because flash is locked, BUSY will be high
353      * for a few cycles and it's not safe to clear WRITECTRL.WREN during that
354      * period. mscStatusWait should return only when it's safe to do so.
355      *
356      * So if user is checking BUSY flag, make sure it matches user's expected
357      * value and only then check the lock bits. Otherwise, do check early and
358      * bail out if necessary.
359      */
360 
361     if ((!(mask & MSC_STATUS_BUSY))
362         && (status & (MSC_STATUS_LOCKED | MSC_STATUS_REGLOCK))) {
363       return mscReturnLocked;
364     }
365 
366     if ((status & mask) == value) {
367       if (status & (MSC_STATUS_LOCKED | MSC_STATUS_REGLOCK)) {
368         return mscReturnLocked;
369       } else {
370         return mscReturnOk;
371       }
372     }
373 
374     timeOut--;
375   }
376 
377   return mscReturnTimeOut;
378 }
379 MSC_RAMFUNC_DEFINITION_END
380 
381 /***************************************************************************//**
382  * @brief
383  *   Writes data to flash memory. It is assumed that start address is word
384  *   aligned and that numBytes is an integer multiple of four, and that the
385  *   write operation does not cross a flash page boundary.
386  *
387  * @param[in] address
388  *   Pointer to the flash word to write to. Must be aligned to words.
389  * @param[in] data
390  *   Data to write to flash.
391  * @param[in] numBytes
392  *   Number of bytes to write to flash. NB: Must be divisable by four.
393  * @return
394  *   Returns the status of the write operation, @ref MSC_Status_TypeDef
395  * @verbatim
396  *   flashReturnOk - Operation completed successfully.
397  *   flashReturnInvalidAddr - Operation tried to write to a non-flash area.
398  *   flashReturnLocked - MSC registers are locked or the operation tried to
399  *                       program a locked area of the flash.
400  *   flashReturnTimeOut - Operation timed out.
401  * @endverbatim
402  ******************************************************************************/
403 MSC_RAMFUNC_DEFINITION_BEGIN
writeBurst(uint32_t address,const uint32_t * data,uint32_t numBytes)404 msc_Return_TypeDef writeBurst(uint32_t address,
405                               const uint32_t *data,
406                               uint32_t numBytes)
407 {
408   msc_Return_TypeDef retVal;
409 
410   MSC->ADDRB = address;
411 
412   if (MSC->STATUS & MSC_STATUS_INVADDR) {
413     return mscReturnInvalidAddr;
414   }
415 
416   MSC->WDATA = *data++;
417   numBytes  -= 4;
418 
419   while (numBytes) {
420     retVal = mscStatusWait(MSC_STATUS_WDATAREADY, MSC_STATUS_WDATAREADY);
421 
422     if (retVal != mscReturnOk) {
423       MSC->WRITECMD = MSC_WRITECMD_WRITEEND;
424       return retVal;
425     }
426 
427     MSC->WDATA = *data++;
428     numBytes  -= 4;
429   }
430 
431   MSC->WRITECMD = MSC_WRITECMD_WRITEEND;
432 
433   retVal = mscStatusWait((MSC_STATUS_BUSY | MSC_STATUS_PENDING), 0);
434 
435   if (retVal == mscReturnOk) {
436     // We need to check twice to be sure
437     retVal = mscStatusWait((MSC_STATUS_BUSY | MSC_STATUS_PENDING), 0);
438   }
439 
440   return retVal;
441 }
442 MSC_RAMFUNC_DEFINITION_END
443 
444 /** @endcond */
445 
446 /***************************************************************************//**
447  * @brief
448  *   Initialize MSC module. Puts MSC hw in a known state.
449  ******************************************************************************/
MSC_Init(void)450 void MSC_Init(void)
451 {
452 #if defined(_CMU_CLKEN1_MASK)
453   CMU->CLKEN1_SET = CMU_CLKEN1_MSC;
454 #endif
455   // Unlock MSC
456   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
457   // Disable flash write
458   MSC->WRITECTRL_CLR = MSC_WRITECTRL_WREN;
459 }
460 
461 /***************************************************************************//**
462  * @brief
463  *   Turn off MSC flash write enable and lock MSC registers.
464  ******************************************************************************/
MSC_Deinit(void)465 void MSC_Deinit(void)
466 {
467   // Unlock MSC
468   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
469   // Disable flash write
470   MSC->WRITECTRL_CLR = MSC_WRITECTRL_WREN;
471   // Lock MSC
472   MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
473 #if defined(_CMU_CLKEN1_MASK)
474   CMU->CLKEN1_CLR = CMU_CLKEN1_MSC;
475 #endif
476 }
477 
478 /***************************************************************************//**
479  * @brief
480  *   Set MSC code execution configuration
481  *
482  * @param[in] execConfig
483  *   Code execution configuration
484  ******************************************************************************/
MSC_ExecConfigSet(MSC_ExecConfig_TypeDef * execConfig)485 void MSC_ExecConfigSet(MSC_ExecConfig_TypeDef *execConfig)
486 {
487   uint32_t mscReadCtrl;
488 
489 #if defined(MSC_RDATACTRL_DOUTBUFEN)
490   mscReadCtrl = MSC->RDATACTRL & ~MSC_RDATACTRL_DOUTBUFEN;
491 
492   if (execConfig->doutBufEn) {
493     mscReadCtrl |= MSC_RDATACTRL_DOUTBUFEN;
494   }
495 
496   MSC->RDATACTRL = mscReadCtrl;
497 #elif defined(MSC_READCTRL_DOUTBUFEN)
498   mscReadCtrl = MSC->READCTRL & ~MSC_READCTRL_DOUTBUFEN;
499 
500   if (execConfig->doutBufEn) {
501     mscReadCtrl |= MSC_READCTRL_DOUTBUFEN;
502   }
503   MSC->READCTRL = mscReadCtrl;
504 #endif
505 }
506 
507 /***************************************************************************//**
508  * @brief
509  *   Erases a page in flash memory.
510  *
511  *   For IAR Embedded Workbench, Simplicity Studio and GCC this will be achieved
512  *   automatically by using attributes in the function proctype. For Keil
513  *   uVision you must define a section called "ram_code" and place this manually
514  *   in your project's scatter file.
515  *
516  * @param[in] startAddress
517  *   Pointer to the flash page to erase. Must be aligned to beginning of page
518  *   boundary.
519  * @return
520  *   Returns the status of erase operation, @ref MSC_Status_TypeDef
521  * @verbatim
522  *   mscReturnOk - Operation completed successfully.
523  *   mscReturnInvalidAddr - Operation tried to erase a non-flash area.
524  *   flashReturnLocked - MSC registers are locked or the operation tried to
525  *                       erase a locked area of the flash.
526  *   flashReturnTimeOut - Operation timed out.
527  * @endverbatim
528  ******************************************************************************/
529 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_ErasePage(uint32_t * startAddress)530 MSC_Status_TypeDef MSC_ErasePage(uint32_t *startAddress)
531 {
532   MSC_Status_TypeDef retVal;
533   bool wasLocked;
534 
535   // Address must be aligned to page boundary
536   EFM_ASSERT((((uint32_t)startAddress) & (FLASH_PAGE_SIZE - 1U)) == 0);
537 
538 #if defined(_CMU_CLKEN1_MASK)
539   CMU->CLKEN1_SET = CMU_CLKEN1_MSC;
540 #endif
541   wasLocked = MSC_IS_LOCKED();
542   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
543 
544   MSC->WRITECTRL_SET = MSC_WRITECTRL_WREN;
545   MSC->ADDRB         = (uint32_t)startAddress;
546   MSC->WRITECMD      = MSC_WRITECMD_ERASEPAGE;
547 
548   retVal = mscStatusWait((MSC_STATUS_BUSY | MSC_STATUS_PENDING), 0);
549 
550   if (retVal == mscReturnOk) {
551     // We need to check twice to be sure
552     retVal = mscStatusWait((MSC_STATUS_BUSY | MSC_STATUS_PENDING), 0);
553   }
554 
555   MSC->WRITECTRL_CLR = MSC_WRITECTRL_WREN;
556 
557   if (wasLocked) {
558     MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
559   }
560 
561   return retVal;
562 }
563 MSC_RAMFUNC_DEFINITION_END
564 
565 /***************************************************************************//**
566  * @brief
567  *   Writes data to flash memory. Write data must be aligned to words and
568  *   contain a number of bytes that is divisible by four.
569  * @note
570  *   It is recommended to erase the flash page before performing a write.
571  *
572  *   For IAR Embedded Workbench, Simplicity Studio and GCC this will be achieved
573  *   automatically by using attributes in the function proctype. For Keil
574  *   uVision you must define a section called "ram_code" and place this manually
575  *   in your project's scatter file.
576  *
577  *   The Flash memory is organized into 64-bit wide double-words.
578  *   Each 64-bit double-word can be written only twice using burst write
579  *   operation between erasing cycles. The user's application must store data in
580  *   RAM to sustain burst write operation.
581  *
582  *   EFR32XG21 RevC is not able to program every word twice before the next erase.
583  *
584  * @param[in] address
585  *   Pointer to the flash word to write to. Must be aligned to words.
586  * @param[in] data
587  *   Data to write to flash.
588  * @param[in] numBytes
589  *   Number of bytes to write to flash. NB: Must be divisable by four.
590  * @return
591  *   Returns the status of the write operation, @ref MSC_Status_TypeDef
592  * @verbatim
593  *   flashReturnOk - Operation completed successfully.
594  *   flashReturnInvalidAddr - Operation tried to write to a non-flash area.
595  *   flashReturnLocked - MSC registers are locked or the operation tried to
596  *                       program a locked area of the flash.
597  *   flashReturnTimeOut - Operation timed out.
598  * @endverbatim
599  ******************************************************************************/
600 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_WriteWord(uint32_t * address,void const * data,uint32_t numBytes)601 MSC_Status_TypeDef MSC_WriteWord(uint32_t *address,
602                                  void const *data,
603                                  uint32_t numBytes)
604 {
605   uint32_t addr;
606   const uint8_t  *pData;
607   uint32_t burstLen;
608   MSC_Status_TypeDef retVal = mscReturnOk;
609   bool wasLocked;
610 
611   // Check alignment (must be aligned to words)
612   EFM_ASSERT(((uint32_t)address & 0x3U) == 0);
613   // Check number of bytes, must be divisable by four
614   EFM_ASSERT((numBytes & 0x3U) == 0);
615 
616 #if defined(_CMU_CLKEN1_MASK)
617   CMU->CLKEN1_SET = CMU_CLKEN1_MSC;
618 #endif
619   wasLocked = MSC_IS_LOCKED();
620   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
621 
622   // Enable flash write
623   MSC->WRITECTRL_SET = MSC_WRITECTRL_WREN;
624 
625   addr  = (uint32_t)address;
626   pData = (uint8_t*)data;
627 
628   while (numBytes) {
629     // Max burst length is up to next flash page boundary
630     burstLen = SL_MIN(numBytes,
631                       ((addr + FLASH_PAGE_SIZE) & FLASH_PAGE_MASK) - addr);
632 
633     if ((retVal = writeBurst(addr, (const uint32_t*)pData, burstLen))
634         != mscReturnOk) {
635       break;
636     }
637 
638     addr     += burstLen;
639     pData    += burstLen;
640     numBytes -= burstLen;
641   }
642 
643   // Disable flash write
644   MSC->WRITECTRL_CLR = MSC_WRITECTRL_WREN;
645 
646   if (wasLocked) {
647     MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
648   }
649 
650   return retVal;
651 }
652 MSC_RAMFUNC_DEFINITION_END
653 
654 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_MassErase(void)655 MSC_Status_TypeDef MSC_MassErase(void)
656 {
657   MSC_Status_TypeDef retVal;
658 
659   if (MSC_IS_LOCKED()) {
660     return mscReturnLocked;
661   }
662 
663   MSC->WRITECTRL_SET    = MSC_WRITECTRL_WREN;                 // Set write enable bit
664   MSC->MISCLOCKWORD_CLR = MSC_MISCLOCKWORD_MELOCKBIT;         // Enable Write ctrl access
665   MSC->WRITECMD         = MSC_WRITECMD_ERASEMAIN0;            // Start Mass erase procedure
666   retVal                = mscStatusWait(MSC_STATUS_BUSY, 0);  // Wait for end of busy flag or a problem (INVADDR, LOCK, REGLOCK, TIMEOUT)
667   MSC->MISCLOCKWORD_SET = MSC_MISCLOCKWORD_MELOCKBIT;         // Reenable mass erase lock bit
668   MSC->WRITECTRL_CLR    = MSC_WRITECTRL_WREN;                 // Disable Write ctrl access
669 
670   return retVal;
671 }
672 MSC_RAMFUNC_DEFINITION_END
673 
674 /***************************************************************************//**
675  * @brief
676  *   Writes data to flash memory using the DMA.
677  *
678  * @details
679  *   This function uses the LDMA to write data to the internal flash memory.
680  *   This is the fastest way to write data to the flash and should be used when
681  *   the application wants to achieve write speeds like they are reported in the
682  *   datasheet. Note that copying data from flash to flash will be slower than
683  *   copying from RAM to flash. So the source data must be in RAM in order to
684  *   see the write speeds similar to the datasheet numbers.
685  *
686  * @note
687  *   This function requires that the LDMA and LDMAXBAR clock is enabled.
688  *
689  * @param[in] ch
690  *   DMA channel to use
691  *
692  * @param[in] address
693  *   A pointer to the flash word to write to. Must be aligned to words.
694  *
695  * @param[in] data
696  *   Data to write to flash and be aligned to words.
697  *
698  * @param[in] numBytes
699  *   A number of bytes to write from flash. NB: Must be divisible by four.
700  *
701  * @return
702  *   Returns the status of the write operation.
703  * @verbatim
704  *   flashReturnOk - The operation completed successfully.
705  *   flashReturnInvalidAddr - The operation tried to erase a non-flash area.
706  * @endverbatim
707  ******************************************************************************/
MSC_WriteWordDma(int ch,uint32_t * address,const void * data,uint32_t numBytes)708 MSC_Status_TypeDef MSC_WriteWordDma(int ch,
709                                     uint32_t *address,
710                                     const void *data,
711                                     uint32_t numBytes)
712 {
713   uint32_t words = numBytes / 4;
714   uint32_t burstLen;
715   uint32_t src = (uint32_t) data;
716   uint32_t dst = (uint32_t) address;
717   bool wasLocked;
718 
719   EFM_ASSERT((ch >= 0) && (ch < (int)DMA_CHAN_COUNT));
720 
721   LDMA->EN_SET = 0x1;
722   LDMAXBAR->CH[ch].REQSEL = LDMAXBAR_CH_REQSEL_SOURCESEL_MSC
723                             | LDMAXBAR_CH_REQSEL_SIGSEL_MSCWDATA;
724   LDMA->CH[ch].CFG = _LDMA_CH_CFG_RESETVALUE;
725   LDMA->CH[ch].LOOP = _LDMA_CH_LOOP_RESETVALUE;
726   LDMA->CH[ch].LINK = _LDMA_CH_LINK_RESETVALUE;
727 
728 #if defined(_CMU_CLKEN1_MASK)
729   CMU->CLKEN1_SET = CMU_CLKEN1_MSC;
730 #endif
731   // Unlock MSC
732   wasLocked = MSC_IS_LOCKED();
733   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
734   // Enable writing to the MSC module.
735   MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
736 
737   while (numBytes) {
738     // Max burst length is up to next flash page boundary
739     burstLen = SL_MIN(numBytes,
740                       ((dst + FLASH_PAGE_SIZE) & FLASH_PAGE_MASK) - dst);
741     words = burstLen / 4;
742 
743     // Load the address.
744     MSC->ADDRB = dst;
745 
746     // Check for an invalid address.
747     if (MSC->STATUS & MSC_STATUS_INVADDR) {
748       return mscReturnInvalidAddr;
749     }
750 
751     LDMA->CH[ch].CTRL = LDMA_CH_CTRL_DSTINC_NONE
752                         | LDMA_CH_CTRL_SIZE_WORD
753                         | ((words - 1) << _LDMA_CH_CTRL_XFERCNT_SHIFT);
754     LDMA->CH[ch].SRC = (uint32_t)src;
755     LDMA->CH[ch].DST = (uint32_t)&MSC->WDATA;
756 
757     // Enable channel
758     LDMA->CHEN_SET = (0x1 << ch);
759 
760     while ((LDMA->CHDONE & (0x1 << ch)) == 0x0) {
761       ;
762     }
763 
764     LDMA->CHDONE_CLR = (0x1 << ch);
765     LDMA->CHDIS_SET = (0x1 << ch);
766     MSC->WRITECMD = MSC_WRITECMD_WRITEEND;
767 
768     dst      += burstLen;
769     src      += burstLen;
770     numBytes -= burstLen;
771   }
772 
773   // Disable writing to the MSC module.
774   MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
775   if (wasLocked) {
776     MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
777   }
778 
779   return mscReturnOk;
780 }
781 
782 #else // defined(_SILICON_LABS_32B_SERIES_2)
783 
784 /***************************************************************************//**
785  * @brief
786  *   Enables the flash controller for writing.
787  * @note
788  *   This function must be called before flash operations when
789  *   AUXHFRCO clock has been changed from a default band.
790  ******************************************************************************/
MSC_Init(void)791 void MSC_Init(void)
792 {
793 #if defined(_MSC_TIMEBASE_MASK)
794   uint32_t freq, cycles;
795 #endif
796 
797 #if defined(_EMU_STATUS_VSCALE_MASK) && defined(_SILICON_LABS_32B_SERIES_1)
798   /* VSCALE must be done. Flash erase and write requires VSCALE2. */
799   EFM_ASSERT(!(EMU->STATUS & _EMU_STATUS_VSCALEBUSY_MASK));
800   EFM_ASSERT((EMU->STATUS & _EMU_STATUS_VSCALE_MASK) == EMU_STATUS_VSCALE_VSCALE2);
801 #endif
802 
803   /* Unlock the MSC module. */
804   MSC->LOCK = MSC_UNLOCK_CODE;
805   /* Disable writing to the Flash. */
806   MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
807 
808 #if defined(_MSC_TIMEBASE_MASK)
809   /* Configure MSC->TIMEBASE according to a selected frequency. */
810   freq = CMU_ClockFreqGet(cmuClock_AUX);
811 
812   /* Timebase 5us is used for the 1/1.2 MHz band only. Note that the 1 MHz band
813      is tuned to 1.2 MHz on newer revisions.  */
814   if (freq > 1200000) {
815     /* Calculate a number of clock cycles for 1 us as a base period. */
816     freq   = (freq * 11) / 10;
817     cycles = (freq / 1000000) + 1;
818 
819     /* Configure clock cycles for flash timing. */
820     MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK
821                                        | _MSC_TIMEBASE_PERIOD_MASK))
822                     | MSC_TIMEBASE_PERIOD_1US
823                     | (cycles << _MSC_TIMEBASE_BASE_SHIFT);
824   } else {
825     /* Calculate a number of clock cycles for 5 us as a base period. */
826     freq   = (freq * 5 * 11) / 10;
827     cycles = (freq / 1000000) + 1;
828 
829     /* Configure clock cycles for flash timing */
830     MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK
831                                        | _MSC_TIMEBASE_PERIOD_MASK))
832                     | MSC_TIMEBASE_PERIOD_5US
833                     | (cycles << _MSC_TIMEBASE_BASE_SHIFT);
834   }
835 #endif
836 }
837 
838 /***************************************************************************//**
839  * @brief
840  *   Disables the flash controller for writing.
841  ******************************************************************************/
MSC_Deinit(void)842 void MSC_Deinit(void)
843 {
844   /* Disable writing to the Flash. */
845   MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
846   /* Lock the MSC module.*/
847   MSC->LOCK = 0;
848 }
849 
850 /***************************************************************************//**
851  * @brief
852  *   Set the MSC code execution configuration.
853  *
854  * @param[in] execConfig
855  *   The code execution configuration.
856  ******************************************************************************/
MSC_ExecConfigSet(MSC_ExecConfig_TypeDef * execConfig)857 void MSC_ExecConfigSet(MSC_ExecConfig_TypeDef *execConfig)
858 {
859   uint32_t mscReadCtrl;
860 
861 #if defined(MSC_READCTRL_MODE_WS0SCBTP)
862   mscReadCtrl = MSC->READCTRL & _MSC_READCTRL_MODE_MASK;
863   if ((mscReadCtrl == MSC_READCTRL_MODE_WS0) && (execConfig->scbtEn)) {
864     mscReadCtrl |= MSC_READCTRL_MODE_WS0SCBTP;
865   } else if ((mscReadCtrl == MSC_READCTRL_MODE_WS1) && (execConfig->scbtEn)) {
866     mscReadCtrl |= MSC_READCTRL_MODE_WS1SCBTP;
867   } else if ((mscReadCtrl == MSC_READCTRL_MODE_WS0SCBTP) && (!execConfig->scbtEn)) {
868     mscReadCtrl |= MSC_READCTRL_MODE_WS0;
869   } else if ((mscReadCtrl == MSC_READCTRL_MODE_WS1SCBTP) && (!execConfig->scbtEn)) {
870     mscReadCtrl |= MSC_READCTRL_MODE_WS1;
871   } else {
872     /* No change needed. */
873   }
874 #endif
875 
876   mscReadCtrl = MSC->READCTRL & ~(0
877 #if defined(MSC_READCTRL_SCBTP)
878                                   | MSC_READCTRL_SCBTP
879 #endif
880 #if defined(MSC_READCTRL_USEHPROT)
881                                   | MSC_READCTRL_USEHPROT
882 #endif
883 #if defined(MSC_READCTRL_PREFETCH)
884                                   | MSC_READCTRL_PREFETCH
885 #endif
886 #if defined(MSC_READCTRL_ICCDIS)
887                                   | MSC_READCTRL_ICCDIS
888 #endif
889 #if defined(MSC_READCTRL_AIDIS)
890                                   | MSC_READCTRL_AIDIS
891 #endif
892 #if defined(MSC_READCTRL_IFCDIS)
893                                   | MSC_READCTRL_IFCDIS
894 #endif
895                                   );
896   mscReadCtrl |= (0
897 #if defined(MSC_READCTRL_SCBTP)
898                   | (execConfig->scbtEn ? MSC_READCTRL_SCBTP : 0)
899 #endif
900 #if defined(MSC_READCTRL_USEHPROT)
901                   | (execConfig->useHprot ? MSC_READCTRL_USEHPROT : 0)
902 #endif
903 #if defined(MSC_READCTRL_PREFETCH)
904                   | (execConfig->prefetchEn ? MSC_READCTRL_PREFETCH : 0)
905 #endif
906 #if defined(MSC_READCTRL_ICCDIS)
907                   | (execConfig->iccDis ? MSC_READCTRL_ICCDIS : 0)
908 #endif
909 #if defined(MSC_READCTRL_AIDIS)
910                   | (execConfig->aiDis ? MSC_READCTRL_AIDIS : 0)
911 #endif
912 #if defined(MSC_READCTRL_IFCDIS)
913                   | (execConfig->ifcDis ? MSC_READCTRL_IFCDIS : 0)
914 #endif
915                   );
916 
917   MSC->READCTRL = mscReadCtrl;
918 }
919 
920 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
921 
922 /***************************************************************************//**
923  * @brief
924  *   Perform the address phase of the flash write cycle.
925  * @details
926  *   This function performs the address phase of a flash write operation by
927  *   writing the given flash address to the ADDRB register and issuing the
928  *   LADDRIM command to load the address.
929  * @param[in] address
930  *   An address in flash memory. Must be aligned at a 4 byte boundary.
931  * @return
932  *   Returns the status of the address load operation, @ref MSC_Status_TypeDef
933  * @verbatim
934  *   mscReturnOk - The operation completed successfully.
935  *   mscReturnInvalidAddr - The operation tried to erase a non-flash area.
936  *   mscReturnLocked - The operation tried to erase a locked area of the Flash.
937  * @endverbatim
938  ******************************************************************************/
939 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_LoadVerifyAddress(uint32_t * address)940 MSC_Status_TypeDef MSC_LoadVerifyAddress(uint32_t* address)
941 {
942   uint32_t timeOut;
943 
944   /* Wait for the MSC to become ready. */
945   timeOut = MSC_PROGRAM_TIMEOUT;
946   while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) {
947     timeOut--;
948   }
949 
950   /* Check for timeout. */
951   if (timeOut == 0) {
952     return mscReturnTimeOut;
953   }
954   /* Load the address. */
955   MSC->ADDRB    = (uint32_t)address;
956   MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
957 
958   /* Check for an invalid address. */
959   if (MSC->STATUS & MSC_STATUS_INVADDR) {
960     return mscReturnInvalidAddr;
961   }
962   return mscReturnOk;
963 }
964 MSC_RAMFUNC_DEFINITION_END
965 
966 /***************************************************************************//**
967  * @brief
968  *   Perform a flash data write phase.
969  * @details
970  *   This function performs the data phase of a flash write operation by loading
971  *   the given number of 32-bit words to the WDATA register.
972  * @param[in] data
973  *   A pointer to the first data word to load.
974  * @param[in] numWords
975  *   A number of data words (32-bit) to load.
976  * @return
977  *   Returns the status of the data load operation.
978  * @verbatim
979  *   mscReturnOk - An operation completed successfully.
980  *   mscReturnTimeOut - An operation timed out waiting for the flash operation
981  *                      to complete.
982  * @endverbatim
983  ******************************************************************************/
984 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_LoadWriteData(uint32_t * data,uint32_t numWords)985 MSC_Status_TypeDef MSC_LoadWriteData(uint32_t* data,
986                                      uint32_t numWords)
987 {
988   uint32_t timeOut;
989   uint32_t wordIndex;
990   bool useWDouble = false;
991   MSC_Status_TypeDef retval = mscReturnOk;
992 
993 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_MSC_WRITECTRL_WDOUBLE_MASK)
994   /* If the LPWRITE (Low Power Write) is NOT enabled, set WDOUBLE (Write Double word). */
995   if (!(MSC->WRITECTRL & MSC_WRITECTRL_LPWRITE)) {
996     /* If the number of words to be written is odd, align by writing
997        a single word first, before setting the WDOUBLE bit. */
998     if (numWords & 0x1) {
999       /* Wait for the MSC to become ready for the next word. */
1000       timeOut = MSC_PROGRAM_TIMEOUT;
1001       while ((!(MSC->STATUS & MSC_STATUS_WDATAREADY)) && (timeOut != 0)) {
1002         timeOut--;
1003       }
1004       /* Check for timeout. */
1005       if (timeOut == 0) {
1006         return mscReturnTimeOut;
1007       }
1008 
1009       /* Clear the double word option to write the initial single word. */
1010       MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
1011       /* Write first data word. */
1012       MSC->WDATA = *data++;
1013       MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
1014 
1015       /* Wait for the operation to finish. It may be required to change the WDOUBLE
1016          configuration after the initial write. It should not be changed while BUSY. */
1017       timeOut = MSC_PROGRAM_TIMEOUT;
1018       while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) {
1019         timeOut--;
1020       }
1021       /* Check for timeout. */
1022       if (timeOut == 0) {
1023         return mscReturnTimeOut;
1024       }
1025       /* Check for a write protected flash area. */
1026       if (MSC->STATUS & MSC_STATUS_LOCKED) {
1027         return mscReturnLocked;
1028       }
1029       /* Subtract this initial odd word for the write loop below. */
1030       numWords -= 1;
1031       retval = mscReturnOk;
1032     }
1033     /* Set the double word option to write two words per
1034        data phase. */
1035     MSC->WRITECTRL |= MSC_WRITECTRL_WDOUBLE;
1036     useWDouble = true;
1037   }
1038 #endif /* defined( _MSC_WRITECTRL_LPWRITE_MASK ) && defined( _MSC_WRITECTRL_WDOUBLE_MASK ) */
1039 
1040   /* Write the rest as a double word write if wordsPerDataPhase == 2 */
1041   if (numWords > 0) {
1042     /* Requires a system core clock at 1MHz or higher */
1043     EFM_ASSERT(SystemCoreClock >= 1000000);
1044     wordIndex = 0;
1045     while (wordIndex < numWords) {
1046       if (!useWDouble) {
1047         MSC->WDATA = *data++;
1048         wordIndex++;
1049         MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
1050       } else {
1051         /* Trigger a double write according to flash properties. */
1052 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_MSC_WRITECTRL_WDOUBLE_MASK)
1053         MSC->WDATA = *data++;
1054         while (!(MSC->STATUS & MSC_STATUS_WDATAREADY)) ;
1055         MSC->WDATA = *data++;
1056         wordIndex += 2;
1057         MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;
1058 #endif
1059       }
1060 
1061       /* Wait for the transaction to finish. */
1062       timeOut = MSC_PROGRAM_TIMEOUT;
1063       while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) {
1064         timeOut--;
1065       }
1066       /* Check for a timeout. */
1067       if (timeOut == 0) {
1068         retval = mscReturnTimeOut;
1069         break;
1070       }
1071       /* Check for a write protected flash area. */
1072       if (MSC->STATUS & MSC_STATUS_LOCKED) {
1073         retval = mscReturnLocked;
1074         break;
1075       }
1076 #if defined(_EFM32_GECKO_FAMILY)
1077       MSC->ADDRB += 4;
1078       MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
1079 #endif
1080     }
1081   }
1082 
1083 #if defined(_MSC_WRITECTRL_WDOUBLE_MASK)
1084   /* Clear a double word option, which should not be left on when returning. */
1085   MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
1086 #endif
1087 
1088   return retval;
1089 }
1090 MSC_RAMFUNC_DEFINITION_END
1091 
1092 /***************************************************************************//**
1093  * @brief
1094  *   An internal flash write function.
1095  * @param[in] address
1096  *   A write address.
1097  * @param[in] data
1098  *   A pointer to the first data word to load.
1099  * @param[in] numBytes
1100  *   A nsumber of data bytes to load, which must be a multiple of 4 bytes.
1101  * @return
1102  *   Returns the status of the data load operation.
1103  ******************************************************************************/
1104 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_WriteWordI(uint32_t * address,void const * data,uint32_t numBytes)1105 MSC_Status_TypeDef MSC_WriteWordI(uint32_t *address,
1106                                   void const *data,
1107                                   uint32_t numBytes)
1108 {
1109   uint32_t wordCount;
1110   uint32_t numWords;
1111   uint32_t pageWords;
1112   uint32_t* pData;
1113   bool wasLocked;
1114   MSC_Status_TypeDef retval = mscReturnOk;
1115 
1116   wasLocked = MSC_IS_LOCKED();
1117   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
1118 
1119   /* Check alignment (must be aligned to words). */
1120   EFM_ASSERT(((uint32_t) address & 0x3) == 0);
1121 
1122   /* Check a number of bytes. Must be divisible by four. */
1123   EFM_ASSERT((numBytes & 0x3) == 0);
1124 
1125 #if defined(_EMU_STATUS_VSCALE_MASK) && defined(_SILICON_LABS_32B_SERIES_1)
1126   /* VSCALE must be done and flash write requires VSCALE2. */
1127   EFM_ASSERT(!(EMU->STATUS & _EMU_STATUS_VSCALEBUSY_MASK));
1128   EFM_ASSERT((EMU->STATUS & _EMU_STATUS_VSCALE_MASK) == EMU_STATUS_VSCALE_VSCALE2);
1129 #endif
1130 
1131   /* Enable writing to the MSC module. */
1132   MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
1133 
1134   /* Convert bytes to words. */
1135   numWords = numBytes >> 2;
1136   EFM_ASSERT(numWords > 0);
1137 
1138   /* The following loop splits the data into chunks corresponding to flash pages.
1139      The address is loaded only once per page because the hardware automatically
1140      increments the address internally for each data load inside a page. */
1141   for (wordCount = 0, pData = (uint32_t *)data; wordCount < numWords; ) {
1142     /* First, the address is loaded. The address is auto-incremented within a page.
1143        Therefore, the address phase is only needed once for each page. */
1144     retval = MSC_LoadVerifyAddress(address + wordCount);
1145     if (mscReturnOk != retval) {
1146       /* Disable writing to the MSC module. */
1147       MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
1148       if (wasLocked) {
1149         MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
1150       }
1151       return retval;
1152     }
1153     /* Compute the number of words to write to the current page. */
1154     pageWords =
1155       (FLASH_PAGE_SIZE
1156        - (((uint32_t) (address + wordCount)) & (FLASH_PAGE_SIZE - 1)))
1157       / sizeof(uint32_t);
1158     if (pageWords > numWords - wordCount) {
1159       pageWords = numWords - wordCount;
1160     }
1161     /* Write the data in the current page. */
1162     retval = MSC_LoadWriteData(pData, pageWords);
1163     if (mscReturnOk != retval) {
1164       break;
1165     }
1166     wordCount += pageWords;
1167     pData += pageWords;
1168   }
1169 
1170 #if defined(ERRATA_FIX_FLASH_E201_EN)
1171   /* Fix for errata FLASH_E201 - Potential program failure after Power On.
1172    *
1173    * Check if the first word was programmed correctly. If a failure is detected,
1174    * retry programming of the first word.
1175    *
1176    * A full description of the errata is in the errata document. */
1177   pData = (uint32_t *) data;
1178   if (*address != *pData) {
1179     retval = MSC_LoadVerifyAddress(address);
1180     if (mscReturnOk == retval) {
1181       retval = MSC_LoadWriteData(pData, 1);
1182     }
1183   }
1184 #endif
1185 
1186   /* Disable writing to the MSC module. */
1187   MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
1188 
1189 #if defined(_MSC_WRITECTRL_WDOUBLE_MASK)
1190 #if (WORDS_PER_DATA_PHASE == 2)
1191   /* Turn off the double word write cycle support. */
1192   MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
1193 #endif
1194 #endif
1195   if (wasLocked) {
1196     MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
1197   }
1198   return retval;
1199 }
1200 MSC_RAMFUNC_DEFINITION_END
1201 
1202 /** @endcond */
1203 
1204 /***************************************************************************//**
1205  * @brief
1206  *   Erases a page in flash memory.
1207  * @note
1208  *   For the Gecko family, it is required to run this function from RAM.
1209  *
1210  *   For IAR Embedded Workbench, Simplicity Studio and GCC, this is
1211  *   achieved automatically by using attributes in the function proctype. For Keil
1212  *   uVision IDE, define a section called "ram_code" and place this manually in
1213  *   the project's scatter file.
1214  *
1215  * @param[in] startAddress
1216  *   A pointer to the flash page to erase. Must be aligned to the beginning of the page
1217  *   boundary.
1218  * @return
1219  *   Returns the status of erase operation, @ref MSC_Status_TypeDef
1220  * @verbatim
1221  *   mscReturnOk - The operation completed successfully.
1222  *   mscReturnInvalidAddr - The operation tried to erase a non-flash area.
1223  *   mscReturnLocked - The operation tried to erase a locked area of the flash.
1224  *   mscReturnTimeOut - The operation timed out waiting for the flash operation
1225  *       to complete.
1226  * @endverbatim
1227  ******************************************************************************/
1228 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_ErasePage(uint32_t * startAddress)1229 MSC_Status_TypeDef MSC_ErasePage(uint32_t *startAddress)
1230 {
1231   uint32_t timeOut = MSC_PROGRAM_TIMEOUT;
1232   bool wasLocked;
1233 
1234   wasLocked = MSC_IS_LOCKED();
1235   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
1236 
1237   /* An address must be aligned to pages. */
1238   EFM_ASSERT((((uint32_t) startAddress) & (FLASH_PAGE_SIZE - 1)) == 0);
1239 #if defined(_EMU_STATUS_VSCALE_MASK) && defined(_SILICON_LABS_32B_SERIES_1)
1240   /* VSCALE must be done and flash erase requires VSCALE2. */
1241   EFM_ASSERT(!(EMU->STATUS & _EMU_STATUS_VSCALEBUSY_MASK));
1242   EFM_ASSERT((EMU->STATUS & _EMU_STATUS_VSCALE_MASK) == EMU_STATUS_VSCALE_VSCALE2);
1243 #endif
1244 
1245   /* Enable writing to the MSC module. */
1246   MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
1247 
1248   /* Load an address. */
1249   MSC->ADDRB    = (uint32_t)startAddress;
1250   MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
1251 
1252   /* Check for an invalid address. */
1253   if (MSC->STATUS & MSC_STATUS_INVADDR) {
1254     /* Disable writing to the MSC module. */
1255     MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
1256     if (wasLocked) {
1257       MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
1258     }
1259     return mscReturnInvalidAddr;
1260   }
1261 
1262   /* Send erase page command. */
1263   MSC->WRITECMD = MSC_WRITECMD_ERASEPAGE;
1264 
1265   /* Wait for the erase to complete. */
1266   while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) {
1267     timeOut--;
1268   }
1269   /* Check for write protected page. */
1270   if (MSC->STATUS & MSC_STATUS_LOCKED) {
1271     /* Disable writing to the MSC module. */
1272     MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
1273     if (wasLocked) {
1274       MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
1275     }
1276     return mscReturnLocked;
1277   }
1278   if (timeOut == 0) {
1279     /* Disable writing to the MSC module. */
1280     MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
1281     if (wasLocked) {
1282       MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
1283     }
1284     return mscReturnTimeOut;
1285   }
1286   /* Disable writing to the MSC module. */
1287   MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
1288   if (wasLocked) {
1289     MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
1290   }
1291   return mscReturnOk;
1292 }
1293 MSC_RAMFUNC_DEFINITION_END
1294 
1295 /***************************************************************************//**
1296  * @brief
1297  *   Writes data to flash memory. This function is interrupt-safe, but slower than
1298  *   MSC_WriteWordFast(), which writes to flash with interrupts disabled.
1299  *   Write data must be aligned to words and contain a number of bytes that is
1300  *   divisible by four.
1301  * @note
1302  *   It is recommended to erase the flash page before performing a write.
1303  *
1304  *   For the Gecko family, it is required to run this function from RAM.
1305  *
1306  *   For IAR Embedded Workbench, Simplicity Studio and GCC,
1307  *   this is done automatically by using attributes in the function proctype.
1308  *   For Keil uVision IDE, define a section called "ram_code" and place it
1309  *   manually in the project's scatter file.
1310  *
1311  *   This function requires a system core clock at 1 MHz or higher.
1312  *
1313  * @param[in] address
1314  *   A pointer to the flash word to write to. Must be aligned to words.
1315  * @param[in] data
1316  *   Data to write to flash.
1317  * @param[in] numBytes
1318  *   A number of bytes to write from flash. NB: Must be divisible by four.
1319  * @return
1320  *   Returns the status of the write operation.
1321  * @verbatim
1322  *   flashReturnOk - The operation completed successfully.
1323  *   flashReturnInvalidAddr - The operation tried to erase a non-flash area.
1324  *   flashReturnLocked - The operation tried to erase a locked area of the Flash.
1325  *   flashReturnTimeOut - The operation timed out waiting for the flash operation
1326  *       to complete, or the MSC module timed out waiting for the software to write
1327  *       the next word into the DWORD register.
1328  * @endverbatim
1329  ******************************************************************************/
1330 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_WriteWord(uint32_t * address,void const * data,uint32_t numBytes)1331 MSC_Status_TypeDef MSC_WriteWord(uint32_t *address,
1332                                  void const *data,
1333                                  uint32_t numBytes)
1334 {
1335   return MSC_WriteWordI(address, data, numBytes);
1336 }
1337 MSC_RAMFUNC_DEFINITION_END
1338 
1339 /***************************************************************************//**
1340  * @brief
1341  *   Writes data to flash memory. This function is faster than MSC_WriteWord(),
1342  *   but it disables interrupts. Write data must be aligned to words and contain
1343  *   a number of bytes that is divisible by four.
1344  * @warning
1345  *   This function is only available for certain devices.
1346  * @note
1347  *   It is recommended to erase the flash page before performing a write.
1348  *   It is required to run this function from RAM on parts that include a
1349  *   flash write buffer.
1350  *
1351  *   For IAR Embedded Workbench, Simplicity Studio and GCC,
1352  *   this is done automatically by using attributes in the function proctype.
1353  *   For Keil uVision IDE, define a section called "ram_code" and place this manually
1354  *   in the project's scatter file.
1355  *
1356  * @deprecated
1357  *   This function is deprecated, the functionality is the same as calling
1358  *   @ref MSC_WriteWord().
1359  *
1360  * @param[in] address
1361  *   A pointer to the flash word to write to. Must be aligned to words.
1362  * @param[in] data
1363  *   Data to write to flash.
1364  * @param[in] numBytes
1365  *   A number of bytes to write from the Flash. NB: Must be divisible by four.
1366  * @return
1367  *   Returns the status of the write operation.
1368  * @verbatim
1369  *   flashReturnOk - The operation completed successfully.
1370  *   flashReturnInvalidAddr - The operation tried to erase a non-flash area.
1371  *   flashReturnLocked - The operation tried to erase a locked area of the flash.
1372  *   flashReturnTimeOut - The operation timed out waiting for flash operation
1373  *       to complete. Or the MSC timed out waiting for the software to write
1374  *       the next word into the DWORD register.
1375  * @endverbatim
1376  ******************************************************************************/
1377 MSC_RAMFUNC_DEFINITION_BEGIN
MSC_WriteWordFast(uint32_t * address,void const * data,uint32_t numBytes)1378 MSC_Status_TypeDef MSC_WriteWordFast(uint32_t *address,
1379                                      void const *data,
1380                                      uint32_t numBytes)
1381 {
1382   return MSC_WriteWord(address, data, numBytes);
1383 }
1384 MSC_RAMFUNC_DEFINITION_END
1385 
1386 #if (_SILICON_LABS_32B_SERIES > 0)
1387 /***************************************************************************//**
1388  * @brief
1389  *   Writes data from RAM to flash memory using the DMA.
1390  *
1391  * @details
1392  *   This function uses the LDMA to write data to the internal flash memory.
1393  *   This is the fastest way to write data to the flash and should be used when
1394  *   the application wants to achieve write speeds like they are reported in the
1395  *   datasheet. Note that this function only supports writing data from RAM to
1396  *   flash, it does not support writing data from flash to flash.
1397  *
1398  * @note
1399  *   This function requires that the LDMA clock is enabled.
1400  *
1401  * @param[in] ch
1402  *   DMA channel to use
1403  *
1404  * @param[in] address
1405  *   A pointer to the flash word to write to. Must be aligned to words.
1406  *
1407  * @param[in] data
1408  *   Data to write to flash. Note that this argument must be an address in RAM.
1409  *   This function does not support copying data from flash to flash on series-1
1410  *   devices. Must be aligned to words.
1411  *
1412  * @param[in] numBytes
1413  *   A number of bytes to write from flash. NB: Must be divisible by four.
1414  *
1415  * @return
1416  *   Returns the status of the write operation.
1417  * @verbatim
1418  *   flashReturnOk - The operation completed successfully.
1419  *   flashReturnInvalidAddr - The operation tried to erase a non-flash area.
1420  * @endverbatim
1421  ******************************************************************************/
MSC_WriteWordDma(int ch,uint32_t * address,const void * data,uint32_t numBytes)1422 MSC_Status_TypeDef MSC_WriteWordDma(int ch,
1423                                     uint32_t *address,
1424                                     const void *data,
1425                                     uint32_t numBytes)
1426 {
1427   uint32_t words = numBytes / 4;
1428   uint32_t burstLen;
1429   uint32_t src = (uint32_t) data;
1430   uint32_t dst = (uint32_t) address;
1431   bool wasLocked;
1432 
1433   EFM_ASSERT((ch >= 0) && (ch < (int)DMA_CHAN_COUNT));
1434 
1435   // Verify that the data argument is in RAM
1436   if (((uint32_t)data < SRAM_BASE) || ((uint32_t)data > (SRAM_BASE + SRAM_SIZE))) {
1437     EFM_ASSERT(false);
1438     return mscReturnInvalidAddr;
1439   }
1440 
1441   LDMA->CH[ch].REQSEL = LDMA_CH_REQSEL_SOURCESEL_MSC
1442                         | LDMA_CH_REQSEL_SIGSEL_MSCWDATA;
1443   LDMA->CH[ch].CFG = _LDMA_CH_CFG_RESETVALUE;
1444   LDMA->CH[ch].LOOP = _LDMA_CH_LOOP_RESETVALUE;
1445   LDMA->CH[ch].LINK = _LDMA_CH_LINK_RESETVALUE;
1446 
1447   wasLocked = MSC_IS_LOCKED();
1448   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
1449   // Enable writing to the MSC module.
1450   MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
1451 
1452   while (numBytes) {
1453     // Max burst length is up to next flash page boundary
1454     burstLen = SL_MIN(numBytes,
1455                       ((dst + FLASH_PAGE_SIZE) & FLASH_PAGE_MASK) - dst);
1456     words = burstLen / 4;
1457 
1458     // Load the address.
1459     MSC->ADDRB    = dst;
1460     MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
1461 
1462     // Check for an invalid address.
1463     if (MSC->STATUS & MSC_STATUS_INVADDR) {
1464       return mscReturnInvalidAddr;
1465     }
1466 
1467     LDMA->CH[ch].CTRL = LDMA_CH_CTRL_DSTINC_NONE
1468                         | LDMA_CH_CTRL_SIZE_WORD
1469                         | ((words - 1) << _LDMA_CH_CTRL_XFERCNT_SHIFT);
1470     LDMA->CH[ch].SRC = (uint32_t)src;
1471     LDMA->CH[ch].DST = (uint32_t)&MSC->WDATA;
1472 
1473     // Enable channel
1474     LDMA->CHEN |= (0x1 << ch);
1475     MSC->WRITECMD = MSC_WRITECMD_WRITETRIG;
1476 
1477     while ((LDMA->CHDONE & (0x1 << ch)) == 0x0) {
1478       ;
1479     }
1480     BUS_RegMaskedClear(&LDMA->CHDONE, (0x1 << ch));
1481     BUS_RegMaskedClear(&LDMA->CHEN, (0x1 << ch));
1482 
1483     dst      += burstLen;
1484     src      += burstLen;
1485     numBytes -= burstLen;
1486   }
1487 
1488   MSC->WRITECMD = MSC_WRITECMD_WRITEEND;
1489 
1490   // Disable writing to the MSC module.
1491   MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
1492   if (wasLocked) {
1493     MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
1494   }
1495 
1496   return mscReturnOk;
1497 }
1498 #endif
1499 
1500 #if defined(_MSC_MASSLOCK_MASK)
1501 SL_RAMFUNC_DEFINITION_BEGIN
MSC_MassErase(void)1502 MSC_Status_TypeDef MSC_MassErase(void)
1503 {
1504   bool wasLocked;
1505   wasLocked = MSC_IS_LOCKED();
1506   MSC->LOCK = MSC_LOCK_LOCKKEY_UNLOCK;
1507 
1508   /* Enable writing to the MSC module. */
1509   MSC->WRITECTRL |= MSC_WRITECTRL_WREN;
1510 
1511   /* Unlock the device mass erase. */
1512   MSC->MASSLOCK = MSC_MASSLOCK_LOCKKEY_UNLOCK;
1513 
1514   /* Erase the first 512 K block. */
1515   MSC->WRITECMD = MSC_WRITECMD_ERASEMAIN0;
1516 
1517   /* Waiting for erase to complete. */
1518   while ((MSC->STATUS & MSC_STATUS_BUSY) != 0U) {
1519   }
1520 
1521 #if ((FLASH_SIZE >= (512 * 1024)) && defined(_MSC_WRITECMD_ERASEMAIN1_MASK))
1522   /* Erase the second 512 K block. */
1523   MSC->WRITECMD = MSC_WRITECMD_ERASEMAIN1;
1524 
1525   /* Waiting for erase to complete. */
1526   while ((MSC->STATUS & MSC_STATUS_BUSY) != 0U) {
1527   }
1528 #endif
1529 
1530   /* Restore the mass erase lock. */
1531   MSC->MASSLOCK = MSC_MASSLOCK_LOCKKEY_LOCK;
1532 
1533   /* Disable writing to the MSC module. */
1534   MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;
1535 
1536   if (wasLocked) {
1537     MSC->LOCK = MSC_LOCK_LOCKKEY_LOCK;
1538   }
1539 
1540   /* This will only successfully return if calling function is also in SRAM. */
1541   return mscReturnOk;
1542 }
1543 SL_RAMFUNC_DEFINITION_END
1544 #endif  // defined(_MSC_MASSLOCK_MASK)
1545 
1546 #endif // defined(_SILICON_LABS_32B_SERIES_2)
1547 
1548 #if defined(_MSC_ECCCTRL_MASK)          \
1549   || defined(_SYSCFG_DMEM0ECCCTRL_MASK) \
1550   || defined(_MPAHBRAM_CTRL_MASK)
1551 
1552 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)  \
1553   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7) \
1554   || defined(_MPAHBRAM_CTRL_MASK)
1555 
1556 /***************************************************************************//**
1557  * @brief
1558  *    Read and write existing values in RAM (for ECC initialization).
1559  *
1560  * @details
1561  *    This function uses core to load and store the existing data
1562  *    values in the given RAM bank.
1563  *
1564  * @param[in] eccBank
1565  *    Pointer to ECC RAM bank (MSC_EccBank_Typedef)
1566  ******************************************************************************/
mscEccReadWriteExistingPio(const MSC_EccBank_Typedef * eccBank)1567 static void mscEccReadWriteExistingPio(const MSC_EccBank_Typedef *eccBank)
1568 {
1569   volatile uint32_t *ramptr = (volatile uint32_t *) eccBank->base;
1570   const uint32_t *endptr = (const uint32_t *) (eccBank->base + eccBank->size);
1571   volatile uint32_t *ctrlreg;
1572   uint32_t enableEcc;
1573 
1574 #if defined(DMEM_COUNT) && (DMEM_COUNT == 2)
1575   if (eccBank->base == ECC_RAM0_MEM_BASE) {
1576     ctrlreg = &ECC_CTRL0_REG;
1577   } else if (eccBank->base == ECC_RAM1_MEM_BASE) {
1578     ctrlreg = &ECC_CTRL1_REG;
1579   } else {
1580     EFM_ASSERT(0);
1581     return;
1582   }
1583 #else
1584   ctrlreg = &ECC_CTRL_REG;
1585 #endif /* defined(DMEM_COUNT) && (DMEM_COUNT == 2) */
1586 
1587   EFM_ASSERT(ramptr < endptr);
1588 
1589 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
1590   enableEcc = eccBank->initSyndromeEnable;
1591 #elif defined(_MPAHBRAM_CTRL_MASK)
1592   /* MPAHBRAM ECC requires both ECCEN and ECCWEN to be set for the syndromes
1593      to be written in ECC */
1594   enableEcc = eccBank->correctionEnable;
1595 
1596   /* Enable ECC syndrome write */
1597 #if defined(DMEM_COUNT) && (DMEM_COUNT == 2)
1598   if (eccBank->base == ECC_RAM0_MEM_BASE) {
1599     ECC_CTRL0_REG |= eccBank->initSyndromeEnable;
1600     ECC_IFC0_REG = ECC_IFC_MASK;
1601   } else if (eccBank->base == ECC_RAM1_MEM_BASE) {
1602     ECC_CTRL1_REG |= eccBank->initSyndromeEnable;
1603     ECC_IFC1_REG = ECC_IFC_MASK;
1604   }
1605 #else
1606   ECC_CTRL_REG |= eccBank->initSyndromeEnable;
1607   ECC_IFC_REG = ECC_IFC_MASK;
1608 #endif /* defined(DMEM_COUNT) && (DMEM_COUNT == 2) */
1609 
1610 #endif
1611 
1612 #ifndef __GNUC__
1613 #define __asm__        asm
1614 #endif
1615 
1616   /*
1617    * Performs a read and write of all RAM address to initialize
1618    * ECC syndromes. ECC is initialized by reading a RAM address
1619    * while ECC is disabled and write it back while ECC is enabled.
1620    *
1621    * HardFault could occur if we try to read values from RAM while ECC
1622    * is enabled and not initialized. In this case, ECC tries to correct the
1623    * value and ended giving the wrong value which could be sometimes an
1624    * non-existing address.
1625    *
1626    * So for ECC initialization to work properly, this must ensures that while
1627    * ECC is enabled, RAM will be accessed only through writes, no reads shall
1628    * occur. It's hard to have such guarantee with C code, because the C
1629    * compiler with optimization settings, can get in the way
1630    * and do some unwanted reads while ECC is enabled. Assembly allows such
1631    * guarantee and let ECC be initialized without triggering errors.
1632    */
1633 
1634   __asm__ volatile (
1635     "1:\n\t"                         /* define label 1                       */
1636     "LDR r1, [%[ramptr]]\n\t"        /* load content of ramptr into R1, ECC
1637                                         is disabled to get a correct value   */
1638     "LDR r0, [%[ctrlreg]]\n\t"       /* load ctrlreg content into R0         */
1639     "ORR r0, r0, %[enableEcc]\n\t"     /* OR R0 and enableEcc, and store result
1640                                           in R0                                */
1641     "STR r0, [%[ctrlreg]]\n\t"       /* write R0 into ctrlreg, ECC is
1642                                         enabled from now on                  */
1643     "STR r1, [%[ramptr]]\n\t"        /* write back ram content where it was,
1644                                         syndrome will be written in ECC      */
1645     "BIC r0, r0, %[enableEcc]\n\t"     /* bit clear enableEcc from R0, and store
1646                                           result in R0                         */
1647     "STR r0, [%[ctrlreg]]\n\t"       /* write R0 into ctrlreg, ECC is
1648                                         disabled                             */
1649     "ADDS %[ramptr], %[ramptr], #4\n\t" /* increment ramptr by 4 (size of
1650                                            a word)                           */
1651     "CMP %[ramptr], %[endptr]\n\t"   /* compare ramptr and endptr...         */
1652     "BCC 1b\n\t"                     /* ... and jump back to label 1 if Carrry
1653                                         Clear (meaning ramptr < endptr)      */
1654     "ORR r0, r0, %[enableEcc]\n\t"     /* and re-enable ECC ASAP to be sure no */
1655     "STR r0, [%[ctrlreg]]\n\t"       /* STR occurs with ECC disabled         */
1656     :[ramptr] "+r" (ramptr)
1657     :[endptr] "r" (endptr),
1658     [ctrlreg] "r" (ctrlreg),
1659     [enableEcc] "r" (enableEcc)
1660     : "r0", "r1", /* R0  and R1 used as temporary registers */
1661     "memory"      /* Memory pointed by ramptr is modified   */
1662     );
1663 }
1664 
1665 #else
1666 
1667 /***************************************************************************//**
1668  * @brief
1669  *    DMA read and write existing values (for ECC initialization).
1670  *
1671  * @details
1672  *    This function uses DMA to read and write the existing data values in
1673  *    the RAM region specified by start and size. The function will use the
1674  *    2 DMA channels specified by the channels[2] array.
1675  *
1676  * @param[in] start
1677  *    Start address of address range in RAM to read/write.
1678  *
1679  * @param[in] size
1680  *    Size of address range in RAM to read/write.
1681  *
1682  * @param[in] channels[2]
1683  *    Array of 2 DMA channels to use.
1684  ******************************************************************************/
1685 static void mscEccReadWriteExistingDma(uint32_t start,
1686                                        uint32_t size,
1687                                        uint32_t channels[2])
1688 {
1689   uint32_t descCnt = 0;
1690   volatile uint32_t dmaDesc[ECC_DMA_DESCS][4];
1691   uint32_t chMask = (1 << channels[0]) | (1 << channels[1]);
1692   /* Assert that the 2 DMA channel numbers are different. */
1693   EFM_ASSERT(channels[0] != channels[1]);
1694 
1695   /* Make sure ECC_RAM_SIZE_MAX is a multiple of ECC_DMA_DESC_SIZE in order
1696      to match the total xfer size of the descriptor chain with the largest
1697      ECC RAM bank. */
1698   EFM_ASSERT((ECC_RAM_SIZE_MAX % ECC_DMA_DESC_SIZE) == 0);
1699 
1700   /* Initialize LDMA descriptor chain. */
1701   do {
1702     dmaDesc[descCnt][0] =                 /* DMA desc CTRL word */
1703                           LDMA_CH_CTRL_STRUCTTYPE_TRANSFER
1704                           | LDMA_CH_CTRL_STRUCTREQ
1705                           | _LDMA_CH_CTRL_XFERCNT_MASK
1706                           | LDMA_CH_CTRL_BLOCKSIZE_ALL
1707                           | LDMA_CH_CTRL_REQMODE_ALL
1708                           | LDMA_CH_CTRL_SRCINC_ONE
1709                           | LDMA_CH_CTRL_SIZE_WORD
1710                           | LDMA_CH_CTRL_DSTINC_ONE;
1711 
1712     /* source and destination address */
1713     dmaDesc[descCnt][1] = start;
1714     dmaDesc[descCnt][2] = start;
1715     /* link to next descriptor */
1716     dmaDesc[descCnt][3] = LDMA_CH_LINK_LINK
1717                           | (((uint32_t) &dmaDesc[descCnt + 1][0])
1718                              & _LDMA_CH_LINK_LINKADDR_MASK);
1719 
1720     start += ECC_DMA_DESC_SIZE;
1721     size  -= ECC_DMA_DESC_SIZE;
1722     descCnt++;
1723   } while (size);
1724 
1725   /* Make sure descCnt is valid to avoid out-of-bounds access when writing to
1726      dmaDesc array. */
1727   if ((descCnt < 2) || (descCnt > ECC_DMA_DESCS)) {
1728     while (true) {
1729       EFM_ASSERT(false);
1730     }
1731   }
1732 
1733   /* Now, divide the descriptor list in two parts, one for each channel,
1734      by setting the link bit and address 0 of the descriptor in the middle
1735      to 0. */
1736   dmaDesc[(descCnt / 2) - 1][3] = 0;
1737 
1738   /* Set last descriptor link bit and address to 0. */
1739   dmaDesc[descCnt - 1][3] = 0;
1740 
1741 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1742   /* Start the LDMA clock now */
1743   CMU_ClockEnable(cmuClock_LDMA, true);
1744 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1745   CMU_ClockEnable(cmuClock_LDMAXBAR, true);
1746 #endif
1747 #endif
1748   /* Round robin scheduling for all channels (0 = no fixed priority channels).
1749    */
1750   LDMA->CTRL    = 0 << _LDMA_CTRL_NUMFIXED_SHIFT;
1751 #if defined(LDMA_EN_EN)
1752   LDMA->EN      = LDMA_EN_EN;
1753 #endif
1754   LDMA->CHEN    = 0;
1755   LDMA->DBGHALT = 0;
1756   LDMA->REQDIS  = 0;
1757 
1758   /* Disable LDMA interrupts, and clear interrupt status. */
1759   LDMA->IEN = 0;
1760 #if defined (LDMA_HAS_SET_CLEAR)
1761   LDMA->IF_CLR = chMask;
1762 #else
1763   LDMA->IFC = chMask;
1764 #endif
1765 
1766   /* Disable looping */
1767   LDMA->CH[channels[0]].LOOP = 0;
1768   LDMA->CH[channels[1]].LOOP = 0;
1769 
1770   /* Set descriptor address for first channel. */
1771   LDMA->CH[channels[0]].LINK = ((uint32_t)&dmaDesc[0][0])
1772                                & _LDMA_CH_LINK_LINKADDR_MASK;
1773   /* Set descriptor address for second channel. */
1774   LDMA->CH[channels[1]].LINK = ((uint32_t)&dmaDesc[descCnt / 2][0])
1775                                & _LDMA_CH_LINK_LINKADDR_MASK;
1776   /* Clear the channel done flags.  */
1777   BUS_RegMaskedClear(&LDMA->CHDONE, chMask);
1778 
1779   /* Start transfer by loading descriptors.  */
1780   LDMA->LINKLOAD = chMask;
1781 
1782   /* Wait until finished. */
1783   while (!(
1784 #if defined(_LDMA_CHSTATUS_MASK)
1785            ((LDMA->CHSTATUS & chMask) == 0)
1786 #else
1787            ((LDMA->CHEN & chMask) == 0)
1788 #endif
1789            && ((LDMA->CHDONE & chMask) == chMask))) {
1790   }
1791 
1792 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1793   /* Stop the LDMA clock now */
1794   CMU_ClockEnable(cmuClock_LDMA, false);
1795 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1796   CMU_ClockEnable(cmuClock_LDMAXBAR, false);
1797 #endif
1798 #endif
1799 }
1800 #endif // #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) || defined(_MPAHBRAM_CTRL_MASK)
1801 
1802 /***************************************************************************//**
1803  * @brief
1804  *    Initialize ECC for a given memory bank.
1805  *
1806  * @brief
1807  *    This function initializes ECC for a given memory bank which is specified
1808  *    with the MSC_EccBank_Typedef structure input parameter.
1809  *
1810  * @param[in] eccBank
1811  *    ECC memory bank device structure.
1812  *
1813  * @param[in] dmaChannels
1814  *    Array of 2 DMA channels that may be used during ECC initialization.
1815  *
1816  ******************************************************************************/
mscEccBankInit(const MSC_EccBank_Typedef * eccBank,uint32_t dmaChannels[2])1817 static void mscEccBankInit(const MSC_EccBank_Typedef *eccBank,
1818                            uint32_t dmaChannels[2])
1819 {
1820   CORE_DECLARE_IRQ_STATE;
1821 
1822   CORE_ENTER_CRITICAL();
1823 
1824 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)  \
1825   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7) \
1826   || defined(_MPAHBRAM_CTRL_MASK)
1827   (void) dmaChannels;
1828 #if !defined(_MPAHBRAM_CTRL_MASK)
1829   /* Disable ECC write */
1830   ECC_CTRL_REG &= ~eccBank->initSyndromeEnable;
1831 #endif
1832   /* Initialize ECC syndromes by using core cpu to load and store the existing
1833      data values in RAM. */
1834   mscEccReadWriteExistingPio(eccBank);
1835 #else
1836   /* Enable ECC write */
1837   ECC_CTRL_REG |= eccBank->initSyndromeEnable;
1838   /* Initialize ECC syndromes by using DMA to read and write the existing
1839      data values in RAM. */
1840   mscEccReadWriteExistingDma(eccBank->base, eccBank->size, dmaChannels);
1841 #endif
1842 
1843   /* Clear any ECC errors that may have been reported before or during
1844      initialization. */
1845 #if defined(DMEM_COUNT) && (DMEM_COUNT == 2)
1846   if (eccBank->base == ECC_RAM0_MEM_BASE) {
1847     ECC_IFC0_REG = ECC_IFC_MASK;
1848   } else if (eccBank->base == ECC_RAM1_MEM_BASE) {
1849     ECC_IFC1_REG = ECC_IFC_MASK;
1850   }
1851 #else
1852   ECC_IFC_REG = ECC_IFC_MASK;
1853 #endif /* defined(DMEM_COUNT) && (DMEM_COUNT == 2) */
1854 
1855 #if !defined(_MPAHBRAM_CTRL_MASK)
1856   /* Enable ECC decoder to detect and report ECC errors. */
1857   ECC_CTRL_REG |= eccBank->correctionEnable;
1858 #endif
1859 
1860   CORE_EXIT_CRITICAL();
1861 }
1862 
1863 /***************************************************************************//**
1864  * @brief
1865  *    Disable ECC for a given memory bank.
1866  *
1867  * @brief
1868  *    This function disables ECC for a given memory bank which is specified
1869  *    with the MSC_EccBank_Typedef structure input parameter.
1870  *
1871  * @param[in] eccBank
1872  *    ECC memory bank device structure.
1873  *
1874  ******************************************************************************/
mscEccBankDisable(const MSC_EccBank_Typedef * eccBank)1875 static void mscEccBankDisable(const MSC_EccBank_Typedef *eccBank)
1876 {
1877   /* Disable ECC write (encoder) and checking (decoder). */
1878 #if defined(DMEM_COUNT) && (DMEM_COUNT == 2)
1879   if (eccBank->base == ECC_RAM0_MEM_BASE) {
1880     ECC_CTRL0_REG &= ~(eccBank->initSyndromeEnable | eccBank->correctionEnable);
1881   } else if (eccBank->base == ECC_RAM1_MEM_BASE) {
1882     ECC_CTRL1_REG &= ~(eccBank->initSyndromeEnable | eccBank->correctionEnable);
1883   }
1884 #else
1885   ECC_CTRL_REG &= ~(eccBank->initSyndromeEnable | eccBank->correctionEnable);
1886 #endif /* defined(DMEM_COUNT) && (DMEM_COUNT == 2) */
1887 }
1888 
1889 /***************************************************************************//**
1890  * @brief
1891  *   Configure Error Correcting Code (ECC).
1892  *
1893  * @details
1894  *   This function configures ECC support according to the configuration
1895  *   input parameter. If the user requests enabling ECC for a given RAM bank
1896  *   this function will initialize ECC memory (syndromes) for the bank by
1897  *   reading and writing the existing values in memory. I.e. all data is
1898  *   preserved. The initialization process runs in a critical section
1899  *   disallowing interrupts and thread scheduling, and will consume a
1900  *   considerable amount of clock cycles. Therefore the user should carefully
1901  *   assess where to call this function. The user can consider to increase
1902  *   the clock frequency in order to reduce the execution time.
1903  *   This function makes use of 2 DMA channels to move data to/from RAM in an
1904  *   efficient way. The user can select which 2 DMA channels to use in order
1905  *   to avoid conflicts with the application. However the user must make sure
1906  *   that no other DMA operations takes place while this function is executing.
1907  *   If the application has been using the DMA controller prior to calling this
1908  *   function, the application will need to reinitialize DMA registers after
1909  *   this function has completed.
1910  *
1911  * @note
1912  *   This function protects the ECC initialization procedure from interrupts
1913  *   and other threads by using a critical section (defined by em_core.h)
1914  *   When running on RTOS the user may need to override CORE_EnterCritical
1915  *   CORE_ExitCritical which are declared as 'SL_WEAK' in em_core.c.
1916  *
1917  * @param[in] eccConfig
1918  *   ECC configuration
1919  ******************************************************************************/
MSC_EccConfigSet(MSC_EccConfig_TypeDef * eccConfig)1920 void MSC_EccConfigSet(MSC_EccConfig_TypeDef *eccConfig)
1921 {
1922   unsigned int cnt;
1923 #if defined(ECC_FAULT_CTRL_REG)
1924   uint32_t faultCtrlReg = ECC_FAULT_CTRL_REG;
1925   /* Disable ECC faults if ecc fault ctrl register is defined. */
1926   faultCtrlReg &= ~ECC_FAULT_EN;
1927   ECC_FAULT_CTRL_REG = faultCtrlReg;
1928 #endif
1929 
1930   /* Loop through the ECC banks array, enable or disable according to
1931      the eccConfig->enableEccBank array. */
1932   for (cnt = 0; cnt < MSC_ECC_BANKS; cnt++) {
1933     if (eccConfig->enableEccBank[cnt]) {
1934       mscEccBankInit(&eccBankTbl[cnt], eccConfig->dmaChannels);
1935     } else {
1936       mscEccBankDisable(&eccBankTbl[cnt]);
1937     }
1938   }
1939 
1940 #if defined(ECC_FAULT_CTRL_REG) && !defined(_SILICON_LABS_32B_SERIES_1_CONFIG_1)
1941   /*
1942    * Enable ECC faults if ecc fault ctrl register is set.
1943    * On Series 1 Config 1, aka EFM32GG11, ECC faults should stay disabled.
1944    * Reload register first, in case it was modified and/or shared by bank
1945    * init functions.
1946    */
1947   faultCtrlReg = ECC_FAULT_CTRL_REG;
1948   faultCtrlReg |= ECC_FAULT_EN;
1949   ECC_FAULT_CTRL_REG = faultCtrlReg;
1950 #endif
1951 }
1952 
1953 #endif /* #if defined(_MSC_ECCCTRL_MASK) */
1954 
1955 #if defined(_SYSCFG_DMEM0PORTMAPSEL_MASK)
1956 /***************************************************************************//**
1957  * @brief
1958  *   Set MPAHBRAM port to use to access DMEM.
1959  *
1960  * @details
1961  *   This function configures which MPAHBRAM slave port is used to access DMEM.
1962  *   Depending on the use case, it might improve performance by spreading the
1963  *   load over the N ports (N is usually 2 or 4), instead of starving because a
1964  *   port is used by another master.
1965  *
1966  * @param[in] master
1967  *   AHBHOST master to be configured.
1968  * @param[in] port
1969  *   AHBHOST slave port to use.
1970  ******************************************************************************/
MSC_DmemPortMapSet(MSC_DmemMaster_TypeDef master,uint8_t port)1971 void MSC_DmemPortMapSet(MSC_DmemMaster_TypeDef master, uint8_t port)
1972 {
1973 #if defined(DMEM_COUNT) && (DMEM_COUNT == 1)
1974   uint32_t bitfieldMask = DMEM_NUM_PORTS - 1;
1975 #elif defined(DMEM_COUNT) && (DMEM_COUNT == 2)
1976   uint32_t bitfieldMask = DMEM0_NUM_PORTS - 1;
1977 #endif
1978 
1979   /* make sure master is within the mask of port map that can be changed
1980    * make sure port is a sensible value
1981    */
1982   EFM_ASSERT(((1 << master) & _SYSCFG_DMEM0PORTMAPSEL_MASK) != 0x0);
1983 
1984 #if defined(DMEM_COUNT) && (DMEM_COUNT == 1)
1985   EFM_ASSERT(port < DMEM_NUM_PORTS);
1986 #elif defined(DMEM_COUNT) && (DMEM_COUNT == 2)
1987   EFM_ASSERT(port < DMEM0_NUM_PORTS);
1988 #endif
1989 
1990 #if defined(CMU_CLKEN0_SYSCFG)
1991   bool disableSyscfgClk = false;
1992 
1993   if (!(CMU->CLKEN0 & _CMU_CLKEN0_SYSCFG_MASK)) {
1994     disableSyscfgClk = true;
1995     CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1996   }
1997 #endif
1998 
1999   BUS_RegMaskedWrite(&SYSCFG->DMEM0PORTMAPSEL,
2000                      bitfieldMask << master,
2001                      (uint32_t)port << master);
2002 
2003 #if defined(CMU_CLKEN0_SYSCFG)
2004   if (disableSyscfgClk) {
2005     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
2006   }
2007 #endif
2008 }
2009 #endif
2010 
2011 #if defined(_MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK)
2012 /***************************************************************************//**
2013  * @brief
2014  *   Set MPAHBRAM port priority for arbitration when multiple concurrent
2015  *   transactions to DMEM.
2016  *
2017  * @details
2018  *   This function configures which MPAHBRAM slave port will have priority.
2019  *   The AHB port arbitration default scheme, round-robin arbitration, is
2020  *   selected when portPriority == mscPortPriorityNone.
2021  *
2022  * @note
2023  *   Doing this can potentially starve the others AHB port(s).
2024  *
2025  * @param[in] portPriority
2026  *   AHBHOST slave port having elevated priority.
2027  ******************************************************************************/
MSC_PortSetPriority(MSC_PortPriority_TypeDef portPriority)2028 void MSC_PortSetPriority(MSC_PortPriority_TypeDef portPriority)
2029 {
2030 #if defined(DMEM_COUNT) && (DMEM_COUNT == 1)
2031   EFM_ASSERT(portPriority < ((DMEM_NUM_PORTS + 1) << _MPAHBRAM_CTRL_AHBPORTPRIORITY_SHIFT));
2032 
2033   BUS_RegMaskedWrite(&DMEM->CTRL,
2034                      _MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK,
2035                      (uint32_t)portPriority << _MPAHBRAM_CTRL_AHBPORTPRIORITY_SHIFT);
2036 #elif defined(DMEM_COUNT) && (DMEM_COUNT == 2)
2037   EFM_ASSERT(portPriority < ((DMEM0_NUM_PORTS + 1) << _MPAHBRAM_CTRL_AHBPORTPRIORITY_SHIFT));
2038 
2039   BUS_RegMaskedWrite(&DMEM0->CTRL,
2040                      _MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK,
2041                      (uint32_t)portPriority << _MPAHBRAM_CTRL_AHBPORTPRIORITY_SHIFT);
2042   BUS_RegMaskedWrite(&DMEM1->CTRL,
2043                      _MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK,
2044                      (uint32_t)portPriority << _MPAHBRAM_CTRL_AHBPORTPRIORITY_SHIFT);
2045 #endif
2046 }
2047 
2048 /***************************************************************************//**
2049  * @brief
2050  *   Get MPAHBRAM port arbitration priority selection.
2051  *
2052  * @details
2053  *   This function returns the AHBHOST slave with raised priority.
2054  *
2055  * @return
2056  *   Returns the AHBHOST slave port given priority or none.
2057  ******************************************************************************/
MSC_PortGetCurrentPriority(void)2058 MSC_PortPriority_TypeDef MSC_PortGetCurrentPriority(void)
2059 {
2060   uint32_t port = 0;
2061 
2062 #if defined(DMEM_COUNT) && (DMEM_COUNT == 1)
2063   port = BUS_RegMaskedRead(&DMEM->CTRL,
2064                            _MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK);
2065 #elif defined(DMEM_COUNT) && (DMEM_COUNT == 2)
2066   port = BUS_RegMaskedRead(&DMEM0->CTRL,
2067                            _MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK);
2068 #endif
2069 
2070   return (MSC_PortPriority_TypeDef)(port >> _MPAHBRAM_CTRL_AHBPORTPRIORITY_SHIFT);
2071 }
2072 #endif /* if defined(_MPAHBRAM_CTRL_AHBPORTPRIORITY_MASK) */
2073 
2074 /** @} (end addtogroup msc) */
2075 #endif /* defined(MSC_COUNT) && (MSC_COUNT > 0) */
2076