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) 2024, 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 stable-c1f95ddf60 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 #if defined(AM_ID_APOLLO5A)
88 static const uint8_t g_DeviceNameApollo5a[]   = "Apollo5 revA";
89 #endif // AM_ID_APOLLO5A
90 #if defined(AM_ID_APOLLO5B)
91 static const uint8_t g_DeviceNameApollo5b[]   = "Apollo5 revB";
92 #endif // AM_ID_APOLLO5B
93 
94 static const uint8_t g_TempRange[][11] = { "Commercial", "Military", "Automotive", "Industrial" };
95 static const uint8_t g_ui8VendorNameAmbq[]    = "AMBQ";
96 static const uint8_t g_ui8VendorNameUnknown[] = "????";
97 static const uint8_t g_ui8DeviceNameUnknown[] = "Unknown device";
98 
99 #if !defined(AM_ID_APOLLO) && !defined(AM_ID_APOLLO2)
100 //*****************************************************************************
101 // Return the major version of the chip rev.
102 // Returns: 'A', 'B', 'C', ...
103 //*****************************************************************************
104 static uint32_t
revmaj_get(uint32_t ui32ChipRev)105 revmaj_get(uint32_t ui32ChipRev)
106 {
107     uint32_t ui32ret;
108 
109 #ifdef _FLD2VAL
110     ui32ret = _FLD2VAL(MCUCTRL_CHIPREV_REVMAJ, ui32ChipRev);
111 #else
112     ui32ret = (ui32ChipRev & 0xF0) >> 4;
113 #endif
114 
115     //
116     // Major revision is 1=A, 2=B, 3=C, ...
117     // Convert to the expected return value.
118     //
119     return ui32ret + 'A' - 1;
120 
121 } // revmaj_get()
122 #endif
123 
124 //*****************************************************************************
125 // Update the ID structure with the appropriate ChipRev letter.
126 // ui32minrevbase should be 0 for Apollo or Apollo2, 1 for Apollo3.
127 //*****************************************************************************
128 static void
chiprev_set(am_util_id_t * psIDDevice,uint32_t ui32minrevbase)129 chiprev_set(am_util_id_t *psIDDevice, uint32_t ui32minrevbase)
130 {
131     uint32_t ui32maj, ui32min;
132 
133     ui32maj = ((psIDDevice->sMcuCtrlDevice.ui32ChipRev & 0xF0) >> 4);
134     psIDDevice->ui8ChipRevMaj  = (uint8_t)('A' - 1 + ui32maj);
135 
136     //
137     // For Apollo and Apollo2:  rev0=0, rev1=1, ... (0-based)
138     // For Apollo3:             rev0=1, rev1=2, ... (1-based)
139     //
140     ui32min = ((psIDDevice->sMcuCtrlDevice.ui32ChipRev & 0x0F) >> 0);
141     psIDDevice->ui8ChipRevMin = (uint8_t)('0' + ui32min - ui32minrevbase);
142 
143 } // chiprev_set()
144 
145 //*****************************************************************************
146 //
147 // Device identification.
148 //
149 //*****************************************************************************
150 uint32_t
am_util_id_device(am_util_id_t * psIDDevice)151 am_util_id_device(am_util_id_t *psIDDevice)
152 {
153 #if !defined(AM_ID_APOLLO) && !defined(AM_ID_APOLLO2)
154     uint32_t ui32ChipRev;
155 #endif
156     uint32_t ui32PN;
157 
158     //
159     // Initialize to default as "unknown".
160     //
161     psIDDevice->ui32Device = AM_UTIL_ID_UNKNOWN;
162     psIDDevice->pui8DeviceName = g_ui8DeviceNameUnknown;
163     psIDDevice->pui8VendorName = g_ui8VendorNameUnknown;
164     psIDDevice->ui8ChipRevMaj = (uint8_t)'?';
165     psIDDevice->ui8ChipRevMin = (uint8_t)' ';
166 
167     //
168     // Go get all the device (hardware) info from the HAL
169     //
170 #if defined(AM_PART_APOLLO3_API) || defined(AM_PART_APOLLO4_API) || defined(AM_PART_APOLLO5_API)
171     am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_DEVICEID, &psIDDevice->sMcuCtrlDevice);
172     am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_FEATURES_AVAIL, &psIDDevice->sMcuCtrlFeature);
173 #else
174     am_hal_mcuctrl_device_info_get(&psIDDevice->sMcuCtrlDevice);
175 #endif
176 
177     //
178     // Device identification
179     //
180     ui32PN = psIDDevice->sMcuCtrlDevice.ui32ChipPN  &
181              AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
182 #if !defined(AM_ID_APOLLO) && !defined(AM_ID_APOLLO2)
183     ui32ChipRev = psIDDevice->sMcuCtrlDevice.ui32ChipRev;
184 #endif
185 
186     if ( ( psIDDevice->sMcuCtrlDevice.ui32VendorID ==
187             (('A' << 24) | ('M' << 16) | ('B' << 8) | ('Q' << 0)) ) )
188     {
189         //
190         // VENDORID is AMBQ. Set the manufacturer string pointer.
191         //
192         psIDDevice->pui8VendorName = g_ui8VendorNameAmbq;
193     }
194 
195 #if defined(AM_ID_APOLLO)
196     //
197     // Apollo1 did not support VENDORID.
198     // Do a specific check from JEDEC values to verify Ambiq as the vendor.
199     //
200     if ( ((psIDDevice->sMcuCtrlDevice.ui32JedecCID   == 0xB105100D)     &&
201          (psIDDevice->sMcuCtrlDevice.ui32JedecJEPID == 0x0000009B)      &&
202          ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0xF00) == 0xE00)) )
203     {
204         //
205         // VENDORID is AMBQ. Set the manufacturer string pointer.
206         //
207         psIDDevice->pui8VendorName = g_ui8VendorNameAmbq;
208     }
209 
210     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO )             &&
211          ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0E0) )
212     {
213         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO;
214         psIDDevice->pui8DeviceName = g_DeviceNameApollo;
215         chiprev_set(psIDDevice, 0);
216     }
217 #endif // AM_ID_APOLLO
218 
219 #if defined(AM_ID_APOLLO2)
220     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO2 )            &&
221               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0D0) )
222     {
223         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO2;
224         psIDDevice->pui8DeviceName = g_DeviceNameApollo2;
225         chiprev_set(psIDDevice, 0);
226     }
227 #endif // AM_ID_APOLLO2
228 
229 #if defined(AM_ID_APOLLO3)
230     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO3 )            &&
231               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0C0)   &&
232               ( revmaj_get(ui32ChipRev) <= 'B' ) )
233     {
234         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO3;
235         psIDDevice->pui8DeviceName = g_DeviceNameApollo3;
236         chiprev_set(psIDDevice, 1);
237     }
238 #endif // AM_ID_APOLLO3
239 
240 #if defined(AM_ID_APOLLO3P)
241     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO3P)            &&
242               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0C0)   &&
243               ( revmaj_get(ui32ChipRev) == 'C' ) )
244     {
245         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO3P;
246         psIDDevice->pui8DeviceName = g_DeviceNameApollo3p;
247         chiprev_set(psIDDevice, 1);
248     }
249 #endif // AM_ID_APOLLO3P
250 
251 #if defined(AM_ID_APOLLO4A)
252     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO4)             &&
253               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0B0)   &&
254                ( revmaj_get(ui32ChipRev) == 'A' ) )
255     {
256         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO4;
257         psIDDevice->pui8DeviceName = g_DeviceNameApollo4;
258         chiprev_set(psIDDevice, 1);
259     }
260 #endif // AM_ID_APOLLO4A
261 
262 #if defined(AM_ID_APOLLO4B)
263     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO4)             &&
264               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0B0)   &&
265                ( revmaj_get(ui32ChipRev) == 'B' ) )
266     {
267         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO4;
268         psIDDevice->pui8DeviceName = g_DeviceNameApollo4b;
269         chiprev_set(psIDDevice, 1);
270     }
271 #endif // AM_ID_APOLLO4B
272 
273 #if defined(AM_ID_APOLLO4P)
274     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO4)             &&
275               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0B0)   &&
276               ( revmaj_get(ui32ChipRev) == 'C' ) )
277     {
278         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO4P;
279         if ( ((psIDDevice->sMcuCtrlDevice.ui32ChipPN & 0xc0) >> 6) >= 2 )
280         {
281             psIDDevice->pui8DeviceName = g_DeviceNameApollo4p;
282         }
283         else
284         {
285             psIDDevice->pui8DeviceName = g_DeviceNameApollo4p_blue;
286         }
287         chiprev_set(psIDDevice, 1);
288     }
289 #endif // AM_ID_APOLLO4P
290 
291 #if defined(AM_ID_APOLLO4L)
292     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO4L)             &&
293               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0F0) == 0x0B0)   &&
294               ( revmaj_get(ui32ChipRev) == 'A' ) )
295     {
296         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO4L;
297         psIDDevice->pui8DeviceName = g_DeviceNameApollo4l;
298         chiprev_set(psIDDevice, 1);
299     }
300 #endif // AM_ID_APOLLO4L
301 
302 #if defined(AM_ID_APOLLO5A)
303     if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO5A)            &&
304               ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0FF) == 0x0D2)   &&
305               ( revmaj_get(ui32ChipRev) == 'A' ) )
306     {
307         psIDDevice->ui32Device = AM_UTIL_ID_APOLLO5A;
308         psIDDevice->pui8DeviceName = g_DeviceNameApollo5a;
309         chiprev_set(psIDDevice, 1);
310     }
311 #endif // AM_ID_APOLLO5A
312 
313 #if defined(AM_ID_APOLLO5B)
314         if ( ( ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLO5B)            &&
315                   ((psIDDevice->sMcuCtrlDevice.ui32JedecPN & 0x0FF) == 0x0D2)   &&
316                   ( revmaj_get(ui32ChipRev) == 'B' ) )
317         {
318             psIDDevice->ui32Device = AM_UTIL_ID_APOLLO5B;
319             psIDDevice->pui8DeviceName = g_DeviceNameApollo5b;
320             chiprev_set(psIDDevice, 1);
321         }
322 #endif // AM_ID_APOLLO5B
323 
324     //
325     // This section defines the package type
326     //
327     // currently this is only defined for the Apollo4 Plus / Blue Plus
328     //
329 #if defined(AM_PART_APOLLO4P)
330     psIDDevice->pui8PackageType = g_PackageType[((psIDDevice->sMcuCtrlDevice.ui32ChipPN & 0xC0) >> 6)];
331 #else
332     psIDDevice->pui8PackageType = NULL;
333 #endif
334 
335     psIDDevice->pui8TempRange = g_TempRange[((psIDDevice->sMcuCtrlDevice.ui32ChipPN & 0x06) >> 1)];
336 
337     return psIDDevice->ui32Device;
338 }
339 
340 //*****************************************************************************
341 //
342 // End Doxygen group.
343 //! @}
344 //
345 //*****************************************************************************
346 
347