From 2ee8abb05ec8ad6e44ec69ba4e428b5f5d823f95 Mon Sep 17 00:00:00 2001
From: Yann Gautier <yann.gautier@st.com>
Date: Tue, 15 Sep 2020 14:35:05 +0200
Subject: [PATCH] stm32mp1: apply ETZPC configuration from DT

The security configuration of peripherals is retrieved from device tree
file.

Change-Id: Iccd846462913cae8784dd6d7d613eb22834936a3
Signed-off-by: Yann Gautier <yann.gautier@st.com>
---
 drivers/st/etzpc/etzpc.c                      |  50 ++++-
 plat/st/stm32mp1/include/stm32mp1_private.h   |   4 +
 .../include/stm32mp1_shared_resources.h       |  17 ++
 plat/st/stm32mp1/stm32mp1_private.c           |  22 ++
 plat/st/stm32mp1/stm32mp1_shared_resources.c  | 206 +++++++++++++++---
 5 files changed, 273 insertions(+), 26 deletions(-)

diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c
index ff52a22d9..eb1c79cf7 100644
--- a/drivers/st/etzpc/etzpc.c
+++ b/drivers/st/etzpc/etzpc.c
@@ -66,6 +66,10 @@ struct etzpc_instance {
 /* Only 1 instance of the ETZPC is expected per platform */
 static struct etzpc_instance etzpc_dev;
 
+struct dt_id_attr {
+	fdt32_t id_attr[STM32MP1_ETZPC_MAX_ID];
+};
+
 /*
  * Implementation uses uint8_t to store each securable DECPROT configuration.
  * When resuming from deep suspend, the DECPROT configurations are restored.
@@ -85,6 +89,50 @@ static bool valid_tzma_id(unsigned int id)
 }
 #endif
 
+static int etzpc_dt_conf_decprot(int node)
+{
+	const struct dt_id_attr *conf_list;
+	void *fdt;
+	unsigned int i;
+	int len = 0;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	conf_list = (const struct dt_id_attr *)fdt_getprop(fdt, node,
+							   "st,decprot", &len);
+	if (conf_list == NULL) {
+		INFO("No ETZPC configuration in DT, use default\n");
+		return 0;
+	}
+
+	for (i = 0U; i < (unsigned int)len / sizeof(uint32_t); i++) {
+		enum etzpc_decprot_attributes attr;
+		uint32_t value;
+		uint32_t id;
+		uint32_t mode;
+
+		value = fdt32_to_cpu(conf_list->id_attr[i]);
+
+		id = ((value >> ETZPC_ID_SHIFT) & ETZPC_ID_MASK);
+		assert(valid_decprot_id(id));
+
+		mode = (value >> ETZPC_MODE_SHIFT) & ETZPC_MODE_MASK;
+		attr = stm32mp_etzpc_binding2decprot(mode);
+
+		stm32mp1_register_etzpc_decprot(id, attr);
+
+		etzpc_configure_decprot(id, attr);
+
+		if ((value & ETZPC_LOCK_MASK) != 0U) {
+			etzpc_lock_decprot(id);
+		}
+	}
+
+	return 0;
+}
+
 /*
  * etzpc_configure_decprot : Load a DECPROT configuration
  * decprot_id : ID of the IP
@@ -254,5 +302,5 @@ int etzpc_init(void)
 
 	VERBOSE("ETZPC version 0x%x", etzpc_dev.revision);
 
-	return 0;
+	return etzpc_dt_conf_decprot(node);
 }
diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h
index 91ecc21d5..ebbb71824 100644
--- a/plat/st/stm32mp1/include/stm32mp1_private.h
+++ b/plat/st/stm32mp1/include/stm32mp1_private.h
@@ -9,6 +9,8 @@
 
 #include <stdint.h>
 
+#include <drivers/st/etzpc.h>
+
 enum boot_device_e {
 	BOOT_DEVICE_USB,
 	BOOT_DEVICE_BOARD
@@ -27,6 +29,8 @@ enum boot_device_e get_boot_device(void);
 void stm32mp1_gic_pcpu_init(void);
 void stm32mp1_gic_init(void);
 
+enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode);
+
 void stm32mp1_syscfg_init(void);
 void stm32mp1_syscfg_enable_io_compensation(void);
 void stm32mp1_syscfg_disable_io_compensation(void);
diff --git a/plat/st/stm32mp1/include/stm32mp1_shared_resources.h b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h
index 3f6367ebe..519a67bad 100644
--- a/plat/st/stm32mp1/include/stm32mp1_shared_resources.h
+++ b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h
@@ -7,6 +7,8 @@
 #ifndef STM32MP1_SHARED_RESOURCES_H
 #define STM32MP1_SHARED_RESOURCES_H
 
+#include <drivers/st/etzpc.h>
+
 #include <stm32mp_shared_resources.h>
 
 #define STM32MP1_SHRES_GPIOZ(i)		(STM32MP1_SHRES_GPIOZ_0 + (i))
@@ -35,4 +37,19 @@ enum stm32mp_shres {
 
 	STM32MP1_SHRES_COUNT
 };
+
+#ifdef STM32MP_SHARED_RESOURCES
+/*
+ * Register a (non-)secure peripheral based on the ETZPC DECPROT configuration
+ */
+void stm32mp1_register_etzpc_decprot(unsigned int id,
+				     enum etzpc_decprot_attributes attr);
+#else
+static inline
+void stm32mp1_register_etzpc_decprot(unsigned int id,
+				     enum etzpc_decprot_attributes attr)
+{
+}
+#endif
+
 #endif /* STM32MP1_SHARED_RESOURCES_H */
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
index 57c936855..788931701 100644
--- a/plat/st/stm32mp1/stm32mp1_private.c
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -508,6 +508,28 @@ uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags)
 }
 #endif
 
+/*
+ * This function allows to split bindings between platform and ETZPC
+ * HW mapping. If this conversion was done at driver level, the driver
+ * should include all supported platform bindings. ETZPC may be used on
+ * other platforms.
+ */
+enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode)
+{
+	switch (mode) {
+	case DECPROT_S_RW:
+		return ETZPC_DECPROT_S_RW;
+	case DECPROT_NS_R_S_W:
+		return ETZPC_DECPROT_NS_R_S_W;
+	case DECPROT_MCU_ISOLATION:
+		return ETZPC_DECPROT_MCU_ISOLATION;
+	case DECPROT_NS_RW:
+		return ETZPC_DECPROT_NS_RW;
+	default:
+		panic();
+	}
+}
+
 int plat_bind_regulator(struct stm32mp_regulator *regu)
 {
 	if ((dt_pmic_status() > 0) && is_pmic_regulator(regu)) {
diff --git a/plat/st/stm32mp1/stm32mp1_shared_resources.c b/plat/st/stm32mp1/stm32mp1_shared_resources.c
index 208e34a8b..14e4fcc03 100644
--- a/plat/st/stm32mp1/stm32mp1_shared_resources.c
+++ b/plat/st/stm32mp1/stm32mp1_shared_resources.c
@@ -87,6 +87,64 @@ static const char __unused *shres2str_state(unsigned int state)
 	return shres2str_state_tbl[state];
 }
 
+struct shres2decprot {
+	unsigned int shres_id;
+	unsigned int decprot_id;
+	const char *decprot_str;
+};
+
+#define SHRES2DECPROT(shres, decprot, str) {	\
+		.shres_id = shres,		\
+		.decprot_id = decprot,		\
+		.decprot_str = str,		\
+	}
+
+#define SHRES_INVALID		~0U
+
+static const struct shres2decprot shres2decprot_tbl[] = {
+	SHRES2DECPROT(STM32MP1_SHRES_IWDG1, STM32MP1_ETZPC_IWDG1_ID, "IWDG1"),
+	SHRES2DECPROT(STM32MP1_SHRES_USART1, STM32MP1_ETZPC_USART1_ID, "UART1"),
+	SHRES2DECPROT(STM32MP1_SHRES_SPI6, STM32MP1_ETZPC_SPI6_ID, "SPI6"),
+	SHRES2DECPROT(STM32MP1_SHRES_I2C4, STM32MP1_ETZPC_I2C4_ID, "I2C4"),
+	SHRES2DECPROT(STM32MP1_SHRES_RNG1, STM32MP1_ETZPC_RNG1_ID, "RNG1"),
+	SHRES2DECPROT(STM32MP1_SHRES_HASH1, STM32MP1_ETZPC_HASH1_ID, "HASH1"),
+	SHRES2DECPROT(STM32MP1_SHRES_CRYP1, STM32MP1_ETZPC_CRYP1_ID, "CRYP1"),
+	SHRES2DECPROT(STM32MP1_SHRES_I2C6, STM32MP1_ETZPC_I2C6_ID, "I2C6"),
+	/* Below are specific IDs without a 1-to-1 mapping to SHRES IDs */
+	SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_STGENC_ID, "STGEN"),
+	SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_BKPSRAM_ID, "BKPSRAM"),
+	SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRCTRL_ID, "DDRCTRL"),
+	SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRPHYC_ID, "DDRPHY"),
+};
+
+static unsigned int decprot2shres(unsigned int decprot_id)
+{
+	uint32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) {
+		if (shres2decprot_tbl[i].decprot_id == decprot_id) {
+			return shres2decprot_tbl[i].shres_id;
+		}
+	}
+
+	VERBOSE("No shared resource %u", decprot_id);
+	return SHRES_INVALID;
+}
+
+static const char *decprot2str(unsigned int decprot_id)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) {
+		if (shres2decprot_tbl[i].decprot_id == decprot_id) {
+			return shres2decprot_tbl[i].decprot_str;
+		}
+	}
+
+	ERROR("Invalid ID %u", decprot_id);
+	panic();
+}
+
 /* Get resource state: these accesses lock the registering support */
 static void lock_registering(void)
 {
@@ -334,6 +392,53 @@ void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin)
 	}
 }
 
+void stm32mp1_register_etzpc_decprot(unsigned int id,
+				     enum etzpc_decprot_attributes attr)
+{
+	unsigned int state = SHRES_SECURE;
+	unsigned int id_shres;
+
+	switch (attr) {
+	case ETZPC_DECPROT_S_RW:
+		break;
+	case ETZPC_DECPROT_NS_R_S_W:
+	case ETZPC_DECPROT_MCU_ISOLATION:
+	case ETZPC_DECPROT_NS_RW:
+		state = SHRES_NON_SECURE;
+		break;
+	default:
+		panic();
+	}
+
+	switch (id) {
+	case STM32MP1_ETZPC_STGENC_ID:
+	case STM32MP1_ETZPC_BKPSRAM_ID:
+		/* We assume these must always be assigned to secure world */
+		if (state != SHRES_SECURE) {
+			panic();
+		}
+		break;
+	case STM32MP1_ETZPC_DDRCTRL_ID:
+	case STM32MP1_ETZPC_DDRPHYC_ID:
+		/* allow write only for secure world */
+		if ((attr != ETZPC_DECPROT_S_RW) &&
+		    (attr != ETZPC_DECPROT_NS_R_S_W)) {
+			panic();
+		}
+		break;
+	default:
+		id_shres = decprot2shres(id);
+		if (id_shres == SHRES_INVALID) {
+			if (state == SHRES_SECURE) {
+				panic();
+			}
+		} else {
+			register_periph(id_shres, state);
+		}
+		break;
+	}
+}
+
 static bool stm32mp_gpio_bank_is_non_secure(unsigned int bank)
 {
 	unsigned int non_secure = 0U;
@@ -379,12 +484,15 @@ bool stm32mp_nsec_can_access_clock(unsigned long clock_id)
 	enum stm32mp_shres shres_id = STM32MP1_SHRES_COUNT;
 
 	switch (clock_id) {
+	case BSEC:
+	case CK_AXI:
 	case CK_CSI:
 	case CK_HSE:
 	case CK_HSE_DIV2:
 	case CK_HSI:
 	case CK_LSE:
 	case CK_LSI:
+	case CK_MPU:
 	case PLL1_P:
 	case PLL1_Q:
 	case PLL1_R:
@@ -499,33 +607,81 @@ static enum etzpc_decprot_attributes shres2decprot_attr(enum stm32mp_shres id)
 	return ETZPC_DECPROT_S_RW;
 }
 
-static void set_etzpc_secure_configuration(void)
+static bool check_decprot(unsigned int id, enum etzpc_decprot_attributes exp)
 {
-	/* Some system peripherals shall be secure */
-	etzpc_configure_decprot(STM32MP1_ETZPC_STGENC_ID, ETZPC_DECPROT_S_RW);
-	etzpc_configure_decprot(STM32MP1_ETZPC_BKPSRAM_ID, ETZPC_DECPROT_S_RW);
-	etzpc_configure_decprot(STM32MP1_ETZPC_DDRCTRL_ID,
-				ETZPC_DECPROT_NS_R_S_W);
-	etzpc_configure_decprot(STM32MP1_ETZPC_DDRPHYC_ID,
-				ETZPC_DECPROT_NS_R_S_W);
-
-	/* Configure ETZPC with peripheral registering */
-	etzpc_configure_decprot(STM32MP1_ETZPC_CRYP1_ID,
-				shres2decprot_attr(STM32MP1_SHRES_CRYP1));
-	etzpc_configure_decprot(STM32MP1_ETZPC_HASH1_ID,
-				shres2decprot_attr(STM32MP1_SHRES_HASH1));
-	etzpc_configure_decprot(STM32MP1_ETZPC_I2C4_ID,
-				shres2decprot_attr(STM32MP1_SHRES_I2C4));
-	etzpc_configure_decprot(STM32MP1_ETZPC_I2C6_ID,
-				shres2decprot_attr(STM32MP1_SHRES_I2C6));
-	etzpc_configure_decprot(STM32MP1_ETZPC_IWDG1_ID,
-				shres2decprot_attr(STM32MP1_SHRES_IWDG1));
-	etzpc_configure_decprot(STM32MP1_ETZPC_RNG1_ID,
-				shres2decprot_attr(STM32MP1_SHRES_RNG1));
-	etzpc_configure_decprot(STM32MP1_ETZPC_USART1_ID,
+	enum etzpc_decprot_attributes cur = etzpc_get_decprot(id);
+
+	if (cur == exp) {
+		return true;
+	}
+
+	switch (exp) {
+	case ETZPC_DECPROT_NS_RW:
+		if (cur == ETZPC_DECPROT_S_RW) {
+			INFO("ETZPC: %s (%d) could be non secure\n",
+			     decprot2str(id), id);
+		}
+		return true;
+
+	case ETZPC_DECPROT_S_RW:
+		ERROR("ETZPC: %s (%d) expected secure but DECPROT = %d\n",
+		      decprot2str(id), id, cur);
+		break;
+
+	case ETZPC_DECPROT_NS_R_S_W:
+	case ETZPC_DECPROT_MCU_ISOLATION:
+		break;
+	default:
+		panic();
+	}
+
+	return false;
+}
+
+static void check_etzpc_secure_configuration(void)
+{
+	bool error = false;
+
+	assert(registering_locked);
+
+	error |= !check_decprot(STM32MP1_ETZPC_STGENC_ID, ETZPC_DECPROT_S_RW);
+
+	error |= !check_decprot(STM32MP1_ETZPC_BKPSRAM_ID, ETZPC_DECPROT_S_RW);
+
+	error |= !check_decprot(STM32MP1_ETZPC_USART1_ID,
 				shres2decprot_attr(STM32MP1_SHRES_USART1));
-	etzpc_configure_decprot(STM32MP1_ETZPC_SPI6_ID,
+
+	error |= !check_decprot(STM32MP1_ETZPC_I2C4_ID,
+				shres2decprot_attr(STM32MP1_SHRES_I2C4));
+
+	error |= !check_decprot(STM32MP1_ETZPC_SPI6_ID,
 				shres2decprot_attr(STM32MP1_SHRES_SPI6));
+
+	error |= !check_decprot(STM32MP1_ETZPC_RNG1_ID,
+				shres2decprot_attr(STM32MP1_SHRES_RNG1));
+
+	error |= !check_decprot(STM32MP1_ETZPC_HASH1_ID,
+				shres2decprot_attr(STM32MP1_SHRES_HASH1));
+
+	error |= !check_decprot(STM32MP1_ETZPC_CRYP1_ID,
+				shres2decprot_attr(STM32MP1_SHRES_CRYP1));
+
+	error |= !((check_decprot(STM32MP1_ETZPC_DDRCTRL_ID,
+				  ETZPC_DECPROT_NS_R_S_W)) ||
+		   (check_decprot(STM32MP1_ETZPC_DDRCTRL_ID,
+				  ETZPC_DECPROT_S_RW)));
+
+	error |= !((check_decprot(STM32MP1_ETZPC_DDRPHYC_ID,
+				  ETZPC_DECPROT_NS_R_S_W)) ||
+		   (check_decprot(STM32MP1_ETZPC_DDRPHYC_ID,
+				  ETZPC_DECPROT_S_RW)));
+
+	error |= !check_decprot(STM32MP1_ETZPC_I2C6_ID,
+				shres2decprot_attr(STM32MP1_SHRES_I2C6));
+
+	if (error) {
+		panic();
+	}
 }
 
 static void check_rcc_secure_configuration(void)
@@ -592,6 +748,6 @@ void stm32mp_lock_periph_registering(void)
 	print_shared_resources_state();
 
 	check_rcc_secure_configuration();
-	set_etzpc_secure_configuration();
+	check_etzpc_secure_configuration();
 	set_gpio_secure_configuration();
 }
-- 
GitLab