xref: /optee_os/core/drivers/firewall/stm32_risab.c (revision c94adf20a68d5525f96dad699ee3d9d1a379f106)
1c413678cSGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2c413678cSGatien Chevallier /*
3c413678cSGatien Chevallier  * Copyright (c) 2022-2024, STMicroelectronics
4c413678cSGatien Chevallier  */
5c413678cSGatien Chevallier 
6c413678cSGatien Chevallier #include <assert.h>
7c413678cSGatien Chevallier #include <drivers/clk.h>
8c413678cSGatien Chevallier #include <drivers/clk_dt.h>
9c413678cSGatien Chevallier #include <drivers/firewall.h>
10c413678cSGatien Chevallier #include <drivers/stm32_rif.h>
11c413678cSGatien Chevallier #include <drivers/stm32_risab.h>
12c413678cSGatien Chevallier #include <dt-bindings/firewall/stm32mp25-risab.h>
13c413678cSGatien Chevallier #include <io.h>
14c413678cSGatien Chevallier #include <kernel/boot.h>
15c413678cSGatien Chevallier #include <kernel/dt.h>
16c413678cSGatien Chevallier #include <kernel/pm.h>
178d8a3cb3SGatien Chevallier #include <kernel/spinlock.h>
18c413678cSGatien Chevallier #include <kernel/tee_misc.h>
19c413678cSGatien Chevallier #include <libfdt.h>
20c413678cSGatien Chevallier #include <mm/core_memprot.h>
21c413678cSGatien Chevallier #include <platform_config.h>
22c413678cSGatien Chevallier #include <stdint.h>
23c413678cSGatien Chevallier #include <string_ext.h>
24c413678cSGatien Chevallier #include <stm32_sysconf.h>
25c413678cSGatien Chevallier #include <util.h>
26c413678cSGatien Chevallier 
27c413678cSGatien Chevallier #define _RISAB_CR				U(0x0)
28c413678cSGatien Chevallier #define _RISAB_IASR				U(0x8)
29c413678cSGatien Chevallier #define _RISAB_IACR				U(0xC)
30c413678cSGatien Chevallier #define _RISAB_RCFGLOCKR			U(0x10)
31c413678cSGatien Chevallier #define _RISAB_IAESR				U(0x20)
32c413678cSGatien Chevallier #define _RISAB_IADDR				U(0x24)
33c413678cSGatien Chevallier #define _RISAB_PGy_SECCFGR(y)			(U(0x100) + (0x4 * (y)))
34c413678cSGatien Chevallier #define _RISAB_PGy_PRIVCFGR(y)			(U(0x200) + (0x4 * (y)))
35c413678cSGatien Chevallier #define _RISAB_RISAB_PGy_C2PRIVCFGR(y)		(U(0x600) + (0x4 * (y)))
36c413678cSGatien Chevallier #define _RISAB_CIDxPRIVCFGR(x)			(U(0x800) + (0x20 * (x)))
37c413678cSGatien Chevallier #define _RISAB_CIDxRDCFGR(x)			(U(0x808) + (0x20 * (x)))
38c413678cSGatien Chevallier #define _RISAB_CIDxWRCFGR(x)			(U(0x810) + (0x20 * (x)))
39c413678cSGatien Chevallier #define _RISAB_PGy_CIDCFGR(y)			(U(0xA00) + (0x4 * (y)))
40c413678cSGatien Chevallier #define _RISAB_HWCFGR3				U(0xFE8)
41c413678cSGatien Chevallier #define _RISAB_HWCFGR2				U(0xFEC)
42c413678cSGatien Chevallier #define _RISAB_HWCFGR1				U(0xFF0)
43c413678cSGatien Chevallier #define _RISAB_VERR				U(0xFF4)
44c413678cSGatien Chevallier #define _RISAB_IPIDR				U(0xFF8)
45c413678cSGatien Chevallier #define _RISAB_SIDR				U(0xFFC)
46c413678cSGatien Chevallier 
47c413678cSGatien Chevallier /* RISAB_CR bitfields */
48c413678cSGatien Chevallier #define _RISAB_CR_SRWIAD			BIT(31)
49c413678cSGatien Chevallier 
50c413678cSGatien Chevallier /* RISAB_IACR bitfields */
51c413678cSGatien Chevallier #define _RISAB_IACR_CAEF			BIT(0)
52c413678cSGatien Chevallier #define _RISAB_IACR_IAEF			BIT(1)
53c413678cSGatien Chevallier #define _RISAB_IACR_MASK			(_RISAB_IACR_CAEF | \
54c413678cSGatien Chevallier 						 _RISAB_IACR_IAEF)
55c413678cSGatien Chevallier 
56c413678cSGatien Chevallier /* Define RISAB_PG_SECCFGR bitfields */
57c413678cSGatien Chevallier #define _RISAB_PG_SECCFGR_MASK			GENMASK_32(7, 0)
58c413678cSGatien Chevallier 
59c413678cSGatien Chevallier /* Define RISAB_PG_PRIVCFGR bitfields */
60c413678cSGatien Chevallier #define _RISAB_PG_PRIVCFGR_MASK			GENMASK_32(7, 0)
61c413678cSGatien Chevallier 
62c413678cSGatien Chevallier /* CIDCFGR bitfields */
63c413678cSGatien Chevallier #define _RISAB_PG_CIDCFGR_CFEN			BIT(0)
64c413678cSGatien Chevallier #define _RISAB_PG_CIDCFGR_DCEN			BIT(2)
65c413678cSGatien Chevallier #define _RISAB_PG_CIDCFGR_DDCID_SHIFT		U(4)
66c413678cSGatien Chevallier #define _RISAB_PG_CIDCFGR_DDCID_MASK		GENMASK_32(6, 4)
67c413678cSGatien Chevallier #define _RISAB_PG_CIDCFGR_CONF_MASK		(_RISAB_PG_CIDCFGR_CFEN | \
68c413678cSGatien Chevallier 						 _RISAB_PG_CIDCFGR_DCEN | \
69c413678cSGatien Chevallier 						 _RISAB_PG_CIDCFGR_DDCID_MASK)
70c413678cSGatien Chevallier 
71c413678cSGatien Chevallier /* Miscellaneous */
72c413678cSGatien Chevallier #define _RISAB_NB_PAGES_MAX			U(32)
73c413678cSGatien Chevallier #define _RISAB_PAGE_SIZE			U(0x1000)
74c413678cSGatien Chevallier #define _RISAB_NB_MAX_CID_SUPPORTED		U(7)
75c413678cSGatien Chevallier 
76c413678cSGatien Chevallier #define RISAB_NAME_LEN_MAX			U(20)
77c413678cSGatien Chevallier 
78c413678cSGatien Chevallier struct mem_region {
79c413678cSGatien Chevallier 	paddr_t base;
80c413678cSGatien Chevallier 	size_t size;
81c413678cSGatien Chevallier };
82c413678cSGatien Chevallier 
83c413678cSGatien Chevallier struct stm32_risab_rif_conf {
84c413678cSGatien Chevallier 	unsigned int first_page;
85c413678cSGatien Chevallier 	unsigned int nb_pages_cfged;
86c413678cSGatien Chevallier 	uint32_t plist[_RISAB_NB_MAX_CID_SUPPORTED];
87c413678cSGatien Chevallier 	uint32_t rlist[_RISAB_NB_MAX_CID_SUPPORTED];
88c413678cSGatien Chevallier 	uint32_t wlist[_RISAB_NB_MAX_CID_SUPPORTED];
89c413678cSGatien Chevallier 	uint32_t cidcfgr;
90c413678cSGatien Chevallier 	uint32_t dprivcfgr;
91c413678cSGatien Chevallier 	uint32_t seccfgr;
92c413678cSGatien Chevallier };
93c413678cSGatien Chevallier 
94c413678cSGatien Chevallier struct stm32_risab_pdata {
95c413678cSGatien Chevallier 	unsigned int nb_regions_cfged;
96c413678cSGatien Chevallier 	struct clk *clock;
97c413678cSGatien Chevallier 	struct mem_region region_cfged;
98c413678cSGatien Chevallier 	struct stm32_risab_rif_conf *subr_cfg;
99c413678cSGatien Chevallier 	struct io_pa_va base;
100c413678cSGatien Chevallier 	unsigned int conf_lock;
101c413678cSGatien Chevallier 	char risab_name[RISAB_NAME_LEN_MAX];
102c413678cSGatien Chevallier 	uint32_t pages_configured;
103c413678cSGatien Chevallier 	bool srwiad;
104*c94adf20SGatien Chevallier 	bool errata_ahbrisab;
105c413678cSGatien Chevallier 
106c413678cSGatien Chevallier 	SLIST_ENTRY(stm32_risab_pdata) link;
107c413678cSGatien Chevallier };
108c413678cSGatien Chevallier 
109c413678cSGatien Chevallier static SLIST_HEAD(, stm32_risab_pdata) risab_list =
110c413678cSGatien Chevallier 		SLIST_HEAD_INITIALIZER(risab_list);
111c413678cSGatien Chevallier 
112c413678cSGatien Chevallier static bool is_tdcid;
113c413678cSGatien Chevallier 
risab_base(struct stm32_risab_pdata * risab)114c413678cSGatien Chevallier static vaddr_t risab_base(struct stm32_risab_pdata *risab)
115c413678cSGatien Chevallier {
116c413678cSGatien Chevallier 	return io_pa_or_va_secure(&risab->base, 1);
117c413678cSGatien Chevallier }
118c413678cSGatien Chevallier 
stm32_risab_clear_illegal_access_flags(void)119c413678cSGatien Chevallier void stm32_risab_clear_illegal_access_flags(void)
120c413678cSGatien Chevallier {
121c413678cSGatien Chevallier 	struct stm32_risab_pdata *risab = NULL;
122c413678cSGatien Chevallier 
123c413678cSGatien Chevallier 	SLIST_FOREACH(risab, &risab_list, link) {
124c413678cSGatien Chevallier 		vaddr_t base = risab_base(risab);
125c413678cSGatien Chevallier 
126c413678cSGatien Chevallier 		if (!io_read32(base + _RISAB_IASR))
127c413678cSGatien Chevallier 			continue;
128c413678cSGatien Chevallier 
129c413678cSGatien Chevallier 		io_write32(base + _RISAB_IACR, _RISAB_IACR_CAEF |
130c413678cSGatien Chevallier 			   _RISAB_IACR_IAEF);
131c413678cSGatien Chevallier 	}
132c413678cSGatien Chevallier }
133c413678cSGatien Chevallier 
134c413678cSGatien Chevallier #ifdef CFG_TEE_CORE_DEBUG
stm32_risab_print_erroneous_data(void)135c413678cSGatien Chevallier void stm32_risab_print_erroneous_data(void)
136c413678cSGatien Chevallier {
137c413678cSGatien Chevallier 	struct stm32_risab_pdata *risab = NULL;
138c413678cSGatien Chevallier 
139c413678cSGatien Chevallier 	SLIST_FOREACH(risab, &risab_list, link) {
140c413678cSGatien Chevallier 		vaddr_t base = risab_base(risab);
141c413678cSGatien Chevallier 
142c413678cSGatien Chevallier 		/* Check if faulty address on this RISAB */
143c413678cSGatien Chevallier 		if (!io_read32(base + _RISAB_IASR))
144c413678cSGatien Chevallier 			continue;
145c413678cSGatien Chevallier 
146c413678cSGatien Chevallier 		EMSG("\n\nDUMPING DATA FOR %s\n\n", risab->risab_name);
147c413678cSGatien Chevallier 		EMSG("=====================================================");
148c413678cSGatien Chevallier 		EMSG("Status register (IAESR): %#"PRIx32,
149c413678cSGatien Chevallier 		     io_read32(base + _RISAB_IAESR));
150c413678cSGatien Chevallier 		EMSG("-----------------------------------------------------");
151c413678cSGatien Chevallier 		EMSG("Faulty address (IADDR): %#"PRIx32,
152c413678cSGatien Chevallier 		     io_read32(base + _RISAB_IADDR));
153c413678cSGatien Chevallier 		EMSG("=====================================================\n");
154c413678cSGatien Chevallier 	};
155c413678cSGatien Chevallier }
156c413678cSGatien Chevallier #endif /* CFG_TEE_CORE_DEBUG */
157c413678cSGatien Chevallier 
regs_access_granted(struct stm32_risab_pdata * risab_d,unsigned int reg_idx)158c413678cSGatien Chevallier static bool regs_access_granted(struct stm32_risab_pdata *risab_d,
159c413678cSGatien Chevallier 				unsigned int reg_idx)
160c413678cSGatien Chevallier {
161c413678cSGatien Chevallier 	unsigned int first_page = risab_d->subr_cfg[reg_idx].first_page;
162c413678cSGatien Chevallier 	uint32_t cidcfgr = io_read32(risab_base(risab_d) +
163c413678cSGatien Chevallier 				     _RISAB_PGy_CIDCFGR(first_page));
164c413678cSGatien Chevallier 
165d1b39e37SGatien Chevallier 	if (virt_to_phys((void *)risab_base(risab_d)) == RISAB1_BASE ||
166d1b39e37SGatien Chevallier 	    virt_to_phys((void *)risab_base(risab_d)) == RISAB2_BASE)
167d1b39e37SGatien Chevallier 		return true;
168d1b39e37SGatien Chevallier 
169d1b39e37SGatien Chevallier 	/* No CID filtering */
170d1b39e37SGatien Chevallier 	if (!(cidcfgr & _RISAB_PG_CIDCFGR_CFEN))
171d1b39e37SGatien Chevallier 		return true;
172d1b39e37SGatien Chevallier 
173c413678cSGatien Chevallier 	/* Trusted CID access */
174d1b39e37SGatien Chevallier 	if (is_tdcid && !(cidcfgr & _RISAB_PG_CIDCFGR_DCEN))
175c413678cSGatien Chevallier 		return true;
176c413678cSGatien Chevallier 
177c413678cSGatien Chevallier 	/* Delegated CID access check */
178d1b39e37SGatien Chevallier 	if (cidcfgr & _RISAB_PG_CIDCFGR_DCEN &&
179c413678cSGatien Chevallier 	    ((cidcfgr & _RISAB_PG_CIDCFGR_DDCID_MASK) >>
180c413678cSGatien Chevallier 	     _RISAB_PG_CIDCFGR_DDCID_SHIFT) == RIF_CID1)
181c413678cSGatien Chevallier 		return true;
182c413678cSGatien Chevallier 
183c413678cSGatien Chevallier 	return false;
184c413678cSGatien Chevallier }
185c413678cSGatien Chevallier 
set_block_seccfgr(struct stm32_risab_pdata * risab_d,struct stm32_risab_rif_conf * subr_cfg)186c413678cSGatien Chevallier static void set_block_seccfgr(struct stm32_risab_pdata *risab_d,
187c413678cSGatien Chevallier 			      struct stm32_risab_rif_conf *subr_cfg)
188c413678cSGatien Chevallier {
189c413678cSGatien Chevallier 	vaddr_t base = risab_base(risab_d);
190c413678cSGatien Chevallier 	unsigned int i = 0;
191c413678cSGatien Chevallier 	unsigned int last_page = subr_cfg->first_page +
192c413678cSGatien Chevallier 				 subr_cfg->nb_pages_cfged - 1;
193c413678cSGatien Chevallier 
194c413678cSGatien Chevallier 	for (i = subr_cfg->first_page; i <= last_page; i++)
195c413678cSGatien Chevallier 		io_clrsetbits32(base + _RISAB_PGy_SECCFGR(i),
196c413678cSGatien Chevallier 				_RISAB_PG_SECCFGR_MASK, subr_cfg->seccfgr);
197c413678cSGatien Chevallier }
198c413678cSGatien Chevallier 
set_block_dprivcfgr(struct stm32_risab_pdata * risab_d,struct stm32_risab_rif_conf * subr_cfg)199c413678cSGatien Chevallier static void set_block_dprivcfgr(struct stm32_risab_pdata *risab_d,
200c413678cSGatien Chevallier 				struct stm32_risab_rif_conf *subr_cfg)
201c413678cSGatien Chevallier {
202c413678cSGatien Chevallier 	vaddr_t base = risab_base(risab_d);
203c413678cSGatien Chevallier 	unsigned int i = 0;
204c413678cSGatien Chevallier 	unsigned int last_page = subr_cfg->first_page +
205c413678cSGatien Chevallier 				 subr_cfg->nb_pages_cfged - 1;
206c413678cSGatien Chevallier 
207c413678cSGatien Chevallier 	for (i = subr_cfg->first_page; i <= last_page; i++)
208c413678cSGatien Chevallier 		io_clrsetbits32(base + _RISAB_PGy_PRIVCFGR(i),
209c413678cSGatien Chevallier 				_RISAB_PG_PRIVCFGR_MASK,
210c413678cSGatien Chevallier 				subr_cfg->dprivcfgr);
211c413678cSGatien Chevallier }
212c413678cSGatien Chevallier 
set_cidcfgr(struct stm32_risab_pdata * risab_d,struct stm32_risab_rif_conf * subr_cfg)213c413678cSGatien Chevallier static void set_cidcfgr(struct stm32_risab_pdata *risab_d,
214c413678cSGatien Chevallier 			struct stm32_risab_rif_conf *subr_cfg)
215c413678cSGatien Chevallier {
216c413678cSGatien Chevallier 	vaddr_t base = risab_base(risab_d);
217c413678cSGatien Chevallier 	unsigned int i = 0;
218c413678cSGatien Chevallier 	unsigned int last_page = subr_cfg->first_page +
219c413678cSGatien Chevallier 				 subr_cfg->nb_pages_cfged - 1;
220c413678cSGatien Chevallier 
221c413678cSGatien Chevallier 	for (i = subr_cfg->first_page; i <= last_page; i++) {
222c413678cSGatien Chevallier 		/*
223c413678cSGatien Chevallier 		 * When TDCID, OP-TEE should be the one to set the CID filtering
224c413678cSGatien Chevallier 		 * configuration. Clearing previous configuration prevents
225c413678cSGatien Chevallier 		 * undesired events during the only legitimate configuration.
226c413678cSGatien Chevallier 		 */
227c413678cSGatien Chevallier 		io_clrsetbits32(base + _RISAB_PGy_CIDCFGR(i),
228c413678cSGatien Chevallier 				_RISAB_PG_CIDCFGR_CONF_MASK,
229c413678cSGatien Chevallier 				subr_cfg->cidcfgr);
230c413678cSGatien Chevallier 	}
231c413678cSGatien Chevallier }
232c413678cSGatien Chevallier 
set_read_conf(struct stm32_risab_pdata * risab_d,struct stm32_risab_rif_conf * subr_cfg)233c413678cSGatien Chevallier static void set_read_conf(struct stm32_risab_pdata *risab_d,
234c413678cSGatien Chevallier 			  struct stm32_risab_rif_conf *subr_cfg)
235c413678cSGatien Chevallier {
236c413678cSGatien Chevallier 	vaddr_t base = risab_base(risab_d);
237c413678cSGatien Chevallier 	unsigned int i = 0;
238c413678cSGatien Chevallier 	unsigned int last_page = subr_cfg->first_page +
239c413678cSGatien Chevallier 				 subr_cfg->nb_pages_cfged - 1;
240c413678cSGatien Chevallier 	uint32_t mask = GENMASK_32(last_page, subr_cfg->first_page);
241c413678cSGatien Chevallier 
242c413678cSGatien Chevallier 	for (i = 0; i < _RISAB_NB_MAX_CID_SUPPORTED; i++) {
243*c94adf20SGatien Chevallier 		/*
244*c94adf20SGatien Chevallier 		 * Errata: CID0 must be authorized for RISAB accesses if
245*c94adf20SGatien Chevallier 		 * CID filtering is enabled on some RISAB instances so that
246*c94adf20SGatien Chevallier 		 * transient CID0 transactions are handled.
247*c94adf20SGatien Chevallier 		 */
248*c94adf20SGatien Chevallier 		if (subr_cfg->rlist[i] ||
249*c94adf20SGatien Chevallier 		    (risab_d->errata_ahbrisab && i == RIF_CID0))
250*c94adf20SGatien Chevallier 			io_clrsetbits32(base + _RISAB_CIDxRDCFGR(i), mask,
251*c94adf20SGatien Chevallier 					mask);
252c413678cSGatien Chevallier 	}
253c413678cSGatien Chevallier }
254c413678cSGatien Chevallier 
set_write_conf(struct stm32_risab_pdata * risab_d,struct stm32_risab_rif_conf * subr_cfg)255c413678cSGatien Chevallier static void set_write_conf(struct stm32_risab_pdata *risab_d,
256c413678cSGatien Chevallier 			   struct stm32_risab_rif_conf *subr_cfg)
257c413678cSGatien Chevallier {
258c413678cSGatien Chevallier 	vaddr_t base = risab_base(risab_d);
259c413678cSGatien Chevallier 	unsigned int i = 0;
260c413678cSGatien Chevallier 	unsigned int last_page = subr_cfg->first_page +
261c413678cSGatien Chevallier 				 subr_cfg->nb_pages_cfged - 1;
262c413678cSGatien Chevallier 	uint32_t mask = GENMASK_32(last_page, subr_cfg->first_page);
263c413678cSGatien Chevallier 
264c413678cSGatien Chevallier 	for (i = 0; i < _RISAB_NB_MAX_CID_SUPPORTED; i++) {
265*c94adf20SGatien Chevallier 		/*
266*c94adf20SGatien Chevallier 		 * Errata: CID0 must be authorized for RISAB accesses if
267*c94adf20SGatien Chevallier 		 * CID filtering is enabled on some RISAB instances so that
268*c94adf20SGatien Chevallier 		 * transient CID0 transactions are handled.
269*c94adf20SGatien Chevallier 		 */
270*c94adf20SGatien Chevallier 		if (subr_cfg->wlist[i] ||
271*c94adf20SGatien Chevallier 		    (risab_d->errata_ahbrisab && i == RIF_CID0))
272*c94adf20SGatien Chevallier 			io_clrsetbits32(base + _RISAB_CIDxWRCFGR(i), mask,
273*c94adf20SGatien Chevallier 					mask);
274c413678cSGatien Chevallier 	}
275c413678cSGatien Chevallier }
276c413678cSGatien Chevallier 
set_cid_priv_conf(struct stm32_risab_pdata * risab_d,struct stm32_risab_rif_conf * subr_cfg)277c413678cSGatien Chevallier static void set_cid_priv_conf(struct stm32_risab_pdata *risab_d,
278c413678cSGatien Chevallier 			      struct stm32_risab_rif_conf *subr_cfg)
279c413678cSGatien Chevallier {
280c413678cSGatien Chevallier 	vaddr_t base = risab_base(risab_d);
281c413678cSGatien Chevallier 	unsigned int i = 0;
282c413678cSGatien Chevallier 	unsigned int last_page = subr_cfg->first_page +
283c413678cSGatien Chevallier 				 subr_cfg->nb_pages_cfged - 1;
284c413678cSGatien Chevallier 	uint32_t mask = GENMASK_32(last_page, subr_cfg->first_page);
285c413678cSGatien Chevallier 
286c413678cSGatien Chevallier 	for (i = 0; i < _RISAB_NB_MAX_CID_SUPPORTED; i++) {
287c413678cSGatien Chevallier 		if (subr_cfg->plist[i])
288c413678cSGatien Chevallier 			io_clrsetbits32(base + _RISAB_CIDxPRIVCFGR(i), mask,
289c413678cSGatien Chevallier 					subr_cfg->plist[i]);
290c413678cSGatien Chevallier 	}
291c413678cSGatien Chevallier }
292c413678cSGatien Chevallier 
set_rif_registers(struct stm32_risab_pdata * risab,unsigned int reg_idx)2938d8a3cb3SGatien Chevallier static TEE_Result set_rif_registers(struct stm32_risab_pdata *risab,
2948d8a3cb3SGatien Chevallier 				    unsigned int reg_idx)
2958d8a3cb3SGatien Chevallier {
2968d8a3cb3SGatien Chevallier 	struct stm32_risab_rif_conf *subr_cfg = NULL;
2978d8a3cb3SGatien Chevallier 
2988d8a3cb3SGatien Chevallier 	assert(&risab->subr_cfg[reg_idx]);
2998d8a3cb3SGatien Chevallier 
3008d8a3cb3SGatien Chevallier 	subr_cfg = &risab->subr_cfg[reg_idx];
3018d8a3cb3SGatien Chevallier 
3028d8a3cb3SGatien Chevallier 	/*
3038d8a3cb3SGatien Chevallier 	 * This sequence will generate an IAC if the CID filtering
3048d8a3cb3SGatien Chevallier 	 * configuration is inconsistent with these desired rights
3058d8a3cb3SGatien Chevallier 	 * to apply.
3068d8a3cb3SGatien Chevallier 	 */
3078d8a3cb3SGatien Chevallier 	if (!regs_access_granted(risab, reg_idx))
3088d8a3cb3SGatien Chevallier 		return TEE_ERROR_ACCESS_DENIED;
3098d8a3cb3SGatien Chevallier 
3108d8a3cb3SGatien Chevallier 	set_block_dprivcfgr(risab, subr_cfg);
3118d8a3cb3SGatien Chevallier 	set_block_seccfgr(risab, subr_cfg);
3128d8a3cb3SGatien Chevallier 
3138d8a3cb3SGatien Chevallier 	/*
3148d8a3cb3SGatien Chevallier 	 * Grant page access to some CIDs, in read and/or write, and the
3158d8a3cb3SGatien Chevallier 	 * necessary privilege level.
3168d8a3cb3SGatien Chevallier 	 */
3178d8a3cb3SGatien Chevallier 	set_read_conf(risab, subr_cfg);
3188d8a3cb3SGatien Chevallier 	set_write_conf(risab, subr_cfg);
3198d8a3cb3SGatien Chevallier 	set_cid_priv_conf(risab, subr_cfg);
3208d8a3cb3SGatien Chevallier 
3218d8a3cb3SGatien Chevallier 	if (virt_to_phys((void *)risab_base(risab)) != RISAB1_BASE &&
3228d8a3cb3SGatien Chevallier 	    virt_to_phys((void *)risab_base(risab)) != RISAB2_BASE) {
3238d8a3cb3SGatien Chevallier 		/* Delegate RIF configuration or not */
3248d8a3cb3SGatien Chevallier 		if (!is_tdcid)
3258d8a3cb3SGatien Chevallier 			DMSG("Cannot set %s CID config for region %u",
3268d8a3cb3SGatien Chevallier 			     risab->risab_name, reg_idx);
3278d8a3cb3SGatien Chevallier 		else
3288d8a3cb3SGatien Chevallier 			set_cidcfgr(risab, subr_cfg);
3298d8a3cb3SGatien Chevallier 	} else {
3308d8a3cb3SGatien Chevallier 		set_cidcfgr(risab, subr_cfg);
3318d8a3cb3SGatien Chevallier 	}
3328d8a3cb3SGatien Chevallier 
3338d8a3cb3SGatien Chevallier 	dsb();
3348d8a3cb3SGatien Chevallier 
3358d8a3cb3SGatien Chevallier 	return TEE_SUCCESS;
3368d8a3cb3SGatien Chevallier }
3378d8a3cb3SGatien Chevallier 
apply_rif_config(struct stm32_risab_pdata * risab_d)338c413678cSGatien Chevallier static void apply_rif_config(struct stm32_risab_pdata *risab_d)
339c413678cSGatien Chevallier {
340c413678cSGatien Chevallier 	vaddr_t base = risab_base(risab_d);
341c413678cSGatien Chevallier 	unsigned int i = 0;
342c413678cSGatien Chevallier 
343c413678cSGatien Chevallier 	/* If TDCID, we expect to restore default RISAB configuration */
344c413678cSGatien Chevallier 	if (is_tdcid) {
345c413678cSGatien Chevallier 		for (i = 0; i < _RISAB_NB_PAGES_MAX; i++) {
346c413678cSGatien Chevallier 			io_clrbits32(base + _RISAB_PGy_CIDCFGR(i),
347c413678cSGatien Chevallier 				     _RISAB_PG_CIDCFGR_CONF_MASK);
348c413678cSGatien Chevallier 			io_clrbits32(base + _RISAB_PGy_SECCFGR(i),
349c413678cSGatien Chevallier 				     _RISAB_PG_SECCFGR_MASK);
350c413678cSGatien Chevallier 			io_clrbits32(base + _RISAB_PGy_PRIVCFGR(i),
351c413678cSGatien Chevallier 				     _RISAB_PG_PRIVCFGR_MASK);
352c413678cSGatien Chevallier 		}
353c413678cSGatien Chevallier 		for (i = 0; i < _RISAB_NB_MAX_CID_SUPPORTED; i++) {
354c413678cSGatien Chevallier 			io_clrbits32(base + _RISAB_CIDxRDCFGR(i), UINT32_MAX);
355c413678cSGatien Chevallier 			io_clrbits32(base + _RISAB_CIDxWRCFGR(i), UINT32_MAX);
356c413678cSGatien Chevallier 			io_clrbits32(base + _RISAB_CIDxPRIVCFGR(i), UINT32_MAX);
357c413678cSGatien Chevallier 		}
358c413678cSGatien Chevallier 	}
359c413678cSGatien Chevallier 
360c413678cSGatien Chevallier 	for (i = 0; i < risab_d->nb_regions_cfged; i++) {
3618d8a3cb3SGatien Chevallier 		if (set_rif_registers(risab_d, i))
362c413678cSGatien Chevallier 			panic();
363c413678cSGatien Chevallier 	}
364c413678cSGatien Chevallier }
365c413678cSGatien Chevallier 
parse_risab_rif_conf(struct stm32_risab_pdata * risab_d,struct stm32_risab_rif_conf * subr_cfg,uint32_t rif_conf,bool check_overlap)366c413678cSGatien Chevallier static void parse_risab_rif_conf(struct stm32_risab_pdata *risab_d,
367c413678cSGatien Chevallier 				 struct stm32_risab_rif_conf *subr_cfg,
368c413678cSGatien Chevallier 				 uint32_t rif_conf, bool check_overlap)
369c413678cSGatien Chevallier {
370c413678cSGatien Chevallier 	unsigned int first_page = subr_cfg->first_page;
371c413678cSGatien Chevallier 	unsigned int last_page = first_page + subr_cfg->nb_pages_cfged - 1;
372c413678cSGatien Chevallier 	uint32_t reg_pages_cfged = GENMASK_32(last_page, first_page);
373c413678cSGatien Chevallier 	unsigned int i = 0;
374c413678cSGatien Chevallier 
375c413678cSGatien Chevallier 	assert(last_page <= _RISAB_NB_PAGES_MAX);
376c413678cSGatien Chevallier 
377c413678cSGatien Chevallier 	DMSG("Configuring pages %u to %u", first_page, last_page);
378c413678cSGatien Chevallier 
379c413678cSGatien Chevallier 	/* Parse secure configuration */
380c413678cSGatien Chevallier 	if (rif_conf & BIT(RISAB_SEC_SHIFT)) {
381c413678cSGatien Chevallier 		subr_cfg->seccfgr = _RISAB_PG_SECCFGR_MASK;
382c413678cSGatien Chevallier 		/*
383c413678cSGatien Chevallier 		 * Memory region overlapping should only be checked at platform
384c413678cSGatien Chevallier 		 * setup when memory mapping is first applied. A region's
385c413678cSGatien Chevallier 		 * attributes can later be dynamically modified but not its
386c413678cSGatien Chevallier 		 * bounds.
387c413678cSGatien Chevallier 		 */
388c413678cSGatien Chevallier 		if (check_overlap &&
389c413678cSGatien Chevallier 		    reg_pages_cfged & risab_d->pages_configured)
390c413678cSGatien Chevallier 			panic("Memory region overlap detected");
391c413678cSGatien Chevallier 	} else {
392c413678cSGatien Chevallier 		subr_cfg->seccfgr = 0;
393c413678cSGatien Chevallier 	}
394c413678cSGatien Chevallier 
395c413678cSGatien Chevallier 	/* Parse default privilege configuration */
396c413678cSGatien Chevallier 	if (rif_conf & BIT(RISAB_DPRIV_SHIFT)) {
397c413678cSGatien Chevallier 		subr_cfg->dprivcfgr = _RISAB_PG_PRIVCFGR_MASK;
398c413678cSGatien Chevallier 		if (check_overlap &&
399c413678cSGatien Chevallier 		    reg_pages_cfged & risab_d->pages_configured)
400c413678cSGatien Chevallier 			panic("Memory region overlap detected");
401c413678cSGatien Chevallier 	} else {
402c413678cSGatien Chevallier 		subr_cfg->dprivcfgr = 0;
403c413678cSGatien Chevallier 	}
404c413678cSGatien Chevallier 
405c413678cSGatien Chevallier 	if (check_overlap)
406c413678cSGatien Chevallier 		risab_d->pages_configured |= reg_pages_cfged;
407c413678cSGatien Chevallier 
408c413678cSGatien Chevallier 	for (i = 0; i < _RISAB_NB_MAX_CID_SUPPORTED; i++) {
409c413678cSGatien Chevallier 		/* RISAB compartment priv configuration */
410c413678cSGatien Chevallier 		if (rif_conf & BIT(i))
411c413678cSGatien Chevallier 			subr_cfg->plist[i] |= GENMASK_32(last_page, first_page);
412c413678cSGatien Chevallier 
413c413678cSGatien Chevallier 		/* RISAB compartment read configuration */
414c413678cSGatien Chevallier 		if (rif_conf & BIT(i + RISAB_READ_LIST_SHIFT))
415c413678cSGatien Chevallier 			subr_cfg->rlist[i] |= GENMASK_32(last_page, first_page);
416c413678cSGatien Chevallier 
417c413678cSGatien Chevallier 		/* RISAB compartment write configuration */
418c413678cSGatien Chevallier 		if (rif_conf & BIT(i + RISAB_WRITE_LIST_SHIFT))
419c413678cSGatien Chevallier 			subr_cfg->wlist[i] |= GENMASK_32(last_page, first_page);
420c413678cSGatien Chevallier 	}
421c413678cSGatien Chevallier 
422c413678cSGatien Chevallier 	/* CID filtering configuration */
423c413678cSGatien Chevallier 	if (rif_conf & BIT(RISAB_CFEN_SHIFT))
424c413678cSGatien Chevallier 		subr_cfg->cidcfgr |= _RISAB_PG_CIDCFGR_CFEN;
425c413678cSGatien Chevallier 
426c413678cSGatien Chevallier 	if (rif_conf & BIT(RISAB_DCEN_SHIFT))
427c413678cSGatien Chevallier 		subr_cfg->cidcfgr |= _RISAB_PG_CIDCFGR_DCEN;
428c413678cSGatien Chevallier 
429c413678cSGatien Chevallier 	if (rif_conf & RISAB_DCCID_MASK) {
430c413678cSGatien Chevallier 		uint32_t ddcid = SHIFT_U32((rif_conf & RISAB_DCCID_MASK) >>
431c413678cSGatien Chevallier 					   RISAB_DCCID_SHIFT,
432c413678cSGatien Chevallier 					   _RISAB_PG_CIDCFGR_DDCID_SHIFT);
433c413678cSGatien Chevallier 
434c413678cSGatien Chevallier 		assert(((rif_conf & RISAB_DCCID_MASK) >> RISAB_DCCID_SHIFT) <
435c413678cSGatien Chevallier 		       _RISAB_NB_MAX_CID_SUPPORTED);
436c413678cSGatien Chevallier 
437c413678cSGatien Chevallier 		subr_cfg->cidcfgr |= ddcid;
438c413678cSGatien Chevallier 	}
439c413678cSGatien Chevallier }
440c413678cSGatien Chevallier 
parse_dt(const void * fdt,int node,struct stm32_risab_pdata * risab_d)441c413678cSGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node,
442c413678cSGatien Chevallier 			   struct stm32_risab_pdata *risab_d)
443c413678cSGatien Chevallier {
444c413678cSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
445c413678cSGatien Chevallier 	const fdt32_t *mem_regions = NULL;
446c413678cSGatien Chevallier 	struct dt_node_info info = { };
447c413678cSGatien Chevallier 	const fdt32_t *cuint = NULL;
448c413678cSGatien Chevallier 	int mem_reg_node = 0;
449c413678cSGatien Chevallier 	unsigned int i = 0;
450c413678cSGatien Chevallier 	int lenp = 0;
451c413678cSGatien Chevallier 
452c413678cSGatien Chevallier 	fdt_fill_device_info(fdt, &info, node);
453c413678cSGatien Chevallier 	assert(info.reg != DT_INFO_INVALID_REG &&
454c413678cSGatien Chevallier 	       info.reg_size != DT_INFO_INVALID_REG_SIZE);
455c413678cSGatien Chevallier 
456c413678cSGatien Chevallier 	risab_d->base.pa = info.reg;
457c413678cSGatien Chevallier 
458c413678cSGatien Chevallier 	/* Gate the IP */
459c413678cSGatien Chevallier 	res = clk_dt_get_by_index(fdt, node, 0, &risab_d->clock);
460c413678cSGatien Chevallier 	if (res)
461c413678cSGatien Chevallier 		return res;
462c413678cSGatien Chevallier 
463c413678cSGatien Chevallier 	strlcpy(risab_d->risab_name, fdt_get_name(fdt, node, NULL),
464c413678cSGatien Chevallier 		sizeof(risab_d->risab_name));
465c413678cSGatien Chevallier 
466c413678cSGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,srwiad", NULL);
467c413678cSGatien Chevallier 	if (cuint)
468c413678cSGatien Chevallier 		risab_d->srwiad = true;
469c413678cSGatien Chevallier 
470*c94adf20SGatien Chevallier 	risab_d->errata_ahbrisab = fdt_getprop(fdt, node, "st,errata-ahbrisab",
471*c94adf20SGatien Chevallier 					       NULL);
472*c94adf20SGatien Chevallier 
473c413678cSGatien Chevallier 	/* Get the memory region being configured */
474c413678cSGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,mem-map", &lenp);
475c413678cSGatien Chevallier 	if (!cuint)
476c413678cSGatien Chevallier 		panic("Missing st,mem-map property in configure memory region");
477c413678cSGatien Chevallier 
478c413678cSGatien Chevallier 	assert((unsigned int)(lenp / sizeof(uint32_t)) == 2);
479c413678cSGatien Chevallier 
480c413678cSGatien Chevallier 	risab_d->region_cfged.base = fdt32_to_cpu(cuint[0]);
481c413678cSGatien Chevallier 	risab_d->region_cfged.size = fdt32_to_cpu(cuint[1]);
482c413678cSGatien Chevallier 
483c413678cSGatien Chevallier 	/* Get the memory regions to configure */
484c413678cSGatien Chevallier 	mem_regions = fdt_getprop(fdt, node, "memory-region", &lenp);
485c413678cSGatien Chevallier 	if (!mem_regions)
486c413678cSGatien Chevallier 		panic("No memory region to configure");
487c413678cSGatien Chevallier 
488c413678cSGatien Chevallier 	risab_d->nb_regions_cfged = (unsigned int)(lenp / sizeof(uint32_t));
489c413678cSGatien Chevallier 	assert(risab_d->nb_regions_cfged < _RISAB_NB_PAGES_MAX);
490c413678cSGatien Chevallier 
491c413678cSGatien Chevallier 	risab_d->subr_cfg = calloc(risab_d->nb_regions_cfged,
492c413678cSGatien Chevallier 				   sizeof(*risab_d->subr_cfg));
493c413678cSGatien Chevallier 	if (!risab_d->subr_cfg)
494c413678cSGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
495c413678cSGatien Chevallier 
496c413678cSGatien Chevallier 	for (i = 0; i < risab_d->nb_regions_cfged; i++) {
497c413678cSGatien Chevallier 		uint32_t phandle = fdt32_to_cpu(mem_regions[i]);
498c413678cSGatien Chevallier 		size_t sub_region_offset = 0;
499c413678cSGatien Chevallier 		paddr_t address = 0;
500c413678cSGatien Chevallier 		size_t length = 0;
501c413678cSGatien Chevallier 
502c413678cSGatien Chevallier 		mem_reg_node = fdt_node_offset_by_phandle(fdt, phandle);
503c413678cSGatien Chevallier 		if (mem_reg_node < 0)
504c413678cSGatien Chevallier 			return TEE_ERROR_ITEM_NOT_FOUND;
505c413678cSGatien Chevallier 
506c413678cSGatien Chevallier 		/*
507c413678cSGatien Chevallier 		 * Get the reg property to determine the number of pages
508c413678cSGatien Chevallier 		 * to configure
509c413678cSGatien Chevallier 		 */
510c413678cSGatien Chevallier 		address = fdt_reg_base_address(fdt, mem_reg_node);
511c413678cSGatien Chevallier 		length = fdt_reg_size(fdt, mem_reg_node);
512c413678cSGatien Chevallier 
513c413678cSGatien Chevallier 		assert(IS_ALIGNED(address, _RISAB_PAGE_SIZE) &&
514c413678cSGatien Chevallier 		       IS_ALIGNED(length, _RISAB_PAGE_SIZE));
515c413678cSGatien Chevallier 
516c413678cSGatien Chevallier 		/*
517c413678cSGatien Chevallier 		 * Get the sub region offset and check if it is not out
518c413678cSGatien Chevallier 		 * of bonds
519c413678cSGatien Chevallier 		 */
520c413678cSGatien Chevallier 		sub_region_offset = address - risab_d->region_cfged.base;
521c413678cSGatien Chevallier 
522c413678cSGatien Chevallier 		if (!core_is_buffer_inside(address, length,
523c413678cSGatien Chevallier 					   risab_d->region_cfged.base,
524c413678cSGatien Chevallier 					   risab_d->region_cfged.size)) {
525c413678cSGatien Chevallier 			EMSG("Region %#"PRIxPA"..%#"PRIxPA" outside RISAB area %#"PRIxPA"...%#"PRIxPA,
526c413678cSGatien Chevallier 			     address, address + length,
527c413678cSGatien Chevallier 			     risab_d->region_cfged.base,
528c413678cSGatien Chevallier 			     risab_d->region_cfged.base +
529c413678cSGatien Chevallier 			     risab_d->region_cfged.size);
530c413678cSGatien Chevallier 			return TEE_ERROR_BAD_PARAMETERS;
531c413678cSGatien Chevallier 		}
532c413678cSGatien Chevallier 
533c413678cSGatien Chevallier 		risab_d->subr_cfg[i].first_page = sub_region_offset /
534c413678cSGatien Chevallier 						  _RISAB_PAGE_SIZE;
535c413678cSGatien Chevallier 		risab_d->subr_cfg[i].nb_pages_cfged = length /
536c413678cSGatien Chevallier 						      _RISAB_PAGE_SIZE;
537c413678cSGatien Chevallier 		if (!risab_d->subr_cfg[i].nb_pages_cfged)
538c413678cSGatien Chevallier 			panic("Range to configure is < to the size of a page");
539c413678cSGatien Chevallier 
540c413678cSGatien Chevallier 		/* Get the RIF configuration for this region */
541c413678cSGatien Chevallier 		cuint = fdt_getprop(fdt, mem_reg_node, "st,protreg", &lenp);
542c413678cSGatien Chevallier 		if (!cuint)
543c413678cSGatien Chevallier 			panic("No RIF configuration available");
544c413678cSGatien Chevallier 
545c413678cSGatien Chevallier 		/* There should be only one configuration for this region */
546c413678cSGatien Chevallier 		assert((unsigned int)(lenp / sizeof(uint32_t)) == 1);
547c413678cSGatien Chevallier 
548c413678cSGatien Chevallier 		parse_risab_rif_conf(risab_d, &risab_d->subr_cfg[i],
549c413678cSGatien Chevallier 				     fdt32_to_cpu(cuint[0]),
550c413678cSGatien Chevallier 				     true /*check_overlap*/);
551c413678cSGatien Chevallier 	}
552c413678cSGatien Chevallier 
553c413678cSGatien Chevallier 	return TEE_SUCCESS;
554c413678cSGatien Chevallier }
555c413678cSGatien Chevallier 
enable_srwiad_if_set(struct stm32_risab_pdata * risab_d)556c413678cSGatien Chevallier static void enable_srwiad_if_set(struct stm32_risab_pdata *risab_d)
557c413678cSGatien Chevallier {
558c413678cSGatien Chevallier 	if (is_tdcid && risab_d->srwiad)
559c413678cSGatien Chevallier 		io_setbits32(risab_base(risab_d), _RISAB_CR_SRWIAD);
560c413678cSGatien Chevallier };
561c413678cSGatien Chevallier 
disable_srwiad_if_unset(struct stm32_risab_pdata * risab_d)562c413678cSGatien Chevallier static void disable_srwiad_if_unset(struct stm32_risab_pdata *risab_d)
563c413678cSGatien Chevallier {
564c413678cSGatien Chevallier 	if (is_tdcid && !risab_d->srwiad)
565c413678cSGatien Chevallier 		io_clrbits32(risab_base(risab_d), _RISAB_CR_SRWIAD);
566c413678cSGatien Chevallier };
567c413678cSGatien Chevallier 
clear_iac_regs(struct stm32_risab_pdata * risab_d)568c413678cSGatien Chevallier static void clear_iac_regs(struct stm32_risab_pdata *risab_d)
569c413678cSGatien Chevallier {
570c413678cSGatien Chevallier 	io_setbits32(risab_base(risab_d) + _RISAB_IACR, _RISAB_IACR_MASK);
571c413678cSGatien Chevallier }
572c413678cSGatien Chevallier 
set_vderam_syscfg(struct stm32_risab_pdata * risab_d)573c413678cSGatien Chevallier static void set_vderam_syscfg(struct stm32_risab_pdata *risab_d)
574c413678cSGatien Chevallier {
575c413678cSGatien Chevallier 	/*
576c413678cSGatien Chevallier 	 * Set the VDERAMCR_VDERAM_EN bit if the VDERAM should be accessed by
577c413678cSGatien Chevallier 	 * the system. Else, clear it so that VDEC/VENC can access it.
578c413678cSGatien Chevallier 	 */
579c413678cSGatien Chevallier 	if (risab_d->nb_regions_cfged)
580c413678cSGatien Chevallier 		stm32mp_syscfg_write(SYSCFG_VDERAMCR, VDERAMCR_VDERAM_EN,
581c413678cSGatien Chevallier 				     VDERAMCR_MASK);
582c413678cSGatien Chevallier 	else
583c413678cSGatien Chevallier 		stm32mp_syscfg_write(SYSCFG_VDERAMCR, 0, VDERAMCR_MASK);
584c413678cSGatien Chevallier }
585c413678cSGatien Chevallier 
586c413678cSGatien Chevallier static struct stm32_risab_rif_conf *
get_subreg_by_range(struct stm32_risab_pdata * risab,paddr_t paddr,size_t size)587c413678cSGatien Chevallier get_subreg_by_range(struct stm32_risab_pdata *risab, paddr_t paddr, size_t size)
588c413678cSGatien Chevallier {
589c413678cSGatien Chevallier 	unsigned int nb_page = size / _RISAB_PAGE_SIZE;
590c413678cSGatien Chevallier 	unsigned int i = 0;
591c413678cSGatien Chevallier 
592c413678cSGatien Chevallier 	for (i = 0; i < risab->nb_regions_cfged; i++) {
593c413678cSGatien Chevallier 		unsigned int first_page = (paddr - risab->region_cfged.base) /
594c413678cSGatien Chevallier 					  _RISAB_PAGE_SIZE;
595c413678cSGatien Chevallier 
596c413678cSGatien Chevallier 		if (first_page == risab->subr_cfg[i].first_page &&
597c413678cSGatien Chevallier 		    nb_page == risab->subr_cfg[i].nb_pages_cfged)
598c413678cSGatien Chevallier 			return risab->subr_cfg + i;
599c413678cSGatien Chevallier 	}
600c413678cSGatien Chevallier 
601c413678cSGatien Chevallier 	return NULL;
602c413678cSGatien Chevallier }
603c413678cSGatien Chevallier 
stm32_risab_check_access(struct firewall_query * fw,paddr_t paddr,size_t size,bool read,bool write)604c413678cSGatien Chevallier static TEE_Result stm32_risab_check_access(struct firewall_query *fw,
605c413678cSGatien Chevallier 					   paddr_t paddr, size_t size,
606c413678cSGatien Chevallier 					   bool read, bool write)
607c413678cSGatien Chevallier {
608c413678cSGatien Chevallier 	struct stm32_risab_rif_conf *reg_conf = NULL;
609c413678cSGatien Chevallier 	struct stm32_risab_pdata *risab = NULL;
610c413678cSGatien Chevallier 	unsigned int first_page = 0;
611c413678cSGatien Chevallier 	uint32_t write_cids = 0;
612c413678cSGatien Chevallier 	uint32_t read_cids = 0;
613c413678cSGatien Chevallier 	uint32_t priv_cids = 0;
614c413678cSGatien Chevallier 	uint32_t dprivcfgr = 0;
615c413678cSGatien Chevallier 	uint32_t seccfgr = 0;
616c413678cSGatien Chevallier 	uint32_t cidcfgr = 0;
617c413678cSGatien Chevallier 	uint32_t q_conf = 0;
618c413678cSGatien Chevallier 	unsigned int i = 0;
619c413678cSGatien Chevallier 	vaddr_t base = 0;
620c413678cSGatien Chevallier 
621c413678cSGatien Chevallier 	assert(fw->ctrl->priv && (read || write));
622c413678cSGatien Chevallier 
623c413678cSGatien Chevallier 	risab = fw->ctrl->priv;
624c413678cSGatien Chevallier 	base = risab_base(risab);
625c413678cSGatien Chevallier 
626c413678cSGatien Chevallier 	if (!IS_ALIGNED(paddr, _RISAB_PAGE_SIZE) ||
627c413678cSGatien Chevallier 	    !IS_ALIGNED(size, _RISAB_PAGE_SIZE)) {
628c413678cSGatien Chevallier 		EMSG("Physical address %"PRIxPA" or size:%#zx misaligned with RISAB page boundaries",
629c413678cSGatien Chevallier 		     paddr, size);
630c413678cSGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
631c413678cSGatien Chevallier 	}
632c413678cSGatien Chevallier 
633c413678cSGatien Chevallier 	if (fw->arg_count != 1)
634c413678cSGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
635c413678cSGatien Chevallier 
636c413678cSGatien Chevallier 	/*
637c413678cSGatien Chevallier 	 * RISAF region configuration, we assume the query is as
638c413678cSGatien Chevallier 	 * follows:
639c413678cSGatien Chevallier 	 * fw->args[0]: Configuration of the region
640c413678cSGatien Chevallier 	 */
641c413678cSGatien Chevallier 	q_conf = fw->args[0];
642c413678cSGatien Chevallier 
643c413678cSGatien Chevallier 	reg_conf = get_subreg_by_range(risab, paddr, size);
644c413678cSGatien Chevallier 	if (!reg_conf)
645c413678cSGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
646c413678cSGatien Chevallier 
647c413678cSGatien Chevallier 	first_page = reg_conf->first_page;
648c413678cSGatien Chevallier 
649c413678cSGatien Chevallier 	seccfgr = io_read32(base + _RISAB_PGy_SECCFGR(first_page));
650c413678cSGatien Chevallier 	/* Security level is exclusive on memories */
651c413678cSGatien Chevallier 	if (!!(q_conf & BIT(RISAB_SEC_SHIFT)) ^ !!(seccfgr & BIT(first_page))) {
652c413678cSGatien Chevallier 		if (!(q_conf & BIT(RISAB_SEC_SHIFT) &&
653c413678cSGatien Chevallier 		      (io_read32(base + _RISAB_CR) & _RISAB_CR_SRWIAD)))
654c413678cSGatien Chevallier 			return TEE_ERROR_ACCESS_DENIED;
655c413678cSGatien Chevallier 	}
656c413678cSGatien Chevallier 
657c413678cSGatien Chevallier 	dprivcfgr = io_read32(base + _RISAB_PGy_PRIVCFGR(first_page));
658c413678cSGatien Chevallier 	cidcfgr = io_read32(base + _RISAB_PGy_CIDCFGR(first_page));
659c413678cSGatien Chevallier 
660c413678cSGatien Chevallier 	if (!(cidcfgr & _RISAB_PG_CIDCFGR_CFEN)) {
661c413678cSGatien Chevallier 		if (dprivcfgr && !(q_conf & BIT(RISAB_DPRIV_SHIFT)))
662c413678cSGatien Chevallier 			return TEE_ERROR_ACCESS_DENIED;
663c413678cSGatien Chevallier 		else
664c413678cSGatien Chevallier 			return TEE_SUCCESS;
665c413678cSGatien Chevallier 	}
666c413678cSGatien Chevallier 
667c413678cSGatien Chevallier 	read_cids = SHIFT_U32(q_conf & RISAB_RLIST_MASK, RISAB_READ_LIST_SHIFT);
668c413678cSGatien Chevallier 	write_cids = SHIFT_U32(q_conf & RISAB_WLIST_MASK,
669c413678cSGatien Chevallier 			       RISAB_WRITE_LIST_SHIFT);
670c413678cSGatien Chevallier 	priv_cids = q_conf & RISAB_PLIST_MASK;
671c413678cSGatien Chevallier 
672c413678cSGatien Chevallier 	for (i = 0; i < _RISAB_NB_MAX_CID_SUPPORTED; i++) {
673c413678cSGatien Chevallier 		uint32_t read_list = io_read32(base + _RISAB_CIDxRDCFGR(i));
674c413678cSGatien Chevallier 		uint32_t write_list = io_read32(base + _RISAB_CIDxWRCFGR(i));
675c413678cSGatien Chevallier 		uint32_t priv_list = io_read32(base + _RISAB_CIDxPRIVCFGR(i));
676c413678cSGatien Chevallier 
677c413678cSGatien Chevallier 		if (read && (read_cids & BIT(i)) &&
678c413678cSGatien Chevallier 		    !(read_list & BIT(first_page)))
679c413678cSGatien Chevallier 			return TEE_ERROR_ACCESS_DENIED;
680c413678cSGatien Chevallier 
681c413678cSGatien Chevallier 		if (write && (write_cids & BIT(i)) &&
682c413678cSGatien Chevallier 		    !(write_list & BIT(first_page)))
683c413678cSGatien Chevallier 			return TEE_ERROR_ACCESS_DENIED;
684c413678cSGatien Chevallier 
685c413678cSGatien Chevallier 		if ((priv_list & BIT(first_page)) && !(priv_cids & BIT(i)))
686c413678cSGatien Chevallier 			return TEE_ERROR_ACCESS_DENIED;
687c413678cSGatien Chevallier 	}
688c413678cSGatien Chevallier 
689c413678cSGatien Chevallier 	return TEE_SUCCESS;
690c413678cSGatien Chevallier }
691c413678cSGatien Chevallier 
stm32_risab_reconfigure_region(struct firewall_query * fw,paddr_t paddr,size_t size)6928d8a3cb3SGatien Chevallier static TEE_Result stm32_risab_reconfigure_region(struct firewall_query *fw,
6938d8a3cb3SGatien Chevallier 						 paddr_t paddr, size_t size)
6948d8a3cb3SGatien Chevallier {
6958d8a3cb3SGatien Chevallier 	struct stm32_risab_pdata *risab = NULL;
6968d8a3cb3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
6978d8a3cb3SGatien Chevallier 	paddr_t sub_region_offset = 0;
6988d8a3cb3SGatien Chevallier 	uint32_t exceptions = 0;
6998d8a3cb3SGatien Chevallier 	unsigned int i = 0;
7008d8a3cb3SGatien Chevallier 
7018d8a3cb3SGatien Chevallier 	assert(fw->ctrl->priv);
7028d8a3cb3SGatien Chevallier 
7038d8a3cb3SGatien Chevallier 	risab = fw->ctrl->priv;
7048d8a3cb3SGatien Chevallier 
7058d8a3cb3SGatien Chevallier 	if (!IS_ALIGNED(paddr, _RISAB_PAGE_SIZE) ||
7068d8a3cb3SGatien Chevallier 	    !IS_ALIGNED(size, _RISAB_PAGE_SIZE)) {
7078d8a3cb3SGatien Chevallier 		EMSG("Unaligned region: pa %#"PRIxPA" size %zx", paddr, size);
7088d8a3cb3SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
7098d8a3cb3SGatien Chevallier 	}
7108d8a3cb3SGatien Chevallier 
7118d8a3cb3SGatien Chevallier 	if (fw->arg_count != 1)
7128d8a3cb3SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
7138d8a3cb3SGatien Chevallier 
7148d8a3cb3SGatien Chevallier 	/*
7158d8a3cb3SGatien Chevallier 	 * Get the sub region offset and check if it is not out
7168d8a3cb3SGatien Chevallier 	 * of bounds
7178d8a3cb3SGatien Chevallier 	 */
7188d8a3cb3SGatien Chevallier 	sub_region_offset = paddr - risab->region_cfged.base;
7198d8a3cb3SGatien Chevallier 	if (!core_is_buffer_inside(paddr, size, risab->region_cfged.base,
7208d8a3cb3SGatien Chevallier 				   risab->region_cfged.size))
7218d8a3cb3SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
7228d8a3cb3SGatien Chevallier 
7238d8a3cb3SGatien Chevallier 	/*
7248d8a3cb3SGatien Chevallier 	 * RISAF region configuration, we assume the query is as
7258d8a3cb3SGatien Chevallier 	 * follows:
7268d8a3cb3SGatien Chevallier 	 * fw->args[0]: Configuration of the region
7278d8a3cb3SGatien Chevallier 	 */
7288d8a3cb3SGatien Chevallier 	for (i = 0; i < risab->nb_regions_cfged; i++) {
7298d8a3cb3SGatien Chevallier 		if (sub_region_offset / _RISAB_PAGE_SIZE !=
7308d8a3cb3SGatien Chevallier 		    risab->subr_cfg[i].first_page ||
7318d8a3cb3SGatien Chevallier 		    (size / _RISAB_PAGE_SIZE) !=
7328d8a3cb3SGatien Chevallier 		    risab->subr_cfg[i].nb_pages_cfged)
7338d8a3cb3SGatien Chevallier 			continue;
7348d8a3cb3SGatien Chevallier 
7358d8a3cb3SGatien Chevallier 		parse_risab_rif_conf(risab, &risab->subr_cfg[i], fw->args[0],
7368d8a3cb3SGatien Chevallier 				     false /*!check_overlap*/);
7378d8a3cb3SGatien Chevallier 
7388d8a3cb3SGatien Chevallier 		break;
7398d8a3cb3SGatien Chevallier 	}
7408d8a3cb3SGatien Chevallier 
7418d8a3cb3SGatien Chevallier 	if (i == risab->nb_regions_cfged)
7428d8a3cb3SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
7438d8a3cb3SGatien Chevallier 
7448d8a3cb3SGatien Chevallier 	DMSG("Reconfiguring %s pages %u-%u: %s, %s, CID attributes: %#"PRIx32", R:%#"PRIx32", W:%#"PRIx32", P:%#"PRIx32"",
7458d8a3cb3SGatien Chevallier 	     risab->risab_name, risab->subr_cfg[i].first_page,
7468d8a3cb3SGatien Chevallier 	     risab->subr_cfg[i].first_page +
7478d8a3cb3SGatien Chevallier 	     risab->subr_cfg[i].nb_pages_cfged - 1,
7488d8a3cb3SGatien Chevallier 	     risab->subr_cfg[i].seccfgr ? "Secure" : "Non secure",
7498d8a3cb3SGatien Chevallier 	     risab->subr_cfg[i].dprivcfgr ? "Default priv" : "Default unpriv",
7508d8a3cb3SGatien Chevallier 	     risab->subr_cfg[i].cidcfgr,
7518d8a3cb3SGatien Chevallier 	     fw->args[0] & RISAB_RLIST_MASK,
7528d8a3cb3SGatien Chevallier 	     fw->args[0] & RISAB_WLIST_MASK,
7538d8a3cb3SGatien Chevallier 	     fw->args[0] & RISAB_PLIST_MASK);
7548d8a3cb3SGatien Chevallier 
7558d8a3cb3SGatien Chevallier 	exceptions = cpu_spin_lock_xsave(&risab->conf_lock);
7568d8a3cb3SGatien Chevallier 
7578d8a3cb3SGatien Chevallier 	res = set_rif_registers(risab, i);
7588d8a3cb3SGatien Chevallier 
7598d8a3cb3SGatien Chevallier 	cpu_spin_unlock_xrestore(&risab->conf_lock, exceptions);
7608d8a3cb3SGatien Chevallier 
7618d8a3cb3SGatien Chevallier 	return res;
7628d8a3cb3SGatien Chevallier }
7638d8a3cb3SGatien Chevallier 
stm32_risab_pm_resume(struct stm32_risab_pdata * risab)764c413678cSGatien Chevallier static TEE_Result stm32_risab_pm_resume(struct stm32_risab_pdata *risab)
765c413678cSGatien Chevallier {
766c413678cSGatien Chevallier 	unsigned int i = 0;
767c413678cSGatien Chevallier 
768c413678cSGatien Chevallier 	if (risab->base.pa == RISAB6_BASE)
769c413678cSGatien Chevallier 		set_vderam_syscfg(risab);
770c413678cSGatien Chevallier 	enable_srwiad_if_set(risab);
771c413678cSGatien Chevallier 	clear_iac_regs(risab);
772c413678cSGatien Chevallier 
773c413678cSGatien Chevallier 	for (i = 0; i < risab->nb_regions_cfged; i++) {
7748d8a3cb3SGatien Chevallier 		if (set_rif_registers(risab, i))
7758d8a3cb3SGatien Chevallier 			panic();
776c413678cSGatien Chevallier 	}
777c413678cSGatien Chevallier 
778c413678cSGatien Chevallier 	disable_srwiad_if_unset(risab);
779c413678cSGatien Chevallier 
780c413678cSGatien Chevallier 	return TEE_SUCCESS;
781c413678cSGatien Chevallier }
782c413678cSGatien Chevallier 
stm32_risab_pm_suspend(struct stm32_risab_pdata * risab)783c413678cSGatien Chevallier static TEE_Result stm32_risab_pm_suspend(struct stm32_risab_pdata *risab)
784c413678cSGatien Chevallier {
785c413678cSGatien Chevallier 	vaddr_t base = risab_base(risab);
786c413678cSGatien Chevallier 	size_t i = 0;
787c413678cSGatien Chevallier 
788c413678cSGatien Chevallier 	for (i = 0; i < risab->nb_regions_cfged; i++) {
789c413678cSGatien Chevallier 		size_t j = 0;
790c413678cSGatien Chevallier 		unsigned int first_page = risab->subr_cfg[i].first_page;
791c413678cSGatien Chevallier 
792c413678cSGatien Chevallier 		/* Save all configuration fields that need to be restored */
793c413678cSGatien Chevallier 		risab->subr_cfg[i].seccfgr =
794c413678cSGatien Chevallier 			io_read32(base + _RISAB_PGy_SECCFGR(first_page));
795c413678cSGatien Chevallier 		risab->subr_cfg[i].dprivcfgr =
796c413678cSGatien Chevallier 			io_read32(base + _RISAB_PGy_PRIVCFGR(first_page));
797c413678cSGatien Chevallier 		risab->subr_cfg[i].cidcfgr =
798c413678cSGatien Chevallier 			io_read32(base + _RISAB_PGy_CIDCFGR(first_page));
799c413678cSGatien Chevallier 
800c413678cSGatien Chevallier 		for (j = 0; j < _RISAB_NB_MAX_CID_SUPPORTED; j++) {
801c413678cSGatien Chevallier 			risab->subr_cfg[i].rlist[j] =
802c413678cSGatien Chevallier 				io_read32(base + _RISAB_CIDxRDCFGR(j));
803c413678cSGatien Chevallier 			risab->subr_cfg[i].wlist[j] =
804c413678cSGatien Chevallier 				io_read32(base + _RISAB_CIDxWRCFGR(j));
805c413678cSGatien Chevallier 			risab->subr_cfg[i].plist[j] =
806c413678cSGatien Chevallier 				io_read32(base + _RISAB_CIDxPRIVCFGR(j));
807c413678cSGatien Chevallier 		}
808c413678cSGatien Chevallier 	}
809c413678cSGatien Chevallier 
810c413678cSGatien Chevallier 	return TEE_SUCCESS;
811c413678cSGatien Chevallier }
812c413678cSGatien Chevallier 
813c413678cSGatien Chevallier static TEE_Result
stm32_risab_pm(enum pm_op op,unsigned int pm_hint,const struct pm_callback_handle * pm_handle)814c413678cSGatien Chevallier stm32_risab_pm(enum pm_op op, unsigned int pm_hint,
815c413678cSGatien Chevallier 	       const struct pm_callback_handle *pm_handle)
816c413678cSGatien Chevallier {
817c413678cSGatien Chevallier 	struct stm32_risab_pdata *risab = pm_handle->handle;
818c413678cSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
819c413678cSGatien Chevallier 
820c413678cSGatien Chevallier 	if (!PM_HINT_IS_STATE(pm_hint, CONTEXT) || !is_tdcid)
821c413678cSGatien Chevallier 		return TEE_SUCCESS;
822c413678cSGatien Chevallier 
823c413678cSGatien Chevallier 	if (op == PM_OP_RESUME)
824c413678cSGatien Chevallier 		res = stm32_risab_pm_resume(risab);
825c413678cSGatien Chevallier 	else
826c413678cSGatien Chevallier 		res = stm32_risab_pm_suspend(risab);
827c413678cSGatien Chevallier 
828c413678cSGatien Chevallier 	return res;
829c413678cSGatien Chevallier }
830c413678cSGatien Chevallier 
831c413678cSGatien Chevallier static const struct firewall_controller_ops firewall_ops = {
832c413678cSGatien Chevallier 	.check_memory_access = stm32_risab_check_access,
8338d8a3cb3SGatien Chevallier 	.set_memory_conf = stm32_risab_reconfigure_region,
834c413678cSGatien Chevallier };
835c413678cSGatien Chevallier 
stm32_risab_probe(const void * fdt,int node,const void * compat_data __maybe_unused)836c413678cSGatien Chevallier static TEE_Result stm32_risab_probe(const void *fdt, int node,
837c413678cSGatien Chevallier 				    const void *compat_data __maybe_unused)
838c413678cSGatien Chevallier {
839c413678cSGatien Chevallier 	struct firewall_controller *controller = NULL;
840c413678cSGatien Chevallier 	struct stm32_risab_pdata *risab_d = NULL;
841c413678cSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
842c413678cSGatien Chevallier 
843c413678cSGatien Chevallier 	res = stm32_rifsc_check_tdcid(&is_tdcid);
844c413678cSGatien Chevallier 	if (res)
845c413678cSGatien Chevallier 		return res;
846c413678cSGatien Chevallier 
847c413678cSGatien Chevallier 	risab_d = calloc(1, sizeof(*risab_d));
848c413678cSGatien Chevallier 	if (!risab_d)
849c413678cSGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
850c413678cSGatien Chevallier 
851c413678cSGatien Chevallier 	res = parse_dt(fdt, node, risab_d);
852c413678cSGatien Chevallier 	if (res)
853c413678cSGatien Chevallier 		goto err;
854c413678cSGatien Chevallier 
855c413678cSGatien Chevallier 	if (clk_enable(risab_d->clock))
856c413678cSGatien Chevallier 		panic("Can't enable RISAB clock");
857c413678cSGatien Chevallier 
858c413678cSGatien Chevallier 	if (is_tdcid) {
859c413678cSGatien Chevallier 		if (risab_d->base.pa == RISAB6_BASE)
860c413678cSGatien Chevallier 			set_vderam_syscfg(risab_d);
861c413678cSGatien Chevallier 		clear_iac_regs(risab_d);
862c413678cSGatien Chevallier 		enable_srwiad_if_set(risab_d);
863c413678cSGatien Chevallier 	}
864c413678cSGatien Chevallier 
865c413678cSGatien Chevallier 	apply_rif_config(risab_d);
866c413678cSGatien Chevallier 
867c413678cSGatien Chevallier 	disable_srwiad_if_unset(risab_d);
868c413678cSGatien Chevallier 
869c413678cSGatien Chevallier 	controller = calloc(1, sizeof(*controller));
870c413678cSGatien Chevallier 	if (!controller) {
871c413678cSGatien Chevallier 		res = TEE_ERROR_OUT_OF_MEMORY;
872c413678cSGatien Chevallier 		goto err;
873c413678cSGatien Chevallier 	}
874c413678cSGatien Chevallier 
875c413678cSGatien Chevallier 	controller->base = &risab_d->base;
876c413678cSGatien Chevallier 	controller->name = risab_d->risab_name;
877c413678cSGatien Chevallier 	controller->priv = risab_d;
878c413678cSGatien Chevallier 	controller->ops = &firewall_ops;
879c413678cSGatien Chevallier 
880c413678cSGatien Chevallier 	SLIST_INSERT_HEAD(&risab_list, risab_d, link);
881c413678cSGatien Chevallier 
882c413678cSGatien Chevallier 	res = firewall_dt_controller_register(fdt, node, controller);
883c413678cSGatien Chevallier 	if (res)
884c413678cSGatien Chevallier 		panic();
885c413678cSGatien Chevallier 
886c413678cSGatien Chevallier 	register_pm_core_service_cb(stm32_risab_pm, risab_d, "stm32-risab");
887c413678cSGatien Chevallier 
888c413678cSGatien Chevallier 	return TEE_SUCCESS;
889c413678cSGatien Chevallier 
890c413678cSGatien Chevallier err:
891c413678cSGatien Chevallier 	clk_disable(risab_d->clock);
892c413678cSGatien Chevallier 	free(risab_d->subr_cfg);
893c413678cSGatien Chevallier 	free(risab_d);
894c413678cSGatien Chevallier 
895c413678cSGatien Chevallier 	return res;
896c413678cSGatien Chevallier }
897c413678cSGatien Chevallier 
898c413678cSGatien Chevallier static const struct dt_device_match risab_match_table[] = {
899c413678cSGatien Chevallier 	{ .compatible = "st,stm32mp25-risab" },
900c413678cSGatien Chevallier 	{ }
901c413678cSGatien Chevallier };
902c413678cSGatien Chevallier 
903c413678cSGatien Chevallier DEFINE_DT_DRIVER(risab_dt_driver) = {
904c413678cSGatien Chevallier 	.name = "stm32-risab",
905c413678cSGatien Chevallier 	.match_table = risab_match_table,
906c413678cSGatien Chevallier 	.probe = stm32_risab_probe,
907c413678cSGatien Chevallier };
908