/*
 * Copyright 2018 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_prince.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
/* Component ID definition, used by tools. */

#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.prince"
#endif

/*******************************************************************************
 * Variables
 ******************************************************************************/

const bus_crypto_engine_interface_t *s_busCryptoEngineInterface;
const bus_crypto_engine_interface_ext_t s_busCryptoEngineInterfaceExt = {
    /* TO 1.0 - specific address */
    .bus_crypto_engine_set_encrypt_for_address_range = (BUS_CRYPTO_ENGINE_SET_ENCRYPT_FOR_ADDRESS_RANGE_FPTR)0x13003dfb,
};

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * brief Generate new IV code.
 *
 * This function generates new IV code and stores it into the persistent memory.
 * This function is implemented as a wrapper of the exported ROM bootloader API.
 * Ensure about 800 bytes free space on the stack when calling this routine with the store parameter set to true!
 *
 * param region PRINCE region index.
 * param iv_code IV code pointer used for storing the newly generated 52 bytes long IV code.
 * param store flag to allow storing the newly generated IV code into the persistent memory (FFR).
 *
 * return kStatus_Success upon success
 * return kStatus_Fail    otherwise, kStatus_Fail is also returned if the key code for the particular
 *                         PRINCE region is not present in the keystore (though new IV code has been provided)
 */
status_t PRINCE_GenNewIV(prince_region_t region, uint8_t *iv_code, bool store)
{
    status_t status = kStatus_Fail;
    s_busCryptoEngineInterface = (const bus_crypto_engine_interface_t *)(*(uint32_t **)0x13000020)[9];

    status = s_busCryptoEngineInterface->bus_crypto_engine_gen_new_iv((uint32_t)region, &iv_code[0],
                                                                      (store == true) ? kSECURE_TRUE : kSECURE_FALSE);

    if (kStatus_SKBOOT_Success == status)
    {
        return kStatus_Success;
    }
    else
    {
        return kStatus_Fail;
    }
}

/*!
 * brief Load IV code.
 *
 * This function enables IV code loading into the PRINCE bus encryption engine.
 * This function is implemented as a wrapper of the exported ROM bootloader API.
 *
 * param region PRINCE region index.
 * param iv_code IV code pointer used for passing the IV code.
 *
 * return kStatus_Success upon success
 * return kStatus_Fail    otherwise
 */
status_t PRINCE_LoadIV(prince_region_t region, uint8_t *iv_code)
{
    status_t status = kStatus_Fail;
    s_busCryptoEngineInterface = (const bus_crypto_engine_interface_t *)(*(uint32_t **)0x13000020)[9];

    status = s_busCryptoEngineInterface->bus_crypto_engine_load_iv((uint32_t)region, &iv_code[0]);

    if (kStatus_SKBOOT_Success == status)
    {
        return kStatus_Success;
    }
    else
    {
        return kStatus_Fail;
    }
}

/*!
 * brief Allow encryption/decryption for specified address range.
 *
 * This function sets the encryption/decryption for specified address range.
 * This function is implemented as a wrapper of the exported ROM bootloader API.
 * Ensure about 800 bytes free space on the stack when calling this routine!
 *
 * param region PRINCE region index.
 * param start_address start address of the area to be encrypted/decrypted.
 * param length length of the area to be encrypted/decrypted.
 *
 * return kStatus_Success upon success
 * return kStatus_Fail    otherwise
 */
status_t PRINCE_SetEncryptForAddressRange(prince_region_t region, uint32_t start_address, uint32_t length)
{
    status_t status = kStatus_Fail;

    /* This function call is valid for the TapeOut v.1.0
       and utilizes the PRINCE ROM API function that is not exported by the bootloader (busCryptoEngine ROM interface).
       */
    status = s_busCryptoEngineInterfaceExt.bus_crypto_engine_set_encrypt_for_address_range((uint8_t)region,
                                                                                           start_address, length);

    if (kStatus_SKBOOT_Success == status)
    {
        return kStatus_Success;
    }
    else
    {
        return kStatus_Fail;
    }
}

/*!
 * brief Gets the PRINCE Sub-Region Enable register.
 *
 * This function gets PRINCE SR_ENABLE register.
 *
 * param base PRINCE peripheral address.
 * param region PRINCE region index.
 * param sr_enable Sub-Region Enable register pointer.
 *
 * return kStatus_Success upon success
 * return kStatus_InvalidArgument
 */
status_t PRINCE_GetRegionSREnable(PRINCE_Type *base, prince_region_t region, uint32_t *sr_enable)
{
    status_t status = kStatus_Success;

    switch (region)
    {
        case kPRINCE_Region0:
            *sr_enable = base->SR_ENABLE0;
            break;

        case kPRINCE_Region1:
            *sr_enable = base->SR_ENABLE1;
            break;

        case kPRINCE_Region2:
            *sr_enable = base->SR_ENABLE2;
            break;

        default:
            status = kStatus_InvalidArgument;
            break;
    }

    return status;
}

/*!
 * brief Gets the PRINCE region base address register.
 *
 * This function gets PRINCE BASE_ADDR register.
 *
 * param base PRINCE peripheral address.
 * param region PRINCE region index.
 * param region_base_addr Region base address pointer.
 *
 * return kStatus_Success upon success
 * return kStatus_InvalidArgument
 */
status_t PRINCE_GetRegionBaseAddress(PRINCE_Type *base, prince_region_t region, uint32_t *region_base_addr)
{
    status_t status = kStatus_Success;

    switch (region)
    {
        case kPRINCE_Region0:
            *region_base_addr = base->BASE_ADDR0;
            break;

        case kPRINCE_Region1:
            *region_base_addr = base->BASE_ADDR1;
            break;

        case kPRINCE_Region2:
            *region_base_addr = base->BASE_ADDR2;
            break;

        default:
            status = kStatus_InvalidArgument;
            break;
    }

    return status;
}
