From 90c579db542f2336dd6e0d4630d032c531785088 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Thu, 14 Mar 2019 09:06:13 +0100 Subject: stm32mp1: shres: secure clock parents Add API function stm32mp_register_clock_parents_secure(). The function registers as secure the parent clock(s) of the target clock reference. This API is used by shared_resources.c when a clock is registered as secure so that its dependencies are also registered as secure. Signed-off-by: Etienne Carriere Acked-by: Jens Wiklander --- core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c | 215 +++++++++++++++++++++ core/arch/arm/plat-stm32mp1/shared_resources.c | 48 ++++- core/arch/arm/plat-stm32mp1/stm32_util.h | 3 + 3 files changed, 265 insertions(+), 1 deletion(-) (limited to 'core') diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c index 4d0e6375..dc58ad7a 100644 --- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c +++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c @@ -441,6 +441,43 @@ static const uint8_t stm32mp1_axi_div[8] = { 1, 2, 3, 4, 4, 4, 4, 4 }; +static const char __maybe_unused *const stm32mp1_clk_parent_name[_PARENT_NB] = { + [_HSI] = "HSI", + [_HSE] = "HSE", + [_CSI] = "CSI", + [_LSI] = "LSI", + [_LSE] = "LSE", + [_I2S_CKIN] = "I2S_CKIN", + [_HSI_KER] = "HSI_KER", + [_HSE_KER] = "HSE_KER", + [_HSE_KER_DIV2] = "HSE_KER_DIV2", + [_CSI_KER] = "CSI_KER", + [_PLL1_P] = "PLL1_P", + [_PLL1_Q] = "PLL1_Q", + [_PLL1_R] = "PLL1_R", + [_PLL2_P] = "PLL2_P", + [_PLL2_Q] = "PLL2_Q", + [_PLL2_R] = "PLL2_R", + [_PLL3_P] = "PLL3_P", + [_PLL3_Q] = "PLL3_Q", + [_PLL3_R] = "PLL3_R", + [_PLL4_P] = "PLL4_P", + [_PLL4_Q] = "PLL4_Q", + [_PLL4_R] = "PLL4_R", + [_ACLK] = "ACLK", + [_PCLK1] = "PCLK1", + [_PCLK2] = "PCLK2", + [_PCLK3] = "PCLK3", + [_PCLK4] = "PCLK4", + [_PCLK5] = "PCLK5", + [_HCLK6] = "KCLK6", + [_HCLK2] = "HCLK2", + [_CK_PER] = "CK_PER", + [_CK_MPU] = "CK_MPU", + [_CK_MCU] = "CK_MCU", + [_USB_PHY_48] = "USB_PHY_48", +}; + /* * Oscillator frequency in Hz. This array shall be initialized * according to platform. @@ -942,6 +979,184 @@ unsigned long stm32_clock_get_rate(unsigned long id) return rate; } +/* + * Get the parent ID of the target parent clock, or -1 if no parent found. + */ +static int get_parent_id_parent(unsigned int parent_id) +{ + enum stm32mp1_parent_sel s = _UNKNOWN_SEL; + enum stm32mp1_pll_id pll_id = _PLL_NB; + uint32_t p_sel = 0; + + switch (parent_id) { + case _ACLK: + case _PCLK4: + case _PCLK5: + s = _ASS_SEL; + break; + case _PLL1_P: + case _PLL1_Q: + case _PLL1_R: + pll_id = _PLL1; + break; + case _PLL2_P: + case _PLL2_Q: + case _PLL2_R: + pll_id = _PLL2; + break; + case _PLL3_P: + case _PLL3_Q: + case _PLL3_R: + pll_id = _PLL3; + break; + case _PLL4_P: + case _PLL4_Q: + case _PLL4_R: + pll_id = _PLL4; + break; + case _PCLK1: + case _PCLK2: + case _HCLK2: + case _HCLK6: + case _CK_PER: + case _CK_MPU: + case _CK_MCU: + case _USB_PHY_48: + /* We do not expected to access these */ + panic(); + break; + default: + /* Other parents have no parent */ + return -1; + } + + if (s != _UNKNOWN_SEL) { + const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); + vaddr_t rcc_base = stm32_rcc_base(); + + p_sel = (io_read32(rcc_base + sel->offset) >> sel->src) & + sel->msk; + + if (p_sel < sel->nb_parent) + return sel->parent[p_sel]; + } else { + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + + p_sel = io_read32(stm32_rcc_base() + pll->rckxselr) & + RCC_SELR_REFCLK_SRC_MASK; + + if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) + return pll->refclk[p_sel]; + } + + FMSG("No parent found for %s", stm32mp1_clk_parent_name[parent_id]); + return -1; +} + +static void secure_parent_clocks(unsigned long parent_id) +{ + int grandparent_id = 0; + + switch (parent_id) { + /* Secure only the parents for these clocks */ + case _ACLK: + case _HCLK2: + case _HCLK6: + case _PCLK4: + case _PCLK5: + break; + /* PLLs */ + case _PLL1_P: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL1_P); + break; + case _PLL1_Q: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL1_Q); + break; + case _PLL1_R: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL1_R); + break; + + case _PLL2_P: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL2_P); + break; + case _PLL2_Q: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL2_Q); + break; + case _PLL2_R: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL2_R); + break; + + case _PLL3_P: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3_P); + break; + case _PLL3_Q: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3_Q); + break; + case _PLL3_R: + stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3_R); + break; + + /* Source clocks */ + case _HSI: + case _HSI_KER: + stm32mp_register_secure_periph(STM32MP1_SHRES_HSI); + break; + case _LSI: + stm32mp_register_secure_periph(STM32MP1_SHRES_LSI); + break; + case _CSI: + case _CSI_KER: + stm32mp_register_secure_periph(STM32MP1_SHRES_CSI); + break; + case _HSE: + case _HSE_KER: + case _HSE_KER_DIV2: + stm32mp_register_secure_periph(STM32MP1_SHRES_HSE); + break; + case _LSE: + stm32mp_register_secure_periph(STM32MP1_SHRES_LSE); + break; + + default: + panic(); + } + + grandparent_id = get_parent_id_parent(parent_id); + if (grandparent_id >= 0) + secure_parent_clocks(grandparent_id); +} + +void stm32mp_register_clock_parents_secure(unsigned long clock_id) +{ + int parent_id = 0; + + switch (clock_id) { + case PLL1: + parent_id = get_parent_id_parent(_PLL1_P); + break; + case PLL2: + parent_id = get_parent_id_parent(_PLL2_P); + break; + case PLL3: + parent_id = get_parent_id_parent(_PLL3_P); + break; + case PLL4: + EMSG("PLL4 cannot be secure"); + panic(); + default: + /* Others are expected gateable clock */ + parent_id = stm32mp1_clk_get_parent(clock_id); + break; + } + + if (parent_id < 0) { + DMSG("No parent for clock %lu", clock_id); + panic(); + } + + secure_parent_clocks(parent_id); +} + #ifdef CFG_EMBED_DTB #define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" diff --git a/core/arch/arm/plat-stm32mp1/shared_resources.c b/core/arch/arm/plat-stm32mp1/shared_resources.c index 162005ff..0a0ad4c8 100644 --- a/core/arch/arm/plat-stm32mp1/shared_resources.c +++ b/core/arch/arm/plat-stm32mp1/shared_resources.c @@ -183,24 +183,70 @@ static void register_periph(enum stm32mp_shres id, enum shres_state state) shres_state[id] = state; - /* Explore clock tree to lock dependencies */ + /* Explore clock tree to lock secure clock dependencies */ if (state == SHRES_SECURE) { switch (id) { + case STM32MP1_SHRES_GPIOZ(0): + case STM32MP1_SHRES_GPIOZ(1): + case STM32MP1_SHRES_GPIOZ(2): + case STM32MP1_SHRES_GPIOZ(3): + case STM32MP1_SHRES_GPIOZ(4): + case STM32MP1_SHRES_GPIOZ(5): + case STM32MP1_SHRES_GPIOZ(6): + case STM32MP1_SHRES_GPIOZ(7): + stm32mp_register_clock_parents_secure(GPIOZ); + break; + case STM32MP1_SHRES_IWDG1: + stm32mp_register_clock_parents_secure(IWDG1); + break; + case STM32MP1_SHRES_USART1: + stm32mp_register_clock_parents_secure(USART1_K); + break; + case STM32MP1_SHRES_SPI6: + stm32mp_register_clock_parents_secure(SPI6_K); + break; + case STM32MP1_SHRES_I2C4: + stm32mp_register_clock_parents_secure(I2C4_K); + break; + case STM32MP1_SHRES_RNG1: + stm32mp_register_clock_parents_secure(RNG1_K); + break; + case STM32MP1_SHRES_HASH1: + stm32mp_register_clock_parents_secure(HASH1); + break; + case STM32MP1_SHRES_CRYP1: + stm32mp_register_clock_parents_secure(CRYP1); + break; + case STM32MP1_SHRES_I2C6: + stm32mp_register_clock_parents_secure(I2C6_K); + break; + case STM32MP1_SHRES_RTC: + stm32mp_register_clock_parents_secure(RTC); + break; case STM32MP1_SHRES_PLL1_P: case STM32MP1_SHRES_PLL1_Q: case STM32MP1_SHRES_PLL1_R: register_periph(STM32MP1_SHRES_PLL1, SHRES_SECURE); break; + case STM32MP1_SHRES_PLL1: + stm32mp_register_clock_parents_secure(PLL1); + break; case STM32MP1_SHRES_PLL2_P: case STM32MP1_SHRES_PLL2_Q: case STM32MP1_SHRES_PLL2_R: register_periph(STM32MP1_SHRES_PLL2, SHRES_SECURE); break; + case STM32MP1_SHRES_PLL2: + stm32mp_register_clock_parents_secure(PLL2); + break; case STM32MP1_SHRES_PLL3_P: case STM32MP1_SHRES_PLL3_Q: case STM32MP1_SHRES_PLL3_R: register_periph(STM32MP1_SHRES_PLL3, SHRES_SECURE); break; + case STM32MP1_SHRES_PLL3: + stm32mp_register_clock_parents_secure(PLL3); + break; default: /* No expected resource dependency */ break; diff --git a/core/arch/arm/plat-stm32mp1/stm32_util.h b/core/arch/arm/plat-stm32mp1/stm32_util.h index e61ba6ff..3e440b25 100644 --- a/core/arch/arm/plat-stm32mp1/stm32_util.h +++ b/core/arch/arm/plat-stm32mp1/stm32_util.h @@ -260,4 +260,7 @@ bool stm32mp_clock_is_shared(unsigned long clock_id); /* Return true if and only if @clock_id is assigned to non-secure world */ bool stm32mp_clock_is_non_secure(unsigned long clock_id); +/* Register parent clocks of @clock (ID used in clock DT bindings) as secure */ +void stm32mp_register_clock_parents_secure(unsigned long clock_id); + #endif /*__STM32_UTIL_H__*/ -- cgit v1.2.3