1. add cvitek folders to u-boot-2021.10 2. add cv183x/cv182x part 3. add cv181x/cv180x part Change-Id: I6dc2e5ff509dbab16bd60bfb3fd61852da5e01f6
711 lines
17 KiB
C
711 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <malloc.h>
|
|
#include <mmio.h>
|
|
#include <cvi_efuse.h>
|
|
|
|
#define EFUSE_DEBUG 0
|
|
|
|
#define _cc_trace(fmt, ...) __trace("", __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
|
#define _cc_error(fmt, ...) __trace("ERROR:", __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
|
|
|
#define ERROR(fmt, ...) __trace("ERROR:", __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
|
|
|
#if EFUSE_DEBUG
|
|
|
|
#define VERBOSE(fmt, ...) __trace("VERBOSE:", __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__)
|
|
|
|
static int __trace(const char *prefix, const char *path, const char *func, int lineno, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
int ret;
|
|
|
|
printf("[%s%s:%s:%d] ", prefix, path, func, lineno);
|
|
if (!fmt || fmt[0] == '\0') {
|
|
ret = printf("\n");
|
|
} else {
|
|
va_start(ap, fmt);
|
|
ret = vprintf(fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#else
|
|
|
|
#define VERBOSE(fmt, ...)
|
|
|
|
static int __trace(const char *prefix, const char *path, const char *func, int lineno, const char *fmt, ...)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int hex2bytes(const char *hex, unsigned char *buf, int buf_size)
|
|
{
|
|
int i, total = 0;
|
|
char tmp[3];
|
|
|
|
memset(buf, 0, buf_size);
|
|
|
|
for (i = 0; i < buf_size; i++) {
|
|
if (!hex[0] || !hex[1])
|
|
break;
|
|
|
|
tmp[0] = hex[0];
|
|
tmp[1] = hex[1];
|
|
tmp[2] = '\0';
|
|
|
|
buf[i] = simple_strtoul(tmp, NULL, 16);
|
|
hex += 2;
|
|
total += 1;
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// EFUSE implementation
|
|
// ===========================================================================
|
|
#define EFUSE_SHADOW_REG (EFUSE_BASE + 0x100)
|
|
#define EFUSE_SIZE 0x100
|
|
|
|
#define EFUSE_MODE (EFUSE_BASE + 0x0)
|
|
#define EFUSE_ADR (EFUSE_BASE + 0x4)
|
|
#define EFUSE_DIR_CMD (EFUSE_BASE + 0x8)
|
|
#define EFUSE_RD_DATA (EFUSE_BASE + 0xC)
|
|
#define EFUSE_STATUS (EFUSE_BASE + 0x10)
|
|
#define EFUSE_ONE_WAY (EFUSE_BASE + 0x14)
|
|
|
|
#define EFUSE_BIT_AREAD BIT(0)
|
|
#define EFUSE_BIT_MREAD BIT(1)
|
|
#define EFUSE_BIT_PRG BIT(2)
|
|
#define EFUSE_BIT_PWR_DN BIT(3)
|
|
#define EFUSE_BIT_CMD BIT(4)
|
|
#define EFUSE_BIT_BUSY BIT(0)
|
|
#define EFUSE_CMD_REFRESH (0x30)
|
|
|
|
enum EFUSE_READ_TYPE { EFUSE_AREAD, EFUSE_MREAD };
|
|
|
|
static void cvi_efuse_wait_for_ready(void)
|
|
{
|
|
while (mmio_read_32(EFUSE_STATUS) & EFUSE_BIT_BUSY)
|
|
;
|
|
}
|
|
|
|
static void cvi_efuse_power_on(uint32_t on)
|
|
{
|
|
if (on)
|
|
mmio_setbits_32(EFUSE_MODE, EFUSE_BIT_CMD);
|
|
else
|
|
mmio_setbits_32(EFUSE_MODE, EFUSE_BIT_PWR_DN | EFUSE_BIT_CMD);
|
|
}
|
|
|
|
static void cvi_efuse_refresh(void)
|
|
{
|
|
mmio_write_32(EFUSE_MODE, EFUSE_CMD_REFRESH);
|
|
}
|
|
|
|
static void cvi_efuse_prog_bit(uint32_t word_addr, uint32_t bit_addr, uint32_t high_row)
|
|
{
|
|
uint32_t phy_addr;
|
|
|
|
// word_addr: virtual addr, take "lower 6-bits" from 7-bits (0-127)
|
|
// bit_addr: virtual addr, 5-bits (0-31)
|
|
|
|
// composite physical addr[11:0] = [11:7]bit_addr + [6:0]word_addr
|
|
phy_addr = ((bit_addr & 0x1F) << 7) | ((word_addr & 0x3F) << 1) | high_row;
|
|
|
|
cvi_efuse_wait_for_ready();
|
|
|
|
// send efuse program cmd
|
|
mmio_write_32(EFUSE_ADR, phy_addr);
|
|
mmio_write_32(EFUSE_MODE, EFUSE_BIT_PRG | EFUSE_BIT_CMD);
|
|
}
|
|
|
|
static uint32_t cvi_efuse_read_from_phy(uint32_t phy_word_addr, enum EFUSE_READ_TYPE type)
|
|
{
|
|
// power on efuse macro
|
|
cvi_efuse_power_on(1);
|
|
|
|
cvi_efuse_wait_for_ready();
|
|
|
|
mmio_write_32(EFUSE_ADR, phy_word_addr);
|
|
|
|
if (type == EFUSE_AREAD) // array read
|
|
mmio_write_32(EFUSE_MODE, EFUSE_BIT_AREAD | EFUSE_BIT_CMD);
|
|
else if (type == EFUSE_MREAD) // margin read
|
|
mmio_write_32(EFUSE_MODE, EFUSE_BIT_MREAD | EFUSE_BIT_CMD);
|
|
else {
|
|
ERROR("EFUSE: Unsupported read type!");
|
|
return (uint32_t)-1;
|
|
}
|
|
|
|
cvi_efuse_wait_for_ready();
|
|
|
|
return mmio_read_32(EFUSE_RD_DATA);
|
|
}
|
|
|
|
static int cvi_efuse_write_word(uint32_t vir_word_addr, uint32_t val)
|
|
{
|
|
uint32_t i, j, row_val, zero_bit;
|
|
uint32_t new_value;
|
|
int err_cnt = 0;
|
|
|
|
for (j = 0; j < 2; j++) {
|
|
VERBOSE("EFUSE: Program physical word addr #%d\n", (vir_word_addr << 1) | j);
|
|
|
|
// array read by word address
|
|
row_val = cvi_efuse_read_from_phy((vir_word_addr << 1) | j,
|
|
EFUSE_AREAD); // read low word of word_addr
|
|
zero_bit = val & (~row_val); // only program zero bit
|
|
|
|
// program row which bit is zero
|
|
for (i = 0; i < 32; i++) {
|
|
if ((zero_bit >> i) & 1)
|
|
cvi_efuse_prog_bit(vir_word_addr, i, j);
|
|
}
|
|
|
|
// check by margin read
|
|
new_value = cvi_efuse_read_from_phy((vir_word_addr << 1) | j, EFUSE_MREAD);
|
|
VERBOSE("%s(): val=0x%x new_value=0x%x\n", __func__, val, new_value);
|
|
if ((val & new_value) != val) {
|
|
err_cnt += 1;
|
|
ERROR("EFUSE: Program bits check failed (%d)!\n", err_cnt);
|
|
}
|
|
}
|
|
|
|
cvi_efuse_refresh();
|
|
|
|
return err_cnt >= 2 ? -EIO : 0;
|
|
}
|
|
|
|
static void cvi_efuse_init(void)
|
|
{
|
|
// power on efuse macro
|
|
cvi_efuse_power_on(1);
|
|
|
|
// send refresh cmd to reload all eFuse values to shadow registers
|
|
cvi_efuse_refresh();
|
|
|
|
// efuse macro will be auto powered off after refresh cmd, so don't
|
|
// need to turn it off manually
|
|
}
|
|
|
|
void cvi_efuse_dump(uint32_t vir_word_addr)
|
|
{
|
|
uint32_t j, val;
|
|
|
|
for (j = 0; j < 2; j++) {
|
|
// check by margin read
|
|
val = cvi_efuse_read_from_phy((vir_word_addr << 1) | j, EFUSE_MREAD);
|
|
printf("EFUSE EFUSE_MREAD: Program bits %d check 0x%x\n", j, val);
|
|
val = cvi_efuse_read_from_phy((vir_word_addr << 1) | j, EFUSE_AREAD);
|
|
printf("EFUSE EFUSE_AREAD: Program bits %d check 0x%x\n", j, val);
|
|
}
|
|
}
|
|
|
|
int64_t cvi_efuse_read_from_shadow(uint32_t addr)
|
|
{
|
|
if (addr >= EFUSE_SIZE)
|
|
return -EFAULT;
|
|
|
|
if (addr % 4 != 0)
|
|
return -EFAULT;
|
|
|
|
return mmio_read_32(EFUSE_SHADOW_REG + addr);
|
|
}
|
|
|
|
int cvi_efuse_write(uint32_t addr, uint32_t value)
|
|
{
|
|
int ret;
|
|
|
|
VERBOSE("%s(): 0x%x = 0x%x\n", __func__, addr, value);
|
|
|
|
if (addr >= EFUSE_SIZE)
|
|
return -EFAULT;
|
|
|
|
if (addr % 4 != 0)
|
|
return -EFAULT;
|
|
|
|
ret = cvi_efuse_write_word(addr / 4, value);
|
|
VERBOSE("%s(): ret=%d\n", __func__, ret);
|
|
cvi_efuse_init();
|
|
cvi_efuse_wait_for_ready();
|
|
|
|
return ret;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// EFUSE API
|
|
// ===========================================================================
|
|
enum CVI_EFUSE_LOCK_WRITE_E {
|
|
CVI_EFUSE_LOCK_WRITE_HASH0_PUBLIC = CVI_EFUSE_OTHERS + 1,
|
|
CVI_EFUSE_LOCK_WRITE_LOADER_EK,
|
|
CVI_EFUSE_LOCK_WRITE_DEVICE_EK,
|
|
CVI_EFUSE_LOCK_WRITE_LAST
|
|
};
|
|
|
|
static struct _CVI_EFUSE_AREA_S {
|
|
CVI_U32 addr;
|
|
CVI_U32 size;
|
|
} cvi_efuse_area[] = { [CVI_EFUSE_AREA_USER] = { 0x40, 40 },
|
|
[CVI_EFUSE_AREA_DEVICE_ID] = { 0x8c, 8 },
|
|
[CVI_EFUSE_AREA_HASH0_PUBLIC] = { 0xA8, 32 },
|
|
[CVI_EFUSE_AREA_LOADER_EK] = { 0xD8, 16 },
|
|
[CVI_EFUSE_AREA_DEVICE_EK] = { 0xE8, 16 } };
|
|
|
|
static struct _CVI_EFUSE_LOCK_S {
|
|
CVI_S32 wlock_shift;
|
|
CVI_S32 rlock_shift;
|
|
} cvi_efuse_lock[] = { [CVI_EFUSE_LOCK_HASH0_PUBLIC] = { 0, 8 }, [CVI_EFUSE_LOCK_LOADER_EK] = { 4, 12 },
|
|
[CVI_EFUSE_LOCK_DEVICE_EK] = { 6, 14 }, [CVI_EFUSE_LOCK_WRITE_HASH0_PUBLIC] = { 0, -1 },
|
|
[CVI_EFUSE_LOCK_WRITE_LOADER_EK] = { 4, -1 }, [CVI_EFUSE_LOCK_WRITE_DEVICE_EK] = { 6, -1 } };
|
|
|
|
static struct _CVI_EFUSE_USER_S {
|
|
CVI_U32 addr;
|
|
CVI_U32 size;
|
|
} cvi_efuse_user[] = {
|
|
{ 0x40, 4 }, { 0x48, 4 }, { 0x50, 4 }, { 0x58, 4 }, { 0x60, 4 },
|
|
{ 0x68, 4 }, { 0x70, 4 }, { 0x78, 4 }, { 0x80, 4 }, { 0x88, 4 },
|
|
};
|
|
|
|
#define CVI_EFUSE_TOTAL_SIZE 0x100
|
|
|
|
#define CVI_EFUSE_LOCK_ADDR 0xF8
|
|
#define CVI_EFUSE_SECURE_CONF_ADDR 0xA0
|
|
#define CVI_EFUSE_SCS_ENABLE_SHIFT 0
|
|
|
|
CVI_S32 CVI_EFUSE_GetSize(enum CVI_EFUSE_AREA_E area, CVI_U32 *size)
|
|
{
|
|
if (area >= ARRAY_SIZE(cvi_efuse_area) || cvi_efuse_area[area].size == 0) {
|
|
_cc_error("area (%d) is not found\n", area);
|
|
return CVI_ERR_EFUSE_INVALID_AREA;
|
|
}
|
|
|
|
if (size)
|
|
*size = cvi_efuse_area[area].size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
CVI_S32 _CVI_EFUSE_Read(CVI_U32 addr, void *buf, CVI_U32 buf_size)
|
|
{
|
|
int64_t ret = -1;
|
|
int i;
|
|
|
|
VERBOSE("%s(): 0x%x(%u) to %p\n", __func__, addr, buf_size, buf);
|
|
|
|
if (!buf)
|
|
return CVI_ERR_EFUSE_INVALID_PARA;
|
|
|
|
if (buf_size > EFUSE_SIZE)
|
|
buf_size = EFUSE_SIZE;
|
|
|
|
for (i = 0; i < buf_size; i += 4) {
|
|
ret = cvi_efuse_read_from_shadow(addr + i);
|
|
VERBOSE("%s(): i=%x ret=%lx\n", __func__, i, ret);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
*(uint32_t *)(buf + i) = (ret >= 0) ? ret : 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static CVI_S32 _CVI_EFUSE_Write(CVI_U32 addr, const void *buf, CVI_U32 buf_size)
|
|
{
|
|
_cc_trace("addr=0x%02x\n", addr);
|
|
|
|
int ret = -1;
|
|
|
|
CVI_U32 value;
|
|
int i;
|
|
|
|
if (!buf)
|
|
return CVI_ERR_EFUSE_INVALID_PARA;
|
|
|
|
for (i = 0; i < buf_size; i += 4) {
|
|
memcpy(&value, buf + i, sizeof(value));
|
|
|
|
_cc_trace("smc call: 0x%02x=0x%08x\n", addr + i, value);
|
|
ret = cvi_efuse_write(addr + i, value);
|
|
|
|
if (ret < 0) {
|
|
printf("%s: error (%d)\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
CVI_S32 CVI_EFUSE_Read(enum CVI_EFUSE_AREA_E area, CVI_U8 *buf, CVI_U32 buf_size)
|
|
{
|
|
CVI_U32 user_size = cvi_efuse_area[CVI_EFUSE_AREA_USER].size;
|
|
CVI_U8 user[user_size], *p;
|
|
CVI_S32 ret;
|
|
int i;
|
|
|
|
if (area >= ARRAY_SIZE(cvi_efuse_area) || cvi_efuse_area[area].size == 0) {
|
|
_cc_error("area (%d) is not found\n", area);
|
|
return CVI_ERR_EFUSE_INVALID_AREA;
|
|
}
|
|
|
|
if (!buf)
|
|
return CVI_ERR_EFUSE_INVALID_PARA;
|
|
|
|
memset(buf, 0, buf_size);
|
|
|
|
if (buf_size > cvi_efuse_area[area].size)
|
|
buf_size = cvi_efuse_area[area].size;
|
|
|
|
if (area != CVI_EFUSE_AREA_USER)
|
|
return _CVI_EFUSE_Read(cvi_efuse_area[area].addr, buf, buf_size);
|
|
|
|
memset(user, 0, user_size);
|
|
|
|
p = user;
|
|
for (i = 0; i < ARRAY_SIZE(cvi_efuse_user); i++) {
|
|
ret = _CVI_EFUSE_Read(cvi_efuse_user[i].addr, p, cvi_efuse_user[i].size);
|
|
if (ret < 0)
|
|
return ret;
|
|
p += cvi_efuse_user[i].size;
|
|
}
|
|
|
|
memcpy(buf, user, buf_size);
|
|
|
|
return CVI_SUCCESS;
|
|
}
|
|
|
|
CVI_S32 CVI_EFUSE_Write(enum CVI_EFUSE_AREA_E area, const CVI_U8 *buf, CVI_U32 buf_size)
|
|
{
|
|
CVI_U32 user_size = cvi_efuse_area[CVI_EFUSE_AREA_USER].size;
|
|
CVI_U8 user[user_size], *p;
|
|
CVI_S32 ret;
|
|
int i;
|
|
|
|
if (area >= ARRAY_SIZE(cvi_efuse_area) || cvi_efuse_area[area].size == 0) {
|
|
_cc_error("area (%d) is not found\n", area);
|
|
return CVI_ERR_EFUSE_INVALID_AREA;
|
|
}
|
|
if (!buf)
|
|
return CVI_ERR_EFUSE_INVALID_PARA;
|
|
|
|
if (buf_size > cvi_efuse_area[area].size)
|
|
buf_size = cvi_efuse_area[area].size;
|
|
|
|
if (area != CVI_EFUSE_AREA_USER)
|
|
return _CVI_EFUSE_Write(cvi_efuse_area[area].addr, buf, buf_size);
|
|
|
|
memset(user, 0, user_size);
|
|
memcpy(user, buf, buf_size);
|
|
|
|
p = user;
|
|
for (i = 0; i < ARRAY_SIZE(cvi_efuse_user); i++) {
|
|
ret = _CVI_EFUSE_Write(cvi_efuse_user[i].addr, p, cvi_efuse_user[i].size);
|
|
if (ret < 0)
|
|
return ret;
|
|
p += cvi_efuse_user[i].size;
|
|
}
|
|
|
|
return CVI_SUCCESS;
|
|
}
|
|
|
|
CVI_S32 CVI_EFUSE_EnableSecureBoot(void)
|
|
{
|
|
CVI_U32 value = 0x3 << CVI_EFUSE_SCS_ENABLE_SHIFT;
|
|
|
|
return _CVI_EFUSE_Write(CVI_EFUSE_SECURE_CONF_ADDR, &value, sizeof(value));
|
|
}
|
|
|
|
CVI_S32 CVI_EFUSE_IsSecureBootEnabled(void)
|
|
{
|
|
CVI_U32 value = 0;
|
|
CVI_S32 ret = 0;
|
|
|
|
ret = _CVI_EFUSE_Read(CVI_EFUSE_SECURE_CONF_ADDR, &value, sizeof(value));
|
|
_cc_trace("ret=%d value=%u\n", ret, value);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
value &= 0x3 << CVI_EFUSE_SCS_ENABLE_SHIFT;
|
|
return !!value;
|
|
}
|
|
|
|
CVI_S32 CVI_EFUSE_Lock(enum CVI_EFUSE_LOCK_E lock)
|
|
{
|
|
CVI_U32 value = 0;
|
|
CVI_U32 ret = 0;
|
|
|
|
if (lock >= ARRAY_SIZE(cvi_efuse_lock)) {
|
|
_cc_error("lock (%d) is not found\n", lock);
|
|
return CVI_ERR_EFUSE_INVALID_AREA;
|
|
}
|
|
|
|
value = 0x3 << cvi_efuse_lock[lock].wlock_shift;
|
|
ret = _CVI_EFUSE_Write(CVI_EFUSE_LOCK_ADDR, &value, sizeof(value));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (cvi_efuse_lock[lock].rlock_shift >= 0) {
|
|
value = 0x3 << cvi_efuse_lock[lock].rlock_shift;
|
|
ret = _CVI_EFUSE_Write(CVI_EFUSE_LOCK_ADDR, &value, sizeof(value));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
CVI_S32 CVI_EFUSE_IsLocked(enum CVI_EFUSE_LOCK_E lock)
|
|
{
|
|
CVI_S32 ret = 0;
|
|
CVI_U32 value = 0;
|
|
|
|
if (lock >= ARRAY_SIZE(cvi_efuse_lock)) {
|
|
_cc_error("lock (%d) is not found\n", lock);
|
|
return CVI_ERR_EFUSE_INVALID_AREA;
|
|
}
|
|
|
|
ret = _CVI_EFUSE_Read(CVI_EFUSE_LOCK_ADDR, &value, sizeof(value));
|
|
_cc_trace("ret=%d value=%u\n", ret, value);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
value &= 0x3 << cvi_efuse_lock[lock].wlock_shift;
|
|
return !!value;
|
|
}
|
|
|
|
CVI_S32 CVI_EFUSE_LockWrite(enum CVI_EFUSE_LOCK_E lock)
|
|
{
|
|
CVI_U32 value = 0;
|
|
CVI_S32 ret = 0;
|
|
|
|
if (lock >= ARRAY_SIZE(cvi_efuse_lock)) {
|
|
_cc_error("lock (%d) is not found\n", lock);
|
|
return CVI_ERR_EFUSE_INVALID_AREA;
|
|
}
|
|
|
|
value = 0x3 << cvi_efuse_lock[lock].wlock_shift;
|
|
ret = _CVI_EFUSE_Write(CVI_EFUSE_LOCK_ADDR, &value, sizeof(value));
|
|
return ret;
|
|
}
|
|
|
|
CVI_S32 CVI_EFUSE_IsWriteLocked(enum CVI_EFUSE_LOCK_E lock)
|
|
{
|
|
CVI_S32 ret = 0;
|
|
CVI_U32 value = 0;
|
|
|
|
if (lock >= ARRAY_SIZE(cvi_efuse_lock)) {
|
|
_cc_error("lock (%d) is not found\n", lock);
|
|
return CVI_ERR_EFUSE_INVALID_AREA;
|
|
}
|
|
|
|
ret = _CVI_EFUSE_Read(CVI_EFUSE_LOCK_ADDR, &value, sizeof(value));
|
|
_cc_trace("ret=%d value=%u\n", ret, value);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
value &= 0x3 << cvi_efuse_lock[lock].wlock_shift;
|
|
return !!value;
|
|
}
|
|
|
|
static const char *const efuse_index[] = {
|
|
[CVI_EFUSE_AREA_USER] = "USER",
|
|
[CVI_EFUSE_AREA_DEVICE_ID] = "DEVICE_ID",
|
|
[CVI_EFUSE_AREA_HASH0_PUBLIC] = "HASH0_PUBLIC",
|
|
[CVI_EFUSE_AREA_LOADER_EK] = "LOADER_EK",
|
|
[CVI_EFUSE_AREA_DEVICE_EK] = "DEVICE_EK",
|
|
[CVI_EFUSE_LOCK_HASH0_PUBLIC] = "LOCK_HASH0_PUBLIC",
|
|
[CVI_EFUSE_LOCK_LOADER_EK] = "LOCK_LOADER_EK",
|
|
[CVI_EFUSE_LOCK_DEVICE_EK] = "LOCK_DEVICE_EK",
|
|
[CVI_EFUSE_LOCK_WRITE_HASH0_PUBLIC] = "LOCK_WRITE_HASH0_PUBLIC",
|
|
[CVI_EFUSE_LOCK_WRITE_LOADER_EK] = "LOCK_WRITE_LOADER_EK",
|
|
[CVI_EFUSE_LOCK_WRITE_DEVICE_EK] = "LOCK_WRITE_DEVICE_EK",
|
|
[CVI_EFUSE_SECUREBOOT] = "SECUREBOOT",
|
|
};
|
|
|
|
static int find_efuse_by_name(const char *name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(efuse_index); i++) {
|
|
if (!efuse_index[i])
|
|
continue;
|
|
|
|
if (!strcmp(name, efuse_index[i]))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int do_efuser(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
|
{
|
|
int idx;
|
|
int ret;
|
|
unsigned int size;
|
|
unsigned char buf[128];
|
|
|
|
if (argc != 2)
|
|
return CMD_RET_USAGE;
|
|
|
|
_cc_trace("Read eFuse: %s\n", argv[1]);
|
|
idx = find_efuse_by_name(argv[1]);
|
|
if (idx < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
_cc_trace("idx=%d %s\n", idx, efuse_index[idx]);
|
|
|
|
if (idx < CVI_EFUSE_AREA_LAST) {
|
|
if (CVI_EFUSE_GetSize(idx, &size) < 0)
|
|
return CMD_RET_FAILURE;
|
|
|
|
_cc_trace("size=%d\n", size);
|
|
|
|
if (CVI_EFUSE_Read(idx, buf, size) < 0)
|
|
return CMD_RET_FAILURE;
|
|
|
|
print_buffer(0, buf, 1, size, 0);
|
|
return 0;
|
|
} else if (idx < CVI_EFUSE_LOCK_LAST) {
|
|
ret = CVI_EFUSE_IsLocked(idx);
|
|
printf("%s is %s locked\n", efuse_index[idx], ret ? "" : "not");
|
|
return 0;
|
|
} else if (idx < CVI_EFUSE_LOCK_WRITE_LAST) {
|
|
ret = CVI_EFUSE_IsWriteLocked(idx);
|
|
printf("%s is %s write_locked\n", efuse_index[idx], ret ? "" : "not");
|
|
return 0;
|
|
} else if (idx == CVI_EFUSE_SECUREBOOT) {
|
|
ret = CVI_EFUSE_IsSecureBootEnabled();
|
|
printf("Secure Boot is %s\n", ret ? "enabled" : "disabled");
|
|
return 0;
|
|
}
|
|
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
static int do_efusew(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
|
{
|
|
int idx;
|
|
int ret;
|
|
unsigned int size;
|
|
unsigned char buf[128] = { 0 };
|
|
|
|
_cc_trace("argc=%d\n", argc);
|
|
|
|
if (argc != 2 && argc != 3)
|
|
return CMD_RET_USAGE;
|
|
|
|
_cc_trace("Write eFuse: %s=%s\n", argv[1], argv[2]);
|
|
idx = find_efuse_by_name(argv[1]);
|
|
if (idx < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
_cc_trace("idx=%d %s\n", idx, efuse_index[idx]);
|
|
printf("Write eFuse %s(%d) with:\n", efuse_index[idx], idx);
|
|
|
|
if (idx < CVI_EFUSE_AREA_LAST) {
|
|
if (argc != 3)
|
|
return CMD_RET_USAGE;
|
|
|
|
size = hex2bytes(argv[2], buf, sizeof(buf));
|
|
if (size <= 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
print_buffer(0, buf, 1, size, 0);
|
|
|
|
if (CVI_EFUSE_GetSize(idx, &size) < 0)
|
|
return CMD_RET_FAILURE;
|
|
|
|
_cc_trace("size=%d\n", size);
|
|
|
|
ret = CVI_EFUSE_Write(idx, buf, size);
|
|
if (ret < 0) {
|
|
printf("Failed to write %s\n", efuse_index[idx]);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
return 0;
|
|
|
|
} else if (idx < CVI_EFUSE_LOCK_LAST) {
|
|
if (CVI_EFUSE_Lock(idx) < 0) {
|
|
printf("Failed to lock %s\n", efuse_index[idx]);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
printf("%s is locked\n", efuse_index[idx]);
|
|
return 0;
|
|
} else if (idx < CVI_EFUSE_LOCK_WRITE_LAST) {
|
|
if (CVI_EFUSE_LockWrite(idx) < 0) {
|
|
printf("Failed to lock write %s\n", efuse_index[idx]);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
printf("%s is locked\n", efuse_index[idx]);
|
|
return 0;
|
|
|
|
} else if (idx == CVI_EFUSE_SECUREBOOT) {
|
|
ret = CVI_EFUSE_EnableSecureBoot();
|
|
printf("Enabled Secure Boot is %s\n", ret >= 0 ? "success" : "failed");
|
|
return 0;
|
|
}
|
|
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
static int do_efusew_word(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
|
{
|
|
uint32_t addr, value;
|
|
int ret = -1;
|
|
|
|
if (argc != 3)
|
|
return CMD_RET_USAGE;
|
|
|
|
addr = simple_strtoul(argv[1], NULL, 0);
|
|
value = simple_strtoul(argv[2], NULL, 0);
|
|
|
|
printf("Write eFuse: 0x%04x=0x%08x\n", addr, value);
|
|
|
|
ret = cvi_efuse_write(addr, value);
|
|
|
|
if (ret < 0) {
|
|
printf("ERROR: ret=%d\n", ret);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_efuser_dump(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
|
{
|
|
int i;
|
|
uint32_t buf[EFUSE_SIZE / sizeof(uint32_t)];
|
|
|
|
for (i = 0; i < ARRAY_SIZE(buf); i++)
|
|
buf[i] = cvi_efuse_read_from_shadow(i * sizeof(uint32_t));
|
|
|
|
print_buffer(0, buf, 1, sizeof(buf), 16);
|
|
|
|
return 0;
|
|
}
|
|
|
|
U_BOOT_CMD(efuser, 9, 1, do_efuser, "Read efuse",
|
|
"[args..]\n"
|
|
" - args ...");
|
|
|
|
U_BOOT_CMD(efusew, 9, 1, do_efusew, "Write efuse",
|
|
"[args..]\n"
|
|
" - args ...");
|
|
|
|
U_BOOT_CMD(efusew_word, 9, 1, do_efusew_word, "Write word to efuse",
|
|
"efusew_word addr value\n"
|
|
" - args ...");
|
|
|
|
U_BOOT_CMD(efuser_dump, 9, 1, do_efuser_dump, "Read/Dump efuse",
|
|
"do_efuser_dump\n"
|
|
" - args ..."); |