11b104208SGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
21b104208SGatien Chevallier /*
31b104208SGatien Chevallier * Copyright (c) 2021-2024, STMicroelectronics
41b104208SGatien Chevallier */
51b104208SGatien Chevallier
61b104208SGatien Chevallier #include <assert.h>
71b104208SGatien Chevallier #include <drivers/clk.h>
81b104208SGatien Chevallier #include <drivers/clk_dt.h>
9*e78e87a9SGatien Chevallier #include <drivers/firewall.h>
101b104208SGatien Chevallier #include <drivers/stm32_rif.h>
111b104208SGatien Chevallier #include <drivers/stm32_risaf.h>
121b104208SGatien Chevallier #include <dt-bindings/firewall/stm32mp25-risaf.h>
131b104208SGatien Chevallier #include <io.h>
141b104208SGatien Chevallier #include <kernel/boot.h>
151b104208SGatien Chevallier #include <kernel/dt.h>
161b104208SGatien Chevallier #include <kernel/pm.h>
17*e78e87a9SGatien Chevallier #include <kernel/spinlock.h>
181b104208SGatien Chevallier #include <kernel/tee_misc.h>
191b104208SGatien Chevallier #include <libfdt.h>
201b104208SGatien Chevallier #include <mm/core_memprot.h>
211b104208SGatien Chevallier #include <platform_config.h>
221b104208SGatien Chevallier #include <stdint.h>
231b104208SGatien Chevallier #include <util.h>
241b104208SGatien Chevallier
251b104208SGatien Chevallier /* RISAF general registers (base relative) */
261b104208SGatien Chevallier #define _RISAF_CR U(0x00)
271b104208SGatien Chevallier #define _RISAF_SR U(0x04)
281b104208SGatien Chevallier #define _RISAF_IASR U(0x08)
291b104208SGatien Chevallier #define _RISAF_IACR U(0xC)
301b104208SGatien Chevallier #define _RISAF_IAESR0 U(0x20)
311b104208SGatien Chevallier #define _RISAF_IADDR0 U(0x24)
321b104208SGatien Chevallier #define _RISAF_IAESR1 U(0x28)
331b104208SGatien Chevallier #define _RISAF_IADDR1 U(0x2C)
341b104208SGatien Chevallier #define _RISAF_KEYR U(0x30)
351b104208SGatien Chevallier #define _RISAF_HWCFGR U(0xFF0)
361b104208SGatien Chevallier #define _RISAF_VERR U(0xFF4)
371b104208SGatien Chevallier #define _RISAF_IPIDR U(0xFF8)
381b104208SGatien Chevallier #define _RISAF_SIDR U(0xFFC)
391b104208SGatien Chevallier
401b104208SGatien Chevallier /* RISAF general register field description */
411b104208SGatien Chevallier /* _RISAF_CR register fields */
421b104208SGatien Chevallier #define _RISAF_CR_GLOCK BIT(0)
431b104208SGatien Chevallier /* _RISAF_SR register fields */
441b104208SGatien Chevallier #define _RISAF_SR_KEYVALID BIT(0)
451b104208SGatien Chevallier #define _RISAF_SR_KEYRDY BIT(1)
461b104208SGatien Chevallier #define _RISAF_SR_ENCDIS BIT(2)
471b104208SGatien Chevallier /* _RISAF_IACR register fields */
481b104208SGatien Chevallier #define _RISAF_IACR_CAEF BIT(0)
491b104208SGatien Chevallier #define _RISAF_IACR_IAEF0 BIT(1)
501b104208SGatien Chevallier #define _RISAF_IACR_IAEF1 BIT(2)
511b104208SGatien Chevallier /* _RISAF_HWCFGR register fields */
521b104208SGatien Chevallier #define _RISAF_HWCFGR_CFG1_SHIFT U(0)
531b104208SGatien Chevallier #define _RISAF_HWCFGR_CFG1_MASK GENMASK_32(7, 0)
541b104208SGatien Chevallier #define _RISAF_HWCFGR_CFG2_SHIFT U(8)
551b104208SGatien Chevallier #define _RISAF_HWCFGR_CFG2_MASK GENMASK_32(15, 8)
561b104208SGatien Chevallier #define _RISAF_HWCFGR_CFG3_SHIFT U(16)
571b104208SGatien Chevallier #define _RISAF_HWCFGR_CFG3_MASK GENMASK_32(23, 16)
581b104208SGatien Chevallier #define _RISAF_HWCFGR_CFG4_SHIFT U(24)
591b104208SGatien Chevallier #define _RISAF_HWCFGR_CFG4_MASK GENMASK_32(31, 24)
601b104208SGatien Chevallier /* _RISAF_VERR register fields */
611b104208SGatien Chevallier #define _RISAF_VERR_MINREV_SHIFT U(0)
621b104208SGatien Chevallier #define _RISAF_VERR_MINREV_MASK GENMASK_32(3, 0)
631b104208SGatien Chevallier #define _RISAF_VERR_MAJREV_SHIFT U(4)
641b104208SGatien Chevallier #define _RISAF_VERR_MAJREV_MASK GENMASK_32(7, 4)
651b104208SGatien Chevallier
661b104208SGatien Chevallier /* RISAF region registers (base relative) */
671b104208SGatien Chevallier #define _RISAF_REG_BASE U(0x40)
681b104208SGatien Chevallier #define _RISAF_REG_SIZE U(0x40)
691b104208SGatien Chevallier #define _RISAF_REG(n) (_RISAF_REG_BASE + \
701b104208SGatien Chevallier (((n) - 1) * _RISAF_REG_SIZE))
711b104208SGatien Chevallier #define _RISAF_REG_CFGR_OFFSET U(0x0)
721b104208SGatien Chevallier #define _RISAF_REG_CFGR(n) (_RISAF_REG(n) + _RISAF_REG_CFGR_OFFSET)
731b104208SGatien Chevallier #define _RISAF_REG_STARTR_OFFSET U(0x4)
741b104208SGatien Chevallier #define _RISAF_REG_STARTR(n) (_RISAF_REG(n) + \
751b104208SGatien Chevallier _RISAF_REG_STARTR_OFFSET)
761b104208SGatien Chevallier #define _RISAF_REG_ENDR_OFFSET U(0x8)
771b104208SGatien Chevallier #define _RISAF_REG_ENDR(n) (_RISAF_REG(n) + _RISAF_REG_ENDR_OFFSET)
781b104208SGatien Chevallier #define _RISAF_REG_CIDCFGR_OFFSET U(0xC)
791b104208SGatien Chevallier #define _RISAF_REG_CIDCFGR(n) (_RISAF_REG(n) + \
801b104208SGatien Chevallier _RISAF_REG_CIDCFGR_OFFSET)
811b104208SGatien Chevallier
821b104208SGatien Chevallier /* RISAF region register field description */
831b104208SGatien Chevallier /* _RISAF_REG_CFGR(n) register fields */
841b104208SGatien Chevallier #define _RISAF_REG_CFGR_BREN_SHIFT U(0)
851b104208SGatien Chevallier #define _RISAF_REG_CFGR_BREN BIT(_RISAF_REG_CFGR_BREN_SHIFT)
861b104208SGatien Chevallier #define _RISAF_REG_CFGR_SEC_SHIFT U(8)
871b104208SGatien Chevallier #define _RISAF_REG_CFGR_SEC BIT(_RISAF_REG_CFGR_SEC_SHIFT)
881b104208SGatien Chevallier #define _RISAF_REG_CFGR_ENC_SHIFT U(15)
891b104208SGatien Chevallier #define _RISAF_REG_CFGR_ENC BIT(_RISAF_REG_CFGR_ENC_SHIFT)
901b104208SGatien Chevallier #define _RISAF_REG_CFGR_PRIVC_SHIFT U(16)
911b104208SGatien Chevallier #define _RISAF_REG_CFGR_PRIVC_MASK GENMASK_32(23, 16)
921b104208SGatien Chevallier #define _RISAF_REG_CFGR_ALL_MASK (_RISAF_REG_CFGR_BREN | \
931b104208SGatien Chevallier _RISAF_REG_CFGR_SEC | \
941b104208SGatien Chevallier _RISAF_REG_CFGR_ENC | \
951b104208SGatien Chevallier _RISAF_REG_CFGR_PRIVC_MASK)
961b104208SGatien Chevallier
971b104208SGatien Chevallier /* _RISAF_REG_CIDCFGR(n) register fields */
981b104208SGatien Chevallier #define _RISAF_REG_CIDCFGR_RDENC_SHIFT U(0)
991b104208SGatien Chevallier #define _RISAF_REG_CIDCFGR_RDENC_MASK GENMASK_32(7, 0)
1001b104208SGatien Chevallier #define _RISAF_REG_CIDCFGR_WRENC_SHIFT U(16)
1011b104208SGatien Chevallier #define _RISAF_REG_CIDCFGR_WRENC_MASK GENMASK_32(23, 16)
1021b104208SGatien Chevallier #define _RISAF_REG_CIDCFGR_ALL_MASK (_RISAF_REG_CIDCFGR_RDENC_MASK | \
1031b104208SGatien Chevallier _RISAF_REG_CIDCFGR_WRENC_MASK)
1041b104208SGatien Chevallier #define _RISAF_REG_READ_OK(reg, cid) \
1051b104208SGatien Chevallier ((reg) & BIT((cid) + _RISAF_REG_CIDCFGR_RDENC_SHIFT))
1061b104208SGatien Chevallier #define _RISAF_REG_WRITE_OK(reg, cid) \
1071b104208SGatien Chevallier ((reg) & BIT((cid) + _RISAF_REG_CIDCFGR_WRENC_SHIFT))
1081b104208SGatien Chevallier
1091b104208SGatien Chevallier #define _RISAF_GET_REGION_ID(cfg) ((cfg) & DT_RISAF_REG_ID_MASK)
1101b104208SGatien Chevallier
1111b104208SGatien Chevallier #define _RISAF_NB_CID_SUPPORTED U(8)
1121b104208SGatien Chevallier
1131b104208SGatien Chevallier /**
1141b104208SGatien Chevallier * struct stm32_risaf_region - RISAF memory region
1151b104208SGatien Chevallier *
1161b104208SGatien Chevallier * @addr: Region base address.
1171b104208SGatien Chevallier * @len: Length of the memory region.
1181b104208SGatien Chevallier * @cfg: Region configuration.
1191b104208SGatien Chevallier */
1201b104208SGatien Chevallier struct stm32_risaf_region {
1211b104208SGatien Chevallier paddr_t addr;
1221b104208SGatien Chevallier size_t len;
1231b104208SGatien Chevallier uint32_t cfg;
1241b104208SGatien Chevallier };
1251b104208SGatien Chevallier
1261b104208SGatien Chevallier /**
1271b104208SGatien Chevallier * struct stm32_risaf_pdata - RISAF platform data
1281b104208SGatien Chevallier *
1291b104208SGatien Chevallier * @base: Base address of the RISAF instance.
1301b104208SGatien Chevallier * @clock: Clock of the RISAF.
1311b104208SGatien Chevallier * @regions: Number of memory regions, defined by the device tree configuration.
1321b104208SGatien Chevallier * @risaf_name: Name of the RISAF instance
1331b104208SGatien Chevallier * @nregions: Number of memory regions found in the device tree.
1341b104208SGatien Chevallier * @conf_lock: State whether the RISAF configuration is locked.
1351b104208SGatien Chevallier * @mem_base: Base address of the memory range covered by the RISAF instance.
1361b104208SGatien Chevallier * @mem_size: Size of the memory range covered by the RISAF instance.
1371b104208SGatien Chevallier * @enc_supported: If true, the RISAF instance supports encryption of the memory
1381b104208SGatien Chevallier * regions.
1391b104208SGatien Chevallier */
1401b104208SGatien Chevallier struct stm32_risaf_pdata {
1411b104208SGatien Chevallier struct io_pa_va base;
1421b104208SGatien Chevallier struct clk *clock;
1431b104208SGatien Chevallier struct stm32_risaf_region *regions;
1441b104208SGatien Chevallier char risaf_name[20];
1451b104208SGatien Chevallier unsigned int nregions;
1461b104208SGatien Chevallier unsigned int conf_lock;
1471b104208SGatien Chevallier paddr_t mem_base;
1481b104208SGatien Chevallier size_t mem_size;
1491b104208SGatien Chevallier bool enc_supported;
1501b104208SGatien Chevallier };
1511b104208SGatien Chevallier
1521b104208SGatien Chevallier /**
1531b104208SGatien Chevallier * struct stm32_risaf_ddata - RISAF driver data
1541b104208SGatien Chevallier *
1551b104208SGatien Chevallier * @mask_regions: Number of address bits to match when determining access to a
1561b104208SGatien Chevallier * base region or subregion (WIDTH).
1571b104208SGatien Chevallier * @max_base_regions: Number of subdivision of the memory range (A.K.A memory
1581b104208SGatien Chevallier * regions) supported by the RISAF instance.
1591b104208SGatien Chevallier * @granularity: Length of the smallest possible region size.
1601b104208SGatien Chevallier */
1611b104208SGatien Chevallier struct stm32_risaf_ddata {
1621b104208SGatien Chevallier uint32_t mask_regions;
1631b104208SGatien Chevallier uint32_t max_base_regions;
1641b104208SGatien Chevallier uint32_t granularity;
1651b104208SGatien Chevallier };
1661b104208SGatien Chevallier
1671b104208SGatien Chevallier struct stm32_risaf_instance {
1681b104208SGatien Chevallier struct stm32_risaf_pdata pdata;
1691b104208SGatien Chevallier struct stm32_risaf_ddata *ddata;
1701b104208SGatien Chevallier
1711b104208SGatien Chevallier SLIST_ENTRY(stm32_risaf_instance) link;
1721b104208SGatien Chevallier };
1731b104208SGatien Chevallier
1741b104208SGatien Chevallier struct stm32_risaf_version {
1751b104208SGatien Chevallier uint32_t major;
1761b104208SGatien Chevallier uint32_t minor;
1771b104208SGatien Chevallier uint32_t ip_id;
1781b104208SGatien Chevallier uint32_t size_id;
1791b104208SGatien Chevallier };
1801b104208SGatien Chevallier
1811b104208SGatien Chevallier /**
1821b104208SGatien Chevallier * struct stm32_risaf_compat_data - Describes RISAF associated data
1831b104208SGatien Chevallier * for compatible list.
1841b104208SGatien Chevallier *
1851b104208SGatien Chevallier * @supported_encryption: identify RISAF encryption capabilities.
1861b104208SGatien Chevallier */
1871b104208SGatien Chevallier struct stm32_risaf_compat_data {
1881b104208SGatien Chevallier bool supported_encryption;
1891b104208SGatien Chevallier };
1901b104208SGatien Chevallier
1911b104208SGatien Chevallier static bool is_tdcid;
1921b104208SGatien Chevallier
1931b104208SGatien Chevallier static const struct stm32_risaf_compat_data stm32_risaf_compat = {
1941b104208SGatien Chevallier .supported_encryption = false,
1951b104208SGatien Chevallier };
1961b104208SGatien Chevallier
1971b104208SGatien Chevallier static const struct stm32_risaf_compat_data stm32_risaf_enc_compat = {
1981b104208SGatien Chevallier .supported_encryption = true,
1991b104208SGatien Chevallier };
2001b104208SGatien Chevallier
2011b104208SGatien Chevallier static SLIST_HEAD(, stm32_risaf_instance) risaf_list =
2021b104208SGatien Chevallier SLIST_HEAD_INITIALIZER(risaf_list);
2031b104208SGatien Chevallier
risaf_base(struct stm32_risaf_instance * risaf)2041b104208SGatien Chevallier static vaddr_t risaf_base(struct stm32_risaf_instance *risaf)
2051b104208SGatien Chevallier {
2061b104208SGatien Chevallier return io_pa_or_va_secure(&risaf->pdata.base, 1);
2071b104208SGatien Chevallier }
2081b104208SGatien Chevallier
stm32_risaf_get_region_config(uint32_t cfg)2091b104208SGatien Chevallier static uint32_t stm32_risaf_get_region_config(uint32_t cfg)
2101b104208SGatien Chevallier {
2111b104208SGatien Chevallier return SHIFT_U32((cfg & DT_RISAF_EN_MASK) >> DT_RISAF_EN_SHIFT,
2121b104208SGatien Chevallier _RISAF_REG_CFGR_BREN_SHIFT) |
2131b104208SGatien Chevallier SHIFT_U32((cfg & DT_RISAF_SEC_MASK) >> DT_RISAF_SEC_SHIFT,
2141b104208SGatien Chevallier _RISAF_REG_CFGR_SEC_SHIFT) |
2151b104208SGatien Chevallier SHIFT_U32((cfg & DT_RISAF_ENC_MASK) >> (DT_RISAF_ENC_SHIFT + 1),
2161b104208SGatien Chevallier _RISAF_REG_CFGR_ENC_SHIFT) |
2171b104208SGatien Chevallier SHIFT_U32((cfg & DT_RISAF_PRIV_MASK) >> DT_RISAF_PRIV_SHIFT,
2181b104208SGatien Chevallier _RISAF_REG_CFGR_PRIVC_SHIFT);
2191b104208SGatien Chevallier }
2201b104208SGatien Chevallier
stm32_risaf_get_region_cid_config(uint32_t cfg)2211b104208SGatien Chevallier static uint32_t stm32_risaf_get_region_cid_config(uint32_t cfg)
2221b104208SGatien Chevallier {
2231b104208SGatien Chevallier return SHIFT_U32((cfg & DT_RISAF_WRITE_MASK) >> DT_RISAF_WRITE_SHIFT,
2241b104208SGatien Chevallier _RISAF_REG_CIDCFGR_WRENC_SHIFT) |
2251b104208SGatien Chevallier SHIFT_U32((cfg & DT_RISAF_READ_MASK) >> DT_RISAF_READ_SHIFT,
2261b104208SGatien Chevallier _RISAF_REG_CIDCFGR_RDENC_SHIFT);
2271b104208SGatien Chevallier }
2281b104208SGatien Chevallier
stm32_risaf_clear_illegal_access_flags(void)2291b104208SGatien Chevallier void stm32_risaf_clear_illegal_access_flags(void)
2301b104208SGatien Chevallier {
2311b104208SGatien Chevallier struct stm32_risaf_instance *risaf = NULL;
2321b104208SGatien Chevallier
2331b104208SGatien Chevallier SLIST_FOREACH(risaf, &risaf_list, link) {
2341b104208SGatien Chevallier vaddr_t base = io_pa_or_va_secure(&risaf->pdata.base, 1);
2351b104208SGatien Chevallier
2361b104208SGatien Chevallier if (!io_read32(base + _RISAF_IASR))
2371b104208SGatien Chevallier continue;
2381b104208SGatien Chevallier
2391b104208SGatien Chevallier io_write32(base + _RISAF_IACR, _RISAF_IACR_CAEF |
2401b104208SGatien Chevallier _RISAF_IACR_IAEF0 | _RISAF_IACR_IAEF1);
2411b104208SGatien Chevallier }
2421b104208SGatien Chevallier }
2431b104208SGatien Chevallier
stm32_risaf_print_erroneous_data(void)2441b104208SGatien Chevallier void stm32_risaf_print_erroneous_data(void)
2451b104208SGatien Chevallier {
2461b104208SGatien Chevallier struct stm32_risaf_instance *risaf = NULL;
2471b104208SGatien Chevallier
2481b104208SGatien Chevallier if (!IS_ENABLED(CFG_TEE_CORE_DEBUG))
2491b104208SGatien Chevallier return;
2501b104208SGatien Chevallier
2511b104208SGatien Chevallier SLIST_FOREACH(risaf, &risaf_list, link) {
2521b104208SGatien Chevallier vaddr_t base = io_pa_or_va_secure(&risaf->pdata.base, 1);
2531b104208SGatien Chevallier
2541b104208SGatien Chevallier /* Check if faulty address on this RISAF */
2551b104208SGatien Chevallier if (!io_read32(base + _RISAF_IASR))
2561b104208SGatien Chevallier continue;
2571b104208SGatien Chevallier
2581b104208SGatien Chevallier IMSG("\n\nDUMPING DATA FOR %s\n\n", risaf->pdata.risaf_name);
2591b104208SGatien Chevallier IMSG("=====================================================");
2601b104208SGatien Chevallier IMSG("Status register (IAESR0): %#"PRIx32,
2611b104208SGatien Chevallier io_read32(base + _RISAF_IAESR0));
2621b104208SGatien Chevallier
2631b104208SGatien Chevallier /* Reserved if dual port feature not available */
2641b104208SGatien Chevallier if (io_read32(base + _RISAF_IAESR1))
2651b104208SGatien Chevallier IMSG("Status register Dual Port (IAESR1) %#"PRIx32,
2661b104208SGatien Chevallier io_read32(base + _RISAF_IAESR1));
2671b104208SGatien Chevallier
2681b104208SGatien Chevallier IMSG("-----------------------------------------------------");
2691b104208SGatien Chevallier if (virt_to_phys((void *)base) == RISAF4_BASE) {
2701b104208SGatien Chevallier IMSG("Faulty address (IADDR0): %#"PRIxPA,
2711b104208SGatien Chevallier risaf->pdata.mem_base +
2721b104208SGatien Chevallier io_read32(base + _RISAF_IADDR0));
2731b104208SGatien Chevallier
2741b104208SGatien Chevallier /* Reserved if dual port feature not available */
2751b104208SGatien Chevallier if (io_read32(base + _RISAF_IADDR1))
2761b104208SGatien Chevallier IMSG("Dual port faulty address (IADDR1): %#"PRIxPA,
2771b104208SGatien Chevallier risaf->pdata.mem_base +
2781b104208SGatien Chevallier io_read32(base + _RISAF_IADDR1));
2791b104208SGatien Chevallier } else {
2801b104208SGatien Chevallier IMSG("Faulty address (IADDR0): %#"PRIx32,
2811b104208SGatien Chevallier io_read32(base + _RISAF_IADDR0));
2821b104208SGatien Chevallier
2831b104208SGatien Chevallier /* Reserved if dual port feature not available */
2841b104208SGatien Chevallier if (io_read32(base + _RISAF_IADDR1))
2851b104208SGatien Chevallier IMSG("Dual port faulty address (IADDR1): %#"PRIx32,
2861b104208SGatien Chevallier io_read32(base + _RISAF_IADDR1));
2871b104208SGatien Chevallier }
2881b104208SGatien Chevallier
2891b104208SGatien Chevallier IMSG("=====================================================\n");
2901b104208SGatien Chevallier };
2911b104208SGatien Chevallier }
2921b104208SGatien Chevallier
2931b104208SGatien Chevallier static __maybe_unused
risaf_is_hw_encryption_enabled(struct stm32_risaf_instance * risaf)2941b104208SGatien Chevallier bool risaf_is_hw_encryption_enabled(struct stm32_risaf_instance *risaf)
2951b104208SGatien Chevallier {
2961b104208SGatien Chevallier return (io_read32(risaf_base(risaf) + _RISAF_SR) &
2971b104208SGatien Chevallier _RISAF_SR_ENCDIS) != _RISAF_SR_ENCDIS;
2981b104208SGatien Chevallier }
2991b104208SGatien Chevallier
3001b104208SGatien Chevallier static TEE_Result
risaf_check_region_boundaries(struct stm32_risaf_instance * risaf,struct stm32_risaf_region * region)3011b104208SGatien Chevallier risaf_check_region_boundaries(struct stm32_risaf_instance *risaf,
3021b104208SGatien Chevallier struct stm32_risaf_region *region)
3031b104208SGatien Chevallier {
3041b104208SGatien Chevallier if (!core_is_buffer_inside(region->addr, region->len,
3051b104208SGatien Chevallier risaf->pdata.mem_base,
3061b104208SGatien Chevallier risaf->pdata.mem_size)) {
3071b104208SGatien Chevallier EMSG("Region %#"PRIxPA"..%#"PRIxPA" outside RISAF area %#"PRIxPA"...%#"PRIxPA,
3081b104208SGatien Chevallier region->addr, region->addr + region->len - 1,
3091b104208SGatien Chevallier risaf->pdata.mem_base,
3101b104208SGatien Chevallier risaf->pdata.mem_base + risaf->pdata.mem_size - 1);
3111b104208SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
3121b104208SGatien Chevallier }
3131b104208SGatien Chevallier
3141b104208SGatien Chevallier if (!risaf->ddata->granularity ||
3151b104208SGatien Chevallier (region->addr % risaf->ddata->granularity) ||
3161b104208SGatien Chevallier (region->len % risaf->ddata->granularity)) {
3171b104208SGatien Chevallier EMSG("RISAF %#"PRIxPA": start/end address granularity not respected",
3181b104208SGatien Chevallier risaf->pdata.base.pa);
3191b104208SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
3201b104208SGatien Chevallier }
3211b104208SGatien Chevallier
3221b104208SGatien Chevallier return TEE_SUCCESS;
3231b104208SGatien Chevallier }
3241b104208SGatien Chevallier
3251b104208SGatien Chevallier static TEE_Result
risaf_check_overlap(struct stm32_risaf_instance * risaf __maybe_unused,struct stm32_risaf_region * region,unsigned int index)3261b104208SGatien Chevallier risaf_check_overlap(struct stm32_risaf_instance *risaf __maybe_unused,
3271b104208SGatien Chevallier struct stm32_risaf_region *region, unsigned int index)
3281b104208SGatien Chevallier {
3291b104208SGatien Chevallier unsigned int i = 0;
3301b104208SGatien Chevallier
3311b104208SGatien Chevallier for (i = 0; i < index; i++) {
3321b104208SGatien Chevallier /* Skip region if there's no configuration */
3331b104208SGatien Chevallier if (!region[i].cfg)
3341b104208SGatien Chevallier continue;
3351b104208SGatien Chevallier
3361b104208SGatien Chevallier if (core_is_buffer_intersect(region[index].addr,
3371b104208SGatien Chevallier region[index].len,
3381b104208SGatien Chevallier region[i].addr,
3391b104208SGatien Chevallier region[i].len)) {
3401b104208SGatien Chevallier EMSG("RISAF %#"PRIxPA": Regions %u and %u overlap",
3411b104208SGatien Chevallier risaf->pdata.base.pa, index, i);
3421b104208SGatien Chevallier return TEE_ERROR_GENERIC;
3431b104208SGatien Chevallier }
3441b104208SGatien Chevallier }
3451b104208SGatien Chevallier
3461b104208SGatien Chevallier return TEE_SUCCESS;
3471b104208SGatien Chevallier }
3481b104208SGatien Chevallier
risaf_configure_region(struct stm32_risaf_instance * risaf,uint32_t region_id,uint32_t cfg,uint32_t cid_cfg,paddr_t saddr,paddr_t eaddr)3491b104208SGatien Chevallier static TEE_Result risaf_configure_region(struct stm32_risaf_instance *risaf,
3501b104208SGatien Chevallier uint32_t region_id, uint32_t cfg,
3511b104208SGatien Chevallier uint32_t cid_cfg, paddr_t saddr,
3521b104208SGatien Chevallier paddr_t eaddr)
3531b104208SGatien Chevallier {
3541b104208SGatien Chevallier uint32_t mask = risaf->ddata->mask_regions;
3551b104208SGatien Chevallier vaddr_t base = risaf_base(risaf);
3561b104208SGatien Chevallier
3571b104208SGatien Chevallier if (cfg & _RISAF_REG_CFGR_ENC) {
3581b104208SGatien Chevallier if (!risaf->pdata.enc_supported) {
3591b104208SGatien Chevallier EMSG("RISAF %#"PRIxPA": encryption feature error",
3601b104208SGatien Chevallier risaf->pdata.base.pa);
3611b104208SGatien Chevallier return TEE_ERROR_GENERIC;
3621b104208SGatien Chevallier }
3631b104208SGatien Chevallier
3641b104208SGatien Chevallier if ((cfg & _RISAF_REG_CFGR_SEC) != _RISAF_REG_CFGR_SEC) {
3651b104208SGatien Chevallier EMSG("RISAF %#"PRIxPA": encryption on non-secure area",
3661b104208SGatien Chevallier risaf->pdata.base.pa);
3671b104208SGatien Chevallier return TEE_ERROR_GENERIC;
3681b104208SGatien Chevallier }
3691b104208SGatien Chevallier }
3701b104208SGatien Chevallier
3711b104208SGatien Chevallier io_clrbits32(base + _RISAF_REG_CFGR(region_id), _RISAF_REG_CFGR_BREN);
3721b104208SGatien Chevallier
3731b104208SGatien Chevallier io_clrsetbits32(base + _RISAF_REG_STARTR(region_id), mask,
3741b104208SGatien Chevallier (saddr - risaf->pdata.mem_base) & mask);
3751b104208SGatien Chevallier io_clrsetbits32(base + _RISAF_REG_ENDR(region_id), mask,
3761b104208SGatien Chevallier (eaddr - risaf->pdata.mem_base) & mask);
3771b104208SGatien Chevallier io_clrsetbits32(base + _RISAF_REG_CIDCFGR(region_id),
3781b104208SGatien Chevallier _RISAF_REG_CIDCFGR_ALL_MASK,
3791b104208SGatien Chevallier cid_cfg & _RISAF_REG_CIDCFGR_ALL_MASK);
3801b104208SGatien Chevallier
3811b104208SGatien Chevallier io_clrsetbits32(base + _RISAF_REG_CFGR(region_id),
3821b104208SGatien Chevallier _RISAF_REG_CFGR_ALL_MASK,
3831b104208SGatien Chevallier cfg & _RISAF_REG_CFGR_ALL_MASK);
3841b104208SGatien Chevallier
3851b104208SGatien Chevallier DMSG("RISAF %#"PRIxPA": region %02"PRIu32" - start %#"PRIxPA
3861b104208SGatien Chevallier "- end %#"PRIxPA" - cfg %#08"PRIx32" - cidcfg %#08"PRIx32,
3871b104208SGatien Chevallier risaf->pdata.base.pa, region_id,
3881b104208SGatien Chevallier risaf->pdata.mem_base +
3891b104208SGatien Chevallier io_read32(base + _RISAF_REG_STARTR(region_id)),
3901b104208SGatien Chevallier risaf->pdata.mem_base +
3911b104208SGatien Chevallier io_read32(base + _RISAF_REG_ENDR(region_id)),
3921b104208SGatien Chevallier io_read32(base + _RISAF_REG_CFGR(region_id)),
3931b104208SGatien Chevallier io_read32(base + _RISAF_REG_CIDCFGR(region_id)));
3941b104208SGatien Chevallier
3951b104208SGatien Chevallier return TEE_SUCCESS;
3961b104208SGatien Chevallier }
3971b104208SGatien Chevallier
risaf_print_version(struct stm32_risaf_instance * risaf)3981b104208SGatien Chevallier static void risaf_print_version(struct stm32_risaf_instance *risaf)
3991b104208SGatien Chevallier {
4001b104208SGatien Chevallier vaddr_t base = risaf_base(risaf);
4011b104208SGatien Chevallier struct stm32_risaf_version __maybe_unused version = {
4021b104208SGatien Chevallier .major = (io_read32(base + _RISAF_VERR) &
4031b104208SGatien Chevallier _RISAF_VERR_MAJREV_MASK) >> _RISAF_VERR_MAJREV_SHIFT,
4041b104208SGatien Chevallier .minor = (io_read32(base + _RISAF_VERR) &
4051b104208SGatien Chevallier _RISAF_VERR_MINREV_MASK) >> _RISAF_VERR_MINREV_SHIFT,
4061b104208SGatien Chevallier .ip_id = io_read32(base + _RISAF_IPIDR),
4071b104208SGatien Chevallier .size_id = io_read32(base + _RISAF_SIDR)
4081b104208SGatien Chevallier };
4091b104208SGatien Chevallier
4101b104208SGatien Chevallier DMSG("RISAF %#"PRIxPA" version %"PRIu32".%"PRIu32", ip%#"PRIx32" size%#"PRIx32,
4111b104208SGatien Chevallier risaf->pdata.base.pa, version.major, version.minor, version.ip_id,
4121b104208SGatien Chevallier version.size_id);
4131b104208SGatien Chevallier }
4141b104208SGatien Chevallier
4151b104208SGatien Chevallier static __maybe_unused
stm32_risaf_lock(struct stm32_risaf_instance * risaf)4161b104208SGatien Chevallier void stm32_risaf_lock(struct stm32_risaf_instance *risaf)
4171b104208SGatien Chevallier {
4181b104208SGatien Chevallier assert(risaf);
4191b104208SGatien Chevallier
4201b104208SGatien Chevallier io_setbits32(risaf_base(risaf) + _RISAF_CR, _RISAF_CR_GLOCK);
4211b104208SGatien Chevallier }
4221b104208SGatien Chevallier
4231b104208SGatien Chevallier static __maybe_unused
stm32_risaf_is_locked(struct stm32_risaf_instance * risaf,bool * state)4241b104208SGatien Chevallier void stm32_risaf_is_locked(struct stm32_risaf_instance *risaf, bool *state)
4251b104208SGatien Chevallier {
4261b104208SGatien Chevallier assert(risaf);
4271b104208SGatien Chevallier
4281b104208SGatien Chevallier *state = (io_read32(risaf_base(risaf) + _RISAF_CR) &
4291b104208SGatien Chevallier _RISAF_CR_GLOCK) == _RISAF_CR_GLOCK;
4301b104208SGatien Chevallier }
4311b104208SGatien Chevallier
stm32_risaf_init_ddata(struct stm32_risaf_instance * risaf)4321b104208SGatien Chevallier static TEE_Result stm32_risaf_init_ddata(struct stm32_risaf_instance *risaf)
4331b104208SGatien Chevallier {
4341b104208SGatien Chevallier vaddr_t base = risaf_base(risaf);
4351b104208SGatien Chevallier uint32_t granularity = 0;
4361b104208SGatien Chevallier uint32_t mask_lsb = 0;
4371b104208SGatien Chevallier uint32_t mask_msb = 0;
4381b104208SGatien Chevallier uint32_t hwcfgr = 0;
4391b104208SGatien Chevallier
4401b104208SGatien Chevallier risaf->ddata = calloc(1, sizeof(*risaf->ddata));
4411b104208SGatien Chevallier if (!risaf->ddata)
4421b104208SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY;
4431b104208SGatien Chevallier
4441b104208SGatien Chevallier /* Get address mask depending on RISAF instance HW configuration */
4451b104208SGatien Chevallier hwcfgr = io_read32(base + _RISAF_HWCFGR);
4461b104208SGatien Chevallier mask_lsb = (hwcfgr & _RISAF_HWCFGR_CFG3_MASK) >>
4471b104208SGatien Chevallier _RISAF_HWCFGR_CFG3_SHIFT;
4481b104208SGatien Chevallier mask_msb = mask_lsb + ((hwcfgr & _RISAF_HWCFGR_CFG4_MASK) >>
4491b104208SGatien Chevallier _RISAF_HWCFGR_CFG4_SHIFT) - 1U;
4501b104208SGatien Chevallier risaf->ddata->mask_regions = GENMASK_32(mask_msb, mask_lsb);
4511b104208SGatien Chevallier risaf->ddata->max_base_regions = (hwcfgr & _RISAF_HWCFGR_CFG1_MASK) >>
4521b104208SGatien Chevallier _RISAF_HWCFGR_CFG1_SHIFT;
4531b104208SGatien Chevallier
4541b104208SGatien Chevallier /* Get IP region granularity */
4551b104208SGatien Chevallier granularity = io_read32(risaf_base(risaf) + _RISAF_HWCFGR);
4561b104208SGatien Chevallier granularity = BIT((granularity & _RISAF_HWCFGR_CFG3_MASK) >>
4571b104208SGatien Chevallier _RISAF_HWCFGR_CFG3_SHIFT);
4581b104208SGatien Chevallier risaf->ddata->granularity = granularity;
4591b104208SGatien Chevallier
4601b104208SGatien Chevallier return TEE_SUCCESS;
4611b104208SGatien Chevallier }
4621b104208SGatien Chevallier
stm32_risaf_pm_resume(struct stm32_risaf_instance * risaf)4631b104208SGatien Chevallier static TEE_Result stm32_risaf_pm_resume(struct stm32_risaf_instance *risaf)
4641b104208SGatien Chevallier {
4651b104208SGatien Chevallier struct stm32_risaf_region *regions = risaf->pdata.regions;
4661b104208SGatien Chevallier size_t i = 0;
4671b104208SGatien Chevallier
4681b104208SGatien Chevallier for (i = 0; i < risaf->pdata.nregions; i++) {
4691b104208SGatien Chevallier uint32_t id = _RISAF_GET_REGION_ID(regions[i].cfg);
4701b104208SGatien Chevallier paddr_t start_addr = 0;
4711b104208SGatien Chevallier paddr_t end_addr = 0;
4721b104208SGatien Chevallier uint32_t cid_cfg = 0;
4731b104208SGatien Chevallier uint32_t cfg = 0;
4741b104208SGatien Chevallier
4751b104208SGatien Chevallier if (!id)
4761b104208SGatien Chevallier continue;
4771b104208SGatien Chevallier
4781b104208SGatien Chevallier cfg = stm32_risaf_get_region_config(regions[i].cfg);
4791b104208SGatien Chevallier cid_cfg = stm32_risaf_get_region_cid_config(regions[i].cfg);
4801b104208SGatien Chevallier start_addr = regions[i].addr;
4811b104208SGatien Chevallier end_addr = start_addr + regions[i].len - 1U;
4821b104208SGatien Chevallier if (risaf_configure_region(risaf, id, cfg, cid_cfg,
4831b104208SGatien Chevallier start_addr, end_addr))
4841b104208SGatien Chevallier panic();
4851b104208SGatien Chevallier }
4861b104208SGatien Chevallier
4871b104208SGatien Chevallier return TEE_SUCCESS;
4881b104208SGatien Chevallier }
4891b104208SGatien Chevallier
stm32_risaf_pm_suspend(struct stm32_risaf_instance * risaf)4901b104208SGatien Chevallier static TEE_Result stm32_risaf_pm_suspend(struct stm32_risaf_instance *risaf)
4911b104208SGatien Chevallier {
4921b104208SGatien Chevallier vaddr_t base = io_pa_or_va_secure(&risaf->pdata.base, 1);
4931b104208SGatien Chevallier size_t i = 0;
4941b104208SGatien Chevallier
4951b104208SGatien Chevallier for (i = 0; i < risaf->pdata.nregions; i++) {
4961b104208SGatien Chevallier uint32_t id = _RISAF_GET_REGION_ID(risaf->pdata.regions[i].cfg);
4971b104208SGatien Chevallier struct stm32_risaf_region *region = risaf->pdata.regions + i;
4981b104208SGatien Chevallier paddr_t start_addr = 0;
4991b104208SGatien Chevallier paddr_t end_addr = 0;
5001b104208SGatien Chevallier uint32_t cid_cfg = 0;
5011b104208SGatien Chevallier uint32_t priv = 0;
5021b104208SGatien Chevallier uint32_t rden = 0;
5031b104208SGatien Chevallier uint32_t wren = 0;
5041b104208SGatien Chevallier uint32_t cfg = 0;
5051b104208SGatien Chevallier uint32_t enc = 0;
5061b104208SGatien Chevallier uint32_t sec = 0;
5071b104208SGatien Chevallier uint32_t en = 0;
5081b104208SGatien Chevallier
5091b104208SGatien Chevallier /* Skip region not defined in DT, not configured in probe */
5101b104208SGatien Chevallier if (!id)
5111b104208SGatien Chevallier continue;
5121b104208SGatien Chevallier
5131b104208SGatien Chevallier cfg = io_read32(base + _RISAF_REG_CFGR(id));
5141b104208SGatien Chevallier en = cfg & _RISAF_REG_CFGR_BREN;
5151b104208SGatien Chevallier sec = (cfg & _RISAF_REG_CFGR_SEC) >> _RISAF_REG_CFGR_SEC_SHIFT;
5161b104208SGatien Chevallier enc = (cfg & _RISAF_REG_CFGR_ENC) >> _RISAF_REG_CFGR_ENC_SHIFT;
5171b104208SGatien Chevallier priv = (cfg & _RISAF_REG_CFGR_PRIVC_MASK) >>
5181b104208SGatien Chevallier _RISAF_REG_CFGR_PRIVC_SHIFT;
5191b104208SGatien Chevallier
5201b104208SGatien Chevallier cid_cfg = io_read32(base + _RISAF_REG_CIDCFGR(id));
5211b104208SGatien Chevallier rden = cid_cfg & _RISAF_REG_CIDCFGR_RDENC_MASK;
5221b104208SGatien Chevallier wren = (cid_cfg & _RISAF_REG_CIDCFGR_WRENC_MASK) >>
5231b104208SGatien Chevallier _RISAF_REG_CIDCFGR_WRENC_SHIFT;
5241b104208SGatien Chevallier
5251b104208SGatien Chevallier region->cfg = id | SHIFT_U32(en, DT_RISAF_EN_SHIFT) |
5261b104208SGatien Chevallier SHIFT_U32(sec, DT_RISAF_SEC_SHIFT) |
5271b104208SGatien Chevallier SHIFT_U32(enc, DT_RISAF_ENC_SHIFT + 1) |
5281b104208SGatien Chevallier SHIFT_U32(priv, DT_RISAF_PRIV_SHIFT) |
5291b104208SGatien Chevallier SHIFT_U32(rden, DT_RISAF_READ_SHIFT) |
5301b104208SGatien Chevallier SHIFT_U32(wren, DT_RISAF_WRITE_SHIFT);
5311b104208SGatien Chevallier start_addr = io_read32(base + _RISAF_REG_STARTR(id));
5321b104208SGatien Chevallier end_addr = io_read32(base + _RISAF_REG_ENDR(id));
5331b104208SGatien Chevallier region->addr = start_addr + risaf->pdata.mem_base;
5341b104208SGatien Chevallier region->len = end_addr - start_addr + 1;
5351b104208SGatien Chevallier }
5361b104208SGatien Chevallier
5371b104208SGatien Chevallier return TEE_SUCCESS;
5381b104208SGatien Chevallier }
5391b104208SGatien Chevallier
5401b104208SGatien Chevallier static TEE_Result
stm32_risaf_pm(enum pm_op op,unsigned int pm_hint,const struct pm_callback_handle * pm_handle)5411b104208SGatien Chevallier stm32_risaf_pm(enum pm_op op, unsigned int pm_hint,
5421b104208SGatien Chevallier const struct pm_callback_handle *pm_handle)
5431b104208SGatien Chevallier {
5441b104208SGatien Chevallier struct stm32_risaf_instance *risaf = pm_handle->handle;
5451b104208SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
5461b104208SGatien Chevallier
5471b104208SGatien Chevallier assert(risaf);
5481b104208SGatien Chevallier
5491b104208SGatien Chevallier if (!PM_HINT_IS_STATE(pm_hint, CONTEXT))
5501b104208SGatien Chevallier return TEE_SUCCESS;
5511b104208SGatien Chevallier
5521b104208SGatien Chevallier if (op == PM_OP_RESUME)
5531b104208SGatien Chevallier res = stm32_risaf_pm_resume(risaf);
5541b104208SGatien Chevallier else
5551b104208SGatien Chevallier res = stm32_risaf_pm_suspend(risaf);
5561b104208SGatien Chevallier
5571b104208SGatien Chevallier return res;
5581b104208SGatien Chevallier }
5591b104208SGatien Chevallier
stm32_risaf_acquire_access(struct firewall_query * fw,paddr_t paddr,size_t size,bool read,bool write)560*e78e87a9SGatien Chevallier static TEE_Result stm32_risaf_acquire_access(struct firewall_query *fw,
561*e78e87a9SGatien Chevallier paddr_t paddr, size_t size,
562*e78e87a9SGatien Chevallier bool read, bool write)
563*e78e87a9SGatien Chevallier {
564*e78e87a9SGatien Chevallier struct stm32_risaf_instance *risaf = NULL;
565*e78e87a9SGatien Chevallier struct stm32_risaf_region *region = NULL;
566*e78e87a9SGatien Chevallier uint32_t cidcfgr = 0;
567*e78e87a9SGatien Chevallier unsigned int i = 0;
568*e78e87a9SGatien Chevallier uint32_t cfgr = 0;
569*e78e87a9SGatien Chevallier vaddr_t base = 0;
570*e78e87a9SGatien Chevallier uint32_t id = 0;
571*e78e87a9SGatien Chevallier
572*e78e87a9SGatien Chevallier assert(fw->ctrl->priv && (read || write));
573*e78e87a9SGatien Chevallier
574*e78e87a9SGatien Chevallier if (paddr == TZDRAM_BASE && size == TZDRAM_SIZE)
575*e78e87a9SGatien Chevallier return TEE_SUCCESS;
576*e78e87a9SGatien Chevallier
577*e78e87a9SGatien Chevallier risaf = fw->ctrl->priv;
578*e78e87a9SGatien Chevallier base = risaf_base(risaf);
579*e78e87a9SGatien Chevallier
580*e78e87a9SGatien Chevallier if (fw->arg_count != 1)
581*e78e87a9SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
582*e78e87a9SGatien Chevallier
583*e78e87a9SGatien Chevallier /*
584*e78e87a9SGatien Chevallier * RISAF region configuration, we assume the query is as
585*e78e87a9SGatien Chevallier * follows:
586*e78e87a9SGatien Chevallier * firewall->args[0]: Region configuration
587*e78e87a9SGatien Chevallier */
588*e78e87a9SGatien Chevallier id = _RISAF_GET_REGION_ID(fw->args[0]);
589*e78e87a9SGatien Chevallier
590*e78e87a9SGatien Chevallier if (!id || id >= risaf->pdata.nregions)
591*e78e87a9SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
592*e78e87a9SGatien Chevallier
593*e78e87a9SGatien Chevallier for (i = 0; i < risaf->pdata.nregions; i++) {
594*e78e87a9SGatien Chevallier if (id == _RISAF_GET_REGION_ID(risaf->pdata.regions[i].cfg)) {
595*e78e87a9SGatien Chevallier region = &risaf->pdata.regions[i];
596*e78e87a9SGatien Chevallier if (region->addr != paddr || region->len != size)
597*e78e87a9SGatien Chevallier return TEE_ERROR_GENERIC;
598*e78e87a9SGatien Chevallier break;
599*e78e87a9SGatien Chevallier }
600*e78e87a9SGatien Chevallier }
601*e78e87a9SGatien Chevallier if (!region)
602*e78e87a9SGatien Chevallier return TEE_ERROR_ITEM_NOT_FOUND;
603*e78e87a9SGatien Chevallier
604*e78e87a9SGatien Chevallier cfgr = io_read32(base + _RISAF_REG_CFGR(id));
605*e78e87a9SGatien Chevallier cidcfgr = io_read32(base + _RISAF_REG_CIDCFGR(id));
606*e78e87a9SGatien Chevallier
607*e78e87a9SGatien Chevallier /*
608*e78e87a9SGatien Chevallier * Access is denied if the region is disabled and OP-TEE does not run as
609*e78e87a9SGatien Chevallier * TDCID, or the region is not secure, or if it is not accessible in
610*e78e87a9SGatien Chevallier * read and/or write mode, if requested, by OP-TEE CID.
611*e78e87a9SGatien Chevallier */
612*e78e87a9SGatien Chevallier if (!(cfgr & _RISAF_REG_CFGR_BREN) && !is_tdcid)
613*e78e87a9SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
614*e78e87a9SGatien Chevallier
615*e78e87a9SGatien Chevallier if ((cfgr & _RISAF_REG_CFGR_BREN) &&
616*e78e87a9SGatien Chevallier (!(cfgr & _RISAF_REG_CFGR_SEC) ||
617*e78e87a9SGatien Chevallier (read && !_RISAF_REG_READ_OK(cidcfgr, RIF_CID1)) ||
618*e78e87a9SGatien Chevallier (write && !_RISAF_REG_WRITE_OK(cidcfgr, RIF_CID1)))) {
619*e78e87a9SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
620*e78e87a9SGatien Chevallier }
621*e78e87a9SGatien Chevallier
622*e78e87a9SGatien Chevallier return TEE_SUCCESS;
623*e78e87a9SGatien Chevallier }
624*e78e87a9SGatien Chevallier
stm32_risaf_reconfigure_region(struct firewall_query * fw,paddr_t paddr,size_t size)625*e78e87a9SGatien Chevallier static TEE_Result stm32_risaf_reconfigure_region(struct firewall_query *fw,
626*e78e87a9SGatien Chevallier paddr_t paddr, size_t size)
627*e78e87a9SGatien Chevallier {
628*e78e87a9SGatien Chevallier struct stm32_risaf_instance *risaf = NULL;
629*e78e87a9SGatien Chevallier struct stm32_risaf_region *region = NULL;
630*e78e87a9SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
631*e78e87a9SGatien Chevallier uint32_t exceptions = 0;
632*e78e87a9SGatien Chevallier uint32_t q_cfg = 0;
633*e78e87a9SGatien Chevallier unsigned int i = 0;
634*e78e87a9SGatien Chevallier uint32_t id = 0;
635*e78e87a9SGatien Chevallier
636*e78e87a9SGatien Chevallier assert(fw->ctrl->priv);
637*e78e87a9SGatien Chevallier
638*e78e87a9SGatien Chevallier risaf = fw->ctrl->priv;
639*e78e87a9SGatien Chevallier
640*e78e87a9SGatien Chevallier if (fw->arg_count != 1)
641*e78e87a9SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
642*e78e87a9SGatien Chevallier
643*e78e87a9SGatien Chevallier /*
644*e78e87a9SGatien Chevallier * RISAF region configuration, we assume the query is as
645*e78e87a9SGatien Chevallier * follows:
646*e78e87a9SGatien Chevallier * firewall->args[0]: Region configuration
647*e78e87a9SGatien Chevallier */
648*e78e87a9SGatien Chevallier q_cfg = fw->args[0];
649*e78e87a9SGatien Chevallier id = _RISAF_GET_REGION_ID(q_cfg);
650*e78e87a9SGatien Chevallier
651*e78e87a9SGatien Chevallier if (!id || id >= risaf->pdata.nregions)
652*e78e87a9SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
653*e78e87a9SGatien Chevallier
654*e78e87a9SGatien Chevallier for (i = 0; i < risaf->pdata.nregions; i++) {
655*e78e87a9SGatien Chevallier if (id == _RISAF_GET_REGION_ID(risaf->pdata.regions[i].cfg)) {
656*e78e87a9SGatien Chevallier region = &risaf->pdata.regions[i];
657*e78e87a9SGatien Chevallier if (region->addr != paddr || region->len != size)
658*e78e87a9SGatien Chevallier return TEE_ERROR_GENERIC;
659*e78e87a9SGatien Chevallier break;
660*e78e87a9SGatien Chevallier }
661*e78e87a9SGatien Chevallier }
662*e78e87a9SGatien Chevallier if (!region)
663*e78e87a9SGatien Chevallier return TEE_ERROR_ITEM_NOT_FOUND;
664*e78e87a9SGatien Chevallier
665*e78e87a9SGatien Chevallier DMSG("Reconfiguring %s region ID: %"PRIu32, risaf->pdata.risaf_name,
666*e78e87a9SGatien Chevallier id);
667*e78e87a9SGatien Chevallier
668*e78e87a9SGatien Chevallier exceptions = cpu_spin_lock_xsave(&risaf->pdata.conf_lock);
669*e78e87a9SGatien Chevallier res = risaf_configure_region(risaf, id,
670*e78e87a9SGatien Chevallier stm32_risaf_get_region_config(q_cfg),
671*e78e87a9SGatien Chevallier stm32_risaf_get_region_cid_config(q_cfg),
672*e78e87a9SGatien Chevallier region->addr,
673*e78e87a9SGatien Chevallier region->addr + region->len - 1);
674*e78e87a9SGatien Chevallier
675*e78e87a9SGatien Chevallier cpu_spin_unlock_xrestore(&risaf->pdata.conf_lock, exceptions);
676*e78e87a9SGatien Chevallier
677*e78e87a9SGatien Chevallier return res;
678*e78e87a9SGatien Chevallier }
679*e78e87a9SGatien Chevallier
680*e78e87a9SGatien Chevallier static const struct firewall_controller_ops firewall_ops = {
681*e78e87a9SGatien Chevallier .acquire_memory_access = stm32_risaf_acquire_access,
682*e78e87a9SGatien Chevallier .set_memory_conf = stm32_risaf_reconfigure_region,
683*e78e87a9SGatien Chevallier };
684*e78e87a9SGatien Chevallier
stm32_risaf_probe(const void * fdt,int node,const void * compat_data)6851b104208SGatien Chevallier static TEE_Result stm32_risaf_probe(const void *fdt, int node,
6861b104208SGatien Chevallier const void *compat_data)
6871b104208SGatien Chevallier {
6881b104208SGatien Chevallier const struct stm32_risaf_compat_data *compat = compat_data;
689*e78e87a9SGatien Chevallier struct firewall_controller *controller = NULL;
6901b104208SGatien Chevallier struct stm32_risaf_instance *risaf = NULL;
6911b104208SGatien Chevallier struct stm32_risaf_region *regions = NULL;
6921b104208SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
6931b104208SGatien Chevallier struct dt_node_info dt_info = { };
6941b104208SGatien Chevallier const fdt32_t *conf_list = NULL;
6951b104208SGatien Chevallier const fdt64_t *cuint = NULL;
6961b104208SGatien Chevallier unsigned int nregions = 0;
6971b104208SGatien Chevallier unsigned int i = 0;
6981b104208SGatien Chevallier int len = 0;
6991b104208SGatien Chevallier
7001b104208SGatien Chevallier res = stm32_rifsc_check_tdcid(&is_tdcid);
7011b104208SGatien Chevallier if (res)
7021b104208SGatien Chevallier return res;
7031b104208SGatien Chevallier
7041b104208SGatien Chevallier if (!is_tdcid)
7051b104208SGatien Chevallier return TEE_SUCCESS;
7061b104208SGatien Chevallier
7071b104208SGatien Chevallier risaf = calloc(1, sizeof(*risaf));
7081b104208SGatien Chevallier if (!risaf)
7091b104208SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY;
7101b104208SGatien Chevallier
7111b104208SGatien Chevallier fdt_fill_device_info(fdt, &dt_info, node);
7121b104208SGatien Chevallier if (dt_info.reg == DT_INFO_INVALID_REG ||
7131b104208SGatien Chevallier dt_info.reg_size == DT_INFO_INVALID_REG_SIZE) {
7141b104208SGatien Chevallier free(risaf);
7151b104208SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
7161b104208SGatien Chevallier }
7171b104208SGatien Chevallier
7181b104208SGatien Chevallier risaf->pdata.base.pa = dt_info.reg;
7191b104208SGatien Chevallier io_pa_or_va_secure(&risaf->pdata.base, dt_info.reg_size);
7201b104208SGatien Chevallier
7211b104208SGatien Chevallier risaf->pdata.enc_supported = compat->supported_encryption;
7221b104208SGatien Chevallier
7231b104208SGatien Chevallier res = clk_dt_get_by_index(fdt, node, 0, &risaf->pdata.clock);
7241b104208SGatien Chevallier if (!risaf->pdata.clock)
7251b104208SGatien Chevallier goto err;
7261b104208SGatien Chevallier
7271b104208SGatien Chevallier conf_list = fdt_getprop(fdt, node, "memory-region", &len);
7281b104208SGatien Chevallier if (!conf_list) {
7291b104208SGatien Chevallier DMSG("RISAF %#"PRIxPA": No configuration in DT, use default",
7301b104208SGatien Chevallier risaf->pdata.base.pa);
7311b104208SGatien Chevallier free(risaf);
7321b104208SGatien Chevallier return TEE_SUCCESS;
7331b104208SGatien Chevallier }
7341b104208SGatien Chevallier
7351b104208SGatien Chevallier nregions = (unsigned int)len / sizeof(uint32_t);
7361b104208SGatien Chevallier
7371b104208SGatien Chevallier /* Silently allow unexpected truncated names */
7381b104208SGatien Chevallier strncpy(risaf->pdata.risaf_name, fdt_get_name(fdt, node, NULL),
7391b104208SGatien Chevallier sizeof(risaf->pdata.risaf_name) - 1);
7401b104208SGatien Chevallier
7411b104208SGatien Chevallier res = clk_enable(risaf->pdata.clock);
7421b104208SGatien Chevallier if (res)
7431b104208SGatien Chevallier goto err;
7441b104208SGatien Chevallier
7451b104208SGatien Chevallier res = stm32_risaf_init_ddata(risaf);
7461b104208SGatien Chevallier if (res)
7471b104208SGatien Chevallier goto err_clk;
7481b104208SGatien Chevallier
7491b104208SGatien Chevallier risaf_print_version(risaf);
7501b104208SGatien Chevallier
7511b104208SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,mem-map", &len);
7521b104208SGatien Chevallier if (!cuint || (size_t)len != sizeof(*cuint) * 2)
7531b104208SGatien Chevallier panic();
7541b104208SGatien Chevallier
7551b104208SGatien Chevallier risaf->pdata.mem_base = (paddr_t)fdt64_to_cpu(*cuint);
7561b104208SGatien Chevallier risaf->pdata.mem_size = (size_t)fdt64_to_cpu(*(cuint + 1));
7571b104208SGatien Chevallier
7581b104208SGatien Chevallier regions = calloc(nregions, sizeof(*regions));
7591b104208SGatien Chevallier if (nregions && !regions) {
7601b104208SGatien Chevallier res = TEE_ERROR_OUT_OF_MEMORY;
7611b104208SGatien Chevallier goto err_ddata;
7621b104208SGatien Chevallier }
7631b104208SGatien Chevallier
7641b104208SGatien Chevallier DMSG("RISAF %#"PRIxPA" memory range: %#"PRIxPA" - %#"PRIxPA,
7651b104208SGatien Chevallier risaf->pdata.base.pa, risaf->pdata.mem_base,
7661b104208SGatien Chevallier risaf->pdata.mem_base + risaf->pdata.mem_size - 1);
7671b104208SGatien Chevallier
7681b104208SGatien Chevallier for (i = 0; i < nregions; i++) {
7691b104208SGatien Chevallier const fdt32_t *prop = NULL;
7701b104208SGatien Chevallier paddr_t start_addr = 0;
7711b104208SGatien Chevallier paddr_t end_addr = 0;
7721b104208SGatien Chevallier uint32_t cid_cfg = 0;
7731b104208SGatien Chevallier uint32_t phandle = 0;
7741b104208SGatien Chevallier uint32_t cfg = 0;
7751b104208SGatien Chevallier uint32_t id = 0;
7761b104208SGatien Chevallier int pnode = 0;
7771b104208SGatien Chevallier
7781b104208SGatien Chevallier phandle = fdt32_to_cpu(*(conf_list + i));
7791b104208SGatien Chevallier pnode = fdt_node_offset_by_phandle(fdt, phandle);
7801b104208SGatien Chevallier if (pnode < 0)
7811b104208SGatien Chevallier continue;
7821b104208SGatien Chevallier
7836a0116edSEtienne Carriere if (fdt_reg_info(fdt, pnode, ®ions[i].addr,
7846a0116edSEtienne Carriere ®ions[i].len)) {
7856a0116edSEtienne Carriere EMSG("Invalid config in node %s",
7866a0116edSEtienne Carriere fdt_get_name(fdt, pnode, NULL));
7876a0116edSEtienne Carriere panic();
7886a0116edSEtienne Carriere }
7891b104208SGatien Chevallier
7901b104208SGatien Chevallier if (!regions[i].len)
7911b104208SGatien Chevallier continue;
7921b104208SGatien Chevallier
7931b104208SGatien Chevallier /*
7941b104208SGatien Chevallier * The secure bootloader is in charge of configuring RISAF
7951b104208SGatien Chevallier * related to OP-TEE secure memory. Therefore, skip OP-TEE
7961b104208SGatien Chevallier * region so that RISAF configuration cannot interfere with
7971b104208SGatien Chevallier * OP-TEE execution flow.
7981b104208SGatien Chevallier */
7991b104208SGatien Chevallier if (regions[i].addr == TZDRAM_BASE &&
8001b104208SGatien Chevallier regions[i].len == TZDRAM_SIZE) {
8011b104208SGatien Chevallier continue;
8021b104208SGatien Chevallier }
8031b104208SGatien Chevallier
8041b104208SGatien Chevallier prop = fdt_getprop(fdt, pnode, "st,protreg", NULL);
8051b104208SGatien Chevallier if (!prop)
8061b104208SGatien Chevallier continue;
8071b104208SGatien Chevallier
8081b104208SGatien Chevallier regions[i].cfg = fdt32_to_cpu(*prop);
8091b104208SGatien Chevallier
8101b104208SGatien Chevallier if (risaf_check_region_boundaries(risaf, ®ions[i]) ||
8111b104208SGatien Chevallier risaf_check_overlap(risaf, regions, i))
8121b104208SGatien Chevallier panic();
8131b104208SGatien Chevallier
8141b104208SGatien Chevallier id = _RISAF_GET_REGION_ID(regions[i].cfg);
8151b104208SGatien Chevallier assert(id < risaf->ddata->max_base_regions);
8161b104208SGatien Chevallier
8171b104208SGatien Chevallier cfg = stm32_risaf_get_region_config(regions[i].cfg);
8181b104208SGatien Chevallier
8191b104208SGatien Chevallier cid_cfg = stm32_risaf_get_region_cid_config(regions[i].cfg);
8201b104208SGatien Chevallier
8211b104208SGatien Chevallier start_addr = regions[i].addr;
8221b104208SGatien Chevallier end_addr = start_addr + regions[i].len - 1U;
8231b104208SGatien Chevallier
8241b104208SGatien Chevallier if (risaf_configure_region(risaf, id, cfg, cid_cfg,
8251b104208SGatien Chevallier start_addr, end_addr))
8261b104208SGatien Chevallier panic();
8271b104208SGatien Chevallier }
8281b104208SGatien Chevallier
829*e78e87a9SGatien Chevallier controller = calloc(1, sizeof(*controller));
830*e78e87a9SGatien Chevallier if (!controller)
831*e78e87a9SGatien Chevallier panic();
832*e78e87a9SGatien Chevallier
833*e78e87a9SGatien Chevallier controller->base = &risaf->pdata.base;
834*e78e87a9SGatien Chevallier controller->name = risaf->pdata.risaf_name;
835*e78e87a9SGatien Chevallier controller->priv = risaf;
836*e78e87a9SGatien Chevallier controller->ops = &firewall_ops;
837*e78e87a9SGatien Chevallier
8381b104208SGatien Chevallier risaf->pdata.regions = regions;
8391b104208SGatien Chevallier risaf->pdata.nregions = nregions;
8401b104208SGatien Chevallier
8411b104208SGatien Chevallier SLIST_INSERT_HEAD(&risaf_list, risaf, link);
8421b104208SGatien Chevallier
843*e78e87a9SGatien Chevallier res = firewall_dt_controller_register(fdt, node, controller);
844*e78e87a9SGatien Chevallier if (res)
845*e78e87a9SGatien Chevallier panic();
846*e78e87a9SGatien Chevallier
8471b104208SGatien Chevallier register_pm_core_service_cb(stm32_risaf_pm, risaf, "stm32-risaf");
8481b104208SGatien Chevallier
8491b104208SGatien Chevallier return TEE_SUCCESS;
8501b104208SGatien Chevallier
8511b104208SGatien Chevallier err_ddata:
8521b104208SGatien Chevallier free(risaf->ddata);
8531b104208SGatien Chevallier err_clk:
8541b104208SGatien Chevallier clk_disable(risaf->pdata.clock);
8551b104208SGatien Chevallier err:
8561b104208SGatien Chevallier free(risaf);
8571b104208SGatien Chevallier return res;
8581b104208SGatien Chevallier }
8591b104208SGatien Chevallier
8601b104208SGatien Chevallier static const struct dt_device_match risaf_match_table[] = {
8611b104208SGatien Chevallier {
8621b104208SGatien Chevallier .compatible = "st,stm32mp25-risaf",
8631b104208SGatien Chevallier .compat_data = &stm32_risaf_compat,
8641b104208SGatien Chevallier },
8651b104208SGatien Chevallier {
8661b104208SGatien Chevallier .compatible = "st,stm32mp25-risaf-enc",
8671b104208SGatien Chevallier .compat_data = &stm32_risaf_enc_compat,
8681b104208SGatien Chevallier },
8691b104208SGatien Chevallier { }
8701b104208SGatien Chevallier };
8711b104208SGatien Chevallier
8721b104208SGatien Chevallier DEFINE_DT_DRIVER(risaf_dt_driver) = {
8731b104208SGatien Chevallier .name = "stm32-risaf",
8741b104208SGatien Chevallier .match_table = risaf_match_table,
8751b104208SGatien Chevallier .probe = stm32_risaf_probe,
8761b104208SGatien Chevallier };
877