xref: /optee_os/core/drivers/stm32_fmc.c (revision b573873cdeae0918a20f5634652424a8bffc96bf)
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_NB_MAX_CID_SUPPORTED	U(7)
79778a36bfSGatien Chevallier 
80778a36bfSGatien Chevallier #define FMC_NSEC_PER_SEC		UL(1000000000)
81778a36bfSGatien Chevallier 
82778a36bfSGatien Chevallier struct fmc_pdata {
83778a36bfSGatien Chevallier 	struct clk *fmc_clock;
84778a36bfSGatien Chevallier 	struct pinctrl_state *pinctrl_d;
85778a36bfSGatien Chevallier 	struct pinctrl_state *pinctrl_s;
86*b573873cSGatien Chevallier 	struct rif_conf_data *conf_data;
87778a36bfSGatien Chevallier 	unsigned int nb_controller;
88778a36bfSGatien Chevallier 	vaddr_t base;
89778a36bfSGatien Chevallier 	uint32_t clk_period_ns;
90778a36bfSGatien Chevallier 	bool cclken;
91778a36bfSGatien Chevallier };
92778a36bfSGatien Chevallier 
93778a36bfSGatien Chevallier static struct fmc_pdata *fmc_d;
94778a36bfSGatien Chevallier 
95778a36bfSGatien Chevallier static bool fmc_controller_is_secure(uint8_t controller)
96778a36bfSGatien Chevallier {
97778a36bfSGatien Chevallier 	return io_read32(fmc_d->base + _FMC_SECCFGR) & BIT(controller);
98778a36bfSGatien Chevallier }
99778a36bfSGatien Chevallier 
100778a36bfSGatien Chevallier static TEE_Result apply_rif_config(void)
101778a36bfSGatien Chevallier {
102778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_ACCESS_DENIED;
103778a36bfSGatien Chevallier 	uint32_t cidcfgr = 0;
104778a36bfSGatien Chevallier 	unsigned int i = 0;
105778a36bfSGatien Chevallier 
106*b573873cSGatien Chevallier 	if (!fmc_d->conf_data)
107*b573873cSGatien Chevallier 		return TEE_SUCCESS;
108*b573873cSGatien Chevallier 
109778a36bfSGatien Chevallier 	res = clk_enable(fmc_d->fmc_clock);
110778a36bfSGatien Chevallier 	if (res)
111778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
112778a36bfSGatien Chevallier 
113778a36bfSGatien Chevallier 	for (i = 0; i < FMC_RIF_CONTROLLERS; i++) {
114*b573873cSGatien Chevallier 		if (!(BIT(i) & fmc_d->conf_data->access_mask[0]))
115778a36bfSGatien Chevallier 			continue;
116778a36bfSGatien Chevallier 
117778a36bfSGatien Chevallier 		/*
118778a36bfSGatien Chevallier 		 * Whatever the TDCID state, try to clear the configurable part
119778a36bfSGatien Chevallier 		 * of the CIDCFGR register.
120778a36bfSGatien Chevallier 		 * If TDCID, register will be cleared, if not, the clear will
121778a36bfSGatien Chevallier 		 * be ignored.
122778a36bfSGatien Chevallier 		 * When TDCID, OP-TEE should be the one to set the CID filtering
123778a36bfSGatien Chevallier 		 * configuration. Clearing previous configuration prevents
124778a36bfSGatien Chevallier 		 * undesired events during the only legitimate configuration.
125778a36bfSGatien Chevallier 		 */
126778a36bfSGatien Chevallier 		io_clrbits32(fmc_d->base + _FMC_CIDCFGR(i),
127778a36bfSGatien Chevallier 			     _FMC_CIDCFGR_CONF_MASK);
128778a36bfSGatien Chevallier 
129778a36bfSGatien Chevallier 		cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i));
130778a36bfSGatien Chevallier 
131778a36bfSGatien Chevallier 		/* Check if the controller is in semaphore mode */
132778a36bfSGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1))
133778a36bfSGatien Chevallier 			continue;
134778a36bfSGatien Chevallier 
135778a36bfSGatien Chevallier 		/* If not TDCID, we want to acquire semaphores assigned to us */
136778a36bfSGatien Chevallier 		res = stm32_rif_acquire_semaphore(fmc_d->base + _FMC_SEMCR(i),
137778a36bfSGatien Chevallier 						  FMC_NB_MAX_CID_SUPPORTED);
138778a36bfSGatien Chevallier 		if (res) {
139778a36bfSGatien Chevallier 			EMSG("Couldn't acquire semaphore for controller %u", i);
140778a36bfSGatien Chevallier 			clk_disable(fmc_d->fmc_clock);
141778a36bfSGatien Chevallier 			return res;
142778a36bfSGatien Chevallier 		}
143778a36bfSGatien Chevallier 	}
144778a36bfSGatien Chevallier 
145778a36bfSGatien Chevallier 	/* Security and privilege RIF configuration */
146778a36bfSGatien Chevallier 	io_clrsetbits32(fmc_d->base + _FMC_PRIVCFGR, _FMC_PRIVCFGR_MASK,
147*b573873cSGatien Chevallier 			fmc_d->conf_data->priv_conf[0]);
148778a36bfSGatien Chevallier 	io_clrsetbits32(fmc_d->base + _FMC_SECCFGR, _FMC_SECCFGR_MASK,
149*b573873cSGatien Chevallier 			fmc_d->conf_data->sec_conf[0]);
150778a36bfSGatien Chevallier 
151778a36bfSGatien Chevallier 	for (i = 0; i < FMC_RIF_CONTROLLERS; i++) {
152*b573873cSGatien Chevallier 		if (!(BIT(i) & fmc_d->conf_data->access_mask[0]))
153778a36bfSGatien Chevallier 			continue;
154778a36bfSGatien Chevallier 
155778a36bfSGatien Chevallier 		io_clrsetbits32(fmc_d->base + _FMC_CIDCFGR(i),
156778a36bfSGatien Chevallier 				_FMC_CIDCFGR_CONF_MASK,
157*b573873cSGatien Chevallier 				fmc_d->conf_data->cid_confs[i]);
158778a36bfSGatien Chevallier 
159778a36bfSGatien Chevallier 		cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i));
160778a36bfSGatien Chevallier 
161778a36bfSGatien Chevallier 		/*
162778a36bfSGatien Chevallier 		 * Take semaphore if the resource is in semaphore mode
163778a36bfSGatien Chevallier 		 * and secured
164778a36bfSGatien Chevallier 		 */
165778a36bfSGatien Chevallier 		if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1) ||
166778a36bfSGatien Chevallier 		    !(io_read32(fmc_d->base + _FMC_SECCFGR) & BIT(i))) {
167778a36bfSGatien Chevallier 			res =
168778a36bfSGatien Chevallier 			stm32_rif_release_semaphore(fmc_d->base + _FMC_SEMCR(i),
169778a36bfSGatien Chevallier 						    FMC_NB_MAX_CID_SUPPORTED);
170778a36bfSGatien Chevallier 			if (res) {
171778a36bfSGatien Chevallier 				EMSG("Couldn't release semaphore for res%u", i);
172778a36bfSGatien Chevallier 				clk_disable(fmc_d->fmc_clock);
173778a36bfSGatien Chevallier 				return res;
174778a36bfSGatien Chevallier 			}
175778a36bfSGatien Chevallier 		} else {
176778a36bfSGatien Chevallier 			res =
177778a36bfSGatien Chevallier 			stm32_rif_acquire_semaphore(fmc_d->base + _FMC_SEMCR(i),
178778a36bfSGatien Chevallier 						    FMC_NB_MAX_CID_SUPPORTED);
179778a36bfSGatien Chevallier 			if (res) {
180778a36bfSGatien Chevallier 				EMSG("Couldn't acquire semaphore for res%u", i);
181778a36bfSGatien Chevallier 				clk_disable(fmc_d->fmc_clock);
182778a36bfSGatien Chevallier 				return res;
183778a36bfSGatien Chevallier 			}
184778a36bfSGatien Chevallier 		}
185778a36bfSGatien Chevallier 	}
186778a36bfSGatien Chevallier 
187778a36bfSGatien Chevallier 	/*
188778a36bfSGatien Chevallier 	 * Lock RIF configuration if configured. This cannot be undone until
189778a36bfSGatien Chevallier 	 * next reset.
190778a36bfSGatien Chevallier 	 */
191778a36bfSGatien Chevallier 	io_clrsetbits32(fmc_d->base + _FMC_RCFGLOCKR, _FMC_RCFGLOCKR_MASK,
192*b573873cSGatien Chevallier 			fmc_d->conf_data->lock_conf[0]);
193778a36bfSGatien Chevallier 
194778a36bfSGatien Chevallier 	if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) {
195778a36bfSGatien Chevallier 		/* Check that RIF config are applied, panic otherwise */
196778a36bfSGatien Chevallier 		if ((io_read32(fmc_d->base + _FMC_PRIVCFGR) &
197*b573873cSGatien Chevallier 		     fmc_d->conf_data->access_mask[0]) !=
198*b573873cSGatien Chevallier 		    fmc_d->conf_data->priv_conf[0]) {
199778a36bfSGatien Chevallier 			EMSG("FMC controller priv conf is incorrect");
200778a36bfSGatien Chevallier 			panic();
201778a36bfSGatien Chevallier 		}
202778a36bfSGatien Chevallier 
203778a36bfSGatien Chevallier 		if ((io_read32(fmc_d->base + _FMC_SECCFGR) &
204*b573873cSGatien Chevallier 		     fmc_d->conf_data->access_mask[0]) !=
205*b573873cSGatien Chevallier 		    fmc_d->conf_data->sec_conf[0]) {
206778a36bfSGatien Chevallier 			EMSG("FMC controller sec conf is incorrect");
207778a36bfSGatien Chevallier 			panic();
208778a36bfSGatien Chevallier 		}
209778a36bfSGatien Chevallier 	}
210778a36bfSGatien Chevallier 
211778a36bfSGatien Chevallier 	/* Disable the clock to allow RCC RIF re-configuration on this clock */
212778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
213778a36bfSGatien Chevallier 
214778a36bfSGatien Chevallier 	return TEE_SUCCESS;
215778a36bfSGatien Chevallier }
216778a36bfSGatien Chevallier 
217778a36bfSGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node)
218778a36bfSGatien Chevallier {
219778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
220778a36bfSGatien Chevallier 	struct dt_node_info info = { };
221*b573873cSGatien Chevallier 	const fdt32_t *cuint = NULL;
222778a36bfSGatien Chevallier 	struct io_pa_va addr = { };
223*b573873cSGatien Chevallier 	unsigned int i = 0;
224778a36bfSGatien Chevallier 	int ctrl_node = 0;
225*b573873cSGatien Chevallier 	int lenp = 0;
226778a36bfSGatien Chevallier 
227778a36bfSGatien Chevallier 	fdt_fill_device_info(fdt, &info, node);
228778a36bfSGatien Chevallier 	assert(info.reg != DT_INFO_INVALID_REG &&
229778a36bfSGatien Chevallier 	       info.reg_size != DT_INFO_INVALID_REG_SIZE);
230778a36bfSGatien Chevallier 
231778a36bfSGatien Chevallier 	addr.pa = info.reg;
232778a36bfSGatien Chevallier 	fmc_d->base = io_pa_or_va(&addr, info.reg_size);
233778a36bfSGatien Chevallier 
234778a36bfSGatien Chevallier 	res = clk_dt_get_by_index(fdt, node, 0, &fmc_d->fmc_clock);
235778a36bfSGatien Chevallier 	if (res)
236778a36bfSGatien Chevallier 		return res;
237778a36bfSGatien Chevallier 
238778a36bfSGatien Chevallier 	res = pinctrl_get_state_by_name(fdt, node, "default",
239778a36bfSGatien Chevallier 					&fmc_d->pinctrl_d);
240778a36bfSGatien Chevallier 	if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
241778a36bfSGatien Chevallier 		return res;
242778a36bfSGatien Chevallier 
243778a36bfSGatien Chevallier 	res = pinctrl_get_state_by_name(fdt, node, "sleep",
244778a36bfSGatien Chevallier 					&fmc_d->pinctrl_s);
245778a36bfSGatien Chevallier 	if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
246778a36bfSGatien Chevallier 		return res;
247778a36bfSGatien Chevallier 
248778a36bfSGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
249*b573873cSGatien Chevallier 	if (!cuint) {
250*b573873cSGatien Chevallier 		DMSG("No RIF configuration available");
251*b573873cSGatien Chevallier 		goto skip_rif;
252*b573873cSGatien Chevallier 	}
253*b573873cSGatien Chevallier 
254*b573873cSGatien Chevallier 	fmc_d->conf_data = calloc(1, sizeof(*fmc_d->conf_data));
255*b573873cSGatien Chevallier 	if (!fmc_d->conf_data)
256*b573873cSGatien Chevallier 		panic();
257778a36bfSGatien Chevallier 
258778a36bfSGatien Chevallier 	fmc_d->nb_controller = (unsigned int)(lenp / sizeof(uint32_t));
259778a36bfSGatien Chevallier 	assert(fmc_d->nb_controller <= FMC_RIF_CONTROLLERS);
260778a36bfSGatien Chevallier 
261*b573873cSGatien Chevallier 	fmc_d->conf_data->cid_confs = calloc(FMC_RIF_CONTROLLERS,
262778a36bfSGatien Chevallier 					     sizeof(uint32_t));
263*b573873cSGatien Chevallier 	fmc_d->conf_data->sec_conf = calloc(1, sizeof(uint32_t));
264*b573873cSGatien Chevallier 	fmc_d->conf_data->priv_conf = calloc(1, sizeof(uint32_t));
265*b573873cSGatien Chevallier 	fmc_d->conf_data->lock_conf = calloc(1, sizeof(uint32_t));
266*b573873cSGatien Chevallier 	fmc_d->conf_data->access_mask = calloc(1, sizeof(uint32_t));
267*b573873cSGatien Chevallier 	if (!fmc_d->conf_data->cid_confs || !fmc_d->conf_data->sec_conf ||
268*b573873cSGatien Chevallier 	    !fmc_d->conf_data->priv_conf || !fmc_d->conf_data->access_mask)
269*b573873cSGatien Chevallier 		panic("Missing memory capacity for FMC RIF configuration");
270778a36bfSGatien Chevallier 
271*b573873cSGatien Chevallier 	for (i = 0; i < fmc_d->nb_controller; i++)
272*b573873cSGatien Chevallier 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), fmc_d->conf_data,
273778a36bfSGatien Chevallier 				    FMC_RIF_CONTROLLERS);
274778a36bfSGatien Chevallier 
275*b573873cSGatien Chevallier skip_rif:
276778a36bfSGatien Chevallier 	fdt_for_each_subnode(ctrl_node, fdt, node) {
277778a36bfSGatien Chevallier 		int status = fdt_get_status(fdt, ctrl_node);
278778a36bfSGatien Chevallier 		uint32_t bank = 0;
279778a36bfSGatien Chevallier 
280778a36bfSGatien Chevallier 		if (status == DT_STATUS_DISABLED)
281778a36bfSGatien Chevallier 			continue;
282778a36bfSGatien Chevallier 
283778a36bfSGatien Chevallier 		if (fdt_read_uint32(fdt, ctrl_node, "reg", &bank) < 0)
284778a36bfSGatien Chevallier 			return TEE_ERROR_BAD_PARAMETERS;
285778a36bfSGatien Chevallier 
286778a36bfSGatien Chevallier 		if (bank != 0)
287778a36bfSGatien Chevallier 			continue;
288778a36bfSGatien Chevallier 
289778a36bfSGatien Chevallier 		if (fdt_getprop(fdt, ctrl_node,
290778a36bfSGatien Chevallier 				"st,fmc2-ebi-cs-cclk-enable", NULL))
291778a36bfSGatien Chevallier 			fmc_d->cclken = true;
292778a36bfSGatien Chevallier 
293778a36bfSGatien Chevallier 		if (!fmc_d->cclken)
294778a36bfSGatien Chevallier 			continue;
295778a36bfSGatien Chevallier 
296778a36bfSGatien Chevallier 		if (fdt_read_uint32(fdt, ctrl_node,
297778a36bfSGatien Chevallier 				    "st,fmc2-ebi-cs-clk-period-ns",
298778a36bfSGatien Chevallier 				    &fmc_d->clk_period_ns) < 0)
299778a36bfSGatien Chevallier 			return TEE_ERROR_BAD_PARAMETERS;
300778a36bfSGatien Chevallier 	}
301778a36bfSGatien Chevallier 
302778a36bfSGatien Chevallier 	return TEE_SUCCESS;
303778a36bfSGatien Chevallier }
304778a36bfSGatien Chevallier 
305778a36bfSGatien Chevallier static TEE_Result __maybe_unused check_fmc_rif_conf(void)
306778a36bfSGatien Chevallier {
307778a36bfSGatien Chevallier 	unsigned int i = 0;
308778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
309778a36bfSGatien Chevallier 
310778a36bfSGatien Chevallier 	res = clk_enable(fmc_d->fmc_clock);
311778a36bfSGatien Chevallier 	if (res)
312778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
313778a36bfSGatien Chevallier 
314778a36bfSGatien Chevallier 	if (fmc_controller_is_secure(0))
315778a36bfSGatien Chevallier 		goto end;
316778a36bfSGatien Chevallier 
317778a36bfSGatien Chevallier 	for (i = 1; i < fmc_d->nb_controller; i++) {
318778a36bfSGatien Chevallier 		uint32_t cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i));
319778a36bfSGatien Chevallier 		uint32_t semcr = io_read32(fmc_d->base + _FMC_SEMCR(i));
320778a36bfSGatien Chevallier 
321778a36bfSGatien Chevallier 		/* Check if a controller is secure */
322778a36bfSGatien Chevallier 		if (fmc_controller_is_secure(i)) {
323778a36bfSGatien Chevallier 			res = TEE_ERROR_BAD_STATE;
324778a36bfSGatien Chevallier 			goto end;
325778a36bfSGatien Chevallier 		}
326778a36bfSGatien Chevallier 
327778a36bfSGatien Chevallier 		/*
328778a36bfSGatien Chevallier 		 * Check if a controller is shared with incorrect CID
329778a36bfSGatien Chevallier 		 * (!= RIF_CID1)
330778a36bfSGatien Chevallier 		 */
331778a36bfSGatien Chevallier 		res = stm32_rif_check_access(cidcfgr, semcr,
332778a36bfSGatien Chevallier 					     FMC_NB_MAX_CID_SUPPORTED,
333778a36bfSGatien Chevallier 					     RIF_CID1);
334778a36bfSGatien Chevallier 		if (res)
335778a36bfSGatien Chevallier 			break;
336778a36bfSGatien Chevallier 	}
337778a36bfSGatien Chevallier 
338778a36bfSGatien Chevallier end:
339778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
340778a36bfSGatien Chevallier 
341778a36bfSGatien Chevallier 	return res;
342778a36bfSGatien Chevallier }
343778a36bfSGatien Chevallier 
344778a36bfSGatien Chevallier static void configure_fmc(void)
345778a36bfSGatien Chevallier {
346778a36bfSGatien Chevallier 	uint32_t cidcfgr = 0;
347778a36bfSGatien Chevallier 	uint32_t semcr = 0;
348778a36bfSGatien Chevallier 
349778a36bfSGatien Chevallier 	if (clk_enable(fmc_d->fmc_clock))
350778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
351778a36bfSGatien Chevallier 
352778a36bfSGatien Chevallier 	semcr = io_read32(fmc_d->base + _FMC_SEMCR(0));
353778a36bfSGatien Chevallier 	cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(0));
354778a36bfSGatien Chevallier 
355778a36bfSGatien Chevallier 	/*
356778a36bfSGatien Chevallier 	 * If OP-TEE doesn't have access to the controller 0,
357778a36bfSGatien Chevallier 	 * then we don't want to try to enable the FMC.
358778a36bfSGatien Chevallier 	 */
359778a36bfSGatien Chevallier 	if (stm32_rif_check_access(cidcfgr, semcr,
360778a36bfSGatien Chevallier 				   FMC_NB_MAX_CID_SUPPORTED, RIF_CID1))
361778a36bfSGatien Chevallier 		goto end;
362778a36bfSGatien Chevallier 
363778a36bfSGatien Chevallier 	/* Check controller 0 access */
364778a36bfSGatien Chevallier 	if (!fmc_controller_is_secure(0)) {
365778a36bfSGatien Chevallier 		DMSG("Controller 0 non-secure, FMC not enabled");
366778a36bfSGatien Chevallier 		goto end;
367778a36bfSGatien Chevallier 	}
368778a36bfSGatien Chevallier 
369778a36bfSGatien Chevallier 	if (cidcfgr & _CIDCFGR_SEMEN &&
370778a36bfSGatien Chevallier 	    stm32_rif_acquire_semaphore(fmc_d->base + _FMC_SEMCR(0),
371778a36bfSGatien Chevallier 					FMC_NB_MAX_CID_SUPPORTED))
372778a36bfSGatien Chevallier 		panic("Couldn't acquire controller 0 semaphore");
373778a36bfSGatien Chevallier 
374778a36bfSGatien Chevallier 	if (fmc_d->pinctrl_d && pinctrl_apply_state(fmc_d->pinctrl_d))
375778a36bfSGatien Chevallier 		panic("Could not apply FMC pinctrl");
376778a36bfSGatien Chevallier 
377778a36bfSGatien Chevallier 	if (fmc_d->cclken) {
378778a36bfSGatien Chevallier 		unsigned long hclk = clk_get_rate(fmc_d->fmc_clock);
379778a36bfSGatien Chevallier 		unsigned long hclkp = FMC_NSEC_PER_SEC / (hclk / 1000);
380778a36bfSGatien Chevallier 		unsigned long timing = DIV_ROUND_UP(fmc_d->clk_period_ns * 1000,
381778a36bfSGatien Chevallier 						    hclkp);
382778a36bfSGatien Chevallier 		uint32_t clk_div = SHIFT_U32(1, _FMC_CFGR_CLKDIV_SHIFT);
383778a36bfSGatien Chevallier 
384778a36bfSGatien Chevallier 		if (timing > 1) {
385778a36bfSGatien Chevallier 			timing--;
386778a36bfSGatien Chevallier 			if (timing >
387778a36bfSGatien Chevallier 			    _FMC_CFGR_CLKDIV_MASK >> _FMC_CFGR_CLKDIV_SHIFT)
388778a36bfSGatien Chevallier 				clk_div = _FMC_CFGR_CLKDIV_MASK;
389778a36bfSGatien Chevallier 			else
390778a36bfSGatien Chevallier 				clk_div = SHIFT_U32(timing,
391778a36bfSGatien Chevallier 						    _FMC_CFGR_CLKDIV_SHIFT);
392778a36bfSGatien Chevallier 		}
393778a36bfSGatien Chevallier 
394778a36bfSGatien Chevallier 		io_clrsetbits32(fmc_d->base + _FMC_CFGR,
395778a36bfSGatien Chevallier 				_FMC_CFGR_CLKDIV_MASK | _FMC_CFGR_CCLKEN,
396778a36bfSGatien Chevallier 				clk_div | _FMC_CFGR_CCLKEN);
397778a36bfSGatien Chevallier 	}
398778a36bfSGatien Chevallier 
399778a36bfSGatien Chevallier 	/* Set the FMC enable BIT */
400778a36bfSGatien Chevallier 	io_setbits32(fmc_d->base + _FMC_CFGR, _FMC_CFGR_ENABLE);
401778a36bfSGatien Chevallier 
402778a36bfSGatien Chevallier end:
403778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
404778a36bfSGatien Chevallier }
405778a36bfSGatien Chevallier 
406778a36bfSGatien Chevallier static void fmc_setup(void)
407778a36bfSGatien Chevallier {
408778a36bfSGatien Chevallier 	if (apply_rif_config())
409778a36bfSGatien Chevallier 		panic("Failed to apply rif_config");
410778a36bfSGatien Chevallier 
411778a36bfSGatien Chevallier 	/* Sanity check for FMC RIF config */
412778a36bfSGatien Chevallier 	assert(check_fmc_rif_conf());
413778a36bfSGatien Chevallier 
414778a36bfSGatien Chevallier 	configure_fmc();
415778a36bfSGatien Chevallier }
416778a36bfSGatien Chevallier 
417778a36bfSGatien Chevallier static void fmc_suspend(void)
418778a36bfSGatien Chevallier {
419778a36bfSGatien Chevallier 	unsigned int i = 0;
420778a36bfSGatien Chevallier 
421778a36bfSGatien Chevallier 	if (clk_enable(fmc_d->fmc_clock))
422778a36bfSGatien Chevallier 		panic("Cannot access FMC clock");
423778a36bfSGatien Chevallier 
424778a36bfSGatien Chevallier 	if (fmc_controller_is_secure(0) && fmc_d->pinctrl_s &&
425778a36bfSGatien Chevallier 	    pinctrl_apply_state(fmc_d->pinctrl_s))
426778a36bfSGatien Chevallier 		panic();
427778a36bfSGatien Chevallier 
428778a36bfSGatien Chevallier 	for (i = 0; i < FMC_RIF_CONTROLLERS; i++)
429*b573873cSGatien Chevallier 		fmc_d->conf_data->cid_confs[i] =
430778a36bfSGatien Chevallier 			io_read32(fmc_d->base + _FMC_CIDCFGR(i)) &
431778a36bfSGatien Chevallier 			_FMC_CIDCFGR_CONF_MASK;
432778a36bfSGatien Chevallier 
433*b573873cSGatien Chevallier 	fmc_d->conf_data->priv_conf[0] =
434778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_PRIVCFGR) & _FMC_PRIVCFGR_MASK;
435*b573873cSGatien Chevallier 	fmc_d->conf_data->sec_conf[0] =
436778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_SECCFGR) & _FMC_SECCFGR_MASK;
437*b573873cSGatien Chevallier 	fmc_d->conf_data->lock_conf[0] =
438778a36bfSGatien Chevallier 		io_read32(fmc_d->base + _FMC_RCFGLOCKR) & _FMC_RCFGLOCKR_MASK;
439*b573873cSGatien Chevallier 	fmc_d->conf_data->access_mask[0] =
440778a36bfSGatien Chevallier 		GENMASK_32(FMC_RIF_CONTROLLERS - 1, 0);
441778a36bfSGatien Chevallier 
442778a36bfSGatien Chevallier 	clk_disable(fmc_d->fmc_clock);
443778a36bfSGatien Chevallier }
444778a36bfSGatien Chevallier 
445778a36bfSGatien Chevallier static TEE_Result fmc_pm(enum pm_op op, unsigned int pm_hint,
446778a36bfSGatien Chevallier 			 const struct pm_callback_handle *pm_handle __unused)
447778a36bfSGatien Chevallier {
448778a36bfSGatien Chevallier 	if (pm_hint != PM_HINT_CONTEXT_STATE)
449778a36bfSGatien Chevallier 		return TEE_SUCCESS;
450778a36bfSGatien Chevallier 
451778a36bfSGatien Chevallier 	if (op == PM_OP_RESUME)
452778a36bfSGatien Chevallier 		fmc_setup();
453778a36bfSGatien Chevallier 	else
454778a36bfSGatien Chevallier 		fmc_suspend();
455778a36bfSGatien Chevallier 
456778a36bfSGatien Chevallier 	return TEE_SUCCESS;
457778a36bfSGatien Chevallier }
458778a36bfSGatien Chevallier 
459778a36bfSGatien Chevallier static TEE_Result fmc_probe(const void *fdt, int node,
460778a36bfSGatien Chevallier 			    const void *compat_data __unused)
461778a36bfSGatien Chevallier {
462778a36bfSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
463778a36bfSGatien Chevallier 
464778a36bfSGatien Chevallier 	fmc_d = calloc(1, sizeof(*fmc_d));
465778a36bfSGatien Chevallier 	if (!fmc_d)
466778a36bfSGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
467778a36bfSGatien Chevallier 
468778a36bfSGatien Chevallier 	res = parse_dt(fdt, node);
469778a36bfSGatien Chevallier 	if (res)
470778a36bfSGatien Chevallier 		goto err;
471778a36bfSGatien Chevallier 
472778a36bfSGatien Chevallier 	fmc_setup();
473778a36bfSGatien Chevallier 
474778a36bfSGatien Chevallier 	register_pm_core_service_cb(fmc_pm, NULL, "stm32-fmc");
475778a36bfSGatien Chevallier 
476778a36bfSGatien Chevallier 	return TEE_SUCCESS;
477778a36bfSGatien Chevallier err:
478778a36bfSGatien Chevallier 	/* Free all allocated resources */
479*b573873cSGatien Chevallier 	if (fmc_d->conf_data) {
480*b573873cSGatien Chevallier 		free(fmc_d->conf_data->access_mask);
481*b573873cSGatien Chevallier 		free(fmc_d->conf_data->cid_confs);
482*b573873cSGatien Chevallier 		free(fmc_d->conf_data->priv_conf);
483*b573873cSGatien Chevallier 		free(fmc_d->conf_data->sec_conf);
484*b573873cSGatien Chevallier 	}
485*b573873cSGatien Chevallier 	free(fmc_d->conf_data);
486778a36bfSGatien Chevallier 	free(fmc_d);
487778a36bfSGatien Chevallier 
488778a36bfSGatien Chevallier 	return res;
489778a36bfSGatien Chevallier }
490778a36bfSGatien Chevallier 
491778a36bfSGatien Chevallier static const struct dt_device_match stm32_fmc_match_table[] = {
492778a36bfSGatien Chevallier 	{ .compatible = "st,stm32mp25-fmc2-ebi" },
493778a36bfSGatien Chevallier 	{ }
494778a36bfSGatien Chevallier };
495778a36bfSGatien Chevallier 
496778a36bfSGatien Chevallier DEFINE_DT_DRIVER(stm32_fmc_dt_driver) = {
497778a36bfSGatien Chevallier 	.name = "stm32_fmc",
498778a36bfSGatien Chevallier 	.match_table = stm32_fmc_match_table,
499778a36bfSGatien Chevallier 	.probe = fmc_probe,
500778a36bfSGatien Chevallier };
501