NXP: Driver for NXP Security Monitor

NXP Security Monitor IP provides hardware anchored
- current security state of the SoC.
- Tamper detect etc.

Signed-off-by: Ruchika Gupta <ruchika.gupta@nxp.com>
Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
Change-Id: I8ff809fe2f3fd013844ab3d4a8733f53c2b06c81
diff --git a/drivers/nxp/sec_mon/sec_mon.mk b/drivers/nxp/sec_mon/sec_mon.mk
new file mode 100644
index 0000000..51e3e86
--- /dev/null
+++ b/drivers/nxp/sec_mon/sec_mon.mk
@@ -0,0 +1,27 @@
+#
+# Copyright 2021 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ADD_SNVS},)
+
+ADD_SNVS		:= 1
+
+SNVS_DRIVERS_PATH	:= ${PLAT_DRIVERS_PATH}/sec_mon
+
+PLAT_INCLUDES		+= -I$(SNVS_DRIVERS_PATH)
+
+SNVS_SOURCES		+= $(SNVS_DRIVERS_PATH)/snvs.c
+
+ifeq (${BL_COMM_SNVS_NEEDED},yes)
+BL_COMMON_SOURCES	+= ${SNVS_SOURCES}
+else
+ifeq (${BL2_SNVS_NEEDED},yes)
+BL2_SOURCES		+= ${SNVS_SOURCES}
+endif
+ifeq (${BL31_SNVS_NEEDED},yes)
+BL31_SOURCES		+= ${SNVS_SOURCES}
+endif
+endif
+endif
diff --git a/drivers/nxp/sec_mon/snvs.c b/drivers/nxp/sec_mon/snvs.c
new file mode 100644
index 0000000..6208b67
--- /dev/null
+++ b/drivers/nxp/sec_mon/snvs.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <snvs.h>
+
+static uintptr_t g_nxp_snvs_addr;
+
+void snvs_init(uintptr_t nxp_snvs_addr)
+{
+	g_nxp_snvs_addr = nxp_snvs_addr;
+}
+
+uint32_t get_snvs_state(void)
+{
+	struct snvs_regs *snvs = (struct snvs_regs *) (g_nxp_snvs_addr);
+
+	return (snvs_read32(&snvs->hp_stat) & HPSTS_MASK_SSM_ST);
+}
+
+static uint32_t do_snvs_state_transition(uint32_t state_transtion_bit,
+					 uint32_t target_state)
+{
+	struct snvs_regs *snvs = (struct snvs_regs *) (g_nxp_snvs_addr);
+	uint32_t sts = get_snvs_state();
+	uint32_t fetch_cnt = 16U;
+	uint32_t val = snvs_read32(&snvs->hp_com) | state_transtion_bit;
+
+	snvs_write32(&snvs->hp_com, val);
+
+	/* polling loop till SNVS is in target state */
+	do {
+		sts = get_snvs_state();
+	} while ((sts != target_state) && ((--fetch_cnt) != 0));
+
+	return sts;
+}
+void transition_snvs_non_secure(void)
+{
+	struct snvs_regs *snvs = (struct snvs_regs *) (g_nxp_snvs_addr);
+	uint32_t sts = get_snvs_state();
+
+	switch (sts) {
+		/* If initial state is check or Non-Secure, then
+		 * set the Software Security Violation Bit and
+		 * transition to Non-Secure State.
+		 */
+	case HPSTS_CHECK_SSM_ST:
+		sts = do_snvs_state_transition(HPCOM_SW_SV, HPSTS_NON_SECURE_SSM_ST);
+		break;
+
+		/* If initial state is Trusted, Secure or Soft-Fail, then
+		 * first set the Software Security Violation Bit and
+		 * transition to Soft-Fail State.
+		 */
+	case HPSTS_TRUST_SSM_ST:
+	case HPSTS_SECURE_SSM_ST:
+	case HPSTS_SOFT_FAIL_SSM_ST:
+		sts = do_snvs_state_transition(HPCOM_SW_SV, HPSTS_NON_SECURE_SSM_ST);
+
+		/* If SSM Soft Fail to Non-Secure State Transition
+		 * Disable is not set, then set SSM_ST bit and
+		 * transition to Non-Secure State.
+		 */
+		if ((snvs_read32(&snvs->hp_com) & HPCOM_SSM_SFNS_DIS) == 0) {
+			sts = do_snvs_state_transition(HPCOM_SSM_ST, HPSTS_NON_SECURE_SSM_ST);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void transition_snvs_soft_fail(void)
+{
+	do_snvs_state_transition(HPCOM_SW_FSV, HPSTS_SOFT_FAIL_SSM_ST);
+}
+
+uint32_t transition_snvs_trusted(void)
+{
+	struct snvs_regs *snvs = (struct snvs_regs *) (g_nxp_snvs_addr);
+	uint32_t sts = get_snvs_state();
+
+	switch (sts) {
+		/* If initial state is check, set the SSM_ST bit to
+		 * change the state to trusted.
+		 */
+	case HPSTS_CHECK_SSM_ST:
+		sts = do_snvs_state_transition(HPCOM_SSM_ST, HPSTS_TRUST_SSM_ST);
+		break;
+		/* If SSM Secure to Trusted State Transition Disable
+		 * is not set, then set SSM_ST bit and
+		 * transition to Trusted State.
+		 */
+	case HPSTS_SECURE_SSM_ST:
+		if ((snvs_read32(&snvs->hp_com) & HPCOM_SSM_ST_DIS) == 0) {
+			sts = do_snvs_state_transition(HPCOM_SSM_ST, HPSTS_TRUST_SSM_ST);
+		}
+		break;
+		/* If initial state is Soft-Fail or Non-Secure, then
+		 * transition to Trusted is not Possible.
+		 */
+	default:
+		break;
+	}
+
+	return sts;
+}
+
+uint32_t transition_snvs_secure(void)
+{
+	uint32_t sts = get_snvs_state();
+
+	if (sts == HPSTS_SECURE_SSM_ST) {
+		return sts;
+	}
+
+	if (sts != HPSTS_TRUST_SSM_ST) {
+		sts = transition_snvs_trusted();
+		if (sts != HPSTS_TRUST_SSM_ST) {
+			return sts;
+		}
+	}
+
+	sts = do_snvs_state_transition(HPCOM_SSM_ST, HPSTS_TRUST_SSM_ST);
+
+	return sts;
+}
+
+void snvs_write_lp_gpr_bit(uint32_t offset, uint32_t bit_pos, bool flag_val)
+{
+	if (flag_val) {
+		snvs_write32(g_nxp_snvs_addr + offset,
+			     (snvs_read32(g_nxp_snvs_addr + offset))
+			     | (1 << bit_pos));
+	} else {
+		snvs_write32(g_nxp_snvs_addr + offset,
+			     (snvs_read32(g_nxp_snvs_addr + offset))
+			     & ~(1 << bit_pos));
+	}
+}
+
+uint32_t snvs_read_lp_gpr_bit(uint32_t offset, uint32_t bit_pos)
+{
+	return (snvs_read32(g_nxp_snvs_addr + offset) & (1 << bit_pos));
+}
+
+void snvs_disable_zeroize_lp_gpr(void)
+{
+	snvs_write_lp_gpr_bit(NXP_LPCR_OFFSET,
+			  NXP_GPR_Z_DIS_BIT,
+			  true);
+}
+
+#if defined(NXP_NV_SW_MAINT_LAST_EXEC_DATA) && defined(NXP_COINED_BB)
+void snvs_write_app_data_bit(uint32_t bit_pos)
+{
+	snvs_write_lp_gpr_bit(NXP_APP_DATA_LP_GPR_OFFSET,
+			      bit_pos,
+			      true);
+}
+
+uint32_t snvs_read_app_data(void)
+{
+	return snvs_read32(g_nxp_snvs_addr + NXP_APP_DATA_LP_GPR_OFFSET);
+}
+
+uint32_t snvs_read_app_data_bit(uint32_t bit_pos)
+{
+	uint8_t ret = snvs_read_lp_gpr_bit(NXP_APP_DATA_LP_GPR_OFFSET, bit_pos);
+
+	return ((ret != 0U) ? 1U : 0U);
+}
+
+void snvs_clear_app_data(void)
+{
+	snvs_write32(g_nxp_snvs_addr + NXP_APP_DATA_LP_GPR_OFFSET, 0x0);
+}
+#endif
diff --git a/drivers/nxp/sec_mon/snvs.h b/drivers/nxp/sec_mon/snvs.h
new file mode 100644
index 0000000..4455383
--- /dev/null
+++ b/drivers/nxp/sec_mon/snvs.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SNVS_H
+#define SNVS_H
+
+
+#ifndef __ASSEMBLER__
+
+#include <endian.h>
+#include <stdbool.h>
+
+#include <lib/mmio.h>
+
+struct snvs_regs {
+	uint32_t reserved1;
+	uint32_t hp_com;		/* 0x04 SNVS_HP Command Register */
+	uint32_t reserved2[3];
+	uint32_t hp_stat;		/* 0x14 SNVS_HP Status Register */
+};
+
+#ifdef NXP_SNVS_BE
+#define snvs_read32(a)           bswap32(mmio_read_32((uintptr_t)(a)))
+#define snvs_write32(a, v)       mmio_write_32((uintptr_t)(a), bswap32((v)))
+#elif defined(NXP_SNVS_LE)
+#define snvs_read32(a)           mmio_read_32((uintptr_t)(a))
+#define snvs_write32(a, v)       mmio_write_32((uintptr_t)(a), (v))
+#else
+#error Please define CCSR SNVS register endianness
+#endif
+
+void snvs_init(uintptr_t nxp_snvs_addr);
+uint32_t get_snvs_state(void);
+void transition_snvs_non_secure(void);
+void transition_snvs_soft_fail(void);
+uint32_t transition_snvs_trusted(void);
+uint32_t transition_snvs_secure(void);
+
+uint32_t snvs_read_lp_gpr_bit(uint32_t offset, uint32_t bit_pos);
+void snvs_write_lp_gpr_bit(uint32_t offset, uint32_t bit_pos, bool flag_val);
+
+void snvs_disable_zeroize_lp_gpr(void);
+
+#if defined(NXP_NV_SW_MAINT_LAST_EXEC_DATA) && defined(NXP_COINED_BB)
+uint32_t snvs_read_app_data(void);
+uint32_t snvs_read_app_data_bit(uint32_t bit_pos);
+void snvs_clear_app_data(void);
+void snvs_write_app_data_bit(uint32_t bit_pos);
+#endif
+
+#endif	/*  __ASSEMBLER__  */
+
+/* SSM_ST field in SNVS status reg */
+#define HPSTS_CHECK_SSM_ST	0x900	/* SNVS is in check state */
+#define HPSTS_NON_SECURE_SSM_ST	0xb00	/* SNVS is in non secure state */
+#define HPSTS_TRUST_SSM_ST	0xd00	/* SNVS is in trusted state */
+#define HPSTS_SECURE_SSM_ST	0xf00	/* SNVS is in secure state */
+#define HPSTS_SOFT_FAIL_SSM_ST	0x300	/* SNVS is in soft fail state */
+#define HPSTS_MASK_SSM_ST	0xf00	/* SSM_ST field mask in SNVS reg */
+
+/* SNVS register bits */
+#define HPCOM_SW_SV		0x100	/* Security Violation bit */
+#define HPCOM_SW_FSV		0x200	/* Fatal Security Violation bit */
+#define HPCOM_SSM_ST		0x1	/* SSM_ST field in SNVS command reg */
+#define HPCOM_SSM_ST_DIS	0x2	/* Disable Secure to Trusted State */
+#define HPCOM_SSM_SFNS_DIS	0x4	/* Disable Soft Fail to Non-Secure */
+
+#define NXP_LP_GPR0_OFFSET	0x90
+#define NXP_LPCR_OFFSET		0x38
+#define NXP_GPR_Z_DIS_BIT	24
+
+#ifdef NXP_COINED_BB
+
+#ifndef NXP_APP_DATA_LP_GPR_OFFSET
+#define NXP_APP_DATA_LP_GPR_OFFSET NXP_LP_GPR0_OFFSET
+#endif
+
+#define NXP_LPGPR_ZEROTH_BIT		0
+
+#endif	/* NXP_COINED_BB */
+
+#endif	/* SNVS_H  */