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_NB_MAX_CID_SUPPORTED U(7) 62 #define HSEM_RIF_RESOURCES U(16) 63 64 struct hsem_pdata { 65 struct clk *hsem_clock; 66 struct rif_conf_data conf_data; 67 unsigned int nb_channels; 68 vaddr_t base; 69 uint32_t *rif_proc_conf; 70 }; 71 72 static struct hsem_pdata *hsem_d; 73 74 static void apply_rif_config(bool is_tdcid) 75 { 76 unsigned int i = 0; 77 unsigned int j = 0; 78 uint32_t prev_cid_value = 0; 79 80 /* 81 * When TDCID, OP-TEE should be the one to set the CID filtering 82 * configuration. Clearing previous configuration prevents 83 * undesired events during the only legitimate configuration. 84 */ 85 if (is_tdcid) { 86 for (i = 0; i < HSEM_NB_PROC; i++) 87 io_clrbits32(hsem_d->base + HSEM_CnCIDCFGR(i + 1), 88 HSEM_CnCIDCFGR_CONF_MASK); 89 90 /* Clean HSEM groups configuration registers */ 91 for (i = 0; i < HSEM_NB_SEM_GROUPS; i++) 92 io_clrbits32(hsem_d->base + HSEM_GpCIDCFGR(i), 93 HSEM_GpCIDCFGR_CONF_MASK); 94 } 95 96 /* Security and privilege RIF configuration */ 97 io_clrsetbits32(hsem_d->base + HSEM_SECCFGR, 98 HSEM_SECCFGR_MASK & hsem_d->conf_data.access_mask[0], 99 hsem_d->conf_data.sec_conf[0]); 100 io_clrsetbits32(hsem_d->base + HSEM_PRIVCFGR, 101 HSEM_PRIVCFGR_MASK & hsem_d->conf_data.access_mask[0], 102 hsem_d->conf_data.priv_conf[0]); 103 104 if (!is_tdcid) 105 return; 106 107 /* Configure HSEM processors configuration registers */ 108 for (i = 0; i < HSEM_NB_PROC; i++) { 109 /* 110 * If a processor CID configuration is present, enable it. 111 * Else, nothing to do. 112 */ 113 if (!hsem_d->rif_proc_conf[i]) 114 continue; 115 116 io_clrsetbits32(hsem_d->base + HSEM_CnCIDCFGR(i + 1), 117 HSEM_CnCIDCFGR_CONF_MASK, 118 _CIDCFGR_CFEN | hsem_d->rif_proc_conf[i]); 119 } 120 121 /* 122 * Configure HSEM groups configuration registers 123 * If one semaphore is configured, all semaphores of its group 124 * must be configured too and MUST have the same RIF 125 * configuration. 126 */ 127 for (i = 0; i < HSEM_NB_SEM_GROUPS; i++) { 128 unsigned int hsem_idx = i * HSEM_NB_SEM_PER_GROUP; 129 unsigned int hsem_cid = 0; 130 unsigned int known_cid_idx = 0; 131 132 prev_cid_value = hsem_d->conf_data.cid_confs[hsem_idx]; 133 134 /* If CID filtering is disabled, do nothing */ 135 if (!(prev_cid_value & _CIDCFGR_CFEN)) 136 continue; 137 138 /* 139 * Check if configured CID corresponds to a processor's 140 * CID in HSEM_CnCIDCFGR. 141 */ 142 for (j = 0; j < HSEM_NB_PROC; j++) { 143 uint32_t proc_cid = hsem_d->rif_proc_conf[j]; 144 145 hsem_cid = (prev_cid_value & HSEM_CnCIDCFGR_SCID_MASK); 146 DMSG("hsem_cid %u", hsem_cid); 147 DMSG("proc_cid %u", proc_cid); 148 if (proc_cid == hsem_cid) { 149 known_cid_idx = BIT(j + 150 HSEM_GpCIDCFGR_SEM_WLIST_SHIFT); 151 break; 152 } 153 } 154 if (!known_cid_idx) 155 panic("Unknown HSEM processor CID"); 156 157 /* 158 * HSEM resources in the same group must have the same CID 159 * filtering configuration. Else it is inconsistent. 160 */ 161 for (j = 0; j < HSEM_NB_SEM_PER_GROUP; j++) 162 if (hsem_d->conf_data.cid_confs[j + hsem_idx] != 163 prev_cid_value) 164 panic("Inconsistent HSEM RIF group config"); 165 166 io_clrsetbits32(hsem_d->base + HSEM_GpCIDCFGR(i), 167 HSEM_GpCIDCFGR_CONF_MASK, 168 _CIDCFGR_CFEN | known_cid_idx); 169 } 170 } 171 172 static TEE_Result parse_dt(const void *fdt, int node) 173 { 174 TEE_Result res = TEE_ERROR_GENERIC; 175 unsigned int i = 0; 176 int lenp = 0; 177 const fdt32_t *cuint = NULL; 178 struct dt_node_info info = { }; 179 struct io_pa_va addr = { }; 180 181 fdt_fill_device_info(fdt, &info, node); 182 assert(info.reg != DT_INFO_INVALID_REG && 183 info.reg_size != DT_INFO_INVALID_REG_SIZE); 184 185 addr.pa = info.reg; 186 hsem_d->base = io_pa_or_va_secure(&addr, info.reg_size); 187 188 /* Gate the IP */ 189 res = clk_dt_get_by_index(fdt, node, 0, &hsem_d->hsem_clock); 190 if (res) 191 return res; 192 193 cuint = fdt_getprop(fdt, node, "st,protreg", &lenp); 194 if (!cuint) 195 panic("No RIF configuration available"); 196 197 hsem_d->nb_channels = (unsigned int)(lenp / sizeof(uint32_t)); 198 assert(hsem_d->nb_channels <= HSEM_RIF_RESOURCES); 199 200 hsem_d->rif_proc_conf = calloc(HSEM_NB_PROC, sizeof(uint32_t)); 201 assert(hsem_d->rif_proc_conf); 202 hsem_d->conf_data.cid_confs = calloc(HSEM_RIF_RESOURCES, 203 sizeof(uint32_t)); 204 hsem_d->conf_data.sec_conf = calloc(1, sizeof(uint32_t)); 205 hsem_d->conf_data.priv_conf = calloc(1, sizeof(uint32_t)); 206 hsem_d->conf_data.access_mask = calloc(1, sizeof(uint32_t)); 207 assert(hsem_d->conf_data.cid_confs && hsem_d->conf_data.sec_conf && 208 hsem_d->conf_data.priv_conf && hsem_d->conf_data.access_mask); 209 210 for (i = 0; i < hsem_d->nb_channels; i++) 211 stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), &hsem_d->conf_data, 212 HSEM_RIF_RESOURCES); 213 214 cuint = fdt_getprop(fdt, node, "st,proccid", &lenp); 215 if (!cuint) 216 panic("No RIF proc configuration available"); 217 218 lenp = (unsigned int)(lenp / sizeof(uint32_t)); 219 /* 220 * There should be maximum (HSEM_NB_PROC * 2) property argument. 221 * First argument for a processor is its number, the second is its CID. 222 */ 223 assert((unsigned int)lenp <= (HSEM_NB_PROC * 2)); 224 225 for (i = 0; i < (unsigned int)lenp / 2; i++) { 226 unsigned int pos = fdt32_to_cpu(cuint[i * 2]) - 1; 227 unsigned int cid_value = fdt32_to_cpu(cuint[(i * 2) + 1]); 228 229 hsem_d->rif_proc_conf[pos] = SHIFT_U32(cid_value, 230 _CIDCFGR_SCID_SHIFT); 231 } 232 233 return TEE_SUCCESS; 234 } 235 236 static TEE_Result stm32_hsem_probe(const void *fdt, int node, 237 const void *compat_data __unused) 238 { 239 TEE_Result res = TEE_ERROR_GENERIC; 240 bool is_tdcid = false; 241 242 res = stm32_rifsc_check_tdcid(&is_tdcid); 243 if (res) 244 return res; 245 246 hsem_d = calloc(1, sizeof(*hsem_d)); 247 if (!hsem_d) 248 return TEE_ERROR_OUT_OF_MEMORY; 249 250 res = parse_dt(fdt, node); 251 if (res) { 252 free(hsem_d); 253 return res; 254 } 255 256 res = clk_enable(hsem_d->hsem_clock); 257 if (res) 258 panic("Cannot access HSEM clock"); 259 260 apply_rif_config(is_tdcid); 261 262 clk_disable(hsem_d->hsem_clock); 263 264 return TEE_SUCCESS; 265 } 266 267 static const struct dt_device_match stm32_hsem_match_table[] = { 268 { .compatible = "st,stm32mp25-hsem" }, 269 { } 270 }; 271 272 DEFINE_DT_DRIVER(stm32_hsem_dt_driver) = { 273 .name = "st,stm32-hsem", 274 .match_table = stm32_hsem_match_table, 275 .probe = stm32_hsem_probe, 276 }; 277