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