1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+ 269d5fd8fSJohnny Huang /* 3a219f6deSJohnny Huang * Copyright 2021 Aspeed Technology Inc. 469d5fd8fSJohnny Huang */ 5e417205bSJohnny Huang 64c1c9b35SJohnny Huang #include <stdlib.h> 769d5fd8fSJohnny Huang #include <common.h> 869d5fd8fSJohnny Huang #include <console.h> 969d5fd8fSJohnny Huang #include <bootretry.h> 1069d5fd8fSJohnny Huang #include <cli.h> 1169d5fd8fSJohnny Huang #include <command.h> 1269d5fd8fSJohnny Huang #include <console.h> 134c1c9b35SJohnny Huang #include <malloc.h> 1469d5fd8fSJohnny Huang #include <inttypes.h> 1569d5fd8fSJohnny Huang #include <mapmem.h> 1669d5fd8fSJohnny Huang #include <asm/io.h> 1769d5fd8fSJohnny Huang #include <linux/compiler.h> 182031a123SJohnny Huang #include <linux/iopoll.h> 19*e7e21c44SJohnny Huang #include <u-boot/sha256.h> 20a3dcef30SJohnny Huang #include <u-boot/sha512.h> 21*e7e21c44SJohnny Huang #include <u-boot/rsa.h> 22*e7e21c44SJohnny Huang #include <u-boot/rsa-mod-exp.h> 23*e7e21c44SJohnny Huang #include <dm.h> 240cee9a95SJohnny Huang #include "otp_info.h" 2569d5fd8fSJohnny Huang 2669d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2769d5fd8fSJohnny Huang 28a3dcef30SJohnny Huang #define OTP_VER "2.0.0" 29f67375f7SJohnny Huang 3069d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 31dacbba92SJohnny Huang #define RETRY 20 327332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 337332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 347332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 3569d5fd8fSJohnny Huang 362a856b9aSJohnny Huang #define OTP_USAGE -1 372a856b9aSJohnny Huang #define OTP_FAILURE -2 382a856b9aSJohnny Huang #define OTP_SUCCESS 0 392a856b9aSJohnny Huang 40a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 41a6af4a17SJohnny Huang 42181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB 1 43181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV 2 44181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES 3 45181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT 4 46181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC 5 479a4fe690SJohnny Huang 48*e7e21c44SJohnny Huang #define OTP_LIT_END 0 49*e7e21c44SJohnny Huang #define OTP_BIG_END 1 50*e7e21c44SJohnny Huang 513d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 523d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 533d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 543d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 553d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 563d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 573d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 583d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 593d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 603d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 61a8789b47SJohnny Huang #define SW_REV_ID0 OTP_BASE + 0x68 62a8789b47SJohnny Huang #define SW_REV_ID1 OTP_BASE + 0x6c 63030cb4a7SJohnny Huang #define SEC_KEY_NUM OTP_BASE + 0x78 643d3688adSJohnny Huang 65696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 66*e7e21c44SJohnny Huang #define CHECKSUM_LEN 64 67a219f6deSJohnny Huang #define OTP_INC_DATA BIT(31) 68a219f6deSJohnny Huang #define OTP_INC_CONFIG BIT(30) 69a219f6deSJohnny Huang #define OTP_INC_STRAP BIT(29) 70a219f6deSJohnny Huang #define OTP_ECC_EN BIT(28) 71b25f02d2SJohnny Huang #define OTP_INC_SCU_PRO BIT(25) 72696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 73696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 74696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 75696656c6SJohnny Huang 76e417205bSJohnny Huang #define OTP_A0 0 77e417205bSJohnny Huang #define OTP_A1 1 78e417205bSJohnny Huang #define OTP_A2 2 79e417205bSJohnny Huang #define OTP_A3 3 80e417205bSJohnny Huang 81e417205bSJohnny Huang #define ID0_AST2600A0 0x05000303 82e417205bSJohnny Huang #define ID1_AST2600A0 0x05000303 83e417205bSJohnny Huang #define ID0_AST2600A1 0x05010303 8421a8cfceSJohnny Huang #define ID1_AST2600A1 0x05010303 85e417205bSJohnny Huang #define ID0_AST2600A2 0x05010303 86e417205bSJohnny Huang #define ID1_AST2600A2 0x05020303 87e417205bSJohnny Huang #define ID0_AST2600A3 0x05030303 88e417205bSJohnny Huang #define ID1_AST2600A3 0x05030303 89e417205bSJohnny Huang #define ID0_AST2620A1 0x05010203 90e417205bSJohnny Huang #define ID1_AST2620A1 0x05010203 91e417205bSJohnny Huang #define ID0_AST2620A2 0x05010203 92e417205bSJohnny Huang #define ID1_AST2620A2 0x05020203 93e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 94e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 95e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 96e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 97e417205bSJohnny Huang #define ID0_AST2605A2 0x05010103 98e417205bSJohnny Huang #define ID1_AST2605A2 0x05020103 99e417205bSJohnny Huang #define ID0_AST2605A3 0x05030103 100e417205bSJohnny Huang #define ID1_AST2605A3 0x05030103 101e417205bSJohnny Huang #define ID0_AST2625A3 0x05030403 102e417205bSJohnny Huang #define ID1_AST2625A3 0x05030403 103696656c6SJohnny Huang 10461a6cda7SJohnny Huang #define SOC_AST2600A0 0 10561a6cda7SJohnny Huang #define SOC_AST2600A1 1 10661a6cda7SJohnny Huang #define SOC_AST2600A2 2 10761a6cda7SJohnny Huang #define SOC_AST2600A3 3 10861a6cda7SJohnny Huang 10961a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c)) 1105e096f11SJohnny Huang #define OTPTOOL_VERSION_MAJOR(x) (((x) >> 24) & 0xff) 1115e096f11SJohnny Huang #define OTPTOOL_VERSION_PATCHLEVEL(x) (((x) >> 12) & 0xfff) 1125e096f11SJohnny Huang #define OTPTOOL_VERSION_SUBLEVEL(x) ((x) & 0xfff) 113a3dcef30SJohnny Huang #define OTPTOOL_COMPT_VERSION 2 11461a6cda7SJohnny Huang 115696656c6SJohnny Huang struct otp_header { 116696656c6SJohnny Huang u8 otp_magic[8]; 11761a6cda7SJohnny Huang u32 soc_ver; 11861a6cda7SJohnny Huang u32 otptool_ver; 119696656c6SJohnny Huang u32 image_info; 120696656c6SJohnny Huang u32 data_info; 121696656c6SJohnny Huang u32 config_info; 122696656c6SJohnny Huang u32 strap_info; 1237e523e3bSJohnny Huang u32 scu_protect_info; 124696656c6SJohnny Huang u32 checksum_offset; 125a219f6deSJohnny Huang } __packed; 126696656c6SJohnny Huang 12766f2f8e5SJohnny Huang struct otpstrap_status { 12869d5fd8fSJohnny Huang int value; 12969d5fd8fSJohnny Huang int option_array[7]; 13069d5fd8fSJohnny Huang int remain_times; 13169d5fd8fSJohnny Huang int writeable_option; 13269d5fd8fSJohnny Huang int protected; 13369d5fd8fSJohnny Huang }; 13469d5fd8fSJohnny Huang 1359a4fe690SJohnny Huang struct otpkey_type { 1369a4fe690SJohnny Huang int value; 1379a4fe690SJohnny Huang int key_type; 138*e7e21c44SJohnny Huang int order; 1399a4fe690SJohnny Huang int need_id; 1409a4fe690SJohnny Huang char information[110]; 1419a4fe690SJohnny Huang }; 1429a4fe690SJohnny Huang 143030cb4a7SJohnny Huang struct otp_pro_sts { 144030cb4a7SJohnny Huang char mem_lock; 145030cb4a7SJohnny Huang char pro_key_ret; 146030cb4a7SJohnny Huang char pro_strap; 147030cb4a7SJohnny Huang char pro_conf; 148030cb4a7SJohnny Huang char pro_data; 149030cb4a7SJohnny Huang char pro_sec; 150030cb4a7SJohnny Huang u32 sec_size; 151030cb4a7SJohnny Huang }; 152030cb4a7SJohnny Huang 1539a4fe690SJohnny Huang struct otp_info_cb { 1549a4fe690SJohnny Huang int version; 155e417205bSJohnny Huang char ver_name[3]; 15679e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1579a4fe690SJohnny Huang int strap_info_len; 15879e42a59SJoel Stanley const struct otpconf_info *conf_info; 1599a4fe690SJohnny Huang int conf_info_len; 16079e42a59SJoel Stanley const struct otpkey_type *key_info; 1619a4fe690SJohnny Huang int key_info_len; 1620dc9a440SJohnny Huang const struct scu_info *scu_info; 1630dc9a440SJohnny Huang int scu_info_len; 164030cb4a7SJohnny Huang struct otp_pro_sts pro_sts; 1659a4fe690SJohnny Huang }; 1669a4fe690SJohnny Huang 167696656c6SJohnny Huang struct otp_image_layout { 1685010032bSJohnny Huang int data_length; 1695010032bSJohnny Huang int conf_length; 1705010032bSJohnny Huang int strap_length; 171b25f02d2SJohnny Huang int scu_pro_length; 172a219f6deSJohnny Huang u8 *data; 173a219f6deSJohnny Huang u8 *data_ignore; 174a219f6deSJohnny Huang u8 *conf; 175a219f6deSJohnny Huang u8 *conf_ignore; 176a219f6deSJohnny Huang u8 *strap; 177a219f6deSJohnny Huang u8 *strap_pro; 178a219f6deSJohnny Huang u8 *strap_ignore; 179b25f02d2SJohnny Huang u8 *scu_pro; 180b25f02d2SJohnny Huang u8 *scu_pro_ignore; 181696656c6SJohnny Huang }; 182696656c6SJohnny Huang 183*e7e21c44SJohnny Huang struct sb_info { 184*e7e21c44SJohnny Huang int header_offset; 185*e7e21c44SJohnny Huang int secure_region; 186*e7e21c44SJohnny Huang int rsa_algo; 187*e7e21c44SJohnny Huang int sha_algo; 188*e7e21c44SJohnny Huang int digest_len; 189*e7e21c44SJohnny Huang int retire_list[8]; 190*e7e21c44SJohnny Huang int enc_flag; 191*e7e21c44SJohnny Huang }; 192*e7e21c44SJohnny Huang 193*e7e21c44SJohnny Huang struct key_list { 194*e7e21c44SJohnny Huang const struct otpkey_type *key_info; 195*e7e21c44SJohnny Huang int offset; 196*e7e21c44SJohnny Huang int id; 197*e7e21c44SJohnny Huang int retire; 198*e7e21c44SJohnny Huang }; 199*e7e21c44SJohnny Huang 200*e7e21c44SJohnny Huang struct sb_header { 201*e7e21c44SJohnny Huang u32 aes_data_offset; 202*e7e21c44SJohnny Huang u32 enc_offset; 203*e7e21c44SJohnny Huang u32 sign_image_size; 204*e7e21c44SJohnny Huang u32 signature_offset; 205*e7e21c44SJohnny Huang u32 revision_low; 206*e7e21c44SJohnny Huang u32 revision_high; 207*e7e21c44SJohnny Huang u32 reserved; 208*e7e21c44SJohnny Huang u32 bl1_header_checksum; 209*e7e21c44SJohnny Huang }; 210*e7e21c44SJohnny Huang 2119a4fe690SJohnny Huang static struct otp_info_cb info_cb; 2129a4fe690SJohnny Huang 21379e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 214*e7e21c44SJohnny Huang {0, OTP_KEY_TYPE_AES, OTP_LIT_END, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 215*e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"}, 216*e7e21c44SJohnny Huang {4, OTP_KEY_TYPE_HMAC, OTP_LIT_END, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 217*e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 218*e7e21c44SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as SOC public key"}, 219*e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"}, 220*e7e21c44SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as SOC private key"}, 221*e7e21c44SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"}, 2229a4fe690SJohnny Huang }; 2239a4fe690SJohnny Huang 22479e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 225*e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"}, 226*e7e21c44SJohnny Huang {2, OTP_KEY_TYPE_AES, OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 227*e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 228*e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"}, 229*e7e21c44SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"}, 2309a4fe690SJohnny Huang }; 2319a4fe690SJohnny Huang 2325fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 233*e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"}, 234*e7e21c44SJohnny Huang {2, OTP_KEY_TYPE_AES, OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 235*e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 236*e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"}, 237*e7e21c44SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"}, 238181f72d8SJohnny Huang }; 239181f72d8SJohnny Huang 240181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = { 241*e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"}, 242*e7e21c44SJohnny Huang {2, OTP_KEY_TYPE_AES, OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 243*e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 244*e7e21c44SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, OTP_BIG_END, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 245*e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"}, 246*e7e21c44SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, OTP_BIG_END, 0, "RSA-public as AES key decryption key(big endian)"}, 247*e7e21c44SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"}, 248*e7e21c44SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, OTP_BIG_END, 0, "RSA-private as AES key decryption key(big endian)"}, 2495fdde29fSJohnny Huang }; 2505fdde29fSJohnny Huang 251f347c284SJohnny Huang static void buf_print(u8 *buf, int len) 252f347c284SJohnny Huang { 253f347c284SJohnny Huang int i; 254f347c284SJohnny Huang 255f347c284SJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 256f347c284SJohnny Huang for (i = 0; i < len; i++) { 257f347c284SJohnny Huang if (i % 16 == 0) 258f347c284SJohnny Huang printf("%04X: ", i); 259f347c284SJohnny Huang printf("%02X ", buf[i]); 260f347c284SJohnny Huang if ((i + 1) % 16 == 0) 261f347c284SJohnny Huang printf("\n"); 262f347c284SJohnny Huang } 26388bd7d58SJohnny Huang printf("\n"); 264f347c284SJohnny Huang } 265f347c284SJohnny Huang 266794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset) 267794e27ecSJohnny Huang { 268794e27ecSJohnny Huang int bit_offset; 269794e27ecSJohnny Huang int i; 270794e27ecSJohnny Huang 271794e27ecSJohnny Huang if (offset < 32) { 272794e27ecSJohnny Huang i = 0; 273794e27ecSJohnny Huang bit_offset = offset; 274794e27ecSJohnny Huang } else { 275794e27ecSJohnny Huang i = 1; 276794e27ecSJohnny Huang bit_offset = offset - 32; 277794e27ecSJohnny Huang } 278794e27ecSJohnny Huang if ((rid[i] >> bit_offset) & 0x1) 279794e27ecSJohnny Huang return 1; 280794e27ecSJohnny Huang else 281794e27ecSJohnny Huang return 0; 282794e27ecSJohnny Huang } 283794e27ecSJohnny Huang 284794e27ecSJohnny Huang static int get_rid_num(u32 *rid) 285794e27ecSJohnny Huang { 286794e27ecSJohnny Huang int i; 287794e27ecSJohnny Huang int fz = 0; 288794e27ecSJohnny Huang int rid_num = 0; 289794e27ecSJohnny Huang int ret = 0; 290794e27ecSJohnny Huang 291794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 292794e27ecSJohnny Huang if (get_dw_bit(rid, i) == 0) { 293794e27ecSJohnny Huang if (!fz) 294794e27ecSJohnny Huang fz = 1; 295794e27ecSJohnny Huang 296794e27ecSJohnny Huang } else { 297794e27ecSJohnny Huang rid_num++; 298794e27ecSJohnny Huang if (fz) 299794e27ecSJohnny Huang ret = OTP_FAILURE; 300794e27ecSJohnny Huang } 301794e27ecSJohnny Huang } 302794e27ecSJohnny Huang if (ret) 303794e27ecSJohnny Huang return ret; 304794e27ecSJohnny Huang 305794e27ecSJohnny Huang return rid_num; 306794e27ecSJohnny Huang } 307794e27ecSJohnny Huang 308*e7e21c44SJohnny Huang static void sb_sha256(u8 *src, u32 len, u8 *digest_ret) 309*e7e21c44SJohnny Huang { 310*e7e21c44SJohnny Huang sha256_context ctx; 311*e7e21c44SJohnny Huang 312*e7e21c44SJohnny Huang sha256_starts(&ctx); 313*e7e21c44SJohnny Huang sha256_update(&ctx, src, len); 314*e7e21c44SJohnny Huang sha256_finish(&ctx, digest_ret); 315*e7e21c44SJohnny Huang } 316*e7e21c44SJohnny Huang 317*e7e21c44SJohnny Huang static void sb_sha384(u8 *src, u32 len, u8 *digest_ret) 318*e7e21c44SJohnny Huang { 319*e7e21c44SJohnny Huang sha512_context ctx; 320*e7e21c44SJohnny Huang 321*e7e21c44SJohnny Huang sha384_starts(&ctx); 322*e7e21c44SJohnny Huang sha384_update(&ctx, src, len); 323*e7e21c44SJohnny Huang sha384_finish(&ctx, digest_ret); 324*e7e21c44SJohnny Huang } 325*e7e21c44SJohnny Huang 326*e7e21c44SJohnny Huang static void sb_sha512(u8 *src, u32 len, u8 *digest_ret) 327*e7e21c44SJohnny Huang { 328*e7e21c44SJohnny Huang sha512_context ctx; 329*e7e21c44SJohnny Huang 330*e7e21c44SJohnny Huang sha512_starts(&ctx); 331*e7e21c44SJohnny Huang sha512_update(&ctx, src, len); 332*e7e21c44SJohnny Huang sha512_finish(&ctx, digest_ret); 333*e7e21c44SJohnny Huang } 334*e7e21c44SJohnny Huang 335a219f6deSJohnny Huang static u32 chip_version(void) 3369a4fe690SJohnny Huang { 337e417205bSJohnny Huang u32 revid0, revid1; 3389a4fe690SJohnny Huang 339e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0); 340e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1); 3419a4fe690SJohnny Huang 342e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { 343badd21c2SJohnny Huang /* AST2600-A0 */ 344e417205bSJohnny Huang return OTP_A0; 345e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { 346badd21c2SJohnny Huang /* AST2600-A1 */ 347e417205bSJohnny Huang return OTP_A1; 348e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { 349badd21c2SJohnny Huang /* AST2600-A2 */ 350e417205bSJohnny Huang return OTP_A2; 351e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { 35264b66712SJohnny Huang /* AST2600-A3 */ 353e417205bSJohnny Huang return OTP_A3; 354e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { 355e417205bSJohnny Huang /* AST2620-A1 */ 356e417205bSJohnny Huang return OTP_A1; 357e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { 358e417205bSJohnny Huang /* AST2620-A2 */ 359e417205bSJohnny Huang return OTP_A2; 360e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { 36164b66712SJohnny Huang /* AST2620-A3 */ 362e417205bSJohnny Huang return OTP_A3; 363e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { 364e417205bSJohnny Huang /* AST2605-A2 */ 365e417205bSJohnny Huang return OTP_A2; 366e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { 367e417205bSJohnny Huang /* AST2605-A3 */ 368e417205bSJohnny Huang return OTP_A3; 369e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { 370e417205bSJohnny Huang /* AST2605-A3 */ 371e417205bSJohnny Huang return OTP_A3; 3720dae9d52SJohnny Huang } 373f347c284SJohnny Huang return OTP_FAILURE; 3749a4fe690SJohnny Huang } 3759a4fe690SJohnny Huang 3762031a123SJohnny Huang static int wait_complete(void) 3773d3688adSJohnny Huang { 3782031a123SJohnny Huang u32 val; 3792031a123SJohnny Huang int ret; 3803d3688adSJohnny Huang 3812031a123SJohnny Huang udelay(1); 3822031a123SJohnny Huang ret = readl_poll_timeout(OTP_STATUS, val, (val & 0x6) == 0x6, 100000); 3832031a123SJohnny Huang if (ret) 3842031a123SJohnny Huang printf("%s: timeout, SEC14 = 0x%x\n", __func__, val); 3852031a123SJohnny Huang 3862031a123SJohnny Huang return ret; 3873d3688adSJohnny Huang } 3883d3688adSJohnny Huang 389a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 390dacbba92SJohnny Huang { 391dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 392dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 393dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 394dacbba92SJohnny Huang wait_complete(); 395dacbba92SJohnny Huang } 396dacbba92SJohnny Huang 397dacbba92SJohnny Huang static void otp_soak(int soak) 398dacbba92SJohnny Huang { 399e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) { 400dacbba92SJohnny Huang switch (soak) { 401dacbba92SJohnny Huang case 0: //default 402377f8cd7SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 403377f8cd7SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 404dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 405dacbba92SJohnny Huang break; 406dacbba92SJohnny Huang case 1: //normal program 407377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 408377f8cd7SJohnny Huang otp_write(0x5000, 0x1008); // Write MRB 409377f8cd7SJohnny Huang otp_write(0x1000, 0x0024); // Write MR 410feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 411dacbba92SJohnny Huang break; 412dacbba92SJohnny Huang case 2: //soak program 413377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 414377f8cd7SJohnny Huang otp_write(0x5000, 0x0007); // Write MRB 415377f8cd7SJohnny Huang otp_write(0x1000, 0x0100); // Write MR 416feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 417dacbba92SJohnny Huang break; 418dacbba92SJohnny Huang } 419dacbba92SJohnny Huang } else { 420dacbba92SJohnny Huang switch (soak) { 421dacbba92SJohnny Huang case 0: //default 422dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 423dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 424dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 425dacbba92SJohnny Huang break; 426dacbba92SJohnny Huang case 1: //normal program 427dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 428dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 429dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 430feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 431dacbba92SJohnny Huang break; 432dacbba92SJohnny Huang case 2: //soak program 433dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 434dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 435dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 436feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 437dacbba92SJohnny Huang break; 438dacbba92SJohnny Huang } 439dacbba92SJohnny Huang } 440dacbba92SJohnny Huang 441dacbba92SJohnny Huang wait_complete(); 442dacbba92SJohnny Huang } 443dacbba92SJohnny Huang 444a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 44569d5fd8fSJohnny Huang { 4463d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 4473d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4483d3688adSJohnny Huang wait_complete(); 4493d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 4503d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 45169d5fd8fSJohnny Huang } 45269d5fd8fSJohnny Huang 453f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data) 45469d5fd8fSJohnny Huang { 45569d5fd8fSJohnny Huang int config_offset; 45669d5fd8fSJohnny Huang 45769d5fd8fSJohnny Huang config_offset = 0x800; 45869d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 45969d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 46069d5fd8fSJohnny Huang 4613d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 4623d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4633d3688adSJohnny Huang wait_complete(); 4643d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 46569d5fd8fSJohnny Huang } 46669d5fd8fSJohnny Huang 467a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 46869d5fd8fSJohnny Huang { 469a219f6deSJohnny Huang u32 ret; 470a219f6deSJohnny Huang u32 *buf; 47169d5fd8fSJohnny Huang 47269d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 47369d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 47469d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 47569d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 47669d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 4773d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 4783d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 4793d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 4803d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 4813d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 4823d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 4833d3688adSJohnny Huang wait_complete(); 4843d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 48569d5fd8fSJohnny Huang if (ret & 0x1) 486f347c284SJohnny Huang return OTP_SUCCESS; 48769d5fd8fSJohnny Huang else 488f347c284SJohnny Huang return OTP_FAILURE; 48969d5fd8fSJohnny Huang } 49069d5fd8fSJohnny Huang 491a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 49269d5fd8fSJohnny Huang { 493a219f6deSJohnny Huang u32 ret[2]; 49469d5fd8fSJohnny Huang 49530a8c590SJohnny Huang if (otp_addr % 2 == 0) 4963d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 49730a8c590SJohnny Huang else 4983d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 49930a8c590SJohnny Huang 5003d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 5013d3688adSJohnny Huang wait_complete(); 5023d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 5033d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 50483655e91SJohnny Huang 50530a8c590SJohnny Huang if (otp_addr % 2 == 0) { 50630a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 507f347c284SJohnny Huang return OTP_SUCCESS; 50869d5fd8fSJohnny Huang else 509f347c284SJohnny Huang return OTP_FAILURE; 51030a8c590SJohnny Huang } else { 51130a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 512f347c284SJohnny Huang return OTP_SUCCESS; 51330a8c590SJohnny Huang else 514f347c284SJohnny Huang return OTP_FAILURE; 51530a8c590SJohnny Huang } 51669d5fd8fSJohnny Huang } 51769d5fd8fSJohnny Huang 518a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 5194c1c9b35SJohnny Huang { 520a219f6deSJohnny Huang u32 ret[2]; 5214c1c9b35SJohnny Huang 5224c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 5234c1c9b35SJohnny Huang 5244c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 5253d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 5264c1c9b35SJohnny Huang else 5273d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 5283d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 5293d3688adSJohnny Huang wait_complete(); 5303d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 5313d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 5324c1c9b35SJohnny Huang if (size == 1) { 5334c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 5344c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 535696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 5364c1c9b35SJohnny Huang compare[0] = 0; 537f347c284SJohnny Huang return OTP_SUCCESS; 538a219f6deSJohnny Huang } 5394c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 540f347c284SJohnny Huang return OTP_FAILURE; 5414c1c9b35SJohnny Huang 5424c1c9b35SJohnny Huang } else { 5434c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 544696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 5454c1c9b35SJohnny Huang compare[0] = ~0; 546f347c284SJohnny Huang return OTP_SUCCESS; 547a219f6deSJohnny Huang } 548d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 549f347c284SJohnny Huang return OTP_FAILURE; 5504c1c9b35SJohnny Huang } 5514c1c9b35SJohnny Huang } else if (size == 2) { 5524c1c9b35SJohnny Huang // otp_addr should be even 553696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 5544c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 5554c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 5564c1c9b35SJohnny Huang compare[0] = 0; 5574c1c9b35SJohnny Huang compare[1] = ~0; 558f347c284SJohnny Huang return OTP_SUCCESS; 559a219f6deSJohnny Huang } 5604c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 5614c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 5624c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 5634c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 564f347c284SJohnny Huang return OTP_FAILURE; 5654c1c9b35SJohnny Huang } else { 566f347c284SJohnny Huang return OTP_FAILURE; 5674c1c9b35SJohnny Huang } 5684c1c9b35SJohnny Huang } 5694c1c9b35SJohnny Huang 5702031a123SJohnny Huang static int otp_prog(u32 otp_addr, u32 prog_bit) 57183655e91SJohnny Huang { 57290965bb3SJohnny Huang otp_write(0x0, prog_bit); 57383655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 57483655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 57583655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 5762031a123SJohnny Huang 5772031a123SJohnny Huang return wait_complete(); 57883655e91SJohnny Huang } 57983655e91SJohnny Huang 5802031a123SJohnny Huang static int _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 58183655e91SJohnny Huang { 58283655e91SJohnny Huang int prog_bit; 58383655e91SJohnny Huang 58483655e91SJohnny Huang if (prog_address % 2 == 0) { 58583655e91SJohnny Huang if (value) 58683655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 58783655e91SJohnny Huang else 5882031a123SJohnny Huang return 0; 58983655e91SJohnny Huang } else { 590e417205bSJohnny Huang if (info_cb.version != OTP_A3) 59183655e91SJohnny Huang prog_address |= 1 << 15; 59283655e91SJohnny Huang if (!value) 59383655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 59483655e91SJohnny Huang else 5952031a123SJohnny Huang return 0; 59683655e91SJohnny Huang } 5972031a123SJohnny Huang return otp_prog(prog_address, prog_bit); 59883655e91SJohnny Huang } 59983655e91SJohnny Huang 600f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset) 60183655e91SJohnny Huang { 60283655e91SJohnny Huang int pass; 60383655e91SJohnny Huang int i; 6042031a123SJohnny Huang int ret; 60583655e91SJohnny Huang 60683655e91SJohnny Huang otp_soak(1); 6072031a123SJohnny Huang ret = _otp_prog_bit(value, prog_address, bit_offset); 6082031a123SJohnny Huang if (ret) 6092031a123SJohnny Huang return OTP_FAILURE; 61083655e91SJohnny Huang pass = 0; 61183655e91SJohnny Huang 61283655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 61383655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 61483655e91SJohnny Huang otp_soak(2); 6152031a123SJohnny Huang ret = _otp_prog_bit(value, prog_address, bit_offset); 6162031a123SJohnny Huang if (ret) 6172031a123SJohnny Huang return OTP_FAILURE; 61883655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 61983655e91SJohnny Huang otp_soak(1); 62083655e91SJohnny Huang } else { 62183655e91SJohnny Huang pass = 1; 62283655e91SJohnny Huang break; 62383655e91SJohnny Huang } 62483655e91SJohnny Huang } else { 62583655e91SJohnny Huang pass = 1; 62683655e91SJohnny Huang break; 62783655e91SJohnny Huang } 62883655e91SJohnny Huang } 629794e27ecSJohnny Huang if (pass) 630794e27ecSJohnny Huang return OTP_SUCCESS; 63183655e91SJohnny Huang 632794e27ecSJohnny Huang return OTP_FAILURE; 63383655e91SJohnny Huang } 63483655e91SJohnny Huang 6352031a123SJohnny Huang static int otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 636d90825e2SJohnny Huang { 637d90825e2SJohnny Huang int j, bit_value, prog_bit; 6382031a123SJohnny Huang int ret; 639d90825e2SJohnny Huang 640d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 641696656c6SJohnny Huang if ((ignore >> j) & 0x1) 642d90825e2SJohnny Huang continue; 643d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 644d90825e2SJohnny Huang if (prog_address % 2 == 0) { 645d90825e2SJohnny Huang if (bit_value) 646d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 647d90825e2SJohnny Huang else 648d90825e2SJohnny Huang continue; 649d90825e2SJohnny Huang } else { 650e417205bSJohnny Huang if (info_cb.version != OTP_A3) 651d90825e2SJohnny Huang prog_address |= 1 << 15; 652d90825e2SJohnny Huang if (bit_value) 653d90825e2SJohnny Huang continue; 654d90825e2SJohnny Huang else 655d90825e2SJohnny Huang prog_bit = 0x1 << j; 656d90825e2SJohnny Huang } 6572031a123SJohnny Huang ret = otp_prog(prog_address, prog_bit); 6582031a123SJohnny Huang if (ret) 6592031a123SJohnny Huang return ret; 660d90825e2SJohnny Huang } 6612031a123SJohnny Huang return 0; 662d90825e2SJohnny Huang } 663d90825e2SJohnny Huang 664a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 66554552c69SJohnny Huang { 66654552c69SJohnny Huang int pass; 66754552c69SJohnny Huang int i; 668a219f6deSJohnny Huang u32 data0_masked; 669a219f6deSJohnny Huang u32 data1_masked; 670a219f6deSJohnny Huang u32 buf0_masked; 671a219f6deSJohnny Huang u32 buf1_masked; 672a219f6deSJohnny Huang u32 compare[2]; 6732031a123SJohnny Huang int ret; 67454552c69SJohnny Huang 67554552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 67654552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 67754552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 67854552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 679a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 680f347c284SJohnny Huang return OTP_SUCCESS; 68154552c69SJohnny Huang 682b64ca396SJohnny Huang for (i = 0; i < 32; i++) { 683b64ca396SJohnny Huang if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0) 684b64ca396SJohnny Huang return OTP_FAILURE; 685b64ca396SJohnny Huang if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1) 686b64ca396SJohnny Huang return OTP_FAILURE; 687b64ca396SJohnny Huang } 688b64ca396SJohnny Huang 68954552c69SJohnny Huang otp_soak(1); 6902031a123SJohnny Huang if (data0_masked != buf0_masked) { 6912031a123SJohnny Huang ret = otp_prog_dw(buf[0], ignore_mask[0], prog_address); 6922031a123SJohnny Huang if (ret) 6932031a123SJohnny Huang return OTP_FAILURE; 6942031a123SJohnny Huang } 6952031a123SJohnny Huang 6962031a123SJohnny Huang if (data1_masked != buf1_masked) { 6972031a123SJohnny Huang ret = otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 6982031a123SJohnny Huang if (ret) 6992031a123SJohnny Huang return OTP_FAILURE; 7002031a123SJohnny Huang } 70154552c69SJohnny Huang 70254552c69SJohnny Huang pass = 0; 70354552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 70454552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 70554552c69SJohnny Huang otp_soak(2); 7062031a123SJohnny Huang if (compare[0] != 0) { 7072031a123SJohnny Huang ret = otp_prog_dw(compare[0], ignore_mask[0], prog_address); 7082031a123SJohnny Huang if (ret) 7092031a123SJohnny Huang return OTP_FAILURE; 7102031a123SJohnny Huang } 7112031a123SJohnny Huang if (compare[1] != ~0) { 7122031a123SJohnny Huang ret = otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 7132031a123SJohnny Huang if (ret) 7142031a123SJohnny Huang return OTP_FAILURE; 7152031a123SJohnny Huang } 71654552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 71754552c69SJohnny Huang otp_soak(1); 71854552c69SJohnny Huang } else { 71954552c69SJohnny Huang pass = 1; 72054552c69SJohnny Huang break; 72154552c69SJohnny Huang } 72254552c69SJohnny Huang } else { 72354552c69SJohnny Huang pass = 1; 72454552c69SJohnny Huang break; 72554552c69SJohnny Huang } 72654552c69SJohnny Huang } 72754552c69SJohnny Huang 72854552c69SJohnny Huang if (!pass) { 72954552c69SJohnny Huang otp_soak(0); 73054552c69SJohnny Huang return OTP_FAILURE; 73154552c69SJohnny Huang } 73254552c69SJohnny Huang return OTP_SUCCESS; 73354552c69SJohnny Huang } 73454552c69SJohnny Huang 735541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 73676d13988SJohnny Huang { 737a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 7385010032bSJohnny Huang int strap_end; 73976d13988SJohnny Huang int i, j; 74076d13988SJohnny Huang 741e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 74276d13988SJohnny Huang for (j = 0; j < 64; j++) { 74376d13988SJohnny Huang otpstrap[j].value = 0; 74476d13988SJohnny Huang otpstrap[j].remain_times = 7; 74576d13988SJohnny Huang otpstrap[j].writeable_option = -1; 74676d13988SJohnny Huang otpstrap[j].protected = 0; 74776d13988SJohnny Huang } 7485010032bSJohnny Huang strap_end = 30; 7495010032bSJohnny Huang } else { 7505010032bSJohnny Huang for (j = 0; j < 64; j++) { 7515010032bSJohnny Huang otpstrap[j].value = 0; 7525010032bSJohnny Huang otpstrap[j].remain_times = 6; 7535010032bSJohnny Huang otpstrap[j].writeable_option = -1; 7545010032bSJohnny Huang otpstrap[j].protected = 0; 7555010032bSJohnny Huang } 7565010032bSJohnny Huang strap_end = 28; 7575010032bSJohnny Huang } 75876d13988SJohnny Huang 759dacbba92SJohnny Huang otp_soak(0); 7605010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 76176d13988SJohnny Huang int option = (i - 16) / 2; 762a219f6deSJohnny Huang 763f347c284SJohnny Huang otp_read_conf(i, &OTPSTRAP_RAW[0]); 764f347c284SJohnny Huang otp_read_conf(i + 1, &OTPSTRAP_RAW[1]); 76576d13988SJohnny Huang for (j = 0; j < 32; j++) { 76676d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 767a219f6deSJohnny Huang 768a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 76976d13988SJohnny Huang otpstrap[j].writeable_option = option; 77076d13988SJohnny Huang if (bit_value == 1) 77176d13988SJohnny Huang otpstrap[j].remain_times--; 77276d13988SJohnny Huang otpstrap[j].value ^= bit_value; 77376d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 77476d13988SJohnny Huang } 77576d13988SJohnny Huang for (j = 32; j < 64; j++) { 77676d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 777a219f6deSJohnny Huang 778a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 77976d13988SJohnny Huang otpstrap[j].writeable_option = option; 78076d13988SJohnny Huang if (bit_value == 1) 78176d13988SJohnny Huang otpstrap[j].remain_times--; 78276d13988SJohnny Huang otpstrap[j].value ^= bit_value; 78376d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 78476d13988SJohnny Huang } 78576d13988SJohnny Huang } 7865010032bSJohnny Huang 787f347c284SJohnny Huang otp_read_conf(30, &OTPSTRAP_RAW[0]); 788f347c284SJohnny Huang otp_read_conf(31, &OTPSTRAP_RAW[1]); 78976d13988SJohnny Huang for (j = 0; j < 32; j++) { 79076d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 79176d13988SJohnny Huang otpstrap[j].protected = 1; 79276d13988SJohnny Huang } 79376d13988SJohnny Huang for (j = 32; j < 64; j++) { 79476d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 79576d13988SJohnny Huang otpstrap[j].protected = 1; 79676d13988SJohnny Huang } 79776d13988SJohnny Huang } 79876d13988SJohnny Huang 7997e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit) 800f347c284SJohnny Huang { 801f347c284SJohnny Huang int prog_flag = 0; 802f347c284SJohnny Huang 803f347c284SJohnny Huang // ignore this bit 804f347c284SJohnny Huang if (ibit == 1) 805f347c284SJohnny Huang return OTP_SUCCESS; 806b489486eSJohnny Huang printf("OTPSTRAP[0x%X]:\n", offset); 807f347c284SJohnny Huang 808f347c284SJohnny Huang if (bit == otpstrap->value) { 8097e523e3bSJohnny Huang if (!pbit) { 810f347c284SJohnny Huang printf(" The value is same as before, skip it.\n"); 811f347c284SJohnny Huang return OTP_PROG_SKIP; 812f347c284SJohnny Huang } 813f347c284SJohnny Huang printf(" The value is same as before.\n"); 814f347c284SJohnny Huang } else { 815f347c284SJohnny Huang prog_flag = 1; 816f347c284SJohnny Huang } 817f347c284SJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 818f347c284SJohnny Huang printf(" This bit is protected and is not writable\n"); 819f347c284SJohnny Huang return OTP_FAILURE; 820f347c284SJohnny Huang } 821f347c284SJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 822b489486eSJohnny Huang printf(" This bit has no remaining chance to write.\n"); 823f347c284SJohnny Huang return OTP_FAILURE; 824f347c284SJohnny Huang } 825f347c284SJohnny Huang if (pbit == 1) 826f347c284SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 827f347c284SJohnny Huang if (prog_flag) 828b489486eSJohnny Huang printf(" Write 1 to OTPSTRAP[0x%X] OPTION[0x%X], that value becomes from 0x%X to 0x%X.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1); 829f347c284SJohnny Huang 830f347c284SJohnny Huang return OTP_SUCCESS; 831f347c284SJohnny Huang } 832f347c284SJohnny Huang 833f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value) 834f347c284SJohnny Huang { 835f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 836f347c284SJohnny Huang u32 prog_address; 837f347c284SJohnny Huang int offset; 838f347c284SJohnny Huang int ret; 839f347c284SJohnny Huang 840f347c284SJohnny Huang otp_strap_status(otpstrap); 841f347c284SJohnny Huang 8427e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 843f347c284SJohnny Huang 844f347c284SJohnny Huang if (ret != OTP_SUCCESS) 845f347c284SJohnny Huang return ret; 846f347c284SJohnny Huang 847f347c284SJohnny Huang prog_address = 0x800; 848f347c284SJohnny Huang if (bit_offset < 32) { 849f347c284SJohnny Huang offset = bit_offset; 850f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 851f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 852f347c284SJohnny Huang 853f347c284SJohnny Huang } else { 854f347c284SJohnny Huang offset = (bit_offset - 32); 855f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 856f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 857f347c284SJohnny Huang } 858f347c284SJohnny Huang 859f347c284SJohnny Huang return otp_prog_dc_b(1, prog_address, offset); 860f347c284SJohnny Huang } 861f347c284SJohnny Huang 862f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count) 863f347c284SJohnny Huang { 864f347c284SJohnny Huang int i; 865f347c284SJohnny Huang u32 ret[1]; 866f347c284SJohnny Huang 867f347c284SJohnny Huang if (offset + dw_count > 32) 868f347c284SJohnny Huang return OTP_USAGE; 869f347c284SJohnny Huang otp_soak(0); 870f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i++) { 871f347c284SJohnny Huang otp_read_conf(i, ret); 872b489486eSJohnny Huang printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]); 873f347c284SJohnny Huang } 874f347c284SJohnny Huang printf("\n"); 875f347c284SJohnny Huang return OTP_SUCCESS; 876f347c284SJohnny Huang } 877f347c284SJohnny Huang 878f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count) 879f347c284SJohnny Huang { 880f347c284SJohnny Huang int i; 881f347c284SJohnny Huang u32 ret[2]; 882f347c284SJohnny Huang 883f347c284SJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 884f347c284SJohnny Huang return OTP_USAGE; 885f347c284SJohnny Huang otp_soak(0); 886f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 887f347c284SJohnny Huang otp_read_data(i, ret); 888f347c284SJohnny Huang if (i % 4 == 0) 889f347c284SJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 890f347c284SJohnny Huang else 891f347c284SJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 892f347c284SJohnny Huang } 893f347c284SJohnny Huang printf("\n"); 894f347c284SJohnny Huang return OTP_SUCCESS; 895f347c284SJohnny Huang } 896f347c284SJohnny Huang 897f347c284SJohnny Huang static int otp_print_strap(int start, int count) 898f347c284SJohnny Huang { 899f347c284SJohnny Huang int i, j; 900f347c284SJohnny Huang int remains; 901f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 902f347c284SJohnny Huang 903f347c284SJohnny Huang if (start < 0 || start > 64) 904f347c284SJohnny Huang return OTP_USAGE; 905f347c284SJohnny Huang 906f347c284SJohnny Huang if ((start + count) < 0 || (start + count) > 64) 907f347c284SJohnny Huang return OTP_USAGE; 908f347c284SJohnny Huang 909f347c284SJohnny Huang otp_strap_status(otpstrap); 910f347c284SJohnny Huang 9117e523e3bSJohnny Huang if (info_cb.version == OTP_A0) 912f347c284SJohnny Huang remains = 7; 9137e523e3bSJohnny Huang else 914f347c284SJohnny Huang remains = 6; 9157e523e3bSJohnny Huang printf("BIT(hex) Value Option Status\n"); 916f347c284SJohnny Huang printf("______________________________________________________________________________\n"); 917f347c284SJohnny Huang 918f347c284SJohnny Huang for (i = start; i < start + count; i++) { 919f347c284SJohnny Huang printf("0x%-8X", i); 920f347c284SJohnny Huang printf("%-7d", otpstrap[i].value); 921f347c284SJohnny Huang for (j = 0; j < remains; j++) 922f347c284SJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 923f347c284SJohnny Huang printf(" "); 924f347c284SJohnny Huang if (otpstrap[i].protected == 1) { 925f347c284SJohnny Huang printf("protected and not writable"); 926f347c284SJohnny Huang } else { 927f347c284SJohnny Huang printf("not protected "); 928f347c284SJohnny Huang if (otpstrap[i].remain_times == 0) 929f347c284SJohnny Huang printf("and no remaining times to write."); 930f347c284SJohnny Huang else 931f347c284SJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 932f347c284SJohnny Huang } 933f347c284SJohnny Huang printf("\n"); 934f347c284SJohnny Huang } 935f347c284SJohnny Huang 936f347c284SJohnny Huang return OTP_SUCCESS; 937f347c284SJohnny Huang } 938f347c284SJohnny Huang 939794e27ecSJohnny Huang static void otp_print_revid(u32 *rid) 940794e27ecSJohnny Huang { 941794e27ecSJohnny Huang int bit_offset; 942794e27ecSJohnny Huang int i, j; 943794e27ecSJohnny Huang 944794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 945794e27ecSJohnny Huang printf("___________________________________________________\n"); 946794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 947794e27ecSJohnny Huang if (i < 32) { 948794e27ecSJohnny Huang j = 0; 949794e27ecSJohnny Huang bit_offset = i; 950794e27ecSJohnny Huang } else { 951794e27ecSJohnny Huang j = 1; 952794e27ecSJohnny Huang bit_offset = i - 32; 953794e27ecSJohnny Huang } 954794e27ecSJohnny Huang if (i % 16 == 0) 955794e27ecSJohnny Huang printf("%2x | ", i); 956794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1); 957794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 958794e27ecSJohnny Huang printf("\n"); 959794e27ecSJohnny Huang } 960794e27ecSJohnny Huang } 961794e27ecSJohnny Huang 962b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout) 963b25f02d2SJohnny Huang { 964b25f02d2SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 965b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 966b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 967b25f02d2SJohnny Huang int i; 968b25f02d2SJohnny Huang u32 scu_offset; 969b25f02d2SJohnny Huang u32 dw_offset; 970b25f02d2SJohnny Huang u32 bit_offset; 971b25f02d2SJohnny Huang u32 mask; 972b25f02d2SJohnny Huang u32 otp_value; 973b25f02d2SJohnny Huang u32 otp_ignore; 974b25f02d2SJohnny Huang 975b25f02d2SJohnny Huang printf("SCU BIT reg_protect Description\n"); 976b25f02d2SJohnny Huang printf("____________________________________________________________________\n"); 977b25f02d2SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 978b25f02d2SJohnny Huang mask = BIT(scu_info[i].length) - 1; 979b25f02d2SJohnny Huang 980b25f02d2SJohnny Huang if (scu_info[i].bit_offset > 31) { 981b25f02d2SJohnny Huang scu_offset = 0x510; 982b25f02d2SJohnny Huang dw_offset = 1; 983b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset - 32; 984b25f02d2SJohnny Huang } else { 985b25f02d2SJohnny Huang scu_offset = 0x500; 986b25f02d2SJohnny Huang dw_offset = 0; 987b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset; 988b25f02d2SJohnny Huang } 989b25f02d2SJohnny Huang 990b25f02d2SJohnny Huang otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask; 991b25f02d2SJohnny Huang otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask; 992b25f02d2SJohnny Huang 993b25f02d2SJohnny Huang if (otp_ignore == mask) 994b25f02d2SJohnny Huang continue; 995b25f02d2SJohnny Huang else if (otp_ignore != 0) 996b25f02d2SJohnny Huang return OTP_FAILURE; 997b25f02d2SJohnny Huang 998b25f02d2SJohnny Huang if (otp_value != 0 && otp_value != mask) 999b25f02d2SJohnny Huang return OTP_FAILURE; 1000b25f02d2SJohnny Huang 1001b25f02d2SJohnny Huang printf("0x%-6X", scu_offset); 1002b25f02d2SJohnny Huang if (scu_info[i].length == 1) 1003b25f02d2SJohnny Huang printf("0x%-11X", bit_offset); 1004b25f02d2SJohnny Huang else 10052131c250SJohnny Huang printf("0x%-2X:0x%-6x", bit_offset, bit_offset + scu_info[i].length - 1); 1006b25f02d2SJohnny Huang printf("0x%-14X", otp_value); 1007b25f02d2SJohnny Huang printf("%s\n", scu_info[i].information); 1008b25f02d2SJohnny Huang } 1009b25f02d2SJohnny Huang return OTP_SUCCESS; 1010b25f02d2SJohnny Huang } 1011b25f02d2SJohnny Huang 10120dc9a440SJohnny Huang static void otp_print_scu_info(void) 10130dc9a440SJohnny Huang { 10140dc9a440SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 10150dc9a440SJohnny Huang u32 OTPCFG[2]; 10160dc9a440SJohnny Huang u32 scu_offset; 10170dc9a440SJohnny Huang u32 bit_offset; 10180dc9a440SJohnny Huang u32 reg_p; 10190dc9a440SJohnny Huang u32 length; 10200dc9a440SJohnny Huang int i, j; 10210dc9a440SJohnny Huang 10220dc9a440SJohnny Huang otp_soak(0); 10230dc9a440SJohnny Huang otp_read_conf(28, &OTPCFG[0]); 10240dc9a440SJohnny Huang otp_read_conf(29, &OTPCFG[1]); 10250dc9a440SJohnny Huang printf("SCU BIT reg_protect Description\n"); 10260dc9a440SJohnny Huang printf("____________________________________________________________________\n"); 10270dc9a440SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 10280dc9a440SJohnny Huang length = scu_info[i].length; 10290dc9a440SJohnny Huang for (j = 0; j < length; j++) { 10300dc9a440SJohnny Huang if (scu_info[i].bit_offset + j < 32) { 10310dc9a440SJohnny Huang scu_offset = 0x500; 10320dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j; 10330dc9a440SJohnny Huang reg_p = (OTPCFG[0] >> bit_offset) & 0x1; 10340dc9a440SJohnny Huang } else { 10350dc9a440SJohnny Huang scu_offset = 0x510; 10360dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j - 32; 10370dc9a440SJohnny Huang reg_p = (OTPCFG[1] >> bit_offset) & 0x1; 10380dc9a440SJohnny Huang } 10390dc9a440SJohnny Huang printf("0x%-6X", scu_offset); 10400dc9a440SJohnny Huang printf("0x%-4X", bit_offset); 10410dc9a440SJohnny Huang printf("0x%-13X", reg_p); 10420dc9a440SJohnny Huang if (length == 1) { 10430dc9a440SJohnny Huang printf(" %s\n", scu_info[i].information); 10440dc9a440SJohnny Huang continue; 10450dc9a440SJohnny Huang } 10460dc9a440SJohnny Huang 10470dc9a440SJohnny Huang if (j == 0) 10480dc9a440SJohnny Huang printf("/%s\n", scu_info[i].information); 10490dc9a440SJohnny Huang else if (j == length - 1) 10500dc9a440SJohnny Huang printf("\\ \"\n"); 10510dc9a440SJohnny Huang else 10520dc9a440SJohnny Huang printf("| \"\n"); 10530dc9a440SJohnny Huang } 10540dc9a440SJohnny Huang } 10550dc9a440SJohnny Huang } 10560dc9a440SJohnny Huang 1057696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 105869d5fd8fSJohnny Huang { 105979e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1060a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 1061a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 1062a219f6deSJohnny Huang u32 mask; 1063a219f6deSJohnny Huang u32 dw_offset; 1064a219f6deSJohnny Huang u32 bit_offset; 1065a219f6deSJohnny Huang u32 otp_value; 1066a219f6deSJohnny Huang u32 otp_ignore; 1067b458cd62SJohnny Huang int fail = 0; 10687adec5f6SJohnny Huang int mask_err; 1069794e27ecSJohnny Huang int rid_num = 0; 107073f11549SJohnny Huang char valid_bit[20]; 1071794e27ecSJohnny Huang int fz; 107266f2f8e5SJohnny Huang int i; 107373f11549SJohnny Huang int j; 107466f2f8e5SJohnny Huang 1075737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 107666f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 10773cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 10787adec5f6SJohnny Huang mask_err = 0; 10793cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 10803cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 10813cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1082b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1083696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 1084b458cd62SJohnny Huang 10857adec5f6SJohnny Huang if (conf_info[i].value == OTP_REG_VALID_BIT) { 10867adec5f6SJohnny Huang if (((otp_value + otp_ignore) & mask) != mask) { 1087b458cd62SJohnny Huang fail = 1; 10887adec5f6SJohnny Huang mask_err = 1; 10897adec5f6SJohnny Huang } 10907adec5f6SJohnny Huang } else { 10917adec5f6SJohnny Huang if (otp_ignore == mask) { 10927adec5f6SJohnny Huang continue; 10937adec5f6SJohnny Huang } else if (otp_ignore != 0) { 10947adec5f6SJohnny Huang fail = 1; 10957adec5f6SJohnny Huang mask_err = 1; 10967adec5f6SJohnny Huang } 10977adec5f6SJohnny Huang } 1098b458cd62SJohnny Huang 1099a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 11003cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 11013cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 11023cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1103b458cd62SJohnny Huang continue; 1104b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1105b458cd62SJohnny Huang 11063cb28812SJohnny Huang if (conf_info[i].length == 1) { 11073cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 110866f2f8e5SJohnny Huang } else { 1109b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 11103cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 11113cb28812SJohnny Huang conf_info[i].bit_offset); 111266f2f8e5SJohnny Huang } 1113b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1114b458cd62SJohnny Huang 11157adec5f6SJohnny Huang if (mask_err) { 11167adec5f6SJohnny Huang printf("Ignore, mask error\n"); 1117a219f6deSJohnny Huang continue; 1118a219f6deSJohnny Huang } 11193cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1120b458cd62SJohnny Huang printf("Reserved\n"); 11213cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 11223cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1123b458cd62SJohnny Huang printf("\n"); 11243cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1125b458cd62SJohnny Huang if (otp_value != 0) { 112673f11549SJohnny Huang for (j = 0; j < 7; j++) { 1127e2b82258SJohnny Huang if (otp_value & (1 << j)) 112873f11549SJohnny Huang valid_bit[j * 2] = '1'; 1129a219f6deSJohnny Huang else 113073f11549SJohnny Huang valid_bit[j * 2] = '0'; 113173f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 113273f11549SJohnny Huang } 113373f11549SJohnny Huang valid_bit[15] = 0; 113473f11549SJohnny Huang } else { 113573f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1136b458cd62SJohnny Huang } 11373cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1138b458cd62SJohnny Huang printf("\n"); 1139b458cd62SJohnny Huang } else { 11403cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1141b458cd62SJohnny Huang } 1142b458cd62SJohnny Huang } 1143b458cd62SJohnny Huang 1144794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) { 1145794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) { 1146794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1147794e27ecSJohnny Huang fail = 1; 1148794e27ecSJohnny Huang } else { 1149794e27ecSJohnny Huang fz = 0; 1150794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 1151794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) { 1152794e27ecSJohnny Huang if (!fz) 1153794e27ecSJohnny Huang fz = 1; 1154794e27ecSJohnny Huang } else { 1155794e27ecSJohnny Huang rid_num++; 1156794e27ecSJohnny Huang if (fz) { 1157794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1158794e27ecSJohnny Huang fail = 1; 1159794e27ecSJohnny Huang break; 1160794e27ecSJohnny Huang } 1161794e27ecSJohnny Huang } 1162794e27ecSJohnny Huang } 1163794e27ecSJohnny Huang } 1164794e27ecSJohnny Huang if (fail) 1165794e27ecSJohnny Huang printf("OTP revision ID\n"); 1166794e27ecSJohnny Huang else 1167794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1168794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]); 1169794e27ecSJohnny Huang } 1170794e27ecSJohnny Huang 1171b458cd62SJohnny Huang if (fail) 1172b458cd62SJohnny Huang return OTP_FAILURE; 1173b458cd62SJohnny Huang 117466f2f8e5SJohnny Huang return OTP_SUCCESS; 117566f2f8e5SJohnny Huang } 117666f2f8e5SJohnny Huang 11772d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 117866f2f8e5SJohnny Huang { 117979e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1180a219f6deSJohnny Huang u32 OTPCFG[16]; 1181a219f6deSJohnny Huang u32 mask; 1182a219f6deSJohnny Huang u32 dw_offset; 1183a219f6deSJohnny Huang u32 bit_offset; 1184a219f6deSJohnny Huang u32 otp_value; 118573f11549SJohnny Huang char valid_bit[20]; 118666f2f8e5SJohnny Huang int i; 118773f11549SJohnny Huang int j; 118866f2f8e5SJohnny Huang 1189dacbba92SJohnny Huang otp_soak(0); 1190bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 1191f347c284SJohnny Huang otp_read_conf(i, &OTPCFG[i]); 119266f2f8e5SJohnny Huang 1193b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 1194b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 11953cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 11963cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 11972d4b0742SJohnny Huang continue; 11983cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 11993cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 12003cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1201b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1202b458cd62SJohnny Huang 1203a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 12043cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 12053cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 12063cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1207b458cd62SJohnny Huang continue; 1208b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1209b458cd62SJohnny Huang 12103cb28812SJohnny Huang if (conf_info[i].length == 1) { 12113cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 1212b458cd62SJohnny Huang } else { 1213b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 12143cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 12153cb28812SJohnny Huang conf_info[i].bit_offset); 1216b458cd62SJohnny Huang } 1217b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1218b458cd62SJohnny Huang 12193cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1220b458cd62SJohnny Huang printf("Reserved\n"); 12213cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 12223cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1223b458cd62SJohnny Huang printf("\n"); 12243cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1225b458cd62SJohnny Huang if (otp_value != 0) { 122673f11549SJohnny Huang for (j = 0; j < 7; j++) { 1227030cb4a7SJohnny Huang if (otp_value & (1 << j)) 122873f11549SJohnny Huang valid_bit[j * 2] = '1'; 1229a219f6deSJohnny Huang else 123073f11549SJohnny Huang valid_bit[j * 2] = '0'; 123173f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 123273f11549SJohnny Huang } 123373f11549SJohnny Huang valid_bit[15] = 0; 123473f11549SJohnny Huang } else { 123573f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1236b458cd62SJohnny Huang } 12373cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1238b458cd62SJohnny Huang printf("\n"); 1239b458cd62SJohnny Huang } else { 12403cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1241b458cd62SJohnny Huang } 1242b458cd62SJohnny Huang } 1243b458cd62SJohnny Huang return OTP_SUCCESS; 124466f2f8e5SJohnny Huang } 124566f2f8e5SJohnny Huang 12465010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 124776d13988SJohnny Huang { 124879e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 1249a219f6deSJohnny Huang u32 *OTPSTRAP; 1250a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 1251a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 125276d13988SJohnny Huang int i; 1253a8bd6d8cSJohnny Huang int fail = 0; 1254a219f6deSJohnny Huang u32 bit_offset; 1255a219f6deSJohnny Huang u32 dw_offset; 1256a219f6deSJohnny Huang u32 mask; 1257a219f6deSJohnny Huang u32 otp_value; 1258a219f6deSJohnny Huang u32 otp_protect; 1259a219f6deSJohnny Huang u32 otp_ignore; 126076d13988SJohnny Huang 1261a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 1262a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 1263a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 12647e523e3bSJohnny Huang 1265a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 1266de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 1267b458cd62SJohnny Huang 12683cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 12697adec5f6SJohnny Huang fail = 0; 1270696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 1271a8bd6d8cSJohnny Huang dw_offset = 1; 12723cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 1273a8bd6d8cSJohnny Huang } else { 1274a8bd6d8cSJohnny Huang dw_offset = 0; 12753cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 1276a8bd6d8cSJohnny Huang } 127776d13988SJohnny Huang 12783cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 1279a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 1280a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 1281696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 1282a8bd6d8cSJohnny Huang 1283a219f6deSJohnny Huang if (otp_ignore == mask) 1284a8bd6d8cSJohnny Huang continue; 1285a219f6deSJohnny Huang else if (otp_ignore != 0) 1286a8bd6d8cSJohnny Huang fail = 1; 1287a8bd6d8cSJohnny Huang 1288a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 12893cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1290a8bd6d8cSJohnny Huang continue; 1291a8bd6d8cSJohnny Huang 12923cb28812SJohnny Huang if (strap_info[i].length == 1) { 12933cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1294a8bd6d8cSJohnny Huang } else { 1295b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 12963cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 12973cb28812SJohnny Huang strap_info[i].bit_offset); 1298a8bd6d8cSJohnny Huang } 1299a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 1300a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 1301a8bd6d8cSJohnny Huang 1302a8bd6d8cSJohnny Huang if (fail) { 1303696656c6SJohnny Huang printf("Ignore mask error\n"); 1304a8bd6d8cSJohnny Huang } else { 13053cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 13063cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1307a8bd6d8cSJohnny Huang else 1308a8bd6d8cSJohnny Huang printf("Reserved\n"); 1309a8bd6d8cSJohnny Huang } 1310a8bd6d8cSJohnny Huang } 1311a8bd6d8cSJohnny Huang 1312a8bd6d8cSJohnny Huang if (fail) 131376d13988SJohnny Huang return OTP_FAILURE; 131476d13988SJohnny Huang 131576d13988SJohnny Huang return OTP_SUCCESS; 131676d13988SJohnny Huang } 131776d13988SJohnny Huang 1318b458cd62SJohnny Huang static int otp_print_strap_info(int view) 131976d13988SJohnny Huang { 132079e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 132176d13988SJohnny Huang struct otpstrap_status strap_status[64]; 132207baa4e8SJohnny Huang int i, j; 1323b458cd62SJohnny Huang int fail = 0; 1324a219f6deSJohnny Huang u32 bit_offset; 1325a219f6deSJohnny Huang u32 length; 1326a219f6deSJohnny Huang u32 otp_value; 1327a219f6deSJohnny Huang u32 otp_protect; 132876d13988SJohnny Huang 1329541eb887SJohnny Huang otp_strap_status(strap_status); 133076d13988SJohnny Huang 1331b458cd62SJohnny Huang if (view) { 133207baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 133307baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 1334b458cd62SJohnny Huang } else { 1335b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 1336b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 133776d13988SJohnny Huang } 13383cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 1339b458cd62SJohnny Huang otp_value = 0; 13403cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 13413cb28812SJohnny Huang length = strap_info[i].length; 1342b458cd62SJohnny Huang for (j = 0; j < length; j++) { 1343c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 1344c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 1345b458cd62SJohnny Huang } 1346a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 13473cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1348b458cd62SJohnny Huang continue; 1349b458cd62SJohnny Huang if (view) { 1350b458cd62SJohnny Huang for (j = 0; j < length; j++) { 13513cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 1352b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 135307baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 1354e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 13553cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 1356b458cd62SJohnny Huang printf(" Reserved\n"); 1357b458cd62SJohnny Huang continue; 1358b458cd62SJohnny Huang } 1359b458cd62SJohnny Huang if (length == 1) { 13603cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 1361b458cd62SJohnny Huang continue; 136276d13988SJohnny Huang } 136376d13988SJohnny Huang 1364b458cd62SJohnny Huang if (j == 0) 13653cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 1366b458cd62SJohnny Huang else if (j == length - 1) 1367b458cd62SJohnny Huang printf("\\ \"\n"); 1368b458cd62SJohnny Huang else 1369b458cd62SJohnny Huang printf("| \"\n"); 137076d13988SJohnny Huang } 1371b458cd62SJohnny Huang } else { 1372c947ef08SJohnny Huang if (length == 1) { 13733cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1374b458cd62SJohnny Huang } else { 1375b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 1376b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 1377b458cd62SJohnny Huang } 1378b458cd62SJohnny Huang 1379b458cd62SJohnny Huang printf("0x%-10X", otp_value); 1380b458cd62SJohnny Huang 13813cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 13823cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1383b458cd62SJohnny Huang else 1384b458cd62SJohnny Huang printf("Reserved\n"); 1385b458cd62SJohnny Huang } 1386b458cd62SJohnny Huang } 1387b458cd62SJohnny Huang 1388b458cd62SJohnny Huang if (fail) 1389b458cd62SJohnny Huang return OTP_FAILURE; 1390b458cd62SJohnny Huang 1391b458cd62SJohnny Huang return OTP_SUCCESS; 1392b458cd62SJohnny Huang } 1393b458cd62SJohnny Huang 139488bd7d58SJohnny Huang static void _otp_print_key(u32 *data) 139569d5fd8fSJohnny Huang { 139688bd7d58SJohnny Huang int i, j; 139769d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 13989a4fe690SJohnny Huang struct otpkey_type key_info; 139988bd7d58SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 140088bd7d58SJohnny Huang int len = 0; 1401a219f6deSJohnny Huang u8 *byte_buf; 140288bd7d58SJohnny Huang int empty; 140354552c69SJohnny Huang 140488bd7d58SJohnny Huang byte_buf = (u8 *)data; 14059d998018SJohnny Huang 140688bd7d58SJohnny Huang empty = 1; 14079d998018SJohnny Huang for (i = 0; i < 16; i++) { 140888bd7d58SJohnny Huang if (i % 2) { 140988bd7d58SJohnny Huang if (data[i] != 0xffffffff) 141088bd7d58SJohnny Huang empty = 0; 141188bd7d58SJohnny Huang } else { 141288bd7d58SJohnny Huang if (data[i] != 0) 14139d998018SJohnny Huang empty = 0; 14149d998018SJohnny Huang } 141588bd7d58SJohnny Huang } 141688bd7d58SJohnny Huang if (empty) { 141788bd7d58SJohnny Huang printf("OTP data header is empty\n"); 141888bd7d58SJohnny Huang return; 141988bd7d58SJohnny Huang } 14209d998018SJohnny Huang 142188bd7d58SJohnny Huang for (i = 0; i < 16; i++) { 142288bd7d58SJohnny Huang key_id = data[i] & 0x7; 142388bd7d58SJohnny Huang key_offset = data[i] & 0x1ff8; 142488bd7d58SJohnny Huang last = (data[i] >> 13) & 1; 142588bd7d58SJohnny Huang key_type = (data[i] >> 14) & 0xf; 142688bd7d58SJohnny Huang key_length = (data[i] >> 18) & 0x3; 142788bd7d58SJohnny Huang exp_length = (data[i] >> 20) & 0xfff; 14289a4fe690SJohnny Huang 142988bd7d58SJohnny Huang key_info.value = -1; 14309a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 14319a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 14329a4fe690SJohnny Huang key_info = key_info_array[j]; 14339a4fe690SJohnny Huang break; 14349a4fe690SJohnny Huang } 14359a4fe690SJohnny Huang } 143688bd7d58SJohnny Huang if (key_info.value == -1) 143788bd7d58SJohnny Huang break; 14389a4fe690SJohnny Huang 14397f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 144069d5fd8fSJohnny Huang printf("Key Type: "); 14419a4fe690SJohnny Huang printf("%s\n", key_info.information); 14429a4fe690SJohnny Huang 14439a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 144469d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 144569d5fd8fSJohnny Huang switch (key_length) { 144669d5fd8fSJohnny Huang case 0: 144769d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 144869d5fd8fSJohnny Huang break; 144969d5fd8fSJohnny Huang case 1: 145069d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 145169d5fd8fSJohnny Huang break; 145269d5fd8fSJohnny Huang case 2: 145369d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 145469d5fd8fSJohnny Huang break; 145569d5fd8fSJohnny Huang case 3: 145669d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 145769d5fd8fSJohnny Huang break; 145869d5fd8fSJohnny Huang } 1459181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1460181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 146169d5fd8fSJohnny Huang printf("RSA SHA Type: "); 146269d5fd8fSJohnny Huang switch (key_length) { 146369d5fd8fSJohnny Huang case 0: 146469d5fd8fSJohnny Huang printf("RSA1024\n"); 146569d5fd8fSJohnny Huang len = 0x100; 146669d5fd8fSJohnny Huang break; 146769d5fd8fSJohnny Huang case 1: 146869d5fd8fSJohnny Huang printf("RSA2048\n"); 146969d5fd8fSJohnny Huang len = 0x200; 147069d5fd8fSJohnny Huang break; 147169d5fd8fSJohnny Huang case 2: 147269d5fd8fSJohnny Huang printf("RSA3072\n"); 147369d5fd8fSJohnny Huang len = 0x300; 147469d5fd8fSJohnny Huang break; 147569d5fd8fSJohnny Huang case 3: 147669d5fd8fSJohnny Huang printf("RSA4096\n"); 147769d5fd8fSJohnny Huang len = 0x400; 147869d5fd8fSJohnny Huang break; 147969d5fd8fSJohnny Huang } 148069d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 148169d5fd8fSJohnny Huang } 14829a4fe690SJohnny Huang if (key_info.need_id) 148369d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 148469d5fd8fSJohnny Huang printf("Key Value:\n"); 14859a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 148669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 14879a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 14889a4fe690SJohnny Huang printf("AES Key:\n"); 14899a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 1490e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 14919a4fe690SJohnny Huang printf("AES IV:\n"); 14929a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 14939a4fe690SJohnny Huang } 14949a4fe690SJohnny Huang 14959a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1496e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 149769d5fd8fSJohnny Huang printf("AES Key:\n"); 149869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 149969d5fd8fSJohnny Huang printf("AES IV:\n"); 150069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 15015fdde29fSJohnny Huang } else { 15029a4fe690SJohnny Huang printf("AES Key 1:\n"); 15039a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 15049a4fe690SJohnny Huang printf("AES Key 2:\n"); 15059a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 15069a4fe690SJohnny Huang } 1507181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 150869d5fd8fSJohnny Huang printf("RSA mod:\n"); 150969d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 151069d5fd8fSJohnny Huang printf("RSA exp:\n"); 151169d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1512181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1513181f72d8SJohnny Huang printf("RSA mod:\n"); 1514181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1515181f72d8SJohnny Huang printf("RSA exp:\n"); 1516a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 151769d5fd8fSJohnny Huang } 151869d5fd8fSJohnny Huang if (last) 151969d5fd8fSJohnny Huang break; 152069d5fd8fSJohnny Huang } 152188bd7d58SJohnny Huang } 152288bd7d58SJohnny Huang 152388bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 152488bd7d58SJohnny Huang { 152588bd7d58SJohnny Huang u32 *buf; 152688bd7d58SJohnny Huang 152788bd7d58SJohnny Huang buf = (u32 *)image_layout->data; 152888bd7d58SJohnny Huang _otp_print_key(buf); 152988bd7d58SJohnny Huang 1530f347c284SJohnny Huang return OTP_SUCCESS; 1531f347c284SJohnny Huang } 1532f347c284SJohnny Huang 153388bd7d58SJohnny Huang static void otp_print_key_info(void) 153488bd7d58SJohnny Huang { 153588bd7d58SJohnny Huang u32 data[2048]; 153688bd7d58SJohnny Huang int i; 153788bd7d58SJohnny Huang 153888bd7d58SJohnny Huang for (i = 0; i < 2048 ; i += 2) 153988bd7d58SJohnny Huang otp_read_data(i, &data[i]); 154088bd7d58SJohnny Huang 154188bd7d58SJohnny Huang _otp_print_key(data); 154288bd7d58SJohnny Huang } 154388bd7d58SJohnny Huang 1544b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data) 1545f347c284SJohnny Huang { 1546f347c284SJohnny Huang int i; 1547f347c284SJohnny Huang int ret; 1548f347c284SJohnny Huang u32 *buf; 1549f347c284SJohnny Huang u32 *buf_ignore; 1550f347c284SJohnny Huang 1551f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1552f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1553f347c284SJohnny Huang printf("Start Programing...\n"); 1554f347c284SJohnny Huang 1555f347c284SJohnny Huang // programing ecc region first 1556f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1557f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1558f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1559f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1560f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1561f347c284SJohnny Huang return ret; 1562f347c284SJohnny Huang } 1563f347c284SJohnny Huang } 1564f347c284SJohnny Huang 1565f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1566f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1567f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1568f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1569f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1570f347c284SJohnny Huang return ret; 1571f347c284SJohnny Huang } 1572f347c284SJohnny Huang } 1573f347c284SJohnny Huang otp_soak(0); 1574f347c284SJohnny Huang return OTP_SUCCESS; 1575f347c284SJohnny Huang } 1576f347c284SJohnny Huang 1577b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1578f347c284SJohnny Huang { 1579f347c284SJohnny Huang u32 *strap; 1580f347c284SJohnny Huang u32 *strap_ignore; 1581f347c284SJohnny Huang u32 *strap_pro; 1582f347c284SJohnny Huang u32 prog_address; 1583f347c284SJohnny Huang int i; 15847e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1585f347c284SJohnny Huang int fail = 0; 1586f347c284SJohnny Huang int ret; 1587f347c284SJohnny Huang int prog_flag = 0; 1588f347c284SJohnny Huang 1589f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1590f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1591f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1592f347c284SJohnny Huang 1593f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1594f347c284SJohnny Huang prog_address = 0x800; 1595f347c284SJohnny Huang if (i < 32) { 1596f347c284SJohnny Huang offset = i; 1597f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1598f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1599f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1600f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1601f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1602f347c284SJohnny Huang 1603f347c284SJohnny Huang } else { 1604f347c284SJohnny Huang offset = (i - 32); 1605f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1606f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1607f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1608f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1609f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1610f347c284SJohnny Huang } 1611f347c284SJohnny Huang 1612f347c284SJohnny Huang if (ibit == 1) 1613f347c284SJohnny Huang continue; 1614f347c284SJohnny Huang if (bit == otpstrap[i].value) 1615f347c284SJohnny Huang prog_flag = 0; 1616f347c284SJohnny Huang else 1617f347c284SJohnny Huang prog_flag = 1; 1618f347c284SJohnny Huang 1619f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1620f347c284SJohnny Huang fail = 1; 1621f347c284SJohnny Huang continue; 1622f347c284SJohnny Huang } 1623f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1624f347c284SJohnny Huang fail = 1; 1625f347c284SJohnny Huang continue; 1626f347c284SJohnny Huang } 1627f347c284SJohnny Huang 1628f347c284SJohnny Huang if (prog_flag) { 1629f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1630f347c284SJohnny Huang if (ret) 1631f347c284SJohnny Huang return OTP_FAILURE; 1632f347c284SJohnny Huang } 1633f347c284SJohnny Huang 1634f347c284SJohnny Huang if (pbit != 0) { 1635f347c284SJohnny Huang prog_address = 0x800; 1636f347c284SJohnny Huang if (i < 32) 1637f347c284SJohnny Huang prog_address |= 0x60c; 1638f347c284SJohnny Huang else 1639f347c284SJohnny Huang prog_address |= 0x60e; 1640f347c284SJohnny Huang 1641f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1642f347c284SJohnny Huang if (ret) 1643f347c284SJohnny Huang return OTP_FAILURE; 1644f347c284SJohnny Huang } 1645f347c284SJohnny Huang } 1646f347c284SJohnny Huang otp_soak(0); 1647f347c284SJohnny Huang if (fail == 1) 1648f347c284SJohnny Huang return OTP_FAILURE; 1649f347c284SJohnny Huang return OTP_SUCCESS; 165069d5fd8fSJohnny Huang } 165169d5fd8fSJohnny Huang 1652b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf) 165369d5fd8fSJohnny Huang { 1654a6d0d645SJohnny Huang int i, k; 1655d90825e2SJohnny Huang int pass = 0; 1656a219f6deSJohnny Huang u32 prog_address; 1657a219f6deSJohnny Huang u32 compare[2]; 1658a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1659a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1660a219f6deSJohnny Huang u32 data_masked; 1661a219f6deSJohnny Huang u32 buf_masked; 16622031a123SJohnny Huang int ret; 166369d5fd8fSJohnny Huang 1664a6d0d645SJohnny Huang printf("Start Programing...\n"); 1665d90825e2SJohnny Huang otp_soak(0); 1666bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 1667b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 16685010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1669a6d0d645SJohnny Huang prog_address = 0x800; 1670a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1671a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1672bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1673bb34a7bfSJohnny Huang pass = 1; 1674a6d0d645SJohnny Huang continue; 1675bb34a7bfSJohnny Huang } 1676de6fbf1cSJohnny Huang 1677de6fbf1cSJohnny Huang otp_soak(1); 16782031a123SJohnny Huang ret = otp_prog_dw(conf[i], conf_ignore[i], prog_address); 16792031a123SJohnny Huang if (ret) 16802031a123SJohnny Huang return OTP_FAILURE; 1681a6d0d645SJohnny Huang 168269d5fd8fSJohnny Huang pass = 0; 168369d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 16845010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1685de6fbf1cSJohnny Huang otp_soak(2); 16862031a123SJohnny Huang ret = otp_prog_dw(compare[0], conf_ignore[i], prog_address); 16872031a123SJohnny Huang if (ret) 16882031a123SJohnny Huang return OTP_FAILURE; 16895010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1690de6fbf1cSJohnny Huang otp_soak(1); 1691de6fbf1cSJohnny Huang } else { 1692de6fbf1cSJohnny Huang pass = 1; 1693de6fbf1cSJohnny Huang break; 1694de6fbf1cSJohnny Huang } 1695a6d0d645SJohnny Huang } else { 169669d5fd8fSJohnny Huang pass = 1; 169769d5fd8fSJohnny Huang break; 169869d5fd8fSJohnny Huang } 169969d5fd8fSJohnny Huang } 1700bb34a7bfSJohnny Huang if (pass == 0) { 1701b64ca396SJohnny Huang printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n", 1702b64ca396SJohnny Huang i, otp_conf[i], conf[i], conf_ignore[i]); 1703bb34a7bfSJohnny Huang break; 1704bb34a7bfSJohnny Huang } 1705a6d0d645SJohnny Huang } 1706a6d0d645SJohnny Huang 1707de6fbf1cSJohnny Huang otp_soak(0); 170869d5fd8fSJohnny Huang if (!pass) 17092a856b9aSJohnny Huang return OTP_FAILURE; 1710a6d0d645SJohnny Huang 17112a856b9aSJohnny Huang return OTP_SUCCESS; 171269d5fd8fSJohnny Huang } 171369d5fd8fSJohnny Huang 1714b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro) 1715b25f02d2SJohnny Huang { 1716b25f02d2SJohnny Huang int i, k; 1717b25f02d2SJohnny Huang int pass = 0; 1718b25f02d2SJohnny Huang u32 prog_address; 1719b25f02d2SJohnny Huang u32 compare[2]; 1720b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1721b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1722b25f02d2SJohnny Huang u32 data_masked; 1723b25f02d2SJohnny Huang u32 buf_masked; 17242031a123SJohnny Huang int ret; 1725b25f02d2SJohnny Huang 1726b25f02d2SJohnny Huang printf("Start Programing...\n"); 1727b25f02d2SJohnny Huang otp_soak(0); 1728b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1729b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1730b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1731b25f02d2SJohnny Huang prog_address = 0xe08 + i * 2; 1732b25f02d2SJohnny Huang if (data_masked == buf_masked) { 1733b25f02d2SJohnny Huang pass = 1; 1734b25f02d2SJohnny Huang continue; 1735b25f02d2SJohnny Huang } 1736b25f02d2SJohnny Huang 1737b25f02d2SJohnny Huang otp_soak(1); 17382031a123SJohnny Huang ret = otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address); 17392031a123SJohnny Huang if (ret) 17402031a123SJohnny Huang return OTP_FAILURE; 1741b25f02d2SJohnny Huang pass = 0; 1742b25f02d2SJohnny Huang for (k = 0; k < RETRY; k++) { 1743b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1744b25f02d2SJohnny Huang otp_soak(2); 17452031a123SJohnny Huang ret = otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address); 17462031a123SJohnny Huang if (ret) 17472031a123SJohnny Huang return OTP_FAILURE; 1748b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1749b25f02d2SJohnny Huang otp_soak(1); 1750b25f02d2SJohnny Huang } else { 1751b25f02d2SJohnny Huang pass = 1; 1752b25f02d2SJohnny Huang break; 1753b25f02d2SJohnny Huang } 1754b25f02d2SJohnny Huang } else { 1755b25f02d2SJohnny Huang pass = 1; 1756b25f02d2SJohnny Huang break; 1757b25f02d2SJohnny Huang } 1758b25f02d2SJohnny Huang } 1759b25f02d2SJohnny Huang if (pass == 0) { 1760b489486eSJohnny Huang printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n", 1761b25f02d2SJohnny Huang i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]); 1762b25f02d2SJohnny Huang break; 1763b25f02d2SJohnny Huang } 1764b25f02d2SJohnny Huang } 1765b25f02d2SJohnny Huang 1766b25f02d2SJohnny Huang otp_soak(0); 1767b25f02d2SJohnny Huang if (!pass) 1768b25f02d2SJohnny Huang return OTP_FAILURE; 1769b25f02d2SJohnny Huang 1770b25f02d2SJohnny Huang return OTP_SUCCESS; 1771b25f02d2SJohnny Huang } 1772b25f02d2SJohnny Huang 1773b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data) 1774b64ca396SJohnny Huang { 1775b64ca396SJohnny Huang int data_dw; 1776b64ca396SJohnny Huang u32 data_masked; 1777b64ca396SJohnny Huang u32 buf_masked; 1778b64ca396SJohnny Huang u32 *buf = (u32 *)image_layout->data; 1779b64ca396SJohnny Huang u32 *buf_ignore = (u32 *)image_layout->data_ignore; 1780b64ca396SJohnny Huang int i; 1781b64ca396SJohnny Huang 1782b64ca396SJohnny Huang data_dw = image_layout->data_length / 4; 1783b64ca396SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1784b64ca396SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1785b64ca396SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1786b64ca396SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1787b64ca396SJohnny Huang if (data_masked == buf_masked) 1788b64ca396SJohnny Huang continue; 1789b64ca396SJohnny Huang if (i % 2 == 0) { 1790b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1791b64ca396SJohnny Huang continue; 1792b64ca396SJohnny Huang } else { 1793b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1794b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1795b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1796b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1797b64ca396SJohnny Huang return OTP_FAILURE; 1798b64ca396SJohnny Huang } 1799b64ca396SJohnny Huang } else { 1800b64ca396SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1801b64ca396SJohnny Huang continue; 1802b64ca396SJohnny Huang } else { 1803b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1804b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1805b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1806b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1807b64ca396SJohnny Huang return OTP_FAILURE; 1808b64ca396SJohnny Huang } 1809b64ca396SJohnny Huang } 1810b64ca396SJohnny Huang } 1811b64ca396SJohnny Huang return OTP_SUCCESS; 1812b64ca396SJohnny Huang } 1813b64ca396SJohnny Huang 1814b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1815b64ca396SJohnny Huang { 1816b64ca396SJohnny Huang int i; 1817b64ca396SJohnny Huang u32 *strap; 1818b64ca396SJohnny Huang u32 *strap_ignore; 1819b64ca396SJohnny Huang u32 *strap_pro; 1820b64ca396SJohnny Huang int bit, pbit, ibit; 1821b64ca396SJohnny Huang int fail = 0; 1822b64ca396SJohnny Huang int ret; 1823b64ca396SJohnny Huang 1824b64ca396SJohnny Huang strap = (u32 *)image_layout->strap; 1825b64ca396SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1826b64ca396SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1827b64ca396SJohnny Huang 1828b64ca396SJohnny Huang for (i = 0; i < 64; i++) { 1829b64ca396SJohnny Huang if (i < 32) { 1830b64ca396SJohnny Huang bit = (strap[0] >> i) & 0x1; 1831b64ca396SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1832b64ca396SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1833b64ca396SJohnny Huang } else { 1834b64ca396SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1835b64ca396SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1836b64ca396SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1837b64ca396SJohnny Huang } 1838b64ca396SJohnny Huang 1839b64ca396SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1840b64ca396SJohnny Huang 1841b64ca396SJohnny Huang if (ret == OTP_FAILURE) 1842b64ca396SJohnny Huang fail = 1; 1843b64ca396SJohnny Huang } 1844b64ca396SJohnny Huang if (fail == 1) { 1845b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1846b64ca396SJohnny Huang return OTP_FAILURE; 1847b64ca396SJohnny Huang } 1848b64ca396SJohnny Huang return OTP_SUCCESS; 1849b64ca396SJohnny Huang } 1850b64ca396SJohnny Huang 1851b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf) 1852b64ca396SJohnny Huang { 1853b64ca396SJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1854b64ca396SJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1855b64ca396SJohnny Huang u32 data_masked; 1856b64ca396SJohnny Huang u32 buf_masked; 1857b64ca396SJohnny Huang int i; 1858b64ca396SJohnny Huang 1859b64ca396SJohnny Huang for (i = 0; i < 16; i++) { 1860b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 1861b64ca396SJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1862b64ca396SJohnny Huang if (data_masked == buf_masked) 1863b64ca396SJohnny Huang continue; 1864b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1865b64ca396SJohnny Huang continue; 1866b64ca396SJohnny Huang } else { 1867b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1868b64ca396SJohnny Huang printf("OTPCFG[%X] = %x\n", i, otp_conf[i]); 1869b64ca396SJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 1870b64ca396SJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 1871b64ca396SJohnny Huang return OTP_FAILURE; 1872b64ca396SJohnny Huang } 1873b64ca396SJohnny Huang } 1874b64ca396SJohnny Huang return OTP_SUCCESS; 1875b64ca396SJohnny Huang } 1876b64ca396SJohnny Huang 1877b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro) 1878b25f02d2SJohnny Huang { 1879b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1880b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1881b25f02d2SJohnny Huang u32 data_masked; 1882b25f02d2SJohnny Huang u32 buf_masked; 1883b25f02d2SJohnny Huang int i; 1884b25f02d2SJohnny Huang 1885b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1886b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1887b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1888b25f02d2SJohnny Huang if (data_masked == buf_masked) 1889b25f02d2SJohnny Huang continue; 1890b25f02d2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1891b25f02d2SJohnny Huang continue; 1892b25f02d2SJohnny Huang } else { 1893b25f02d2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1894b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]); 1895b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]); 1896b489486eSJohnny Huang printf("Mask [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]); 1897b25f02d2SJohnny Huang return OTP_FAILURE; 1898b25f02d2SJohnny Huang } 1899b25f02d2SJohnny Huang } 1900b25f02d2SJohnny Huang return OTP_SUCCESS; 1901b25f02d2SJohnny Huang } 1902b25f02d2SJohnny Huang 1903*e7e21c44SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf, int version) 1904696656c6SJohnny Huang { 1905*e7e21c44SJohnny Huang u8 digest_ret[48]; 1906*e7e21c44SJohnny Huang int digest_len; 1907696656c6SJohnny Huang 1908*e7e21c44SJohnny Huang switch (version) { 1909*e7e21c44SJohnny Huang case 1: 1910*e7e21c44SJohnny Huang sb_sha256(src_buf, length, digest_ret); 1911*e7e21c44SJohnny Huang digest_len = 32; 1912*e7e21c44SJohnny Huang break; 1913*e7e21c44SJohnny Huang case 2: 1914*e7e21c44SJohnny Huang sb_sha384(src_buf, length, digest_ret); 1915*e7e21c44SJohnny Huang digest_len = 48; 1916*e7e21c44SJohnny Huang break; 1917*e7e21c44SJohnny Huang default: 1918*e7e21c44SJohnny Huang return OTP_FAILURE; 1919*e7e21c44SJohnny Huang } 1920696656c6SJohnny Huang 1921*e7e21c44SJohnny Huang if (!memcmp(digest_buf, digest_ret, digest_len)) 1922f347c284SJohnny Huang return OTP_SUCCESS; 1923f347c284SJohnny Huang return OTP_FAILURE; 1924696656c6SJohnny Huang } 1925696656c6SJohnny Huang 1926f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 192769d5fd8fSJohnny Huang { 192869d5fd8fSJohnny Huang int ret; 192961a6cda7SJohnny Huang int image_soc_ver = 0; 1930696656c6SJohnny Huang struct otp_header *otp_header; 1931696656c6SJohnny Huang struct otp_image_layout image_layout; 1932696656c6SJohnny Huang int image_size; 1933a219f6deSJohnny Huang u8 *buf; 1934a219f6deSJohnny Huang u8 *checksum; 1935b64ca396SJohnny Huang int i; 1936b64ca396SJohnny Huang u32 data[2048]; 1937b64ca396SJohnny Huang u32 conf[16]; 1938b25f02d2SJohnny Huang u32 scu_pro[2]; 1939b64ca396SJohnny Huang struct otpstrap_status otpstrap[64]; 194069d5fd8fSJohnny Huang 1941696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1942696656c6SJohnny Huang if (!otp_header) { 1943030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 19442a856b9aSJohnny Huang return OTP_FAILURE; 194569d5fd8fSJohnny Huang } 1946d90825e2SJohnny Huang 1947696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1948696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1949696656c6SJohnny Huang 1950696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1951696656c6SJohnny Huang 1952696656c6SJohnny Huang if (!buf) { 1953030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 1954696656c6SJohnny Huang return OTP_FAILURE; 1955696656c6SJohnny Huang } 1956696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1957696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1958696656c6SJohnny Huang 1959696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1960030cb4a7SJohnny Huang printf("Image is invalid\n"); 1961696656c6SJohnny Huang return OTP_FAILURE; 1962696656c6SJohnny Huang } 1963696656c6SJohnny Huang 19645010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 19655010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 19665010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 19675010032bSJohnny Huang 19685010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1969696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 19705010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1971696656c6SJohnny Huang 1972696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 19735010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 19745010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 19755010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 19767e523e3bSJohnny Huang 1977b25f02d2SJohnny Huang image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info); 1978b25f02d2SJohnny Huang image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2); 1979b25f02d2SJohnny Huang image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length; 1980b25f02d2SJohnny Huang 19817e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 19827e523e3bSJohnny Huang image_soc_ver = OTP_A0; 198361a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 198461a6cda7SJohnny Huang image_soc_ver = OTP_A1; 198561a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 198661a6cda7SJohnny Huang image_soc_ver = OTP_A2; 198761a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 198861a6cda7SJohnny Huang image_soc_ver = OTP_A3; 1989696656c6SJohnny Huang } else { 1990030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n"); 1991696656c6SJohnny Huang return OTP_FAILURE; 1992696656c6SJohnny Huang } 1993696656c6SJohnny Huang 199461a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 19955e096f11SJohnny Huang printf("Image SOC version is not match to HW SOC version\n"); 19969a4fe690SJohnny Huang return OTP_FAILURE; 19979a4fe690SJohnny Huang } 19989a4fe690SJohnny Huang 1999*e7e21c44SJohnny Huang switch (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver)) { 2000*e7e21c44SJohnny Huang case 1: 2001*e7e21c44SJohnny Huang printf("WARNING: OTP image is not generated by otptool v2.x.x\n"); 2002*e7e21c44SJohnny Huang printf("Please use the latest version of otptool to generate OTP image\n"); 2003*e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 1); 2004*e7e21c44SJohnny Huang break; 2005*e7e21c44SJohnny Huang case 2: 2006*e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 2); 2007*e7e21c44SJohnny Huang break; 2008*e7e21c44SJohnny Huang default: 2009*e7e21c44SJohnny Huang printf("OTP image version is not supported\n"); 201061a6cda7SJohnny Huang return OTP_FAILURE; 201161a6cda7SJohnny Huang } 201261a6cda7SJohnny Huang 2013*e7e21c44SJohnny Huang if (ret) { 2014030cb4a7SJohnny Huang printf("checksum is invalid\n"); 2015696656c6SJohnny Huang return OTP_FAILURE; 2016d90825e2SJohnny Huang } 20177332532cSJohnny Huang 2018030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2019030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2020030cb4a7SJohnny Huang return OTP_FAILURE; 2021030cb4a7SJohnny Huang } 2022b64ca396SJohnny Huang ret = 0; 2023030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 2024030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2025030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2026030cb4a7SJohnny Huang ret = -1; 2027030cb4a7SJohnny Huang } 2028030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2029030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2030030cb4a7SJohnny Huang ret = -1; 2031030cb4a7SJohnny Huang } 2032b64ca396SJohnny Huang printf("Read OTP Data Region:\n"); 2033b64ca396SJohnny Huang for (i = 0; i < 2048 ; i += 2) 2034b64ca396SJohnny Huang otp_read_data(i, &data[i]); 2035b64ca396SJohnny Huang 2036b64ca396SJohnny Huang printf("Check writable...\n"); 2037b64ca396SJohnny Huang if (otp_check_data_image(&image_layout, data) == OTP_FAILURE) 2038b64ca396SJohnny Huang ret = -1; 2039030cb4a7SJohnny Huang } 2040030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 2041030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2042030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2043030cb4a7SJohnny Huang ret = -1; 2044030cb4a7SJohnny Huang } 2045b64ca396SJohnny Huang printf("Read OTP Config Region:\n"); 2046b64ca396SJohnny Huang for (i = 0; i < 16 ; i++) 2047b64ca396SJohnny Huang otp_read_conf(i, &conf[i]); 2048b64ca396SJohnny Huang 2049b64ca396SJohnny Huang printf("Check writable...\n"); 2050b64ca396SJohnny Huang if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE) 2051b64ca396SJohnny Huang ret = -1; 2052030cb4a7SJohnny Huang } 2053030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 2054030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2055030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2056030cb4a7SJohnny Huang ret = -1; 2057030cb4a7SJohnny Huang } 2058b64ca396SJohnny Huang printf("Read OTP Strap Region:\n"); 2059b64ca396SJohnny Huang otp_strap_status(otpstrap); 2060b64ca396SJohnny Huang 2061b64ca396SJohnny Huang printf("Check writable...\n"); 2062b64ca396SJohnny Huang if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE) 2063b64ca396SJohnny Huang ret = -1; 2064030cb4a7SJohnny Huang } 2065b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2066b25f02d2SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2067b25f02d2SJohnny Huang printf("OTP strap region is protected\n"); 2068b25f02d2SJohnny Huang ret = -1; 2069b25f02d2SJohnny Huang } 2070b25f02d2SJohnny Huang printf("Read SCU Protect Region:\n"); 2071b25f02d2SJohnny Huang otp_read_conf(28, &scu_pro[0]); 2072b25f02d2SJohnny Huang otp_read_conf(29, &scu_pro[1]); 2073b25f02d2SJohnny Huang 2074b25f02d2SJohnny Huang printf("Check writable...\n"); 2075b25f02d2SJohnny Huang if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE) 2076b25f02d2SJohnny Huang ret = -1; 2077b25f02d2SJohnny Huang } 2078030cb4a7SJohnny Huang if (ret == -1) 2079030cb4a7SJohnny Huang return OTP_FAILURE; 2080b64ca396SJohnny Huang 208169d5fd8fSJohnny Huang if (!nconfirm) { 2082696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 20837f795e57SJohnny Huang printf("\nOTP data region :\n"); 2084f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 208569d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 20862a856b9aSJohnny Huang return OTP_FAILURE; 208769d5fd8fSJohnny Huang } 208869d5fd8fSJohnny Huang } 2089696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 20907332532cSJohnny Huang printf("\nOTP configuration region :\n"); 2091696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 20927332532cSJohnny Huang printf("OTP config error, please check.\n"); 20937332532cSJohnny Huang return OTP_FAILURE; 20947332532cSJohnny Huang } 20957332532cSJohnny Huang } 20967adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 20977adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 20987adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 20997adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 21007adec5f6SJohnny Huang return OTP_FAILURE; 21017adec5f6SJohnny Huang } 21027adec5f6SJohnny Huang } 2103b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2104b25f02d2SJohnny Huang printf("\nOTP scu protect region :\n"); 2105b25f02d2SJohnny Huang if (otp_print_scu_image(&image_layout) < 0) { 2106b25f02d2SJohnny Huang printf("OTP scu protect error, please check.\n"); 2107b25f02d2SJohnny Huang return OTP_FAILURE; 2108b25f02d2SJohnny Huang } 2109b25f02d2SJohnny Huang } 21107332532cSJohnny Huang 211169d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 211269d5fd8fSJohnny Huang if (!confirm_yesno()) { 211369d5fd8fSJohnny Huang printf(" Aborting\n"); 21142a856b9aSJohnny Huang return OTP_FAILURE; 211569d5fd8fSJohnny Huang } 211669d5fd8fSJohnny Huang } 21177332532cSJohnny Huang 21185010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 21195010032bSJohnny Huang printf("programing data region ...\n"); 2120b64ca396SJohnny Huang ret = otp_prog_data(&image_layout, data); 21215010032bSJohnny Huang if (ret != 0) { 21225010032bSJohnny Huang printf("Error\n"); 21235010032bSJohnny Huang return ret; 21245010032bSJohnny Huang } 2125a219f6deSJohnny Huang printf("Done\n"); 21265010032bSJohnny Huang } 21275010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 21285010032bSJohnny Huang printf("programing strap region ...\n"); 2129b64ca396SJohnny Huang ret = otp_prog_strap(&image_layout, otpstrap); 21305010032bSJohnny Huang if (ret != 0) { 21315010032bSJohnny Huang printf("Error\n"); 21325010032bSJohnny Huang return ret; 21335010032bSJohnny Huang } 2134a219f6deSJohnny Huang printf("Done\n"); 21355010032bSJohnny Huang } 2136b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2137b25f02d2SJohnny Huang printf("programing scu protect region ...\n"); 2138b25f02d2SJohnny Huang ret = otp_prog_scu_protect(&image_layout, scu_pro); 2139b25f02d2SJohnny Huang if (ret != 0) { 2140b25f02d2SJohnny Huang printf("Error\n"); 2141b25f02d2SJohnny Huang return ret; 2142b25f02d2SJohnny Huang } 2143b25f02d2SJohnny Huang printf("Done\n"); 2144b25f02d2SJohnny Huang } 21455010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 21465010032bSJohnny Huang printf("programing configuration region ...\n"); 2147b64ca396SJohnny Huang ret = otp_prog_conf(&image_layout, conf); 21485010032bSJohnny Huang if (ret != 0) { 21495010032bSJohnny Huang printf("Error\n"); 21505010032bSJohnny Huang return ret; 21515010032bSJohnny Huang } 21525010032bSJohnny Huang printf("Done\n"); 21535010032bSJohnny Huang } 2154cd1610b4SJohnny Huang 21557332532cSJohnny Huang return OTP_SUCCESS; 21562a856b9aSJohnny Huang } 21572a856b9aSJohnny Huang 2158f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 2159cd1610b4SJohnny Huang { 2160a219f6deSJohnny Huang u32 read[2]; 2161a219f6deSJohnny Huang u32 prog_address = 0; 216266f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 2163cd1610b4SJohnny Huang int otp_bit; 216483655e91SJohnny Huang int ret = 0; 2165cd1610b4SJohnny Huang 2166dacbba92SJohnny Huang otp_soak(0); 2167cd1610b4SJohnny Huang switch (mode) { 2168a6d0d645SJohnny Huang case OTP_REGION_CONF: 2169f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 2170cd1610b4SJohnny Huang prog_address = 0x800; 2171cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 2172cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 2173a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2174cd1610b4SJohnny Huang if (otp_bit == value) { 2175b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2176cd1610b4SJohnny Huang printf("No need to program\n"); 21772a856b9aSJohnny Huang return OTP_SUCCESS; 2178cd1610b4SJohnny Huang } 2179cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 2180b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 21810dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 21822a856b9aSJohnny Huang return OTP_FAILURE; 2183cd1610b4SJohnny Huang } 2184b489486eSJohnny Huang printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2185cd1610b4SJohnny Huang break; 2186a6d0d645SJohnny Huang case OTP_REGION_DATA: 2187cd1610b4SJohnny Huang prog_address = otp_dw_offset; 2188cd1610b4SJohnny Huang 2189cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 2190a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 2191a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2192643b9cfdSJohnny Huang 2193643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 2194b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2195b64ca396SJohnny Huang printf("OTP is programmed, which can't be cleared\n"); 2196643b9cfdSJohnny Huang return OTP_FAILURE; 2197643b9cfdSJohnny Huang } 2198cd1610b4SJohnny Huang } else { 2199a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 2200a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 2201643b9cfdSJohnny Huang 2202643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 2203b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2204b64ca396SJohnny Huang printf("OTP is programmed, which can't be written\n"); 2205643b9cfdSJohnny Huang return OTP_FAILURE; 2206643b9cfdSJohnny Huang } 2207cd1610b4SJohnny Huang } 2208cd1610b4SJohnny Huang if (otp_bit == value) { 2209b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2210cd1610b4SJohnny Huang printf("No need to program\n"); 22112a856b9aSJohnny Huang return OTP_SUCCESS; 2212cd1610b4SJohnny Huang } 2213643b9cfdSJohnny Huang 2214b489486eSJohnny Huang printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2215cd1610b4SJohnny Huang break; 2216a6d0d645SJohnny Huang case OTP_REGION_STRAP: 22178848d5dcSJohnny Huang otp_strap_status(otpstrap); 22188848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 22197e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 22208848d5dcSJohnny Huang if (ret == OTP_FAILURE) 22218848d5dcSJohnny Huang return OTP_FAILURE; 22228848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 22238848d5dcSJohnny Huang return OTP_SUCCESS; 2224a6af4a17SJohnny Huang 2225cd1610b4SJohnny Huang break; 2226cd1610b4SJohnny Huang } 2227cd1610b4SJohnny Huang 2228cd1610b4SJohnny Huang if (!nconfirm) { 2229cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2230cd1610b4SJohnny Huang if (!confirm_yesno()) { 2231cd1610b4SJohnny Huang printf(" Aborting\n"); 22322a856b9aSJohnny Huang return OTP_FAILURE; 2233cd1610b4SJohnny Huang } 2234cd1610b4SJohnny Huang } 2235cd1610b4SJohnny Huang 2236cd1610b4SJohnny Huang switch (mode) { 2237a6d0d645SJohnny Huang case OTP_REGION_STRAP: 2238f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 223983655e91SJohnny Huang break; 2240a6d0d645SJohnny Huang case OTP_REGION_CONF: 2241a6d0d645SJohnny Huang case OTP_REGION_DATA: 2242f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 2243de6fbf1cSJohnny Huang break; 2244de6fbf1cSJohnny Huang } 2245de6fbf1cSJohnny Huang otp_soak(0); 224683655e91SJohnny Huang if (ret) { 22470dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 2248794e27ecSJohnny Huang printf("FAILURE\n"); 2249794e27ecSJohnny Huang return OTP_FAILURE; 2250794e27ecSJohnny Huang } 2251794e27ecSJohnny Huang 22529009c25dSJohnny Huang printf("SUCCESS\n"); 22532a856b9aSJohnny Huang return OTP_SUCCESS; 2254a219f6deSJohnny Huang } 2255a219f6deSJohnny Huang 2256794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 2257794e27ecSJohnny Huang { 2258794e27ecSJohnny Huang u32 otp_rid[2]; 2259a8789b47SJohnny Huang u32 sw_rid[2]; 2260794e27ecSJohnny Huang int rid_num = 0; 2261a8789b47SJohnny Huang int sw_rid_num = 0; 2262794e27ecSJohnny Huang int bit_offset; 2263794e27ecSJohnny Huang int dw_offset; 2264794e27ecSJohnny Huang int i; 2265794e27ecSJohnny Huang int ret; 2266794e27ecSJohnny Huang 2267f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2268f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2269794e27ecSJohnny Huang 2270a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2271a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2272a8789b47SJohnny Huang 2273794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2274a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2275a8789b47SJohnny Huang 2276a8789b47SJohnny Huang if (sw_rid_num < 0) { 2277a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2278a8789b47SJohnny Huang return OTP_FAILURE; 2279a8789b47SJohnny Huang } 2280a8789b47SJohnny Huang 2281a8789b47SJohnny Huang if (update_num > sw_rid_num) { 2282a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2283a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2284a8789b47SJohnny Huang return OTP_FAILURE; 2285a8789b47SJohnny Huang } 2286794e27ecSJohnny Huang 2287794e27ecSJohnny Huang if (rid_num < 0) { 2288b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by this command,\n" 2289b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n"); 2290794e27ecSJohnny Huang otp_print_revid(otp_rid); 22919009c25dSJohnny Huang return OTP_FAILURE; 22929009c25dSJohnny Huang } 2293cd1610b4SJohnny Huang 2294794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2295794e27ecSJohnny Huang otp_print_revid(otp_rid); 2296794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 2297794e27ecSJohnny Huang 2298a8789b47SJohnny Huang if (rid_num > update_num) { 2299a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 2300a8789b47SJohnny Huang printf("Skip\n"); 2301a8789b47SJohnny Huang return OTP_FAILURE; 2302a8789b47SJohnny Huang } else if (rid_num == update_num) { 2303a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 2304794e27ecSJohnny Huang printf("Skip\n"); 2305794e27ecSJohnny Huang return OTP_FAILURE; 2306794e27ecSJohnny Huang } 2307794e27ecSJohnny Huang 2308794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2309794e27ecSJohnny Huang if (i < 32) { 2310794e27ecSJohnny Huang dw_offset = 0xa; 2311794e27ecSJohnny Huang bit_offset = i; 2312794e27ecSJohnny Huang } else { 2313794e27ecSJohnny Huang dw_offset = 0xb; 2314794e27ecSJohnny Huang bit_offset = i - 32; 2315794e27ecSJohnny Huang } 2316b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset); 2317794e27ecSJohnny Huang if (i + 1 != update_num) 2318794e27ecSJohnny Huang printf(", "); 2319794e27ecSJohnny Huang } 2320794e27ecSJohnny Huang 2321794e27ecSJohnny Huang printf(" will be programmed\n"); 2322794e27ecSJohnny Huang if (force == 0) { 2323794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2324794e27ecSJohnny Huang if (!confirm_yesno()) { 2325794e27ecSJohnny Huang printf(" Aborting\n"); 2326794e27ecSJohnny Huang return OTP_FAILURE; 2327794e27ecSJohnny Huang } 2328794e27ecSJohnny Huang } 2329794e27ecSJohnny Huang 2330794e27ecSJohnny Huang ret = 0; 2331794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2332794e27ecSJohnny Huang if (i < 32) { 2333794e27ecSJohnny Huang dw_offset = 0xa04; 2334794e27ecSJohnny Huang bit_offset = i; 2335794e27ecSJohnny Huang } else { 2336794e27ecSJohnny Huang dw_offset = 0xa06; 2337794e27ecSJohnny Huang bit_offset = i - 32; 2338794e27ecSJohnny Huang } 2339f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 2340b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset); 2341794e27ecSJohnny Huang ret = OTP_FAILURE; 2342794e27ecSJohnny Huang break; 2343794e27ecSJohnny Huang } 2344794e27ecSJohnny Huang } 2345061d3279SJohnny Huang otp_soak(0); 2346f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2347f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2348794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2349794e27ecSJohnny Huang if (rid_num >= 0) 2350794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 2351794e27ecSJohnny Huang else 2352794e27ecSJohnny Huang printf("OTP revision ID\n"); 2353794e27ecSJohnny Huang otp_print_revid(otp_rid); 2354794e27ecSJohnny Huang if (!ret) 2355794e27ecSJohnny Huang printf("SUCCESS\n"); 2356794e27ecSJohnny Huang else 2357794e27ecSJohnny Huang printf("FAILED\n"); 2358794e27ecSJohnny Huang return ret; 2359794e27ecSJohnny Huang } 2360794e27ecSJohnny Huang 2361883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force) 2362883625c5SJohnny Huang { 2363883625c5SJohnny Huang u32 otpcfg4; 2364883625c5SJohnny Huang u32 krb; 2365883625c5SJohnny Huang u32 krb_b; 2366883625c5SJohnny Huang u32 krb_or; 2367883625c5SJohnny Huang u32 current_id; 2368883625c5SJohnny Huang 2369883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2370883625c5SJohnny Huang current_id = readl(SEC_KEY_NUM) & 7; 2371883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2372883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2373883625c5SJohnny Huang krb_or = krb | krb_b; 2374883625c5SJohnny Huang 2375883625c5SJohnny Huang printf("current Key ID: 0x%x\n", current_id); 2376883625c5SJohnny Huang printf("input retire ID: 0x%x\n", retire_id); 2377883625c5SJohnny Huang printf("OTPCFG0x4 = 0x%X\n", otpcfg4); 2378883625c5SJohnny Huang 2379883625c5SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2380883625c5SJohnny Huang printf("OTPCFG4 is protected\n"); 2381883625c5SJohnny Huang return OTP_FAILURE; 2382883625c5SJohnny Huang } 2383883625c5SJohnny Huang 2384883625c5SJohnny Huang if (retire_id >= current_id) { 2385883625c5SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2386883625c5SJohnny Huang return OTP_FAILURE; 2387883625c5SJohnny Huang } 2388883625c5SJohnny Huang 2389883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2390883625c5SJohnny Huang printf("Key 0x%X already retired\n", retire_id); 2391883625c5SJohnny Huang return OTP_SUCCESS; 2392883625c5SJohnny Huang } 2393883625c5SJohnny Huang 2394883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id); 2395883625c5SJohnny Huang if (force == 0) { 2396883625c5SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2397883625c5SJohnny Huang if (!confirm_yesno()) { 2398883625c5SJohnny Huang printf(" Aborting\n"); 2399883625c5SJohnny Huang return OTP_FAILURE; 2400883625c5SJohnny Huang } 2401883625c5SJohnny Huang } 2402883625c5SJohnny Huang 2403883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) { 2404883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed\n", retire_id); 2405883625c5SJohnny Huang printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16); 2406883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE) 2407883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16); 2408883625c5SJohnny Huang } 2409883625c5SJohnny Huang 2410883625c5SJohnny Huang otp_soak(0); 2411883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2412883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2413883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2414883625c5SJohnny Huang krb_or = krb | krb_b; 2415883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2416883625c5SJohnny Huang printf("SUCCESS\n"); 2417883625c5SJohnny Huang return OTP_SUCCESS; 2418883625c5SJohnny Huang } 2419883625c5SJohnny Huang printf("FAILED\n"); 2420883625c5SJohnny Huang return OTP_FAILURE; 2421883625c5SJohnny Huang } 2422883625c5SJohnny Huang 2423*e7e21c44SJohnny Huang static int parse_config(struct sb_info *si) 2424*e7e21c44SJohnny Huang { 2425*e7e21c44SJohnny Huang int i; 2426*e7e21c44SJohnny Huang u32 cfg0, cfg3, cfg4; 2427*e7e21c44SJohnny Huang u32 sb_mode; 2428*e7e21c44SJohnny Huang u32 key_retire; 2429*e7e21c44SJohnny Huang u32 rsa_len; 2430*e7e21c44SJohnny Huang u32 sha_len; 2431*e7e21c44SJohnny Huang 2432*e7e21c44SJohnny Huang otp_read_conf(0, &cfg0); 2433*e7e21c44SJohnny Huang otp_read_conf(3, &cfg3); 2434*e7e21c44SJohnny Huang otp_read_conf(4, &cfg4); 2435*e7e21c44SJohnny Huang 2436*e7e21c44SJohnny Huang sb_mode = (cfg0 >> 7) & 0x1; 2437*e7e21c44SJohnny Huang si->enc_flag = (cfg0 >> 27) & 0x1; 2438*e7e21c44SJohnny Huang key_retire = (cfg4 & 0x7f) | ((cfg4 >> 16) & 0x7f); 2439*e7e21c44SJohnny Huang 2440*e7e21c44SJohnny Huang if ((cfg0 >> 16) & 0x3f) 2441*e7e21c44SJohnny Huang si->secure_region = 1; 2442*e7e21c44SJohnny Huang else 2443*e7e21c44SJohnny Huang si->secure_region = 0; 2444*e7e21c44SJohnny Huang 2445*e7e21c44SJohnny Huang si->header_offset = cfg3 & 0xffff; 2446*e7e21c44SJohnny Huang if (si->header_offset == 0) 2447*e7e21c44SJohnny Huang si->header_offset = 0x20; 2448*e7e21c44SJohnny Huang 2449*e7e21c44SJohnny Huang for (i = 0; i < 8; i++) { 2450*e7e21c44SJohnny Huang if ((key_retire >> i) & 0x1) 2451*e7e21c44SJohnny Huang si->retire_list[i] = 1; 2452*e7e21c44SJohnny Huang else 2453*e7e21c44SJohnny Huang si->retire_list[i] = 0; 2454*e7e21c44SJohnny Huang } 2455*e7e21c44SJohnny Huang 2456*e7e21c44SJohnny Huang if (sb_mode == 0) { 2457*e7e21c44SJohnny Huang printf("Mode GCM is not supported.\n"); 2458*e7e21c44SJohnny Huang return OTP_FAILURE; 2459*e7e21c44SJohnny Huang } 2460*e7e21c44SJohnny Huang 2461*e7e21c44SJohnny Huang if (si->enc_flag) 2462*e7e21c44SJohnny Huang printf("Algorithm: AES_RSA_SHA\n"); 2463*e7e21c44SJohnny Huang else 2464*e7e21c44SJohnny Huang printf("Algorithm: RSA_SHA\n"); 2465*e7e21c44SJohnny Huang 2466*e7e21c44SJohnny Huang rsa_len = (cfg0 >> 10) & 0x3; 2467*e7e21c44SJohnny Huang sha_len = (cfg0 >> 12) & 0x3; 2468*e7e21c44SJohnny Huang 2469*e7e21c44SJohnny Huang if (rsa_len == 0) { 2470*e7e21c44SJohnny Huang si->rsa_algo = 1024; 2471*e7e21c44SJohnny Huang printf("RSA length: 1024\n"); 2472*e7e21c44SJohnny Huang } else if (rsa_len == 1) { 2473*e7e21c44SJohnny Huang si->rsa_algo = 2048; 2474*e7e21c44SJohnny Huang printf("RSA length: 2048\n"); 2475*e7e21c44SJohnny Huang } else if (rsa_len == 2) { 2476*e7e21c44SJohnny Huang si->rsa_algo = 3072; 2477*e7e21c44SJohnny Huang printf("RSA length: 3072\n"); 2478*e7e21c44SJohnny Huang } else { 2479*e7e21c44SJohnny Huang si->rsa_algo = 4096; 2480*e7e21c44SJohnny Huang printf("RSA length: 4096\n"); 2481*e7e21c44SJohnny Huang } 2482*e7e21c44SJohnny Huang if (sha_len == 0) { 2483*e7e21c44SJohnny Huang si->sha_algo = 224; 2484*e7e21c44SJohnny Huang si->digest_len = 28; 2485*e7e21c44SJohnny Huang printf("HASH length: 224\n"); 2486*e7e21c44SJohnny Huang } else if (sha_len == 1) { 2487*e7e21c44SJohnny Huang si->sha_algo = 256; 2488*e7e21c44SJohnny Huang si->digest_len = 32; 2489*e7e21c44SJohnny Huang printf("HASH length: 256\n"); 2490*e7e21c44SJohnny Huang } else if (sha_len == 2) { 2491*e7e21c44SJohnny Huang si->sha_algo = 384; 2492*e7e21c44SJohnny Huang si->digest_len = 48; 2493*e7e21c44SJohnny Huang printf("HASH length: 384\n"); 2494*e7e21c44SJohnny Huang } else { 2495*e7e21c44SJohnny Huang si->sha_algo = 512; 2496*e7e21c44SJohnny Huang si->digest_len = 64; 2497*e7e21c44SJohnny Huang printf("HASH length: 512\n"); 2498*e7e21c44SJohnny Huang } 2499*e7e21c44SJohnny Huang return OTP_SUCCESS; 2500*e7e21c44SJohnny Huang } 2501*e7e21c44SJohnny Huang 2502*e7e21c44SJohnny Huang static void parse_data(struct key_list *kl, int *key_num, struct sb_info *si, u32 *data) 2503*e7e21c44SJohnny Huang { 2504*e7e21c44SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 2505*e7e21c44SJohnny Huang int i, j; 2506*e7e21c44SJohnny Huang int id = 0; 2507*e7e21c44SJohnny Huang u32 h; 2508*e7e21c44SJohnny Huang u32 t; 2509*e7e21c44SJohnny Huang 2510*e7e21c44SJohnny Huang *key_num = 0; 2511*e7e21c44SJohnny Huang for (i = 0; i < 16; i++) { 2512*e7e21c44SJohnny Huang h = data[i]; 2513*e7e21c44SJohnny Huang t = (h >> 14) & 0xf; 2514*e7e21c44SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 2515*e7e21c44SJohnny Huang if (t == key_info_array[j].value) { 2516*e7e21c44SJohnny Huang kl[*key_num].key_info = &key_info_array[j]; 2517*e7e21c44SJohnny Huang kl[*key_num].offset = h & 0x1ff8; 2518*e7e21c44SJohnny Huang id = h & 0x7; 2519*e7e21c44SJohnny Huang kl[*key_num].id = id; 2520*e7e21c44SJohnny Huang if (si->retire_list[id] == 1) 2521*e7e21c44SJohnny Huang kl[*key_num].retire = 1; 2522*e7e21c44SJohnny Huang else 2523*e7e21c44SJohnny Huang kl[*key_num].retire = 0; 2524*e7e21c44SJohnny Huang (*key_num)++; 2525*e7e21c44SJohnny Huang break; 2526*e7e21c44SJohnny Huang } 2527*e7e21c44SJohnny Huang } 2528*e7e21c44SJohnny Huang if ((data[i] >> 13) & 1) 2529*e7e21c44SJohnny Huang break; 2530*e7e21c44SJohnny Huang } 2531*e7e21c44SJohnny Huang } 2532*e7e21c44SJohnny Huang 2533*e7e21c44SJohnny Huang static int sb_sha(struct sb_info *si, u8 *sec_image, u32 sign_image_size, u8 *digest_ret) 2534*e7e21c44SJohnny Huang { 2535*e7e21c44SJohnny Huang switch (si->sha_algo) { 2536*e7e21c44SJohnny Huang case 224: 2537*e7e21c44SJohnny Huang printf("otp verify does not support SHA224\n"); 2538*e7e21c44SJohnny Huang return OTP_FAILURE; 2539*e7e21c44SJohnny Huang case 256: 2540*e7e21c44SJohnny Huang sb_sha256(sec_image, sign_image_size, digest_ret); 2541*e7e21c44SJohnny Huang break; 2542*e7e21c44SJohnny Huang case 384: 2543*e7e21c44SJohnny Huang sb_sha384(sec_image, sign_image_size, digest_ret); 2544*e7e21c44SJohnny Huang break; 2545*e7e21c44SJohnny Huang case 512: 2546*e7e21c44SJohnny Huang sb_sha512(sec_image, sign_image_size, digest_ret); 2547*e7e21c44SJohnny Huang break; 2548*e7e21c44SJohnny Huang default: 2549*e7e21c44SJohnny Huang printf("SHA Algorithm is invalid\n"); 2550*e7e21c44SJohnny Huang return OTP_FAILURE; 2551*e7e21c44SJohnny Huang } 2552*e7e21c44SJohnny Huang return 0; 2553*e7e21c44SJohnny Huang } 2554*e7e21c44SJohnny Huang 2555*e7e21c44SJohnny Huang static int mode2_verify(u8 *sec_image, u32 sign_image_size, 2556*e7e21c44SJohnny Huang u8 *signature, u8 *rsa_m, 2557*e7e21c44SJohnny Huang int order, u8 *digest, 2558*e7e21c44SJohnny Huang struct sb_info *si, struct udevice *mod_exp_dev) 2559*e7e21c44SJohnny Huang { 2560*e7e21c44SJohnny Huang struct key_prop prop; 2561*e7e21c44SJohnny Huang u8 rsa_e[3] = "\x01\x00\x01"; 2562*e7e21c44SJohnny Huang u8 sign_ret[512]; 2563*e7e21c44SJohnny Huang u8 rsa_m_rev[512]; 2564*e7e21c44SJohnny Huang u8 signature_rev[512]; 2565*e7e21c44SJohnny Huang u8 tmp; 2566*e7e21c44SJohnny Huang u32 rsa_len = si->rsa_algo / 8; 2567*e7e21c44SJohnny Huang int i; 2568*e7e21c44SJohnny Huang int ret; 2569*e7e21c44SJohnny Huang 2570*e7e21c44SJohnny Huang memset(&prop, 0, sizeof(struct key_prop)); 2571*e7e21c44SJohnny Huang 2572*e7e21c44SJohnny Huang if (order == OTP_LIT_END) { 2573*e7e21c44SJohnny Huang memset(rsa_m_rev, 0, 512); 2574*e7e21c44SJohnny Huang memset(signature_rev, 0, 512); 2575*e7e21c44SJohnny Huang for (i = 0; i < rsa_len; i++) { 2576*e7e21c44SJohnny Huang rsa_m_rev[i] = rsa_m[rsa_len - 1 - i]; 2577*e7e21c44SJohnny Huang signature_rev[i] = signature[rsa_len - 1 - i]; 2578*e7e21c44SJohnny Huang } 2579*e7e21c44SJohnny Huang prop.modulus = rsa_m_rev; 2580*e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo; 2581*e7e21c44SJohnny Huang prop.public_exponent = rsa_e; 2582*e7e21c44SJohnny Huang prop.exp_len = 3; 2583*e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature_rev, rsa_len, &prop, sign_ret); 2584*e7e21c44SJohnny Huang } else { 2585*e7e21c44SJohnny Huang prop.modulus = rsa_m; 2586*e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo; 2587*e7e21c44SJohnny Huang prop.public_exponent = rsa_e; 2588*e7e21c44SJohnny Huang prop.exp_len = 3; 2589*e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature, rsa_len, &prop, sign_ret); 2590*e7e21c44SJohnny Huang } 2591*e7e21c44SJohnny Huang 2592*e7e21c44SJohnny Huang if (ret) { 2593*e7e21c44SJohnny Huang printf("rsa_mod_exp error: %d\n", ret); 2594*e7e21c44SJohnny Huang return OTP_FAILURE; 2595*e7e21c44SJohnny Huang } 2596*e7e21c44SJohnny Huang 2597*e7e21c44SJohnny Huang if (order == OTP_LIT_END) { 2598*e7e21c44SJohnny Huang for (i = 0; i < rsa_len / 2; i++) { 2599*e7e21c44SJohnny Huang tmp = sign_ret[i]; 2600*e7e21c44SJohnny Huang sign_ret[i] = sign_ret[rsa_len - 1 - i]; 2601*e7e21c44SJohnny Huang sign_ret[rsa_len - 1 - i] = tmp; 2602*e7e21c44SJohnny Huang } 2603*e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret, si->digest_len); 2604*e7e21c44SJohnny Huang } else { 2605*e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret + (rsa_len - si->digest_len), si->digest_len); 2606*e7e21c44SJohnny Huang } 2607*e7e21c44SJohnny Huang 2608*e7e21c44SJohnny Huang if (ret) 2609*e7e21c44SJohnny Huang return OTP_FAILURE; 2610*e7e21c44SJohnny Huang return 0; 2611*e7e21c44SJohnny Huang } 2612*e7e21c44SJohnny Huang 2613*e7e21c44SJohnny Huang static int otp_verify_boot_image(phys_addr_t addr) 2614*e7e21c44SJohnny Huang { 2615*e7e21c44SJohnny Huang struct udevice *mod_exp_dev; 2616*e7e21c44SJohnny Huang struct sb_info si; 2617*e7e21c44SJohnny Huang struct key_list kl[16]; 2618*e7e21c44SJohnny Huang struct sb_header *sh; 2619*e7e21c44SJohnny Huang u32 data[2048]; 2620*e7e21c44SJohnny Huang u8 digest[64]; 2621*e7e21c44SJohnny Huang u8 *sec_image; 2622*e7e21c44SJohnny Huang u8 *signature; 2623*e7e21c44SJohnny Huang u8 *key; 2624*e7e21c44SJohnny Huang u32 otp_rid[2]; 2625*e7e21c44SJohnny Huang u32 sw_rid[2]; 2626*e7e21c44SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2627*e7e21c44SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2628*e7e21c44SJohnny Huang int key_num; 2629*e7e21c44SJohnny Huang int ret; 2630*e7e21c44SJohnny Huang int i; 2631*e7e21c44SJohnny Huang int pass = 0; 2632*e7e21c44SJohnny Huang 2633*e7e21c44SJohnny Huang ret = uclass_get_device_by_driver(UCLASS_MOD_EXP, DM_GET_DRIVER(aspeed_acry), &mod_exp_dev); 2634*e7e21c44SJohnny Huang if (ret) { 2635*e7e21c44SJohnny Huang printf("RSA engine: Can't find aspeed_acry\n"); 2636*e7e21c44SJohnny Huang return OTP_FAILURE; 2637*e7e21c44SJohnny Huang } 2638*e7e21c44SJohnny Huang 2639*e7e21c44SJohnny Huang for (i = 0; i < 2048 ; i += 2) 2640*e7e21c44SJohnny Huang otp_read_data(i, &data[i]); 2641*e7e21c44SJohnny Huang if (parse_config(&si)) 2642*e7e21c44SJohnny Huang return OTP_FAILURE; 2643*e7e21c44SJohnny Huang parse_data(kl, &key_num, &si, data); 2644*e7e21c44SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2645*e7e21c44SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2646*e7e21c44SJohnny Huang 2647*e7e21c44SJohnny Huang sec_image = (u8 *)addr; 2648*e7e21c44SJohnny Huang sh = (struct sb_header *)(sec_image + si.header_offset); 2649*e7e21c44SJohnny Huang signature = sec_image + sh->signature_offset; 2650*e7e21c44SJohnny Huang 2651*e7e21c44SJohnny Huang if (si.secure_region) 2652*e7e21c44SJohnny Huang printf("WARNING: Secure Region is enabled, the verification may not correct.\n"); 2653*e7e21c44SJohnny Huang 2654*e7e21c44SJohnny Huang if (sh->sign_image_size % 512) { 2655*e7e21c44SJohnny Huang printf("ERROR: The sign_image_size should be 512 bytes aligned\n"); 2656*e7e21c44SJohnny Huang return OTP_FAILURE; 2657*e7e21c44SJohnny Huang } 2658*e7e21c44SJohnny Huang 2659*e7e21c44SJohnny Huang printf("Check revision ID: "); 2660*e7e21c44SJohnny Huang 2661*e7e21c44SJohnny Huang sw_rid[0] = sh->revision_low; 2662*e7e21c44SJohnny Huang sw_rid[1] = sh->revision_high; 2663*e7e21c44SJohnny Huang 2664*e7e21c44SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2665*e7e21c44SJohnny Huang printf("FAIL\n"); 2666*e7e21c44SJohnny Huang printf("Header revision_low: %x\n", sh->revision_low); 2667*e7e21c44SJohnny Huang printf("Header revision_high: %x\n", sh->revision_high); 2668*e7e21c44SJohnny Huang printf("OTP revision_low: %x\n", otp_rid[0]); 2669*e7e21c44SJohnny Huang printf("OTP revision_high: %x\n", otp_rid[1]); 2670*e7e21c44SJohnny Huang return OTP_FAILURE; 2671*e7e21c44SJohnny Huang } 2672*e7e21c44SJohnny Huang printf("PASS\n"); 2673*e7e21c44SJohnny Huang 2674*e7e21c44SJohnny Huang printf("Check secure image header: "); 2675*e7e21c44SJohnny Huang if (((sh->aes_data_offset + sh->enc_offset + sh->sign_image_size + 2676*e7e21c44SJohnny Huang sh->signature_offset + sh->revision_high + sh->revision_low + 2677*e7e21c44SJohnny Huang sh->reserved + sh->bl1_header_checksum) & 0xffffffff) != 0) { 2678*e7e21c44SJohnny Huang printf("FAIL\n"); 2679*e7e21c44SJohnny Huang printf("aes_data_offset: %x\n", sh->aes_data_offset); 2680*e7e21c44SJohnny Huang printf("enc_offset: %x\n", sh->enc_offset); 2681*e7e21c44SJohnny Huang printf("sign_image_size: %x\n", sh->sign_image_size); 2682*e7e21c44SJohnny Huang printf("signature_offset: %x\n", sh->signature_offset); 2683*e7e21c44SJohnny Huang printf("revision_high: %x\n", sh->revision_high); 2684*e7e21c44SJohnny Huang printf("revision_low: %x\n", sh->revision_low); 2685*e7e21c44SJohnny Huang printf("reserved: %x\n", sh->reserved); 2686*e7e21c44SJohnny Huang printf("bl1_header_checksum: %x\n", sh->bl1_header_checksum); 2687*e7e21c44SJohnny Huang return OTP_FAILURE; 2688*e7e21c44SJohnny Huang } 2689*e7e21c44SJohnny Huang printf("PASS\n"); 2690*e7e21c44SJohnny Huang 2691*e7e21c44SJohnny Huang ret = sb_sha(&si, sec_image, sh->sign_image_size, digest); 2692*e7e21c44SJohnny Huang if (ret) 2693*e7e21c44SJohnny Huang return OTP_FAILURE; 2694*e7e21c44SJohnny Huang 2695*e7e21c44SJohnny Huang printf("Verifying secure image\n"); 2696*e7e21c44SJohnny Huang for (i = 0; i < key_num; i++) { 2697*e7e21c44SJohnny Huang if (kl[i].key_info->key_type != OTP_KEY_TYPE_RSA_PUB) 2698*e7e21c44SJohnny Huang continue; 2699*e7e21c44SJohnny Huang printf(" Key %d\n", kl[i].id); 2700*e7e21c44SJohnny Huang if (kl[i].retire) { 2701*e7e21c44SJohnny Huang printf(" Key %d is retired.\n", kl[i].id); 2702*e7e21c44SJohnny Huang continue; 2703*e7e21c44SJohnny Huang } 2704*e7e21c44SJohnny Huang key = (u8 *)data + kl[i].offset; 2705*e7e21c44SJohnny Huang if (!mode2_verify(sec_image, sh->sign_image_size, 2706*e7e21c44SJohnny Huang signature, key, kl[i].key_info->order, digest, 2707*e7e21c44SJohnny Huang &si, mod_exp_dev)) { 2708*e7e21c44SJohnny Huang pass = 1; 2709*e7e21c44SJohnny Huang break; 2710*e7e21c44SJohnny Huang } 2711*e7e21c44SJohnny Huang } 2712*e7e21c44SJohnny Huang if (pass) { 2713*e7e21c44SJohnny Huang printf(" OEM DSS RSA public keys\n"); 2714*e7e21c44SJohnny Huang printf(" ID: %d\n", kl[i].id); 2715*e7e21c44SJohnny Huang if (kl[i].key_info->order == OTP_BIG_END) 2716*e7e21c44SJohnny Huang printf(" Big endian\n"); 2717*e7e21c44SJohnny Huang else 2718*e7e21c44SJohnny Huang printf(" Little endian\n"); 2719*e7e21c44SJohnny Huang printf("Verify secure image: PASS\n"); 2720*e7e21c44SJohnny Huang return OTP_SUCCESS; 2721*e7e21c44SJohnny Huang } 2722*e7e21c44SJohnny Huang printf("Verify secure image: FAIL\n"); 2723*e7e21c44SJohnny Huang return OTP_FAILURE; 2724*e7e21c44SJohnny Huang } 2725*e7e21c44SJohnny Huang 27262a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 272769d5fd8fSJohnny Huang { 2728a219f6deSJohnny Huang u32 offset, count; 27292a856b9aSJohnny Huang int ret; 273069d5fd8fSJohnny Huang 27312a856b9aSJohnny Huang if (argc == 4) { 27322a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 27332a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 27342a856b9aSJohnny Huang } else if (argc == 3) { 27352a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 27362a856b9aSJohnny Huang count = 1; 27372a856b9aSJohnny Huang } else { 273869d5fd8fSJohnny Huang return CMD_RET_USAGE; 273969d5fd8fSJohnny Huang } 274069d5fd8fSJohnny Huang 2741030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2742f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2743030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 27442a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2745030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 27462a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2747030cb4a7SJohnny Huang else 27482a856b9aSJohnny Huang return CMD_RET_USAGE; 274969d5fd8fSJohnny Huang 27502a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 27512a856b9aSJohnny Huang return CMD_RET_SUCCESS; 27522a856b9aSJohnny Huang return CMD_RET_USAGE; 27532a856b9aSJohnny Huang } 27542a856b9aSJohnny Huang 27552a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 27562a856b9aSJohnny Huang { 27572a856b9aSJohnny Huang phys_addr_t addr; 27582a856b9aSJohnny Huang int ret; 27592a856b9aSJohnny Huang 2760de6b0cc4SJohnny Huang if (argc == 3) { 2761ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 27622a856b9aSJohnny Huang return CMD_RET_USAGE; 27632a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2764f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2765de6b0cc4SJohnny Huang } else if (argc == 2) { 27662a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2767f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 27682a856b9aSJohnny Huang } else { 27692a856b9aSJohnny Huang return CMD_RET_USAGE; 27702a856b9aSJohnny Huang } 27712a856b9aSJohnny Huang 27722a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 27732a856b9aSJohnny Huang return CMD_RET_SUCCESS; 27742a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 27752a856b9aSJohnny Huang return CMD_RET_FAILURE; 27762a856b9aSJohnny Huang else 27772a856b9aSJohnny Huang return CMD_RET_USAGE; 27782a856b9aSJohnny Huang } 27792a856b9aSJohnny Huang 27802a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 27812a856b9aSJohnny Huang { 27822a856b9aSJohnny Huang int mode = 0; 27832a856b9aSJohnny Huang int nconfirm = 0; 27842a856b9aSJohnny Huang int otp_addr = 0; 27852a856b9aSJohnny Huang int bit_offset; 27862a856b9aSJohnny Huang int value; 27872a856b9aSJohnny Huang int ret; 2788030cb4a7SJohnny Huang u32 otp_strap_pro; 27892a856b9aSJohnny Huang 27902a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 27912a856b9aSJohnny Huang return CMD_RET_USAGE; 27922a856b9aSJohnny Huang 27932a856b9aSJohnny Huang /* Drop the pb cmd */ 27942a856b9aSJohnny Huang argc--; 27952a856b9aSJohnny Huang argv++; 27962a856b9aSJohnny Huang 27972a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2798a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 27992a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2800a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 28012a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2802a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2803cd1610b4SJohnny Huang else 28042a856b9aSJohnny Huang return CMD_RET_USAGE; 28052a856b9aSJohnny Huang 28062a856b9aSJohnny Huang /* Drop the region cmd */ 28072a856b9aSJohnny Huang argc--; 28082a856b9aSJohnny Huang argv++; 28092a856b9aSJohnny Huang 2810ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2811cd1610b4SJohnny Huang nconfirm = 1; 28122a856b9aSJohnny Huang /* Drop the force option */ 28132a856b9aSJohnny Huang argc--; 28142a856b9aSJohnny Huang argv++; 28152a856b9aSJohnny Huang } 2816cd1610b4SJohnny Huang 2817a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 28182a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 28192a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 28200808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 28212a856b9aSJohnny Huang return CMD_RET_USAGE; 2822cd1610b4SJohnny Huang } else { 28232a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 28242a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 28252a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 28260808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 28272a856b9aSJohnny Huang return CMD_RET_USAGE; 28280808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 282978855207SJohnny Huang if (otp_addr >= 0x800) 28300808cc55SJohnny Huang return CMD_RET_USAGE; 28310808cc55SJohnny Huang } else { 283278855207SJohnny Huang if (otp_addr >= 0x20) 28330808cc55SJohnny Huang return CMD_RET_USAGE; 28340808cc55SJohnny Huang } 2835cd1610b4SJohnny Huang } 2836cd1610b4SJohnny Huang if (value != 0 && value != 1) 28372a856b9aSJohnny Huang return CMD_RET_USAGE; 2838cd1610b4SJohnny Huang 2839030cb4a7SJohnny Huang ret = 0; 2840030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2841030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2842030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2843030cb4a7SJohnny Huang } 2844030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2845030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2846030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2847030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2848030cb4a7SJohnny Huang ret = -1; 2849030cb4a7SJohnny Huang } 2850030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2851030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2852030cb4a7SJohnny Huang ret = -1; 2853030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2854030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2855030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2856030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2857030cb4a7SJohnny Huang ret = -1; 2858030cb4a7SJohnny Huang } 2859030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2860030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2861030cb4a7SJohnny Huang ret = -1; 2862030cb4a7SJohnny Huang } 2863030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2864030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2865030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2866030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2867030cb4a7SJohnny Huang ret = -1; 2868030cb4a7SJohnny Huang } 2869030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2870030cb4a7SJohnny Huang u32 otp_rid[2]; 2871030cb4a7SJohnny Huang u32 sw_rid[2]; 2872030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2873030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2874030cb4a7SJohnny Huang 2875030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2876030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2877030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2878030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2879030cb4a7SJohnny Huang 2880030cb4a7SJohnny Huang if (otp_addr == 10) 2881030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2882030cb4a7SJohnny Huang else 2883030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2884030cb4a7SJohnny Huang 2885030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2886030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2887030cb4a7SJohnny Huang ret = -1; 2888030cb4a7SJohnny Huang } 2889030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2890030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2891030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2892030cb4a7SJohnny Huang ret = -1; 2893030cb4a7SJohnny Huang } else { 2894030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2895030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2896030cb4a7SJohnny Huang u32 key_num; 2897030cb4a7SJohnny Huang u32 retire; 2898030cb4a7SJohnny Huang 2899030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2900030cb4a7SJohnny Huang if (bit_offset >= 16) 2901030cb4a7SJohnny Huang retire = bit_offset - 16; 2902030cb4a7SJohnny Huang else 2903030cb4a7SJohnny Huang retire = bit_offset; 2904030cb4a7SJohnny Huang if (retire >= key_num) { 2905030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2906030cb4a7SJohnny Huang ret = -1; 2907030cb4a7SJohnny Huang } 2908030cb4a7SJohnny Huang } 2909030cb4a7SJohnny Huang } 2910030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2911030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2912030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2913030cb4a7SJohnny Huang ret = -1; 2914030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2915030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2916030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2917030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2918030cb4a7SJohnny Huang else 2919030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2920030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2921b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset); 2922030cb4a7SJohnny Huang ret = -1; 2923030cb4a7SJohnny Huang } 2924030cb4a7SJohnny Huang } 2925030cb4a7SJohnny Huang } 2926030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2927030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2928030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2929030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2930030cb4a7SJohnny Huang ret = -1; 2931030cb4a7SJohnny Huang } 2932030cb4a7SJohnny Huang } 2933030cb4a7SJohnny Huang 2934030cb4a7SJohnny Huang if (ret == -1) 2935030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2936030cb4a7SJohnny Huang 2937f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 29382a856b9aSJohnny Huang 29392a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 29402a856b9aSJohnny Huang return CMD_RET_SUCCESS; 29412a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 29422a856b9aSJohnny Huang return CMD_RET_FAILURE; 29432a856b9aSJohnny Huang else 29442a856b9aSJohnny Huang return CMD_RET_USAGE; 29452a856b9aSJohnny Huang } 29462a856b9aSJohnny Huang 29472a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 29482a856b9aSJohnny Huang { 29492a856b9aSJohnny Huang phys_addr_t addr; 29502a856b9aSJohnny Huang int otp_addr = 0; 2951b8590031SJohnny Huang int ret; 29522a856b9aSJohnny Huang 29532a856b9aSJohnny Huang if (argc != 3) 29542a856b9aSJohnny Huang return CMD_RET_USAGE; 29552a856b9aSJohnny Huang 29562a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 29572a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 2958b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 2959b8590031SJohnny Huang if (ret == 0) { 296069d5fd8fSJohnny Huang printf("Compare pass\n"); 29612a856b9aSJohnny Huang return CMD_RET_SUCCESS; 2962a219f6deSJohnny Huang } 296369d5fd8fSJohnny Huang printf("Compare fail\n"); 29642a856b9aSJohnny Huang return CMD_RET_FAILURE; 296569d5fd8fSJohnny Huang } 296669d5fd8fSJohnny Huang 296766f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 296866f2f8e5SJohnny Huang { 2969a8bd6d8cSJohnny Huang int view = 0; 29702d4b0742SJohnny Huang int input; 2971a8bd6d8cSJohnny Huang 2972a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 297366f2f8e5SJohnny Huang return CMD_RET_USAGE; 297466f2f8e5SJohnny Huang 29752d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 29762d4b0742SJohnny Huang if (argc == 3) { 29772d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 29782d4b0742SJohnny Huang otp_print_conf_info(input); 29792d4b0742SJohnny Huang } else { 29802d4b0742SJohnny Huang otp_print_conf_info(-1); 29812d4b0742SJohnny Huang } 29822d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 29832d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 2984a8bd6d8cSJohnny Huang view = 1; 2985a8bd6d8cSJohnny Huang /* Drop the view option */ 2986a8bd6d8cSJohnny Huang argc--; 2987a8bd6d8cSJohnny Huang argv++; 2988a8bd6d8cSJohnny Huang } 2989b458cd62SJohnny Huang otp_print_strap_info(view); 29900dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 29910dc9a440SJohnny Huang otp_print_scu_info(); 299288bd7d58SJohnny Huang } else if (!strcmp(argv[1], "key")) { 299388bd7d58SJohnny Huang otp_print_key_info(); 299466f2f8e5SJohnny Huang } else { 299566f2f8e5SJohnny Huang return CMD_RET_USAGE; 299666f2f8e5SJohnny Huang } 29972d4b0742SJohnny Huang 299866f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 299966f2f8e5SJohnny Huang } 300066f2f8e5SJohnny Huang 30010dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3002737ed20bSJohnny Huang { 30030dc9a440SJohnny Huang u32 input; 30040dc9a440SJohnny Huang u32 bit_offset; 3005e14b073cSJohnny Huang u32 prog_address; 3006030cb4a7SJohnny Huang char force; 300783655e91SJohnny Huang int ret; 3008a219f6deSJohnny Huang 3009737ed20bSJohnny Huang if (argc != 3 && argc != 2) 3010737ed20bSJohnny Huang return CMD_RET_USAGE; 3011737ed20bSJohnny Huang 3012e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 3013737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 3014030cb4a7SJohnny Huang force = 1; 3015737ed20bSJohnny Huang } else { 3016737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 3017030cb4a7SJohnny Huang force = 0; 3018737ed20bSJohnny Huang } 3019737ed20bSJohnny Huang 3020737ed20bSJohnny Huang if (input < 32) { 3021737ed20bSJohnny Huang bit_offset = input; 30220dc9a440SJohnny Huang prog_address = 0xe0c; 3023737ed20bSJohnny Huang } else if (input < 64) { 3024737ed20bSJohnny Huang bit_offset = input - 32; 30250dc9a440SJohnny Huang prog_address = 0xe0e; 3026737ed20bSJohnny Huang } else { 3027737ed20bSJohnny Huang return CMD_RET_USAGE; 3028737ed20bSJohnny Huang } 3029737ed20bSJohnny Huang 3030030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 3031030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 3032030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3033030cb4a7SJohnny Huang } 3034030cb4a7SJohnny Huang 3035030cb4a7SJohnny Huang if (!force) { 3036b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input); 3037030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 3038030cb4a7SJohnny Huang if (!confirm_yesno()) { 3039030cb4a7SJohnny Huang printf(" Aborting\n"); 3040030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3041030cb4a7SJohnny Huang } 3042030cb4a7SJohnny Huang } 3043030cb4a7SJohnny Huang 3044e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 3045b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input); 3046e14b073cSJohnny Huang return CMD_RET_SUCCESS; 3047e14b073cSJohnny Huang } 3048de6fbf1cSJohnny Huang 3049f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 3050de6fbf1cSJohnny Huang otp_soak(0); 305183655e91SJohnny Huang 305283655e91SJohnny Huang if (ret) { 3053b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input); 3054737ed20bSJohnny Huang return CMD_RET_FAILURE; 3055737ed20bSJohnny Huang } 30569a4fe690SJohnny Huang 3057b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input); 3058794e27ecSJohnny Huang return CMD_RET_SUCCESS; 3059794e27ecSJohnny Huang } 3060794e27ecSJohnny Huang 30610dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3062e14b073cSJohnny Huang { 30630dc9a440SJohnny Huang u32 scu_offset; 30640dc9a440SJohnny Huang u32 bit_offset; 30650dc9a440SJohnny Huang u32 conf_offset; 30660dc9a440SJohnny Huang u32 prog_address; 30670dc9a440SJohnny Huang char force; 30680dc9a440SJohnny Huang int ret; 30690dc9a440SJohnny Huang 30700dc9a440SJohnny Huang if (argc != 4 && argc != 3) 30710dc9a440SJohnny Huang return CMD_RET_USAGE; 30720dc9a440SJohnny Huang 30730dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 30740dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 30750dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 30760dc9a440SJohnny Huang force = 1; 30770dc9a440SJohnny Huang } else { 30780dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 30790dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 30800dc9a440SJohnny Huang force = 0; 30810dc9a440SJohnny Huang } 30820dc9a440SJohnny Huang if (scu_offset == 0x500) { 30830dc9a440SJohnny Huang prog_address = 0xe08; 30840dc9a440SJohnny Huang conf_offset = 28; 30850dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 30860dc9a440SJohnny Huang prog_address = 0xe0a; 30870dc9a440SJohnny Huang conf_offset = 29; 30880dc9a440SJohnny Huang } else { 30890dc9a440SJohnny Huang return CMD_RET_USAGE; 30900dc9a440SJohnny Huang } 30910dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 30920dc9a440SJohnny Huang return CMD_RET_USAGE; 3093030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 3094030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 3095030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3096030cb4a7SJohnny Huang } 30970dc9a440SJohnny Huang if (!force) { 3098b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset); 3099b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset); 31000dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 31010dc9a440SJohnny Huang if (!confirm_yesno()) { 31020dc9a440SJohnny Huang printf(" Aborting\n"); 31030dc9a440SJohnny Huang return CMD_RET_FAILURE; 31040dc9a440SJohnny Huang } 3105e14b073cSJohnny Huang } 3106e14b073cSJohnny Huang 31070dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 3108b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset); 31090dc9a440SJohnny Huang return CMD_RET_SUCCESS; 31100dc9a440SJohnny Huang } 31110dc9a440SJohnny Huang 31120dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 31130dc9a440SJohnny Huang otp_soak(0); 31140dc9a440SJohnny Huang 31150dc9a440SJohnny Huang if (ret) { 3116b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset); 31170dc9a440SJohnny Huang return CMD_RET_FAILURE; 31180dc9a440SJohnny Huang } 31190dc9a440SJohnny Huang 3120b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset); 31210dc9a440SJohnny Huang return CMD_RET_SUCCESS; 3122e14b073cSJohnny Huang } 3123e14b073cSJohnny Huang 3124f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3125f67375f7SJohnny Huang { 3126e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 3127f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 3128f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 3129f67375f7SJohnny Huang 3130f67375f7SJohnny Huang return CMD_RET_SUCCESS; 3131f67375f7SJohnny Huang } 3132f67375f7SJohnny Huang 3133794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3134794e27ecSJohnny Huang { 3135794e27ecSJohnny Huang u32 update_num; 3136794e27ecSJohnny Huang int force = 0; 3137794e27ecSJohnny Huang int ret; 3138794e27ecSJohnny Huang 3139794e27ecSJohnny Huang if (argc == 3) { 3140794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 3141794e27ecSJohnny Huang return CMD_RET_USAGE; 3142794e27ecSJohnny Huang force = 1; 3143794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 3144794e27ecSJohnny Huang } else if (argc == 2) { 3145794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 3146794e27ecSJohnny Huang } else { 3147794e27ecSJohnny Huang return CMD_RET_USAGE; 3148794e27ecSJohnny Huang } 3149794e27ecSJohnny Huang 3150794e27ecSJohnny Huang if (update_num > 64) 3151794e27ecSJohnny Huang return CMD_RET_USAGE; 3152794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 3153b8590031SJohnny Huang 3154794e27ecSJohnny Huang if (ret) 3155794e27ecSJohnny Huang return CMD_RET_FAILURE; 3156794e27ecSJohnny Huang return CMD_RET_SUCCESS; 3157794e27ecSJohnny Huang } 3158794e27ecSJohnny Huang 3159794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3160794e27ecSJohnny Huang { 3161794e27ecSJohnny Huang u32 otp_rid[2]; 3162a8789b47SJohnny Huang u32 sw_rid[2]; 3163794e27ecSJohnny Huang int rid_num = 0; 3164a8789b47SJohnny Huang int sw_rid_num = 0; 3165794e27ecSJohnny Huang int ret; 3166794e27ecSJohnny Huang 3167794e27ecSJohnny Huang if (argc != 1) 3168794e27ecSJohnny Huang return CMD_RET_USAGE; 3169794e27ecSJohnny Huang 3170f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 3171f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 3172794e27ecSJohnny Huang 3173a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 3174a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 3175794e27ecSJohnny Huang 3176a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 3177a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 3178a8789b47SJohnny Huang 3179030cb4a7SJohnny Huang if (sw_rid_num < 0) { 3180030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 3181030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 3182030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 3183030cb4a7SJohnny Huang } else { 3184a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 3185030cb4a7SJohnny Huang } 3186794e27ecSJohnny Huang if (rid_num >= 0) { 3187794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 3188794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 3189794e27ecSJohnny Huang } else { 3190b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n" 3191b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n" 3192794e27ecSJohnny Huang "current OTP revision ID\n"); 3193794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 3194794e27ecSJohnny Huang } 3195794e27ecSJohnny Huang otp_print_revid(otp_rid); 3196794e27ecSJohnny Huang 3197794e27ecSJohnny Huang return ret; 3198794e27ecSJohnny Huang } 3199794e27ecSJohnny Huang 3200883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3201883625c5SJohnny Huang { 3202883625c5SJohnny Huang u32 retire_id; 3203883625c5SJohnny Huang int force = 0; 3204883625c5SJohnny Huang int ret; 3205883625c5SJohnny Huang 3206883625c5SJohnny Huang if (argc == 3) { 3207883625c5SJohnny Huang if (strcmp(argv[1], "o")) 3208883625c5SJohnny Huang return CMD_RET_USAGE; 3209883625c5SJohnny Huang force = 1; 3210883625c5SJohnny Huang retire_id = simple_strtoul(argv[2], NULL, 16); 3211883625c5SJohnny Huang } else if (argc == 2) { 3212883625c5SJohnny Huang retire_id = simple_strtoul(argv[1], NULL, 16); 3213883625c5SJohnny Huang } else { 3214883625c5SJohnny Huang return CMD_RET_USAGE; 3215883625c5SJohnny Huang } 3216883625c5SJohnny Huang 3217883625c5SJohnny Huang if (retire_id > 7) 3218883625c5SJohnny Huang return CMD_RET_USAGE; 3219883625c5SJohnny Huang ret = otp_retire_key(retire_id, force); 3220883625c5SJohnny Huang 3221883625c5SJohnny Huang if (ret) 3222883625c5SJohnny Huang return CMD_RET_FAILURE; 3223883625c5SJohnny Huang return CMD_RET_SUCCESS; 3224883625c5SJohnny Huang } 3225883625c5SJohnny Huang 3226*e7e21c44SJohnny Huang static int do_otpverify(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3227*e7e21c44SJohnny Huang { 3228*e7e21c44SJohnny Huang phys_addr_t addr; 3229*e7e21c44SJohnny Huang int ret; 3230*e7e21c44SJohnny Huang 3231*e7e21c44SJohnny Huang if (argc == 2) { 3232*e7e21c44SJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 3233*e7e21c44SJohnny Huang ret = otp_verify_boot_image(addr); 3234*e7e21c44SJohnny Huang } else { 3235*e7e21c44SJohnny Huang return CMD_RET_USAGE; 3236*e7e21c44SJohnny Huang } 3237*e7e21c44SJohnny Huang 3238*e7e21c44SJohnny Huang if (ret == OTP_SUCCESS) 3239*e7e21c44SJohnny Huang return CMD_RET_SUCCESS; 3240*e7e21c44SJohnny Huang else if (ret == OTP_FAILURE) 3241*e7e21c44SJohnny Huang return CMD_RET_FAILURE; 3242*e7e21c44SJohnny Huang else 3243*e7e21c44SJohnny Huang return CMD_RET_USAGE; 3244*e7e21c44SJohnny Huang } 3245*e7e21c44SJohnny Huang 32462a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 3247f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 32482a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 3249a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 3250de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 32512a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 3252737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 32530dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 32542a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 3255794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 3256794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 3257883625c5SJohnny Huang U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""), 3258*e7e21c44SJohnny Huang U_BOOT_CMD_MKENT(verify, 2, 0, do_otpverify, "", ""), 32592a856b9aSJohnny Huang }; 32602a856b9aSJohnny Huang 32612a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 32622a856b9aSJohnny Huang { 3263030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 32642a856b9aSJohnny Huang cmd_tbl_t *cp; 3265a219f6deSJohnny Huang u32 ver; 3266e14b073cSJohnny Huang int ret; 3267030cb4a7SJohnny Huang u32 otp_conf0; 32682a856b9aSJohnny Huang 32692a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 32702a856b9aSJohnny Huang 3271737ed20bSJohnny Huang /* Drop the otp command */ 32722a856b9aSJohnny Huang argc--; 32732a856b9aSJohnny Huang argv++; 32742a856b9aSJohnny Huang 3275a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 32762a856b9aSJohnny Huang return CMD_RET_USAGE; 32772a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 32782a856b9aSJohnny Huang return CMD_RET_SUCCESS; 32792a856b9aSJohnny Huang 32800dae9d52SJohnny Huang ver = chip_version(); 32810dae9d52SJohnny Huang switch (ver) { 3282e417205bSJohnny Huang case OTP_A0: 3283e417205bSJohnny Huang info_cb.version = OTP_A0; 32849a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 32859a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 32869a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 32879a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 32889a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 32899a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 3290e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 32910dae9d52SJohnny Huang break; 3292e417205bSJohnny Huang case OTP_A1: 3293e417205bSJohnny Huang info_cb.version = OTP_A1; 32943cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 32953cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 32963cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 32973cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 32989a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 32999a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 33000dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33010dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3302e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 33030dae9d52SJohnny Huang break; 3304e417205bSJohnny Huang case OTP_A2: 3305e417205bSJohnny Huang info_cb.version = OTP_A2; 33065fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 33075fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 3308fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 3309fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 33105fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 33115fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 33120dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33130dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3314e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 33150dae9d52SJohnny Huang break; 3316e417205bSJohnny Huang case OTP_A3: 3317e417205bSJohnny Huang info_cb.version = OTP_A3; 3318b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 3319b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 3320fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 3321fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 3322181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 3323181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 33240dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33250dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3326e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 332764b66712SJohnny Huang break; 33280dae9d52SJohnny Huang default: 3329f1be5099SJohnny Huang printf("SOC is not supported\n"); 33300dae9d52SJohnny Huang return CMD_RET_FAILURE; 33319a4fe690SJohnny Huang } 33329a4fe690SJohnny Huang 3333030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 3334030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 3335030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 3336030cb4a7SJohnny Huang 3337030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 3338030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 3339030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 3340030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 3341030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 3342030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 3343030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 3344030cb4a7SJohnny Huang 3345e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 3346b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 3347e14b073cSJohnny Huang 3348e14b073cSJohnny Huang return ret; 334969d5fd8fSJohnny Huang } 335069d5fd8fSJohnny Huang 3351a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 335269d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 3353f67375f7SJohnny Huang "version\n" 3354f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 33552a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 33562d4b0742SJohnny Huang "otp info strap [v]\n" 33572d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 33580dc9a440SJohnny Huang "otp info scu\n" 335988bd7d58SJohnny Huang "otp info key\n" 3360de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 3361ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 3362ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 3363ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 33640dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 3365794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 3366794e27ecSJohnny Huang "otp rid\n" 3367883625c5SJohnny Huang "otp retire [o] <key_id>\n" 3368*e7e21c44SJohnny Huang "otp verify <addr>\n" 336969d5fd8fSJohnny Huang ); 3370