| /* |
| * Copyright 2021 NXP |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| * |
| */ |
| |
| #include <errno.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <arch_helpers.h> |
| #include "caam.h" |
| #include <common/debug.h> |
| #include "jobdesc.h" |
| #include "sec_hw_specific.h" |
| |
| static uintptr_t g_nxp_caam_addr; |
| static void *job_ring; |
| |
| uintptr_t get_caam_addr(void) |
| { |
| if (g_nxp_caam_addr == 0) { |
| ERROR("Sec Init is not done.\n"); |
| panic(); |
| } |
| return g_nxp_caam_addr; |
| } |
| |
| /* This function sets the TZ bit for the Job ring number passed as @num */ |
| static void config_tz(int num) |
| { |
| uint32_t jricid; |
| |
| /* Setting TZ bit of job ring */ |
| switch (num) { |
| case 0: |
| jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET); |
| sec_out32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET, |
| jricid | JRICID_MS_TZ); |
| break; |
| case 1: |
| jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET); |
| sec_out32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET, |
| jricid | JRICID_MS_TZ); |
| break; |
| case 2: |
| jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET); |
| sec_out32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET, |
| jricid | JRICID_MS_TZ); |
| break; |
| case 3: |
| jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET); |
| sec_out32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET, |
| jricid | JRICID_MS_TZ); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* This function checks if Virtualization is enabled for JR and |
| * accordingly sets the bot for starting JR<num> in JRSTARTR register |
| */ |
| static inline void start_jr(int num) |
| { |
| uint32_t ctpr = sec_in32((g_nxp_caam_addr + SEC_REG_CTPR_MS_OFFSET)); |
| uint32_t tmp = sec_in32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET)); |
| uint32_t scfgr = sec_in32((g_nxp_caam_addr + SEC_REG_SCFGR_OFFSET)); |
| bool start = false; |
| |
| if ((ctpr & CTPR_VIRT_EN_INC) != 0U) { |
| if (((ctpr & CTPR_VIRT_EN_POR) != 0U) || |
| ((scfgr & SCFGR_VIRT_EN) != 0U)) { |
| start = true; |
| } |
| } else { |
| if ((ctpr & CTPR_VIRT_EN_POR) != 0U) { |
| start = true; |
| } |
| } |
| |
| if (start == true) { |
| switch (num) { |
| case 0: |
| tmp |= JRSTARTR_STARTJR0; |
| break; |
| case 1: |
| tmp |= JRSTARTR_STARTJR1; |
| break; |
| case 2: |
| tmp |= JRSTARTR_STARTJR2; |
| break; |
| case 3: |
| tmp |= JRSTARTR_STARTJR3; |
| break; |
| default: |
| break; |
| } |
| } |
| sec_out32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET), tmp); |
| } |
| |
| /* This functions configures the Job Ring |
| * JR3 is reserved for use by Secure world |
| */ |
| static int configure_jr(int num) |
| { |
| int ret; |
| void *reg_base_addr; |
| |
| switch (num) { |
| case 0: |
| reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR0_OFFSET); |
| break; |
| case 1: |
| reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR1_OFFSET); |
| break; |
| case 2: |
| reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR2_OFFSET); |
| break; |
| case 3: |
| reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR3_OFFSET); |
| break; |
| default: |
| break; |
| } |
| |
| /* Initialize the JR library */ |
| ret = sec_jr_lib_init(); |
| if (ret != 0) { |
| ERROR("Error in sec_jr_lib_init"); |
| return -1; |
| } |
| |
| start_jr(num); |
| |
| /* Do HW configuration of the JR */ |
| job_ring = init_job_ring(SEC_NOTIFICATION_TYPE_POLL, 0, 0, |
| reg_base_addr, 0); |
| |
| if (job_ring == NULL) { |
| ERROR("Error in init_job_ring"); |
| return -1; |
| } |
| |
| return ret; |
| } |
| |
| /* TBD - Configures and locks the ICID values for various JR */ |
| static inline void configure_icid(void) |
| { |
| } |
| |
| /* TBD configures the TZ settings of RTIC */ |
| static inline void configure_rtic(void) |
| { |
| } |
| |
| int sec_init(uintptr_t nxp_caam_addr) |
| { |
| g_nxp_caam_addr = nxp_caam_addr; |
| return config_sec_block(); |
| } |
| |
| /* This function configure SEC block: |
| * - It does basic parameter setting |
| * - Configures the default Job ring assigned to TZ /secure world |
| * - Instantiates the RNG |
| */ |
| int config_sec_block(void) |
| { |
| int ret = 0; |
| uint32_t mcfgr; |
| |
| if (g_nxp_caam_addr == 0) { |
| ERROR("Sec Init is not done.\n"); |
| return -1; |
| } else if (job_ring != NULL) { |
| NOTICE("Sec is already initialized and configured.\n"); |
| return ret; |
| } |
| |
| mcfgr = sec_in32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET); |
| |
| /* Modify CAAM Read/Write attributes |
| * AXI Write - Cacheable, WB and WA |
| * AXI Read - Cacheable, RA |
| */ |
| #if defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS2088A) |
| mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0xb << MCFGR_AWCACHE_SHIFT); |
| mcfgr = (mcfgr & ~MCFGR_ARCACHE_MASK) | (0x6 << MCFGR_ARCACHE_SHIFT); |
| #else |
| mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0x2 << MCFGR_AWCACHE_SHIFT); |
| #endif |
| |
| /* Set PS bit to 1 */ |
| #ifdef CONFIG_PHYS_64BIT |
| mcfgr |= (1 << MCFGR_PS_SHIFT); |
| #endif |
| sec_out32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET, mcfgr); |
| |
| /* Asssign ICID to all Job rings and lock them for usage */ |
| configure_icid(); |
| |
| /* Configure the RTIC */ |
| configure_rtic(); |
| |
| /* Configure the default JR for usage */ |
| ret = configure_jr(DEFAULT_JR); |
| if (ret != 0) { |
| ERROR("\nFSL_JR: configuration failure\n"); |
| return -1; |
| } |
| /* Do TZ configuration of default JR for sec firmware */ |
| config_tz(DEFAULT_JR); |
| |
| #ifdef CONFIG_RNG_INIT |
| /* Instantiate the RNG */ |
| ret = hw_rng_instantiate(); |
| if (ret != 0) { |
| ERROR("\nRNG Instantiation failure\n"); |
| return -1; |
| } |
| #endif |
| |
| return ret; |
| } |
| |
| /* This function is used for sumbitting job to the Job Ring |
| * [param] [in] - jobdesc to be submitted |
| * Return - -1 in case of error and 0 in case of SUCCESS |
| */ |
| int run_descriptor_jr(struct job_descriptor *jobdesc) |
| { |
| int i = 0, ret = 0; |
| uint32_t *desc_addr = jobdesc->desc; |
| uint32_t desc_len = desc_length(jobdesc->desc); |
| uint32_t desc_word; |
| |
| for (i = 0; i < desc_len; i++) { |
| desc_word = desc_addr[i]; |
| VERBOSE("%x\n", desc_word); |
| sec_out32((uint32_t *)&desc_addr[i], desc_word); |
| } |
| dsb(); |
| |
| #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2) |
| flush_dcache_range((uintptr_t)desc_addr, desc_len * 4); |
| dmbsy(); |
| dsbsy(); |
| isb(); |
| #endif |
| |
| ret = enq_jr_desc(job_ring, jobdesc); |
| if (ret == 0) { |
| VERBOSE("JR enqueue done...\n"); |
| } else { |
| ERROR("Error in Enqueue\n"); |
| return ret; |
| } |
| |
| VERBOSE("Dequeue in progress"); |
| |
| ret = dequeue_jr(job_ring, -1); |
| if (ret >= 0) { |
| VERBOSE("Dequeue of %x desc success\n", ret); |
| ret = 0; |
| } else { |
| ERROR("deq_ret %x\n", ret); |
| ret = -1; |
| } |
| |
| return ret; |
| } |
| |
| /* this function returns a random number using HW RNG Algo |
| * In case of failure, random number returned is 0 |
| * prngWidth = 0 - 32 bit random number |
| * prngWidth > 0 means 64 bit random number |
| */ |
| unsigned long long get_random(int rngWidth) |
| { |
| unsigned long long result = 0; |
| uint8_t rand_byte[64] __aligned(CACHE_WRITEBACK_GRANULE); |
| uint8_t rand_byte_swp[8]; |
| int bytes = 0; |
| int i = 0; |
| int ret = 0; |
| |
| #ifdef CAAM_TEST |
| rand_byte[0] = U(0x12); |
| rand_byte[1] = U(0x34); |
| rand_byte[2] = U(0x56); |
| rand_byte[3] = U(0x78); |
| rand_byte[4] = U(0x9a); |
| rand_byte[5] = U(0xbc); |
| rand_byte[6] = U(0xde); |
| rand_byte[7] = U(0xf1); |
| #endif |
| |
| if (rngWidth == 0U) { |
| bytes = 4; |
| } else { |
| bytes = 8; |
| } |
| |
| memset(rand_byte, 0, 64); |
| |
| ret = get_rand_bytes_hw(rand_byte, bytes); |
| |
| for (i = 0; i < bytes; i++) { |
| if (ret != 0) { |
| /* Return 0 in case of failure */ |
| rand_byte_swp[i] = 0; |
| } else { |
| rand_byte_swp[i] = rand_byte[bytes - i - 1]; |
| result = (result << 8) | rand_byte_swp[i]; |
| } |
| } |
| |
| INFO("result %llx\n", result); |
| |
| return result; |
| |
| } /* _get_RNG() */ |
| |
| unsigned int _get_hw_unq_key(uint64_t hw_key_phy_addr, unsigned int size) |
| { |
| int ret = 0; |
| uint8_t *hw_key = (uint8_t *) ptov((phys_addr_t *) hw_key_phy_addr); |
| |
| ret = get_hw_unq_key_blob_hw(hw_key, size); |
| |
| return ret; |
| } |