blob: d46fab2a82fdf57a93d358c112925df75eb67625 [file] [log] [blame]
Marat Dukhan006461a2017-08-24 16:10:46 -07001#include <stdbool.h>
2#include <stdint.h>
3#include <stdio.h>
4#include <string.h>
5
Marat Dukhan3c634552017-10-16 16:46:45 +00006#include <arm/linux/api.h>
7#ifdef __ANDROID__
8 #include <arm/android/api.h>
9#endif
Marat Dukhan006461a2017-08-24 16:10:46 -070010#include <log.h>
11
12
13#define CPUINFO_COUNT_OF(x) (sizeof(x) / sizeof(0[x]))
14
15
16static inline bool is_ascii_whitespace(char c) {
17 switch (c) {
18 case ' ':
19 case '\t':
20 case '\r':
21 case '\n':
22 return true;
23 default:
24 return false;
25 }
26}
27
28static inline bool is_ascii_alphabetic(char c) {
29 const char lower_c = c | '\x20';
30 return (uint8_t) (lower_c - 'a') <= (uint8_t) ('z' - 'a');
31}
32
33static inline bool is_ascii_alphabetic_uppercase(char c) {
34 return (uint8_t) (c - 'A') <= (uint8_t) ('Z' - 'A');
35}
36
37static inline bool is_ascii_numeric(char c) {
38 return (uint8_t) (c - '0') < 10;
39}
40
Marat Dukhan006461a2017-08-24 16:10:46 -070041static inline uint16_t load_u16le(const void* ptr) {
42#if defined(__ARM_ARCH_7A__) || defined(__aarch64__)
43 return *((const uint16_t*) ptr);
44#else
45 const uint8_t* byte_ptr = (const uint8_t*) ptr;
46 return ((uint16_t) byte_ptr[1] << 8) | (uint16_t) byte_ptr[0];
47#endif
48}
49
50static inline uint32_t load_u24le(const void* ptr) {
51#if defined(__ARM_ARCH_7A__) || defined(__aarch64__)
52 return ((uint32_t) ((const uint8_t*) ptr)[2] << 16) | ((uint32_t) *((const uint16_t*) ptr));
53#else
54 const uint8_t* byte_ptr = (const uint8_t*) ptr;
55 return ((uint32_t) byte_ptr[2] << 16) | ((uint32_t) byte_ptr[1] << 8) | (uint32_t) byte_ptr[0];
56#endif
57}
58
59static inline uint32_t load_u32le(const void* ptr) {
60#if defined(__ARM_ARCH_7A__) || defined(__aarch64__)
61 return *((const uint32_t*) ptr);
62#else
63 return ((uint32_t) ((const uint8_t*) ptr)[3] << 24) | load_u24le(ptr);
64#endif
65}
66
67/*
68 * Map from ARM chipset series ID to ARM chipset vendor ID.
69 * This map is used to avoid storing vendor IDs in tables.
70 */
71static enum cpuinfo_arm_chipset_vendor chipset_series_vendor[cpuinfo_arm_chipset_series_max] = {
72 [cpuinfo_arm_chipset_series_unknown] = cpuinfo_arm_chipset_vendor_unknown,
73 [cpuinfo_arm_chipset_series_qualcomm_qsd] = cpuinfo_arm_chipset_vendor_qualcomm,
74 [cpuinfo_arm_chipset_series_qualcomm_msm] = cpuinfo_arm_chipset_vendor_qualcomm,
75 [cpuinfo_arm_chipset_series_qualcomm_apq] = cpuinfo_arm_chipset_vendor_qualcomm,
76 [cpuinfo_arm_chipset_series_qualcomm_snapdragon] = cpuinfo_arm_chipset_vendor_qualcomm,
77 [cpuinfo_arm_chipset_series_mediatek_mt] = cpuinfo_arm_chipset_vendor_mediatek,
78 [cpuinfo_arm_chipset_series_samsung_exynos] = cpuinfo_arm_chipset_vendor_samsung,
79 [cpuinfo_arm_chipset_series_hisilicon_k3v] = cpuinfo_arm_chipset_vendor_hisilicon,
80 [cpuinfo_arm_chipset_series_hisilicon_hi] = cpuinfo_arm_chipset_vendor_hisilicon,
81 [cpuinfo_arm_chipset_series_hisilicon_kirin] = cpuinfo_arm_chipset_vendor_hisilicon,
82 [cpuinfo_arm_chipset_series_actions_atm] = cpuinfo_arm_chipset_vendor_actions,
83 [cpuinfo_arm_chipset_series_allwinner_a] = cpuinfo_arm_chipset_vendor_allwinner,
84 [cpuinfo_arm_chipset_series_amlogic_aml] = cpuinfo_arm_chipset_vendor_amlogic,
85 [cpuinfo_arm_chipset_series_amlogic_s] = cpuinfo_arm_chipset_vendor_amlogic,
86 [cpuinfo_arm_chipset_series_broadcom_bcm] = cpuinfo_arm_chipset_vendor_broadcom,
87 [cpuinfo_arm_chipset_series_lg_nuclun] = cpuinfo_arm_chipset_vendor_lg,
88 [cpuinfo_arm_chipset_series_leadcore_lc] = cpuinfo_arm_chipset_vendor_leadcore,
89 [cpuinfo_arm_chipset_series_marvell_pxa] = cpuinfo_arm_chipset_vendor_marvell,
90 [cpuinfo_arm_chipset_series_mstar_6a] = cpuinfo_arm_chipset_vendor_mstar,
91 [cpuinfo_arm_chipset_series_novathor_u] = cpuinfo_arm_chipset_vendor_novathor,
92 [cpuinfo_arm_chipset_series_nvidia_tegra_t] = cpuinfo_arm_chipset_vendor_nvidia,
93 [cpuinfo_arm_chipset_series_nvidia_tegra_ap] = cpuinfo_arm_chipset_vendor_nvidia,
94 [cpuinfo_arm_chipset_series_nvidia_tegra_sl] = cpuinfo_arm_chipset_vendor_nvidia,
95 [cpuinfo_arm_chipset_series_pinecone_surge_s] = cpuinfo_arm_chipset_vendor_pinecone,
96 [cpuinfo_arm_chipset_series_renesas_mp] = cpuinfo_arm_chipset_vendor_renesas,
97 [cpuinfo_arm_chipset_series_rockchip_rk] = cpuinfo_arm_chipset_vendor_rockchip,
98 [cpuinfo_arm_chipset_series_spreadtrum_sc] = cpuinfo_arm_chipset_vendor_spreadtrum,
99 [cpuinfo_arm_chipset_series_telechips_tcc] = cpuinfo_arm_chipset_vendor_telechips,
100 [cpuinfo_arm_chipset_series_texas_instruments_omap] = cpuinfo_arm_chipset_vendor_texas_instruments,
101 [cpuinfo_arm_chipset_series_wondermedia_wm] = cpuinfo_arm_chipset_vendor_wondermedia,
102};
103
104/**
105 * Tries to match /(MSM|APQ)\d{4}([A-Z\-]*)/ signature (case-insensitive) for Qualcomm MSM and APQ chipsets.
106 * If match successful, extracts model information into \p chipset argument.
107 *
108 * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board, ro.board.platform
109 * or ro.chipname) to match.
110 * @param end - end of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board, ro.board.platform or
111 * ro.chipname) to match.
112 * @param[out] chipset - location where chipset information will be stored upon a successful match.
113 *
114 * @returns true if signature matched, false otherwise.
115 */
116static bool match_msm_apq(
117 const char* start, const char* end,
118 struct cpuinfo_arm_chipset chipset[restrict static 1])
119{
120 /* Expect at least 7 symbols: 3 symbols "MSM" or "APQ" + 4 digits */
121 if (start + 7 > end) {
122 return false;
123 }
124
125 /* Check that string starts with "MSM" or "APQ", case-insensitive.
126 * The first three characters are loaded as 24-bit little endian word, binary ORed with 0x20 to convert to lower
127 * case, and compared to "MSM" and "APQ" strings as integers.
128 */
129 const uint32_t series_signature = UINT32_C(0x00202020) | load_u24le(start);
130 enum cpuinfo_arm_chipset_series series;
131 switch (series_signature) {
132 case UINT32_C(0x6D736D): /* "msm" = reverse("msm") */
133 series = cpuinfo_arm_chipset_series_qualcomm_msm;
134 break;
135 case UINT32_C(0x717061): /* "qpa" = reverse("apq") */
136 series = cpuinfo_arm_chipset_series_qualcomm_apq;
137 break;
138 default:
139 return false;
140 }
141
142 /* Sometimes there is a space ' ' following the MSM/APQ series */
143 const char* pos = start + 3;
144 if (*pos == ' ') {
145 pos++;
146
147 /* Expect at least 4 more symbols (4-digit model number) */
148 if (pos + 4 > end) {
149 return false;
150 }
151 }
152
153 /* Validate and parse 4-digit model number */
154 uint32_t model = 0;
155 for (uint32_t i = 0; i < 4; i++) {
156 const uint32_t digit = (uint32_t) (uint8_t) (*pos++) - '0';
157 if (digit >= 10) {
158 /* Not really a digit */
159 return false;
160 }
161 model = model * 10 + digit;
162 }
163
164 /* Suffix is optional, so if we got to this point, parsing is successful. Commit parsed chipset. */
165 *chipset = (struct cpuinfo_arm_chipset) {
166 .vendor = cpuinfo_arm_chipset_vendor_qualcomm,
167 .series = series,
168 .model = model,
169 };
170
171 /* Parse as many suffix characters as match the pattern [A-Za-z\-] */
172 for (uint32_t i = 0; i < CPUINFO_ARM_CHIPSET_SUFFIX_MAX; i++) {
173 if (pos + i == end) {
174 break;
175 }
176
177 const char c = pos[i];
178 if (is_ascii_alphabetic(c)) {
179 /* Matched a letter [A-Za-z] */
180 chipset->suffix[i] = c & '\xDF';
181 } else if (c == '-') {
182 /* Matched a dash '-' */
183 chipset->suffix[i] = c;
184 } else {
185 /* Neither of [A-Za-z\-] */
186 break;
187 }
188 }
189 return true;
190}
191
192/**
193 * Tries to match /SDM\d{3}$/ signature for Qualcomm Snapdragon chipsets.
194 * If match successful, extracts model information into \p chipset argument.
195 *
196 * @param start - start of the /proc/cpuinfo Hardware string to match.
197 * @param end - end of the /proc/cpuinfo Hardware string to match.
198 * @param[out] chipset - location where chipset information will be stored upon a successful match.
199 *
200 * @returns true if signature matched, false otherwise.
201 */
202static bool match_sdm(
203 const char* start, const char* end,
204 struct cpuinfo_arm_chipset chipset[restrict static 1])
205{
206 /* Expect exactly 6 symbols: 3 symbols "SDM" + 3 digits */
207 if (start + 6 != end) {
208 return false;
209 }
210
211 /* Check that string starts with "SDM".
212 * The first three characters are loaded and compared as 24-bit little endian word.
213 */
214 const uint32_t expected_sdm = load_u24le(start);
215 if (expected_sdm != UINT32_C(0x004D4453) /* "MDS" = reverse("SDM") */) {
216 return false;
217 }
218
219 /* Validate and parse 3-digit model number */
220 uint32_t model = 0;
221 for (uint32_t i = 3; i < 6; i++) {
222 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
223 if (digit >= 10) {
224 /* Not really a digit */
225 return false;
226 }
227 model = model * 10 + digit;
228 }
229
230 /* Return parsed chipset. */
231 *chipset = (struct cpuinfo_arm_chipset) {
232 .vendor = cpuinfo_arm_chipset_vendor_qualcomm,
233 .series = cpuinfo_arm_chipset_series_qualcomm_snapdragon,
234 .model = model,
235 };
236 return true;
237}
238
239/**
240 * Tries to match /Samsung Exynos\d{4}$/ signature (case-insensitive) for Samsung Exynos chipsets.
241 * If match successful, extracts model information into \p chipset argument.
242 *
243 * @param start - start of the /proc/cpuinfo Hardware string to match.
244 * @param end - end of the /proc/cpuinfo Hardware string to match.
245 * @param[out] chipset - location where chipset information will be stored upon a successful match.
246 *
247 * @returns true if signature matched, false otherwise.
248 */
249static bool match_samsung_exynos(
250 const char* start, const char* end,
251 struct cpuinfo_arm_chipset chipset[restrict static 1])
252{
253 /*
254 * Expect at 18-19 symbols:
255 * - "Samsung" (7 symbols) + space + "Exynos" (6 symbols) + optional space 4-digit model number
256 */
257 const size_t length = end - start;
258 switch (length) {
259 case 18:
260 case 19:
261 break;
262 default:
263 return false;
264 }
265
266 /*
267 * Check that the string starts with "samsung exynos", case-insensitive.
268 * Blocks of 4 characters are loaded and compared as little-endian 32-bit word.
269 * Case-insensitive characters are binary ORed with 0x20 to convert them to lowercase.
270 */
271 const uint32_t expected_sams = UINT32_C(0x20202000) | load_u32le(start);
272 if (expected_sams != UINT32_C(0x736D6153) /* "smaS" = reverse("Sams") */) {
273 return false;
274 }
275 const uint32_t expected_ung = UINT32_C(0x00202020) | load_u32le(start + 4);
276 if (expected_ung != UINT32_C(0x20676E75) /* " ung" = reverse("ung ") */) {
277 return false;
278 }
279 const uint32_t expected_exyn = UINT32_C(0x20202000) | load_u32le(start + 8);
280 if (expected_exyn != UINT32_C(0x6E797845) /* "nyxE" = reverse("Exyn") */) {
281 return false;
282 }
283 const uint16_t expected_os = UINT16_C(0x2020) | load_u16le(start + 12);
284 if (expected_os != UINT16_C(0x736F) /* "so" = reverse("os") */) {
285 return false;
286 }
287
288 const char* pos = start + 14;
289
290 /* There can be a space ' ' following the "Exynos" string */
291 if (*pos == ' ') {
292 pos++;
293
294 /* If optional space if present, we expect exactly 19 characters */
295 if (length != 19) {
296 return false;
297 }
298 }
299
300 /* Validate and parse 4-digit model number */
301 uint32_t model = 0;
302 for (uint32_t i = 0; i < 4; i++) {
303 const uint32_t digit = (uint32_t) (uint8_t) (*pos++) - '0';
304 if (digit >= 10) {
305 /* Not really a digit */
306 return start;
307 }
308 model = model * 10 + digit;
309 }
310
311 /* Return parsed chipset */
312 *chipset = (struct cpuinfo_arm_chipset) {
313 .vendor = cpuinfo_arm_chipset_vendor_samsung,
314 .series = cpuinfo_arm_chipset_series_samsung_exynos,
315 .model = model,
316 };
317 return pos;
318}
319
320/**
321 * Tries to match /exynos\d{4}$/ signature for Samsung Exynos chipsets.
322 * If match successful, extracts model information into \p chipset argument.
323 *
324 * @param start - start of the platform identifier (ro.board.platform or ro.chipname) to match.
325 * @param end - end of the platform identifier (ro.board.platform or ro.chipname) to match.
326 * @param[out] chipset - location where chipset information will be stored upon a successful match.
327 *
328 * @returns true if signature matched, false otherwise.
329 */
330static bool match_exynos(
331 const char* start, const char* end,
332 struct cpuinfo_arm_chipset chipset[restrict static 1])
333{
334 /* Expect exactly 10 symbols: "exynos" (6 symbols) + 4-digit model number */
335 if (start + 10 != end) {
336 return false;
337 }
338
339 /* Load first 4 bytes as little endian 32-bit word */
340 const uint32_t expected_exyn = load_u32le(start);
341 if (expected_exyn != UINT32_C(0x6E797865) /* "nyxe" = reverse("exyn") */ ) {
342 return false;
343 }
344
345 /* Load next 2 bytes as little endian 16-bit word */
346 const uint16_t expected_os = load_u16le(start + 4);
347 if (expected_os != UINT16_C(0x736F) /* "so" = reverse("os") */ ) {
348 return false;
349 }
350
351 /* Check and parse 4-digit model number */
352 uint32_t model = 0;
353 for (uint32_t i = 6; i < 10; i++) {
354 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
355 if (digit >= 10) {
356 /* Not really a digit */
357 return false;
358 }
359 model = model * 10 + digit;
360 }
361
362 /* Return parsed chipset. */
363 *chipset = (struct cpuinfo_arm_chipset) {
364 .vendor = cpuinfo_arm_chipset_vendor_samsung,
365 .series = cpuinfo_arm_chipset_series_samsung_exynos,
366 .model = model,
367 };
368 return true;
369}
370
371/**
372 * Tries to match /universal\d{4}$/ signature for Samsung Exynos chipsets.
373 * If match successful, extracts model information into \p chipset argument.
374 *
375 * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board or ro.chipname)
376 * to match.
377 * @param end - end of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board or ro.chipname)
378 * to match.
379 * @param[out] chipset - location where chipset information will be stored upon a successful match.
380 *
381 * @returns true if signature matched, false otherwise.
382 */
383static bool match_universal(
384 const char* start, const char* end,
385 struct cpuinfo_arm_chipset chipset[restrict static 1])
386{
387 /* Expect exactly 13 symbols: "universal" (9 symbols) + 4-digit model number */
388 if (start + 13 != end) {
389 return false;
390 }
391
392 /*
393 * Check that the string starts with "universal".
394 * Blocks of 4 characters are loaded and compared as little-endian 32-bit word.
395 * Case-insensitive characters are binary ORed with 0x20 to convert them to lowercase.
396 */
397 const uint8_t expected_u = UINT8_C(0x20) | (uint8_t) start[0];
398 if (expected_u != UINT8_C(0x75) /* "u" */) {
399 return false;
400 }
401 const uint32_t expected_nive = UINT32_C(0x20202020) | load_u32le(start + 1);
402 if (expected_nive != UINT32_C(0x6576696E) /* "evin" = reverse("nive") */ ) {
403 return false;
404 }
405 const uint32_t expected_ersa = UINT32_C(0x20202020) | load_u32le(start + 5);
406 if (expected_ersa != UINT32_C(0x6C617372) /* "lasr" = reverse("rsal") */) {
407 return false;
408 }
409
410 /* Validate and parse 4-digit model number */
411 uint32_t model = 0;
412 for (uint32_t i = 9; i < 13; i++) {
413 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
414 if (digit >= 10) {
415 /* Not really a digit */
416 return false;
417 }
418 model = model * 10 + digit;
419 }
420
421 /* Return parsed chipset. */
422 *chipset = (struct cpuinfo_arm_chipset) {
423 .vendor = cpuinfo_arm_chipset_vendor_samsung,
424 .series = cpuinfo_arm_chipset_series_samsung_exynos,
425 .model = model,
426 };
427 return true;
428}
429
430/**
431 * Compares, case insensitively, a string to known values "SMDK4210" and "SMDK4x12" for Samsung Exynos chipsets.
432 * If platform identifier matches one of the SMDK* values, extracts model information into \p chipset argument.
433 * For "SMDK4x12" match, decodes the chipset name using number of cores.
434 *
435 * @param start - start of the platform identifier (/proc/cpuinfo Hardware string or ro.product.board) to match.
436 * @param end - end of the platform identifier (/proc/cpuinfo Hardware string or ro.product.board) to match.
437 * @param cores - number of cores in the chipset.
438 * @param[out] chipset - location where chipset information will be stored upon a successful match.
439 *
440 * @returns true if signature matched, false otherwise.
441 */
442static bool match_and_parse_smdk(
443 const char* start, const char* end, uint32_t cores,
444 struct cpuinfo_arm_chipset chipset[restrict static 1])
445{
446 /* Expect exactly 8 symbols: "SMDK" (4 symbols) + 4-digit model number */
447 if (start + 8 != end) {
448 return false;
449 }
450
451 /*
452 * Check that string starts with "MT" (case-insensitive).
453 * The first four characters are loaded as a 32-bit little endian word and converted to lowercase.
454 */
455 const uint32_t expected_smdk = UINT32_C(0x20202020) | load_u32le(start);
456 if (expected_smdk != UINT32_C(0x6B646D73) /* "kdms" = reverse("smdk") */) {
457 return false;
458 }
459
460 /*
461 * Check that string ends with "4210" or "4x12".
462 * The last four characters are loaded and compared as a 32-bit little endian word.
463 */
464 uint32_t model = 0;
465 const uint32_t expected_model = load_u32le(start + 4);
466 switch (expected_model) {
467 case UINT32_C(0x30313234): /* "0124" = reverse("4210") */
468 model = 4210;
469 break;
470 case UINT32_C(0x32317834): /* "21x4" = reverse("4x12") */
471 switch (cores) {
472 case 2:
473 model = 4212;
474 break;
475 case 4:
476 model = 4412;
477 break;
478 default:
479 cpuinfo_log_warning("system reported invalid %"PRIu32"-core Exynos 4x12 chipset", cores);
480 }
481 }
482
483 if (model == 0) {
484 return false;
485 }
486
487 *chipset = (struct cpuinfo_arm_chipset) {
488 .vendor = cpuinfo_arm_chipset_vendor_samsung,
489 .series = cpuinfo_arm_chipset_series_samsung_exynos,
490 .model = model,
491 };
492 return true;
493}
494
495/**
496 * Tries to match /MTK?\d{4}[A-Z]*$/ signature for MediaTek MT chipsets.
497 * If match successful, extracts model information into \p chipset argument.
498 *
499 * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board, ro.board.platform,
500 * ro.mediatek.platform, or ro.chipname) to match.
501 * @param end - end of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board, ro.board.platform,
502 * ro.mediatek.platform, or ro.chipname) to match.
503 * @param match_end - indicates if the function should attempt to match through the end of the string and fail if there
504 * are unparsed characters in the end, or match only MTK signature, model number, and some of the
505 * suffix characters (the ones that pass validation).
506 * @param[out] chipset - location where chipset information will be stored upon a successful match.
507 *
508 * @returns true if signature matched, false otherwise.
509 */
510static bool match_mt(
511 const char* start, const char* end, bool match_end,
512 struct cpuinfo_arm_chipset chipset[restrict static 1])
513{
514 /* Expect at least 6 symbols: "MT" (2 symbols) + 4-digit model number */
515 if (start + 6 > end) {
516 return false;
517 }
518
519 /*
520 * Check that string starts with "MT" (case-insensitive).
521 * The first two characters are loaded as 16-bit little endian word and converted to lowercase.
522 */
523 const uint16_t mt = UINT16_C(0x2020) | load_u16le(start);
524 if (mt != UINT16_C(0x746D) /* "tm" */) {
525 return false;
526 }
527
528
529 /* Some images report "MTK" rather than "MT" */
530 const char* pos = start + 2;
531 if (((uint8_t) *pos | UINT8_C(0x20)) == (uint8_t) 'k') {
532 pos++;
533
534 /* Expect 4 more symbols after "MTK" (4-digit model number) */
535 if (pos + 4 > end) {
536 return false;
537 }
538 }
539
540 /* Validate and parse 4-digit model number */
541 uint32_t model = 0;
542 for (uint32_t i = 0; i < 4; i++) {
543 const uint32_t digit = (uint32_t) (uint8_t) (*pos++) - '0';
544 if (digit >= 10) {
545 /* Not really a digit */
546 return false;
547 }
548 model = model * 10 + digit;
549 }
550
551 /* Record parsed chipset. This implicitly zeroes-out suffix, which will be parsed later. */
552 *chipset = (struct cpuinfo_arm_chipset) {
553 .vendor = cpuinfo_arm_chipset_vendor_mediatek,
554 .series = cpuinfo_arm_chipset_series_mediatek_mt,
555 .model = model,
556 };
557
558 if (match_end) {
559 /* Check that the potential suffix does not exceed maximum length */
560 const size_t suffix_length = end - pos;
561 if (suffix_length > CPUINFO_ARM_CHIPSET_SUFFIX_MAX) {
562 return false;
563 }
564
565 /* Validate suffix characters and copy them to chipset structure */
566 for (size_t i = 0; i < suffix_length; i++) {
567 const char c = (*pos++);
568 if (is_ascii_alphabetic(c)) {
569 /* Matched a letter [A-Za-z], convert to uppercase */
570 chipset->suffix[i] = c & '\xDF';
571 } else if (c == '/') {
572 /* Matched a slash '/' */
573 chipset->suffix[i] = c;
574 } else {
575 /* Invalid suffix character (neither of [A-Za-z/]) */
576 return false;
577 }
578 }
579 } else {
580 /* Validate and parse as many suffix characters as we can */
581 for (size_t i = 0; i < CPUINFO_ARM_CHIPSET_SUFFIX_MAX; i++) {
582 if (pos + i == end) {
583 break;
584 }
585
586 const char c = pos[i];
587 if (is_ascii_alphabetic(c)) {
588 /* Matched a letter [A-Za-z], convert to uppercase */
589 chipset->suffix[i] = c & '\xDF';
590 } else if (c == '/') {
591 /* Matched a slash '/' */
592 chipset->suffix[i] = c;
593 } else {
594 /* Invalid suffix character (neither of [A-Za-z/]). This marks the end of the suffix. */
595 break;
596 }
597 }
598 }
599 /* All suffix characters successfully validated and copied to chipset data */
600 return true;
601}
602
603/**
604 * Tries to match /Kirin\s?\d{3}$/ signature for HiSilicon Kirin chipsets.
605 * If match successful, extracts model information into \p chipset argument.
606 *
607 * @param start - start of the /proc/cpuinfo Hardware string to match.
608 * @param end - end of the /proc/cpuinfo Hardware string to match.
609 * @param[out] chipset - location where chipset information will be stored upon a successful match.
610 *
611 * @returns true if signature matched, false otherwise.
612 */
613static bool match_kirin(
614 const char* start, const char* end,
615 struct cpuinfo_arm_chipset chipset[restrict static 1])
616{
617 /* Expect 8-9 symbols: "Kirin" (5 symbols) + optional whitespace (1 symbol) + 3-digit model number */
618 const size_t length = end - start;
619 switch (length) {
620 case 8:
621 case 9:
622 break;
623 default:
624 return false;
625 }
626
627 /* Check that the string starts with "Kirin". Symbols 1-5 are loaded and compared as little-endian 32-bit word. */
628 if (start[0] != 'K') {
629 return false;
630 }
631 const uint32_t irin = load_u32le(start + 1);
632 if (irin != UINT32_C(0x6E697269) /* "niri" = reverse("irin") */) {
633 return false;
634 }
635
636 /* Check for optional whitespace after "Kirin" */
637 if (is_ascii_whitespace(start[5])) {
638 /* When whitespace is present after "Kirin", expect 9 symbols total */
639 if (length != 9) {
640 return false;
641 }
642 }
643
644 /* Validate and parse 3-digit model number */
645 uint32_t model = 0;
646 for (int32_t i = 0; i < 3; i++) {
647 const uint32_t digit = (uint32_t) (uint8_t) end[i - 3] - '0';
648 if (digit >= 10) {
649 /* Not really a digit */
650 return start;
651 }
652 model = model * 10 + digit;
653 }
654
655 /*
656 * Thats it, return parsed chipset.
657 * Technically, Kirin 910T has a suffix, but it never appears in the form of "910T" string.
658 * Instead, Kirin 910T devices report "hi6620oem" string (handled outside of this function).
659 */
660 *chipset = (struct cpuinfo_arm_chipset) {
661 .vendor = cpuinfo_arm_chipset_vendor_hisilicon,
662 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
663 .model = model,
664 };
665 return true;
666}
667
668/**
669 * Tries to match /rk\d{4}[a-z]?$/ signature for Rockchip RK chipsets.
670 * If match successful, extracts model information into \p chipset argument.
671 *
672 * @param start - start of the platform identifier (/proc/cpuinfo Hardware string or ro.board.platform) to match.
673 * @param end - end of the platform identifier (/proc/cpuinfo Hardware string or ro.board.platform) to match.
674 * @param[out] chipset - location where chipset information will be stored upon a successful match.
675 *
676 * @returns true if signature matched, false otherwise.
677 */
678static bool match_rk(
679 const char* start, const char* end,
680 struct cpuinfo_arm_chipset chipset[restrict static 1])
681{
682 /* Expect 6-7 symbols: "RK" (2 symbols) + 4-digit model number + optional 1-letter suffix */
683 const size_t length = end - start;
684 switch (length) {
685 case 6:
686 case 7:
687 break;
688 default:
689 return false;
690 }
691
692 /*
693 * Check that string starts with "RK" (case-insensitive).
694 * The first two characters are loaded as 16-bit little endian word and converted to lowercase.
695 */
696 const uint16_t expected_rk = UINT16_C(0x2020) | load_u16le(start);
697 if (expected_rk != UINT16_C(0x6B72) /* "kr" = reverse("rk") */) {
698 return false;
699 }
700
701 /* Validate and parse 4-digit model number */
702 uint32_t model = 0;
703 for (uint32_t i = 2; i < 6; i++) {
704 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
705 if (digit >= 10) {
706 /* Not really a digit */
707 return start;
708 }
709 model = model * 10 + digit;
710 }
711
712 /* Parse optional suffix */
713 char suffix = 0;
714 if (length == 7) {
715 /* Parse the suffix letter */
716 const char c = start[6];
717 if (is_ascii_alphabetic(c)) {
718 /* Convert to upper case */
719 suffix = c & '\xDF';
720 } else {
721 /* Invalid suffix character */
722 return false;
723 }
724 }
725
726 /* Return parsed chipset */
727 *chipset = (struct cpuinfo_arm_chipset) {
728 .vendor = cpuinfo_arm_chipset_vendor_rockchip,
729 .series = cpuinfo_arm_chipset_series_rockchip_rk,
730 .model = model,
731 .suffix = {
732 [0] = suffix,
733 },
734 };
735 return true;
736}
737
738/**
739 * Tries to match, case-insentitively, /sc\d{4}[a-z]*|scx15$/ signature for Spreadtrum SC chipsets.
740 * If match successful, extracts model information into \p chipset argument.
741 *
742 * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board,
743 * ro.board.platform, or ro.chipname) to match.
744 * @param end - end of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board,
745 * ro.board.platform, or ro.chipname) to match.
746 * @param[out] chipset - location where chipset information will be stored upon a successful match.
747 *
748 * @returns true if signature matched, false otherwise.
749 */
750static bool match_sc(
751 const char* start, const char* end,
752 struct cpuinfo_arm_chipset chipset[restrict static 1])
753{
754 /* Expect at least 5 symbols: "scx15" */
755 if (start + 5 > end) {
756 return false;
757 }
758
759 /*
760 * Check that string starts with "SC" (case-insensitive).
761 * The first two characters are loaded as 16-bit little endian word and converted to lowercase.
762 */
763 const uint16_t expected_sc = UINT16_C(0x2020) | load_u16le(start);
764 if (expected_sc != UINT16_C(0x6373) /* "cs" = reverse("sc") */) {
765 return false;
766 }
767
768 /* Special case: "scx" prefix (SC7715 reported as "scx15") */
769 if ((start[2] | '\x20') == 'x') {
770 /* Expect exactly 5 characters: "scx15" */
771 if (start + 5 != end) {
772 return false;
773 }
774
775 /* Check that string ends with "15" */
776 const uint16_t expected_15 = load_u16le(start + 3);
777 if (expected_15 != UINT16_C(0x3531) /* "51" = reverse("15") */ ) {
778 return false;
779 }
780
781 *chipset = (struct cpuinfo_arm_chipset) {
782 .vendor = cpuinfo_arm_chipset_vendor_spreadtrum,
783 .series = cpuinfo_arm_chipset_series_spreadtrum_sc,
784 .model = 7715,
785 };
786 return true;
787 }
788
789 /* Expect at least 6 symbols: "SC" (2 symbols) + 4-digit model number */
790 if (start + 6 > end) {
791 return false;
792 }
793
794 /* Validate and parse 4-digit model number */
795 uint32_t model = 0;
796 for (uint32_t i = 2; i < 6; i++) {
797 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
798 if (digit >= 10) {
799 /* Not really a digit */
800 return false;
801 }
802 model = model * 10 + digit;
803 }
804
805 /* Write parsed chipset */
806 *chipset = (struct cpuinfo_arm_chipset) {
807 .vendor = cpuinfo_arm_chipset_vendor_spreadtrum,
808 .series = cpuinfo_arm_chipset_series_spreadtrum_sc,
809 .model = model,
810 };
811
812 /* Validate and copy suffix letters. If suffix is too long, truncate at CPUINFO_ARM_CHIPSET_SUFFIX_MAX letters. */
813 const char* suffix = start + 6;
814 for (size_t i = 0; i < CPUINFO_ARM_CHIPSET_SUFFIX_MAX; i++) {
815 if (suffix + i == end) {
816 break;
817 }
818
819 const char c = suffix[i];
820 if (!is_ascii_alphabetic(c)) {
821 /* Invalid suffix character */
822 return false;
823 }
824 /* Convert suffix letter to uppercase */
825 chipset->suffix[i] = c & '\xDF';
826 }
827 return true;
828}
829
830/**
831 * Tries to match /lc\d{4}[a-z]?$/ signature for Leadcore LC chipsets.
832 * If match successful, extracts model information into \p chipset argument.
833 *
834 * @param start - start of the platform identifier (ro.product.board or ro.board.platform) to match.
835 * @param end - end of the platform identifier (ro.product.board or ro.board.platform) to match.
836 * @param[out] chipset - location where chipset information will be stored upon a successful match.
837 *
838 * @returns true if signature matched, false otherwise.
839 */
840static bool match_lc(
841 const char* start, const char* end,
842 struct cpuinfo_arm_chipset chipset[restrict static 1])
843{
844 /* Expect at 6-7 symbols: "lc" (2 symbols) + 4-digit model number + optional 1-letter suffix */
845 const size_t length = end - start;
846 switch (length) {
847 case 6:
848 case 7:
849 break;
850 default:
851 return false;
852 }
853
854 /* Check that string starts with "lc". The first two characters are loaded as 16-bit little endian word */
855 const uint16_t expected_lc = load_u16le(start);
856 if (expected_lc != UINT16_C(0x636C) /* "cl" = reverse("lc") */) {
857 return false;
858 }
859
860 /* Validate and parse 4-digit model number */
861 uint32_t model = 0;
862 for (uint32_t i = 2; i < 6; i++) {
863 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
864 if (digit >= 10) {
865 /* Not really a digit */
866 return false;
867 }
868 model = model * 10 + digit;
869 }
870
871 /* Parse optional suffix letter */
872 char suffix = 0;
873 if (length == 7) {
874 const char c = start[6];
875 if (is_ascii_alphabetic(c)) {
876 /* Convert to uppercase */
877 chipset->suffix[0] = c & '\xDF';
878 } else {
879 /* Invalid suffix character */
880 return false;
881 }
882 }
883
884 /* Return parsed chipset */
885 *chipset = (struct cpuinfo_arm_chipset) {
886 .vendor = cpuinfo_arm_chipset_vendor_leadcore,
887 .series = cpuinfo_arm_chipset_series_leadcore_lc,
888 .model = model,
889 .suffix = {
890 [0] = suffix,
891 },
892 };
893 return true;
894}
895
896/**
897 * Tries to match /PXA(\d{3,4}|1L88)$/ signature for Marvell PXA chipsets.
898 * If match successful, extracts model information into \p chipset argument.
899 *
900 * @param start - start of the platform identifier (/proc/cpuinfo Hardware string, ro.product.board or ro.chipname)
901 * to match.
902 * @param end - end of the platform identifier (/proc/cpuinfo Hardaware string, ro.product.board or ro.chipname) to
903 * match.
904 * @param[out] chipset - location where chipset information will be stored upon a successful match.
905 *
906 * @returns true if signature matched, false otherwise.
907 */
908static bool match_pxa(
909 const char* start, const char* end,
910 struct cpuinfo_arm_chipset chipset[restrict static 1])
911{
912 /* Expect 6-7 symbols: "PXA" (3 symbols) + 3-4 digit model number */
913 const size_t length = end - start;
914 switch (length) {
915 case 6:
916 case 7:
917 break;
918 default:
919 return false;
920 }
921
922 /* Check that the string starts with "PXA". Symbols 1-3 are loaded and compared as little-endian 16-bit word. */
923 if (start[0] != 'P') {
924 return false;
925 }
926 const uint16_t expected_xa = load_u16le(start + 1);
927 if (expected_xa != UINT16_C(0x4158) /* "AX" = reverse("XA") */) {
928 return false;
929 }
930
931 uint32_t model = 0;
932
933
934 /* Check for a very common typo: "PXA1L88" for "PXA1088" */
935 if (length == 7) {
936 /* Load 4 model "number" symbols as a little endian 32-bit word and compare to "1L88" */
937 const uint32_t expected_1L88 = load_u32le(start + 3);
938 if (expected_1L88 == UINT32_C(0x38384C31) /* "88L1" = reverse("1L88") */) {
939 model = 1088;
940 goto write_chipset;
941 }
942 }
943
944 /* Check and parse 3-4 digit model number */
945 for (uint32_t i = 3; i < length; i++) {
946 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
947 if (digit >= 10) {
948 /* Not really a digit */
949 return false;
950 }
951 model = model * 10 + digit;
952 }
953
954 /* Return parsed chipset. */
955write_chipset:
956 *chipset = (struct cpuinfo_arm_chipset) {
957 .vendor = cpuinfo_arm_chipset_vendor_marvell,
958 .series = cpuinfo_arm_chipset_series_marvell_pxa,
959 .model = model,
960 };
961 return true;
962}
963
964/**
965 * Tries to match /OMAP\d{4}$/ signature for Texas Instruments OMAP chipsets.
966 * If match successful, extracts model information into \p chipset argument.
967 *
968 * @param start - start of the /proc/cpuinfo Hardware string to match.
969 * @param end - end of the /proc/cpuinfo Hardaware string to match.
970 * @param[out] chipset - location where chipset information will be stored upon a successful match.
971 *
972 * @returns true if signature matched, false otherwise.
973 */
974static bool match_omap(
975 const char* start, const char* end,
976 struct cpuinfo_arm_chipset chipset[restrict static 1])
977{
978 /* Expect exactly 8 symbols: "OMAP" (4 symbols) + 4-digit model number */
979 if (start + 8 != end) {
980 return false;
981 }
982
983 /* Check that the string starts with "OMAP". Symbols 0-4 are loaded and compared as little-endian 32-bit word. */
984 const uint32_t expected_omap = load_u32le(start);
985 if (expected_omap != UINT32_C(0x50414D4F) /* "PAMO" = reverse("OMAP") */) {
986 return false;
987 }
988
989 /* Validate and parse 4-digit model number */
990 uint32_t model = 0;
991 for (uint32_t i = 4; i < 8; i++) {
992 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
993 if (digit >= 10) {
994 /* Not really a digit */
995 return false;
996 }
997 model = model * 10 + digit;
998 }
999
1000 /* Return parsed chipset. */
1001 *chipset = (struct cpuinfo_arm_chipset) {
1002 .vendor = cpuinfo_arm_chipset_vendor_texas_instruments,
1003 .series = cpuinfo_arm_chipset_series_texas_instruments_omap,
1004 .model = model,
1005 };
1006 return true;
1007}
1008
1009/**
1010 * Compares platform identifier string to known values for Broadcom chipsets.
1011 * If the string matches one of the known values, the function decodes Broadcom chipset from frequency and number of
1012 * cores into \p chipset argument.
1013 *
1014 * @param start - start of the platform identifier (ro.product.board or ro.board.platform) to match.
1015 * @param end - end of the platform identifier (ro.product.board or ro.board.platform) to match.
1016 * @param cores - number of cores in the chipset.
1017 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
1018 * @param[out] chipset - location where chipset information will be stored upon a successful match and decoding.
1019 *
1020 * @returns true if signature matched (even if exact model can't be decoded), false otherwise.
1021 */
1022static bool match_and_parse_broadcom(
1023 const char* start, const char* end, uint32_t cores, uint32_t max_cpu_freq_max,
1024 struct cpuinfo_arm_chipset chipset[restrict static 1])
1025{
1026 /* Expect 4-6 symbols: "java" (4 symbols), "rhea" (4 symbols), "capri" (5 symbols), or "hawaii" (6 symbols) */
1027 const size_t length = end - start;
1028 switch (length) {
1029 case 4:
1030 case 5:
1031 case 6:
1032 break;
1033 default:
1034 return false;
1035 }
1036
1037 /*
1038 * Compare the platform identifier to known values for Broadcom chipsets:
1039 * - "rhea"
1040 * - "java"
1041 * - "capri"
1042 * - "hawaii"
1043 * Upon a successful match, decode chipset name from frequency and number of cores.
1044 */
1045 uint32_t model = 0;
1046 char suffix = 0;
1047 const uint32_t expected_platform = load_u32le(start);
1048 switch (expected_platform) {
1049 case UINT32_C(0x61656872): /* "aehr" = reverse("rhea") */
1050 if (length == 4) {
1051 /*
1052 * Detected "rhea" platform:
1053 * - 1 core @ 849999 KHz -> BCM21654
1054 * - 1 core @ 999999 KHz -> BCM21654G
1055 */
1056 if (cores == 1) {
1057 model = 21654;
1058 if (max_cpu_freq_max >= 999999) {
1059 suffix = 'G';
1060 }
1061 }
1062 }
1063 break;
1064 case UINT32_C(0x6176616A): /* "avaj" = reverse("java") */
1065 if (length == 4) {
1066 /*
1067 * Detected "java" platform:
1068 * - 4 cores -> BCM23550
1069 */
1070 if (cores == 4) {
1071 model = 23550;
1072 }
1073 }
1074 break;
1075 case UINT32_C(0x61776168): /* "awah" = reverse("hawa") */
1076 if (length == 6) {
1077 /* Check that string equals "hawaii" */
1078 const uint16_t expected_ii = load_u16le(start + 4);
1079 if (expected_ii == UINT16_C(0x6969) /* "ii" */ ) {
1080 /*
1081 * Detected "hawaii" platform:
1082 * - 1 core -> BCM21663
1083 * - 2 cores @ 999999 KHz -> BCM21664
1084 * - 2 cores @ 1200000 KHz -> BCM21664T
1085 */
1086 switch (cores) {
1087 case 1:
1088 model = 21663;
1089 break;
1090 case 2:
1091 model = 21664;
1092 if (max_cpu_freq_max >= 1200000) {
1093 suffix = 'T';
1094 }
1095 break;
1096 }
1097 }
1098 }
1099 break;
1100 case UINT32_C(0x72706163): /* "rpac" = reverse("capr") */
1101 if (length == 5) {
1102 /* Check that string equals "capri" */
1103 if (start[4] == 'i') {
1104 /*
1105 * Detected "capri" platform:
1106 * - 2 cores -> BCM28155
1107 */
1108 if (cores == 2) {
1109 model = 28155;
1110 }
1111 }
1112 }
1113 break;
1114 }
1115
1116 if (model != 0) {
1117 /* Chipset was successfully decoded */
1118 *chipset = (struct cpuinfo_arm_chipset) {
1119 .vendor = cpuinfo_arm_chipset_vendor_broadcom,
1120 .series = cpuinfo_arm_chipset_series_broadcom_bcm,
1121 .model = model,
1122 .suffix = {
1123 [0] = suffix,
1124 },
1125 };
1126 }
1127 return model != 0;
1128}
1129
1130struct sunxi_map_entry {
1131 uint8_t sunxi;
1132 uint8_t cores;
1133 uint8_t model;
1134 char suffix;
1135};
1136
1137static const struct sunxi_map_entry sunxi_map_entries[] = {
1138 {
1139 /* ("sun4i", 1) -> "A10" */
1140 .sunxi = 4,
1141 .cores = 1,
1142 .model = 10,
1143 },
1144 {
1145 /* ("sun5i", 1) -> "A13" */
1146 .sunxi = 5,
1147 .cores = 1,
1148 .model = 13,
1149 },
1150 {
1151 /* ("sun6i", 4) -> "A31" */
1152 .sunxi = 6,
1153 .cores = 4,
1154 .model = 31,
1155 },
1156 {
1157 /* ("sun7i", 2) -> "A20" */
1158 .sunxi = 7,
1159 .cores = 2,
1160 .model = 20,
1161
1162 },
1163 {
1164 /* ("sun8i", 2) -> "A23" */
1165 .sunxi = 8,
1166 .cores = 2,
1167 .model = 23,
1168 },
1169 {
1170 /* ("sun8i", 4) -> "A33" */
1171 .sunxi = 8,
1172 .cores = 4,
1173 .model = 33,
1174 },
1175 {
1176 /* ("sun8i", 8) -> "A83T" */
1177 .sunxi = 8,
1178 .cores = 8,
1179 .model = 83,
1180 .suffix = 'T',
1181 },
1182 {
1183 /* ("sun9i", 8) -> "A80" */
1184 .sunxi = 9,
1185 .cores = 8,
1186 .model = 80,
1187 },
1188 {
1189 /* ("sun50i", 4) -> "A64" */
1190 .sunxi = 50,
1191 .cores = 4,
1192 .model = 64,
1193 },
1194};
1195
1196/**
1197 * Tries to match /proc/cpuinfo Hardware string to Allwinner /sun\d+i/ signature.
1198 * If the string matches signature, the function decodes Allwinner chipset from the number in the signature and the
1199 * number of cores, and stores it in \p chipset argument.
1200 *
1201 * @param start - start of the /proc/cpuinfo Hardware string to match.
1202 * @param end - end of the /proc/cpuinfo Hardware string to match.
1203 * @param cores - number of cores in the chipset.
1204 * @param[out] chipset - location where chipset information will be stored upon a successful match and decoding.
1205 *
1206 * @returns true if signature matched (even if exact model can't be decoded), false otherwise.
1207 */
1208static bool match_and_parse_sunxi(
1209 const char* start, const char* end, uint32_t cores,
1210 struct cpuinfo_arm_chipset chipset[restrict static 1])
1211{
1212 /* Expect at least 5 symbols: "sun" (3 symbols) + platform id (1-2 digits) + "i" (1 symbol) */
1213 if (start + 5 > end) {
1214 return false;
1215 }
1216
1217 /* Compare the first 3 characters to "sun" */
1218 if (start[0] != 's') {
1219 return false;
1220 }
1221 const uint16_t expected_un = load_u16le(start + 1);
1222 if (expected_un != UINT16_C(0x6E75) /* "nu" = reverse("un") */) {
1223 return false;
1224 }
1225
1226 /* Check and parse the first (required) digit of the sunXi platform id */
1227 uint32_t sunxi_platform = 0;
1228 {
1229 const uint32_t digit = (uint32_t) (uint8_t) start[3] - '0';
1230 if (digit >= 10) {
1231 /* Not really a digit */
1232 return false;
1233 }
1234 sunxi_platform = digit;
1235 }
1236
1237 /* Parse optional second digit of the sunXi platform id */
1238 const char* pos = start + 4;
1239 {
1240 const uint32_t digit = (uint32_t) (uint8_t) (*pos) - '0';
1241 if (digit < 10) {
1242 sunxi_platform = sunxi_platform * 10 + digit;
1243 if (++pos == end) {
1244 /* Expected one more character, final 'i' letter */
1245 return false;
1246 }
1247 }
1248 }
1249
1250 /* Validate the final 'i' letter */
1251 if (*pos != 'i') {
1252 return false;
1253 }
1254
1255 /* Compare sunXi platform id and number of cores to tabluted values to decode chipset name */
1256 uint32_t model = 0;
1257 char suffix = 0;
1258 for (size_t i = 0; i < CPUINFO_COUNT_OF(sunxi_map_entries); i++) {
1259 if (sunxi_platform == sunxi_map_entries[i].sunxi && cores == sunxi_map_entries[i].cores) {
1260 model = sunxi_map_entries[i].model;
1261 suffix = sunxi_map_entries[i].suffix;
1262 break;
1263 }
1264 }
1265
1266 if (model == 0) {
1267 cpuinfo_log_info("unrecognized %"PRIu32"-core Allwinner sun%"PRIu32" platform", cores, sunxi_platform);
1268 }
1269 /* Create chipset name from decoded data */
1270 *chipset = (struct cpuinfo_arm_chipset) {
1271 .vendor = cpuinfo_arm_chipset_vendor_allwinner,
1272 .series = cpuinfo_arm_chipset_series_allwinner_a,
1273 .model = model,
1274 .suffix = {
1275 [0] = suffix,
1276 },
1277 };
1278 return true;
1279}
1280
1281/**
1282 * Compares /proc/cpuinfo Hardware string to "WMT" signature.
1283 * If the string matches signature, the function decodes WonderMedia chipset from frequency and number of cores into
1284 * \p chipset argument.
1285 *
1286 * @param start - start of the /proc/cpuinfo Hardware string to match.
1287 * @param end - end of the /proc/cpuinfo Hardware string to match.
1288 * @param cores - number of cores in the chipset.
1289 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
1290 * @param[out] chipset - location where chipset information will be stored upon a successful match and decoding.
1291 *
1292 * @returns true if signature matched (even if exact model can't be decoded), false otherwise.
1293 */
1294static bool match_and_parse_wmt(
1295 const char* start, const char* end, uint32_t cores, uint32_t max_cpu_freq_max,
1296 struct cpuinfo_arm_chipset chipset[restrict static 1])
1297{
1298 /* Expected 3 symbols: "WMT" */
1299 if (start + 3 != end) {
1300 return false;
1301 }
1302
1303 /* Compare string to "WMT" */
1304 if (start[0] != 'W') {
1305 return false;
1306 }
1307 const uint16_t expected_mt = load_u16le(start + 1);
1308 if (expected_mt != UINT16_C(0x544D) /* "TM" = reverse("MT") */) {
1309 return false;
1310 }
1311
1312 /* Decode chipset name from frequency and number of cores */
1313 uint32_t model = 0;
1314 switch (cores) {
1315 case 1:
1316 switch (max_cpu_freq_max) {
1317 case 1008000:
1318 /* 1 core @ 1008000 KHz -> WM8950 */
1319 model = 8950;
1320 break;
1321 case 1200000:
1322 /* 1 core @ 1200000 KHz -> WM8850 */
1323 model = 8850;
1324 break;
1325 }
1326 break;
1327 case 2:
1328 if (max_cpu_freq_max == 1500000) {
1329 /* 2 cores @ 1500000 KHz -> WM8880 */
1330 model = 8880;
1331 }
1332 break;
1333 }
1334
1335 if (model == 0) {
1336 cpuinfo_log_info("unrecognized WonderMedia platform with %"PRIu32" cores at %"PRIu32" KHz",
1337 cores, max_cpu_freq_max);
1338 }
1339 *chipset = (struct cpuinfo_arm_chipset) {
1340 .vendor = cpuinfo_arm_chipset_vendor_wondermedia,
1341 .series = cpuinfo_arm_chipset_series_wondermedia_wm,
1342 .model = model,
1343 };
1344 return true;
1345}
1346
1347struct huawei_map_entry {
1348 uint32_t platform;
1349 uint32_t model;
1350};
1351
1352static const struct huawei_map_entry huawei_platform_map[] = {
1353 {
1354 /* "BAC" -> Kirin 659 */
1355 .platform = UINT32_C(0x00434142), /* "\0CAB" = reverse("BAC\0") */
1356 .model = 659,
1357 },
1358 {
1359 /* "DUK" -> Kirin 960 */
1360 .platform = UINT32_C(0x004B5544), /* "\0KUD" = reverse("DUK\0") */
1361 .model = 960,
1362 },
1363 {
1364 /* "EVA" -> Kirin 955 */
1365 .platform = UINT32_C(0x00415645), /* "\0AVE" = reverse("EVA\0") */
1366 .model = 955,
1367 },
1368 {
1369 /* "FRD" -> Kirin 950 */
1370 .platform = UINT32_C(0x00445246), /* "\0DRF" = reverse("FRD\0") */
1371 .model = 950,
1372 },
1373 {
1374 /* "KNT" -> Kirin 950 */
1375 .platform = UINT32_C(0x00544E4B), /* "\0TNK" = reverse("KNT\0") */
1376 .model = 950,
1377 },
1378 {
1379 /* "LON" -> Kirin 960 */
1380 .platform = UINT32_C(0x004E4F4C), /* "\0NOL" = reverse("LON\0") */
1381 .model = 960,
1382 },
1383 {
1384 /* "MHA" -> Kirin 960 */
1385 .platform = UINT32_C(0x0041484D), /* "\0AHM" = reverse("MHA\0") */
1386 .model = 960,
1387 },
1388 {
1389 /* "NXT" -> Kirin 950 */
1390 .platform = UINT32_C(0x0054584E), /* "\0TXN" = reverse("NXT\0") */
1391 .model = 950,
1392 },
1393 {
1394 /* "STF" -> Kirin 960 */
1395 .platform = UINT32_C(0x00465453), /* "\0FTS" = reverse("STF\0") */
1396 .model = 960,
1397 },
1398 {
1399 /* "VIE" -> Kirin 955 */
1400 .platform = UINT32_C(0x00454956), /* "\0EIV" = reverse("VIE\0") */
1401 .model = 955,
1402 },
1403 {
1404 /* "VKY" -> Kirin 960 */
1405 .platform = UINT32_C(0x00594B56), /* "\0YKV" = reverse("VKY\0") */
1406 .model = 960,
1407 },
1408 {
1409 /* "VTR" -> Kirin 960 */
1410 .platform = UINT32_C(0x00525456), /* "\0RTV" = reverse("VTR\0") */
1411 .model = 960,
1412 },
1413};
1414
1415/**
1416 * Tries to match ro.product.board string to Huawei /([A-Z]{3})(\-[A-Z]?L\d{2})$/ signature where \1 is one of the
1417 * known values for Huawei devices, which do not report chipset name elsewhere.
1418 * If the string matches signature, the function decodes chipset (always HiSilicon Kirin for matched devices) from
1419 * the number in the signature and stores it in \p chipset argument.
1420 *
1421 * @param start - start of the ro.product.board string to match.
1422 * @param end - end of the ro.product.board string to match.
1423 * @param[out] chipset - location where chipset information will be stored upon a successful match and decoding.
1424 *
1425 * @returns true if signature matched, false otherwise.
1426 */
1427static bool match_and_parse_huawei(
1428 const char* start, const char* end,
1429 struct cpuinfo_arm_chipset chipset[restrict static 1])
1430{
1431 /*
1432 * Expect length of either 3, 7 or 8, exactly:
1433 * - 3-letter platform identifier (see huawei_platform_map)
1434 * - 3-letter platform identifier + '-' + 'L' + two digits
1435 * - 3-letter platform identifier + '-' + capital letter + 'L' + two digits
1436 */
1437 const size_t length = end - start;
1438 switch (length) {
1439 case 3:
1440 case 7:
1441 case 8:
1442 break;
1443 default:
1444 return false;
1445 }
1446
1447 /*
1448 * Try to find the first three-letter substring in among the tabulated entries for Huawei devices.
1449 * The first three letters are loaded and compared as a little-endian 24-bit word.
1450 */
1451 uint32_t model = 0;
1452 const uint32_t target_platform_id = load_u24le(start);
1453 for (uint32_t i = 0; i < CPUINFO_COUNT_OF(huawei_platform_map); i++) {
1454 if (huawei_platform_map[i].platform == target_platform_id) {
1455 model = huawei_platform_map[i].model;
1456 break;
1457 }
1458 }
1459
1460 if (model == 0) {
1461 /* Platform does not match the tabulated Huawei entries */
1462 return false;
1463 }
1464
1465 if (length > 3) {
1466 /*
1467 * Check that:
1468 * - The symbol after platform id is a dash
1469 * - The symbol after it is an uppercase letter. For 7-symbol strings, the symbol is just 'L'.
1470 */
1471 if (start[3] != '-' || !is_ascii_alphabetic_uppercase(start[4])) {
1472 return false;
1473 }
1474
1475 /* Check that the last 3 entries are /L\d\d/ */
1476 if (end[-3] != 'L' || !is_ascii_numeric(end[-2]) || !is_ascii_numeric(end[-1])) {
1477 return false;
1478 }
1479 }
1480
1481 /* All checks succeeded, commit chipset name */
1482 *chipset = (struct cpuinfo_arm_chipset) {
1483 .vendor = cpuinfo_arm_chipset_vendor_hisilicon,
1484 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1485 .model = model,
1486 };
1487 return true;
1488}
1489
1490/**
1491 * Tries to match /tcc\d{3}x$/ signature for Telechips TCCXXXx chipsets.
1492 * If match successful, extracts model information into \p chipset argument.
1493 *
1494 * @param start - start of the /proc/cpuinfo Hardware string to match.
1495 * @param end - end of the /proc/cpuinfo Hardware string to match.
1496 * @param[out] chipset - location where chipset information will be stored upon a successful match.
1497 *
1498 * @returns true if signature matched, false otherwise.
1499 */
1500static bool match_tcc(
1501 const char* start, const char* end,
1502 struct cpuinfo_arm_chipset chipset[restrict static 1])
1503{
1504 /* Expect exactly 7 symbols: "tcc" (3 symbols) + 3-digit model number + fixed "x" suffix */
1505 if (start + 7 != end) {
1506 return false;
1507 }
1508
1509 /* Quick check for the first character */
1510 if (start[0] != 't') {
1511 return false;
1512 }
1513
1514 /* Load the next 2 bytes as little endian 16-bit word */
1515 const uint16_t expected_cc = load_u16le(start + 1);
1516 if (expected_cc != UINT16_C(0x6363) /* "cc" */ ) {
1517 return false;
1518 }
1519
1520 /* Check and parse 3-digit model number */
1521 uint32_t model = 0;
1522 for (uint32_t i = 3; i < 6; i++) {
1523 const uint32_t digit = (uint32_t) (uint8_t) start[i] - '0';
1524 if (digit >= 10) {
1525 /* Not really a digit */
1526 return false;
1527 }
1528 model = model * 10 + digit;
1529 }
1530
1531 /* Check the fixed 'x' suffix in the end */
1532 if (start[6] != 'x') {
1533 return false;
1534 }
1535
1536 /* Commit parsed chipset. */
1537 *chipset = (struct cpuinfo_arm_chipset) {
1538 .vendor = cpuinfo_arm_chipset_vendor_telechips,
1539 .series = cpuinfo_arm_chipset_series_telechips_tcc,
1540 .model = model,
Marat Dukhan63a6a102017-08-24 21:28:02 -07001541 .suffix = {
1542 [0] = 'X'
1543 },
Marat Dukhan006461a2017-08-24 16:10:46 -07001544 };
1545 return true;
1546}
1547
1548/*
1549 * Compares ro.board.platform string to nVidia Tegra signatures ("tegra" and "tegra3")
1550 * This check has effect on how /proc/cpuinfo Hardware string is interpreted.
1551 *
1552 * @param start - start of the ro.board.platform string to check.
1553 * @param end - end of the ro.board.platform string to check.
1554 *
1555 * @returns true if the string matches an nVidia Tegra signature, and false otherwise
1556 */
1557static bool is_tegra(const char* start, const char* end) {
1558 /* Expect 5 ("tegra") or 6 ("tegra3") symbols */
1559 const size_t length = end - start;
1560 switch (length) {
1561 case 5:
1562 case 6:
1563 break;
1564 default:
1565 return false;
1566 }
1567
1568 /* Check that the first 5 characters match "tegra" */
1569 if (start[0] != 't') {
1570 return false;
1571 }
1572 const uint32_t expected_egra = load_u32le(start + 1);
1573 if (expected_egra != UINT32_C(0x61726765) /* "arge" = reverse("egra") */) {
1574 return false;
1575 }
1576
1577 /* Check if the string is either "tegra" (length = 5) or "tegra3" (length != 5) and last character is '3' */
1578 return (length == 5 || start[5] == '3');
1579}
1580
1581struct special_map_entry {
1582 const char* platform;
1583 uint16_t model;
1584 uint8_t series;
1585 char suffix;
1586};
1587
1588static const struct special_map_entry special_hardware_map_entries[] = {
1589 {
1590 /* "k3v2oem1" -> HiSilicon K3V2 */
1591 .platform = "k3v2oem1",
1592 .series = cpuinfo_arm_chipset_series_hisilicon_k3v,
1593 .model = 2,
1594 },
1595 {
1596 /* "hi6620oem" -> HiSilicon Kirin 910T */
1597 .platform = "hi6620oem",
1598 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1599 .model = 910,
1600 .suffix = 'T'
1601 },
1602 {
1603 /* "hi6250" -> HiSilicon Kirin 650 */
1604 .platform = "hi6250",
1605 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1606 .model = 650,
1607 },
1608 {
1609 /* "hi6210sft" -> HiSilicon Kirin 620 */
1610 .platform = "hi6210sft",
1611 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1612 .model = 620,
1613 },
1614 {
1615 /* "hi3751" -> HiSilicon Hi3751 */
1616 .platform = "hi3751",
1617 .series = cpuinfo_arm_chipset_series_hisilicon_hi,
1618 .model = 3751,
1619 },
1620 {
1621 /* "hi3635" -> HiSilicon Kirin 930 */
1622 .platform = "hi3635",
1623 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1624 .model = 930,
1625 },
1626 {
1627 /* "hi3630" -> HiSilicon Kirin 920 */
1628 .platform = "hi3630",
1629 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
1630 .model = 920,
1631 },
1632 {
1633 /* "gs705a" -> Actions ATM7059A */
1634 .platform = "gs705a",
1635 .series = cpuinfo_arm_chipset_series_actions_atm,
1636 .model = 7059,
1637 .suffix = 'A',
1638 },
1639 {
1640 /* "gs702a" -> Actions ATM7029 */
1641 .platform = "gs702a",
1642 .series = cpuinfo_arm_chipset_series_actions_atm,
1643 .model = 7029,
1644 },
1645 {
1646 /* "gs702c" -> Actions ATM7029B */
1647 .platform = "gs702c",
1648 .series = cpuinfo_arm_chipset_series_actions_atm,
1649 .model = 7029,
1650 .suffix = 'B'
1651 },
1652 {
1653 /* "Amlogic Meson8" -> Amlogic S812 */
1654 .platform = "Amlogic Meson8",
1655 .series = cpuinfo_arm_chipset_series_amlogic_s,
1656 .model = 812,
1657 },
1658 {
1659 /* "Amlogic Meson8B" -> Amlogic S805 */
1660 .platform = "Amlogic Meson8B",
1661 .series = cpuinfo_arm_chipset_series_amlogic_s,
1662 .model = 805,
1663 },
1664 {
1665 /* "mapphone_CDMA" -> Texas Instruments OMAP4430 */
1666 .platform = "mapphone_CDMA",
1667 .series = cpuinfo_arm_chipset_series_texas_instruments_omap,
1668 .model = 4430,
1669 },
1670 {
1671 /* "Tuna" (Samsung Galaxy Nexus) -> Texas Instruments OMAP4460 */
1672 .platform = "Tuna",
1673 .series = cpuinfo_arm_chipset_series_texas_instruments_omap,
1674 .model = 4460,
1675 },
1676 {
1677 /* "Manta" (Samsung Nexus 10) -> Samsung Exynos 5250 */
1678 .platform = "Manta",
1679 .series = cpuinfo_arm_chipset_series_samsung_exynos,
1680 .model = 5250,
1681 },
1682 {
1683 /* "Odin" -> LG Nuclun 7111 */
1684 .platform = "Odin",
1685 .series = cpuinfo_arm_chipset_series_lg_nuclun,
1686 .model = 7111,
1687 },
1688 {
1689 /* "Madison" -> MStar 6A338 */
1690 .platform = "Madison",
1691 .series = cpuinfo_arm_chipset_series_mstar_6a,
1692 .model = 338,
1693 },
1694};
1695
1696static const struct special_map_entry tegra_hardware_map_entries[] = {
1697 {
1698 /* "cardhu" (nVidia Cardhu developer tablet) -> Tegra T30 */
1699 .platform = "cardhu",
1700 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1701 .model = 30,
1702 },
1703 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001704 /* "kai" -> Tegra T30L */
1705 .platform = "kai",
1706 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1707 .model = 30,
1708 .suffix = 'L',
1709 },
1710 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001711 /* "p3" (Samsung Galaxy Tab 8.9) -> Tegra T20 */
1712 .platform = "p3",
1713 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1714 .model = 20,
1715 },
1716 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001717 /* "n1" (Samsung Galaxy R / Samsung Captivate Glide) -> Tegra AP20H */
1718 .platform = "n1",
1719 .series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1720 .model = 20,
1721 .suffix = 'H',
1722 },
1723 {
1724 /* "SHW-M380S" (Samsung Galaxy Tab 10.1) -> Tegra T20 */
1725 .platform = "SHW-M380S",
1726 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1727 .model = 20,
1728 },
1729 {
1730 /* "m470" (Hisense Sero 7 Pro) -> Tegra T30L */
1731 .platform = "m470",
1732 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1733 .model = 30,
1734 .suffix = 'L',
1735 },
1736 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001737 /* "endeavoru" (HTC One X) -> Tegra AP33 */
1738 .platform = "endeavoru",
1739 .series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1740 .model = 33,
1741 },
1742 {
1743 /* "evitareul" (HTC One X+) -> Tegra T33 */
1744 .platform = "evitareul",
1745 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1746 .model = 33,
1747 },
1748 {
1749 /* "enrc2b" (HTC One X+) -> Tegra T33 */
1750 .platform = "enrc2b",
1751 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1752 .model = 33,
1753 },
1754 {
1755 /* "mozart" (Asus Transformer Pad TF701T) -> Tegra T114 */
1756 .platform = "mozart",
1757 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1758 .model = 114,
1759 },
1760 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001761 /* "tegratab" (Tegra Note 7) -> Tegra T114 */
1762 .platform = "tegratab",
1763 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1764 .model = 114,
1765 },
1766 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001767 /* "tn8" (nVidia Shield Tablet K1) -> Tegra T124 */
1768 .platform = "tn8",
1769 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1770 .model = 124,
1771 },
1772 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001773 /* "roth" (nVidia Shield Portable) -> Tegra T114 */
1774 .platform = "roth",
1775 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1776 .model = 114,
1777 },
1778 {
1779 /* "foster_e" (nVidia Shield TV, Flash) -> Tegra T210 */
1780 .platform = "foster_e",
1781 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1782 .model = 210,
1783 },
1784 {
1785 /* "foster_e_hdd" (nVidia Shield TV, HDD) -> Tegra T210 */
1786 .platform = "foster_e_hdd",
1787 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1788 .model = 210,
1789 },
1790 {
1791 /* "darcy" (nVidia Shield TV 2017) -> Tegra T210 */
1792 .platform = "darcy",
1793 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1794 .model = 210,
1795 },
1796 {
1797 /* "pisces" (Xiaomi Mi 3) -> Tegra T114 */
1798 .platform = "pisces",
1799 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1800 .model = 114,
1801 },
1802 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001803 /* "mocha" (Xiaomi Mi Pad) -> Tegra T124 */
1804 .platform = "mocha",
1805 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1806 .model = 124,
1807 },
1808 {
1809 /* "stingray" (Motorola XOOM) -> Tegra AP20H */
1810 .platform = "stingray",
1811 .series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1812 .model = 20,
1813 .suffix = 'H',
1814 },
1815 {
1816 /* "Ceres" (Wiko Highway 4G) -> Tegra SL460N */
1817 .platform = "Ceres",
1818 .series = cpuinfo_arm_chipset_series_nvidia_tegra_sl,
1819 .model = 460,
1820 .suffix = 'N',
1821 },
1822 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001823 /* "MT799" (nabi 2 Tablet) -> Tegra T30 */
1824 .platform = "MT799",
1825 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1826 .model = 30,
1827 },
1828 {
1829 /* "t8400n" (nabi DreamTab HD8) -> Tegra T114 */
1830 .platform = "t8400n",
1831 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1832 .model = 114,
1833 },
1834 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001835 /* "chagall" (Fujitsu Stylistic M532) -> Tegra T30 */
1836 .platform = "chagall",
1837 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1838 .model = 30,
1839 },
1840 {
1841 /* "ventana" (Asus Transformer TF101) -> Tegra T20 */
1842 .platform = "ventana",
1843 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1844 .model = 20,
1845 },
1846 {
1847 /* "bobsleigh" (Fujitsu Arrows Tab F-05E) -> Tegra T33 */
1848 .platform = "bobsleigh",
1849 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1850 .model = 33,
1851 },
1852 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001853 /* "tegra_fjdev101" (Fujitsu Arrows X F-10D) -> Tegra AP33 */
1854 .platform = "tegra_fjdev101",
1855 .series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1856 .model = 33,
1857 },
1858 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001859 /* "tegra_fjdev103" (Fujitsu Arrows V F-04E) -> Tegra T33 */
1860 .platform = "tegra_fjdev103",
1861 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1862 .model = 33,
1863 },
1864 {
1865 /* "nbx03" (Sony Tablet S) -> Tegra T20 */
1866 .platform = "nbx03",
1867 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1868 .model = 20,
1869 },
1870 {
1871 /* "txs03" (Sony Xperia Tablet S) -> Tegra T30L */
1872 .platform = "txs03",
1873 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1874 .model = 30,
1875 .suffix = 'L',
1876 },
1877 {
1878 /* "x3" (LG Optimus 4X HD P880) -> Tegra AP33 */
1879 .platform = "x3",
1880 .series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1881 .model = 33,
1882 },
1883 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001884 /* "vu10" (LG Optimus Vu P895) -> Tegra AP33 */
1885 .platform = "vu10",
1886 .series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1887 .model = 33,
1888 },
1889 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001890 /* "BIRCH" (HP Slate 7 Plus) -> Tegra T30L */
1891 .platform = "BIRCH",
1892 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1893 .model = 30,
1894 .suffix = 'L',
1895 },
1896 {
1897 /* "macallan" (HP Slate 8 Pro) -> Tegra T114 */
1898 .platform = "macallan",
1899 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1900 .model = 114,
1901 },
1902 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001903 /* "maya" (HP SlateBook 10 x2) -> Tegra T114 */
1904 .platform = "maya",
1905 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1906 .model = 114,
1907 },
1908 {
1909 /* "antares" (Toshiba AT100) -> Tegra T20 */
1910 .platform = "antares",
1911 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1912 .model = 20,
1913 },
1914 {
1915 /* "tostab12AL" (Toshiba AT300SE "Excite 10 SE") -> Tegra T30L */
1916 .platform = "tostab12AL",
1917 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1918 .model = 30,
1919 .suffix = 'L',
1920 },
1921 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001922 /* "tostab12BL" (Toshiba AT10-A "Excite Pure") -> Tegra T30L */
1923 .platform = "tostab12BL",
1924 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1925 .model = 30,
1926 .suffix = 'L',
1927 },
1928 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001929 /* "sphinx" (Toshiba AT270 "Excite 7.7") -> Tegra T30 */
1930 .platform = "sphinx",
1931 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1932 .model = 30,
1933 },
1934 {
1935 /* "tostab11BS" (Toshiba AT570 "Regza 7.7") -> Tegra T30 */
1936 .platform = "tostab11BS",
1937 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1938 .model = 30,
1939 },
1940 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001941 /* "tostab12BA" (Toshiba AT10-LE-A "Excite Pro") -> Tegra T114 */
1942 .platform = "tostab12BA",
1943 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1944 .model = 114,
1945 },
1946 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001947 /* "vangogh" (Acer Iconia Tab A100) -> Tegra T20 */
1948 .platform = "vangogh",
1949 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
Marat Dukhan006461a2017-08-24 16:10:46 -07001950 .model = 20,
Marat Dukhan56b24032017-09-05 18:40:20 -07001951 },
1952 {
1953 /* "a110" (Acer Iconia Tab A110) -> Tegra T30L */
1954 .platform = "a110",
1955 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1956 .model = 30,
1957 .suffix = 'L',
Marat Dukhan006461a2017-08-24 16:10:46 -07001958 },
1959 {
1960 /* "picasso_e" (Acer Iconia Tab A200) -> Tegra AP20H */
1961 .platform = "picasso_e",
1962 .series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1963 .model = 20,
1964 .suffix = 'H',
1965 },
1966 {
1967 /* "picasso_e2" (Acer Iconia Tab A210) -> Tegra T30L */
1968 .platform = "picasso_e2",
1969 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1970 .model = 30,
1971 .suffix = 'L',
1972 },
1973 {
Marat Dukhan56b24032017-09-05 18:40:20 -07001974 /* "picasso" (Acer Iconia Tab A500) -> Tegra AP20H */
1975 .platform = "picasso",
1976 .series = cpuinfo_arm_chipset_series_nvidia_tegra_ap,
1977 .model = 20,
1978 .suffix = 'H',
1979 },
1980 {
Marat Dukhan006461a2017-08-24 16:10:46 -07001981 /* "picasso_m" (Acer Iconia Tab A510) -> Tegra T30 */
1982 .platform = "picasso_m",
1983 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1984 .model = 30,
1985 },
1986 {
1987 /* "picasso_mf" (Acer Iconia Tab A700) -> Tegra T30 */
1988 .platform = "picasso_mf",
1989 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1990 .model = 30,
1991 },
1992 {
1993 /* "avalon" (Toshiba AT300 "Excite 10") -> Tegra T30L */
1994 .platform = "avalon",
1995 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
1996 .model = 30,
1997 .suffix = 'L',
1998 },
1999 {
2000 /* "NS_14T004" (iRiver NS-14T004) -> Tegra T30L */
2001 .platform = "NS_14T004",
2002 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2003 .model = 30,
2004 .suffix = 'L',
2005 },
Marat Dukhan56b24032017-09-05 18:40:20 -07002006 {
2007 /* "WIKIPAD" (Wikipad) -> Tegra T30 */
2008 .platform = "WIKIPAD",
2009 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2010 .model = 30,
2011 },
2012 {
2013 /* "kb" (Pegatron Q00Q) -> Tegra T114 */
2014 .platform = "kb",
2015 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2016 .model = 114,
2017 },
Marat Dukhan006461a2017-08-24 16:10:46 -07002018};
2019
2020/*
2021 * Decodes chipset name from /proc/cpuinfo Hardware string.
2022 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
2023 *
2024 * @param[in] platform - /proc/cpuinfo Hardware string.
2025 * @param cores - number of cores in the chipset.
2026 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
2027 *
2028 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
2029 * and series identifiers.
2030 */
Marat Dukhan1415d7d2017-10-16 09:40:15 -07002031struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(
Marat Dukhan006461a2017-08-24 16:10:46 -07002032 const char hardware[restrict static CPUINFO_HARDWARE_VALUE_MAX],
2033 uint32_t cores, uint32_t max_cpu_freq_max, bool is_tegra)
2034{
2035 struct cpuinfo_arm_chipset chipset;
2036 const size_t hardware_length = strnlen(hardware, CPUINFO_HARDWARE_VALUE_MAX);
2037 const char* hardware_end = hardware + hardware_length;
2038
2039 if (is_tegra) {
2040 /*
2041 * nVidia Tegra-specific path: compare /proc/cpuinfo Hardware string to
2042 * tabulated Hardware values for popular chipsets/devices with Tegra chipsets.
2043 * This path is only used when ro.board.platform indicates a Tegra chipset
2044 * (albeit does not indicate which exactly Tegra chipset).
2045 */
2046 for (size_t i = 0; i < CPUINFO_COUNT_OF(tegra_hardware_map_entries); i++) {
2047 if (strncmp(tegra_hardware_map_entries[i].platform, hardware, hardware_length) == 0 &&
2048 tegra_hardware_map_entries[i].platform[hardware_length] == 0)
2049 {
2050 cpuinfo_log_debug(
2051 "found /proc/cpuinfo Hardware string \"%.*s\" in nVidia Tegra chipset table",
2052 (int) hardware_length, hardware);
2053 /* Create chipset name from entry */
2054 return (struct cpuinfo_arm_chipset) {
2055 .vendor = chipset_series_vendor[tegra_hardware_map_entries[i].series],
2056 .series = (enum cpuinfo_arm_chipset_series) tegra_hardware_map_entries[i].series,
2057 .model = tegra_hardware_map_entries[i].model,
2058 .suffix = {
2059 [0] = tegra_hardware_map_entries[i].suffix,
2060 },
2061 };
2062 }
2063 }
2064 } else {
2065 /* Generic path: consider all other vendors */
2066
2067 bool word_start = true;
2068 for (const char* pos = hardware; pos != hardware_end; pos++) {
2069 const char c = *pos;
2070 switch (c) {
2071 case ' ':
2072 case '\t':
2073 case ',':
2074 word_start = true;
2075 break;
2076 default:
2077 if (word_start && is_ascii_alphabetic(c)) {
2078 /* Check Qualcomm MSM/APQ signature */
2079 if (match_msm_apq(pos, hardware_end, &chipset)) {
2080 cpuinfo_log_debug(
2081 "matched Qualcomm MSM/APQ signature in /proc/cpuinfo Hardware string \"%.*s\"",
2082 (int) hardware_length, hardware);
2083 return chipset;
2084 }
2085
2086 /* Check SDMxxx (Qualcomm Snapdragon) signature */
2087 if (match_sdm(pos, hardware_end, &chipset)) {
2088 cpuinfo_log_debug(
2089 "matched Qualcomm SDM signature in /proc/cpuinfo Hardware string \"%.*s\"",
2090 (int) hardware_length, hardware);
2091 return chipset;
2092 }
2093
2094 /* Check MediaTek MT signature */
2095 if (match_mt(pos, hardware_end, true, &chipset)) {
2096 cpuinfo_log_debug(
2097 "matched MediaTek MT signature in /proc/cpuinfo Hardware string \"%.*s\"",
2098 (int) hardware_length, hardware);
2099 return chipset;
2100 }
2101
2102 /* Check HiSilicon Kirin signature */
2103 if (match_kirin(pos, hardware_end, &chipset)) {
2104 cpuinfo_log_debug(
2105 "matched HiSilicon Kirin signature in /proc/cpuinfo Hardware string \"%.*s\"",
2106 (int) hardware_length, hardware);
2107 return chipset;
2108 }
2109
2110 /* Check Rockchip RK signature */
2111 if (match_rk(pos, hardware_end, &chipset)) {
2112 cpuinfo_log_debug(
2113 "matched Rockchip RK signature in /proc/cpuinfo Hardware string \"%.*s\"",
2114 (int) hardware_length, hardware);
2115 return chipset;
2116 }
2117 }
2118 word_start = false;
2119 break;
2120 }
2121 }
2122
2123 /* Check Samsung Exynos signature */
2124 if (match_samsung_exynos(hardware, hardware_end, &chipset)) {
2125 cpuinfo_log_debug(
2126 "matched Samsung Exynos signature in /proc/cpuinfo Hardware string \"%.*s\"",
2127 (int) hardware_length, hardware);
2128 return chipset;
2129 }
2130
2131 /* Check universalXXXX (Samsung Exynos) signature */
2132 if (match_universal(hardware, hardware_end, &chipset)) {
2133 cpuinfo_log_debug(
2134 "matched UNIVERSAL (Samsung Exynos) signature in /proc/cpuinfo Hardware string \"%.*s\"",
2135 (int) hardware_length, hardware);
2136 return chipset;
2137 }
2138
2139 /* Match /SMDK(4410|4x12)$/ */
2140 if (match_and_parse_smdk(hardware, hardware_end, cores, &chipset)) {
2141 cpuinfo_log_debug(
2142 "matched SMDK (Samsung Exynos) signature in /proc/cpuinfo Hardware string \"%.*s\"",
2143 (int) hardware_length, hardware);
2144 return chipset;
2145 }
2146
2147 /* Check Spreadtrum SC signature */
2148 if (match_sc(hardware, hardware_end, &chipset)) {
2149 cpuinfo_log_debug(
2150 "matched Spreadtrum SC signature in /proc/cpuinfo Hardware string \"%.*s\"",
2151 (int) hardware_length, hardware);
2152 return chipset;
2153 }
2154
2155 /* Check Marvell PXA signature */
2156 if (match_pxa(hardware, hardware_end, &chipset)) {
2157 cpuinfo_log_debug(
2158 "matched Marvell PXA signature in /proc/cpuinfo Hardware string \"%.*s\"",
2159 (int) hardware_length, hardware);
2160 return chipset;
2161 }
2162
2163 /* Match /sun\d+i/ signature and map to Allwinner chipset name */
2164 if (match_and_parse_sunxi(hardware, hardware_end, cores, &chipset)) {
2165 cpuinfo_log_debug(
2166 "matched sunxi (Allwinner Ax) signature in /proc/cpuinfo Hardware string \"%.*s\"",
2167 (int) hardware_length, hardware);
2168 return chipset;
2169 }
2170
2171 /* Check Texas Instruments OMAP signature */
2172 if (match_omap(hardware, hardware_end, &chipset)) {
2173 cpuinfo_log_debug(
2174 "matched Texas Instruments OMAP signature in /proc/cpuinfo Hardware string \"%.*s\"",
2175 (int) hardware_length, hardware);
2176 return chipset;
2177 }
2178
2179 /* Check WonderMedia WMT signature and decode chipset from frequency and number of cores */
2180 if (match_and_parse_wmt(hardware, hardware_end, cores, max_cpu_freq_max, &chipset)) {
2181 cpuinfo_log_debug(
2182 "matched WonderMedia WMT signature in /proc/cpuinfo Hardware string \"%.*s\"",
2183 (int) hardware_length, hardware);
2184 return chipset;
2185 }
2186
2187 /* Check Telechips TCC signature */
2188 if (match_tcc(hardware, hardware_end, &chipset)) {
2189 cpuinfo_log_debug(
2190 "matched Telechips TCC signature in /proc/cpuinfo Hardware string \"%.*s\"",
2191 (int) hardware_length, hardware);
2192 return chipset;
2193 }
2194
2195 /* Compare to tabulated Hardware values for popular chipsets/devices which can't be otherwise detected */
2196 for (size_t i = 0; i < CPUINFO_COUNT_OF(special_hardware_map_entries); i++) {
2197 if (strncmp(special_hardware_map_entries[i].platform, hardware, hardware_length) == 0 &&
2198 special_hardware_map_entries[i].platform[hardware_length] == 0)
2199 {
2200 cpuinfo_log_debug(
2201 "found /proc/cpuinfo Hardware string \"%.*s\" in special chipset table",
2202 (int) hardware_length, hardware);
2203 /* Create chipset name from entry */
2204 return (struct cpuinfo_arm_chipset) {
2205 .vendor = chipset_series_vendor[special_hardware_map_entries[i].series],
2206 .series = (enum cpuinfo_arm_chipset_series) special_hardware_map_entries[i].series,
2207 .model = special_hardware_map_entries[i].model,
2208 .suffix = {
2209 [0] = special_hardware_map_entries[i].suffix,
2210 },
2211 };
2212 }
2213 }
2214 }
2215
2216 return (struct cpuinfo_arm_chipset) {
2217 .vendor = cpuinfo_arm_chipset_vendor_unknown,
2218 .series = cpuinfo_arm_chipset_series_unknown,
2219 };
2220}
2221
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002222#ifdef __ANDROID__
2223 static const struct special_map_entry special_board_map_entries[] = {
Marat Dukhan006461a2017-08-24 16:10:46 -07002224 {
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002225 /* "hi6250" -> HiSilicon Kirin 650 */
2226 .platform = "hi6250",
2227 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2228 .model = 650,
2229 },
2230 {
2231 /* "hi6210sft" -> HiSilicon Kirin 620 */
2232 .platform = "hi6210sft",
2233 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2234 .model = 620,
2235 },
2236 {
2237 /* "hi3650" -> HiSilicon Kirin 950 */
2238 .platform = "hi3650",
2239 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2240 .model = 950,
2241 },
2242 {
2243 /* "hi3635" -> HiSilicon Kirin 930 */
2244 .platform = "hi3635",
2245 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2246 .model = 930,
2247 },
2248 {
2249 /* "hi3630" -> HiSilicon Kirin 920 */
2250 .platform = "hi3630",
2251 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2252 .model = 920,
2253 },
2254 {
2255 /* "mp523x" -> Renesas MP5232 */
2256 .platform = "mp523x",
2257 .series = cpuinfo_arm_chipset_series_renesas_mp,
2258 .model = 5232,
2259 },
2260 {
2261 /* "piranha" -> Texas Instruments OMAP4430 */
2262 .platform = "piranha",
Marat Dukhan006461a2017-08-24 16:10:46 -07002263 .series = cpuinfo_arm_chipset_series_texas_instruments_omap,
2264 .model = 4430,
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002265 },
2266 {
2267 /* "BEETHOVEN" (Huawei MadiaPad M3) -> HiSilicon Kirin 950 */
2268 .platform = "BEETHOVEN",
2269 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2270 .model = 950,
2271 },
2272 {
2273 /* "hws7701u" (Huawei MediaPad 7 Youth) -> Rockchip RK3168 */
2274 .platform = "hws7701u",
2275 .series = cpuinfo_arm_chipset_series_rockchip_rk,
2276 .model = 3168,
2277 },
2278 {
2279 /* "g2mv" (LG G2 mini LTE) -> nVidia Tegra SL460N */
2280 .platform = "g2mv",
2281 .series = cpuinfo_arm_chipset_series_nvidia_tegra_sl,
2282 .model = 460,
2283 .suffix = 'N',
2284 },
2285 {
2286 /* "K00F" (Asus MeMO Pad 10) -> Rockchip RK3188 */
2287 .platform = "K00F",
2288 .series = cpuinfo_arm_chipset_series_rockchip_rk,
2289 .model = 3188,
2290 },
2291 {
2292 /* "T7H" (HP Slate 7) -> Rockchip RK3066 */
2293 .platform = "T7H",
2294 .series = cpuinfo_arm_chipset_series_rockchip_rk,
2295 .model = 3066,
2296 },
2297 {
2298 /* "tuna" (Samsung Galaxy Nexus) -> Texas Instruments OMAP4460 */
2299 .platform = "tuna",
2300 .series = cpuinfo_arm_chipset_series_texas_instruments_omap,
2301 .model = 4460,
2302 },
2303 {
2304 /* "grouper" (Asus Nexus 7 2012) -> nVidia Tegra T30L */
2305 .platform = "grouper",
2306 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2307 .model = 30,
2308 .suffix = 'L',
2309 },
2310 {
2311 /* "flounder" (HTC Nexus 9) -> nVidia Tegra T132 */
2312 .platform = "flounder",
2313 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2314 .model = 132,
2315 },
2316 {
2317 /* "dragon" (Google Pixel C) -> nVidia Tegra T210 */
2318 .platform = "dragon",
2319 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2320 .model = 210,
2321 },
2322 {
2323 /* "sailfish" (Google Pixel) -> Qualcomm MSM8996PRO */
2324 .platform = "sailfish",
2325 .series = cpuinfo_arm_chipset_series_qualcomm_msm,
2326 .model = 8996,
2327 .suffix = 'P',
2328 },
2329 {
2330 /* "marlin" (Google Pixel XL) -> Qualcomm MSM8996PRO */
2331 .platform = "marlin",
2332 .series = cpuinfo_arm_chipset_series_qualcomm_msm,
2333 .model = 8996,
2334 .suffix = 'P',
2335 },
2336 };
Marat Dukhan006461a2017-08-24 16:10:46 -07002337
2338 /*
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002339 * Decodes chipset name from ro.product.board Android system property.
2340 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
2341 *
2342 * @param[in] platform - ro.product.board value.
2343 * @param cores - number of cores in the chipset.
2344 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
2345 *
2346 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
2347 * and series identifiers.
Marat Dukhan006461a2017-08-24 16:10:46 -07002348 */
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002349 struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_product_board(
2350 const char ro_product_board[restrict static CPUINFO_BUILD_PROP_VALUE_MAX],
2351 uint32_t cores, uint32_t max_cpu_freq_max)
2352 {
2353 struct cpuinfo_arm_chipset chipset;
2354 const char* board = ro_product_board;
2355 const size_t board_length = strnlen(ro_product_board, CPUINFO_BUILD_PROP_VALUE_MAX);
2356 const char* board_end = ro_product_board + board_length;
2357
2358 /* Check Qualcomm MSM/APQ signature */
2359 if (match_msm_apq(board, board_end, &chipset)) {
2360 cpuinfo_log_debug(
2361 "matched Qualcomm MSM/APQ signature in ro.product.board string \"%.*s\"", (int) board_length, board);
2362 return chipset;
2363 }
2364
2365 /* Check universaXXXX (Samsung Exynos) signature */
2366 if (match_universal(board, board_end, &chipset)) {
2367 cpuinfo_log_debug(
2368 "matched UNIVERSAL (Samsung Exynos) signature in ro.product.board string \"%.*s\"",
2369 (int) board_length, board);
2370 return chipset;
2371 }
2372
2373 /* Check SMDK (Samsung Exynos) signature */
2374 if (match_and_parse_smdk(board, board_end, cores, &chipset)) {
2375 cpuinfo_log_debug(
2376 "matched SMDK (Samsung Exynos) signature in ro.product.board string \"%.*s\"",
2377 (int) board_length, board);
2378 return chipset;
2379 }
2380
2381 /* Check MediaTek MT signature */
2382 if (match_mt(board, board_end, true, &chipset)) {
2383 cpuinfo_log_debug(
2384 "matched MediaTek MT signature in ro.product.board string \"%.*s\"",
2385 (int) board_length, board);
2386 return chipset;
2387 }
2388
2389 /* Check Spreadtrum SC signature */
2390 if (match_sc(board, board_end, &chipset)) {
2391 cpuinfo_log_debug(
2392 "matched Spreadtrum SC signature in ro.product.board string \"%.*s\"",
2393 (int) board_length, board);
2394 return chipset;
2395 }
2396
2397 /* Check Marvell PXA signature */
2398 if (match_pxa(board, board_end, &chipset)) {
2399 cpuinfo_log_debug(
2400 "matched Marvell PXA signature in ro.product.board string \"%.*s\"",
2401 (int) board_length, board);
2402 return chipset;
2403 }
2404
2405 /* Check Leadcore LCxxxx signature */
2406 if (match_lc(board, board_end, &chipset)) {
2407 cpuinfo_log_debug(
2408 "matched Leadcore LC signature in ro.product.board string \"%.*s\"",
2409 (int) board_length, board);
2410 return chipset;
2411 }
2412
2413 /*
2414 * Compare to tabulated ro.product.board values for Broadcom chipsets and decode chipset from frequency and
2415 * number of cores.
2416 */
2417 if (match_and_parse_broadcom(board, board_end, cores, max_cpu_freq_max, &chipset)) {
2418 cpuinfo_log_debug(
2419 "found ro.product.board string \"%.*s\" in Broadcom chipset table",
2420 (int) board_length, board);
2421 return chipset;
2422 }
2423
2424 /* Compare to tabulated ro.product.board values for Huawei devices which don't report chipset elsewhere */
2425 if (match_and_parse_huawei(board, board_end, &chipset)) {
2426 cpuinfo_log_debug(
2427 "found ro.product.board string \"%.*s\" in Huawei chipset table",
2428 (int) board_length, board);
2429 return chipset;
2430 }
2431
2432 /* Compare to tabulated ro.product.board values for popular chipsets/devices which can't be otherwise detected */
2433 for (size_t i = 0; i < CPUINFO_COUNT_OF(special_board_map_entries); i++) {
2434 if (strncmp(special_board_map_entries[i].platform, board, board_length) == 0 &&
2435 special_board_map_entries[i].platform[board_length] == 0)
2436 {
Marat Dukhan006461a2017-08-24 16:10:46 -07002437 cpuinfo_log_debug(
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002438 "found ro.product.board string \"%.*s\" in special chipset table",
2439 (int) board_length, board);
Marat Dukhan006461a2017-08-24 16:10:46 -07002440 /* Create chipset name from entry */
2441 return (struct cpuinfo_arm_chipset) {
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002442 .vendor = chipset_series_vendor[special_board_map_entries[i].series],
2443 .series = (enum cpuinfo_arm_chipset_series) special_board_map_entries[i].series,
2444 .model = special_board_map_entries[i].model,
Marat Dukhan006461a2017-08-24 16:10:46 -07002445 .suffix = {
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002446 [0] = special_board_map_entries[i].suffix,
2447 /* The suffix of MSM8996PRO is truncated at the first letter, reconstruct it here. */
2448 [1] = special_board_map_entries[i].suffix == 'P' ? 'R' : 0,
2449 [2] = special_board_map_entries[i].suffix == 'P' ? 'O' : 0,
Marat Dukhan006461a2017-08-24 16:10:46 -07002450 },
2451 };
2452 }
2453 }
Marat Dukhan006461a2017-08-24 16:10:46 -07002454
2455 return (struct cpuinfo_arm_chipset) {
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002456 .vendor = cpuinfo_arm_chipset_vendor_unknown,
2457 .series = cpuinfo_arm_chipset_series_unknown,
Marat Dukhan006461a2017-08-24 16:10:46 -07002458 };
2459 }
2460
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002461 struct amlogic_map_entry {
2462 char ro_board_platform[6];
2463 uint16_t model;
2464 uint8_t series;
2465 char suffix[3];
Marat Dukhan006461a2017-08-24 16:10:46 -07002466 };
Marat Dukhan7c775ab2017-10-15 21:50:11 +00002467
2468 static const struct amlogic_map_entry amlogic_map_entries[] = {
2469 {
2470 /* "meson3" -> Amlogic AML8726-M */
2471 .ro_board_platform = "meson3",
2472 .series = cpuinfo_arm_chipset_series_amlogic_aml,
2473 .model = 8726,
2474 .suffix = "-M",
2475 },
2476 {
2477 /* "meson6" -> Amlogic AML8726-MX */
2478 .ro_board_platform = "meson6",
2479 .series = cpuinfo_arm_chipset_series_amlogic_aml,
2480 .model = 8726,
2481 .suffix = "-MX",
2482 },
2483 {
2484 /* "meson8" -> Amlogic S805 */
2485 .ro_board_platform = "meson8",
2486 .series = cpuinfo_arm_chipset_series_amlogic_s,
2487 .model = 805,
2488 },
2489 {
2490 /* "gxbaby" -> Amlogic S905 */
2491 .ro_board_platform = "gxbaby",
2492 .series = cpuinfo_arm_chipset_series_amlogic_s,
2493 .model = 905,
2494 },
2495 {
2496 /* "gxl" -> Amlogic S905X */
2497 .ro_board_platform = "gxl",
2498 .series = cpuinfo_arm_chipset_series_amlogic_s,
2499 .model = 905,
2500 .suffix = "X",
2501 },
2502 {
2503 /* "gxm" -> Amlogic S912 */
2504 .ro_board_platform = "gxm",
2505 .series = cpuinfo_arm_chipset_series_amlogic_s,
2506 .model = 912,
2507 },
2508 };
2509
2510 static const struct special_map_entry special_platform_map_entries[] = {
2511 {
2512 /* "hi6620oem" -> HiSilicon Kirin 910T */
2513 .platform = "hi6620oem",
2514 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2515 .model = 910,
2516 .suffix = 'T',
2517 },
2518 {
2519 /* "hi6250" -> HiSilicon Kirin 650 */
2520 .platform = "hi6250",
2521 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2522 .model = 650,
2523 },
2524 {
2525 /* "hi6210sft" -> HiSilicon Kirin 620 */
2526 .platform = "hi6210sft",
2527 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2528 .model = 620,
2529 },
2530 {
2531 /* "hi3650" -> HiSilicon Kirin 950 */
2532 .platform = "hi3650",
2533 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2534 .model = 950,
2535 },
2536 {
2537 /* "hi3635" -> HiSilicon Kirin 930 */
2538 .platform = "hi3635",
2539 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2540 .model = 930,
2541 },
2542 {
2543 /* "hi3630" -> HiSilicon Kirin 920 */
2544 .platform = "hi3630",
2545 .series = cpuinfo_arm_chipset_series_hisilicon_kirin,
2546 .model = 920,
2547 },
2548 {
2549 /* "k3v2oem1" -> HiSilicon K3V2 */
2550 .platform = "k3v2oem1",
2551 .series = cpuinfo_arm_chipset_series_hisilicon_k3v,
2552 .model = 2,
2553 },
2554 {
2555 /* "k3v200" -> HiSilicon K3V2 */
2556 .platform = "k3v200",
2557 .series = cpuinfo_arm_chipset_series_hisilicon_k3v,
2558 .model = 2,
2559 },
2560 {
2561 /* "montblanc" -> NovaThor U8500 */
2562 .platform = "montblanc",
2563 .series = cpuinfo_arm_chipset_series_novathor_u,
2564 .model = 8500,
2565 },
2566 {
2567 /* "song" -> Pinecone Surge S1 */
2568 .platform = "song",
2569 .series = cpuinfo_arm_chipset_series_pinecone_surge_s,
2570 .model = 1,
2571 },
2572 {
2573 /* "tegra132" -> nVidia Tegra T132 */
2574 .platform = "tegra132",
2575 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2576 .model = 132,
2577 },
2578 {
2579 /* "tegra210_dragon" -> nVidia Tegra T210 */
2580 .platform = "tegra210_dragon",
2581 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2582 .model = 210,
2583 },
2584 {
2585 /* "tegra4" -> nVidia Tegra T114 */
2586 .platform = "tegra4",
2587 .series = cpuinfo_arm_chipset_series_nvidia_tegra_t,
2588 .model = 114,
2589 },
2590 {
2591 /* "s5pc110" -> Samsung Exynos 3110 */
2592 .platform = "s5pc110",
2593 .series = cpuinfo_arm_chipset_series_samsung_exynos,
2594 .model = 3110,
2595 },
2596 };
2597
2598 /*
2599 * Decodes chipset name from ro.board.platform Android system property.
2600 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
2601 *
2602 * @param[in] platform - ro.board.platform value.
2603 * @param cores - number of cores in the chipset.
2604 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
2605 *
2606 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
2607 * and series identifiers.
2608 */
2609 struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_board_platform(
2610 const char platform[restrict static CPUINFO_BUILD_PROP_VALUE_MAX],
2611 uint32_t cores, uint32_t max_cpu_freq_max)
2612 {
2613 struct cpuinfo_arm_chipset chipset;
2614 const size_t platform_length = strnlen(platform, CPUINFO_BUILD_PROP_VALUE_MAX);
2615 const char* platform_end = platform + platform_length;
2616
2617 /* Check Qualcomm MSM/APQ signature */
2618 if (match_msm_apq(platform, platform_end, &chipset)) {
2619 cpuinfo_log_debug(
2620 "matched Qualcomm MSM/APQ signature in ro.board.platform string \"%.*s\"",
2621 (int) platform_length, platform);
2622 return chipset;
2623 }
2624
2625 /* Check exynosXXXX (Samsung Exynos) signature */
2626 if (match_exynos(platform, platform_end, &chipset)) {
2627 cpuinfo_log_debug(
2628 "matched exynosXXXX (Samsung Exynos) signature in ro.board.platform string \"%.*s\"",
2629 (int) platform_length, platform);
2630 return chipset;
2631 }
2632
2633 /* Check MediaTek MT signature */
2634 if (match_mt(platform, platform_end, true, &chipset)) {
2635 cpuinfo_log_debug(
2636 "matched MediaTek MT signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2637 return chipset;
2638 }
2639
2640 /* Check Spreadtrum SC signature */
2641 if (match_sc(platform, platform_end, &chipset)) {
2642 cpuinfo_log_debug(
2643 "matched Spreadtrum SC signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2644 return chipset;
2645 }
2646
2647 /* Check Rockchip RK signature */
2648 if (match_rk(platform, platform_end, &chipset)) {
2649 cpuinfo_log_debug(
2650 "matched Rockchip RK signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2651 return chipset;
2652 }
2653
2654 /* Check Leadcore LCxxxx signature */
2655 if (match_lc(platform, platform_end, &chipset)) {
2656 cpuinfo_log_debug(
2657 "matched Leadcore LC signature in ro.board.platform string \"%.*s\"", (int) platform_length, platform);
2658 return chipset;
2659 }
2660
2661 /* Compare to tabulated ro.board.platform values for Huawei devices which don't report chipset elsewhere */
2662 if (match_and_parse_huawei(platform, platform_end, &chipset)) {
2663 cpuinfo_log_debug(
2664 "found ro.board.platform string \"%.*s\" in Huawei chipset table",
2665 (int) platform_length, platform);
2666 return chipset;
2667 }
2668
2669 /*
2670 * Compare to known ro.board.platform values for Broadcom devices and
2671 * detect chipset from frequency and number of cores
2672 */
2673 if (match_and_parse_broadcom(platform, platform_end, cores, max_cpu_freq_max, &chipset)) {
2674 cpuinfo_log_debug(
2675 "found ro.board.platform string \"%.*s\" in Broadcom chipset table",
2676 (int) platform_length, platform);
2677 return chipset;
2678 }
2679
2680 /*
2681 * Compare to ro.board.platform value ("omap4") for OMAP4xxx chipsets.
2682 * Upon successful match, detect OMAP4430 from frequency and number of cores.
2683 */
2684 if (platform_length == 5 && cores == 2 && max_cpu_freq_max == 1008000 && memcmp(platform, "omap4", 5) == 0) {
2685 cpuinfo_log_debug(
2686 "matched Texas Instruments OMAP4 signature in ro.board.platform string \"%.*s\"",
2687 (int) platform_length, platform);
2688
2689 return (struct cpuinfo_arm_chipset) {
2690 .vendor = cpuinfo_arm_chipset_vendor_texas_instruments,
2691 .series = cpuinfo_arm_chipset_series_texas_instruments_omap,
2692 .model = 4430,
2693 };
2694 }
2695
2696 /*
2697 * Compare to tabulated ro.board.platform values for Amlogic chipsets/devices which can't be otherwise detected.
2698 * The tabulated Amlogic ro.board.platform values have not more than 6 characters.
2699 */
2700 if (platform_length <= 6) {
2701 for (size_t i = 0; i < CPUINFO_COUNT_OF(amlogic_map_entries); i++) {
2702 if (strncmp(amlogic_map_entries[i].ro_board_platform, platform, 6) == 0) {
2703 cpuinfo_log_debug(
2704 "found ro.board.platform string \"%.*s\" in Amlogic chipset table",
2705 (int) platform_length, platform);
2706 /* Create chipset name from entry */
2707 return (struct cpuinfo_arm_chipset) {
2708 .vendor = cpuinfo_arm_chipset_vendor_amlogic,
2709 .series = (enum cpuinfo_arm_chipset_series) amlogic_map_entries[i].series,
2710 .model = amlogic_map_entries[i].model,
2711 .suffix = {
2712 [0] = amlogic_map_entries[i].suffix[0],
2713 [1] = amlogic_map_entries[i].suffix[1],
2714 [2] = amlogic_map_entries[i].suffix[2],
2715 },
2716 };
2717 }
2718 }
2719 }
2720
2721 /* Compare to tabulated ro.board.platform values for popular chipsets/devices which can't be otherwise detected */
2722 for (size_t i = 0; i < CPUINFO_COUNT_OF(special_platform_map_entries); i++) {
2723 if (strncmp(special_platform_map_entries[i].platform, platform, platform_length) == 0 &&
2724 special_platform_map_entries[i].platform[platform_length] == 0)
2725 {
2726 /* Create chipset name from entry */
2727 cpuinfo_log_debug(
2728 "found ro.board.platform string \"%.*s\" in special chipset table", (int) platform_length, platform);
2729 return (struct cpuinfo_arm_chipset) {
2730 .vendor = chipset_series_vendor[special_platform_map_entries[i].series],
2731 .series = (enum cpuinfo_arm_chipset_series) special_platform_map_entries[i].series,
2732 .model = special_platform_map_entries[i].model,
2733 .suffix = {
2734 [0] = special_platform_map_entries[i].suffix,
2735 },
2736 };
2737 }
2738 }
2739
2740 /* None of the ro.board.platform signatures matched, indicate unknown chipset */
2741 return (struct cpuinfo_arm_chipset) {
2742 .vendor = cpuinfo_arm_chipset_vendor_unknown,
2743 .series = cpuinfo_arm_chipset_series_unknown,
2744 };
2745 }
2746
2747 /*
2748 * Decodes chipset name from ro.mediatek.platform Android system property.
2749 *
2750 * @param[in] platform - ro.mediatek.platform value.
2751 *
2752 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
2753 * and series identifiers.
2754 */
2755 struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_mediatek_platform(
2756 const char platform[restrict static CPUINFO_BUILD_PROP_VALUE_MAX])
2757 {
2758 struct cpuinfo_arm_chipset chipset;
2759 const char* platform_end = platform + strnlen(platform, CPUINFO_BUILD_PROP_VALUE_MAX);;
2760
2761 /* Check MediaTek MT signature */
2762 if (match_mt(platform, platform_end, false, &chipset)) {
2763 return chipset;
2764 }
2765
2766 return (struct cpuinfo_arm_chipset) {
2767 .vendor = cpuinfo_arm_chipset_vendor_unknown,
2768 .series = cpuinfo_arm_chipset_series_unknown,
2769 };
2770 }
2771
2772 /*
2773 * Decodes chipset name from ro.chipname Android system property.
2774 *
2775 * @param[in] chipname - ro.chipname value.
2776 *
2777 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
2778 * and series identifiers.
2779 */
2780 struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset_from_ro_chipname(
2781 const char chipname[restrict static CPUINFO_BUILD_PROP_VALUE_MAX])
2782 {
2783 struct cpuinfo_arm_chipset chipset;
2784 const size_t chipname_length = strnlen(chipname, CPUINFO_BUILD_PROP_VALUE_MAX);
2785 const char* chipname_end = chipname + chipname_length;
2786
2787 /* Check Qualcomm MSM/APQ signatures */
2788 if (match_msm_apq(chipname, chipname_end, &chipset)) {
2789 cpuinfo_log_debug(
2790 "matched Qualcomm MSM/APQ signature in ro.chipname string \"%.*s\"",
2791 (int) chipname_length, chipname);
2792 return chipset;
2793 }
2794
2795 /* Check exynosXXXX (Samsung Exynos) signature */
2796 if (match_exynos(chipname, chipname_end, &chipset)) {
2797 cpuinfo_log_debug(
2798 "matched exynosXXXX (Samsung Exynos) signature in ro.chipname string \"%.*s\"",
2799 (int) chipname_length, chipname);
2800 return chipset;
2801 }
2802
2803 /* Check universalXXXX (Samsung Exynos) signature */
2804 if (match_universal(chipname, chipname_end, &chipset)) {
2805 cpuinfo_log_debug(
2806 "matched UNIVERSAL (Samsung Exynos) signature in ro.chipname Hardware string \"%.*s\"",
2807 (int) chipname_length, chipname);
2808 return chipset;
2809 }
2810
2811 /* Check MediaTek MT signature */
2812 if (match_mt(chipname, chipname_end, true, &chipset)) {
2813 cpuinfo_log_debug(
2814 "matched MediaTek MT signature in ro.chipname string \"%.*s\"",
2815 (int) chipname_length, chipname);
2816 return chipset;
2817 }
2818
2819 /* Check Spreadtrum SC signature */
2820 if (match_sc(chipname, chipname_end, &chipset)) {
2821 cpuinfo_log_debug(
2822 "matched Spreadtrum SC signature in ro.chipname string \"%.*s\"",
2823 (int) chipname_length, chipname);
2824 return chipset;
2825 }
2826
2827 /* Check Marvell PXA signature */
2828 if (match_pxa(chipname, chipname_end, &chipset)) {
2829 cpuinfo_log_debug(
2830 "matched Marvell PXA signature in ro.chipname string \"%.*s\"",
2831 (int) chipname_length, chipname);
2832 return chipset;
2833 }
2834
2835 /* Compare to ro.chipname value ("mp523x") for Renesas MP5232 which can't be otherwise detected */
2836 if (chipname_length == 6 && memcmp(chipname, "mp523x", 6) == 0) {
2837 cpuinfo_log_debug(
2838 "matched Renesas MP5232 signature in ro.chipname string \"%.*s\"",
2839 (int) chipname_length, chipname);
2840
2841 return (struct cpuinfo_arm_chipset) {
2842 .vendor = cpuinfo_arm_chipset_vendor_renesas,
2843 .series = cpuinfo_arm_chipset_series_renesas_mp,
2844 .model = 5232,
2845 };
2846 }
2847
2848 return (struct cpuinfo_arm_chipset) {
2849 .vendor = cpuinfo_arm_chipset_vendor_unknown,
2850 .series = cpuinfo_arm_chipset_series_unknown,
2851 };
2852 }
2853#endif /* __ANDROID__ */
Marat Dukhan006461a2017-08-24 16:10:46 -07002854
2855/*
2856 * Fix common bugs, typos, and renames in chipset name.
2857 *
2858 * @param[in,out] chipset - chipset name to fix.
2859 * @param cores - number of cores in the chipset.
2860 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
2861 */
2862void cpuinfo_arm_fixup_chipset(
2863 struct cpuinfo_arm_chipset chipset[restrict static 1], uint32_t cores, uint32_t max_cpu_freq_max)
2864{
2865 switch (chipset->series) {
2866 case cpuinfo_arm_chipset_series_qualcomm_msm:
2867 /* Check if there is suffix */
2868 if (chipset->suffix[0] == 0) {
2869 /* No suffix, but the model may be misreported */
2870 switch (chipset->model) {
2871 case 8216:
2872 /* MSM8216 was renamed to MSM8916 */
2873 cpuinfo_log_info("reinterpreted MSM8216 chipset as MSM8916");
2874 chipset->model = 8916;
2875 break;
2876 case 8916:
2877 /* Common bug: MSM8939 (Octa-core) reported as MSM8916 (Quad-core) */
2878 switch (cores) {
2879 case 4:
2880 break;
2881 case 8:
2882 cpuinfo_log_info("reinterpreted MSM8916 chipset with 8 cores as MSM8939");
2883 chipset->model = 8939;
2884 break;
2885 default:
2886 cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
2887 cores, chipset->model);
2888 chipset->model = 0;
2889 }
2890 break;
2891 case 8937:
2892 /* Common bug: MSM8917 (Quad-core) reported as MSM8937 (Octa-core) */
2893 switch (cores) {
2894 case 4:
2895 cpuinfo_log_info("reinterpreted MSM8937 chipset with 4 cores as MSM8917");
2896 chipset->model = 8917;
2897 break;
2898 case 8:
2899 break;
2900 default:
2901 cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
2902 cores, chipset->model);
2903 chipset->model = 0;
2904 }
2905 break;
2906 case 8960:
2907 /* Common bug: APQ8064 (Quad-core) reported as MSM8960 (Dual-core) */
2908 switch (cores) {
2909 case 2:
2910 break;
2911 case 4:
2912 cpuinfo_log_info("reinterpreted MSM8960 chipset with 4 cores as APQ8064");
2913 chipset->series = cpuinfo_arm_chipset_series_qualcomm_apq;
2914 chipset->model = 8064;
2915 break;
2916 default:
2917 cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
2918 cores, chipset->model);
2919 chipset->model = 0;
2920 }
2921 break;
2922 case 8996:
2923 /* Common bug: MSM8994 (Octa-core) reported as MSM8996 (Quad-core) */
2924 switch (cores) {
2925 case 4:
2926 break;
2927 case 8:
2928 cpuinfo_log_info("reinterpreted MSM8996 chipset with 8 cores as MSM8994");
2929 chipset->model = 8994;
2930 break;
2931 default:
2932 cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
2933 cores, chipset->model);
2934 chipset->model = 0;
2935 }
2936 break;
2937 case 8610:
2938 /* Common bug: MSM8212 (Quad-core) reported as MSM8610 (Dual-core) */
2939 switch (cores) {
2940 case 2:
2941 break;
2942 case 4:
2943 cpuinfo_log_info("reinterpreted MSM8610 chipset with 4 cores as MSM8212");
2944 chipset->model = 8212;
2945 break;
2946 default:
2947 cpuinfo_log_warning("system reported invalid %"PRIu32"-core MSM%"PRIu32" chipset",
2948 cores, chipset->model);
2949 chipset->model = 0;
2950 }
2951 break;
2952 }
2953 } else {
2954 /* Suffix may need correction */
2955 const uint32_t suffix_word = load_u32le(chipset->suffix);
2956 if (suffix_word == UINT32_C(0x004D534D) /* "\0MSM" = reverse("MSM\0") */) {
2957 /*
2958 * Common bug: model name repeated twice, e.g. "MSM8916MSM8916"
2959 * In this case, model matching code parses the second "MSM" as a suffix
2960 */
2961 chipset->suffix[0] = 0;
2962 chipset->suffix[1] = 0;
2963 chipset->suffix[2] = 0;
2964 } else {
2965 switch (chipset->model) {
2966 case 8976:
2967 /* MSM8976SG -> MSM8976PRO */
2968 if (suffix_word == UINT32_C(0x00004753) /* "\0\0GS" = reverse("SG\0\0") */ ) {
2969 chipset->suffix[0] = 'P';
2970 chipset->suffix[1] = 'R';
2971 chipset->suffix[2] = 'O';
2972 }
2973 break;
2974 case 8996:
2975 /* MSM8996PRO -> MSM8996PRO-AB or MSM8996PRO-AC */
2976 if (suffix_word == UINT32_C(0x004F5250) /* "\0ORP" = reverse("PRO\0") */ ) {
2977 chipset->suffix[3] = '-';
2978 chipset->suffix[4] = 'A';
2979 chipset->suffix[5] = 'B' + (char) (max_cpu_freq_max >= 2188800);
2980 }
2981 break;
2982 }
2983 }
2984 }
2985 break;
2986 case cpuinfo_arm_chipset_series_qualcomm_apq:
2987 {
2988 /* Suffix may need correction */
2989 const uint32_t expected_apq = load_u32le(chipset->suffix);
2990 if (expected_apq == UINT32_C(0x00515041) /* "\0QPA" = reverse("APQ\0") */) {
2991 /*
2992 * Common bug: model name repeated twice, e.g. "APQ8016APQ8016"
2993 * In this case, model matching code parses the second "APQ" as a suffix
2994 */
2995 chipset->suffix[0] = 0;
2996 chipset->suffix[1] = 0;
2997 chipset->suffix[2] = 0;
2998 }
2999 break;
3000 }
3001 case cpuinfo_arm_chipset_series_samsung_exynos:
3002 if (chipset->model == 7580) {
3003 /* Common bug: Exynos 7578 (Quad-core) reported as Exynos 7580 (Octa-core) */
3004 switch (cores) {
3005 case 4:
3006 cpuinfo_log_info("reinterpreted Exynos 7580 chipset with 4 cores as Exynos 7578");
3007 chipset->model = 7578;
3008 break;
3009 case 8:
3010 break;
3011 default:
3012 cpuinfo_log_warning("system reported invalid %"PRIu32"-core Exynos 7580 chipset", cores);
3013 chipset->model = 0;
3014 }
3015 }
3016 break;
3017 case cpuinfo_arm_chipset_series_mediatek_mt:
3018 if (chipset->model == 6752) {
3019 /* Common bug: MT6732 (Quad-core) reported as MT6752 (Octa-core) */
3020 switch (cores) {
3021 case 4:
3022 cpuinfo_log_info("reinterpreted MT6752 chipset with 4 cores as MT6732");
3023 chipset->model = 6732;
3024 break;
3025 case 8:
3026 break;
3027 default:
3028 cpuinfo_log_warning("system reported invalid %"PRIu32"-core MT6752 chipset", cores);
3029 chipset->model = 0;
3030 }
3031 }
3032 if (chipset->suffix[0] == 'T') {
3033 /* Normalization: "TURBO" and "TRUBO" (apparently a typo) -> "T" */
3034 const uint32_t suffix_word = load_u32le(chipset->suffix + 1);
3035 switch (suffix_word) {
3036 case UINT32_C(0x4F425255): /* "OBRU" = reverse("URBO") */
3037 case UINT32_C(0x4F425552): /* "OBUR" = reverse("RUBO") */
3038 if (chipset->suffix[5] == 0) {
3039 chipset->suffix[1] = 0;
3040 chipset->suffix[2] = 0;
3041 chipset->suffix[3] = 0;
3042 chipset->suffix[4] = 0;
3043 }
3044 break;
3045 }
3046 }
3047 break;
3048 default:
3049 break;
3050 }
3051}
3052
3053/* Map from ARM chipset vendor ID to its string representation */
3054static const char* chipset_vendor_string[cpuinfo_arm_chipset_vendor_max] = {
3055 [cpuinfo_arm_chipset_vendor_unknown] = "Unknown",
3056 [cpuinfo_arm_chipset_vendor_qualcomm] = "Qualcomm",
3057 [cpuinfo_arm_chipset_vendor_mediatek] = "MediaTek",
3058 [cpuinfo_arm_chipset_vendor_samsung] = "Samsung",
3059 [cpuinfo_arm_chipset_vendor_hisilicon] = "HiSilicon",
3060 [cpuinfo_arm_chipset_vendor_actions] = "Actions",
3061 [cpuinfo_arm_chipset_vendor_allwinner] = "Allwinner",
3062 [cpuinfo_arm_chipset_vendor_amlogic] = "Amlogic",
3063 [cpuinfo_arm_chipset_vendor_broadcom] = "Broadcom",
3064 [cpuinfo_arm_chipset_vendor_lg] = "LG",
3065 [cpuinfo_arm_chipset_vendor_leadcore] = "Leadcore",
3066 [cpuinfo_arm_chipset_vendor_marvell] = "Marvell",
3067 [cpuinfo_arm_chipset_vendor_mstar] = "MStar",
3068 [cpuinfo_arm_chipset_vendor_novathor] = "NovaThor",
3069 [cpuinfo_arm_chipset_vendor_nvidia] = "nVidia",
3070 [cpuinfo_arm_chipset_vendor_pinecone] = "Pinecone",
3071 [cpuinfo_arm_chipset_vendor_renesas] = "Renesas",
3072 [cpuinfo_arm_chipset_vendor_rockchip] = "Rockchip",
3073 [cpuinfo_arm_chipset_vendor_spreadtrum] = "Spreadtrum",
3074 [cpuinfo_arm_chipset_vendor_telechips] = "Telechips",
3075 [cpuinfo_arm_chipset_vendor_texas_instruments] = "Texas Instruments",
3076 [cpuinfo_arm_chipset_vendor_wondermedia] = "WonderMedia",
3077};
3078
3079/* Map from ARM chipset series ID to its string representation */
3080static const char* chipset_series_string[cpuinfo_arm_chipset_series_max] = {
3081 [cpuinfo_arm_chipset_series_unknown] = NULL,
3082 [cpuinfo_arm_chipset_series_qualcomm_qsd] = "QSD",
3083 [cpuinfo_arm_chipset_series_qualcomm_msm] = "MSM",
3084 [cpuinfo_arm_chipset_series_qualcomm_apq] = "APQ",
3085 [cpuinfo_arm_chipset_series_qualcomm_snapdragon] = "Snapdragon ",
3086 [cpuinfo_arm_chipset_series_mediatek_mt] = "MT",
3087 [cpuinfo_arm_chipset_series_samsung_exynos] = "Exynos ",
3088 [cpuinfo_arm_chipset_series_hisilicon_k3v] = "K3V",
3089 [cpuinfo_arm_chipset_series_hisilicon_hi] = "Hi",
3090 [cpuinfo_arm_chipset_series_hisilicon_kirin] = "Kirin ",
3091 [cpuinfo_arm_chipset_series_actions_atm] = "ATM",
3092 [cpuinfo_arm_chipset_series_allwinner_a] = "A",
3093 [cpuinfo_arm_chipset_series_amlogic_aml] = "AML",
3094 [cpuinfo_arm_chipset_series_amlogic_s] = "S",
3095 [cpuinfo_arm_chipset_series_broadcom_bcm] = "BCM",
3096 [cpuinfo_arm_chipset_series_lg_nuclun] = "Nuclun ",
3097 [cpuinfo_arm_chipset_series_leadcore_lc] = "LC",
3098 [cpuinfo_arm_chipset_series_marvell_pxa] = "PXA",
3099 [cpuinfo_arm_chipset_series_mstar_6a] = "6A",
3100 [cpuinfo_arm_chipset_series_novathor_u] = "U",
3101 [cpuinfo_arm_chipset_series_nvidia_tegra_t] = "Tegra T",
3102 [cpuinfo_arm_chipset_series_nvidia_tegra_ap] = "Tegra AP",
3103 [cpuinfo_arm_chipset_series_nvidia_tegra_sl] = "Tegra SL",
3104 [cpuinfo_arm_chipset_series_pinecone_surge_s] = "Surge S",
3105 [cpuinfo_arm_chipset_series_renesas_mp] = "MP",
3106 [cpuinfo_arm_chipset_series_rockchip_rk] = "RK",
3107 [cpuinfo_arm_chipset_series_spreadtrum_sc] = "SC",
3108 [cpuinfo_arm_chipset_series_telechips_tcc] = "TCC",
3109 [cpuinfo_arm_chipset_series_texas_instruments_omap] = "OMAP",
3110 [cpuinfo_arm_chipset_series_wondermedia_wm] = "WM",
3111};
3112
3113/* Convert chipset name represented by cpuinfo_arm_chipset structure to a string representation */
3114void cpuinfo_arm_chipset_to_string(
3115 const struct cpuinfo_arm_chipset chipset[restrict static 1],
3116 char name[restrict static CPUINFO_ARM_CHIPSET_NAME_MAX])
3117{
3118 enum cpuinfo_arm_chipset_vendor vendor = chipset->vendor;
3119 if (vendor >= cpuinfo_arm_chipset_vendor_max) {
3120 vendor = cpuinfo_arm_chipset_vendor_unknown;
3121 }
3122 enum cpuinfo_arm_chipset_series series = chipset->series;
3123 if (series >= cpuinfo_arm_chipset_series_max) {
3124 series = cpuinfo_arm_chipset_series_unknown;
3125 }
3126 const char* vendor_string = chipset_vendor_string[vendor];
3127 const char* series_string = chipset_series_string[series];
3128 const uint32_t model = chipset->model;
3129 if (model == 0) {
3130 if (series == cpuinfo_arm_chipset_series_unknown) {
3131 strncpy(name, vendor_string, CPUINFO_ARM_CHIPSET_NAME_MAX);
3132 } else {
3133 snprintf(name, CPUINFO_ARM_CHIPSET_NAME_MAX,
3134 "%s %s", vendor_string, series_string);
3135 }
3136 } else {
3137 const size_t suffix_length = strnlen(chipset->suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
3138 snprintf(name, CPUINFO_ARM_CHIPSET_NAME_MAX,
3139 "%s %s%"PRIu32"%.*s", vendor_string, series_string, model, (int) suffix_length, chipset->suffix);
3140 }
3141}
3142
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003143#ifdef __ANDROID__
3144 static inline struct cpuinfo_arm_chipset disambiguate_qualcomm_chipset(
3145 const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3146 const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3147 const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1],
3148 const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static 1])
3149 {
3150 if (ro_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3151 return *ro_chipname_chipset;
3152 }
3153 if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3154 return *proc_cpuinfo_hardware_chipset;
3155 }
3156 if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3157 return *ro_product_board_chipset;
3158 }
Marat Dukhan006461a2017-08-24 16:10:46 -07003159 return *ro_board_platform_chipset;
3160 }
Marat Dukhan006461a2017-08-24 16:10:46 -07003161
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003162 static inline struct cpuinfo_arm_chipset disambiguate_mediatek_chipset(
3163 const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3164 const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3165 const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1],
3166 const struct cpuinfo_arm_chipset ro_mediatek_platform_chipset[restrict static 1],
3167 const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static 1])
3168 {
3169 if (ro_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3170 return *ro_chipname_chipset;
Marat Dukhan006461a2017-08-24 16:10:46 -07003171 }
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003172 if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3173 return *proc_cpuinfo_hardware_chipset;
3174 }
3175 if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3176 return *ro_product_board_chipset;
3177 }
3178 if (ro_board_platform_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3179 return *ro_board_platform_chipset;
3180 }
3181 return *ro_mediatek_platform_chipset;
Marat Dukhan006461a2017-08-24 16:10:46 -07003182 }
3183
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003184 static inline struct cpuinfo_arm_chipset disambiguate_hisilicon_chipset(
3185 const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3186 const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3187 const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1])
3188 {
3189 if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3190 return *proc_cpuinfo_hardware_chipset;
3191 }
3192 if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3193 return *ro_product_board_chipset;
3194 }
3195 return *ro_board_platform_chipset;
3196 }
3197
3198 static inline struct cpuinfo_arm_chipset disambiguate_amlogic_chipset(
3199 const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3200 const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1])
3201 {
3202 if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3203 return *proc_cpuinfo_hardware_chipset;
3204 }
3205 return *ro_board_platform_chipset;
3206 }
3207
3208 static inline struct cpuinfo_arm_chipset disambiguate_marvell_chipset(
3209 const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3210 const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3211 const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static 1])
3212 {
3213 if (ro_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3214 return *ro_chipname_chipset;
3215 }
3216 if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3217 return *ro_product_board_chipset;
3218 }
3219 return *proc_cpuinfo_hardware_chipset;
3220 }
3221
3222 static inline struct cpuinfo_arm_chipset disambiguate_rockchip_chipset(
3223 const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3224 const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3225 const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1])
3226 {
3227 if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3228 return *ro_product_board_chipset;
3229 }
3230 if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3231 return *proc_cpuinfo_hardware_chipset;
3232 }
3233 return *ro_board_platform_chipset;
3234 }
3235
3236 static inline struct cpuinfo_arm_chipset disambiguate_spreadtrum_chipset(
3237 const struct cpuinfo_arm_chipset proc_cpuinfo_hardware_chipset[restrict static 1],
3238 const struct cpuinfo_arm_chipset ro_product_board_chipset[restrict static 1],
3239 const struct cpuinfo_arm_chipset ro_board_platform_chipset[restrict static 1],
3240 const struct cpuinfo_arm_chipset ro_chipname_chipset[restrict static 1])
3241 {
3242 if (ro_chipname_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3243 return *ro_chipname_chipset;
3244 }
3245 if (ro_product_board_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3246 return *ro_product_board_chipset;
3247 }
3248 if (proc_cpuinfo_hardware_chipset->series != cpuinfo_arm_chipset_series_unknown) {
3249 return *proc_cpuinfo_hardware_chipset;
3250 }
3251 return *ro_board_platform_chipset;
Marat Dukhan006461a2017-08-24 16:10:46 -07003252 }
3253
3254 /*
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003255 * Decodes chipset name from Android system properties:
3256 * - /proc/cpuinfo Hardware string
3257 * - ro.product.board
3258 * - ro.board.platform
3259 * - ro.mediatek.platform
3260 * - ro.chipname
3261 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
3262 *
3263 * @param[in] properties - structure with the Android system properties described above.
3264 * @param cores - number of cores in the chipset.
3265 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
3266 *
3267 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
3268 * and series identifiers.
Marat Dukhan006461a2017-08-24 16:10:46 -07003269 */
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003270 struct cpuinfo_arm_chipset cpuinfo_arm_android_decode_chipset(
3271 const struct cpuinfo_android_properties properties[restrict static 1],
3272 uint32_t cores,
3273 uint32_t max_cpu_freq_max)
3274 {
3275 struct cpuinfo_arm_chipset chipset = {
3276 .vendor = cpuinfo_arm_chipset_vendor_unknown,
3277 .series = cpuinfo_arm_chipset_series_unknown,
3278 };
3279
3280 const bool tegra_platform = is_tegra(
3281 properties->ro_board_platform,
3282 properties->ro_board_platform + strnlen(properties->ro_board_platform, CPUINFO_BUILD_PROP_VALUE_MAX));
3283
3284 struct cpuinfo_arm_chipset chipsets[cpuinfo_android_chipset_property_max] = {
3285 [cpuinfo_android_chipset_property_proc_cpuinfo_hardware] =
Marat Dukhan1415d7d2017-10-16 09:40:15 -07003286 cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003287 properties->proc_cpuinfo_hardware, cores, max_cpu_freq_max, tegra_platform),
3288 [cpuinfo_android_chipset_property_ro_product_board] =
3289 cpuinfo_arm_android_decode_chipset_from_ro_product_board(
3290 properties->ro_product_board, cores, max_cpu_freq_max),
3291 [cpuinfo_android_chipset_property_ro_board_platform] =
3292 cpuinfo_arm_android_decode_chipset_from_ro_board_platform(
3293 properties->ro_board_platform, cores, max_cpu_freq_max),
3294 [cpuinfo_android_chipset_property_ro_mediatek_platform] =
3295 cpuinfo_arm_android_decode_chipset_from_ro_mediatek_platform(properties->ro_mediatek_platform),
3296 [cpuinfo_android_chipset_property_ro_chipname] =
3297 cpuinfo_arm_android_decode_chipset_from_ro_chipname(properties->ro_chipname),
3298 };
3299 enum cpuinfo_arm_chipset_vendor vendor = cpuinfo_arm_chipset_vendor_unknown;
3300 for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
3301 const enum cpuinfo_arm_chipset_vendor decoded_vendor = chipsets[i].vendor;
3302 if (decoded_vendor != cpuinfo_arm_chipset_vendor_unknown) {
3303 if (vendor == cpuinfo_arm_chipset_vendor_unknown) {
3304 vendor = decoded_vendor;
3305 } else if (vendor != decoded_vendor) {
3306 /* Parsing different system properties produces different chipset vendors. This situation is rare. */
3307 cpuinfo_log_error(
3308 "chipset detection failed: different chipset vendors reported in different system properties");
3309 goto finish;
3310 }
3311 }
3312 }
3313 if (vendor == cpuinfo_arm_chipset_vendor_unknown) {
3314 cpuinfo_log_warning(
3315 "chipset detection failed: none of the system properties matched known signatures");
3316 goto finish;
3317 }
3318
3319 /* Fix common bugs in reported chipsets */
3320 for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
3321 cpuinfo_arm_fixup_chipset(&chipsets[i], cores, max_cpu_freq_max);
3322 }
3323
3324 /*
3325 * Propagate suffixes: consider all pairs of chipsets, if both chipsets in the pair are from the same series,
3326 * and one's suffix is a prefix of another's chipset suffix, use the longest suffix.
3327 */
3328 for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
3329 const size_t chipset_i_suffix_length = strnlen(chipsets[i].suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
3330 for (size_t j = 0; j < i; j++) {
3331 if (chipsets[i].series == chipsets[j].series) {
3332 const size_t chipset_j_suffix_length = strnlen(chipsets[j].suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX);
3333 if (chipset_i_suffix_length != chipset_j_suffix_length) {
3334 const size_t common_prefix_length = (chipset_i_suffix_length < chipset_j_suffix_length) ?
3335 chipset_i_suffix_length : chipset_j_suffix_length;
3336 if (common_prefix_length == 0 ||
3337 memcmp(chipsets[i].suffix, chipsets[j].suffix, common_prefix_length) == 0)
3338 {
3339 if (chipset_i_suffix_length > chipset_j_suffix_length) {
3340 memcpy(chipsets[j].suffix, chipsets[i].suffix, chipset_i_suffix_length);
3341 } else {
3342 memcpy(chipsets[i].suffix, chipsets[j].suffix, chipset_j_suffix_length);
3343 }
Marat Dukhan006461a2017-08-24 16:10:46 -07003344 }
3345 }
3346 }
3347 }
3348 }
Marat Dukhan006461a2017-08-24 16:10:46 -07003349
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003350 for (size_t i = 0; i < cpuinfo_android_chipset_property_max; i++) {
3351 if (chipsets[i].series != cpuinfo_arm_chipset_series_unknown) {
3352 if (chipset.series == cpuinfo_arm_chipset_series_unknown) {
3353 chipset = chipsets[i];
3354 } else if (chipsets[i].series != chipset.series || chipsets[i].model != chipset.model ||
3355 strncmp(chipsets[i].suffix, chipset.suffix, CPUINFO_ARM_CHIPSET_SUFFIX_MAX) != 0)
3356 {
3357 cpuinfo_log_info(
3358 "different chipsets reported in different system properties; "
3359 "vendor-specific disambiguation heuristic would be used");
3360 switch (vendor) {
3361 case cpuinfo_arm_chipset_vendor_qualcomm:
3362 return disambiguate_qualcomm_chipset(
3363 &chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3364 &chipsets[cpuinfo_android_chipset_property_ro_product_board],
3365 &chipsets[cpuinfo_android_chipset_property_ro_board_platform],
3366 &chipsets[cpuinfo_android_chipset_property_ro_chipname]);
3367 case cpuinfo_arm_chipset_vendor_mediatek:
3368 return disambiguate_mediatek_chipset(
3369 &chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3370 &chipsets[cpuinfo_android_chipset_property_ro_product_board],
3371 &chipsets[cpuinfo_android_chipset_property_ro_board_platform],
3372 &chipsets[cpuinfo_android_chipset_property_ro_mediatek_platform],
3373 &chipsets[cpuinfo_android_chipset_property_ro_chipname]);
3374 case cpuinfo_arm_chipset_vendor_hisilicon:
3375 return disambiguate_hisilicon_chipset(
3376 &chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3377 &chipsets[cpuinfo_android_chipset_property_ro_product_board],
3378 &chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
3379 case cpuinfo_arm_chipset_vendor_amlogic:
3380 return disambiguate_amlogic_chipset(
3381 &chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3382 &chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
3383 case cpuinfo_arm_chipset_vendor_marvell:
3384 return disambiguate_marvell_chipset(
3385 &chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3386 &chipsets[cpuinfo_android_chipset_property_ro_product_board],
3387 &chipsets[cpuinfo_android_chipset_property_ro_chipname]);
3388 case cpuinfo_arm_chipset_vendor_rockchip:
3389 return disambiguate_rockchip_chipset(
3390 &chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3391 &chipsets[cpuinfo_android_chipset_property_ro_product_board],
3392 &chipsets[cpuinfo_android_chipset_property_ro_board_platform]);
3393 case cpuinfo_arm_chipset_vendor_spreadtrum:
3394 return disambiguate_spreadtrum_chipset(
3395 &chipsets[cpuinfo_android_chipset_property_proc_cpuinfo_hardware],
3396 &chipsets[cpuinfo_android_chipset_property_ro_product_board],
3397 &chipsets[cpuinfo_android_chipset_property_ro_board_platform],
3398 &chipsets[cpuinfo_android_chipset_property_ro_chipname]);
3399 default:
3400 cpuinfo_log_error(
3401 "chipset detection failed: "
3402 "could not disambiguate different chipsets reported in different system properties");
3403 /* chipset variable contains valid, but inconsistent chipset information, overwrite it */
3404 chipset = (struct cpuinfo_arm_chipset) {
3405 .vendor = cpuinfo_arm_chipset_vendor_unknown,
3406 .series = cpuinfo_arm_chipset_series_unknown,
3407 };
3408 goto finish;
3409 }
Marat Dukhan006461a2017-08-24 16:10:46 -07003410 }
3411 }
3412 }
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003413
3414 finish:
3415 return chipset;
3416 }
3417#else /* !defined(__ANDROID__) */
3418
3419 /*
3420 * Decodes chipset name from /proc/cpuinfo Hardware string.
3421 * For some chipsets, the function relies frequency and on number of cores for chipset detection.
3422 *
3423 * @param[in] hardware - /proc/cpuinfo Hardware string.
3424 * @param cores - number of cores in the chipset.
3425 * @param max_cpu_freq_max - maximum of /sys/devices/system/cpu/cpu<number>/cpofreq/cpu_freq_max values.
3426 *
3427 * @returns Decoded chipset name. If chipset could not be decoded, the resulting structure would use `unknown` vendor
3428 * and series identifiers.
3429 */
3430 struct cpuinfo_arm_chipset cpuinfo_arm_linux_decode_chipset(
3431 const char hardware[restrict static CPUINFO_HARDWARE_VALUE_MAX],
3432 uint32_t cores,
3433 uint32_t max_cpu_freq_max)
3434 {
3435 struct cpuinfo_arm_chipset chipset =
Marat Dukhan1415d7d2017-10-16 09:40:15 -07003436 cpuinfo_arm_linux_decode_chipset_from_proc_cpuinfo_hardware(
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003437 hardware, cores, max_cpu_freq_max, false);
3438 if (chipset.vendor == cpuinfo_arm_chipset_vendor_unknown) {
3439 cpuinfo_log_warning(
3440 "chipset detection failed: /proc/cpuinfo Hardware string did not match known signatures");
3441 } else {
3442 cpuinfo_arm_fixup_chipset(&chipset, cores, max_cpu_freq_max);
3443 }
3444 return chipset;
Marat Dukhan006461a2017-08-24 16:10:46 -07003445 }
3446
Marat Dukhan7c775ab2017-10-15 21:50:11 +00003447#endif