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