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> 19e7e21c44SJohnny Huang #include <u-boot/sha256.h> 20a3dcef30SJohnny Huang #include <u-boot/sha512.h> 21e7e21c44SJohnny Huang #include <u-boot/rsa.h> 22e7e21c44SJohnny Huang #include <u-boot/rsa-mod-exp.h> 23e7e21c44SJohnny 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 48e7e21c44SJohnny Huang #define OTP_LIT_END 0 49e7e21c44SJohnny Huang #define OTP_BIG_END 1 50e7e21c44SJohnny 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" 66e7e21c44SJohnny 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; 138e7e21c44SJohnny 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 183e7e21c44SJohnny Huang struct sb_info { 184e7e21c44SJohnny Huang int header_offset; 185e7e21c44SJohnny Huang int secure_region; 186e7e21c44SJohnny Huang int rsa_algo; 187e7e21c44SJohnny Huang int sha_algo; 188e7e21c44SJohnny Huang int digest_len; 189e7e21c44SJohnny Huang int retire_list[8]; 190e7e21c44SJohnny Huang int enc_flag; 191e7e21c44SJohnny Huang }; 192e7e21c44SJohnny Huang 193e7e21c44SJohnny Huang struct key_list { 194e7e21c44SJohnny Huang const struct otpkey_type *key_info; 195e7e21c44SJohnny Huang int offset; 196e7e21c44SJohnny Huang int id; 197e7e21c44SJohnny Huang int retire; 198e7e21c44SJohnny Huang }; 199e7e21c44SJohnny Huang 200e7e21c44SJohnny Huang struct sb_header { 201e7e21c44SJohnny Huang u32 aes_data_offset; 202e7e21c44SJohnny Huang u32 enc_offset; 203e7e21c44SJohnny Huang u32 sign_image_size; 204e7e21c44SJohnny Huang u32 signature_offset; 205e7e21c44SJohnny Huang u32 revision_low; 206e7e21c44SJohnny Huang u32 revision_high; 207e7e21c44SJohnny Huang u32 reserved; 208e7e21c44SJohnny Huang u32 bl1_header_checksum; 209e7e21c44SJohnny Huang }; 210e7e21c44SJohnny Huang 2119a4fe690SJohnny Huang static struct otp_info_cb info_cb; 2129a4fe690SJohnny Huang 21379e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 214e7e21c44SJohnny Huang {0, OTP_KEY_TYPE_AES, OTP_LIT_END, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 215e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"}, 216e7e21c44SJohnny Huang {4, OTP_KEY_TYPE_HMAC, OTP_LIT_END, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 217e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 218e7e21c44SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as SOC public key"}, 219e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"}, 220e7e21c44SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as SOC private key"}, 221e7e21c44SJohnny 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[] = { 225e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"}, 226e7e21c44SJohnny 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"}, 227e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 228e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"}, 229e7e21c44SJohnny 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[] = { 233e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"}, 234e7e21c44SJohnny 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"}, 235e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 236e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"}, 237e7e21c44SJohnny 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[] = { 241e7e21c44SJohnny Huang {1, OTP_KEY_TYPE_VAULT, OTP_LIT_END, 0, "AES-256 as secret vault key"}, 242e7e21c44SJohnny 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"}, 243e7e21c44SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 244e7e21c44SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, OTP_BIG_END, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 245e7e21c44SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, OTP_LIT_END, 0, "RSA-public as AES key decryption key"}, 246e7e21c44SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, OTP_BIG_END, 0, "RSA-public as AES key decryption key(big endian)"}, 247e7e21c44SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"}, 248e7e21c44SJohnny 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 308e7e21c44SJohnny Huang static void sb_sha256(u8 *src, u32 len, u8 *digest_ret) 309e7e21c44SJohnny Huang { 310e7e21c44SJohnny Huang sha256_context ctx; 311e7e21c44SJohnny Huang 312e7e21c44SJohnny Huang sha256_starts(&ctx); 313e7e21c44SJohnny Huang sha256_update(&ctx, src, len); 314e7e21c44SJohnny Huang sha256_finish(&ctx, digest_ret); 315e7e21c44SJohnny Huang } 316e7e21c44SJohnny Huang 317e7e21c44SJohnny Huang static void sb_sha384(u8 *src, u32 len, u8 *digest_ret) 318e7e21c44SJohnny Huang { 319e7e21c44SJohnny Huang sha512_context ctx; 320e7e21c44SJohnny Huang 321e7e21c44SJohnny Huang sha384_starts(&ctx); 322e7e21c44SJohnny Huang sha384_update(&ctx, src, len); 323e7e21c44SJohnny Huang sha384_finish(&ctx, digest_ret); 324e7e21c44SJohnny Huang } 325e7e21c44SJohnny Huang 326e7e21c44SJohnny Huang static void sb_sha512(u8 *src, u32 len, u8 *digest_ret) 327e7e21c44SJohnny Huang { 328e7e21c44SJohnny Huang sha512_context ctx; 329e7e21c44SJohnny Huang 330e7e21c44SJohnny Huang sha512_starts(&ctx); 331e7e21c44SJohnny Huang sha512_update(&ctx, src, len); 332e7e21c44SJohnny Huang sha512_finish(&ctx, digest_ret); 333e7e21c44SJohnny Huang } 334e7e21c44SJohnny 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 1394418822f0SJohnny Huang static void _otp_print_key(u32 header, u32 offset, u8 *data) 139569d5fd8fSJohnny Huang { 139688bd7d58SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 1397418822f0SJohnny Huang struct otpkey_type key_info; 1398418822f0SJohnny Huang int key_id, key_offset, key_type, key_length, exp_length; 139988bd7d58SJohnny Huang int len = 0; 1400418822f0SJohnny Huang int i; 140154552c69SJohnny Huang 1402418822f0SJohnny Huang key_id = header & 0x7; 1403418822f0SJohnny Huang key_offset = header & 0x1ff8; 1404418822f0SJohnny Huang key_type = (header >> 14) & 0xf; 1405418822f0SJohnny Huang key_length = (header >> 18) & 0x3; 1406418822f0SJohnny Huang exp_length = (header >> 20) & 0xfff; 14079d998018SJohnny Huang 1408418822f0SJohnny Huang printf("\nKey[%d]:\n", offset); 1409418822f0SJohnny Huang printf("Header: %x\n", header); 14109a4fe690SJohnny Huang 141188bd7d58SJohnny Huang key_info.value = -1; 1412418822f0SJohnny Huang for (i = 0; i < info_cb.key_info_len; i++) { 1413418822f0SJohnny Huang if (key_type == key_info_array[i].value) { 1414418822f0SJohnny Huang key_info = key_info_array[i]; 14159a4fe690SJohnny Huang break; 14169a4fe690SJohnny Huang } 14179a4fe690SJohnny Huang } 141888bd7d58SJohnny Huang if (key_info.value == -1) 1419418822f0SJohnny Huang return; 14209a4fe690SJohnny Huang 142169d5fd8fSJohnny Huang printf("Key Type: "); 14229a4fe690SJohnny Huang printf("%s\n", key_info.information); 14239a4fe690SJohnny Huang 14249a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 142569d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 142669d5fd8fSJohnny Huang switch (key_length) { 142769d5fd8fSJohnny Huang case 0: 142869d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 142969d5fd8fSJohnny Huang break; 143069d5fd8fSJohnny Huang case 1: 143169d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 143269d5fd8fSJohnny Huang break; 143369d5fd8fSJohnny Huang case 2: 143469d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 143569d5fd8fSJohnny Huang break; 143669d5fd8fSJohnny Huang case 3: 143769d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 143869d5fd8fSJohnny Huang break; 143969d5fd8fSJohnny Huang } 1440181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1441181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 144269d5fd8fSJohnny Huang printf("RSA SHA Type: "); 144369d5fd8fSJohnny Huang switch (key_length) { 144469d5fd8fSJohnny Huang case 0: 144569d5fd8fSJohnny Huang printf("RSA1024\n"); 144669d5fd8fSJohnny Huang len = 0x100; 144769d5fd8fSJohnny Huang break; 144869d5fd8fSJohnny Huang case 1: 144969d5fd8fSJohnny Huang printf("RSA2048\n"); 145069d5fd8fSJohnny Huang len = 0x200; 145169d5fd8fSJohnny Huang break; 145269d5fd8fSJohnny Huang case 2: 145369d5fd8fSJohnny Huang printf("RSA3072\n"); 145469d5fd8fSJohnny Huang len = 0x300; 145569d5fd8fSJohnny Huang break; 145669d5fd8fSJohnny Huang case 3: 145769d5fd8fSJohnny Huang printf("RSA4096\n"); 145869d5fd8fSJohnny Huang len = 0x400; 145969d5fd8fSJohnny Huang break; 146069d5fd8fSJohnny Huang } 146169d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 146269d5fd8fSJohnny Huang } 14639a4fe690SJohnny Huang if (key_info.need_id) 146469d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 1465418822f0SJohnny Huang if (!data) 1466418822f0SJohnny Huang return; 146769d5fd8fSJohnny Huang printf("Key Value:\n"); 14689a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 1469418822f0SJohnny Huang buf_print(&data[key_offset], 0x40); 14709a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 14719a4fe690SJohnny Huang printf("AES Key:\n"); 1472418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 1473e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 14749a4fe690SJohnny Huang printf("AES IV:\n"); 1475418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x10); 14769a4fe690SJohnny Huang } 14779a4fe690SJohnny Huang 14789a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1479e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 148069d5fd8fSJohnny Huang printf("AES Key:\n"); 1481418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 148269d5fd8fSJohnny Huang printf("AES IV:\n"); 1483418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x10); 14845fdde29fSJohnny Huang } else { 14859a4fe690SJohnny Huang printf("AES Key 1:\n"); 1486418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 14879a4fe690SJohnny Huang printf("AES Key 2:\n"); 1488418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x20); 14899a4fe690SJohnny Huang } 1490181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 149169d5fd8fSJohnny Huang printf("RSA mod:\n"); 1492418822f0SJohnny Huang buf_print(&data[key_offset], len / 2); 149369d5fd8fSJohnny Huang printf("RSA exp:\n"); 1494418822f0SJohnny Huang buf_print(&data[key_offset + (len / 2)], len / 2); 1495181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1496181f72d8SJohnny Huang printf("RSA mod:\n"); 1497418822f0SJohnny Huang buf_print(&data[key_offset], len / 2); 1498181f72d8SJohnny Huang printf("RSA exp:\n"); 1499a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 150069d5fd8fSJohnny Huang } 1501418822f0SJohnny Huang } 1502418822f0SJohnny Huang 1503418822f0SJohnny Huang static void otp_print_key(u32 *data) 1504418822f0SJohnny Huang { 1505418822f0SJohnny Huang int i; 1506418822f0SJohnny Huang int last; 1507418822f0SJohnny Huang u8 *byte_buf; 1508418822f0SJohnny Huang int empty; 1509418822f0SJohnny Huang 1510418822f0SJohnny Huang byte_buf = (u8 *)data; 1511418822f0SJohnny Huang 1512418822f0SJohnny Huang empty = 1; 1513418822f0SJohnny Huang for (i = 0; i < 16; i++) { 1514418822f0SJohnny Huang if (i % 2) { 1515418822f0SJohnny Huang if (data[i] != 0xffffffff) 1516418822f0SJohnny Huang empty = 0; 1517418822f0SJohnny Huang } else { 1518418822f0SJohnny Huang if (data[i] != 0) 1519418822f0SJohnny Huang empty = 0; 1520418822f0SJohnny Huang } 1521418822f0SJohnny Huang } 1522418822f0SJohnny Huang if (empty) { 1523418822f0SJohnny Huang printf("OTP data header is empty\n"); 1524418822f0SJohnny Huang return; 1525418822f0SJohnny Huang } 1526418822f0SJohnny Huang 1527418822f0SJohnny Huang for (i = 0; i < 16; i++) { 1528418822f0SJohnny Huang last = (data[i] >> 13) & 1; 1529418822f0SJohnny Huang _otp_print_key(data[i], i, byte_buf); 153069d5fd8fSJohnny Huang if (last) 153169d5fd8fSJohnny Huang break; 153269d5fd8fSJohnny Huang } 153388bd7d58SJohnny Huang } 153488bd7d58SJohnny Huang 153588bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 153688bd7d58SJohnny Huang { 153788bd7d58SJohnny Huang u32 *buf; 153888bd7d58SJohnny Huang 153988bd7d58SJohnny Huang buf = (u32 *)image_layout->data; 1540418822f0SJohnny Huang otp_print_key(buf); 154188bd7d58SJohnny Huang 1542f347c284SJohnny Huang return OTP_SUCCESS; 1543f347c284SJohnny Huang } 1544f347c284SJohnny Huang 154588bd7d58SJohnny Huang static void otp_print_key_info(void) 154688bd7d58SJohnny Huang { 154788bd7d58SJohnny Huang u32 data[2048]; 154888bd7d58SJohnny Huang int i; 154988bd7d58SJohnny Huang 155088bd7d58SJohnny Huang for (i = 0; i < 2048 ; i += 2) 155188bd7d58SJohnny Huang otp_read_data(i, &data[i]); 155288bd7d58SJohnny Huang 1553418822f0SJohnny Huang otp_print_key(data); 155488bd7d58SJohnny Huang } 155588bd7d58SJohnny Huang 1556b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data) 1557f347c284SJohnny Huang { 1558f347c284SJohnny Huang int i; 1559f347c284SJohnny Huang int ret; 1560f347c284SJohnny Huang u32 *buf; 1561f347c284SJohnny Huang u32 *buf_ignore; 1562f347c284SJohnny Huang 1563f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1564f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1565f347c284SJohnny Huang printf("Start Programing...\n"); 1566f347c284SJohnny Huang 1567f347c284SJohnny Huang // programing ecc region first 1568f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1569f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1570f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1571f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1572f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1573f347c284SJohnny Huang return ret; 1574f347c284SJohnny Huang } 1575f347c284SJohnny Huang } 1576f347c284SJohnny Huang 1577f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1578f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1579f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1580f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1581f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1582f347c284SJohnny Huang return ret; 1583f347c284SJohnny Huang } 1584f347c284SJohnny Huang } 1585f347c284SJohnny Huang otp_soak(0); 1586f347c284SJohnny Huang return OTP_SUCCESS; 1587f347c284SJohnny Huang } 1588f347c284SJohnny Huang 1589b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1590f347c284SJohnny Huang { 1591f347c284SJohnny Huang u32 *strap; 1592f347c284SJohnny Huang u32 *strap_ignore; 1593f347c284SJohnny Huang u32 *strap_pro; 1594f347c284SJohnny Huang u32 prog_address; 1595f347c284SJohnny Huang int i; 15967e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1597f347c284SJohnny Huang int fail = 0; 1598f347c284SJohnny Huang int ret; 1599f347c284SJohnny Huang int prog_flag = 0; 1600f347c284SJohnny Huang 1601f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1602f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1603f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1604f347c284SJohnny Huang 1605f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1606f347c284SJohnny Huang prog_address = 0x800; 1607f347c284SJohnny Huang if (i < 32) { 1608f347c284SJohnny Huang offset = i; 1609f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1610f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1611f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1612f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1613f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1614f347c284SJohnny Huang 1615f347c284SJohnny Huang } else { 1616f347c284SJohnny Huang offset = (i - 32); 1617f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1618f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1619f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1620f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1621f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1622f347c284SJohnny Huang } 1623f347c284SJohnny Huang 1624f347c284SJohnny Huang if (ibit == 1) 1625f347c284SJohnny Huang continue; 1626f347c284SJohnny Huang if (bit == otpstrap[i].value) 1627f347c284SJohnny Huang prog_flag = 0; 1628f347c284SJohnny Huang else 1629f347c284SJohnny Huang prog_flag = 1; 1630f347c284SJohnny Huang 1631f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1632f347c284SJohnny Huang fail = 1; 1633f347c284SJohnny Huang continue; 1634f347c284SJohnny Huang } 1635f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1636f347c284SJohnny Huang fail = 1; 1637f347c284SJohnny Huang continue; 1638f347c284SJohnny Huang } 1639f347c284SJohnny Huang 1640f347c284SJohnny Huang if (prog_flag) { 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 if (pbit != 0) { 1647f347c284SJohnny Huang prog_address = 0x800; 1648f347c284SJohnny Huang if (i < 32) 1649f347c284SJohnny Huang prog_address |= 0x60c; 1650f347c284SJohnny Huang else 1651f347c284SJohnny Huang prog_address |= 0x60e; 1652f347c284SJohnny Huang 1653f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1654f347c284SJohnny Huang if (ret) 1655f347c284SJohnny Huang return OTP_FAILURE; 1656f347c284SJohnny Huang } 1657f347c284SJohnny Huang } 1658f347c284SJohnny Huang otp_soak(0); 1659f347c284SJohnny Huang if (fail == 1) 1660f347c284SJohnny Huang return OTP_FAILURE; 1661f347c284SJohnny Huang return OTP_SUCCESS; 166269d5fd8fSJohnny Huang } 166369d5fd8fSJohnny Huang 1664b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf) 166569d5fd8fSJohnny Huang { 1666a6d0d645SJohnny Huang int i, k; 1667d90825e2SJohnny Huang int pass = 0; 1668a219f6deSJohnny Huang u32 prog_address; 1669a219f6deSJohnny Huang u32 compare[2]; 1670a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1671a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1672a219f6deSJohnny Huang u32 data_masked; 1673a219f6deSJohnny Huang u32 buf_masked; 16742031a123SJohnny Huang int ret; 167569d5fd8fSJohnny Huang 1676a6d0d645SJohnny Huang printf("Start Programing...\n"); 1677d90825e2SJohnny Huang otp_soak(0); 1678bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 1679b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 16805010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1681a6d0d645SJohnny Huang prog_address = 0x800; 1682a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1683a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1684bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1685bb34a7bfSJohnny Huang pass = 1; 1686a6d0d645SJohnny Huang continue; 1687bb34a7bfSJohnny Huang } 1688de6fbf1cSJohnny Huang 1689de6fbf1cSJohnny Huang otp_soak(1); 16902031a123SJohnny Huang ret = otp_prog_dw(conf[i], conf_ignore[i], prog_address); 16912031a123SJohnny Huang if (ret) 16922031a123SJohnny Huang return OTP_FAILURE; 1693a6d0d645SJohnny Huang 169469d5fd8fSJohnny Huang pass = 0; 169569d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 16965010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1697de6fbf1cSJohnny Huang otp_soak(2); 16982031a123SJohnny Huang ret = otp_prog_dw(compare[0], conf_ignore[i], prog_address); 16992031a123SJohnny Huang if (ret) 17002031a123SJohnny Huang return OTP_FAILURE; 17015010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1702de6fbf1cSJohnny Huang otp_soak(1); 1703de6fbf1cSJohnny Huang } else { 1704de6fbf1cSJohnny Huang pass = 1; 1705de6fbf1cSJohnny Huang break; 1706de6fbf1cSJohnny Huang } 1707a6d0d645SJohnny Huang } else { 170869d5fd8fSJohnny Huang pass = 1; 170969d5fd8fSJohnny Huang break; 171069d5fd8fSJohnny Huang } 171169d5fd8fSJohnny Huang } 1712bb34a7bfSJohnny Huang if (pass == 0) { 1713b64ca396SJohnny Huang printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n", 1714b64ca396SJohnny Huang i, otp_conf[i], conf[i], conf_ignore[i]); 1715bb34a7bfSJohnny Huang break; 1716bb34a7bfSJohnny Huang } 1717a6d0d645SJohnny Huang } 1718a6d0d645SJohnny Huang 1719de6fbf1cSJohnny Huang otp_soak(0); 172069d5fd8fSJohnny Huang if (!pass) 17212a856b9aSJohnny Huang return OTP_FAILURE; 1722a6d0d645SJohnny Huang 17232a856b9aSJohnny Huang return OTP_SUCCESS; 172469d5fd8fSJohnny Huang } 172569d5fd8fSJohnny Huang 1726b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro) 1727b25f02d2SJohnny Huang { 1728b25f02d2SJohnny Huang int i, k; 1729b25f02d2SJohnny Huang int pass = 0; 1730b25f02d2SJohnny Huang u32 prog_address; 1731b25f02d2SJohnny Huang u32 compare[2]; 1732b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1733b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1734b25f02d2SJohnny Huang u32 data_masked; 1735b25f02d2SJohnny Huang u32 buf_masked; 17362031a123SJohnny Huang int ret; 1737b25f02d2SJohnny Huang 1738b25f02d2SJohnny Huang printf("Start Programing...\n"); 1739b25f02d2SJohnny Huang otp_soak(0); 1740b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1741b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1742b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1743b25f02d2SJohnny Huang prog_address = 0xe08 + i * 2; 1744b25f02d2SJohnny Huang if (data_masked == buf_masked) { 1745b25f02d2SJohnny Huang pass = 1; 1746b25f02d2SJohnny Huang continue; 1747b25f02d2SJohnny Huang } 1748b25f02d2SJohnny Huang 1749b25f02d2SJohnny Huang otp_soak(1); 17502031a123SJohnny Huang ret = otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address); 17512031a123SJohnny Huang if (ret) 17522031a123SJohnny Huang return OTP_FAILURE; 1753b25f02d2SJohnny Huang pass = 0; 1754b25f02d2SJohnny Huang for (k = 0; k < RETRY; k++) { 1755b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1756b25f02d2SJohnny Huang otp_soak(2); 17572031a123SJohnny Huang ret = otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address); 17582031a123SJohnny Huang if (ret) 17592031a123SJohnny Huang return OTP_FAILURE; 1760b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1761b25f02d2SJohnny Huang otp_soak(1); 1762b25f02d2SJohnny Huang } else { 1763b25f02d2SJohnny Huang pass = 1; 1764b25f02d2SJohnny Huang break; 1765b25f02d2SJohnny Huang } 1766b25f02d2SJohnny Huang } else { 1767b25f02d2SJohnny Huang pass = 1; 1768b25f02d2SJohnny Huang break; 1769b25f02d2SJohnny Huang } 1770b25f02d2SJohnny Huang } 1771b25f02d2SJohnny Huang if (pass == 0) { 1772b489486eSJohnny Huang printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n", 1773b25f02d2SJohnny Huang i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]); 1774b25f02d2SJohnny Huang break; 1775b25f02d2SJohnny Huang } 1776b25f02d2SJohnny Huang } 1777b25f02d2SJohnny Huang 1778b25f02d2SJohnny Huang otp_soak(0); 1779b25f02d2SJohnny Huang if (!pass) 1780b25f02d2SJohnny Huang return OTP_FAILURE; 1781b25f02d2SJohnny Huang 1782b25f02d2SJohnny Huang return OTP_SUCCESS; 1783b25f02d2SJohnny Huang } 1784b25f02d2SJohnny Huang 1785b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data) 1786b64ca396SJohnny Huang { 1787b64ca396SJohnny Huang int data_dw; 1788b64ca396SJohnny Huang u32 data_masked; 1789b64ca396SJohnny Huang u32 buf_masked; 1790b64ca396SJohnny Huang u32 *buf = (u32 *)image_layout->data; 1791b64ca396SJohnny Huang u32 *buf_ignore = (u32 *)image_layout->data_ignore; 1792b64ca396SJohnny Huang int i; 1793b64ca396SJohnny Huang 1794b64ca396SJohnny Huang data_dw = image_layout->data_length / 4; 1795b64ca396SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1796b64ca396SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1797b64ca396SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1798b64ca396SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1799b64ca396SJohnny Huang if (data_masked == buf_masked) 1800b64ca396SJohnny Huang continue; 1801b64ca396SJohnny Huang if (i % 2 == 0) { 1802b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1803b64ca396SJohnny Huang continue; 1804b64ca396SJohnny Huang } else { 1805b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1806b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1807b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1808b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1809b64ca396SJohnny Huang return OTP_FAILURE; 1810b64ca396SJohnny Huang } 1811b64ca396SJohnny Huang } else { 1812b64ca396SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1813b64ca396SJohnny Huang continue; 1814b64ca396SJohnny Huang } else { 1815b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1816b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1817b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1818b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1819b64ca396SJohnny Huang return OTP_FAILURE; 1820b64ca396SJohnny Huang } 1821b64ca396SJohnny Huang } 1822b64ca396SJohnny Huang } 1823b64ca396SJohnny Huang return OTP_SUCCESS; 1824b64ca396SJohnny Huang } 1825b64ca396SJohnny Huang 1826b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1827b64ca396SJohnny Huang { 1828b64ca396SJohnny Huang int i; 1829b64ca396SJohnny Huang u32 *strap; 1830b64ca396SJohnny Huang u32 *strap_ignore; 1831b64ca396SJohnny Huang u32 *strap_pro; 1832b64ca396SJohnny Huang int bit, pbit, ibit; 1833b64ca396SJohnny Huang int fail = 0; 1834b64ca396SJohnny Huang int ret; 1835b64ca396SJohnny Huang 1836b64ca396SJohnny Huang strap = (u32 *)image_layout->strap; 1837b64ca396SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1838b64ca396SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1839b64ca396SJohnny Huang 1840b64ca396SJohnny Huang for (i = 0; i < 64; i++) { 1841b64ca396SJohnny Huang if (i < 32) { 1842b64ca396SJohnny Huang bit = (strap[0] >> i) & 0x1; 1843b64ca396SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1844b64ca396SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1845b64ca396SJohnny Huang } else { 1846b64ca396SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1847b64ca396SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1848b64ca396SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1849b64ca396SJohnny Huang } 1850b64ca396SJohnny Huang 1851b64ca396SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1852b64ca396SJohnny Huang 1853b64ca396SJohnny Huang if (ret == OTP_FAILURE) 1854b64ca396SJohnny Huang fail = 1; 1855b64ca396SJohnny Huang } 1856b64ca396SJohnny Huang if (fail == 1) { 1857b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1858b64ca396SJohnny Huang return OTP_FAILURE; 1859b64ca396SJohnny Huang } 1860b64ca396SJohnny Huang return OTP_SUCCESS; 1861b64ca396SJohnny Huang } 1862b64ca396SJohnny Huang 1863b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf) 1864b64ca396SJohnny Huang { 1865b64ca396SJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1866b64ca396SJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1867b64ca396SJohnny Huang u32 data_masked; 1868b64ca396SJohnny Huang u32 buf_masked; 1869b64ca396SJohnny Huang int i; 1870b64ca396SJohnny Huang 1871b64ca396SJohnny Huang for (i = 0; i < 16; i++) { 1872b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 1873b64ca396SJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1874b64ca396SJohnny Huang if (data_masked == buf_masked) 1875b64ca396SJohnny Huang continue; 1876b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1877b64ca396SJohnny Huang continue; 1878b64ca396SJohnny Huang } else { 1879b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1880b64ca396SJohnny Huang printf("OTPCFG[%X] = %x\n", i, otp_conf[i]); 1881b64ca396SJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 1882b64ca396SJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 1883b64ca396SJohnny Huang return OTP_FAILURE; 1884b64ca396SJohnny Huang } 1885b64ca396SJohnny Huang } 1886b64ca396SJohnny Huang return OTP_SUCCESS; 1887b64ca396SJohnny Huang } 1888b64ca396SJohnny Huang 1889b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro) 1890b25f02d2SJohnny Huang { 1891b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1892b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1893b25f02d2SJohnny Huang u32 data_masked; 1894b25f02d2SJohnny Huang u32 buf_masked; 1895b25f02d2SJohnny Huang int i; 1896b25f02d2SJohnny Huang 1897b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1898b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1899b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1900b25f02d2SJohnny Huang if (data_masked == buf_masked) 1901b25f02d2SJohnny Huang continue; 1902b25f02d2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1903b25f02d2SJohnny Huang continue; 1904b25f02d2SJohnny Huang } else { 1905b25f02d2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1906b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]); 1907b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]); 1908b489486eSJohnny Huang printf("Mask [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]); 1909b25f02d2SJohnny Huang return OTP_FAILURE; 1910b25f02d2SJohnny Huang } 1911b25f02d2SJohnny Huang } 1912b25f02d2SJohnny Huang return OTP_SUCCESS; 1913b25f02d2SJohnny Huang } 1914b25f02d2SJohnny Huang 1915e7e21c44SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf, int version) 1916696656c6SJohnny Huang { 1917e7e21c44SJohnny Huang u8 digest_ret[48]; 1918e7e21c44SJohnny Huang int digest_len; 1919696656c6SJohnny Huang 1920e7e21c44SJohnny Huang switch (version) { 1921e7e21c44SJohnny Huang case 1: 1922e7e21c44SJohnny Huang sb_sha256(src_buf, length, digest_ret); 1923e7e21c44SJohnny Huang digest_len = 32; 1924e7e21c44SJohnny Huang break; 1925e7e21c44SJohnny Huang case 2: 1926e7e21c44SJohnny Huang sb_sha384(src_buf, length, digest_ret); 1927e7e21c44SJohnny Huang digest_len = 48; 1928e7e21c44SJohnny Huang break; 1929e7e21c44SJohnny Huang default: 1930e7e21c44SJohnny Huang return OTP_FAILURE; 1931e7e21c44SJohnny Huang } 1932696656c6SJohnny Huang 1933e7e21c44SJohnny Huang if (!memcmp(digest_buf, digest_ret, digest_len)) 1934f347c284SJohnny Huang return OTP_SUCCESS; 1935f347c284SJohnny Huang return OTP_FAILURE; 1936696656c6SJohnny Huang } 1937696656c6SJohnny Huang 1938f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 193969d5fd8fSJohnny Huang { 194069d5fd8fSJohnny Huang int ret; 194161a6cda7SJohnny Huang int image_soc_ver = 0; 1942696656c6SJohnny Huang struct otp_header *otp_header; 1943696656c6SJohnny Huang struct otp_image_layout image_layout; 1944696656c6SJohnny Huang int image_size; 1945a219f6deSJohnny Huang u8 *buf; 1946a219f6deSJohnny Huang u8 *checksum; 1947b64ca396SJohnny Huang int i; 1948b64ca396SJohnny Huang u32 data[2048]; 1949b64ca396SJohnny Huang u32 conf[16]; 1950b25f02d2SJohnny Huang u32 scu_pro[2]; 1951b64ca396SJohnny Huang struct otpstrap_status otpstrap[64]; 195269d5fd8fSJohnny Huang 1953696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1954696656c6SJohnny Huang if (!otp_header) { 1955030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 19562a856b9aSJohnny Huang return OTP_FAILURE; 195769d5fd8fSJohnny Huang } 1958d90825e2SJohnny Huang 1959696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1960696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1961696656c6SJohnny Huang 1962696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1963696656c6SJohnny Huang 1964696656c6SJohnny Huang if (!buf) { 1965030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 1966696656c6SJohnny Huang return OTP_FAILURE; 1967696656c6SJohnny Huang } 1968696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1969696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1970696656c6SJohnny Huang 1971696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1972030cb4a7SJohnny Huang printf("Image is invalid\n"); 1973696656c6SJohnny Huang return OTP_FAILURE; 1974696656c6SJohnny Huang } 1975696656c6SJohnny Huang 19765010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 19775010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 19785010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 19795010032bSJohnny Huang 19805010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1981696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 19825010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1983696656c6SJohnny Huang 1984696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 19855010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 19865010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 19875010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 19887e523e3bSJohnny Huang 1989b25f02d2SJohnny Huang image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info); 1990b25f02d2SJohnny Huang image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2); 1991b25f02d2SJohnny Huang image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length; 1992b25f02d2SJohnny Huang 19937e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 19947e523e3bSJohnny Huang image_soc_ver = OTP_A0; 199561a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 199661a6cda7SJohnny Huang image_soc_ver = OTP_A1; 199761a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 199861a6cda7SJohnny Huang image_soc_ver = OTP_A2; 199961a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 200061a6cda7SJohnny Huang image_soc_ver = OTP_A3; 2001696656c6SJohnny Huang } else { 2002030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n"); 2003696656c6SJohnny Huang return OTP_FAILURE; 2004696656c6SJohnny Huang } 2005696656c6SJohnny Huang 200661a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 20075e096f11SJohnny Huang printf("Image SOC version is not match to HW SOC version\n"); 20089a4fe690SJohnny Huang return OTP_FAILURE; 20099a4fe690SJohnny Huang } 20109a4fe690SJohnny Huang 2011e7e21c44SJohnny Huang switch (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver)) { 2012e7e21c44SJohnny Huang case 1: 2013e7e21c44SJohnny Huang printf("WARNING: OTP image is not generated by otptool v2.x.x\n"); 2014e7e21c44SJohnny Huang printf("Please use the latest version of otptool to generate OTP image\n"); 2015e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 1); 2016e7e21c44SJohnny Huang break; 2017e7e21c44SJohnny Huang case 2: 2018e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 2); 2019e7e21c44SJohnny Huang break; 2020e7e21c44SJohnny Huang default: 2021e7e21c44SJohnny Huang printf("OTP image version is not supported\n"); 202261a6cda7SJohnny Huang return OTP_FAILURE; 202361a6cda7SJohnny Huang } 202461a6cda7SJohnny Huang 2025e7e21c44SJohnny Huang if (ret) { 2026030cb4a7SJohnny Huang printf("checksum is invalid\n"); 2027696656c6SJohnny Huang return OTP_FAILURE; 2028d90825e2SJohnny Huang } 20297332532cSJohnny Huang 2030030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2031030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2032030cb4a7SJohnny Huang return OTP_FAILURE; 2033030cb4a7SJohnny Huang } 2034b64ca396SJohnny Huang ret = 0; 2035030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 2036030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2037030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2038030cb4a7SJohnny Huang ret = -1; 2039030cb4a7SJohnny Huang } 2040030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2041030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2042030cb4a7SJohnny Huang ret = -1; 2043030cb4a7SJohnny Huang } 2044b64ca396SJohnny Huang printf("Read OTP Data Region:\n"); 2045b64ca396SJohnny Huang for (i = 0; i < 2048 ; i += 2) 2046b64ca396SJohnny Huang otp_read_data(i, &data[i]); 2047b64ca396SJohnny Huang 2048b64ca396SJohnny Huang printf("Check writable...\n"); 2049b64ca396SJohnny Huang if (otp_check_data_image(&image_layout, data) == OTP_FAILURE) 2050b64ca396SJohnny Huang ret = -1; 2051030cb4a7SJohnny Huang } 2052030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 2053030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2054030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2055030cb4a7SJohnny Huang ret = -1; 2056030cb4a7SJohnny Huang } 2057b64ca396SJohnny Huang printf("Read OTP Config Region:\n"); 2058b64ca396SJohnny Huang for (i = 0; i < 16 ; i++) 2059b64ca396SJohnny Huang otp_read_conf(i, &conf[i]); 2060b64ca396SJohnny Huang 2061b64ca396SJohnny Huang printf("Check writable...\n"); 2062b64ca396SJohnny Huang if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE) 2063b64ca396SJohnny Huang ret = -1; 2064030cb4a7SJohnny Huang } 2065030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 2066030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2067030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2068030cb4a7SJohnny Huang ret = -1; 2069030cb4a7SJohnny Huang } 2070b64ca396SJohnny Huang printf("Read OTP Strap Region:\n"); 2071b64ca396SJohnny Huang otp_strap_status(otpstrap); 2072b64ca396SJohnny Huang 2073b64ca396SJohnny Huang printf("Check writable...\n"); 2074b64ca396SJohnny Huang if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE) 2075b64ca396SJohnny Huang ret = -1; 2076030cb4a7SJohnny Huang } 2077b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2078b25f02d2SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2079b25f02d2SJohnny Huang printf("OTP strap region is protected\n"); 2080b25f02d2SJohnny Huang ret = -1; 2081b25f02d2SJohnny Huang } 2082b25f02d2SJohnny Huang printf("Read SCU Protect Region:\n"); 2083b25f02d2SJohnny Huang otp_read_conf(28, &scu_pro[0]); 2084b25f02d2SJohnny Huang otp_read_conf(29, &scu_pro[1]); 2085b25f02d2SJohnny Huang 2086b25f02d2SJohnny Huang printf("Check writable...\n"); 2087b25f02d2SJohnny Huang if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE) 2088b25f02d2SJohnny Huang ret = -1; 2089b25f02d2SJohnny Huang } 2090030cb4a7SJohnny Huang if (ret == -1) 2091030cb4a7SJohnny Huang return OTP_FAILURE; 2092b64ca396SJohnny Huang 209369d5fd8fSJohnny Huang if (!nconfirm) { 2094696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 20957f795e57SJohnny Huang printf("\nOTP data region :\n"); 2096f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 209769d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 20982a856b9aSJohnny Huang return OTP_FAILURE; 209969d5fd8fSJohnny Huang } 210069d5fd8fSJohnny Huang } 2101696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 21027332532cSJohnny Huang printf("\nOTP configuration region :\n"); 2103696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 21047332532cSJohnny Huang printf("OTP config error, please check.\n"); 21057332532cSJohnny Huang return OTP_FAILURE; 21067332532cSJohnny Huang } 21077332532cSJohnny Huang } 21087adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 21097adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 21107adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 21117adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 21127adec5f6SJohnny Huang return OTP_FAILURE; 21137adec5f6SJohnny Huang } 21147adec5f6SJohnny Huang } 2115b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2116b25f02d2SJohnny Huang printf("\nOTP scu protect region :\n"); 2117b25f02d2SJohnny Huang if (otp_print_scu_image(&image_layout) < 0) { 2118b25f02d2SJohnny Huang printf("OTP scu protect error, please check.\n"); 2119b25f02d2SJohnny Huang return OTP_FAILURE; 2120b25f02d2SJohnny Huang } 2121b25f02d2SJohnny Huang } 21227332532cSJohnny Huang 212369d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 212469d5fd8fSJohnny Huang if (!confirm_yesno()) { 212569d5fd8fSJohnny Huang printf(" Aborting\n"); 21262a856b9aSJohnny Huang return OTP_FAILURE; 212769d5fd8fSJohnny Huang } 212869d5fd8fSJohnny Huang } 21297332532cSJohnny Huang 21305010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 21315010032bSJohnny Huang printf("programing data region ...\n"); 2132b64ca396SJohnny Huang ret = otp_prog_data(&image_layout, data); 21335010032bSJohnny Huang if (ret != 0) { 21345010032bSJohnny Huang printf("Error\n"); 21355010032bSJohnny Huang return ret; 21365010032bSJohnny Huang } 2137a219f6deSJohnny Huang printf("Done\n"); 21385010032bSJohnny Huang } 21395010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 21405010032bSJohnny Huang printf("programing strap region ...\n"); 2141b64ca396SJohnny Huang ret = otp_prog_strap(&image_layout, otpstrap); 21425010032bSJohnny Huang if (ret != 0) { 21435010032bSJohnny Huang printf("Error\n"); 21445010032bSJohnny Huang return ret; 21455010032bSJohnny Huang } 2146a219f6deSJohnny Huang printf("Done\n"); 21475010032bSJohnny Huang } 2148b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2149b25f02d2SJohnny Huang printf("programing scu protect region ...\n"); 2150b25f02d2SJohnny Huang ret = otp_prog_scu_protect(&image_layout, scu_pro); 2151b25f02d2SJohnny Huang if (ret != 0) { 2152b25f02d2SJohnny Huang printf("Error\n"); 2153b25f02d2SJohnny Huang return ret; 2154b25f02d2SJohnny Huang } 2155b25f02d2SJohnny Huang printf("Done\n"); 2156b25f02d2SJohnny Huang } 21575010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 21585010032bSJohnny Huang printf("programing configuration region ...\n"); 2159b64ca396SJohnny Huang ret = otp_prog_conf(&image_layout, conf); 21605010032bSJohnny Huang if (ret != 0) { 21615010032bSJohnny Huang printf("Error\n"); 21625010032bSJohnny Huang return ret; 21635010032bSJohnny Huang } 21645010032bSJohnny Huang printf("Done\n"); 21655010032bSJohnny Huang } 2166cd1610b4SJohnny Huang 21677332532cSJohnny Huang return OTP_SUCCESS; 21682a856b9aSJohnny Huang } 21692a856b9aSJohnny Huang 2170f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 2171cd1610b4SJohnny Huang { 2172a219f6deSJohnny Huang u32 read[2]; 2173a219f6deSJohnny Huang u32 prog_address = 0; 217466f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 2175cd1610b4SJohnny Huang int otp_bit; 217683655e91SJohnny Huang int ret = 0; 2177cd1610b4SJohnny Huang 2178dacbba92SJohnny Huang otp_soak(0); 2179cd1610b4SJohnny Huang switch (mode) { 2180a6d0d645SJohnny Huang case OTP_REGION_CONF: 2181f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 2182cd1610b4SJohnny Huang prog_address = 0x800; 2183cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 2184cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 2185a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2186cd1610b4SJohnny Huang if (otp_bit == value) { 2187b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2188cd1610b4SJohnny Huang printf("No need to program\n"); 21892a856b9aSJohnny Huang return OTP_SUCCESS; 2190cd1610b4SJohnny Huang } 2191cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 2192b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 21930dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 21942a856b9aSJohnny Huang return OTP_FAILURE; 2195cd1610b4SJohnny Huang } 2196b489486eSJohnny Huang printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2197cd1610b4SJohnny Huang break; 2198a6d0d645SJohnny Huang case OTP_REGION_DATA: 2199cd1610b4SJohnny Huang prog_address = otp_dw_offset; 2200cd1610b4SJohnny Huang 2201cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 2202a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 2203a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2204643b9cfdSJohnny Huang 2205643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 2206b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2207b64ca396SJohnny Huang printf("OTP is programmed, which can't be cleared\n"); 2208643b9cfdSJohnny Huang return OTP_FAILURE; 2209643b9cfdSJohnny Huang } 2210cd1610b4SJohnny Huang } else { 2211a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 2212a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 2213643b9cfdSJohnny Huang 2214643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 2215b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2216b64ca396SJohnny Huang printf("OTP is programmed, which can't be written\n"); 2217643b9cfdSJohnny Huang return OTP_FAILURE; 2218643b9cfdSJohnny Huang } 2219cd1610b4SJohnny Huang } 2220cd1610b4SJohnny Huang if (otp_bit == value) { 2221b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2222cd1610b4SJohnny Huang printf("No need to program\n"); 22232a856b9aSJohnny Huang return OTP_SUCCESS; 2224cd1610b4SJohnny Huang } 2225643b9cfdSJohnny Huang 2226b489486eSJohnny Huang printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2227cd1610b4SJohnny Huang break; 2228a6d0d645SJohnny Huang case OTP_REGION_STRAP: 22298848d5dcSJohnny Huang otp_strap_status(otpstrap); 22308848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 22317e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 22328848d5dcSJohnny Huang if (ret == OTP_FAILURE) 22338848d5dcSJohnny Huang return OTP_FAILURE; 22348848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 22358848d5dcSJohnny Huang return OTP_SUCCESS; 2236a6af4a17SJohnny Huang 2237cd1610b4SJohnny Huang break; 2238cd1610b4SJohnny Huang } 2239cd1610b4SJohnny Huang 2240cd1610b4SJohnny Huang if (!nconfirm) { 2241cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2242cd1610b4SJohnny Huang if (!confirm_yesno()) { 2243cd1610b4SJohnny Huang printf(" Aborting\n"); 22442a856b9aSJohnny Huang return OTP_FAILURE; 2245cd1610b4SJohnny Huang } 2246cd1610b4SJohnny Huang } 2247cd1610b4SJohnny Huang 2248cd1610b4SJohnny Huang switch (mode) { 2249a6d0d645SJohnny Huang case OTP_REGION_STRAP: 2250f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 225183655e91SJohnny Huang break; 2252a6d0d645SJohnny Huang case OTP_REGION_CONF: 2253a6d0d645SJohnny Huang case OTP_REGION_DATA: 2254f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 2255de6fbf1cSJohnny Huang break; 2256de6fbf1cSJohnny Huang } 2257de6fbf1cSJohnny Huang otp_soak(0); 225883655e91SJohnny Huang if (ret) { 22590dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 2260794e27ecSJohnny Huang printf("FAILURE\n"); 2261794e27ecSJohnny Huang return OTP_FAILURE; 2262794e27ecSJohnny Huang } 2263794e27ecSJohnny Huang 22649009c25dSJohnny Huang printf("SUCCESS\n"); 22652a856b9aSJohnny Huang return OTP_SUCCESS; 2266a219f6deSJohnny Huang } 2267a219f6deSJohnny Huang 2268794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 2269794e27ecSJohnny Huang { 2270794e27ecSJohnny Huang u32 otp_rid[2]; 2271a8789b47SJohnny Huang u32 sw_rid[2]; 2272794e27ecSJohnny Huang int rid_num = 0; 2273a8789b47SJohnny Huang int sw_rid_num = 0; 2274794e27ecSJohnny Huang int bit_offset; 2275794e27ecSJohnny Huang int dw_offset; 2276794e27ecSJohnny Huang int i; 2277794e27ecSJohnny Huang int ret; 2278794e27ecSJohnny Huang 2279f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2280f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2281794e27ecSJohnny Huang 2282a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2283a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2284a8789b47SJohnny Huang 2285794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2286a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2287a8789b47SJohnny Huang 2288a8789b47SJohnny Huang if (sw_rid_num < 0) { 2289a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2290a8789b47SJohnny Huang return OTP_FAILURE; 2291a8789b47SJohnny Huang } 2292a8789b47SJohnny Huang 2293a8789b47SJohnny Huang if (update_num > sw_rid_num) { 2294a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2295a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2296a8789b47SJohnny Huang return OTP_FAILURE; 2297a8789b47SJohnny Huang } 2298794e27ecSJohnny Huang 2299794e27ecSJohnny Huang if (rid_num < 0) { 2300b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by this command,\n" 2301b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n"); 2302794e27ecSJohnny Huang otp_print_revid(otp_rid); 23039009c25dSJohnny Huang return OTP_FAILURE; 23049009c25dSJohnny Huang } 2305cd1610b4SJohnny Huang 2306794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2307794e27ecSJohnny Huang otp_print_revid(otp_rid); 2308794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 2309794e27ecSJohnny Huang 2310a8789b47SJohnny Huang if (rid_num > update_num) { 2311a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 2312a8789b47SJohnny Huang printf("Skip\n"); 2313a8789b47SJohnny Huang return OTP_FAILURE; 2314a8789b47SJohnny Huang } else if (rid_num == update_num) { 2315a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 2316794e27ecSJohnny Huang printf("Skip\n"); 2317794e27ecSJohnny Huang return OTP_FAILURE; 2318794e27ecSJohnny Huang } 2319794e27ecSJohnny Huang 2320794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2321794e27ecSJohnny Huang if (i < 32) { 2322794e27ecSJohnny Huang dw_offset = 0xa; 2323794e27ecSJohnny Huang bit_offset = i; 2324794e27ecSJohnny Huang } else { 2325794e27ecSJohnny Huang dw_offset = 0xb; 2326794e27ecSJohnny Huang bit_offset = i - 32; 2327794e27ecSJohnny Huang } 2328b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset); 2329794e27ecSJohnny Huang if (i + 1 != update_num) 2330794e27ecSJohnny Huang printf(", "); 2331794e27ecSJohnny Huang } 2332794e27ecSJohnny Huang 2333794e27ecSJohnny Huang printf(" will be programmed\n"); 2334794e27ecSJohnny Huang if (force == 0) { 2335794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2336794e27ecSJohnny Huang if (!confirm_yesno()) { 2337794e27ecSJohnny Huang printf(" Aborting\n"); 2338794e27ecSJohnny Huang return OTP_FAILURE; 2339794e27ecSJohnny Huang } 2340794e27ecSJohnny Huang } 2341794e27ecSJohnny Huang 2342794e27ecSJohnny Huang ret = 0; 2343794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2344794e27ecSJohnny Huang if (i < 32) { 2345794e27ecSJohnny Huang dw_offset = 0xa04; 2346794e27ecSJohnny Huang bit_offset = i; 2347794e27ecSJohnny Huang } else { 2348794e27ecSJohnny Huang dw_offset = 0xa06; 2349794e27ecSJohnny Huang bit_offset = i - 32; 2350794e27ecSJohnny Huang } 2351f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 2352b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset); 2353794e27ecSJohnny Huang ret = OTP_FAILURE; 2354794e27ecSJohnny Huang break; 2355794e27ecSJohnny Huang } 2356794e27ecSJohnny Huang } 2357061d3279SJohnny Huang otp_soak(0); 2358f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2359f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2360794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2361794e27ecSJohnny Huang if (rid_num >= 0) 2362794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 2363794e27ecSJohnny Huang else 2364794e27ecSJohnny Huang printf("OTP revision ID\n"); 2365794e27ecSJohnny Huang otp_print_revid(otp_rid); 2366794e27ecSJohnny Huang if (!ret) 2367794e27ecSJohnny Huang printf("SUCCESS\n"); 2368794e27ecSJohnny Huang else 2369794e27ecSJohnny Huang printf("FAILED\n"); 2370794e27ecSJohnny Huang return ret; 2371794e27ecSJohnny Huang } 2372794e27ecSJohnny Huang 2373883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force) 2374883625c5SJohnny Huang { 2375883625c5SJohnny Huang u32 otpcfg4; 2376883625c5SJohnny Huang u32 krb; 2377883625c5SJohnny Huang u32 krb_b; 2378883625c5SJohnny Huang u32 krb_or; 2379883625c5SJohnny Huang u32 current_id; 2380883625c5SJohnny Huang 2381883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2382883625c5SJohnny Huang current_id = readl(SEC_KEY_NUM) & 7; 2383883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2384883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2385883625c5SJohnny Huang krb_or = krb | krb_b; 2386883625c5SJohnny Huang 2387883625c5SJohnny Huang printf("current Key ID: 0x%x\n", current_id); 2388883625c5SJohnny Huang printf("input retire ID: 0x%x\n", retire_id); 2389883625c5SJohnny Huang printf("OTPCFG0x4 = 0x%X\n", otpcfg4); 2390883625c5SJohnny Huang 2391883625c5SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2392883625c5SJohnny Huang printf("OTPCFG4 is protected\n"); 2393883625c5SJohnny Huang return OTP_FAILURE; 2394883625c5SJohnny Huang } 2395883625c5SJohnny Huang 2396883625c5SJohnny Huang if (retire_id >= current_id) { 2397883625c5SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2398883625c5SJohnny Huang return OTP_FAILURE; 2399883625c5SJohnny Huang } 2400883625c5SJohnny Huang 2401883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2402883625c5SJohnny Huang printf("Key 0x%X already retired\n", retire_id); 2403883625c5SJohnny Huang return OTP_SUCCESS; 2404883625c5SJohnny Huang } 2405883625c5SJohnny Huang 2406883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id); 2407883625c5SJohnny Huang if (force == 0) { 2408883625c5SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2409883625c5SJohnny Huang if (!confirm_yesno()) { 2410883625c5SJohnny Huang printf(" Aborting\n"); 2411883625c5SJohnny Huang return OTP_FAILURE; 2412883625c5SJohnny Huang } 2413883625c5SJohnny Huang } 2414883625c5SJohnny Huang 2415883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) { 2416883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed\n", retire_id); 2417883625c5SJohnny Huang printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16); 2418883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE) 2419883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16); 2420883625c5SJohnny Huang } 2421883625c5SJohnny Huang 2422883625c5SJohnny Huang otp_soak(0); 2423883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2424883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2425883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2426883625c5SJohnny Huang krb_or = krb | krb_b; 2427883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2428883625c5SJohnny Huang printf("SUCCESS\n"); 2429883625c5SJohnny Huang return OTP_SUCCESS; 2430883625c5SJohnny Huang } 2431883625c5SJohnny Huang printf("FAILED\n"); 2432883625c5SJohnny Huang return OTP_FAILURE; 2433883625c5SJohnny Huang } 2434883625c5SJohnny Huang 2435e7e21c44SJohnny Huang static int parse_config(struct sb_info *si) 2436e7e21c44SJohnny Huang { 2437e7e21c44SJohnny Huang int i; 2438e7e21c44SJohnny Huang u32 cfg0, cfg3, cfg4; 2439e7e21c44SJohnny Huang u32 sb_mode; 2440e7e21c44SJohnny Huang u32 key_retire; 2441e7e21c44SJohnny Huang u32 rsa_len; 2442e7e21c44SJohnny Huang u32 sha_len; 2443e7e21c44SJohnny Huang 2444e7e21c44SJohnny Huang otp_read_conf(0, &cfg0); 2445e7e21c44SJohnny Huang otp_read_conf(3, &cfg3); 2446e7e21c44SJohnny Huang otp_read_conf(4, &cfg4); 2447e7e21c44SJohnny Huang 2448e7e21c44SJohnny Huang sb_mode = (cfg0 >> 7) & 0x1; 2449e7e21c44SJohnny Huang si->enc_flag = (cfg0 >> 27) & 0x1; 2450e7e21c44SJohnny Huang key_retire = (cfg4 & 0x7f) | ((cfg4 >> 16) & 0x7f); 2451e7e21c44SJohnny Huang 2452e7e21c44SJohnny Huang if ((cfg0 >> 16) & 0x3f) 2453e7e21c44SJohnny Huang si->secure_region = 1; 2454e7e21c44SJohnny Huang else 2455e7e21c44SJohnny Huang si->secure_region = 0; 2456e7e21c44SJohnny Huang 2457e7e21c44SJohnny Huang si->header_offset = cfg3 & 0xffff; 2458e7e21c44SJohnny Huang if (si->header_offset == 0) 2459e7e21c44SJohnny Huang si->header_offset = 0x20; 2460e7e21c44SJohnny Huang 2461e7e21c44SJohnny Huang for (i = 0; i < 8; i++) { 2462e7e21c44SJohnny Huang if ((key_retire >> i) & 0x1) 2463e7e21c44SJohnny Huang si->retire_list[i] = 1; 2464e7e21c44SJohnny Huang else 2465e7e21c44SJohnny Huang si->retire_list[i] = 0; 2466e7e21c44SJohnny Huang } 2467e7e21c44SJohnny Huang 2468e7e21c44SJohnny Huang if (sb_mode == 0) { 2469e7e21c44SJohnny Huang printf("Mode GCM is not supported.\n"); 2470e7e21c44SJohnny Huang return OTP_FAILURE; 2471e7e21c44SJohnny Huang } 2472e7e21c44SJohnny Huang 2473e7e21c44SJohnny Huang if (si->enc_flag) 2474e7e21c44SJohnny Huang printf("Algorithm: AES_RSA_SHA\n"); 2475e7e21c44SJohnny Huang else 2476e7e21c44SJohnny Huang printf("Algorithm: RSA_SHA\n"); 2477e7e21c44SJohnny Huang 2478e7e21c44SJohnny Huang rsa_len = (cfg0 >> 10) & 0x3; 2479e7e21c44SJohnny Huang sha_len = (cfg0 >> 12) & 0x3; 2480e7e21c44SJohnny Huang 2481e7e21c44SJohnny Huang if (rsa_len == 0) { 2482e7e21c44SJohnny Huang si->rsa_algo = 1024; 2483e7e21c44SJohnny Huang printf("RSA length: 1024\n"); 2484e7e21c44SJohnny Huang } else if (rsa_len == 1) { 2485e7e21c44SJohnny Huang si->rsa_algo = 2048; 2486e7e21c44SJohnny Huang printf("RSA length: 2048\n"); 2487e7e21c44SJohnny Huang } else if (rsa_len == 2) { 2488e7e21c44SJohnny Huang si->rsa_algo = 3072; 2489e7e21c44SJohnny Huang printf("RSA length: 3072\n"); 2490e7e21c44SJohnny Huang } else { 2491e7e21c44SJohnny Huang si->rsa_algo = 4096; 2492e7e21c44SJohnny Huang printf("RSA length: 4096\n"); 2493e7e21c44SJohnny Huang } 2494e7e21c44SJohnny Huang if (sha_len == 0) { 2495e7e21c44SJohnny Huang si->sha_algo = 224; 2496e7e21c44SJohnny Huang si->digest_len = 28; 2497e7e21c44SJohnny Huang printf("HASH length: 224\n"); 2498e7e21c44SJohnny Huang } else if (sha_len == 1) { 2499e7e21c44SJohnny Huang si->sha_algo = 256; 2500e7e21c44SJohnny Huang si->digest_len = 32; 2501e7e21c44SJohnny Huang printf("HASH length: 256\n"); 2502e7e21c44SJohnny Huang } else if (sha_len == 2) { 2503e7e21c44SJohnny Huang si->sha_algo = 384; 2504e7e21c44SJohnny Huang si->digest_len = 48; 2505e7e21c44SJohnny Huang printf("HASH length: 384\n"); 2506e7e21c44SJohnny Huang } else { 2507e7e21c44SJohnny Huang si->sha_algo = 512; 2508e7e21c44SJohnny Huang si->digest_len = 64; 2509e7e21c44SJohnny Huang printf("HASH length: 512\n"); 2510e7e21c44SJohnny Huang } 2511e7e21c44SJohnny Huang return OTP_SUCCESS; 2512e7e21c44SJohnny Huang } 2513e7e21c44SJohnny Huang 2514e7e21c44SJohnny Huang static void parse_data(struct key_list *kl, int *key_num, struct sb_info *si, u32 *data) 2515e7e21c44SJohnny Huang { 2516e7e21c44SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 2517e7e21c44SJohnny Huang int i, j; 2518e7e21c44SJohnny Huang int id = 0; 2519e7e21c44SJohnny Huang u32 h; 2520e7e21c44SJohnny Huang u32 t; 2521e7e21c44SJohnny Huang 2522e7e21c44SJohnny Huang *key_num = 0; 2523e7e21c44SJohnny Huang for (i = 0; i < 16; i++) { 2524e7e21c44SJohnny Huang h = data[i]; 2525e7e21c44SJohnny Huang t = (h >> 14) & 0xf; 2526e7e21c44SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 2527e7e21c44SJohnny Huang if (t == key_info_array[j].value) { 2528e7e21c44SJohnny Huang kl[*key_num].key_info = &key_info_array[j]; 2529e7e21c44SJohnny Huang kl[*key_num].offset = h & 0x1ff8; 2530e7e21c44SJohnny Huang id = h & 0x7; 2531e7e21c44SJohnny Huang kl[*key_num].id = id; 2532e7e21c44SJohnny Huang if (si->retire_list[id] == 1) 2533e7e21c44SJohnny Huang kl[*key_num].retire = 1; 2534e7e21c44SJohnny Huang else 2535e7e21c44SJohnny Huang kl[*key_num].retire = 0; 2536e7e21c44SJohnny Huang (*key_num)++; 2537e7e21c44SJohnny Huang break; 2538e7e21c44SJohnny Huang } 2539e7e21c44SJohnny Huang } 2540e7e21c44SJohnny Huang if ((data[i] >> 13) & 1) 2541e7e21c44SJohnny Huang break; 2542e7e21c44SJohnny Huang } 2543e7e21c44SJohnny Huang } 2544e7e21c44SJohnny Huang 2545e7e21c44SJohnny Huang static int sb_sha(struct sb_info *si, u8 *sec_image, u32 sign_image_size, u8 *digest_ret) 2546e7e21c44SJohnny Huang { 2547e7e21c44SJohnny Huang switch (si->sha_algo) { 2548e7e21c44SJohnny Huang case 224: 2549e7e21c44SJohnny Huang printf("otp verify does not support SHA224\n"); 2550e7e21c44SJohnny Huang return OTP_FAILURE; 2551e7e21c44SJohnny Huang case 256: 2552e7e21c44SJohnny Huang sb_sha256(sec_image, sign_image_size, digest_ret); 2553e7e21c44SJohnny Huang break; 2554e7e21c44SJohnny Huang case 384: 2555e7e21c44SJohnny Huang sb_sha384(sec_image, sign_image_size, digest_ret); 2556e7e21c44SJohnny Huang break; 2557e7e21c44SJohnny Huang case 512: 2558e7e21c44SJohnny Huang sb_sha512(sec_image, sign_image_size, digest_ret); 2559e7e21c44SJohnny Huang break; 2560e7e21c44SJohnny Huang default: 2561e7e21c44SJohnny Huang printf("SHA Algorithm is invalid\n"); 2562e7e21c44SJohnny Huang return OTP_FAILURE; 2563e7e21c44SJohnny Huang } 2564e7e21c44SJohnny Huang return 0; 2565e7e21c44SJohnny Huang } 2566e7e21c44SJohnny Huang 2567e7e21c44SJohnny Huang static int mode2_verify(u8 *sec_image, u32 sign_image_size, 2568e7e21c44SJohnny Huang u8 *signature, u8 *rsa_m, 2569e7e21c44SJohnny Huang int order, u8 *digest, 2570e7e21c44SJohnny Huang struct sb_info *si, struct udevice *mod_exp_dev) 2571e7e21c44SJohnny Huang { 2572e7e21c44SJohnny Huang struct key_prop prop; 2573e7e21c44SJohnny Huang u8 rsa_e[3] = "\x01\x00\x01"; 2574e7e21c44SJohnny Huang u8 sign_ret[512]; 2575e7e21c44SJohnny Huang u8 rsa_m_rev[512]; 2576e7e21c44SJohnny Huang u8 signature_rev[512]; 2577e7e21c44SJohnny Huang u8 tmp; 2578e7e21c44SJohnny Huang u32 rsa_len = si->rsa_algo / 8; 2579e7e21c44SJohnny Huang int i; 2580e7e21c44SJohnny Huang int ret; 2581e7e21c44SJohnny Huang 2582e7e21c44SJohnny Huang memset(&prop, 0, sizeof(struct key_prop)); 2583e7e21c44SJohnny Huang 2584e7e21c44SJohnny Huang if (order == OTP_LIT_END) { 2585e7e21c44SJohnny Huang memset(rsa_m_rev, 0, 512); 2586e7e21c44SJohnny Huang memset(signature_rev, 0, 512); 2587e7e21c44SJohnny Huang for (i = 0; i < rsa_len; i++) { 2588e7e21c44SJohnny Huang rsa_m_rev[i] = rsa_m[rsa_len - 1 - i]; 2589e7e21c44SJohnny Huang signature_rev[i] = signature[rsa_len - 1 - i]; 2590e7e21c44SJohnny Huang } 2591e7e21c44SJohnny Huang prop.modulus = rsa_m_rev; 2592e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo; 2593e7e21c44SJohnny Huang prop.public_exponent = rsa_e; 2594e7e21c44SJohnny Huang prop.exp_len = 3; 2595e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature_rev, rsa_len, &prop, sign_ret); 2596e7e21c44SJohnny Huang } else { 2597e7e21c44SJohnny Huang prop.modulus = rsa_m; 2598e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo; 2599e7e21c44SJohnny Huang prop.public_exponent = rsa_e; 2600e7e21c44SJohnny Huang prop.exp_len = 3; 2601e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature, rsa_len, &prop, sign_ret); 2602e7e21c44SJohnny Huang } 2603e7e21c44SJohnny Huang 2604e7e21c44SJohnny Huang if (ret) { 2605e7e21c44SJohnny Huang printf("rsa_mod_exp error: %d\n", ret); 2606e7e21c44SJohnny Huang return OTP_FAILURE; 2607e7e21c44SJohnny Huang } 2608e7e21c44SJohnny Huang 2609e7e21c44SJohnny Huang if (order == OTP_LIT_END) { 2610e7e21c44SJohnny Huang for (i = 0; i < rsa_len / 2; i++) { 2611e7e21c44SJohnny Huang tmp = sign_ret[i]; 2612e7e21c44SJohnny Huang sign_ret[i] = sign_ret[rsa_len - 1 - i]; 2613e7e21c44SJohnny Huang sign_ret[rsa_len - 1 - i] = tmp; 2614e7e21c44SJohnny Huang } 2615e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret, si->digest_len); 2616e7e21c44SJohnny Huang } else { 2617e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret + (rsa_len - si->digest_len), si->digest_len); 2618e7e21c44SJohnny Huang } 2619e7e21c44SJohnny Huang 2620e7e21c44SJohnny Huang if (ret) 2621e7e21c44SJohnny Huang return OTP_FAILURE; 2622e7e21c44SJohnny Huang return 0; 2623e7e21c44SJohnny Huang } 2624e7e21c44SJohnny Huang 2625e7e21c44SJohnny Huang static int otp_verify_boot_image(phys_addr_t addr) 2626e7e21c44SJohnny Huang { 2627e7e21c44SJohnny Huang struct udevice *mod_exp_dev; 2628e7e21c44SJohnny Huang struct sb_info si; 2629e7e21c44SJohnny Huang struct key_list kl[16]; 2630e7e21c44SJohnny Huang struct sb_header *sh; 2631e7e21c44SJohnny Huang u32 data[2048]; 2632e7e21c44SJohnny Huang u8 digest[64]; 2633e7e21c44SJohnny Huang u8 *sec_image; 2634e7e21c44SJohnny Huang u8 *signature; 2635e7e21c44SJohnny Huang u8 *key; 2636e7e21c44SJohnny Huang u32 otp_rid[2]; 2637e7e21c44SJohnny Huang u32 sw_rid[2]; 2638e7e21c44SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2639e7e21c44SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2640e7e21c44SJohnny Huang int key_num; 2641e7e21c44SJohnny Huang int ret; 2642e7e21c44SJohnny Huang int i; 2643e7e21c44SJohnny Huang int pass = 0; 2644e7e21c44SJohnny Huang 2645*09f2a38fSJoel Stanley ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev); 2646e7e21c44SJohnny Huang if (ret) { 2647*09f2a38fSJoel Stanley printf("RSA: Can't find RSA driver\n"); 2648e7e21c44SJohnny Huang return OTP_FAILURE; 2649e7e21c44SJohnny Huang } 2650e7e21c44SJohnny Huang 2651e7e21c44SJohnny Huang for (i = 0; i < 2048 ; i += 2) 2652e7e21c44SJohnny Huang otp_read_data(i, &data[i]); 2653e7e21c44SJohnny Huang if (parse_config(&si)) 2654e7e21c44SJohnny Huang return OTP_FAILURE; 2655e7e21c44SJohnny Huang parse_data(kl, &key_num, &si, data); 2656e7e21c44SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2657e7e21c44SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2658e7e21c44SJohnny Huang 2659e7e21c44SJohnny Huang sec_image = (u8 *)addr; 2660e7e21c44SJohnny Huang sh = (struct sb_header *)(sec_image + si.header_offset); 2661e7e21c44SJohnny Huang signature = sec_image + sh->signature_offset; 2662e7e21c44SJohnny Huang 2663e7e21c44SJohnny Huang if (si.secure_region) 2664e7e21c44SJohnny Huang printf("WARNING: Secure Region is enabled, the verification may not correct.\n"); 2665e7e21c44SJohnny Huang 2666e7e21c44SJohnny Huang if (sh->sign_image_size % 512) { 2667e7e21c44SJohnny Huang printf("ERROR: The sign_image_size should be 512 bytes aligned\n"); 2668e7e21c44SJohnny Huang return OTP_FAILURE; 2669e7e21c44SJohnny Huang } 2670e7e21c44SJohnny Huang 2671e7e21c44SJohnny Huang printf("Check revision ID: "); 2672e7e21c44SJohnny Huang 2673e7e21c44SJohnny Huang sw_rid[0] = sh->revision_low; 2674e7e21c44SJohnny Huang sw_rid[1] = sh->revision_high; 2675e7e21c44SJohnny Huang 2676e7e21c44SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2677e7e21c44SJohnny Huang printf("FAIL\n"); 2678e7e21c44SJohnny Huang printf("Header revision_low: %x\n", sh->revision_low); 2679e7e21c44SJohnny Huang printf("Header revision_high: %x\n", sh->revision_high); 2680e7e21c44SJohnny Huang printf("OTP revision_low: %x\n", otp_rid[0]); 2681e7e21c44SJohnny Huang printf("OTP revision_high: %x\n", otp_rid[1]); 2682e7e21c44SJohnny Huang return OTP_FAILURE; 2683e7e21c44SJohnny Huang } 2684e7e21c44SJohnny Huang printf("PASS\n"); 2685e7e21c44SJohnny Huang 2686e7e21c44SJohnny Huang printf("Check secure image header: "); 2687e7e21c44SJohnny Huang if (((sh->aes_data_offset + sh->enc_offset + sh->sign_image_size + 2688e7e21c44SJohnny Huang sh->signature_offset + sh->revision_high + sh->revision_low + 2689e7e21c44SJohnny Huang sh->reserved + sh->bl1_header_checksum) & 0xffffffff) != 0) { 2690e7e21c44SJohnny Huang printf("FAIL\n"); 2691e7e21c44SJohnny Huang printf("aes_data_offset: %x\n", sh->aes_data_offset); 2692e7e21c44SJohnny Huang printf("enc_offset: %x\n", sh->enc_offset); 2693e7e21c44SJohnny Huang printf("sign_image_size: %x\n", sh->sign_image_size); 2694e7e21c44SJohnny Huang printf("signature_offset: %x\n", sh->signature_offset); 2695e7e21c44SJohnny Huang printf("revision_high: %x\n", sh->revision_high); 2696e7e21c44SJohnny Huang printf("revision_low: %x\n", sh->revision_low); 2697e7e21c44SJohnny Huang printf("reserved: %x\n", sh->reserved); 2698e7e21c44SJohnny Huang printf("bl1_header_checksum: %x\n", sh->bl1_header_checksum); 2699e7e21c44SJohnny Huang return OTP_FAILURE; 2700e7e21c44SJohnny Huang } 2701e7e21c44SJohnny Huang printf("PASS\n"); 2702e7e21c44SJohnny Huang 2703e7e21c44SJohnny Huang ret = sb_sha(&si, sec_image, sh->sign_image_size, digest); 2704e7e21c44SJohnny Huang if (ret) 2705e7e21c44SJohnny Huang return OTP_FAILURE; 2706e7e21c44SJohnny Huang 2707e7e21c44SJohnny Huang printf("Verifying secure image\n"); 2708e7e21c44SJohnny Huang for (i = 0; i < key_num; i++) { 2709e7e21c44SJohnny Huang if (kl[i].key_info->key_type != OTP_KEY_TYPE_RSA_PUB) 2710e7e21c44SJohnny Huang continue; 2711e7e21c44SJohnny Huang printf(" Key %d\n", kl[i].id); 2712e7e21c44SJohnny Huang if (kl[i].retire) { 2713e7e21c44SJohnny Huang printf(" Key %d is retired.\n", kl[i].id); 2714e7e21c44SJohnny Huang continue; 2715e7e21c44SJohnny Huang } 2716e7e21c44SJohnny Huang key = (u8 *)data + kl[i].offset; 2717e7e21c44SJohnny Huang if (!mode2_verify(sec_image, sh->sign_image_size, 2718e7e21c44SJohnny Huang signature, key, kl[i].key_info->order, digest, 2719e7e21c44SJohnny Huang &si, mod_exp_dev)) { 2720e7e21c44SJohnny Huang pass = 1; 2721e7e21c44SJohnny Huang break; 2722e7e21c44SJohnny Huang } 2723e7e21c44SJohnny Huang } 2724e7e21c44SJohnny Huang if (pass) { 2725e7e21c44SJohnny Huang printf(" OEM DSS RSA public keys\n"); 2726e7e21c44SJohnny Huang printf(" ID: %d\n", kl[i].id); 2727e7e21c44SJohnny Huang if (kl[i].key_info->order == OTP_BIG_END) 2728e7e21c44SJohnny Huang printf(" Big endian\n"); 2729e7e21c44SJohnny Huang else 2730e7e21c44SJohnny Huang printf(" Little endian\n"); 2731e7e21c44SJohnny Huang printf("Verify secure image: PASS\n"); 2732e7e21c44SJohnny Huang return OTP_SUCCESS; 2733e7e21c44SJohnny Huang } 2734e7e21c44SJohnny Huang printf("Verify secure image: FAIL\n"); 2735e7e21c44SJohnny Huang return OTP_FAILURE; 2736e7e21c44SJohnny Huang } 2737e7e21c44SJohnny Huang 2738418822f0SJohnny Huang static int otp_invalid_key(u32 header_offset, int force) 2739418822f0SJohnny Huang { 2740418822f0SJohnny Huang int i; 2741418822f0SJohnny Huang int ret; 2742418822f0SJohnny Huang u32 header_list[16]; 2743418822f0SJohnny Huang u32 header; 2744418822f0SJohnny Huang u32 key_type; 2745418822f0SJohnny Huang u32 prog_val; 2746418822f0SJohnny Huang 2747418822f0SJohnny Huang for (i = 0; i < 16 ; i += 2) 2748418822f0SJohnny Huang otp_read_data(i, &header_list[i]); 2749418822f0SJohnny Huang header = header_list[header_offset]; 2750418822f0SJohnny Huang key_type = (header >> 14) & 0xf; 2751418822f0SJohnny Huang _otp_print_key(header, header_offset, NULL); 2752418822f0SJohnny Huang if (key_type == 0 || key_type == 0xf) { 2753418822f0SJohnny Huang printf("Key[%d] already invalid\n", header_offset); 2754418822f0SJohnny Huang return OTP_SUCCESS; 2755418822f0SJohnny Huang } 2756418822f0SJohnny Huang 2757418822f0SJohnny Huang printf("Key[%d] will be invalid\n", header_offset); 2758418822f0SJohnny Huang if (force == 0) { 2759418822f0SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2760418822f0SJohnny Huang if (!confirm_yesno()) { 2761418822f0SJohnny Huang printf(" Aborting\n"); 2762418822f0SJohnny Huang return OTP_FAILURE; 2763418822f0SJohnny Huang } 2764418822f0SJohnny Huang } 2765418822f0SJohnny Huang 2766418822f0SJohnny Huang if (header_offset % 2) 2767418822f0SJohnny Huang prog_val = 0; 2768418822f0SJohnny Huang else 2769418822f0SJohnny Huang prog_val = 1; 2770418822f0SJohnny Huang for (i = 14; i <= 17; i++) { 2771418822f0SJohnny Huang ret = otp_prog_dc_b(prog_val, header_offset, i); 2772418822f0SJohnny Huang if (ret) { 2773418822f0SJohnny Huang printf("OTPDATA0x%x[%d] programming failed\n", header_offset, i); 2774418822f0SJohnny Huang return OTP_FAILURE; 2775418822f0SJohnny Huang } 2776418822f0SJohnny Huang } 2777418822f0SJohnny Huang 2778418822f0SJohnny Huang printf("SUCCESS\n"); 2779418822f0SJohnny Huang return OTP_SUCCESS; 2780418822f0SJohnny Huang } 2781418822f0SJohnny Huang 27822a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 278369d5fd8fSJohnny Huang { 2784a219f6deSJohnny Huang u32 offset, count; 27852a856b9aSJohnny Huang int ret; 278669d5fd8fSJohnny Huang 27872a856b9aSJohnny Huang if (argc == 4) { 27882a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 27892a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 27902a856b9aSJohnny Huang } else if (argc == 3) { 27912a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 27922a856b9aSJohnny Huang count = 1; 27932a856b9aSJohnny Huang } else { 279469d5fd8fSJohnny Huang return CMD_RET_USAGE; 279569d5fd8fSJohnny Huang } 279669d5fd8fSJohnny Huang 2797030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2798f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2799030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 28002a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2801030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 28022a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2803030cb4a7SJohnny Huang else 28042a856b9aSJohnny Huang return CMD_RET_USAGE; 280569d5fd8fSJohnny Huang 28062a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 28072a856b9aSJohnny Huang return CMD_RET_SUCCESS; 28082a856b9aSJohnny Huang return CMD_RET_USAGE; 28092a856b9aSJohnny Huang } 28102a856b9aSJohnny Huang 28112a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 28122a856b9aSJohnny Huang { 28132a856b9aSJohnny Huang phys_addr_t addr; 28142a856b9aSJohnny Huang int ret; 28152a856b9aSJohnny Huang 2816de6b0cc4SJohnny Huang if (argc == 3) { 2817ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 28182a856b9aSJohnny Huang return CMD_RET_USAGE; 28192a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2820f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2821de6b0cc4SJohnny Huang } else if (argc == 2) { 28222a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2823f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 28242a856b9aSJohnny Huang } else { 28252a856b9aSJohnny Huang return CMD_RET_USAGE; 28262a856b9aSJohnny Huang } 28272a856b9aSJohnny Huang 28282a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 28292a856b9aSJohnny Huang return CMD_RET_SUCCESS; 28302a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 28312a856b9aSJohnny Huang return CMD_RET_FAILURE; 28322a856b9aSJohnny Huang else 28332a856b9aSJohnny Huang return CMD_RET_USAGE; 28342a856b9aSJohnny Huang } 28352a856b9aSJohnny Huang 28362a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 28372a856b9aSJohnny Huang { 28382a856b9aSJohnny Huang int mode = 0; 28392a856b9aSJohnny Huang int nconfirm = 0; 28402a856b9aSJohnny Huang int otp_addr = 0; 28412a856b9aSJohnny Huang int bit_offset; 28422a856b9aSJohnny Huang int value; 28432a856b9aSJohnny Huang int ret; 2844030cb4a7SJohnny Huang u32 otp_strap_pro; 28452a856b9aSJohnny Huang 28462a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 28472a856b9aSJohnny Huang return CMD_RET_USAGE; 28482a856b9aSJohnny Huang 28492a856b9aSJohnny Huang /* Drop the pb cmd */ 28502a856b9aSJohnny Huang argc--; 28512a856b9aSJohnny Huang argv++; 28522a856b9aSJohnny Huang 28532a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2854a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 28552a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2856a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 28572a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2858a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2859cd1610b4SJohnny Huang else 28602a856b9aSJohnny Huang return CMD_RET_USAGE; 28612a856b9aSJohnny Huang 28622a856b9aSJohnny Huang /* Drop the region cmd */ 28632a856b9aSJohnny Huang argc--; 28642a856b9aSJohnny Huang argv++; 28652a856b9aSJohnny Huang 2866ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2867cd1610b4SJohnny Huang nconfirm = 1; 28682a856b9aSJohnny Huang /* Drop the force option */ 28692a856b9aSJohnny Huang argc--; 28702a856b9aSJohnny Huang argv++; 28712a856b9aSJohnny Huang } 2872cd1610b4SJohnny Huang 2873a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 28742a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 28752a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 28760808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 28772a856b9aSJohnny Huang return CMD_RET_USAGE; 2878cd1610b4SJohnny Huang } else { 28792a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 28802a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 28812a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 28820808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 28832a856b9aSJohnny Huang return CMD_RET_USAGE; 28840808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 288578855207SJohnny Huang if (otp_addr >= 0x800) 28860808cc55SJohnny Huang return CMD_RET_USAGE; 28870808cc55SJohnny Huang } else { 288878855207SJohnny Huang if (otp_addr >= 0x20) 28890808cc55SJohnny Huang return CMD_RET_USAGE; 28900808cc55SJohnny Huang } 2891cd1610b4SJohnny Huang } 2892cd1610b4SJohnny Huang if (value != 0 && value != 1) 28932a856b9aSJohnny Huang return CMD_RET_USAGE; 2894cd1610b4SJohnny Huang 2895030cb4a7SJohnny Huang ret = 0; 2896030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2897030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2898030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2899030cb4a7SJohnny Huang } 2900030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2901030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2902030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2903030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2904030cb4a7SJohnny Huang ret = -1; 2905030cb4a7SJohnny Huang } 2906030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2907030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2908030cb4a7SJohnny Huang ret = -1; 2909030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2910030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2911030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2912030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2913030cb4a7SJohnny Huang ret = -1; 2914030cb4a7SJohnny Huang } 2915030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2916030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2917030cb4a7SJohnny Huang ret = -1; 2918030cb4a7SJohnny Huang } 2919030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2920030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2921030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2922030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2923030cb4a7SJohnny Huang ret = -1; 2924030cb4a7SJohnny Huang } 2925030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2926030cb4a7SJohnny Huang u32 otp_rid[2]; 2927030cb4a7SJohnny Huang u32 sw_rid[2]; 2928030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2929030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2930030cb4a7SJohnny Huang 2931030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2932030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2933030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2934030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2935030cb4a7SJohnny Huang 2936030cb4a7SJohnny Huang if (otp_addr == 10) 2937030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2938030cb4a7SJohnny Huang else 2939030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2940030cb4a7SJohnny Huang 2941030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2942030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2943030cb4a7SJohnny Huang ret = -1; 2944030cb4a7SJohnny Huang } 2945030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2946030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2947030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2948030cb4a7SJohnny Huang ret = -1; 2949030cb4a7SJohnny Huang } else { 2950030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2951030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2952030cb4a7SJohnny Huang u32 key_num; 2953030cb4a7SJohnny Huang u32 retire; 2954030cb4a7SJohnny Huang 2955030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2956030cb4a7SJohnny Huang if (bit_offset >= 16) 2957030cb4a7SJohnny Huang retire = bit_offset - 16; 2958030cb4a7SJohnny Huang else 2959030cb4a7SJohnny Huang retire = bit_offset; 2960030cb4a7SJohnny Huang if (retire >= key_num) { 2961030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2962030cb4a7SJohnny Huang ret = -1; 2963030cb4a7SJohnny Huang } 2964030cb4a7SJohnny Huang } 2965030cb4a7SJohnny Huang } 2966030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2967030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2968030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2969030cb4a7SJohnny Huang ret = -1; 2970030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2971030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2972030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2973030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2974030cb4a7SJohnny Huang else 2975030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2976030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2977b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset); 2978030cb4a7SJohnny Huang ret = -1; 2979030cb4a7SJohnny Huang } 2980030cb4a7SJohnny Huang } 2981030cb4a7SJohnny Huang } 2982030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2983030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2984030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2985030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2986030cb4a7SJohnny Huang ret = -1; 2987030cb4a7SJohnny Huang } 2988030cb4a7SJohnny Huang } 2989030cb4a7SJohnny Huang 2990030cb4a7SJohnny Huang if (ret == -1) 2991030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2992030cb4a7SJohnny Huang 2993f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 29942a856b9aSJohnny Huang 29952a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 29962a856b9aSJohnny Huang return CMD_RET_SUCCESS; 29972a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 29982a856b9aSJohnny Huang return CMD_RET_FAILURE; 29992a856b9aSJohnny Huang else 30002a856b9aSJohnny Huang return CMD_RET_USAGE; 30012a856b9aSJohnny Huang } 30022a856b9aSJohnny Huang 30032a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 30042a856b9aSJohnny Huang { 30052a856b9aSJohnny Huang phys_addr_t addr; 30062a856b9aSJohnny Huang int otp_addr = 0; 3007b8590031SJohnny Huang int ret; 30082a856b9aSJohnny Huang 30092a856b9aSJohnny Huang if (argc != 3) 30102a856b9aSJohnny Huang return CMD_RET_USAGE; 30112a856b9aSJohnny Huang 30122a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 30132a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 3014b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 3015b8590031SJohnny Huang if (ret == 0) { 301669d5fd8fSJohnny Huang printf("Compare pass\n"); 30172a856b9aSJohnny Huang return CMD_RET_SUCCESS; 3018a219f6deSJohnny Huang } 301969d5fd8fSJohnny Huang printf("Compare fail\n"); 30202a856b9aSJohnny Huang return CMD_RET_FAILURE; 302169d5fd8fSJohnny Huang } 302269d5fd8fSJohnny Huang 302366f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 302466f2f8e5SJohnny Huang { 3025a8bd6d8cSJohnny Huang int view = 0; 30262d4b0742SJohnny Huang int input; 3027a8bd6d8cSJohnny Huang 3028a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 302966f2f8e5SJohnny Huang return CMD_RET_USAGE; 303066f2f8e5SJohnny Huang 30312d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 30322d4b0742SJohnny Huang if (argc == 3) { 30332d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 30342d4b0742SJohnny Huang otp_print_conf_info(input); 30352d4b0742SJohnny Huang } else { 30362d4b0742SJohnny Huang otp_print_conf_info(-1); 30372d4b0742SJohnny Huang } 30382d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 30392d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 3040a8bd6d8cSJohnny Huang view = 1; 3041a8bd6d8cSJohnny Huang /* Drop the view option */ 3042a8bd6d8cSJohnny Huang argc--; 3043a8bd6d8cSJohnny Huang argv++; 3044a8bd6d8cSJohnny Huang } 3045b458cd62SJohnny Huang otp_print_strap_info(view); 30460dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 30470dc9a440SJohnny Huang otp_print_scu_info(); 304888bd7d58SJohnny Huang } else if (!strcmp(argv[1], "key")) { 304988bd7d58SJohnny Huang otp_print_key_info(); 305066f2f8e5SJohnny Huang } else { 305166f2f8e5SJohnny Huang return CMD_RET_USAGE; 305266f2f8e5SJohnny Huang } 30532d4b0742SJohnny Huang 305466f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 305566f2f8e5SJohnny Huang } 305666f2f8e5SJohnny Huang 30570dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3058737ed20bSJohnny Huang { 30590dc9a440SJohnny Huang u32 input; 30600dc9a440SJohnny Huang u32 bit_offset; 3061e14b073cSJohnny Huang u32 prog_address; 3062030cb4a7SJohnny Huang char force; 306383655e91SJohnny Huang int ret; 3064a219f6deSJohnny Huang 3065737ed20bSJohnny Huang if (argc != 3 && argc != 2) 3066737ed20bSJohnny Huang return CMD_RET_USAGE; 3067737ed20bSJohnny Huang 3068e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 3069737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 3070030cb4a7SJohnny Huang force = 1; 3071737ed20bSJohnny Huang } else { 3072737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 3073030cb4a7SJohnny Huang force = 0; 3074737ed20bSJohnny Huang } 3075737ed20bSJohnny Huang 3076737ed20bSJohnny Huang if (input < 32) { 3077737ed20bSJohnny Huang bit_offset = input; 30780dc9a440SJohnny Huang prog_address = 0xe0c; 3079737ed20bSJohnny Huang } else if (input < 64) { 3080737ed20bSJohnny Huang bit_offset = input - 32; 30810dc9a440SJohnny Huang prog_address = 0xe0e; 3082737ed20bSJohnny Huang } else { 3083737ed20bSJohnny Huang return CMD_RET_USAGE; 3084737ed20bSJohnny Huang } 3085737ed20bSJohnny Huang 3086030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 3087030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 3088030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3089030cb4a7SJohnny Huang } 3090030cb4a7SJohnny Huang 3091030cb4a7SJohnny Huang if (!force) { 3092b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input); 3093030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 3094030cb4a7SJohnny Huang if (!confirm_yesno()) { 3095030cb4a7SJohnny Huang printf(" Aborting\n"); 3096030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3097030cb4a7SJohnny Huang } 3098030cb4a7SJohnny Huang } 3099030cb4a7SJohnny Huang 3100e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 3101b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input); 3102e14b073cSJohnny Huang return CMD_RET_SUCCESS; 3103e14b073cSJohnny Huang } 3104de6fbf1cSJohnny Huang 3105f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 3106de6fbf1cSJohnny Huang otp_soak(0); 310783655e91SJohnny Huang 310883655e91SJohnny Huang if (ret) { 3109b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input); 3110737ed20bSJohnny Huang return CMD_RET_FAILURE; 3111737ed20bSJohnny Huang } 31129a4fe690SJohnny Huang 3113b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input); 3114794e27ecSJohnny Huang return CMD_RET_SUCCESS; 3115794e27ecSJohnny Huang } 3116794e27ecSJohnny Huang 31170dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3118e14b073cSJohnny Huang { 31190dc9a440SJohnny Huang u32 scu_offset; 31200dc9a440SJohnny Huang u32 bit_offset; 31210dc9a440SJohnny Huang u32 conf_offset; 31220dc9a440SJohnny Huang u32 prog_address; 31230dc9a440SJohnny Huang char force; 31240dc9a440SJohnny Huang int ret; 31250dc9a440SJohnny Huang 31260dc9a440SJohnny Huang if (argc != 4 && argc != 3) 31270dc9a440SJohnny Huang return CMD_RET_USAGE; 31280dc9a440SJohnny Huang 31290dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 31300dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 31310dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 31320dc9a440SJohnny Huang force = 1; 31330dc9a440SJohnny Huang } else { 31340dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 31350dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 31360dc9a440SJohnny Huang force = 0; 31370dc9a440SJohnny Huang } 31380dc9a440SJohnny Huang if (scu_offset == 0x500) { 31390dc9a440SJohnny Huang prog_address = 0xe08; 31400dc9a440SJohnny Huang conf_offset = 28; 31410dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 31420dc9a440SJohnny Huang prog_address = 0xe0a; 31430dc9a440SJohnny Huang conf_offset = 29; 31440dc9a440SJohnny Huang } else { 31450dc9a440SJohnny Huang return CMD_RET_USAGE; 31460dc9a440SJohnny Huang } 31470dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 31480dc9a440SJohnny Huang return CMD_RET_USAGE; 3149030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 3150030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 3151030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3152030cb4a7SJohnny Huang } 31530dc9a440SJohnny Huang if (!force) { 3154b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset); 3155b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset); 31560dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 31570dc9a440SJohnny Huang if (!confirm_yesno()) { 31580dc9a440SJohnny Huang printf(" Aborting\n"); 31590dc9a440SJohnny Huang return CMD_RET_FAILURE; 31600dc9a440SJohnny Huang } 3161e14b073cSJohnny Huang } 3162e14b073cSJohnny Huang 31630dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 3164b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset); 31650dc9a440SJohnny Huang return CMD_RET_SUCCESS; 31660dc9a440SJohnny Huang } 31670dc9a440SJohnny Huang 31680dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 31690dc9a440SJohnny Huang otp_soak(0); 31700dc9a440SJohnny Huang 31710dc9a440SJohnny Huang if (ret) { 3172b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset); 31730dc9a440SJohnny Huang return CMD_RET_FAILURE; 31740dc9a440SJohnny Huang } 31750dc9a440SJohnny Huang 3176b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset); 31770dc9a440SJohnny Huang return CMD_RET_SUCCESS; 3178e14b073cSJohnny Huang } 3179e14b073cSJohnny Huang 3180f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3181f67375f7SJohnny Huang { 3182e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 3183f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 3184f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 3185f67375f7SJohnny Huang 3186f67375f7SJohnny Huang return CMD_RET_SUCCESS; 3187f67375f7SJohnny Huang } 3188f67375f7SJohnny Huang 3189794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3190794e27ecSJohnny Huang { 3191794e27ecSJohnny Huang u32 update_num; 3192794e27ecSJohnny Huang int force = 0; 3193794e27ecSJohnny Huang int ret; 3194794e27ecSJohnny Huang 3195794e27ecSJohnny Huang if (argc == 3) { 3196794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 3197794e27ecSJohnny Huang return CMD_RET_USAGE; 3198794e27ecSJohnny Huang force = 1; 3199794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 3200794e27ecSJohnny Huang } else if (argc == 2) { 3201794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 3202794e27ecSJohnny Huang } else { 3203794e27ecSJohnny Huang return CMD_RET_USAGE; 3204794e27ecSJohnny Huang } 3205794e27ecSJohnny Huang 3206794e27ecSJohnny Huang if (update_num > 64) 3207794e27ecSJohnny Huang return CMD_RET_USAGE; 3208794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 3209b8590031SJohnny Huang 3210794e27ecSJohnny Huang if (ret) 3211794e27ecSJohnny Huang return CMD_RET_FAILURE; 3212794e27ecSJohnny Huang return CMD_RET_SUCCESS; 3213794e27ecSJohnny Huang } 3214794e27ecSJohnny Huang 3215794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3216794e27ecSJohnny Huang { 3217794e27ecSJohnny Huang u32 otp_rid[2]; 3218a8789b47SJohnny Huang u32 sw_rid[2]; 3219794e27ecSJohnny Huang int rid_num = 0; 3220a8789b47SJohnny Huang int sw_rid_num = 0; 3221794e27ecSJohnny Huang int ret; 3222794e27ecSJohnny Huang 3223794e27ecSJohnny Huang if (argc != 1) 3224794e27ecSJohnny Huang return CMD_RET_USAGE; 3225794e27ecSJohnny Huang 3226f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 3227f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 3228794e27ecSJohnny Huang 3229a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 3230a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 3231794e27ecSJohnny Huang 3232a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 3233a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 3234a8789b47SJohnny Huang 3235030cb4a7SJohnny Huang if (sw_rid_num < 0) { 3236030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 3237030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 3238030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 3239030cb4a7SJohnny Huang } else { 3240a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 3241030cb4a7SJohnny Huang } 3242794e27ecSJohnny Huang if (rid_num >= 0) { 3243794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 3244794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 3245794e27ecSJohnny Huang } else { 3246b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n" 3247b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n" 3248794e27ecSJohnny Huang "current OTP revision ID\n"); 3249794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 3250794e27ecSJohnny Huang } 3251794e27ecSJohnny Huang otp_print_revid(otp_rid); 3252794e27ecSJohnny Huang 3253794e27ecSJohnny Huang return ret; 3254794e27ecSJohnny Huang } 3255794e27ecSJohnny Huang 3256883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3257883625c5SJohnny Huang { 3258883625c5SJohnny Huang u32 retire_id; 3259883625c5SJohnny Huang int force = 0; 3260883625c5SJohnny Huang int ret; 3261883625c5SJohnny Huang 3262883625c5SJohnny Huang if (argc == 3) { 3263883625c5SJohnny Huang if (strcmp(argv[1], "o")) 3264883625c5SJohnny Huang return CMD_RET_USAGE; 3265883625c5SJohnny Huang force = 1; 3266883625c5SJohnny Huang retire_id = simple_strtoul(argv[2], NULL, 16); 3267883625c5SJohnny Huang } else if (argc == 2) { 3268883625c5SJohnny Huang retire_id = simple_strtoul(argv[1], NULL, 16); 3269883625c5SJohnny Huang } else { 3270883625c5SJohnny Huang return CMD_RET_USAGE; 3271883625c5SJohnny Huang } 3272883625c5SJohnny Huang 3273883625c5SJohnny Huang if (retire_id > 7) 3274883625c5SJohnny Huang return CMD_RET_USAGE; 3275883625c5SJohnny Huang ret = otp_retire_key(retire_id, force); 3276883625c5SJohnny Huang 3277883625c5SJohnny Huang if (ret) 3278883625c5SJohnny Huang return CMD_RET_FAILURE; 3279883625c5SJohnny Huang return CMD_RET_SUCCESS; 3280883625c5SJohnny Huang } 3281883625c5SJohnny Huang 3282e7e21c44SJohnny Huang static int do_otpverify(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3283e7e21c44SJohnny Huang { 3284e7e21c44SJohnny Huang phys_addr_t addr; 3285e7e21c44SJohnny Huang int ret; 3286e7e21c44SJohnny Huang 3287e7e21c44SJohnny Huang if (argc == 2) { 3288e7e21c44SJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 3289e7e21c44SJohnny Huang ret = otp_verify_boot_image(addr); 3290e7e21c44SJohnny Huang } else { 3291e7e21c44SJohnny Huang return CMD_RET_USAGE; 3292e7e21c44SJohnny Huang } 3293e7e21c44SJohnny Huang 3294e7e21c44SJohnny Huang if (ret == OTP_SUCCESS) 3295e7e21c44SJohnny Huang return CMD_RET_SUCCESS; 3296e7e21c44SJohnny Huang else if (ret == OTP_FAILURE) 3297e7e21c44SJohnny Huang return CMD_RET_FAILURE; 3298e7e21c44SJohnny Huang else 3299e7e21c44SJohnny Huang return CMD_RET_USAGE; 3300e7e21c44SJohnny Huang } 3301e7e21c44SJohnny Huang 3302418822f0SJohnny Huang static int do_otpinvalid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3303418822f0SJohnny Huang { 3304418822f0SJohnny Huang u32 header_offset; 3305418822f0SJohnny Huang int force = 0; 3306418822f0SJohnny Huang int ret; 3307418822f0SJohnny Huang 3308418822f0SJohnny Huang if (argc == 3) { 3309418822f0SJohnny Huang if (strcmp(argv[1], "o")) 3310418822f0SJohnny Huang return CMD_RET_USAGE; 3311418822f0SJohnny Huang force = 1; 3312418822f0SJohnny Huang header_offset = simple_strtoul(argv[2], NULL, 16); 3313418822f0SJohnny Huang } else if (argc == 2) { 3314418822f0SJohnny Huang header_offset = simple_strtoul(argv[1], NULL, 16); 3315418822f0SJohnny Huang } else { 3316418822f0SJohnny Huang return CMD_RET_USAGE; 3317418822f0SJohnny Huang } 3318418822f0SJohnny Huang 3319418822f0SJohnny Huang if (header_offset > 16) 3320418822f0SJohnny Huang return CMD_RET_USAGE; 3321418822f0SJohnny Huang ret = otp_invalid_key(header_offset, force); 3322418822f0SJohnny Huang 3323418822f0SJohnny Huang if (ret) 3324418822f0SJohnny Huang return CMD_RET_FAILURE; 3325418822f0SJohnny Huang return CMD_RET_SUCCESS; 3326418822f0SJohnny Huang } 3327418822f0SJohnny Huang 33282a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 3329f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 33302a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 3331a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 3332de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 33332a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 3334737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 33350dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 33362a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 3337794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 3338794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 3339883625c5SJohnny Huang U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""), 3340e7e21c44SJohnny Huang U_BOOT_CMD_MKENT(verify, 2, 0, do_otpverify, "", ""), 3341418822f0SJohnny Huang U_BOOT_CMD_MKENT(invalid, 3, 0, do_otpinvalid, "", ""), 33422a856b9aSJohnny Huang }; 33432a856b9aSJohnny Huang 33442a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 33452a856b9aSJohnny Huang { 3346030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 33472a856b9aSJohnny Huang cmd_tbl_t *cp; 3348a219f6deSJohnny Huang u32 ver; 3349e14b073cSJohnny Huang int ret; 3350030cb4a7SJohnny Huang u32 otp_conf0; 33512a856b9aSJohnny Huang 33522a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 33532a856b9aSJohnny Huang 3354737ed20bSJohnny Huang /* Drop the otp command */ 33552a856b9aSJohnny Huang argc--; 33562a856b9aSJohnny Huang argv++; 33572a856b9aSJohnny Huang 3358a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 33592a856b9aSJohnny Huang return CMD_RET_USAGE; 33602a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 33612a856b9aSJohnny Huang return CMD_RET_SUCCESS; 33622a856b9aSJohnny Huang 33630dae9d52SJohnny Huang ver = chip_version(); 33640dae9d52SJohnny Huang switch (ver) { 3365e417205bSJohnny Huang case OTP_A0: 3366e417205bSJohnny Huang info_cb.version = OTP_A0; 33679a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 33689a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 33699a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 33709a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 33719a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 33729a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 3373e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 33740dae9d52SJohnny Huang break; 3375e417205bSJohnny Huang case OTP_A1: 3376e417205bSJohnny Huang info_cb.version = OTP_A1; 33773cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 33783cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 33793cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 33803cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 33819a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 33829a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 33830dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33840dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3385e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 33860dae9d52SJohnny Huang break; 3387e417205bSJohnny Huang case OTP_A2: 3388e417205bSJohnny Huang info_cb.version = OTP_A2; 33895fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 33905fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 3391fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 3392fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 33935fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 33945fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 33950dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33960dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3397e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 33980dae9d52SJohnny Huang break; 3399e417205bSJohnny Huang case OTP_A3: 3400e417205bSJohnny Huang info_cb.version = OTP_A3; 3401b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 3402b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 3403fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 3404fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 3405181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 3406181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 34070dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 34080dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3409e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 341064b66712SJohnny Huang break; 34110dae9d52SJohnny Huang default: 3412f1be5099SJohnny Huang printf("SOC is not supported\n"); 34130dae9d52SJohnny Huang return CMD_RET_FAILURE; 34149a4fe690SJohnny Huang } 34159a4fe690SJohnny Huang 3416030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 3417030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 3418030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 3419030cb4a7SJohnny Huang 3420030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 3421030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 3422030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 3423030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 3424030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 3425030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 3426030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 3427030cb4a7SJohnny Huang 3428e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 3429b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 3430e14b073cSJohnny Huang 3431e14b073cSJohnny Huang return ret; 343269d5fd8fSJohnny Huang } 343369d5fd8fSJohnny Huang 3434a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 343569d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 3436f67375f7SJohnny Huang "version\n" 3437f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 34382a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 34392d4b0742SJohnny Huang "otp info strap [v]\n" 34402d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 34410dc9a440SJohnny Huang "otp info scu\n" 344288bd7d58SJohnny Huang "otp info key\n" 3443de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 3444ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 3445ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 3446ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 34470dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 3448794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 3449794e27ecSJohnny Huang "otp rid\n" 3450883625c5SJohnny Huang "otp retire [o] <key_id>\n" 3451e7e21c44SJohnny Huang "otp verify <addr>\n" 3452418822f0SJohnny Huang "otp invalid [o] <header_offset>\n" 345369d5fd8fSJohnny Huang ); 3454