MLK-20758 mx7: Add new command for tamper pin

Add new u-boot command "imx_tamper" to configure and check the tamper pins.
The codes are used for reference and test. So command is disabled at default,
user can enable it by adding CONFIG_IMX_TAMPER=y to defconfig

The iMX7D has 10 tamper pins those can be used for SNVS tamper detection.

Tamper 9 pin is NVCC_DRAM power switch for LPSR by default.
It must be fused to tamper function by command
=> fuse prog -y 1 3 0x80000000
Otherwise, SNVS power consumption would be high

When tamper is detected, CPU can't enter/stay in SNVS mode,
the tamper must be cleared and disabled before enter SNVS.

Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Shaojun Wang <shaojun.wang@nxp.com>
Acked-by: Peng Fan <peng.fan@nxp.com>
(cherry picked from commit d520e1c6067c08103a020b0bc19feb620473e543)
diff --git a/arch/arm/include/asm/arch-mx7/snvs.h b/arch/arm/include/asm/arch-mx7/snvs.h
new file mode 100644
index 0000000..a18f853
--- /dev/null
+++ b/arch/arm/include/asm/arch-mx7/snvs.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __MX7_SNVS_H__
+#define __MX7_SNVS_H__
+
+#define SNVS_HPCOMR			SNVS_BASE_ADDR + 0x04
+#define SNVS_HPSICR			SNVS_BASE_ADDR + 0x0C
+#define SNVS_HPSVCR			SNVS_BASE_ADDR + 0x10
+#define SNVS_HPSR			SNVS_BASE_ADDR + 0x14
+#define SNVS_HPSVSR			SNVS_BASE_ADDR + 0x18
+#define SNVS_LPCR			SNVS_BASE_ADDR + 0x38
+#define SNVS_LPMKCR			SNVS_BASE_ADDR + 0x3C
+#define SNVS_LPTGFCR		SNVS_BASE_ADDR + 0x44
+#define SNVS_LPTDCR			SNVS_BASE_ADDR + 0x48
+#define SNVS_LPSR			SNVS_BASE_ADDR + 0x4C
+#define SNVS_LPPGDR			SNVS_BASE_ADDR + 0x64
+#define SNVS_LPZMKR0		SNVS_BASE_ADDR + 0x6C
+#define SNVS_LPZMKR1		SNVS_BASE_ADDR + 0x70
+#define SNVS_LPZMKR2		SNVS_BASE_ADDR + 0x74
+#define SNVS_LPZMKR3		SNVS_BASE_ADDR + 0x78
+#define SNVS_LPZMKR4		SNVS_BASE_ADDR + 0x7C
+#define SNVS_LPZMKR5		SNVS_BASE_ADDR + 0x80
+#define SNVS_LPZMKR6		SNVS_BASE_ADDR + 0x84
+#define SNVS_LPZMKR7		SNVS_BASE_ADDR + 0x88
+#define SNVS_LPTDC2R		SNVS_BASE_ADDR + 0xA0
+#define SNVS_LPTDSR			SNVS_BASE_ADDR + 0xA4
+#define SNVS_LPTGF1CR		SNVS_BASE_ADDR + 0xA8
+#define SNVS_LPTGF2CR		SNVS_BASE_ADDR + 0xAC
+#define SNVS_LPAT1CR		SNVS_BASE_ADDR + 0xC0
+#define SNVS_LPATCTLR		SNVS_BASE_ADDR + 0xE0
+#define SNVS_LPATCLKR		SNVS_BASE_ADDR + 0xE4
+#define SNVS_LPATRC1R		SNVS_BASE_ADDR + 0xE8
+#define SNVS_LPATRC2R		SNVS_BASE_ADDR + 0xEC
+
+#define AT5_POLYSEED		0x12345678
+
+#endif
diff --git a/arch/arm/mach-imx/mx7/Kconfig b/arch/arm/mach-imx/mx7/Kconfig
index 9327858..58658d8 100644
--- a/arch/arm/mach-imx/mx7/Kconfig
+++ b/arch/arm/mach-imx/mx7/Kconfig
@@ -16,6 +16,11 @@
 	select ROM_UNIFIED_SECTIONS
 	imply CMD_FUSE
 
+config IMX_TAMPER
+	bool "Enable commands for SNVS tamper pin configuration and test"
+	help
+	  Set "Y" to enable the tamper commands
+
 choice
 	prompt "MX7 board select"
 	optional
diff --git a/arch/arm/mach-imx/mx7/Makefile b/arch/arm/mach-imx/mx7/Makefile
index f1436e2..2555037 100644
--- a/arch/arm/mach-imx/mx7/Makefile
+++ b/arch/arm/mach-imx/mx7/Makefile
@@ -4,4 +4,5 @@
 #
 
 obj-y	:= soc.o clock.o clock_slice.o ddr.o snvs.o
+obj-$(CONFIG_IMX_TAMPER) += tamper.o
 obj-$(CONFIG_ARMV7_PSCI)  += psci-mx7.o psci-suspend.o
diff --git a/arch/arm/mach-imx/mx7/tamper.c b/arch/arm/mach-imx/mx7/tamper.c
new file mode 100644
index 0000000..89f6239
--- /dev/null
+++ b/arch/arm/mach-imx/mx7/tamper.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/arch/snvs.h>
+
+void enable_active_tamper(unsigned int tx, unsigned int rx)
+{
+	int val;
+
+	printf("start active tamper test on %d -> %d\n", tx, rx);
+
+	/****************************
+	 *   Configuring CAAM and SNVS  *
+	 ****************************/
+
+	/* Initialize power glitch detector register */
+	val = 0x41736166;
+	writel(val, SNVS_LPPGDR);
+
+	/* W1C PGD */
+	val = readl(SNVS_LPSR) & 0x00000008;
+	writel(val, SNVS_LPSR);
+
+	/* Programming ZMK via SW */
+	writel(0x11110000, SNVS_LPZMKR0);
+	writel(0x22220000, SNVS_LPZMKR1);
+	writel(0x33330000, SNVS_LPZMKR2);
+	writel(0x44440000, SNVS_LPZMKR3);
+	writel(0x55550000, SNVS_LPZMKR4);
+	writel(0x66660000, SNVS_LPZMKR5);
+	writel(0x77770000, SNVS_LPZMKR6);
+	writel(0x88880000, SNVS_LPZMKR7);
+
+	val = readl(SNVS_LPMKCR) | 0xa;
+	writel(val, SNVS_LPMKCR);
+	val = readl(SNVS_HPCOMR) | 0x1000;
+	writel(val, SNVS_HPCOMR);
+
+	val = readl(SNVS_LPMKCR) | 0x10;
+	writel(val, SNVS_LPMKCR);
+
+	val = readl(SNVS_HPSVSR);
+
+	/* LP Security Violation is a non-fatal Violation */
+	val = 0x40000000;
+	writel(val, SNVS_HPSVCR);
+
+	/* Enable SRTC invalidation in case of security violation */
+	val = readl(SNVS_LPCR);
+	val |= 0x11;
+	writel(val, SNVS_LPCR);
+
+	/*********************************
+	 *   Configuring active tamper tx output  *
+	 *********************************/
+
+	/* Configure LFSR polynomial and seed for active tamper tx */
+	val = AT5_POLYSEED;
+	writel(val, SNVS_LPAT1CR + (tx - 5) * 4);
+
+	/* Enable active tamper tx external pad */
+	val = readl(SNVS_LPATCTLR) | (1 << (tx - 5 + 16));
+	writel(val, SNVS_LPATCTLR);
+
+	/* Enable active tamper tx clk 16hz */
+	val = readl(SNVS_LPATCLKR);
+	val &= ~(3 << (tx - 5) * 4);
+	writel(val, SNVS_LPATCLKR);
+
+	/* Enable active tamper tx LFSR */
+	val = readl(SNVS_LPATCTLR) | (1 << (tx - 5));
+	writel(val, SNVS_LPATCTLR);
+
+	/* Enable glitch filter for external tamper rx */
+	if (rx < 2) {
+		val = readl(SNVS_LPTGFCR);
+		if (rx == 0)
+			val |= 0x800000;
+		else if (rx == 1)
+			val |= 0x80000000;
+		writel(val, SNVS_LPTGFCR);
+	} else if (rx < 6) {
+		val = readl(SNVS_LPTGF1CR);
+		val |= 1 << ((rx - 1) * 8 - 1);
+		writel(val, SNVS_LPTGF1CR);
+	} else {
+		val = readl(SNVS_LPTGF2CR);
+		val |= 1 << ((rx - 5) * 8 - 1);
+		writel(val, SNVS_LPTGF2CR);
+	}
+
+	/* Route active tamper tx to external tamper rx */
+	if (rx < 8) {
+		val = readl(SNVS_LPATRC1R);
+		val &= ~(0xf << (rx * 4));
+		val |= ((tx - 4) << (rx * 4));
+		writel(val, SNVS_LPATRC1R);
+	} else {
+		val = readl(SNVS_LPATRC2R);
+		val &= ~(0xf << ((rx - 8) * 4));
+		val |= ((tx - 4) << ((rx - 8) * 4));
+		writel(val, SNVS_LPATRC2R);
+	}
+
+	/* Enable external tamper rx */
+	if (rx < 2) {
+		val = readl(SNVS_LPTDCR);
+		if (rx == 0)
+			val |= 0x200;
+		else if (rx == 1)
+			val |= 0x400;
+		writel(val, SNVS_LPTDCR);
+	} else {
+		val = readl(SNVS_LPTDC2R);
+		val |= 1 << (rx - 2);
+		writel(val, SNVS_LPTDC2R);
+	}
+}
+
+void enable_passive_tamper(unsigned int rx, unsigned int high)
+{
+	int val;
+
+	printf("start passive tamper test on pin %d\n", rx);
+
+	/****************************
+	 *   Configuring CAAM and SNVS  *
+	 ****************************/
+
+	/* Initialize power glitch detector register */
+	val = 0x41736166;
+	writel(val, SNVS_LPPGDR);
+
+	/* W1C PGD */
+	val = readl(SNVS_LPSR) & 0x00000008;
+	writel(val, SNVS_LPSR);
+
+	/* Programming ZMK via SW */
+	writel(0x11111111, SNVS_LPZMKR0);
+	writel(0x22222222, SNVS_LPZMKR1);
+	writel(0x33333333, SNVS_LPZMKR2);
+	writel(0x44444444, SNVS_LPZMKR3);
+	writel(0x55555555, SNVS_LPZMKR4);
+	writel(0x66666666, SNVS_LPZMKR5);
+	writel(0x77777777, SNVS_LPZMKR6);
+	writel(0x88888888, SNVS_LPZMKR7);
+
+	val = readl(SNVS_LPMKCR) | 0xa;
+	writel(val, SNVS_LPMKCR);
+	val = readl(SNVS_HPCOMR) | 0x1000;
+	writel(val, SNVS_HPCOMR);
+
+	val = readl(SNVS_LPMKCR) | 0x10;
+	writel(val, SNVS_LPMKCR);
+
+	/* LP Security Violation is a non-fatal Violation */
+	val = 0x40000000;
+	writel(val, SNVS_HPSVCR);
+
+	/* Enable SRTC invalidation in case of security violation */
+	val = readl(SNVS_LPCR);
+	val |= 0x11;
+	writel(val, SNVS_LPCR);
+
+	/*********************************
+	 *   Configuring passive tamper rx          *
+	 *********************************/
+
+	/* Enable glitch filter for external tamper rx */
+	if (rx < 2) {
+		val = readl(SNVS_LPTGFCR);
+		if (rx == 0)
+			val |= 0x800000;
+		else if (rx == 1)
+			val |= 0x80000000;
+		writel(val, SNVS_LPTGFCR);
+	} else if (rx < 6) {
+		val = readl(SNVS_LPTGF1CR);
+		val |= 1 << ((rx - 1) * 8 - 1);
+		writel(val, SNVS_LPTGF1CR);
+	} else {
+		val = readl(SNVS_LPTGF2CR);
+		val |= 1 << ((rx - 5) * 8 - 1);
+		writel(val, SNVS_LPTGF2CR);
+	}
+
+	if (high == 1) {
+		/* Set external tampering rx polarity to high and enable tamper */
+		if (rx < 2) {
+			val = readl(SNVS_LPTDCR);
+			if (rx == 0)
+				val |= 0x800;
+			else if (rx == 1)
+				val |= 0x1000;
+			writel(val, SNVS_LPTDCR);
+		} else {
+			val = readl(SNVS_LPTDC2R);
+			val |= 1 << (rx - 2 + 16);
+			writel(val, SNVS_LPTDC2R);
+		}
+	}
+	/* Enable external tamper rx */
+	if (rx < 2) {
+		val = readl(SNVS_LPTDCR);
+		if (rx == 0)
+			val |= 0x200;
+		else if (rx == 1)
+			val |= 0x400;
+		writel(val, SNVS_LPTDCR);
+	} else {
+		val = readl(SNVS_LPTDC2R);
+		val |= 1 << (rx - 2);
+		writel(val, SNVS_LPTDC2R);
+	}
+}
+
+void stop_tamper(int rx)
+{
+	int val;
+
+	/* stop tamper */
+	if (rx < 2) {
+		val = readl(SNVS_LPTDCR);
+		if (rx == 0)
+			val &= ~0x200;
+		else if (rx == 1)
+			val &= ~0x400;
+		writel(val, SNVS_LPTDCR);
+	} else {
+		val = readl(SNVS_LPTDC2R);
+		val &= ~(1 << (rx - 2));
+		writel(val, SNVS_LPTDC2R);
+	}
+
+	/* clear tamper status */
+	if (rx < 2) {
+		val = readl(SNVS_LPSR);
+		val |= 1 << (rx + 9);
+		writel(val, SNVS_LPSR);
+	} else if (rx < 10) {
+		val = readl(SNVS_LPTDSR);
+		val |= 1 << (rx - 2);
+		writel(val, SNVS_LPTDSR);
+	}
+}
+
+static void get_tamper_status(void)
+{
+	unsigned int lpsr, lptdsr, hpsr, ssm;
+
+	lpsr = readl(SNVS_LPSR);
+	lptdsr = readl(SNVS_LPTDSR);
+	hpsr = readl(SNVS_HPSR);
+	ssm = (hpsr & 0xf00) >> 8;
+
+	if (lpsr & (1 << 9))
+		printf("External Tampering 0 Detected\n");
+	if (lpsr & (1 << 10))
+		printf("External Tampering 1 Detected\n");
+	if (lptdsr & (1 << 0))
+		printf("External Tampering 2 Detected\n");
+	if (lptdsr & (1 << 1))
+		printf("External Tampering 3 Detected\n");
+	if (lptdsr & (1 << 2))
+		printf("External Tampering 4 Detected\n");
+	if (lptdsr & (1 << 3))
+		printf("External Tampering 5 Detected\n");
+	if (lptdsr & (1 << 4))
+		printf("External Tampering 6 Detected\n");
+	if (lptdsr & (1 << 5))
+		printf("External Tampering 7 Detected\n");
+	if (lptdsr & (1 << 6))
+		printf("External Tampering 8 Detected\n");
+	if (lptdsr & (1 << 7))
+		printf("External Tampering 9 Detected\n");
+	if (!(lpsr & (3 << 9)) && !(lptdsr & 0xff))
+		printf("No External Tampering Detected\n");
+
+	if (hpsr & 0x80000000)
+		printf("Zeroizable Master Key is clear\n");
+	else
+		printf("Zeroizable Master Key is not zero\n");
+
+	if (ssm == 0)
+		printf("System Security Monitor State: Init\n");
+	else if (ssm == 0x8)
+		printf("System Security Monitor State: Init Intermediate\n");
+	else if (ssm == 0x9)
+		printf("System Security Monitor State: Check\n");
+	else if (ssm == 0xb)
+		printf("System Security Monitor State: Non-Secure\n");
+	else if (ssm == 0xd)
+		printf("System Security Monitor State: Trusted\n");
+	else if (ssm == 0xf)
+		printf("System Security Monitor State: Secure\n");
+	else if (ssm == 0x3)
+		printf("System Security Monitor State: Soft Fail\n");
+	else if (ssm == 0x1)
+		printf("System Security Monitor State: Hard Fail\n");
+	else
+		printf("System Security Monitor State: 0x%x\n", ssm);
+}
+
+static void clear_tamper_warning(void)
+{
+	unsigned int lpsr, lptdsr;
+
+	lpsr = readl(SNVS_LPSR);
+	lptdsr = readl(SNVS_LPTDSR);
+
+	writel(lpsr, SNVS_LPSR);
+	writel(lptdsr, SNVS_LPTDSR);
+}
+
+static int do_tamper(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	const char *op = argc >= 2 ? argv[1] : NULL;
+	unsigned int tx, rx, high;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	if (!strcmp(op, "active")) {
+		if (argc < 4)
+			return CMD_RET_USAGE;
+
+		tx = simple_strtoul(argv[2], NULL, 16);
+		rx = simple_strtoul(argv[3], NULL, 16);
+		if ((tx > 9) || (tx < 5))
+			return CMD_RET_USAGE;
+		if ((rx > 9) || (rx == tx))
+			return CMD_RET_USAGE;
+
+		enable_active_tamper(tx, rx);
+
+	} else if (!strcmp(op, "passive")) {
+		if (argc < 4)
+			return CMD_RET_USAGE;
+
+		rx = simple_strtoul(argv[2], NULL, 16);
+		if (rx > 9)
+			return CMD_RET_USAGE;
+
+		high = simple_strtoul(argv[3], NULL, 16);
+		if (high != 0)
+			high = 1;
+		enable_passive_tamper(rx, high);
+
+	} else if (!strcmp(op, "status")) {
+		get_tamper_status();
+	} else if (!strcmp(op, "clear")) {
+		clear_tamper_warning();
+	} else if (!strcmp(op, "stop")) {
+		if (argc < 3)
+			return CMD_RET_USAGE;
+
+		rx = simple_strtoul(argv[2], NULL, 16);
+		if (rx > 9)
+			return CMD_RET_USAGE;
+		stop_tamper(rx);
+	} else {
+		return CMD_RET_USAGE;
+	}
+
+	return 0;
+}
+
+U_BOOT_CMD(
+		imx_tamper, CONFIG_SYS_MAXARGS, 0, do_tamper,
+		"imx tamper command for setting for test",
+		"active <tx rx>  - tx is active tamper pin from 9 ~ 5, \n"
+		"    rx pin is from 9 ~ 0 and should not equal to tx pin\n"
+		"passive <rx> <high> - rx is passive tamper pin from 9 ~ 0, \n"
+		"    high: 1 - high assert, 0 - low assert\n"
+		"status - Get tamper status\n"
+		"clear - clear tamper warning\n"
+		"stop rx - rx is tamper pin to stop\n"
+	  );