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