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