rt-thread/bsp/allwinner/libraries/sunxi-hal/hal/source/efuse/efuse.c

341 lines
10 KiB
C

/*
* =====================================================================================
*
* Filename: hal_efuse.c
*
* Description: efuse
*
* Version: 1.0
* Created: 2019-07-19
* Revision: none
* Compiler: gcc
*
* Author: wangwei
* Organization:
*
* =====================================================================================
*/
#include <stdio.h>
#include <string.h>
#include <sunxi_hal_efuse.h>
#include <sunxi_hal_common.h>
#include <hal_osal.h>
#include "platform_efuse.h"
#include "efuse.h"
#define EFUSE_CHIPID_NAME "chipid"
#define EFUSE_BROM_CONF_NAME "brom_conf"
#define EFUSE_BROM_TRY_NAME "brom_try"
#define EFUSE_THM_SENSOR_NAME "thermal_sensor"
#define EFUSE_FT_ZONE_NAME "ft_zone"
#define EFUSE_TV_OUT_NAME "tvout"
#define EFUSE_OEM_NAME "oem"
#define EFUSE_OEM_SEC_NAME "oem_secure"
#define EFUSE_EMAC_NAME "emac"
#define EFUSE_WR_PROTECT_NAME "write_protect"
#define EFUSE_RD_PROTECT_NAME "read_protect"
#define EFUSE_IN_NAME "in"
#define EFUSE_ID_NAME "id"
#define EFUSE_ROTPK_NAME "rotpk"
#define EFUSE_SSK_NAME "ssk"
#define EFUSE_RSSK_NAME "rssk"
#define EFUSE_HDCP_HASH_NAME "hdcp_hash"
#define EFUSE_HDCP_PKF_NAME "hdcp_pkf"
#define EFUSE_HDCP_DUK_NAME "hdcp_duk"
#define EFUSE_EK_HASH_NAME "ek_hash"
#define EFUSE_SN_NAME "sn"
#define EFUSE_NV1_NAME "nv1"
#define EFUSE_NV2_NAME "nv2"
#define EFUSE_BACKUP_KEY_NAME "backup_key"
#define EFUSE_RSAKEY_HASH_NAME "rsakey_hash"
#define EFUSE_RENEW_NAME "renewability"
#define EFUSE_IPTV_MAC "efusemac"
#define EFUSE_OPT_ID_NAME "operator_id"
#define EFUSE_LIFE_CYCLE_NAME "life_cycle"
#define EFUSE_JTAG_SECU_NAME "jtag_security"
#define EFUSE_JTAG_ATTR_NAME "jtag_attr"
#define EFUSE_CHIP_CONF_NAME "chip_config"
#define EFUSE_RESERVED_NAME "reserved"
#define EFUSE_RESERVED2_NAME "reserved2"
#define EFUSE_HUK_NAME "huk"
#define EFUSE_ANTI_BLUSH_NAME "anti_blushing"
#define EFUSE_TVE_NAME "tve"
/* For KeyLadder */
#define EFUSE_KL_SCK0_NAME "keyladder_sck0"
#define EFUSE_KL_KEY0_NAME "keyladder_master_key0"
#define EFUSE_KL_SCK1_NAME "keyladder_sck1"
#define EFUSE_KL_KEY1_NAME "keyladder_master_key1"
#define SUNXI_KEY_NAME_LEN 64
#if EFUSE_DBG_EN
#define EFUSE_DBG(fmt,args...) hal_log_debug(fmt ,##args)
#define EFUSE_DBG_E 1
static unsigned int g_err_flg = 0;
#else
#define EFUSE_DBG_DUMP(...) do{} while(0);
#define EFUSE_DBG(...) do{} while(0);
#define EFUSE_DBG_E 0
#endif
static hal_spinlock_t efuse_lock;
int __efuse_acl_ck(efuse_key_map_new_t *key_map,int burn);
static efuse_key_map_new_t g_key_info[] = {
EFUSE_DEF_ITEM(EFUSE_CHIPID_NAME, 0x0, 128, -1, 0, EFUSE_RO),
EFUSE_DEF_ITEM(EFUSE_THM_SENSOR_NAME, EFUSE_THERMAL_SENSOR, 64, -1, 0, EFUSE_RO),
EFUSE_DEF_ITEM(EFUSE_FT_ZONE_NAME, EFUSE_TF_ZONE, 128, -1, 0, EFUSE_RO),
#ifdef EFUSE_ROTPK
EFUSE_DEF_ITEM(EFUSE_ROTPK_NAME, EFUSE_ROTPK, 256, -1, 12, EFUSE_RO),
#endif
#ifdef EFUSE_NV1
EFUSE_DEF_ITEM(EFUSE_NV1_NAME, EFUSE_NV1, 32, -1, 15, EFUSE_RO),
#endif
#ifdef EFUSE_PSENSOR
EFUSE_DEF_ITEM("psensor", EFUSE_PSENSOR, 32, -1, 15, EFUSE_RO),
#endif
#ifdef EFUSE_TVOUT
EFUSE_DEF_ITEM(EFUSE_TV_OUT_NAME, EFUSE_TVOUT, SID_TVOUT_SIZE, -1, -1, EFUSE_RO),
#endif
//EFUSE_DEF_ITEM("anti_blushing", EFUSE_ANTI_BLUSHING, 32, -1, 15, EFUSE_RO),
//EFUSE_DEF_ITEM(EFUSE_RESERVED_NAME, EFUSE_CLIENT_RESERVE, 256, -1, 12, EFUSE_RO),
EFUSE_DEF_ITEM("", 0, 0, 0, 0, EFUSE_PRIVATE),
};
static uint _efuse_reg_read_key(uint key_index)
{
uint reg_val;
uint32_t cpu_sr;
// taskENTER_CRITICAL(cpu_sr);
//rt_enter_critical();
cpu_sr = hal_spin_lock_irqsave(&efuse_lock);
reg_val = hal_readl((unsigned long)SID_PRCTL);
reg_val &= ~((0x1ff<<16)|0x3);
reg_val |= key_index<<16;
hal_writel(reg_val, (unsigned long)SID_PRCTL);
reg_val &= ~((0xff<<8)|0x3);
reg_val |= (SID_OP_LOCK<<8) | 0x2;
hal_writel(reg_val, (unsigned long)SID_PRCTL);
while(hal_readl(SID_PRCTL)&0x2){};
reg_val &= ~((0x1ff<<16)|(0xff<<8)|0x3);
hal_writel(reg_val, (unsigned long)SID_PRCTL);
reg_val = hal_readl((unsigned long)SID_RDKEY);
hal_spin_unlock_irqrestore(&efuse_lock, cpu_sr);
//rt_exit_critical();
// taskEXIT_CRITICAL(cpu_sr);
return reg_val;
}
static void _efuse_program_key(uint key_index, uint key_value)
{
uint reg_val;
uint32_t cpu_sr;
// taskENTER_CRITICAL(cpu_sr);
cpu_sr = hal_spin_lock_irqsave(&efuse_lock);
#ifdef EFUSE_HV_SWITCH
hal_writel(0x1, (unsigned long)EFUSE_HV_SWITCH);
#endif
hal_writel(key_value, SID_PRKEY);
reg_val = hal_readl((unsigned long)SID_PRCTL);
reg_val &= ~((0x1ff<<16)|0x3);
reg_val |= key_index<<16;
hal_writel(reg_val, (unsigned long)SID_PRCTL);
reg_val &= ~((0xff<<8)|0x3);
reg_val |= (SID_OP_LOCK<<8) | 0x1;
hal_writel(reg_val, (unsigned long)SID_PRCTL);
while(hal_readl((unsigned long)SID_PRCTL)&0x1){};
reg_val &= ~((0x1ff<<16)|(0xff<<8)|0x3);
hal_writel(reg_val, (unsigned long)SID_PRCTL);
#ifdef EFUSE_HV_SWITCH
hal_writel(0x0, (unsigned long)EFUSE_HV_SWITCH);
#endif
hal_spin_unlock_irqrestore(&efuse_lock, cpu_sr);
// taskEXIT_CRITICAL(cpu_sr);
return ;
}
static int _get_burned_flag(efuse_key_map_new_t *key_map)
{
if(key_map->burned_flg_offset < 0)
{
EFUSE_DBG("_get_burned_flag offset:%d\n", key_map->burned_flg_offset);
return 0;
}
else
{
EFUSE_DBG("_get_burned_flag val:%d\n", _efuse_reg_read_key(EFUSE_WRITE_PROTECT));
return (_efuse_reg_read_key(EFUSE_WRITE_PROTECT)
>> (key_map->burned_flg_offset & EFUSE_BRUN_RD_OFFSET_MASK)) & 1;
}
}
static int _sw_acl_ck(efuse_key_map_new_t *key_map,int burn)
{
if(key_map->sw_rule == EFUSE_PRIVATE)
{
EFUSE_DBG("\n[efuse]%s: PRIVATE\n",key_map->name);
return EFUSE_ERR_PRIVATE;
}
if(burn==0)
{
if(key_map->sw_rule == EFUSE_NACCESS)
{
EFUSE_DBG("\n[efuse]%s:NACCESS\n",key_map->name);
return EFUSE_ERR_NO_ACCESS;
}
}
else
{
/*If already burned:*/
if(_get_burned_flag(key_map))
{
EFUSE_DBG("\n[efuse]%s: already burned\n",key_map->name);
EFUSE_DBG("config reg:0x%x\n",efuse_sram_read_key(EFUSE_WRITE_PROTECT));
if(key_map->sw_rule == EFUSE_NACCESS)
return EFUSE_ERR_NO_ACCESS;
return EFUSE_ERR_ALREADY_BURNED;
}
if(key_map->sw_rule == EFUSE_RW)
{
/*modify burned_flg_offset&&rd_fbd_offset in case of the config bits been burned*/
key_map->burned_flg_offset |= EFUSE_ACL_SET_BRUN_BIT;
key_map->rd_fbd_offset |= EFUSE_ACL_SET_RD_FORBID_BIT;
}
else if(key_map->sw_rule == EFUSE_RO)
{
/*modify rd_fbd_offset in case of the config bit been burned*/
key_map->rd_fbd_offset |= EFUSE_ACL_SET_RD_FORBID_BIT;
}
}
return 0;
}
uint efuse_sram_read_key(uint key_index)
{
return hal_readl((unsigned long)EFUSE_SRAM + key_index);
}
/*Please reference 1728 spec page11 to know why to call _efuse_reg_read_key
* but efuse_sram_read_key
*burn efuse :efuse sram can not get the latest value
*unless via sid read or reboot.
*/
int efuse_uni_burn_key(uint key_index, uint key_value)
{
#define EFUSE_BURN_MAX_TRY_CNT 3
uint key_burn_bitmask = ~(efuse_sram_read_key(key_index)) & key_value;
int fail = 0;
while(key_burn_bitmask)
{
_efuse_program_key(key_index,key_burn_bitmask);
if(fail > EFUSE_BURN_MAX_TRY_CNT)
{
EFUSE_DBG("%s: **failed **",
__func__);
#if EFUSE_DBG_E
g_err_flg++;
#endif
return -1;
}
key_burn_bitmask &= (~(_efuse_reg_read_key(key_index)));
fail++;
}
return 0;
}
void efuse_set_cfg_flg(int efuse_cfg_base,int bit_offset)
{
if(efuse_uni_burn_key(efuse_cfg_base,(1<<bit_offset)))
{
EFUSE_DBG("[efuse] %s %d fatal err: **_set_cfg_flg [base:%d][offset:%d] **",
__FILE__,__LINE__,efuse_cfg_base,bit_offset);
}
return;
}
/*Efuse access control rule check.*/
int efuse_acl_ck(efuse_key_map_new_t *key_map,int burn)
{
/*For normal solution only check EFUSE_PRIVATE,other will be seemed as EFUSE_RW */
if(hal_efuse_get_security_mode() == 0)
{
if(key_map->sw_rule == EFUSE_PRIVATE)
{
return EFUSE_ERR_PRIVATE;
}
return 0;
}
int ret = _sw_acl_ck(key_map,burn);
if(ret)
{
EFUSE_DBG("[efuse]%s sw check failed\n",key_map->name);
return ret;
}
if(burn)
{
EFUSE_DBG("[efuse]burn %s burned bit check begin\n",key_map->name);
if(_get_burned_flag(key_map))
{
/*already burned*/
EFUSE_DBG("[efuse]%s:already burned\n",key_map->name);
EFUSE_DBG("config reg:0x%x\n",efuse_sram_read_key(EFUSE_WRITE_PROTECT));
return EFUSE_ERR_ALREADY_BURNED;
}
EFUSE_DBG("[efuse]burn %s burned bit check end\n",key_map->name);
}
else
{
if((key_map->rd_fbd_offset>=0)&&
((efuse_sram_read_key(EFUSE_READ_PROTECT) >>
(key_map->rd_fbd_offset & EFUSE_BRUN_RD_OFFSET_MASK)) & 1))
{
/*Read is not allowed because of the read forbidden bit was set*/
EFUSE_DBG("[efuse]%s forbid bit set\n",key_map->name);
EFUSE_DBG("config reg:0x%x\n",efuse_sram_read_key(EFUSE_READ_PROTECT));
return EFUSE_ERR_READ_FORBID;
}
}
return 0;
}
efuse_key_map_new_t *efuse_search_key_by_name(const char *key_name)
{
efuse_key_map_new_t *key_map = g_key_info;
for (; key_map->size != 0; key_map++) {
if (strlen(key_map->name) != strlen(key_name)) {
continue;
}
if (!memcmp(key_name, key_map->name, strlen(key_map->name))) {
break;
}
}
return key_map;
}