1 /***************************************************************************//**
2  * @file
3  * @brief System 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_system.h"
32 #include "sl_assert.h"
33 #include <stddef.h>
34 #if defined(SYSCFG_PRESENT)
35 #include "em_syscfg.h"
36 #endif
37 /***************************************************************************//**
38  * @addtogroup system
39  * @{
40  ******************************************************************************/
41 
42 /*******************************************************************************
43  *********************************   DEFINES   *********************************
44  ******************************************************************************/
45 
46 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
47 
48 /* Bit mask used to extract the part number value without the new naming
49  * bitfield. */
50 #define SYSCFG_CHIPREV_PARTNUMBER1  0xFE0
51 #define SYSCFG_CHIPREV_PARTNUMBER0  0xF
52 
53 /* Bit mask to convert NON-SECURE to SECURE */
54 #define CONVERT_NS_TO_S (~(1 << 28U))
55 
56 /** @endcond */
57 
58 /*******************************************************************************
59  **************************   GLOBAL FUNCTIONS   *******************************
60  ******************************************************************************/
61 
62 /***************************************************************************//**
63  * @brief
64  *   Get a chip major/minor revision.
65  *
66  * @param[out] rev
67  *   A location to place the chip revision information.
68  ******************************************************************************/
SYSTEM_ChipRevisionGet(SYSTEM_ChipRevision_TypeDef * rev)69 void SYSTEM_ChipRevisionGet(SYSTEM_ChipRevision_TypeDef *rev)
70 {
71 #if defined(_SYSCFG_CHIPREV_FAMILY_MASK) || defined(_SYSCFG_CHIPREV_PARTNUMBER_MASK)
72   /* On series-2 (and higher) the revision info is in the SYSCFG->CHIPREV register. */
73 #if defined(CMU_CLKEN0_SYSCFG)
74   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
75 #endif
76   uint32_t chiprev = SYSCFG_readChipRev();
77 #if defined(_SYSCFG_CHIPREV_PARTNUMBER_MASK)
78   rev->partNumber = ((chiprev & SYSCFG_CHIPREV_PARTNUMBER1) >> 5) | (chiprev & SYSCFG_CHIPREV_PARTNUMBER0);
79 #else
80   rev->family = (chiprev & _SYSCFG_CHIPREV_FAMILY_MASK) >> _SYSCFG_CHIPREV_FAMILY_SHIFT;
81 #endif
82   rev->major  = (chiprev & _SYSCFG_CHIPREV_MAJOR_MASK)  >> _SYSCFG_CHIPREV_MAJOR_SHIFT;
83   rev->minor  = (chiprev & _SYSCFG_CHIPREV_MINOR_MASK)  >> _SYSCFG_CHIPREV_MINOR_SHIFT;
84 #else
85   uint8_t tmp;
86 
87   EFM_ASSERT(rev);
88 
89   /* CHIP FAMILY bit [5:2] */
90   tmp  = (uint8_t)(((ROMTABLE->PID1 & _ROMTABLE_PID1_FAMILYMSB_MASK)
91                     >> _ROMTABLE_PID1_FAMILYMSB_SHIFT) << 2);
92   /* CHIP FAMILY bit [1:0] */
93   tmp |=  (uint8_t)((ROMTABLE->PID0 & _ROMTABLE_PID0_FAMILYLSB_MASK)
94                     >> _ROMTABLE_PID0_FAMILYLSB_SHIFT);
95   rev->family = tmp;
96 
97   /* CHIP MAJOR bit [3:0] */
98   rev->major = (uint8_t)((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
99                          >> _ROMTABLE_PID0_REVMAJOR_SHIFT);
100 
101   /* CHIP MINOR bit [7:4] */
102   tmp  = (uint8_t)(((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
103                     >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4);
104   /* CHIP MINOR bit [3:0] */
105   tmp |= (uint8_t)((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
106                    >> _ROMTABLE_PID3_REVMINORLSB_SHIFT);
107   rev->minor = tmp;
108 #endif
109 }
110 
111 /***************************************************************************//**
112  * @brief
113  *    Get a factory calibration value for a given peripheral register.
114  *
115  * @param[in] regAddress
116  *    The peripheral calibration register address to get a calibration value for. If
117  *    the calibration value is found, this register is updated with the
118  *    calibration value.
119  *
120  * @return
121  *    True if a calibration value exists, false otherwise.
122  ******************************************************************************/
SYSTEM_GetCalibrationValue(volatile uint32_t * regAddress)123 bool SYSTEM_GetCalibrationValue(volatile uint32_t *regAddress)
124 {
125   SYSTEM_CalAddrVal_TypeDef * p, * end;
126 
127   uint32_t s_regAddress = (uint32_t)regAddress;
128   s_regAddress = s_regAddress & CONVERT_NS_TO_S;
129 
130 #if defined(MSC_FLASH_CHIPCONFIG_MEM_BASE)
131   p   = (SYSTEM_CalAddrVal_TypeDef *)MSC_FLASH_CHIPCONFIG_MEM_BASE;
132   end = (SYSTEM_CalAddrVal_TypeDef *)MSC_FLASH_CHIPCONFIG_MEM_END;
133 #else
134   p   = (SYSTEM_CalAddrVal_TypeDef *)(DEVINFO_BASE & 0xFFFFF000U);
135   end = (SYSTEM_CalAddrVal_TypeDef *)DEVINFO_BASE;
136 #endif
137 
138   for (; p < end; p++) {
139     if (p->address == 0) {
140       /* p->address == 0 marks the end of the table */
141       return false;
142     }
143     if (p->address == s_regAddress) {
144       *regAddress = p->calValue;
145       return true;
146     }
147   }
148   /* Nothing found for regAddress. */
149   return false;
150 }
151 
152 /***************************************************************************//**
153  * @brief
154  *   Get family security capability.
155  *
156  * @note
157  *   This function retrieves the family security capability based on the
158  *   device number. The device number is one letter and 3 digits:
159  *   DEVICENUMBER = (alpha-'A')*1000 + numeric. i.e. 0d = "A000"; 1123d = "B123".
160  *   The security capabilities are represented by ::SYSTEM_SecurityCapability_TypeDef.
161  *
162  * @return
163  *   Security capability of MCU.
164  ******************************************************************************/
SYSTEM_GetSecurityCapability(void)165 SYSTEM_SecurityCapability_TypeDef SYSTEM_GetSecurityCapability(void)
166 {
167   SYSTEM_SecurityCapability_TypeDef sc;
168 
169 #if (_SILICON_LABS_32B_SERIES == 0)
170   sc = securityCapabilityNA;
171 #elif (_SILICON_LABS_32B_SERIES == 1)
172   sc = securityCapabilityBasic;
173 #else
174   sc = securityCapabilityUnknown;
175 #endif
176 
177 #if (_SILICON_LABS_32B_SERIES == 2)
178   uint16_t mcuFeatureSetMajor;
179   uint16_t deviceNumber;
180   deviceNumber = SYSTEM_GetPartNumber();
181   mcuFeatureSetMajor = 'A' + (deviceNumber / 1000);
182 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
183   // override feature set since BRD4182A Rev A00 -> rev B02 are marked "A"
184   mcuFeatureSetMajor = 'C';
185 #endif
186 
187   switch (mcuFeatureSetMajor) {
188     case 'A':
189       sc = securityCapabilitySE;
190       break;
191 
192     case 'B':
193       sc = securityCapabilityVault;
194       break;
195 
196     case 'C':
197       sc = securityCapabilityRoT;
198       break;
199 
200     default:
201       sc = securityCapabilityUnknown;
202       break;
203   }
204 #endif
205 
206   return sc;
207 }
208 
209 /***************************************************************************//**
210  * @brief
211  *   Get the unique number for this device.
212  *
213  * @return
214  *   Unique number for this device.
215  ******************************************************************************/
SYSTEM_GetUnique(void)216 uint64_t SYSTEM_GetUnique(void)
217 {
218 #if defined (_DEVINFO_EUI64H_MASK)
219   uint32_t tmp = DEVINFO->EUI64L;
220   return (uint64_t)((uint64_t)DEVINFO->EUI64H << 32) | tmp;
221 #elif defined(_DEVINFO_UNIQUEH_MASK)
222   uint32_t tmp = DEVINFO->UNIQUEL;
223   return (uint64_t)((uint64_t)DEVINFO->UNIQUEH << 32) | tmp;
224 #else
225 #error (em_system.c): Location of device unique number is not defined.
226 #endif
227 }
228 
229 /***************************************************************************//**
230  * @brief
231  *   Get the production revision for this part.
232  *
233  * @return
234  *   Production revision for this part.
235  ******************************************************************************/
SYSTEM_GetProdRev(void)236 uint8_t SYSTEM_GetProdRev(void)
237 {
238 #if defined (_DEVINFO_PART_PROD_REV_MASK)
239   return (uint8_t)((DEVINFO->PART & _DEVINFO_PART_PROD_REV_MASK)
240                    >> _DEVINFO_PART_PROD_REV_SHIFT);
241 #elif defined (_DEVINFO_INFO_PRODREV_MASK)
242   return (uint8_t)((DEVINFO->INFO & _DEVINFO_INFO_PRODREV_MASK)
243                    >> _DEVINFO_INFO_PRODREV_SHIFT);
244 #else
245 #error (em_system.c): Location of production revision is not defined.
246 #endif
247 }
248 
249 /***************************************************************************//**
250  * @brief
251  *   Get the SRAM Base Address.
252  *
253  * @note
254  *   This function is used to retrieve the base address of the SRAM.
255  *
256  * @return
257  *   Base address SRAM (32-bit unsigned integer).
258  ******************************************************************************/
SYSTEM_GetSRAMBaseAddress(void)259 uint32_t SYSTEM_GetSRAMBaseAddress(void)
260 {
261   return (uint32_t)SRAM_BASE;
262 }
263 
264 /***************************************************************************//**
265  * @brief
266  *   Get the SRAM size (in KB).
267  *
268  * @note
269  *   This function retrieves SRAM size by reading the chip device
270  *   info structure. If your binary is made for one specific device only,
271  *   use SRAM_SIZE instead.
272  *
273  * @return
274  *   Size of internal SRAM (in KB).
275  ******************************************************************************/
SYSTEM_GetSRAMSize(void)276 uint16_t SYSTEM_GetSRAMSize(void)
277 {
278   uint16_t sizekb;
279 
280 #if defined(_EFM32_GECKO_FAMILY)
281   /* Early Gecko devices had a bug where SRAM and Flash size were swapped. */
282   if (SYSTEM_GetProdRev() < 5) {
283     sizekb = (DEVINFO->MSIZE & _DEVINFO_MSIZE_FLASH_MASK)
284              >> _DEVINFO_MSIZE_FLASH_SHIFT;
285   }
286 #endif
287   sizekb = (uint16_t)((DEVINFO->MSIZE & _DEVINFO_MSIZE_SRAM_MASK)
288                       >> _DEVINFO_MSIZE_SRAM_SHIFT);
289 
290 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) && defined(_EFR_DEVICE)
291   /* Do not include EFR32xG1 RAMH. */
292   sizekb--;
293 #endif
294 
295   return sizekb;
296 }
297 
298 /***************************************************************************//**
299  * @brief
300  *   Get the flash size (in KB).
301  *
302  * @note
303  *   This function retrieves flash size by reading the chip device
304  *   info structure. If your binary is made for one specific device only,
305  *   use FLASH_SIZE instead.
306  *
307  * @return
308  *   Size of internal flash (in KB).
309  ******************************************************************************/
SYSTEM_GetFlashSize(void)310 uint16_t SYSTEM_GetFlashSize(void)
311 {
312 #if defined(_EFM32_GECKO_FAMILY)
313   /* Early Gecko devices had a bug where SRAM and Flash size were swapped. */
314   if (SYSTEM_GetProdRev() < 5) {
315     return (DEVINFO->MSIZE & _DEVINFO_MSIZE_SRAM_MASK)
316            >> _DEVINFO_MSIZE_SRAM_SHIFT;
317   }
318 #endif
319   return (uint16_t)((DEVINFO->MSIZE & _DEVINFO_MSIZE_FLASH_MASK)
320                     >> _DEVINFO_MSIZE_FLASH_SHIFT);
321 }
322 
323 /***************************************************************************//**
324  * @brief
325  *   Get the flash page size in bytes.
326  *
327  * @note
328  *   This function retrieves flash page size by reading the chip device
329  *   info structure. If your binary is made for one specific device only,
330  *   use FLASH_PAGE_SIZE instead.
331  *
332  * @return
333  *   Page size of internal flash in bytes.
334  ******************************************************************************/
SYSTEM_GetFlashPageSize(void)335 uint32_t SYSTEM_GetFlashPageSize(void)
336 {
337   uint32_t tmp;
338 
339 #if defined(_SILICON_LABS_32B_SERIES_0)
340 
341 #if defined(_EFM32_GIANT_FAMILY)
342   if (SYSTEM_GetProdRev() < 18) {
343     /* Early Giant/Leopard devices did not have MEMINFO in DEVINFO. */
344     return FLASH_PAGE_SIZE;
345   }
346 #elif defined(_EFM32_ZERO_FAMILY)
347   if (SYSTEM_GetProdRev() < 24) {
348     /* Early Zero devices have an incorrect DEVINFO flash page size */
349     return FLASH_PAGE_SIZE;
350   }
351 #endif
352 #endif
353 
354 #if defined(_DEVINFO_MEMINFO_FLASHPAGESIZE_MASK)
355   tmp = (DEVINFO->MEMINFO & _DEVINFO_MEMINFO_FLASHPAGESIZE_MASK)
356         >> _DEVINFO_MEMINFO_FLASHPAGESIZE_SHIFT;
357 #elif defined(_DEVINFO_MEMINFO_FLASH_PAGE_SIZE_MASK)
358   tmp = (DEVINFO->MEMINFO & _DEVINFO_MEMINFO_FLASH_PAGE_SIZE_MASK)
359         >> _DEVINFO_MEMINFO_FLASH_PAGE_SIZE_SHIFT;
360 #else
361 #error (em_system.c): Location of flash page size is not defined.
362 #endif
363 
364   return 1UL << ((tmp + 10UL) & 0x1FUL);
365 }
366 
367 /***************************************************************************//**
368  * @brief
369  *   Get the MCU part number.
370  *
371  * @return
372  *   The part number of MCU.
373  ******************************************************************************/
SYSTEM_GetPartNumber(void)374 uint16_t SYSTEM_GetPartNumber(void)
375 {
376 #if defined(_DEVINFO_PART_DEVICENUM_MASK)
377   return (uint16_t)((DEVINFO->PART & _DEVINFO_PART_DEVICENUM_MASK)
378                     >> _DEVINFO_PART_DEVICENUM_SHIFT);
379 #elif defined(_DEVINFO_PART_DEVICE_NUMBER_MASK)
380   return (uint16_t)((DEVINFO->PART & _DEVINFO_PART_DEVICE_NUMBER_MASK)
381                     >> _DEVINFO_PART_DEVICE_NUMBER_SHIFT);
382 #else
383 #error (em_system.c): Location of device part number is not defined.
384 #endif
385 }
386 
387 /***************************************************************************//**
388  * @brief
389  *   Get the calibration temperature (in degrees Celsius).
390  *
391  * @return
392  *   Calibration temperature in Celsius.
393  ******************************************************************************/
SYSTEM_GetCalibrationTemperature(void)394 uint8_t SYSTEM_GetCalibrationTemperature(void)
395 {
396 #if defined(_DEVINFO_CAL_TEMP_MASK)
397   return (uint8_t)((DEVINFO->CAL & _DEVINFO_CAL_TEMP_MASK)
398                    >> _DEVINFO_CAL_TEMP_SHIFT);
399 #elif defined(_DEVINFO_CALTEMP_TEMP_MASK)
400   return (uint8_t)((DEVINFO->CALTEMP & _DEVINFO_CALTEMP_TEMP_MASK)
401                    >> _DEVINFO_CALTEMP_TEMP_SHIFT);
402 #else
403 #error (em_system.c): Location of calibration temperature is not defined.
404 #endif
405 }
406 
407 /***************************************************************************//**
408  * @brief
409  *   Get the MCU family identifier.
410  *
411  * @note
412  *   This function retrieves family ID by reading the chip's device info
413  *   structure in flash memory. Users can retrieve family ID directly
414  *   by reading DEVINFO->PART item and decode with mask and shift
415  *   \#defines defined in \<part_family\>_devinfo.h (refer to code
416  *   below for details).
417  *
418  * @return
419  *   Family identifier of MCU.
420  ******************************************************************************/
SYSTEM_GetFamily(void)421 SYSTEM_PartFamily_TypeDef SYSTEM_GetFamily(void)
422 {
423 #if defined(_DEVINFO_PART_FAMILY_MASK)
424   return (SYSTEM_PartFamily_TypeDef)
425          ((uint32_t)((DEVINFO->PART & (_DEVINFO_PART_FAMILY_MASK
426                                        | _DEVINFO_PART_FAMILYNUM_MASK))));
427 #elif defined(_DEVINFO_PART_DEVICE_FAMILY_MASK)
428   return (SYSTEM_PartFamily_TypeDef)
429          ((uint32_t)((DEVINFO->PART & _DEVINFO_PART_DEVICE_FAMILY_MASK)
430                      >> _DEVINFO_PART_DEVICE_FAMILY_SHIFT));
431 #else
432   #error (em_system.h): Location of device family name is not defined.
433 #endif
434 }
435 
436 /** @} (end addtogroup system) */
437