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