nt9856x/BSP/u-boot/arch/arm/mach-novatek/nvt_na51068_a32/nvt-otp.c
2023-03-28 15:07:53 +08:00

483 lines
12 KiB
C
Executable File

/**
nvt-opt key manager
This file will Enable and disable SRAM shutdown
@file nvt-otp.c
@ingroup
@note
Copyright Novatek Microelectronics Corp. 2018. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
*/
#include <common.h>
#include <asm/arch/efuse_protected.h>
#ifndef CHKPNT
#define CHKPNT printf("\033[37mCHK: %d, %s\033[0m\r\n", __LINE__, __func__)
#endif
#ifndef DBGD
#define DBGD(x) printf("\033[0;35m%s=%d\033[0m\r\n", #x, x)
#endif
#ifndef DBGH
#define DBGH(x) printf("\033[0;35m%s=0x%08X\033[0m\r\n", #x, x)
#endif
#ifndef DBG_DUMP
#define DBG_DUMP(fmtstr, args...) printf(fmtstr, ##args)
#endif
#ifndef DBG_ERR
#define DBG_ERR(fmtstr, args...) printf("\033[0;31mERR:%s() \033[0m" fmtstr, __func__, ##args)
#endif
#ifndef DBG_WRN
#define DBG_WRN(fmtstr, args...) printf("\033[0;33mWRN:%s() \033[0m" fmtstr, __func__, ##args)
#endif
#if 0
#define DBG_IND(fmtstr, args...) printf("%s(): " fmtstr, __func__, ##args)
#else
#ifndef DBG_IND
#define DBG_IND(fmtstr, args...)
#endif
#endif
#define OUTREG32(x, y) (*((volatile UINT32*)(x)) = (y)) ///< Write 32bits IO register
extern INT32 local_load(UINT32 uiRowAddress);
extern INT32 local_store(UINT32 uiRowAddress);
static INT32 key_program_bit(UINT32 rol, UINT32 col)
{
return local_store(rol | (col << 5));
}
static INT32 key_write_data(UINT32 addr, UINT32 data)
{
UINT32 ui_bits;
UINT32 ui_data;
if (addr < 12 && addr != 8) {
DBG_ERR("key_write_data addr = 0x%08x error(need >= 12 or == 8)\r\n", (int)addr);
return EFUSE_PARAM_ERR;
}
ui_data = data;
ui_bits = 0;
while (ui_data) {
ui_bits = __builtin_ctz(ui_data);
ui_data &= ~(1 << ui_bits);
if (key_program_bit(addr, ui_bits) != E_OK) {
DBG_ERR("%s,eFuse program addr[%03lx] bit[%2d] fail\r\n", __func__, (UINT32)addr, (int)ui_bits);
return EFUSE_OPS_ERR;
}
}
return EFUSE_SUCCESS;
}
#define KEY_MANAGER_READ_PARAM() otp_key_manager(8)
#define KEY_MANAGER_WRITE_PARAM(m) key_write_data(8, m)
/*
efuse_set_key_destination
Destination of efuse get key field value
@return IC revision of specific package revision
- @b NT9666X_VER_A NT9666X version A
- @b UNKNOWN_DIE_VER Unknown IC die version(system must halt)
*/
static ER set_key_destination(OTP_KEY_DESTINATION key_dst, SCE_KEY_SET_TO_OTP_FIELD key_field_set)
{
if (key_dst >= OTP_KEY_MANAGER_CNT) {
DBG_ERR("key_dst out of range %d\r\n", key_dst);
return EFUSE_PARAM_ERR;
}
if (key_dst == OTP_KEY_MANAGER_CRYPTO && key_field_set >= EFUSE_CRYPTO_ENGINE_KEY_CNT) {
DBG_ERR("Dest[Crypto]=>key_field_set out of range %d > %d\r\n", key_field_set, EFUSE_CRYPTO_ENGINE_KEY_CNT);
return EFUSE_PARAM_ERR;
}
if ((key_dst == OTP_KEY_MANAGER_RSA || key_dst == OTP_KEY_MANAGER_HASH) && key_field_set >= EFUSE_TOTAL_KEY_SET_FIELD) {
DBG_ERR("Dest[RSA] or [HASH] =>key_field_set out of range %d > %d\r\n", key_field_set, EFUSE_CRYPTO_ENGINE_KEY_CNT);
return EFUSE_PARAM_ERR;
}
OUTREG32(KEY_MANAGER_DESTINATION_ADDRESS, key_dst);
OUTREG32(KEY_MANAGER_KEY_INDEX_ADDRESS, key_field_set);
return E_OK;
}
/**
otp_write_key
Write specific key into specific key set (0~3)
@Note: key set 0 is for secure boot use
@param[in] key_set_index key set (0~3)
@param[in] ucKey key (16bytes)
@return Description of data returned.
- @b E_OK: Success
- @b E_SYS: Fail
*/
INT32 otp_write_key(EFUSE_OTP_KEY_SET_FIELD key_set_index, UINT8 *uc_key)
{
INT32 result = EFUSE_SUCCESS;
UINT32 key_data;
UINT32 u32_key = (UINT32)(uc_key);
UINT32 data[4];
UINT32 key_field_start_index = 16;
UINT32 index_cnt;
UINT32 enable_secure_number = 32;
switch (key_set_index) {
//Note: >>>1st Key set is dedicate for secure boot usage<<<
case EFUSE_OTP_1ST_KEY_SET_FIELD:
key_field_start_index = 16;
if (is_1st_key_programmed() == 1) {
result = EFUSE_FREEZE_ERR;
} else {
enable_secure_number = SECUREBOOT_1ST_KEY_SET_PROGRAMMED;
}
break;
case EFUSE_OTP_2ND_KEY_SET_FIELD:
key_field_start_index = 20;
if (is_2nd_key_programmed() == 1) {
result = EFUSE_FREEZE_ERR;
} else {
enable_secure_number = SECUREBOOT_2ND_KEY_SET_PROGRAMMED;
}
break;
case EFUSE_OTP_3RD_KEY_SET_FIELD:
key_field_start_index = 24;
if (is_3rd_key_programmed() == 1) {
result = EFUSE_FREEZE_ERR;
} else {
enable_secure_number = SECUREBOOT_3RD_KEY_SET_PROGRAMMED;
}
break;
case EFUSE_OTP_4TH_KEY_SET_FIELD:
key_field_start_index = 28;
if (is_4th_key_programmed() == 1) {
result = EFUSE_FREEZE_ERR;
} else {
enable_secure_number = SECUREBOOT_4TH_KEY_SET_PROGRAMMED;
}
break;
case EFUSE_OTP_5TH_KEY_SET_FIELD:
key_field_start_index = 12;
if (is_5th_key_programmed() == 1) {
result = EFUSE_FREEZE_ERR;
} else {
enable_secure_number = SECUREBOOT_5TH_KEY_SET_PROGRAMMED;
}
break;
default:
DBG_ERR("Unknow key set[%d] => should be 0~4\r\n", (int)key_set_index + 1);
result = EFUSE_OPS_ERR;
break;
}
if (result != EFUSE_SUCCESS) {
if (result == EFUSE_FREEZE_ERR) {
DBG_ERR("key set[%d], key field not enpty\r\n", (int)key_set_index);
}
return result;
}
//Need porting
data[0] = *(UINT32 *)(u32_key + 0);
data[1] = *(UINT32 *)(u32_key + 4);
data[2] = *(UINT32 *)(u32_key + 8);
data[3] = *(UINT32 *)(u32_key + 12);
for (index_cnt = 0; index_cnt < EFUSE_OTP_KEY_FIELD_CNT; index_cnt++) {
result = key_write_data(key_field_start_index + index_cnt, data[index_cnt]);
if (result < 0) {
DBG_ERR("[%d]set key => write addr[%2d][0x%08lx] fail\r\n", (int)(((key_field_start_index - 16) / 4) + 1), (int)(key_field_start_index + index_cnt), (UINT32)data[index_cnt]);
break;
} else {
key_data = otp_key_manager(key_field_start_index + index_cnt);
if(key_data != data[index_cnt]) {
DBG_ERR("[%d]set key => write addr[%2d][0x%08lx] fail\r\n", (int)(((key_field_start_index - 16) / 4) + 1), (int)(key_field_start_index + index_cnt), (UINT32)data[index_cnt]);
result = EFUSE_CONTENT_ERR;
break;
}
}
}
if(result == EFUSE_SUCCESS) {
enable_secure_boot(enable_secure_number);
}
return result;
}
/**
otp_set_key_destination
Durung encrypt or decrypt, configure specific key set as AES key(0~3) to crypto engine
@Note: key set 0 is for secure boot use
@param[in] key_set_index key set (0~4)
@return Description of data returned.
- @b E_OK: Success
*/
INT32 otp_set_key_destination(EFUSE_OTP_KEY_SET_FIELD key_set_index)
{
UINT32 key_field_start_index = 16;
switch (key_set_index) {
//Note: >>>1st Key set is dedicate for secure boot usage<<<
case EFUSE_OTP_1ST_KEY_SET_FIELD:
key_field_start_index = 16;
break;
case EFUSE_OTP_2ND_KEY_SET_FIELD:
key_field_start_index = 20;
break;
case EFUSE_OTP_3RD_KEY_SET_FIELD:
key_field_start_index = 24;
break;
case EFUSE_OTP_4TH_KEY_SET_FIELD:
key_field_start_index = 28;
break;
case EFUSE_OTP_5TH_KEY_SET_FIELD:
key_field_start_index = 12;
break;
default:
DBG_ERR("Unknow key set[%d] => should be 0~4\r\n", (int)key_set_index);
return EFUSE_OPS_ERR;
}
set_key_destination(OTP_KEY_MANAGER_CRYPTO, 0);
otp_key_manager(key_field_start_index);
set_key_destination(OTP_KEY_MANAGER_CRYPTO, 1);
otp_key_manager(key_field_start_index + 1);
set_key_destination(OTP_KEY_MANAGER_CRYPTO, 2);
otp_key_manager(key_field_start_index + 2);
set_key_destination(OTP_KEY_MANAGER_CRYPTO, 3);
otp_key_manager(key_field_start_index + 3);
return E_OK;
}
//Bit[0] & Bit[5] == 1
/**
quary_secure_boot
Quary now is what kind of secure boot type
@Note: key set 0 is for secure boot use
@param[in] scu_status status
@return Description of data returned.
- @b TRUE: enabled
- @b FALSE: disabled
*/
BOOL quary_secure_boot(SECUREBOOT_STATUS scu_status)
{
UINT32 sec;
BOOL result = FALSE;
sec = KEY_MANAGER_READ_PARAM();
switch (scu_status) {
case SECUREBOOT_SECURE_EN:
if ((sec & (OTP_HW_SECURE_EN | OTP_FW_SECURE_EN)) == (OTP_HW_SECURE_EN | OTP_FW_SECURE_EN)) {
result = TRUE;
}
break;
case SECUREBOOT_DATA_AREA_ENCRYPT:
if ((sec & OTP_DATA_ENCRYPT_EN) == OTP_DATA_ENCRYPT_EN) {
result = TRUE;
}
break;
case SECUREBOOT_SIGN_RSA:
if ((sec & OTP_SIGNATURE_RSA) == OTP_SIGNATURE_RSA) {
result = TRUE;
}
break;
case SECUREBOOT_SIGN_RSA_CHK:
if ((sec & OTP_SIGNATURE_RSA_CHK_EN) == OTP_SIGNATURE_RSA_CHK_EN) {
result = TRUE;
}
break;
case SECUREBOOT_JTAG_DISABLE_EN:
if ((sec & OTP_JTAG_DISABLE_EN) == OTP_JTAG_DISABLE_EN) {
result = TRUE;
}
break;
case SECUREBOOT_1ST_KEY_SET_PROGRAMMED:
if ((sec & OTP_1ST_KEY_PROGRAMMED) == OTP_1ST_KEY_PROGRAMMED) {
result = TRUE;
}
break;
case SECUREBOOT_2ND_KEY_SET_PROGRAMMED:
if ((sec & OTP_2ND_KEY_PROGRAMMED) == OTP_2ND_KEY_PROGRAMMED) {
result = TRUE;
}
break;
case SECUREBOOT_3RD_KEY_SET_PROGRAMMED:
if ((sec & OTP_3RD_KEY_PROGRAMMED) == OTP_3RD_KEY_PROGRAMMED) {
result = TRUE;
}
break;
case SECUREBOOT_4TH_KEY_SET_PROGRAMMED:
if ((sec & OTP_4TH_KEY_PROGRAMMED) == OTP_4TH_KEY_PROGRAMMED) {
result = TRUE;
}
break;
case SECUREBOOT_5TH_KEY_SET_PROGRAMMED:
if ((sec & OTP_5TH_KEY_PROGRAMMED) == OTP_5TH_KEY_PROGRAMMED) {
result = TRUE;
}
break;
default:
break;
}
return result;
}
/**
set_secure_boot
Quary now is what kind of secure boot type
@Note: key set 0 is for secure boot use
@param[in] scu_status status
@return Description of data returned.
- @b TRUE: enabled
- @b FALSE: something wrong(already configured)
*/
BOOL enable_secure_boot(SECUREBOOT_STATUS scu_status)
{
UINT32 sec;
BOOL result = FALSE;
sec = KEY_MANAGER_READ_PARAM();
switch (scu_status) {
case SECUREBOOT_SECURE_EN:
if ((sec & (OTP_HW_SECURE_EN | OTP_FW_SECURE_EN)) != 0x0) {
DBG_ERR("Secure already enabled ...");
} else {
result = TRUE;
KEY_MANAGER_WRITE_PARAM((OTP_HW_SECURE_EN | OTP_FW_SECURE_EN));
}
break;
case SECUREBOOT_DATA_AREA_ENCRYPT:
if ((sec & OTP_DATA_ENCRYPT_EN) != 0x0) {
DBG_ERR("Data area encrypted bit already set ...");
} else {
result = TRUE;
KEY_MANAGER_WRITE_PARAM(OTP_DATA_ENCRYPT_EN);
}
break;
case SECUREBOOT_SIGN_RSA:
if ((sec & OTP_SIGNATURE_RSA) != 0x0) {
DBG_ERR("Signature use RSA bit already set ...");
} else {
result = TRUE;
KEY_MANAGER_WRITE_PARAM(OTP_SIGNATURE_RSA);
}
break;
case SECUREBOOT_SIGN_RSA_CHK:
if ((sec & OTP_SIGNATURE_RSA_CHK_EN) != 0x0) {
DBG_ERR("Signature use RSA and process hash checksum bit already set ...\r\n");
} else {
result = TRUE;
KEY_MANAGER_WRITE_PARAM(OTP_SIGNATURE_RSA_CHK_EN);
}
break;
case SECUREBOOT_JTAG_DISABLE_EN:
KEY_MANAGER_WRITE_PARAM(OTP_JTAG_DISABLE_EN);
result = TRUE;
break;
case SECUREBOOT_1ST_KEY_SET_PROGRAMMED:
KEY_MANAGER_WRITE_PARAM(OTP_1ST_KEY_PROGRAMMED);
result = TRUE;
break;
case SECUREBOOT_2ND_KEY_SET_PROGRAMMED:
KEY_MANAGER_WRITE_PARAM(OTP_2ND_KEY_PROGRAMMED);
result = TRUE;
break;
case SECUREBOOT_3RD_KEY_SET_PROGRAMMED:
KEY_MANAGER_WRITE_PARAM(OTP_3RD_KEY_PROGRAMMED);
result = TRUE;
break;
case SECUREBOOT_4TH_KEY_SET_PROGRAMMED:
KEY_MANAGER_WRITE_PARAM(OTP_4TH_KEY_PROGRAMMED);
result = TRUE;
break;
case SECUREBOOT_5TH_KEY_SET_PROGRAMMED:
KEY_MANAGER_WRITE_PARAM(OTP_5TH_KEY_PROGRAMMED);
result = TRUE;
break;
default:
break;
}
return result;
}
/*
otp read data
Read specific eFuse addressing(32bits/per time)
^
|-- (row address)
@param[in] rowAddress row address
@return read half-word efuse data
- @b Positive: Valid data
- @b E_SYS : Invalid data
*/
UINT32 otp_key_manager(UINT32 rowAddress)
{
INT32 uiData;
uiData = local_load(rowAddress);
return uiData;
}