xref: /optee_os/core/drivers/firewall/stm32_rifsc.c (revision 37954afbedb868ac53aeb7abbfa1d376075c908d)
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, &reg_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