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