Merge tag 'arc-updates-for-2019.01-rc1' of git://git.denx.de/u-boot-arc

We introduce much better automatic identification of ARC cores.

 1. Try to match found HW features to known ARC core templates
 2. Print CPU frequency for all ARC boards
 3. Add more board-specific info
diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h
index 9920d2e..fff6591 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 a969a16..07daaa8 100644
--- a/arch/arc/lib/cpu.c
+++ b/arch/arc/lib/cpu.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <malloc.h>
 #include <asm/arcregs.h>
 #include <asm/cache.h>
 
@@ -35,34 +36,193 @@
 }
 
 #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 */
diff --git a/board/synopsys/axs10x/axs10x.c b/board/synopsys/axs10x/axs10x.c
index c95f7af..ffa7c15 100644
--- a/board/synopsys/axs10x/axs10x.c
+++ b/board/synopsys/axs10x/axs10x.c
@@ -109,3 +109,11 @@
 	writel(cmd, (void __iomem *)AXC003_CREG_CPU_START);
 }
 #endif
+
+int checkboard(void)
+{
+	printf("Board: ARC Software Development Platform AXS%s\n",
+	     is_isa_arcv2() ? "103" : "101");
+
+	return 0;
+};
diff --git a/board/synopsys/emsdp/emsdp.c b/board/synopsys/emsdp/emsdp.c
index b5ec7f1..c0770b5 100644
--- a/board/synopsys/emsdp/emsdp.c
+++ b/board/synopsys/emsdp/emsdp.c
@@ -7,10 +7,46 @@
 #include <dwmmc.h>
 #include <malloc.h>
 
+#include <asm/arcregs.h>
+
 DECLARE_GLOBAL_DATA_PTR;
 
-#define ARC_PERIPHERAL_BASE	0xF0000000
-#define SDIO_BASE		(ARC_PERIPHERAL_BASE + 0x10000)
+#define ARC_PERIPHERAL_BASE		0xF0000000
+
+#define CGU_ARC_FMEAS_ARC		(void *)(ARC_PERIPHERAL_BASE + 0x84)
+#define CGU_ARC_FMEAS_ARC_START		BIT(31)
+#define CGU_ARC_FMEAS_ARC_DONE		BIT(30)
+#define CGU_ARC_FMEAS_ARC_CNT_MASK	GENMASK(14, 0)
+#define CGU_ARC_FMEAS_ARC_RCNT_OFFSET	0
+#define CGU_ARC_FMEAS_ARC_FCNT_OFFSET	15
+
+#define SDIO_BASE			(void *)(ARC_PERIPHERAL_BASE + 0x10000)
+
+int mach_cpu_init(void)
+{
+	int rcnt, fcnt;
+	u32 data;
+
+	/* Start frequency measurement */
+	writel(CGU_ARC_FMEAS_ARC_START, CGU_ARC_FMEAS_ARC);
+
+	/* Poll DONE bit */
+	do {
+		data = readl(CGU_ARC_FMEAS_ARC);
+	} while (!(data & CGU_ARC_FMEAS_ARC_DONE));
+
+	/* Amount of reference 100 MHz clocks */
+	rcnt = ((data >> CGU_ARC_FMEAS_ARC_RCNT_OFFSET) &
+	       CGU_ARC_FMEAS_ARC_CNT_MASK);
+
+	/* Amount of CPU clocks */
+	fcnt = ((data >> CGU_ARC_FMEAS_ARC_FCNT_OFFSET) &
+	       CGU_ARC_FMEAS_ARC_CNT_MASK);
+
+	gd->cpu_clk = ((100 * fcnt) / rcnt) * 1000000;
+
+	return 0;
+}
 
 int board_mmc_init(bd_t *bis)
 {
@@ -24,7 +60,7 @@
 
 	memset(host, 0, sizeof(struct dwmci_host));
 	host->name = "Synopsys Mobile storage";
-	host->ioaddr = (void *)SDIO_BASE;
+	host->ioaddr = SDIO_BASE;
 	host->buswidth = 4;
 	host->dev_index = 0;
 	host->bus_hz = 50000000;
@@ -42,31 +78,32 @@
 }
 
 #define CREG_BASE		0xF0001000
-#define CREG_BOOT_OFFSET	0
-#define CREG_BOOT_WP_OFFSET	8
+#define CREG_BOOT		(void *)(CREG_BASE + 0x0FF0)
+#define CREG_IP_SW_RESET	(void *)(CREG_BASE + 0x0FF0)
+#define CREG_IP_VERSION		(void *)(CREG_BASE + 0x0FF8)
 
-#define CGU_BASE		0xF0000000
-#define CGU_IP_SW_RESET		0x0FF0
+/* Bits in CREG_BOOT register */
+#define CREG_BOOT_WP_BIT	BIT(8)
 
 void reset_cpu(ulong addr)
 {
-	writel(1, (u32 *)(CGU_BASE + CGU_IP_SW_RESET));
+	writel(1, CREG_IP_SW_RESET);
 	while (1)
 		; /* loop forever till reset */
 }
 
 static int do_emsdp_rom(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
-	u32 creg_boot = readl((u32 *)(CREG_BASE + CREG_BOOT_OFFSET));
+	u32 creg_boot = readl(CREG_BOOT);
 
 	if (!strcmp(argv[1], "unlock"))
-		creg_boot &= ~BIT(CREG_BOOT_WP_OFFSET);
+		creg_boot &= ~CREG_BOOT_WP_BIT;
 	else if (!strcmp(argv[1], "lock"))
-		creg_boot |= BIT(CREG_BOOT_WP_OFFSET);
+		creg_boot |= CREG_BOOT_WP_BIT;
 	else
 		return CMD_RET_USAGE;
 
-	writel(creg_boot, (u32 *)(CREG_BASE + CREG_BOOT_OFFSET));
+	writel(creg_boot, CREG_BOOT);
 
 	return CMD_RET_SUCCESS;
 }
@@ -97,3 +134,12 @@
 	"rom unlock - Unlock non-volatile memory for writing\n"
 	"emsdp rom lock - Lock non-volatile memory to prevent writing\n"
 );
+
+int checkboard(void)
+{
+	int version = readl(CREG_IP_VERSION);
+
+	printf("Board: ARC EM Software Development Platform v%d.%d\n",
+	       (version >> 16) & 0xff, version & 0xff);
+	return 0;
+};
diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c
index b6aefdb..8a2c201 100644
--- a/board/synopsys/hsdk/hsdk.c
+++ b/board/synopsys/hsdk/hsdk.c
@@ -1054,10 +1054,8 @@
 	return 0;
 }
 
-#ifdef CONFIG_DISPLAY_CPUINFO
-int print_cpuinfo(void)
+int checkboard(void)
 {
-	printf("CPU:   ARC HS38 v2.1c\n");
+	puts("Board: Synopsys ARC HS Development Kit\n");
 	return 0;
-}
-#endif /* CONFIG_DISPLAY_CPUINFO */
+};
diff --git a/board/synopsys/iot_devkit/iot_devkit.c b/board/synopsys/iot_devkit/iot_devkit.c
index f8838fb..8424e09 100644
--- a/board/synopsys/iot_devkit/iot_devkit.c
+++ b/board/synopsys/iot_devkit/iot_devkit.c
@@ -189,13 +189,3 @@
 	puts("Board: Synopsys IoT Development Kit\n");
 	return 0;
 };
-
-#ifdef CONFIG_DISPLAY_CPUINFO
-int print_cpuinfo(void)
-{
-	char mhz[8];
-
-	printf("CPU:   ARC EM9D at %s MHz\n", strmhz(mhz, gd->cpu_clk));
-	return 0;
-}
-#endif /* CONFIG_DISPLAY_CPUINFO */
diff --git a/include/configs/emsdp.h b/include/configs/emsdp.h
index 385d59e..9a205ed 100644
--- a/include/configs/emsdp.h
+++ b/include/configs/emsdp.h
@@ -11,7 +11,7 @@
 #define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
 
 #define CONFIG_SYS_SDRAM_BASE		0x10000000
-#define CONFIG_SYS_SDRAM_SIZE		SZ_8M
+#define CONFIG_SYS_SDRAM_SIZE		SZ_16M
 
 #define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_1M)