diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 9920d2e719..fff6591c68 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -16,6 +16,20 @@ * access: "lr"/"sr". */ +/* + * Typically 8 least significant bits of Build Configuration Register (BCR) + * describe version of the HW block in question. Moreover if decoded version + * is 0 this means given HW block is absent - this is especially useful because + * we may safely read BRC regardless HW block existence while an attempt to + * access any other AUX regs associated with this HW block lead to imediate + * "instruction error" exception. + * + * I.e. before using any cofigurable HW block it's required to make sure it + * exists at all, and for that we introduce a special macro below. + */ +#define ARC_BCR_VERSION_MASK GENMASK(7, 0) +#define ARC_FEATURE_EXISTS(bcr) !!(__builtin_arc_lr(bcr) & ARC_BCR_VERSION_MASK) + #define ARC_AUX_IDENTITY 0x04 #define ARC_AUX_STATUS32 0x0a @@ -73,7 +87,7 @@ #define ARC_BCR_CLUSTER 0xcf /* MMU Management regs */ -#define ARC_AUX_MMU_BCR 0x06f +#define ARC_AUX_MMU_BCR 0x6f /* IO coherency related auxiliary registers */ #define ARC_AUX_IO_COH_ENABLE 0x500 @@ -81,6 +95,15 @@ #define ARC_AUX_IO_COH_AP0_BASE 0x508 #define ARC_AUX_IO_COH_AP0_SIZE 0x509 +/* XY-memory related */ +#define ARC_AUX_XY_BUILD 0x79 + +/* DSP-extensions related auxiliary registers */ +#define ARC_AUX_DSP_BUILD 0x7A + +/* ARC Subsystems related auxiliary registers */ +#define ARC_AUX_SUBSYS_BUILD 0xF0 + #ifndef __ASSEMBLY__ /* Accessors for auxiliary registers */ #define read_aux_reg(reg) __builtin_arc_lr(reg) diff --git a/arch/arc/lib/cpu.c b/arch/arc/lib/cpu.c index a969a16722..07daaa8d15 100644 --- a/arch/arc/lib/cpu.c +++ b/arch/arc/lib/cpu.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -35,34 +36,193 @@ int dram_init(void) } #ifdef CONFIG_DISPLAY_CPUINFO -const char *decode_identity(void) +const char *arc_700_version(int arcver, char *name, int name_len) { - int arcver = read_aux_reg(ARC_AUX_IDENTITY) & 0xff; + const char *arc_ver; switch (arcver) { - /* ARCompact cores */ - case 0x32: return "ARC 700 v4.4-4.5"; - case 0x33: return "ARC 700 v4.6-v4.9"; - case 0x34: return "ARC 700 v4.10"; - case 0x35: return "ARC 700 v4.11"; - - /* ARCv2 cores */ - case 0x41: return "ARC EM v1.1a"; - case 0x42: return "ARC EM v3.0"; - case 0x43: return "ARC EM v4.0"; - case 0x50: return "ARC HS v1.0"; - case 0x51: return "ARC EM v2.0"; - case 0x52: return "ARC EM v2.1"; - case 0x53: return "ARC HS v3.0"; - case 0x54: return "ARC HS v4.0"; - - default: return "Unknown ARC core"; + case 0x32: + arc_ver = "v4.4-4.5"; + break; + case 0x33: + arc_ver = "v4.6-v4.9"; + break; + case 0x34: + arc_ver = "v4.10"; + break; + case 0x35: + arc_ver = "v4.11"; + break; + default: + arc_ver = "unknown version"; } + + snprintf(name, name_len, "ARC 700 %s", arc_ver); + + return name; +} + +struct em_template_t { + const bool cache; + const bool dsp; + const bool xymem; + const char name[8]; +}; + +static const struct em_template_t em_versions[] = { + {false, false, false, "EM4"}, + {true, false, false, "EM6"}, + {false, true, false, "EM5D"}, + {true, true, false, "EM7D"}, + {false, true, true, "EM9D"}, + {true, true, true, "EM11D"}, +}; + +const char *arc_em_version(int arcver, char *name, int name_len) +{ + const char *arc_name = "EM"; + const char *arc_ver; + bool cache = ARC_FEATURE_EXISTS(ARC_BCR_IC_BUILD); + bool dsp = ARC_FEATURE_EXISTS(ARC_AUX_DSP_BUILD); + bool xymem = ARC_FEATURE_EXISTS(ARC_AUX_XY_BUILD); + int i; + + for (i = 0; i++ < sizeof(em_versions) / sizeof(struct em_template_t);) { + if (em_versions[i].cache == cache && + em_versions[i].dsp == dsp && + em_versions[i].xymem == xymem) { + arc_name = em_versions[i].name; + break; + } + } + + switch (arcver) { + case 0x41: + arc_ver = "v1.1a"; + break; + case 0x42: + arc_ver = "v3.0"; + break; + case 0x43: + arc_ver = "v4.0"; + break; + case 0x44: + arc_ver = "v5.0"; + break; + default: + arc_ver = "unknown version"; + } + + snprintf(name, name_len, "ARC %s %s", arc_name, arc_ver); + + return name; +} + +struct hs_template_t { + const bool cache; + const bool mmu; + const bool dual_issue; + const bool dsp; + const char name[8]; +}; + +static const struct hs_template_t hs_versions[] = { + {false, false, false, false, "HS34"}, + {true, false, false, false, "HS36"}, + {true, true, false, false, "HS38"}, + {false, false, true, false, "HS44"}, + {true, false, true, false, "HS46"}, + {true, true, true, false, "HS48"}, + {false, false, true, true, "HS45D"}, + {true, false, true, true, "HS47D"}, +}; + +const char *arc_hs_version(int arcver, char *name, int name_len) +{ + const char *arc_name = "HS"; + const char *arc_ver; + bool cache = ARC_FEATURE_EXISTS(ARC_BCR_IC_BUILD); + bool dsp = ARC_FEATURE_EXISTS(ARC_AUX_DSP_BUILD); + bool mmu = !!read_aux_reg(ARC_AUX_MMU_BCR); + bool dual_issue = arcver == 0x54 ? true : false; + int i; + + for (i = 0; i++ < sizeof(hs_versions) / sizeof(struct hs_template_t);) { + if (hs_versions[i].cache == cache && + hs_versions[i].mmu == mmu && + hs_versions[i].dual_issue == dual_issue && + hs_versions[i].dsp == dsp) { + arc_name = hs_versions[i].name; + break; + } + } + + switch (arcver) { + case 0x50: + arc_ver = "v1.0"; + break; + case 0x51: + arc_ver = "v2.0"; + break; + case 0x52: + arc_ver = "v2.1c"; + break; + case 0x53: + arc_ver = "v3.0"; + break; + case 0x54: + arc_ver = "v4.0"; + break; + default: + arc_ver = "unknown version"; + } + + snprintf(name, name_len, "ARC %s %s", arc_name, arc_ver); + + return name; +} + +const char *decode_identity(void) +{ +#define MAX_CPU_NAME_LEN 64 + + int arcver = read_aux_reg(ARC_AUX_IDENTITY) & 0xff; + char *name = malloc(MAX_CPU_NAME_LEN); + + if (arcver >= 0x50) + return arc_hs_version(arcver, name, MAX_CPU_NAME_LEN); + else if (arcver >= 0x40) + return arc_em_version(arcver, name, MAX_CPU_NAME_LEN); + else if (arcver >= 0x30) + return arc_700_version(arcver, name, MAX_CPU_NAME_LEN); + else + return "Unknown ARC core"; +} + +const char *decode_subsystem(void) +{ + int subsys_type = read_aux_reg(ARC_AUX_SUBSYS_BUILD) & GENMASK(3, 0); + + switch (subsys_type) { + case 0: return NULL; + case 2: return "ARC Sensor & Control IP Subsystem"; + case 3: return "ARC Data Fusion IP Subsystem"; + case 4: return "ARC Secure Subsystem"; + default: return "Unknown subsystem"; + }; } __weak int print_cpuinfo(void) { - printf("CPU: %s\n", decode_identity()); + const char *subsys_name = decode_subsystem(); + char mhz[8]; + + printf("CPU: %s at %s MHz\n", decode_identity(), + strmhz(mhz, gd->cpu_clk)); + + if (subsys_name) + printf("Subsys:%s\n", subsys_name); + return 0; } #endif /* CONFIG_DISPLAY_CPUINFO */