1 /* 2 * Copyright 2021 NXP 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 */ 7 8 #include <errno.h> 9 #include <stdbool.h> 10 #include <stdint.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <arch_helpers.h> 16 #include "caam.h" 17 #include <common/debug.h> 18 #include "jobdesc.h" 19 #include "sec_hw_specific.h" 20 21 static uintptr_t g_nxp_caam_addr; 22 static void *job_ring; 23 24 uintptr_t get_caam_addr(void) 25 { 26 if (g_nxp_caam_addr == 0) { 27 ERROR("Sec Init is not done.\n"); 28 panic(); 29 } 30 return g_nxp_caam_addr; 31 } 32 33 /* This function sets the TZ bit for the Job ring number passed as @num */ 34 static void config_tz(int num) 35 { 36 uint32_t jricid; 37 38 /* Setting TZ bit of job ring */ 39 switch (num) { 40 case 0: 41 jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET); 42 sec_out32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET, 43 jricid | JRICID_MS_TZ); 44 break; 45 case 1: 46 jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET); 47 sec_out32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET, 48 jricid | JRICID_MS_TZ); 49 break; 50 case 2: 51 jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET); 52 sec_out32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET, 53 jricid | JRICID_MS_TZ); 54 break; 55 case 3: 56 jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET); 57 sec_out32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET, 58 jricid | JRICID_MS_TZ); 59 break; 60 default: 61 break; 62 } 63 } 64 65 /* This function checks if Virtualization is enabled for JR and 66 * accordingly sets the bot for starting JR<num> in JRSTARTR register 67 */ 68 static inline void start_jr(int num) 69 { 70 uint32_t ctpr = sec_in32((g_nxp_caam_addr + SEC_REG_CTPR_MS_OFFSET)); 71 uint32_t tmp = sec_in32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET)); 72 uint32_t scfgr = sec_in32((g_nxp_caam_addr + SEC_REG_SCFGR_OFFSET)); 73 bool start = false; 74 75 if ((ctpr & CTPR_VIRT_EN_INC) != 0U) { 76 if (((ctpr & CTPR_VIRT_EN_POR) != 0U) || 77 ((scfgr & SCFGR_VIRT_EN) != 0U)) { 78 start = true; 79 } 80 } else { 81 if ((ctpr & CTPR_VIRT_EN_POR) != 0U) { 82 start = true; 83 } 84 } 85 86 if (start == true) { 87 switch (num) { 88 case 0: 89 tmp |= JRSTARTR_STARTJR0; 90 break; 91 case 1: 92 tmp |= JRSTARTR_STARTJR1; 93 break; 94 case 2: 95 tmp |= JRSTARTR_STARTJR2; 96 break; 97 case 3: 98 tmp |= JRSTARTR_STARTJR3; 99 break; 100 default: 101 break; 102 } 103 } 104 sec_out32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET), tmp); 105 } 106 107 /* This functions configures the Job Ring 108 * JR3 is reserved for use by Secure world 109 */ 110 static int configure_jr(int num) 111 { 112 int ret; 113 void *reg_base_addr; 114 115 switch (num) { 116 case 0: 117 reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR0_OFFSET); 118 break; 119 case 1: 120 reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR1_OFFSET); 121 break; 122 case 2: 123 reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR2_OFFSET); 124 break; 125 case 3: 126 reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR3_OFFSET); 127 break; 128 default: 129 break; 130 } 131 132 /* Initialize the JR library */ 133 ret = sec_jr_lib_init(); 134 if (ret != 0) { 135 ERROR("Error in sec_jr_lib_init"); 136 return -1; 137 } 138 139 start_jr(num); 140 141 /* Do HW configuration of the JR */ 142 job_ring = init_job_ring(SEC_NOTIFICATION_TYPE_POLL, 0, 0, 143 reg_base_addr, 0); 144 145 if (job_ring == NULL) { 146 ERROR("Error in init_job_ring"); 147 return -1; 148 } 149 150 return ret; 151 } 152 153 /* TBD - Configures and locks the ICID values for various JR */ 154 static inline void configure_icid(void) 155 { 156 } 157 158 /* TBD configures the TZ settings of RTIC */ 159 static inline void configure_rtic(void) 160 { 161 } 162 163 int sec_init(uintptr_t nxp_caam_addr) 164 { 165 g_nxp_caam_addr = nxp_caam_addr; 166 return config_sec_block(); 167 } 168 169 /* This function configure SEC block: 170 * - It does basic parameter setting 171 * - Configures the default Job ring assigned to TZ /secure world 172 * - Instantiates the RNG 173 */ 174 int config_sec_block(void) 175 { 176 int ret = 0; 177 uint32_t mcfgr; 178 179 if (g_nxp_caam_addr == 0) { 180 ERROR("Sec Init is not done.\n"); 181 return -1; 182 } else if (job_ring != NULL) { 183 NOTICE("Sec is already initialized and configured.\n"); 184 return ret; 185 } 186 187 mcfgr = sec_in32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET); 188 189 /* Modify CAAM Read/Write attributes 190 * AXI Write - Cacheable, WB and WA 191 * AXI Read - Cacheable, RA 192 */ 193 #if defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS2088A) 194 mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0xb << MCFGR_AWCACHE_SHIFT); 195 mcfgr = (mcfgr & ~MCFGR_ARCACHE_MASK) | (0x6 << MCFGR_ARCACHE_SHIFT); 196 #else 197 mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0x2 << MCFGR_AWCACHE_SHIFT); 198 #endif 199 200 /* Set PS bit to 1 */ 201 #ifdef CONFIG_PHYS_64BIT 202 mcfgr |= (1 << MCFGR_PS_SHIFT); 203 #endif 204 sec_out32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET, mcfgr); 205 206 /* Asssign ICID to all Job rings and lock them for usage */ 207 configure_icid(); 208 209 /* Configure the RTIC */ 210 configure_rtic(); 211 212 /* Configure the default JR for usage */ 213 ret = configure_jr(DEFAULT_JR); 214 if (ret != 0) { 215 ERROR("\nFSL_JR: configuration failure\n"); 216 return -1; 217 } 218 /* Do TZ configuration of default JR for sec firmware */ 219 config_tz(DEFAULT_JR); 220 221 #ifdef CONFIG_RNG_INIT 222 /* Instantiate the RNG */ 223 ret = hw_rng_instantiate(); 224 if (ret != 0) { 225 ERROR("\nRNG Instantiation failure\n"); 226 return -1; 227 } 228 #endif 229 230 return ret; 231 } 232 233 /* This function is used for sumbitting job to the Job Ring 234 * [param] [in] - jobdesc to be submitted 235 * Return - -1 in case of error and 0 in case of SUCCESS 236 */ 237 int run_descriptor_jr(struct job_descriptor *jobdesc) 238 { 239 int i = 0, ret = 0; 240 uint32_t *desc_addr = jobdesc->desc; 241 uint32_t desc_len = desc_length(jobdesc->desc); 242 uint32_t desc_word; 243 244 for (i = 0; i < desc_len; i++) { 245 desc_word = desc_addr[i]; 246 VERBOSE("%x\n", desc_word); 247 sec_out32((uint32_t *)&desc_addr[i], desc_word); 248 } 249 dsb(); 250 251 #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2) 252 flush_dcache_range((uintptr_t)desc_addr, desc_len * 4); 253 dmbsy(); 254 dsbsy(); 255 isb(); 256 #endif 257 258 ret = enq_jr_desc(job_ring, jobdesc); 259 if (ret == 0) { 260 VERBOSE("JR enqueue done...\n"); 261 } else { 262 ERROR("Error in Enqueue\n"); 263 return ret; 264 } 265 266 VERBOSE("Dequeue in progress"); 267 268 ret = dequeue_jr(job_ring, -1); 269 if (ret >= 0) { 270 VERBOSE("Dequeue of %x desc success\n", ret); 271 ret = 0; 272 } else { 273 ERROR("deq_ret %x\n", ret); 274 ret = -1; 275 } 276 277 return ret; 278 } 279 280 /* this function returns a random number using HW RNG Algo 281 * In case of failure, random number returned is 0 282 * prngWidth = 0 - 32 bit random number 283 * prngWidth > 0 means 64 bit random number 284 */ 285 unsigned long long get_random(int rngWidth) 286 { 287 unsigned long long result = 0; 288 uint8_t rand_byte[64] __aligned(CACHE_WRITEBACK_GRANULE); 289 uint8_t rand_byte_swp[8]; 290 int bytes = 0; 291 int i = 0; 292 int ret = 0; 293 294 #ifdef CAAM_TEST 295 rand_byte[0] = U(0x12); 296 rand_byte[1] = U(0x34); 297 rand_byte[2] = U(0x56); 298 rand_byte[3] = U(0x78); 299 rand_byte[4] = U(0x9a); 300 rand_byte[5] = U(0xbc); 301 rand_byte[6] = U(0xde); 302 rand_byte[7] = U(0xf1); 303 #endif 304 305 if (rngWidth == 0U) { 306 bytes = 4; 307 } else { 308 bytes = 8; 309 } 310 311 memset(rand_byte, 0, 64); 312 313 ret = get_rand_bytes_hw(rand_byte, bytes); 314 315 for (i = 0; i < bytes; i++) { 316 if (ret != 0) { 317 /* Return 0 in case of failure */ 318 rand_byte_swp[i] = 0; 319 } else { 320 rand_byte_swp[i] = rand_byte[bytes - i - 1]; 321 result = (result << 8) | rand_byte_swp[i]; 322 } 323 } 324 325 INFO("result %llx\n", result); 326 327 return result; 328 329 } /* _get_RNG() */ 330 331 unsigned int _get_hw_unq_key(uint64_t hw_key_phy_addr, unsigned int size) 332 { 333 int ret = 0; 334 uint8_t *hw_key = (uint8_t *) ptov((phys_addr_t *) hw_key_phy_addr); 335 336 ret = get_hw_unq_key_blob_hw(hw_key, size); 337 338 return ret; 339 } 340