CPU (Linux): fixes Snapdragon X2 series model detection

Fixes #2611
This commit is contained in:
Carter Li
2026-09-25 08:46:13 +08:00
parent d223b04ad8
commit 80a931a87f
4 changed files with 123 additions and 41 deletions
+63 -41
View File
@@ -706,6 +706,68 @@ static bool detectFrequency(FFCPUResult* cpu, const FFCPUOptions* options) {
return true;
}
// Also used in tests/cpu.c
bool ffCPUQualcommSnapdragonToName(FFstrbuf* name, const char* model) {
// X2 device trees use platform codenames rather than exact retail part
// numbers. qcom,glymur is used by X2 Elite Extreme boards, qcom,mahua by
// X2 Elite boards, and qcom,kalambo by X2 Plus boards. Do not append a
// part number from /sys/bus/soc/devices/soc0/soc_id: it contains
// SMEM_HW_SW_BUILD_ID.id (the platform ID), 662 is unnamed in the public
// qcom,ids.h, and one compatible can cover multiple retail SKUs.
// https://github.com/fastfetch-cli/fastfetch/issues/2611
if (ffStrEquals(model, "glymur")) {
ffStrbufSetS(name, "Qualcomm Snapdragon X2 Elite Extreme");
return true;
}
if (ffStrEquals(model, "mahua")) {
ffStrbufSetS(name, "Qualcomm Snapdragon X2 Elite");
return true;
}
if (ffStrEquals(model, "kalambo")) {
ffStrbufSetS(name, "Qualcomm Snapdragon X2 Plus");
return true;
}
// SoC models are enumerated in the form of `x<gen>[e|p]<part><rev>`, e.g. `x1e80100`,
// which is marketed as `X1E-80-100`, where `e` stands for Elite and `p` for Plus.
// https://en.wikipedia.org/wiki/List_of_Qualcomm_Snapdragon_systems_on_chips#Snapdragon_X_series
const char* prefix;
uint32_t prefixLen;
if (ffStrStartsWith(model, "x1e")) {
prefix = "Qualcomm Snapdragon X Elite";
prefixLen = 3;
} else if (ffStrStartsWith(model, "x1p")) {
prefix = "Qualcomm Snapdragon X Plus";
prefixLen = 3;
} else if (ffStrStartsWith(model, "x2e")) {
// Only X2E-94-100 and X2E-96-100 are branded as Extreme
bool extreme = ffStrStartsWith(model, "x2e94") || ffStrStartsWith(model, "x2e96");
prefix = extreme ? "Qualcomm Snapdragon X2 Elite Extreme" : "Qualcomm Snapdragon X2 Elite";
prefixLen = 3;
} else if (ffStrStartsWith(model, "x2p")) {
prefix = "Qualcomm Snapdragon X2 Plus";
prefixLen = 3;
} else if (ffStrStartsWith(model, "x1")) {
prefix = "Qualcomm Snapdragon X";
prefixLen = 2;
} else {
return false;
}
uint32_t length = (uint32_t) strlen(model);
bool splitCode = length - prefixLen == 5;
ffStrbufSetF(name, "%s X", prefix);
for (uint32_t i = 1; i < length; ++i) {
if (i == prefixLen || (splitCode && i == length - 3)) {
ffStrbufAppendC(name, '-');
}
ffStrbufAppendC(name, (char) toupper(model[i]));
}
return true;
}
#if __i386__ || __x86_64__
[[maybe_unused]] static uint16_t getPackageCount(FFstrbuf* cpuinfo) {
@@ -840,46 +902,6 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) {
return nullptr;
}
[[maybe_unused]] static bool detectSnapdragonX(FFstrbuf* name, const char* model) {
// SoC models are enumerated in the form of `x<gen>[e|p]<part><rev>`, e.g. `x1e80100`,
// which is marketed as `X1E-80-100`, where `e` stands for Elite and `p` for Plus.
// https://en.wikipedia.org/wiki/List_of_Qualcomm_Snapdragon_systems_on_chips#Snapdragon_X_series
const char* prefix;
uint32_t prefixLen;
if (ffStrStartsWith(model, "x1e")) {
prefix = "Qualcomm Snapdragon X Elite";
prefixLen = 3;
} else if (ffStrStartsWith(model, "x1p")) {
prefix = "Qualcomm Snapdragon X Plus";
prefixLen = 3;
} else if (ffStrStartsWith(model, "x2e")) {
// Only X2E-94-100 and X2E-96-100 are branded as Extreme
prefix = model[3] == '9' ? "Qualcomm Snapdragon X2 Elite Extreme" : "Qualcomm Snapdragon X2 Elite";
prefixLen = 3;
} else if (ffStrStartsWith(model, "x2p")) {
prefix = "Qualcomm Snapdragon X2 Plus";
prefixLen = 3;
} else if (ffStrStartsWith(model, "x1")) {
prefix = "Qualcomm Snapdragon X";
prefixLen = 2;
} else {
return false;
}
uint32_t length = (uint32_t) strlen(model);
bool splitCode = length - prefixLen == 5;
ffStrbufSetF(name, "%s X", prefix);
for (uint32_t i = 1; i < length; ++i) {
if (i == prefixLen || (splitCode && i == length - 3)) {
ffStrbufAppendC(name, '-');
}
ffStrbufAppendC(name, (char) toupper(model[i]));
}
return true;
}
[[maybe_unused]] static void parseIsa(FFstrbuf* cpuIsa) {
// Always use the last part of the ISA string. Ref: #590 #1204
ffStrbufSubstrAfterLastC(cpuIsa, ' ');
@@ -982,7 +1004,7 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) {
#endif
else if (ffStrEquals(vendor, "qcom")) {
// https://elixir.bootlin.com/linux/latest/source/arch/arm64/boot/dts/qcom
if (!detectSnapdragonX(&cpu->name, model)) {
if (!ffCPUQualcommSnapdragonToName(&cpu->name, model)) {
if (ffStrStartsWith(model, "sc")) {
const char* code = model + 2;
uint32_t deviceId = (uint32_t) strtoul(code, nullptr, 10);