493 lines
11 KiB
C
493 lines
11 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <asm/arch/io.h>
|
|
#include <asm/arch/efuse.h>
|
|
#ifdef CONFIG_ARMV8_MULTIENTRY
|
|
#include <spinlock.h>
|
|
#ifdef CONFIG_EFUSE_OBJ_API
|
|
static spin_lock_t efuse_field_lock = {UNLOCK};
|
|
#endif
|
|
#endif
|
|
|
|
char efuse_buf[EFUSE_BYTES] = {0};
|
|
|
|
#if (IS_ENABLED(CONFIG_AMPK))
|
|
#include <tee.h>
|
|
|
|
#define PROVISION_PTA_UUID \
|
|
{ 0x24b17b16, 0x89d1, 0x43a3, \
|
|
{ 0x95, 0xed, 0x19, 0x3c, 0xe1, 0xed, 0xa7, 0x15 } }
|
|
#define PROVISION_PTA_CMD_AMPK_GET_DEVICE_PUBLIC_KEY (1)
|
|
#define PROVISION_PTA_CMD_AMPK_REGEN_ENC_KEY (2)
|
|
#define PROVISION_PTA_CMD_AMPK_INIT (3)
|
|
#define TEE_PARAM_NUM (4)
|
|
|
|
static int g_init_ampk;
|
|
#endif
|
|
|
|
ssize_t efuse_read(char *buf, size_t count, loff_t *ppos)
|
|
{
|
|
unsigned int pos = *ppos;
|
|
|
|
struct efuse_hal_api_arg arg;
|
|
unsigned int retcnt;
|
|
int ret;
|
|
|
|
arg.cmd = EFUSE_HAL_API_READ;
|
|
arg.offset = pos;
|
|
arg.size = count;
|
|
arg.buffer_phy = (unsigned long)buf;
|
|
arg.retcnt_phy = (unsigned long)&retcnt;
|
|
ret = meson_trustzone_efuse(&arg);
|
|
if (ret == 0) {
|
|
*ppos += retcnt;
|
|
return retcnt;
|
|
} else{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ssize_t efuse_read_cali(char *buf, size_t count, uint32_t offset)
|
|
{
|
|
#ifdef EFUSE_HAL_API_READ_CALI
|
|
char data[EFUSE_BYTES];
|
|
struct efuse_hal_api_arg arg;
|
|
unsigned long retcnt;
|
|
int ret;
|
|
memset(data, 0, count);
|
|
arg.cmd = EFUSE_HAL_API_READ_CALI;
|
|
arg.offset = offset;
|
|
arg.size = count;
|
|
arg.buffer_phy = (unsigned long)data;
|
|
arg.retcnt_phy = (unsigned long)&retcnt;
|
|
ret = meson_trustzone_efuse(&arg);
|
|
if (ret == 0) {
|
|
memcpy(buf, data, count);
|
|
printf("retcnt=%ld\n", retcnt);
|
|
return (unsigned int)retcnt;
|
|
} else{
|
|
return ret;
|
|
}
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int efuse_get_cali_cvbs(void)
|
|
{
|
|
#ifdef EFUSE_CALI_CVBS
|
|
efuse_cali_t cali_data;
|
|
int ret;
|
|
|
|
ret = efuse_read_cali((char *)&(cali_data), EFUSE_CALI_SIZE, 0x00);
|
|
if (ret == EFUSE_CALI_SIZE && cali_data.cvbs_flag)
|
|
return cali_data.cvbs_data;
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* return: >=0:succ and valid data, <0:fail
|
|
*/
|
|
int efuse_get_cali_item(char *str)
|
|
{
|
|
#ifdef EFUSE_HAL_API_READ_CALI_ITEM
|
|
int64_t ret;
|
|
|
|
extern int64_t meson_trustzone_efuse_caliItem(const char *str);
|
|
ret = meson_trustzone_efuse_caliItem(str);
|
|
|
|
return ret;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int efuse_check_pattern_item(char *str)
|
|
{
|
|
#ifdef EFUSE_HAL_API_CHECKPATTERN_ITEM
|
|
int64_t ret;
|
|
|
|
//extern int64_t meson_trustzone_efuse_lockitem(const char *str);
|
|
ret = meson_trustzone_efuse_lockitem(str);
|
|
return ret;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
ssize_t efuse_write(const char *buf, size_t count, loff_t *ppos)
|
|
{
|
|
unsigned int pos = *ppos;
|
|
|
|
if ((pos & 0xffff) >= EFUSE_BYTES)
|
|
return 0; /* Past EOF */
|
|
if (count > EFUSE_BYTES - pos)
|
|
count = EFUSE_BYTES - pos;
|
|
if (count > EFUSE_BYTES)
|
|
return -1;
|
|
|
|
struct efuse_hal_api_arg arg;
|
|
unsigned int retcnt;
|
|
|
|
arg.cmd = EFUSE_HAL_API_WRITE;
|
|
arg.offset = pos;
|
|
arg.size = count;
|
|
arg.buffer_phy = (unsigned long)buf;
|
|
arg.retcnt_phy = (unsigned long)&retcnt;
|
|
int ret;
|
|
|
|
ret = meson_trustzone_efuse(&arg);
|
|
if (ret == 0) {
|
|
*ppos = retcnt;
|
|
return retcnt;
|
|
} else{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
int efuse_read_usr(char *buf, size_t count, loff_t *ppos)
|
|
{
|
|
char data[EFUSE_BYTES];
|
|
char *pdata = NULL;
|
|
int ret;
|
|
loff_t pos;
|
|
|
|
memset(data, 0, count);
|
|
|
|
pdata = data;
|
|
pos = *ppos;
|
|
ret = efuse_read(pdata, count, (loff_t *)&pos);
|
|
|
|
memcpy(buf, data, count);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int efuse_write_usr(char *buf, size_t count, loff_t *ppos)
|
|
{
|
|
char data[EFUSE_BYTES];
|
|
char *pdata = NULL;
|
|
char *penc = NULL;
|
|
int ret;
|
|
loff_t pos;
|
|
|
|
if (count == 0) {
|
|
printf("data length: 0 is error!\n");
|
|
return -1;
|
|
}
|
|
|
|
memset(data, 0, EFUSE_BYTES);
|
|
memset(efuse_buf, 0, EFUSE_BYTES);
|
|
|
|
memcpy(data, buf, count);
|
|
pdata = data;
|
|
penc = efuse_buf;
|
|
|
|
memcpy(penc, pdata, count);
|
|
pos = *ppos;
|
|
|
|
ret = efuse_write(efuse_buf, count, (loff_t *)&pos);
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t efuse_get_max(void)
|
|
{
|
|
struct efuse_hal_api_arg arg;
|
|
int ret;
|
|
|
|
arg.cmd = EFUSE_HAL_API_USER_MAX;
|
|
|
|
ret = meson_trustzone_efuse_get_max(&arg);
|
|
if (ret == 0) {
|
|
printf("ERROR: can not get efuse user max bytes!!!\n");
|
|
return -1;
|
|
} else{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_EFUSE_OBJ_API
|
|
uint32_t efuse_obj_write(uint32_t obj_id, char *name, uint8_t *buff, uint32_t size)
|
|
{
|
|
uint32_t ret;
|
|
efuse_obj_field_t efuseinfo;
|
|
|
|
memset(&efuseinfo, 0, sizeof(efuseinfo));
|
|
strncpy(efuseinfo.name, name, sizeof(efuseinfo.name) - 1);
|
|
if (size > sizeof(efuseinfo.data))
|
|
return EFUSE_OBJ_ERR_SIZE;
|
|
efuseinfo.size = size;
|
|
memcpy(efuseinfo.data, buff, efuseinfo.size);
|
|
ret = meson_efuse_obj_write(obj_id, (uint8_t *)&efuseinfo, sizeof(efuseinfo));
|
|
return ret;
|
|
}
|
|
|
|
#if (IS_ENABLED(CONFIG_AMPK))
|
|
static uint32_t init_ampk(void)
|
|
{
|
|
int ret = CMD_RET_FAILURE;
|
|
struct udevice *dev = NULL;
|
|
struct tee_open_session_arg open_arg = { 0 };
|
|
struct tee_invoke_arg invoke_arg = { 0 };
|
|
struct tee_param param[TEE_PARAM_NUM] = { 0 };
|
|
const struct tee_optee_ta_uuid uuid = PROVISION_PTA_UUID;
|
|
|
|
if (g_init_ampk)
|
|
return 0;
|
|
|
|
dev = tee_find_device(NULL, NULL, NULL, NULL);
|
|
if (!dev) {
|
|
printf("tee find device failed\n");
|
|
return EFUSE_OBJ_ERR_OTHER_INTERNAL;
|
|
}
|
|
|
|
memset(&open_arg, 0, sizeof(open_arg));
|
|
tee_optee_ta_uuid_to_octets(open_arg.uuid, &uuid);
|
|
ret = tee_open_session(dev, &open_arg, 0, NULL);
|
|
if (ret) {
|
|
printf("open session failed, ret = 0x%x\n", ret);
|
|
return EFUSE_OBJ_ERR_OTHER_INTERNAL;
|
|
}
|
|
|
|
if (open_arg.ret) {
|
|
printf("open session failed, ret = 0x%x, ret_origin = 0x%x\n",
|
|
open_arg.ret, open_arg.ret_origin);
|
|
return EFUSE_OBJ_ERR_OTHER_INTERNAL;
|
|
}
|
|
|
|
param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
|
|
param[0].u.value.a = 0;
|
|
param[0].u.value.b = 0;
|
|
param[0].u.value.c = 0;
|
|
|
|
memset(&invoke_arg, 0, sizeof(invoke_arg));
|
|
invoke_arg.session = open_arg.session;
|
|
invoke_arg.func = PROVISION_PTA_CMD_AMPK_INIT;
|
|
|
|
ret = tee_invoke_func(dev, &invoke_arg, TEE_PARAM_NUM, param);
|
|
if (ret) {
|
|
printf("invoke failed, cmd = 0x%x, ret = 0x%x\n", invoke_arg.func, ret);
|
|
ret = EFUSE_OBJ_ERR_OTHER_INTERNAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (invoke_arg.ret) {
|
|
printf("invoke failed, cmd = 0x%x, ret = 0x%x, origin = 0x%x\n",
|
|
invoke_arg.func, invoke_arg.ret, invoke_arg.ret_origin);
|
|
ret = EFUSE_OBJ_ERR_OTHER_INTERNAL;
|
|
goto exit;
|
|
}
|
|
g_init_ampk = 1;
|
|
|
|
exit:
|
|
tee_close_session(dev, open_arg.session);
|
|
return ret;
|
|
}
|
|
|
|
uint32_t efuse_obj_enc_write(uint32_t obj_id, char *name, uint8_t *buff, uint32_t size)
|
|
{
|
|
uint32_t ret;
|
|
efuse_obj_enc_field_t efuseinfo;
|
|
size_t data_len;
|
|
const size_t IV_LEN = 12;
|
|
const size_t TAG_LEN = 16;
|
|
|
|
if (size <= IV_LEN + TAG_LEN)
|
|
return EFUSE_OBJ_ERR_SIZE;
|
|
data_len = size - IV_LEN - TAG_LEN;
|
|
if (data_len > sizeof(efuseinfo.data))
|
|
return EFUSE_OBJ_ERR_SIZE;
|
|
|
|
ret = init_ampk();
|
|
if (ret != EFUSE_OBJ_SUCCESS)
|
|
return ret;
|
|
|
|
memset(&efuseinfo, 0, sizeof(efuseinfo));
|
|
strncpy(efuseinfo.name, name, sizeof(efuseinfo.name) - 1);
|
|
efuseinfo.size = data_len;
|
|
memcpy(efuseinfo.data, buff, efuseinfo.size);
|
|
memcpy(efuseinfo.iv, buff + data_len, IV_LEN);
|
|
memcpy(efuseinfo.tag, buff + data_len + IV_LEN, TAG_LEN);
|
|
ret = meson_efuse_obj_write(obj_id, (uint8_t *)&efuseinfo, sizeof(efuseinfo));
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_AMPK */
|
|
|
|
uint32_t efuse_obj_read(uint32_t obj_id, char *name, uint8_t *buff, uint32_t *size)
|
|
{
|
|
uint32_t ret;
|
|
efuse_obj_field_t efuseinfo;
|
|
|
|
memset(&efuseinfo, 0, sizeof(efuseinfo));
|
|
strncpy(efuseinfo.name, name, sizeof(efuseinfo.name) - 1);
|
|
*size = sizeof(efuseinfo);
|
|
ret = meson_efuse_obj_read(obj_id, (uint8_t *)&efuseinfo, size);
|
|
memcpy(buff, efuseinfo.data, efuseinfo.size);
|
|
*size = efuseinfo.size;
|
|
return ret;
|
|
}
|
|
|
|
static int hex2bin(char *hex, void *bin, size_t hexlen)
|
|
{
|
|
int i, c, n1, n2, k;
|
|
|
|
k = 0;
|
|
n1 = -1;
|
|
n2 = -1;
|
|
for (i = 0; i < hexlen; i++) {
|
|
n2 = n1;
|
|
c = hex[i];
|
|
if (c >= '0' && c <= '9') {
|
|
n1 = c - '0';
|
|
} else if (c >= 'a' && c <= 'f') {
|
|
n1 = c - 'a' + 10;
|
|
} else if (c >= 'A' && c <= 'F') {
|
|
n1 = c - 'A' + 10;
|
|
} else if (c == ' ') {
|
|
n1 = -1;
|
|
continue;
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
if (n1 >= 0 && n2 >= 0) {
|
|
((uint8_t *)bin)[k] = (n2 << 4) | n1;
|
|
n1 = -1;
|
|
k++;
|
|
}
|
|
}
|
|
return k;
|
|
}
|
|
|
|
uint32_t efuse_obj_set_data(char *name, char *data)
|
|
{
|
|
uint32_t ret;
|
|
int dlen = strnlen(data, 64);
|
|
uint8_t databuf[32] = {0};
|
|
|
|
dlen = hex2bin(data, databuf, dlen);
|
|
if (dlen < 0) {
|
|
printf("parse data hex2bin error\n");
|
|
return EFUSE_OBJ_ERR_INVALID_DATA;
|
|
}
|
|
ret = efuse_obj_write(EFUSE_OBJ_EFUSE_DATA, name, databuf, dlen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if (IS_ENABLED(CONFIG_AMPK))
|
|
uint32_t efuse_obj_set_enc_data(char *name, char *data)
|
|
{
|
|
uint32_t ret;
|
|
int dlen = strnlen(data, 128);
|
|
uint8_t databuf[64] = {0};
|
|
|
|
dlen = hex2bin(data, databuf, dlen);
|
|
if (dlen < 0) {
|
|
printf("parse data hex2bin error\n");
|
|
return EFUSE_OBJ_ERR_INVALID_DATA;
|
|
}
|
|
ret = efuse_obj_enc_write(EFUSE_OBJ_EFUSE_ENC_DATA, name, databuf, dlen);
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
uint32_t efuse_obj_set_license(char *name)
|
|
{
|
|
uint32_t ret;
|
|
uint8_t databuf = 0x01;
|
|
|
|
ret = efuse_obj_write(EFUSE_OBJ_EFUSE_DATA, name, &databuf, 1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t efuse_obj_lock(char *name)
|
|
{
|
|
uint32_t ret;
|
|
uint8_t databuf = 0x01;
|
|
|
|
ret = efuse_obj_write(EFUSE_OBJ_LOCK_STATUS, name, &databuf, 1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
efuse_obj_field_t efuse_field;
|
|
|
|
uint32_t efuse_obj_get_data(char *name)
|
|
{
|
|
uint32_t ret;
|
|
uint8_t buff[32];
|
|
uint32_t bufflen = sizeof(buff);
|
|
|
|
#ifdef CONFIG_ARMV8_MULTIENTRY
|
|
spin_lock(&efuse_field_lock);
|
|
#endif
|
|
ret = efuse_obj_read(EFUSE_OBJ_EFUSE_DATA, name, buff, &bufflen);
|
|
if (ret == EFUSE_OBJ_SUCCESS) {
|
|
memset(&efuse_field, 0, sizeof(efuse_field));
|
|
strncpy(efuse_field.name, name, sizeof(efuse_field.name) - 1);
|
|
memcpy(efuse_field.data, buff, bufflen);
|
|
efuse_field.size = bufflen;
|
|
}
|
|
#ifdef CONFIG_ARMV8_MULTIENTRY
|
|
spin_unlock(&efuse_field_lock);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
uint32_t efuse_obj_get_lock(char *name)
|
|
{
|
|
uint32_t ret;
|
|
uint8_t buff[32];
|
|
uint32_t bufflen = sizeof(buff);
|
|
|
|
#ifdef CONFIG_ARMV8_MULTIENTRY
|
|
spin_lock(&efuse_field_lock);
|
|
#endif
|
|
ret = efuse_obj_read(EFUSE_OBJ_LOCK_STATUS, name, buff, &bufflen);
|
|
if (ret == EFUSE_OBJ_SUCCESS) {
|
|
memset(&efuse_field, 0, sizeof(efuse_field));
|
|
strncpy(efuse_field.name, name, sizeof(efuse_field.name) - 1);
|
|
memcpy(efuse_field.data, buff, bufflen);
|
|
efuse_field.size = bufflen;
|
|
}
|
|
#ifdef CONFIG_ARMV8_MULTIENTRY
|
|
spin_unlock(&efuse_field_lock);
|
|
#endif
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_EFUSE_OBJ_API */
|
|
|
|
#ifdef CONFIG_EFUSE_MRK_GET_CHECKNUM
|
|
uint32_t efuse_mrk_get_checknum(char *name, uint32_t longmrk, uint32_t *checksum)
|
|
{
|
|
uint32_t ret;
|
|
char mrk_name[16];
|
|
|
|
memset(mrk_name, 0, sizeof(mrk_name));
|
|
strncpy(mrk_name, name, sizeof(mrk_name) - 1);
|
|
ret = meson_efuse_mrk_get_checknum(name, longmrk, checksum);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_EFUSE_AUDIO_ID_CHECKNUM
|
|
int efuse_audio_id_get_checknum(void *out, int len)
|
|
{
|
|
uint32_t ret;
|
|
|
|
ret = meson_efuse_audio_id_get_checknum(out, len);
|
|
return ret;
|
|
}
|
|
#endif
|