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