xref: /optee_os/core/drivers/stm32_hsem.c (revision 9f34db38245c9b3a4e6e7e63eb78a75e23ab2da3)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2022-2024, STMicroelectronics
4  */
5 
6 #include <arm.h>
7 #include <config.h>
8 #include <drivers/clk.h>
9 #include <drivers/clk_dt.h>
10 #include <drivers/stm32_rif.h>
11 #include <io.h>
12 #include <kernel/boot.h>
13 #include <kernel/delay.h>
14 #include <kernel/dt.h>
15 #include <kernel/dt_driver.h>
16 #include <kernel/panic.h>
17 #include <libfdt.h>
18 #include <mm/core_memprot.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <stm32_util.h>
22 #include <trace.h>
23 
24 #define HSEM_SECCFGR			U(0x200)
25 #define HSEM_PRIVCFGR			U(0x210)
26 #define HSEM_CnCIDCFGR(x)		(U(0x220) + U(0x004) * ((x) - 1))
27 #define HSEM_GpCIDCFGR(x)		(U(0x240) + U(0x004) * (x))
28 
29 /*
30  * CnCIDCFGR register bitfields
31  */
32 #define HSEM_CnCIDCFGR_CONF_MASK	(_CIDCFGR_CFEN |	 \
33 					 HSEM_CnCIDCFGR_SCID_MASK)
34 #define HSEM_CnCIDCFGR_SCID_MASK	GENMASK_32(6, 4)
35 
36 /*
37  * GpCIDCFGR register bitfields
38  */
39 #define HSEM_GpCIDCFGR_SEM_WLIST_C_MASK	GENMASK_32(18, 16)
40 #define HSEM_GpCIDCFGR_SEM_WLIST_SHIFT	U(16)
41 #define HSEM_GpCIDCFGR_CONF_MASK	(_CIDCFGR_CFEN |	 \
42 					 HSEM_GpCIDCFGR_SEM_WLIST_C_MASK)
43 
44 /*
45  * PRIVCFGR register bitfields
46  */
47 #define HSEM_PRIVCFGR_MASK		GENMASK_32(15, 0)
48 
49 /*
50  * SECCFGR register bitfields
51  */
52 #define HSEM_SECCFGR_MASK		GENMASK_32(15, 0)
53 
54 /*
55  * Miscellaneous
56  */
57 #define HSEM_NB_PROC			U(3)
58 #define HSEM_NB_SEM_GROUPS		U(4)
59 #define HSEM_NB_SEM_PER_GROUP		U(4)
60 
61 #define HSEM_RIF_RESOURCES		U(16)
62 
63 struct hsem_pdata {
64 	struct clk *hsem_clock;
65 	struct rif_conf_data conf_data;
66 	unsigned int nb_channels;
67 	vaddr_t base;
68 	uint32_t *rif_proc_conf;
69 };
70 
71 static struct hsem_pdata *hsem_d;
72 
73 static void apply_rif_config(bool is_tdcid)
74 {
75 	unsigned int i = 0;
76 	unsigned int j = 0;
77 
78 	/*
79 	 * When TDCID, OP-TEE should be the one to set the CID filtering
80 	 * configuration. Clearing previous configuration prevents
81 	 * undesired events during the only legitimate configuration.
82 	 */
83 	if (is_tdcid) {
84 		for (i = 0; i < HSEM_NB_PROC; i++)
85 			io_clrbits32(hsem_d->base + HSEM_CnCIDCFGR(i + 1),
86 				     HSEM_CnCIDCFGR_CONF_MASK);
87 
88 		/* Clean HSEM groups configuration registers */
89 		for (i = 0; i < HSEM_NB_SEM_GROUPS; i++)
90 			io_clrbits32(hsem_d->base + HSEM_GpCIDCFGR(i),
91 				     HSEM_GpCIDCFGR_CONF_MASK);
92 	}
93 
94 	/* Security and privilege RIF configuration */
95 	io_clrsetbits32(hsem_d->base + HSEM_SECCFGR,
96 			HSEM_SECCFGR_MASK & hsem_d->conf_data.access_mask[0],
97 			hsem_d->conf_data.sec_conf[0]);
98 	io_clrsetbits32(hsem_d->base + HSEM_PRIVCFGR,
99 			HSEM_PRIVCFGR_MASK & hsem_d->conf_data.access_mask[0],
100 			hsem_d->conf_data.priv_conf[0]);
101 
102 	if (!is_tdcid)
103 		return;
104 
105 	/* Configure HSEM processors configuration registers */
106 	for (i = 0; i < HSEM_NB_PROC; i++) {
107 		/*
108 		 * If a processor CID configuration is present, enable it.
109 		 * Else, nothing to do.
110 		 */
111 		if (!hsem_d->rif_proc_conf[i])
112 			continue;
113 
114 		io_clrsetbits32(hsem_d->base + HSEM_CnCIDCFGR(i + 1),
115 				HSEM_CnCIDCFGR_CONF_MASK,
116 				_CIDCFGR_CFEN | hsem_d->rif_proc_conf[i]);
117 	}
118 
119 	/*
120 	 * Configure HSEM groups configuration registers
121 	 * If one semaphore is configured, all semaphores of its group
122 	 * must be configured too and MUST have the same RIF
123 	 * configuration.
124 	 */
125 	for (i = 0; i < HSEM_NB_SEM_GROUPS; i++) {
126 		unsigned int grp_idx = i * HSEM_NB_SEM_PER_GROUP;
127 		uint32_t group_cid_value = hsem_d->conf_data.cid_confs[grp_idx];
128 		unsigned int sem_wlist_c = 0;
129 		bool cid_found = false;
130 
131 		/*
132 		 * HSEM resources in the same group must have the same CID
133 		 * filtering configuration. Else it is inconsistent.
134 		 */
135 		for (j = 0; j < HSEM_NB_SEM_PER_GROUP; j++)
136 			if (hsem_d->conf_data.cid_confs[j + grp_idx] !=
137 			    group_cid_value)
138 				panic("Inconsistent HSEM RIF group config");
139 
140 		/* If CID filtering is disabled, do nothing */
141 		if (!(group_cid_value & _CIDCFGR_CFEN))
142 			continue;
143 
144 		/*
145 		 * Check if configured CIDs correspond to a processor's
146 		 * CID in HSEM_CnCIDCFGR registers.
147 		 */
148 		for (j = 0; j < HSEM_NB_PROC; j++) {
149 			uint32_t proc_cid = hsem_d->rif_proc_conf[j] >>
150 					    _CIDCFGR_SCID_SHIFT;
151 
152 			assert(proc_cid <= MAX_CID_SUPPORTED);
153 			if (BIT(proc_cid + _CIDCFGR_SEMWL_SHIFT) &
154 			    group_cid_value) {
155 				sem_wlist_c |=
156 					BIT(j + HSEM_GpCIDCFGR_SEM_WLIST_SHIFT);
157 				cid_found = true;
158 			}
159 		}
160 		if (!cid_found)
161 			panic("Unknown HSEM processor CID");
162 
163 		io_clrsetbits32(hsem_d->base + HSEM_GpCIDCFGR(i),
164 				HSEM_GpCIDCFGR_CONF_MASK,
165 				_CIDCFGR_CFEN | sem_wlist_c);
166 	}
167 }
168 
169 static TEE_Result parse_dt(const void *fdt, int node)
170 {
171 	TEE_Result res = TEE_ERROR_GENERIC;
172 	unsigned int i = 0;
173 	int lenp = 0;
174 	const fdt32_t *cuint = NULL;
175 	struct dt_node_info info = { };
176 	struct io_pa_va addr = { };
177 
178 	fdt_fill_device_info(fdt, &info, node);
179 	assert(info.reg != DT_INFO_INVALID_REG &&
180 	       info.reg_size != DT_INFO_INVALID_REG_SIZE);
181 
182 	addr.pa = info.reg;
183 	hsem_d->base = io_pa_or_va_secure(&addr, info.reg_size);
184 
185 	/* Gate the IP */
186 	res = clk_dt_get_by_index(fdt, node, 0, &hsem_d->hsem_clock);
187 	if (res)
188 		return res;
189 
190 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
191 	if (!cuint)
192 		panic("No RIF configuration available");
193 
194 	hsem_d->nb_channels = (unsigned int)(lenp / sizeof(uint32_t));
195 	assert(hsem_d->nb_channels <= HSEM_RIF_RESOURCES);
196 
197 	hsem_d->rif_proc_conf = calloc(HSEM_NB_PROC, sizeof(uint32_t));
198 	assert(hsem_d->rif_proc_conf);
199 	hsem_d->conf_data.cid_confs = calloc(HSEM_RIF_RESOURCES,
200 					     sizeof(uint32_t));
201 	hsem_d->conf_data.sec_conf = calloc(1, sizeof(uint32_t));
202 	hsem_d->conf_data.priv_conf = calloc(1, sizeof(uint32_t));
203 	hsem_d->conf_data.access_mask = calloc(1, sizeof(uint32_t));
204 	assert(hsem_d->conf_data.cid_confs && hsem_d->conf_data.sec_conf &&
205 	       hsem_d->conf_data.priv_conf && hsem_d->conf_data.access_mask);
206 
207 	for (i = 0; i < hsem_d->nb_channels; i++)
208 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), &hsem_d->conf_data,
209 				    HSEM_RIF_RESOURCES);
210 
211 	cuint = fdt_getprop(fdt, node, "st,proccid", &lenp);
212 	if (!cuint)
213 		panic("No RIF proc configuration available");
214 
215 	lenp = (unsigned int)(lenp / sizeof(uint32_t));
216 	/*
217 	 * There should be maximum (HSEM_NB_PROC * 2) property argument.
218 	 * First argument for a processor is its number, the second is its CID.
219 	 */
220 	assert((unsigned int)lenp <= (HSEM_NB_PROC * 2));
221 
222 	for (i = 0; i < (unsigned int)lenp / 2; i++) {
223 		unsigned int pos = fdt32_to_cpu(cuint[i * 2]) - 1;
224 		unsigned int cid_value = fdt32_to_cpu(cuint[(i * 2) + 1]);
225 
226 		hsem_d->rif_proc_conf[pos] = SHIFT_U32(cid_value,
227 						       _CIDCFGR_SCID_SHIFT);
228 	}
229 
230 	return TEE_SUCCESS;
231 }
232 
233 static TEE_Result stm32_hsem_probe(const void *fdt, int node,
234 				   const void *compat_data __unused)
235 {
236 	TEE_Result res = TEE_ERROR_GENERIC;
237 	bool is_tdcid = false;
238 
239 	res = stm32_rifsc_check_tdcid(&is_tdcid);
240 	if (res)
241 		return res;
242 
243 	hsem_d = calloc(1, sizeof(*hsem_d));
244 	if (!hsem_d)
245 		return TEE_ERROR_OUT_OF_MEMORY;
246 
247 	res = parse_dt(fdt, node);
248 	if (res) {
249 		free(hsem_d);
250 		return res;
251 	}
252 
253 	res = clk_enable(hsem_d->hsem_clock);
254 	if (res)
255 		panic("Cannot access HSEM clock");
256 
257 	apply_rif_config(is_tdcid);
258 
259 	clk_disable(hsem_d->hsem_clock);
260 
261 	return TEE_SUCCESS;
262 }
263 
264 static const struct dt_device_match stm32_hsem_match_table[] = {
265 	{ .compatible = "st,stm32mp25-hsem" },
266 	{ }
267 };
268 
269 DEFINE_DT_DRIVER(stm32_hsem_dt_driver) = {
270 	.name = "st,stm32-hsem",
271 	.match_table = stm32_hsem_match_table,
272 	.probe = stm32_hsem_probe,
273 };
274