1*ec9aa1a4SGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause 2*ec9aa1a4SGatien Chevallier /* 3*ec9aa1a4SGatien Chevallier * Copyright (c) 2022-2024, STMicroelectronics 4*ec9aa1a4SGatien Chevallier */ 5*ec9aa1a4SGatien Chevallier 6*ec9aa1a4SGatien Chevallier #include <arm.h> 7*ec9aa1a4SGatien Chevallier #include <config.h> 8*ec9aa1a4SGatien Chevallier #include <drivers/clk.h> 9*ec9aa1a4SGatien Chevallier #include <drivers/clk_dt.h> 10*ec9aa1a4SGatien Chevallier #include <drivers/stm32_rif.h> 11*ec9aa1a4SGatien Chevallier #include <io.h> 12*ec9aa1a4SGatien Chevallier #include <kernel/boot.h> 13*ec9aa1a4SGatien Chevallier #include <kernel/delay.h> 14*ec9aa1a4SGatien Chevallier #include <kernel/dt.h> 15*ec9aa1a4SGatien Chevallier #include <kernel/dt_driver.h> 16*ec9aa1a4SGatien Chevallier #include <kernel/panic.h> 17*ec9aa1a4SGatien Chevallier #include <libfdt.h> 18*ec9aa1a4SGatien Chevallier #include <mm/core_memprot.h> 19*ec9aa1a4SGatien Chevallier #include <stdbool.h> 20*ec9aa1a4SGatien Chevallier #include <stdlib.h> 21*ec9aa1a4SGatien Chevallier #include <stm32_util.h> 22*ec9aa1a4SGatien Chevallier #include <trace.h> 23*ec9aa1a4SGatien Chevallier 24*ec9aa1a4SGatien Chevallier #define HSEM_SECCFGR U(0x200) 25*ec9aa1a4SGatien Chevallier #define HSEM_PRIVCFGR U(0x210) 26*ec9aa1a4SGatien Chevallier #define HSEM_CnCIDCFGR(x) (U(0x220) + U(0x004) * ((x) - 1)) 27*ec9aa1a4SGatien Chevallier #define HSEM_GpCIDCFGR(x) (U(0x240) + U(0x004) * (x)) 28*ec9aa1a4SGatien Chevallier 29*ec9aa1a4SGatien Chevallier /* 30*ec9aa1a4SGatien Chevallier * CnCIDCFGR register bitfields 31*ec9aa1a4SGatien Chevallier */ 32*ec9aa1a4SGatien Chevallier #define HSEM_CnCIDCFGR_CONF_MASK (_CIDCFGR_CFEN | \ 33*ec9aa1a4SGatien Chevallier HSEM_CnCIDCFGR_SCID_MASK) 34*ec9aa1a4SGatien Chevallier #define HSEM_CnCIDCFGR_SCID_MASK GENMASK_32(6, 4) 35*ec9aa1a4SGatien Chevallier 36*ec9aa1a4SGatien Chevallier /* 37*ec9aa1a4SGatien Chevallier * GpCIDCFGR register bitfields 38*ec9aa1a4SGatien Chevallier */ 39*ec9aa1a4SGatien Chevallier #define HSEM_GpCIDCFGR_SEM_WLIST_C_MASK GENMASK_32(18, 16) 40*ec9aa1a4SGatien Chevallier #define HSEM_GpCIDCFGR_SEM_WLIST_SHIFT U(16) 41*ec9aa1a4SGatien Chevallier #define HSEM_GpCIDCFGR_CONF_MASK (_CIDCFGR_CFEN | \ 42*ec9aa1a4SGatien Chevallier HSEM_GpCIDCFGR_SEM_WLIST_C_MASK) 43*ec9aa1a4SGatien Chevallier 44*ec9aa1a4SGatien Chevallier /* 45*ec9aa1a4SGatien Chevallier * PRIVCFGR register bitfields 46*ec9aa1a4SGatien Chevallier */ 47*ec9aa1a4SGatien Chevallier #define HSEM_PRIVCFGR_MASK GENMASK_32(15, 0) 48*ec9aa1a4SGatien Chevallier 49*ec9aa1a4SGatien Chevallier /* 50*ec9aa1a4SGatien Chevallier * SECCFGR register bitfields 51*ec9aa1a4SGatien Chevallier */ 52*ec9aa1a4SGatien Chevallier #define HSEM_SECCFGR_MASK GENMASK_32(15, 0) 53*ec9aa1a4SGatien Chevallier 54*ec9aa1a4SGatien Chevallier /* 55*ec9aa1a4SGatien Chevallier * Miscellaneous 56*ec9aa1a4SGatien Chevallier */ 57*ec9aa1a4SGatien Chevallier #define HSEM_NB_PROC U(3) 58*ec9aa1a4SGatien Chevallier #define HSEM_NB_SEM_GROUPS U(4) 59*ec9aa1a4SGatien Chevallier #define HSEM_NB_SEM_PER_GROUP U(4) 60*ec9aa1a4SGatien Chevallier 61*ec9aa1a4SGatien Chevallier #define HSEM_NB_MAX_CID_SUPPORTED U(7) 62*ec9aa1a4SGatien Chevallier #define HSEM_RIF_RESOURCES U(16) 63*ec9aa1a4SGatien Chevallier 64*ec9aa1a4SGatien Chevallier struct hsem_pdata { 65*ec9aa1a4SGatien Chevallier struct clk *hsem_clock; 66*ec9aa1a4SGatien Chevallier struct rif_conf_data conf_data; 67*ec9aa1a4SGatien Chevallier unsigned int nb_channels; 68*ec9aa1a4SGatien Chevallier vaddr_t base; 69*ec9aa1a4SGatien Chevallier uint32_t *rif_proc_conf; 70*ec9aa1a4SGatien Chevallier }; 71*ec9aa1a4SGatien Chevallier 72*ec9aa1a4SGatien Chevallier static struct hsem_pdata *hsem_d; 73*ec9aa1a4SGatien Chevallier 74*ec9aa1a4SGatien Chevallier static void apply_rif_config(bool is_tdcid) 75*ec9aa1a4SGatien Chevallier { 76*ec9aa1a4SGatien Chevallier unsigned int i = 0; 77*ec9aa1a4SGatien Chevallier unsigned int j = 0; 78*ec9aa1a4SGatien Chevallier uint32_t prev_cid_value = 0; 79*ec9aa1a4SGatien Chevallier 80*ec9aa1a4SGatien Chevallier /* 81*ec9aa1a4SGatien Chevallier * When TDCID, OP-TEE should be the one to set the CID filtering 82*ec9aa1a4SGatien Chevallier * configuration. Clearing previous configuration prevents 83*ec9aa1a4SGatien Chevallier * undesired events during the only legitimate configuration. 84*ec9aa1a4SGatien Chevallier */ 85*ec9aa1a4SGatien Chevallier if (is_tdcid) { 86*ec9aa1a4SGatien Chevallier for (i = 0; i < HSEM_NB_PROC; i++) 87*ec9aa1a4SGatien Chevallier io_clrbits32(hsem_d->base + HSEM_CnCIDCFGR(i + 1), 88*ec9aa1a4SGatien Chevallier HSEM_CnCIDCFGR_CONF_MASK); 89*ec9aa1a4SGatien Chevallier 90*ec9aa1a4SGatien Chevallier /* Clean HSEM groups configuration registers */ 91*ec9aa1a4SGatien Chevallier for (i = 0; i < HSEM_NB_SEM_GROUPS; i++) 92*ec9aa1a4SGatien Chevallier io_clrbits32(hsem_d->base + HSEM_GpCIDCFGR(i), 93*ec9aa1a4SGatien Chevallier HSEM_GpCIDCFGR_CONF_MASK); 94*ec9aa1a4SGatien Chevallier } 95*ec9aa1a4SGatien Chevallier 96*ec9aa1a4SGatien Chevallier /* Security and privilege RIF configuration */ 97*ec9aa1a4SGatien Chevallier io_clrsetbits32(hsem_d->base + HSEM_SECCFGR, 98*ec9aa1a4SGatien Chevallier HSEM_SECCFGR_MASK & hsem_d->conf_data.access_mask[0], 99*ec9aa1a4SGatien Chevallier hsem_d->conf_data.sec_conf[0]); 100*ec9aa1a4SGatien Chevallier io_clrsetbits32(hsem_d->base + HSEM_PRIVCFGR, 101*ec9aa1a4SGatien Chevallier HSEM_PRIVCFGR_MASK & hsem_d->conf_data.access_mask[0], 102*ec9aa1a4SGatien Chevallier hsem_d->conf_data.priv_conf[0]); 103*ec9aa1a4SGatien Chevallier 104*ec9aa1a4SGatien Chevallier if (!is_tdcid) 105*ec9aa1a4SGatien Chevallier return; 106*ec9aa1a4SGatien Chevallier 107*ec9aa1a4SGatien Chevallier /* Configure HSEM processors configuration registers */ 108*ec9aa1a4SGatien Chevallier for (i = 0; i < HSEM_NB_PROC; i++) { 109*ec9aa1a4SGatien Chevallier /* 110*ec9aa1a4SGatien Chevallier * If a processor CID configuration is present, enable it. 111*ec9aa1a4SGatien Chevallier * Else, nothing to do. 112*ec9aa1a4SGatien Chevallier */ 113*ec9aa1a4SGatien Chevallier if (!hsem_d->rif_proc_conf[i]) 114*ec9aa1a4SGatien Chevallier continue; 115*ec9aa1a4SGatien Chevallier 116*ec9aa1a4SGatien Chevallier io_clrsetbits32(hsem_d->base + HSEM_CnCIDCFGR(i + 1), 117*ec9aa1a4SGatien Chevallier HSEM_CnCIDCFGR_CONF_MASK, 118*ec9aa1a4SGatien Chevallier _CIDCFGR_CFEN | hsem_d->rif_proc_conf[i]); 119*ec9aa1a4SGatien Chevallier } 120*ec9aa1a4SGatien Chevallier 121*ec9aa1a4SGatien Chevallier /* 122*ec9aa1a4SGatien Chevallier * Configure HSEM groups configuration registers 123*ec9aa1a4SGatien Chevallier * If one semaphore is configured, all semaphores of its group 124*ec9aa1a4SGatien Chevallier * must be configured too and MUST have the same RIF 125*ec9aa1a4SGatien Chevallier * configuration. 126*ec9aa1a4SGatien Chevallier */ 127*ec9aa1a4SGatien Chevallier for (i = 0; i < HSEM_NB_SEM_GROUPS; i++) { 128*ec9aa1a4SGatien Chevallier unsigned int hsem_idx = i * HSEM_NB_SEM_PER_GROUP; 129*ec9aa1a4SGatien Chevallier unsigned int hsem_cid = 0; 130*ec9aa1a4SGatien Chevallier unsigned int known_cid_idx = 0; 131*ec9aa1a4SGatien Chevallier 132*ec9aa1a4SGatien Chevallier prev_cid_value = hsem_d->conf_data.cid_confs[hsem_idx]; 133*ec9aa1a4SGatien Chevallier 134*ec9aa1a4SGatien Chevallier /* If CID filtering is disabled, do nothing */ 135*ec9aa1a4SGatien Chevallier if (!(prev_cid_value & _CIDCFGR_CFEN)) 136*ec9aa1a4SGatien Chevallier continue; 137*ec9aa1a4SGatien Chevallier 138*ec9aa1a4SGatien Chevallier /* 139*ec9aa1a4SGatien Chevallier * Check if configured CID corresponds to a processor's 140*ec9aa1a4SGatien Chevallier * CID in HSEM_CnCIDCFGR. 141*ec9aa1a4SGatien Chevallier */ 142*ec9aa1a4SGatien Chevallier for (j = 0; j < HSEM_NB_PROC; j++) { 143*ec9aa1a4SGatien Chevallier uint32_t proc_cid = hsem_d->rif_proc_conf[j]; 144*ec9aa1a4SGatien Chevallier 145*ec9aa1a4SGatien Chevallier hsem_cid = (prev_cid_value & HSEM_CnCIDCFGR_SCID_MASK); 146*ec9aa1a4SGatien Chevallier DMSG("hsem_cid %u", hsem_cid); 147*ec9aa1a4SGatien Chevallier DMSG("proc_cid %u", proc_cid); 148*ec9aa1a4SGatien Chevallier if (proc_cid == hsem_cid) { 149*ec9aa1a4SGatien Chevallier known_cid_idx = BIT(j + 150*ec9aa1a4SGatien Chevallier HSEM_GpCIDCFGR_SEM_WLIST_SHIFT); 151*ec9aa1a4SGatien Chevallier break; 152*ec9aa1a4SGatien Chevallier } 153*ec9aa1a4SGatien Chevallier } 154*ec9aa1a4SGatien Chevallier if (!known_cid_idx) 155*ec9aa1a4SGatien Chevallier panic("Unknown HSEM processor CID"); 156*ec9aa1a4SGatien Chevallier 157*ec9aa1a4SGatien Chevallier /* 158*ec9aa1a4SGatien Chevallier * HSEM resources in the same group must have the same CID 159*ec9aa1a4SGatien Chevallier * filtering configuration. Else it is inconsistent. 160*ec9aa1a4SGatien Chevallier */ 161*ec9aa1a4SGatien Chevallier for (j = 0; j < HSEM_NB_SEM_PER_GROUP; j++) 162*ec9aa1a4SGatien Chevallier if (hsem_d->conf_data.cid_confs[j + hsem_idx] != 163*ec9aa1a4SGatien Chevallier prev_cid_value) 164*ec9aa1a4SGatien Chevallier panic("Inconsistent HSEM RIF group config"); 165*ec9aa1a4SGatien Chevallier 166*ec9aa1a4SGatien Chevallier io_clrsetbits32(hsem_d->base + HSEM_GpCIDCFGR(i), 167*ec9aa1a4SGatien Chevallier HSEM_GpCIDCFGR_CONF_MASK, 168*ec9aa1a4SGatien Chevallier _CIDCFGR_CFEN | known_cid_idx); 169*ec9aa1a4SGatien Chevallier } 170*ec9aa1a4SGatien Chevallier } 171*ec9aa1a4SGatien Chevallier 172*ec9aa1a4SGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node) 173*ec9aa1a4SGatien Chevallier { 174*ec9aa1a4SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 175*ec9aa1a4SGatien Chevallier unsigned int i = 0; 176*ec9aa1a4SGatien Chevallier int lenp = 0; 177*ec9aa1a4SGatien Chevallier const fdt32_t *cuint = NULL; 178*ec9aa1a4SGatien Chevallier struct dt_node_info info = { }; 179*ec9aa1a4SGatien Chevallier struct io_pa_va addr = { }; 180*ec9aa1a4SGatien Chevallier 181*ec9aa1a4SGatien Chevallier fdt_fill_device_info(fdt, &info, node); 182*ec9aa1a4SGatien Chevallier assert(info.reg != DT_INFO_INVALID_REG && 183*ec9aa1a4SGatien Chevallier info.reg_size != DT_INFO_INVALID_REG_SIZE); 184*ec9aa1a4SGatien Chevallier 185*ec9aa1a4SGatien Chevallier addr.pa = info.reg; 186*ec9aa1a4SGatien Chevallier hsem_d->base = io_pa_or_va_secure(&addr, info.reg_size); 187*ec9aa1a4SGatien Chevallier 188*ec9aa1a4SGatien Chevallier /* Gate the IP */ 189*ec9aa1a4SGatien Chevallier res = clk_dt_get_by_index(fdt, node, 0, &hsem_d->hsem_clock); 190*ec9aa1a4SGatien Chevallier if (res) 191*ec9aa1a4SGatien Chevallier return res; 192*ec9aa1a4SGatien Chevallier 193*ec9aa1a4SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,protreg", &lenp); 194*ec9aa1a4SGatien Chevallier if (!cuint) 195*ec9aa1a4SGatien Chevallier panic("No RIF configuration available"); 196*ec9aa1a4SGatien Chevallier 197*ec9aa1a4SGatien Chevallier hsem_d->nb_channels = (unsigned int)(lenp / sizeof(uint32_t)); 198*ec9aa1a4SGatien Chevallier assert(hsem_d->nb_channels <= HSEM_RIF_RESOURCES); 199*ec9aa1a4SGatien Chevallier 200*ec9aa1a4SGatien Chevallier hsem_d->rif_proc_conf = calloc(HSEM_NB_PROC, sizeof(uint32_t)); 201*ec9aa1a4SGatien Chevallier assert(hsem_d->rif_proc_conf); 202*ec9aa1a4SGatien Chevallier hsem_d->conf_data.cid_confs = calloc(HSEM_RIF_RESOURCES, 203*ec9aa1a4SGatien Chevallier sizeof(uint32_t)); 204*ec9aa1a4SGatien Chevallier hsem_d->conf_data.sec_conf = calloc(1, sizeof(uint32_t)); 205*ec9aa1a4SGatien Chevallier hsem_d->conf_data.priv_conf = calloc(1, sizeof(uint32_t)); 206*ec9aa1a4SGatien Chevallier hsem_d->conf_data.access_mask = calloc(1, sizeof(uint32_t)); 207*ec9aa1a4SGatien Chevallier assert(hsem_d->conf_data.cid_confs && hsem_d->conf_data.sec_conf && 208*ec9aa1a4SGatien Chevallier hsem_d->conf_data.priv_conf && hsem_d->conf_data.access_mask); 209*ec9aa1a4SGatien Chevallier 210*ec9aa1a4SGatien Chevallier for (i = 0; i < hsem_d->nb_channels; i++) 211*ec9aa1a4SGatien Chevallier stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), &hsem_d->conf_data, 212*ec9aa1a4SGatien Chevallier HSEM_NB_MAX_CID_SUPPORTED, 213*ec9aa1a4SGatien Chevallier HSEM_RIF_RESOURCES); 214*ec9aa1a4SGatien Chevallier 215*ec9aa1a4SGatien Chevallier cuint = fdt_getprop(fdt, node, "st,proccid", &lenp); 216*ec9aa1a4SGatien Chevallier if (!cuint) 217*ec9aa1a4SGatien Chevallier panic("No RIF proc configuration available"); 218*ec9aa1a4SGatien Chevallier 219*ec9aa1a4SGatien Chevallier lenp = (unsigned int)(lenp / sizeof(uint32_t)); 220*ec9aa1a4SGatien Chevallier /* 221*ec9aa1a4SGatien Chevallier * There should be maximum (HSEM_NB_PROC * 2) property argument. 222*ec9aa1a4SGatien Chevallier * First argument for a processor is its number, the second is its CID. 223*ec9aa1a4SGatien Chevallier */ 224*ec9aa1a4SGatien Chevallier assert((unsigned int)lenp <= (HSEM_NB_PROC * 2)); 225*ec9aa1a4SGatien Chevallier 226*ec9aa1a4SGatien Chevallier for (i = 0; i < (unsigned int)lenp / 2; i++) { 227*ec9aa1a4SGatien Chevallier unsigned int pos = fdt32_to_cpu(cuint[i * 2]) - 1; 228*ec9aa1a4SGatien Chevallier unsigned int cid_value = fdt32_to_cpu(cuint[(i * 2) + 1]); 229*ec9aa1a4SGatien Chevallier 230*ec9aa1a4SGatien Chevallier hsem_d->rif_proc_conf[pos] = SHIFT_U32(cid_value, SCID_SHIFT); 231*ec9aa1a4SGatien Chevallier } 232*ec9aa1a4SGatien Chevallier 233*ec9aa1a4SGatien Chevallier return TEE_SUCCESS; 234*ec9aa1a4SGatien Chevallier } 235*ec9aa1a4SGatien Chevallier 236*ec9aa1a4SGatien Chevallier static TEE_Result stm32_hsem_probe(const void *fdt, int node, 237*ec9aa1a4SGatien Chevallier const void *compat_data __unused) 238*ec9aa1a4SGatien Chevallier { 239*ec9aa1a4SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC; 240*ec9aa1a4SGatien Chevallier bool is_tdcid = false; 241*ec9aa1a4SGatien Chevallier 242*ec9aa1a4SGatien Chevallier res = stm32_rifsc_check_tdcid(&is_tdcid); 243*ec9aa1a4SGatien Chevallier if (res) 244*ec9aa1a4SGatien Chevallier return res; 245*ec9aa1a4SGatien Chevallier 246*ec9aa1a4SGatien Chevallier hsem_d = calloc(1, sizeof(*hsem_d)); 247*ec9aa1a4SGatien Chevallier if (!hsem_d) 248*ec9aa1a4SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY; 249*ec9aa1a4SGatien Chevallier 250*ec9aa1a4SGatien Chevallier res = parse_dt(fdt, node); 251*ec9aa1a4SGatien Chevallier if (res) 252*ec9aa1a4SGatien Chevallier return res; 253*ec9aa1a4SGatien Chevallier 254*ec9aa1a4SGatien Chevallier res = clk_enable(hsem_d->hsem_clock); 255*ec9aa1a4SGatien Chevallier if (res) 256*ec9aa1a4SGatien Chevallier panic("Cannot access HSEM clock"); 257*ec9aa1a4SGatien Chevallier 258*ec9aa1a4SGatien Chevallier apply_rif_config(is_tdcid); 259*ec9aa1a4SGatien Chevallier 260*ec9aa1a4SGatien Chevallier clk_disable(hsem_d->hsem_clock); 261*ec9aa1a4SGatien Chevallier 262*ec9aa1a4SGatien Chevallier return TEE_SUCCESS; 263*ec9aa1a4SGatien Chevallier } 264*ec9aa1a4SGatien Chevallier 265*ec9aa1a4SGatien Chevallier static const struct dt_device_match stm32_hsem_match_table[] = { 266*ec9aa1a4SGatien Chevallier { .compatible = "st,stm32mp25-hsem" }, 267*ec9aa1a4SGatien Chevallier { } 268*ec9aa1a4SGatien Chevallier }; 269*ec9aa1a4SGatien Chevallier 270*ec9aa1a4SGatien Chevallier DEFINE_DT_DRIVER(stm32_hsem_dt_driver) = { 271*ec9aa1a4SGatien Chevallier .name = "st,stm32-hsem", 272*ec9aa1a4SGatien Chevallier .match_table = stm32_hsem_match_table, 273*ec9aa1a4SGatien Chevallier .probe = stm32_hsem_probe, 274*ec9aa1a4SGatien Chevallier }; 275