aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorEtienne Carriere <etienne.carriere@st.com>2019-03-14 09:06:13 +0100
committerJérôme Forissier <jerome.forissier@linaro.org>2019-04-11 14:52:21 +0200
commit90c579db542f2336dd6e0d4630d032c531785088 (patch)
tree1b185665eefbd89280563678018d6de7ddc15998 /core
parent646fd5c7c2215e340d2e8709ef9c5cadd9823ff7 (diff)
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 <etienne.carriere@st.com> Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
Diffstat (limited to 'core')
-rw-r--r--core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c215
-rw-r--r--core/arch/arm/plat-stm32mp1/shared_resources.c48
-rw-r--r--core/arch/arm/plat-stm32mp1/stm32_util.h3
3 files changed, 265 insertions, 1 deletions
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__*/