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 { 136*22fda007SJoel Stanley int value: 4; 137*22fda007SJoel Stanley int key_type: 4; 138*22fda007SJoel Stanley int order: 1; 139*22fda007SJoel Stanley int need_id: 1; 140*22fda007SJoel Stanley char *information; 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 308a219f6deSJohnny Huang static u32 chip_version(void) 3099a4fe690SJohnny Huang { 310e417205bSJohnny Huang u32 revid0, revid1; 3119a4fe690SJohnny Huang 312e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0); 313e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1); 3149a4fe690SJohnny Huang 315e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { 316badd21c2SJohnny Huang /* AST2600-A0 */ 317e417205bSJohnny Huang return OTP_A0; 318e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { 319badd21c2SJohnny Huang /* AST2600-A1 */ 320e417205bSJohnny Huang return OTP_A1; 321e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { 322badd21c2SJohnny Huang /* AST2600-A2 */ 323e417205bSJohnny Huang return OTP_A2; 324e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { 32564b66712SJohnny Huang /* AST2600-A3 */ 326e417205bSJohnny Huang return OTP_A3; 327e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { 328e417205bSJohnny Huang /* AST2620-A1 */ 329e417205bSJohnny Huang return OTP_A1; 330e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { 331e417205bSJohnny Huang /* AST2620-A2 */ 332e417205bSJohnny Huang return OTP_A2; 333e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { 33464b66712SJohnny Huang /* AST2620-A3 */ 335e417205bSJohnny Huang return OTP_A3; 336e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { 337e417205bSJohnny Huang /* AST2605-A2 */ 338e417205bSJohnny Huang return OTP_A2; 339e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { 340e417205bSJohnny Huang /* AST2605-A3 */ 341e417205bSJohnny Huang return OTP_A3; 342e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { 343e417205bSJohnny Huang /* AST2605-A3 */ 344e417205bSJohnny Huang return OTP_A3; 3450dae9d52SJohnny Huang } 346f347c284SJohnny Huang return OTP_FAILURE; 3479a4fe690SJohnny Huang } 3489a4fe690SJohnny Huang 3492031a123SJohnny Huang static int wait_complete(void) 3503d3688adSJohnny Huang { 3512031a123SJohnny Huang u32 val; 3522031a123SJohnny Huang int ret; 3533d3688adSJohnny Huang 3542031a123SJohnny Huang udelay(1); 3552031a123SJohnny Huang ret = readl_poll_timeout(OTP_STATUS, val, (val & 0x6) == 0x6, 100000); 3562031a123SJohnny Huang if (ret) 3572031a123SJohnny Huang printf("%s: timeout, SEC14 = 0x%x\n", __func__, val); 3582031a123SJohnny Huang 3592031a123SJohnny Huang return ret; 3603d3688adSJohnny Huang } 3613d3688adSJohnny Huang 362a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 363dacbba92SJohnny Huang { 364dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 365dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 366dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 367dacbba92SJohnny Huang wait_complete(); 368dacbba92SJohnny Huang } 369dacbba92SJohnny Huang 370dacbba92SJohnny Huang static void otp_soak(int soak) 371dacbba92SJohnny Huang { 372e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) { 373dacbba92SJohnny Huang switch (soak) { 374dacbba92SJohnny Huang case 0: //default 375377f8cd7SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 376377f8cd7SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 377dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 378dacbba92SJohnny Huang break; 379dacbba92SJohnny Huang case 1: //normal program 380377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 381377f8cd7SJohnny Huang otp_write(0x5000, 0x1008); // Write MRB 382377f8cd7SJohnny Huang otp_write(0x1000, 0x0024); // Write MR 383feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 384dacbba92SJohnny Huang break; 385dacbba92SJohnny Huang case 2: //soak program 386377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 387377f8cd7SJohnny Huang otp_write(0x5000, 0x0007); // Write MRB 388377f8cd7SJohnny Huang otp_write(0x1000, 0x0100); // Write MR 389feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 390dacbba92SJohnny Huang break; 391dacbba92SJohnny Huang } 392dacbba92SJohnny Huang } else { 393dacbba92SJohnny Huang switch (soak) { 394dacbba92SJohnny Huang case 0: //default 395dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 396dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 397dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 398dacbba92SJohnny Huang break; 399dacbba92SJohnny Huang case 1: //normal program 400dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 401dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 402dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 403feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 404dacbba92SJohnny Huang break; 405dacbba92SJohnny Huang case 2: //soak program 406dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 407dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 408dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 409feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 410dacbba92SJohnny Huang break; 411dacbba92SJohnny Huang } 412dacbba92SJohnny Huang } 413dacbba92SJohnny Huang 414dacbba92SJohnny Huang wait_complete(); 415dacbba92SJohnny Huang } 416dacbba92SJohnny Huang 417a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 41869d5fd8fSJohnny Huang { 4193d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 4203d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4213d3688adSJohnny Huang wait_complete(); 4223d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 4233d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 42469d5fd8fSJohnny Huang } 42569d5fd8fSJohnny Huang 426f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data) 42769d5fd8fSJohnny Huang { 42869d5fd8fSJohnny Huang int config_offset; 42969d5fd8fSJohnny Huang 43069d5fd8fSJohnny Huang config_offset = 0x800; 43169d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 43269d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 43369d5fd8fSJohnny Huang 4343d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 4353d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4363d3688adSJohnny Huang wait_complete(); 4373d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 43869d5fd8fSJohnny Huang } 43969d5fd8fSJohnny Huang 440a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 44169d5fd8fSJohnny Huang { 442a219f6deSJohnny Huang u32 ret; 443a219f6deSJohnny Huang u32 *buf; 44469d5fd8fSJohnny Huang 44569d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 44669d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 44769d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 44869d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 44969d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 4503d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 4513d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 4523d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 4533d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 4543d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 4553d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 4563d3688adSJohnny Huang wait_complete(); 4573d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 45869d5fd8fSJohnny Huang if (ret & 0x1) 459f347c284SJohnny Huang return OTP_SUCCESS; 46069d5fd8fSJohnny Huang else 461f347c284SJohnny Huang return OTP_FAILURE; 46269d5fd8fSJohnny Huang } 46369d5fd8fSJohnny Huang 464a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 46569d5fd8fSJohnny Huang { 466a219f6deSJohnny Huang u32 ret[2]; 46769d5fd8fSJohnny Huang 46830a8c590SJohnny Huang if (otp_addr % 2 == 0) 4693d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 47030a8c590SJohnny Huang else 4713d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 47230a8c590SJohnny Huang 4733d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4743d3688adSJohnny Huang wait_complete(); 4753d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4763d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 47783655e91SJohnny Huang 47830a8c590SJohnny Huang if (otp_addr % 2 == 0) { 47930a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 480f347c284SJohnny Huang return OTP_SUCCESS; 48169d5fd8fSJohnny Huang else 482f347c284SJohnny Huang return OTP_FAILURE; 48330a8c590SJohnny Huang } else { 48430a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 485f347c284SJohnny Huang return OTP_SUCCESS; 48630a8c590SJohnny Huang else 487f347c284SJohnny Huang return OTP_FAILURE; 48830a8c590SJohnny Huang } 48969d5fd8fSJohnny Huang } 49069d5fd8fSJohnny Huang 491a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 4924c1c9b35SJohnny Huang { 493a219f6deSJohnny Huang u32 ret[2]; 4944c1c9b35SJohnny Huang 4954c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 4964c1c9b35SJohnny Huang 4974c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 4983d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 4994c1c9b35SJohnny Huang else 5003d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 5013d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 5023d3688adSJohnny Huang wait_complete(); 5033d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 5043d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 5054c1c9b35SJohnny Huang if (size == 1) { 5064c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 5074c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 508696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 5094c1c9b35SJohnny Huang compare[0] = 0; 510f347c284SJohnny Huang return OTP_SUCCESS; 511a219f6deSJohnny Huang } 5124c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 513f347c284SJohnny Huang return OTP_FAILURE; 5144c1c9b35SJohnny Huang 5154c1c9b35SJohnny Huang } else { 5164c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 517696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 5184c1c9b35SJohnny Huang compare[0] = ~0; 519f347c284SJohnny Huang return OTP_SUCCESS; 520a219f6deSJohnny Huang } 521d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 522f347c284SJohnny Huang return OTP_FAILURE; 5234c1c9b35SJohnny Huang } 5244c1c9b35SJohnny Huang } else if (size == 2) { 5254c1c9b35SJohnny Huang // otp_addr should be even 526696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 5274c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 5284c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 5294c1c9b35SJohnny Huang compare[0] = 0; 5304c1c9b35SJohnny Huang compare[1] = ~0; 531f347c284SJohnny Huang return OTP_SUCCESS; 532a219f6deSJohnny Huang } 5334c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 5344c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 5354c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 5364c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 537f347c284SJohnny Huang return OTP_FAILURE; 5384c1c9b35SJohnny Huang } else { 539f347c284SJohnny Huang return OTP_FAILURE; 5404c1c9b35SJohnny Huang } 5414c1c9b35SJohnny Huang } 5424c1c9b35SJohnny Huang 5432031a123SJohnny Huang static int otp_prog(u32 otp_addr, u32 prog_bit) 54483655e91SJohnny Huang { 54590965bb3SJohnny Huang otp_write(0x0, prog_bit); 54683655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 54783655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 54883655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 5492031a123SJohnny Huang 5502031a123SJohnny Huang return wait_complete(); 55183655e91SJohnny Huang } 55283655e91SJohnny Huang 5532031a123SJohnny Huang static int _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 55483655e91SJohnny Huang { 55583655e91SJohnny Huang int prog_bit; 55683655e91SJohnny Huang 55783655e91SJohnny Huang if (prog_address % 2 == 0) { 55883655e91SJohnny Huang if (value) 55983655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 56083655e91SJohnny Huang else 5612031a123SJohnny Huang return 0; 56283655e91SJohnny Huang } else { 563e417205bSJohnny Huang if (info_cb.version != OTP_A3) 56483655e91SJohnny Huang prog_address |= 1 << 15; 56583655e91SJohnny Huang if (!value) 56683655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 56783655e91SJohnny Huang else 5682031a123SJohnny Huang return 0; 56983655e91SJohnny Huang } 5702031a123SJohnny Huang return otp_prog(prog_address, prog_bit); 57183655e91SJohnny Huang } 57283655e91SJohnny Huang 573f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset) 57483655e91SJohnny Huang { 57583655e91SJohnny Huang int pass; 57683655e91SJohnny Huang int i; 5772031a123SJohnny Huang int ret; 57883655e91SJohnny Huang 57983655e91SJohnny Huang otp_soak(1); 5802031a123SJohnny Huang ret = _otp_prog_bit(value, prog_address, bit_offset); 5812031a123SJohnny Huang if (ret) 5822031a123SJohnny Huang return OTP_FAILURE; 58383655e91SJohnny Huang pass = 0; 58483655e91SJohnny Huang 58583655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 58683655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 58783655e91SJohnny Huang otp_soak(2); 5882031a123SJohnny Huang ret = _otp_prog_bit(value, prog_address, bit_offset); 5892031a123SJohnny Huang if (ret) 5902031a123SJohnny Huang return OTP_FAILURE; 59183655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 59283655e91SJohnny Huang otp_soak(1); 59383655e91SJohnny Huang } else { 59483655e91SJohnny Huang pass = 1; 59583655e91SJohnny Huang break; 59683655e91SJohnny Huang } 59783655e91SJohnny Huang } else { 59883655e91SJohnny Huang pass = 1; 59983655e91SJohnny Huang break; 60083655e91SJohnny Huang } 60183655e91SJohnny Huang } 602794e27ecSJohnny Huang if (pass) 603794e27ecSJohnny Huang return OTP_SUCCESS; 60483655e91SJohnny Huang 605794e27ecSJohnny Huang return OTP_FAILURE; 60683655e91SJohnny Huang } 60783655e91SJohnny Huang 6082031a123SJohnny Huang static int otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 609d90825e2SJohnny Huang { 610d90825e2SJohnny Huang int j, bit_value, prog_bit; 6112031a123SJohnny Huang int ret; 612d90825e2SJohnny Huang 613d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 614696656c6SJohnny Huang if ((ignore >> j) & 0x1) 615d90825e2SJohnny Huang continue; 616d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 617d90825e2SJohnny Huang if (prog_address % 2 == 0) { 618d90825e2SJohnny Huang if (bit_value) 619d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 620d90825e2SJohnny Huang else 621d90825e2SJohnny Huang continue; 622d90825e2SJohnny Huang } else { 623e417205bSJohnny Huang if (info_cb.version != OTP_A3) 624d90825e2SJohnny Huang prog_address |= 1 << 15; 625d90825e2SJohnny Huang if (bit_value) 626d90825e2SJohnny Huang continue; 627d90825e2SJohnny Huang else 628d90825e2SJohnny Huang prog_bit = 0x1 << j; 629d90825e2SJohnny Huang } 6302031a123SJohnny Huang ret = otp_prog(prog_address, prog_bit); 6312031a123SJohnny Huang if (ret) 6322031a123SJohnny Huang return ret; 633d90825e2SJohnny Huang } 6342031a123SJohnny Huang return 0; 635d90825e2SJohnny Huang } 636d90825e2SJohnny Huang 637a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 63854552c69SJohnny Huang { 63954552c69SJohnny Huang int pass; 64054552c69SJohnny Huang int i; 641a219f6deSJohnny Huang u32 data0_masked; 642a219f6deSJohnny Huang u32 data1_masked; 643a219f6deSJohnny Huang u32 buf0_masked; 644a219f6deSJohnny Huang u32 buf1_masked; 645a219f6deSJohnny Huang u32 compare[2]; 6462031a123SJohnny Huang int ret; 64754552c69SJohnny Huang 64854552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 64954552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 65054552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 65154552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 652a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 653f347c284SJohnny Huang return OTP_SUCCESS; 65454552c69SJohnny Huang 655b64ca396SJohnny Huang for (i = 0; i < 32; i++) { 656b64ca396SJohnny Huang if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0) 657b64ca396SJohnny Huang return OTP_FAILURE; 658b64ca396SJohnny Huang if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1) 659b64ca396SJohnny Huang return OTP_FAILURE; 660b64ca396SJohnny Huang } 661b64ca396SJohnny Huang 66254552c69SJohnny Huang otp_soak(1); 6632031a123SJohnny Huang if (data0_masked != buf0_masked) { 6642031a123SJohnny Huang ret = otp_prog_dw(buf[0], ignore_mask[0], prog_address); 6652031a123SJohnny Huang if (ret) 6662031a123SJohnny Huang return OTP_FAILURE; 6672031a123SJohnny Huang } 6682031a123SJohnny Huang 6692031a123SJohnny Huang if (data1_masked != buf1_masked) { 6702031a123SJohnny Huang ret = otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 6712031a123SJohnny Huang if (ret) 6722031a123SJohnny Huang return OTP_FAILURE; 6732031a123SJohnny Huang } 67454552c69SJohnny Huang 67554552c69SJohnny Huang pass = 0; 67654552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 67754552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 67854552c69SJohnny Huang otp_soak(2); 6792031a123SJohnny Huang if (compare[0] != 0) { 6802031a123SJohnny Huang ret = otp_prog_dw(compare[0], ignore_mask[0], prog_address); 6812031a123SJohnny Huang if (ret) 6822031a123SJohnny Huang return OTP_FAILURE; 6832031a123SJohnny Huang } 6842031a123SJohnny Huang if (compare[1] != ~0) { 6852031a123SJohnny Huang ret = otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 6862031a123SJohnny Huang if (ret) 6872031a123SJohnny Huang return OTP_FAILURE; 6882031a123SJohnny Huang } 68954552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 69054552c69SJohnny Huang otp_soak(1); 69154552c69SJohnny Huang } else { 69254552c69SJohnny Huang pass = 1; 69354552c69SJohnny Huang break; 69454552c69SJohnny Huang } 69554552c69SJohnny Huang } else { 69654552c69SJohnny Huang pass = 1; 69754552c69SJohnny Huang break; 69854552c69SJohnny Huang } 69954552c69SJohnny Huang } 70054552c69SJohnny Huang 70154552c69SJohnny Huang if (!pass) { 70254552c69SJohnny Huang otp_soak(0); 70354552c69SJohnny Huang return OTP_FAILURE; 70454552c69SJohnny Huang } 70554552c69SJohnny Huang return OTP_SUCCESS; 70654552c69SJohnny Huang } 70754552c69SJohnny Huang 708541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 70976d13988SJohnny Huang { 710a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 7115010032bSJohnny Huang int strap_end; 71276d13988SJohnny Huang int i, j; 71376d13988SJohnny Huang 714e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 71576d13988SJohnny Huang for (j = 0; j < 64; j++) { 71676d13988SJohnny Huang otpstrap[j].value = 0; 71776d13988SJohnny Huang otpstrap[j].remain_times = 7; 71876d13988SJohnny Huang otpstrap[j].writeable_option = -1; 71976d13988SJohnny Huang otpstrap[j].protected = 0; 72076d13988SJohnny Huang } 7215010032bSJohnny Huang strap_end = 30; 7225010032bSJohnny Huang } else { 7235010032bSJohnny Huang for (j = 0; j < 64; j++) { 7245010032bSJohnny Huang otpstrap[j].value = 0; 7255010032bSJohnny Huang otpstrap[j].remain_times = 6; 7265010032bSJohnny Huang otpstrap[j].writeable_option = -1; 7275010032bSJohnny Huang otpstrap[j].protected = 0; 7285010032bSJohnny Huang } 7295010032bSJohnny Huang strap_end = 28; 7305010032bSJohnny Huang } 73176d13988SJohnny Huang 732dacbba92SJohnny Huang otp_soak(0); 7335010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 73476d13988SJohnny Huang int option = (i - 16) / 2; 735a219f6deSJohnny Huang 736f347c284SJohnny Huang otp_read_conf(i, &OTPSTRAP_RAW[0]); 737f347c284SJohnny Huang otp_read_conf(i + 1, &OTPSTRAP_RAW[1]); 73876d13988SJohnny Huang for (j = 0; j < 32; j++) { 73976d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 740a219f6deSJohnny Huang 741a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 74276d13988SJohnny Huang otpstrap[j].writeable_option = option; 74376d13988SJohnny Huang if (bit_value == 1) 74476d13988SJohnny Huang otpstrap[j].remain_times--; 74576d13988SJohnny Huang otpstrap[j].value ^= bit_value; 74676d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 74776d13988SJohnny Huang } 74876d13988SJohnny Huang for (j = 32; j < 64; j++) { 74976d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 750a219f6deSJohnny Huang 751a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 75276d13988SJohnny Huang otpstrap[j].writeable_option = option; 75376d13988SJohnny Huang if (bit_value == 1) 75476d13988SJohnny Huang otpstrap[j].remain_times--; 75576d13988SJohnny Huang otpstrap[j].value ^= bit_value; 75676d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 75776d13988SJohnny Huang } 75876d13988SJohnny Huang } 7595010032bSJohnny Huang 760f347c284SJohnny Huang otp_read_conf(30, &OTPSTRAP_RAW[0]); 761f347c284SJohnny Huang otp_read_conf(31, &OTPSTRAP_RAW[1]); 76276d13988SJohnny Huang for (j = 0; j < 32; j++) { 76376d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 76476d13988SJohnny Huang otpstrap[j].protected = 1; 76576d13988SJohnny Huang } 76676d13988SJohnny Huang for (j = 32; j < 64; j++) { 76776d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 76876d13988SJohnny Huang otpstrap[j].protected = 1; 76976d13988SJohnny Huang } 77076d13988SJohnny Huang } 77176d13988SJohnny Huang 7727e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit) 773f347c284SJohnny Huang { 774f347c284SJohnny Huang int prog_flag = 0; 775f347c284SJohnny Huang 776f347c284SJohnny Huang // ignore this bit 777f347c284SJohnny Huang if (ibit == 1) 778f347c284SJohnny Huang return OTP_SUCCESS; 779b489486eSJohnny Huang printf("OTPSTRAP[0x%X]:\n", offset); 780f347c284SJohnny Huang 781f347c284SJohnny Huang if (bit == otpstrap->value) { 7827e523e3bSJohnny Huang if (!pbit) { 783f347c284SJohnny Huang printf(" The value is same as before, skip it.\n"); 784f347c284SJohnny Huang return OTP_PROG_SKIP; 785f347c284SJohnny Huang } 786f347c284SJohnny Huang printf(" The value is same as before.\n"); 787f347c284SJohnny Huang } else { 788f347c284SJohnny Huang prog_flag = 1; 789f347c284SJohnny Huang } 790f347c284SJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 791f347c284SJohnny Huang printf(" This bit is protected and is not writable\n"); 792f347c284SJohnny Huang return OTP_FAILURE; 793f347c284SJohnny Huang } 794f347c284SJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 795b489486eSJohnny Huang printf(" This bit has no remaining chance to write.\n"); 796f347c284SJohnny Huang return OTP_FAILURE; 797f347c284SJohnny Huang } 798f347c284SJohnny Huang if (pbit == 1) 799f347c284SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 800f347c284SJohnny Huang if (prog_flag) 801b489486eSJohnny 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); 802f347c284SJohnny Huang 803f347c284SJohnny Huang return OTP_SUCCESS; 804f347c284SJohnny Huang } 805f347c284SJohnny Huang 806f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value) 807f347c284SJohnny Huang { 808f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 809f347c284SJohnny Huang u32 prog_address; 810f347c284SJohnny Huang int offset; 811f347c284SJohnny Huang int ret; 812f347c284SJohnny Huang 813f347c284SJohnny Huang otp_strap_status(otpstrap); 814f347c284SJohnny Huang 8157e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 816f347c284SJohnny Huang 817f347c284SJohnny Huang if (ret != OTP_SUCCESS) 818f347c284SJohnny Huang return ret; 819f347c284SJohnny Huang 820f347c284SJohnny Huang prog_address = 0x800; 821f347c284SJohnny Huang if (bit_offset < 32) { 822f347c284SJohnny Huang offset = bit_offset; 823f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 824f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 825f347c284SJohnny Huang 826f347c284SJohnny Huang } else { 827f347c284SJohnny Huang offset = (bit_offset - 32); 828f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 829f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 830f347c284SJohnny Huang } 831f347c284SJohnny Huang 832f347c284SJohnny Huang return otp_prog_dc_b(1, prog_address, offset); 833f347c284SJohnny Huang } 834f347c284SJohnny Huang 835f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count) 836f347c284SJohnny Huang { 837f347c284SJohnny Huang int i; 838f347c284SJohnny Huang u32 ret[1]; 839f347c284SJohnny Huang 840f347c284SJohnny Huang if (offset + dw_count > 32) 841f347c284SJohnny Huang return OTP_USAGE; 842f347c284SJohnny Huang otp_soak(0); 843f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i++) { 844f347c284SJohnny Huang otp_read_conf(i, ret); 845b489486eSJohnny Huang printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]); 846f347c284SJohnny Huang } 847f347c284SJohnny Huang printf("\n"); 848f347c284SJohnny Huang return OTP_SUCCESS; 849f347c284SJohnny Huang } 850f347c284SJohnny Huang 851f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count) 852f347c284SJohnny Huang { 853f347c284SJohnny Huang int i; 854f347c284SJohnny Huang u32 ret[2]; 855f347c284SJohnny Huang 856f347c284SJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 857f347c284SJohnny Huang return OTP_USAGE; 858f347c284SJohnny Huang otp_soak(0); 859f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 860f347c284SJohnny Huang otp_read_data(i, ret); 861f347c284SJohnny Huang if (i % 4 == 0) 862f347c284SJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 863f347c284SJohnny Huang else 864f347c284SJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 865f347c284SJohnny Huang } 866f347c284SJohnny Huang printf("\n"); 867f347c284SJohnny Huang return OTP_SUCCESS; 868f347c284SJohnny Huang } 869f347c284SJohnny Huang 870f347c284SJohnny Huang static int otp_print_strap(int start, int count) 871f347c284SJohnny Huang { 872f347c284SJohnny Huang int i, j; 873f347c284SJohnny Huang int remains; 874f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 875f347c284SJohnny Huang 876f347c284SJohnny Huang if (start < 0 || start > 64) 877f347c284SJohnny Huang return OTP_USAGE; 878f347c284SJohnny Huang 879f347c284SJohnny Huang if ((start + count) < 0 || (start + count) > 64) 880f347c284SJohnny Huang return OTP_USAGE; 881f347c284SJohnny Huang 882f347c284SJohnny Huang otp_strap_status(otpstrap); 883f347c284SJohnny Huang 8847e523e3bSJohnny Huang if (info_cb.version == OTP_A0) 885f347c284SJohnny Huang remains = 7; 8867e523e3bSJohnny Huang else 887f347c284SJohnny Huang remains = 6; 8887e523e3bSJohnny Huang printf("BIT(hex) Value Option Status\n"); 889f347c284SJohnny Huang printf("______________________________________________________________________________\n"); 890f347c284SJohnny Huang 891f347c284SJohnny Huang for (i = start; i < start + count; i++) { 892f347c284SJohnny Huang printf("0x%-8X", i); 893f347c284SJohnny Huang printf("%-7d", otpstrap[i].value); 894f347c284SJohnny Huang for (j = 0; j < remains; j++) 895f347c284SJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 896f347c284SJohnny Huang printf(" "); 897f347c284SJohnny Huang if (otpstrap[i].protected == 1) { 898f347c284SJohnny Huang printf("protected and not writable"); 899f347c284SJohnny Huang } else { 900f347c284SJohnny Huang printf("not protected "); 901f347c284SJohnny Huang if (otpstrap[i].remain_times == 0) 902f347c284SJohnny Huang printf("and no remaining times to write."); 903f347c284SJohnny Huang else 904f347c284SJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 905f347c284SJohnny Huang } 906f347c284SJohnny Huang printf("\n"); 907f347c284SJohnny Huang } 908f347c284SJohnny Huang 909f347c284SJohnny Huang return OTP_SUCCESS; 910f347c284SJohnny Huang } 911f347c284SJohnny Huang 912794e27ecSJohnny Huang static void otp_print_revid(u32 *rid) 913794e27ecSJohnny Huang { 914794e27ecSJohnny Huang int bit_offset; 915794e27ecSJohnny Huang int i, j; 916794e27ecSJohnny Huang 917794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 918794e27ecSJohnny Huang printf("___________________________________________________\n"); 919794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 920794e27ecSJohnny Huang if (i < 32) { 921794e27ecSJohnny Huang j = 0; 922794e27ecSJohnny Huang bit_offset = i; 923794e27ecSJohnny Huang } else { 924794e27ecSJohnny Huang j = 1; 925794e27ecSJohnny Huang bit_offset = i - 32; 926794e27ecSJohnny Huang } 927794e27ecSJohnny Huang if (i % 16 == 0) 928794e27ecSJohnny Huang printf("%2x | ", i); 929794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1); 930794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 931794e27ecSJohnny Huang printf("\n"); 932794e27ecSJohnny Huang } 933794e27ecSJohnny Huang } 934794e27ecSJohnny Huang 935b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout) 936b25f02d2SJohnny Huang { 937b25f02d2SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 938b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 939b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 940b25f02d2SJohnny Huang int i; 941b25f02d2SJohnny Huang u32 scu_offset; 942b25f02d2SJohnny Huang u32 dw_offset; 943b25f02d2SJohnny Huang u32 bit_offset; 944b25f02d2SJohnny Huang u32 mask; 945b25f02d2SJohnny Huang u32 otp_value; 946b25f02d2SJohnny Huang u32 otp_ignore; 947b25f02d2SJohnny Huang 948b25f02d2SJohnny Huang printf("SCU BIT reg_protect Description\n"); 949b25f02d2SJohnny Huang printf("____________________________________________________________________\n"); 950b25f02d2SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 951b25f02d2SJohnny Huang mask = BIT(scu_info[i].length) - 1; 952b25f02d2SJohnny Huang 953b25f02d2SJohnny Huang if (scu_info[i].bit_offset > 31) { 954b25f02d2SJohnny Huang scu_offset = 0x510; 955b25f02d2SJohnny Huang dw_offset = 1; 956b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset - 32; 957b25f02d2SJohnny Huang } else { 958b25f02d2SJohnny Huang scu_offset = 0x500; 959b25f02d2SJohnny Huang dw_offset = 0; 960b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset; 961b25f02d2SJohnny Huang } 962b25f02d2SJohnny Huang 963b25f02d2SJohnny Huang otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask; 964b25f02d2SJohnny Huang otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask; 965b25f02d2SJohnny Huang 966b25f02d2SJohnny Huang if (otp_ignore == mask) 967b25f02d2SJohnny Huang continue; 968b25f02d2SJohnny Huang else if (otp_ignore != 0) 969b25f02d2SJohnny Huang return OTP_FAILURE; 970b25f02d2SJohnny Huang 971b25f02d2SJohnny Huang if (otp_value != 0 && otp_value != mask) 972b25f02d2SJohnny Huang return OTP_FAILURE; 973b25f02d2SJohnny Huang 974b25f02d2SJohnny Huang printf("0x%-6X", scu_offset); 975b25f02d2SJohnny Huang if (scu_info[i].length == 1) 976b25f02d2SJohnny Huang printf("0x%-11X", bit_offset); 977b25f02d2SJohnny Huang else 9782131c250SJohnny Huang printf("0x%-2X:0x%-6x", bit_offset, bit_offset + scu_info[i].length - 1); 979b25f02d2SJohnny Huang printf("0x%-14X", otp_value); 980b25f02d2SJohnny Huang printf("%s\n", scu_info[i].information); 981b25f02d2SJohnny Huang } 982b25f02d2SJohnny Huang return OTP_SUCCESS; 983b25f02d2SJohnny Huang } 984b25f02d2SJohnny Huang 9850dc9a440SJohnny Huang static void otp_print_scu_info(void) 9860dc9a440SJohnny Huang { 9870dc9a440SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 9880dc9a440SJohnny Huang u32 OTPCFG[2]; 9890dc9a440SJohnny Huang u32 scu_offset; 9900dc9a440SJohnny Huang u32 bit_offset; 9910dc9a440SJohnny Huang u32 reg_p; 9920dc9a440SJohnny Huang u32 length; 9930dc9a440SJohnny Huang int i, j; 9940dc9a440SJohnny Huang 9950dc9a440SJohnny Huang otp_soak(0); 9960dc9a440SJohnny Huang otp_read_conf(28, &OTPCFG[0]); 9970dc9a440SJohnny Huang otp_read_conf(29, &OTPCFG[1]); 9980dc9a440SJohnny Huang printf("SCU BIT reg_protect Description\n"); 9990dc9a440SJohnny Huang printf("____________________________________________________________________\n"); 10000dc9a440SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 10010dc9a440SJohnny Huang length = scu_info[i].length; 10020dc9a440SJohnny Huang for (j = 0; j < length; j++) { 10030dc9a440SJohnny Huang if (scu_info[i].bit_offset + j < 32) { 10040dc9a440SJohnny Huang scu_offset = 0x500; 10050dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j; 10060dc9a440SJohnny Huang reg_p = (OTPCFG[0] >> bit_offset) & 0x1; 10070dc9a440SJohnny Huang } else { 10080dc9a440SJohnny Huang scu_offset = 0x510; 10090dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j - 32; 10100dc9a440SJohnny Huang reg_p = (OTPCFG[1] >> bit_offset) & 0x1; 10110dc9a440SJohnny Huang } 10120dc9a440SJohnny Huang printf("0x%-6X", scu_offset); 10130dc9a440SJohnny Huang printf("0x%-4X", bit_offset); 10140dc9a440SJohnny Huang printf("0x%-13X", reg_p); 10150dc9a440SJohnny Huang if (length == 1) { 10160dc9a440SJohnny Huang printf(" %s\n", scu_info[i].information); 10170dc9a440SJohnny Huang continue; 10180dc9a440SJohnny Huang } 10190dc9a440SJohnny Huang 10200dc9a440SJohnny Huang if (j == 0) 10210dc9a440SJohnny Huang printf("/%s\n", scu_info[i].information); 10220dc9a440SJohnny Huang else if (j == length - 1) 10230dc9a440SJohnny Huang printf("\\ \"\n"); 10240dc9a440SJohnny Huang else 10250dc9a440SJohnny Huang printf("| \"\n"); 10260dc9a440SJohnny Huang } 10270dc9a440SJohnny Huang } 10280dc9a440SJohnny Huang } 10290dc9a440SJohnny Huang 1030696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 103169d5fd8fSJohnny Huang { 103279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1033a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 1034a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 1035a219f6deSJohnny Huang u32 mask; 1036a219f6deSJohnny Huang u32 dw_offset; 1037a219f6deSJohnny Huang u32 bit_offset; 1038a219f6deSJohnny Huang u32 otp_value; 1039a219f6deSJohnny Huang u32 otp_ignore; 1040b458cd62SJohnny Huang int fail = 0; 10417adec5f6SJohnny Huang int mask_err; 1042794e27ecSJohnny Huang int rid_num = 0; 104373f11549SJohnny Huang char valid_bit[20]; 1044794e27ecSJohnny Huang int fz; 104566f2f8e5SJohnny Huang int i; 104673f11549SJohnny Huang int j; 104766f2f8e5SJohnny Huang 1048737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 104966f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 10503cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 10517adec5f6SJohnny Huang mask_err = 0; 10523cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 10533cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 10543cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1055b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1056696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 1057b458cd62SJohnny Huang 10587adec5f6SJohnny Huang if (conf_info[i].value == OTP_REG_VALID_BIT) { 10597adec5f6SJohnny Huang if (((otp_value + otp_ignore) & mask) != mask) { 1060b458cd62SJohnny Huang fail = 1; 10617adec5f6SJohnny Huang mask_err = 1; 10627adec5f6SJohnny Huang } 10637adec5f6SJohnny Huang } else { 10647adec5f6SJohnny Huang if (otp_ignore == mask) { 10657adec5f6SJohnny Huang continue; 10667adec5f6SJohnny Huang } else if (otp_ignore != 0) { 10677adec5f6SJohnny Huang fail = 1; 10687adec5f6SJohnny Huang mask_err = 1; 10697adec5f6SJohnny Huang } 10707adec5f6SJohnny Huang } 1071b458cd62SJohnny Huang 1072a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 10733cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 10743cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 10753cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1076b458cd62SJohnny Huang continue; 1077b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1078b458cd62SJohnny Huang 10793cb28812SJohnny Huang if (conf_info[i].length == 1) { 10803cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 108166f2f8e5SJohnny Huang } else { 1082b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 10833cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 10843cb28812SJohnny Huang conf_info[i].bit_offset); 108566f2f8e5SJohnny Huang } 1086b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1087b458cd62SJohnny Huang 10887adec5f6SJohnny Huang if (mask_err) { 10897adec5f6SJohnny Huang printf("Ignore, mask error\n"); 1090a219f6deSJohnny Huang continue; 1091a219f6deSJohnny Huang } 10923cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1093b458cd62SJohnny Huang printf("Reserved\n"); 10943cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 10953cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1096b458cd62SJohnny Huang printf("\n"); 10973cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1098b458cd62SJohnny Huang if (otp_value != 0) { 109973f11549SJohnny Huang for (j = 0; j < 7; j++) { 1100e2b82258SJohnny Huang if (otp_value & (1 << j)) 110173f11549SJohnny Huang valid_bit[j * 2] = '1'; 1102a219f6deSJohnny Huang else 110373f11549SJohnny Huang valid_bit[j * 2] = '0'; 110473f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 110573f11549SJohnny Huang } 110673f11549SJohnny Huang valid_bit[15] = 0; 110773f11549SJohnny Huang } else { 110873f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1109b458cd62SJohnny Huang } 11103cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1111b458cd62SJohnny Huang printf("\n"); 1112b458cd62SJohnny Huang } else { 11133cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1114b458cd62SJohnny Huang } 1115b458cd62SJohnny Huang } 1116b458cd62SJohnny Huang 1117794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) { 1118794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) { 1119794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1120794e27ecSJohnny Huang fail = 1; 1121794e27ecSJohnny Huang } else { 1122794e27ecSJohnny Huang fz = 0; 1123794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 1124794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) { 1125794e27ecSJohnny Huang if (!fz) 1126794e27ecSJohnny Huang fz = 1; 1127794e27ecSJohnny Huang } else { 1128794e27ecSJohnny Huang rid_num++; 1129794e27ecSJohnny Huang if (fz) { 1130794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1131794e27ecSJohnny Huang fail = 1; 1132794e27ecSJohnny Huang break; 1133794e27ecSJohnny Huang } 1134794e27ecSJohnny Huang } 1135794e27ecSJohnny Huang } 1136794e27ecSJohnny Huang } 1137794e27ecSJohnny Huang if (fail) 1138794e27ecSJohnny Huang printf("OTP revision ID\n"); 1139794e27ecSJohnny Huang else 1140794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1141794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]); 1142794e27ecSJohnny Huang } 1143794e27ecSJohnny Huang 1144b458cd62SJohnny Huang if (fail) 1145b458cd62SJohnny Huang return OTP_FAILURE; 1146b458cd62SJohnny Huang 114766f2f8e5SJohnny Huang return OTP_SUCCESS; 114866f2f8e5SJohnny Huang } 114966f2f8e5SJohnny Huang 11502d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 115166f2f8e5SJohnny Huang { 115279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1153a219f6deSJohnny Huang u32 OTPCFG[16]; 1154a219f6deSJohnny Huang u32 mask; 1155a219f6deSJohnny Huang u32 dw_offset; 1156a219f6deSJohnny Huang u32 bit_offset; 1157a219f6deSJohnny Huang u32 otp_value; 115873f11549SJohnny Huang char valid_bit[20]; 115966f2f8e5SJohnny Huang int i; 116073f11549SJohnny Huang int j; 116166f2f8e5SJohnny Huang 1162dacbba92SJohnny Huang otp_soak(0); 1163bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 1164f347c284SJohnny Huang otp_read_conf(i, &OTPCFG[i]); 116566f2f8e5SJohnny Huang 1166b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 1167b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 11683cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 11693cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 11702d4b0742SJohnny Huang continue; 11713cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 11723cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 11733cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1174b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1175b458cd62SJohnny Huang 1176a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 11773cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 11783cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 11793cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1180b458cd62SJohnny Huang continue; 1181b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1182b458cd62SJohnny Huang 11833cb28812SJohnny Huang if (conf_info[i].length == 1) { 11843cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 1185b458cd62SJohnny Huang } else { 1186b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 11873cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 11883cb28812SJohnny Huang conf_info[i].bit_offset); 1189b458cd62SJohnny Huang } 1190b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1191b458cd62SJohnny Huang 11923cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1193b458cd62SJohnny Huang printf("Reserved\n"); 11943cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 11953cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1196b458cd62SJohnny Huang printf("\n"); 11973cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1198b458cd62SJohnny Huang if (otp_value != 0) { 119973f11549SJohnny Huang for (j = 0; j < 7; j++) { 1200030cb4a7SJohnny Huang if (otp_value & (1 << j)) 120173f11549SJohnny Huang valid_bit[j * 2] = '1'; 1202a219f6deSJohnny Huang else 120373f11549SJohnny Huang valid_bit[j * 2] = '0'; 120473f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 120573f11549SJohnny Huang } 120673f11549SJohnny Huang valid_bit[15] = 0; 120773f11549SJohnny Huang } else { 120873f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1209b458cd62SJohnny Huang } 12103cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1211b458cd62SJohnny Huang printf("\n"); 1212b458cd62SJohnny Huang } else { 12133cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1214b458cd62SJohnny Huang } 1215b458cd62SJohnny Huang } 1216b458cd62SJohnny Huang return OTP_SUCCESS; 121766f2f8e5SJohnny Huang } 121866f2f8e5SJohnny Huang 12195010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 122076d13988SJohnny Huang { 122179e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 1222a219f6deSJohnny Huang u32 *OTPSTRAP; 1223a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 1224a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 122576d13988SJohnny Huang int i; 1226a8bd6d8cSJohnny Huang int fail = 0; 1227a219f6deSJohnny Huang u32 bit_offset; 1228a219f6deSJohnny Huang u32 dw_offset; 1229a219f6deSJohnny Huang u32 mask; 1230a219f6deSJohnny Huang u32 otp_value; 1231a219f6deSJohnny Huang u32 otp_protect; 1232a219f6deSJohnny Huang u32 otp_ignore; 123376d13988SJohnny Huang 1234a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 1235a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 1236a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 12377e523e3bSJohnny Huang 1238a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 1239de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 1240b458cd62SJohnny Huang 12413cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 12427adec5f6SJohnny Huang fail = 0; 1243696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 1244a8bd6d8cSJohnny Huang dw_offset = 1; 12453cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 1246a8bd6d8cSJohnny Huang } else { 1247a8bd6d8cSJohnny Huang dw_offset = 0; 12483cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 1249a8bd6d8cSJohnny Huang } 125076d13988SJohnny Huang 12513cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 1252a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 1253a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 1254696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 1255a8bd6d8cSJohnny Huang 1256a219f6deSJohnny Huang if (otp_ignore == mask) 1257a8bd6d8cSJohnny Huang continue; 1258a219f6deSJohnny Huang else if (otp_ignore != 0) 1259a8bd6d8cSJohnny Huang fail = 1; 1260a8bd6d8cSJohnny Huang 1261a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 12623cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1263a8bd6d8cSJohnny Huang continue; 1264a8bd6d8cSJohnny Huang 12653cb28812SJohnny Huang if (strap_info[i].length == 1) { 12663cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1267a8bd6d8cSJohnny Huang } else { 1268b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 12693cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 12703cb28812SJohnny Huang strap_info[i].bit_offset); 1271a8bd6d8cSJohnny Huang } 1272a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 1273a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 1274a8bd6d8cSJohnny Huang 1275a8bd6d8cSJohnny Huang if (fail) { 1276696656c6SJohnny Huang printf("Ignore mask error\n"); 1277a8bd6d8cSJohnny Huang } else { 12783cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12793cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1280a8bd6d8cSJohnny Huang else 1281a8bd6d8cSJohnny Huang printf("Reserved\n"); 1282a8bd6d8cSJohnny Huang } 1283a8bd6d8cSJohnny Huang } 1284a8bd6d8cSJohnny Huang 1285a8bd6d8cSJohnny Huang if (fail) 128676d13988SJohnny Huang return OTP_FAILURE; 128776d13988SJohnny Huang 128876d13988SJohnny Huang return OTP_SUCCESS; 128976d13988SJohnny Huang } 129076d13988SJohnny Huang 1291b458cd62SJohnny Huang static int otp_print_strap_info(int view) 129276d13988SJohnny Huang { 129379e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 129476d13988SJohnny Huang struct otpstrap_status strap_status[64]; 129507baa4e8SJohnny Huang int i, j; 1296b458cd62SJohnny Huang int fail = 0; 1297a219f6deSJohnny Huang u32 bit_offset; 1298a219f6deSJohnny Huang u32 length; 1299a219f6deSJohnny Huang u32 otp_value; 1300a219f6deSJohnny Huang u32 otp_protect; 130176d13988SJohnny Huang 1302541eb887SJohnny Huang otp_strap_status(strap_status); 130376d13988SJohnny Huang 1304b458cd62SJohnny Huang if (view) { 130507baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 130607baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 1307b458cd62SJohnny Huang } else { 1308b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 1309b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 131076d13988SJohnny Huang } 13113cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 1312b458cd62SJohnny Huang otp_value = 0; 13133cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 13143cb28812SJohnny Huang length = strap_info[i].length; 1315b458cd62SJohnny Huang for (j = 0; j < length; j++) { 1316c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 1317c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 1318b458cd62SJohnny Huang } 1319a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 13203cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1321b458cd62SJohnny Huang continue; 1322b458cd62SJohnny Huang if (view) { 1323b458cd62SJohnny Huang for (j = 0; j < length; j++) { 13243cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 1325b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 132607baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 1327e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 13283cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 1329b458cd62SJohnny Huang printf(" Reserved\n"); 1330b458cd62SJohnny Huang continue; 1331b458cd62SJohnny Huang } 1332b458cd62SJohnny Huang if (length == 1) { 13333cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 1334b458cd62SJohnny Huang continue; 133576d13988SJohnny Huang } 133676d13988SJohnny Huang 1337b458cd62SJohnny Huang if (j == 0) 13383cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 1339b458cd62SJohnny Huang else if (j == length - 1) 1340b458cd62SJohnny Huang printf("\\ \"\n"); 1341b458cd62SJohnny Huang else 1342b458cd62SJohnny Huang printf("| \"\n"); 134376d13988SJohnny Huang } 1344b458cd62SJohnny Huang } else { 1345c947ef08SJohnny Huang if (length == 1) { 13463cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1347b458cd62SJohnny Huang } else { 1348b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 1349b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 1350b458cd62SJohnny Huang } 1351b458cd62SJohnny Huang 1352b458cd62SJohnny Huang printf("0x%-10X", otp_value); 1353b458cd62SJohnny Huang 13543cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 13553cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1356b458cd62SJohnny Huang else 1357b458cd62SJohnny Huang printf("Reserved\n"); 1358b458cd62SJohnny Huang } 1359b458cd62SJohnny Huang } 1360b458cd62SJohnny Huang 1361b458cd62SJohnny Huang if (fail) 1362b458cd62SJohnny Huang return OTP_FAILURE; 1363b458cd62SJohnny Huang 1364b458cd62SJohnny Huang return OTP_SUCCESS; 1365b458cd62SJohnny Huang } 1366b458cd62SJohnny Huang 1367418822f0SJohnny Huang static void _otp_print_key(u32 header, u32 offset, u8 *data) 136869d5fd8fSJohnny Huang { 136988bd7d58SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 1370418822f0SJohnny Huang struct otpkey_type key_info; 1371418822f0SJohnny Huang int key_id, key_offset, key_type, key_length, exp_length; 137288bd7d58SJohnny Huang int len = 0; 1373418822f0SJohnny Huang int i; 137454552c69SJohnny Huang 1375418822f0SJohnny Huang key_id = header & 0x7; 1376418822f0SJohnny Huang key_offset = header & 0x1ff8; 1377418822f0SJohnny Huang key_type = (header >> 14) & 0xf; 1378418822f0SJohnny Huang key_length = (header >> 18) & 0x3; 1379418822f0SJohnny Huang exp_length = (header >> 20) & 0xfff; 13809d998018SJohnny Huang 1381418822f0SJohnny Huang printf("\nKey[%d]:\n", offset); 1382418822f0SJohnny Huang printf("Header: %x\n", header); 13839a4fe690SJohnny Huang 138488bd7d58SJohnny Huang key_info.value = -1; 1385418822f0SJohnny Huang for (i = 0; i < info_cb.key_info_len; i++) { 1386418822f0SJohnny Huang if (key_type == key_info_array[i].value) { 1387418822f0SJohnny Huang key_info = key_info_array[i]; 13889a4fe690SJohnny Huang break; 13899a4fe690SJohnny Huang } 13909a4fe690SJohnny Huang } 139188bd7d58SJohnny Huang if (key_info.value == -1) 1392418822f0SJohnny Huang return; 13939a4fe690SJohnny Huang 139469d5fd8fSJohnny Huang printf("Key Type: "); 13959a4fe690SJohnny Huang printf("%s\n", key_info.information); 13969a4fe690SJohnny Huang 13979a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 139869d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 139969d5fd8fSJohnny Huang switch (key_length) { 140069d5fd8fSJohnny Huang case 0: 140169d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 140269d5fd8fSJohnny Huang break; 140369d5fd8fSJohnny Huang case 1: 140469d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 140569d5fd8fSJohnny Huang break; 140669d5fd8fSJohnny Huang case 2: 140769d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 140869d5fd8fSJohnny Huang break; 140969d5fd8fSJohnny Huang case 3: 141069d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 141169d5fd8fSJohnny Huang break; 141269d5fd8fSJohnny Huang } 1413181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1414181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 141569d5fd8fSJohnny Huang printf("RSA SHA Type: "); 141669d5fd8fSJohnny Huang switch (key_length) { 141769d5fd8fSJohnny Huang case 0: 141869d5fd8fSJohnny Huang printf("RSA1024\n"); 141969d5fd8fSJohnny Huang len = 0x100; 142069d5fd8fSJohnny Huang break; 142169d5fd8fSJohnny Huang case 1: 142269d5fd8fSJohnny Huang printf("RSA2048\n"); 142369d5fd8fSJohnny Huang len = 0x200; 142469d5fd8fSJohnny Huang break; 142569d5fd8fSJohnny Huang case 2: 142669d5fd8fSJohnny Huang printf("RSA3072\n"); 142769d5fd8fSJohnny Huang len = 0x300; 142869d5fd8fSJohnny Huang break; 142969d5fd8fSJohnny Huang case 3: 143069d5fd8fSJohnny Huang printf("RSA4096\n"); 143169d5fd8fSJohnny Huang len = 0x400; 143269d5fd8fSJohnny Huang break; 143369d5fd8fSJohnny Huang } 143469d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 143569d5fd8fSJohnny Huang } 14369a4fe690SJohnny Huang if (key_info.need_id) 143769d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 1438418822f0SJohnny Huang if (!data) 1439418822f0SJohnny Huang return; 144069d5fd8fSJohnny Huang printf("Key Value:\n"); 14419a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 1442418822f0SJohnny Huang buf_print(&data[key_offset], 0x40); 14439a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 14449a4fe690SJohnny Huang printf("AES Key:\n"); 1445418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 1446e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 14479a4fe690SJohnny Huang printf("AES IV:\n"); 1448418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x10); 14499a4fe690SJohnny Huang } 14509a4fe690SJohnny Huang 14519a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1452e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 145369d5fd8fSJohnny Huang printf("AES Key:\n"); 1454418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 145569d5fd8fSJohnny Huang printf("AES IV:\n"); 1456418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x10); 14575fdde29fSJohnny Huang } else { 14589a4fe690SJohnny Huang printf("AES Key 1:\n"); 1459418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 14609a4fe690SJohnny Huang printf("AES Key 2:\n"); 1461418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x20); 14629a4fe690SJohnny Huang } 1463181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 146469d5fd8fSJohnny Huang printf("RSA mod:\n"); 1465418822f0SJohnny Huang buf_print(&data[key_offset], len / 2); 146669d5fd8fSJohnny Huang printf("RSA exp:\n"); 1467418822f0SJohnny Huang buf_print(&data[key_offset + (len / 2)], len / 2); 1468181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1469181f72d8SJohnny Huang printf("RSA mod:\n"); 1470418822f0SJohnny Huang buf_print(&data[key_offset], len / 2); 1471181f72d8SJohnny Huang printf("RSA exp:\n"); 1472a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 147369d5fd8fSJohnny Huang } 1474418822f0SJohnny Huang } 1475418822f0SJohnny Huang 1476418822f0SJohnny Huang static void otp_print_key(u32 *data) 1477418822f0SJohnny Huang { 1478418822f0SJohnny Huang int i; 1479418822f0SJohnny Huang int last; 1480418822f0SJohnny Huang u8 *byte_buf; 1481418822f0SJohnny Huang int empty; 1482418822f0SJohnny Huang 1483418822f0SJohnny Huang byte_buf = (u8 *)data; 1484418822f0SJohnny Huang 1485418822f0SJohnny Huang empty = 1; 1486418822f0SJohnny Huang for (i = 0; i < 16; i++) { 1487418822f0SJohnny Huang if (i % 2) { 1488418822f0SJohnny Huang if (data[i] != 0xffffffff) 1489418822f0SJohnny Huang empty = 0; 1490418822f0SJohnny Huang } else { 1491418822f0SJohnny Huang if (data[i] != 0) 1492418822f0SJohnny Huang empty = 0; 1493418822f0SJohnny Huang } 1494418822f0SJohnny Huang } 1495418822f0SJohnny Huang if (empty) { 1496418822f0SJohnny Huang printf("OTP data header is empty\n"); 1497418822f0SJohnny Huang return; 1498418822f0SJohnny Huang } 1499418822f0SJohnny Huang 1500418822f0SJohnny Huang for (i = 0; i < 16; i++) { 1501418822f0SJohnny Huang last = (data[i] >> 13) & 1; 1502418822f0SJohnny Huang _otp_print_key(data[i], i, byte_buf); 150369d5fd8fSJohnny Huang if (last) 150469d5fd8fSJohnny Huang break; 150569d5fd8fSJohnny Huang } 150688bd7d58SJohnny Huang } 150788bd7d58SJohnny Huang 150888bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 150988bd7d58SJohnny Huang { 151088bd7d58SJohnny Huang u32 *buf; 151188bd7d58SJohnny Huang 151288bd7d58SJohnny Huang buf = (u32 *)image_layout->data; 1513418822f0SJohnny Huang otp_print_key(buf); 151488bd7d58SJohnny Huang 1515f347c284SJohnny Huang return OTP_SUCCESS; 1516f347c284SJohnny Huang } 1517f347c284SJohnny Huang 151888bd7d58SJohnny Huang static void otp_print_key_info(void) 151988bd7d58SJohnny Huang { 152088bd7d58SJohnny Huang u32 data[2048]; 152188bd7d58SJohnny Huang int i; 152288bd7d58SJohnny Huang 152388bd7d58SJohnny Huang for (i = 0; i < 2048 ; i += 2) 152488bd7d58SJohnny Huang otp_read_data(i, &data[i]); 152588bd7d58SJohnny Huang 1526418822f0SJohnny Huang otp_print_key(data); 152788bd7d58SJohnny Huang } 152888bd7d58SJohnny Huang 1529b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data) 1530f347c284SJohnny Huang { 1531f347c284SJohnny Huang int i; 1532f347c284SJohnny Huang int ret; 1533f347c284SJohnny Huang u32 *buf; 1534f347c284SJohnny Huang u32 *buf_ignore; 1535f347c284SJohnny Huang 1536f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1537f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1538f347c284SJohnny Huang printf("Start Programing...\n"); 1539f347c284SJohnny Huang 1540f347c284SJohnny Huang // programing ecc region first 1541f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1542f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1543f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1544f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1545f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1546f347c284SJohnny Huang return ret; 1547f347c284SJohnny Huang } 1548f347c284SJohnny Huang } 1549f347c284SJohnny Huang 1550f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1551f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1552f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1553f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1554f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1555f347c284SJohnny Huang return ret; 1556f347c284SJohnny Huang } 1557f347c284SJohnny Huang } 1558f347c284SJohnny Huang otp_soak(0); 1559f347c284SJohnny Huang return OTP_SUCCESS; 1560f347c284SJohnny Huang } 1561f347c284SJohnny Huang 1562b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1563f347c284SJohnny Huang { 1564f347c284SJohnny Huang u32 *strap; 1565f347c284SJohnny Huang u32 *strap_ignore; 1566f347c284SJohnny Huang u32 *strap_pro; 1567f347c284SJohnny Huang u32 prog_address; 1568f347c284SJohnny Huang int i; 15697e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1570f347c284SJohnny Huang int fail = 0; 1571f347c284SJohnny Huang int ret; 1572f347c284SJohnny Huang int prog_flag = 0; 1573f347c284SJohnny Huang 1574f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1575f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1576f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1577f347c284SJohnny Huang 1578f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1579f347c284SJohnny Huang prog_address = 0x800; 1580f347c284SJohnny Huang if (i < 32) { 1581f347c284SJohnny Huang offset = i; 1582f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1583f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1584f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1585f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1586f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1587f347c284SJohnny Huang 1588f347c284SJohnny Huang } else { 1589f347c284SJohnny Huang offset = (i - 32); 1590f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1591f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1592f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1593f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1594f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1595f347c284SJohnny Huang } 1596f347c284SJohnny Huang 1597f347c284SJohnny Huang if (ibit == 1) 1598f347c284SJohnny Huang continue; 1599f347c284SJohnny Huang if (bit == otpstrap[i].value) 1600f347c284SJohnny Huang prog_flag = 0; 1601f347c284SJohnny Huang else 1602f347c284SJohnny Huang prog_flag = 1; 1603f347c284SJohnny Huang 1604f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1605f347c284SJohnny Huang fail = 1; 1606f347c284SJohnny Huang continue; 1607f347c284SJohnny Huang } 1608f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1609f347c284SJohnny Huang fail = 1; 1610f347c284SJohnny Huang continue; 1611f347c284SJohnny Huang } 1612f347c284SJohnny Huang 1613f347c284SJohnny Huang if (prog_flag) { 1614f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1615f347c284SJohnny Huang if (ret) 1616f347c284SJohnny Huang return OTP_FAILURE; 1617f347c284SJohnny Huang } 1618f347c284SJohnny Huang 1619f347c284SJohnny Huang if (pbit != 0) { 1620f347c284SJohnny Huang prog_address = 0x800; 1621f347c284SJohnny Huang if (i < 32) 1622f347c284SJohnny Huang prog_address |= 0x60c; 1623f347c284SJohnny Huang else 1624f347c284SJohnny Huang prog_address |= 0x60e; 1625f347c284SJohnny Huang 1626f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1627f347c284SJohnny Huang if (ret) 1628f347c284SJohnny Huang return OTP_FAILURE; 1629f347c284SJohnny Huang } 1630f347c284SJohnny Huang } 1631f347c284SJohnny Huang otp_soak(0); 1632f347c284SJohnny Huang if (fail == 1) 1633f347c284SJohnny Huang return OTP_FAILURE; 1634f347c284SJohnny Huang return OTP_SUCCESS; 163569d5fd8fSJohnny Huang } 163669d5fd8fSJohnny Huang 1637b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf) 163869d5fd8fSJohnny Huang { 1639a6d0d645SJohnny Huang int i, k; 1640d90825e2SJohnny Huang int pass = 0; 1641a219f6deSJohnny Huang u32 prog_address; 1642a219f6deSJohnny Huang u32 compare[2]; 1643a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1644a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1645a219f6deSJohnny Huang u32 data_masked; 1646a219f6deSJohnny Huang u32 buf_masked; 16472031a123SJohnny Huang int ret; 164869d5fd8fSJohnny Huang 1649a6d0d645SJohnny Huang printf("Start Programing...\n"); 1650d90825e2SJohnny Huang otp_soak(0); 1651bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 1652b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 16535010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1654a6d0d645SJohnny Huang prog_address = 0x800; 1655a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1656a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1657bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1658bb34a7bfSJohnny Huang pass = 1; 1659a6d0d645SJohnny Huang continue; 1660bb34a7bfSJohnny Huang } 1661de6fbf1cSJohnny Huang 1662de6fbf1cSJohnny Huang otp_soak(1); 16632031a123SJohnny Huang ret = otp_prog_dw(conf[i], conf_ignore[i], prog_address); 16642031a123SJohnny Huang if (ret) 16652031a123SJohnny Huang return OTP_FAILURE; 1666a6d0d645SJohnny Huang 166769d5fd8fSJohnny Huang pass = 0; 166869d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 16695010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1670de6fbf1cSJohnny Huang otp_soak(2); 16712031a123SJohnny Huang ret = otp_prog_dw(compare[0], conf_ignore[i], prog_address); 16722031a123SJohnny Huang if (ret) 16732031a123SJohnny Huang return OTP_FAILURE; 16745010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1675de6fbf1cSJohnny Huang otp_soak(1); 1676de6fbf1cSJohnny Huang } else { 1677de6fbf1cSJohnny Huang pass = 1; 1678de6fbf1cSJohnny Huang break; 1679de6fbf1cSJohnny Huang } 1680a6d0d645SJohnny Huang } else { 168169d5fd8fSJohnny Huang pass = 1; 168269d5fd8fSJohnny Huang break; 168369d5fd8fSJohnny Huang } 168469d5fd8fSJohnny Huang } 1685bb34a7bfSJohnny Huang if (pass == 0) { 1686b64ca396SJohnny Huang printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n", 1687b64ca396SJohnny Huang i, otp_conf[i], conf[i], conf_ignore[i]); 1688bb34a7bfSJohnny Huang break; 1689bb34a7bfSJohnny Huang } 1690a6d0d645SJohnny Huang } 1691a6d0d645SJohnny Huang 1692de6fbf1cSJohnny Huang otp_soak(0); 169369d5fd8fSJohnny Huang if (!pass) 16942a856b9aSJohnny Huang return OTP_FAILURE; 1695a6d0d645SJohnny Huang 16962a856b9aSJohnny Huang return OTP_SUCCESS; 169769d5fd8fSJohnny Huang } 169869d5fd8fSJohnny Huang 1699b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro) 1700b25f02d2SJohnny Huang { 1701b25f02d2SJohnny Huang int i, k; 1702b25f02d2SJohnny Huang int pass = 0; 1703b25f02d2SJohnny Huang u32 prog_address; 1704b25f02d2SJohnny Huang u32 compare[2]; 1705b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1706b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1707b25f02d2SJohnny Huang u32 data_masked; 1708b25f02d2SJohnny Huang u32 buf_masked; 17092031a123SJohnny Huang int ret; 1710b25f02d2SJohnny Huang 1711b25f02d2SJohnny Huang printf("Start Programing...\n"); 1712b25f02d2SJohnny Huang otp_soak(0); 1713b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1714b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1715b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1716b25f02d2SJohnny Huang prog_address = 0xe08 + i * 2; 1717b25f02d2SJohnny Huang if (data_masked == buf_masked) { 1718b25f02d2SJohnny Huang pass = 1; 1719b25f02d2SJohnny Huang continue; 1720b25f02d2SJohnny Huang } 1721b25f02d2SJohnny Huang 1722b25f02d2SJohnny Huang otp_soak(1); 17232031a123SJohnny Huang ret = otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address); 17242031a123SJohnny Huang if (ret) 17252031a123SJohnny Huang return OTP_FAILURE; 1726b25f02d2SJohnny Huang pass = 0; 1727b25f02d2SJohnny Huang for (k = 0; k < RETRY; k++) { 1728b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1729b25f02d2SJohnny Huang otp_soak(2); 17302031a123SJohnny Huang ret = otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address); 17312031a123SJohnny Huang if (ret) 17322031a123SJohnny Huang return OTP_FAILURE; 1733b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1734b25f02d2SJohnny Huang otp_soak(1); 1735b25f02d2SJohnny Huang } else { 1736b25f02d2SJohnny Huang pass = 1; 1737b25f02d2SJohnny Huang break; 1738b25f02d2SJohnny Huang } 1739b25f02d2SJohnny Huang } else { 1740b25f02d2SJohnny Huang pass = 1; 1741b25f02d2SJohnny Huang break; 1742b25f02d2SJohnny Huang } 1743b25f02d2SJohnny Huang } 1744b25f02d2SJohnny Huang if (pass == 0) { 1745b489486eSJohnny Huang printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n", 1746b25f02d2SJohnny Huang i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]); 1747b25f02d2SJohnny Huang break; 1748b25f02d2SJohnny Huang } 1749b25f02d2SJohnny Huang } 1750b25f02d2SJohnny Huang 1751b25f02d2SJohnny Huang otp_soak(0); 1752b25f02d2SJohnny Huang if (!pass) 1753b25f02d2SJohnny Huang return OTP_FAILURE; 1754b25f02d2SJohnny Huang 1755b25f02d2SJohnny Huang return OTP_SUCCESS; 1756b25f02d2SJohnny Huang } 1757b25f02d2SJohnny Huang 1758b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data) 1759b64ca396SJohnny Huang { 1760b64ca396SJohnny Huang int data_dw; 1761b64ca396SJohnny Huang u32 data_masked; 1762b64ca396SJohnny Huang u32 buf_masked; 1763b64ca396SJohnny Huang u32 *buf = (u32 *)image_layout->data; 1764b64ca396SJohnny Huang u32 *buf_ignore = (u32 *)image_layout->data_ignore; 1765b64ca396SJohnny Huang int i; 1766b64ca396SJohnny Huang 1767b64ca396SJohnny Huang data_dw = image_layout->data_length / 4; 1768b64ca396SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1769b64ca396SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1770b64ca396SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1771b64ca396SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1772b64ca396SJohnny Huang if (data_masked == buf_masked) 1773b64ca396SJohnny Huang continue; 1774b64ca396SJohnny Huang if (i % 2 == 0) { 1775b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1776b64ca396SJohnny Huang continue; 1777b64ca396SJohnny Huang } else { 1778b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1779b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1780b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1781b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1782b64ca396SJohnny Huang return OTP_FAILURE; 1783b64ca396SJohnny Huang } 1784b64ca396SJohnny Huang } else { 1785b64ca396SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1786b64ca396SJohnny Huang continue; 1787b64ca396SJohnny Huang } else { 1788b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1789b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1790b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1791b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1792b64ca396SJohnny Huang return OTP_FAILURE; 1793b64ca396SJohnny Huang } 1794b64ca396SJohnny Huang } 1795b64ca396SJohnny Huang } 1796b64ca396SJohnny Huang return OTP_SUCCESS; 1797b64ca396SJohnny Huang } 1798b64ca396SJohnny Huang 1799b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1800b64ca396SJohnny Huang { 1801b64ca396SJohnny Huang int i; 1802b64ca396SJohnny Huang u32 *strap; 1803b64ca396SJohnny Huang u32 *strap_ignore; 1804b64ca396SJohnny Huang u32 *strap_pro; 1805b64ca396SJohnny Huang int bit, pbit, ibit; 1806b64ca396SJohnny Huang int fail = 0; 1807b64ca396SJohnny Huang int ret; 1808b64ca396SJohnny Huang 1809b64ca396SJohnny Huang strap = (u32 *)image_layout->strap; 1810b64ca396SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1811b64ca396SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1812b64ca396SJohnny Huang 1813b64ca396SJohnny Huang for (i = 0; i < 64; i++) { 1814b64ca396SJohnny Huang if (i < 32) { 1815b64ca396SJohnny Huang bit = (strap[0] >> i) & 0x1; 1816b64ca396SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1817b64ca396SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1818b64ca396SJohnny Huang } else { 1819b64ca396SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1820b64ca396SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1821b64ca396SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1822b64ca396SJohnny Huang } 1823b64ca396SJohnny Huang 1824b64ca396SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1825b64ca396SJohnny Huang 1826b64ca396SJohnny Huang if (ret == OTP_FAILURE) 1827b64ca396SJohnny Huang fail = 1; 1828b64ca396SJohnny Huang } 1829b64ca396SJohnny Huang if (fail == 1) { 1830b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1831b64ca396SJohnny Huang return OTP_FAILURE; 1832b64ca396SJohnny Huang } 1833b64ca396SJohnny Huang return OTP_SUCCESS; 1834b64ca396SJohnny Huang } 1835b64ca396SJohnny Huang 1836b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf) 1837b64ca396SJohnny Huang { 1838b64ca396SJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1839b64ca396SJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1840b64ca396SJohnny Huang u32 data_masked; 1841b64ca396SJohnny Huang u32 buf_masked; 1842b64ca396SJohnny Huang int i; 1843b64ca396SJohnny Huang 1844b64ca396SJohnny Huang for (i = 0; i < 16; i++) { 1845b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 1846b64ca396SJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1847b64ca396SJohnny Huang if (data_masked == buf_masked) 1848b64ca396SJohnny Huang continue; 1849b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1850b64ca396SJohnny Huang continue; 1851b64ca396SJohnny Huang } else { 1852b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1853b64ca396SJohnny Huang printf("OTPCFG[%X] = %x\n", i, otp_conf[i]); 1854b64ca396SJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 1855b64ca396SJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 1856b64ca396SJohnny Huang return OTP_FAILURE; 1857b64ca396SJohnny Huang } 1858b64ca396SJohnny Huang } 1859b64ca396SJohnny Huang return OTP_SUCCESS; 1860b64ca396SJohnny Huang } 1861b64ca396SJohnny Huang 1862b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro) 1863b25f02d2SJohnny Huang { 1864b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1865b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1866b25f02d2SJohnny Huang u32 data_masked; 1867b25f02d2SJohnny Huang u32 buf_masked; 1868b25f02d2SJohnny Huang int i; 1869b25f02d2SJohnny Huang 1870b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1871b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1872b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1873b25f02d2SJohnny Huang if (data_masked == buf_masked) 1874b25f02d2SJohnny Huang continue; 1875b25f02d2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1876b25f02d2SJohnny Huang continue; 1877b25f02d2SJohnny Huang } else { 1878b25f02d2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1879b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]); 1880b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]); 1881b489486eSJohnny Huang printf("Mask [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]); 1882b25f02d2SJohnny Huang return OTP_FAILURE; 1883b25f02d2SJohnny Huang } 1884b25f02d2SJohnny Huang } 1885b25f02d2SJohnny Huang return OTP_SUCCESS; 1886b25f02d2SJohnny Huang } 1887b25f02d2SJohnny Huang 1888948e73aaSJoel Stanley static void do_hash(const void *data, int data_len, const char *algo_name, uint8_t *value) 1889948e73aaSJoel Stanley { 1890948e73aaSJoel Stanley struct hash_algo *algo; 1891948e73aaSJoel Stanley 1892948e73aaSJoel Stanley if (hash_lookup_algo(algo_name, &algo)) { 1893948e73aaSJoel Stanley debug("Unsupported hash alogrithm\n"); 1894948e73aaSJoel Stanley return; 1895948e73aaSJoel Stanley } 1896948e73aaSJoel Stanley 1897948e73aaSJoel Stanley algo->hash_func_ws(data, data_len, value, algo->chunk_size); 1898948e73aaSJoel Stanley } 1899948e73aaSJoel Stanley 1900e7e21c44SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf, int version) 1901696656c6SJohnny Huang { 1902e7e21c44SJohnny Huang u8 digest_ret[48]; 1903e7e21c44SJohnny Huang int digest_len; 1904696656c6SJohnny Huang 1905e7e21c44SJohnny Huang switch (version) { 1906e7e21c44SJohnny Huang case 1: 1907948e73aaSJoel Stanley do_hash(src_buf, length, "sha256", digest_ret); 1908e7e21c44SJohnny Huang digest_len = 32; 1909e7e21c44SJohnny Huang break; 1910e7e21c44SJohnny Huang case 2: 1911948e73aaSJoel Stanley do_hash(src_buf, length, "sha384", digest_ret); 1912e7e21c44SJohnny Huang digest_len = 48; 1913e7e21c44SJohnny Huang break; 1914e7e21c44SJohnny Huang default: 1915e7e21c44SJohnny Huang return OTP_FAILURE; 1916e7e21c44SJohnny Huang } 1917696656c6SJohnny Huang 1918e7e21c44SJohnny Huang if (!memcmp(digest_buf, digest_ret, digest_len)) 1919f347c284SJohnny Huang return OTP_SUCCESS; 1920f347c284SJohnny Huang return OTP_FAILURE; 1921696656c6SJohnny Huang } 1922696656c6SJohnny Huang 1923f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 192469d5fd8fSJohnny Huang { 192569d5fd8fSJohnny Huang int ret; 192661a6cda7SJohnny Huang int image_soc_ver = 0; 1927696656c6SJohnny Huang struct otp_header *otp_header; 1928696656c6SJohnny Huang struct otp_image_layout image_layout; 1929696656c6SJohnny Huang int image_size; 1930a219f6deSJohnny Huang u8 *buf; 1931a219f6deSJohnny Huang u8 *checksum; 1932b64ca396SJohnny Huang int i; 1933b64ca396SJohnny Huang u32 data[2048]; 1934b64ca396SJohnny Huang u32 conf[16]; 1935b25f02d2SJohnny Huang u32 scu_pro[2]; 1936b64ca396SJohnny Huang struct otpstrap_status otpstrap[64]; 193769d5fd8fSJohnny Huang 1938696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1939696656c6SJohnny Huang if (!otp_header) { 1940030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 19412a856b9aSJohnny Huang return OTP_FAILURE; 194269d5fd8fSJohnny Huang } 1943d90825e2SJohnny Huang 1944696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1945696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1946696656c6SJohnny Huang 1947696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1948696656c6SJohnny Huang 1949696656c6SJohnny Huang if (!buf) { 1950030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 1951696656c6SJohnny Huang return OTP_FAILURE; 1952696656c6SJohnny Huang } 1953696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1954696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1955696656c6SJohnny Huang 1956696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1957030cb4a7SJohnny Huang printf("Image is invalid\n"); 1958696656c6SJohnny Huang return OTP_FAILURE; 1959696656c6SJohnny Huang } 1960696656c6SJohnny Huang 19615010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 19625010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 19635010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 19645010032bSJohnny Huang 19655010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1966696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 19675010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1968696656c6SJohnny Huang 1969696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 19705010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 19715010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 19725010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 19737e523e3bSJohnny Huang 1974b25f02d2SJohnny Huang image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info); 1975b25f02d2SJohnny Huang image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2); 1976b25f02d2SJohnny Huang image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length; 1977b25f02d2SJohnny Huang 19787e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 19797e523e3bSJohnny Huang image_soc_ver = OTP_A0; 198061a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 198161a6cda7SJohnny Huang image_soc_ver = OTP_A1; 198261a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 198361a6cda7SJohnny Huang image_soc_ver = OTP_A2; 198461a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 198561a6cda7SJohnny Huang image_soc_ver = OTP_A3; 1986696656c6SJohnny Huang } else { 1987030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n"); 1988696656c6SJohnny Huang return OTP_FAILURE; 1989696656c6SJohnny Huang } 1990696656c6SJohnny Huang 199161a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 19925e096f11SJohnny Huang printf("Image SOC version is not match to HW SOC version\n"); 19939a4fe690SJohnny Huang return OTP_FAILURE; 19949a4fe690SJohnny Huang } 19959a4fe690SJohnny Huang 1996e7e21c44SJohnny Huang switch (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver)) { 1997e7e21c44SJohnny Huang case 1: 1998e7e21c44SJohnny Huang printf("WARNING: OTP image is not generated by otptool v2.x.x\n"); 1999e7e21c44SJohnny Huang printf("Please use the latest version of otptool to generate OTP image\n"); 2000e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 1); 2001e7e21c44SJohnny Huang break; 2002e7e21c44SJohnny Huang case 2: 2003e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 2); 2004e7e21c44SJohnny Huang break; 2005e7e21c44SJohnny Huang default: 2006e7e21c44SJohnny Huang printf("OTP image version is not supported\n"); 200761a6cda7SJohnny Huang return OTP_FAILURE; 200861a6cda7SJohnny Huang } 200961a6cda7SJohnny Huang 2010e7e21c44SJohnny Huang if (ret) { 2011030cb4a7SJohnny Huang printf("checksum is invalid\n"); 2012696656c6SJohnny Huang return OTP_FAILURE; 2013d90825e2SJohnny Huang } 20147332532cSJohnny Huang 2015030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2016030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2017030cb4a7SJohnny Huang return OTP_FAILURE; 2018030cb4a7SJohnny Huang } 2019b64ca396SJohnny Huang ret = 0; 2020030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 2021030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2022030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2023030cb4a7SJohnny Huang ret = -1; 2024030cb4a7SJohnny Huang } 2025030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2026030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2027030cb4a7SJohnny Huang ret = -1; 2028030cb4a7SJohnny Huang } 2029b64ca396SJohnny Huang printf("Read OTP Data Region:\n"); 2030b64ca396SJohnny Huang for (i = 0; i < 2048 ; i += 2) 2031b64ca396SJohnny Huang otp_read_data(i, &data[i]); 2032b64ca396SJohnny Huang 2033b64ca396SJohnny Huang printf("Check writable...\n"); 2034b64ca396SJohnny Huang if (otp_check_data_image(&image_layout, data) == OTP_FAILURE) 2035b64ca396SJohnny Huang ret = -1; 2036030cb4a7SJohnny Huang } 2037030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 2038030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2039030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2040030cb4a7SJohnny Huang ret = -1; 2041030cb4a7SJohnny Huang } 2042b64ca396SJohnny Huang printf("Read OTP Config Region:\n"); 2043b64ca396SJohnny Huang for (i = 0; i < 16 ; i++) 2044b64ca396SJohnny Huang otp_read_conf(i, &conf[i]); 2045b64ca396SJohnny Huang 2046b64ca396SJohnny Huang printf("Check writable...\n"); 2047b64ca396SJohnny Huang if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE) 2048b64ca396SJohnny Huang ret = -1; 2049030cb4a7SJohnny Huang } 2050030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 2051030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2052030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2053030cb4a7SJohnny Huang ret = -1; 2054030cb4a7SJohnny Huang } 2055b64ca396SJohnny Huang printf("Read OTP Strap Region:\n"); 2056b64ca396SJohnny Huang otp_strap_status(otpstrap); 2057b64ca396SJohnny Huang 2058b64ca396SJohnny Huang printf("Check writable...\n"); 2059b64ca396SJohnny Huang if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE) 2060b64ca396SJohnny Huang ret = -1; 2061030cb4a7SJohnny Huang } 2062b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2063b25f02d2SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2064b25f02d2SJohnny Huang printf("OTP strap region is protected\n"); 2065b25f02d2SJohnny Huang ret = -1; 2066b25f02d2SJohnny Huang } 2067b25f02d2SJohnny Huang printf("Read SCU Protect Region:\n"); 2068b25f02d2SJohnny Huang otp_read_conf(28, &scu_pro[0]); 2069b25f02d2SJohnny Huang otp_read_conf(29, &scu_pro[1]); 2070b25f02d2SJohnny Huang 2071b25f02d2SJohnny Huang printf("Check writable...\n"); 2072b25f02d2SJohnny Huang if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE) 2073b25f02d2SJohnny Huang ret = -1; 2074b25f02d2SJohnny Huang } 2075030cb4a7SJohnny Huang if (ret == -1) 2076030cb4a7SJohnny Huang return OTP_FAILURE; 2077b64ca396SJohnny Huang 207869d5fd8fSJohnny Huang if (!nconfirm) { 2079696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 20807f795e57SJohnny Huang printf("\nOTP data region :\n"); 2081f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 208269d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 20832a856b9aSJohnny Huang return OTP_FAILURE; 208469d5fd8fSJohnny Huang } 208569d5fd8fSJohnny Huang } 2086696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 20877332532cSJohnny Huang printf("\nOTP configuration region :\n"); 2088696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 20897332532cSJohnny Huang printf("OTP config error, please check.\n"); 20907332532cSJohnny Huang return OTP_FAILURE; 20917332532cSJohnny Huang } 20927332532cSJohnny Huang } 20937adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 20947adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 20957adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 20967adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 20977adec5f6SJohnny Huang return OTP_FAILURE; 20987adec5f6SJohnny Huang } 20997adec5f6SJohnny Huang } 2100b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2101b25f02d2SJohnny Huang printf("\nOTP scu protect region :\n"); 2102b25f02d2SJohnny Huang if (otp_print_scu_image(&image_layout) < 0) { 2103b25f02d2SJohnny Huang printf("OTP scu protect error, please check.\n"); 2104b25f02d2SJohnny Huang return OTP_FAILURE; 2105b25f02d2SJohnny Huang } 2106b25f02d2SJohnny Huang } 21077332532cSJohnny Huang 210869d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 210969d5fd8fSJohnny Huang if (!confirm_yesno()) { 211069d5fd8fSJohnny Huang printf(" Aborting\n"); 21112a856b9aSJohnny Huang return OTP_FAILURE; 211269d5fd8fSJohnny Huang } 211369d5fd8fSJohnny Huang } 21147332532cSJohnny Huang 21155010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 21165010032bSJohnny Huang printf("programing data region ...\n"); 2117b64ca396SJohnny Huang ret = otp_prog_data(&image_layout, data); 21185010032bSJohnny Huang if (ret != 0) { 21195010032bSJohnny Huang printf("Error\n"); 21205010032bSJohnny Huang return ret; 21215010032bSJohnny Huang } 2122a219f6deSJohnny Huang printf("Done\n"); 21235010032bSJohnny Huang } 21245010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 21255010032bSJohnny Huang printf("programing strap region ...\n"); 2126b64ca396SJohnny Huang ret = otp_prog_strap(&image_layout, otpstrap); 21275010032bSJohnny Huang if (ret != 0) { 21285010032bSJohnny Huang printf("Error\n"); 21295010032bSJohnny Huang return ret; 21305010032bSJohnny Huang } 2131a219f6deSJohnny Huang printf("Done\n"); 21325010032bSJohnny Huang } 2133b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2134b25f02d2SJohnny Huang printf("programing scu protect region ...\n"); 2135b25f02d2SJohnny Huang ret = otp_prog_scu_protect(&image_layout, scu_pro); 2136b25f02d2SJohnny Huang if (ret != 0) { 2137b25f02d2SJohnny Huang printf("Error\n"); 2138b25f02d2SJohnny Huang return ret; 2139b25f02d2SJohnny Huang } 2140b25f02d2SJohnny Huang printf("Done\n"); 2141b25f02d2SJohnny Huang } 21425010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 21435010032bSJohnny Huang printf("programing configuration region ...\n"); 2144b64ca396SJohnny Huang ret = otp_prog_conf(&image_layout, conf); 21455010032bSJohnny Huang if (ret != 0) { 21465010032bSJohnny Huang printf("Error\n"); 21475010032bSJohnny Huang return ret; 21485010032bSJohnny Huang } 21495010032bSJohnny Huang printf("Done\n"); 21505010032bSJohnny Huang } 2151cd1610b4SJohnny Huang 21527332532cSJohnny Huang return OTP_SUCCESS; 21532a856b9aSJohnny Huang } 21542a856b9aSJohnny Huang 2155f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 2156cd1610b4SJohnny Huang { 2157a219f6deSJohnny Huang u32 read[2]; 2158a219f6deSJohnny Huang u32 prog_address = 0; 215966f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 2160cd1610b4SJohnny Huang int otp_bit; 216183655e91SJohnny Huang int ret = 0; 2162cd1610b4SJohnny Huang 2163dacbba92SJohnny Huang otp_soak(0); 2164cd1610b4SJohnny Huang switch (mode) { 2165a6d0d645SJohnny Huang case OTP_REGION_CONF: 2166f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 2167cd1610b4SJohnny Huang prog_address = 0x800; 2168cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 2169cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 2170a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2171cd1610b4SJohnny Huang if (otp_bit == value) { 2172b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2173cd1610b4SJohnny Huang printf("No need to program\n"); 21742a856b9aSJohnny Huang return OTP_SUCCESS; 2175cd1610b4SJohnny Huang } 2176cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 2177b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 21780dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 21792a856b9aSJohnny Huang return OTP_FAILURE; 2180cd1610b4SJohnny Huang } 2181b489486eSJohnny Huang printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2182cd1610b4SJohnny Huang break; 2183a6d0d645SJohnny Huang case OTP_REGION_DATA: 2184cd1610b4SJohnny Huang prog_address = otp_dw_offset; 2185cd1610b4SJohnny Huang 2186cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 2187a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 2188a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2189643b9cfdSJohnny Huang 2190643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 2191b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2192b64ca396SJohnny Huang printf("OTP is programmed, which can't be cleared\n"); 2193643b9cfdSJohnny Huang return OTP_FAILURE; 2194643b9cfdSJohnny Huang } 2195cd1610b4SJohnny Huang } else { 2196a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 2197a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 2198643b9cfdSJohnny Huang 2199643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 2200b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2201b64ca396SJohnny Huang printf("OTP is programmed, which can't be written\n"); 2202643b9cfdSJohnny Huang return OTP_FAILURE; 2203643b9cfdSJohnny Huang } 2204cd1610b4SJohnny Huang } 2205cd1610b4SJohnny Huang if (otp_bit == value) { 2206b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2207cd1610b4SJohnny Huang printf("No need to program\n"); 22082a856b9aSJohnny Huang return OTP_SUCCESS; 2209cd1610b4SJohnny Huang } 2210643b9cfdSJohnny Huang 2211b489486eSJohnny Huang printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2212cd1610b4SJohnny Huang break; 2213a6d0d645SJohnny Huang case OTP_REGION_STRAP: 22148848d5dcSJohnny Huang otp_strap_status(otpstrap); 22158848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 22167e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 22178848d5dcSJohnny Huang if (ret == OTP_FAILURE) 22188848d5dcSJohnny Huang return OTP_FAILURE; 22198848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 22208848d5dcSJohnny Huang return OTP_SUCCESS; 2221a6af4a17SJohnny Huang 2222cd1610b4SJohnny Huang break; 2223cd1610b4SJohnny Huang } 2224cd1610b4SJohnny Huang 2225cd1610b4SJohnny Huang if (!nconfirm) { 2226cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2227cd1610b4SJohnny Huang if (!confirm_yesno()) { 2228cd1610b4SJohnny Huang printf(" Aborting\n"); 22292a856b9aSJohnny Huang return OTP_FAILURE; 2230cd1610b4SJohnny Huang } 2231cd1610b4SJohnny Huang } 2232cd1610b4SJohnny Huang 2233cd1610b4SJohnny Huang switch (mode) { 2234a6d0d645SJohnny Huang case OTP_REGION_STRAP: 2235f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 223683655e91SJohnny Huang break; 2237a6d0d645SJohnny Huang case OTP_REGION_CONF: 2238a6d0d645SJohnny Huang case OTP_REGION_DATA: 2239f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 2240de6fbf1cSJohnny Huang break; 2241de6fbf1cSJohnny Huang } 2242de6fbf1cSJohnny Huang otp_soak(0); 224383655e91SJohnny Huang if (ret) { 22440dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 2245794e27ecSJohnny Huang printf("FAILURE\n"); 2246794e27ecSJohnny Huang return OTP_FAILURE; 2247794e27ecSJohnny Huang } 2248794e27ecSJohnny Huang 22499009c25dSJohnny Huang printf("SUCCESS\n"); 22502a856b9aSJohnny Huang return OTP_SUCCESS; 2251a219f6deSJohnny Huang } 2252a219f6deSJohnny Huang 2253794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 2254794e27ecSJohnny Huang { 2255794e27ecSJohnny Huang u32 otp_rid[2]; 2256a8789b47SJohnny Huang u32 sw_rid[2]; 2257794e27ecSJohnny Huang int rid_num = 0; 2258a8789b47SJohnny Huang int sw_rid_num = 0; 2259794e27ecSJohnny Huang int bit_offset; 2260794e27ecSJohnny Huang int dw_offset; 2261794e27ecSJohnny Huang int i; 2262794e27ecSJohnny Huang int ret; 2263794e27ecSJohnny Huang 2264f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2265f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2266794e27ecSJohnny Huang 2267a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2268a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2269a8789b47SJohnny Huang 2270794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2271a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2272a8789b47SJohnny Huang 2273a8789b47SJohnny Huang if (sw_rid_num < 0) { 2274a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2275a8789b47SJohnny Huang return OTP_FAILURE; 2276a8789b47SJohnny Huang } 2277a8789b47SJohnny Huang 2278a8789b47SJohnny Huang if (update_num > sw_rid_num) { 2279a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2280a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2281a8789b47SJohnny Huang return OTP_FAILURE; 2282a8789b47SJohnny Huang } 2283794e27ecSJohnny Huang 2284794e27ecSJohnny Huang if (rid_num < 0) { 2285b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by this command,\n" 2286b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n"); 2287794e27ecSJohnny Huang otp_print_revid(otp_rid); 22889009c25dSJohnny Huang return OTP_FAILURE; 22899009c25dSJohnny Huang } 2290cd1610b4SJohnny Huang 2291794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2292794e27ecSJohnny Huang otp_print_revid(otp_rid); 2293794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 2294794e27ecSJohnny Huang 2295a8789b47SJohnny Huang if (rid_num > update_num) { 2296a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 2297a8789b47SJohnny Huang printf("Skip\n"); 2298a8789b47SJohnny Huang return OTP_FAILURE; 2299a8789b47SJohnny Huang } else if (rid_num == update_num) { 2300a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 2301794e27ecSJohnny Huang printf("Skip\n"); 2302794e27ecSJohnny Huang return OTP_FAILURE; 2303794e27ecSJohnny Huang } 2304794e27ecSJohnny Huang 2305794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2306794e27ecSJohnny Huang if (i < 32) { 2307794e27ecSJohnny Huang dw_offset = 0xa; 2308794e27ecSJohnny Huang bit_offset = i; 2309794e27ecSJohnny Huang } else { 2310794e27ecSJohnny Huang dw_offset = 0xb; 2311794e27ecSJohnny Huang bit_offset = i - 32; 2312794e27ecSJohnny Huang } 2313b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset); 2314794e27ecSJohnny Huang if (i + 1 != update_num) 2315794e27ecSJohnny Huang printf(", "); 2316794e27ecSJohnny Huang } 2317794e27ecSJohnny Huang 2318794e27ecSJohnny Huang printf(" will be programmed\n"); 2319794e27ecSJohnny Huang if (force == 0) { 2320794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2321794e27ecSJohnny Huang if (!confirm_yesno()) { 2322794e27ecSJohnny Huang printf(" Aborting\n"); 2323794e27ecSJohnny Huang return OTP_FAILURE; 2324794e27ecSJohnny Huang } 2325794e27ecSJohnny Huang } 2326794e27ecSJohnny Huang 2327794e27ecSJohnny Huang ret = 0; 2328794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2329794e27ecSJohnny Huang if (i < 32) { 2330794e27ecSJohnny Huang dw_offset = 0xa04; 2331794e27ecSJohnny Huang bit_offset = i; 2332794e27ecSJohnny Huang } else { 2333794e27ecSJohnny Huang dw_offset = 0xa06; 2334794e27ecSJohnny Huang bit_offset = i - 32; 2335794e27ecSJohnny Huang } 2336f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 2337b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset); 2338794e27ecSJohnny Huang ret = OTP_FAILURE; 2339794e27ecSJohnny Huang break; 2340794e27ecSJohnny Huang } 2341794e27ecSJohnny Huang } 2342061d3279SJohnny Huang otp_soak(0); 2343f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2344f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2345794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2346794e27ecSJohnny Huang if (rid_num >= 0) 2347794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 2348794e27ecSJohnny Huang else 2349794e27ecSJohnny Huang printf("OTP revision ID\n"); 2350794e27ecSJohnny Huang otp_print_revid(otp_rid); 2351794e27ecSJohnny Huang if (!ret) 2352794e27ecSJohnny Huang printf("SUCCESS\n"); 2353794e27ecSJohnny Huang else 2354794e27ecSJohnny Huang printf("FAILED\n"); 2355794e27ecSJohnny Huang return ret; 2356794e27ecSJohnny Huang } 2357794e27ecSJohnny Huang 2358883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force) 2359883625c5SJohnny Huang { 2360883625c5SJohnny Huang u32 otpcfg4; 2361883625c5SJohnny Huang u32 krb; 2362883625c5SJohnny Huang u32 krb_b; 2363883625c5SJohnny Huang u32 krb_or; 2364883625c5SJohnny Huang u32 current_id; 2365883625c5SJohnny Huang 2366883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2367883625c5SJohnny Huang current_id = readl(SEC_KEY_NUM) & 7; 2368883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2369883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2370883625c5SJohnny Huang krb_or = krb | krb_b; 2371883625c5SJohnny Huang 2372883625c5SJohnny Huang printf("current Key ID: 0x%x\n", current_id); 2373883625c5SJohnny Huang printf("input retire ID: 0x%x\n", retire_id); 2374883625c5SJohnny Huang printf("OTPCFG0x4 = 0x%X\n", otpcfg4); 2375883625c5SJohnny Huang 2376883625c5SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2377883625c5SJohnny Huang printf("OTPCFG4 is protected\n"); 2378883625c5SJohnny Huang return OTP_FAILURE; 2379883625c5SJohnny Huang } 2380883625c5SJohnny Huang 2381883625c5SJohnny Huang if (retire_id >= current_id) { 2382883625c5SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2383883625c5SJohnny Huang return OTP_FAILURE; 2384883625c5SJohnny Huang } 2385883625c5SJohnny Huang 2386883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2387883625c5SJohnny Huang printf("Key 0x%X already retired\n", retire_id); 2388883625c5SJohnny Huang return OTP_SUCCESS; 2389883625c5SJohnny Huang } 2390883625c5SJohnny Huang 2391883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id); 2392883625c5SJohnny Huang if (force == 0) { 2393883625c5SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2394883625c5SJohnny Huang if (!confirm_yesno()) { 2395883625c5SJohnny Huang printf(" Aborting\n"); 2396883625c5SJohnny Huang return OTP_FAILURE; 2397883625c5SJohnny Huang } 2398883625c5SJohnny Huang } 2399883625c5SJohnny Huang 2400883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) { 2401883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed\n", retire_id); 2402883625c5SJohnny Huang printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16); 2403883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE) 2404883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16); 2405883625c5SJohnny Huang } 2406883625c5SJohnny Huang 2407883625c5SJohnny Huang otp_soak(0); 2408883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2409883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2410883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2411883625c5SJohnny Huang krb_or = krb | krb_b; 2412883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2413883625c5SJohnny Huang printf("SUCCESS\n"); 2414883625c5SJohnny Huang return OTP_SUCCESS; 2415883625c5SJohnny Huang } 2416883625c5SJohnny Huang printf("FAILED\n"); 2417883625c5SJohnny Huang return OTP_FAILURE; 2418883625c5SJohnny Huang } 2419883625c5SJohnny Huang 2420e7e21c44SJohnny Huang static int parse_config(struct sb_info *si) 2421e7e21c44SJohnny Huang { 2422e7e21c44SJohnny Huang int i; 2423e7e21c44SJohnny Huang u32 cfg0, cfg3, cfg4; 2424e7e21c44SJohnny Huang u32 sb_mode; 2425e7e21c44SJohnny Huang u32 key_retire; 2426e7e21c44SJohnny Huang u32 rsa_len; 2427e7e21c44SJohnny Huang u32 sha_len; 2428e7e21c44SJohnny Huang 2429e7e21c44SJohnny Huang otp_read_conf(0, &cfg0); 2430e7e21c44SJohnny Huang otp_read_conf(3, &cfg3); 2431e7e21c44SJohnny Huang otp_read_conf(4, &cfg4); 2432e7e21c44SJohnny Huang 2433e7e21c44SJohnny Huang sb_mode = (cfg0 >> 7) & 0x1; 2434e7e21c44SJohnny Huang si->enc_flag = (cfg0 >> 27) & 0x1; 2435e7e21c44SJohnny Huang key_retire = (cfg4 & 0x7f) | ((cfg4 >> 16) & 0x7f); 2436e7e21c44SJohnny Huang 2437e7e21c44SJohnny Huang if ((cfg0 >> 16) & 0x3f) 2438e7e21c44SJohnny Huang si->secure_region = 1; 2439e7e21c44SJohnny Huang else 2440e7e21c44SJohnny Huang si->secure_region = 0; 2441e7e21c44SJohnny Huang 2442e7e21c44SJohnny Huang si->header_offset = cfg3 & 0xffff; 2443e7e21c44SJohnny Huang if (si->header_offset == 0) 2444e7e21c44SJohnny Huang si->header_offset = 0x20; 2445e7e21c44SJohnny Huang 2446e7e21c44SJohnny Huang for (i = 0; i < 8; i++) { 2447e7e21c44SJohnny Huang if ((key_retire >> i) & 0x1) 2448e7e21c44SJohnny Huang si->retire_list[i] = 1; 2449e7e21c44SJohnny Huang else 2450e7e21c44SJohnny Huang si->retire_list[i] = 0; 2451e7e21c44SJohnny Huang } 2452e7e21c44SJohnny Huang 2453e7e21c44SJohnny Huang if (sb_mode == 0) { 2454e7e21c44SJohnny Huang printf("Mode GCM is not supported.\n"); 2455e7e21c44SJohnny Huang return OTP_FAILURE; 2456e7e21c44SJohnny Huang } 2457e7e21c44SJohnny Huang 2458e7e21c44SJohnny Huang if (si->enc_flag) 2459e7e21c44SJohnny Huang printf("Algorithm: AES_RSA_SHA\n"); 2460e7e21c44SJohnny Huang else 2461e7e21c44SJohnny Huang printf("Algorithm: RSA_SHA\n"); 2462e7e21c44SJohnny Huang 2463e7e21c44SJohnny Huang rsa_len = (cfg0 >> 10) & 0x3; 2464e7e21c44SJohnny Huang sha_len = (cfg0 >> 12) & 0x3; 2465e7e21c44SJohnny Huang 2466e7e21c44SJohnny Huang if (rsa_len == 0) { 2467e7e21c44SJohnny Huang si->rsa_algo = 1024; 2468e7e21c44SJohnny Huang printf("RSA length: 1024\n"); 2469e7e21c44SJohnny Huang } else if (rsa_len == 1) { 2470e7e21c44SJohnny Huang si->rsa_algo = 2048; 2471e7e21c44SJohnny Huang printf("RSA length: 2048\n"); 2472e7e21c44SJohnny Huang } else if (rsa_len == 2) { 2473e7e21c44SJohnny Huang si->rsa_algo = 3072; 2474e7e21c44SJohnny Huang printf("RSA length: 3072\n"); 2475e7e21c44SJohnny Huang } else { 2476e7e21c44SJohnny Huang si->rsa_algo = 4096; 2477e7e21c44SJohnny Huang printf("RSA length: 4096\n"); 2478e7e21c44SJohnny Huang } 2479e7e21c44SJohnny Huang if (sha_len == 0) { 2480e7e21c44SJohnny Huang si->sha_algo = 224; 2481e7e21c44SJohnny Huang si->digest_len = 28; 2482e7e21c44SJohnny Huang printf("HASH length: 224\n"); 2483e7e21c44SJohnny Huang } else if (sha_len == 1) { 2484e7e21c44SJohnny Huang si->sha_algo = 256; 2485e7e21c44SJohnny Huang si->digest_len = 32; 2486e7e21c44SJohnny Huang printf("HASH length: 256\n"); 2487e7e21c44SJohnny Huang } else if (sha_len == 2) { 2488e7e21c44SJohnny Huang si->sha_algo = 384; 2489e7e21c44SJohnny Huang si->digest_len = 48; 2490e7e21c44SJohnny Huang printf("HASH length: 384\n"); 2491e7e21c44SJohnny Huang } else { 2492e7e21c44SJohnny Huang si->sha_algo = 512; 2493e7e21c44SJohnny Huang si->digest_len = 64; 2494e7e21c44SJohnny Huang printf("HASH length: 512\n"); 2495e7e21c44SJohnny Huang } 2496e7e21c44SJohnny Huang return OTP_SUCCESS; 2497e7e21c44SJohnny Huang } 2498e7e21c44SJohnny Huang 2499e7e21c44SJohnny Huang static void parse_data(struct key_list *kl, int *key_num, struct sb_info *si, u32 *data) 2500e7e21c44SJohnny Huang { 2501e7e21c44SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 2502e7e21c44SJohnny Huang int i, j; 2503e7e21c44SJohnny Huang int id = 0; 2504e7e21c44SJohnny Huang u32 h; 2505e7e21c44SJohnny Huang u32 t; 2506e7e21c44SJohnny Huang 2507e7e21c44SJohnny Huang *key_num = 0; 2508e7e21c44SJohnny Huang for (i = 0; i < 16; i++) { 2509e7e21c44SJohnny Huang h = data[i]; 2510e7e21c44SJohnny Huang t = (h >> 14) & 0xf; 2511e7e21c44SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 2512e7e21c44SJohnny Huang if (t == key_info_array[j].value) { 2513e7e21c44SJohnny Huang kl[*key_num].key_info = &key_info_array[j]; 2514e7e21c44SJohnny Huang kl[*key_num].offset = h & 0x1ff8; 2515e7e21c44SJohnny Huang id = h & 0x7; 2516e7e21c44SJohnny Huang kl[*key_num].id = id; 2517e7e21c44SJohnny Huang if (si->retire_list[id] == 1) 2518e7e21c44SJohnny Huang kl[*key_num].retire = 1; 2519e7e21c44SJohnny Huang else 2520e7e21c44SJohnny Huang kl[*key_num].retire = 0; 2521e7e21c44SJohnny Huang (*key_num)++; 2522e7e21c44SJohnny Huang break; 2523e7e21c44SJohnny Huang } 2524e7e21c44SJohnny Huang } 2525e7e21c44SJohnny Huang if ((data[i] >> 13) & 1) 2526e7e21c44SJohnny Huang break; 2527e7e21c44SJohnny Huang } 2528e7e21c44SJohnny Huang } 2529e7e21c44SJohnny Huang 2530e7e21c44SJohnny Huang static int sb_sha(struct sb_info *si, u8 *sec_image, u32 sign_image_size, u8 *digest_ret) 2531e7e21c44SJohnny Huang { 2532e7e21c44SJohnny Huang switch (si->sha_algo) { 2533e7e21c44SJohnny Huang case 224: 2534e7e21c44SJohnny Huang printf("otp verify does not support SHA224\n"); 2535e7e21c44SJohnny Huang return OTP_FAILURE; 2536e7e21c44SJohnny Huang case 256: 2537948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha256", digest_ret); 2538e7e21c44SJohnny Huang break; 2539e7e21c44SJohnny Huang case 384: 2540948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha384", digest_ret); 2541e7e21c44SJohnny Huang break; 2542e7e21c44SJohnny Huang case 512: 2543948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha512", digest_ret); 2544e7e21c44SJohnny Huang break; 2545e7e21c44SJohnny Huang default: 2546e7e21c44SJohnny Huang printf("SHA Algorithm is invalid\n"); 2547e7e21c44SJohnny Huang return OTP_FAILURE; 2548e7e21c44SJohnny Huang } 2549e7e21c44SJohnny Huang return 0; 2550e7e21c44SJohnny Huang } 2551e7e21c44SJohnny Huang 2552e7e21c44SJohnny Huang static int mode2_verify(u8 *sec_image, u32 sign_image_size, 2553e7e21c44SJohnny Huang u8 *signature, u8 *rsa_m, 2554e7e21c44SJohnny Huang int order, u8 *digest, 2555e7e21c44SJohnny Huang struct sb_info *si, struct udevice *mod_exp_dev) 2556e7e21c44SJohnny Huang { 2557e7e21c44SJohnny Huang struct key_prop prop; 2558e7e21c44SJohnny Huang u8 rsa_e[3] = "\x01\x00\x01"; 2559e7e21c44SJohnny Huang u8 sign_ret[512]; 2560e7e21c44SJohnny Huang u8 rsa_m_rev[512]; 2561e7e21c44SJohnny Huang u8 signature_rev[512]; 2562e7e21c44SJohnny Huang u8 tmp; 2563e7e21c44SJohnny Huang u32 rsa_len = si->rsa_algo / 8; 2564e7e21c44SJohnny Huang int i; 2565e7e21c44SJohnny Huang int ret; 2566e7e21c44SJohnny Huang 2567e7e21c44SJohnny Huang memset(&prop, 0, sizeof(struct key_prop)); 2568e7e21c44SJohnny Huang 2569e7e21c44SJohnny Huang if (order == OTP_LIT_END) { 2570e7e21c44SJohnny Huang memset(rsa_m_rev, 0, 512); 2571e7e21c44SJohnny Huang memset(signature_rev, 0, 512); 2572e7e21c44SJohnny Huang for (i = 0; i < rsa_len; i++) { 2573e7e21c44SJohnny Huang rsa_m_rev[i] = rsa_m[rsa_len - 1 - i]; 2574e7e21c44SJohnny Huang signature_rev[i] = signature[rsa_len - 1 - i]; 2575e7e21c44SJohnny Huang } 2576e7e21c44SJohnny Huang prop.modulus = rsa_m_rev; 2577e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo; 2578e7e21c44SJohnny Huang prop.public_exponent = rsa_e; 2579e7e21c44SJohnny Huang prop.exp_len = 3; 2580e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature_rev, rsa_len, &prop, sign_ret); 2581e7e21c44SJohnny Huang } else { 2582e7e21c44SJohnny Huang prop.modulus = rsa_m; 2583e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo; 2584e7e21c44SJohnny Huang prop.public_exponent = rsa_e; 2585e7e21c44SJohnny Huang prop.exp_len = 3; 2586e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature, rsa_len, &prop, sign_ret); 2587e7e21c44SJohnny Huang } 2588e7e21c44SJohnny Huang 2589e7e21c44SJohnny Huang if (ret) { 2590e7e21c44SJohnny Huang printf("rsa_mod_exp error: %d\n", ret); 2591e7e21c44SJohnny Huang return OTP_FAILURE; 2592e7e21c44SJohnny Huang } 2593e7e21c44SJohnny Huang 2594e7e21c44SJohnny Huang if (order == OTP_LIT_END) { 2595e7e21c44SJohnny Huang for (i = 0; i < rsa_len / 2; i++) { 2596e7e21c44SJohnny Huang tmp = sign_ret[i]; 2597e7e21c44SJohnny Huang sign_ret[i] = sign_ret[rsa_len - 1 - i]; 2598e7e21c44SJohnny Huang sign_ret[rsa_len - 1 - i] = tmp; 2599e7e21c44SJohnny Huang } 2600e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret, si->digest_len); 2601e7e21c44SJohnny Huang } else { 2602e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret + (rsa_len - si->digest_len), si->digest_len); 2603e7e21c44SJohnny Huang } 2604e7e21c44SJohnny Huang 2605e7e21c44SJohnny Huang if (ret) 2606e7e21c44SJohnny Huang return OTP_FAILURE; 2607e7e21c44SJohnny Huang return 0; 2608e7e21c44SJohnny Huang } 2609e7e21c44SJohnny Huang 2610e7e21c44SJohnny Huang static int otp_verify_boot_image(phys_addr_t addr) 2611e7e21c44SJohnny Huang { 2612e7e21c44SJohnny Huang struct udevice *mod_exp_dev; 2613e7e21c44SJohnny Huang struct sb_info si; 2614e7e21c44SJohnny Huang struct key_list kl[16]; 2615e7e21c44SJohnny Huang struct sb_header *sh; 2616e7e21c44SJohnny Huang u32 data[2048]; 2617e7e21c44SJohnny Huang u8 digest[64]; 2618e7e21c44SJohnny Huang u8 *sec_image; 2619e7e21c44SJohnny Huang u8 *signature; 2620e7e21c44SJohnny Huang u8 *key; 2621e7e21c44SJohnny Huang u32 otp_rid[2]; 2622e7e21c44SJohnny Huang u32 sw_rid[2]; 2623e7e21c44SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2624e7e21c44SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2625e7e21c44SJohnny Huang int key_num; 2626e7e21c44SJohnny Huang int ret; 2627e7e21c44SJohnny Huang int i; 2628e7e21c44SJohnny Huang int pass = 0; 2629e7e21c44SJohnny Huang 263009f2a38fSJoel Stanley ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev); 2631e7e21c44SJohnny Huang if (ret) { 263209f2a38fSJoel Stanley printf("RSA: Can't find RSA driver\n"); 2633e7e21c44SJohnny Huang return OTP_FAILURE; 2634e7e21c44SJohnny Huang } 2635e7e21c44SJohnny Huang 2636e7e21c44SJohnny Huang for (i = 0; i < 2048 ; i += 2) 2637e7e21c44SJohnny Huang otp_read_data(i, &data[i]); 2638e7e21c44SJohnny Huang if (parse_config(&si)) 2639e7e21c44SJohnny Huang return OTP_FAILURE; 2640e7e21c44SJohnny Huang parse_data(kl, &key_num, &si, data); 2641e7e21c44SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2642e7e21c44SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2643e7e21c44SJohnny Huang 2644e7e21c44SJohnny Huang sec_image = (u8 *)addr; 2645e7e21c44SJohnny Huang sh = (struct sb_header *)(sec_image + si.header_offset); 2646e7e21c44SJohnny Huang signature = sec_image + sh->signature_offset; 2647e7e21c44SJohnny Huang 2648e7e21c44SJohnny Huang if (si.secure_region) 2649e7e21c44SJohnny Huang printf("WARNING: Secure Region is enabled, the verification may not correct.\n"); 2650e7e21c44SJohnny Huang 2651e7e21c44SJohnny Huang if (sh->sign_image_size % 512) { 2652e7e21c44SJohnny Huang printf("ERROR: The sign_image_size should be 512 bytes aligned\n"); 2653e7e21c44SJohnny Huang return OTP_FAILURE; 2654e7e21c44SJohnny Huang } 2655e7e21c44SJohnny Huang 2656e7e21c44SJohnny Huang printf("Check revision ID: "); 2657e7e21c44SJohnny Huang 2658e7e21c44SJohnny Huang sw_rid[0] = sh->revision_low; 2659e7e21c44SJohnny Huang sw_rid[1] = sh->revision_high; 2660e7e21c44SJohnny Huang 2661e7e21c44SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2662e7e21c44SJohnny Huang printf("FAIL\n"); 2663e7e21c44SJohnny Huang printf("Header revision_low: %x\n", sh->revision_low); 2664e7e21c44SJohnny Huang printf("Header revision_high: %x\n", sh->revision_high); 2665e7e21c44SJohnny Huang printf("OTP revision_low: %x\n", otp_rid[0]); 2666e7e21c44SJohnny Huang printf("OTP revision_high: %x\n", otp_rid[1]); 2667e7e21c44SJohnny Huang return OTP_FAILURE; 2668e7e21c44SJohnny Huang } 2669e7e21c44SJohnny Huang printf("PASS\n"); 2670e7e21c44SJohnny Huang 2671e7e21c44SJohnny Huang printf("Check secure image header: "); 2672e7e21c44SJohnny Huang if (((sh->aes_data_offset + sh->enc_offset + sh->sign_image_size + 2673e7e21c44SJohnny Huang sh->signature_offset + sh->revision_high + sh->revision_low + 2674e7e21c44SJohnny Huang sh->reserved + sh->bl1_header_checksum) & 0xffffffff) != 0) { 2675e7e21c44SJohnny Huang printf("FAIL\n"); 2676e7e21c44SJohnny Huang printf("aes_data_offset: %x\n", sh->aes_data_offset); 2677e7e21c44SJohnny Huang printf("enc_offset: %x\n", sh->enc_offset); 2678e7e21c44SJohnny Huang printf("sign_image_size: %x\n", sh->sign_image_size); 2679e7e21c44SJohnny Huang printf("signature_offset: %x\n", sh->signature_offset); 2680e7e21c44SJohnny Huang printf("revision_high: %x\n", sh->revision_high); 2681e7e21c44SJohnny Huang printf("revision_low: %x\n", sh->revision_low); 2682e7e21c44SJohnny Huang printf("reserved: %x\n", sh->reserved); 2683e7e21c44SJohnny Huang printf("bl1_header_checksum: %x\n", sh->bl1_header_checksum); 2684e7e21c44SJohnny Huang return OTP_FAILURE; 2685e7e21c44SJohnny Huang } 2686e7e21c44SJohnny Huang printf("PASS\n"); 2687e7e21c44SJohnny Huang 2688e7e21c44SJohnny Huang ret = sb_sha(&si, sec_image, sh->sign_image_size, digest); 2689e7e21c44SJohnny Huang if (ret) 2690e7e21c44SJohnny Huang return OTP_FAILURE; 2691e7e21c44SJohnny Huang 2692e7e21c44SJohnny Huang printf("Verifying secure image\n"); 2693e7e21c44SJohnny Huang for (i = 0; i < key_num; i++) { 2694e7e21c44SJohnny Huang if (kl[i].key_info->key_type != OTP_KEY_TYPE_RSA_PUB) 2695e7e21c44SJohnny Huang continue; 2696e7e21c44SJohnny Huang printf(" Key %d\n", kl[i].id); 2697e7e21c44SJohnny Huang if (kl[i].retire) { 2698e7e21c44SJohnny Huang printf(" Key %d is retired.\n", kl[i].id); 2699e7e21c44SJohnny Huang continue; 2700e7e21c44SJohnny Huang } 2701e7e21c44SJohnny Huang key = (u8 *)data + kl[i].offset; 2702e7e21c44SJohnny Huang if (!mode2_verify(sec_image, sh->sign_image_size, 2703e7e21c44SJohnny Huang signature, key, kl[i].key_info->order, digest, 2704e7e21c44SJohnny Huang &si, mod_exp_dev)) { 2705e7e21c44SJohnny Huang pass = 1; 2706e7e21c44SJohnny Huang break; 2707e7e21c44SJohnny Huang } 2708e7e21c44SJohnny Huang } 2709e7e21c44SJohnny Huang if (pass) { 2710e7e21c44SJohnny Huang printf(" OEM DSS RSA public keys\n"); 2711e7e21c44SJohnny Huang printf(" ID: %d\n", kl[i].id); 2712e7e21c44SJohnny Huang if (kl[i].key_info->order == OTP_BIG_END) 2713e7e21c44SJohnny Huang printf(" Big endian\n"); 2714e7e21c44SJohnny Huang else 2715e7e21c44SJohnny Huang printf(" Little endian\n"); 2716e7e21c44SJohnny Huang printf("Verify secure image: PASS\n"); 2717e7e21c44SJohnny Huang return OTP_SUCCESS; 2718e7e21c44SJohnny Huang } 2719e7e21c44SJohnny Huang printf("Verify secure image: FAIL\n"); 2720e7e21c44SJohnny Huang return OTP_FAILURE; 2721e7e21c44SJohnny Huang } 2722e7e21c44SJohnny Huang 2723418822f0SJohnny Huang static int otp_invalid_key(u32 header_offset, int force) 2724418822f0SJohnny Huang { 2725418822f0SJohnny Huang int i; 2726418822f0SJohnny Huang int ret; 2727418822f0SJohnny Huang u32 header_list[16]; 2728418822f0SJohnny Huang u32 header; 2729418822f0SJohnny Huang u32 key_type; 2730418822f0SJohnny Huang u32 prog_val; 2731418822f0SJohnny Huang 2732418822f0SJohnny Huang for (i = 0; i < 16 ; i += 2) 2733418822f0SJohnny Huang otp_read_data(i, &header_list[i]); 2734418822f0SJohnny Huang header = header_list[header_offset]; 2735418822f0SJohnny Huang key_type = (header >> 14) & 0xf; 2736418822f0SJohnny Huang _otp_print_key(header, header_offset, NULL); 2737418822f0SJohnny Huang if (key_type == 0 || key_type == 0xf) { 2738418822f0SJohnny Huang printf("Key[%d] already invalid\n", header_offset); 2739418822f0SJohnny Huang return OTP_SUCCESS; 2740418822f0SJohnny Huang } 2741418822f0SJohnny Huang 2742418822f0SJohnny Huang printf("Key[%d] will be invalid\n", header_offset); 2743418822f0SJohnny Huang if (force == 0) { 2744418822f0SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2745418822f0SJohnny Huang if (!confirm_yesno()) { 2746418822f0SJohnny Huang printf(" Aborting\n"); 2747418822f0SJohnny Huang return OTP_FAILURE; 2748418822f0SJohnny Huang } 2749418822f0SJohnny Huang } 2750418822f0SJohnny Huang 2751418822f0SJohnny Huang if (header_offset % 2) 2752418822f0SJohnny Huang prog_val = 0; 2753418822f0SJohnny Huang else 2754418822f0SJohnny Huang prog_val = 1; 2755418822f0SJohnny Huang for (i = 14; i <= 17; i++) { 2756418822f0SJohnny Huang ret = otp_prog_dc_b(prog_val, header_offset, i); 2757418822f0SJohnny Huang if (ret) { 2758418822f0SJohnny Huang printf("OTPDATA0x%x[%d] programming failed\n", header_offset, i); 2759418822f0SJohnny Huang return OTP_FAILURE; 2760418822f0SJohnny Huang } 2761418822f0SJohnny Huang } 2762418822f0SJohnny Huang 2763418822f0SJohnny Huang printf("SUCCESS\n"); 2764418822f0SJohnny Huang return OTP_SUCCESS; 2765418822f0SJohnny Huang } 2766418822f0SJohnny Huang 27672a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 276869d5fd8fSJohnny Huang { 2769a219f6deSJohnny Huang u32 offset, count; 27702a856b9aSJohnny Huang int ret; 277169d5fd8fSJohnny Huang 27722a856b9aSJohnny Huang if (argc == 4) { 27732a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 27742a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 27752a856b9aSJohnny Huang } else if (argc == 3) { 27762a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 27772a856b9aSJohnny Huang count = 1; 27782a856b9aSJohnny Huang } else { 277969d5fd8fSJohnny Huang return CMD_RET_USAGE; 278069d5fd8fSJohnny Huang } 278169d5fd8fSJohnny Huang 2782030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2783f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2784030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 27852a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2786030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 27872a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2788030cb4a7SJohnny Huang else 27892a856b9aSJohnny Huang return CMD_RET_USAGE; 279069d5fd8fSJohnny Huang 27912a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 27922a856b9aSJohnny Huang return CMD_RET_SUCCESS; 27932a856b9aSJohnny Huang return CMD_RET_USAGE; 27942a856b9aSJohnny Huang } 27952a856b9aSJohnny Huang 27962a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 27972a856b9aSJohnny Huang { 27982a856b9aSJohnny Huang phys_addr_t addr; 27992a856b9aSJohnny Huang int ret; 28002a856b9aSJohnny Huang 2801de6b0cc4SJohnny Huang if (argc == 3) { 2802ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 28032a856b9aSJohnny Huang return CMD_RET_USAGE; 28042a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2805f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2806de6b0cc4SJohnny Huang } else if (argc == 2) { 28072a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2808f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 28092a856b9aSJohnny Huang } else { 28102a856b9aSJohnny Huang return CMD_RET_USAGE; 28112a856b9aSJohnny Huang } 28122a856b9aSJohnny Huang 28132a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 28142a856b9aSJohnny Huang return CMD_RET_SUCCESS; 28152a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 28162a856b9aSJohnny Huang return CMD_RET_FAILURE; 28172a856b9aSJohnny Huang else 28182a856b9aSJohnny Huang return CMD_RET_USAGE; 28192a856b9aSJohnny Huang } 28202a856b9aSJohnny Huang 28212a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 28222a856b9aSJohnny Huang { 28232a856b9aSJohnny Huang int mode = 0; 28242a856b9aSJohnny Huang int nconfirm = 0; 28252a856b9aSJohnny Huang int otp_addr = 0; 28262a856b9aSJohnny Huang int bit_offset; 28272a856b9aSJohnny Huang int value; 28282a856b9aSJohnny Huang int ret; 2829030cb4a7SJohnny Huang u32 otp_strap_pro; 28302a856b9aSJohnny Huang 28312a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 28322a856b9aSJohnny Huang return CMD_RET_USAGE; 28332a856b9aSJohnny Huang 28342a856b9aSJohnny Huang /* Drop the pb cmd */ 28352a856b9aSJohnny Huang argc--; 28362a856b9aSJohnny Huang argv++; 28372a856b9aSJohnny Huang 28382a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2839a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 28402a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2841a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 28422a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2843a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2844cd1610b4SJohnny Huang else 28452a856b9aSJohnny Huang return CMD_RET_USAGE; 28462a856b9aSJohnny Huang 28472a856b9aSJohnny Huang /* Drop the region cmd */ 28482a856b9aSJohnny Huang argc--; 28492a856b9aSJohnny Huang argv++; 28502a856b9aSJohnny Huang 2851ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2852cd1610b4SJohnny Huang nconfirm = 1; 28532a856b9aSJohnny Huang /* Drop the force option */ 28542a856b9aSJohnny Huang argc--; 28552a856b9aSJohnny Huang argv++; 28562a856b9aSJohnny Huang } 2857cd1610b4SJohnny Huang 2858a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 28592a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 28602a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 28610808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 28622a856b9aSJohnny Huang return CMD_RET_USAGE; 2863cd1610b4SJohnny Huang } else { 28642a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 28652a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 28662a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 28670808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 28682a856b9aSJohnny Huang return CMD_RET_USAGE; 28690808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 287078855207SJohnny Huang if (otp_addr >= 0x800) 28710808cc55SJohnny Huang return CMD_RET_USAGE; 28720808cc55SJohnny Huang } else { 287378855207SJohnny Huang if (otp_addr >= 0x20) 28740808cc55SJohnny Huang return CMD_RET_USAGE; 28750808cc55SJohnny Huang } 2876cd1610b4SJohnny Huang } 2877cd1610b4SJohnny Huang if (value != 0 && value != 1) 28782a856b9aSJohnny Huang return CMD_RET_USAGE; 2879cd1610b4SJohnny Huang 2880030cb4a7SJohnny Huang ret = 0; 2881030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2882030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2883030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2884030cb4a7SJohnny Huang } 2885030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2886030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2887030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2888030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2889030cb4a7SJohnny Huang ret = -1; 2890030cb4a7SJohnny Huang } 2891030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2892030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2893030cb4a7SJohnny Huang ret = -1; 2894030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2895030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2896030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2897030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2898030cb4a7SJohnny Huang ret = -1; 2899030cb4a7SJohnny Huang } 2900030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2901030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2902030cb4a7SJohnny Huang ret = -1; 2903030cb4a7SJohnny Huang } 2904030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2905030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2906030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2907030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2908030cb4a7SJohnny Huang ret = -1; 2909030cb4a7SJohnny Huang } 2910030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2911030cb4a7SJohnny Huang u32 otp_rid[2]; 2912030cb4a7SJohnny Huang u32 sw_rid[2]; 2913030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2914030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2915030cb4a7SJohnny Huang 2916030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2917030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2918030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2919030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2920030cb4a7SJohnny Huang 2921030cb4a7SJohnny Huang if (otp_addr == 10) 2922030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2923030cb4a7SJohnny Huang else 2924030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2925030cb4a7SJohnny Huang 2926030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2927030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2928030cb4a7SJohnny Huang ret = -1; 2929030cb4a7SJohnny Huang } 2930030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2931030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2932030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2933030cb4a7SJohnny Huang ret = -1; 2934030cb4a7SJohnny Huang } else { 2935030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2936030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2937030cb4a7SJohnny Huang u32 key_num; 2938030cb4a7SJohnny Huang u32 retire; 2939030cb4a7SJohnny Huang 2940030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2941030cb4a7SJohnny Huang if (bit_offset >= 16) 2942030cb4a7SJohnny Huang retire = bit_offset - 16; 2943030cb4a7SJohnny Huang else 2944030cb4a7SJohnny Huang retire = bit_offset; 2945030cb4a7SJohnny Huang if (retire >= key_num) { 2946030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2947030cb4a7SJohnny Huang ret = -1; 2948030cb4a7SJohnny Huang } 2949030cb4a7SJohnny Huang } 2950030cb4a7SJohnny Huang } 2951030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2952030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2953030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2954030cb4a7SJohnny Huang ret = -1; 2955030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2956030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2957030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2958030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2959030cb4a7SJohnny Huang else 2960030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2961030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2962b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset); 2963030cb4a7SJohnny Huang ret = -1; 2964030cb4a7SJohnny Huang } 2965030cb4a7SJohnny Huang } 2966030cb4a7SJohnny Huang } 2967030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2968030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2969030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2970030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2971030cb4a7SJohnny Huang ret = -1; 2972030cb4a7SJohnny Huang } 2973030cb4a7SJohnny Huang } 2974030cb4a7SJohnny Huang 2975030cb4a7SJohnny Huang if (ret == -1) 2976030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2977030cb4a7SJohnny Huang 2978f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 29792a856b9aSJohnny Huang 29802a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 29812a856b9aSJohnny Huang return CMD_RET_SUCCESS; 29822a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 29832a856b9aSJohnny Huang return CMD_RET_FAILURE; 29842a856b9aSJohnny Huang else 29852a856b9aSJohnny Huang return CMD_RET_USAGE; 29862a856b9aSJohnny Huang } 29872a856b9aSJohnny Huang 29882a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 29892a856b9aSJohnny Huang { 29902a856b9aSJohnny Huang phys_addr_t addr; 29912a856b9aSJohnny Huang int otp_addr = 0; 2992b8590031SJohnny Huang int ret; 29932a856b9aSJohnny Huang 29942a856b9aSJohnny Huang if (argc != 3) 29952a856b9aSJohnny Huang return CMD_RET_USAGE; 29962a856b9aSJohnny Huang 29972a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 29982a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 2999b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 3000b8590031SJohnny Huang if (ret == 0) { 300169d5fd8fSJohnny Huang printf("Compare pass\n"); 30022a856b9aSJohnny Huang return CMD_RET_SUCCESS; 3003a219f6deSJohnny Huang } 300469d5fd8fSJohnny Huang printf("Compare fail\n"); 30052a856b9aSJohnny Huang return CMD_RET_FAILURE; 300669d5fd8fSJohnny Huang } 300769d5fd8fSJohnny Huang 300866f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 300966f2f8e5SJohnny Huang { 3010a8bd6d8cSJohnny Huang int view = 0; 30112d4b0742SJohnny Huang int input; 3012a8bd6d8cSJohnny Huang 3013a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 301466f2f8e5SJohnny Huang return CMD_RET_USAGE; 301566f2f8e5SJohnny Huang 30162d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 30172d4b0742SJohnny Huang if (argc == 3) { 30182d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 30192d4b0742SJohnny Huang otp_print_conf_info(input); 30202d4b0742SJohnny Huang } else { 30212d4b0742SJohnny Huang otp_print_conf_info(-1); 30222d4b0742SJohnny Huang } 30232d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 30242d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 3025a8bd6d8cSJohnny Huang view = 1; 3026a8bd6d8cSJohnny Huang /* Drop the view option */ 3027a8bd6d8cSJohnny Huang argc--; 3028a8bd6d8cSJohnny Huang argv++; 3029a8bd6d8cSJohnny Huang } 3030b458cd62SJohnny Huang otp_print_strap_info(view); 30310dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 30320dc9a440SJohnny Huang otp_print_scu_info(); 303388bd7d58SJohnny Huang } else if (!strcmp(argv[1], "key")) { 303488bd7d58SJohnny Huang otp_print_key_info(); 303566f2f8e5SJohnny Huang } else { 303666f2f8e5SJohnny Huang return CMD_RET_USAGE; 303766f2f8e5SJohnny Huang } 30382d4b0742SJohnny Huang 303966f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 304066f2f8e5SJohnny Huang } 304166f2f8e5SJohnny Huang 30420dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3043737ed20bSJohnny Huang { 30440dc9a440SJohnny Huang u32 input; 30450dc9a440SJohnny Huang u32 bit_offset; 3046e14b073cSJohnny Huang u32 prog_address; 3047030cb4a7SJohnny Huang char force; 304883655e91SJohnny Huang int ret; 3049a219f6deSJohnny Huang 3050737ed20bSJohnny Huang if (argc != 3 && argc != 2) 3051737ed20bSJohnny Huang return CMD_RET_USAGE; 3052737ed20bSJohnny Huang 3053e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 3054737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 3055030cb4a7SJohnny Huang force = 1; 3056737ed20bSJohnny Huang } else { 3057737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 3058030cb4a7SJohnny Huang force = 0; 3059737ed20bSJohnny Huang } 3060737ed20bSJohnny Huang 3061737ed20bSJohnny Huang if (input < 32) { 3062737ed20bSJohnny Huang bit_offset = input; 30630dc9a440SJohnny Huang prog_address = 0xe0c; 3064737ed20bSJohnny Huang } else if (input < 64) { 3065737ed20bSJohnny Huang bit_offset = input - 32; 30660dc9a440SJohnny Huang prog_address = 0xe0e; 3067737ed20bSJohnny Huang } else { 3068737ed20bSJohnny Huang return CMD_RET_USAGE; 3069737ed20bSJohnny Huang } 3070737ed20bSJohnny Huang 3071030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 3072030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 3073030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3074030cb4a7SJohnny Huang } 3075030cb4a7SJohnny Huang 3076030cb4a7SJohnny Huang if (!force) { 3077b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input); 3078030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 3079030cb4a7SJohnny Huang if (!confirm_yesno()) { 3080030cb4a7SJohnny Huang printf(" Aborting\n"); 3081030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3082030cb4a7SJohnny Huang } 3083030cb4a7SJohnny Huang } 3084030cb4a7SJohnny Huang 3085e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 3086b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input); 3087e14b073cSJohnny Huang return CMD_RET_SUCCESS; 3088e14b073cSJohnny Huang } 3089de6fbf1cSJohnny Huang 3090f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 3091de6fbf1cSJohnny Huang otp_soak(0); 309283655e91SJohnny Huang 309383655e91SJohnny Huang if (ret) { 3094b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input); 3095737ed20bSJohnny Huang return CMD_RET_FAILURE; 3096737ed20bSJohnny Huang } 30979a4fe690SJohnny Huang 3098b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input); 3099794e27ecSJohnny Huang return CMD_RET_SUCCESS; 3100794e27ecSJohnny Huang } 3101794e27ecSJohnny Huang 31020dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3103e14b073cSJohnny Huang { 31040dc9a440SJohnny Huang u32 scu_offset; 31050dc9a440SJohnny Huang u32 bit_offset; 31060dc9a440SJohnny Huang u32 conf_offset; 31070dc9a440SJohnny Huang u32 prog_address; 31080dc9a440SJohnny Huang char force; 31090dc9a440SJohnny Huang int ret; 31100dc9a440SJohnny Huang 31110dc9a440SJohnny Huang if (argc != 4 && argc != 3) 31120dc9a440SJohnny Huang return CMD_RET_USAGE; 31130dc9a440SJohnny Huang 31140dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 31150dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 31160dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 31170dc9a440SJohnny Huang force = 1; 31180dc9a440SJohnny Huang } else { 31190dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 31200dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 31210dc9a440SJohnny Huang force = 0; 31220dc9a440SJohnny Huang } 31230dc9a440SJohnny Huang if (scu_offset == 0x500) { 31240dc9a440SJohnny Huang prog_address = 0xe08; 31250dc9a440SJohnny Huang conf_offset = 28; 31260dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 31270dc9a440SJohnny Huang prog_address = 0xe0a; 31280dc9a440SJohnny Huang conf_offset = 29; 31290dc9a440SJohnny Huang } else { 31300dc9a440SJohnny Huang return CMD_RET_USAGE; 31310dc9a440SJohnny Huang } 31320dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 31330dc9a440SJohnny Huang return CMD_RET_USAGE; 3134030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 3135030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 3136030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3137030cb4a7SJohnny Huang } 31380dc9a440SJohnny Huang if (!force) { 3139b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset); 3140b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset); 31410dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 31420dc9a440SJohnny Huang if (!confirm_yesno()) { 31430dc9a440SJohnny Huang printf(" Aborting\n"); 31440dc9a440SJohnny Huang return CMD_RET_FAILURE; 31450dc9a440SJohnny Huang } 3146e14b073cSJohnny Huang } 3147e14b073cSJohnny Huang 31480dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 3149b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset); 31500dc9a440SJohnny Huang return CMD_RET_SUCCESS; 31510dc9a440SJohnny Huang } 31520dc9a440SJohnny Huang 31530dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 31540dc9a440SJohnny Huang otp_soak(0); 31550dc9a440SJohnny Huang 31560dc9a440SJohnny Huang if (ret) { 3157b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset); 31580dc9a440SJohnny Huang return CMD_RET_FAILURE; 31590dc9a440SJohnny Huang } 31600dc9a440SJohnny Huang 3161b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset); 31620dc9a440SJohnny Huang return CMD_RET_SUCCESS; 3163e14b073cSJohnny Huang } 3164e14b073cSJohnny Huang 3165f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3166f67375f7SJohnny Huang { 3167e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 3168f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 3169f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 3170f67375f7SJohnny Huang 3171f67375f7SJohnny Huang return CMD_RET_SUCCESS; 3172f67375f7SJohnny Huang } 3173f67375f7SJohnny Huang 3174794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3175794e27ecSJohnny Huang { 3176794e27ecSJohnny Huang u32 update_num; 3177794e27ecSJohnny Huang int force = 0; 3178794e27ecSJohnny Huang int ret; 3179794e27ecSJohnny Huang 3180794e27ecSJohnny Huang if (argc == 3) { 3181794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 3182794e27ecSJohnny Huang return CMD_RET_USAGE; 3183794e27ecSJohnny Huang force = 1; 3184794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 3185794e27ecSJohnny Huang } else if (argc == 2) { 3186794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 3187794e27ecSJohnny Huang } else { 3188794e27ecSJohnny Huang return CMD_RET_USAGE; 3189794e27ecSJohnny Huang } 3190794e27ecSJohnny Huang 3191794e27ecSJohnny Huang if (update_num > 64) 3192794e27ecSJohnny Huang return CMD_RET_USAGE; 3193794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 3194b8590031SJohnny Huang 3195794e27ecSJohnny Huang if (ret) 3196794e27ecSJohnny Huang return CMD_RET_FAILURE; 3197794e27ecSJohnny Huang return CMD_RET_SUCCESS; 3198794e27ecSJohnny Huang } 3199794e27ecSJohnny Huang 3200794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3201794e27ecSJohnny Huang { 3202794e27ecSJohnny Huang u32 otp_rid[2]; 3203a8789b47SJohnny Huang u32 sw_rid[2]; 3204794e27ecSJohnny Huang int rid_num = 0; 3205a8789b47SJohnny Huang int sw_rid_num = 0; 3206794e27ecSJohnny Huang int ret; 3207794e27ecSJohnny Huang 3208794e27ecSJohnny Huang if (argc != 1) 3209794e27ecSJohnny Huang return CMD_RET_USAGE; 3210794e27ecSJohnny Huang 3211f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 3212f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 3213794e27ecSJohnny Huang 3214a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 3215a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 3216794e27ecSJohnny Huang 3217a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 3218a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 3219a8789b47SJohnny Huang 3220030cb4a7SJohnny Huang if (sw_rid_num < 0) { 3221030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 3222030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 3223030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 3224030cb4a7SJohnny Huang } else { 3225a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 3226030cb4a7SJohnny Huang } 3227794e27ecSJohnny Huang if (rid_num >= 0) { 3228794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 3229794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 3230794e27ecSJohnny Huang } else { 3231b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n" 3232b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n" 3233794e27ecSJohnny Huang "current OTP revision ID\n"); 3234794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 3235794e27ecSJohnny Huang } 3236794e27ecSJohnny Huang otp_print_revid(otp_rid); 3237794e27ecSJohnny Huang 3238794e27ecSJohnny Huang return ret; 3239794e27ecSJohnny Huang } 3240794e27ecSJohnny Huang 3241883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3242883625c5SJohnny Huang { 3243883625c5SJohnny Huang u32 retire_id; 3244883625c5SJohnny Huang int force = 0; 3245883625c5SJohnny Huang int ret; 3246883625c5SJohnny Huang 3247883625c5SJohnny Huang if (argc == 3) { 3248883625c5SJohnny Huang if (strcmp(argv[1], "o")) 3249883625c5SJohnny Huang return CMD_RET_USAGE; 3250883625c5SJohnny Huang force = 1; 3251883625c5SJohnny Huang retire_id = simple_strtoul(argv[2], NULL, 16); 3252883625c5SJohnny Huang } else if (argc == 2) { 3253883625c5SJohnny Huang retire_id = simple_strtoul(argv[1], NULL, 16); 3254883625c5SJohnny Huang } else { 3255883625c5SJohnny Huang return CMD_RET_USAGE; 3256883625c5SJohnny Huang } 3257883625c5SJohnny Huang 3258883625c5SJohnny Huang if (retire_id > 7) 3259883625c5SJohnny Huang return CMD_RET_USAGE; 3260883625c5SJohnny Huang ret = otp_retire_key(retire_id, force); 3261883625c5SJohnny Huang 3262883625c5SJohnny Huang if (ret) 3263883625c5SJohnny Huang return CMD_RET_FAILURE; 3264883625c5SJohnny Huang return CMD_RET_SUCCESS; 3265883625c5SJohnny Huang } 3266883625c5SJohnny Huang 3267e7e21c44SJohnny Huang static int do_otpverify(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3268e7e21c44SJohnny Huang { 3269e7e21c44SJohnny Huang phys_addr_t addr; 3270e7e21c44SJohnny Huang int ret; 3271e7e21c44SJohnny Huang 3272e7e21c44SJohnny Huang if (argc == 2) { 3273e7e21c44SJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 3274e7e21c44SJohnny Huang ret = otp_verify_boot_image(addr); 3275e7e21c44SJohnny Huang } else { 3276e7e21c44SJohnny Huang return CMD_RET_USAGE; 3277e7e21c44SJohnny Huang } 3278e7e21c44SJohnny Huang 3279e7e21c44SJohnny Huang if (ret == OTP_SUCCESS) 3280e7e21c44SJohnny Huang return CMD_RET_SUCCESS; 3281e7e21c44SJohnny Huang else if (ret == OTP_FAILURE) 3282e7e21c44SJohnny Huang return CMD_RET_FAILURE; 3283e7e21c44SJohnny Huang else 3284e7e21c44SJohnny Huang return CMD_RET_USAGE; 3285e7e21c44SJohnny Huang } 3286e7e21c44SJohnny Huang 3287418822f0SJohnny Huang static int do_otpinvalid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3288418822f0SJohnny Huang { 3289418822f0SJohnny Huang u32 header_offset; 3290418822f0SJohnny Huang int force = 0; 3291418822f0SJohnny Huang int ret; 3292418822f0SJohnny Huang 3293418822f0SJohnny Huang if (argc == 3) { 3294418822f0SJohnny Huang if (strcmp(argv[1], "o")) 3295418822f0SJohnny Huang return CMD_RET_USAGE; 3296418822f0SJohnny Huang force = 1; 3297418822f0SJohnny Huang header_offset = simple_strtoul(argv[2], NULL, 16); 3298418822f0SJohnny Huang } else if (argc == 2) { 3299418822f0SJohnny Huang header_offset = simple_strtoul(argv[1], NULL, 16); 3300418822f0SJohnny Huang } else { 3301418822f0SJohnny Huang return CMD_RET_USAGE; 3302418822f0SJohnny Huang } 3303418822f0SJohnny Huang 3304418822f0SJohnny Huang if (header_offset > 16) 3305418822f0SJohnny Huang return CMD_RET_USAGE; 3306418822f0SJohnny Huang ret = otp_invalid_key(header_offset, force); 3307418822f0SJohnny Huang 3308418822f0SJohnny Huang if (ret) 3309418822f0SJohnny Huang return CMD_RET_FAILURE; 3310418822f0SJohnny Huang return CMD_RET_SUCCESS; 3311418822f0SJohnny Huang } 3312418822f0SJohnny Huang 33132a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 3314f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 33152a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 3316a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 3317de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 33182a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 3319737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 33200dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 33212a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 3322794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 3323794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 3324883625c5SJohnny Huang U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""), 3325e7e21c44SJohnny Huang U_BOOT_CMD_MKENT(verify, 2, 0, do_otpverify, "", ""), 3326418822f0SJohnny Huang U_BOOT_CMD_MKENT(invalid, 3, 0, do_otpinvalid, "", ""), 33272a856b9aSJohnny Huang }; 33282a856b9aSJohnny Huang 33292a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 33302a856b9aSJohnny Huang { 3331030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 33322a856b9aSJohnny Huang cmd_tbl_t *cp; 3333a219f6deSJohnny Huang u32 ver; 3334e14b073cSJohnny Huang int ret; 3335030cb4a7SJohnny Huang u32 otp_conf0; 33362a856b9aSJohnny Huang 33372a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 33382a856b9aSJohnny Huang 3339737ed20bSJohnny Huang /* Drop the otp command */ 33402a856b9aSJohnny Huang argc--; 33412a856b9aSJohnny Huang argv++; 33422a856b9aSJohnny Huang 3343a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 33442a856b9aSJohnny Huang return CMD_RET_USAGE; 33452a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 33462a856b9aSJohnny Huang return CMD_RET_SUCCESS; 33472a856b9aSJohnny Huang 33480dae9d52SJohnny Huang ver = chip_version(); 33490dae9d52SJohnny Huang switch (ver) { 3350e417205bSJohnny Huang case OTP_A0: 3351e417205bSJohnny Huang info_cb.version = OTP_A0; 33529a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 33539a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 33549a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 33559a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 33569a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 33579a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 3358e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 33590dae9d52SJohnny Huang break; 3360e417205bSJohnny Huang case OTP_A1: 3361e417205bSJohnny Huang info_cb.version = OTP_A1; 33623cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 33633cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 33643cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 33653cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 33669a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 33679a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 33680dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33690dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3370e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 33710dae9d52SJohnny Huang break; 3372e417205bSJohnny Huang case OTP_A2: 3373e417205bSJohnny Huang info_cb.version = OTP_A2; 33745fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 33755fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 3376fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 3377fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 33785fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 33795fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 33800dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33810dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3382e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 33830dae9d52SJohnny Huang break; 3384e417205bSJohnny Huang case OTP_A3: 3385e417205bSJohnny Huang info_cb.version = OTP_A3; 3386b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 3387b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 3388fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 3389fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 3390181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 3391181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 33920dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33930dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3394e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 339564b66712SJohnny Huang break; 33960dae9d52SJohnny Huang default: 3397f1be5099SJohnny Huang printf("SOC is not supported\n"); 33980dae9d52SJohnny Huang return CMD_RET_FAILURE; 33999a4fe690SJohnny Huang } 34009a4fe690SJohnny Huang 3401030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 3402030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 3403030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 3404030cb4a7SJohnny Huang 3405030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 3406030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 3407030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 3408030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 3409030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 3410030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 3411030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 3412030cb4a7SJohnny Huang 3413e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 3414b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 3415e14b073cSJohnny Huang 3416e14b073cSJohnny Huang return ret; 341769d5fd8fSJohnny Huang } 341869d5fd8fSJohnny Huang 3419a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 342069d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 3421f67375f7SJohnny Huang "version\n" 3422f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 34232a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 34242d4b0742SJohnny Huang "otp info strap [v]\n" 34252d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 34260dc9a440SJohnny Huang "otp info scu\n" 342788bd7d58SJohnny Huang "otp info key\n" 3428de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 3429ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 3430ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 3431ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 34320dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 3433794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 3434794e27ecSJohnny Huang "otp rid\n" 3435883625c5SJohnny Huang "otp retire [o] <key_id>\n" 3436e7e21c44SJohnny Huang "otp verify <addr>\n" 3437418822f0SJohnny Huang "otp invalid [o] <header_offset>\n" 343869d5fd8fSJohnny Huang ); 3439