#include <linux/dmi.h>
#include <linux/string.h>
#include <linux/cputypes.h>
#include <linux/classtypes.h>
static char core_count;
static void get_core_count_by_dmi(const struct dmi_header *dm, void *cpu_count)
{
const u8 *dmi_data = (const u8 *)dm;
if (dm->type == 4 && dm->length >= 0x28)
*(u8 *)cpu_count = *(const u8 *)(dmi_data + 0x23);
}
static u8 get_core_count(void)
{
if (!core_count)
dmi_walk(get_core_count_by_dmi, &core_count);
return core_count;
}
static DEFINE_MUTEX(system_cpu_lock);
static struct cpu_identifier system_cpu;
static bool system_cpu_initialized;
static void detect_cpu_vendor(void)
{
if (read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM)
system_cpu.vendor = CPU_VENDOR_PHYTIUM;
else
system_cpu.vendor = CPU_VENDOR_UNKNOWN;
}
static void detect_phytium_models(void)
{
int model = read_cpuid_id() & MIDR_CPU_MODEL_MASK;
const char *name = get_cpu_name();
if (model == MIDR_PHYTIUM_FTC663 || model == MIDR_PHYTIUM_PS17064) {
if (get_core_count() == 8) {
system_cpu.model_bits = PHYTIUM_MODEL_D2000;
} else if (get_core_count() == 4 ||
strncmp(name, "FT2004", 6) == 0 ||
strncmp(name, "FT2000A", 7) == 0 ||
strncmp(name, "FT-2000/4", 9) == 0) {
system_cpu.model_bits = PHYTIUM_MODEL_FT2004;
} else {
pr_info("%s: core_count:%d from SMBIOS is invalid!\n",
__func__, get_core_count());
}
} else {
pr_info("%s: unknown model %x", __func__, model);
}
}
static void init_cpu_identifier(void)
{
mutex_lock(&system_cpu_lock);
if (unlikely(system_cpu_initialized)) {
mutex_unlock(&system_cpu_lock);
return;
}
detect_cpu_vendor();
if (system_cpu.vendor == CPU_VENDOR_PHYTIUM)
detect_phytium_models();
smp_store_release(&system_cpu_initialized, true);
mutex_unlock(&system_cpu_lock);
}
bool cpu_match(u32 vendor, u32 model_mask)
{
if (unlikely(!smp_load_acquire(&system_cpu_initialized)))
init_cpu_identifier();
return (vendor == system_cpu.vendor) &&
(model_mask & system_cpu.model_bits);
}
EXPORT_SYMBOL(cpu_match);
bool cpu_is_ft2004(void)
{
return cpu_match(CPU_VENDOR_PHYTIUM, PHYTIUM_MODEL_FT2004);
}
EXPORT_SYMBOL(cpu_is_ft2004);
bool cpu_is_ft_d2000(void)
{
return cpu_match(CPU_VENDOR_PHYTIUM, PHYTIUM_MODEL_D2000);
}
EXPORT_SYMBOL(cpu_is_ft_d2000);