blob: 7764ac1ba7183218e31dc03e7b27642de98832d7 [file]
/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <printf.h>
#include <cpuid.h>
#define CPUID_IMPL(cpuid) (((cpuid) >> 24) & 0xff)
#define CPUID_MAJOR(cpuid) (((cpuid) >> 20) & 0xf)
#define CPUID_VARIANT(cpuid) (((cpuid) >> 20) & 0xf)
#define CPUID_ARCH(cpuid) (((cpuid) >> 16) & 0xf)
#define CPUID_PART(cpuid) (((cpuid) >> 4) & 0xfff)
#define CPUID_MINOR(cpuid) (((cpuid) >> 0) & 0xf)
#define CPUID_IMPL_ARM 'A'
#define CPUID_IMPL_DEC 'D'
#define CPUID_IMPL_QCOMM 'Q'
#define CPUID_IMPL_MARV 'V'
#define CPUID_IMPL_MOT 'M'
#define CPUID_IMPL_INTEL 'i'
#define CPUID_ARCH_ARMv4 0x1
#define CPUID_ARCH_ARMv4T 0x2
#define CPUID_ARCH_ARMv5 0x3
#define CPUID_ARCH_ARMv5T 0x4
#define CPUID_ARCH_ARMv5TE 0x5
#define CPUID_ARCH_ARMv5TEJ 0x6
#define CPUID_ARCH_ARMv6 0x7
#define CPUID_ARCH_CPUID 0xF
#if __has_attribute(optimize)
#define OPTIMIZE_CHANGE __attribute__((optimize(1)))
#else
#define OPTIMIZE_CHANGE __attribute__((optnone))
#endif
/*
* At O2 the switch gets optimised into a table, (at least on GCC 7.4 and 8.2)
* which isn't handled properly for position independent code (i.e. when booting on EFI).
*/
OPTIMIZE_CHANGE static const char *cpuid_get_implementer_str(uint32_t cpuid)
{
switch (CPUID_IMPL(cpuid)) {
case CPUID_IMPL_ARM:
return "ARM Ltd.";
case CPUID_IMPL_DEC:
return "Digital Equipment Corp.";
case CPUID_IMPL_QCOMM:
return "Qualcomm Inc.";
case CPUID_IMPL_MARV:
return "Marvell Semiconductor Inc.";
case CPUID_IMPL_MOT:
return "Motorola, Freescale Semiconductor Inc.";
case CPUID_IMPL_INTEL:
return "Intel Corp.";
default:
return "<Reserved>";
}
}
OPTIMIZE_CHANGE static const char *cpuid_get_arch_str(uint32_t cpuid)
{
switch (CPUID_ARCH(cpuid)) {
case CPUID_ARCH_ARMv4:
return "ARMv4";
case CPUID_ARCH_ARMv4T:
return "ARMv4T";
case CPUID_ARCH_ARMv5:
return "ARMv5 (obsolete)";
case CPUID_ARCH_ARMv5T:
return "ARMv5T";
case CPUID_ARCH_ARMv5TE:
return "ARMv5TE";
case CPUID_ARCH_ARMv5TEJ:
return "ARMv5TEJ";
case CPUID_ARCH_ARMv6:
return "ARMv6";
case CPUID_ARCH_CPUID:
return "Defined by CPUID scheme";
default:
return "<Reserved>";
}
}
OPTIMIZE_CHANGE static const char *cpuid_get_arm_part_str(uint32_t cpuid)
{
switch (CPUID_PART(cpuid)) {
case 0xC05:
return "Cortex-A5";
case 0xC07:
return "Cortex-A7";
case 0xC08:
return "Cortex-A8";
case 0xC09:
return "Cortex-A9";
case 0xC0D:
return "Cortex-A12";
case 0xC0F:
return "Cortex-A15";
case 0xC0E:
return "Cortex-A17";
case 0xD01:
return "Cortex-A32";
case 0xD02:
return "Cortex-A34";
case 0xD03:
return "Cortex-A53";
case 0xD04:
return "Cortex-A35";
case 0xD05:
return "Cortex-A55";
case 0xD06:
return "Cortex-A65";
case 0xD07:
return "Cortex-A57";
case 0xD08:
return "Cortex-A72";
case 0xD09:
return "Cortex-A73";
case 0xD0A:
return "Cortex-A75";
case 0xD0B:
return "Cortex-A76";
case 0xD0C:
return "Neoverse N1";
case 0xD0D:
return "Cortex-A77";
case 0xD0E:
return "Cortex-A76AE";
case 0xD40:
return "Neoverse V1";
case 0xD41:
return "Cortex-A78";
case 0xD42:
return "Cortex-A78AE";
case 0xD43:
return "Cortex-A65AE";
case 0xD44:
return "Cortex-X1";
case 0xD46:
return "Cortex-A510";
case 0xD47:
return "Cortex-A710";
case 0xD48:
return "Cortex-X2";
case 0xD49:
return "Neoverse N2";
case 0xD4A:
return "Neoverse E1";
case 0xD4B:
return "Cortex-78C";
default:
return NULL;
}
}
void print_cpuid(void)
{
uint32_t cpuid;
const char *part = NULL;
cpuid = read_cpuid_id();
if (CPUID_IMPL(cpuid) == CPUID_IMPL_ARM) {
part = cpuid_get_arm_part_str(cpuid);
}
printf("CPU: %s ", cpuid_get_implementer_str(cpuid));
if (CPUID_ARCH(cpuid) != CPUID_ARCH_CPUID) {
printf("%s ", cpuid_get_arch_str(cpuid));
}
if (part == NULL) {
printf("Part: 0x%03x ", CPUID_PART(cpuid));
} else {
printf("%s ", part);
}
printf("r%dp%d", CPUID_MAJOR(cpuid), CPUID_MINOR(cpuid));
printf("\n");
}
int get_cortex_a_part(void)
{
uint32_t cpuid;
cpuid = read_cpuid_id();
if (CPUID_ARCH(cpuid) == CPUID_ARCH_CPUID && CPUID_IMPL(cpuid) == CPUID_IMPL_ARM) {
return CPUID_PART(cpuid) & 0xFF;
} else {
return -1;
}
}