1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (C) 2016 Freescale Semiconductor, Inc. 4 * Copyright 2017-2022 NXP 5 */ 6 #include <drivers/imx_mu.h> 7 #include <drivers/imx_sc_api.h> 8 #include <imx-regs.h> 9 #include <initcall.h> 10 #include <kernel/mutex.h> 11 #include <mm/core_memprot.h> 12 #include <tee_api_types.h> 13 #include <trace.h> 14 15 #define RNG_INIT_RETRY 100 16 17 #define SC_RPC_VERSION 1 18 #define SC_RPC_MAX_MSG 8 19 20 /* Defines for struct sc_rpc_msg svc field */ 21 #define SC_RPC_SVC_PM 2 22 #define SC_RPC_SVC_RM 3 23 #define SC_RPC_SVC_SECO 9 24 25 /* Define for PM function calls */ 26 enum sc_pm_func { 27 SC_PM_FUNC_SET_RESOURCE_POWER_MODE = 3 28 }; 29 30 /* Defines for RM function calls */ 31 enum sc_rm_func { 32 SC_RM_FUNC_GET_PARTITION = 5, 33 SC_RM_FUNC_ASSIGN_RESOURCE = 8 34 }; 35 36 /* Define for SECO function calls */ 37 enum sc_seco_func { 38 SC_SECO_FUNC_START_RNG = 22 39 }; 40 41 /* Internal SCFW API error codes */ 42 enum sc_error { 43 SC_ERR_NONE = 0, /* Success */ 44 SC_ERR_VERSION, /* Incompatible API version */ 45 SC_ERR_CONFIG, /* Configuration error */ 46 SC_ERR_PARM, /* Bad parameter */ 47 SC_ERR_NOACCESS, /* Permission error (no access) */ 48 SC_ERR_LOCKED, /* Permission error (locked) */ 49 SC_ERR_UNAVAILABLE, /* Unavailable (out of resources) */ 50 SC_ERR_NOTFOUND, /* Not found */ 51 SC_ERR_NOPOWER, /* No power */ 52 SC_ERR_IPC, /* Generic IPC error */ 53 SC_ERR_BUSY, /* Resource is currently busy/active */ 54 SC_ERR_FAIL, /* General I/O failure */ 55 SC_ERR_LAST 56 }; 57 58 /* RNG SECO states */ 59 enum sc_seco_rng_status { 60 SC_SECO_RNG_STAT_UNAVAILABLE = 0, 61 SC_SECO_RNG_STAT_INPROGRESS, 62 SC_SECO_RNG_STAT_READY 63 }; 64 65 /* Resources IDs */ 66 enum sc_resource { 67 SC_RES_CAAM_JR1 = 500, 68 SC_RES_CAAM_JR2, 69 SC_RES_CAAM_JR3, 70 SC_RES_CAAM_JR1_OUT = 514, 71 SC_RES_CAAM_JR2_OUT, 72 SC_RES_CAAM_JR3_OUT, 73 SC_RES_CAAM_JR0 = 519, 74 SC_RES_CAAM_JR0_OUT, 75 SC_RES_LAST = 546 76 }; 77 78 /* Power modes */ 79 enum sc_power_mode { 80 SC_PM_PW_MODE_OFF = 0, 81 SC_PM_PW_MODE_STBY, 82 SC_PM_PW_MODE_LP, 83 SC_PM_PW_MODE_ON 84 }; 85 86 static vaddr_t secure_ipc_addr; 87 88 register_phys_mem(MEM_AREA_IO_SEC, SC_IPC_BASE_SECURE, SC_IPC_SIZE); 89 90 /* 91 * Get the partition ID of secure world 92 * 93 * @partition Partition ID 94 */ 95 static TEE_Result sc_rm_get_partition(uint8_t *partition) 96 { 97 TEE_Result res = TEE_ERROR_GENERIC; 98 enum sc_error err = SC_ERR_LAST; 99 struct imx_mu_msg msg = { 100 .header.version = SC_RPC_VERSION, 101 .header.size = 1, 102 .header.tag = SC_RPC_SVC_RM, 103 .header.command = SC_RM_FUNC_GET_PARTITION, 104 }; 105 106 res = imx_mu_call(secure_ipc_addr, &msg, true); 107 if (res != TEE_SUCCESS) { 108 EMSG("Communication error"); 109 return res; 110 } 111 112 err = msg.header.command; 113 if (err != SC_ERR_NONE) { 114 EMSG("Unable to get partition ID, sc_error: %d", err); 115 return TEE_ERROR_GENERIC; 116 } 117 118 *partition = IMX_MU_DATA_U8(&msg, 0); 119 120 return TEE_SUCCESS; 121 } 122 123 /* 124 * Set the given power mode of a resource 125 * 126 * @resource ID of the resource 127 * @mode Power mode to apply 128 */ 129 static TEE_Result sc_pm_set_resource_power_mode(enum sc_resource resource, 130 enum sc_power_mode mode) 131 { 132 TEE_Result res = TEE_ERROR_GENERIC; 133 enum sc_error scu_error = SC_ERR_LAST; 134 struct imx_mu_msg msg = { 135 .header.version = SC_RPC_VERSION, 136 .header.size = 2, 137 .header.tag = SC_RPC_SVC_PM, 138 .header.command = SC_PM_FUNC_SET_RESOURCE_POWER_MODE, 139 }; 140 141 IMX_MU_DATA_U16(&msg, 0) = (uint16_t)resource; 142 IMX_MU_DATA_U8(&msg, 2) = (uint8_t)mode; 143 144 res = imx_mu_call(secure_ipc_addr, &msg, true); 145 if (res != TEE_SUCCESS) { 146 EMSG("Communication error"); 147 return res; 148 } 149 150 scu_error = msg.header.command; 151 if (scu_error != SC_ERR_NONE) { 152 EMSG("Unable to set resource power mode sc_error: %d", 153 scu_error); 154 return TEE_ERROR_GENERIC; 155 } 156 157 return TEE_SUCCESS; 158 } 159 160 /* 161 * Assign ownership of a resource to the secure partition 162 * 163 * @resource Resource to assign 164 */ 165 static TEE_Result sc_rm_assign_resource(enum sc_resource resource) 166 { 167 TEE_Result res = TEE_ERROR_GENERIC; 168 enum sc_error err = SC_ERR_LAST; 169 uint8_t secure_partition = 0; 170 struct imx_mu_msg msg = { 171 .header.version = SC_RPC_VERSION, 172 .header.size = 2, 173 .header.tag = SC_RPC_SVC_RM, 174 .header.command = SC_RM_FUNC_ASSIGN_RESOURCE, 175 }; 176 177 res = sc_rm_get_partition(&secure_partition); 178 if (res != TEE_SUCCESS) { 179 EMSG("Cannot get secure partition ID"); 180 return res; 181 } 182 183 IMX_MU_DATA_U16(&msg, 0) = (uint16_t)resource; 184 IMX_MU_DATA_U8(&msg, 2) = secure_partition; 185 186 res = imx_mu_call(secure_ipc_addr, &msg, true); 187 if (res != TEE_SUCCESS) { 188 EMSG("Communication error"); 189 return res; 190 } 191 192 err = msg.header.command; 193 if (err != SC_ERR_NONE) { 194 EMSG("Unable to assign resource, sc_error: %d", err); 195 return TEE_ERROR_GENERIC; 196 } 197 198 return TEE_SUCCESS; 199 } 200 201 TEE_Result imx_sc_rm_enable_jr(unsigned int jr_index) 202 { 203 TEE_Result res = TEE_ERROR_GENERIC; 204 enum sc_resource jr_res = SC_RES_LAST; 205 enum sc_resource jr_out_res = SC_RES_LAST; 206 207 switch (jr_index) { 208 case 0: 209 jr_res = SC_RES_CAAM_JR0; 210 jr_out_res = SC_RES_CAAM_JR0_OUT; 211 break; 212 213 case 1: 214 jr_res = SC_RES_CAAM_JR1; 215 jr_out_res = SC_RES_CAAM_JR1_OUT; 216 break; 217 218 case 2: 219 jr_res = SC_RES_CAAM_JR2; 220 jr_out_res = SC_RES_CAAM_JR2_OUT; 221 break; 222 223 case 3: 224 jr_res = SC_RES_CAAM_JR3; 225 jr_out_res = SC_RES_CAAM_JR3_OUT; 226 break; 227 228 default: 229 EMSG("Wrong JR Index, should be 0, 1, 2 or 3"); 230 return TEE_ERROR_GENERIC; 231 } 232 233 /* Assign JR resources to secure world */ 234 res = sc_rm_assign_resource(jr_res); 235 if (res != TEE_SUCCESS) { 236 EMSG("Assign SC_R_CAAM_JR%u resource failed", jr_index); 237 return res; 238 } 239 240 res = sc_rm_assign_resource(jr_out_res); 241 if (res != TEE_SUCCESS) { 242 EMSG("Assign SC_R_CAAM_JR%u_OUT resource failed", jr_index); 243 return res; 244 } 245 246 /* Power ON JR resources */ 247 res = sc_pm_set_resource_power_mode(jr_res, SC_PM_PW_MODE_ON); 248 if (res != TEE_SUCCESS) { 249 EMSG("POWER ON SC_R_CAAM_JR%u resource failed", jr_index); 250 return res; 251 } 252 253 res = sc_pm_set_resource_power_mode(jr_out_res, SC_PM_PW_MODE_ON); 254 if (res != TEE_SUCCESS) { 255 EMSG("POWER ON SC_R_CAAM_JR%u_OUT resource failed", jr_index); 256 return res; 257 } 258 259 return TEE_SUCCESS; 260 } 261 262 TEE_Result imx_sc_seco_start_rng(void) 263 { 264 TEE_Result res = TEE_ERROR_GENERIC; 265 enum sc_error err = SC_ERR_LAST; 266 enum sc_seco_rng_status status = SC_SECO_RNG_STAT_UNAVAILABLE; 267 unsigned int retry = 0; 268 struct imx_mu_msg msg = { 269 .header.version = SC_RPC_VERSION, 270 .header.size = 1, 271 .header.tag = SC_RPC_SVC_SECO, 272 .header.command = SC_SECO_FUNC_START_RNG, 273 }; 274 275 for (retry = RNG_INIT_RETRY; retry; retry--) { 276 res = imx_mu_call(secure_ipc_addr, &msg, true); 277 if (res != TEE_SUCCESS) { 278 EMSG("Configuration error"); 279 return res; 280 } 281 282 err = msg.header.command; 283 if (err != SC_ERR_NONE) { 284 EMSG("RNG status: %d", err); 285 return TEE_ERROR_GENERIC; 286 } 287 288 status = IMX_MU_DATA_U32(&msg, 0); 289 290 if (status == SC_SECO_RNG_STAT_READY) 291 return TEE_SUCCESS; 292 } 293 294 return TEE_ERROR_GENERIC; 295 } 296 297 TEE_Result imx_sc_driver_init(void) 298 { 299 vaddr_t va = 0; 300 301 va = core_mmu_get_va(SC_IPC_BASE_SECURE, MEM_AREA_IO_SEC, SC_IPC_SIZE); 302 if (!va) 303 return TEE_ERROR_GENERIC; 304 305 imx_mu_init(va); 306 secure_ipc_addr = va; 307 308 return TEE_SUCCESS; 309 } 310