1 /***************************************************************************//**
2  * @file
3  * @brief Chip Errata Workarounds
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 #ifndef EM_CHIP_H
32 #define EM_CHIP_H
33 
34 #include "em_device.h"
35 #include "sl_common.h"
36 #if defined(_SILICON_LABS_32B_SERIES) && (_SILICON_LABS_32B_SERIES <= 2)
37 #include "em_system.h"
38 #endif
39 #include "em_bus.h"
40 
41 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
42 #include "em_gpio.h"
43 #endif
44 
45 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_240)
46 #include "em_cmu.h"
47 #endif
48 
49 #ifdef __cplusplus
50 extern "C" {
51 #endif
52 
53 /***************************************************************************//**
54  * @addtogroup chip CHIP - Chip Errata Workarounds
55  * @brief Chip errata workaround APIs
56  * @details
57  *  API to apply chip errata workarounds at initialization and reset.
58  * @{
59  ******************************************************************************/
60 
61 /**************************************************************************//**
62  * @brief
63  *   Chip initialization routine for revision errata workarounds.
64  *
65  * @note
66  *   This function must be called immediately in main().
67  *
68  * This initialization function configures the device to a state
69  * as similar to later revisions as possible to improve software compatibility
70  * with newer parts. See the device-specific errata for details.
71  *****************************************************************************/
CHIP_Init(void)72 __STATIC_INLINE void CHIP_Init(void)
73 {
74 #if defined(MSC_CACHECMD_INVCACHE)
75   MSC->CACHECMD = MSC_CACHECMD_INVCACHE;
76 #elif defined(MSC_CMD_INVCACHE)
77   MSC->CMD = MSC_CMD_INVCACHE;
78 #endif
79 
80 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GECKO_FAMILY)
81   uint32_t                    rev;
82   SYSTEM_ChipRevision_TypeDef chipRev;
83   volatile uint32_t           *reg;
84 
85   rev = *(volatile uint32_t *)(0x0FE081FC);
86   /* Engineering Sample calibration setup. */
87   if ((rev >> 24) == 0) {
88     reg   = (volatile uint32_t *)0x400CA00C;
89     *reg &= ~(0x70UL);
90     /* DREG */
91     reg   = (volatile uint32_t *)0x400C6020;
92     *reg &= ~(0xE0000000UL);
93     *reg |= ~(7UL << 25);
94   }
95   if ((rev >> 24) <= 3) {
96     /* DREG */
97     reg   = (volatile uint32_t *)0x400C6020;
98     *reg &= ~(0x00001F80UL);
99     /* Update CMU reset values. */
100     reg  = (volatile uint32_t *)0x400C8040;
101     *reg = 0;
102     reg  = (volatile uint32_t *)0x400C8044;
103     *reg = 0;
104     reg  = (volatile uint32_t *)0x400C8058;
105     *reg = 0;
106     reg  = (volatile uint32_t *)0x400C8060;
107     *reg = 0;
108     reg  = (volatile uint32_t *)0x400C8078;
109     *reg = 0;
110   }
111 
112   SYSTEM_ChipRevisionGet(&chipRev);
113   if (chipRev.major == 0x01) {
114     /* Rev A errata handling for EM2/3. Must enable DMA clock to get EM2/3 */
115     /* to work. This will be fixed in later chip revisions and is only needed for rev A. */
116     if (chipRev.minor == 00) {
117       reg   = (volatile uint32_t *)0x400C8040;
118       *reg |= 0x2;
119     }
120 
121     /* Rev A+B errata handling for I2C when using EM2/3. USART0 clock must be enabled */
122     /* after waking up from EM2/EM3 to get I2C to work. This will be fixed in */
123     /* later chip revisions and is only needed for rev A+B. */
124     if (chipRev.minor <= 0x01) {
125       reg   = (volatile uint32_t *)0x400C8044;
126       *reg |= 0x1;
127     }
128   }
129   /* Ensure correct ADC/DAC calibration value. */
130   rev = *(volatile uint32_t *)0x0FE081F0;
131   if (rev < 0x4C8ABA00) {
132     uint32_t cal;
133 
134     /* Enable ADC/DAC clocks. */
135     reg   = (volatile uint32_t *)0x400C8044UL;
136     *reg |= (1 << 14 | 1 << 11);
137 
138     /* Retrive calibration values. */
139     cal = ((*(volatile uint32_t *)(0x0FE081B4UL) & 0x00007F00UL)
140            >> 8) << 24;
141 
142     cal |= ((*(volatile uint32_t *)(0x0FE081B4UL) & 0x0000007FUL)
143             >> 0) << 16;
144 
145     cal |= ((*(volatile uint32_t *)(0x0FE081B4UL) & 0x00007F00UL)
146             >> 8) << 8;
147 
148     cal |= ((*(volatile uint32_t *)(0x0FE081B4UL) & 0x0000007FUL)
149             >> 0) << 0;
150 
151     /* ADC0->CAL = 1.25 reference. */
152     reg  = (volatile uint32_t *)0x40002034UL;
153     *reg = cal;
154 
155     /* DAC0->CAL = 1.25 reference. */
156     reg  = (volatile uint32_t *)(0x4000402CUL);
157     cal  = *(volatile uint32_t *)0x0FE081C8UL;
158     *reg = cal;
159 
160     /* Turn off ADC/DAC clocks. */
161     reg   = (volatile uint32_t *)0x400C8044UL;
162     *reg &= ~(1 << 14 | 1 << 11);
163   }
164 #endif
165 
166 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GIANT_FAMILY)
167 
168   /****************************/
169   /* Fix for errata CMU_E113. */
170 
171   uint8_t                     prodRev;
172   SYSTEM_ChipRevision_TypeDef chipRev;
173 
174   prodRev = SYSTEM_GetProdRev();
175   SYSTEM_ChipRevisionGet(&chipRev);
176 
177   // All Giant and Leopard parts except Leopard Rev E
178   if ((prodRev >= 16) && (chipRev.minor >= 3)
179       && !((chipRev.major == 2) && (chipRev.minor == 4))) {
180     /* This fixes an issue with the LFXO on high temperatures. */
181     *(volatile uint32_t*)0x400C80C0 =
182       (*(volatile uint32_t*)0x400C80C0 & ~(1 << 6) ) | (1 << 4);
183   }
184 #endif
185 
186 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_HAPPY_FAMILY)
187 
188   uint8_t prodRev;
189   prodRev = SYSTEM_GetProdRev();
190 
191   if (prodRev <= 129) {
192     /* This fixes a mistaken internal connection between PC0 and PC4. */
193     /* This disables an internal pull-down on PC4. */
194     *(volatile uint32_t*)(0x400C6018) = (1 << 26) | (5 << 0);
195     /* This disables an internal LDO test signal driving PC4. */
196     *(volatile uint32_t*)(0x400C80E4) &= ~(1 << 24);
197   }
198 #endif
199 
200 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
201 
202   /****************************
203    * Fixes for errata GPIO_E201 (slewrate) and
204    * HFXO high-temperature oscillator startup robustness fix. */
205 
206   uint32_t port;
207   uint32_t clkEn;
208   uint8_t prodRev;
209   const uint32_t setVal   = (0x5 << _GPIO_P_CTRL_SLEWRATEALT_SHIFT)
210                             | (0x5 << _GPIO_P_CTRL_SLEWRATE_SHIFT);
211   const uint32_t resetVal = _GPIO_P_CTRL_RESETVALUE
212                             & ~(_GPIO_P_CTRL_SLEWRATE_MASK
213                                 | _GPIO_P_CTRL_SLEWRATEALT_MASK);
214 
215   prodRev = SYSTEM_GetProdRev();
216   SYSTEM_ChipRevision_TypeDef chipRev;
217   SYSTEM_ChipRevisionGet(&chipRev);
218 
219   /* This errata is fixed in hardware from PRODREV 0x8F. */
220   if (prodRev < 0x8F) {
221     /* Fixes for errata GPIO_E201 (slewrate). */
222 
223     /* Save HFBUSCLK enable state and enable GPIO clock. */
224     clkEn = CMU->HFBUSCLKEN0;
225     CMU->HFBUSCLKEN0 = clkEn | CMU_HFBUSCLKEN0_GPIO;
226 
227     /* Update slewrate. */
228     for (port = 0; port <= GPIO_PORT_MAX; port++) {
229       GPIO->P[port].CTRL = setVal | resetVal;
230     }
231 
232     /* Restore HFBUSCLK enable state. */
233     CMU->HFBUSCLKEN0 = clkEn;
234   }
235 
236   /* This errata is fixed in hardware from PRODREV 0x90. */
237   if (prodRev < 0x90) {
238     /* HFXO high-temperature oscillator startup robustness fix. */
239     CMU->HFXOSTARTUPCTRL =
240       (CMU->HFXOSTARTUPCTRL & ~_CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_MASK)
241       | (0x20 << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT);
242   }
243 
244   if (chipRev.major == 0x01) {
245     /* Fix for errata EMU_E210 - Potential Power-Down When Entering EM2 */
246     *(volatile uint32_t *)(EMU_BASE + 0x164) |= 0x4;
247   }
248 
249   /****************************
250    * Fix for errata DCDC_E206.
251    * Disable bypass limit enabled temporarily in SystemInit() errata
252    * workaround. */
253   BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, 0);
254 #endif
255 
256 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)
257 
258   uint8_t prodRev = SYSTEM_GetProdRev();
259 
260   /* EM2 current fixes for early samples. */
261   if (prodRev == 0U) {
262     *(volatile uint32_t *)(EMU_BASE + 0x190UL)  = 0x0000ADE8UL;
263     *(volatile uint32_t *)(EMU_BASE + 0x198UL) |= (0x1UL << 2);
264     *(volatile uint32_t *)(EMU_BASE + 0x190UL)  = 0x0;
265   }
266   if (prodRev < 2U) {
267     *(volatile uint32_t *)(EMU_BASE + 0x164UL) |= (0x1UL << 13);
268   }
269 
270   /* Set optimal LFRCOCTRL VREFUPDATE and enable duty cycling of VREF. */
271   CMU->LFRCOCTRL = (CMU->LFRCOCTRL & ~_CMU_LFRCOCTRL_VREFUPDATE_MASK)
272                    | CMU_LFRCOCTRL_VREFUPDATE_64CYCLES
273                    | CMU_LFRCOCTRL_ENVREF;
274 #endif
275 
276 #if defined(_SILICON_LABS_32B_SERIES_1) \
277   && defined(_EFR_DEVICE) && (_SILICON_LABS_GECKO_INTERNAL_SDID >= 84)
278   MSC->CTRL |= 0x1UL << 8;
279 #endif
280 
281 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89)
282   SYSTEM_ChipRevision_TypeDef chipRev;
283   SYSTEM_ChipRevisionGet(&chipRev);
284 
285   if ((chipRev.major > 1) || (chipRev.minor >= 3)) {
286     /* PLFRCO trim values */
287     *(volatile uint32_t *)(CMU_BASE + 0x28CUL) = 608;
288     *(volatile uint32_t *)(CMU_BASE + 0x290UL) = 356250;
289     *(volatile uint32_t *)(CMU_BASE + 0x2F0UL) = 0x04000118;
290     *(volatile uint32_t *)(CMU_BASE + 0x2F8UL) = 0x08328400;
291   }
292 #endif
293 
294 /* Charge redist setup (fixed value): LCD->DBGCTRL.CHGRDSTSTR = 1 (reset: 0). */
295 #if defined(_LCD_DISPCTRL_CHGRDST_MASK)
296 #if defined(_SILICON_LABS_32B_SERIES_1)
297   CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_LE;
298   CMU->LFACLKEN0   |= CMU_LFACLKEN0_LCD;
299   *(volatile uint32_t *)(LCD_BASE + 0x034) |= (0x1UL << 12);
300   CMU->LFACLKEN0   &= ~CMU_LFACLKEN0_LCD;
301   CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_LE;
302 #endif
303 #endif
304 
305 #if defined(_SILICON_LABS_32B_SERIES_1)             \
306   && !defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) \
307   && !defined(ERRATA_FIX_EMU_E220_DECBOD_IGNORE)
308   /* First part of the EMU_E220 DECBOD Errata fix. DECBOD Reset can occur
309    * during voltage scaling after EM2/3 wakeup. Second part is in em_emu.c */
310   *(volatile uint32_t *)(EMU_BASE + 0x1A4) |= 0x1f << 10;
311 #endif
312 
313 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
314   SYSTEM_ChipRevision_TypeDef chipRev;
315   SYSTEM_ChipRevisionGet(&chipRev);
316 
317   if (chipRev.major == 0x01 && (HFXO0->STATUS & HFXO_STATUS_ENS) == 0U) {
318     /* Change HFXO default peak detector settings. */
319     *(volatile uint32_t*)(HFXO0_BASE + 0x34U) =
320       (*(volatile uint32_t*)(HFXO0_BASE + 0x34U) & 0xFF8000FFU)
321       | 0x00178500U;
322     /* Change HFXO low power control settings. */
323     *(volatile uint32_t*)(HFXO0_BASE + 0x30U) =
324       (*(volatile uint32_t*)(HFXO0_BASE + 0x30U) & 0xFFFF0FFFU)
325       | 0x0000C000U;
326     /* Change default SQBUF bias current. */
327     *(volatile uint32_t*)(HFXO0_BASE + 0x30U) |= 0x700;
328   }
329 
330   if (chipRev.major == 0x01 && chipRev.minor == 0x0) {
331     /* Trigger RAM read for each RAM instance */
332     volatile uint32_t *dmem = (volatile uint32_t *) DMEM_RAM0_RAM_MEM_BASE;
333     for (uint32_t i = 0U; i < DMEM_NUM_BANK; i++) {
334       // Force memory read
335       *dmem;
336       dmem += (DMEM_BANK0_SIZE / 4U);
337     }
338   }
339 
340   /* Set TRACE clock to intended reset value. */
341   CMU->TRACECLKCTRL = (CMU->TRACECLKCTRL & ~_CMU_TRACECLKCTRL_CLKSEL_MASK)
342                       | CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23;
343 #endif
344 
345 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205)
346 #if defined(SL_TRUSTZONE_SECURE)
347 #define HFRCO_CLK_CFG_CLR_ADDR (0x40012020UL)
348 #else
349 #define HFRCO_CLK_CFG_CLR_ADDR (0x50012020UL)
350 #endif
351 #define HFRCO_CLK_CFG_CLKOUTDIS0 (0x4UL)
352   if (SYSTEM_GetProdRev() == 1) {
353     bool hfrcoClkIsOff = (CMU->CLKEN0 & CMU_CLKEN0_HFRCO0) == 0;
354     CMU->CLKEN0_SET = CMU_CLKEN0_HFRCO0;
355     /* Enable HFRCO CLKOUT0. */
356     *(volatile uint32_t*)(HFRCO_CLK_CFG_CLR_ADDR) = HFRCO_CLK_CFG_CLKOUTDIS0;
357     if (hfrcoClkIsOff) {
358       CMU->CLKEN0_CLR = CMU_CLKEN0_HFRCO0;
359     }
360   }
361 #endif
362 
363 /* PM-3503 */
364 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_210)
365   {
366     bool syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
367     CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
368 
369     bool dcdcClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) == 0);
370     CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
371 
372     bool dcdcIsLock = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK_LOCKED) != 0);
373     DCDC->LOCK = DCDC_LOCK_LOCKKEY_UNLOCKKEY;
374 
375     while (DCDC->SYNCBUSY & DCDC_SYNCBUSY_CTRL) {
376       /* Wait for previous synchronization to finish */
377     }
378 
379     DCDC->CTRL_CLR = DCDC_CTRL_MODE;
380     while ((DCDC->STATUS & DCDC_STATUS_BYPSW) == 0U) {
381       /* Wait for BYPASS switch enable. */
382     }
383 
384     if (dcdcIsLock) {
385       DCDC->LOCK = ~DCDC_LOCK_LOCKKEY_UNLOCKKEY;
386     }
387 
388     if (dcdcClkIsOff) {
389       CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
390     }
391 
392     if (syscfgClkIsOff) {
393       CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
394     }
395   }
396 #endif
397 
398 /* PM-5163 */
399 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_215)    \
400   && defined(_SILICON_LABS_EFR32_2G4HZ_HP_PA_PRESENT) \
401   && (_SILICON_LABS_EFR32_2G4HZ_HP_PA_MAX_OUTPUT_DBM == 20)
402   SYSTEM_ChipRevision_TypeDef chipRev;
403   SYSTEM_ChipRevisionGet(&chipRev);
404 
405   if (chipRev.major == 0x01 && chipRev.minor == 0x00) {
406     bool hfxo0ClkIsOff = (CMU->CLKEN0 & CMU_CLKEN0_HFXO0) == 0;
407     CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
408 
409     *(volatile uint32_t*)(HFXO0_BASE + 0x0034UL) =
410       (*(volatile uint32_t*)(HFXO0_BASE + 0x0034UL) & 0xE3FFFFFFUL)
411       | 0x0C000000UL;
412 
413     if (hfxo0ClkIsOff) {
414       CMU->CLKEN0_CLR = CMU_CLKEN0_HFXO0;
415     }
416   }
417 #endif
418 
419 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_240)
420 
421   // Enable ICache out of reset.
422   CMU->CLKEN1_SET = _CMU_CLKEN1_ICACHE0_MASK;
423   ICACHE0->CTRL_CLR = _ICACHE_CTRL_CACHEDIS_MASK;
424   CMU->CLKEN1_CLR = _CMU_CLKEN1_ICACHE0_MASK;
425 
426   CMU->CLKEN0_SET = _CMU_CLKEN0_HFRCO0_MASK;
427 
428   if (((HFRCO0->CAL & _HFRCO_CAL_TUNING_MASK) >> _HFRCO_CAL_TUNING_SHIFT) == _HFRCO_CAL_TUNING_MASK) {
429     CMU_HFRCODPLLBandSet(cmuHFRCODPLLFreq_19M0Hz);
430   }
431 
432   CMU->CLKEN0_CLR = _CMU_CLKEN0_HFRCO0_MASK;
433 
434 #endif
435 }
436 
437 /**************************************************************************//**
438  * @brief
439  *   Chip reset routine with errata workarounds.
440  *
441  * @note
442  *   This function should be called to reset the chip. It does not return.
443  *
444  * This function applies any errata workarounds needed to cleanly reset the
445  * device and then performs a system reset. See the device-specific errata for
446  * details.
447  *****************************************************************************/
CHIP_Reset(void)448 __STATIC_INLINE void CHIP_Reset(void)
449 {
450 #if defined(_EFR_DEVICE) && defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
451   /****************************
452    * Workaround for errata DCDC_E206.
453    * Disable radio interference minimization features when resetting */
454 
455   // Ensure access to EMU registers
456   EMU->LOCK = EMU_LOCK_LOCKKEY_UNLOCK;
457   EMU->PWRLOCK = EMU_PWRLOCK_LOCKKEY_LOCK;
458 
459   // No need to do anything if the DCDC is not powering DVDD
460   if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) == EMU_PWRCFG_PWRCFG_DCDCTODVDD) {
461     // Make sure radio cannot accidentally re-enable features
462     *(volatile uint32_t *)(0x40084040UL) = 0x1UL;
463 
464     // If DCDC is in use, disable features
465     uint32_t dcdcMode = EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK;
466     if ((dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWNOISE)
467         || (dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWPOWER)) {
468       BUS_RegBitWrite((volatile uint32_t *)(0x400E3060UL), 28UL, 0);
469       BUS_RegBitWrite((volatile uint32_t *)(0x400E3074UL), 0, 0);
470     }
471   }
472 #endif
473 
474   NVIC_SystemReset();
475 }
476 
477 /** @} (end addtogroup chip) */
478 
479 #ifdef __cplusplus
480 }
481 #endif
482 
483 #endif /* EM_CHIP_H */
484