ARC: Improve identification of ARC cores
authorAlexey Brodkin <alexey.brodkin@synopsys.com>
Tue, 27 Nov 2018 06:46:57 +0000 (09:46 +0300)
committerAlexey Brodkin <abrodkin@synopsys.com>
Mon, 3 Dec 2018 11:26:18 +0000 (14:26 +0300)
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>
arch/arc/include/asm/arcregs.h
arch/arc/lib/cpu.c

index 9920d2e71952e10e3c956a41bee00391141d4759..fff6591c681d9968df82b90b2977f9fc0eb8d52b 100644 (file)
  * 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
 #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)
index a969a167228d780c8180c07a54890034650bc033..07daaa8d155156f157e62d0794d62f7b9d0ebf70 100644 (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) {
+       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) {
-       /* 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 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 */