// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (c) 2021-2024, STMicroelectronics */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _FMC_CFGR U(0x020) #define _FMC_SECCFGR U(0x300) #define _FMC_PRIVCFGR U(0x304) #define _FMC_RCFGLOCKR U(0x308) #define _FMC_CIDCFGR(x) (U(0x30C) + U(0x8) * (x)) #define _FMC_SEMCR(x) (U(0x310) + U(0x8) * (x)) /* * CFGR register bitfields */ #define _FMC_CFGR_CLKDIV_MASK GENMASK_32(19, 16) #define _FMC_CFGR_CLKDIV_SHIFT U(16) #define _FMC_CFGR_CCLKEN BIT(20) #define _FMC_CFGR_ENABLE BIT(31) /* * CIDCFGR register bitfields */ #define _FMC_CIDCFGR_SEMWL_MASK GENMASK_32(23, 16) #define _FMC_CIDCFGR_SCID_MASK GENMASK_32(6, 4) #define _FMC_CIDCFGR_CONF_MASK (_CIDCFGR_CFEN | \ _CIDCFGR_SEMEN | \ _FMC_CIDCFGR_SCID_MASK |\ _FMC_CIDCFGR_SEMWL_MASK) /* * PRIVCFGR register bitfields */ #define _FMC_PRIVCFGR_MASK GENMASK_32(5, 0) /* * RCFGLOCKR register bitfields */ #define _FMC_RCFGLOCKR_MASK GENMASK_32(5, 0) /* * SECCFGR register bitfields */ #define _FMC_SECCFGR_EN BIT(0) #define _FMC_SECCFGR_MASK GENMASK_32(5, 0) /* * SEMCR register bitfields */ #define _FMC_SEMCR_SCID_MASK GENMASK_32(7, 5) #define _FMC_SEMCR_SCID_SHIFT U(5) /* * Miscellaneous */ #define FMC_RIF_CONTROLLERS U(6) #define FMC_NSEC_PER_SEC UL(1000000000) struct fmc_pdata { struct clk *fmc_clock; struct pinctrl_state *pinctrl_d; struct pinctrl_state *pinctrl_s; struct rif_conf_data *conf_data; unsigned int nb_controller; vaddr_t base; uint32_t clk_period_ns; bool is_tdcid; bool cclken; }; static struct fmc_pdata *fmc_d; static bool fmc_controller_is_secure(uint8_t controller) { return io_read32(fmc_d->base + _FMC_SECCFGR) & BIT(controller); } static TEE_Result handle_available_semaphores(void) { TEE_Result res = TEE_ERROR_GENERIC; uint32_t cidcfgr = 0; unsigned int i = 0; for (i = 0; i < FMC_RIF_CONTROLLERS; i++) { if (!(BIT(i) & fmc_d->conf_data->access_mask[0])) continue; cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i)); if (!stm32_rif_semaphore_enabled_and_ok(cidcfgr, RIF_CID1)) continue; if (!(io_read32(fmc_d->base + _FMC_SECCFGR) & BIT(i))) { res = stm32_rif_release_semaphore(fmc_d->base + _FMC_SEMCR(i), MAX_CID_SUPPORTED); if (res) { EMSG("Cannot release semaphore for resource %u", i); return res; } } else { res = stm32_rif_acquire_semaphore(fmc_d->base + _FMC_SEMCR(i), MAX_CID_SUPPORTED); if (res) { EMSG("Cannot acquire semaphore for resource %u", i); return res; } } } return TEE_SUCCESS; } static TEE_Result apply_rif_config(void) { TEE_Result res = TEE_ERROR_ACCESS_DENIED; unsigned int i = 0; if (!fmc_d->conf_data) return TEE_SUCCESS; res = clk_enable(fmc_d->fmc_clock); if (res) panic("Cannot access FMC clock"); if (fmc_d->is_tdcid) { for (i = 0; i < FMC_RIF_CONTROLLERS; i++) { if (!(BIT(i) & fmc_d->conf_data->access_mask[0])) continue; /* * When TDCID, OP-TEE should be the one to set the CID * filtering configuration. Clearing previous * configuration prevents undesired events during the * only legitimate configuration. */ io_clrbits32(fmc_d->base + _FMC_CIDCFGR(i), _FMC_CIDCFGR_CONF_MASK); } } else { res = handle_available_semaphores(); if (res) panic(); } /* Security and privilege RIF configuration */ io_clrsetbits32(fmc_d->base + _FMC_PRIVCFGR, _FMC_PRIVCFGR_MASK, fmc_d->conf_data->priv_conf[0]); io_clrsetbits32(fmc_d->base + _FMC_SECCFGR, _FMC_SECCFGR_MASK, fmc_d->conf_data->sec_conf[0]); if (!fmc_d->is_tdcid) goto out; for (i = 0; i < FMC_RIF_CONTROLLERS; i++) { if (!(BIT(i) & fmc_d->conf_data->access_mask[0])) continue; io_clrsetbits32(fmc_d->base + _FMC_CIDCFGR(i), _FMC_CIDCFGR_CONF_MASK, fmc_d->conf_data->cid_confs[i]); } /* * Lock RIF configuration if configured. This cannot be undone until * next reset. */ io_setbits32(fmc_d->base + _FMC_RCFGLOCKR, fmc_d->conf_data->lock_conf[0]); res = handle_available_semaphores(); if (res) panic(); out: if (IS_ENABLED(CFG_TEE_CORE_DEBUG)) { /* Check that RIF config are applied, panic otherwise */ if ((io_read32(fmc_d->base + _FMC_PRIVCFGR) & fmc_d->conf_data->access_mask[0]) != fmc_d->conf_data->priv_conf[0]) { EMSG("FMC controller priv conf is incorrect"); panic(); } if ((io_read32(fmc_d->base + _FMC_SECCFGR) & fmc_d->conf_data->access_mask[0]) != fmc_d->conf_data->sec_conf[0]) { EMSG("FMC controller sec conf is incorrect"); panic(); } } /* Disable the clock to allow RCC RIF re-configuration on this clock */ clk_disable(fmc_d->fmc_clock); return TEE_SUCCESS; } static TEE_Result parse_dt(const void *fdt, int node) { TEE_Result res = TEE_ERROR_GENERIC; struct dt_node_info info = { }; const fdt32_t *cuint = NULL; struct io_pa_va addr = { }; unsigned int i = 0; int ctrl_node = 0; int lenp = 0; fdt_fill_device_info(fdt, &info, node); assert(info.reg != DT_INFO_INVALID_REG && info.reg_size != DT_INFO_INVALID_REG_SIZE); addr.pa = info.reg; fmc_d->base = io_pa_or_va(&addr, info.reg_size); res = clk_dt_get_by_index(fdt, node, 0, &fmc_d->fmc_clock); if (res) return res; res = pinctrl_get_state_by_name(fdt, node, "default", &fmc_d->pinctrl_d); if (res && res != TEE_ERROR_ITEM_NOT_FOUND) return res; res = pinctrl_get_state_by_name(fdt, node, "sleep", &fmc_d->pinctrl_s); if (res && res != TEE_ERROR_ITEM_NOT_FOUND) return res; cuint = fdt_getprop(fdt, node, "st,protreg", &lenp); if (!cuint) { DMSG("No RIF configuration available"); goto skip_rif; } fmc_d->conf_data = calloc(1, sizeof(*fmc_d->conf_data)); if (!fmc_d->conf_data) panic(); fmc_d->nb_controller = (unsigned int)(lenp / sizeof(uint32_t)); assert(fmc_d->nb_controller <= FMC_RIF_CONTROLLERS); fmc_d->conf_data->cid_confs = calloc(FMC_RIF_CONTROLLERS, sizeof(uint32_t)); fmc_d->conf_data->sec_conf = calloc(1, sizeof(uint32_t)); fmc_d->conf_data->priv_conf = calloc(1, sizeof(uint32_t)); fmc_d->conf_data->lock_conf = calloc(1, sizeof(uint32_t)); fmc_d->conf_data->access_mask = calloc(1, sizeof(uint32_t)); if (!fmc_d->conf_data->cid_confs || !fmc_d->conf_data->sec_conf || !fmc_d->conf_data->priv_conf || !fmc_d->conf_data->access_mask) panic("Missing memory capacity for FMC RIF configuration"); for (i = 0; i < fmc_d->nb_controller; i++) stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), fmc_d->conf_data, FMC_RIF_CONTROLLERS); skip_rif: fdt_for_each_subnode(ctrl_node, fdt, node) { int status = fdt_get_status(fdt, ctrl_node); uint32_t bank = 0; if (status == DT_STATUS_DISABLED) continue; if (fdt_read_uint32(fdt, ctrl_node, "reg", &bank) < 0) return TEE_ERROR_BAD_PARAMETERS; if (bank != 0) continue; if (fdt_getprop(fdt, ctrl_node, "st,fmc2-ebi-cs-cclk-enable", NULL)) fmc_d->cclken = true; if (!fmc_d->cclken) continue; if (fdt_read_uint32(fdt, ctrl_node, "st,fmc2-ebi-cs-clk-period-ns", &fmc_d->clk_period_ns) < 0) return TEE_ERROR_BAD_PARAMETERS; } return TEE_SUCCESS; } static TEE_Result __maybe_unused check_fmc_rif_conf(void) { unsigned int i = 0; TEE_Result res = TEE_ERROR_GENERIC; res = clk_enable(fmc_d->fmc_clock); if (res) panic("Cannot access FMC clock"); if (fmc_controller_is_secure(0)) { res = TEE_SUCCESS; goto end; } for (i = 1; i < fmc_d->nb_controller; i++) { uint32_t cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(i)); uint32_t semcr = io_read32(fmc_d->base + _FMC_SEMCR(i)); /* Check if a controller is secure */ if (fmc_controller_is_secure(i)) { res = TEE_ERROR_BAD_STATE; goto end; } /* * Check if a controller is shared with incorrect CID * (!= RIF_CID1) */ res = stm32_rif_check_access(cidcfgr, semcr, MAX_CID_SUPPORTED, RIF_CID1); if (res) break; } end: clk_disable(fmc_d->fmc_clock); return res; } static void configure_fmc(void) { uint32_t cidcfgr = 0; uint32_t semcr = 0; if (clk_enable(fmc_d->fmc_clock)) panic("Cannot access FMC clock"); semcr = io_read32(fmc_d->base + _FMC_SEMCR(0)); cidcfgr = io_read32(fmc_d->base + _FMC_CIDCFGR(0)); /* * If OP-TEE doesn't have access to the controller 0, * then we don't want to try to enable the FMC. */ if (stm32_rif_check_access(cidcfgr, semcr, MAX_CID_SUPPORTED, RIF_CID1)) goto end; /* Check controller 0 access */ if (!fmc_controller_is_secure(0)) { DMSG("Controller 0 non-secure, FMC not enabled"); goto end; } if (cidcfgr & _CIDCFGR_SEMEN && stm32_rif_acquire_semaphore(fmc_d->base + _FMC_SEMCR(0), MAX_CID_SUPPORTED)) panic("Couldn't acquire controller 0 semaphore"); if (fmc_d->pinctrl_d && pinctrl_apply_state(fmc_d->pinctrl_d)) panic("Could not apply FMC pinctrl"); if (fmc_d->cclken) { unsigned long hclk = clk_get_rate(fmc_d->fmc_clock); unsigned long hclkp = FMC_NSEC_PER_SEC / (hclk / 1000); unsigned long timing = DIV_ROUND_UP(fmc_d->clk_period_ns * 1000, hclkp); uint32_t clk_div = SHIFT_U32(1, _FMC_CFGR_CLKDIV_SHIFT); if (timing > 1) { timing--; if (timing > _FMC_CFGR_CLKDIV_MASK >> _FMC_CFGR_CLKDIV_SHIFT) clk_div = _FMC_CFGR_CLKDIV_MASK; else clk_div = SHIFT_U32(timing, _FMC_CFGR_CLKDIV_SHIFT); } io_clrsetbits32(fmc_d->base + _FMC_CFGR, _FMC_CFGR_CLKDIV_MASK | _FMC_CFGR_CCLKEN, clk_div | _FMC_CFGR_CCLKEN); } /* Set the FMC enable BIT */ io_setbits32(fmc_d->base + _FMC_CFGR, _FMC_CFGR_ENABLE); end: clk_disable(fmc_d->fmc_clock); } static void fmc_setup(void) { if (apply_rif_config()) panic("Failed to apply rif_config"); /* Sanity check for FMC RIF config */ assert(!check_fmc_rif_conf()); configure_fmc(); } static void fmc_suspend(void) { unsigned int i = 0; if (clk_enable(fmc_d->fmc_clock)) panic("Cannot access FMC clock"); if (fmc_controller_is_secure(0) && fmc_d->pinctrl_s && pinctrl_apply_state(fmc_d->pinctrl_s)) panic(); for (i = 0; i < FMC_RIF_CONTROLLERS; i++) fmc_d->conf_data->cid_confs[i] = io_read32(fmc_d->base + _FMC_CIDCFGR(i)) & _FMC_CIDCFGR_CONF_MASK; fmc_d->conf_data->priv_conf[0] = io_read32(fmc_d->base + _FMC_PRIVCFGR) & _FMC_PRIVCFGR_MASK; fmc_d->conf_data->sec_conf[0] = io_read32(fmc_d->base + _FMC_SECCFGR) & _FMC_SECCFGR_MASK; fmc_d->conf_data->lock_conf[0] = io_read32(fmc_d->base + _FMC_RCFGLOCKR) & _FMC_RCFGLOCKR_MASK; fmc_d->conf_data->access_mask[0] = GENMASK_32(FMC_RIF_CONTROLLERS - 1, 0); clk_disable(fmc_d->fmc_clock); } static TEE_Result fmc_pm(enum pm_op op, unsigned int pm_hint, const struct pm_callback_handle *pm_handle __unused) { if (!PM_HINT_IS_STATE(pm_hint, CONTEXT)) return TEE_SUCCESS; if (op == PM_OP_RESUME) fmc_setup(); else fmc_suspend(); return TEE_SUCCESS; } static TEE_Result fmc_probe(const void *fdt, int node, const void *compat_data __unused) { TEE_Result res = TEE_ERROR_GENERIC; fmc_d = calloc(1, sizeof(*fmc_d)); if (!fmc_d) return TEE_ERROR_OUT_OF_MEMORY; res = stm32_rifsc_check_tdcid(&fmc_d->is_tdcid); if (res) { free(fmc_d); return res; } res = parse_dt(fdt, node); if (res) goto err; fmc_setup(); register_pm_core_service_cb(fmc_pm, NULL, "stm32-fmc"); return TEE_SUCCESS; err: /* Free all allocated resources */ if (fmc_d->conf_data) { free(fmc_d->conf_data->access_mask); free(fmc_d->conf_data->cid_confs); free(fmc_d->conf_data->priv_conf); free(fmc_d->conf_data->sec_conf); } free(fmc_d->conf_data); free(fmc_d); return res; } static const struct dt_device_match stm32_fmc_match_table[] = { { .compatible = "st,stm32mp25-fmc2-ebi" }, { } }; DEFINE_DT_DRIVER(stm32_fmc_dt_driver) = { .name = "stm32_fmc", .match_table = stm32_fmc_match_table, .probe = fmc_probe, };