ARC: Improve identification of ARC cores

1. Try to guess a ARC core template that was used
   i.e. not just name a core family but something more
   menaingful like "ARC HS38", "ARC EM11D" etc.

   We do it checking availability of the key differentiation
   features like:
    - Caches (we actually only check for L1 I$ fpr simplicity)
    - XY-memory
    - DSP extensions etc.

2. Identify ARC subsystems

3. Print core clock frequency

Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
This commit is contained in:
Alexey Brodkin 2018-11-27 09:46:57 +03:00 committed by Alexey Brodkin
parent ad74bb4fe3
commit 85e529fdfc
2 changed files with 204 additions and 21 deletions

View File

@ -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)

View File

@ -4,6 +4,7 @@
*/
#include <common.h>
#include <malloc.h>
#include <asm/arcregs.h>
#include <asm/cache.h>
@ -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 */