xref: /optee_os/core/drivers/stm32_fmc.c (revision 90df040bda9a80945e934076bcdd8ccf9e61ff8b)
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;
885da989f3SGatien Chevallier 	bool is_tdcid;
89778a36bfSGatien Chevallier 	bool cclken;
90778a36bfSGatien Chevallier };
91778a36bfSGatien Chevallier 
92778a36bfSGatien Chevallier static struct fmc_pdata *fmc_d;
93778a36bfSGatien Chevallier 
fmc_controller_is_secure(uint8_t controller)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 
handle_available_semaphores(void)995da989f3SGatien Chevallier static TEE_Result handle_available_semaphores(void)
1005da989f3SGatien Chevallier {
1015da989f3SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1025da989f3SGatien Chevallier 	uint32_t cidcfgr = 0;
1035da989f3SGatien Chevallier 	unsigned int i = 0;
1045da989f3SGatien Chevallier 
1055da989f3SGatien Chevallier 	for (i = 0; i < FMC_RIF_CONTROLLERS; i++) {
1065da989f3SGatien Chevallier 		if (!(BIT(i) & fmc_d->conf_data->access_mask[0]))
1075da989f3SGatien Chevallier 			continue;
1085da989f3SGatien Chevallier 
1095da989f3SGatien Chevallier 		cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i));
1105da989f3SGatien Chevallier 
1115da989f3SGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
1125da989f3SGatien Chevallier 			continue;
1135da989f3SGatien Chevallier 
1145da989f3SGatien Chevallier 		if (!(io_read32(fmc_d->base + _FMC_SECCFGR) & BIT(i))) {
1155da989f3SGatien Chevallier 			res = stm32_rif_release_semaphore(fmc_d->base +
1165da989f3SGatien Chevallier 							  _FMC_SEMCR(i),
1175da989f3SGatien Chevallier 							  MAX_CID_SUPPORTED);
1185da989f3SGatien Chevallier 			if (res) {
1195da989f3SGatien Chevallier 				EMSG("Cannot release semaphore for resource %u",
1205da989f3SGatien Chevallier 				     i);
1215da989f3SGatien Chevallier 				return res;
1225da989f3SGatien Chevallier 			}
1235da989f3SGatien Chevallier 		} else {
1245da989f3SGatien Chevallier 			res = stm32_rif_acquire_semaphore(fmc_d->base +
1255da989f3SGatien Chevallier 							  _FMC_SEMCR(i),
1265da989f3SGatien Chevallier 							  MAX_CID_SUPPORTED);
1275da989f3SGatien Chevallier 			if (res) {
1285da989f3SGatien Chevallier 				EMSG("Cannot acquire semaphore for resource %u",
1295da989f3SGatien Chevallier 				     i);
1305da989f3SGatien Chevallier 				return res;
1315da989f3SGatien Chevallier 			}
1325da989f3SGatien Chevallier 		}
1335da989f3SGatien Chevallier 	}
1345da989f3SGatien Chevallier 
1355da989f3SGatien Chevallier 	return TEE_SUCCESS;
1365da989f3SGatien Chevallier }
1375da989f3SGatien Chevallier 
apply_rif_config(void)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 
1505da989f3SGatien 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 			/*
1555da989f3SGatien Chevallier 			 * When TDCID, OP-TEE should be the one to set the CID
1565da989f3SGatien Chevallier 			 * filtering configuration. Clearing previous
1575da989f3SGatien Chevallier 			 * configuration prevents undesired events during the
1585da989f3SGatien Chevallier 			 * only legitimate configuration.
159778a36bfSGatien Chevallier 			 */
160778a36bfSGatien Chevallier 			io_clrbits32(fmc_d->base + _FMC_CIDCFGR(i),
161778a36bfSGatien Chevallier 				     _FMC_CIDCFGR_CONF_MASK);
162778a36bfSGatien Chevallier 		}
1635da989f3SGatien Chevallier 	} else {
1645da989f3SGatien Chevallier 		res = handle_available_semaphores();
1655da989f3SGatien Chevallier 		if (res)
1665da989f3SGatien 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 
1755da989f3SGatien Chevallier 	if (!fmc_d->is_tdcid)
1765da989f3SGatien Chevallier 		goto out;
1775da989f3SGatien 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 	 */
1915da989f3SGatien Chevallier 	io_setbits32(fmc_d->base + _FMC_RCFGLOCKR,
192b573873cSGatien Chevallier 		     fmc_d->conf_data->lock_conf[0]);
193778a36bfSGatien Chevallier 
1945da989f3SGatien Chevallier 	res = handle_available_semaphores();
1955da989f3SGatien Chevallier 	if (res)
1965da989f3SGatien Chevallier 		panic();
1975da989f3SGatien 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 
parse_dt(const void * fdt,int node)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 
check_fmc_rif_conf(void)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 
318*90df040bSGatien Chevallier 	if (fmc_controller_is_secure(0)) {
319*90df040bSGatien Chevallier 		res = TEE_SUCCESS;
320778a36bfSGatien Chevallier 		goto end;
321*90df040bSGatien Chevallier 	}
322778a36bfSGatien Chevallier 
323778a36bfSGatien Chevallier 	for (i = 1; i < fmc_d->nb_controller; i++) {
324778a36bfSGatien Chevallier 		uint32_t cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i));
325778a36bfSGatien Chevallier 		uint32_t semcr = io_read32(fmc_d->base + _FMC_SEMCR(i));
326778a36bfSGatien Chevallier 
327778a36bfSGatien Chevallier 		/* Check if a controller is secure */
328778a36bfSGatien Chevallier 		if (fmc_controller_is_secure(i)) {
329778a36bfSGatien Chevallier 			res = TEE_ERROR_BAD_STATE;
330778a36bfSGatien Chevallier 			goto end;
331778a36bfSGatien Chevallier 		}
332778a36bfSGatien Chevallier 
333778a36bfSGatien Chevallier 		/*
334778a36bfSGatien Chevallier 		 * Check if a controller is shared with incorrect CID
335778a36bfSGatien Chevallier 		 * (!= RIF_CID1)
336778a36bfSGatien Chevallier 		 */
3375da989f3SGatien Chevallier 		res = stm32_rif_check_access(cidcfgr, semcr, MAX_CID_SUPPORTED,
338778a36bfSGatien Chevallier 					     RIF_CID1);
339778a36bfSGatien Chevallier 		if (res)
340778a36bfSGatien Chevallier 			break;
341778a36bfSGatien Chevallier 	}
342778a36bfSGatien Chevallier 
343778a36bfSGatien Chevallier end:
344778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
345778a36bfSGatien Chevallier 
346778a36bfSGatien Chevallier 	return res;
347778a36bfSGatien Chevallier }
348778a36bfSGatien Chevallier 
configure_fmc(void)349778a36bfSGatien Chevallier static void configure_fmc(void)
350778a36bfSGatien Chevallier {
351778a36bfSGatien Chevallier 	uint32_t cidcfgr = 0;
352778a36bfSGatien Chevallier 	uint32_t semcr = 0;
353778a36bfSGatien Chevallier 
354778a36bfSGatien Chevallier 	if (clk_enable(fmc_d->fmc_clock))
355778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
356778a36bfSGatien Chevallier 
357778a36bfSGatien Chevallier 	semcr = io_read32(fmc_d->base + _FMC_SEMCR(0));
358778a36bfSGatien Chevallier 	cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(0));
359778a36bfSGatien Chevallier 
360778a36bfSGatien Chevallier 	/*
361778a36bfSGatien Chevallier 	 * If OP-TEE doesn't have access to the controller 0,
362778a36bfSGatien Chevallier 	 * then we don't want to try to enable the FMC.
363778a36bfSGatien Chevallier 	 */
3645da989f3SGatien Chevallier 	if (stm32_rif_check_access(cidcfgr, semcr, MAX_CID_SUPPORTED, RIF_CID1))
365778a36bfSGatien Chevallier 		goto end;
366778a36bfSGatien Chevallier 
367778a36bfSGatien Chevallier 	/* Check controller 0 access */
368778a36bfSGatien Chevallier 	if (!fmc_controller_is_secure(0)) {
369778a36bfSGatien Chevallier 		DMSG("Controller 0 non-secure, FMC not enabled");
370778a36bfSGatien Chevallier 		goto end;
371778a36bfSGatien Chevallier 	}
372778a36bfSGatien Chevallier 
373778a36bfSGatien Chevallier 	if (cidcfgr & _CIDCFGR_SEMEN &&
374778a36bfSGatien Chevallier 	    stm32_rif_acquire_semaphore(fmc_d->base + _FMC_SEMCR(0),
3755da989f3SGatien Chevallier 					MAX_CID_SUPPORTED))
376778a36bfSGatien Chevallier 		panic("Couldn't acquire controller 0 semaphore");
377778a36bfSGatien Chevallier 
378778a36bfSGatien Chevallier 	if (fmc_d->pinctrl_d && pinctrl_apply_state(fmc_d->pinctrl_d))
379778a36bfSGatien Chevallier 		panic("Could not apply FMC pinctrl");
380778a36bfSGatien Chevallier 
381778a36bfSGatien Chevallier 	if (fmc_d->cclken) {
382778a36bfSGatien Chevallier 		unsigned long hclk = clk_get_rate(fmc_d->fmc_clock);
383778a36bfSGatien Chevallier 		unsigned long hclkp = FMC_NSEC_PER_SEC / (hclk / 1000);
384778a36bfSGatien Chevallier 		unsigned long timing = DIV_ROUND_UP(fmc_d->clk_period_ns * 1000,
385778a36bfSGatien Chevallier 						    hclkp);
386778a36bfSGatien Chevallier 		uint32_t clk_div = SHIFT_U32(1, _FMC_CFGR_CLKDIV_SHIFT);
387778a36bfSGatien Chevallier 
388778a36bfSGatien Chevallier 		if (timing > 1) {
389778a36bfSGatien Chevallier 			timing--;
390778a36bfSGatien Chevallier 			if (timing >
391778a36bfSGatien Chevallier 			    _FMC_CFGR_CLKDIV_MASK >> _FMC_CFGR_CLKDIV_SHIFT)
392778a36bfSGatien Chevallier 				clk_div = _FMC_CFGR_CLKDIV_MASK;
393778a36bfSGatien Chevallier 			else
394778a36bfSGatien Chevallier 				clk_div = SHIFT_U32(timing,
395778a36bfSGatien Chevallier 						    _FMC_CFGR_CLKDIV_SHIFT);
396778a36bfSGatien Chevallier 		}
397778a36bfSGatien Chevallier 
398778a36bfSGatien Chevallier 		io_clrsetbits32(fmc_d->base + _FMC_CFGR,
399778a36bfSGatien Chevallier 				_FMC_CFGR_CLKDIV_MASK | _FMC_CFGR_CCLKEN,
400778a36bfSGatien Chevallier 				clk_div | _FMC_CFGR_CCLKEN);
401778a36bfSGatien Chevallier 	}
402778a36bfSGatien Chevallier 
403778a36bfSGatien Chevallier 	/* Set the FMC enable BIT */
404778a36bfSGatien Chevallier 	io_setbits32(fmc_d->base + _FMC_CFGR, _FMC_CFGR_ENABLE);
405778a36bfSGatien Chevallier 
406778a36bfSGatien Chevallier end:
407778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
408778a36bfSGatien Chevallier }
409778a36bfSGatien Chevallier 
fmc_setup(void)410778a36bfSGatien Chevallier static void fmc_setup(void)
411778a36bfSGatien Chevallier {
412778a36bfSGatien Chevallier 	if (apply_rif_config())
413778a36bfSGatien Chevallier 		panic("Failed to apply rif_config");
414778a36bfSGatien Chevallier 
415778a36bfSGatien Chevallier 	/* Sanity check for FMC RIF config */
416*90df040bSGatien Chevallier 	assert(!check_fmc_rif_conf());
417778a36bfSGatien Chevallier 
418778a36bfSGatien Chevallier 	configure_fmc();
419778a36bfSGatien Chevallier }
420778a36bfSGatien Chevallier 
fmc_suspend(void)421778a36bfSGatien Chevallier static void fmc_suspend(void)
422778a36bfSGatien Chevallier {
423778a36bfSGatien Chevallier 	unsigned int i = 0;
424778a36bfSGatien Chevallier 
425778a36bfSGatien Chevallier 	if (clk_enable(fmc_d->fmc_clock))
426778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
427778a36bfSGatien Chevallier 
428778a36bfSGatien Chevallier 	if (fmc_controller_is_secure(0) && fmc_d->pinctrl_s &&
429778a36bfSGatien Chevallier 	    pinctrl_apply_state(fmc_d->pinctrl_s))
430778a36bfSGatien Chevallier 		panic();
431778a36bfSGatien Chevallier 
432778a36bfSGatien Chevallier 	for (i = 0; i < FMC_RIF_CONTROLLERS; i++)
433b573873cSGatien Chevallier 		fmc_d->conf_data->cid_confs[i] =
434778a36bfSGatien Chevallier 			io_read32(fmc_d->base + _FMC_CIDCFGR(i)) &
435778a36bfSGatien Chevallier 			_FMC_CIDCFGR_CONF_MASK;
436778a36bfSGatien Chevallier 
437b573873cSGatien Chevallier 	fmc_d->conf_data->priv_conf[0] =
438778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_PRIVCFGR) & _FMC_PRIVCFGR_MASK;
439b573873cSGatien Chevallier 	fmc_d->conf_data->sec_conf[0] =
440778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_SECCFGR) & _FMC_SECCFGR_MASK;
441b573873cSGatien Chevallier 	fmc_d->conf_data->lock_conf[0] =
442778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_RCFGLOCKR) & _FMC_RCFGLOCKR_MASK;
443b573873cSGatien Chevallier 	fmc_d->conf_data->access_mask[0] =
444778a36bfSGatien Chevallier 		GENMASK_32(FMC_RIF_CONTROLLERS - 1, 0);
445778a36bfSGatien Chevallier 
446778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
447778a36bfSGatien Chevallier }
448778a36bfSGatien Chevallier 
fmc_pm(enum pm_op op,unsigned int pm_hint,const struct pm_callback_handle * pm_handle __unused)449778a36bfSGatien Chevallier static TEE_Result fmc_pm(enum pm_op op, unsigned int pm_hint,
450778a36bfSGatien Chevallier 			 const struct pm_callback_handle *pm_handle __unused)
451778a36bfSGatien Chevallier {
4526e15f946SGatien Chevallier 	if (!PM_HINT_IS_STATE(pm_hint, CONTEXT))
453778a36bfSGatien Chevallier 		return TEE_SUCCESS;
454778a36bfSGatien Chevallier 
455778a36bfSGatien Chevallier 	if (op == PM_OP_RESUME)
456778a36bfSGatien Chevallier 		fmc_setup();
457778a36bfSGatien Chevallier 	else
458778a36bfSGatien Chevallier 		fmc_suspend();
459778a36bfSGatien Chevallier 
460778a36bfSGatien Chevallier 	return TEE_SUCCESS;
461778a36bfSGatien Chevallier }
462778a36bfSGatien Chevallier 
fmc_probe(const void * fdt,int node,const void * compat_data __unused)463778a36bfSGatien Chevallier static TEE_Result fmc_probe(const void *fdt, int node,
464778a36bfSGatien Chevallier 			    const void *compat_data __unused)
465778a36bfSGatien Chevallier {
466778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
467778a36bfSGatien Chevallier 
468778a36bfSGatien Chevallier 	fmc_d = calloc(1, sizeof(*fmc_d));
469778a36bfSGatien Chevallier 	if (!fmc_d)
470778a36bfSGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
471778a36bfSGatien Chevallier 
4725da989f3SGatien Chevallier 	res = stm32_rifsc_check_tdcid(&fmc_d->is_tdcid);
4735da989f3SGatien Chevallier 	if (res) {
4745da989f3SGatien Chevallier 		free(fmc_d);
4755da989f3SGatien Chevallier 		return res;
4765da989f3SGatien Chevallier 	}
4775da989f3SGatien Chevallier 
478778a36bfSGatien Chevallier 	res = parse_dt(fdt, node);
479778a36bfSGatien Chevallier 	if (res)
480778a36bfSGatien Chevallier 		goto err;
481778a36bfSGatien Chevallier 
482778a36bfSGatien Chevallier 	fmc_setup();
483778a36bfSGatien Chevallier 
484778a36bfSGatien Chevallier 	register_pm_core_service_cb(fmc_pm, NULL, "stm32-fmc");
485778a36bfSGatien Chevallier 
486778a36bfSGatien Chevallier 	return TEE_SUCCESS;
487778a36bfSGatien Chevallier err:
488778a36bfSGatien Chevallier 	/* Free all allocated resources */
489b573873cSGatien Chevallier 	if (fmc_d->conf_data) {
490b573873cSGatien Chevallier 		free(fmc_d->conf_data->access_mask);
491b573873cSGatien Chevallier 		free(fmc_d->conf_data->cid_confs);
492b573873cSGatien Chevallier 		free(fmc_d->conf_data->priv_conf);
493b573873cSGatien Chevallier 		free(fmc_d->conf_data->sec_conf);
494b573873cSGatien Chevallier 	}
495b573873cSGatien Chevallier 	free(fmc_d->conf_data);
496778a36bfSGatien Chevallier 	free(fmc_d);
497778a36bfSGatien Chevallier 
498778a36bfSGatien Chevallier 	return res;
499778a36bfSGatien Chevallier }
500778a36bfSGatien Chevallier 
501778a36bfSGatien Chevallier static const struct dt_device_match stm32_fmc_match_table[] = {
502778a36bfSGatien Chevallier 	{ .compatible = "st,stm32mp25-fmc2-ebi" },
503778a36bfSGatien Chevallier 	{ }
504778a36bfSGatien Chevallier };
505778a36bfSGatien Chevallier 
506778a36bfSGatien Chevallier DEFINE_DT_DRIVER(stm32_fmc_dt_driver) = {
507778a36bfSGatien Chevallier 	.name = "stm32_fmc",
508778a36bfSGatien Chevallier 	.match_table = stm32_fmc_match_table,
509778a36bfSGatien Chevallier 	.probe = fmc_probe,
510778a36bfSGatien Chevallier };
511