169b8b983SEtienne Carriere // SPDX-License-Identifier: BSD-3-Clause 269b8b983SEtienne Carriere /* 369b8b983SEtienne Carriere * Copyright (c) 2021-2022, STMicroelectronics 469b8b983SEtienne Carriere */ 569b8b983SEtienne Carriere 669b8b983SEtienne Carriere #include <drivers/clk.h> 769b8b983SEtienne Carriere #include <drivers/clk_dt.h> 869b8b983SEtienne Carriere #include <drivers/stm32_tamp.h> 969b8b983SEtienne Carriere #include <io.h> 1069b8b983SEtienne Carriere #include <kernel/dt.h> 11*9e3c57c8SEtienne Carriere #include <kernel/dt_driver.h> 1269b8b983SEtienne Carriere #include <kernel/interrupt.h> 1369b8b983SEtienne Carriere #include <libfdt.h> 1469b8b983SEtienne Carriere #include <mm/core_memprot.h> 1569b8b983SEtienne Carriere #include <stdbool.h> 1669b8b983SEtienne Carriere 1769b8b983SEtienne Carriere /* STM32 Registers */ 1869b8b983SEtienne Carriere #define _TAMP_CR1 0x00U 1969b8b983SEtienne Carriere #define _TAMP_CR2 0x04U 2069b8b983SEtienne Carriere #define _TAMP_CR3 0x08U 2169b8b983SEtienne Carriere #define _TAMP_FLTCR 0x0CU 2269b8b983SEtienne Carriere #define _TAMP_ATCR1 0x10U 2369b8b983SEtienne Carriere #define _TAMP_ATSEEDR 0x14U 2469b8b983SEtienne Carriere #define _TAMP_ATOR 0x18U 2569b8b983SEtienne Carriere #define _TAMP_ATCR2 0x1CU 2669b8b983SEtienne Carriere #define _TAMP_SECCFGR 0x20U 2769b8b983SEtienne Carriere #define _TAMP_SMCR 0x20U 2869b8b983SEtienne Carriere #define _TAMP_PRIVCFGR 0x24U 2969b8b983SEtienne Carriere #define _TAMP_IER 0x2CU 3069b8b983SEtienne Carriere #define _TAMP_SR 0x30U 3169b8b983SEtienne Carriere #define _TAMP_MISR 0x34U 3269b8b983SEtienne Carriere #define _TAMP_SMISR 0x38U 3369b8b983SEtienne Carriere #define _TAMP_SCR 0x3CU 3469b8b983SEtienne Carriere #define _TAMP_COUNTR 0x40U 3569b8b983SEtienne Carriere #define _TAMP_COUNT2R 0x44U 3669b8b983SEtienne Carriere #define _TAMP_OR 0x50U 3769b8b983SEtienne Carriere #define _TAMP_ERCFGR 0X54U 3869b8b983SEtienne Carriere #define _TAMP_HWCFGR2 0x3ECU 3969b8b983SEtienne Carriere #define _TAMP_HWCFGR1 0x3F0U 4069b8b983SEtienne Carriere #define _TAMP_VERR 0x3F4U 4169b8b983SEtienne Carriere #define _TAMP_IPIDR 0x3F8U 4269b8b983SEtienne Carriere #define _TAMP_SIDR 0x3FCU 4369b8b983SEtienne Carriere 4469b8b983SEtienne Carriere /* _TAMP_SECCFGR bit fields */ 4569b8b983SEtienne Carriere #define _TAMP_SECCFGR_BKPRWSEC_MASK GENMASK_32(7, 0) 4669b8b983SEtienne Carriere #define _TAMP_SECCFGR_BKPRWSEC_SHIFT 0U 4769b8b983SEtienne Carriere #define _TAMP_SECCFGR_CNT2SEC BIT(14) 4869b8b983SEtienne Carriere #define _TAMP_SECCFGR_CNT1SEC BIT(15) 4969b8b983SEtienne Carriere #define _TAMP_SECCFGR_BKPWSEC_MASK GENMASK_32(23, 16) 5069b8b983SEtienne Carriere #define _TAMP_SECCFGR_BKPWSEC_SHIFT 16U 5169b8b983SEtienne Carriere #define _TAMP_SECCFGR_BHKLOCK BIT(30) 5269b8b983SEtienne Carriere #define _TAMP_SECCFGR_TAMPSEC BIT(31) 5369b8b983SEtienne Carriere #define _TAMP_SECCFGR_BUT_BKP_MASK (GENMASK_32(31, 30) | \ 5469b8b983SEtienne Carriere GENMASK_32(15, 14)) 5569b8b983SEtienne Carriere 5669b8b983SEtienne Carriere /* _TAMP_SMCR bit fields */ 5769b8b983SEtienne Carriere #define _TAMP_SMCR_BKPRWDPROT_MASK GENMASK_32(7, 0) 5869b8b983SEtienne Carriere #define _TAMP_SMCR_BKPRWDPROT_SHIFT 0U 5969b8b983SEtienne Carriere #define _TAMP_SMCR_BKPWDPROT_MASK GENMASK_32(23, 16) 6069b8b983SEtienne Carriere #define _TAMP_SMCR_BKPWDPROT_SHIFT 16U 6169b8b983SEtienne Carriere #define _TAMP_SMCR_DPROT BIT(31) 6269b8b983SEtienne Carriere /* 6369b8b983SEtienne Carriere * _TAMP_PRIVCFGR bit fields 6469b8b983SEtienne Carriere */ 6569b8b983SEtienne Carriere #define _TAMP_PRIVCFG_CNT2PRIV BIT(14) 6669b8b983SEtienne Carriere #define _TAMP_PRIVCFG_CNT1PRIV BIT(15) 6769b8b983SEtienne Carriere #define _TAMP_PRIVCFG_BKPRWPRIV BIT(29) 6869b8b983SEtienne Carriere #define _TAMP_PRIVCFG_BKPWPRIV BIT(30) 6969b8b983SEtienne Carriere #define _TAMP_PRIVCFG_TAMPPRIV BIT(31) 7069b8b983SEtienne Carriere #define _TAMP_PRIVCFGR_MASK (GENMASK_32(31, 29) | \ 7169b8b983SEtienne Carriere GENMASK_32(15, 14)) 7269b8b983SEtienne Carriere 7369b8b983SEtienne Carriere /* 7469b8b983SEtienne Carriere * _TAMP_PRIVCFGR bit fields 7569b8b983SEtienne Carriere */ 7669b8b983SEtienne Carriere #define _TAMP_PRIVCFG_CNT2PRIV BIT(14) 7769b8b983SEtienne Carriere #define _TAMP_PRIVCFG_CNT1PRIV BIT(15) 7869b8b983SEtienne Carriere #define _TAMP_PRIVCFG_BKPRWPRIV BIT(29) 7969b8b983SEtienne Carriere #define _TAMP_PRIVCFG_BKPWPRIV BIT(30) 8069b8b983SEtienne Carriere #define _TAMP_PRIVCFG_TAMPPRIV BIT(31) 8169b8b983SEtienne Carriere #define _TAMP_PRIVCFGR_MASK (GENMASK_32(31, 29) | \ 8269b8b983SEtienne Carriere GENMASK_32(15, 14)) 8369b8b983SEtienne Carriere 8469b8b983SEtienne Carriere /* _TAMP_HWCFGR2 bit fields */ 8569b8b983SEtienne Carriere #define _TAMP_HWCFGR2_TZ GENMASK_32(11, 8) 8669b8b983SEtienne Carriere #define _TAMP_HWCFGR2_OR GENMASK_32(7, 0) 8769b8b983SEtienne Carriere 8869b8b983SEtienne Carriere /* _TAMP_HWCFGR1 bit fields */ 8969b8b983SEtienne Carriere #define _TAMP_HWCFGR1_BKPREG GENMASK_32(7, 0) 9069b8b983SEtienne Carriere #define _TAMP_HWCFGR1_TAMPER GENMASK_32(11, 8) 9169b8b983SEtienne Carriere #define _TAMP_HWCFGR1_ACTIVE GENMASK_32(15, 12) 9269b8b983SEtienne Carriere #define _TAMP_HWCFGR1_INTERN GENMASK_32(31, 16) 9369b8b983SEtienne Carriere #define _TAMP_HWCFGR1_ITAMP_MAX_ID 16U 9469b8b983SEtienne Carriere #define _TAMP_HWCFGR1_ITAMP(id) BIT((id) - INT_TAMP1 + 16U) 9569b8b983SEtienne Carriere 9669b8b983SEtienne Carriere /* _TAMP_VERR bit fields */ 9769b8b983SEtienne Carriere #define _TAMP_VERR_MINREV GENMASK_32(3, 0) 9869b8b983SEtienne Carriere #define _TAMP_VERR_MAJREV GENMASK_32(7, 4) 9969b8b983SEtienne Carriere 10069b8b983SEtienne Carriere /* 10169b8b983SEtienne Carriere * TAMP instance data 10269b8b983SEtienne Carriere * @base - IOMEM base address 10369b8b983SEtienne Carriere * @clock - TAMP clock 10469b8b983SEtienne Carriere * @it - TAMP interrupt number 10569b8b983SEtienne Carriere * @hwconf1 - Copy of TAMP HWCONF1 register content 10669b8b983SEtienne Carriere * @hwconf2 - Copy of TAMP HWCONF2 register content 10769b8b983SEtienne Carriere * @compat - Reference to compat data passed at driver initialization 10869b8b983SEtienne Carriere */ 10969b8b983SEtienne Carriere struct stm32_tamp_instance { 11069b8b983SEtienne Carriere struct io_pa_va base; 11169b8b983SEtienne Carriere struct clk *clock; 11269b8b983SEtienne Carriere int it; 11369b8b983SEtienne Carriere uint32_t hwconf1; 11469b8b983SEtienne Carriere uint32_t hwconf2; 11569b8b983SEtienne Carriere struct stm32_tamp_compat *compat; 11669b8b983SEtienne Carriere }; 11769b8b983SEtienne Carriere 11869b8b983SEtienne Carriere /* 11969b8b983SEtienne Carriere * Compatibility capabilities 12069b8b983SEtienne Carriere * TAMP_HAS_REGISTER_SECCFG - Supports SECCFGR, otherwise supports SMCR register 12169b8b983SEtienne Carriere * TAMP_HAS_REGISTER_PRIVCFG - Supports PRIVCFGR configuration register 12269b8b983SEtienne Carriere */ 12369b8b983SEtienne Carriere #define TAMP_HAS_REGISTER_SECCFG BIT(0) 12469b8b983SEtienne Carriere #define TAMP_HAS_REGISTER_PRIVCFGR BIT(1) 12569b8b983SEtienne Carriere 12669b8b983SEtienne Carriere /* 12769b8b983SEtienne Carriere * @nb_monotonic_counter - Number of monotic counter supported 12869b8b983SEtienne Carriere * @tags - Bit flags TAMP_HAS_* for compatibily management 12969b8b983SEtienne Carriere */ 13069b8b983SEtienne Carriere struct stm32_tamp_compat { 13169b8b983SEtienne Carriere int nb_monotonic_counter; 13269b8b983SEtienne Carriere uint32_t tags; 13369b8b983SEtienne Carriere }; 13469b8b983SEtienne Carriere 13569b8b983SEtienne Carriere /* Expects at most a single instance */ 13669b8b983SEtienne Carriere static struct stm32_tamp_instance *stm32_tamp_device; 13769b8b983SEtienne Carriere 13869b8b983SEtienne Carriere TEE_Result stm32_tamp_set_secure_bkpregs(struct stm32_bkpregs_conf *bkr_conf) 13969b8b983SEtienne Carriere { 14069b8b983SEtienne Carriere struct stm32_tamp_instance *tamp = stm32_tamp_device; 14169b8b983SEtienne Carriere vaddr_t base = 0; 14269b8b983SEtienne Carriere uint32_t first_z2 = 0; 14369b8b983SEtienne Carriere uint32_t first_z3 = 0; 14469b8b983SEtienne Carriere 14569b8b983SEtienne Carriere if (!tamp) 14669b8b983SEtienne Carriere return TEE_ERROR_DEFER_DRIVER_INIT; 14769b8b983SEtienne Carriere 14869b8b983SEtienne Carriere if (!bkr_conf) 14969b8b983SEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 15069b8b983SEtienne Carriere 15169b8b983SEtienne Carriere base = io_pa_or_va(&tamp->base, 1); 15269b8b983SEtienne Carriere 15369b8b983SEtienne Carriere first_z2 = bkr_conf->nb_zone1_regs; 15469b8b983SEtienne Carriere first_z3 = bkr_conf->nb_zone1_regs + bkr_conf->nb_zone2_regs; 15569b8b983SEtienne Carriere 15669b8b983SEtienne Carriere if ((first_z2 > (tamp->hwconf1 & _TAMP_HWCFGR1_BKPREG)) || 15769b8b983SEtienne Carriere (first_z3 > (tamp->hwconf1 & _TAMP_HWCFGR1_BKPREG))) 15869b8b983SEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 15969b8b983SEtienne Carriere 16069b8b983SEtienne Carriere if (tamp->compat && (tamp->compat->tags & TAMP_HAS_REGISTER_SECCFG)) { 16169b8b983SEtienne Carriere io_clrsetbits32(base + _TAMP_SECCFGR, 16269b8b983SEtienne Carriere _TAMP_SECCFGR_BKPRWSEC_MASK, 16369b8b983SEtienne Carriere (first_z2 << _TAMP_SECCFGR_BKPRWSEC_SHIFT) & 16469b8b983SEtienne Carriere _TAMP_SECCFGR_BKPRWSEC_MASK); 16569b8b983SEtienne Carriere 16669b8b983SEtienne Carriere io_clrsetbits32(base + _TAMP_SECCFGR, 16769b8b983SEtienne Carriere _TAMP_SECCFGR_BKPWSEC_MASK, 16869b8b983SEtienne Carriere (first_z3 << _TAMP_SECCFGR_BKPWSEC_SHIFT) & 16969b8b983SEtienne Carriere _TAMP_SECCFGR_BKPWSEC_MASK); 17069b8b983SEtienne Carriere } else { 17169b8b983SEtienne Carriere io_clrsetbits32(base + _TAMP_SMCR, 17269b8b983SEtienne Carriere _TAMP_SMCR_BKPRWDPROT_MASK, 17369b8b983SEtienne Carriere (first_z2 << _TAMP_SMCR_BKPRWDPROT_SHIFT) & 17469b8b983SEtienne Carriere _TAMP_SMCR_BKPRWDPROT_MASK); 17569b8b983SEtienne Carriere 17669b8b983SEtienne Carriere io_clrsetbits32(base + _TAMP_SMCR, 17769b8b983SEtienne Carriere _TAMP_SMCR_BKPWDPROT_MASK, 17869b8b983SEtienne Carriere (first_z3 << _TAMP_SMCR_BKPWDPROT_SHIFT) & 17969b8b983SEtienne Carriere _TAMP_SMCR_BKPWDPROT_MASK); 18069b8b983SEtienne Carriere } 18169b8b983SEtienne Carriere 18269b8b983SEtienne Carriere return TEE_SUCCESS; 18369b8b983SEtienne Carriere } 18469b8b983SEtienne Carriere 18569b8b983SEtienne Carriere static void stm32_tamp_set_secure(struct stm32_tamp_instance *tamp, 18669b8b983SEtienne Carriere uint32_t mode) 18769b8b983SEtienne Carriere { 18869b8b983SEtienne Carriere vaddr_t base = io_pa_or_va(&tamp->base, 1); 18969b8b983SEtienne Carriere 19069b8b983SEtienne Carriere if (tamp->compat && (tamp->compat->tags & TAMP_HAS_REGISTER_SECCFG)) { 19169b8b983SEtienne Carriere io_clrsetbits32(base + _TAMP_SECCFGR, 19269b8b983SEtienne Carriere _TAMP_SECCFGR_BUT_BKP_MASK, 19369b8b983SEtienne Carriere mode & _TAMP_SECCFGR_BUT_BKP_MASK); 19469b8b983SEtienne Carriere } else { 19569b8b983SEtienne Carriere /* 19669b8b983SEtienne Carriere * Note: MP15 doesn't use SECCFG register and 19769b8b983SEtienne Carriere * inverts the secure bit. 19869b8b983SEtienne Carriere */ 19969b8b983SEtienne Carriere if (mode & _TAMP_SECCFGR_TAMPSEC) 20069b8b983SEtienne Carriere io_clrbits32(base + _TAMP_SMCR, _TAMP_SMCR_DPROT); 20169b8b983SEtienne Carriere else 20269b8b983SEtienne Carriere io_setbits32(base + _TAMP_SMCR, _TAMP_SMCR_DPROT); 20369b8b983SEtienne Carriere } 20469b8b983SEtienne Carriere } 20569b8b983SEtienne Carriere 20669b8b983SEtienne Carriere static void stm32_tamp_set_privilege(struct stm32_tamp_instance *tamp, 20769b8b983SEtienne Carriere uint32_t mode) 20869b8b983SEtienne Carriere { 20969b8b983SEtienne Carriere vaddr_t base = io_pa_or_va(&tamp->base, 1); 21069b8b983SEtienne Carriere 21169b8b983SEtienne Carriere if (tamp->compat && (tamp->compat->tags & TAMP_HAS_REGISTER_PRIVCFGR)) 21269b8b983SEtienne Carriere io_clrsetbits32(base + _TAMP_PRIVCFGR, _TAMP_PRIVCFGR_MASK, 21369b8b983SEtienne Carriere mode & _TAMP_PRIVCFGR_MASK); 21469b8b983SEtienne Carriere } 21569b8b983SEtienne Carriere 21669b8b983SEtienne Carriere static TEE_Result stm32_tamp_parse_fdt(struct stm32_tamp_instance *tamp, 21769b8b983SEtienne Carriere const void *fdt, int node, 21869b8b983SEtienne Carriere const void *compat) 21969b8b983SEtienne Carriere { 22069b8b983SEtienne Carriere struct dt_node_info dt_tamp = { }; 22169b8b983SEtienne Carriere 222f354a5d8SGatien Chevallier fdt_fill_device_info(fdt, &dt_tamp, node); 22369b8b983SEtienne Carriere 22469b8b983SEtienne Carriere if (dt_tamp.reg == DT_INFO_INVALID_REG || 22569b8b983SEtienne Carriere dt_tamp.reg_size == DT_INFO_INVALID_REG_SIZE) 22669b8b983SEtienne Carriere return TEE_ERROR_BAD_PARAMETERS; 22769b8b983SEtienne Carriere 22869b8b983SEtienne Carriere tamp->compat = (struct stm32_tamp_compat *)compat; 22969b8b983SEtienne Carriere tamp->it = dt_tamp.interrupt; 23069b8b983SEtienne Carriere tamp->base.pa = dt_tamp.reg; 23169b8b983SEtienne Carriere io_pa_or_va_secure(&tamp->base, dt_tamp.reg_size); 23269b8b983SEtienne Carriere 23369b8b983SEtienne Carriere return clk_dt_get_by_index(fdt, node, 0, &tamp->clock); 23469b8b983SEtienne Carriere } 23569b8b983SEtienne Carriere 23669b8b983SEtienne Carriere static TEE_Result stm32_tamp_probe(const void *fdt, int node, 23769b8b983SEtienne Carriere const void *compat_data) 23869b8b983SEtienne Carriere { 23969b8b983SEtienne Carriere struct stm32_tamp_instance *tamp = NULL; 24069b8b983SEtienne Carriere uint32_t __maybe_unused revision = 0; 24169b8b983SEtienne Carriere TEE_Result res = TEE_SUCCESS; 24269b8b983SEtienne Carriere vaddr_t base = 0; 24369b8b983SEtienne Carriere 24469b8b983SEtienne Carriere tamp = calloc(1, sizeof(*tamp)); 24569b8b983SEtienne Carriere if (!tamp) 24669b8b983SEtienne Carriere return TEE_ERROR_OUT_OF_MEMORY; 24769b8b983SEtienne Carriere 24869b8b983SEtienne Carriere res = stm32_tamp_parse_fdt(tamp, fdt, node, compat_data); 24969b8b983SEtienne Carriere if (res) 25069b8b983SEtienne Carriere goto err; 25169b8b983SEtienne Carriere 25269b8b983SEtienne Carriere clk_enable(tamp->clock); 25369b8b983SEtienne Carriere 25469b8b983SEtienne Carriere base = io_pa_or_va(&tamp->base, 1); 25569b8b983SEtienne Carriere 25669b8b983SEtienne Carriere tamp->hwconf1 = io_read32(base + _TAMP_HWCFGR1); 25769b8b983SEtienne Carriere tamp->hwconf2 = io_read32(base + _TAMP_HWCFGR2); 25869b8b983SEtienne Carriere 25969b8b983SEtienne Carriere revision = io_read32(base + _TAMP_VERR); 26069b8b983SEtienne Carriere FMSG("STM32 TAMPER V%"PRIx32".%"PRIu32, 26169b8b983SEtienne Carriere (revision & _TAMP_VERR_MAJREV) >> 4, revision & _TAMP_VERR_MINREV); 26269b8b983SEtienne Carriere 26369b8b983SEtienne Carriere if (!(tamp->hwconf2 & _TAMP_HWCFGR2_TZ)) { 26469b8b983SEtienne Carriere EMSG("TAMP doesn't support TrustZone"); 26569b8b983SEtienne Carriere res = TEE_ERROR_NOT_SUPPORTED; 26669b8b983SEtienne Carriere goto err_clk; 26769b8b983SEtienne Carriere } 26869b8b983SEtienne Carriere 26969b8b983SEtienne Carriere /* 27069b8b983SEtienne Carriere * Enforce secure only access to protected TAMP registers. 27169b8b983SEtienne Carriere * Allow non-secure access to monotonic counter. 27269b8b983SEtienne Carriere */ 27369b8b983SEtienne Carriere stm32_tamp_set_secure(tamp, _TAMP_SECCFGR_TAMPSEC); 27469b8b983SEtienne Carriere 27569b8b983SEtienne Carriere /* 27669b8b983SEtienne Carriere * Enforce privilege only access to TAMP registers, backup 27769b8b983SEtienne Carriere * registers and monotonic counter. 27869b8b983SEtienne Carriere */ 27969b8b983SEtienne Carriere stm32_tamp_set_privilege(tamp, _TAMP_PRIVCFG_TAMPPRIV | 28069b8b983SEtienne Carriere _TAMP_PRIVCFG_BKPRWPRIV | 28169b8b983SEtienne Carriere _TAMP_PRIVCFG_BKPWPRIV); 28269b8b983SEtienne Carriere 28369b8b983SEtienne Carriere stm32_tamp_device = tamp; 28469b8b983SEtienne Carriere 28569b8b983SEtienne Carriere return TEE_SUCCESS; 28669b8b983SEtienne Carriere 28769b8b983SEtienne Carriere err_clk: 28869b8b983SEtienne Carriere clk_disable(tamp->clock); 28969b8b983SEtienne Carriere err: 29069b8b983SEtienne Carriere free(tamp); 29169b8b983SEtienne Carriere return res; 29269b8b983SEtienne Carriere } 29369b8b983SEtienne Carriere 29469b8b983SEtienne Carriere static const struct stm32_tamp_compat mp13_compat = { 29569b8b983SEtienne Carriere .nb_monotonic_counter = 2, 29669b8b983SEtienne Carriere .tags = TAMP_HAS_REGISTER_SECCFG | TAMP_HAS_REGISTER_PRIVCFGR, 29769b8b983SEtienne Carriere }; 29869b8b983SEtienne Carriere 29969b8b983SEtienne Carriere static const struct stm32_tamp_compat mp15_compat = { 30069b8b983SEtienne Carriere .nb_monotonic_counter = 1, 30169b8b983SEtienne Carriere .tags = 0, 30269b8b983SEtienne Carriere }; 30369b8b983SEtienne Carriere 30469b8b983SEtienne Carriere static const struct dt_device_match stm32_tamp_match_table[] = { 30569b8b983SEtienne Carriere { .compatible = "st,stm32mp13-tamp", .compat_data = &mp13_compat }, 30669b8b983SEtienne Carriere { .compatible = "st,stm32-tamp", .compat_data = &mp15_compat }, 30769b8b983SEtienne Carriere { } 30869b8b983SEtienne Carriere }; 30969b8b983SEtienne Carriere 31069b8b983SEtienne Carriere DEFINE_DT_DRIVER(stm32_tamp_dt_driver) = { 31169b8b983SEtienne Carriere .name = "stm32-tamp", 31269b8b983SEtienne Carriere .match_table = stm32_tamp_match_table, 31369b8b983SEtienne Carriere .probe = stm32_tamp_probe, 31469b8b983SEtienne Carriere }; 315