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