common/recipes-core/otp/files/otp.c (1,885 lines of code) (raw):
/*
* otp
*
* Copyright 2021-present Facebook. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <termios.h>
#include <termios.h>
#include <ctype.h>
#include "aspeed-otp.h"
#include "otp_info.h"
#include "sha256.h"
#define OTP_VER "1.1.0"
#define BIT(nr) (1UL << (nr))
#define OTP_REGION_STRAP BIT(0)
#define OTP_REGION_CONF BIT(1)
#define OTP_REGION_DATA BIT(2)
#define OTP_USAGE -1
#define OTP_FAILURE -2
#define OTP_SUCCESS 0
#define OTP_PROG_SKIP 1
#define OTP_KEY_TYPE_RSA_PUB 1
#define OTP_KEY_TYPE_RSA_PRIV 2
#define OTP_KEY_TYPE_AES 3
#define OTP_KEY_TYPE_VAULT 4
#define OTP_KEY_TYPE_HMAC 5
#define OTP_MAGIC "SOCOTP"
#define CHECKSUM_LEN 32
#define OTP_INC_DATA BIT(31)
#define OTP_INC_CONF BIT(30)
#define OTP_INC_STRAP BIT(29)
#define OTP_ECC_EN BIT(28)
#define OTP_REGION_SIZE(info) (((info) >> 16) & 0xffff)
#define OTP_REGION_OFFSET(info) ((info) & 0xffff)
#define OTP_IMAGE_SIZE(info) ((info) & 0xffff)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
struct otp_header {
u8 otp_magic[8];
u8 otp_version[8];
u32 image_info;
u32 data_info;
u32 conf_info;
u32 strap_info;
u32 checksum_offset;
} __packed;
struct otpstrap_status {
int value;
int option_array[7];
int remain_times;
int writeable_option;
int reg_protected;
int protected;
};
struct otpconf_parse {
int dw_offset;
int bit;
int length;
int value;
int ignore;
char status[80];
};
struct otpkey_type {
int value;
int key_type;
int need_id;
char information[110];
};
struct otp_info_cb {
int otp_fd;
int version;
const struct otpstrap_info *strap_info;
int strap_info_len;
const struct otpconf_info *conf_info;
int conf_info_len;
const struct otpkey_type *key_info;
int key_info_len;
};
struct otp_image_layout {
int data_length;
int conf_length;
int strap_length;
uint8_t *data;
uint8_t *data_ignore;
uint8_t *conf;
uint8_t *conf_ignore;
uint8_t *strap;
uint8_t *strap_reg_pro;
uint8_t *strap_pro;
uint8_t *strap_ignore;
};
static struct otp_info_cb info_cb;
static const struct otpkey_type a0_key_type[] = {
{0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"},
{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
{4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
{8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"},
{9, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as SOC public key"},
{10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"},
{13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as SOC private key"},
{14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"},
};
static const struct otpkey_type a1_key_type[] = {
{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
{2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
{8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"},
{10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"},
{14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"},
};
static const struct otpkey_type a2_key_type[] = {
{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
{2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
{8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"},
{10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"},
{14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"},
};
static const struct otpkey_type a3_key_type[] = {
{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
{2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
{8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"},
{9, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
{10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"},
{11, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key(big endian)"},
{12, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"},
{13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key(big endian)"},
};
int confirm_yesno(void)
{
int i;
char str_input[5];
i = 0;
while (i < sizeof(str_input)) {
str_input[i] = getc(stdin);
if (str_input[i] == '\n')
break;
i++;
}
if (strncmp(str_input, "y\n", 2) == 0 ||
strncmp(str_input, "Y\n", 2) == 0 ||
strncmp(str_input, "yes\n", 4) == 0 ||
strncmp(str_input, "YES\n", 4) == 0)
return 1;
return 0;
}
static void buf_print(uint8_t *buf, int len)
{
int i;
printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
for (i = 0; i < len; i++) {
if (i % 16 == 0)
printf("%04X: ", i);
printf("%02X ", buf[i]);
if ((i + 1) % 16 == 0)
printf("\n");
}
}
static int get_dw_bit(uint32_t *rid, int offset)
{
int bit_offset;
int i;
if (offset < 32) {
i = 0;
bit_offset = offset;
} else {
i = 1;
bit_offset = offset - 32;
}
if ((rid[i] >> bit_offset) & 0x1)
return 1;
else
return 0;
}
static int get_rid_num(uint32_t *rid)
{
int i;
int fz = 0;
int rid_num = 0;
int ret = 0;
for (i = 0; i < 64; i++) {
if (get_dw_bit(rid, i) == 0) {
if (!fz)
fz = 1;
} else {
rid_num++;
if (fz)
ret = OTP_FAILURE;
}
}
if (ret)
return ret;
return rid_num;
}
static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit)
{
int prog_flag = 0;
// ignore this bit
if (ibit == 1)
return OTP_SUCCESS;
printf("OTPSTRAP[%X]:\n", offset);
if (bit == otpstrap->value) {
if (!pbit && !rpbit) {
printf(" The value is same as before, skip it.\n");
return OTP_PROG_SKIP;
}
printf(" The value is same as before.\n");
} else {
prog_flag = 1;
}
if (otpstrap->protected == 1 && prog_flag) {
printf(" This bit is protected and is not writable\n");
return OTP_FAILURE;
}
if (otpstrap->remain_times == 0 && prog_flag) {
printf(" This bit is no remaining times to write.\n");
return OTP_FAILURE;
}
if (pbit == 1)
printf(" This bit will be protected and become non-writable.\n");
if (rpbit == 1 && info_cb.version != OTP_A0)
printf(" The relative register will be protected.\n");
if (prog_flag)
printf(" Write 1 to OTPSTRAP[%X] OPTION[%X], that value becomes from %d to %d.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1);
return OTP_SUCCESS;
}
static uint32_t chip_version(void)
{
uint32_t ver;
int ret;
ret = ioctl(info_cb.otp_fd, ASPEED_OTP_VER, &ver);
if (ret < 0) {
printf("ioctl err:%d\n", ret);
return OTP_FAILURE;
}
return ver;
}
static uint32_t sw_revid(u32 *sw_rid)
{
int ret;
ret = ioctl(info_cb.otp_fd, ASPEED_OTP_SW_RID, sw_rid);
if (ret < 0) {
printf("ioctl err:%d\n", ret);
return OTP_FAILURE;
}
return OTP_SUCCESS;
}
static int _otp_read(uint32_t offset, int len, uint32_t *data, unsigned long req)
{
int ret;
struct otp_read xfer;
xfer.data = data;
xfer.offset = offset;
xfer.len = len;
ret = ioctl(info_cb.otp_fd, req, &xfer);
if (ret < 0) {
printf("ioctl err:%d\n", ret);
return OTP_FAILURE;
}
return OTP_SUCCESS;
}
static int _otp_prog(uint32_t dw_offset, uint32_t bit_offset, uint32_t value, unsigned long req)
{
int ret;
struct otp_prog prog;
prog.dw_offset = dw_offset;
prog.bit_offset = bit_offset;
prog.value = value;
ret = ioctl(info_cb.otp_fd, req, &prog);
if (ret < 0) {
printf("ioctl err:%d\n", ret);
return OTP_FAILURE;
}
return OTP_SUCCESS;
}
static int otp_read_conf_buf(uint32_t offset, int len, uint32_t *data)
{
return _otp_read(offset, len, data, ASPEED_OTP_READ_CONF);
}
static int otp_read_data_buf(uint32_t offset, int len, uint32_t *data)
{
return _otp_read(offset, len, data, ASPEED_OTP_READ_DATA);
}
static int otp_read_conf(uint32_t offset, uint32_t *data)
{
return _otp_read(offset, 1, data, ASPEED_OTP_READ_CONF);
}
static int otp_read_data(uint32_t offset, uint32_t *data)
{
return _otp_read(offset, 1, data, ASPEED_OTP_READ_DATA);
}
static void otp_read_strap(struct otpstrap_status *otpstrap)
{
uint32_t OTPSTRAP_RAW[16];
int strap_end;
int i, j, k;
char bit_value;
int option;
if (info_cb.version == OTP_A0) {
for (j = 0; j < 64; j++) {
otpstrap[j].value = 0;
otpstrap[j].remain_times = 7;
otpstrap[j].writeable_option = -1;
otpstrap[j].protected = 0;
}
strap_end = 30;
} else {
for (j = 0; j < 64; j++) {
otpstrap[j].value = 0;
otpstrap[j].remain_times = 6;
otpstrap[j].writeable_option = -1;
otpstrap[j].reg_protected = 0;
otpstrap[j].protected = 0;
}
strap_end = 28;
}
otp_read_conf_buf(16, 16, OTPSTRAP_RAW);
for (i = 16, k = 0; i < strap_end; i += 2, k += 2) {
option = (i - 16) / 2;
for (j = 0; j < 32; j++) {
bit_value = ((OTPSTRAP_RAW[k] >> j) & 0x1);
if (bit_value == 0 && (otpstrap[j].writeable_option == -1))
otpstrap[j].writeable_option = option;
if (bit_value == 1)
otpstrap[j].remain_times--;
otpstrap[j].value ^= bit_value;
otpstrap[j].option_array[option] = bit_value;
}
for (j = 32; j < 64; j++) {
bit_value = ((OTPSTRAP_RAW[k + 1] >> (j - 32)) & 0x1);
if (bit_value == 0 && otpstrap[j].writeable_option == -1)
otpstrap[j].writeable_option = option;
if (bit_value == 1)
otpstrap[j].remain_times--;
otpstrap[j].value ^= bit_value;
otpstrap[j].option_array[option] = bit_value;
}
}
if (info_cb.version != OTP_A0) {
for (j = 0; j < 32; j++) {
if (((OTPSTRAP_RAW[12] >> j) & 0x1) == 1)
otpstrap[j].reg_protected = 1;
}
for (j = 32; j < 64; j++) {
if (((OTPSTRAP_RAW[13] >> (j - 32)) & 0x1) == 1)
otpstrap[j].reg_protected = 1;
}
}
for (j = 0; j < 32; j++) {
if (((OTPSTRAP_RAW[14] >> j) & 0x1) == 1)
otpstrap[j].protected = 1;
}
for (j = 32; j < 64; j++) {
if (((OTPSTRAP_RAW[15] >> (j - 32)) & 0x1) == 1)
otpstrap[j].protected = 1;
}
}
static int otp_prog_data_b(uint32_t dw_offset, uint32_t bit_offset, uint32_t value)
{
return _otp_prog(dw_offset, bit_offset, value, ASPEED_OTP_PROG_DATA);
}
static int otp_prog_conf_b(uint32_t dw_offset, uint32_t bit_offset, uint32_t value)
{
return _otp_prog(dw_offset, bit_offset, value, ASPEED_OTP_PROG_CONF);
}
static int otp_prog_strap_b(int bit_offset, int value)
{
struct otpstrap_status otpstrap[64];
uint32_t prog_address;
int offset;
int ret;
otp_read_strap(otpstrap);
ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
if (ret != OTP_SUCCESS)
return ret;
if (bit_offset < 32) {
offset = bit_offset;
prog_address = otpstrap[bit_offset].writeable_option * 2 + 16;
} else {
offset = (bit_offset - 32);
prog_address = otpstrap[bit_offset].writeable_option * 2 + 17;
}
return otp_prog_conf_b(prog_address, offset, 1);
}
static int otp_prog_data_dw(uint32_t value, uint32_t ignore, uint32_t prog_address)
{
int j, bit_value;
int ret;
for (j = 0; j < 32; j++) {
if ((ignore >> j) & 0x1)
continue;
bit_value = (value >> j) & 0x1;
if (prog_address % 2 == 0) {
if (!bit_value)
continue;
} else {
if (bit_value)
continue;
}
ret = otp_prog_data_b(prog_address, j, bit_value);
if (ret)
return ret;
}
return OTP_SUCCESS;
}
static int otp_print_conf(uint32_t offset, int dw_count)
{
int i, j;
uint32_t ret[32];
if (otp_read_conf_buf(offset, dw_count, ret))
return OTP_FAILURE;
for (i = offset, j = 0; j < dw_count; i++, j++)
printf("OTPCFG%X: %08X\n", i, ret[j]);
printf("\n");
return OTP_SUCCESS;
}
static int otp_print_data(uint32_t offset, int dw_count)
{
int i, j;
uint32_t ret[2048];
if (otp_read_data_buf(offset, dw_count, ret))
return OTP_FAILURE;
for (i = offset, j = 0; j < dw_count; i++, j++) {
if (i % 4 == 0)
printf("%03X: %08X ", i * 4, ret[j]);
else
printf("%08X ", ret[j]);
if ((j + 1) % 4 == 0)
printf("\n");
}
printf("\n");
return OTP_SUCCESS;
}
static int otp_print_strap(int offset, int count)
{
int i, j;
int remains;
struct otpstrap_status otpstrap[64];
otp_read_strap(otpstrap);
if (info_cb.version == OTP_A0) {
remains = 7;
printf("BIT(hex) Value Option Status\n");
} else {
remains = 6;
printf("BIT(hex) Value Option Reg_Protect Status\n");
}
printf("______________________________________________________________________________\n");
for (i = offset; i < offset + count; i++) {
printf("0x%-8X", i);
printf("%-7d", otpstrap[i].value);
for (j = 0; j < remains; j++)
printf("%d ", otpstrap[i].option_array[j]);
printf(" ");
if (info_cb.version != OTP_A0)
printf("%d ", otpstrap[i].reg_protected);
if (otpstrap[i].protected == 1) {
printf("protected and not writable");
} else {
printf("not protected ");
if (otpstrap[i].remain_times == 0)
printf("and no remaining times to write.");
else
printf("and still can write %d times", otpstrap[i].remain_times);
}
printf("\n");
}
return OTP_SUCCESS;
}
static void otp_print_revid(uint32_t *rid)
{
int bit_offset;
int i, j;
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
printf("___________________________________________________\n");
for (i = 0; i < 64; i++) {
if (i < 32) {
j = 0;
bit_offset = i;
} else {
j = 1;
bit_offset = i - 32;
}
if (i % 16 == 0)
printf("%2x | ", i);
printf("%d ", (rid[j] >> bit_offset) & 0x1);
if ((i + 1) % 16 == 0)
printf("\n");
}
}
static int otp_print_conf_image(struct otp_image_layout *image_layout)
{
const struct otpconf_info *conf_info = info_cb.conf_info;
uint32_t *OTPCFG = (uint32_t *)image_layout->conf;
uint32_t *OTPCFG_IGNORE = (uint32_t *)image_layout->conf_ignore;
uint32_t mask;
uint32_t dw_offset;
uint32_t bit_offset;
uint32_t otp_value;
uint32_t otp_ignore;
int fail = 0;
int mask_err;
int rid_num = 0;
char valid_bit[20];
int fz;
int i;
int j;
printf("DW BIT Value Description\n");
printf("__________________________________________________________________________\n");
for (i = 0; i < info_cb.conf_info_len; i++) {
mask_err = 0;
dw_offset = conf_info[i].dw_offset;
bit_offset = conf_info[i].bit_offset;
mask = BIT(conf_info[i].length) - 1;
otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
if (conf_info[i].value == OTP_REG_VALID_BIT) {
if (((otp_value + otp_ignore) & mask) != mask) {
fail = 1;
mask_err = 1;
}
} else {
if (otp_ignore == mask) {
continue;
} else if (otp_ignore != 0) {
fail = 1;
mask_err = 1;
}
}
if (otp_value != conf_info[i].value &&
conf_info[i].value != OTP_REG_RESERVED &&
conf_info[i].value != OTP_REG_VALUE &&
conf_info[i].value != OTP_REG_VALID_BIT)
continue;
printf("0x%-4X", dw_offset);
if (conf_info[i].length == 1) {
printf("0x%-9X", conf_info[i].bit_offset);
} else {
printf("0x%-2X:0x%-4X",
conf_info[i].bit_offset + conf_info[i].length - 1,
conf_info[i].bit_offset);
}
printf("0x%-10x", otp_value);
if (mask_err) {
printf("Ignore mask error\n");
continue;
}
if (conf_info[i].value == OTP_REG_RESERVED) {
printf("Reserved\n");
} else if (conf_info[i].value == OTP_REG_VALUE) {
printf(conf_info[i].information, otp_value);
printf("\n");
} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
if (otp_value != 0) {
for (j = 0; j < 7; j++) {
if (otp_value == (1 << j))
valid_bit[j * 2] = '1';
else
valid_bit[j * 2] = '0';
valid_bit[j * 2 + 1] = ' ';
}
valid_bit[15] = 0;
} else {
strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
}
printf(conf_info[i].information, valid_bit);
printf("\n");
} else {
printf("%s\n", conf_info[i].information);
}
}
if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
printf("OTP revision ID is invalid.\n");
fail = 1;
} else {
fz = 0;
for (i = 0; i < 64; i++) {
if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
if (!fz)
fz = 1;
} else {
rid_num++;
if (fz) {
printf("OTP revision ID is invalid.\n");
fail = 1;
break;
}
}
}
}
if (!fail)
printf("OTP revision ID: 0x%x\n", rid_num);
else
printf("OTP revision ID\n");
otp_print_revid(&OTPCFG[0xa]);
}
if (fail)
return OTP_FAILURE;
return OTP_SUCCESS;
}
static int otp_print_conf_info(int input_offset)
{
const struct otpconf_info *conf_info = info_cb.conf_info;
uint32_t OTPCFG[16];
uint32_t mask;
uint32_t dw_offset;
uint32_t bit_offset;
uint32_t otp_value;
char valid_bit[20];
int i;
int j;
otp_read_conf_buf(0, 16, OTPCFG);
printf("DW BIT Value Description\n");
printf("__________________________________________________________________________\n");
for (i = 0; i < info_cb.conf_info_len; i++) {
if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
continue;
dw_offset = conf_info[i].dw_offset;
bit_offset = conf_info[i].bit_offset;
mask = BIT(conf_info[i].length) - 1;
otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
if (otp_value != conf_info[i].value &&
conf_info[i].value != OTP_REG_RESERVED &&
conf_info[i].value != OTP_REG_VALUE &&
conf_info[i].value != OTP_REG_VALID_BIT)
continue;
printf("0x%-4X", dw_offset);
if (conf_info[i].length == 1) {
printf("0x%-9X", conf_info[i].bit_offset);
} else {
printf("0x%-2X:0x%-4X",
conf_info[i].bit_offset + conf_info[i].length - 1,
conf_info[i].bit_offset);
}
printf("0x%-10x", otp_value);
if (conf_info[i].value == OTP_REG_RESERVED) {
printf("Reserved\n");
} else if (conf_info[i].value == OTP_REG_VALUE) {
printf(conf_info[i].information, otp_value);
printf("\n");
} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
if (otp_value != 0) {
for (j = 0; j < 7; j++) {
if (otp_value == (1 << j))
valid_bit[j * 2] = '1';
else
valid_bit[j * 2] = '0';
valid_bit[j * 2 + 1] = ' ';
}
valid_bit[15] = 0;
} else {
strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
}
printf(conf_info[i].information, valid_bit);
printf("\n");
} else {
printf("%s\n", conf_info[i].information);
}
}
return OTP_SUCCESS;
}
static int otp_print_strap_image(struct otp_image_layout *image_layout)
{
const struct otpstrap_info *strap_info = info_cb.strap_info;
uint32_t *OTPSTRAP;
uint32_t *OTPSTRAP_REG_PRO;
uint32_t *OTPSTRAP_PRO;
uint32_t *OTPSTRAP_IGNORE;
int i;
int fail = 0;
uint32_t bit_offset;
uint32_t dw_offset;
uint32_t mask;
uint32_t otp_value;
uint32_t otp_reg_protect;
uint32_t otp_protect;
uint32_t otp_ignore;
OTPSTRAP = (uint32_t *)image_layout->strap;
OTPSTRAP_PRO = (uint32_t *)image_layout->strap_pro;
OTPSTRAP_IGNORE = (uint32_t *)image_layout->strap_ignore;
if (info_cb.version == OTP_A0) {
OTPSTRAP_REG_PRO = NULL;
printf("BIT(hex) Value Protect Description\n");
} else {
OTPSTRAP_REG_PRO = (uint32_t *)image_layout->strap_reg_pro;
printf("BIT(hex) Value Reg_Protect Protect Description\n");
}
printf("__________________________________________________________________________________________\n");
for (i = 0; i < info_cb.strap_info_len; i++) {
fail = 0;
if (strap_info[i].bit_offset > 31) {
dw_offset = 1;
bit_offset = strap_info[i].bit_offset - 32;
} else {
dw_offset = 0;
bit_offset = strap_info[i].bit_offset;
}
mask = BIT(strap_info[i].length) - 1;
otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
if (info_cb.version != OTP_A0)
otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask;
else
otp_reg_protect = 0;
if (otp_ignore == mask)
continue;
else if (otp_ignore != 0)
fail = 1;
if (otp_value != strap_info[i].value &&
strap_info[i].value != OTP_REG_RESERVED)
continue;
if (strap_info[i].length == 1) {
printf("0x%-9X", strap_info[i].bit_offset);
} else {
printf("0x%-2X:0x%-4X",
strap_info[i].bit_offset + strap_info[i].length - 1,
strap_info[i].bit_offset);
}
printf("0x%-10x", otp_value);
if (info_cb.version != OTP_A0)
printf("0x%-10x", otp_reg_protect);
printf("0x%-10x", otp_protect);
if (fail) {
printf("Ignore mask error\n");
} else {
if (strap_info[i].value != OTP_REG_RESERVED)
printf("%s\n", strap_info[i].information);
else
printf("Reserved\n");
}
}
if (fail)
return OTP_FAILURE;
return OTP_SUCCESS;
}
static bool is_reserved_bit(uint8_t bit) {
static uint8_t reserved_bit[5] = {14, 30, 31, 61, 63};
int i = 0;
for (i = 0; i < sizeof(reserved_bit); i++) {
if (bit == reserved_bit[i])
return true;
}
return false;
}
static int otp_print_strap_info(int view)
{
const struct otpstrap_info *strap_info = info_cb.strap_info;
struct otpstrap_status strap_status[64];
int i, j;
int fail = 0;
uint32_t bit_offset;
uint32_t length;
uint32_t otp_value;
uint32_t otp_protect;
otp_read_strap(strap_status);
if (view) {
if (info_cb.version == OTP_A0)
printf("BIT(hex) Value Remains Protect Description\n");
else
printf("BIT(hex) Value Remains Reg_Protect Protect Description\n");
printf("___________________________________________________________________________________________________\n");
} else {
printf("BIT(hex) Value Description\n");
printf("________________________________________________________________________________\n");
}
for (i = 0; i < info_cb.strap_info_len; i++) {
otp_value = 0;
bit_offset = strap_info[i].bit_offset;
length = strap_info[i].length;
for (j = 0; j < length; j++) {
otp_value |= strap_status[bit_offset + j].value << j;
otp_protect |= strap_status[bit_offset + j].protected << j;
}
if (otp_value != strap_info[i].value &&
strap_info[i].value != OTP_REG_RESERVED)
continue;
if (view) {
for (j = 0; j < length; j++) {
printf("0x%-7X", strap_info[i].bit_offset + j);
printf("0x%-5X", strap_status[bit_offset + j].value);
printf("%-9d", strap_status[bit_offset + j].remain_times);
if (info_cb.version != OTP_A0) {
if (is_reserved_bit(bit_offset)) { // reserved bit doesn't map to any SCU strap bit
printf("N/A ");
} else if (bit_offset < 32) { // SCU500
printf("0x%-10X", strap_status[bit_offset + j + 1].reg_protected);
} else { // SCU510
printf("0x%-10X", strap_status[bit_offset + j].reg_protected);
}
}
printf("0x%-7X", strap_status[bit_offset + j].protected);
if (strap_info[i].value == OTP_REG_RESERVED) {
printf(" Reserved\n");
continue;
}
if (length == 1) {
printf(" %s\n", strap_info[i].information);
continue;
}
if (j == 0)
printf("/%s\n", strap_info[i].information);
else if (j == length - 1)
printf("\\ \"\n");
else
printf("| \"\n");
}
} else {
if (length == 1) {
printf("0x%-9X", strap_info[i].bit_offset);
} else {
printf("0x%-2X:0x%-4X",
bit_offset + length - 1, bit_offset);
}
printf("0x%-10X", otp_value);
if (strap_info[i].value != OTP_REG_RESERVED)
printf("%s\n", strap_info[i].information);
else
printf("Reserved\n");
}
}
if (fail)
return OTP_FAILURE;
return OTP_SUCCESS;
}
static int otp_print_data_image(struct otp_image_layout *image_layout)
{
int key_id, key_offset, last, key_type, key_length, exp_length;
const struct otpkey_type *key_info_array = info_cb.key_info;
struct otpkey_type key_info;
uint32_t *buf;
uint8_t *byte_buf;
char empty = 1;
int i = 0, len = 0;
int j;
byte_buf = image_layout->data;
buf = (uint32_t *)byte_buf;
for (i = 0; i < 16; i++) {
if (buf[i] != 0)
empty = 0;
}
if (empty)
return OTP_SUCCESS;
i = 0;
while (1) {
key_id = buf[i] & 0x7;
key_offset = buf[i] & 0x1ff8;
last = (buf[i] >> 13) & 1;
key_type = (buf[i] >> 14) & 0xf;
key_length = (buf[i] >> 18) & 0x3;
exp_length = (buf[i] >> 20) & 0xfff;
for (j = 0; j < info_cb.key_info_len; j++) {
if (key_type == key_info_array[j].value) {
key_info = key_info_array[j];
break;
}
}
printf("\nKey[%d]:\n", i);
printf("Key Type: ");
printf("%s\n", key_info.information);
if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
printf("HMAC SHA Type: ");
switch (key_length) {
case 0:
printf("HMAC(SHA224)\n");
break;
case 1:
printf("HMAC(SHA256)\n");
break;
case 2:
printf("HMAC(SHA384)\n");
break;
case 3:
printf("HMAC(SHA512)\n");
break;
}
} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
printf("RSA SHA Type: ");
switch (key_length) {
case 0:
printf("RSA1024\n");
len = 0x100;
break;
case 1:
printf("RSA2048\n");
len = 0x200;
break;
case 2:
printf("RSA3072\n");
len = 0x300;
break;
case 3:
printf("RSA4096\n");
len = 0x400;
break;
}
printf("RSA exponent bit length: %d\n", exp_length);
}
if (key_info.need_id)
printf("Key Number ID: %d\n", key_id);
printf("Key Value:\n");
if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
buf_print(&byte_buf[key_offset], 0x40);
} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
printf("AES Key:\n");
buf_print(&byte_buf[key_offset], 0x20);
if (info_cb.version == OTP_A0) {
printf("AES IV:\n");
buf_print(&byte_buf[key_offset + 0x20], 0x10);
}
} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
if (info_cb.version == OTP_A0) {
printf("AES Key:\n");
buf_print(&byte_buf[key_offset], 0x20);
printf("AES IV:\n");
buf_print(&byte_buf[key_offset + 0x20], 0x10);
} else {
printf("AES Key 1:\n");
buf_print(&byte_buf[key_offset], 0x20);
printf("AES Key 2:\n");
buf_print(&byte_buf[key_offset + 0x20], 0x20);
}
} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
printf("RSA mod:\n");
buf_print(&byte_buf[key_offset], len / 2);
printf("RSA exp:\n");
buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
printf("RSA mod:\n");
buf_print(&byte_buf[key_offset], len / 2);
printf("RSA exp:\n");
buf_print((uint8_t *)"\x01\x00\x01", 3);
}
if (last)
break;
i++;
}
return OTP_SUCCESS;
}
static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
{
int i;
uint32_t *strap;
uint32_t *strap_ignore;
uint32_t *strap_reg_protect;
uint32_t *strap_pro;
int bit, pbit, ibit, rpbit;
int fail = 0;
int ret;
struct otpstrap_status otpstrap[64];
strap = (uint32_t *)image_layout->strap;
strap_pro = (uint32_t *)image_layout->strap_pro;
strap_ignore = (uint32_t *)image_layout->strap_ignore;
strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro;
otp_read_strap(otpstrap);
for (i = 0; i < 64; i++) {
if (i < 32) {
bit = (strap[0] >> i) & 0x1;
ibit = (strap_ignore[0] >> i) & 0x1;
pbit = (strap_pro[0] >> i) & 0x1;
} else {
bit = (strap[1] >> (i - 32)) & 0x1;
ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
pbit = (strap_pro[1] >> (i - 32)) & 0x1;
}
if (info_cb.version != OTP_A0) {
if (i < 32)
rpbit = (strap_reg_protect[0] >> i) & 0x1;
else
rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
} else {
rpbit = 0;
}
ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit);
if (ret == OTP_FAILURE)
fail = 1;
}
if (fail == 1)
return OTP_FAILURE;
else
return OTP_SUCCESS;
}
static int otp_prog_data(struct otp_image_layout *image_layout)
{
int i;
int ret;
int data_dw;
uint32_t data[2048];
uint32_t *buf;
uint32_t *buf_ignore;
uint32_t data_masked;
uint32_t buf_masked;
buf = (uint32_t *)image_layout->data;
buf_ignore = (uint32_t *)image_layout->data_ignore;
data_dw = 2048;
printf("Read OTP Data:\n");
// ignore last two dw, the last two dw is used for slt otp write check.
otp_read_data_buf(0, data_dw - 2, data);
printf("Check writable...\n");
for (i = 0; i < data_dw - 2; i++) {
data_masked = data[i] & ~buf_ignore[i];
buf_masked = buf[i] & ~buf_ignore[i];
if (data_masked == buf_masked)
continue;
if (i % 2 == 0) {
if ((data_masked | buf_masked) == buf_masked) {
continue;
} else {
printf("Input image can't program into OTP, please check.\n");
printf("OTP_ADDR[%x] = %x\n", i, data[i]);
printf("Input [%x] = %x\n", i, buf[i]);
printf("Mask [%x] = %x\n", i, ~buf_ignore[i]);
return OTP_FAILURE;
}
} else {
if ((data_masked & buf_masked) == buf_masked) {
continue;
} else {
printf("Input image can't program into OTP, please check.\n");
printf("OTP_ADDR[%x] = %x\n", i, data[i]);
printf("Input [%x] = %x\n", i, buf[i]);
printf("Mask [%x] = %x\n", i, ~buf_ignore[i]);
return OTP_FAILURE;
}
}
}
printf("Start Programing...\n");
// programing ecc region first
for (i = 1792; i < 2046; i++) {
data_masked = data[i] & ~buf_ignore[i];
buf_masked = buf[i] & ~buf_ignore[i];
if (data_masked == buf_masked)
continue;
ret = otp_prog_data_dw(buf[i], buf_ignore[i], i);
if (ret != OTP_SUCCESS) {
printf("address: %08x, data: %08x, buffer: %08x mask: %08x\n",
i, data[i], buf[i], buf_ignore[i]);
return ret;
}
}
for (i = 0; i < 1792; i++) {
data_masked = data[i] & ~buf_ignore[i];
buf_masked = buf[i] & ~buf_ignore[i];
if (data_masked == buf_masked)
continue;
ret = otp_prog_data_dw(buf[i], buf_ignore[i], i);
if (ret != OTP_SUCCESS) {
printf("address: %08x, data: %08x, buffer: %08x mask: %08x\n",
i, data[i], buf[i], buf_ignore[i]);
return ret;
}
}
return OTP_SUCCESS;
}
static int otp_prog_strap(struct otp_image_layout *image_layout)
{
uint32_t *strap;
uint32_t *strap_ignore;
uint32_t *strap_pro;
uint32_t *strap_reg_protect;
uint32_t prog_address;
int i;
int bit, pbit, ibit, offset, rpbit, rp_offset = 0;
int fail = 0;
int ret;
int prog_flag = 0;
struct otpstrap_status otpstrap[64];
strap = (uint32_t *)image_layout->strap;
strap_pro = (uint32_t *)image_layout->strap_pro;
strap_ignore = (uint32_t *)image_layout->strap_ignore;
strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro;
printf("Read OTP Strap Region:\n");
otp_read_strap(otpstrap);
printf("Check writable...\n");
if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
printf("Input image can't program into OTP, please check.\n");
return OTP_FAILURE;
}
for (i = 0; i < 64; i++) {
if (i < 32) {
offset = i;
rp_offset = i + 1;
bit = (strap[0] >> offset) & 0x1;
ibit = (strap_ignore[0] >> offset) & 0x1;
pbit = (strap_pro[0] >> offset) & 0x1;
prog_address = otpstrap[i].writeable_option * 2 + 16;
} else {
offset = (i - 32);
rp_offset = (i - 32);
bit = (strap[1] >> offset) & 0x1;
ibit = (strap_ignore[1] >> offset) & 0x1;
pbit = (strap_pro[1] >> offset) & 0x1;
prog_address = otpstrap[i].writeable_option * 2 + 17;
}
if (info_cb.version != OTP_A0) {
if (i == 30 || i == 31)
rpbit = 0;
else if (i < 32)
rpbit = (strap_reg_protect[0] >> i) & 0x1;
else
rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
} else {
rpbit = 0;
}
if (ibit == 1)
continue;
if (bit == otpstrap[i].value)
prog_flag = 0;
else
prog_flag = 1;
if (otpstrap[i].protected == 1 && prog_flag) {
fail = 1;
continue;
}
if (otpstrap[i].remain_times == 0 && prog_flag) {
fail = 1;
continue;
}
if (prog_flag) {
ret = otp_prog_conf_b(prog_address, offset, 1);
if (ret)
return OTP_FAILURE;
}
if (rpbit == 1 && info_cb.version != OTP_A0) {
if (i < 32)
prog_address = 28;
else
prog_address = 29;
ret = otp_prog_conf_b(prog_address, rp_offset, 1);
if (ret)
return OTP_FAILURE;
}
if (pbit != 0) {
if (i < 32)
prog_address = 30;
else
prog_address = 31;
ret = otp_prog_conf_b(prog_address, offset, 1);
if (ret)
return OTP_FAILURE;
}
}
if (fail == 1)
return OTP_FAILURE;
else
return OTP_SUCCESS;
}
static int otp_prog_conf(struct otp_image_layout *image_layout)
{
int i, j;
int pass = 0;
uint32_t data[16];
uint32_t *conf = (uint32_t *)image_layout->conf;
uint32_t *conf_ignore = (uint32_t *)image_layout->conf_ignore;
uint32_t data_masked;
uint32_t buf_masked;
printf("Read OTP configuration Region:\n");
otp_read_conf_buf(0, 16, data);
printf("Check writable...\n");
for (i = 0; i < 16; i++) {
data_masked = data[i] & ~conf_ignore[i];
buf_masked = conf[i] & ~conf_ignore[i];
if (data_masked == buf_masked)
continue;
if ((data_masked | buf_masked) == buf_masked) {
continue;
} else {
printf("Input image can't program into OTP, please check.\n");
printf("OTPCFG[%X] = %x\n", i, data[i]);
printf("Input [%X] = %x\n", i, conf[i]);
printf("Mask [%X] = %x\n", i, ~conf_ignore[i]);
return OTP_FAILURE;
}
}
printf("Start Programing...\n");
pass = 1;
for (i = 0; i < 16; i++) {
data_masked = data[i] & ~conf_ignore[i];
buf_masked = conf[i] & ~conf_ignore[i];
if (data_masked == buf_masked)
continue;
for (j = 0; j < 32; j++) {
if ((conf_ignore[i] >> j) & 0x1)
continue;
if (!((buf_masked >> j) & 0x1))
continue;
if (otp_prog_conf_b(i, j, 1)) {
pass = 0;
break;
}
}
if (pass == 0) {
printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
i, data[i], conf[i], conf_ignore[i]);
break;
}
}
if (!pass)
return OTP_FAILURE;
return OTP_SUCCESS;
}
static int otp_verify_image(uint8_t *src_buf, uint32_t length, uint8_t *digest_buf)
{
SHA256_CTX ctx;
u8 digest_ret[CHECKSUM_LEN];
sha256_init(&ctx);
sha256_update(&ctx, src_buf, length);
sha256_final(&ctx, digest_ret);
if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
return OTP_SUCCESS;
else
return OTP_FAILURE;
}
static int otp_prog_image(uint8_t *buf, int nconfirm)
{
int ret;
int image_version = 0;
struct otp_header *otp_header;
struct otp_image_layout image_layout;
int image_size;
uint8_t *checksum;
otp_header = (struct otp_header *)buf;
image_size = OTP_IMAGE_SIZE(otp_header->image_info);
checksum = buf + otp_header->checksum_offset;
if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
printf("Image is invalid\n");
return OTP_FAILURE;
}
image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
image_layout.data_ignore = image_layout.data + image_layout.data_length;
image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->conf_info) / 2);
image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->conf_info);
image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
if (!strcmp("A0", (char *)otp_header->otp_version)) {
image_version = OTP_A0;
image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
} else if (!strcmp("A1", (char *)otp_header->otp_version)) {
image_version = OTP_A1;
image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
} else if (!strcmp("A2", (char *)otp_header->otp_version)) {
image_version = OTP_A2;
image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
} else if (!strcmp("A3", (char *)otp_header->otp_version)) {
image_version = OTP_A3;
image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
} else {
puts("Version is not supported\n");
return OTP_FAILURE;
}
if (image_version != info_cb.version) {
puts("Version is not match\n");
return OTP_FAILURE;
}
if (otp_verify_image(buf, image_size, checksum)) {
puts("checksum is invalid\n");
return OTP_FAILURE;
}
if (!nconfirm) {
if (otp_header->image_info & OTP_INC_DATA) {
printf("\nOTP data region :\n");
if (otp_print_data_image(&image_layout) < 0) {
printf("OTP data error, please check.\n");
return OTP_FAILURE;
}
}
if (otp_header->image_info & OTP_INC_STRAP) {
printf("\nOTP strap region :\n");
if (otp_print_strap_image(&image_layout) < 0) {
printf("OTP strap error, please check.\n");
return OTP_FAILURE;
}
}
if (otp_header->image_info & OTP_INC_CONF) {
printf("\nOTP configuration region :\n");
if (otp_print_conf_image(&image_layout) < 0) {
printf("OTP config error, please check.\n");
return OTP_FAILURE;
}
}
printf("type \"YES\" (no quotes) to continue:\n");
if (!confirm_yesno()) {
printf(" Aborting\n");
return OTP_FAILURE;
}
}
if (otp_header->image_info & OTP_INC_DATA) {
printf("programing data region ...\n");
ret = otp_prog_data(&image_layout);
if (ret != 0) {
printf("Error\n");
return ret;
}
printf("Done\n");
}
if (otp_header->image_info & OTP_INC_CONF) {
printf("programing configuration region ...\n");
ret = otp_prog_conf(&image_layout);
if (ret != 0) {
printf("Error\n");
return ret;
}
printf("Done\n");
}
if (otp_header->image_info & OTP_INC_STRAP) {
printf("programing strap region ...\n");
ret = otp_prog_strap(&image_layout);
if (ret != 0) {
printf("Error\n");
return ret;
}
printf("Done\n");
}
return OTP_SUCCESS;
}
static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
{
uint32_t read;
struct otpstrap_status otpstrap[64];
int otp_bit;
int ret = 0;
switch (mode) {
case OTP_REGION_CONF:
otp_read_conf(otp_dw_offset, &read);
otp_bit = (read >> bit_offset) & 0x1;
if (otp_bit == value) {
printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
printf("No need to program\n");
return OTP_SUCCESS;
}
if (otp_bit == 1 && value == 0) {
printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
printf("OTP is programed, which can't be clean\n");
return OTP_FAILURE;
}
printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
break;
case OTP_REGION_DATA:
otp_read_data(otp_dw_offset, &read);
otp_bit = (read >> bit_offset) & 0x1;
if (otp_dw_offset % 2 == 0) {
if (otp_bit == 1 && value == 0) {
printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
printf("OTP is programed, which can't be cleaned\n");
return OTP_FAILURE;
}
} else {
if (otp_bit == 0 && value == 1) {
printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
printf("OTP is programed, which can't be writen\n");
return OTP_FAILURE;
}
}
if (otp_bit == value) {
printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
printf("No need to program\n");
return OTP_SUCCESS;
}
printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
break;
case OTP_REGION_STRAP:
otp_read_strap(otpstrap);
otp_print_strap(bit_offset, 1);
ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
if (ret == OTP_FAILURE)
return OTP_FAILURE;
else if (ret == OTP_PROG_SKIP)
return OTP_SUCCESS;
break;
}
if (!nconfirm) {
printf("type \"YES\" (no quotes) to continue:\n");
if (!confirm_yesno()) {
printf(" Aborting\n");
return OTP_FAILURE;
}
}
switch (mode) {
case OTP_REGION_STRAP:
ret = otp_prog_strap_b(bit_offset, value);
break;
case OTP_REGION_CONF:
ret = otp_prog_conf_b(otp_dw_offset, bit_offset, value);
break;
case OTP_REGION_DATA:
ret = otp_prog_data_b(otp_dw_offset, bit_offset, value);
break;
}
if (ret == OTP_SUCCESS) {
printf("SUCCESS\n");
return OTP_SUCCESS;
}
printf("OTP cannot be programed\n");
printf("FAILED\n");
return OTP_FAILURE;
}
static int otp_update_rid(uint32_t update_num, int force)
{
uint32_t otp_rid[2];
u32 sw_rid[2];
int rid_num = 0;
int sw_rid_num = 0;
int bit_offset;
int dw_offset;
int i;
int ret;
if (otp_read_conf_buf(0xa, 2, otp_rid))
return OTP_FAILURE;
if (sw_revid(sw_rid))
return OTP_FAILURE;
rid_num = get_rid_num(otp_rid);
sw_rid_num = get_rid_num(sw_rid);
if (sw_rid_num < 0) {
printf("SW revision id is invalid, please check.\n");
return OTP_FAILURE;
}
if (update_num > sw_rid_num) {
printf("current SW revision ID: 0x%x\n", sw_rid_num);
printf("update number could not bigger than current SW revision id\n");
return OTP_FAILURE;
}
if (rid_num < 0) {
printf("Currennt OTP revision ID cannot handle by this command,\n"
"plase use 'otp pb' command to update it manually\n");
otp_print_revid(otp_rid);
return OTP_FAILURE;
}
printf("current OTP revision ID: 0x%x\n", rid_num);
otp_print_revid(otp_rid);
printf("input update number: 0x%X\n", update_num);
if (rid_num > update_num) {
printf("OTP rev_id is bigger than 0x%X\n", update_num);
printf("Skip\n");
return OTP_FAILURE;
} else if (rid_num == update_num) {
printf("OTP rev_id is same as input\n");
printf("Skip\n");
return OTP_FAILURE;
}
for (i = rid_num; i < update_num; i++) {
if (i < 32) {
dw_offset = 0xa;
bit_offset = i;
} else {
dw_offset = 0xb;
bit_offset = i - 32;
}
printf("OTPCFG%X[%d]", dw_offset, bit_offset);
if (i + 1 != update_num)
printf(", ");
}
printf(" will be programmed\n");
if (force == 0) {
printf("type \"YES\" (no quotes) to continue:\n");
if (!confirm_yesno()) {
printf(" Aborting\n");
return OTP_FAILURE;
}
}
ret = 0;
for (i = rid_num; i < update_num; i++) {
if (i < 32) {
dw_offset = 0xa;
bit_offset = i;
} else {
dw_offset = 0xb;
bit_offset = i - 32;
}
if (otp_prog_conf_b(dw_offset, bit_offset, 1)) {
printf("OTPCFG%X[%d] programming failed\n", dw_offset, bit_offset);
ret = OTP_FAILURE;
break;
}
}
otp_read_conf_buf(0xa, 2, otp_rid);
rid_num = get_rid_num(otp_rid);
if (rid_num >= 0)
printf("OTP revision ID: 0x%x\n", rid_num);
else
printf("OTP revision ID\n");
otp_print_revid(otp_rid);
if (!ret)
printf("SUCCESS\n");
else
printf("FAILED\n");
return ret;
}
static int do_otpread(int argc, char *const argv[])
{
uint32_t offset, count;
int ret;
if (argc == 4) {
offset = strtoul(argv[2], NULL, 16);
count = strtoul(argv[3], NULL, 16);
} else if (argc == 3) {
offset = strtoul(argv[2], NULL, 16);
count = 1;
} else {
return OTP_USAGE;
}
if (!strcmp(argv[1], "conf")) {
if (offset + count > 32)
return OTP_USAGE;
ret = otp_print_conf(offset, count);
} else if (!strcmp(argv[1], "data")) {
if (offset + count > 2048)
return OTP_USAGE;
ret = otp_print_data(offset, count);
} else if (!strcmp(argv[1], "strap")) {
if (offset + count > 64)
return OTP_USAGE;
ret = otp_print_strap(offset, count);
} else {
return OTP_USAGE;
}
return ret;
}
static int do_otpprog(int argc, char *const argv[])
{
FILE *fd;
int ret;
int force = 0;
char *path;
uint8_t *buf;
long fsize;
if (argc == 3) {
if (strcmp(argv[1], "o"))
return OTP_USAGE;
path = argv[2];
force = 1;
} else if (argc == 2) {
path = argv[1];
force = 0;
} else {
return OTP_USAGE;
}
fd = fopen(path, "rb");
if (!fd) {
printf("failed to open %s\n", path);
return OTP_FAILURE;
}
fseek(fd, 0, SEEK_END);
fsize = ftell(fd);
fseek(fd, 0, SEEK_SET);
buf = malloc(fsize + 1);
ret = fread(buf, 1, fsize, fd);
if (ret != fsize) {
printf("Reading \"%s\" failed\n", path);
return OTP_FAILURE;
}
fclose(fd);
buf[fsize] = 0;
return otp_prog_image(buf, force);
}
static int do_otppb(int argc, char *const argv[])
{
int mode = 0;
int nconfirm = 0;
int otp_addr = 0;
int bit_offset;
int value;
if (argc != 4 && argc != 5 && argc != 6)
return OTP_USAGE;
/* Drop the pb cmd */
argc--;
argv++;
if (!strcmp(argv[0], "conf"))
mode = OTP_REGION_CONF;
else if (!strcmp(argv[0], "strap"))
mode = OTP_REGION_STRAP;
else if (!strcmp(argv[0], "data"))
mode = OTP_REGION_DATA;
else
return OTP_USAGE;
/* Drop the region cmd */
argc--;
argv++;
if (!strcmp(argv[0], "o")) {
nconfirm = 1;
/* Drop the force option */
argc--;
argv++;
}
if (mode == OTP_REGION_STRAP) {
if (argc != 2)
return OTP_USAGE;
bit_offset = strtoul(argv[0], NULL, 16);
value = strtoul(argv[1], NULL, 16);
if (bit_offset >= 64 || (value != 0 && value != 1))
return OTP_USAGE;
} else {
if (argc != 3)
return OTP_USAGE;
otp_addr = strtoul(argv[0], NULL, 16);
bit_offset = strtoul(argv[1], NULL, 16);
value = strtoul(argv[2], NULL, 16);
if (bit_offset >= 32 || (value != 0 && value != 1))
return OTP_USAGE;
if (mode == OTP_REGION_DATA) {
if (otp_addr >= 0x800)
return OTP_USAGE;
} else {
if (otp_addr >= 0x20)
return OTP_USAGE;
}
}
if (value != 0 && value != 1)
return OTP_USAGE;
return otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
}
static int do_otpinfo(int argc, char *const argv[])
{
int view = 0;
int input;
if (argc != 2 && argc != 3)
return OTP_USAGE;
if (!strcmp(argv[1], "conf")) {
if (argc == 3) {
input = strtoul(argv[2], NULL, 16);
otp_print_conf_info(input);
} else {
otp_print_conf_info(-1);
}
} else if (!strcmp(argv[1], "strap")) {
if (argc == 3) {
if (!strcmp(argv[2], "v")) {
view = 1;
/* Drop the view option */
argc--;
argv++;
} else {
return OTP_USAGE;
}
}
otp_print_strap_info(view);
} else {
return OTP_USAGE;
}
return OTP_SUCCESS;
}
static int _do_otpprotect(int argc, char *const argv[], int preg)
{
int input;
int bit_offset;
int prog_address;
int ret = OTP_SUCCESS;
uint32_t read;
char info[10];
if (preg) {
sprintf(info, "register ");
prog_address = 28;
} else {
info[0] = 0;
prog_address = 30;
}
if (argc == 3) {
if (strcmp(argv[1], "o"))
return OTP_USAGE;
input = strtoul(argv[2], NULL, 16);
} else if (argc == 2) {
input = strtoul(argv[1], NULL, 16);
printf("OTPSTRAP[%d] %swill be protected\n", input, info);
printf("type \"YES\" (no quotes) to continue:\n");
if (!confirm_yesno()) {
printf(" Aborting\n");
return OTP_FAILURE;
}
} else {
return OTP_USAGE;
}
if (input < 30) {
bit_offset = input + 1;
} else if (input < 32) {
printf("OTPSTRAP[%d] is reserved register\n", input);
return OTP_FAILURE;
} else if (input < 64) {
bit_offset = input - 32;
prog_address++;
} else {
return OTP_USAGE;
}
otp_read_conf(prog_address, &read);
if (((read >> bit_offset) & 1) == 1) {
printf("OTPSTRAP[%d] %salready protected\n", input, info);
return OTP_SUCCESS;
}
ret = otp_prog_conf_b(prog_address, bit_offset, 1);
if (ret == OTP_SUCCESS)
printf("OTPSTRAP[%d] %sis protected\n", input, info);
else
printf("Protect OTPSTRAP[%d] %sfail\n", input, info);
return ret;
}
static int do_otpprotect(int argc, char *const argv[])
{
return _do_otpprotect(argc, argv, 0);
}
static int do_otprprotect(int argc, char *const argv[])
{
if (info_cb.version == OTP_A0) {
printf("A0 is not support OTPSTRAP register protection\n");
return OTP_FAILURE;
}
return _do_otpprotect(argc, argv, 1);
}
static int do_otpver(char *ver_name)
{
printf("SOC OTP version: %s\n", ver_name);
printf("OTP tool version: %s\n", OTP_VER);
printf("OTP info version: %s\n", OTP_INFO_VER);
return OTP_SUCCESS;
}
static int do_otpupdate(int argc, char *const argv[])
{
uint32_t update_num;
int force = 0;
if (argc == 3) {
if (strcmp(argv[1], "o"))
return OTP_USAGE;
force = 1;
update_num = strtoul(argv[2], NULL, 16);
} else if (argc == 2) {
update_num = strtoul(argv[1], NULL, 16);
} else {
return OTP_USAGE;
}
if (update_num > 64)
return OTP_USAGE;
return otp_update_rid(update_num, force);
}
static int do_otprid(int argc, char *const argv[])
{
uint32_t otp_rid[2];
u32 sw_rid[2];
int rid_num = 0;
int sw_rid_num = 0;
int ret;
if (argc != 1)
return OTP_USAGE;
if (otp_read_conf_buf(0xa, 2, otp_rid))
return OTP_FAILURE;
if (sw_revid(sw_rid))
return OTP_FAILURE;
rid_num = get_rid_num(otp_rid);
sw_rid_num = get_rid_num(sw_rid);
printf("current SW revision ID: 0x%x\n", sw_rid_num);
if (rid_num >= 0) {
printf("current OTP revision ID: 0x%x\n", rid_num);
ret = OTP_SUCCESS;
} else {
printf("Currennt OTP revision ID cannot handle by 'otp update',\n"
"plase use 'otp pb' command to update it manually\n"
"current OTP revision ID\n");
ret = OTP_FAILURE;
}
otp_print_revid(otp_rid);
return ret;
}
static void usage(void)
{
printf("otp version\n"
"otp read conf|data <otp_dw_offset> <dw_count>\n"
"otp read strap <strap_bit_offset> <bit_count>\n"
"otp info strap [v]\n"
"otp info conf [otp_dw_offset]\n"
"otp prog [o] <image_path>\n"
"otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
"otp pb strap [o] <bit_offset> <value>\n"
"otp protect [o] <bit_offset>\n"
"otp rprotect [o] <bit_offset>\n"
"otp update [o] <revision_id>\n"
"otp rid\n");
}
int main(int argc, char *argv[])
{
char *sub_cmd;
uint32_t ver;
int ret;
char ver_name[15];
if (argc < 2 || argc > 7) {
usage();
exit(EXIT_FAILURE);
}
info_cb.otp_fd = open("/dev/aspeed-otp", O_RDWR);
if (info_cb.otp_fd == -1) {
printf("Can't open /dev/aspeed-otp, please install driver!!\n");
exit(EXIT_FAILURE);
}
sub_cmd = argv[1];
/* Drop the otp command */
argc--;
argv++;
ver = chip_version();
ret = 0;
switch (ver) {
case OTP_A0:
info_cb.version = OTP_A0;
info_cb.conf_info = a0_conf_info;
info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
info_cb.strap_info = a0_strap_info;
info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
info_cb.key_info = a0_key_type;
info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
sprintf(ver_name, "A0");
break;
case OTP_A1:
info_cb.version = OTP_A1;
info_cb.conf_info = a1_conf_info;
info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
info_cb.strap_info = a1_strap_info;
info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
info_cb.key_info = a1_key_type;
info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
sprintf(ver_name, "A1");
break;
case OTP_A2:
info_cb.version = OTP_A2;
info_cb.conf_info = a2_conf_info;
info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
info_cb.strap_info = a2_strap_info;
info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
info_cb.key_info = a2_key_type;
info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
sprintf(ver_name, "A2");
break;
case OTP_A3:
info_cb.version = OTP_A3;
info_cb.conf_info = a3_conf_info;
info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
info_cb.strap_info = a3_strap_info;
info_cb.strap_info_len = ARRAY_SIZE(a3_strap_info);
info_cb.key_info = a3_key_type;
info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
sprintf(ver_name, "A3");
break;
default:
sprintf(ver_name, "unrecognized");
ret = EXIT_FAILURE;
}
if (!strcmp(sub_cmd, "version")) {
do_otpver(ver_name);
return EXIT_SUCCESS;
}
if (ret) {
printf("SOC is not supported\n");
return ret;
}
if (!strcmp(sub_cmd, "read"))
ret = do_otpread(argc, argv);
else if (!strcmp(sub_cmd, "info"))
ret = do_otpinfo(argc, argv);
else if (!strcmp(sub_cmd, "pb"))
ret = do_otppb(argc, argv);
else if (!strcmp(sub_cmd, "protect"))
ret = do_otpprotect(argc, argv);
else if (!strcmp(sub_cmd, "rprotect"))
ret = do_otprprotect(argc, argv);
else if (!strcmp(sub_cmd, "prog"))
ret = do_otpprog(argc, argv);
else if (!strcmp(sub_cmd, "update"))
ret = do_otpupdate(argc, argv);
else if (!strcmp(sub_cmd, "rid"))
ret = do_otprid(argc, argv);
else
ret = OTP_USAGE;
if (ret == OTP_USAGE) {
usage();
return EXIT_FAILURE;
} else if (ret == OTP_FAILURE) {
return EXIT_FAILURE;
} else {
return EXIT_SUCCESS;
}
}