aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/st/clk/stm32mp1_clk.c196
-rw-r--r--include/drivers/st/stm32mp1_clk.h3
2 files changed, 199 insertions, 0 deletions
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
index 2f4dcadfcb..d6cd8b1ce4 100644
--- a/drivers/st/clk/stm32mp1_clk.c
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -577,6 +577,43 @@ static const uint8_t stm32mp1_axi_div[8] = {
1, 2, 3, 4, 4, 4, 4, 4
};
+static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
+ [_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",
+};
+
/* RCC clock device driver private */
static unsigned long stm32mp1_osc[NB_OSC];
static struct spinlock reg_lock;
@@ -2007,6 +2044,165 @@ static void stm32mp1_osc_init(void)
}
}
+#ifdef STM32MP_SHARED_RESOURCES
+/*
+ * Get the parent ID of the target parent clock, for tagging as secure
+ * shared clock dependencies.
+ */
+static int get_parent_id_parent(unsigned int parent_id)
+{
+ enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
+ enum stm32mp1_pll_id pll_id;
+ uint32_t p_sel;
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ switch (parent_id) {
+ case _ACLK:
+ case _PCLK4:
+ case _PCLK5:
+ s = _AXIS_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 expect 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);
+
+ p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
+ sel->msk;
+
+ if (p_sel < sel->nb_parent) {
+ return (int)sel->parent[p_sel];
+ }
+ } else {
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+
+ p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
+ RCC_SELR_REFCLK_SRC_MASK;
+
+ if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
+ return (int)pll->refclk[p_sel];
+ }
+ }
+
+ VERBOSE("No parent selected for %s\n",
+ stm32mp1_clk_parent_name[parent_id]);
+
+ return -1;
+}
+
+static void secure_parent_clocks(unsigned long parent_id)
+{
+ int grandparent_id;
+
+ switch (parent_id) {
+ case _PLL3_P:
+ case _PLL3_Q:
+ case _PLL3_R:
+ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
+ break;
+
+ /* These clocks are always secure when RCC is secure */
+ case _ACLK:
+ case _HCLK2:
+ case _HCLK6:
+ case _PCLK4:
+ case _PCLK5:
+ case _PLL1_P:
+ case _PLL1_Q:
+ case _PLL1_R:
+ case _PLL2_P:
+ case _PLL2_Q:
+ case _PLL2_R:
+ case _HSI:
+ case _HSI_KER:
+ case _LSI:
+ case _CSI:
+ case _CSI_KER:
+ case _HSE:
+ case _HSE_KER:
+ case _HSE_KER_DIV2:
+ case _LSE:
+ break;
+
+ default:
+ VERBOSE("Cannot secure parent clock %s\n",
+ stm32mp1_clk_parent_name[parent_id]);
+ panic();
+ }
+
+ grandparent_id = get_parent_id_parent(parent_id);
+ if (grandparent_id >= 0) {
+ secure_parent_clocks(grandparent_id);
+ }
+}
+
+void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
+{
+ int parent_id;
+
+ if (!stm32mp1_rcc_is_secure()) {
+ return;
+ }
+
+ switch (clock_id) {
+ case PLL1:
+ case PLL2:
+ /* PLL1/PLL2 are always secure: nothing to do */
+ break;
+ case PLL3:
+ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
+ break;
+ case PLL4:
+ ERROR("PLL4 cannot be secured\n");
+ panic();
+ break;
+ default:
+ /* Others are expected gateable clock */
+ parent_id = stm32mp1_clk_get_parent(clock_id);
+ if (parent_id < 0) {
+ INFO("No parent found for clock %lu\n", clock_id);
+ } else {
+ secure_parent_clocks(parent_id);
+ }
+ break;
+ }
+}
+#endif /* STM32MP_SHARED_RESOURCES */
+
static void sync_earlyboot_clocks_state(void)
{
unsigned int idx;
diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h
index 1ebd39ff7f..c46892b78e 100644
--- a/include/drivers/st/stm32mp1_clk.h
+++ b/include/drivers/st/stm32mp1_clk.h
@@ -59,4 +59,7 @@ void stm32mp1_clk_rcc_regs_unlock(void);
void stm32mp1_stgen_increment(unsigned long long offset_in_ms);
+#ifdef STM32MP_SHARED_RESOURCES
+void stm32mp1_register_clock_parents_secure(unsigned long id);
+#endif
#endif /* STM32MP1_CLK_H */