stm32mp1: add minimal support for co-processor Cortex-M4

STM32MP1 chip embeds a dual Cortex-A7 and a Cortex-M4.
The support for Cortex-M4 clocks is added when configuring the clock tree.
Some minimal security features to allow communications between A7 and M4
are also added.

Change-Id: I60417e244a476f60a2758f4969700b2684056665
Signed-off-by: Yann Gautier <yann.gautier@st.com>
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
index c9bb9ff..11fd666 100644
--- a/drivers/st/clk/stm32mp1_clk.c
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -70,6 +70,7 @@
 	_HCLK2,
 	_CK_PER,
 	_CK_MPU,
+	_CK_MCU,
 	_USB_PHY_48,
 	_PARENT_NB,
 	_UNKNOWN_ID = 0xff,
@@ -93,6 +94,7 @@
 	_QSPI_SEL,
 	_FMC_SEL,
 	_ASS_SEL,
+	_MSS_SEL,
 	_USBPHY_SEL,
 	_USBO_SEL,
 	_PARENT_SEL_NB,
@@ -117,6 +119,7 @@
 enum stm32mp1_clksrc_id {
 	CLKSRC_MPU,
 	CLKSRC_AXI,
+	CLKSRC_MCU,
 	CLKSRC_PLL12,
 	CLKSRC_PLL3,
 	CLKSRC_PLL4,
@@ -129,6 +132,7 @@
 enum stm32mp1_clkdiv_id {
 	CLKDIV_MPU,
 	CLKDIV_AXI,
+	CLKDIV_MCU,
 	CLKDIV_APB1,
 	CLKDIV_APB2,
 	CLKDIV_APB3,
@@ -272,6 +276,7 @@
 	{ CK_PER, _CK_PER },
 	{ CK_MPU, _CK_MPU },
 	{ CK_AXI, _ACLK },
+	{ CK_MCU, _CK_MCU },
 	{ CK_HSE, _HSE },
 	{ CK_CSI, _CSI },
 	{ CK_LSI, _LSI },
@@ -412,6 +417,10 @@
 	_HSI, _HSE, _PLL2
 };
 
+static const uint8_t mss_parents[] = {
+	_HSI, _HSE, _CSI, _PLL3
+};
+
 static const uint8_t usbphy_parents[] = {
 	_HSE_KER, _PLL4_R, _HSE_KER_DIV2
 };
@@ -437,6 +446,7 @@
 	_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents),
 	_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents),
 	_CLK_PARENT(_ASS_SEL, RCC_ASSCKSELR, 0, 0x3, ass_parents),
+	_CLK_PARENT(_MSS_SEL, RCC_MSSCKSELR, 0, 0x3, mss_parents),
 	_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents),
 	_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents),
 };
@@ -483,6 +493,10 @@
 };
 
 /* Prescaler table lookups for clock computation */
+/* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
+static const uint8_t stm32mp1_mcu_div[16] = {
+	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
+};
 
 /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
 #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
@@ -549,6 +563,13 @@
 	return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) != 0;
 }
 
+bool stm32mp1_rcc_is_mckprot(void)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_MCKPROT) != 0;
+}
+
 void stm32mp1_clk_rcc_regs_lock(void)
 {
 	stm32mp1_clk_lock(&reg_lock);
@@ -775,6 +796,51 @@
 			break;
 		}
 		break;
+	/* MCU sub system */
+	case _CK_MCU:
+	case _PCLK1:
+	case _PCLK2:
+	case _PCLK3:
+		reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
+		switch (reg & RCC_SELR_SRC_MASK) {
+		case RCC_MSSCKSELR_HSI:
+			clock = stm32mp1_clk_get_fixed(_HSI);
+			break;
+		case RCC_MSSCKSELR_HSE:
+			clock = stm32mp1_clk_get_fixed(_HSE);
+			break;
+		case RCC_MSSCKSELR_CSI:
+			clock = stm32mp1_clk_get_fixed(_CSI);
+			break;
+		case RCC_MSSCKSELR_PLL:
+			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
+			break;
+		default:
+			break;
+		}
+
+		/* MCU clock divider */
+		reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
+		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
+
+		switch (p) {
+		case _PCLK1:
+			reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
+			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+			break;
+		case _PCLK2:
+			reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
+			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+			break;
+		case _PCLK3:
+			reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
+			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+			break;
+		case _CK_MCU:
+		default:
+			break;
+		}
+		break;
 	case _CK_PER:
 		reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
 		switch (reg & RCC_SELR_SRC_MASK) {
@@ -1609,6 +1675,10 @@
 	if (ret != 0) {
 		return ret;
 	}
+	ret = stm32mp1_set_clksrc(CLK_MCU_HSI);
+	if (ret != 0) {
+		return ret;
+	}
 
 	if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) &
 	     RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
@@ -1659,6 +1729,10 @@
 	if (ret != 0) {
 		return ret;
 	}
+	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR);
+	if (ret != 0) {
+		return ret;
+	}
 	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR);
 	if (ret != 0) {
 		return ret;
@@ -1757,6 +1831,10 @@
 	if (ret != 0) {
 		return ret;
 	}
+	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]);
+	if (ret != 0) {
+		return ret;
+	}
 	stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css);
 
 	/* Configure PKCK */
diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts
index 0314171..cf0fe28 100644
--- a/fdts/stm32mp157a-dk1.dts
+++ b/fdts/stm32mp157a-dk1.dts
@@ -204,6 +204,7 @@
 	st,clksrc = <
 		CLK_MPU_PLL1P
 		CLK_AXI_PLL2P
+		CLK_MCU_PLL3P
 		CLK_PLL12_HSE
 		CLK_PLL3_HSE
 		CLK_PLL4_HSE
@@ -215,6 +216,7 @@
 	st,clkdiv = <
 		1 /*MPU*/
 		0 /*AXI*/
+		0 /*MCU*/
 		1 /*APB1*/
 		1 /*APB2*/
 		1 /*APB3*/
diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts
index 5d8817f..0fadffb 100644
--- a/fdts/stm32mp157c-ed1.dts
+++ b/fdts/stm32mp157c-ed1.dts
@@ -224,6 +224,7 @@
 	st,clksrc = <
 		CLK_MPU_PLL1P
 		CLK_AXI_PLL2P
+		CLK_MCU_PLL3P
 		CLK_PLL12_HSE
 		CLK_PLL3_HSE
 		CLK_PLL4_HSE
@@ -235,6 +236,7 @@
 	st,clkdiv = <
 		1 /*MPU*/
 		0 /*AXI*/
+		0 /*MCU*/
 		1 /*APB1*/
 		1 /*APB2*/
 		1 /*APB3*/
diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h
index 1e0d949..7afa5ad 100644
--- a/include/drivers/st/stm32mp1_clk.h
+++ b/include/drivers/st/stm32mp1_clk.h
@@ -13,6 +13,7 @@
 int stm32mp1_clk_init(void);
 
 bool stm32mp1_rcc_is_secure(void);
+bool stm32mp1_rcc_is_mckprot(void);
 
 void __stm32mp1_clk_enable(unsigned long id, bool caller_is_secure);
 void __stm32mp1_clk_disable(unsigned long id, bool caller_is_secure);
diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h
index 1922c48..eaa853d 100644
--- a/include/drivers/st/stm32mp1_rcc.h
+++ b/include/drivers/st/stm32mp1_rcc.h
@@ -111,6 +111,7 @@
 #define RCC_RCK4SELR			U(0x824)
 #define RCC_TIMG1PRER			U(0x828)
 #define RCC_TIMG2PRER			U(0x82C)
+#define RCC_MCUDIVR			U(0x830)
 #define RCC_APB1DIVR			U(0x834)
 #define RCC_APB2DIVR			U(0x838)
 #define RCC_APB3DIVR			U(0x83C)
@@ -237,6 +238,7 @@
 
 /* Values for RCC_TZCR register */
 #define RCC_TZCR_TZEN			BIT(0)
+#define RCC_TZCR_MCKPROT		BIT(1)
 
 /* Used for most of RCC_<x>SELR registers */
 #define RCC_SELR_SRC_MASK		GENMASK(2, 0)
@@ -273,6 +275,7 @@
 #define RCC_APBXDIV_MASK		GENMASK(2, 0)
 #define RCC_MPUDIV_MASK			GENMASK(2, 0)
 #define RCC_AXIDIV_MASK			GENMASK(2, 0)
+#define RCC_MCUDIV_MASK			GENMASK(3, 0)
 
 /* Used for TIMER Prescaler */
 #define RCC_TIMGXPRER_TIMGXPRE		BIT(0)
@@ -421,6 +424,7 @@
 
 /* Global Reset Register */
 #define RCC_MP_GRSTCSETR_MPSYSRST	BIT(0)
+#define RCC_MP_GRSTCSETR_MCURST		BIT(1)
 #define RCC_MP_GRSTCSETR_MPUP0RST	BIT(4)
 #define RCC_MP_GRSTCSETR_MPUP1RST	BIT(5)
 
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
index c7bc39f..2477954 100644
--- a/plat/st/stm32mp1/bl2_plat_setup.c
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -202,6 +202,9 @@
 		mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST);
 	}
 
+	/* Disable MCKPROT */
+	mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
+
 	generic_delay_timer_init();
 
 	if (stm32mp1_clk_probe() < 0) {
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
index f0dc575..1c897bd 100644
--- a/plat/st/stm32mp1/stm32mp1_def.h
+++ b/plat/st/stm32mp1/stm32mp1_def.h
@@ -183,6 +183,7 @@
 #define STM32MP1_TZC_BASE		U(0x5C006000)
 
 #define STM32MP1_TZC_A7_ID		U(0)
+#define STM32MP1_TZC_M4_ID		U(1)
 #define STM32MP1_TZC_LCD_ID		U(3)
 #define STM32MP1_TZC_GPU_ID		U(4)
 #define STM32MP1_TZC_MDMA_ID		U(5)
diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c
index ebf1587..0ad43e4 100644
--- a/plat/st/stm32mp1/stm32mp1_security.c
+++ b/plat/st/stm32mp1/stm32mp1_security.c
@@ -41,6 +41,7 @@
 			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) |
 			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) |
 			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) |
+			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_M4_ID) |
 			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) |
 			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) |
 			TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) |