1 //*****************************************************************************
2 //
3 //! @file am_util_id.c
4 //!
5 //! @brief Identification of the Ambiq Micro device.
6 //!
7 //! This module contains functions for run time identification of Ambiq Micro
8 //! devices.
9 //!
10 //! @addtogroup id ID - Identification
11 //! @ingroup utils
12 //! @{
13 //
14 //*****************************************************************************
15 
16 //*****************************************************************************
17 //
18 // Copyright (c) 2023, Ambiq Micro, Inc.
19 // All rights reserved.
20 //
21 // Redistribution and use in source and binary forms, with or without
22 // modification, are permitted provided that the following conditions are met:
23 //
24 // 1. Redistributions of source code must retain the above copyright notice,
25 // this list of conditions and the following disclaimer.
26 //
27 // 2. Redistributions in binary form must reproduce the above copyright
28 // notice, this list of conditions and the following disclaimer in the
29 // documentation and/or other materials provided with the distribution.
30 //
31 // 3. Neither the name of the copyright holder nor the names of its
32 // contributors may be used to endorse or promote products derived from this
33 // software without specific prior written permission.
34 //
35 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
39 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45 // POSSIBILITY OF SUCH DAMAGE.
46 //
47 // This is part of revision release_sdk_4_4_0-3c5977e664 of the AmbiqSuite Development Package.
48 //
49 //*****************************************************************************
50 #include <stdint.h>
51 #include "am_util_id.h"
52 
53 //*****************************************************************************
54 //
55 // Globals.
56 //
57 //*****************************************************************************
58 //
59 //! Strings for use with pui8VendorName.
60 //
61 #if defined(AM_ID_APOLLO)
62 static const uint8_t g_DeviceNameApollo[]     = "Apollo";
63 #endif
64 #if defined(AM_ID_APOLLO2)
65 static const uint8_t g_DeviceNameApollo2[]    = "Apollo2";
66 #endif
67 #if defined(AM_ID_APOLLO3)
68 static const uint8_t g_DeviceNameApollo3[]    = "Apollo3 Blue";
69 #endif
70 #if defined(AM_ID_APOLLO3P)
71 static const uint8_t g_DeviceNameApollo3p[]   = "Apollo3 Blue Plus";
72 #endif
73 #if defined(AM_ID_APOLLO4A)
74 static const uint8_t g_DeviceNameApollo4[]    = "Apollo4 revA";
75 #endif
76 #if defined(AM_ID_APOLLO4B)
77 static const uint8_t g_DeviceNameApollo4b[]   = "Apollo4b";
78 #endif
79 #if defined(AM_ID_APOLLO4P)
80 static const uint8_t g_DeviceNameApollo4p[]        = "Apollo4 Plus";
81 static const uint8_t g_DeviceNameApollo4p_blue[]   = "Apollo4 Blue Plus";
82 static const uint8_t g_PackageType[][4]            = { "SIP", "SIP2", "BGA", "CSP" };
83 #endif
84 #if defined(AM_ID_APOLLO4L)
85 static const uint8_t g_DeviceNameApollo4l[]   = "Apollo4 Lite";
86 #endif
87 
88 static const uint8_t g_TempRange[][11] = { "Commercial", "Military", "Automotive", "Industrial" };
89 static const uint8_t g_ui8VendorNameAmbq[]    = "AMBQ";
90 static const uint8_t g_ui8VendorNameUnknown[] = "????";
91 static const uint8_t g_ui8DeviceNameUnknown[] = "Unknown device";
92 
93 #if !defined(AM_ID_APOLLO) && !defined(AM_ID_APOLLO2)
94 //*****************************************************************************
95 // Return the major version of the chip rev.
96 // Returns: 'A', 'B', 'C', ...
97 //*****************************************************************************
98 static uint32_t
revmaj_get(uint32_t ui32ChipRev)99 revmaj_get(uint32_t ui32ChipRev)
100 {
101     uint32_t ui32ret;
102 
103 #ifdef _FLD2VAL
104     ui32ret = _FLD2VAL(MCUCTRL_CHIPREV_REVMAJ, ui32ChipRev);
105 #else
106     ui32ret = (ui32ChipRev & 0xF0) >> 4;
107 #endif
108 
109     //
110     // Major revision is 1=A, 2=B, 3=C, ...
111     // Convert to the expected return value.
112     //
113     return ui32ret + 'A' - 1;
114 
115 } // revmaj_get()
116 #endif
117 
118 //*****************************************************************************
119 // Update the ID structure with the appropriate ChipRev letter.
120 // ui32minrevbase should be 0 for Apollo or Apollo2, 1 for Apollo3.
121 //*****************************************************************************
122 static void
chiprev_set(am_util_id_t * psIDDevice,uint32_t ui32minrevbase)123 chiprev_set(am_util_id_t *psIDDevice, uint32_t ui32minrevbase)
124 {
125     uint32_t ui32maj, ui32min;
126 
127     ui32maj = ((psIDDevice->sMcuCtrlDevice.ui32ChipRev & 0xF0) >> 4);
128     psIDDevice->ui8ChipRevMaj  = (uint8_t)('A' - 1 + ui32maj);
129 
130     //
131     // For Apollo and Apollo2:  rev0=0, rev1=1, ... (0-based)
132     // For Apollo3:             rev0=1, rev1=2, ... (1-based)
133     //
134     ui32min = ((psIDDevice->sMcuCtrlDevice.ui32ChipRev & 0x0F) >> 0);
135     psIDDevice->ui8ChipRevMin = (uint8_t)('0' + ui32min - ui32minrevbase);
136 
137 } // chiprev_set()
138 
139 //*****************************************************************************
140 //
141 // Device identification.
142 //
143 //*****************************************************************************
144 uint32_t
am_util_id_device(am_util_id_t * psIDDevice)145 am_util_id_device(am_util_id_t *psIDDevice)
146 {
147 #if !defined(AM_ID_APOLLO) && !defined(AM_ID_APOLLO2)
148     uint32_t ui32ChipRev;
149 #endif
150     uint32_t ui32PN;
151 
152     //
153     // Initialize to default as "unknown".
154     //
155     psIDDevice->ui32Device = AM_UTIL_ID_UNKNOWN;
156     psIDDevice->pui8DeviceName = g_ui8DeviceNameUnknown;
157     psIDDevice->pui8VendorName = g_ui8VendorNameUnknown;
158     psIDDevice->ui8ChipRevMaj = (uint8_t)'?';
159     psIDDevice->ui8ChipRevMin = (uint8_t)' ';
160 
161     //
162     // Go get all the device (hardware) info from the HAL
163     //
164 #if AM_APOLLO3_MCUCTRL
165     am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_DEVICEID, &psIDDevice->sMcuCtrlDevice);
166     am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_FEATURES_AVAIL, &psIDDevice->sMcuCtrlFeature);
167 #else // AM_APOLLO3_MCUCTRL
168     am_hal_mcuctrl_device_info_get(&psIDDevice->sMcuCtrlDevice);
169 #endif // AM_APOLLO3_MCUCTRL
170 
171     //
172     // Device identification
173     //
174     ui32PN = psIDDevice->sMcuCtrlDevice.ui32ChipPN  &
175              AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
176 #if !defined(AM_ID_APOLLO) && !defined(AM_ID_APOLLO2)
177     ui32ChipRev = psIDDevice->sMcuCtrlDevice.ui32ChipRev;
178 #endif
179 
180     if ( ( psIDDevice->sMcuCtrlDevice.ui32VendorID ==
181             (('A' << 24) | ('M' << 16) | ('B' << 8) | ('Q' << 0)) ) )
182     {
183         //
184         // VENDORID is AMBQ. Set the manufacturer string pointer.
185         //
186         psIDDevice->pui8VendorName = g_ui8VendorNameAmbq;
187     }
188 
189 #if defined(AM_ID_APOLLO)
190     //
191     // Apollo1 did not support VENDORID.
192     // Do a specific check from JEDEC values to verify Ambiq as the vendor.
193     //
194     if ( ((psIDDevice->sMcuCtrlDevice.ui32JedecCID   == 0xB105100D)     &&
195          (psIDDevice->sMcuCtrlDevice.ui32JedecJEPID == 0x0000009B)      &&
196          ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0xF00) == 0xE00)) )
197     {
198         //
199         // VENDORID is AMBQ. Set the manufacturer string pointer.
200         //
201         psIDDevice->pui8VendorName = g_ui8VendorNameAmbq;
202     }
203 
204     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO )             &&
205          ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0E0) )
206     {
207         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO;
208         psIDDevice->pui8DeviceName = g_DeviceNameApollo;
209         chiprev_set(psIDDevice, 0);
210     }
211 #endif // AM_ID_APOLLO
212 
213 #if defined(AM_ID_APOLLO2)
214     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO2 )            &&
215               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0D0) )
216     {
217         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO2;
218         psIDDevice->pui8DeviceName = g_DeviceNameApollo2;
219         chiprev_set(psIDDevice, 0);
220     }
221 #endif // AM_ID_APOLLO2
222 
223 #if defined(AM_ID_APOLLO3)
224     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO3 )            &&
225               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0C0)   &&
226               ( revmaj_get(ui32ChipRev) <= 'B' ) )
227     {
228         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO3;
229         psIDDevice->pui8DeviceName = g_DeviceNameApollo3;
230         chiprev_set(psIDDevice, 1);
231     }
232 #endif // AM_ID_APOLLO3
233 
234 #if defined(AM_ID_APOLLO3P)
235     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO3P)            &&
236               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0C0)   &&
237               ( revmaj_get(ui32ChipRev) == 'C' ) )
238     {
239         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO3P;
240         psIDDevice->pui8DeviceName = g_DeviceNameApollo3p;
241         chiprev_set(psIDDevice, 1);
242     }
243 #endif // AM_ID_APOLLO3P
244 
245 #if defined(AM_ID_APOLLO4A)
246     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO4)             &&
247               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0B0)   &&
248                ( revmaj_get(ui32ChipRev) == 'A' ) )
249     {
250         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO4;
251         psIDDevice->pui8DeviceName = g_DeviceNameApollo4;
252         chiprev_set(psIDDevice, 1);
253     }
254 #endif // AM_ID_APOLLO4A
255 
256 #if defined(AM_ID_APOLLO4B)
257     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO4)             &&
258               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0B0)   &&
259                ( revmaj_get(ui32ChipRev) == 'B' ) )
260     {
261         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO4;
262         psIDDevice->pui8DeviceName = g_DeviceNameApollo4b;
263         chiprev_set(psIDDevice, 1);
264     }
265 #endif // AM_ID_APOLLO4B
266 
267 #if defined(AM_ID_APOLLO4P)
268     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO4)             &&
269               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0B0)   &&
270               ( revmaj_get(ui32ChipRev) == 'C' ) )
271     {
272         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO4P;
273         if ( ((psIDDevice->sMcuCtrlDevice.ui32ChipPN & 0xc0) >> 6) >= 2 )
274         {
275             psIDDevice->pui8DeviceName = g_DeviceNameApollo4p;
276         }
277         else
278         {
279             psIDDevice->pui8DeviceName = g_DeviceNameApollo4p_blue;
280         }
281         chiprev_set(psIDDevice, 1);
282     }
283 #endif // AM_ID_APOLLO4P
284 
285 #if defined(AM_ID_APOLLO4L)
286     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO4L)             &&
287               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0B0)   &&
288               ( revmaj_get(ui32ChipRev) == 'A' ) )
289     {
290         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO4L;
291         psIDDevice->pui8DeviceName = g_DeviceNameApollo4l;
292         chiprev_set(psIDDevice, 1);
293     }
294 #endif // AM_ID_APOLLO4L
295 
296 
297     //
298     // This section defines the package type
299     //
300     // currently this is only defined for the Apollo4 Plus / Blue Plus
301     //
302 #if defined(AM_PART_APOLLO4P)
303     psIDDevice->pui8PackageType = g_PackageType[((psIDDevice->sMcuCtrlDevice.ui32ChipPN & 0xC0) >> 6)];
304 #else
305     psIDDevice->pui8PackageType = NULL;
306 #endif
307 
308     psIDDevice->pui8TempRange = g_TempRange[((psIDDevice->sMcuCtrlDevice.ui32ChipPN & 0x06) >> 1)];
309 
310     return psIDDevice->ui32Device;
311 }
312 
313 //*****************************************************************************
314 //
315 // End Doxygen group.
316 //! @}
317 //
318 //*****************************************************************************
319 
320