Pankaj Gupta | 95c7eee | 2020-12-09 14:02:39 +0530 | [diff] [blame] | 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 | } |