xref: /optee_os/core/drivers/stm32_fmc.c (revision 5da989f3570ffd9e0e3f8ce2376a8a79701c4f13)
1778a36bfSGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2778a36bfSGatien Chevallier /*
3778a36bfSGatien Chevallier  * Copyright (c) 2021-2024, STMicroelectronics
4778a36bfSGatien Chevallier  */
5778a36bfSGatien Chevallier 
6778a36bfSGatien Chevallier #include <arm.h>
7778a36bfSGatien Chevallier #include <config.h>
8778a36bfSGatien Chevallier #include <drivers/clk.h>
9778a36bfSGatien Chevallier #include <drivers/clk_dt.h>
10778a36bfSGatien Chevallier #include <drivers/stm32_gpio.h>
11778a36bfSGatien Chevallier #include <drivers/stm32_rif.h>
12778a36bfSGatien Chevallier #include <io.h>
13778a36bfSGatien Chevallier #include <kernel/boot.h>
14778a36bfSGatien Chevallier #include <kernel/delay.h>
15778a36bfSGatien Chevallier #include <kernel/dt.h>
16778a36bfSGatien Chevallier #include <kernel/dt_driver.h>
17778a36bfSGatien Chevallier #include <kernel/panic.h>
18778a36bfSGatien Chevallier #include <kernel/pm.h>
19778a36bfSGatien Chevallier #include <libfdt.h>
20778a36bfSGatien Chevallier #include <mm/core_memprot.h>
21778a36bfSGatien Chevallier #include <stdbool.h>
22778a36bfSGatien Chevallier #include <stdlib.h>
23778a36bfSGatien Chevallier #include <stm32_util.h>
24778a36bfSGatien Chevallier #include <trace.h>
25778a36bfSGatien Chevallier 
26778a36bfSGatien Chevallier #define _FMC_CFGR			U(0x020)
27778a36bfSGatien Chevallier #define _FMC_SECCFGR			U(0x300)
28778a36bfSGatien Chevallier #define _FMC_PRIVCFGR			U(0x304)
29778a36bfSGatien Chevallier #define _FMC_RCFGLOCKR			U(0x308)
30778a36bfSGatien Chevallier #define _FMC_CIDCFGR(x)			(U(0x30C) + U(0x8) * (x))
31778a36bfSGatien Chevallier #define _FMC_SEMCR(x)			(U(0x310) + U(0x8) * (x))
32778a36bfSGatien Chevallier /*
33778a36bfSGatien Chevallier  * CFGR register bitfields
34778a36bfSGatien Chevallier  */
35778a36bfSGatien Chevallier #define _FMC_CFGR_CLKDIV_MASK		GENMASK_32(19, 16)
36778a36bfSGatien Chevallier #define _FMC_CFGR_CLKDIV_SHIFT		U(16)
37778a36bfSGatien Chevallier #define _FMC_CFGR_CCLKEN		BIT(20)
38778a36bfSGatien Chevallier #define _FMC_CFGR_ENABLE		BIT(31)
39778a36bfSGatien Chevallier 
40778a36bfSGatien Chevallier /*
41778a36bfSGatien Chevallier  * CIDCFGR register bitfields
42778a36bfSGatien Chevallier  */
43778a36bfSGatien Chevallier #define _FMC_CIDCFGR_SEMWL_MASK		GENMASK_32(23, 16)
44778a36bfSGatien Chevallier #define _FMC_CIDCFGR_SCID_MASK		GENMASK_32(6, 4)
45778a36bfSGatien Chevallier #define _FMC_CIDCFGR_CONF_MASK		(_CIDCFGR_CFEN |	 \
46778a36bfSGatien Chevallier 					 _CIDCFGR_SEMEN |	 \
47778a36bfSGatien Chevallier 					 _FMC_CIDCFGR_SCID_MASK |\
48778a36bfSGatien Chevallier 					 _FMC_CIDCFGR_SEMWL_MASK)
49778a36bfSGatien Chevallier 
50778a36bfSGatien Chevallier /*
51778a36bfSGatien Chevallier  * PRIVCFGR register bitfields
52778a36bfSGatien Chevallier  */
53778a36bfSGatien Chevallier #define _FMC_PRIVCFGR_MASK		GENMASK_32(5, 0)
54778a36bfSGatien Chevallier 
55778a36bfSGatien Chevallier /*
56778a36bfSGatien Chevallier  * RCFGLOCKR register bitfields
57778a36bfSGatien Chevallier  */
58778a36bfSGatien Chevallier #define _FMC_RCFGLOCKR_MASK		GENMASK_32(5, 0)
59778a36bfSGatien Chevallier 
60778a36bfSGatien Chevallier /*
61778a36bfSGatien Chevallier  * SECCFGR register bitfields
62778a36bfSGatien Chevallier  */
63778a36bfSGatien Chevallier #define _FMC_SECCFGR_EN			BIT(0)
64778a36bfSGatien Chevallier #define _FMC_SECCFGR_MASK		GENMASK_32(5, 0)
65778a36bfSGatien Chevallier 
66778a36bfSGatien Chevallier /*
67778a36bfSGatien Chevallier  * SEMCR register bitfields
68778a36bfSGatien Chevallier  */
69778a36bfSGatien Chevallier #define _FMC_SEMCR_SCID_MASK		GENMASK_32(7, 5)
70778a36bfSGatien Chevallier #define _FMC_SEMCR_SCID_SHIFT		U(5)
71778a36bfSGatien Chevallier 
72778a36bfSGatien Chevallier /*
73778a36bfSGatien Chevallier  * Miscellaneous
74778a36bfSGatien Chevallier  */
75778a36bfSGatien Chevallier 
76778a36bfSGatien Chevallier #define FMC_RIF_CONTROLLERS		U(6)
77778a36bfSGatien Chevallier 
78778a36bfSGatien Chevallier #define FMC_NSEC_PER_SEC		UL(1000000000)
79778a36bfSGatien Chevallier 
80778a36bfSGatien Chevallier struct fmc_pdata {
81778a36bfSGatien Chevallier 	struct clk *fmc_clock;
82778a36bfSGatien Chevallier 	struct pinctrl_state *pinctrl_d;
83778a36bfSGatien Chevallier 	struct pinctrl_state *pinctrl_s;
84b573873cSGatien Chevallier 	struct rif_conf_data *conf_data;
85778a36bfSGatien Chevallier 	unsigned int nb_controller;
86778a36bfSGatien Chevallier 	vaddr_t base;
87778a36bfSGatien Chevallier 	uint32_t clk_period_ns;
88*5da989f3SGatien Chevallier 	bool is_tdcid;
89778a36bfSGatien Chevallier 	bool cclken;
90778a36bfSGatien Chevallier };
91778a36bfSGatien Chevallier 
92778a36bfSGatien Chevallier static struct fmc_pdata *fmc_d;
93778a36bfSGatien Chevallier 
94778a36bfSGatien Chevallier static bool fmc_controller_is_secure(uint8_t controller)
95778a36bfSGatien Chevallier {
96778a36bfSGatien Chevallier 	return io_read32(fmc_d->base + _FMC_SECCFGR) & BIT(controller);
97778a36bfSGatien Chevallier }
98778a36bfSGatien Chevallier 
99*5da989f3SGatien Chevallier static TEE_Result handle_available_semaphores(void)
100*5da989f3SGatien Chevallier {
101*5da989f3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
102*5da989f3SGatien Chevallier 	uint32_t cidcfgr = 0;
103*5da989f3SGatien Chevallier 	unsigned int i = 0;
104*5da989f3SGatien Chevallier 
105*5da989f3SGatien Chevallier 	for (i = 0; i < FMC_RIF_CONTROLLERS; i++) {
106*5da989f3SGatien Chevallier 		if (!(BIT(i) & fmc_d->conf_data->access_mask[0]))
107*5da989f3SGatien Chevallier 			continue;
108*5da989f3SGatien Chevallier 
109*5da989f3SGatien Chevallier 		cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i));
110*5da989f3SGatien Chevallier 
111*5da989f3SGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
112*5da989f3SGatien Chevallier 			continue;
113*5da989f3SGatien Chevallier 
114*5da989f3SGatien Chevallier 		if (!(io_read32(fmc_d->base + _FMC_SECCFGR) & BIT(i))) {
115*5da989f3SGatien Chevallier 			res = stm32_rif_release_semaphore(fmc_d->base +
116*5da989f3SGatien Chevallier 							  _FMC_SEMCR(i),
117*5da989f3SGatien Chevallier 							  MAX_CID_SUPPORTED);
118*5da989f3SGatien Chevallier 			if (res) {
119*5da989f3SGatien Chevallier 				EMSG("Cannot release semaphore for resource %u",
120*5da989f3SGatien Chevallier 				     i);
121*5da989f3SGatien Chevallier 				return res;
122*5da989f3SGatien Chevallier 			}
123*5da989f3SGatien Chevallier 		} else {
124*5da989f3SGatien Chevallier 			res = stm32_rif_acquire_semaphore(fmc_d->base +
125*5da989f3SGatien Chevallier 							  _FMC_SEMCR(i),
126*5da989f3SGatien Chevallier 							  MAX_CID_SUPPORTED);
127*5da989f3SGatien Chevallier 			if (res) {
128*5da989f3SGatien Chevallier 				EMSG("Cannot acquire semaphore for resource %u",
129*5da989f3SGatien Chevallier 				     i);
130*5da989f3SGatien Chevallier 				return res;
131*5da989f3SGatien Chevallier 			}
132*5da989f3SGatien Chevallier 		}
133*5da989f3SGatien Chevallier 	}
134*5da989f3SGatien Chevallier 
135*5da989f3SGatien Chevallier 	return TEE_SUCCESS;
136*5da989f3SGatien Chevallier }
137*5da989f3SGatien Chevallier 
138778a36bfSGatien Chevallier static TEE_Result apply_rif_config(void)
139778a36bfSGatien Chevallier {
140778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_ACCESS_DENIED;
141778a36bfSGatien Chevallier 	unsigned int i = 0;
142778a36bfSGatien Chevallier 
143b573873cSGatien Chevallier 	if (!fmc_d->conf_data)
144b573873cSGatien Chevallier 		return TEE_SUCCESS;
145b573873cSGatien Chevallier 
146778a36bfSGatien Chevallier 	res = clk_enable(fmc_d->fmc_clock);
147778a36bfSGatien Chevallier 	if (res)
148778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
149778a36bfSGatien Chevallier 
150*5da989f3SGatien Chevallier 	if (fmc_d->is_tdcid) {
151778a36bfSGatien Chevallier 		for (i = 0; i < FMC_RIF_CONTROLLERS; i++) {
152b573873cSGatien Chevallier 			if (!(BIT(i) & fmc_d->conf_data->access_mask[0]))
153778a36bfSGatien Chevallier 				continue;
154778a36bfSGatien Chevallier 			/*
155*5da989f3SGatien Chevallier 			 * When TDCID, OP-TEE should be the one to set the CID
156*5da989f3SGatien Chevallier 			 * filtering configuration. Clearing previous
157*5da989f3SGatien Chevallier 			 * configuration prevents undesired events during the
158*5da989f3SGatien Chevallier 			 * only legitimate configuration.
159778a36bfSGatien Chevallier 			 */
160778a36bfSGatien Chevallier 			io_clrbits32(fmc_d->base + _FMC_CIDCFGR(i),
161778a36bfSGatien Chevallier 				     _FMC_CIDCFGR_CONF_MASK);
162778a36bfSGatien Chevallier 		}
163*5da989f3SGatien Chevallier 	} else {
164*5da989f3SGatien Chevallier 		res = handle_available_semaphores();
165*5da989f3SGatien Chevallier 		if (res)
166*5da989f3SGatien Chevallier 			panic();
167778a36bfSGatien Chevallier 	}
168778a36bfSGatien Chevallier 
169778a36bfSGatien Chevallier 	/* Security and privilege RIF configuration */
170778a36bfSGatien Chevallier 	io_clrsetbits32(fmc_d->base + _FMC_PRIVCFGR, _FMC_PRIVCFGR_MASK,
171b573873cSGatien Chevallier 			fmc_d->conf_data->priv_conf[0]);
172778a36bfSGatien Chevallier 	io_clrsetbits32(fmc_d->base + _FMC_SECCFGR, _FMC_SECCFGR_MASK,
173b573873cSGatien Chevallier 			fmc_d->conf_data->sec_conf[0]);
174778a36bfSGatien Chevallier 
175*5da989f3SGatien Chevallier 	if (!fmc_d->is_tdcid)
176*5da989f3SGatien Chevallier 		goto out;
177*5da989f3SGatien Chevallier 
178778a36bfSGatien Chevallier 	for (i = 0; i < FMC_RIF_CONTROLLERS; i++) {
179b573873cSGatien Chevallier 		if (!(BIT(i) & fmc_d->conf_data->access_mask[0]))
180778a36bfSGatien Chevallier 			continue;
181778a36bfSGatien Chevallier 
182778a36bfSGatien Chevallier 		io_clrsetbits32(fmc_d->base + _FMC_CIDCFGR(i),
183778a36bfSGatien Chevallier 				_FMC_CIDCFGR_CONF_MASK,
184b573873cSGatien Chevallier 				fmc_d->conf_data->cid_confs[i]);
185778a36bfSGatien Chevallier 	}
186778a36bfSGatien Chevallier 
187778a36bfSGatien Chevallier 	/*
188778a36bfSGatien Chevallier 	 * Lock RIF configuration if configured. This cannot be undone until
189778a36bfSGatien Chevallier 	 * next reset.
190778a36bfSGatien Chevallier 	 */
191*5da989f3SGatien Chevallier 	io_setbits32(fmc_d->base + _FMC_RCFGLOCKR,
192b573873cSGatien Chevallier 		     fmc_d->conf_data->lock_conf[0]);
193778a36bfSGatien Chevallier 
194*5da989f3SGatien Chevallier 	res = handle_available_semaphores();
195*5da989f3SGatien Chevallier 	if (res)
196*5da989f3SGatien Chevallier 		panic();
197*5da989f3SGatien Chevallier out:
198778a36bfSGatien Chevallier 	if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) {
199778a36bfSGatien Chevallier 		/* Check that RIF config are applied, panic otherwise */
200778a36bfSGatien Chevallier 		if ((io_read32(fmc_d->base + _FMC_PRIVCFGR) &
201b573873cSGatien Chevallier 		     fmc_d->conf_data->access_mask[0]) !=
202b573873cSGatien Chevallier 		    fmc_d->conf_data->priv_conf[0]) {
203778a36bfSGatien Chevallier 			EMSG("FMC controller priv conf is incorrect");
204778a36bfSGatien Chevallier 			panic();
205778a36bfSGatien Chevallier 		}
206778a36bfSGatien Chevallier 
207778a36bfSGatien Chevallier 		if ((io_read32(fmc_d->base + _FMC_SECCFGR) &
208b573873cSGatien Chevallier 		     fmc_d->conf_data->access_mask[0]) !=
209b573873cSGatien Chevallier 		    fmc_d->conf_data->sec_conf[0]) {
210778a36bfSGatien Chevallier 			EMSG("FMC controller sec conf is incorrect");
211778a36bfSGatien Chevallier 			panic();
212778a36bfSGatien Chevallier 		}
213778a36bfSGatien Chevallier 	}
214778a36bfSGatien Chevallier 
215778a36bfSGatien Chevallier 	/* Disable the clock to allow RCC RIF re-configuration on this clock */
216778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
217778a36bfSGatien Chevallier 
218778a36bfSGatien Chevallier 	return TEE_SUCCESS;
219778a36bfSGatien Chevallier }
220778a36bfSGatien Chevallier 
221778a36bfSGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node)
222778a36bfSGatien Chevallier {
223778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
224778a36bfSGatien Chevallier 	struct dt_node_info info = { };
225b573873cSGatien Chevallier 	const fdt32_t *cuint = NULL;
226778a36bfSGatien Chevallier 	struct io_pa_va addr = { };
227b573873cSGatien Chevallier 	unsigned int i = 0;
228778a36bfSGatien Chevallier 	int ctrl_node = 0;
229b573873cSGatien Chevallier 	int lenp = 0;
230778a36bfSGatien Chevallier 
231778a36bfSGatien Chevallier 	fdt_fill_device_info(fdt, &info, node);
232778a36bfSGatien Chevallier 	assert(info.reg != DT_INFO_INVALID_REG &&
233778a36bfSGatien Chevallier 	       info.reg_size != DT_INFO_INVALID_REG_SIZE);
234778a36bfSGatien Chevallier 
235778a36bfSGatien Chevallier 	addr.pa = info.reg;
236778a36bfSGatien Chevallier 	fmc_d->base = io_pa_or_va(&addr, info.reg_size);
237778a36bfSGatien Chevallier 
238778a36bfSGatien Chevallier 	res = clk_dt_get_by_index(fdt, node, 0, &fmc_d->fmc_clock);
239778a36bfSGatien Chevallier 	if (res)
240778a36bfSGatien Chevallier 		return res;
241778a36bfSGatien Chevallier 
242778a36bfSGatien Chevallier 	res = pinctrl_get_state_by_name(fdt, node, "default",
243778a36bfSGatien Chevallier 					&fmc_d->pinctrl_d);
244778a36bfSGatien Chevallier 	if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
245778a36bfSGatien Chevallier 		return res;
246778a36bfSGatien Chevallier 
247778a36bfSGatien Chevallier 	res = pinctrl_get_state_by_name(fdt, node, "sleep",
248778a36bfSGatien Chevallier 					&fmc_d->pinctrl_s);
249778a36bfSGatien Chevallier 	if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
250778a36bfSGatien Chevallier 		return res;
251778a36bfSGatien Chevallier 
252778a36bfSGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
253b573873cSGatien Chevallier 	if (!cuint) {
254b573873cSGatien Chevallier 		DMSG("No RIF configuration available");
255b573873cSGatien Chevallier 		goto skip_rif;
256b573873cSGatien Chevallier 	}
257b573873cSGatien Chevallier 
258b573873cSGatien Chevallier 	fmc_d->conf_data = calloc(1, sizeof(*fmc_d->conf_data));
259b573873cSGatien Chevallier 	if (!fmc_d->conf_data)
260b573873cSGatien Chevallier 		panic();
261778a36bfSGatien Chevallier 
262778a36bfSGatien Chevallier 	fmc_d->nb_controller = (unsigned int)(lenp / sizeof(uint32_t));
263778a36bfSGatien Chevallier 	assert(fmc_d->nb_controller <= FMC_RIF_CONTROLLERS);
264778a36bfSGatien Chevallier 
265b573873cSGatien Chevallier 	fmc_d->conf_data->cid_confs = calloc(FMC_RIF_CONTROLLERS,
266778a36bfSGatien Chevallier 					     sizeof(uint32_t));
267b573873cSGatien Chevallier 	fmc_d->conf_data->sec_conf = calloc(1, sizeof(uint32_t));
268b573873cSGatien Chevallier 	fmc_d->conf_data->priv_conf = calloc(1, sizeof(uint32_t));
269b573873cSGatien Chevallier 	fmc_d->conf_data->lock_conf = calloc(1, sizeof(uint32_t));
270b573873cSGatien Chevallier 	fmc_d->conf_data->access_mask = calloc(1, sizeof(uint32_t));
271b573873cSGatien Chevallier 	if (!fmc_d->conf_data->cid_confs || !fmc_d->conf_data->sec_conf ||
272b573873cSGatien Chevallier 	    !fmc_d->conf_data->priv_conf || !fmc_d->conf_data->access_mask)
273b573873cSGatien Chevallier 		panic("Missing memory capacity for FMC RIF configuration");
274778a36bfSGatien Chevallier 
275b573873cSGatien Chevallier 	for (i = 0; i < fmc_d->nb_controller; i++)
276b573873cSGatien Chevallier 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), fmc_d->conf_data,
277778a36bfSGatien Chevallier 				    FMC_RIF_CONTROLLERS);
278778a36bfSGatien Chevallier 
279b573873cSGatien Chevallier skip_rif:
280778a36bfSGatien Chevallier 	fdt_for_each_subnode(ctrl_node, fdt, node) {
281778a36bfSGatien Chevallier 		int status = fdt_get_status(fdt, ctrl_node);
282778a36bfSGatien Chevallier 		uint32_t bank = 0;
283778a36bfSGatien Chevallier 
284778a36bfSGatien Chevallier 		if (status == DT_STATUS_DISABLED)
285778a36bfSGatien Chevallier 			continue;
286778a36bfSGatien Chevallier 
287778a36bfSGatien Chevallier 		if (fdt_read_uint32(fdt, ctrl_node, "reg", &bank) < 0)
288778a36bfSGatien Chevallier 			return TEE_ERROR_BAD_PARAMETERS;
289778a36bfSGatien Chevallier 
290778a36bfSGatien Chevallier 		if (bank != 0)
291778a36bfSGatien Chevallier 			continue;
292778a36bfSGatien Chevallier 
293778a36bfSGatien Chevallier 		if (fdt_getprop(fdt, ctrl_node,
294778a36bfSGatien Chevallier 				"st,fmc2-ebi-cs-cclk-enable", NULL))
295778a36bfSGatien Chevallier 			fmc_d->cclken = true;
296778a36bfSGatien Chevallier 
297778a36bfSGatien Chevallier 		if (!fmc_d->cclken)
298778a36bfSGatien Chevallier 			continue;
299778a36bfSGatien Chevallier 
300778a36bfSGatien Chevallier 		if (fdt_read_uint32(fdt, ctrl_node,
301778a36bfSGatien Chevallier 				    "st,fmc2-ebi-cs-clk-period-ns",
302778a36bfSGatien Chevallier 				    &fmc_d->clk_period_ns) < 0)
303778a36bfSGatien Chevallier 			return TEE_ERROR_BAD_PARAMETERS;
304778a36bfSGatien Chevallier 	}
305778a36bfSGatien Chevallier 
306778a36bfSGatien Chevallier 	return TEE_SUCCESS;
307778a36bfSGatien Chevallier }
308778a36bfSGatien Chevallier 
309778a36bfSGatien Chevallier static TEE_Result __maybe_unused check_fmc_rif_conf(void)
310778a36bfSGatien Chevallier {
311778a36bfSGatien Chevallier 	unsigned int i = 0;
312778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
313778a36bfSGatien Chevallier 
314778a36bfSGatien Chevallier 	res = clk_enable(fmc_d->fmc_clock);
315778a36bfSGatien Chevallier 	if (res)
316778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
317778a36bfSGatien Chevallier 
318778a36bfSGatien Chevallier 	if (fmc_controller_is_secure(0))
319778a36bfSGatien Chevallier 		goto end;
320778a36bfSGatien Chevallier 
321778a36bfSGatien Chevallier 	for (i = 1; i < fmc_d->nb_controller; i++) {
322778a36bfSGatien Chevallier 		uint32_t cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i));
323778a36bfSGatien Chevallier 		uint32_t semcr = io_read32(fmc_d->base + _FMC_SEMCR(i));
324778a36bfSGatien Chevallier 
325778a36bfSGatien Chevallier 		/* Check if a controller is secure */
326778a36bfSGatien Chevallier 		if (fmc_controller_is_secure(i)) {
327778a36bfSGatien Chevallier 			res = TEE_ERROR_BAD_STATE;
328778a36bfSGatien Chevallier 			goto end;
329778a36bfSGatien Chevallier 		}
330778a36bfSGatien Chevallier 
331778a36bfSGatien Chevallier 		/*
332778a36bfSGatien Chevallier 		 * Check if a controller is shared with incorrect CID
333778a36bfSGatien Chevallier 		 * (!= RIF_CID1)
334778a36bfSGatien Chevallier 		 */
335*5da989f3SGatien Chevallier 		res = stm32_rif_check_access(cidcfgr, semcr, MAX_CID_SUPPORTED,
336778a36bfSGatien Chevallier 					     RIF_CID1);
337778a36bfSGatien Chevallier 		if (res)
338778a36bfSGatien Chevallier 			break;
339778a36bfSGatien Chevallier 	}
340778a36bfSGatien Chevallier 
341778a36bfSGatien Chevallier end:
342778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
343778a36bfSGatien Chevallier 
344778a36bfSGatien Chevallier 	return res;
345778a36bfSGatien Chevallier }
346778a36bfSGatien Chevallier 
347778a36bfSGatien Chevallier static void configure_fmc(void)
348778a36bfSGatien Chevallier {
349778a36bfSGatien Chevallier 	uint32_t cidcfgr = 0;
350778a36bfSGatien Chevallier 	uint32_t semcr = 0;
351778a36bfSGatien Chevallier 
352778a36bfSGatien Chevallier 	if (clk_enable(fmc_d->fmc_clock))
353778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
354778a36bfSGatien Chevallier 
355778a36bfSGatien Chevallier 	semcr = io_read32(fmc_d->base + _FMC_SEMCR(0));
356778a36bfSGatien Chevallier 	cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(0));
357778a36bfSGatien Chevallier 
358778a36bfSGatien Chevallier 	/*
359778a36bfSGatien Chevallier 	 * If OP-TEE doesn't have access to the controller 0,
360778a36bfSGatien Chevallier 	 * then we don't want to try to enable the FMC.
361778a36bfSGatien Chevallier 	 */
362*5da989f3SGatien Chevallier 	if (stm32_rif_check_access(cidcfgr, semcr, MAX_CID_SUPPORTED, RIF_CID1))
363778a36bfSGatien Chevallier 		goto end;
364778a36bfSGatien Chevallier 
365778a36bfSGatien Chevallier 	/* Check controller 0 access */
366778a36bfSGatien Chevallier 	if (!fmc_controller_is_secure(0)) {
367778a36bfSGatien Chevallier 		DMSG("Controller 0 non-secure, FMC not enabled");
368778a36bfSGatien Chevallier 		goto end;
369778a36bfSGatien Chevallier 	}
370778a36bfSGatien Chevallier 
371778a36bfSGatien Chevallier 	if (cidcfgr & _CIDCFGR_SEMEN &&
372778a36bfSGatien Chevallier 	    stm32_rif_acquire_semaphore(fmc_d->base + _FMC_SEMCR(0),
373*5da989f3SGatien Chevallier 					MAX_CID_SUPPORTED))
374778a36bfSGatien Chevallier 		panic("Couldn't acquire controller 0 semaphore");
375778a36bfSGatien Chevallier 
376778a36bfSGatien Chevallier 	if (fmc_d->pinctrl_d && pinctrl_apply_state(fmc_d->pinctrl_d))
377778a36bfSGatien Chevallier 		panic("Could not apply FMC pinctrl");
378778a36bfSGatien Chevallier 
379778a36bfSGatien Chevallier 	if (fmc_d->cclken) {
380778a36bfSGatien Chevallier 		unsigned long hclk = clk_get_rate(fmc_d->fmc_clock);
381778a36bfSGatien Chevallier 		unsigned long hclkp = FMC_NSEC_PER_SEC / (hclk / 1000);
382778a36bfSGatien Chevallier 		unsigned long timing = DIV_ROUND_UP(fmc_d->clk_period_ns * 1000,
383778a36bfSGatien Chevallier 						    hclkp);
384778a36bfSGatien Chevallier 		uint32_t clk_div = SHIFT_U32(1, _FMC_CFGR_CLKDIV_SHIFT);
385778a36bfSGatien Chevallier 
386778a36bfSGatien Chevallier 		if (timing > 1) {
387778a36bfSGatien Chevallier 			timing--;
388778a36bfSGatien Chevallier 			if (timing >
389778a36bfSGatien Chevallier 			    _FMC_CFGR_CLKDIV_MASK >> _FMC_CFGR_CLKDIV_SHIFT)
390778a36bfSGatien Chevallier 				clk_div = _FMC_CFGR_CLKDIV_MASK;
391778a36bfSGatien Chevallier 			else
392778a36bfSGatien Chevallier 				clk_div = SHIFT_U32(timing,
393778a36bfSGatien Chevallier 						    _FMC_CFGR_CLKDIV_SHIFT);
394778a36bfSGatien Chevallier 		}
395778a36bfSGatien Chevallier 
396778a36bfSGatien Chevallier 		io_clrsetbits32(fmc_d->base + _FMC_CFGR,
397778a36bfSGatien Chevallier 				_FMC_CFGR_CLKDIV_MASK | _FMC_CFGR_CCLKEN,
398778a36bfSGatien Chevallier 				clk_div | _FMC_CFGR_CCLKEN);
399778a36bfSGatien Chevallier 	}
400778a36bfSGatien Chevallier 
401778a36bfSGatien Chevallier 	/* Set the FMC enable BIT */
402778a36bfSGatien Chevallier 	io_setbits32(fmc_d->base + _FMC_CFGR, _FMC_CFGR_ENABLE);
403778a36bfSGatien Chevallier 
404778a36bfSGatien Chevallier end:
405778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
406778a36bfSGatien Chevallier }
407778a36bfSGatien Chevallier 
408778a36bfSGatien Chevallier static void fmc_setup(void)
409778a36bfSGatien Chevallier {
410778a36bfSGatien Chevallier 	if (apply_rif_config())
411778a36bfSGatien Chevallier 		panic("Failed to apply rif_config");
412778a36bfSGatien Chevallier 
413778a36bfSGatien Chevallier 	/* Sanity check for FMC RIF config */
414778a36bfSGatien Chevallier 	assert(check_fmc_rif_conf());
415778a36bfSGatien Chevallier 
416778a36bfSGatien Chevallier 	configure_fmc();
417778a36bfSGatien Chevallier }
418778a36bfSGatien Chevallier 
419778a36bfSGatien Chevallier static void fmc_suspend(void)
420778a36bfSGatien Chevallier {
421778a36bfSGatien Chevallier 	unsigned int i = 0;
422778a36bfSGatien Chevallier 
423778a36bfSGatien Chevallier 	if (clk_enable(fmc_d->fmc_clock))
424778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
425778a36bfSGatien Chevallier 
426778a36bfSGatien Chevallier 	if (fmc_controller_is_secure(0) && fmc_d->pinctrl_s &&
427778a36bfSGatien Chevallier 	    pinctrl_apply_state(fmc_d->pinctrl_s))
428778a36bfSGatien Chevallier 		panic();
429778a36bfSGatien Chevallier 
430778a36bfSGatien Chevallier 	for (i = 0; i < FMC_RIF_CONTROLLERS; i++)
431b573873cSGatien Chevallier 		fmc_d->conf_data->cid_confs[i] =
432778a36bfSGatien Chevallier 			io_read32(fmc_d->base + _FMC_CIDCFGR(i)) &
433778a36bfSGatien Chevallier 			_FMC_CIDCFGR_CONF_MASK;
434778a36bfSGatien Chevallier 
435b573873cSGatien Chevallier 	fmc_d->conf_data->priv_conf[0] =
436778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_PRIVCFGR) & _FMC_PRIVCFGR_MASK;
437b573873cSGatien Chevallier 	fmc_d->conf_data->sec_conf[0] =
438778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_SECCFGR) & _FMC_SECCFGR_MASK;
439b573873cSGatien Chevallier 	fmc_d->conf_data->lock_conf[0] =
440778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_RCFGLOCKR) & _FMC_RCFGLOCKR_MASK;
441b573873cSGatien Chevallier 	fmc_d->conf_data->access_mask[0] =
442778a36bfSGatien Chevallier 		GENMASK_32(FMC_RIF_CONTROLLERS - 1, 0);
443778a36bfSGatien Chevallier 
444778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
445778a36bfSGatien Chevallier }
446778a36bfSGatien Chevallier 
447778a36bfSGatien Chevallier static TEE_Result fmc_pm(enum pm_op op, unsigned int pm_hint,
448778a36bfSGatien Chevallier 			 const struct pm_callback_handle *pm_handle __unused)
449778a36bfSGatien Chevallier {
450778a36bfSGatien Chevallier 	if (pm_hint != PM_HINT_CONTEXT_STATE)
451778a36bfSGatien Chevallier 		return TEE_SUCCESS;
452778a36bfSGatien Chevallier 
453778a36bfSGatien Chevallier 	if (op == PM_OP_RESUME)
454778a36bfSGatien Chevallier 		fmc_setup();
455778a36bfSGatien Chevallier 	else
456778a36bfSGatien Chevallier 		fmc_suspend();
457778a36bfSGatien Chevallier 
458778a36bfSGatien Chevallier 	return TEE_SUCCESS;
459778a36bfSGatien Chevallier }
460778a36bfSGatien Chevallier 
461778a36bfSGatien Chevallier static TEE_Result fmc_probe(const void *fdt, int node,
462778a36bfSGatien Chevallier 			    const void *compat_data __unused)
463778a36bfSGatien Chevallier {
464778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
465778a36bfSGatien Chevallier 
466778a36bfSGatien Chevallier 	fmc_d = calloc(1, sizeof(*fmc_d));
467778a36bfSGatien Chevallier 	if (!fmc_d)
468778a36bfSGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
469778a36bfSGatien Chevallier 
470*5da989f3SGatien Chevallier 	res = stm32_rifsc_check_tdcid(&fmc_d->is_tdcid);
471*5da989f3SGatien Chevallier 	if (res) {
472*5da989f3SGatien Chevallier 		free(fmc_d);
473*5da989f3SGatien Chevallier 		return res;
474*5da989f3SGatien Chevallier 	}
475*5da989f3SGatien Chevallier 
476778a36bfSGatien Chevallier 	res = parse_dt(fdt, node);
477778a36bfSGatien Chevallier 	if (res)
478778a36bfSGatien Chevallier 		goto err;
479778a36bfSGatien Chevallier 
480778a36bfSGatien Chevallier 	fmc_setup();
481778a36bfSGatien Chevallier 
482778a36bfSGatien Chevallier 	register_pm_core_service_cb(fmc_pm, NULL, "stm32-fmc");
483778a36bfSGatien Chevallier 
484778a36bfSGatien Chevallier 	return TEE_SUCCESS;
485778a36bfSGatien Chevallier err:
486778a36bfSGatien Chevallier 	/* Free all allocated resources */
487b573873cSGatien Chevallier 	if (fmc_d->conf_data) {
488b573873cSGatien Chevallier 		free(fmc_d->conf_data->access_mask);
489b573873cSGatien Chevallier 		free(fmc_d->conf_data->cid_confs);
490b573873cSGatien Chevallier 		free(fmc_d->conf_data->priv_conf);
491b573873cSGatien Chevallier 		free(fmc_d->conf_data->sec_conf);
492b573873cSGatien Chevallier 	}
493b573873cSGatien Chevallier 	free(fmc_d->conf_data);
494778a36bfSGatien Chevallier 	free(fmc_d);
495778a36bfSGatien Chevallier 
496778a36bfSGatien Chevallier 	return res;
497778a36bfSGatien Chevallier }
498778a36bfSGatien Chevallier 
499778a36bfSGatien Chevallier static const struct dt_device_match stm32_fmc_match_table[] = {
500778a36bfSGatien Chevallier 	{ .compatible = "st,stm32mp25-fmc2-ebi" },
501778a36bfSGatien Chevallier 	{ }
502778a36bfSGatien Chevallier };
503778a36bfSGatien Chevallier 
504778a36bfSGatien Chevallier DEFINE_DT_DRIVER(stm32_fmc_dt_driver) = {
505778a36bfSGatien Chevallier 	.name = "stm32_fmc",
506778a36bfSGatien Chevallier 	.match_table = stm32_fmc_match_table,
507778a36bfSGatien Chevallier 	.probe = fmc_probe,
508778a36bfSGatien Chevallier };
509