1cd187630SGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2cd187630SGatien Chevallier /*
3cd187630SGatien Chevallier * Copyright (c) 2021-2024, STMicroelectronics
4cd187630SGatien Chevallier */
5cd187630SGatien Chevallier
6471cec14SGatien Chevallier #include <drivers/firewall.h>
7cd187630SGatien Chevallier #include <drivers/stm32_rif.h>
8471cec14SGatien Chevallier #include <drivers/stm32_shared_io.h>
9cd187630SGatien Chevallier #include <drivers/stm32mp_dt_bindings.h>
10cd187630SGatien Chevallier #include <io.h>
11cd187630SGatien Chevallier #include <kernel/boot.h>
12cd187630SGatien Chevallier #include <kernel/dt.h>
13cd187630SGatien Chevallier #include <kernel/dt_driver.h>
14cd187630SGatien Chevallier #include <kernel/panic.h>
15cd187630SGatien Chevallier #include <kernel/pm.h>
16cd187630SGatien Chevallier #include <libfdt.h>
17cd187630SGatien Chevallier #include <mm/core_memprot.h>
18a6a331e5SGatien Chevallier #include <stm32_util.h>
19cd187630SGatien Chevallier #include <tee_api_defines.h>
20cd187630SGatien Chevallier #include <trace.h>
21cd187630SGatien Chevallier #include <util.h>
22cd187630SGatien Chevallier
23cd187630SGatien Chevallier /* RIFSC offset register */
24cd187630SGatien Chevallier #define _RIFSC_RISC_SECCFGR0 U(0x10)
25cd187630SGatien Chevallier #define _RIFSC_RISC_PRIVCFGR0 U(0x30)
26cd187630SGatien Chevallier #define _RIFSC_RISC_RCFGLOCKR0 U(0x50)
27cd187630SGatien Chevallier #define _RIFSC_RISC_PER0_CIDCFGR U(0x100)
28cd187630SGatien Chevallier #define _RIFSC_RISC_PER0_SEMCR U(0x104)
29cd187630SGatien Chevallier #define _RIFSC_RIMC_CR U(0xC00)
30cd187630SGatien Chevallier #define _RIFSC_RIMC_ATTR0 U(0xC10)
31bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
32662542c7SGwenael Treuveur #define _RIFSC_RISAL_CFGR0_A(y) (U(0x900) + (0x10 * ((y) - 1)))
33662542c7SGwenael Treuveur #define _RIFSC_RISAL_CFGR0_B(y) (U(0x908) + (0x10 * ((y) - 1)))
34662542c7SGwenael Treuveur #define _RIFSC_RISAL_ADDR_A U(0x924)
35662542c7SGwenael Treuveur #define _RIFSC_RISAL_ADDR_B U(0x92C)
36bc951da9SThomas Bourgoin #endif /* CFG_STM32MP25 */
37cd187630SGatien Chevallier #define _RIFSC_HWCFGR3 U(0xFE8)
38cd187630SGatien Chevallier #define _RIFSC_HWCFGR2 U(0xFEC)
39cd187630SGatien Chevallier #define _RIFSC_HWCFGR1 U(0xFF0)
40cd187630SGatien Chevallier #define _RIFSC_VERR U(0xFF4)
41cd187630SGatien Chevallier
42cd187630SGatien Chevallier /* RIFSC_HWCFGR2 register fields */
43cd187630SGatien Chevallier #define _RIFSC_HWCFGR2_CFG1_MASK GENMASK_32(15, 0)
44cd187630SGatien Chevallier #define _RIFSC_HWCFGR2_CFG1_SHIFT U(0)
45cd187630SGatien Chevallier #define _RIFSC_HWCFGR2_CFG2_MASK GENMASK_32(23, 16)
46cd187630SGatien Chevallier #define _RIFSC_HWCFGR2_CFG2_SHIFT U(16)
47cd187630SGatien Chevallier #define _RIFSC_HWCFGR2_CFG3_MASK GENMASK_32(31, 24)
48cd187630SGatien Chevallier #define _RIFSC_HWCFGR2_CFG3_SHIFT U(24)
49cd187630SGatien Chevallier
50cd187630SGatien Chevallier /* RIFSC_HWCFGR1 register fields */
51cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG1_MASK GENMASK_32(3, 0)
52cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG1_SHIFT U(0)
53cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG2_MASK GENMASK_32(7, 4)
54cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG2_SHIFT U(4)
55cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG3_MASK GENMASK_32(11, 8)
56cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG3_SHIFT U(8)
57cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG4_MASK GENMASK_32(15, 12)
58cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG4_SHIFT U(12)
59cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG5_MASK GENMASK_32(19, 16)
60cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG5_SHIFT U(16)
61cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG6_MASK GENMASK_32(23, 20)
62cd187630SGatien Chevallier #define _RIFSC_HWCFGR1_CFG6_SHIFT U(20)
63cd187630SGatien Chevallier
64cd187630SGatien Chevallier /*
65cd187630SGatien Chevallier * RISC_CR register fields
66cd187630SGatien Chevallier */
67cd187630SGatien Chevallier #define _RIFSC_RISC_CR_GLOCK BIT(0)
68cd187630SGatien Chevallier
69cd187630SGatien Chevallier /*
70cd187630SGatien Chevallier * RIMC_CR register fields
71cd187630SGatien Chevallier */
72cd187630SGatien Chevallier #define _RIFSC_RIMC_CR_GLOCK BIT(0)
73cd187630SGatien Chevallier #define _RIFSC_RIMC_CR_TDCID_MASK GENMASK_32(6, 4)
74cd187630SGatien Chevallier
75cd187630SGatien Chevallier /* RIFSC_VERR register fields */
76cd187630SGatien Chevallier #define _RIFSC_VERR_MINREV_MASK GENMASK_32(3, 0)
77cd187630SGatien Chevallier #define _RIFSC_VERR_MINREV_SHIFT U(0)
78cd187630SGatien Chevallier #define _RIFSC_VERR_MAJREV_MASK GENMASK_32(7, 4)
79cd187630SGatien Chevallier #define _RIFSC_VERR_MAJREV_SHIFT U(4)
80cd187630SGatien Chevallier
81cd187630SGatien Chevallier /* Periph id per register */
82cd187630SGatien Chevallier #define _PERIPH_IDS_PER_REG U(32)
83cd187630SGatien Chevallier #define _OFFSET_PERX_CIDCFGR U(0x8)
84cd187630SGatien Chevallier
85471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_CFEN_MASK BIT(0)
86471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_CFEN_SHIFT U(0)
87471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_SEM_EN_MASK BIT(1)
88471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_SEM_EN_SHIFT U(1)
89471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_SCID_MASK GENMASK_32(6, 4)
90471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_SCID_SHIFT U(4)
91471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_LOCK_MASK BIT(10)
92471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_LOCK_SHIFT U(10)
93471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_SEML_MASK GENMASK_32(23, 16)
94471cec14SGatien Chevallier #define RIFSC_RISC_CIDCFGR_SEML_SHIFT U(16)
95cd187630SGatien Chevallier
96471cec14SGatien Chevallier #define RIFSC_RISC_PERx_CID_MASK (RIFSC_RISC_CIDCFGR_CFEN_MASK | \
97471cec14SGatien Chevallier RIFSC_RISC_CIDCFGR_SEM_EN_MASK | \
98471cec14SGatien Chevallier RIFSC_RISC_CIDCFGR_SCID_MASK | \
99471cec14SGatien Chevallier RIFSC_RISC_CIDCFGR_SCID_SHIFT)
100471cec14SGatien Chevallier
1017071b53bSGatien Chevallier #define RIFSC_RISC_PERx_CID_SHIFT U(0)
102cd187630SGatien Chevallier
1036cdfe3e0SGatien Chevallier #define RIFSC_RIMC_CIDSEL_MASK BIT(2)
1046cdfe3e0SGatien Chevallier #define RIFSC_RIMC_CIDSEL_SHIFT U(2)
105cd187630SGatien Chevallier #define RIFSC_RIMC_MCID_MASK GENMASK_32(6, 4)
1066cdfe3e0SGatien Chevallier #define RIFSC_RIMC_MCID_SHIFT U(4)
107cd187630SGatien Chevallier #define RIFSC_RIMC_MSEC_MASK BIT(8)
108cd187630SGatien Chevallier #define RIFSC_RIMC_MPRIV_MASK BIT(9)
109cd187630SGatien Chevallier #define RIFSC_RIMC_M_ID_MASK GENMASK_32(23, 16)
110cd187630SGatien Chevallier
111cd187630SGatien Chevallier #define RIFSC_RIMC_ATTRx_MASK (RIFSC_RIMC_MODE_MASK | \
112cd187630SGatien Chevallier RIFSC_RIMC_MCID_MASK | \
113cd187630SGatien Chevallier RIFSC_RIMC_MSEC_MASK | \
114cd187630SGatien Chevallier RIFSC_RIMC_MPRIV_MASK)
115cd187630SGatien Chevallier
116cd187630SGatien Chevallier /* max entries */
117cd187630SGatien Chevallier #define MAX_RIMU U(16)
118cd187630SGatien Chevallier #define MAX_RISUP U(128)
119cd187630SGatien Chevallier
120cd187630SGatien Chevallier #define _RIF_FLD_GET(field, value) (((uint32_t)(value) & \
121cd187630SGatien Chevallier (field ## _MASK)) >>\
122cd187630SGatien Chevallier (field ## _SHIFT))
123cd187630SGatien Chevallier
1246cdfe3e0SGatien Chevallier #define NO_RISUP_ID UINT32_MAX
1256cdfe3e0SGatien Chevallier
126cd187630SGatien Chevallier struct risup_cfg {
127cd187630SGatien Chevallier uint32_t cid_attr;
128cd187630SGatien Chevallier uint32_t id;
129cd187630SGatien Chevallier bool sec;
130cd187630SGatien Chevallier bool priv;
131cd187630SGatien Chevallier bool lock;
132cd187630SGatien Chevallier bool pm_sem;
133cd187630SGatien Chevallier };
134cd187630SGatien Chevallier
135cd187630SGatien Chevallier struct rimu_cfg {
136cd187630SGatien Chevallier uint32_t id;
1376cdfe3e0SGatien Chevallier uint32_t risup_id;
138cd187630SGatien Chevallier uint32_t attr;
139cd187630SGatien Chevallier };
140cd187630SGatien Chevallier
141662542c7SGwenael Treuveur struct risal_cfg {
142662542c7SGwenael Treuveur uint32_t id;
143662542c7SGwenael Treuveur uint32_t blockid;
144662542c7SGwenael Treuveur uint32_t attr;
145662542c7SGwenael Treuveur };
146662542c7SGwenael Treuveur
147cd187630SGatien Chevallier struct rifsc_driver_data {
148cd187630SGatien Chevallier bool rif_en;
149cd187630SGatien Chevallier bool sec_en;
150cd187630SGatien Chevallier bool priv_en;
151cd187630SGatien Chevallier uint8_t nb_rimu;
152cd187630SGatien Chevallier uint8_t nb_risup;
153bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
154cd187630SGatien Chevallier uint8_t nb_risal;
155bc951da9SThomas Bourgoin #endif /* CFG_STM32MP25 */
156cd187630SGatien Chevallier uint8_t version;
157cd187630SGatien Chevallier };
158cd187630SGatien Chevallier
159cd187630SGatien Chevallier struct rifsc_platdata {
160cd187630SGatien Chevallier uintptr_t base;
161cd187630SGatien Chevallier struct rifsc_driver_data *drv_data;
162cd187630SGatien Chevallier struct risup_cfg *risup;
163cd187630SGatien Chevallier unsigned int nrisup;
164cd187630SGatien Chevallier struct rimu_cfg *rimu;
165cd187630SGatien Chevallier unsigned int nrimu;
166bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
167662542c7SGwenael Treuveur struct risal_cfg *risal;
168662542c7SGwenael Treuveur unsigned int nrisal;
169bc951da9SThomas Bourgoin #endif /* CFG_STM32MP25 */
170471cec14SGatien Chevallier bool is_tdcid;
1716cdfe3e0SGatien Chevallier bool errata_ahbrisab;
1726cdfe3e0SGatien Chevallier };
1736cdfe3e0SGatien Chevallier
1746cdfe3e0SGatien Chevallier /**
1756cdfe3e0SGatien Chevallier * struct rimu_risup_pairs - Association of a RISUP and RIMU ID for a peripheral
1766cdfe3e0SGatien Chevallier *
1776cdfe3e0SGatien Chevallier * @rimu_id: ID of the RIMU
1786cdfe3e0SGatien Chevallier * @risup_id: ID of the associated RISUP
1796cdfe3e0SGatien Chevallier */
1806cdfe3e0SGatien Chevallier struct rimu_risup_pairs {
1816cdfe3e0SGatien Chevallier uint32_t rimu_id;
1826cdfe3e0SGatien Chevallier uint32_t risup_id;
1836cdfe3e0SGatien Chevallier };
1846cdfe3e0SGatien Chevallier
185*37954afbSThomas Bourgoin #if defined(CFG_STM32MP25) || defined(CFG_STM32MP23)
1866cdfe3e0SGatien Chevallier static const struct rimu_risup_pairs rimu_risup[] = {
1876cdfe3e0SGatien Chevallier [0] = {
1886cdfe3e0SGatien Chevallier .rimu_id = 0,
1896cdfe3e0SGatien Chevallier .risup_id = NO_RISUP_ID,
1906cdfe3e0SGatien Chevallier },
1916cdfe3e0SGatien Chevallier [1] = {
1926cdfe3e0SGatien Chevallier .rimu_id = 1,
1936cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_SDMMC1_ID,
1946cdfe3e0SGatien Chevallier },
1956cdfe3e0SGatien Chevallier [2] = {
1966cdfe3e0SGatien Chevallier .rimu_id = 2,
1976cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_SDMMC2_ID,
1986cdfe3e0SGatien Chevallier },
1996cdfe3e0SGatien Chevallier [3] = {
2006cdfe3e0SGatien Chevallier .rimu_id = 3,
2016cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_SDMMC3_ID,
2026cdfe3e0SGatien Chevallier },
2036cdfe3e0SGatien Chevallier [4] = {
2046cdfe3e0SGatien Chevallier .rimu_id = 4,
2056cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_USB3DR_ID,
2066cdfe3e0SGatien Chevallier },
2076cdfe3e0SGatien Chevallier [5] = {
2086cdfe3e0SGatien Chevallier .rimu_id = 5,
2096cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_USBH_ID,
2106cdfe3e0SGatien Chevallier },
2116cdfe3e0SGatien Chevallier [6] = {
2126cdfe3e0SGatien Chevallier .rimu_id = 6,
2136cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_ETH1_ID,
2146cdfe3e0SGatien Chevallier },
2156cdfe3e0SGatien Chevallier [7] = {
2166cdfe3e0SGatien Chevallier .rimu_id = 7,
2176cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_ETH2_ID,
2186cdfe3e0SGatien Chevallier },
2196cdfe3e0SGatien Chevallier [8] = {
2206cdfe3e0SGatien Chevallier .rimu_id = 8,
2216cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_PCIE_ID,
2226cdfe3e0SGatien Chevallier },
2236cdfe3e0SGatien Chevallier [9] = {
2246cdfe3e0SGatien Chevallier .rimu_id = 9,
2256cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_GPU_ID,
2266cdfe3e0SGatien Chevallier },
2276cdfe3e0SGatien Chevallier [10] = {
2286cdfe3e0SGatien Chevallier .rimu_id = 10,
2296cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_DCMIPP_ID,
2306cdfe3e0SGatien Chevallier },
2316cdfe3e0SGatien Chevallier [11] = {
2326cdfe3e0SGatien Chevallier .rimu_id = 11,
2336cdfe3e0SGatien Chevallier .risup_id = NO_RISUP_ID,
2346cdfe3e0SGatien Chevallier },
2356cdfe3e0SGatien Chevallier [12] = {
2366cdfe3e0SGatien Chevallier .rimu_id = 12,
2376cdfe3e0SGatien Chevallier .risup_id = NO_RISUP_ID,
2386cdfe3e0SGatien Chevallier },
2396cdfe3e0SGatien Chevallier [13] = {
2406cdfe3e0SGatien Chevallier .rimu_id = 13,
2416cdfe3e0SGatien Chevallier .risup_id = NO_RISUP_ID,
2426cdfe3e0SGatien Chevallier },
2436cdfe3e0SGatien Chevallier [14] = {
2446cdfe3e0SGatien Chevallier .rimu_id = 14,
2456cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_VDEC_ID,
2466cdfe3e0SGatien Chevallier },
2476cdfe3e0SGatien Chevallier [15] = {
2486cdfe3e0SGatien Chevallier .rimu_id = 15,
2496cdfe3e0SGatien Chevallier .risup_id = STM32MP25_RIFSC_VENC_ID,
2506cdfe3e0SGatien Chevallier },
251cd187630SGatien Chevallier };
252*37954afbSThomas Bourgoin #endif /* CFG_STM32MP25 || CFG_STM32MP23 */
253bc951da9SThomas Bourgoin #if defined(CFG_STM32MP21)
254bc951da9SThomas Bourgoin static const struct rimu_risup_pairs rimu_risup[] = {
255bc951da9SThomas Bourgoin [0] = {
256bc951da9SThomas Bourgoin .rimu_id = 0,
257bc951da9SThomas Bourgoin .risup_id = NO_RISUP_ID,
258bc951da9SThomas Bourgoin },
259bc951da9SThomas Bourgoin [1] = {
260bc951da9SThomas Bourgoin .rimu_id = 1,
261bc951da9SThomas Bourgoin .risup_id = STM32MP21_RIFSC_SDMMC1_ID,
262bc951da9SThomas Bourgoin },
263bc951da9SThomas Bourgoin [2] = {
264bc951da9SThomas Bourgoin .rimu_id = 2,
265bc951da9SThomas Bourgoin .risup_id = STM32MP21_RIFSC_SDMMC2_ID,
266bc951da9SThomas Bourgoin },
267bc951da9SThomas Bourgoin [3] = {
268bc951da9SThomas Bourgoin .rimu_id = 3,
269bc951da9SThomas Bourgoin .risup_id = STM32MP21_RIFSC_SDMMC3_ID,
270bc951da9SThomas Bourgoin },
271bc951da9SThomas Bourgoin [4] = {
272bc951da9SThomas Bourgoin .rimu_id = 4,
273bc951da9SThomas Bourgoin .risup_id = STM32MP21_RIFSC_OTG_HS_ID,
274bc951da9SThomas Bourgoin },
275bc951da9SThomas Bourgoin [5] = {
276bc951da9SThomas Bourgoin .rimu_id = 5,
277bc951da9SThomas Bourgoin .risup_id = STM32MP21_RIFSC_USBH_ID,
278bc951da9SThomas Bourgoin },
279bc951da9SThomas Bourgoin [6] = {
280bc951da9SThomas Bourgoin .rimu_id = 6,
281bc951da9SThomas Bourgoin .risup_id = STM32MP21_RIFSC_ETH1_ID,
282bc951da9SThomas Bourgoin },
283bc951da9SThomas Bourgoin [7] = {
284bc951da9SThomas Bourgoin .rimu_id = 7,
285bc951da9SThomas Bourgoin .risup_id = STM32MP21_RIFSC_ETH2_ID,
286bc951da9SThomas Bourgoin },
287bc951da9SThomas Bourgoin [10] = {
288bc951da9SThomas Bourgoin .rimu_id = 10,
289bc951da9SThomas Bourgoin .risup_id = STM32MP21_RIFSC_DCMIPP_ID,
290bc951da9SThomas Bourgoin },
291bc951da9SThomas Bourgoin [11] = {
292bc951da9SThomas Bourgoin .rimu_id = 11,
293bc951da9SThomas Bourgoin .risup_id = NO_RISUP_ID,
294bc951da9SThomas Bourgoin },
295bc951da9SThomas Bourgoin [12] = {
296bc951da9SThomas Bourgoin .rimu_id = 12,
297bc951da9SThomas Bourgoin .risup_id = NO_RISUP_ID,
298bc951da9SThomas Bourgoin },
299bc951da9SThomas Bourgoin };
300bc951da9SThomas Bourgoin #endif /* CFG_STM32MP21 */
301cd187630SGatien Chevallier
302cd187630SGatien Chevallier /* There is only 1 instance of the RIFSC subsystem */
303cd187630SGatien Chevallier static struct rifsc_driver_data rifsc_drvdata;
304cd187630SGatien Chevallier static struct rifsc_platdata rifsc_pdata;
305cd187630SGatien Chevallier
stm32_rifsc_get_driverdata(struct rifsc_platdata * pdata)306cd187630SGatien Chevallier static void stm32_rifsc_get_driverdata(struct rifsc_platdata *pdata)
307cd187630SGatien Chevallier {
308cd187630SGatien Chevallier uint32_t regval = 0;
309cd187630SGatien Chevallier
310cd187630SGatien Chevallier regval = io_read32(pdata->base + _RIFSC_HWCFGR1);
311cd187630SGatien Chevallier rifsc_drvdata.rif_en = _RIF_FLD_GET(_RIFSC_HWCFGR1_CFG1, regval) != 0;
312cd187630SGatien Chevallier rifsc_drvdata.sec_en = _RIF_FLD_GET(_RIFSC_HWCFGR1_CFG2, regval) != 0;
313cd187630SGatien Chevallier rifsc_drvdata.priv_en = _RIF_FLD_GET(_RIFSC_HWCFGR1_CFG3, regval) != 0;
314cd187630SGatien Chevallier
315cd187630SGatien Chevallier regval = io_read32(pdata->base + _RIFSC_HWCFGR2);
316cd187630SGatien Chevallier rifsc_drvdata.nb_risup = _RIF_FLD_GET(_RIFSC_HWCFGR2_CFG1, regval);
317cd187630SGatien Chevallier rifsc_drvdata.nb_rimu = _RIF_FLD_GET(_RIFSC_HWCFGR2_CFG2, regval);
318bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
319cd187630SGatien Chevallier rifsc_drvdata.nb_risal = _RIF_FLD_GET(_RIFSC_HWCFGR2_CFG3, regval);
320bc951da9SThomas Bourgoin #endif /* CFG_STM32MP25 */
321cd187630SGatien Chevallier
322cd187630SGatien Chevallier pdata->drv_data = &rifsc_drvdata;
323cd187630SGatien Chevallier
324cd187630SGatien Chevallier rifsc_drvdata.version = io_read8(pdata->base + _RIFSC_VERR);
325cd187630SGatien Chevallier
326cd187630SGatien Chevallier DMSG("RIFSC version %"PRIu32".%"PRIu32,
327cd187630SGatien Chevallier _RIF_FLD_GET(_RIFSC_VERR_MAJREV, rifsc_drvdata.version),
328cd187630SGatien Chevallier _RIF_FLD_GET(_RIFSC_VERR_MINREV, rifsc_drvdata.version));
329cd187630SGatien Chevallier
330bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
331cd187630SGatien Chevallier DMSG("HW cap: enabled[rif:sec:priv]:[%s:%s:%s] nb[risup|rimu|risal]:[%"PRIu8",%"PRIu8",%"PRIu8"]",
332cd187630SGatien Chevallier rifsc_drvdata.rif_en ? "true" : "false",
333cd187630SGatien Chevallier rifsc_drvdata.sec_en ? "true" : "false",
334cd187630SGatien Chevallier rifsc_drvdata.priv_en ? "true" : "false",
335cd187630SGatien Chevallier rifsc_drvdata.nb_risup,
336cd187630SGatien Chevallier rifsc_drvdata.nb_rimu,
337cd187630SGatien Chevallier rifsc_drvdata.nb_risal);
338bc951da9SThomas Bourgoin #else /* CFG_STM32MP25 */
339bc951da9SThomas Bourgoin DMSG("HW cap: enabled[rif:sec:priv]:[%s:%s:%s] nb[risup|rimu]:[%"PRIu8",%"PRIu8"]",
340bc951da9SThomas Bourgoin rifsc_drvdata.rif_en ? "true" : "false",
341bc951da9SThomas Bourgoin rifsc_drvdata.sec_en ? "true" : "false",
342bc951da9SThomas Bourgoin rifsc_drvdata.priv_en ? "true" : "false",
343bc951da9SThomas Bourgoin rifsc_drvdata.nb_risup,
344bc951da9SThomas Bourgoin rifsc_drvdata.nb_rimu);
345bc951da9SThomas Bourgoin #endif
346cd187630SGatien Chevallier }
347cd187630SGatien Chevallier
stm32_rifsc_glock_config(const void * fdt,int node,struct rifsc_platdata * pdata)348cd187630SGatien Chevallier static TEE_Result stm32_rifsc_glock_config(const void *fdt, int node,
349cd187630SGatien Chevallier struct rifsc_platdata *pdata)
350cd187630SGatien Chevallier {
351cd187630SGatien Chevallier const fdt32_t *cuint = NULL;
352cd187630SGatien Chevallier uint32_t glock_conf = 0;
353cd187630SGatien Chevallier int len = 0;
354cd187630SGatien Chevallier
355cd187630SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,glocked", &len);
356cd187630SGatien Chevallier if (!cuint) {
357cd187630SGatien Chevallier DMSG("No global lock on RIF configuration");
358cd187630SGatien Chevallier return TEE_SUCCESS;
359cd187630SGatien Chevallier }
360cd187630SGatien Chevallier assert(len == sizeof(uint32_t));
361cd187630SGatien Chevallier
362cd187630SGatien Chevallier glock_conf = fdt32_to_cpu(*cuint);
363cd187630SGatien Chevallier
364cd187630SGatien Chevallier if (glock_conf & RIFSC_RIMU_GLOCK) {
365cd187630SGatien Chevallier DMSG("Setting global lock on RIMU configuration");
366cd187630SGatien Chevallier
367cd187630SGatien Chevallier io_setbits32(pdata->base + _RIFSC_RIMC_CR,
368cd187630SGatien Chevallier _RIFSC_RIMC_CR_GLOCK);
369cd187630SGatien Chevallier
370cd187630SGatien Chevallier if (!(io_read32(pdata->base + _RIFSC_RIMC_CR) &
371cd187630SGatien Chevallier _RIFSC_RIMC_CR_GLOCK))
372cd187630SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
373cd187630SGatien Chevallier }
374cd187630SGatien Chevallier
375cd187630SGatien Chevallier if (glock_conf & RIFSC_RISUP_GLOCK) {
376cd187630SGatien Chevallier DMSG("Setting global lock on RISUP configuration");
377cd187630SGatien Chevallier
378cd187630SGatien Chevallier io_setbits32(pdata->base, _RIFSC_RISC_CR_GLOCK);
379cd187630SGatien Chevallier
380cd187630SGatien Chevallier if (!(io_read32(pdata->base) & _RIFSC_RISC_CR_GLOCK))
381cd187630SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
382cd187630SGatien Chevallier }
383cd187630SGatien Chevallier
384cd187630SGatien Chevallier return TEE_SUCCESS;
385cd187630SGatien Chevallier }
386cd187630SGatien Chevallier
stm32_rifsc_dt_conf_risup(const void * fdt,int node,struct rifsc_platdata * pdata)387cd187630SGatien Chevallier static TEE_Result stm32_rifsc_dt_conf_risup(const void *fdt, int node,
388cd187630SGatien Chevallier struct rifsc_platdata *pdata)
389cd187630SGatien Chevallier {
390cd187630SGatien Chevallier const fdt32_t *conf_list = NULL;
391cd187630SGatien Chevallier unsigned int i = 0;
392cd187630SGatien Chevallier int len = 0;
393cd187630SGatien Chevallier
394cd187630SGatien Chevallier conf_list = fdt_getprop(fdt, node, "st,protreg", &len);
395cd187630SGatien Chevallier if (!conf_list) {
396cd187630SGatien Chevallier DMSG("No RISUP configuration in DT");
397cd187630SGatien Chevallier return TEE_ERROR_ITEM_NOT_FOUND;
398cd187630SGatien Chevallier }
399cd187630SGatien Chevallier assert(!(len % sizeof(uint32_t)));
400cd187630SGatien Chevallier
401cd187630SGatien Chevallier pdata->nrisup = len / sizeof(uint32_t);
402cd187630SGatien Chevallier pdata->risup = calloc(pdata->nrisup, sizeof(*pdata->risup));
403cd187630SGatien Chevallier if (!pdata->risup)
404cd187630SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY;
405cd187630SGatien Chevallier
406cd187630SGatien Chevallier for (i = 0; i < pdata->nrisup; i++) {
407cd187630SGatien Chevallier uint32_t value = fdt32_to_cpu(conf_list[i]);
408cd187630SGatien Chevallier struct risup_cfg *risup = pdata->risup + i;
409cd187630SGatien Chevallier
410471cec14SGatien Chevallier risup->id = _RIF_FLD_GET(RIF_PER_ID, value);
411471cec14SGatien Chevallier risup->sec = _RIF_FLD_GET(RIF_SEC, value) != 0;
412471cec14SGatien Chevallier risup->priv = _RIF_FLD_GET(RIF_PRIV, value) != 0;
413471cec14SGatien Chevallier risup->lock = _RIF_FLD_GET(RIF_LOCK, value) != 0;
414471cec14SGatien Chevallier risup->cid_attr = _RIF_FLD_GET(RIF_PERx_CID, value);
415cd187630SGatien Chevallier }
416cd187630SGatien Chevallier
417cd187630SGatien Chevallier return TEE_SUCCESS;
418cd187630SGatien Chevallier }
419cd187630SGatien Chevallier
stm32_rifsc_dt_conf_rimu(const void * fdt,int node,struct rifsc_platdata * pdata)420cd187630SGatien Chevallier static TEE_Result stm32_rifsc_dt_conf_rimu(const void *fdt, int node,
421cd187630SGatien Chevallier struct rifsc_platdata *pdata)
422cd187630SGatien Chevallier {
423cd187630SGatien Chevallier const fdt32_t *conf_list = NULL;
424cd187630SGatien Chevallier unsigned int i = 0;
425cd187630SGatien Chevallier int len = 0;
426cd187630SGatien Chevallier
427cd187630SGatien Chevallier conf_list = fdt_getprop(fdt, node, "st,rimu", &len);
428cd187630SGatien Chevallier if (!conf_list) {
429cd187630SGatien Chevallier DMSG("No RIMU configuration in DT");
430cd187630SGatien Chevallier return TEE_ERROR_ITEM_NOT_FOUND;
431cd187630SGatien Chevallier }
432cd187630SGatien Chevallier assert(!(len % sizeof(uint32_t)));
433cd187630SGatien Chevallier
434cd187630SGatien Chevallier pdata->nrimu = len / sizeof(uint32_t);
435cd187630SGatien Chevallier pdata->rimu = calloc(pdata->nrimu, sizeof(*pdata->rimu));
436cd187630SGatien Chevallier if (!pdata->rimu)
437cd187630SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY;
438cd187630SGatien Chevallier
439cd187630SGatien Chevallier for (i = 0; i < pdata->nrimu; i++) {
44071d13298SGatien Chevallier uint32_t value = fdt32_to_cpu(conf_list[i]);
441cd187630SGatien Chevallier struct rimu_cfg *rimu = pdata->rimu + i;
442cd187630SGatien Chevallier
443471cec14SGatien Chevallier rimu->id = _RIF_FLD_GET(RIMUPROT_RIMC_M_ID, value) -
444471cec14SGatien Chevallier RIMU_ID_OFFSET;
445471cec14SGatien Chevallier rimu->attr = _RIF_FLD_GET(RIMUPROT_RIMC_ATTRx, value);
446cd187630SGatien Chevallier }
447cd187630SGatien Chevallier
448cd187630SGatien Chevallier return TEE_SUCCESS;
449cd187630SGatien Chevallier }
450cd187630SGatien Chevallier
451bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
stm32_rifsc_dt_conf_risal(const void * fdt,int node,struct rifsc_platdata * pdata)452662542c7SGwenael Treuveur static TEE_Result stm32_rifsc_dt_conf_risal(const void *fdt, int node,
453662542c7SGwenael Treuveur struct rifsc_platdata *pdata)
454662542c7SGwenael Treuveur {
455662542c7SGwenael Treuveur const fdt32_t *cuint = NULL;
456662542c7SGwenael Treuveur int i = 0;
457662542c7SGwenael Treuveur int len = 0;
458662542c7SGwenael Treuveur
459662542c7SGwenael Treuveur cuint = fdt_getprop(fdt, node, "st,risal", &len);
460662542c7SGwenael Treuveur if (!cuint) {
461662542c7SGwenael Treuveur DMSG("No RISAL configuration in DT");
462662542c7SGwenael Treuveur pdata->nrisal = 0;
463662542c7SGwenael Treuveur return TEE_ERROR_ITEM_NOT_FOUND;
464662542c7SGwenael Treuveur }
465662542c7SGwenael Treuveur
466662542c7SGwenael Treuveur len = len / sizeof(uint32_t);
467662542c7SGwenael Treuveur
468662542c7SGwenael Treuveur pdata->nrisal = len;
469662542c7SGwenael Treuveur pdata->risal = calloc(len, sizeof(*pdata->risal));
470662542c7SGwenael Treuveur if (!pdata->risal)
471662542c7SGwenael Treuveur return TEE_ERROR_OUT_OF_MEMORY;
472662542c7SGwenael Treuveur
473662542c7SGwenael Treuveur for (i = 0; i < len; i++) {
474662542c7SGwenael Treuveur uint32_t value = fdt32_to_cpu(cuint[i]);
475662542c7SGwenael Treuveur struct risal_cfg *risal = pdata->risal + i;
476662542c7SGwenael Treuveur
477662542c7SGwenael Treuveur risal->id = _RIF_FLD_GET(RIFSC_RISAL_REG_ID, value);
478662542c7SGwenael Treuveur risal->blockid = _RIF_FLD_GET(RIFSC_RISAL_BLOCK_ID, value);
479662542c7SGwenael Treuveur risal->attr = _RIF_FLD_GET(RIFSC_RISAL_REGx_CFGR, value);
480662542c7SGwenael Treuveur }
481662542c7SGwenael Treuveur
482662542c7SGwenael Treuveur return TEE_SUCCESS;
483662542c7SGwenael Treuveur }
484bc951da9SThomas Bourgoin #endif /* CFG_STM32MP25 */
485662542c7SGwenael Treuveur
stm32_rifsc_parse_fdt(const void * fdt,int node,struct rifsc_platdata * pdata)486cd187630SGatien Chevallier static TEE_Result stm32_rifsc_parse_fdt(const void *fdt, int node,
487cd187630SGatien Chevallier struct rifsc_platdata *pdata)
488cd187630SGatien Chevallier {
489cd187630SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
490cd187630SGatien Chevallier struct io_pa_va base = { };
491cd187630SGatien Chevallier size_t reg_size = 0;
492cd187630SGatien Chevallier
4936a0116edSEtienne Carriere if (fdt_reg_info(fdt, node, &base.pa, ®_size))
494cd187630SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
495cd187630SGatien Chevallier
496cd187630SGatien Chevallier pdata->base = io_pa_or_va_secure(&base, reg_size);
497cd187630SGatien Chevallier
498471cec14SGatien Chevallier res = stm32_rifsc_check_tdcid(&rifsc_pdata.is_tdcid);
499cd187630SGatien Chevallier if (res)
500471cec14SGatien Chevallier panic();
501471cec14SGatien Chevallier
502471cec14SGatien Chevallier res = stm32_rifsc_dt_conf_risup(fdt, node, pdata);
503471cec14SGatien Chevallier if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
504cd187630SGatien Chevallier return res;
505cd187630SGatien Chevallier
506471cec14SGatien Chevallier if (rifsc_pdata.is_tdcid) {
507471cec14SGatien Chevallier res = stm32_rifsc_dt_conf_rimu(fdt, node, pdata);
508471cec14SGatien Chevallier if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
509471cec14SGatien Chevallier return res;
510662542c7SGwenael Treuveur
511bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
512662542c7SGwenael Treuveur res = stm32_rifsc_dt_conf_risal(fdt, node, pdata);
513662542c7SGwenael Treuveur if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
514662542c7SGwenael Treuveur return res;
515bc951da9SThomas Bourgoin #endif /* CFG_STM32MP25 */
516471cec14SGatien Chevallier }
517471cec14SGatien Chevallier
5186cdfe3e0SGatien Chevallier rifsc_pdata.errata_ahbrisab = fdt_getprop(fdt, node,
5196cdfe3e0SGatien Chevallier "st,errata-ahbrisab", NULL);
5206cdfe3e0SGatien Chevallier
521cb3837c9SGatien Chevallier return TEE_SUCCESS;
522cd187630SGatien Chevallier }
523cd187630SGatien Chevallier
stm32_risup_cfg(struct rifsc_platdata * pdata,struct risup_cfg * risup)524cd187630SGatien Chevallier static TEE_Result stm32_risup_cfg(struct rifsc_platdata *pdata,
525cd187630SGatien Chevallier struct risup_cfg *risup)
526cd187630SGatien Chevallier {
527cd187630SGatien Chevallier uintptr_t offset = sizeof(uint32_t) * (risup->id / _PERIPH_IDS_PER_REG);
528cd187630SGatien Chevallier uintptr_t cidcfgr_offset = _OFFSET_PERX_CIDCFGR * risup->id;
529cd187630SGatien Chevallier struct rifsc_driver_data *drv_data = pdata->drv_data;
530cd187630SGatien Chevallier uint32_t shift = risup->id % _PERIPH_IDS_PER_REG;
531cd187630SGatien Chevallier
532cd187630SGatien Chevallier if (!risup || risup->id >= drv_data->nb_risup)
533cd187630SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
534cd187630SGatien Chevallier
535cd187630SGatien Chevallier if (drv_data->sec_en)
536471cec14SGatien Chevallier io_clrsetbits32_stm32shregs(pdata->base + _RIFSC_RISC_SECCFGR0 +
537471cec14SGatien Chevallier offset, BIT(shift),
538471cec14SGatien Chevallier SHIFT_U32(risup->sec, shift));
539cd187630SGatien Chevallier
540cd187630SGatien Chevallier if (drv_data->priv_en)
541471cec14SGatien Chevallier io_clrsetbits32_stm32shregs(pdata->base +
542471cec14SGatien Chevallier _RIFSC_RISC_PRIVCFGR0 + offset,
543471cec14SGatien Chevallier BIT(shift),
544471cec14SGatien Chevallier SHIFT_U32(risup->priv, shift));
545cd187630SGatien Chevallier
546471cec14SGatien Chevallier if (rifsc_pdata.is_tdcid) {
547cd187630SGatien Chevallier if (drv_data->rif_en)
548cd187630SGatien Chevallier io_write32(pdata->base + _RIFSC_RISC_PER0_CIDCFGR +
549cd187630SGatien Chevallier cidcfgr_offset, risup->cid_attr);
550cd187630SGatien Chevallier
551cd187630SGatien Chevallier /* Lock configuration for this RISUP */
552cd187630SGatien Chevallier if (risup->lock) {
553471cec14SGatien Chevallier DMSG("Locking RIF conf for peripheral ID: %"PRIu32,
554471cec14SGatien Chevallier risup->id);
555471cec14SGatien Chevallier io_setbits32_stm32shregs(pdata->base +
556471cec14SGatien Chevallier _RIFSC_RISC_RCFGLOCKR0 +
557471cec14SGatien Chevallier offset, BIT(shift));
558471cec14SGatien Chevallier }
559cd187630SGatien Chevallier }
560cd187630SGatien Chevallier
561cd187630SGatien Chevallier return TEE_SUCCESS;
562cd187630SGatien Chevallier }
563cd187630SGatien Chevallier
stm32_risup_setup(struct rifsc_platdata * pdata)564cd187630SGatien Chevallier static TEE_Result stm32_risup_setup(struct rifsc_platdata *pdata)
565cd187630SGatien Chevallier {
566cd187630SGatien Chevallier struct rifsc_driver_data *drv_data = pdata->drv_data;
567cd187630SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
568cd187630SGatien Chevallier unsigned int i = 0;
569cd187630SGatien Chevallier
570cd187630SGatien Chevallier for (i = 0; i < pdata->nrisup && i < drv_data->nb_risup; i++) {
571cd187630SGatien Chevallier struct risup_cfg *risup = pdata->risup + i;
572cd187630SGatien Chevallier
573cd187630SGatien Chevallier res = stm32_risup_cfg(pdata, risup);
574cd187630SGatien Chevallier if (res) {
575cd187630SGatien Chevallier EMSG("risup cfg(%d/%d) error", i + 1, pdata->nrisup);
576cd187630SGatien Chevallier return res;
577cd187630SGatien Chevallier }
578cd187630SGatien Chevallier }
579cd187630SGatien Chevallier
580cd187630SGatien Chevallier return TEE_SUCCESS;
581cd187630SGatien Chevallier }
582cd187630SGatien Chevallier
5836cdfe3e0SGatien Chevallier /*
5846cdfe3e0SGatien Chevallier * Errata: When CID filtering is enabled on one of RISAB 3/4/5 instances, we
5856cdfe3e0SGatien Chevallier * forbid the use of CID0 for any initiator on the bus to handle transient CID0
5866cdfe3e0SGatien Chevallier * transactions on these RAMs.
5876cdfe3e0SGatien Chevallier */
stm32_rimu_errata_ahbrisab(struct rifsc_platdata * pdata,struct rimu_cfg * rimu)5886cdfe3e0SGatien Chevallier static void stm32_rimu_errata_ahbrisab(struct rifsc_platdata *pdata,
5896cdfe3e0SGatien Chevallier struct rimu_cfg *rimu)
5906cdfe3e0SGatien Chevallier {
5916cdfe3e0SGatien Chevallier unsigned int i = 0;
5926cdfe3e0SGatien Chevallier
5936cdfe3e0SGatien Chevallier if (!pdata->errata_ahbrisab)
5946cdfe3e0SGatien Chevallier return;
5956cdfe3e0SGatien Chevallier
5966cdfe3e0SGatien Chevallier for (i = 0; i < ARRAY_SIZE(rimu_risup); i++) {
5976cdfe3e0SGatien Chevallier if (rimu->id == rimu_risup[i].rimu_id) {
5986cdfe3e0SGatien Chevallier rimu->risup_id = rimu_risup[i].risup_id;
5996cdfe3e0SGatien Chevallier break;
6006cdfe3e0SGatien Chevallier }
6016cdfe3e0SGatien Chevallier }
6026cdfe3e0SGatien Chevallier
6036cdfe3e0SGatien Chevallier if (i == ARRAY_SIZE(rimu_risup))
6046cdfe3e0SGatien Chevallier panic();
6056cdfe3e0SGatien Chevallier
6066cdfe3e0SGatien Chevallier if (rimu->attr & RIFSC_RIMC_CIDSEL_MASK) {
6076cdfe3e0SGatien Chevallier /* No inheritance mode for this RIMU */
6086cdfe3e0SGatien Chevallier if ((rimu->attr & RIFSC_RIMC_MCID_MASK) >>
6096cdfe3e0SGatien Chevallier RIFSC_RIMC_MCID_SHIFT == RIF_CID0) {
6106cdfe3e0SGatien Chevallier EMSG("A CID should be set for RIMU %"PRIu32, rimu->id);
6116cdfe3e0SGatien Chevallier if (!IS_ENABLED(CFG_INSECURE))
6126cdfe3e0SGatien Chevallier panic();
6136cdfe3e0SGatien Chevallier }
6146cdfe3e0SGatien Chevallier } else {
6156cdfe3e0SGatien Chevallier struct risup_cfg *risup = NULL;
6166cdfe3e0SGatien Chevallier uint32_t risup_cidcfgr = 0;
6176cdfe3e0SGatien Chevallier unsigned int j = 0;
6186cdfe3e0SGatien Chevallier
6196cdfe3e0SGatien Chevallier /* Handle RIMU with no inheritance mode */
6206cdfe3e0SGatien Chevallier if (rimu->risup_id == NO_RISUP_ID) {
6216cdfe3e0SGatien Chevallier EMSG("RIMU %"PRIu32" cannot be set in inheritance mode",
6226cdfe3e0SGatien Chevallier rimu->id);
6236cdfe3e0SGatien Chevallier if (!IS_ENABLED(CFG_INSECURE))
6246cdfe3e0SGatien Chevallier panic();
6256cdfe3e0SGatien Chevallier return;
6266cdfe3e0SGatien Chevallier }
6276cdfe3e0SGatien Chevallier
6286cdfe3e0SGatien Chevallier for (j = 0; j < pdata->nrisup; j++) {
6296cdfe3e0SGatien Chevallier if (rimu->risup_id == pdata->risup[j].id) {
6306cdfe3e0SGatien Chevallier risup = &pdata->risup[j];
6316cdfe3e0SGatien Chevallier break;
6326cdfe3e0SGatien Chevallier }
6336cdfe3e0SGatien Chevallier }
6346cdfe3e0SGatien Chevallier
6356cdfe3e0SGatien Chevallier if (!risup)
6366cdfe3e0SGatien Chevallier panic();
6376cdfe3e0SGatien Chevallier
6386cdfe3e0SGatien Chevallier risup_cidcfgr = io_read32(pdata->base +
6396cdfe3e0SGatien Chevallier _RIFSC_RISC_PER0_CIDCFGR +
6406cdfe3e0SGatien Chevallier _OFFSET_PERX_CIDCFGR * risup->id);
6416cdfe3e0SGatien Chevallier
6426cdfe3e0SGatien Chevallier if (!(risup_cidcfgr & RIFSC_RISC_CIDCFGR_CFEN_MASK) ||
6436cdfe3e0SGatien Chevallier (!(risup_cidcfgr & RIFSC_RISC_CIDCFGR_SEM_EN_MASK) &&
6446cdfe3e0SGatien Chevallier ((risup_cidcfgr & RIFSC_RISC_CIDCFGR_SCID_MASK) >>
6456cdfe3e0SGatien Chevallier RIFSC_RISC_CIDCFGR_SCID_SHIFT) == RIF_CID0) ||
6466cdfe3e0SGatien Chevallier (risup_cidcfgr & RIFSC_RISC_CIDCFGR_SEM_EN_MASK &&
6476cdfe3e0SGatien Chevallier risup_cidcfgr & BIT(RIF_CID0 +
6486cdfe3e0SGatien Chevallier RIFSC_RISC_CIDCFGR_SEML_SHIFT))) {
6496cdfe3e0SGatien Chevallier EMSG("RIMU %"PRIu32" in inheritance mode with CID0",
6506cdfe3e0SGatien Chevallier rimu->id);
6516cdfe3e0SGatien Chevallier if (!IS_ENABLED(CFG_INSECURE))
6526cdfe3e0SGatien Chevallier panic();
6536cdfe3e0SGatien Chevallier }
6546cdfe3e0SGatien Chevallier }
6556cdfe3e0SGatien Chevallier }
6566cdfe3e0SGatien Chevallier
stm32_rimu_cfg(struct rifsc_platdata * pdata,struct rimu_cfg * rimu)657cd187630SGatien Chevallier static TEE_Result stm32_rimu_cfg(struct rifsc_platdata *pdata,
658cd187630SGatien Chevallier struct rimu_cfg *rimu)
659cd187630SGatien Chevallier {
660cd187630SGatien Chevallier uintptr_t offset = _RIFSC_RIMC_ATTR0 + (sizeof(uint32_t) * rimu->id);
661cd187630SGatien Chevallier struct rifsc_driver_data *drv_data = pdata->drv_data;
662cd187630SGatien Chevallier
663cd187630SGatien Chevallier if (!rimu || rimu->id >= drv_data->nb_rimu)
664cd187630SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
665cd187630SGatien Chevallier
6666cdfe3e0SGatien Chevallier stm32_rimu_errata_ahbrisab(pdata, rimu);
6676cdfe3e0SGatien Chevallier
668cd187630SGatien Chevallier if (drv_data->rif_en)
669cd187630SGatien Chevallier io_write32(pdata->base + offset, rimu->attr);
670cd187630SGatien Chevallier
671cd187630SGatien Chevallier return TEE_SUCCESS;
672cd187630SGatien Chevallier }
673cd187630SGatien Chevallier
stm32_rimu_setup(struct rifsc_platdata * pdata)674cd187630SGatien Chevallier static TEE_Result stm32_rimu_setup(struct rifsc_platdata *pdata)
675cd187630SGatien Chevallier {
676cd187630SGatien Chevallier struct rifsc_driver_data *drv_data = pdata->drv_data;
677cd187630SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
678cd187630SGatien Chevallier unsigned int i = 0;
679cd187630SGatien Chevallier
680cd187630SGatien Chevallier for (i = 0; i < pdata->nrimu && i < drv_data->nb_rimu; i++) {
681cd187630SGatien Chevallier struct rimu_cfg *rimu = pdata->rimu + i;
682cd187630SGatien Chevallier
683cd187630SGatien Chevallier res = stm32_rimu_cfg(pdata, rimu);
684cd187630SGatien Chevallier if (res) {
685cd187630SGatien Chevallier EMSG("rimu cfg(%d/%d) error", i + 1, pdata->nrimu);
686cd187630SGatien Chevallier return res;
687cd187630SGatien Chevallier }
688cd187630SGatien Chevallier }
689cd187630SGatien Chevallier
690cd187630SGatien Chevallier return TEE_SUCCESS;
691cd187630SGatien Chevallier }
692cd187630SGatien Chevallier
693bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
stm32_risal_cfg(struct rifsc_platdata * pdata,struct risal_cfg * risal)694662542c7SGwenael Treuveur static TEE_Result stm32_risal_cfg(struct rifsc_platdata *pdata,
695662542c7SGwenael Treuveur struct risal_cfg *risal)
696662542c7SGwenael Treuveur {
697662542c7SGwenael Treuveur struct rifsc_driver_data *drv_data = pdata->drv_data;
698662542c7SGwenael Treuveur
699662542c7SGwenael Treuveur if (!risal || risal->id > drv_data->nb_risal)
700662542c7SGwenael Treuveur return TEE_ERROR_BAD_PARAMETERS;
701662542c7SGwenael Treuveur
702662542c7SGwenael Treuveur if (drv_data->rif_en) {
703662542c7SGwenael Treuveur uintptr_t offset_a = _RIFSC_RISAL_CFGR0_A(risal->id);
704662542c7SGwenael Treuveur uintptr_t offset_b = _RIFSC_RISAL_CFGR0_B(risal->id);
705662542c7SGwenael Treuveur
706662542c7SGwenael Treuveur if (risal->blockid == RIFSC_RISAL_BLOCK_A)
707662542c7SGwenael Treuveur io_write32(pdata->base + offset_a, risal->attr);
708662542c7SGwenael Treuveur if (risal->blockid == RIFSC_RISAL_BLOCK_B)
709662542c7SGwenael Treuveur io_write32(pdata->base + offset_b, risal->attr);
710662542c7SGwenael Treuveur }
711662542c7SGwenael Treuveur
712662542c7SGwenael Treuveur return TEE_SUCCESS;
713662542c7SGwenael Treuveur }
714662542c7SGwenael Treuveur
stm32_risal_setup(struct rifsc_platdata * pdata)715662542c7SGwenael Treuveur static TEE_Result stm32_risal_setup(struct rifsc_platdata *pdata)
716662542c7SGwenael Treuveur {
717662542c7SGwenael Treuveur unsigned int i = 0;
718662542c7SGwenael Treuveur TEE_Result res = TEE_ERROR_GENERIC;
719662542c7SGwenael Treuveur
720662542c7SGwenael Treuveur for (i = 0; i < pdata->nrisal; i++) {
721662542c7SGwenael Treuveur struct risal_cfg *risal = pdata->risal + i;
722662542c7SGwenael Treuveur
723662542c7SGwenael Treuveur res = stm32_risal_cfg(pdata, risal);
724662542c7SGwenael Treuveur if (res) {
725662542c7SGwenael Treuveur EMSG("risal cfg(%u/%u) error", i + 1, pdata->nrisal);
726662542c7SGwenael Treuveur return res;
727662542c7SGwenael Treuveur }
728662542c7SGwenael Treuveur }
729662542c7SGwenael Treuveur
730662542c7SGwenael Treuveur return TEE_SUCCESS;
731662542c7SGwenael Treuveur }
732bc951da9SThomas Bourgoin #endif /* CFG_STM32MP25 */
733662542c7SGwenael Treuveur
stm32_rifsc_check_access(struct firewall_query * firewall)734471cec14SGatien Chevallier static TEE_Result stm32_rifsc_check_access(struct firewall_query *firewall)
735471cec14SGatien Chevallier {
736471cec14SGatien Chevallier uintptr_t rifsc_base = rifsc_pdata.base;
737471cec14SGatien Chevallier unsigned int cid_reg_offset = 0;
738471cec14SGatien Chevallier unsigned int periph_offset = 0;
739471cec14SGatien Chevallier unsigned int resource_id = 0;
740471cec14SGatien Chevallier uint32_t cid_to_check = 0;
741471cec14SGatien Chevallier unsigned int reg_id = 0;
742471cec14SGatien Chevallier bool priv_check = true;
743471cec14SGatien Chevallier bool sec_check = true;
744471cec14SGatien Chevallier uint32_t privcfgr = 0;
745471cec14SGatien Chevallier uint32_t seccfgr = 0;
746471cec14SGatien Chevallier uint32_t cidcfgr = 0;
747471cec14SGatien Chevallier
748471cec14SGatien Chevallier assert(rifsc_base);
749471cec14SGatien Chevallier
750471cec14SGatien Chevallier if (!firewall || firewall->arg_count != 1)
751471cec14SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
752471cec14SGatien Chevallier
753471cec14SGatien Chevallier /*
754471cec14SGatien Chevallier * Peripheral configuration, we assume the configuration is as
755471cec14SGatien Chevallier * follows:
756471cec14SGatien Chevallier * firewall->args[0]: RIF configuration to check
757471cec14SGatien Chevallier */
758471cec14SGatien Chevallier resource_id = firewall->args[0] & RIF_PER_ID_MASK;
759471cec14SGatien Chevallier if (resource_id >= RIMU_ID_OFFSET)
760471cec14SGatien Chevallier return TEE_SUCCESS;
761471cec14SGatien Chevallier
762471cec14SGatien Chevallier reg_id = resource_id / _PERIPH_IDS_PER_REG;
763471cec14SGatien Chevallier periph_offset = resource_id % _PERIPH_IDS_PER_REG;
764471cec14SGatien Chevallier cid_reg_offset = _OFFSET_PERX_CIDCFGR * resource_id;
765471cec14SGatien Chevallier cidcfgr = io_read32(rifsc_base + _RIFSC_RISC_PER0_CIDCFGR +
766471cec14SGatien Chevallier cid_reg_offset);
767471cec14SGatien Chevallier seccfgr = io_read32(rifsc_base + _RIFSC_RISC_SECCFGR0 + 0x4 * reg_id);
768471cec14SGatien Chevallier privcfgr = io_read32(rifsc_base + _RIFSC_RISC_PRIVCFGR0 + 0x4 * reg_id);
769471cec14SGatien Chevallier sec_check = (BIT(RIF_SEC_SHIFT) & firewall->args[0]) != 0;
770471cec14SGatien Chevallier priv_check = (BIT(RIF_PRIV_SHIFT) & firewall->args[0]) != 0;
771471cec14SGatien Chevallier cid_to_check = (firewall->args[0] & RIF_SCID_MASK) >> RIF_SCID_SHIFT;
772471cec14SGatien Chevallier
773471cec14SGatien Chevallier if (!sec_check && seccfgr & BIT(periph_offset))
774471cec14SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
775471cec14SGatien Chevallier
776471cec14SGatien Chevallier if (!priv_check && (privcfgr & BIT(periph_offset)))
777471cec14SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
778471cec14SGatien Chevallier
779471cec14SGatien Chevallier if (!(cidcfgr & _CIDCFGR_CFEN))
780471cec14SGatien Chevallier return TEE_SUCCESS;
781471cec14SGatien Chevallier
782471cec14SGatien Chevallier if ((cidcfgr & _CIDCFGR_SEMEN &&
783471cec14SGatien Chevallier !stm32_rif_semaphore_enabled_and_ok(cidcfgr, cid_to_check)) ||
784471cec14SGatien Chevallier (!(cidcfgr & _CIDCFGR_SEMEN) &&
785471cec14SGatien Chevallier !stm32_rif_scid_ok(cidcfgr, RIFSC_RISC_CIDCFGR_SCID_MASK,
786471cec14SGatien Chevallier cid_to_check)))
787471cec14SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
788471cec14SGatien Chevallier
789471cec14SGatien Chevallier return TEE_SUCCESS;
790471cec14SGatien Chevallier }
791471cec14SGatien Chevallier
stm32_rifsc_acquire_access(struct firewall_query * firewall)792471cec14SGatien Chevallier static TEE_Result stm32_rifsc_acquire_access(struct firewall_query *firewall)
793471cec14SGatien Chevallier {
794471cec14SGatien Chevallier uintptr_t rifsc_base = rifsc_pdata.base;
795471cec14SGatien Chevallier unsigned int cid_reg_offset = 0;
796a6a331e5SGatien Chevallier unsigned int periph_offset = 0;
797471cec14SGatien Chevallier unsigned int resource_id = 0;
798a6a331e5SGatien Chevallier unsigned int reg_id = 0;
799471cec14SGatien Chevallier uint32_t cidcfgr = 0;
800a6a331e5SGatien Chevallier uint32_t seccfgr = 0;
801471cec14SGatien Chevallier
802471cec14SGatien Chevallier assert(rifsc_base);
803471cec14SGatien Chevallier
804471cec14SGatien Chevallier if (!firewall || !firewall->arg_count)
805471cec14SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
806471cec14SGatien Chevallier
807471cec14SGatien Chevallier /*
808471cec14SGatien Chevallier * Peripheral configuration, we assume the configuration is as
809471cec14SGatien Chevallier * follows:
810471cec14SGatien Chevallier * firewall->args[0]: Firewall ID of the resource to acquire
811471cec14SGatien Chevallier */
812471cec14SGatien Chevallier resource_id = firewall->args[0] & RIF_PER_ID_MASK;
813471cec14SGatien Chevallier if (resource_id >= RIMU_ID_OFFSET)
814471cec14SGatien Chevallier return TEE_SUCCESS;
815471cec14SGatien Chevallier
816a6a331e5SGatien Chevallier reg_id = resource_id / _PERIPH_IDS_PER_REG;
817a6a331e5SGatien Chevallier periph_offset = resource_id % _PERIPH_IDS_PER_REG;
818a6a331e5SGatien Chevallier
819471cec14SGatien Chevallier cid_reg_offset = _OFFSET_PERX_CIDCFGR * resource_id;
820471cec14SGatien Chevallier cidcfgr = io_read32(rifsc_base + _RIFSC_RISC_PER0_CIDCFGR +
821471cec14SGatien Chevallier cid_reg_offset);
822471cec14SGatien Chevallier
823a6a331e5SGatien Chevallier seccfgr = io_read32(rifsc_base + _RIFSC_RISC_SECCFGR0 + 0x4 * reg_id);
824a6a331e5SGatien Chevallier if (!(seccfgr & BIT(periph_offset)))
825a6a331e5SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
826a6a331e5SGatien Chevallier
827471cec14SGatien Chevallier /* Only check CID attributes */
828471cec14SGatien Chevallier if (!(cidcfgr & _CIDCFGR_CFEN))
829471cec14SGatien Chevallier return TEE_SUCCESS;
830471cec14SGatien Chevallier
831471cec14SGatien Chevallier if (cidcfgr & _CIDCFGR_SEMEN) {
832471cec14SGatien Chevallier if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
833471cec14SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
834471cec14SGatien Chevallier
835471cec14SGatien Chevallier /* Take the semaphore, static CID is irrelevant here */
836471cec14SGatien Chevallier return stm32_rif_acquire_semaphore(rifsc_base +
837471cec14SGatien Chevallier _RIFSC_RISC_PER0_SEMCR +
838471cec14SGatien Chevallier cid_reg_offset,
839471cec14SGatien Chevallier MAX_CID_SUPPORTED);
840471cec14SGatien Chevallier }
841471cec14SGatien Chevallier
842471cec14SGatien Chevallier if (!stm32_rif_scid_ok(cidcfgr, RIFSC_RISC_CIDCFGR_SCID_MASK, RIF_CID1))
843471cec14SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
844471cec14SGatien Chevallier
845471cec14SGatien Chevallier return TEE_SUCCESS;
846471cec14SGatien Chevallier }
847471cec14SGatien Chevallier
stm32_rifsc_set_config(struct firewall_query * firewall)848471cec14SGatien Chevallier static TEE_Result stm32_rifsc_set_config(struct firewall_query *firewall)
849471cec14SGatien Chevallier {
850471cec14SGatien Chevallier struct rimu_cfg rimu = { };
851471cec14SGatien Chevallier unsigned int id = 0;
852471cec14SGatien Chevallier uint32_t conf = 0;
853471cec14SGatien Chevallier
854471cec14SGatien Chevallier if (!firewall || firewall->arg_count != 1)
855471cec14SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
856471cec14SGatien Chevallier
857471cec14SGatien Chevallier /*
858471cec14SGatien Chevallier * Peripheral configuration, we assume the configuration is as
859471cec14SGatien Chevallier * follows:
860471cec14SGatien Chevallier * firewall->args[0]: RIF configuration to set
861471cec14SGatien Chevallier */
862471cec14SGatien Chevallier id = firewall->args[0] & RIF_PER_ID_MASK;
863471cec14SGatien Chevallier conf = firewall->args[0];
864471cec14SGatien Chevallier
865471cec14SGatien Chevallier if (id < RIMU_ID_OFFSET) {
866471cec14SGatien Chevallier struct risup_cfg risup = { };
867471cec14SGatien Chevallier uint32_t cidcfgr = 0;
868471cec14SGatien Chevallier
869471cec14SGatien Chevallier risup.id = id;
870471cec14SGatien Chevallier risup.sec = (BIT(RIF_SEC_SHIFT) & conf) != 0;
871471cec14SGatien Chevallier risup.priv = (BIT(RIF_PRIV_SHIFT) & conf) != 0;
872471cec14SGatien Chevallier risup.lock = (BIT(RIF_LOCK_SHIFT) & conf) != 0;
873471cec14SGatien Chevallier risup.cid_attr = _RIF_FLD_GET(RIF_PERx_CID, conf);
874471cec14SGatien Chevallier
875471cec14SGatien Chevallier if (!rifsc_pdata.is_tdcid) {
876471cec14SGatien Chevallier cidcfgr = io_read32(rifsc_pdata.base +
877471cec14SGatien Chevallier _OFFSET_PERX_CIDCFGR * risup.id +
878471cec14SGatien Chevallier _RIFSC_RISC_PER0_CIDCFGR);
879471cec14SGatien Chevallier
880471cec14SGatien Chevallier if (cidcfgr != risup.cid_attr)
881471cec14SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
882471cec14SGatien Chevallier }
883471cec14SGatien Chevallier
884471cec14SGatien Chevallier DMSG("Setting config for peripheral: %u, %s, %s, cid attr: %#"PRIx32", %s",
885471cec14SGatien Chevallier id, risup.sec ? "Secure" : "Non secure",
886471cec14SGatien Chevallier risup.priv ? "Privileged" : "Non privileged",
887471cec14SGatien Chevallier risup.cid_attr, risup.lock ? "Locked" : "Unlocked");
888471cec14SGatien Chevallier
889471cec14SGatien Chevallier return stm32_risup_cfg(&rifsc_pdata, &risup);
890471cec14SGatien Chevallier }
891471cec14SGatien Chevallier
892471cec14SGatien Chevallier if (!rifsc_pdata.is_tdcid)
893471cec14SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
894471cec14SGatien Chevallier
895471cec14SGatien Chevallier rimu.id = _RIF_FLD_GET(RIMUPROT_RIMC_M_ID, conf) - RIMU_ID_OFFSET;
896471cec14SGatien Chevallier rimu.attr = _RIF_FLD_GET(RIMUPROT_RIMC_ATTRx, conf);
897471cec14SGatien Chevallier
898471cec14SGatien Chevallier return stm32_rimu_cfg(&rifsc_pdata, &rimu);
899471cec14SGatien Chevallier }
900471cec14SGatien Chevallier
stm32_rifsc_release_access(struct firewall_query * firewall)901471cec14SGatien Chevallier static void stm32_rifsc_release_access(struct firewall_query *firewall)
902471cec14SGatien Chevallier {
903471cec14SGatien Chevallier uintptr_t rifsc_base = rifsc_pdata.base;
904471cec14SGatien Chevallier uint32_t cidcfgr = 0;
905471cec14SGatien Chevallier uint32_t id = 0;
906471cec14SGatien Chevallier
907471cec14SGatien Chevallier assert(rifsc_base && firewall && firewall->arg_count);
908471cec14SGatien Chevallier
909471cec14SGatien Chevallier id = firewall->args[0];
910471cec14SGatien Chevallier
911471cec14SGatien Chevallier if (id >= RIMU_ID_OFFSET)
912471cec14SGatien Chevallier return;
913471cec14SGatien Chevallier
914471cec14SGatien Chevallier cidcfgr = io_read32(rifsc_base + _RIFSC_RISC_PER0_CIDCFGR +
915471cec14SGatien Chevallier _OFFSET_PERX_CIDCFGR * id);
916471cec14SGatien Chevallier
917471cec14SGatien Chevallier /* Only thing possible is to release a semaphore taken by OP-TEE CID */
918471cec14SGatien Chevallier if (stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
919471cec14SGatien Chevallier if (stm32_rif_release_semaphore(rifsc_base +
920471cec14SGatien Chevallier _RIFSC_RISC_PER0_SEMCR +
921471cec14SGatien Chevallier id * _OFFSET_PERX_CIDCFGR,
922471cec14SGatien Chevallier MAX_CID_SUPPORTED))
923471cec14SGatien Chevallier panic("Could not release the RIF semaphore");
924471cec14SGatien Chevallier }
925471cec14SGatien Chevallier
stm32_rifsc_sem_pm_suspend(void)926cd187630SGatien Chevallier static TEE_Result stm32_rifsc_sem_pm_suspend(void)
927cd187630SGatien Chevallier {
928cd187630SGatien Chevallier unsigned int i = 0;
929cd187630SGatien Chevallier
930cd187630SGatien Chevallier for (i = 0; i < rifsc_pdata.nrisup && i < rifsc_drvdata.nb_risup; i++) {
931cd187630SGatien Chevallier uint32_t semcfgr = io_read32(rifsc_pdata.base +
932cd187630SGatien Chevallier _RIFSC_RISC_PER0_SEMCR +
933cd187630SGatien Chevallier _OFFSET_PERX_CIDCFGR * i);
934cd187630SGatien Chevallier struct risup_cfg *risup = rifsc_pdata.risup + i;
935cd187630SGatien Chevallier
936cd187630SGatien Chevallier /* Save semaphores that were taken by the CID1 */
937cd187630SGatien Chevallier risup->pm_sem = semcfgr & _SEMCR_MUTEX &&
938cd187630SGatien Chevallier ((semcfgr & _SEMCR_SEMCID_MASK) >>
939cd187630SGatien Chevallier _SEMCR_SEMCID_SHIFT) == RIF_CID1;
940cd187630SGatien Chevallier
941cd187630SGatien Chevallier FMSG("RIF semaphore %s for ID: %"PRIu32,
942cd187630SGatien Chevallier risup->pm_sem ? "SAVED" : "NOT SAVED", risup->id);
943cd187630SGatien Chevallier }
944cd187630SGatien Chevallier
945cd187630SGatien Chevallier return TEE_SUCCESS;
946cd187630SGatien Chevallier }
947cd187630SGatien Chevallier
stm32_rifsc_sem_pm_resume(void)948cd187630SGatien Chevallier static TEE_Result stm32_rifsc_sem_pm_resume(void)
949cd187630SGatien Chevallier {
950cd187630SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
951cd187630SGatien Chevallier unsigned int i = 0;
952cd187630SGatien Chevallier
953cd187630SGatien Chevallier for (i = 0; i < rifsc_pdata.nrisup && i < rifsc_drvdata.nb_risup; i++) {
954cd187630SGatien Chevallier struct risup_cfg *risup = rifsc_pdata.risup + i;
955cd187630SGatien Chevallier uintptr_t cidcfgr_offset = _OFFSET_PERX_CIDCFGR * risup->id;
956cd187630SGatien Chevallier uintptr_t offset = sizeof(uint32_t) *
957cd187630SGatien Chevallier (risup->id / _PERIPH_IDS_PER_REG);
958cd187630SGatien Chevallier uintptr_t perih_offset = risup->id % _PERIPH_IDS_PER_REG;
959cd187630SGatien Chevallier uint32_t seccgfr = io_read32(rifsc_pdata.base +
960cd187630SGatien Chevallier _RIFSC_RISC_SECCFGR0 + offset);
961cd187630SGatien Chevallier uint32_t privcgfr = io_read32(rifsc_pdata.base +
962cd187630SGatien Chevallier _RIFSC_RISC_PRIVCFGR0 + offset);
963cd187630SGatien Chevallier uint32_t lockcfgr = io_read32(rifsc_pdata.base +
964cd187630SGatien Chevallier _RIFSC_RISC_RCFGLOCKR0 + offset);
965cd187630SGatien Chevallier
966cd187630SGatien Chevallier /* Update RISUPs fields */
967cd187630SGatien Chevallier risup->cid_attr = io_read32(rifsc_pdata.base +
968cd187630SGatien Chevallier _RIFSC_RISC_PER0_CIDCFGR +
969cd187630SGatien Chevallier cidcfgr_offset);
970cd187630SGatien Chevallier risup->sec = (seccgfr & BIT(perih_offset)) != 0;
971cd187630SGatien Chevallier risup->priv = (privcgfr & BIT(perih_offset)) != 0;
972cd187630SGatien Chevallier risup->lock = (lockcfgr & BIT(perih_offset)) != 0;
973cd187630SGatien Chevallier
974cd187630SGatien Chevallier /* Acquire available appropriate semaphores */
975cd187630SGatien Chevallier if (!stm32_rif_semaphore_enabled_and_ok(risup->cid_attr,
976cd187630SGatien Chevallier RIF_CID1) ||
977cd187630SGatien Chevallier !risup->pm_sem)
978cd187630SGatien Chevallier continue;
979cd187630SGatien Chevallier
980cd187630SGatien Chevallier res = stm32_rif_acquire_semaphore(rifsc_pdata.base +
981cd187630SGatien Chevallier _RIFSC_RISC_PER0_SEMCR +
982cd187630SGatien Chevallier cidcfgr_offset,
983cd187630SGatien Chevallier MAX_CID_SUPPORTED);
984cd187630SGatien Chevallier if (res) {
985cd187630SGatien Chevallier EMSG("Could not acquire semaphore for resource %"PRIu32,
986cd187630SGatien Chevallier risup->id);
987cd187630SGatien Chevallier return TEE_ERROR_ACCESS_DENIED;
988cd187630SGatien Chevallier }
989cd187630SGatien Chevallier }
990cd187630SGatien Chevallier
991cd187630SGatien Chevallier return TEE_SUCCESS;
992cd187630SGatien Chevallier }
993cd187630SGatien Chevallier
994cd187630SGatien Chevallier static TEE_Result
stm32_rifsc_sem_pm(enum pm_op op,unsigned int pm_hint,const struct pm_callback_handle * pm_handle __unused)995cd187630SGatien Chevallier stm32_rifsc_sem_pm(enum pm_op op, unsigned int pm_hint,
996cd187630SGatien Chevallier const struct pm_callback_handle *pm_handle __unused)
997cd187630SGatien Chevallier {
998cd187630SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
999cd187630SGatien Chevallier
1000cd187630SGatien Chevallier if (pm_hint != PM_HINT_CONTEXT_STATE)
1001cd187630SGatien Chevallier return TEE_SUCCESS;
1002cd187630SGatien Chevallier
1003cd187630SGatien Chevallier if (op == PM_OP_RESUME)
1004cd187630SGatien Chevallier res = stm32_rifsc_sem_pm_resume();
1005cd187630SGatien Chevallier else
1006cd187630SGatien Chevallier res = stm32_rifsc_sem_pm_suspend();
1007cd187630SGatien Chevallier
1008cd187630SGatien Chevallier return res;
1009cd187630SGatien Chevallier }
1010cd187630SGatien Chevallier
stm32_rifsc_check_tdcid(bool * tdcid_state)1011cd187630SGatien Chevallier TEE_Result stm32_rifsc_check_tdcid(bool *tdcid_state)
1012cd187630SGatien Chevallier {
1013cd187630SGatien Chevallier if (!rifsc_pdata.base)
1014cd187630SGatien Chevallier return TEE_ERROR_DEFER_DRIVER_INIT;
1015cd187630SGatien Chevallier
1016cd187630SGatien Chevallier if (((io_read32(rifsc_pdata.base + _RIFSC_RIMC_CR) &
1017646ad62bSGatien Chevallier _RIFSC_RIMC_CR_TDCID_MASK)) == (RIF_CID1 << _CIDCFGR_SCID_SHIFT))
1018cd187630SGatien Chevallier *tdcid_state = true;
1019cd187630SGatien Chevallier else
1020cd187630SGatien Chevallier *tdcid_state = false;
1021cd187630SGatien Chevallier
1022cd187630SGatien Chevallier return TEE_SUCCESS;
1023cd187630SGatien Chevallier }
1024cd187630SGatien Chevallier
1025471cec14SGatien Chevallier static const struct firewall_controller_ops firewall_ops = {
1026471cec14SGatien Chevallier .set_conf = stm32_rifsc_set_config,
1027471cec14SGatien Chevallier .check_access = stm32_rifsc_check_access,
1028471cec14SGatien Chevallier .acquire_access = stm32_rifsc_acquire_access,
1029471cec14SGatien Chevallier .release_access = stm32_rifsc_release_access,
1030471cec14SGatien Chevallier };
1031471cec14SGatien Chevallier
1032a6a331e5SGatien Chevallier /**
1033a6a331e5SGatien Chevallier * stm32_rifsc_dt_probe_bus() - Add bus device tree subnodes that are accessible
1034a6a331e5SGatien Chevallier * by OP-TEE and secure to the driver probe list. This is used at boot time
1035a6a331e5SGatien Chevallier * only, as a sanity check between device tree and firewalls hardware
1036a6a331e5SGatien Chevallier * configurations to prevent undesired accesses when access to a device is not
1037a6a331e5SGatien Chevallier * authorized. This function tries to acquire access to every resource entries
1038a6a331e5SGatien Chevallier * listed in the access-controllers property of each of the subnodes. It panics
1039a6a331e5SGatien Chevallier * if it fails to do so. When CFG_INSECURE is enabled, platform can bypass this
1040a6a331e5SGatien Chevallier * access control test for specific devices assigned to non-secure world and
1041a6a331e5SGatien Chevallier * used by OP-TEE, such as an UART console device.
1042a6a331e5SGatien Chevallier *
1043a6a331e5SGatien Chevallier * @fdt: FDT to work on
1044a6a331e5SGatien Chevallier * @node: RIFSC node
1045a6a331e5SGatien Chevallier * @ctrl: RIFSC firewall controller reference
1046a6a331e5SGatien Chevallier */
1047a6a331e5SGatien Chevallier static TEE_Result
stm32_rifsc_dt_probe_bus(const void * fdt,int node,struct firewall_controller * ctrl __maybe_unused)1048a6a331e5SGatien Chevallier stm32_rifsc_dt_probe_bus(const void *fdt, int node,
1049a6a331e5SGatien Chevallier struct firewall_controller *ctrl __maybe_unused)
1050a6a331e5SGatien Chevallier {
1051a6a331e5SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
1052a6a331e5SGatien Chevallier struct firewall_query *fw = NULL;
1053a6a331e5SGatien Chevallier int subnode = 0;
1054a6a331e5SGatien Chevallier
1055a6a331e5SGatien Chevallier DMSG("Populating %s firewall bus", ctrl->name);
1056a6a331e5SGatien Chevallier
1057a6a331e5SGatien Chevallier fdt_for_each_subnode(subnode, fdt, node) {
1058a6a331e5SGatien Chevallier unsigned int i = 0;
1059a6a331e5SGatien Chevallier
1060a6a331e5SGatien Chevallier if (fdt_get_status(fdt, subnode) == DT_STATUS_DISABLED)
1061a6a331e5SGatien Chevallier continue;
1062a6a331e5SGatien Chevallier
1063a6a331e5SGatien Chevallier if (IS_ENABLED(CFG_INSECURE) &&
1064a6a331e5SGatien Chevallier stm32mp_allow_probe_shared_device(fdt, subnode)) {
1065a6a331e5SGatien Chevallier DMSG("Skipping firewall attributes check for %s",
1066a6a331e5SGatien Chevallier fdt_get_name(fdt, subnode, NULL));
1067a6a331e5SGatien Chevallier goto skip_check;
1068a6a331e5SGatien Chevallier }
1069a6a331e5SGatien Chevallier
1070a6a331e5SGatien Chevallier DMSG("Acquiring firewall access for %s when probing bus",
1071a6a331e5SGatien Chevallier fdt_get_name(fdt, subnode, NULL));
1072a6a331e5SGatien Chevallier
1073a6a331e5SGatien Chevallier do {
1074a6a331e5SGatien Chevallier /*
1075a6a331e5SGatien Chevallier * The access-controllers property is mandatory for
1076a6a331e5SGatien Chevallier * firewall bus devices
1077a6a331e5SGatien Chevallier */
1078a6a331e5SGatien Chevallier res = firewall_dt_get_by_index(fdt, subnode, i, &fw);
1079a6a331e5SGatien Chevallier if (res == TEE_ERROR_ITEM_NOT_FOUND) {
1080a6a331e5SGatien Chevallier /* Stop when nothing more to parse */
1081a6a331e5SGatien Chevallier break;
1082a6a331e5SGatien Chevallier } else if (res) {
1083a6a331e5SGatien Chevallier EMSG("%s: Error on node %s: %#"PRIx32,
1084a6a331e5SGatien Chevallier ctrl->name,
1085a6a331e5SGatien Chevallier fdt_get_name(fdt, subnode, NULL), res);
1086a6a331e5SGatien Chevallier panic();
1087a6a331e5SGatien Chevallier }
1088a6a331e5SGatien Chevallier
1089a6a331e5SGatien Chevallier res = firewall_acquire_access(fw);
1090a6a331e5SGatien Chevallier if (res) {
1091a6a331e5SGatien Chevallier EMSG("%s: %s not accessible: %#"PRIx32,
1092a6a331e5SGatien Chevallier ctrl->name,
1093a6a331e5SGatien Chevallier fdt_get_name(fdt, subnode, NULL), res);
1094a6a331e5SGatien Chevallier panic();
1095a6a331e5SGatien Chevallier }
1096a6a331e5SGatien Chevallier
1097a6a331e5SGatien Chevallier firewall_put(fw);
1098a6a331e5SGatien Chevallier i++;
1099a6a331e5SGatien Chevallier } while (true);
1100a6a331e5SGatien Chevallier
1101a6a331e5SGatien Chevallier skip_check:
1102a6a331e5SGatien Chevallier res = dt_driver_maybe_add_probe_node(fdt, subnode);
1103a6a331e5SGatien Chevallier if (res) {
1104a6a331e5SGatien Chevallier EMSG("Failed on node %s with %#"PRIx32,
1105a6a331e5SGatien Chevallier fdt_get_name(fdt, subnode, NULL), res);
1106a6a331e5SGatien Chevallier panic();
1107a6a331e5SGatien Chevallier }
1108a6a331e5SGatien Chevallier }
1109a6a331e5SGatien Chevallier
1110a6a331e5SGatien Chevallier return TEE_SUCCESS;
1111a6a331e5SGatien Chevallier }
1112a6a331e5SGatien Chevallier
stm32_rifsc_probe(const void * fdt,int node,const void * compat_data __unused)1113cd187630SGatien Chevallier static TEE_Result stm32_rifsc_probe(const void *fdt, int node,
1114cd187630SGatien Chevallier const void *compat_data __unused)
1115cd187630SGatien Chevallier {
1116471cec14SGatien Chevallier struct firewall_controller *controller = NULL;
1117cd187630SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
1118cd187630SGatien Chevallier
1119cd187630SGatien Chevallier res = stm32_rifsc_parse_fdt(fdt, node, &rifsc_pdata);
1120cd187630SGatien Chevallier if (res) {
1121cd187630SGatien Chevallier EMSG("Could not parse RIFSC node, res = %#"PRIx32, res);
1122cd187630SGatien Chevallier panic();
1123cd187630SGatien Chevallier }
1124cd187630SGatien Chevallier
1125cd187630SGatien Chevallier if (!rifsc_pdata.drv_data)
1126cd187630SGatien Chevallier stm32_rifsc_get_driverdata(&rifsc_pdata);
1127cd187630SGatien Chevallier
1128cd187630SGatien Chevallier res = stm32_risup_setup(&rifsc_pdata);
1129cd187630SGatien Chevallier if (res) {
1130cd187630SGatien Chevallier EMSG("Could not setup RISUPs, res = %#"PRIx32, res);
1131cd187630SGatien Chevallier panic();
1132cd187630SGatien Chevallier }
1133cd187630SGatien Chevallier
1134471cec14SGatien Chevallier if (rifsc_pdata.is_tdcid) {
1135cd187630SGatien Chevallier res = stm32_rimu_setup(&rifsc_pdata);
1136cd187630SGatien Chevallier if (res) {
1137cd187630SGatien Chevallier EMSG("Could not setup RIMUs, res = %#"PRIx32, res);
1138cd187630SGatien Chevallier panic();
1139cd187630SGatien Chevallier }
1140662542c7SGwenael Treuveur
1141bc951da9SThomas Bourgoin #if defined(CFG_STM32MP25)
1142662542c7SGwenael Treuveur res = stm32_risal_setup(&rifsc_pdata);
1143662542c7SGwenael Treuveur if (res)
1144662542c7SGwenael Treuveur panic();
1145bc951da9SThomas Bourgoin #endif /* CFG_STM32MP25 */
1146471cec14SGatien Chevallier }
1147cd187630SGatien Chevallier
1148cd187630SGatien Chevallier res = stm32_rifsc_glock_config(fdt, node, &rifsc_pdata);
1149cd187630SGatien Chevallier if (res)
1150cd187630SGatien Chevallier panic("Couldn't lock RIFSC configuration");
1151cd187630SGatien Chevallier
1152471cec14SGatien Chevallier controller = calloc(1, sizeof(*controller));
1153471cec14SGatien Chevallier if (!controller)
1154471cec14SGatien Chevallier panic();
1155471cec14SGatien Chevallier
1156471cec14SGatien Chevallier controller->name = "RIFSC";
1157471cec14SGatien Chevallier controller->priv = &rifsc_pdata;
1158471cec14SGatien Chevallier controller->ops = &firewall_ops;
1159471cec14SGatien Chevallier
1160471cec14SGatien Chevallier res = firewall_dt_controller_register(fdt, node, controller);
1161471cec14SGatien Chevallier if (res)
1162471cec14SGatien Chevallier panic();
1163471cec14SGatien Chevallier
1164a6a331e5SGatien Chevallier res = stm32_rifsc_dt_probe_bus(fdt, node, controller);
1165471cec14SGatien Chevallier if (res)
1166471cec14SGatien Chevallier panic();
1167471cec14SGatien Chevallier
1168cd187630SGatien Chevallier register_pm_core_service_cb(stm32_rifsc_sem_pm, NULL,
1169cd187630SGatien Chevallier "stm32-rifsc-semaphores");
1170cd187630SGatien Chevallier
1171cd187630SGatien Chevallier return TEE_SUCCESS;
1172cd187630SGatien Chevallier }
1173cd187630SGatien Chevallier
1174cd187630SGatien Chevallier static const struct dt_device_match rifsc_match_table[] = {
1175cd187630SGatien Chevallier { .compatible = "st,stm32mp25-rifsc" },
1176cd187630SGatien Chevallier { }
1177cd187630SGatien Chevallier };
1178cd187630SGatien Chevallier
1179cd187630SGatien Chevallier DEFINE_DT_DRIVER(rifsc_dt_driver) = {
1180cd187630SGatien Chevallier .name = "stm32-rifsc",
1181cd187630SGatien Chevallier .match_table = rifsc_match_table,
1182cd187630SGatien Chevallier .probe = stm32_rifsc_probe,
1183cd187630SGatien Chevallier };
1184