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