From 547f5ef88ac962218f2cb8cb90bc4cab1b99f7f9 Mon Sep 17 00:00:00 2001 From: Romuald JEANNE Date: Thu, 28 Oct 2021 15:54:46 +0200 Subject: [PATCH] 3.12.0-stm32mp-r2 --- core/arch/arm/dts/stm32mp15xx-dkx.dtsi | 2 +- core/arch/arm/dts/stm32mp15xx-edx.dtsi | 2 +- core/arch/arm/plat-stm32mp1/conf.mk | 6 + core/arch/arm/plat-stm32mp1/main.c | 77 ++ .../arch/arm/plat-stm32mp1/shared_resources.c | 2 +- core/drivers/clk/clk-stm32mp15.c | 126 ++- .../crypto/caam/hal/common/hal_cfg_dt.c | 4 +- core/drivers/gic.c | 29 + core/drivers/stm32_i2c.c | 33 + core/drivers/stm32_rtc.c | 2 +- core/drivers/stm32_tamp.c | 965 ++++++++++++++++++ core/drivers/sub.mk | 1 + core/include/drivers/stm32_tamp.h | 378 +++++++ core/include/kernel/dt.h | 15 +- core/include/kernel/interrupt.h | 25 + core/kernel/dt.c | 28 +- core/kernel/interrupt.c | 30 + mk/config.mk | 2 +- 18 files changed, 1632 insertions(+), 95 deletions(-) create mode 100644 core/drivers/stm32_tamp.c create mode 100644 core/include/drivers/stm32_tamp.h diff --git a/core/arch/arm/dts/stm32mp15xx-dkx.dtsi b/core/arch/arm/dts/stm32mp15xx-dkx.dtsi index 236cff932..1334b705a 100644 --- a/core/arch/arm/dts/stm32mp15xx-dkx.dtsi +++ b/core/arch/arm/dts/stm32mp15xx-dkx.dtsi @@ -253,7 +253,7 @@ CLK_CKPER_HSE CLK_FMC_ACLK CLK_QSPI_ACLK - CLK_ETH_DISABLED + CLK_ETH_PLL4P CLK_SDMMC12_PLL4P CLK_DSI_DSIPLL CLK_STGEN_HSE diff --git a/core/arch/arm/dts/stm32mp15xx-edx.dtsi b/core/arch/arm/dts/stm32mp15xx-edx.dtsi index ef51b00af..d74d37c4e 100644 --- a/core/arch/arm/dts/stm32mp15xx-edx.dtsi +++ b/core/arch/arm/dts/stm32mp15xx-edx.dtsi @@ -255,7 +255,7 @@ CLK_CKPER_HSE CLK_FMC_ACLK CLK_QSPI_ACLK - CLK_ETH_DISABLED + CLK_ETH_PLL4P CLK_SDMMC12_PLL4P CLK_DSI_DSIPLL CLK_STGEN_HSE diff --git a/core/arch/arm/plat-stm32mp1/conf.mk b/core/arch/arm/plat-stm32mp1/conf.mk index b1d41c92a..d01a430d9 100644 --- a/core/arch/arm/plat-stm32mp1/conf.mk +++ b/core/arch/arm/plat-stm32mp1/conf.mk @@ -110,7 +110,12 @@ $(call force,CFG_STM32_TIM,n) $(call force,CFG_STPMIC1,n) endif +# Remoteproc early TA for coprocessor firmware management CFG_RPROC_PTA ?= n +ifeq ($(CFG_RPROC_PTA),y) +CFG_IN_TREE_EARLY_TAS += remoteproc/80a4c275-0a47-4905-8285-1486a9771a08 +endif + CFG_STM32_BSEC ?= y CFG_STM32_CLKCALIB ?= y CFG_STM32_CRYP ?= y @@ -121,6 +126,7 @@ CFG_STM32_IWDG ?= y CFG_STM32_RNG ?= y CFG_STM32_RTC ?= y CFG_STM32_TIM ?= y +CFG_STM32_TAMP ?= y CFG_STM32_UART ?= y CFG_STM32MP15_CLK ?= y CFG_STPMIC1 ?= y diff --git a/core/arch/arm/plat-stm32mp1/main.c b/core/arch/arm/plat-stm32mp1/main.c index bf2e394fb..13460c6b9 100644 --- a/core/arch/arm/plat-stm32mp1/main.c +++ b/core/arch/arm/plat-stm32mp1/main.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -666,3 +668,78 @@ bool stm32_rtc_get_read_twice(void) return apb1_freq < (rtc_freq * 7U); } #endif + +#ifdef CFG_STM32_TAMP + +static const char * const itamper_name[] = { + [INT_TAMP1] = "RTC power domain", + [INT_TAMP2] = "Temperature monitoring", + [INT_TAMP3] = "LSE monitoring", + [INT_TAMP4] = "HSE monitoring", +}; + +DECLARE_KEEP_PAGER(itamper_name); + +static int stm32mp1_itamper_action(int id) +{ + const char *tamp_name = NULL; + + if (id >= 0 && ((size_t)id < ARRAY_SIZE(itamper_name))) + tamp_name = itamper_name[id]; + + MSG("Internal tamper %u (%s) occurs\n", id + 1, tamp_name); + + return 1; /* Ack TAMPER and reset system */ +} +DECLARE_KEEP_PAGER(stm32mp1_itamper_action); + +static int __unused stm32mp1_etamper_action(int id) +{ + MSG("External tamper %u occurs\n", id + 1); + + return 1; /* Ack TAMPER and reset system */ +} +DECLARE_KEEP_PAGER(stm32mp1_etamper_action); + +static TEE_Result stm32_configure_tamp(void) +{ + struct stm32_bkpregs_conf bkpregs_conf = { + .nb_zone1_regs = 10, /* 10 registers in zone 1 */ + .nb_zone2_regs = 0 /* No register in zone 2 */ + /* Zone3 all remaining */ + }; + + /* Enable BKP Register protection */ + if (stm32_tamp_set_secure_bkpregs(&bkpregs_conf) != TEE_SUCCESS) + panic(); + + /* + * Configure TAMP to accept only secure access, + * and use secure Interrupt. + */ + stm32_tamp_configure_secure_access(TAMP_REGS_IT_SECURE); + + stm32_tamp_configure_internal(INT_TAMP1, TAMP_ENABLE, + stm32mp1_itamper_action); + stm32_tamp_configure_internal(INT_TAMP2, TAMP_ENABLE, + stm32mp1_itamper_action); + stm32_tamp_configure_internal(INT_TAMP3, TAMP_ENABLE, + stm32mp1_itamper_action); + stm32_tamp_configure_internal(INT_TAMP4, TAMP_ENABLE, + stm32mp1_itamper_action); + + stm32_tamp_configure_active(TAMP_ACTIVE_FILTER_OFF); + + stm32_tamp_configure_passive(0); + + if (stm32_tamp_set_config() != TEE_SUCCESS) + panic(); + + /* Enable timestamp for tamper */ + stm32_rtc_set_tamper_timestamp(); + + return TEE_SUCCESS; +} + +boot_final(stm32_configure_tamp); +#endif diff --git a/core/arch/arm/plat-stm32mp1/shared_resources.c b/core/arch/arm/plat-stm32mp1/shared_resources.c index 7ad3d7b9c..7d2bcacba 100644 --- a/core/arch/arm/plat-stm32mp1/shared_resources.c +++ b/core/arch/arm/plat-stm32mp1/shared_resources.c @@ -159,7 +159,7 @@ static const char *shres2str_state_tbl[4] __maybe_unused = { [SHRES_SECURE] = "secure", }; -static __maybe_unused const char *shres2str_state(enum stm32mp_shres id) +static __maybe_unused const char *shres2str_state(enum shres_state id) { return shres2str_state_tbl[id]; } diff --git a/core/drivers/clk/clk-stm32mp15.c b/core/drivers/clk/clk-stm32mp15.c index 6bbab8902..31d9ab6d6 100644 --- a/core/drivers/clk/clk-stm32mp15.c +++ b/core/drivers/clk/clk-stm32mp15.c @@ -44,27 +44,30 @@ /* Identifiers for root oscillators */ enum stm32mp_osc_id { - _HSI = 0, - _HSE, - _CSI, - _LSI, - _LSE, - _I2S_CKIN, - _USB_PHY_48, + OSC_HSI, + OSC_HSE, + OSC_CSI, + OSC_LSI, + OSC_LSE, + OSC_I2S_CKIN, + OSC_USB_PHY_48, NB_OSC, _UNKNOWN_OSC_ID = 0xffU }; /* Identifiers for parent clocks */ enum stm32mp1_parent_id { -/* - * Oscillators are valid IDs for parent clock and are already - * defined in enum stm32mp_osc_id, ending at NB_OSC - 1. - * This enum defines IDs are the other possible clock parents. - */ - _HSI_KER = NB_OSC, + _HSI, + _HSE, + _CSI, + _LSI, + _LSE, + _I2S_CKIN, + _USB_PHY_48, + _HSI_KER, _HSE_KER, _HSE_KER_DIV2, + _HSE_RTC, _CSI_KER, _PLL1_P, _PLL1_Q, @@ -84,6 +87,7 @@ enum stm32mp1_parent_id { _PCLK3, _PCLK4, _PCLK5, + _HCLK5, _HCLK6, _HCLK2, _CK_PER, @@ -130,6 +134,7 @@ static const uint8_t parent_id_clock_id[_PARENT_NB] = { [_HSI_KER] = CK_HSI, [_HSE_KER] = CK_HSE, [_HSE_KER_DIV2] = CK_HSE_DIV2, + [_HSE_RTC] = _UNKNOWN_ID, [_CSI_KER] = CK_CSI, [_PLL1_P] = PLL1_P, [_PLL1_Q] = PLL1_Q, @@ -149,6 +154,7 @@ static const uint8_t parent_id_clock_id[_PARENT_NB] = { [_PCLK3] = CK_AXI, [_PCLK4] = CK_AXI, [_PCLK5] = CK_AXI, + [_HCLK5] = CK_AXI, [_HCLK6] = CK_AXI, [_HCLK2] = CK_AXI, [_CK_PER] = CK_PER, @@ -390,13 +396,13 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { _CLK_SC2_FIXED(SEC, RCC_MP_APB5ENSETR, BSECEN, BSEC, _PCLK5), _CLK_SC2_SELEC(SEC, RCC_MP_APB5ENSETR, STGENEN, STGEN_K, _STGEN_SEL), - _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, GPIOZEN, GPIOZ, _PCLK5), - _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, CRYP1EN, CRYP1, _PCLK5), - _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, HASH1EN, HASH1, _PCLK5), + _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, GPIOZEN, GPIOZ, _HCLK5), + _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, CRYP1EN, CRYP1, _HCLK5), + _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, HASH1EN, HASH1, _HCLK5), _CLK_SC2_SELEC(SEC, RCC_MP_AHB5ENSETR, RNG1EN, RNG1_K, _RNG1_SEL), - _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, BKPSRAMEN, BKPSRAM, _PCLK5), + _CLK_SC2_FIXED(SEC, RCC_MP_AHB5ENSETR, BKPSRAMEN, BKPSRAM, _HCLK5), - _CLK_SC2_FIXED(SEC, RCC_MP_TZAHB6ENSETR, MDMA, MDMA, _PCLK5), + _CLK_SC2_FIXED(SEC, RCC_MP_TZAHB6ENSETR, MDMA, MDMA, _HCLK6), _CLK_SELEC(SEC, RCC_BDCR, RCC_BDCR_RTCCKEN_POS, RTC, _RTC_SEL), @@ -492,7 +498,7 @@ static const uint8_t mcuss_parents[] = { }; static const uint8_t rtc_parents[] = { - _UNKNOWN_ID, _LSE, _LSI, _HSE + _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC }; #ifdef STM32MP1_USE_MPU0_RESET @@ -520,7 +526,7 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { _CLK_PARENT(_SPI6_SEL, RCC_SPI6CKSELR, 0, 0x7, spi6_parents), _CLK_PARENT(_USART1_SEL, RCC_UART1CKSELR, 0, 0x7, usart1_parents), _CLK_PARENT(_RNG1_SEL, RCC_RNG1CKSELR, 0, 0x3, rng1_parents), - _CLK_PARENT(_RTC_SEL, RCC_BDCR, 0, 0x3, rtc_parents), + _CLK_PARENT(_RTC_SEL, RCC_BDCR, 16, 0x3, rtc_parents), _CLK_PARENT(_MPU_SEL, RCC_MPCKSELR, 0, 0x3, mpu_parents), _CLK_PARENT(_AXISS_SEL, RCC_ASSCKSELR, 0, 0x3, axiss_parents), _CLK_PARENT(_MCUSS_SEL, RCC_MSSCKSELR, 0, 0x3, mcuss_parents), @@ -564,19 +570,19 @@ static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { _CLK_PLL(_PLL1, PLL_1600, RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, - _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), + OSC_HSI, OSC_HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), _CLK_PLL(_PLL2, PLL_1600, RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, - _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), + OSC_HSI, OSC_HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), _CLK_PLL(_PLL3, PLL_800, RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, - _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), + OSC_HSI, OSC_HSE, OSC_CSI, _UNKNOWN_OSC_ID), _CLK_PLL(_PLL4, PLL_800, RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, - _HSI, _HSE, _CSI, _I2S_CKIN), + OSC_HSI, OSC_HSE, OSC_CSI, OSC_I2S_CKIN), }; /* Prescaler table lookups for clock computation */ @@ -607,6 +613,7 @@ static const char __maybe_unused *const stm32mp1_clk_parent_name[_PARENT_NB] = { [_HSI_KER] = "HSI_KER", [_HSE_KER] = "HSE_KER", [_HSE_KER_DIV2] = "HSE_KER_DIV2", + [_HSE_RTC] = "HSE_RTC", [_CSI_KER] = "CSI_KER", [_PLL1_P] = "PLL1_P", [_PLL1_Q] = "PLL1_Q", @@ -626,8 +633,9 @@ static const char __maybe_unused *const stm32mp1_clk_parent_name[_PARENT_NB] = { [_PCLK3] = "PCLK3", [_PCLK4] = "PCLK4", [_PCLK5] = "PCLK5", - [_HCLK6] = "KCLK6", [_HCLK2] = "HCLK2", + [_HCLK5] = "HCLK5", + [_HCLK6] = "HCLK6", [_CK_PER] = "CK_PER", [_CK_MPU] = "CK_MPU", [_CK_MCU] = "CK_MCU", @@ -968,10 +976,10 @@ static unsigned long __clk_get_parent_rate(enum stm32mp1_parent_id p) reg = io_read32(rcc_base + RCC_MPCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_MPCKSELR_HSI: - clock = osc_frequency(_HSI); + clock = osc_frequency(OSC_HSI); break; case RCC_MPCKSELR_HSE: - clock = osc_frequency(_HSE); + clock = osc_frequency(OSC_HSE); break; case RCC_MPCKSELR_PLL: clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); @@ -991,16 +999,17 @@ static unsigned long __clk_get_parent_rate(enum stm32mp1_parent_id p) /* AXI sub system */ case _ACLK: case _HCLK2: + case _HCLK5: case _HCLK6: case _PCLK4: case _PCLK5: reg = io_read32(rcc_base + RCC_ASSCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_ASSCKSELR_HSI: - clock = osc_frequency(_HSI); + clock = osc_frequency(OSC_HSI); break; case RCC_ASSCKSELR_HSE: - clock = osc_frequency(_HSE); + clock = osc_frequency(OSC_HSE); break; case RCC_ASSCKSELR_PLL: clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); @@ -1034,13 +1043,13 @@ static unsigned long __clk_get_parent_rate(enum stm32mp1_parent_id p) reg = io_read32(rcc_base + RCC_MSSCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_MSSCKSELR_HSI: - clock = osc_frequency(_HSI); + clock = osc_frequency(OSC_HSI); break; case RCC_MSSCKSELR_HSE: - clock = osc_frequency(_HSE); + clock = osc_frequency(OSC_HSE); break; case RCC_MSSCKSELR_CSI: - clock = osc_frequency(_CSI); + clock = osc_frequency(OSC_CSI); break; case RCC_MSSCKSELR_PLL: clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); @@ -1075,13 +1084,13 @@ static unsigned long __clk_get_parent_rate(enum stm32mp1_parent_id p) reg = io_read32(rcc_base + RCC_CPERCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_CPERCKSELR_HSI: - clock = osc_frequency(_HSI); + clock = osc_frequency(OSC_HSI); break; case RCC_CPERCKSELR_HSE: - clock = osc_frequency(_HSE); + clock = osc_frequency(OSC_HSE); break; case RCC_CPERCKSELR_CSI: - clock = osc_frequency(_CSI); + clock = osc_frequency(OSC_CSI); break; default: break; @@ -1089,24 +1098,28 @@ static unsigned long __clk_get_parent_rate(enum stm32mp1_parent_id p) break; case _HSI: case _HSI_KER: - clock = osc_frequency(_HSI); + clock = osc_frequency(OSC_HSI); break; case _CSI: case _CSI_KER: - clock = osc_frequency(_CSI); + clock = osc_frequency(OSC_CSI); break; case _HSE: case _HSE_KER: - clock = osc_frequency(_HSE); + clock = osc_frequency(OSC_HSE); break; case _HSE_KER_DIV2: - clock = osc_frequency(_HSE) >> 1; + clock = osc_frequency(OSC_HSE) >> 1; + break; + case _HSE_RTC: + clock = osc_frequency(OSC_HSE); + clock /= (io_read32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U; break; case _LSI: - clock = osc_frequency(_LSI); + clock = osc_frequency(OSC_LSI); break; case _LSE: - clock = osc_frequency(_LSE); + clock = osc_frequency(OSC_LSE); break; /* PLL */ case _PLL1_P: @@ -1147,7 +1160,7 @@ static unsigned long __clk_get_parent_rate(enum stm32mp1_parent_id p) break; /* Other */ case _USB_PHY_48: - clock = osc_frequency(_USB_PHY_48); + clock = osc_frequency(OSC_USB_PHY_48); break; default: break; @@ -1347,7 +1360,7 @@ static unsigned long clk_stm32_get_rate(unsigned long id) /* * 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) +static int get_parent_id_parent(enum stm32mp1_parent_id parent_id) { enum stm32mp1_parent_sel s = _UNKNOWN_SEL; enum stm32mp1_pll_id pll_id = _PLL_NB; @@ -1355,6 +1368,8 @@ static int get_parent_id_parent(unsigned int parent_id) switch (parent_id) { case _ACLK: + case _HCLK5: + case _HCLK6: case _PCLK4: case _PCLK5: s = _AXISS_SEL; @@ -1382,7 +1397,6 @@ static int get_parent_id_parent(unsigned int parent_id) case _PCLK1: case _PCLK2: case _HCLK2: - case _HCLK6: case _CK_PER: case _CK_MPU: case _CK_MCU: @@ -1419,13 +1433,14 @@ static int get_parent_id_parent(unsigned int parent_id) } /* We are only interested in knowing if PLL3 shall be secure or not */ -static void secure_parent_clocks(unsigned long parent_id) +static void secure_parent_clocks(enum stm32mp1_parent_id parent_id) { - int grandparent_id = 0; + enum stm32mp1_parent_id grandparent_id = 0; switch (parent_id) { case _ACLK: case _HCLK2: + case _HCLK5: case _HCLK6: case _PCLK4: case _PCLK5: @@ -1439,6 +1454,7 @@ static void secure_parent_clocks(unsigned long parent_id) case _HSE: case _HSE_KER: case _HSE_KER_DIV2: + case _HSE_RTC: case _LSE: case _PLL1_P: case _PLL1_Q: @@ -1487,13 +1503,13 @@ DECLARE_KEEP_PAGER(stm32mp_clk_ops); #ifdef CFG_EMBED_DTB static const char *stm32mp_osc_node_label[NB_OSC] = { - [_LSI] = "clk-lsi", - [_LSE] = "clk-lse", - [_HSI] = "clk-hsi", - [_HSE] = "clk-hse", - [_CSI] = "clk-csi", - [_I2S_CKIN] = "i2s_ckin", - [_USB_PHY_48] = "ck_usbo_48m" + [OSC_LSI] = "clk-lsi", + [OSC_LSE] = "clk-lse", + [OSC_HSI] = "clk-hsi", + [OSC_HSE] = "clk-hse", + [OSC_CSI] = "clk-csi", + [OSC_I2S_CKIN] = "i2s_ckin", + [OSC_USB_PHY_48] = "ck_usbo_48m" }; static unsigned int clk_freq_prop(void *fdt, int node) @@ -1520,8 +1536,8 @@ static void get_osc_freq_from_dt(void *fdt) if (clk_node < 0) panic(); - COMPILE_TIME_ASSERT((int)_HSI == 0); - for (idx = _HSI; idx < NB_OSC; idx++) { + COMPILE_TIME_ASSERT((int)OSC_HSI == 0); + for (idx = OSC_HSI; idx < NB_OSC; idx++) { const char *name = stm32mp_osc_node_label[idx]; int subnode = 0; diff --git a/core/drivers/crypto/caam/hal/common/hal_cfg_dt.c b/core/drivers/crypto/caam/hal/common/hal_cfg_dt.c index f03a7d54a..0133a0696 100644 --- a/core/drivers/crypto/caam/hal/common/hal_cfg_dt.c +++ b/core/drivers/crypto/caam/hal/common/hal_cfg_dt.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -113,8 +114,7 @@ void caam_hal_cfg_get_jobring_dt(void *fdt, struct caam_jrcfg *jrcfg) } jrcfg->offset = jr_offset; - /* Add index of the first SPI interrupt */ - jrcfg->it_num = jr_it_num + 32; + jrcfg->it_num = jr_it_num; } } diff --git a/core/drivers/gic.c b/core/drivers/gic.c index 3f1a606ed..3efce7ab8 100644 --- a/core/drivers/gic.c +++ b/core/drivers/gic.c @@ -6,12 +6,15 @@ #include #include +#include #include #include #include +#include #include #include #include +#include #include #include #include @@ -230,6 +233,29 @@ void gic_init_setup(struct gic_data *gd) #endif } +static int gic_dt_get_irq(const uint32_t *properties, int len) +{ + int it_num = DT_INFO_INVALID_INTERRUPT; + + if (!properties || len < 2) + return DT_INFO_INVALID_INTERRUPT; + + it_num = fdt32_to_cpu(properties[1]); + + switch (fdt32_to_cpu(properties[0])) { + case 1: + it_num += 16; + break; + case 0: + it_num += 32; + break; + default: + it_num = DT_INFO_INVALID_INTERRUPT; + } + + return it_num; +} + void gic_init_base_addr(struct gic_data *gd, vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) { @@ -244,6 +270,9 @@ void gic_init_base_addr(struct gic_data *gd, vaddr_t gicc_base __maybe_unused, void gic_init(struct gic_data *gd, vaddr_t gicc_base, vaddr_t gicd_base) { gic_init_base_addr(gd, gicc_base, gicd_base); + if (IS_ENABLED(CFG_DT)) + gd->chip.dt_get_irq = gic_dt_get_irq; + gic_init_setup(gd); } diff --git a/core/drivers/stm32_i2c.c b/core/drivers/stm32_i2c.c index 2807cc42a..bc10960dc 100644 --- a/core/drivers/stm32_i2c.c +++ b/core/drivers/stm32_i2c.c @@ -870,6 +870,33 @@ static int wait_isr_event(struct i2c_handle_s *hi2c, uint32_t bit_mask, return -1; } +static int wait_isr_event_nack(struct i2c_handle_s *hi2c, uint32_t bit_mask, + unsigned int awaited_value, uint64_t timeout_ref) +{ + vaddr_t isr = get_base(hi2c) + I2C_ISR; + uint32_t val; + + assert(IS_POWER_OF_TWO(bit_mask) && !(awaited_value & ~1U)); + + /* May timeout while TEE thread is suspended */ + while (!timeout_elapsed(timeout_ref)) { + val = io_read32(isr); + if (val & I2C_ISR_NACKF) + return -1; + if (!!(val & bit_mask) == awaited_value) + break; + } + + val = io_read32(isr); + if (val & I2C_ISR_NACKF) + return -1; + if (!!(val & bit_mask) == awaited_value) + return 0; + + notif_i2c_timeout(hi2c); + return -1; +} + /* Handle Acknowledge-Failed sequence detection during an I2C Communication */ static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t timeout_ref) { @@ -1329,6 +1356,12 @@ static int i2c_read(struct i2c_handle_s *hi2c, struct i2c_request *request, I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); } + /* Start polling for data but return if NACK indicates we should poll later */ + if (wait_isr_event_nack(hi2c, I2C_ISR_RXNE, 1, timeout_ref)) { + i2c_ack_failed(hi2c, timeout_ref); + goto bail; + } + do { if (wait_isr_event(hi2c, I2C_ISR_RXNE, 1, timeout_ref)) goto bail; diff --git a/core/drivers/stm32_rtc.c b/core/drivers/stm32_rtc.c index 79ab627e6..58bf69f2d 100644 --- a/core/drivers/stm32_rtc.c +++ b/core/drivers/stm32_rtc.c @@ -71,7 +71,7 @@ #define RTC_ICSR_RSF BIT(5) -#define RTC_PRER_PREDIV_S_MASK GENMASK_32(15, 0) +#define RTC_PRER_PREDIV_S_MASK GENMASK_32(14, 0) #define RTC_CR_BYPSHAD BIT(5) #define RTC_CR_BYPSHAD_SHIFT 5 diff --git a/core/drivers/stm32_tamp.c b/core/drivers/stm32_tamp.c new file mode 100644 index 000000000..317ca7801 --- /dev/null +++ b/core/drivers/stm32_tamp.c @@ -0,0 +1,965 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2021, STMicroelectronics + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* If psci_reset */ +#include +#include +#include /* If stm32_cores_reset() */ + +#include + +/* STM32 Registers */ +#define _TAMP_CR1 0x00U +#define _TAMP_CR2 0x04U +#define _TAMP_CR3 0x08U +#define _TAMP_FLTCR 0x0CU +#define _TAMP_ATCR1 0x10U +#define _TAMP_ATSEEDR 0x14U +#define _TAMP_ATOR 0x18U +#define _TAMP_ATCR2 0x1CU +#define _TAMP_SECCFGR 0x20U +#define _TAMP_SMCR 0x20U +#define _TAMP_PRIVCFGR 0x24U +#define _TAMP_IER 0x2CU +#define _TAMP_SR 0x30U +#define _TAMP_MISR 0x34U +#define _TAMP_SMISR 0x38U +#define _TAMP_SCR 0x3CU +#define _TAMP_COUNTR 0x40U +#define _TAMP_COUNT2R 0x44U +#define _TAMP_OR 0x50U +#define _TAMP_ERCFGR 0X54U +#define _TAMP_HWCFGR2 0x3ECU +#define _TAMP_HWCFGR1 0x3F0U +#define _TAMP_VERR 0x3F4U +#define _TAMP_IPIDR 0x3F8U +#define _TAMP_SIDR 0x3FCU + +/* _TAMP_CR1 bit filds */ +#define _TAMP_CR1_ITAMP(id) BIT((id) + 16U) +#define _TAMP_CR1_ETAMP(id) BIT((id)) + +/* _TAMP_CR2 bit filds */ +#define _TAMP_CR2_ETAMPTRG(id) BIT((id) + 24U) +#define _TAMP_CR2_BKERASE BIT(23) +#define _TAMP_CR2_BKBLOCK BIT(22) +#define _TAMP_CR2_ETAMPMSK_MAX_ID 3U +#define _TAMP_CR2_ETAMPMSK(id) BIT((id) + 16U) +#define _TAMP_CR2_ETAMPNOER(id) BIT((id)) + +/* _TAMP_CR3 bit filds */ +#define _TAMP_CR3_ITAMPNOER_ALL GENMASK_32(12, 0) +#define _TAMP_CR3_ITAMPNOER(id) BIT((id)) + +/* _TAMP_FLTCR bit fields */ +#define _TAMP_FLTCR_TAMPFREQ GENMASK_32(2, 0) +#define _TAMP_FLTCR_TAMPFLT GENMASK_32(4, 3) +#define _TAMP_FLTCR_TAMPPRCH GENMASK_32(6, 5) +#define _TAMP_FLTCR_TAMPPUDIS BIT(7) + +/* _TAMP_ATCR bit fields */ +#define _TAMP_ATCR1_ATCKSEL GENMASK_32(18, 16) +#define _TAMP_ATCR1_ATPER GENMASK_32(26, 24) +#define _TAMP_ATCR1_COMMON_MASK GENMASK_32(31, 16) +#define _TAMP_ATCR1_ETAMPAM(id) BIT((id)) +#define _TAMP_ATCR1_ATOSEL_MASK(i) GENMASK_32(((i) + 1) * 2U + 7U, \ + (i) * 2U + 8U) +#define _TAMP_ATCR1_ATOSEL(i, o) (((o) - 1U) << ((i) * 2U + 8U)) + +/* _TAMP_ATOR bit fields */ +#define _TAMP_PRNG GENMASK_32(7, 0) +#define _TAMP_SEEDF BIT(14) +#define _TAMP_INITS BIT(15) + +/* _TAMP_IER bit fields */ +#define _TAMP_IER_ITAMP(id) BIT((id) + 16U) +#define _TAMP_IER_ETAMP(id) BIT((id)) + +/* _TAMP_SR bit fields */ +#define _TAMP_SR_ETAMPXF_MASK GENMASK_32(7, 0) +#define _TAMP_SR_ITAMPXF_MASK GENMASK_32(31, 16) +#define _TAMP_SR_ITAMP(id) BIT((id) + 16U) +#define _TAMP_SR_ETAMP(id) BIT((id)) + +/* _TAMP_SCR bit fields */ +#define _TAMP_SCR_ITAMP(id) BIT((id) + 16U) +#define _TAMP_SCR_ETAMP(id) BIT((id)) + +/* _TAMP_SECCFGR bit fields */ +#define _TAMP_SECCFGR_BKPRWSEC_MASK GENMASK_32(7, 0) +#define _TAMP_SECCFGR_BKPRWSEC_SHIFT 0U +#define _TAMP_SECCFGR_CNT2SEC BIT(14) +#define _TAMP_SECCFGR_CNT1SEC BIT(15) +#define _TAMP_SECCFGR_BKPWSEC_MASK GENMASK_32(23, 16) +#define _TAMP_SECCFGR_BKPWSEC_SHIFT 16U +#define _TAMP_SECCFGR_BHKLOCK BIT(30) +#define _TAMP_SECCFGR_TAMPSEC BIT(31) + +/* _TAMP_SMCR bit fields */ +#define _TAMP_SMCR_BKPRWDPROT_MASK GENMASK_32(7, 0) +#define _TAMP_SMCR_BKPRWDPROT_SHIFT 0U +#define _TAMP_SMCR_BKPWDPROT_MASK GENMASK_32(23, 16) +#define _TAMP_SMCR_BKPWDPROT_SHIFT 16U +#define _TAMP_SMCR_DPROT BIT(31) + +/* + * _TAMP_PRIVCFGR bit fields defined in stm32_tamp.h + * See TAMP_.*PRIVILEGED + */ +#define _TAMP_PRIVCFGR_MASK (GENMASK_32(31, 29) | \ + GENMASK_32(15, 14)) + +/* _TAMP_ATCR2 bit fields */ +#define _TAMP_ATCR2_ATOSEL_MASK(i) GENMASK_32(((i) + 1) * 3U + 7U, \ + (i) * 3U + 8U) +#define _TAMP_ATCR2_ATOSEL(i, o) ((o) << ((i) * 3U + 8U)) + +/* _TAMP_OR bit fields */ +#define _TAMP_OR_IN1RMP_PF10 0U +#define _TAMP_OR_IN1RMP_PC13 BIT(0) +#define _TAMP_OR_IN2RMP_PA6 0U +#define _TAMP_OR_IN2RMP_PI1 BIT(1) +#define _TAMP_OR_IN3RMP_PC0 0U +#define _TAMP_OR_IN3RMP_PI2 BIT(2) +#define _TAMP_OR_IN4RMP_PG8 0U +#define _TAMP_OR_IN4RMP_PI3 BIT(3) + +#define _TAMP_OR_OUT3RMP_PI8 0U +#define _TAMP_OR_OUT3RMP_PC13 BIT(0) + +/* _TAMP_ERCFGR bit fields */ +#define _TAMP_ERCFGR_ERCFG0 BIT(0) + +/* _TAMP_HWCFGR2 bit fields */ +#define _TAMP_HWCFGR2_TZ GENMASK_32(11, 8) +#define _TAMP_HWCFGR2_OR GENMASK_32(7, 0) + +/* _TAMP_HWCFGR1 bit fields */ +#define _TAMP_HWCFGR1_BKPREG GENMASK_32(7, 0) +#define _TAMP_HWCFGR1_TAMPER GENMASK_32(11, 8) +#define _TAMP_HWCFGR1_ACTIVE GENMASK_32(15, 12) +#define _TAMP_HWCFGR1_INTERN GENMASK_32(31, 16) +#define _TAMP_HWCFGR1_ITAMP_MAX_ID 16U +#define _TAMP_HWCFGR1_ITAMP(id) BIT((id) + 16U) + +/* _TAMP_VERR bit fields */ +#define _TAMP_VERR_MINREV GENMASK_32(3, 0) +#define _TAMP_VERR_MAJREV GENMASK_32(7, 4) + +#define SEED_TIMEOUT_US 1000 + +struct stm32_tamp_int { + const uint32_t id; + uint32_t mode; + int (*func)(int id); +}; + +struct stm32_tamp_ext { + const uint32_t id; + uint32_t mode; + uint8_t out_pin; + int (*func)(int id); +}; + +struct stm32_tamp_instance { + struct stm32_tamp_platdata pdata; + uint32_t hwconf1; + uint32_t hwconf2; + uint32_t secret_list_conf; + uint32_t privilege_conf; + uint32_t secure_conf; + uint32_t passive_conf; + uint32_t active_conf; +}; + +struct stm32_tamp_int int_tamp_mp15[] = { + { .id = INT_TAMP1 }, { .id = INT_TAMP2 }, { .id = INT_TAMP3 }, + { .id = INT_TAMP4 }, { .id = INT_TAMP5 }, { .id = INT_TAMP8 }, +}; + +struct stm32_tamp_ext ext_tamp_mp15[] = { + { .id = EXT_TAMP1 }, { .id = EXT_TAMP2 }, { .id = EXT_TAMP3 }, +}; + +/* + * Only 1 instance of TAMP is expected per platform + * + * 0 is the expected initial values for all fields but .id + */ +static struct stm32_tamp_instance stm32_tamp = { }; +DECLARE_KEEP_PAGER(stm32_tamp); + +struct my_dt_device_match { + const char *compatible; + void *data; +}; + +static struct stm32_tamp_compat mp15_compat = { + .nb_monotonic_counter = 1, + .tags = 0, + .int_tamp = int_tamp_mp15, + .int_tamp_size = ARRAY_SIZE(int_tamp_mp15), + .ext_tamp = ext_tamp_mp15, + .ext_tamp_size = ARRAY_SIZE(ext_tamp_mp15), +}; + +static const struct my_dt_device_match tamp_match_table[] = { + { .compatible = "st,stm32-tamp", .data = &mp15_compat}, + { 0 } +}; + +static void stm32_tamp_set_secret_list(struct stm32_tamp_instance *tamp) +{ + vaddr_t base = io_pa_or_va(&tamp->pdata.base); + + if (tamp->pdata.compat && + (tamp->pdata.compat->tags & TAMP_HAS_CONF_SECRET_IPS)) { + if (tamp->secret_list_conf & TAMP_CONF_SECRET_BACKUP_SRAM) + io_setbits32(base + _TAMP_ERCFGR, _TAMP_ERCFGR_ERCFG0); + else + io_clrbits32(base + _TAMP_ERCFGR, _TAMP_ERCFGR_ERCFG0); + } +} + +static void stm32_tamp_set_secure(struct stm32_tamp_instance *tamp) +{ + vaddr_t base = io_pa_or_va(&tamp->pdata.base); + uint32_t mode = 0; + + /* Force secure mode: within OP-TEE we only access TAMP from secure */ + tamp->secure_conf |= TAMP_REGS_IT_SECURE; + mode = tamp->secure_conf; + + if (tamp->pdata.compat && + (tamp->pdata.compat->tags & TAMP_HAS_CONF_SECURE)) { + if (mode & TAMP_REGS_IT_SECURE) + io_setbits32(base + _TAMP_SECCFGR, + _TAMP_SECCFGR_TAMPSEC); + else + io_clrbits32(base + _TAMP_SECCFGR, + _TAMP_SECCFGR_TAMPSEC); + + if (mode & TAMP_CNT1_SECURE) + io_setbits32(base + _TAMP_SECCFGR, + _TAMP_SECCFGR_CNT1SEC); + else + io_clrbits32(base + _TAMP_SECCFGR, + _TAMP_SECCFGR_CNT1SEC); + + if (mode & TAMP_CNT2_SECURE) + io_setbits32(base + _TAMP_SECCFGR, + _TAMP_SECCFGR_CNT2SEC); + else + io_clrbits32(base + _TAMP_SECCFGR, + _TAMP_SECCFGR_CNT2SEC); + } else { + /* Note: MP15 doesn't use SECCFG register + * and inverts the secure bit + */ + if (mode & TAMP_REGS_IT_SECURE) + io_clrbits32(base + _TAMP_SMCR, _TAMP_SMCR_DPROT); + else + io_setbits32(base + _TAMP_SMCR, _TAMP_SMCR_DPROT); + } +} + +static void stm32_tamp_set_privilege(struct stm32_tamp_instance *tamp) +{ + vaddr_t base = io_pa_or_va(&tamp->pdata.base); + uint32_t mode = tamp->privilege_conf; + + if (tamp->pdata.compat && + (tamp->pdata.compat->tags & TAMP_HAS_CONF_PRIVILEGE)) + io_clrsetbits32(base + _TAMP_PRIVCFGR, _TAMP_PRIVCFGR_MASK, + mode & _TAMP_PRIVCFGR_MASK); +} + +static void stm32_tamp_set_pins(vaddr_t base, uint32_t mode) +{ + io_setbits32(base + _TAMP_OR, mode); +} + +static TEE_Result stm32_tamp_set_seed(vaddr_t base) +{ + /* Need RNG access. */ + uint64_t timeout_ref = timeout_init_us(SEED_TIMEOUT_US); + uint8_t idx = 0; + + for (idx = 0; idx < 4U; idx++) { + uint32_t rnd = 0; + + if (crypto_rng_read((uint8_t *)&rnd, sizeof(uint32_t)) != 0) + return TEE_ERROR_BAD_STATE; + + io_write32(base + _TAMP_ATSEEDR, rnd); + } + + while ((io_read32(base + _TAMP_ATOR) & _TAMP_SEEDF) != 0U) { + if (timeout_elapsed(timeout_ref)) + return TEE_ERROR_BAD_STATE; + } + + return TEE_SUCCESS; +} + +static bool is_int_tamp_id_valid(uint32_t id) +{ + return (id <= _TAMP_HWCFGR1_ITAMP_MAX_ID) && + (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_ITAMP(id)); +} + +static bool is_ext_tamp_id_valid(uint32_t id) +{ + return (stm32_tamp.pdata.compat) && + (id <= stm32_tamp.pdata.compat->ext_tamp_size); +} + +static TEE_Result stm32_tamp_set_int_config(struct stm32_tamp_compat *tcompat, + uint32_t itamp_index, uint32_t *cr1, + uint32_t *cr3, uint32_t *ier) +{ + uint32_t id = 0; + struct stm32_tamp_int *tamp_int = NULL; + + if (!tcompat) + return TEE_ERROR_BAD_PARAMETERS; + + tamp_int = &tcompat->int_tamp[itamp_index]; + id = tamp_int->id; + + if (!is_int_tamp_id_valid(id)) + return TEE_ERROR_BAD_PARAMETERS; + + /* If this internal tamper is disabled, reset its configuration. */ + if ((tamp_int->mode & TAMP_ENABLE) != TAMP_ENABLE) { + *cr1 &= ~_TAMP_CR1_ITAMP(id); + *ier &= ~_TAMP_IER_ITAMP(id); + if (tcompat->tags & TAMP_HAS_CR3) + *cr3 &= ~_TAMP_CR3_ITAMPNOER(id); + + return TEE_SUCCESS; + } + + *cr1 |= _TAMP_CR1_ITAMP(id); + *ier |= _TAMP_IER_ITAMP(id); + + if (tcompat->tags & TAMP_HAS_CR3) { + if ((tamp_int->mode & TAMP_NOERASE) == TAMP_NOERASE) + *cr3 |= _TAMP_CR3_ITAMPNOER(id); + else + *cr3 &= ~_TAMP_CR3_ITAMPNOER(id); + } + + return TEE_SUCCESS; +} + +static TEE_Result stm32_tamp_set_ext_config(struct stm32_tamp_compat *tcompat, + uint32_t etamp_index, + uint32_t *cr1, uint32_t *cr2, + uint32_t *atcr1, uint32_t *atcr2, + uint32_t *ier) +{ + uint32_t id = 0; + struct stm32_tamp_ext *tamp_ext = NULL; + + if (!tcompat) + return TEE_ERROR_BAD_PARAMETERS; + + tamp_ext = &tcompat->ext_tamp[etamp_index]; + id = tamp_ext->id; + + /* Exit if not a valid TAMP_ID */ + if (!is_ext_tamp_id_valid(id)) + return TEE_ERROR_BAD_PARAMETERS; + + /* If this external tamper is disabled, reset its configuration. */ + if ((tamp_ext->mode & TAMP_ENABLE) != TAMP_ENABLE) { + *cr1 &= ~_TAMP_CR1_ETAMP(id); + *cr2 &= ~_TAMP_CR2_ETAMPMSK(id); + *cr2 &= ~_TAMP_CR2_ETAMPTRG(id); + *cr2 &= ~_TAMP_CR2_ETAMPNOER(id); + *ier &= ~_TAMP_IER_ETAMP(id); + return TEE_SUCCESS; + } + + *cr1 |= _TAMP_CR1_ETAMP(id); + + if ((tamp_ext->mode & TAMP_TRIG_ON) == TAMP_TRIG_ON) + *cr2 |= _TAMP_CR2_ETAMPTRG(id); + else + *cr2 &= ~_TAMP_CR2_ETAMPTRG(id); + + if ((tamp_ext->mode & TAMP_ACTIVE) == TAMP_ACTIVE) { + *atcr1 |= _TAMP_ATCR1_ETAMPAM(id); + /* Configure output pin: + * For the case out_pin = 0, we select same output pin than the + * input one. + */ + if (tamp_ext->out_pin == TAMPOUTSEL_SAME_AS_INPUT) + tamp_ext->out_pin = id + 1; + + if (tamp_ext->out_pin <= tcompat->ext_tamp_size) { + if (tcompat->tags & TAMP_HAS_ATCR2) + *atcr2 = (*atcr2 & + ~_TAMP_ATCR2_ATOSEL_MASK(id)) | + _TAMP_ATCR2_ATOSEL(id, + tamp_ext->out_pin); + else + *atcr1 = (*atcr1 & + ~_TAMP_ATCR1_ATOSEL_MASK(id)) | + _TAMP_ATCR1_ATOSEL(id, + tamp_ext->out_pin); + } + } else { + *atcr1 &= ~_TAMP_ATCR1_ETAMPAM(id); + } + + if ((tamp_ext->mode & TAMP_NOERASE) == TAMP_NOERASE) + *cr2 |= _TAMP_CR2_ETAMPNOER(id); + else + *cr2 &= ~_TAMP_CR2_ETAMPNOER(id); + + if (id < _TAMP_CR2_ETAMPMSK_MAX_ID) { + /* + * Only external TAMP 1, 2 and 3 can be masked + */ + if ((tamp_ext->mode & TAMP_EVT_MASK) == TAMP_EVT_MASK) { + /* + * ETAMP(id) event generates a trigger event. This + * ETAMP(id) is masked and internally cleared by + * hardware. + * The secrets are not erased. + */ + *ier &= ~_TAMP_IER_ETAMP(id); + *cr2 |= _TAMP_CR2_ETAMPMSK(id); + } else { + /* + * normal ETAMP interrupt: + * ETAMP(id) event generates a trigger event and + * TAMP(id) must be cleared by software to allow + * next tamper event detection. + */ + *cr2 &= ~_TAMP_CR2_ETAMPMSK(id); + *ier |= _TAMP_IER_ETAMP(id); + } + } else { + /* Other than 1,2,3 external TAMP, we want its interruption */ + *ier |= _TAMP_IER_ETAMP(id); + } + + return TEE_SUCCESS; +} + +TEE_Result stm32_tamp_set_secure_bkpregs(struct stm32_bkpregs_conf *bkr_conf) +{ + uint32_t first_z2 = 0; + uint32_t first_z3 = 0; + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + if (!bkr_conf) + return TEE_ERROR_BAD_PARAMETERS; + + first_z2 = bkr_conf->nb_zone1_regs; + first_z3 = bkr_conf->nb_zone1_regs + bkr_conf->nb_zone2_regs; + + if ((first_z2 > (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_BKPREG)) || + (first_z3 > (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_BKPREG))) + return TEE_ERROR_NOT_SUPPORTED; + + if (stm32_tamp.pdata.compat && + (stm32_tamp.pdata.compat->tags & TAMP_HAS_CONF_SECURE)) { + io_clrsetbits32(base + _TAMP_SECCFGR, + _TAMP_SECCFGR_BKPRWSEC_MASK, + (first_z2 << _TAMP_SECCFGR_BKPRWSEC_SHIFT) & + _TAMP_SECCFGR_BKPRWSEC_MASK); + + io_clrsetbits32(base + _TAMP_SECCFGR, + _TAMP_SECCFGR_BKPWSEC_MASK, + (first_z3 << _TAMP_SECCFGR_BKPWSEC_SHIFT) & + _TAMP_SECCFGR_BKPWSEC_MASK); + } else { + io_clrsetbits32(base + _TAMP_SMCR, + _TAMP_SMCR_BKPRWDPROT_MASK, + (first_z2 << _TAMP_SMCR_BKPRWDPROT_SHIFT) & + _TAMP_SMCR_BKPRWDPROT_MASK); + + io_clrsetbits32(base + _TAMP_SMCR, + _TAMP_SMCR_BKPWDPROT_MASK, + (first_z3 << _TAMP_SMCR_BKPWDPROT_SHIFT) & + _TAMP_SMCR_BKPWDPROT_MASK); + } + + return TEE_SUCCESS; +} + +TEE_Result stm32_tamp_set_config(void) +{ + int ret = TEE_SUCCESS; + uint32_t i = 0; + uint32_t cr1 = 0; + uint32_t cr2 = 0; + uint32_t cr3 = 0; + uint32_t atcr1 = 0; + uint32_t atcr2 = 0; + uint32_t fltcr = 0; + uint32_t ier = 0; + + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + if (!stm32_tamp.pdata.compat || + !stm32_tamp.pdata.compat->int_tamp || + !stm32_tamp.pdata.compat->ext_tamp) + return TEE_ERROR_BAD_STATE; + + /* Select extra IP to add in the deleted/blocked IP in case of + * tamper event + */ + stm32_tamp_set_secret_list(&stm32_tamp); + + /* Select access in secure or unsecure */ + stm32_tamp_set_secure(&stm32_tamp); + + /* Select access in privileged mode or unprivileged mode */ + stm32_tamp_set_privilege(&stm32_tamp); + + /* Set passive filter configuration */ + if (stm32_tamp.passive_conf != 0U) + fltcr = stm32_tamp.passive_conf; + + /* Set active mode configuration */ + if (stm32_tamp.active_conf != 0U) + atcr1 = (atcr1 & ~_TAMP_ATCR1_COMMON_MASK) | + (stm32_tamp.active_conf & _TAMP_ATCR1_COMMON_MASK); + + for (i = 0U; i < stm32_tamp.pdata.compat->int_tamp_size; i++) { + ret = stm32_tamp_set_int_config(stm32_tamp.pdata.compat, i, + &cr1, &cr3, &ier); + if (ret != 0) + return ret; + } + + for (i = 0U; i < stm32_tamp.pdata.compat->ext_tamp_size; i++) { + ret = stm32_tamp_set_ext_config(stm32_tamp.pdata.compat, i, + &cr1, &cr2, &atcr1, &atcr2, + &ier); + if (ret != 0) + return ret; + } + + /* + * We apply configuration all in a row: + * As for active ext tamper "all the needed tampers must be enabled in + * the same write access". + */ + io_write32(base + _TAMP_FLTCR, fltcr); + /* Active filter configuration applied only if not already done. */ + if (((io_read32(base + _TAMP_ATOR) & _TAMP_INITS) != _TAMP_INITS)) { + io_write32(base + _TAMP_ATCR1, atcr1); + if (stm32_tamp.pdata.compat->tags & TAMP_HAS_ATCR2) + io_write32(base + _TAMP_ATCR2, atcr2); + } + + io_write32(base + _TAMP_CR1, cr1); + io_write32(base + _TAMP_CR2, cr2); + if (stm32_tamp.pdata.compat->tags & TAMP_HAS_CR3) + io_write32(base + _TAMP_CR3, cr3); + + /* If active tamper we reinit the seed. */ + if (stm32_tamp.active_conf != 0U) { + if (stm32_tamp_set_seed(base) != TEE_SUCCESS) { + EMSG("Active tamper: SEED not initialized"); + return TEE_ERROR_BAD_STATE; + } + } + + /* Enable interrupts. */ + io_write32(base + _TAMP_IER, ier); + + return TEE_SUCCESS; +} + +TEE_Result stm32_tamp_write_mcounter(int cnt_idx) +{ + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + if (cnt_idx < 0 || !stm32_tamp.pdata.compat || + cnt_idx > stm32_tamp.pdata.compat->nb_monotonic_counter) + return TEE_ERROR_BAD_PARAMETERS; + + io_write32(base + _TAMP_COUNTR + cnt_idx * sizeof(uint32_t), 1U); + + return TEE_SUCCESS; +} + +uint32_t stm32_tamp_read_mcounter(int cnt_idx) +{ + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + if (cnt_idx < 0 || !stm32_tamp.pdata.compat || + cnt_idx > stm32_tamp.pdata.compat->nb_monotonic_counter) + return 0U; + + return io_read32(base + _TAMP_COUNTR + cnt_idx * sizeof(uint32_t)); +} + +void stm32_tamp_configure_secret_list(uint32_t secret_list_conf) +{ + stm32_tamp.secret_list_conf = secret_list_conf; +} + +void stm32_tamp_configure_privilege_access(uint32_t privilege_conf) +{ + stm32_tamp.privilege_conf = privilege_conf; +} + +void stm32_tamp_configure_secure_access(uint32_t secure_conf) +{ + stm32_tamp.secure_conf = secure_conf; +} + +void stm32_tamp_configure_passive(uint32_t passive_conf) +{ + stm32_tamp.passive_conf = passive_conf; +} + +void stm32_tamp_configure_active(uint32_t active_conf) +{ + stm32_tamp.active_conf = active_conf; +} + +TEE_Result stm32_tamp_configure_internal(enum stm32_tamp_int_id id, + uint32_t mode, + int (*callback)(int id)) +{ + uint32_t i = 0; + uint32_t itamp_id = id; + struct stm32_tamp_int *tamp_int = NULL; + + if (!stm32_tamp.pdata.compat) + return TEE_ERROR_BAD_STATE; + + /* Find internal Tamp struct*/ + for (i = 0U; i < stm32_tamp.pdata.compat->int_tamp_size; i++) { + if (stm32_tamp.pdata.compat->int_tamp[i].id == itamp_id) { + tamp_int = &stm32_tamp.pdata.compat->int_tamp[i]; + break; + } + } + + if (!tamp_int) + return TEE_ERROR_BAD_PARAMETERS; + + tamp_int->mode = mode; + tamp_int->func = callback; + + return TEE_SUCCESS; +} + +TEE_Result stm32_tamp_configure_external(enum stm32_tamp_ext_id id, + uint32_t mode, + enum stm32_tamp_ext_out_id out_pin, + int (*callback)(int id)) +{ + uint32_t i = 0; + uint32_t etamp_id = id; + struct stm32_tamp_ext *tamp_ext = NULL; + + if (!stm32_tamp.pdata.compat) + return TEE_ERROR_BAD_STATE; + + /* Find external Tamp struct */ + for (i = 0U; i < stm32_tamp.pdata.compat->ext_tamp_size; i++) { + if (stm32_tamp.pdata.compat->ext_tamp[i].id == etamp_id) { + tamp_ext = &stm32_tamp.pdata.compat->ext_tamp[i]; + break; + } + } + + if (!tamp_ext) + return TEE_ERROR_BAD_PARAMETERS; + + tamp_ext->mode = mode; + tamp_ext->out_pin = out_pin; + tamp_ext->func = callback; + + return TEE_SUCCESS; +} + +bool stm32_tamp_are_secrets_blocked(void) +{ + if (stm32_tamp.pdata.compat && + (stm32_tamp.pdata.compat->tags & TAMP_HAS_SECRET_STATUS)) { + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + return (((io_read32(base + _TAMP_CR2) & + _TAMP_CR2_BKBLOCK) == _TAMP_CR2_BKBLOCK) || + (io_read32(base + _TAMP_SR) != 0)); + } else { + return false; + } +} + +void stm32_tamp_block_secrets(void) +{ + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + if (stm32_tamp.pdata.compat && + (stm32_tamp.pdata.compat->tags & TAMP_HAS_SECRET_STATUS)) + io_setbits32(base + _TAMP_CR2, _TAMP_CR2_BKBLOCK); +} + +void stm32_tamp_unblock_secrets(void) +{ + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + if (stm32_tamp.pdata.compat && + (stm32_tamp.pdata.compat->tags & TAMP_HAS_SECRET_STATUS)) + io_clrbits32(base + _TAMP_CR2, _TAMP_CR2_BKBLOCK); +} + +void stm32_tamp_erase_secrets(void) +{ + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + if (stm32_tamp.pdata.compat && + (stm32_tamp.pdata.compat->tags & TAMP_HAS_SECRET_STATUS)) + io_setbits32(base + _TAMP_CR2, _TAMP_CR2_BKERASE); +} + +void stm32_tamp_lock_boot_hardware_key(void) +{ + vaddr_t base = io_pa_or_va(&stm32_tamp.pdata.base); + + if (stm32_tamp.pdata.compat && + (stm32_tamp.pdata.compat->tags & TAMP_HAS_LOCK_KEY)) + io_setbits32(base + _TAMP_SECCFGR, _TAMP_SECCFGR_BHKLOCK); +} + +static enum itr_return stm32_tamp_it_handler(struct itr_handler *h) +{ + struct stm32_tamp_instance *tamp = h->data; + vaddr_t base = io_pa_or_va(&tamp->pdata.base); + uint32_t it = io_read32(base + _TAMP_SR); + uint32_t int_it = it & _TAMP_SR_ITAMPXF_MASK; + uint32_t ext_it = it & _TAMP_SR_ETAMPXF_MASK; + uint8_t i = 0; + struct stm32_rtc_time tamp_ts = { }; + + if (stm32_rtc_is_timestamp_enable()) { + stm32_rtc_get_timestamp(&tamp_ts); + FMSG("Tamper Event Occurred"); + FMSG("Date : %u/%u\n \t Time : %u:%u:%u", + tamp_ts.day, tamp_ts.month, tamp_ts.hour, + tamp_ts.min, tamp_ts.sec); + } + + while ((int_it != 0U) && (i < stm32_tamp.pdata.compat->int_tamp_size)) { + int ret = -1; + uint32_t id = tamp->pdata.compat->int_tamp[i].id; + + if ((it & _TAMP_SR_ITAMP(id)) != 0U) { + if (tamp->pdata.compat->int_tamp[i].func) + ret = tamp->pdata.compat->int_tamp[i].func(id); + + if (ret >= 0) { + io_setbits32(base + _TAMP_SCR, + _TAMP_SR_ITAMP(id)); + ext_it &= ~_TAMP_SR_ITAMP(id); + + if (ret > 0) { +#ifdef CFG_PM + stm32_cores_reset(); +#else + psci_system_reset(); +#endif + } + } + } + i++; + } + + i = 0; + /* External tamper interrupt */ + while ((ext_it != 0U) && (i < stm32_tamp.pdata.compat->ext_tamp_size)) { + int ret = -1; + uint32_t id = tamp->pdata.compat->ext_tamp[i].id; + + if ((ext_it & _TAMP_SR_ETAMP(id)) != 0U) { + if (tamp->pdata.compat->ext_tamp[i].func) + ret = tamp->pdata.compat->ext_tamp[i].func(id); + + if (ret >= 0) { + io_setbits32(base + _TAMP_SCR, + _TAMP_SCR_ETAMP(id)); + ext_it &= ~_TAMP_SR_ETAMP(id); + + if (ret > 0) { +#ifdef CFG_PM + stm32_cores_reset(); +#else + psci_system_reset(); +#endif + } + } + } + i++; + } + + return ITRR_HANDLED; +} + +#ifdef CFG_DT +static int get_node_from_multiple_compatible(const void *fdt, + struct stm32_tamp_platdata *pdata) +{ + const struct my_dt_device_match *cur = tamp_match_table; + + while (cur->compatible) { + int node = -1; + + node = fdt_node_offset_by_compatible(fdt, node, + cur->compatible); + if (node >= 0) { + pdata->compat = (struct stm32_tamp_compat *)cur->data; + return node; + } + + cur++; + } + + /* Compatible string not found */ + return -1; +} + +static int stm32_tamp_parse_fdt(struct stm32_tamp_platdata *pdata) +{ + int node = -1; + struct dt_node_info dt_tamp = { }; + void *fdt = NULL; + + fdt = get_embedded_dt(); + if (!fdt) + return -1; + + node = get_node_from_multiple_compatible(fdt, pdata); + if (node < 0) + return -1; + + _fdt_fill_device_info(fdt, &dt_tamp, node); + + if (dt_tamp.status == DT_STATUS_DISABLED || + dt_tamp.clock == DT_INFO_INVALID_CLOCK || + dt_tamp.reg == DT_INFO_INVALID_REG || + dt_tamp.interrupt == DT_INFO_INVALID_INTERRUPT) { + return -1; + } + + pdata->it = dt_tamp.interrupt; + pdata->base.pa = dt_tamp.reg; + pdata->base.va = (vaddr_t)phys_to_virt(dt_tamp.reg, MEM_AREA_IO_SEC); + + pdata->clock = dt_tamp.clock; + + pdata->pins_conf = 0; + if (stm32_pinctrl_fdt_get_pinctrl(fdt, node, NULL, 0) > 0) { + if (pdata->compat == &mp15_compat) { + if (fdt_getprop(fdt, node, "st,out3-pc13", NULL)) + pdata->pins_conf |= _TAMP_OR_OUT3RMP_PC13; + } + } + + if (fdt_getprop(fdt, node, "wakeup-source", NULL)) + pdata->is_wakeup_source = true; + + return 0; +} + +__weak +int stm32_tamp_get_platdata(struct stm32_tamp_platdata *pdata __unused) +{ + /* In DT config, the platform data are filled by DT file */ + return 0; +} +#else /* CFG_DT */ +static int stm32_tamp_parse_fdt(struct stm32_tamp_platdata *pdata) +{ + /* Do nothing, there is no fdt to parse in this case */ + return 0; +} + +/* This function can be overridden by platform to define pdata of tamp driver */ +__weak +int stm32_tamp_get_platdata(struct stm32_tamp_platdata *pdata __unused) +{ + return -1; +} +#endif /* CFG_DT */ + +static struct itr_handler stm32_tamp_itr_handler = { + .handler = stm32_tamp_it_handler, +}; +DECLARE_KEEP_PAGER(stm32_tamp_itr_handler); + +static TEE_Result stm32_tamp_init(void) +{ + int ret = TEE_SUCCESS; + vaddr_t base = 0; + uint32_t __unused rev = 0; + + ret = stm32_tamp_get_platdata(&stm32_tamp.pdata); + if (ret) + return TEE_ERROR_NOT_SUPPORTED; + + ret = stm32_tamp_parse_fdt(&stm32_tamp.pdata); + if (ret) + return TEE_ERROR_NOT_SUPPORTED; + + /* Init Tamp clock */ + clk_enable(stm32_tamp.pdata.clock); + + base = io_pa_or_va(&stm32_tamp.pdata.base); + + stm32_tamp.hwconf1 = io_read32(base + _TAMP_HWCFGR1); + stm32_tamp.hwconf2 = io_read32(base + _TAMP_HWCFGR2); + +#if TRACE_LEVEL >= TRACE_FLOW + rev = io_read32(base + _TAMP_VERR); + FMSG("STM32 TAMPER V%u.%u", (rev & _TAMP_VERR_MAJREV) >> 4, + rev & _TAMP_VERR_MINREV); +#endif + + if ((stm32_tamp.hwconf2 & _TAMP_HWCFGR2_TZ) == 0U) { + EMSG("Tamper IP doesn't support trustzone"); + return TEE_ERROR_NOT_SUPPORTED; + } + + stm32_tamp_set_pins(base, stm32_tamp.pdata.pins_conf); + + stm32_tamp_itr_handler.it = stm32_tamp.pdata.it; + stm32_tamp_itr_handler.data = &stm32_tamp; + itr_add(&stm32_tamp_itr_handler); + itr_enable(stm32_tamp_itr_handler.it); + + /* Need a new API */ + if (stm32_tamp.pdata.is_wakeup_source) + IMSG("TAMP event are not configured as wakeup source"); + + return TEE_SUCCESS; +} + +driver_init(stm32_tamp_init); diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk index 0d3b81e21..10a641b9d 100644 --- a/core/drivers/sub.mk +++ b/core/drivers/sub.mk @@ -30,6 +30,7 @@ srcs-$(CFG_STM32_IWDG) += stm32_iwdg.c srcs-$(CFG_STM32_RNG) += stm32_rng.c srcs-$(CFG_STM32_RTC) += stm32_rtc.c srcs-$(CFG_STM32_TIM) += stm32_tim.c +srcs-$(CFG_STM32_TAMP) += stm32_tamp.c srcs-$(CFG_STM32_UART) += stm32_uart.c srcs-$(CFG_STPMIC1) += stpmic1.c srcs-$(CFG_BCM_HWRNG) += bcm_hwrng.c diff --git a/core/include/drivers/stm32_tamp.h b/core/include/drivers/stm32_tamp.h new file mode 100644 index 000000000..556cd136d --- /dev/null +++ b/core/include/drivers/stm32_tamp.h @@ -0,0 +1,378 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2021, STMicroelectronics + */ + +#ifndef __STM32_TAMP_H__ +#define __STM32_TAMP_H__ + +#include +#include +#include +#include +#include + +/* Internal Tamper */ +enum stm32_tamp_int_id { + INT_TAMP1 = 0, + INT_TAMP2, + INT_TAMP3, + INT_TAMP4, + INT_TAMP5, + INT_TAMP6, + INT_TAMP7, + INT_TAMP8, + INT_TAMP9, + INT_TAMP10, + INT_TAMP11, + INT_TAMP12, + INT_TAMP13, + INT_TAMP14, + INT_TAMP15, + INT_TAMP16 +}; + +/* External Tamper */ +enum stm32_tamp_ext_id { + EXT_TAMP1 = 0, + EXT_TAMP2, + EXT_TAMP3, + EXT_TAMP4, + EXT_TAMP5, + EXT_TAMP6, + EXT_TAMP7, + EXT_TAMP8 +}; + +/* Out pin to compare for external Tamper */ +enum stm32_tamp_ext_out_id { + TAMPOUTSEL_SAME_AS_INPUT = 0, + TAMPOUTSEL1, + TAMPOUTSEL2, + TAMPOUTSEL3, + TAMPOUTSEL4, + TAMPOUTSEL5, + TAMPOUTSEL6, + TAMPOUTSEL7, + TAMPOUTSEL8, +}; + +/* + * Define number of backup registers in zone 1 and zone 2 (remaining are in + * zone 3) + * + * backup registers in zone 1 : read/write only in secure mode + * zone 2 : write only in secure mode, read in secure + * and non-secure mode + * zone 3 : read/write in secure and non-secure mode + * + * Protection zone 1 if nb_zone1_regs == 0 no backup register are in zone 1 + * else backup registers from TAMP_BKP0R to TAMP_BKPxR + * with x = nb_zone1_regs - 1 are in zone 1. + * Protection zone 2 if nb_zone2_regs == 0 no backup register are in zone 2 + * else backup registers from + * TAMP_BKPyR with y = nb_zone1_regs + * to + * TAMP_BKPzR with z = (nb_zone1_regs1 + nb_zone2_regs - 1) + * are in zone 2. + * Protection zone 3 backup registers from TAMP_BKPtR + * with t = nb_zone1_regs1 + nb_zone2_regs to last backup + * register are in zone 3. + */ +struct stm32_bkpregs_conf { + uint32_t nb_zone1_regs; + uint32_t nb_zone2_regs; +}; + +/* Define TAMPER modes */ +#define TAMP_DISABLE 0x0U +#define TAMP_ENABLE 0x1U +#define TAMP_TRIG_OFF 0x0U +#define TAMP_TRIG_ON 0x2U +#define TAMP_PASSIVE 0x0U +#define TAMP_ACTIVE 0x4U +#define TAMP_ERASE 0x0U +#define TAMP_NOERASE 0x8U +#define TAMP_NO_EVT_MASK 0x0U +#define TAMP_EVT_MASK 0x10U + +/* Define Passive FILTER mode */ +#define TAMP_FILTER_TAMPPUDIS_OFFSET 7U +#define TAMP_FILTER_PRECHARGE (0x0U << TAMP_FILTER_TAMPPUDIS_OFFSET) +#define TAMP_FILTER_PULL_UP_DISABLE (0x1U << TAMP_FILTER_TAMPPUDIS_OFFSET) +#define TAMP_FILTER_TAMPPRCH_OFFSET 5U +#define TAMP_FILTER_PRECHARGE_1_CYCLE (0x0U << TAMP_FILTER_TAMPPRCH_OFFSET) +#define TAMP_FILTER_PRECHARGE_2_CYCLES (0x1U << TAMP_FILTER_TAMPPRCH_OFFSET) +#define TAMP_FILTER_PRECHARGE_4_CYCLES (0x2U << TAMP_FILTER_TAMPPRCH_OFFSET) +#define TAMP_FILTER_PRECHARGE_8_CYCLES (0x3U << TAMP_FILTER_TAMPPRCH_OFFSET) +#define TAMP_FILTER_TAMPFLT_OFFSET 3U +#define TAMP_FILTER_EDGE (0x0U << TAMP_FILTER_TAMPFLT_OFFSET) +#define TAMP_FILTER_2_SAMPLE (0x1U << TAMP_FILTER_TAMPFLT_OFFSET) +#define TAMP_FILTER_4_SAMPLE (0x2U << TAMP_FILTER_TAMPFLT_OFFSET) +#define TAMP_FILTER_8_SAMPLE (0x3U << TAMP_FILTER_TAMPFLT_OFFSET) +#define TAMP_FILTER_TAMPFREQ_OFFSET 0U +#define TAMP_FILTER_SAMPLING_32768 (0x0U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_16384 (0x1U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_8192 (0x2U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_4096 (0x3U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_2048 (0x4U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_1024 (0x5U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_512 (0x6U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_256 (0x7U << TAMP_FILTER_TAMPFREQ_OFFSET) + +/* Define active filter */ +#define TAMP_ACTIVE_FLTEN_OFFSET 31U +#define TAMP_ACTIVE_FILTER_OFF (0x0U << TAMP_ACTIVE_FLTEN_OFFSET) +#define TAMP_ACTIVE_FILTER_ON (0x1U << TAMP_ACTIVE_FLTEN_OFFSET) +#define TAMP_ACTIVE_ATOSHARE_OFFSET 30U +#define TAMP_ACTIVE_USE_DEDICATED_OUT (0x0U << \ + TAMP_ACTIVE_FILTER_ATOSHARE_OFFSET) +#define TAMP_ACTIVE_SELECT_OUT (0x1U << \ + TAMP_ACTIVE_FILTER_ATOSHARE_OFFSET) +#define TAMP_ACTIVE_ATPER_OFFSET 24U +#define TAMP_ACTIVE_ATPER_1_OUTPUT (0x0U << TAMP_ACTIVE_ATPER_OFFSET) +#define TAMP_ACTIVE_ATPER_2_OUTPUTS (0x1U << TAMP_ACTIVE_ATPER_OFFSET) +#define TAMP_ACTIVE_ATPER_3_4_OUTPUTS (0x2U << TAMP_ACTIVE_ATPER_OFFSET) +#define TAMP_ACTIVE_ATPER_5_OUTPUTS (0x3U << TAMP_ACTIVE_ATPER_OFFSET) +#define TAMP_ACTIVE_ATCKSEL_OFFSET 16U +#define TAMP_ACTIVE_CKSEL_DIV_0 (0x0U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_2 (0x1U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_4 (0x2U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_8 (0x3U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_16 (0x4U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_32 (0x5U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_64 (0x6U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_128 (0x7U << TAMP_ACTIVE_ATCKSEL_OFFSET) + +/* Define device secret list */ +#define TAMP_NON_CONFIGURABLE_SECRETS 0x0U +#define TAMP_CONF_SECRET_BACKUP_SRAM 0x1U + +/* Define secure mode access */ +/* + * Tamper configuration and interrupt can be written when the APB access is + * secure or nonsecure. + */ +#define TAMP_REGS_IT_UNSECURE 0U +/* + * Tamper configuration and interrupt can be written only when the APB access + * is secure. + */ +#define TAMP_REGS_IT_SECURE BIT(31) +/* + * Tamper monotonic counter 1 can be written when the APB access is secure or + * nonsecure. + */ +#define TAMP_CNT1_UNSECURE 0U +/* + * Tamper monotonic counter 3 can be written only when the APB access is + * secure. + */ +#define TAMP_CNT1_SECURE BIT(15) +/* + * Tamper monotonic counter 2 can be written when the APB access is secure or + * nonsecure. + */ +#define TAMP_CNT2_UNSECURE 0U +/* + * Tamper monotonic counter 3 can be written only when the APB access is + * secure. + */ +#define TAMP_CNT2_SECURE BIT(14) + +/* Define privilege mode access */ +/* + * Tamper registers (but backup and cnt) can be written with privileged or + * unprivileged access. + */ +#define TAMP_REGS_UNPRIVILEGE 0U +/* + * Tamper registers (but backupand cnt) can be written only with privileged + * access. + */ +#define TAMP_REGS_PRIVILEGE BIT(31) +/* + * Backup registers zone 2 can be written with privileged or unprivileged + * access. + */ +#define TAMP_BKP2W_UNPRIVILEGE 0U +/* Backup registers zone 2 can be written only with privileged access. */ +#define TAMP_BKP2W_PRIVILEGE BIT(30) +/* + * Backup registers zone 1 can be read and written with privileged or + * unprivileged access. + */ +#define TAMP_BKP1RW_UNPRIVILEGE 0U +/* + * Backup registers zone 1 can be read and written only with privileged + * access. + */ +#define TAMP_BKP1RW_PRIVILEGE BIT(29) +/* + * Monotonic counter 1 can be read and written with privileged or unprivileged + * access. + */ +#define TAMP_CNT1_UNPRIVILEGE 0U +/* Monotonic counter 1 can be read and written only with privileged access. */ +#define TAMP_CNT1_PRIVILEGE BIT(15) +/* + * Monotonic counter 2 can be read and written with privileged or unprivileged + * access. + */ +#define TAMP_CNT2_UNPRIVILEGE 0U +/* Monotonic counter 2 can be read and written only with privileged access. */ +#define TAMP_CNT2_PRIVILEGE BIT(14) + +/* + * stm32_tamp_write_mcounter : Increase monotonic counter[counter_idx]. + */ +TEE_Result stm32_tamp_write_mcounter(int counter_idx); +uint32_t stm32_tamp_read_mcounter(int counter_idx); + +bool stm32_tamp_are_secrets_blocked(void); +void stm32_tamp_block_secrets(void); +void stm32_tamp_unblock_secrets(void); +void stm32_tamp_erase_secrets(void); +void stm32_tamp_lock_boot_hardware_key(void); + +/* + * stm32_tamp_configure_secret_list: Configure which extra IPs + * are blocked/erased in case of tamper event. + * + * secret_list_conf is a bit field from TAMP_CONF_SECRET_.* + */ +void stm32_tamp_configure_secret_list(uint32_t secret_list_conf); + +/* + * stm32_tamp_configure_secure_access: Configure which registers can be + * read/write from unsecure world. + * secure_conf is a bit field from TAMP_.*_{UN,}SECURE define + */ +void stm32_tamp_configure_secure_access(uint32_t secure_conf); + +/* + * stm32_tamp_configure_privilege_access: Configure which registers can be + * read/write from unpriviliged world. + * privilege_conf is a bit field from TAMP_.*_{UN,}PRIVILEGE define + */ +void stm32_tamp_configure_privilege_access(uint32_t privilege_conf); + +/* + * stm32_tamp_configure_passive: Configure passive mode + * passive_conf is a bit field from TAMP_FILTER_* define + */ +void stm32_tamp_configure_passive(uint32_t passive_conf); + +/* + * stm32_tamp_configure_ctive: Configure active mode + * passive_conf is a bit field from TAMP_ACTIVE_* define + */ +void stm32_tamp_configure_active(uint32_t active_conf); + +/* + * stm32_tamp_configure_internal: Configure one internal tamper. + * id: internal tamper id + * mode: bitmask from TAMPER modes define + * callback: function to call when tamper is raised (can be NULL), + * called in interrupt context, + * if callback returns negative value, blocked secrets stay blocked + * (driver doesn't release this specific tamper). + * if callback returns 0 this specific tamp is ack (in case of + * no-erase tamper, blocked secret are unblocked) + * if callback returns positive value, this specific tamp is ack (in + * case of no-erase tamper, blocked secret are unblocked) and system + * is rebooted). + * + * return: TEE_BAD_PARAMETERS if 'id' is not a valid internal tamp id, + * else TEE_SUCCESS. + */ +TEE_Result stm32_tamp_configure_internal(enum stm32_tamp_int_id id, + uint32_t mode, + int (*callback)(int id)); + +/* + * stm32_tamp_configure_external: Configure one external tamper. + * id: external tamper id + * mode: bitmask from TAMPER modes define + * pin_out; output pin connected to input pin (linekd with selected ext tamp id) + * callback: function to call when tamper is raised (can be NULL), + * called in interrupt context, + * if callback returns negative value, blocked secrets stay blocked + * (driver doesn't release this specific tamper). + * if callback returns 0 this specific tamp is ack (in case of + * no-erase tamper, blocked secret are unblocked) + * if callback returns positive value, this specific tamp is ack (in + * case of no-erase tamper, blocked secret are unblocked) and system + * is rebooted). + * + * return: TEE_BAD_PARAMETERS if 'id' is not a valid external tamp id, + * else TEE_SUCCESS. + */ +TEE_Result stm32_tamp_configure_external(enum stm32_tamp_ext_id id, + uint32_t mode, + enum stm32_tamp_ext_out_id out_pin, + int (*callback)(int id)); + +/* + * stm32_tamp_set_secure_bkprwregs : Configure backup registers zone. + * registers in zone 1 : read/write only in secure mode + * zone 2 : write only in secure mode, read in secure and + * non-secure mode + * zone 3 : read/write in secure and non-secure mode + * + * bkpregs_conf : a pointer to struct bkpregs_conf that define the number of + * registers in zone 1 and zone 2 (remaining backup registers will be in + * zone 3). + * + * return TEE_ERROR_NOT_SUPPORTED: if zone 1 and/or zone 2 definition are out + * of range. + * TEE_ERROR_BAD_PARAMETERS: if bkpregs_cond is NULL. + * TEE_SUCCESS : if OK. + */ +TEE_Result stm32_tamp_set_secure_bkpregs(struct stm32_bkpregs_conf + *bkpregs_conf); + +/* + * stm32_tamp_set_config: Apply configuration. + * Default one if no previous call to any of : + * stm32_tamp_configure_passive() + * stm32_tamp_configure_active() + * stm32_tamp_configure_internal() + * stm32_tamp_configure_external() + * stm32_tamp_configure_secret_list() + * stm32_tamp_configure_secure_access() + * stm32_tamp_configure_privilege_access() + * + */ +TEE_Result stm32_tamp_set_config(void); + +/* Compatibility tags */ +#define TAMP_HAS_CONF_SECURE BIT(0) +#define TAMP_HAS_CONF_PRIVILEGE BIT(1) +#define TAMP_HAS_CONF_SECRET_IPS BIT(2) +#define TAMP_HAS_ATCR2 BIT(3) +#define TAMP_HAS_CR3 BIT(4) +#define TAMP_HAS_SECRET_STATUS BIT(5) +#define TAMP_HAS_LOCK_KEY BIT(6) + +struct stm32_tamp_compat { + int nb_monotonic_counter; + uint32_t tags; + struct stm32_tamp_int *int_tamp; + uint32_t int_tamp_size; + struct stm32_tamp_ext *ext_tamp; + uint32_t ext_tamp_size; +}; + +struct stm32_tamp_platdata { + struct io_pa_va base; + uint32_t clock; + int it; + uint32_t pins_conf; + bool is_wakeup_source; + struct stm32_tamp_compat *compat; +}; + +int stm32_tamp_get_platdata(struct stm32_tamp_platdata *pdata); + +#endif /* __STM32_TAMP_H__ */ diff --git a/core/include/kernel/dt.h b/core/include/kernel/dt.h index 3044989c7..e9f816488 100644 --- a/core/include/kernel/dt.h +++ b/core/include/kernel/dt.h @@ -31,12 +31,15 @@ * @reg: Device register physical base address or DT_INFO_INVALID_REG * @clock: Device identifier (positive value) or DT_INFO_INVALID_CLOCK * @reset: Device reset identifier (positive value) or DT_INFO_INVALID_CLOCK + * @interrupt: Device interrupt identifier (positive value) or + * DT_INFO_INVALID_INTERRUPT */ struct dt_node_info { unsigned int status; paddr_t reg; int clock; int reset; + int interrupt; }; #if defined(CFG_DT) @@ -96,18 +99,6 @@ int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size); */ bool dt_have_prop(const void *fdt, int offs, const char *propname); -/* - * Get the DT interrupt property of the @node. In the DT an interrupt - * is defined with at least 2x32 bits detailling the interrupt number and type. - * - * @fdt reference to the Device Tree - * @node is the node offset to read - * - * Returns the interrupt number if value >= 0 - * otherwise DT_INFO_INVALID_INTERRUPT - */ -int dt_get_irq(void *fdt, int node); - /* * Modify or add "status" property to "disabled" * diff --git a/core/include/kernel/interrupt.h b/core/include/kernel/interrupt.h index 796eded29..4a0b4474b 100644 --- a/core/include/kernel/interrupt.h +++ b/core/include/kernel/interrupt.h @@ -14,6 +14,7 @@ struct itr_chip { const struct itr_ops *ops; + int (*dt_get_irq)(const uint32_t *properties, int len); }; struct itr_ops { @@ -48,6 +49,30 @@ struct itr_handler { void itr_init(struct itr_chip *data); void itr_handle(size_t it); +#ifdef CFG_DT +/* + * Get the DT interrupt property at @node. In the DT an interrupt + * + * @fdt reference to the Device Tree + * @node is the node offset to read + * + * Returns the interrupt number if value >= 0 + * otherwise DT_INFO_INVALID_INTERRUPT + */ +int dt_get_irq(const void *fdt, int node); + +/* + * Get the DT secure-interrupt property at @node. + * + * @fdt reference to the Device Tree + * @node is the node offset to read + * + * Returns the interrupt number if value >= 0 + * otherwise DT_INFO_INVALID_INTERRUPT + */ +int dt_get_irq_secure(const void *fdt, int node); +#endif + void itr_add(struct itr_handler *handler); void itr_enable(size_t it); void itr_disable(size_t it); diff --git a/core/kernel/dt.c b/core/kernel/dt.c index fcfa26929..4410bf52b 100644 --- a/core/kernel/dt.c +++ b/core/kernel/dt.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -51,27 +52,6 @@ bool dt_have_prop(const void *fdt, int offs, const char *propname) return prop; } -int dt_get_irq(void *fdt, int node) -{ - const uint32_t *int_prop = NULL; - int len_prop = 0; - int it_num = DT_INFO_INVALID_INTERRUPT; - - /* - * Interrupt property can be defined with at least 2x32 bits word - * - Type of interrupt - * - Interrupt Number - */ - int_prop = fdt_getprop(fdt, node, "interrupts", &len_prop); - - if (!int_prop || len_prop < 2) - return it_num; - - it_num = fdt32_to_cpu(int_prop[1]); - - return it_num; -} - int dt_disable_status(void *fdt, int node) { const char *prop = NULL; @@ -288,6 +268,7 @@ void _fdt_fill_device_info(void *fdt, struct dt_node_info *info, int offs) .reg = DT_INFO_INVALID_REG, .clock = DT_INFO_INVALID_CLOCK, .reset = DT_INFO_INVALID_RESET, + .interrupt = DT_INFO_INVALID_INTERRUPT, }; const fdt32_t *cuint; @@ -305,6 +286,11 @@ void _fdt_fill_device_info(void *fdt, struct dt_node_info *info, int offs) dinfo.reset = (int)fdt32_to_cpu(*cuint); } + /* We first look for the secure interrupt, if not found the interrupt */ + dinfo.interrupt = dt_get_irq_secure(fdt, offs); + if (dinfo.interrupt == DT_INFO_INVALID_INTERRUPT) + dinfo.interrupt = dt_get_irq(fdt, offs); + dinfo.status = _fdt_get_status(fdt, offs); *info = dinfo; diff --git a/core/kernel/interrupt.c b/core/kernel/interrupt.c index 376012556..61c299745 100644 --- a/core/kernel/interrupt.c +++ b/core/kernel/interrupt.c @@ -3,8 +3,10 @@ * Copyright (c) 2016-2019, Linaro Limited */ +#include #include #include +#include #include #include @@ -25,6 +27,34 @@ void itr_init(struct itr_chip *chip) itr_chip = chip; } +#ifdef CFG_DT +static int _dt_get_irq(const void *fdt, int node, const char *prop_name) +{ + const uint32_t *prop = NULL; + int len = 0; + int it_num = DT_INFO_INVALID_INTERRUPT; + + if (!itr_chip || !itr_chip->dt_get_irq) + return it_num; + + prop = fdt_getprop(fdt, node, prop_name, &len); + if (!prop) + return it_num; + + return itr_chip->dt_get_irq(prop, len); +} + +int dt_get_irq(const void *fdt, int node) +{ + return _dt_get_irq(fdt, node, "interrupts"); +} + +int dt_get_irq_secure(const void *fdt, int node) +{ + return _dt_get_irq(fdt, node, "secure-interrupts"); +} +#endif + void itr_handle(size_t it) { struct itr_handler *h = NULL; diff --git a/mk/config.mk b/mk/config.mk index a14c4f832..c92a0edce 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -111,7 +111,7 @@ CFG_TEE_IMPL_DESCR ?= OPTEE CFG_OS_REV_REPORTS_GIT_SHA1 ?= y # Trusted OS implementation version -TEE_IMPL_VERSION ?= $(shell git describe --always --dirty=-dev 2>/dev/null || echo Unknown) +TEE_IMPL_VERSION ?= $(shell git describe --always --tags --dirty=-dev 2>/dev/null || echo Unknown) ifeq ($(CFG_OS_REV_REPORTS_GIT_SHA1),y) TEE_IMPL_GIT_SHA1 := 0x$(shell git rev-parse --short=8 HEAD 2>/dev/null || echo 0) else -- 2.17.1