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 { 13622fda007SJoel Stanley int value: 4; 13722fda007SJoel Stanley int key_type: 4; 13822fda007SJoel Stanley int order: 1; 13922fda007SJoel Stanley int need_id: 1; 14022fda007SJoel 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; 1370*bf54cdd1SJammy Huang struct otpkey_type key_info = { .value = -1 }; 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 1384418822f0SJohnny Huang for (i = 0; i < info_cb.key_info_len; i++) { 1385418822f0SJohnny Huang if (key_type == key_info_array[i].value) { 1386418822f0SJohnny Huang key_info = key_info_array[i]; 13879a4fe690SJohnny Huang break; 13889a4fe690SJohnny Huang } 13899a4fe690SJohnny Huang } 139088bd7d58SJohnny Huang if (key_info.value == -1) 1391418822f0SJohnny Huang return; 13929a4fe690SJohnny Huang 139369d5fd8fSJohnny Huang printf("Key Type: "); 13949a4fe690SJohnny Huang printf("%s\n", key_info.information); 13959a4fe690SJohnny Huang 13969a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 139769d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 139869d5fd8fSJohnny Huang switch (key_length) { 139969d5fd8fSJohnny Huang case 0: 140069d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 140169d5fd8fSJohnny Huang break; 140269d5fd8fSJohnny Huang case 1: 140369d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 140469d5fd8fSJohnny Huang break; 140569d5fd8fSJohnny Huang case 2: 140669d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 140769d5fd8fSJohnny Huang break; 140869d5fd8fSJohnny Huang case 3: 140969d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 141069d5fd8fSJohnny Huang break; 141169d5fd8fSJohnny Huang } 1412181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1413181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 141469d5fd8fSJohnny Huang printf("RSA SHA Type: "); 141569d5fd8fSJohnny Huang switch (key_length) { 141669d5fd8fSJohnny Huang case 0: 141769d5fd8fSJohnny Huang printf("RSA1024\n"); 141869d5fd8fSJohnny Huang len = 0x100; 141969d5fd8fSJohnny Huang break; 142069d5fd8fSJohnny Huang case 1: 142169d5fd8fSJohnny Huang printf("RSA2048\n"); 142269d5fd8fSJohnny Huang len = 0x200; 142369d5fd8fSJohnny Huang break; 142469d5fd8fSJohnny Huang case 2: 142569d5fd8fSJohnny Huang printf("RSA3072\n"); 142669d5fd8fSJohnny Huang len = 0x300; 142769d5fd8fSJohnny Huang break; 142869d5fd8fSJohnny Huang case 3: 142969d5fd8fSJohnny Huang printf("RSA4096\n"); 143069d5fd8fSJohnny Huang len = 0x400; 143169d5fd8fSJohnny Huang break; 143269d5fd8fSJohnny Huang } 143369d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 143469d5fd8fSJohnny Huang } 14359a4fe690SJohnny Huang if (key_info.need_id) 143669d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 1437418822f0SJohnny Huang if (!data) 1438418822f0SJohnny Huang return; 143969d5fd8fSJohnny Huang printf("Key Value:\n"); 14409a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 1441418822f0SJohnny Huang buf_print(&data[key_offset], 0x40); 14429a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 14439a4fe690SJohnny Huang printf("AES Key:\n"); 1444418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 1445e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 14469a4fe690SJohnny Huang printf("AES IV:\n"); 1447418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x10); 14489a4fe690SJohnny Huang } 14499a4fe690SJohnny Huang 14509a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1451e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 145269d5fd8fSJohnny Huang printf("AES Key:\n"); 1453418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 145469d5fd8fSJohnny Huang printf("AES IV:\n"); 1455418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x10); 14565fdde29fSJohnny Huang } else { 14579a4fe690SJohnny Huang printf("AES Key 1:\n"); 1458418822f0SJohnny Huang buf_print(&data[key_offset], 0x20); 14599a4fe690SJohnny Huang printf("AES Key 2:\n"); 1460418822f0SJohnny Huang buf_print(&data[key_offset + 0x20], 0x20); 14619a4fe690SJohnny Huang } 1462181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 146369d5fd8fSJohnny Huang printf("RSA mod:\n"); 1464418822f0SJohnny Huang buf_print(&data[key_offset], len / 2); 146569d5fd8fSJohnny Huang printf("RSA exp:\n"); 1466418822f0SJohnny Huang buf_print(&data[key_offset + (len / 2)], len / 2); 1467181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1468181f72d8SJohnny Huang printf("RSA mod:\n"); 1469418822f0SJohnny Huang buf_print(&data[key_offset], len / 2); 1470181f72d8SJohnny Huang printf("RSA exp:\n"); 1471a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 147269d5fd8fSJohnny Huang } 1473418822f0SJohnny Huang } 1474418822f0SJohnny Huang 1475418822f0SJohnny Huang static void otp_print_key(u32 *data) 1476418822f0SJohnny Huang { 1477418822f0SJohnny Huang int i; 1478418822f0SJohnny Huang int last; 1479418822f0SJohnny Huang u8 *byte_buf; 1480418822f0SJohnny Huang int empty; 1481418822f0SJohnny Huang 1482418822f0SJohnny Huang byte_buf = (u8 *)data; 1483418822f0SJohnny Huang 1484418822f0SJohnny Huang empty = 1; 1485418822f0SJohnny Huang for (i = 0; i < 16; i++) { 1486418822f0SJohnny Huang if (i % 2) { 1487418822f0SJohnny Huang if (data[i] != 0xffffffff) 1488418822f0SJohnny Huang empty = 0; 1489418822f0SJohnny Huang } else { 1490418822f0SJohnny Huang if (data[i] != 0) 1491418822f0SJohnny Huang empty = 0; 1492418822f0SJohnny Huang } 1493418822f0SJohnny Huang } 1494418822f0SJohnny Huang if (empty) { 1495418822f0SJohnny Huang printf("OTP data header is empty\n"); 1496418822f0SJohnny Huang return; 1497418822f0SJohnny Huang } 1498418822f0SJohnny Huang 1499418822f0SJohnny Huang for (i = 0; i < 16; i++) { 1500418822f0SJohnny Huang last = (data[i] >> 13) & 1; 1501418822f0SJohnny Huang _otp_print_key(data[i], i, byte_buf); 150269d5fd8fSJohnny Huang if (last) 150369d5fd8fSJohnny Huang break; 150469d5fd8fSJohnny Huang } 150588bd7d58SJohnny Huang } 150688bd7d58SJohnny Huang 150788bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 150888bd7d58SJohnny Huang { 150988bd7d58SJohnny Huang u32 *buf; 151088bd7d58SJohnny Huang 151188bd7d58SJohnny Huang buf = (u32 *)image_layout->data; 1512418822f0SJohnny Huang otp_print_key(buf); 151388bd7d58SJohnny Huang 1514f347c284SJohnny Huang return OTP_SUCCESS; 1515f347c284SJohnny Huang } 1516f347c284SJohnny Huang 151788bd7d58SJohnny Huang static void otp_print_key_info(void) 151888bd7d58SJohnny Huang { 151988bd7d58SJohnny Huang u32 data[2048]; 152088bd7d58SJohnny Huang int i; 152188bd7d58SJohnny Huang 152288bd7d58SJohnny Huang for (i = 0; i < 2048 ; i += 2) 152388bd7d58SJohnny Huang otp_read_data(i, &data[i]); 152488bd7d58SJohnny Huang 1525418822f0SJohnny Huang otp_print_key(data); 152688bd7d58SJohnny Huang } 152788bd7d58SJohnny Huang 1528b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data) 1529f347c284SJohnny Huang { 1530f347c284SJohnny Huang int i; 1531f347c284SJohnny Huang int ret; 1532f347c284SJohnny Huang u32 *buf; 1533f347c284SJohnny Huang u32 *buf_ignore; 1534f347c284SJohnny Huang 1535f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1536f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1537f347c284SJohnny Huang printf("Start Programing...\n"); 1538f347c284SJohnny Huang 1539f347c284SJohnny Huang // programing ecc region first 1540f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1541f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1542f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1543f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1544f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1545f347c284SJohnny Huang return ret; 1546f347c284SJohnny Huang } 1547f347c284SJohnny Huang } 1548f347c284SJohnny Huang 1549f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1550f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1551f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1552f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1553f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1554f347c284SJohnny Huang return ret; 1555f347c284SJohnny Huang } 1556f347c284SJohnny Huang } 1557f347c284SJohnny Huang otp_soak(0); 1558f347c284SJohnny Huang return OTP_SUCCESS; 1559f347c284SJohnny Huang } 1560f347c284SJohnny Huang 1561b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1562f347c284SJohnny Huang { 1563f347c284SJohnny Huang u32 *strap; 1564f347c284SJohnny Huang u32 *strap_ignore; 1565f347c284SJohnny Huang u32 *strap_pro; 1566f347c284SJohnny Huang u32 prog_address; 1567f347c284SJohnny Huang int i; 15687e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1569f347c284SJohnny Huang int fail = 0; 1570f347c284SJohnny Huang int ret; 1571f347c284SJohnny Huang int prog_flag = 0; 1572f347c284SJohnny Huang 1573f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1574f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1575f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1576f347c284SJohnny Huang 1577f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1578f347c284SJohnny Huang prog_address = 0x800; 1579f347c284SJohnny Huang if (i < 32) { 1580f347c284SJohnny Huang offset = i; 1581f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1582f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1583f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1584f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1585f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1586f347c284SJohnny Huang 1587f347c284SJohnny Huang } else { 1588f347c284SJohnny Huang offset = (i - 32); 1589f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1590f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1591f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1592f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1593f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1594f347c284SJohnny Huang } 1595f347c284SJohnny Huang 1596f347c284SJohnny Huang if (ibit == 1) 1597f347c284SJohnny Huang continue; 1598f347c284SJohnny Huang if (bit == otpstrap[i].value) 1599f347c284SJohnny Huang prog_flag = 0; 1600f347c284SJohnny Huang else 1601f347c284SJohnny Huang prog_flag = 1; 1602f347c284SJohnny Huang 1603f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1604f347c284SJohnny Huang fail = 1; 1605f347c284SJohnny Huang continue; 1606f347c284SJohnny Huang } 1607f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1608f347c284SJohnny Huang fail = 1; 1609f347c284SJohnny Huang continue; 1610f347c284SJohnny Huang } 1611f347c284SJohnny Huang 1612f347c284SJohnny Huang if (prog_flag) { 1613f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1614f347c284SJohnny Huang if (ret) 1615f347c284SJohnny Huang return OTP_FAILURE; 1616f347c284SJohnny Huang } 1617f347c284SJohnny Huang 1618f347c284SJohnny Huang if (pbit != 0) { 1619f347c284SJohnny Huang prog_address = 0x800; 1620f347c284SJohnny Huang if (i < 32) 1621f347c284SJohnny Huang prog_address |= 0x60c; 1622f347c284SJohnny Huang else 1623f347c284SJohnny Huang prog_address |= 0x60e; 1624f347c284SJohnny Huang 1625f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1626f347c284SJohnny Huang if (ret) 1627f347c284SJohnny Huang return OTP_FAILURE; 1628f347c284SJohnny Huang } 1629f347c284SJohnny Huang } 1630f347c284SJohnny Huang otp_soak(0); 1631f347c284SJohnny Huang if (fail == 1) 1632f347c284SJohnny Huang return OTP_FAILURE; 1633f347c284SJohnny Huang return OTP_SUCCESS; 163469d5fd8fSJohnny Huang } 163569d5fd8fSJohnny Huang 1636b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf) 163769d5fd8fSJohnny Huang { 1638a6d0d645SJohnny Huang int i, k; 1639d90825e2SJohnny Huang int pass = 0; 1640a219f6deSJohnny Huang u32 prog_address; 1641a219f6deSJohnny Huang u32 compare[2]; 1642a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1643a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1644a219f6deSJohnny Huang u32 data_masked; 1645a219f6deSJohnny Huang u32 buf_masked; 16462031a123SJohnny Huang int ret; 164769d5fd8fSJohnny Huang 1648a6d0d645SJohnny Huang printf("Start Programing...\n"); 1649d90825e2SJohnny Huang otp_soak(0); 1650bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 1651b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 16525010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1653a6d0d645SJohnny Huang prog_address = 0x800; 1654a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1655a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1656bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1657bb34a7bfSJohnny Huang pass = 1; 1658a6d0d645SJohnny Huang continue; 1659bb34a7bfSJohnny Huang } 1660de6fbf1cSJohnny Huang 1661de6fbf1cSJohnny Huang otp_soak(1); 16622031a123SJohnny Huang ret = otp_prog_dw(conf[i], conf_ignore[i], prog_address); 16632031a123SJohnny Huang if (ret) 16642031a123SJohnny Huang return OTP_FAILURE; 1665a6d0d645SJohnny Huang 166669d5fd8fSJohnny Huang pass = 0; 166769d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 16685010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1669de6fbf1cSJohnny Huang otp_soak(2); 16702031a123SJohnny Huang ret = otp_prog_dw(compare[0], conf_ignore[i], prog_address); 16712031a123SJohnny Huang if (ret) 16722031a123SJohnny Huang return OTP_FAILURE; 16735010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1674de6fbf1cSJohnny Huang otp_soak(1); 1675de6fbf1cSJohnny Huang } else { 1676de6fbf1cSJohnny Huang pass = 1; 1677de6fbf1cSJohnny Huang break; 1678de6fbf1cSJohnny Huang } 1679a6d0d645SJohnny Huang } else { 168069d5fd8fSJohnny Huang pass = 1; 168169d5fd8fSJohnny Huang break; 168269d5fd8fSJohnny Huang } 168369d5fd8fSJohnny Huang } 1684bb34a7bfSJohnny Huang if (pass == 0) { 1685b64ca396SJohnny Huang printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n", 1686b64ca396SJohnny Huang i, otp_conf[i], conf[i], conf_ignore[i]); 1687bb34a7bfSJohnny Huang break; 1688bb34a7bfSJohnny Huang } 1689a6d0d645SJohnny Huang } 1690a6d0d645SJohnny Huang 1691de6fbf1cSJohnny Huang otp_soak(0); 169269d5fd8fSJohnny Huang if (!pass) 16932a856b9aSJohnny Huang return OTP_FAILURE; 1694a6d0d645SJohnny Huang 16952a856b9aSJohnny Huang return OTP_SUCCESS; 169669d5fd8fSJohnny Huang } 169769d5fd8fSJohnny Huang 1698b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro) 1699b25f02d2SJohnny Huang { 1700b25f02d2SJohnny Huang int i, k; 1701b25f02d2SJohnny Huang int pass = 0; 1702b25f02d2SJohnny Huang u32 prog_address; 1703b25f02d2SJohnny Huang u32 compare[2]; 1704b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1705b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1706b25f02d2SJohnny Huang u32 data_masked; 1707b25f02d2SJohnny Huang u32 buf_masked; 17082031a123SJohnny Huang int ret; 1709b25f02d2SJohnny Huang 1710b25f02d2SJohnny Huang printf("Start Programing...\n"); 1711b25f02d2SJohnny Huang otp_soak(0); 1712b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1713b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1714b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1715b25f02d2SJohnny Huang prog_address = 0xe08 + i * 2; 1716b25f02d2SJohnny Huang if (data_masked == buf_masked) { 1717b25f02d2SJohnny Huang pass = 1; 1718b25f02d2SJohnny Huang continue; 1719b25f02d2SJohnny Huang } 1720b25f02d2SJohnny Huang 1721b25f02d2SJohnny Huang otp_soak(1); 17222031a123SJohnny Huang ret = otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address); 17232031a123SJohnny Huang if (ret) 17242031a123SJohnny Huang return OTP_FAILURE; 1725b25f02d2SJohnny Huang pass = 0; 1726b25f02d2SJohnny Huang for (k = 0; k < RETRY; k++) { 1727b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1728b25f02d2SJohnny Huang otp_soak(2); 17292031a123SJohnny Huang ret = otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address); 17302031a123SJohnny Huang if (ret) 17312031a123SJohnny Huang return OTP_FAILURE; 1732b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1733b25f02d2SJohnny Huang otp_soak(1); 1734b25f02d2SJohnny Huang } else { 1735b25f02d2SJohnny Huang pass = 1; 1736b25f02d2SJohnny Huang break; 1737b25f02d2SJohnny Huang } 1738b25f02d2SJohnny Huang } else { 1739b25f02d2SJohnny Huang pass = 1; 1740b25f02d2SJohnny Huang break; 1741b25f02d2SJohnny Huang } 1742b25f02d2SJohnny Huang } 1743b25f02d2SJohnny Huang if (pass == 0) { 1744b489486eSJohnny Huang printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n", 1745b25f02d2SJohnny Huang i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]); 1746b25f02d2SJohnny Huang break; 1747b25f02d2SJohnny Huang } 1748b25f02d2SJohnny Huang } 1749b25f02d2SJohnny Huang 1750b25f02d2SJohnny Huang otp_soak(0); 1751b25f02d2SJohnny Huang if (!pass) 1752b25f02d2SJohnny Huang return OTP_FAILURE; 1753b25f02d2SJohnny Huang 1754b25f02d2SJohnny Huang return OTP_SUCCESS; 1755b25f02d2SJohnny Huang } 1756b25f02d2SJohnny Huang 1757b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data) 1758b64ca396SJohnny Huang { 1759b64ca396SJohnny Huang int data_dw; 1760b64ca396SJohnny Huang u32 data_masked; 1761b64ca396SJohnny Huang u32 buf_masked; 1762b64ca396SJohnny Huang u32 *buf = (u32 *)image_layout->data; 1763b64ca396SJohnny Huang u32 *buf_ignore = (u32 *)image_layout->data_ignore; 1764b64ca396SJohnny Huang int i; 1765b64ca396SJohnny Huang 1766b64ca396SJohnny Huang data_dw = image_layout->data_length / 4; 1767b64ca396SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1768b64ca396SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1769b64ca396SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1770b64ca396SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1771b64ca396SJohnny Huang if (data_masked == buf_masked) 1772b64ca396SJohnny Huang continue; 1773b64ca396SJohnny Huang if (i % 2 == 0) { 1774b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1775b64ca396SJohnny Huang continue; 1776b64ca396SJohnny Huang } else { 1777b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1778b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1779b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1780b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1781b64ca396SJohnny Huang return OTP_FAILURE; 1782b64ca396SJohnny Huang } 1783b64ca396SJohnny Huang } else { 1784b64ca396SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1785b64ca396SJohnny Huang continue; 1786b64ca396SJohnny Huang } else { 1787b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1788b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1789b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1790b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1791b64ca396SJohnny Huang return OTP_FAILURE; 1792b64ca396SJohnny Huang } 1793b64ca396SJohnny Huang } 1794b64ca396SJohnny Huang } 1795b64ca396SJohnny Huang return OTP_SUCCESS; 1796b64ca396SJohnny Huang } 1797b64ca396SJohnny Huang 1798b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1799b64ca396SJohnny Huang { 1800b64ca396SJohnny Huang int i; 1801b64ca396SJohnny Huang u32 *strap; 1802b64ca396SJohnny Huang u32 *strap_ignore; 1803b64ca396SJohnny Huang u32 *strap_pro; 1804b64ca396SJohnny Huang int bit, pbit, ibit; 1805b64ca396SJohnny Huang int fail = 0; 1806b64ca396SJohnny Huang int ret; 1807b64ca396SJohnny Huang 1808b64ca396SJohnny Huang strap = (u32 *)image_layout->strap; 1809b64ca396SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1810b64ca396SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1811b64ca396SJohnny Huang 1812b64ca396SJohnny Huang for (i = 0; i < 64; i++) { 1813b64ca396SJohnny Huang if (i < 32) { 1814b64ca396SJohnny Huang bit = (strap[0] >> i) & 0x1; 1815b64ca396SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1816b64ca396SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1817b64ca396SJohnny Huang } else { 1818b64ca396SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1819b64ca396SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1820b64ca396SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1821b64ca396SJohnny Huang } 1822b64ca396SJohnny Huang 1823b64ca396SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1824b64ca396SJohnny Huang 1825b64ca396SJohnny Huang if (ret == OTP_FAILURE) 1826b64ca396SJohnny Huang fail = 1; 1827b64ca396SJohnny Huang } 1828b64ca396SJohnny Huang if (fail == 1) { 1829b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1830b64ca396SJohnny Huang return OTP_FAILURE; 1831b64ca396SJohnny Huang } 1832b64ca396SJohnny Huang return OTP_SUCCESS; 1833b64ca396SJohnny Huang } 1834b64ca396SJohnny Huang 1835b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf) 1836b64ca396SJohnny Huang { 1837b64ca396SJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1838b64ca396SJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1839b64ca396SJohnny Huang u32 data_masked; 1840b64ca396SJohnny Huang u32 buf_masked; 1841b64ca396SJohnny Huang int i; 1842b64ca396SJohnny Huang 1843b64ca396SJohnny Huang for (i = 0; i < 16; i++) { 1844b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 1845b64ca396SJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1846b64ca396SJohnny Huang if (data_masked == buf_masked) 1847b64ca396SJohnny Huang continue; 1848b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1849b64ca396SJohnny Huang continue; 1850b64ca396SJohnny Huang } else { 1851b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1852b64ca396SJohnny Huang printf("OTPCFG[%X] = %x\n", i, otp_conf[i]); 1853b64ca396SJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 1854b64ca396SJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 1855b64ca396SJohnny Huang return OTP_FAILURE; 1856b64ca396SJohnny Huang } 1857b64ca396SJohnny Huang } 1858b64ca396SJohnny Huang return OTP_SUCCESS; 1859b64ca396SJohnny Huang } 1860b64ca396SJohnny Huang 1861b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro) 1862b25f02d2SJohnny Huang { 1863b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1864b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1865b25f02d2SJohnny Huang u32 data_masked; 1866b25f02d2SJohnny Huang u32 buf_masked; 1867b25f02d2SJohnny Huang int i; 1868b25f02d2SJohnny Huang 1869b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1870b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1871b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1872b25f02d2SJohnny Huang if (data_masked == buf_masked) 1873b25f02d2SJohnny Huang continue; 1874b25f02d2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1875b25f02d2SJohnny Huang continue; 1876b25f02d2SJohnny Huang } else { 1877b25f02d2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1878b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]); 1879b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]); 1880b489486eSJohnny Huang printf("Mask [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]); 1881b25f02d2SJohnny Huang return OTP_FAILURE; 1882b25f02d2SJohnny Huang } 1883b25f02d2SJohnny Huang } 1884b25f02d2SJohnny Huang return OTP_SUCCESS; 1885b25f02d2SJohnny Huang } 1886b25f02d2SJohnny Huang 1887948e73aaSJoel Stanley static void do_hash(const void *data, int data_len, const char *algo_name, uint8_t *value) 1888948e73aaSJoel Stanley { 1889948e73aaSJoel Stanley struct hash_algo *algo; 1890948e73aaSJoel Stanley 1891948e73aaSJoel Stanley if (hash_lookup_algo(algo_name, &algo)) { 1892948e73aaSJoel Stanley debug("Unsupported hash alogrithm\n"); 1893948e73aaSJoel Stanley return; 1894948e73aaSJoel Stanley } 1895948e73aaSJoel Stanley 1896948e73aaSJoel Stanley algo->hash_func_ws(data, data_len, value, algo->chunk_size); 1897948e73aaSJoel Stanley } 1898948e73aaSJoel Stanley 1899e7e21c44SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf, int version) 1900696656c6SJohnny Huang { 1901e7e21c44SJohnny Huang u8 digest_ret[48]; 1902e7e21c44SJohnny Huang int digest_len; 1903696656c6SJohnny Huang 1904e7e21c44SJohnny Huang switch (version) { 1905e7e21c44SJohnny Huang case 1: 1906948e73aaSJoel Stanley do_hash(src_buf, length, "sha256", digest_ret); 1907e7e21c44SJohnny Huang digest_len = 32; 1908e7e21c44SJohnny Huang break; 1909e7e21c44SJohnny Huang case 2: 1910948e73aaSJoel Stanley do_hash(src_buf, length, "sha384", digest_ret); 1911e7e21c44SJohnny Huang digest_len = 48; 1912e7e21c44SJohnny Huang break; 1913e7e21c44SJohnny Huang default: 1914e7e21c44SJohnny Huang return OTP_FAILURE; 1915e7e21c44SJohnny Huang } 1916696656c6SJohnny Huang 1917e7e21c44SJohnny Huang if (!memcmp(digest_buf, digest_ret, digest_len)) 1918f347c284SJohnny Huang return OTP_SUCCESS; 1919f347c284SJohnny Huang return OTP_FAILURE; 1920696656c6SJohnny Huang } 1921696656c6SJohnny Huang 1922f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 192369d5fd8fSJohnny Huang { 192469d5fd8fSJohnny Huang int ret; 192561a6cda7SJohnny Huang int image_soc_ver = 0; 1926696656c6SJohnny Huang struct otp_header *otp_header; 1927696656c6SJohnny Huang struct otp_image_layout image_layout; 1928696656c6SJohnny Huang int image_size; 1929a219f6deSJohnny Huang u8 *buf; 1930a219f6deSJohnny Huang u8 *checksum; 1931b64ca396SJohnny Huang int i; 1932b64ca396SJohnny Huang u32 data[2048]; 1933b64ca396SJohnny Huang u32 conf[16]; 1934b25f02d2SJohnny Huang u32 scu_pro[2]; 1935b64ca396SJohnny Huang struct otpstrap_status otpstrap[64]; 193669d5fd8fSJohnny Huang 1937696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1938696656c6SJohnny Huang if (!otp_header) { 1939030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 19402a856b9aSJohnny Huang return OTP_FAILURE; 194169d5fd8fSJohnny Huang } 1942d90825e2SJohnny Huang 1943696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1944696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1945696656c6SJohnny Huang 1946696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1947696656c6SJohnny Huang 1948696656c6SJohnny Huang if (!buf) { 1949030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 1950696656c6SJohnny Huang return OTP_FAILURE; 1951696656c6SJohnny Huang } 1952696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1953696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1954696656c6SJohnny Huang 1955696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1956030cb4a7SJohnny Huang printf("Image is invalid\n"); 1957696656c6SJohnny Huang return OTP_FAILURE; 1958696656c6SJohnny Huang } 1959696656c6SJohnny Huang 19605010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 19615010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 19625010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 19635010032bSJohnny Huang 19645010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1965696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 19665010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1967696656c6SJohnny Huang 1968696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 19695010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 19705010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 19715010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 19727e523e3bSJohnny Huang 1973b25f02d2SJohnny Huang image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info); 1974b25f02d2SJohnny Huang image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2); 1975b25f02d2SJohnny Huang image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length; 1976b25f02d2SJohnny Huang 19777e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 19787e523e3bSJohnny Huang image_soc_ver = OTP_A0; 197961a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 198061a6cda7SJohnny Huang image_soc_ver = OTP_A1; 198161a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 198261a6cda7SJohnny Huang image_soc_ver = OTP_A2; 198361a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 198461a6cda7SJohnny Huang image_soc_ver = OTP_A3; 1985696656c6SJohnny Huang } else { 1986030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n"); 1987696656c6SJohnny Huang return OTP_FAILURE; 1988696656c6SJohnny Huang } 1989696656c6SJohnny Huang 199061a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 19915e096f11SJohnny Huang printf("Image SOC version is not match to HW SOC version\n"); 19929a4fe690SJohnny Huang return OTP_FAILURE; 19939a4fe690SJohnny Huang } 19949a4fe690SJohnny Huang 1995e7e21c44SJohnny Huang switch (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver)) { 1996e7e21c44SJohnny Huang case 1: 1997e7e21c44SJohnny Huang printf("WARNING: OTP image is not generated by otptool v2.x.x\n"); 1998e7e21c44SJohnny Huang printf("Please use the latest version of otptool to generate OTP image\n"); 1999e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 1); 2000e7e21c44SJohnny Huang break; 2001e7e21c44SJohnny Huang case 2: 2002e7e21c44SJohnny Huang ret = otp_verify_image(buf, image_size, checksum, 2); 2003e7e21c44SJohnny Huang break; 2004e7e21c44SJohnny Huang default: 2005e7e21c44SJohnny Huang printf("OTP image version is not supported\n"); 200661a6cda7SJohnny Huang return OTP_FAILURE; 200761a6cda7SJohnny Huang } 200861a6cda7SJohnny Huang 2009e7e21c44SJohnny Huang if (ret) { 2010030cb4a7SJohnny Huang printf("checksum is invalid\n"); 2011696656c6SJohnny Huang return OTP_FAILURE; 2012d90825e2SJohnny Huang } 20137332532cSJohnny Huang 2014030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2015030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2016030cb4a7SJohnny Huang return OTP_FAILURE; 2017030cb4a7SJohnny Huang } 2018b64ca396SJohnny Huang ret = 0; 2019030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 2020030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2021030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2022030cb4a7SJohnny Huang ret = -1; 2023030cb4a7SJohnny Huang } 2024030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2025030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2026030cb4a7SJohnny Huang ret = -1; 2027030cb4a7SJohnny Huang } 2028b64ca396SJohnny Huang printf("Read OTP Data Region:\n"); 2029b64ca396SJohnny Huang for (i = 0; i < 2048 ; i += 2) 2030b64ca396SJohnny Huang otp_read_data(i, &data[i]); 2031b64ca396SJohnny Huang 2032b64ca396SJohnny Huang printf("Check writable...\n"); 2033b64ca396SJohnny Huang if (otp_check_data_image(&image_layout, data) == OTP_FAILURE) 2034b64ca396SJohnny Huang ret = -1; 2035030cb4a7SJohnny Huang } 2036030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 2037030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2038030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2039030cb4a7SJohnny Huang ret = -1; 2040030cb4a7SJohnny Huang } 2041b64ca396SJohnny Huang printf("Read OTP Config Region:\n"); 2042b64ca396SJohnny Huang for (i = 0; i < 16 ; i++) 2043b64ca396SJohnny Huang otp_read_conf(i, &conf[i]); 2044b64ca396SJohnny Huang 2045b64ca396SJohnny Huang printf("Check writable...\n"); 2046b64ca396SJohnny Huang if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE) 2047b64ca396SJohnny Huang ret = -1; 2048030cb4a7SJohnny Huang } 2049030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 2050030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2051030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2052030cb4a7SJohnny Huang ret = -1; 2053030cb4a7SJohnny Huang } 2054b64ca396SJohnny Huang printf("Read OTP Strap Region:\n"); 2055b64ca396SJohnny Huang otp_strap_status(otpstrap); 2056b64ca396SJohnny Huang 2057b64ca396SJohnny Huang printf("Check writable...\n"); 2058b64ca396SJohnny Huang if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE) 2059b64ca396SJohnny Huang ret = -1; 2060030cb4a7SJohnny Huang } 2061b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2062b25f02d2SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2063b25f02d2SJohnny Huang printf("OTP strap region is protected\n"); 2064b25f02d2SJohnny Huang ret = -1; 2065b25f02d2SJohnny Huang } 2066b25f02d2SJohnny Huang printf("Read SCU Protect Region:\n"); 2067b25f02d2SJohnny Huang otp_read_conf(28, &scu_pro[0]); 2068b25f02d2SJohnny Huang otp_read_conf(29, &scu_pro[1]); 2069b25f02d2SJohnny Huang 2070b25f02d2SJohnny Huang printf("Check writable...\n"); 2071b25f02d2SJohnny Huang if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE) 2072b25f02d2SJohnny Huang ret = -1; 2073b25f02d2SJohnny Huang } 2074030cb4a7SJohnny Huang if (ret == -1) 2075030cb4a7SJohnny Huang return OTP_FAILURE; 2076b64ca396SJohnny Huang 207769d5fd8fSJohnny Huang if (!nconfirm) { 2078696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 20797f795e57SJohnny Huang printf("\nOTP data region :\n"); 2080f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 208169d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 20822a856b9aSJohnny Huang return OTP_FAILURE; 208369d5fd8fSJohnny Huang } 208469d5fd8fSJohnny Huang } 2085696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 20867332532cSJohnny Huang printf("\nOTP configuration region :\n"); 2087696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 20887332532cSJohnny Huang printf("OTP config error, please check.\n"); 20897332532cSJohnny Huang return OTP_FAILURE; 20907332532cSJohnny Huang } 20917332532cSJohnny Huang } 20927adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 20937adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 20947adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 20957adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 20967adec5f6SJohnny Huang return OTP_FAILURE; 20977adec5f6SJohnny Huang } 20987adec5f6SJohnny Huang } 2099b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2100b25f02d2SJohnny Huang printf("\nOTP scu protect region :\n"); 2101b25f02d2SJohnny Huang if (otp_print_scu_image(&image_layout) < 0) { 2102b25f02d2SJohnny Huang printf("OTP scu protect error, please check.\n"); 2103b25f02d2SJohnny Huang return OTP_FAILURE; 2104b25f02d2SJohnny Huang } 2105b25f02d2SJohnny Huang } 21067332532cSJohnny Huang 210769d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 210869d5fd8fSJohnny Huang if (!confirm_yesno()) { 210969d5fd8fSJohnny Huang printf(" Aborting\n"); 21102a856b9aSJohnny Huang return OTP_FAILURE; 211169d5fd8fSJohnny Huang } 211269d5fd8fSJohnny Huang } 21137332532cSJohnny Huang 21145010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 21155010032bSJohnny Huang printf("programing data region ...\n"); 2116b64ca396SJohnny Huang ret = otp_prog_data(&image_layout, data); 21175010032bSJohnny Huang if (ret != 0) { 21185010032bSJohnny Huang printf("Error\n"); 21195010032bSJohnny Huang return ret; 21205010032bSJohnny Huang } 2121a219f6deSJohnny Huang printf("Done\n"); 21225010032bSJohnny Huang } 21235010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 21245010032bSJohnny Huang printf("programing strap region ...\n"); 2125b64ca396SJohnny Huang ret = otp_prog_strap(&image_layout, otpstrap); 21265010032bSJohnny Huang if (ret != 0) { 21275010032bSJohnny Huang printf("Error\n"); 21285010032bSJohnny Huang return ret; 21295010032bSJohnny Huang } 2130a219f6deSJohnny Huang printf("Done\n"); 21315010032bSJohnny Huang } 2132b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2133b25f02d2SJohnny Huang printf("programing scu protect region ...\n"); 2134b25f02d2SJohnny Huang ret = otp_prog_scu_protect(&image_layout, scu_pro); 2135b25f02d2SJohnny Huang if (ret != 0) { 2136b25f02d2SJohnny Huang printf("Error\n"); 2137b25f02d2SJohnny Huang return ret; 2138b25f02d2SJohnny Huang } 2139b25f02d2SJohnny Huang printf("Done\n"); 2140b25f02d2SJohnny Huang } 21415010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 21425010032bSJohnny Huang printf("programing configuration region ...\n"); 2143b64ca396SJohnny Huang ret = otp_prog_conf(&image_layout, conf); 21445010032bSJohnny Huang if (ret != 0) { 21455010032bSJohnny Huang printf("Error\n"); 21465010032bSJohnny Huang return ret; 21475010032bSJohnny Huang } 21485010032bSJohnny Huang printf("Done\n"); 21495010032bSJohnny Huang } 2150cd1610b4SJohnny Huang 21517332532cSJohnny Huang return OTP_SUCCESS; 21522a856b9aSJohnny Huang } 21532a856b9aSJohnny Huang 2154f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 2155cd1610b4SJohnny Huang { 2156a219f6deSJohnny Huang u32 read[2]; 2157a219f6deSJohnny Huang u32 prog_address = 0; 215866f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 2159cd1610b4SJohnny Huang int otp_bit; 216083655e91SJohnny Huang int ret = 0; 2161cd1610b4SJohnny Huang 2162dacbba92SJohnny Huang otp_soak(0); 2163cd1610b4SJohnny Huang switch (mode) { 2164a6d0d645SJohnny Huang case OTP_REGION_CONF: 2165f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 2166cd1610b4SJohnny Huang prog_address = 0x800; 2167cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 2168cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 2169a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2170cd1610b4SJohnny Huang if (otp_bit == value) { 2171b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2172cd1610b4SJohnny Huang printf("No need to program\n"); 21732a856b9aSJohnny Huang return OTP_SUCCESS; 2174cd1610b4SJohnny Huang } 2175cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 2176b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 21770dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 21782a856b9aSJohnny Huang return OTP_FAILURE; 2179cd1610b4SJohnny Huang } 2180b489486eSJohnny Huang printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2181cd1610b4SJohnny Huang break; 2182a6d0d645SJohnny Huang case OTP_REGION_DATA: 2183cd1610b4SJohnny Huang prog_address = otp_dw_offset; 2184cd1610b4SJohnny Huang 2185cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 2186a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 2187a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2188643b9cfdSJohnny Huang 2189643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 2190b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2191b64ca396SJohnny Huang printf("OTP is programmed, which can't be cleared\n"); 2192643b9cfdSJohnny Huang return OTP_FAILURE; 2193643b9cfdSJohnny Huang } 2194cd1610b4SJohnny Huang } else { 2195a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 2196a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 2197643b9cfdSJohnny Huang 2198643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 2199b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2200b64ca396SJohnny Huang printf("OTP is programmed, which can't be written\n"); 2201643b9cfdSJohnny Huang return OTP_FAILURE; 2202643b9cfdSJohnny Huang } 2203cd1610b4SJohnny Huang } 2204cd1610b4SJohnny Huang if (otp_bit == value) { 2205b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2206cd1610b4SJohnny Huang printf("No need to program\n"); 22072a856b9aSJohnny Huang return OTP_SUCCESS; 2208cd1610b4SJohnny Huang } 2209643b9cfdSJohnny Huang 2210b489486eSJohnny Huang printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2211cd1610b4SJohnny Huang break; 2212a6d0d645SJohnny Huang case OTP_REGION_STRAP: 22138848d5dcSJohnny Huang otp_strap_status(otpstrap); 22148848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 22157e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 22168848d5dcSJohnny Huang if (ret == OTP_FAILURE) 22178848d5dcSJohnny Huang return OTP_FAILURE; 22188848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 22198848d5dcSJohnny Huang return OTP_SUCCESS; 2220a6af4a17SJohnny Huang 2221cd1610b4SJohnny Huang break; 2222cd1610b4SJohnny Huang } 2223cd1610b4SJohnny Huang 2224cd1610b4SJohnny Huang if (!nconfirm) { 2225cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2226cd1610b4SJohnny Huang if (!confirm_yesno()) { 2227cd1610b4SJohnny Huang printf(" Aborting\n"); 22282a856b9aSJohnny Huang return OTP_FAILURE; 2229cd1610b4SJohnny Huang } 2230cd1610b4SJohnny Huang } 2231cd1610b4SJohnny Huang 2232cd1610b4SJohnny Huang switch (mode) { 2233a6d0d645SJohnny Huang case OTP_REGION_STRAP: 2234f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 223583655e91SJohnny Huang break; 2236a6d0d645SJohnny Huang case OTP_REGION_CONF: 2237a6d0d645SJohnny Huang case OTP_REGION_DATA: 2238f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 2239de6fbf1cSJohnny Huang break; 2240de6fbf1cSJohnny Huang } 2241de6fbf1cSJohnny Huang otp_soak(0); 224283655e91SJohnny Huang if (ret) { 22430dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 2244794e27ecSJohnny Huang printf("FAILURE\n"); 2245794e27ecSJohnny Huang return OTP_FAILURE; 2246794e27ecSJohnny Huang } 2247794e27ecSJohnny Huang 22489009c25dSJohnny Huang printf("SUCCESS\n"); 22492a856b9aSJohnny Huang return OTP_SUCCESS; 2250a219f6deSJohnny Huang } 2251a219f6deSJohnny Huang 2252794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 2253794e27ecSJohnny Huang { 2254794e27ecSJohnny Huang u32 otp_rid[2]; 2255a8789b47SJohnny Huang u32 sw_rid[2]; 2256794e27ecSJohnny Huang int rid_num = 0; 2257a8789b47SJohnny Huang int sw_rid_num = 0; 2258794e27ecSJohnny Huang int bit_offset; 2259794e27ecSJohnny Huang int dw_offset; 2260794e27ecSJohnny Huang int i; 2261794e27ecSJohnny Huang int ret; 2262794e27ecSJohnny Huang 2263f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2264f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2265794e27ecSJohnny Huang 2266a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2267a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2268a8789b47SJohnny Huang 2269794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2270a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2271a8789b47SJohnny Huang 2272a8789b47SJohnny Huang if (sw_rid_num < 0) { 2273a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2274a8789b47SJohnny Huang return OTP_FAILURE; 2275a8789b47SJohnny Huang } 2276a8789b47SJohnny Huang 2277a8789b47SJohnny Huang if (update_num > sw_rid_num) { 2278a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2279a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2280a8789b47SJohnny Huang return OTP_FAILURE; 2281a8789b47SJohnny Huang } 2282794e27ecSJohnny Huang 2283794e27ecSJohnny Huang if (rid_num < 0) { 2284b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by this command,\n" 2285b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n"); 2286794e27ecSJohnny Huang otp_print_revid(otp_rid); 22879009c25dSJohnny Huang return OTP_FAILURE; 22889009c25dSJohnny Huang } 2289cd1610b4SJohnny Huang 2290794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2291794e27ecSJohnny Huang otp_print_revid(otp_rid); 2292794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 2293794e27ecSJohnny Huang 2294a8789b47SJohnny Huang if (rid_num > update_num) { 2295a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 2296a8789b47SJohnny Huang printf("Skip\n"); 2297a8789b47SJohnny Huang return OTP_FAILURE; 2298a8789b47SJohnny Huang } else if (rid_num == update_num) { 2299a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 2300794e27ecSJohnny Huang printf("Skip\n"); 2301794e27ecSJohnny Huang return OTP_FAILURE; 2302794e27ecSJohnny Huang } 2303794e27ecSJohnny Huang 2304794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2305794e27ecSJohnny Huang if (i < 32) { 2306794e27ecSJohnny Huang dw_offset = 0xa; 2307794e27ecSJohnny Huang bit_offset = i; 2308794e27ecSJohnny Huang } else { 2309794e27ecSJohnny Huang dw_offset = 0xb; 2310794e27ecSJohnny Huang bit_offset = i - 32; 2311794e27ecSJohnny Huang } 2312b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset); 2313794e27ecSJohnny Huang if (i + 1 != update_num) 2314794e27ecSJohnny Huang printf(", "); 2315794e27ecSJohnny Huang } 2316794e27ecSJohnny Huang 2317794e27ecSJohnny Huang printf(" will be programmed\n"); 2318794e27ecSJohnny Huang if (force == 0) { 2319794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2320794e27ecSJohnny Huang if (!confirm_yesno()) { 2321794e27ecSJohnny Huang printf(" Aborting\n"); 2322794e27ecSJohnny Huang return OTP_FAILURE; 2323794e27ecSJohnny Huang } 2324794e27ecSJohnny Huang } 2325794e27ecSJohnny Huang 2326794e27ecSJohnny Huang ret = 0; 2327794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2328794e27ecSJohnny Huang if (i < 32) { 2329794e27ecSJohnny Huang dw_offset = 0xa04; 2330794e27ecSJohnny Huang bit_offset = i; 2331794e27ecSJohnny Huang } else { 2332794e27ecSJohnny Huang dw_offset = 0xa06; 2333794e27ecSJohnny Huang bit_offset = i - 32; 2334794e27ecSJohnny Huang } 2335f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 2336b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset); 2337794e27ecSJohnny Huang ret = OTP_FAILURE; 2338794e27ecSJohnny Huang break; 2339794e27ecSJohnny Huang } 2340794e27ecSJohnny Huang } 2341061d3279SJohnny Huang otp_soak(0); 2342f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2343f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2344794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2345794e27ecSJohnny Huang if (rid_num >= 0) 2346794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 2347794e27ecSJohnny Huang else 2348794e27ecSJohnny Huang printf("OTP revision ID\n"); 2349794e27ecSJohnny Huang otp_print_revid(otp_rid); 2350794e27ecSJohnny Huang if (!ret) 2351794e27ecSJohnny Huang printf("SUCCESS\n"); 2352794e27ecSJohnny Huang else 2353794e27ecSJohnny Huang printf("FAILED\n"); 2354794e27ecSJohnny Huang return ret; 2355794e27ecSJohnny Huang } 2356794e27ecSJohnny Huang 2357883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force) 2358883625c5SJohnny Huang { 2359883625c5SJohnny Huang u32 otpcfg4; 2360883625c5SJohnny Huang u32 krb; 2361883625c5SJohnny Huang u32 krb_b; 2362883625c5SJohnny Huang u32 krb_or; 2363883625c5SJohnny Huang u32 current_id; 2364883625c5SJohnny Huang 2365883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2366883625c5SJohnny Huang current_id = readl(SEC_KEY_NUM) & 7; 2367883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2368883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2369883625c5SJohnny Huang krb_or = krb | krb_b; 2370883625c5SJohnny Huang 2371883625c5SJohnny Huang printf("current Key ID: 0x%x\n", current_id); 2372883625c5SJohnny Huang printf("input retire ID: 0x%x\n", retire_id); 2373883625c5SJohnny Huang printf("OTPCFG0x4 = 0x%X\n", otpcfg4); 2374883625c5SJohnny Huang 2375883625c5SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2376883625c5SJohnny Huang printf("OTPCFG4 is protected\n"); 2377883625c5SJohnny Huang return OTP_FAILURE; 2378883625c5SJohnny Huang } 2379883625c5SJohnny Huang 2380883625c5SJohnny Huang if (retire_id >= current_id) { 2381883625c5SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2382883625c5SJohnny Huang return OTP_FAILURE; 2383883625c5SJohnny Huang } 2384883625c5SJohnny Huang 2385883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2386883625c5SJohnny Huang printf("Key 0x%X already retired\n", retire_id); 2387883625c5SJohnny Huang return OTP_SUCCESS; 2388883625c5SJohnny Huang } 2389883625c5SJohnny Huang 2390883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id); 2391883625c5SJohnny Huang if (force == 0) { 2392883625c5SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2393883625c5SJohnny Huang if (!confirm_yesno()) { 2394883625c5SJohnny Huang printf(" Aborting\n"); 2395883625c5SJohnny Huang return OTP_FAILURE; 2396883625c5SJohnny Huang } 2397883625c5SJohnny Huang } 2398883625c5SJohnny Huang 2399883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) { 2400883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed\n", retire_id); 2401883625c5SJohnny Huang printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16); 2402883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE) 2403883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16); 2404883625c5SJohnny Huang } 2405883625c5SJohnny Huang 2406883625c5SJohnny Huang otp_soak(0); 2407883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2408883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2409883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2410883625c5SJohnny Huang krb_or = krb | krb_b; 2411883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2412883625c5SJohnny Huang printf("SUCCESS\n"); 2413883625c5SJohnny Huang return OTP_SUCCESS; 2414883625c5SJohnny Huang } 2415883625c5SJohnny Huang printf("FAILED\n"); 2416883625c5SJohnny Huang return OTP_FAILURE; 2417883625c5SJohnny Huang } 2418883625c5SJohnny Huang 2419e7e21c44SJohnny Huang static int parse_config(struct sb_info *si) 2420e7e21c44SJohnny Huang { 2421e7e21c44SJohnny Huang int i; 2422e7e21c44SJohnny Huang u32 cfg0, cfg3, cfg4; 2423e7e21c44SJohnny Huang u32 sb_mode; 2424e7e21c44SJohnny Huang u32 key_retire; 2425e7e21c44SJohnny Huang u32 rsa_len; 2426e7e21c44SJohnny Huang u32 sha_len; 2427e7e21c44SJohnny Huang 2428e7e21c44SJohnny Huang otp_read_conf(0, &cfg0); 2429e7e21c44SJohnny Huang otp_read_conf(3, &cfg3); 2430e7e21c44SJohnny Huang otp_read_conf(4, &cfg4); 2431e7e21c44SJohnny Huang 2432e7e21c44SJohnny Huang sb_mode = (cfg0 >> 7) & 0x1; 2433e7e21c44SJohnny Huang si->enc_flag = (cfg0 >> 27) & 0x1; 2434e7e21c44SJohnny Huang key_retire = (cfg4 & 0x7f) | ((cfg4 >> 16) & 0x7f); 2435e7e21c44SJohnny Huang 2436e7e21c44SJohnny Huang if ((cfg0 >> 16) & 0x3f) 2437e7e21c44SJohnny Huang si->secure_region = 1; 2438e7e21c44SJohnny Huang else 2439e7e21c44SJohnny Huang si->secure_region = 0; 2440e7e21c44SJohnny Huang 2441e7e21c44SJohnny Huang si->header_offset = cfg3 & 0xffff; 2442e7e21c44SJohnny Huang if (si->header_offset == 0) 2443e7e21c44SJohnny Huang si->header_offset = 0x20; 2444e7e21c44SJohnny Huang 2445e7e21c44SJohnny Huang for (i = 0; i < 8; i++) { 2446e7e21c44SJohnny Huang if ((key_retire >> i) & 0x1) 2447e7e21c44SJohnny Huang si->retire_list[i] = 1; 2448e7e21c44SJohnny Huang else 2449e7e21c44SJohnny Huang si->retire_list[i] = 0; 2450e7e21c44SJohnny Huang } 2451e7e21c44SJohnny Huang 2452e7e21c44SJohnny Huang if (sb_mode == 0) { 2453e7e21c44SJohnny Huang printf("Mode GCM is not supported.\n"); 2454e7e21c44SJohnny Huang return OTP_FAILURE; 2455e7e21c44SJohnny Huang } 2456e7e21c44SJohnny Huang 2457e7e21c44SJohnny Huang if (si->enc_flag) 2458e7e21c44SJohnny Huang printf("Algorithm: AES_RSA_SHA\n"); 2459e7e21c44SJohnny Huang else 2460e7e21c44SJohnny Huang printf("Algorithm: RSA_SHA\n"); 2461e7e21c44SJohnny Huang 2462e7e21c44SJohnny Huang rsa_len = (cfg0 >> 10) & 0x3; 2463e7e21c44SJohnny Huang sha_len = (cfg0 >> 12) & 0x3; 2464e7e21c44SJohnny Huang 2465e7e21c44SJohnny Huang if (rsa_len == 0) { 2466e7e21c44SJohnny Huang si->rsa_algo = 1024; 2467e7e21c44SJohnny Huang printf("RSA length: 1024\n"); 2468e7e21c44SJohnny Huang } else if (rsa_len == 1) { 2469e7e21c44SJohnny Huang si->rsa_algo = 2048; 2470e7e21c44SJohnny Huang printf("RSA length: 2048\n"); 2471e7e21c44SJohnny Huang } else if (rsa_len == 2) { 2472e7e21c44SJohnny Huang si->rsa_algo = 3072; 2473e7e21c44SJohnny Huang printf("RSA length: 3072\n"); 2474e7e21c44SJohnny Huang } else { 2475e7e21c44SJohnny Huang si->rsa_algo = 4096; 2476e7e21c44SJohnny Huang printf("RSA length: 4096\n"); 2477e7e21c44SJohnny Huang } 2478e7e21c44SJohnny Huang if (sha_len == 0) { 2479e7e21c44SJohnny Huang si->sha_algo = 224; 2480e7e21c44SJohnny Huang si->digest_len = 28; 2481e7e21c44SJohnny Huang printf("HASH length: 224\n"); 2482e7e21c44SJohnny Huang } else if (sha_len == 1) { 2483e7e21c44SJohnny Huang si->sha_algo = 256; 2484e7e21c44SJohnny Huang si->digest_len = 32; 2485e7e21c44SJohnny Huang printf("HASH length: 256\n"); 2486e7e21c44SJohnny Huang } else if (sha_len == 2) { 2487e7e21c44SJohnny Huang si->sha_algo = 384; 2488e7e21c44SJohnny Huang si->digest_len = 48; 2489e7e21c44SJohnny Huang printf("HASH length: 384\n"); 2490e7e21c44SJohnny Huang } else { 2491e7e21c44SJohnny Huang si->sha_algo = 512; 2492e7e21c44SJohnny Huang si->digest_len = 64; 2493e7e21c44SJohnny Huang printf("HASH length: 512\n"); 2494e7e21c44SJohnny Huang } 2495e7e21c44SJohnny Huang return OTP_SUCCESS; 2496e7e21c44SJohnny Huang } 2497e7e21c44SJohnny Huang 2498e7e21c44SJohnny Huang static void parse_data(struct key_list *kl, int *key_num, struct sb_info *si, u32 *data) 2499e7e21c44SJohnny Huang { 2500e7e21c44SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 2501e7e21c44SJohnny Huang int i, j; 2502e7e21c44SJohnny Huang int id = 0; 2503e7e21c44SJohnny Huang u32 h; 2504e7e21c44SJohnny Huang u32 t; 2505e7e21c44SJohnny Huang 2506e7e21c44SJohnny Huang *key_num = 0; 2507e7e21c44SJohnny Huang for (i = 0; i < 16; i++) { 2508e7e21c44SJohnny Huang h = data[i]; 2509e7e21c44SJohnny Huang t = (h >> 14) & 0xf; 2510e7e21c44SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 2511e7e21c44SJohnny Huang if (t == key_info_array[j].value) { 2512e7e21c44SJohnny Huang kl[*key_num].key_info = &key_info_array[j]; 2513e7e21c44SJohnny Huang kl[*key_num].offset = h & 0x1ff8; 2514e7e21c44SJohnny Huang id = h & 0x7; 2515e7e21c44SJohnny Huang kl[*key_num].id = id; 2516e7e21c44SJohnny Huang if (si->retire_list[id] == 1) 2517e7e21c44SJohnny Huang kl[*key_num].retire = 1; 2518e7e21c44SJohnny Huang else 2519e7e21c44SJohnny Huang kl[*key_num].retire = 0; 2520e7e21c44SJohnny Huang (*key_num)++; 2521e7e21c44SJohnny Huang break; 2522e7e21c44SJohnny Huang } 2523e7e21c44SJohnny Huang } 2524e7e21c44SJohnny Huang if ((data[i] >> 13) & 1) 2525e7e21c44SJohnny Huang break; 2526e7e21c44SJohnny Huang } 2527e7e21c44SJohnny Huang } 2528e7e21c44SJohnny Huang 2529e7e21c44SJohnny Huang static int sb_sha(struct sb_info *si, u8 *sec_image, u32 sign_image_size, u8 *digest_ret) 2530e7e21c44SJohnny Huang { 2531e7e21c44SJohnny Huang switch (si->sha_algo) { 2532e7e21c44SJohnny Huang case 224: 2533e7e21c44SJohnny Huang printf("otp verify does not support SHA224\n"); 2534e7e21c44SJohnny Huang return OTP_FAILURE; 2535e7e21c44SJohnny Huang case 256: 2536948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha256", digest_ret); 2537e7e21c44SJohnny Huang break; 2538e7e21c44SJohnny Huang case 384: 2539948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha384", digest_ret); 2540e7e21c44SJohnny Huang break; 2541e7e21c44SJohnny Huang case 512: 2542948e73aaSJoel Stanley do_hash(sec_image, sign_image_size, "sha512", digest_ret); 2543e7e21c44SJohnny Huang break; 2544e7e21c44SJohnny Huang default: 2545e7e21c44SJohnny Huang printf("SHA Algorithm is invalid\n"); 2546e7e21c44SJohnny Huang return OTP_FAILURE; 2547e7e21c44SJohnny Huang } 2548e7e21c44SJohnny Huang return 0; 2549e7e21c44SJohnny Huang } 2550e7e21c44SJohnny Huang 2551e7e21c44SJohnny Huang static int mode2_verify(u8 *sec_image, u32 sign_image_size, 2552e7e21c44SJohnny Huang u8 *signature, u8 *rsa_m, 2553e7e21c44SJohnny Huang int order, u8 *digest, 2554e7e21c44SJohnny Huang struct sb_info *si, struct udevice *mod_exp_dev) 2555e7e21c44SJohnny Huang { 2556e7e21c44SJohnny Huang struct key_prop prop; 2557e7e21c44SJohnny Huang u8 rsa_e[3] = "\x01\x00\x01"; 2558e7e21c44SJohnny Huang u8 sign_ret[512]; 2559e7e21c44SJohnny Huang u8 rsa_m_rev[512]; 2560e7e21c44SJohnny Huang u8 signature_rev[512]; 2561e7e21c44SJohnny Huang u8 tmp; 2562e7e21c44SJohnny Huang u32 rsa_len = si->rsa_algo / 8; 2563e7e21c44SJohnny Huang int i; 2564e7e21c44SJohnny Huang int ret; 2565e7e21c44SJohnny Huang 2566e7e21c44SJohnny Huang memset(&prop, 0, sizeof(struct key_prop)); 2567e7e21c44SJohnny Huang 2568e7e21c44SJohnny Huang if (order == OTP_LIT_END) { 2569e7e21c44SJohnny Huang memset(rsa_m_rev, 0, 512); 2570e7e21c44SJohnny Huang memset(signature_rev, 0, 512); 2571e7e21c44SJohnny Huang for (i = 0; i < rsa_len; i++) { 2572e7e21c44SJohnny Huang rsa_m_rev[i] = rsa_m[rsa_len - 1 - i]; 2573e7e21c44SJohnny Huang signature_rev[i] = signature[rsa_len - 1 - i]; 2574e7e21c44SJohnny Huang } 2575e7e21c44SJohnny Huang prop.modulus = rsa_m_rev; 2576e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo; 2577e7e21c44SJohnny Huang prop.public_exponent = rsa_e; 2578e7e21c44SJohnny Huang prop.exp_len = 3; 2579e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature_rev, rsa_len, &prop, sign_ret); 2580e7e21c44SJohnny Huang } else { 2581e7e21c44SJohnny Huang prop.modulus = rsa_m; 2582e7e21c44SJohnny Huang prop.num_bits = si->rsa_algo; 2583e7e21c44SJohnny Huang prop.public_exponent = rsa_e; 2584e7e21c44SJohnny Huang prop.exp_len = 3; 2585e7e21c44SJohnny Huang ret = rsa_mod_exp(mod_exp_dev, signature, rsa_len, &prop, sign_ret); 2586e7e21c44SJohnny Huang } 2587e7e21c44SJohnny Huang 2588e7e21c44SJohnny Huang if (ret) { 2589e7e21c44SJohnny Huang printf("rsa_mod_exp error: %d\n", ret); 2590e7e21c44SJohnny Huang return OTP_FAILURE; 2591e7e21c44SJohnny Huang } 2592e7e21c44SJohnny Huang 2593e7e21c44SJohnny Huang if (order == OTP_LIT_END) { 2594e7e21c44SJohnny Huang for (i = 0; i < rsa_len / 2; i++) { 2595e7e21c44SJohnny Huang tmp = sign_ret[i]; 2596e7e21c44SJohnny Huang sign_ret[i] = sign_ret[rsa_len - 1 - i]; 2597e7e21c44SJohnny Huang sign_ret[rsa_len - 1 - i] = tmp; 2598e7e21c44SJohnny Huang } 2599e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret, si->digest_len); 2600e7e21c44SJohnny Huang } else { 2601e7e21c44SJohnny Huang ret = memcmp(digest, sign_ret + (rsa_len - si->digest_len), si->digest_len); 2602e7e21c44SJohnny Huang } 2603e7e21c44SJohnny Huang 2604e7e21c44SJohnny Huang if (ret) 2605e7e21c44SJohnny Huang return OTP_FAILURE; 2606e7e21c44SJohnny Huang return 0; 2607e7e21c44SJohnny Huang } 2608e7e21c44SJohnny Huang 2609e7e21c44SJohnny Huang static int otp_verify_boot_image(phys_addr_t addr) 2610e7e21c44SJohnny Huang { 2611e7e21c44SJohnny Huang struct udevice *mod_exp_dev; 2612e7e21c44SJohnny Huang struct sb_info si; 2613e7e21c44SJohnny Huang struct key_list kl[16]; 2614e7e21c44SJohnny Huang struct sb_header *sh; 2615e7e21c44SJohnny Huang u32 data[2048]; 2616e7e21c44SJohnny Huang u8 digest[64]; 2617e7e21c44SJohnny Huang u8 *sec_image; 2618e7e21c44SJohnny Huang u8 *signature; 2619e7e21c44SJohnny Huang u8 *key; 2620e7e21c44SJohnny Huang u32 otp_rid[2]; 2621e7e21c44SJohnny Huang u32 sw_rid[2]; 2622e7e21c44SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2623e7e21c44SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2624e7e21c44SJohnny Huang int key_num; 2625e7e21c44SJohnny Huang int ret; 2626e7e21c44SJohnny Huang int i; 2627e7e21c44SJohnny Huang int pass = 0; 2628e7e21c44SJohnny Huang 262909f2a38fSJoel Stanley ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev); 2630e7e21c44SJohnny Huang if (ret) { 263109f2a38fSJoel Stanley printf("RSA: Can't find RSA driver\n"); 2632e7e21c44SJohnny Huang return OTP_FAILURE; 2633e7e21c44SJohnny Huang } 2634e7e21c44SJohnny Huang 2635e7e21c44SJohnny Huang for (i = 0; i < 2048 ; i += 2) 2636e7e21c44SJohnny Huang otp_read_data(i, &data[i]); 2637e7e21c44SJohnny Huang if (parse_config(&si)) 2638e7e21c44SJohnny Huang return OTP_FAILURE; 2639e7e21c44SJohnny Huang parse_data(kl, &key_num, &si, data); 2640e7e21c44SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2641e7e21c44SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2642e7e21c44SJohnny Huang 2643e7e21c44SJohnny Huang sec_image = (u8 *)addr; 2644e7e21c44SJohnny Huang sh = (struct sb_header *)(sec_image + si.header_offset); 2645e7e21c44SJohnny Huang signature = sec_image + sh->signature_offset; 2646e7e21c44SJohnny Huang 2647e7e21c44SJohnny Huang if (si.secure_region) 2648e7e21c44SJohnny Huang printf("WARNING: Secure Region is enabled, the verification may not correct.\n"); 2649e7e21c44SJohnny Huang 2650e7e21c44SJohnny Huang if (sh->sign_image_size % 512) { 2651e7e21c44SJohnny Huang printf("ERROR: The sign_image_size should be 512 bytes aligned\n"); 2652e7e21c44SJohnny Huang return OTP_FAILURE; 2653e7e21c44SJohnny Huang } 2654e7e21c44SJohnny Huang 2655e7e21c44SJohnny Huang printf("Check revision ID: "); 2656e7e21c44SJohnny Huang 2657e7e21c44SJohnny Huang sw_rid[0] = sh->revision_low; 2658e7e21c44SJohnny Huang sw_rid[1] = sh->revision_high; 2659e7e21c44SJohnny Huang 2660e7e21c44SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2661e7e21c44SJohnny Huang printf("FAIL\n"); 2662e7e21c44SJohnny Huang printf("Header revision_low: %x\n", sh->revision_low); 2663e7e21c44SJohnny Huang printf("Header revision_high: %x\n", sh->revision_high); 2664e7e21c44SJohnny Huang printf("OTP revision_low: %x\n", otp_rid[0]); 2665e7e21c44SJohnny Huang printf("OTP revision_high: %x\n", otp_rid[1]); 2666e7e21c44SJohnny Huang return OTP_FAILURE; 2667e7e21c44SJohnny Huang } 2668e7e21c44SJohnny Huang printf("PASS\n"); 2669e7e21c44SJohnny Huang 2670e7e21c44SJohnny Huang printf("Check secure image header: "); 2671e7e21c44SJohnny Huang if (((sh->aes_data_offset + sh->enc_offset + sh->sign_image_size + 2672e7e21c44SJohnny Huang sh->signature_offset + sh->revision_high + sh->revision_low + 2673e7e21c44SJohnny Huang sh->reserved + sh->bl1_header_checksum) & 0xffffffff) != 0) { 2674e7e21c44SJohnny Huang printf("FAIL\n"); 2675e7e21c44SJohnny Huang printf("aes_data_offset: %x\n", sh->aes_data_offset); 2676e7e21c44SJohnny Huang printf("enc_offset: %x\n", sh->enc_offset); 2677e7e21c44SJohnny Huang printf("sign_image_size: %x\n", sh->sign_image_size); 2678e7e21c44SJohnny Huang printf("signature_offset: %x\n", sh->signature_offset); 2679e7e21c44SJohnny Huang printf("revision_high: %x\n", sh->revision_high); 2680e7e21c44SJohnny Huang printf("revision_low: %x\n", sh->revision_low); 2681e7e21c44SJohnny Huang printf("reserved: %x\n", sh->reserved); 2682e7e21c44SJohnny Huang printf("bl1_header_checksum: %x\n", sh->bl1_header_checksum); 2683e7e21c44SJohnny Huang return OTP_FAILURE; 2684e7e21c44SJohnny Huang } 2685e7e21c44SJohnny Huang printf("PASS\n"); 2686e7e21c44SJohnny Huang 2687e7e21c44SJohnny Huang ret = sb_sha(&si, sec_image, sh->sign_image_size, digest); 2688e7e21c44SJohnny Huang if (ret) 2689e7e21c44SJohnny Huang return OTP_FAILURE; 2690e7e21c44SJohnny Huang 2691e7e21c44SJohnny Huang printf("Verifying secure image\n"); 2692e7e21c44SJohnny Huang for (i = 0; i < key_num; i++) { 2693e7e21c44SJohnny Huang if (kl[i].key_info->key_type != OTP_KEY_TYPE_RSA_PUB) 2694e7e21c44SJohnny Huang continue; 2695e7e21c44SJohnny Huang printf(" Key %d\n", kl[i].id); 2696e7e21c44SJohnny Huang if (kl[i].retire) { 2697e7e21c44SJohnny Huang printf(" Key %d is retired.\n", kl[i].id); 2698e7e21c44SJohnny Huang continue; 2699e7e21c44SJohnny Huang } 2700e7e21c44SJohnny Huang key = (u8 *)data + kl[i].offset; 2701e7e21c44SJohnny Huang if (!mode2_verify(sec_image, sh->sign_image_size, 2702e7e21c44SJohnny Huang signature, key, kl[i].key_info->order, digest, 2703e7e21c44SJohnny Huang &si, mod_exp_dev)) { 2704e7e21c44SJohnny Huang pass = 1; 2705e7e21c44SJohnny Huang break; 2706e7e21c44SJohnny Huang } 2707e7e21c44SJohnny Huang } 2708e7e21c44SJohnny Huang if (pass) { 2709e7e21c44SJohnny Huang printf(" OEM DSS RSA public keys\n"); 2710e7e21c44SJohnny Huang printf(" ID: %d\n", kl[i].id); 2711e7e21c44SJohnny Huang if (kl[i].key_info->order == OTP_BIG_END) 2712e7e21c44SJohnny Huang printf(" Big endian\n"); 2713e7e21c44SJohnny Huang else 2714e7e21c44SJohnny Huang printf(" Little endian\n"); 2715e7e21c44SJohnny Huang printf("Verify secure image: PASS\n"); 2716e7e21c44SJohnny Huang return OTP_SUCCESS; 2717e7e21c44SJohnny Huang } 2718e7e21c44SJohnny Huang printf("Verify secure image: FAIL\n"); 2719e7e21c44SJohnny Huang return OTP_FAILURE; 2720e7e21c44SJohnny Huang } 2721e7e21c44SJohnny Huang 2722418822f0SJohnny Huang static int otp_invalid_key(u32 header_offset, int force) 2723418822f0SJohnny Huang { 2724418822f0SJohnny Huang int i; 2725418822f0SJohnny Huang int ret; 2726418822f0SJohnny Huang u32 header_list[16]; 2727418822f0SJohnny Huang u32 header; 2728418822f0SJohnny Huang u32 key_type; 2729418822f0SJohnny Huang u32 prog_val; 2730418822f0SJohnny Huang 2731418822f0SJohnny Huang for (i = 0; i < 16 ; i += 2) 2732418822f0SJohnny Huang otp_read_data(i, &header_list[i]); 2733418822f0SJohnny Huang header = header_list[header_offset]; 2734418822f0SJohnny Huang key_type = (header >> 14) & 0xf; 2735418822f0SJohnny Huang _otp_print_key(header, header_offset, NULL); 2736418822f0SJohnny Huang if (key_type == 0 || key_type == 0xf) { 2737418822f0SJohnny Huang printf("Key[%d] already invalid\n", header_offset); 2738418822f0SJohnny Huang return OTP_SUCCESS; 2739418822f0SJohnny Huang } 2740418822f0SJohnny Huang 2741418822f0SJohnny Huang printf("Key[%d] will be invalid\n", header_offset); 2742418822f0SJohnny Huang if (force == 0) { 2743418822f0SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2744418822f0SJohnny Huang if (!confirm_yesno()) { 2745418822f0SJohnny Huang printf(" Aborting\n"); 2746418822f0SJohnny Huang return OTP_FAILURE; 2747418822f0SJohnny Huang } 2748418822f0SJohnny Huang } 2749418822f0SJohnny Huang 2750418822f0SJohnny Huang if (header_offset % 2) 2751418822f0SJohnny Huang prog_val = 0; 2752418822f0SJohnny Huang else 2753418822f0SJohnny Huang prog_val = 1; 2754418822f0SJohnny Huang for (i = 14; i <= 17; i++) { 2755418822f0SJohnny Huang ret = otp_prog_dc_b(prog_val, header_offset, i); 2756418822f0SJohnny Huang if (ret) { 2757418822f0SJohnny Huang printf("OTPDATA0x%x[%d] programming failed\n", header_offset, i); 2758418822f0SJohnny Huang return OTP_FAILURE; 2759418822f0SJohnny Huang } 2760418822f0SJohnny Huang } 2761418822f0SJohnny Huang 2762418822f0SJohnny Huang printf("SUCCESS\n"); 2763418822f0SJohnny Huang return OTP_SUCCESS; 2764418822f0SJohnny Huang } 2765418822f0SJohnny Huang 27662a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 276769d5fd8fSJohnny Huang { 2768a219f6deSJohnny Huang u32 offset, count; 27692a856b9aSJohnny Huang int ret; 277069d5fd8fSJohnny Huang 27712a856b9aSJohnny Huang if (argc == 4) { 27722a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 27732a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 27742a856b9aSJohnny Huang } else if (argc == 3) { 27752a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 27762a856b9aSJohnny Huang count = 1; 27772a856b9aSJohnny Huang } else { 277869d5fd8fSJohnny Huang return CMD_RET_USAGE; 277969d5fd8fSJohnny Huang } 278069d5fd8fSJohnny Huang 2781030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2782f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2783030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 27842a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2785030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 27862a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2787030cb4a7SJohnny Huang else 27882a856b9aSJohnny Huang return CMD_RET_USAGE; 278969d5fd8fSJohnny Huang 27902a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 27912a856b9aSJohnny Huang return CMD_RET_SUCCESS; 27922a856b9aSJohnny Huang return CMD_RET_USAGE; 27932a856b9aSJohnny Huang } 27942a856b9aSJohnny Huang 27952a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 27962a856b9aSJohnny Huang { 27972a856b9aSJohnny Huang phys_addr_t addr; 27982a856b9aSJohnny Huang int ret; 27992a856b9aSJohnny Huang 2800de6b0cc4SJohnny Huang if (argc == 3) { 2801ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 28022a856b9aSJohnny Huang return CMD_RET_USAGE; 28032a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2804f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2805de6b0cc4SJohnny Huang } else if (argc == 2) { 28062a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2807f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 28082a856b9aSJohnny Huang } else { 28092a856b9aSJohnny Huang return CMD_RET_USAGE; 28102a856b9aSJohnny Huang } 28112a856b9aSJohnny Huang 28122a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 28132a856b9aSJohnny Huang return CMD_RET_SUCCESS; 28142a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 28152a856b9aSJohnny Huang return CMD_RET_FAILURE; 28162a856b9aSJohnny Huang else 28172a856b9aSJohnny Huang return CMD_RET_USAGE; 28182a856b9aSJohnny Huang } 28192a856b9aSJohnny Huang 28202a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 28212a856b9aSJohnny Huang { 28222a856b9aSJohnny Huang int mode = 0; 28232a856b9aSJohnny Huang int nconfirm = 0; 28242a856b9aSJohnny Huang int otp_addr = 0; 28252a856b9aSJohnny Huang int bit_offset; 28262a856b9aSJohnny Huang int value; 28272a856b9aSJohnny Huang int ret; 2828030cb4a7SJohnny Huang u32 otp_strap_pro; 28292a856b9aSJohnny Huang 28302a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 28312a856b9aSJohnny Huang return CMD_RET_USAGE; 28322a856b9aSJohnny Huang 28332a856b9aSJohnny Huang /* Drop the pb cmd */ 28342a856b9aSJohnny Huang argc--; 28352a856b9aSJohnny Huang argv++; 28362a856b9aSJohnny Huang 28372a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2838a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 28392a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2840a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 28412a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2842a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2843cd1610b4SJohnny Huang else 28442a856b9aSJohnny Huang return CMD_RET_USAGE; 28452a856b9aSJohnny Huang 28462a856b9aSJohnny Huang /* Drop the region cmd */ 28472a856b9aSJohnny Huang argc--; 28482a856b9aSJohnny Huang argv++; 28492a856b9aSJohnny Huang 2850ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2851cd1610b4SJohnny Huang nconfirm = 1; 28522a856b9aSJohnny Huang /* Drop the force option */ 28532a856b9aSJohnny Huang argc--; 28542a856b9aSJohnny Huang argv++; 28552a856b9aSJohnny Huang } 2856cd1610b4SJohnny Huang 2857a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 28582a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 28592a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 28600808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 28612a856b9aSJohnny Huang return CMD_RET_USAGE; 2862cd1610b4SJohnny Huang } else { 28632a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 28642a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 28652a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 28660808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 28672a856b9aSJohnny Huang return CMD_RET_USAGE; 28680808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 286978855207SJohnny Huang if (otp_addr >= 0x800) 28700808cc55SJohnny Huang return CMD_RET_USAGE; 28710808cc55SJohnny Huang } else { 287278855207SJohnny Huang if (otp_addr >= 0x20) 28730808cc55SJohnny Huang return CMD_RET_USAGE; 28740808cc55SJohnny Huang } 2875cd1610b4SJohnny Huang } 2876cd1610b4SJohnny Huang if (value != 0 && value != 1) 28772a856b9aSJohnny Huang return CMD_RET_USAGE; 2878cd1610b4SJohnny Huang 2879030cb4a7SJohnny Huang ret = 0; 2880030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2881030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2882030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2883030cb4a7SJohnny Huang } 2884030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2885030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2886030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2887030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2888030cb4a7SJohnny Huang ret = -1; 2889030cb4a7SJohnny Huang } 2890030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2891030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2892030cb4a7SJohnny Huang ret = -1; 2893030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2894030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2895030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2896030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2897030cb4a7SJohnny Huang ret = -1; 2898030cb4a7SJohnny Huang } 2899030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2900030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2901030cb4a7SJohnny Huang ret = -1; 2902030cb4a7SJohnny Huang } 2903030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2904030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2905030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2906030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2907030cb4a7SJohnny Huang ret = -1; 2908030cb4a7SJohnny Huang } 2909030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2910030cb4a7SJohnny Huang u32 otp_rid[2]; 2911030cb4a7SJohnny Huang u32 sw_rid[2]; 2912030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2913030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2914030cb4a7SJohnny Huang 2915030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2916030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2917030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2918030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2919030cb4a7SJohnny Huang 2920030cb4a7SJohnny Huang if (otp_addr == 10) 2921030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2922030cb4a7SJohnny Huang else 2923030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2924030cb4a7SJohnny Huang 2925030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2926030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2927030cb4a7SJohnny Huang ret = -1; 2928030cb4a7SJohnny Huang } 2929030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2930030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2931030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2932030cb4a7SJohnny Huang ret = -1; 2933030cb4a7SJohnny Huang } else { 2934030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2935030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2936030cb4a7SJohnny Huang u32 key_num; 2937030cb4a7SJohnny Huang u32 retire; 2938030cb4a7SJohnny Huang 2939030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2940030cb4a7SJohnny Huang if (bit_offset >= 16) 2941030cb4a7SJohnny Huang retire = bit_offset - 16; 2942030cb4a7SJohnny Huang else 2943030cb4a7SJohnny Huang retire = bit_offset; 2944030cb4a7SJohnny Huang if (retire >= key_num) { 2945030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2946030cb4a7SJohnny Huang ret = -1; 2947030cb4a7SJohnny Huang } 2948030cb4a7SJohnny Huang } 2949030cb4a7SJohnny Huang } 2950030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2951030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2952030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2953030cb4a7SJohnny Huang ret = -1; 2954030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2955030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2956030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2957030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2958030cb4a7SJohnny Huang else 2959030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2960030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2961b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset); 2962030cb4a7SJohnny Huang ret = -1; 2963030cb4a7SJohnny Huang } 2964030cb4a7SJohnny Huang } 2965030cb4a7SJohnny Huang } 2966030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2967030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2968030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2969030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2970030cb4a7SJohnny Huang ret = -1; 2971030cb4a7SJohnny Huang } 2972030cb4a7SJohnny Huang } 2973030cb4a7SJohnny Huang 2974030cb4a7SJohnny Huang if (ret == -1) 2975030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2976030cb4a7SJohnny Huang 2977f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 29782a856b9aSJohnny Huang 29792a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 29802a856b9aSJohnny Huang return CMD_RET_SUCCESS; 29812a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 29822a856b9aSJohnny Huang return CMD_RET_FAILURE; 29832a856b9aSJohnny Huang else 29842a856b9aSJohnny Huang return CMD_RET_USAGE; 29852a856b9aSJohnny Huang } 29862a856b9aSJohnny Huang 29872a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 29882a856b9aSJohnny Huang { 29892a856b9aSJohnny Huang phys_addr_t addr; 29902a856b9aSJohnny Huang int otp_addr = 0; 2991b8590031SJohnny Huang int ret; 29922a856b9aSJohnny Huang 29932a856b9aSJohnny Huang if (argc != 3) 29942a856b9aSJohnny Huang return CMD_RET_USAGE; 29952a856b9aSJohnny Huang 29962a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 29972a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 2998b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 2999b8590031SJohnny Huang if (ret == 0) { 300069d5fd8fSJohnny Huang printf("Compare pass\n"); 30012a856b9aSJohnny Huang return CMD_RET_SUCCESS; 3002a219f6deSJohnny Huang } 300369d5fd8fSJohnny Huang printf("Compare fail\n"); 30042a856b9aSJohnny Huang return CMD_RET_FAILURE; 300569d5fd8fSJohnny Huang } 300669d5fd8fSJohnny Huang 300766f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 300866f2f8e5SJohnny Huang { 3009a8bd6d8cSJohnny Huang int view = 0; 30102d4b0742SJohnny Huang int input; 3011a8bd6d8cSJohnny Huang 3012a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 301366f2f8e5SJohnny Huang return CMD_RET_USAGE; 301466f2f8e5SJohnny Huang 30152d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 30162d4b0742SJohnny Huang if (argc == 3) { 30172d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 30182d4b0742SJohnny Huang otp_print_conf_info(input); 30192d4b0742SJohnny Huang } else { 30202d4b0742SJohnny Huang otp_print_conf_info(-1); 30212d4b0742SJohnny Huang } 30222d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 30232d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 3024a8bd6d8cSJohnny Huang view = 1; 3025a8bd6d8cSJohnny Huang /* Drop the view option */ 3026a8bd6d8cSJohnny Huang argc--; 3027a8bd6d8cSJohnny Huang argv++; 3028a8bd6d8cSJohnny Huang } 3029b458cd62SJohnny Huang otp_print_strap_info(view); 30300dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 30310dc9a440SJohnny Huang otp_print_scu_info(); 303288bd7d58SJohnny Huang } else if (!strcmp(argv[1], "key")) { 303388bd7d58SJohnny Huang otp_print_key_info(); 303466f2f8e5SJohnny Huang } else { 303566f2f8e5SJohnny Huang return CMD_RET_USAGE; 303666f2f8e5SJohnny Huang } 30372d4b0742SJohnny Huang 303866f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 303966f2f8e5SJohnny Huang } 304066f2f8e5SJohnny Huang 30410dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3042737ed20bSJohnny Huang { 30430dc9a440SJohnny Huang u32 input; 30440dc9a440SJohnny Huang u32 bit_offset; 3045e14b073cSJohnny Huang u32 prog_address; 3046030cb4a7SJohnny Huang char force; 304783655e91SJohnny Huang int ret; 3048a219f6deSJohnny Huang 3049737ed20bSJohnny Huang if (argc != 3 && argc != 2) 3050737ed20bSJohnny Huang return CMD_RET_USAGE; 3051737ed20bSJohnny Huang 3052e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 3053737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 3054030cb4a7SJohnny Huang force = 1; 3055737ed20bSJohnny Huang } else { 3056737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 3057030cb4a7SJohnny Huang force = 0; 3058737ed20bSJohnny Huang } 3059737ed20bSJohnny Huang 3060737ed20bSJohnny Huang if (input < 32) { 3061737ed20bSJohnny Huang bit_offset = input; 30620dc9a440SJohnny Huang prog_address = 0xe0c; 3063737ed20bSJohnny Huang } else if (input < 64) { 3064737ed20bSJohnny Huang bit_offset = input - 32; 30650dc9a440SJohnny Huang prog_address = 0xe0e; 3066737ed20bSJohnny Huang } else { 3067737ed20bSJohnny Huang return CMD_RET_USAGE; 3068737ed20bSJohnny Huang } 3069737ed20bSJohnny Huang 3070030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 3071030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 3072030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3073030cb4a7SJohnny Huang } 3074030cb4a7SJohnny Huang 3075030cb4a7SJohnny Huang if (!force) { 3076b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input); 3077030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 3078030cb4a7SJohnny Huang if (!confirm_yesno()) { 3079030cb4a7SJohnny Huang printf(" Aborting\n"); 3080030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3081030cb4a7SJohnny Huang } 3082030cb4a7SJohnny Huang } 3083030cb4a7SJohnny Huang 3084e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 3085b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input); 3086e14b073cSJohnny Huang return CMD_RET_SUCCESS; 3087e14b073cSJohnny Huang } 3088de6fbf1cSJohnny Huang 3089f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 3090de6fbf1cSJohnny Huang otp_soak(0); 309183655e91SJohnny Huang 309283655e91SJohnny Huang if (ret) { 3093b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input); 3094737ed20bSJohnny Huang return CMD_RET_FAILURE; 3095737ed20bSJohnny Huang } 30969a4fe690SJohnny Huang 3097b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input); 3098794e27ecSJohnny Huang return CMD_RET_SUCCESS; 3099794e27ecSJohnny Huang } 3100794e27ecSJohnny Huang 31010dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3102e14b073cSJohnny Huang { 31030dc9a440SJohnny Huang u32 scu_offset; 31040dc9a440SJohnny Huang u32 bit_offset; 31050dc9a440SJohnny Huang u32 conf_offset; 31060dc9a440SJohnny Huang u32 prog_address; 31070dc9a440SJohnny Huang char force; 31080dc9a440SJohnny Huang int ret; 31090dc9a440SJohnny Huang 31100dc9a440SJohnny Huang if (argc != 4 && argc != 3) 31110dc9a440SJohnny Huang return CMD_RET_USAGE; 31120dc9a440SJohnny Huang 31130dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 31140dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 31150dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 31160dc9a440SJohnny Huang force = 1; 31170dc9a440SJohnny Huang } else { 31180dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 31190dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 31200dc9a440SJohnny Huang force = 0; 31210dc9a440SJohnny Huang } 31220dc9a440SJohnny Huang if (scu_offset == 0x500) { 31230dc9a440SJohnny Huang prog_address = 0xe08; 31240dc9a440SJohnny Huang conf_offset = 28; 31250dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 31260dc9a440SJohnny Huang prog_address = 0xe0a; 31270dc9a440SJohnny Huang conf_offset = 29; 31280dc9a440SJohnny Huang } else { 31290dc9a440SJohnny Huang return CMD_RET_USAGE; 31300dc9a440SJohnny Huang } 31310dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 31320dc9a440SJohnny Huang return CMD_RET_USAGE; 3133030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 3134030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 3135030cb4a7SJohnny Huang return CMD_RET_FAILURE; 3136030cb4a7SJohnny Huang } 31370dc9a440SJohnny Huang if (!force) { 3138b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset); 3139b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset); 31400dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 31410dc9a440SJohnny Huang if (!confirm_yesno()) { 31420dc9a440SJohnny Huang printf(" Aborting\n"); 31430dc9a440SJohnny Huang return CMD_RET_FAILURE; 31440dc9a440SJohnny Huang } 3145e14b073cSJohnny Huang } 3146e14b073cSJohnny Huang 31470dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 3148b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset); 31490dc9a440SJohnny Huang return CMD_RET_SUCCESS; 31500dc9a440SJohnny Huang } 31510dc9a440SJohnny Huang 31520dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 31530dc9a440SJohnny Huang otp_soak(0); 31540dc9a440SJohnny Huang 31550dc9a440SJohnny Huang if (ret) { 3156b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset); 31570dc9a440SJohnny Huang return CMD_RET_FAILURE; 31580dc9a440SJohnny Huang } 31590dc9a440SJohnny Huang 3160b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset); 31610dc9a440SJohnny Huang return CMD_RET_SUCCESS; 3162e14b073cSJohnny Huang } 3163e14b073cSJohnny Huang 3164f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3165f67375f7SJohnny Huang { 3166e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 3167f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 3168f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 3169f67375f7SJohnny Huang 3170f67375f7SJohnny Huang return CMD_RET_SUCCESS; 3171f67375f7SJohnny Huang } 3172f67375f7SJohnny Huang 3173794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3174794e27ecSJohnny Huang { 3175794e27ecSJohnny Huang u32 update_num; 3176794e27ecSJohnny Huang int force = 0; 3177794e27ecSJohnny Huang int ret; 3178794e27ecSJohnny Huang 3179794e27ecSJohnny Huang if (argc == 3) { 3180794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 3181794e27ecSJohnny Huang return CMD_RET_USAGE; 3182794e27ecSJohnny Huang force = 1; 3183794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 3184794e27ecSJohnny Huang } else if (argc == 2) { 3185794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 3186794e27ecSJohnny Huang } else { 3187794e27ecSJohnny Huang return CMD_RET_USAGE; 3188794e27ecSJohnny Huang } 3189794e27ecSJohnny Huang 3190794e27ecSJohnny Huang if (update_num > 64) 3191794e27ecSJohnny Huang return CMD_RET_USAGE; 3192794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 3193b8590031SJohnny Huang 3194794e27ecSJohnny Huang if (ret) 3195794e27ecSJohnny Huang return CMD_RET_FAILURE; 3196794e27ecSJohnny Huang return CMD_RET_SUCCESS; 3197794e27ecSJohnny Huang } 3198794e27ecSJohnny Huang 3199794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3200794e27ecSJohnny Huang { 3201794e27ecSJohnny Huang u32 otp_rid[2]; 3202a8789b47SJohnny Huang u32 sw_rid[2]; 3203794e27ecSJohnny Huang int rid_num = 0; 3204a8789b47SJohnny Huang int sw_rid_num = 0; 3205794e27ecSJohnny Huang int ret; 3206794e27ecSJohnny Huang 3207794e27ecSJohnny Huang if (argc != 1) 3208794e27ecSJohnny Huang return CMD_RET_USAGE; 3209794e27ecSJohnny Huang 3210f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 3211f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 3212794e27ecSJohnny Huang 3213a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 3214a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 3215794e27ecSJohnny Huang 3216a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 3217a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 3218a8789b47SJohnny Huang 3219030cb4a7SJohnny Huang if (sw_rid_num < 0) { 3220030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 3221030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 3222030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 3223030cb4a7SJohnny Huang } else { 3224a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 3225030cb4a7SJohnny Huang } 3226794e27ecSJohnny Huang if (rid_num >= 0) { 3227794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 3228794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 3229794e27ecSJohnny Huang } else { 3230b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n" 3231b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n" 3232794e27ecSJohnny Huang "current OTP revision ID\n"); 3233794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 3234794e27ecSJohnny Huang } 3235794e27ecSJohnny Huang otp_print_revid(otp_rid); 3236794e27ecSJohnny Huang 3237794e27ecSJohnny Huang return ret; 3238794e27ecSJohnny Huang } 3239794e27ecSJohnny Huang 3240883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3241883625c5SJohnny Huang { 3242883625c5SJohnny Huang u32 retire_id; 3243883625c5SJohnny Huang int force = 0; 3244883625c5SJohnny Huang int ret; 3245883625c5SJohnny Huang 3246883625c5SJohnny Huang if (argc == 3) { 3247883625c5SJohnny Huang if (strcmp(argv[1], "o")) 3248883625c5SJohnny Huang return CMD_RET_USAGE; 3249883625c5SJohnny Huang force = 1; 3250883625c5SJohnny Huang retire_id = simple_strtoul(argv[2], NULL, 16); 3251883625c5SJohnny Huang } else if (argc == 2) { 3252883625c5SJohnny Huang retire_id = simple_strtoul(argv[1], NULL, 16); 3253883625c5SJohnny Huang } else { 3254883625c5SJohnny Huang return CMD_RET_USAGE; 3255883625c5SJohnny Huang } 3256883625c5SJohnny Huang 3257883625c5SJohnny Huang if (retire_id > 7) 3258883625c5SJohnny Huang return CMD_RET_USAGE; 3259883625c5SJohnny Huang ret = otp_retire_key(retire_id, force); 3260883625c5SJohnny Huang 3261883625c5SJohnny Huang if (ret) 3262883625c5SJohnny Huang return CMD_RET_FAILURE; 3263883625c5SJohnny Huang return CMD_RET_SUCCESS; 3264883625c5SJohnny Huang } 3265883625c5SJohnny Huang 3266e7e21c44SJohnny Huang static int do_otpverify(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3267e7e21c44SJohnny Huang { 3268e7e21c44SJohnny Huang phys_addr_t addr; 3269e7e21c44SJohnny Huang int ret; 3270e7e21c44SJohnny Huang 3271e7e21c44SJohnny Huang if (argc == 2) { 3272e7e21c44SJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 3273e7e21c44SJohnny Huang ret = otp_verify_boot_image(addr); 3274e7e21c44SJohnny Huang } else { 3275e7e21c44SJohnny Huang return CMD_RET_USAGE; 3276e7e21c44SJohnny Huang } 3277e7e21c44SJohnny Huang 3278e7e21c44SJohnny Huang if (ret == OTP_SUCCESS) 3279e7e21c44SJohnny Huang return CMD_RET_SUCCESS; 3280e7e21c44SJohnny Huang else if (ret == OTP_FAILURE) 3281e7e21c44SJohnny Huang return CMD_RET_FAILURE; 3282e7e21c44SJohnny Huang else 3283e7e21c44SJohnny Huang return CMD_RET_USAGE; 3284e7e21c44SJohnny Huang } 3285e7e21c44SJohnny Huang 3286418822f0SJohnny Huang static int do_otpinvalid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 3287418822f0SJohnny Huang { 3288418822f0SJohnny Huang u32 header_offset; 3289418822f0SJohnny Huang int force = 0; 3290418822f0SJohnny Huang int ret; 3291418822f0SJohnny Huang 3292418822f0SJohnny Huang if (argc == 3) { 3293418822f0SJohnny Huang if (strcmp(argv[1], "o")) 3294418822f0SJohnny Huang return CMD_RET_USAGE; 3295418822f0SJohnny Huang force = 1; 3296418822f0SJohnny Huang header_offset = simple_strtoul(argv[2], NULL, 16); 3297418822f0SJohnny Huang } else if (argc == 2) { 3298418822f0SJohnny Huang header_offset = simple_strtoul(argv[1], NULL, 16); 3299418822f0SJohnny Huang } else { 3300418822f0SJohnny Huang return CMD_RET_USAGE; 3301418822f0SJohnny Huang } 3302418822f0SJohnny Huang 3303418822f0SJohnny Huang if (header_offset > 16) 3304418822f0SJohnny Huang return CMD_RET_USAGE; 3305418822f0SJohnny Huang ret = otp_invalid_key(header_offset, force); 3306418822f0SJohnny Huang 3307418822f0SJohnny Huang if (ret) 3308418822f0SJohnny Huang return CMD_RET_FAILURE; 3309418822f0SJohnny Huang return CMD_RET_SUCCESS; 3310418822f0SJohnny Huang } 3311418822f0SJohnny Huang 33122a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 3313f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 33142a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 3315a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 3316de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 33172a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 3318737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 33190dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 33202a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 3321794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 3322794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 3323883625c5SJohnny Huang U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""), 3324e7e21c44SJohnny Huang U_BOOT_CMD_MKENT(verify, 2, 0, do_otpverify, "", ""), 3325418822f0SJohnny Huang U_BOOT_CMD_MKENT(invalid, 3, 0, do_otpinvalid, "", ""), 33262a856b9aSJohnny Huang }; 33272a856b9aSJohnny Huang 33282a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 33292a856b9aSJohnny Huang { 3330030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 33312a856b9aSJohnny Huang cmd_tbl_t *cp; 3332a219f6deSJohnny Huang u32 ver; 3333e14b073cSJohnny Huang int ret; 3334030cb4a7SJohnny Huang u32 otp_conf0; 33352a856b9aSJohnny Huang 33362a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 33372a856b9aSJohnny Huang 3338737ed20bSJohnny Huang /* Drop the otp command */ 33392a856b9aSJohnny Huang argc--; 33402a856b9aSJohnny Huang argv++; 33412a856b9aSJohnny Huang 3342a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 33432a856b9aSJohnny Huang return CMD_RET_USAGE; 33442a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 33452a856b9aSJohnny Huang return CMD_RET_SUCCESS; 33462a856b9aSJohnny Huang 33470dae9d52SJohnny Huang ver = chip_version(); 33480dae9d52SJohnny Huang switch (ver) { 3349e417205bSJohnny Huang case OTP_A0: 3350e417205bSJohnny Huang info_cb.version = OTP_A0; 33519a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 33529a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 33539a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 33549a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 33559a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 33569a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 3357e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 33580dae9d52SJohnny Huang break; 3359e417205bSJohnny Huang case OTP_A1: 3360e417205bSJohnny Huang info_cb.version = OTP_A1; 33613cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 33623cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 33633cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 33643cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 33659a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 33669a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 33670dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33680dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3369e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 33700dae9d52SJohnny Huang break; 3371e417205bSJohnny Huang case OTP_A2: 3372e417205bSJohnny Huang info_cb.version = OTP_A2; 33735fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 33745fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 3375fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 3376fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 33775fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 33785fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 33790dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33800dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3381e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 33820dae9d52SJohnny Huang break; 3383e417205bSJohnny Huang case OTP_A3: 3384e417205bSJohnny Huang info_cb.version = OTP_A3; 3385b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 3386b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 3387fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 3388fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 3389181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 3390181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 33910dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 33920dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 3393e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 339464b66712SJohnny Huang break; 33950dae9d52SJohnny Huang default: 3396f1be5099SJohnny Huang printf("SOC is not supported\n"); 33970dae9d52SJohnny Huang return CMD_RET_FAILURE; 33989a4fe690SJohnny Huang } 33999a4fe690SJohnny Huang 3400030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 3401030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 3402030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 3403030cb4a7SJohnny Huang 3404030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 3405030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 3406030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 3407030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 3408030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 3409030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 3410030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 3411030cb4a7SJohnny Huang 3412e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 3413b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 3414e14b073cSJohnny Huang 3415e14b073cSJohnny Huang return ret; 341669d5fd8fSJohnny Huang } 341769d5fd8fSJohnny Huang 3418a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 341969d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 3420f67375f7SJohnny Huang "version\n" 3421f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 34222a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 34232d4b0742SJohnny Huang "otp info strap [v]\n" 34242d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 34250dc9a440SJohnny Huang "otp info scu\n" 342688bd7d58SJohnny Huang "otp info key\n" 3427de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 3428ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 3429ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 3430ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 34310dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 3432794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 3433794e27ecSJohnny Huang "otp rid\n" 3434883625c5SJohnny Huang "otp retire [o] <key_id>\n" 3435e7e21c44SJohnny Huang "otp verify <addr>\n" 3436418822f0SJohnny Huang "otp invalid [o] <header_offset>\n" 343769d5fd8fSJohnny Huang ); 3438