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> 18696656c6SJohnny Huang #include <u-boot/sha256.h> 190cee9a95SJohnny Huang #include "otp_info.h" 2069d5fd8fSJohnny Huang 2169d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2269d5fd8fSJohnny Huang 230cc6ef78SJohnny Huang #define OTP_VER "1.2.0" 24f67375f7SJohnny Huang 2569d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 26dacbba92SJohnny Huang #define RETRY 20 277332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 287332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 297332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 3069d5fd8fSJohnny Huang 312a856b9aSJohnny Huang #define OTP_USAGE -1 322a856b9aSJohnny Huang #define OTP_FAILURE -2 332a856b9aSJohnny Huang #define OTP_SUCCESS 0 342a856b9aSJohnny Huang 35a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 36a6af4a17SJohnny Huang 37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB 1 38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV 2 39181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES 3 40181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT 4 41181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC 5 429a4fe690SJohnny Huang 433d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 443d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 453d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 463d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 473d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 483d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 493d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 503d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 513d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 523d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 53a8789b47SJohnny Huang #define SW_REV_ID0 OTP_BASE + 0x68 54a8789b47SJohnny Huang #define SW_REV_ID1 OTP_BASE + 0x6c 55030cb4a7SJohnny Huang #define SEC_KEY_NUM OTP_BASE + 0x78 563d3688adSJohnny Huang 57696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 58696656c6SJohnny Huang #define CHECKSUM_LEN 32 59a219f6deSJohnny Huang #define OTP_INC_DATA BIT(31) 60a219f6deSJohnny Huang #define OTP_INC_CONFIG BIT(30) 61a219f6deSJohnny Huang #define OTP_INC_STRAP BIT(29) 62a219f6deSJohnny Huang #define OTP_ECC_EN BIT(28) 63b25f02d2SJohnny Huang #define OTP_INC_SCU_PRO BIT(25) 64696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 65696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 66696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 67696656c6SJohnny Huang 68e417205bSJohnny Huang #define OTP_A0 0 69e417205bSJohnny Huang #define OTP_A1 1 70e417205bSJohnny Huang #define OTP_A2 2 71e417205bSJohnny Huang #define OTP_A3 3 72e417205bSJohnny Huang 73e417205bSJohnny Huang #define ID0_AST2600A0 0x05000303 74e417205bSJohnny Huang #define ID1_AST2600A0 0x05000303 75e417205bSJohnny Huang #define ID0_AST2600A1 0x05010303 7621a8cfceSJohnny Huang #define ID1_AST2600A1 0x05010303 77e417205bSJohnny Huang #define ID0_AST2600A2 0x05010303 78e417205bSJohnny Huang #define ID1_AST2600A2 0x05020303 79e417205bSJohnny Huang #define ID0_AST2600A3 0x05030303 80e417205bSJohnny Huang #define ID1_AST2600A3 0x05030303 81e417205bSJohnny Huang #define ID0_AST2620A1 0x05010203 82e417205bSJohnny Huang #define ID1_AST2620A1 0x05010203 83e417205bSJohnny Huang #define ID0_AST2620A2 0x05010203 84e417205bSJohnny Huang #define ID1_AST2620A2 0x05020203 85e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 86e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 87e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 88e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 89e417205bSJohnny Huang #define ID0_AST2605A2 0x05010103 90e417205bSJohnny Huang #define ID1_AST2605A2 0x05020103 91e417205bSJohnny Huang #define ID0_AST2605A3 0x05030103 92e417205bSJohnny Huang #define ID1_AST2605A3 0x05030103 93e417205bSJohnny Huang #define ID0_AST2625A3 0x05030403 94e417205bSJohnny Huang #define ID1_AST2625A3 0x05030403 95696656c6SJohnny Huang 9661a6cda7SJohnny Huang #define SOC_AST2600A0 0 9761a6cda7SJohnny Huang #define SOC_AST2600A1 1 9861a6cda7SJohnny Huang #define SOC_AST2600A2 2 9961a6cda7SJohnny Huang #define SOC_AST2600A3 3 10061a6cda7SJohnny Huang 10161a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c)) 102*5e096f11SJohnny Huang #define OTPTOOL_VERSION_MAJOR(x) (((x) >> 24) & 0xff) 103*5e096f11SJohnny Huang #define OTPTOOL_VERSION_PATCHLEVEL(x) (((x) >> 12) & 0xfff) 104*5e096f11SJohnny Huang #define OTPTOOL_VERSION_SUBLEVEL(x) ((x) & 0xfff) 105*5e096f11SJohnny Huang #define OTPTOOL_COMPT_VERSION 1 10661a6cda7SJohnny Huang 107696656c6SJohnny Huang struct otp_header { 108696656c6SJohnny Huang u8 otp_magic[8]; 10961a6cda7SJohnny Huang u32 soc_ver; 11061a6cda7SJohnny Huang u32 otptool_ver; 111696656c6SJohnny Huang u32 image_info; 112696656c6SJohnny Huang u32 data_info; 113696656c6SJohnny Huang u32 config_info; 114696656c6SJohnny Huang u32 strap_info; 1157e523e3bSJohnny Huang u32 scu_protect_info; 116696656c6SJohnny Huang u32 checksum_offset; 117a219f6deSJohnny Huang } __packed; 118696656c6SJohnny Huang 11966f2f8e5SJohnny Huang struct otpstrap_status { 12069d5fd8fSJohnny Huang int value; 12169d5fd8fSJohnny Huang int option_array[7]; 12269d5fd8fSJohnny Huang int remain_times; 12369d5fd8fSJohnny Huang int writeable_option; 12469d5fd8fSJohnny Huang int protected; 12569d5fd8fSJohnny Huang }; 12669d5fd8fSJohnny Huang 1279a4fe690SJohnny Huang struct otpkey_type { 1289a4fe690SJohnny Huang int value; 1299a4fe690SJohnny Huang int key_type; 1309a4fe690SJohnny Huang int need_id; 1319a4fe690SJohnny Huang char information[110]; 1329a4fe690SJohnny Huang }; 1339a4fe690SJohnny Huang 134030cb4a7SJohnny Huang struct otp_pro_sts { 135030cb4a7SJohnny Huang char mem_lock; 136030cb4a7SJohnny Huang char pro_key_ret; 137030cb4a7SJohnny Huang char pro_strap; 138030cb4a7SJohnny Huang char pro_conf; 139030cb4a7SJohnny Huang char pro_data; 140030cb4a7SJohnny Huang char pro_sec; 141030cb4a7SJohnny Huang u32 sec_size; 142030cb4a7SJohnny Huang }; 143030cb4a7SJohnny Huang 1449a4fe690SJohnny Huang struct otp_info_cb { 1459a4fe690SJohnny Huang int version; 146e417205bSJohnny Huang char ver_name[3]; 14779e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1489a4fe690SJohnny Huang int strap_info_len; 14979e42a59SJoel Stanley const struct otpconf_info *conf_info; 1509a4fe690SJohnny Huang int conf_info_len; 15179e42a59SJoel Stanley const struct otpkey_type *key_info; 1529a4fe690SJohnny Huang int key_info_len; 1530dc9a440SJohnny Huang const struct scu_info *scu_info; 1540dc9a440SJohnny Huang int scu_info_len; 155030cb4a7SJohnny Huang struct otp_pro_sts pro_sts; 1569a4fe690SJohnny Huang }; 1579a4fe690SJohnny Huang 158696656c6SJohnny Huang struct otp_image_layout { 1595010032bSJohnny Huang int data_length; 1605010032bSJohnny Huang int conf_length; 1615010032bSJohnny Huang int strap_length; 162b25f02d2SJohnny Huang int scu_pro_length; 163a219f6deSJohnny Huang u8 *data; 164a219f6deSJohnny Huang u8 *data_ignore; 165a219f6deSJohnny Huang u8 *conf; 166a219f6deSJohnny Huang u8 *conf_ignore; 167a219f6deSJohnny Huang u8 *strap; 168a219f6deSJohnny Huang u8 *strap_pro; 169a219f6deSJohnny Huang u8 *strap_ignore; 170b25f02d2SJohnny Huang u8 *scu_pro; 171b25f02d2SJohnny Huang u8 *scu_pro_ignore; 172696656c6SJohnny Huang }; 173696656c6SJohnny Huang 1749a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1759a4fe690SJohnny Huang 17679e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1779a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1789a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1799a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 180181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 181181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as SOC public key"}, 182181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 183181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as SOC private key"}, 184181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1859a4fe690SJohnny Huang }; 1869a4fe690SJohnny Huang 18779e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1889a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1899a4fe690SJohnny Huang {2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 190181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 191181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 192181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1939a4fe690SJohnny Huang }; 1949a4fe690SJohnny Huang 1955fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1965fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1975fdde29fSJohnny Huang {2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 198181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 199181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 200181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 201181f72d8SJohnny Huang }; 202181f72d8SJohnny Huang 203181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = { 204181f72d8SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 205181f72d8SJohnny Huang {2, OTP_KEY_TYPE_AES, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"}, 206181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 207181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 208181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 209181f72d8SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key(big endian)"}, 210181f72d8SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 211181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key(big endian)"}, 2125fdde29fSJohnny Huang }; 2135fdde29fSJohnny Huang 214f347c284SJohnny Huang static void buf_print(u8 *buf, int len) 215f347c284SJohnny Huang { 216f347c284SJohnny Huang int i; 217f347c284SJohnny Huang 218f347c284SJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 219f347c284SJohnny Huang for (i = 0; i < len; i++) { 220f347c284SJohnny Huang if (i % 16 == 0) 221f347c284SJohnny Huang printf("%04X: ", i); 222f347c284SJohnny Huang printf("%02X ", buf[i]); 223f347c284SJohnny Huang if ((i + 1) % 16 == 0) 224f347c284SJohnny Huang printf("\n"); 225f347c284SJohnny Huang } 22688bd7d58SJohnny Huang printf("\n"); 227f347c284SJohnny Huang } 228f347c284SJohnny Huang 229794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset) 230794e27ecSJohnny Huang { 231794e27ecSJohnny Huang int bit_offset; 232794e27ecSJohnny Huang int i; 233794e27ecSJohnny Huang 234794e27ecSJohnny Huang if (offset < 32) { 235794e27ecSJohnny Huang i = 0; 236794e27ecSJohnny Huang bit_offset = offset; 237794e27ecSJohnny Huang } else { 238794e27ecSJohnny Huang i = 1; 239794e27ecSJohnny Huang bit_offset = offset - 32; 240794e27ecSJohnny Huang } 241794e27ecSJohnny Huang if ((rid[i] >> bit_offset) & 0x1) 242794e27ecSJohnny Huang return 1; 243794e27ecSJohnny Huang else 244794e27ecSJohnny Huang return 0; 245794e27ecSJohnny Huang } 246794e27ecSJohnny Huang 247794e27ecSJohnny Huang static int get_rid_num(u32 *rid) 248794e27ecSJohnny Huang { 249794e27ecSJohnny Huang int i; 250794e27ecSJohnny Huang int fz = 0; 251794e27ecSJohnny Huang int rid_num = 0; 252794e27ecSJohnny Huang int ret = 0; 253794e27ecSJohnny Huang 254794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 255794e27ecSJohnny Huang if (get_dw_bit(rid, i) == 0) { 256794e27ecSJohnny Huang if (!fz) 257794e27ecSJohnny Huang fz = 1; 258794e27ecSJohnny Huang 259794e27ecSJohnny Huang } else { 260794e27ecSJohnny Huang rid_num++; 261794e27ecSJohnny Huang if (fz) 262794e27ecSJohnny Huang ret = OTP_FAILURE; 263794e27ecSJohnny Huang } 264794e27ecSJohnny Huang } 265794e27ecSJohnny Huang if (ret) 266794e27ecSJohnny Huang return ret; 267794e27ecSJohnny Huang 268794e27ecSJohnny Huang return rid_num; 269794e27ecSJohnny Huang } 270794e27ecSJohnny Huang 271a219f6deSJohnny Huang static u32 chip_version(void) 2729a4fe690SJohnny Huang { 273e417205bSJohnny Huang u32 revid0, revid1; 2749a4fe690SJohnny Huang 275e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0); 276e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1); 2779a4fe690SJohnny Huang 278e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { 279badd21c2SJohnny Huang /* AST2600-A0 */ 280e417205bSJohnny Huang return OTP_A0; 281e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { 282badd21c2SJohnny Huang /* AST2600-A1 */ 283e417205bSJohnny Huang return OTP_A1; 284e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { 285badd21c2SJohnny Huang /* AST2600-A2 */ 286e417205bSJohnny Huang return OTP_A2; 287e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { 28864b66712SJohnny Huang /* AST2600-A3 */ 289e417205bSJohnny Huang return OTP_A3; 290e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { 291e417205bSJohnny Huang /* AST2620-A1 */ 292e417205bSJohnny Huang return OTP_A1; 293e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { 294e417205bSJohnny Huang /* AST2620-A2 */ 295e417205bSJohnny Huang return OTP_A2; 296e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { 29764b66712SJohnny Huang /* AST2620-A3 */ 298e417205bSJohnny Huang return OTP_A3; 299e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { 300e417205bSJohnny Huang /* AST2605-A2 */ 301e417205bSJohnny Huang return OTP_A2; 302e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { 303e417205bSJohnny Huang /* AST2605-A3 */ 304e417205bSJohnny Huang return OTP_A3; 305e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { 306e417205bSJohnny Huang /* AST2605-A3 */ 307e417205bSJohnny Huang return OTP_A3; 3080dae9d52SJohnny Huang } 309f347c284SJohnny Huang return OTP_FAILURE; 3109a4fe690SJohnny Huang } 3119a4fe690SJohnny Huang 3123d3688adSJohnny Huang static void wait_complete(void) 3133d3688adSJohnny Huang { 3143d3688adSJohnny Huang int reg; 3153d3688adSJohnny Huang 3163d3688adSJohnny Huang do { 3173d3688adSJohnny Huang reg = readl(OTP_STATUS); 3183d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 3193d3688adSJohnny Huang } 3203d3688adSJohnny Huang 321a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 322dacbba92SJohnny Huang { 323dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 324dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 325dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 326dacbba92SJohnny Huang wait_complete(); 327dacbba92SJohnny Huang } 328dacbba92SJohnny Huang 329dacbba92SJohnny Huang static void otp_soak(int soak) 330dacbba92SJohnny Huang { 331e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) { 332dacbba92SJohnny Huang switch (soak) { 333dacbba92SJohnny Huang case 0: //default 334377f8cd7SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 335377f8cd7SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 336dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 337dacbba92SJohnny Huang break; 338dacbba92SJohnny Huang case 1: //normal program 339377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 340377f8cd7SJohnny Huang otp_write(0x5000, 0x1008); // Write MRB 341377f8cd7SJohnny Huang otp_write(0x1000, 0x0024); // Write MR 342feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 343dacbba92SJohnny Huang break; 344dacbba92SJohnny Huang case 2: //soak program 345377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 346377f8cd7SJohnny Huang otp_write(0x5000, 0x0007); // Write MRB 347377f8cd7SJohnny Huang otp_write(0x1000, 0x0100); // Write MR 348feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 349dacbba92SJohnny Huang break; 350dacbba92SJohnny Huang } 351dacbba92SJohnny Huang } else { 352dacbba92SJohnny Huang switch (soak) { 353dacbba92SJohnny Huang case 0: //default 354dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 355dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 356dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 357dacbba92SJohnny Huang break; 358dacbba92SJohnny Huang case 1: //normal program 359dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 360dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 361dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 362feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 363dacbba92SJohnny Huang break; 364dacbba92SJohnny Huang case 2: //soak program 365dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 366dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 367dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 368feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 369dacbba92SJohnny Huang break; 370dacbba92SJohnny Huang } 371dacbba92SJohnny Huang } 372dacbba92SJohnny Huang 373dacbba92SJohnny Huang wait_complete(); 374dacbba92SJohnny Huang } 375dacbba92SJohnny Huang 376a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 37769d5fd8fSJohnny Huang { 3783d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 3793d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3803d3688adSJohnny Huang wait_complete(); 3813d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 3823d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 38369d5fd8fSJohnny Huang } 38469d5fd8fSJohnny Huang 385f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data) 38669d5fd8fSJohnny Huang { 38769d5fd8fSJohnny Huang int config_offset; 38869d5fd8fSJohnny Huang 38969d5fd8fSJohnny Huang config_offset = 0x800; 39069d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 39169d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 39269d5fd8fSJohnny Huang 3933d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 3943d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3953d3688adSJohnny Huang wait_complete(); 3963d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 39769d5fd8fSJohnny Huang } 39869d5fd8fSJohnny Huang 399a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 40069d5fd8fSJohnny Huang { 401a219f6deSJohnny Huang u32 ret; 402a219f6deSJohnny Huang u32 *buf; 40369d5fd8fSJohnny Huang 40469d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 40569d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 40669d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 40769d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 40869d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 4093d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 4103d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 4113d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 4123d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 4133d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 4143d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 4153d3688adSJohnny Huang wait_complete(); 4163d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 41769d5fd8fSJohnny Huang if (ret & 0x1) 418f347c284SJohnny Huang return OTP_SUCCESS; 41969d5fd8fSJohnny Huang else 420f347c284SJohnny Huang return OTP_FAILURE; 42169d5fd8fSJohnny Huang } 42269d5fd8fSJohnny Huang 423a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 42469d5fd8fSJohnny Huang { 425a219f6deSJohnny Huang u32 ret[2]; 42669d5fd8fSJohnny Huang 42730a8c590SJohnny Huang if (otp_addr % 2 == 0) 4283d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 42930a8c590SJohnny Huang else 4303d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 43130a8c590SJohnny Huang 4323d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4333d3688adSJohnny Huang wait_complete(); 4343d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4353d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 43683655e91SJohnny Huang 43730a8c590SJohnny Huang if (otp_addr % 2 == 0) { 43830a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 439f347c284SJohnny Huang return OTP_SUCCESS; 44069d5fd8fSJohnny Huang else 441f347c284SJohnny Huang return OTP_FAILURE; 44230a8c590SJohnny Huang } else { 44330a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 444f347c284SJohnny Huang return OTP_SUCCESS; 44530a8c590SJohnny Huang else 446f347c284SJohnny Huang return OTP_FAILURE; 44730a8c590SJohnny Huang } 44869d5fd8fSJohnny Huang } 44969d5fd8fSJohnny Huang 450a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 4514c1c9b35SJohnny Huang { 452a219f6deSJohnny Huang u32 ret[2]; 4534c1c9b35SJohnny Huang 4544c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 4554c1c9b35SJohnny Huang 4564c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 4573d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 4584c1c9b35SJohnny Huang else 4593d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 4603d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4613d3688adSJohnny Huang wait_complete(); 4623d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4633d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 4644c1c9b35SJohnny Huang if (size == 1) { 4654c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 4664c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 467696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 4684c1c9b35SJohnny Huang compare[0] = 0; 469f347c284SJohnny Huang return OTP_SUCCESS; 470a219f6deSJohnny Huang } 4714c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 472f347c284SJohnny Huang return OTP_FAILURE; 4734c1c9b35SJohnny Huang 4744c1c9b35SJohnny Huang } else { 4754c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 476696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4774c1c9b35SJohnny Huang compare[0] = ~0; 478f347c284SJohnny Huang return OTP_SUCCESS; 479a219f6deSJohnny Huang } 480d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 481f347c284SJohnny Huang return OTP_FAILURE; 4824c1c9b35SJohnny Huang } 4834c1c9b35SJohnny Huang } else if (size == 2) { 4844c1c9b35SJohnny Huang // otp_addr should be even 485696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 4864c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4874c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4884c1c9b35SJohnny Huang compare[0] = 0; 4894c1c9b35SJohnny Huang compare[1] = ~0; 490f347c284SJohnny Huang return OTP_SUCCESS; 491a219f6deSJohnny Huang } 4924c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4934c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4944c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4954c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 496f347c284SJohnny Huang return OTP_FAILURE; 4974c1c9b35SJohnny Huang } else { 498f347c284SJohnny Huang return OTP_FAILURE; 4994c1c9b35SJohnny Huang } 5004c1c9b35SJohnny Huang } 5014c1c9b35SJohnny Huang 502a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit) 50383655e91SJohnny Huang { 50490965bb3SJohnny Huang otp_write(0x0, prog_bit); 50583655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 50683655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 50783655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 50883655e91SJohnny Huang wait_complete(); 50983655e91SJohnny Huang } 51083655e91SJohnny Huang 511a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 51283655e91SJohnny Huang { 51383655e91SJohnny Huang int prog_bit; 51483655e91SJohnny Huang 51583655e91SJohnny Huang if (prog_address % 2 == 0) { 51683655e91SJohnny Huang if (value) 51783655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 51883655e91SJohnny Huang else 51983655e91SJohnny Huang return; 52083655e91SJohnny Huang } else { 521e417205bSJohnny Huang if (info_cb.version != OTP_A3) 52283655e91SJohnny Huang prog_address |= 1 << 15; 52383655e91SJohnny Huang if (!value) 52483655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 52583655e91SJohnny Huang else 52683655e91SJohnny Huang return; 52783655e91SJohnny Huang } 52883655e91SJohnny Huang otp_prog(prog_address, prog_bit); 52983655e91SJohnny Huang } 53083655e91SJohnny Huang 531f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset) 53283655e91SJohnny Huang { 53383655e91SJohnny Huang int pass; 53483655e91SJohnny Huang int i; 53583655e91SJohnny Huang 53683655e91SJohnny Huang otp_soak(1); 53783655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 53883655e91SJohnny Huang pass = 0; 53983655e91SJohnny Huang 54083655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 54183655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 54283655e91SJohnny Huang otp_soak(2); 54383655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 54483655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 54583655e91SJohnny Huang otp_soak(1); 54683655e91SJohnny Huang } else { 54783655e91SJohnny Huang pass = 1; 54883655e91SJohnny Huang break; 54983655e91SJohnny Huang } 55083655e91SJohnny Huang } else { 55183655e91SJohnny Huang pass = 1; 55283655e91SJohnny Huang break; 55383655e91SJohnny Huang } 55483655e91SJohnny Huang } 555794e27ecSJohnny Huang if (pass) 556794e27ecSJohnny Huang return OTP_SUCCESS; 55783655e91SJohnny Huang 558794e27ecSJohnny Huang return OTP_FAILURE; 55983655e91SJohnny Huang } 56083655e91SJohnny Huang 561a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 562d90825e2SJohnny Huang { 563d90825e2SJohnny Huang int j, bit_value, prog_bit; 564d90825e2SJohnny Huang 565d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 566696656c6SJohnny Huang if ((ignore >> j) & 0x1) 567d90825e2SJohnny Huang continue; 568d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 569d90825e2SJohnny Huang if (prog_address % 2 == 0) { 570d90825e2SJohnny Huang if (bit_value) 571d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 572d90825e2SJohnny Huang else 573d90825e2SJohnny Huang continue; 574d90825e2SJohnny Huang } else { 575e417205bSJohnny Huang if (info_cb.version != OTP_A3) 576d90825e2SJohnny Huang prog_address |= 1 << 15; 577d90825e2SJohnny Huang if (bit_value) 578d90825e2SJohnny Huang continue; 579d90825e2SJohnny Huang else 580d90825e2SJohnny Huang prog_bit = 0x1 << j; 581d90825e2SJohnny Huang } 582d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 583d90825e2SJohnny Huang } 584d90825e2SJohnny Huang } 585d90825e2SJohnny Huang 586a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 58754552c69SJohnny Huang { 58854552c69SJohnny Huang int pass; 58954552c69SJohnny Huang int i; 590a219f6deSJohnny Huang u32 data0_masked; 591a219f6deSJohnny Huang u32 data1_masked; 592a219f6deSJohnny Huang u32 buf0_masked; 593a219f6deSJohnny Huang u32 buf1_masked; 594a219f6deSJohnny Huang u32 compare[2]; 59554552c69SJohnny Huang 59654552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 59754552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 59854552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 59954552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 600a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 601f347c284SJohnny Huang return OTP_SUCCESS; 60254552c69SJohnny Huang 603b64ca396SJohnny Huang for (i = 0; i < 32; i++) { 604b64ca396SJohnny Huang if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0) 605b64ca396SJohnny Huang return OTP_FAILURE; 606b64ca396SJohnny Huang if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1) 607b64ca396SJohnny Huang return OTP_FAILURE; 608b64ca396SJohnny Huang } 609b64ca396SJohnny Huang 61054552c69SJohnny Huang otp_soak(1); 61154552c69SJohnny Huang if (data0_masked != buf0_masked) 61254552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 61354552c69SJohnny Huang if (data1_masked != buf1_masked) 61454552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 61554552c69SJohnny Huang 61654552c69SJohnny Huang pass = 0; 61754552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 61854552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 61954552c69SJohnny Huang otp_soak(2); 620a219f6deSJohnny Huang if (compare[0] != 0) 62154552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 622a219f6deSJohnny Huang if (compare[1] != ~0) 6235537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 62454552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 62554552c69SJohnny Huang otp_soak(1); 62654552c69SJohnny Huang } else { 62754552c69SJohnny Huang pass = 1; 62854552c69SJohnny Huang break; 62954552c69SJohnny Huang } 63054552c69SJohnny Huang } else { 63154552c69SJohnny Huang pass = 1; 63254552c69SJohnny Huang break; 63354552c69SJohnny Huang } 63454552c69SJohnny Huang } 63554552c69SJohnny Huang 63654552c69SJohnny Huang if (!pass) { 63754552c69SJohnny Huang otp_soak(0); 63854552c69SJohnny Huang return OTP_FAILURE; 63954552c69SJohnny Huang } 64054552c69SJohnny Huang return OTP_SUCCESS; 64154552c69SJohnny Huang } 64254552c69SJohnny Huang 643541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 64476d13988SJohnny Huang { 645a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 6465010032bSJohnny Huang int strap_end; 64776d13988SJohnny Huang int i, j; 64876d13988SJohnny Huang 649e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 65076d13988SJohnny Huang for (j = 0; j < 64; j++) { 65176d13988SJohnny Huang otpstrap[j].value = 0; 65276d13988SJohnny Huang otpstrap[j].remain_times = 7; 65376d13988SJohnny Huang otpstrap[j].writeable_option = -1; 65476d13988SJohnny Huang otpstrap[j].protected = 0; 65576d13988SJohnny Huang } 6565010032bSJohnny Huang strap_end = 30; 6575010032bSJohnny Huang } else { 6585010032bSJohnny Huang for (j = 0; j < 64; j++) { 6595010032bSJohnny Huang otpstrap[j].value = 0; 6605010032bSJohnny Huang otpstrap[j].remain_times = 6; 6615010032bSJohnny Huang otpstrap[j].writeable_option = -1; 6625010032bSJohnny Huang otpstrap[j].protected = 0; 6635010032bSJohnny Huang } 6645010032bSJohnny Huang strap_end = 28; 6655010032bSJohnny Huang } 66676d13988SJohnny Huang 667dacbba92SJohnny Huang otp_soak(0); 6685010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 66976d13988SJohnny Huang int option = (i - 16) / 2; 670a219f6deSJohnny Huang 671f347c284SJohnny Huang otp_read_conf(i, &OTPSTRAP_RAW[0]); 672f347c284SJohnny Huang otp_read_conf(i + 1, &OTPSTRAP_RAW[1]); 67376d13988SJohnny Huang for (j = 0; j < 32; j++) { 67476d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 675a219f6deSJohnny Huang 676a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 67776d13988SJohnny Huang otpstrap[j].writeable_option = option; 67876d13988SJohnny Huang if (bit_value == 1) 67976d13988SJohnny Huang otpstrap[j].remain_times--; 68076d13988SJohnny Huang otpstrap[j].value ^= bit_value; 68176d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 68276d13988SJohnny Huang } 68376d13988SJohnny Huang for (j = 32; j < 64; j++) { 68476d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 685a219f6deSJohnny Huang 686a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 68776d13988SJohnny Huang otpstrap[j].writeable_option = option; 68876d13988SJohnny Huang if (bit_value == 1) 68976d13988SJohnny Huang otpstrap[j].remain_times--; 69076d13988SJohnny Huang otpstrap[j].value ^= bit_value; 69176d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 69276d13988SJohnny Huang } 69376d13988SJohnny Huang } 6945010032bSJohnny Huang 695f347c284SJohnny Huang otp_read_conf(30, &OTPSTRAP_RAW[0]); 696f347c284SJohnny Huang otp_read_conf(31, &OTPSTRAP_RAW[1]); 69776d13988SJohnny Huang for (j = 0; j < 32; j++) { 69876d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 69976d13988SJohnny Huang otpstrap[j].protected = 1; 70076d13988SJohnny Huang } 70176d13988SJohnny Huang for (j = 32; j < 64; j++) { 70276d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 70376d13988SJohnny Huang otpstrap[j].protected = 1; 70476d13988SJohnny Huang } 70576d13988SJohnny Huang } 70676d13988SJohnny Huang 7077e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit) 708f347c284SJohnny Huang { 709f347c284SJohnny Huang int prog_flag = 0; 710f347c284SJohnny Huang 711f347c284SJohnny Huang // ignore this bit 712f347c284SJohnny Huang if (ibit == 1) 713f347c284SJohnny Huang return OTP_SUCCESS; 714b489486eSJohnny Huang printf("OTPSTRAP[0x%X]:\n", offset); 715f347c284SJohnny Huang 716f347c284SJohnny Huang if (bit == otpstrap->value) { 7177e523e3bSJohnny Huang if (!pbit) { 718f347c284SJohnny Huang printf(" The value is same as before, skip it.\n"); 719f347c284SJohnny Huang return OTP_PROG_SKIP; 720f347c284SJohnny Huang } 721f347c284SJohnny Huang printf(" The value is same as before.\n"); 722f347c284SJohnny Huang } else { 723f347c284SJohnny Huang prog_flag = 1; 724f347c284SJohnny Huang } 725f347c284SJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 726f347c284SJohnny Huang printf(" This bit is protected and is not writable\n"); 727f347c284SJohnny Huang return OTP_FAILURE; 728f347c284SJohnny Huang } 729f347c284SJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 730b489486eSJohnny Huang printf(" This bit has no remaining chance to write.\n"); 731f347c284SJohnny Huang return OTP_FAILURE; 732f347c284SJohnny Huang } 733f347c284SJohnny Huang if (pbit == 1) 734f347c284SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 735f347c284SJohnny Huang if (prog_flag) 736b489486eSJohnny 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); 737f347c284SJohnny Huang 738f347c284SJohnny Huang return OTP_SUCCESS; 739f347c284SJohnny Huang } 740f347c284SJohnny Huang 741f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value) 742f347c284SJohnny Huang { 743f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 744f347c284SJohnny Huang u32 prog_address; 745f347c284SJohnny Huang int offset; 746f347c284SJohnny Huang int ret; 747f347c284SJohnny Huang 748f347c284SJohnny Huang otp_strap_status(otpstrap); 749f347c284SJohnny Huang 7507e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 751f347c284SJohnny Huang 752f347c284SJohnny Huang if (ret != OTP_SUCCESS) 753f347c284SJohnny Huang return ret; 754f347c284SJohnny Huang 755f347c284SJohnny Huang prog_address = 0x800; 756f347c284SJohnny Huang if (bit_offset < 32) { 757f347c284SJohnny Huang offset = bit_offset; 758f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 759f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 760f347c284SJohnny Huang 761f347c284SJohnny Huang } else { 762f347c284SJohnny Huang offset = (bit_offset - 32); 763f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 764f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 765f347c284SJohnny Huang } 766f347c284SJohnny Huang 767f347c284SJohnny Huang return otp_prog_dc_b(1, prog_address, offset); 768f347c284SJohnny Huang } 769f347c284SJohnny Huang 770f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count) 771f347c284SJohnny Huang { 772f347c284SJohnny Huang int i; 773f347c284SJohnny Huang u32 ret[1]; 774f347c284SJohnny Huang 775f347c284SJohnny Huang if (offset + dw_count > 32) 776f347c284SJohnny Huang return OTP_USAGE; 777f347c284SJohnny Huang otp_soak(0); 778f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i++) { 779f347c284SJohnny Huang otp_read_conf(i, ret); 780b489486eSJohnny Huang printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]); 781f347c284SJohnny Huang } 782f347c284SJohnny Huang printf("\n"); 783f347c284SJohnny Huang return OTP_SUCCESS; 784f347c284SJohnny Huang } 785f347c284SJohnny Huang 786f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count) 787f347c284SJohnny Huang { 788f347c284SJohnny Huang int i; 789f347c284SJohnny Huang u32 ret[2]; 790f347c284SJohnny Huang 791f347c284SJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 792f347c284SJohnny Huang return OTP_USAGE; 793f347c284SJohnny Huang otp_soak(0); 794f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 795f347c284SJohnny Huang otp_read_data(i, ret); 796f347c284SJohnny Huang if (i % 4 == 0) 797f347c284SJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 798f347c284SJohnny Huang else 799f347c284SJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 800f347c284SJohnny Huang } 801f347c284SJohnny Huang printf("\n"); 802f347c284SJohnny Huang return OTP_SUCCESS; 803f347c284SJohnny Huang } 804f347c284SJohnny Huang 805f347c284SJohnny Huang static int otp_print_strap(int start, int count) 806f347c284SJohnny Huang { 807f347c284SJohnny Huang int i, j; 808f347c284SJohnny Huang int remains; 809f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 810f347c284SJohnny Huang 811f347c284SJohnny Huang if (start < 0 || start > 64) 812f347c284SJohnny Huang return OTP_USAGE; 813f347c284SJohnny Huang 814f347c284SJohnny Huang if ((start + count) < 0 || (start + count) > 64) 815f347c284SJohnny Huang return OTP_USAGE; 816f347c284SJohnny Huang 817f347c284SJohnny Huang otp_strap_status(otpstrap); 818f347c284SJohnny Huang 8197e523e3bSJohnny Huang if (info_cb.version == OTP_A0) 820f347c284SJohnny Huang remains = 7; 8217e523e3bSJohnny Huang else 822f347c284SJohnny Huang remains = 6; 8237e523e3bSJohnny Huang printf("BIT(hex) Value Option Status\n"); 824f347c284SJohnny Huang printf("______________________________________________________________________________\n"); 825f347c284SJohnny Huang 826f347c284SJohnny Huang for (i = start; i < start + count; i++) { 827f347c284SJohnny Huang printf("0x%-8X", i); 828f347c284SJohnny Huang printf("%-7d", otpstrap[i].value); 829f347c284SJohnny Huang for (j = 0; j < remains; j++) 830f347c284SJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 831f347c284SJohnny Huang printf(" "); 832f347c284SJohnny Huang if (otpstrap[i].protected == 1) { 833f347c284SJohnny Huang printf("protected and not writable"); 834f347c284SJohnny Huang } else { 835f347c284SJohnny Huang printf("not protected "); 836f347c284SJohnny Huang if (otpstrap[i].remain_times == 0) 837f347c284SJohnny Huang printf("and no remaining times to write."); 838f347c284SJohnny Huang else 839f347c284SJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 840f347c284SJohnny Huang } 841f347c284SJohnny Huang printf("\n"); 842f347c284SJohnny Huang } 843f347c284SJohnny Huang 844f347c284SJohnny Huang return OTP_SUCCESS; 845f347c284SJohnny Huang } 846f347c284SJohnny Huang 847794e27ecSJohnny Huang static void otp_print_revid(u32 *rid) 848794e27ecSJohnny Huang { 849794e27ecSJohnny Huang int bit_offset; 850794e27ecSJohnny Huang int i, j; 851794e27ecSJohnny Huang 852794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 853794e27ecSJohnny Huang printf("___________________________________________________\n"); 854794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 855794e27ecSJohnny Huang if (i < 32) { 856794e27ecSJohnny Huang j = 0; 857794e27ecSJohnny Huang bit_offset = i; 858794e27ecSJohnny Huang } else { 859794e27ecSJohnny Huang j = 1; 860794e27ecSJohnny Huang bit_offset = i - 32; 861794e27ecSJohnny Huang } 862794e27ecSJohnny Huang if (i % 16 == 0) 863794e27ecSJohnny Huang printf("%2x | ", i); 864794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1); 865794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 866794e27ecSJohnny Huang printf("\n"); 867794e27ecSJohnny Huang } 868794e27ecSJohnny Huang } 869794e27ecSJohnny Huang 870b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout) 871b25f02d2SJohnny Huang { 872b25f02d2SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 873b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 874b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 875b25f02d2SJohnny Huang int i; 876b25f02d2SJohnny Huang u32 scu_offset; 877b25f02d2SJohnny Huang u32 dw_offset; 878b25f02d2SJohnny Huang u32 bit_offset; 879b25f02d2SJohnny Huang u32 mask; 880b25f02d2SJohnny Huang u32 otp_value; 881b25f02d2SJohnny Huang u32 otp_ignore; 882b25f02d2SJohnny Huang 883b25f02d2SJohnny Huang printf("SCU BIT reg_protect Description\n"); 884b25f02d2SJohnny Huang printf("____________________________________________________________________\n"); 885b25f02d2SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 886b25f02d2SJohnny Huang mask = BIT(scu_info[i].length) - 1; 887b25f02d2SJohnny Huang 888b25f02d2SJohnny Huang if (scu_info[i].bit_offset > 31) { 889b25f02d2SJohnny Huang scu_offset = 0x510; 890b25f02d2SJohnny Huang dw_offset = 1; 891b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset - 32; 892b25f02d2SJohnny Huang } else { 893b25f02d2SJohnny Huang scu_offset = 0x500; 894b25f02d2SJohnny Huang dw_offset = 0; 895b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset; 896b25f02d2SJohnny Huang } 897b25f02d2SJohnny Huang 898b25f02d2SJohnny Huang otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask; 899b25f02d2SJohnny Huang otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask; 900b25f02d2SJohnny Huang 901b25f02d2SJohnny Huang if (otp_ignore == mask) 902b25f02d2SJohnny Huang continue; 903b25f02d2SJohnny Huang else if (otp_ignore != 0) 904b25f02d2SJohnny Huang return OTP_FAILURE; 905b25f02d2SJohnny Huang 906b25f02d2SJohnny Huang if (otp_value != 0 && otp_value != mask) 907b25f02d2SJohnny Huang return OTP_FAILURE; 908b25f02d2SJohnny Huang 909b25f02d2SJohnny Huang printf("0x%-6X", scu_offset); 910b25f02d2SJohnny Huang if (scu_info[i].length == 1) 911b25f02d2SJohnny Huang printf("0x%-11X", bit_offset); 912b25f02d2SJohnny Huang else 9132131c250SJohnny Huang printf("0x%-2X:0x%-6x", bit_offset, bit_offset + scu_info[i].length - 1); 914b25f02d2SJohnny Huang printf("0x%-14X", otp_value); 915b25f02d2SJohnny Huang printf("%s\n", scu_info[i].information); 916b25f02d2SJohnny Huang } 917b25f02d2SJohnny Huang return OTP_SUCCESS; 918b25f02d2SJohnny Huang } 919b25f02d2SJohnny Huang 9200dc9a440SJohnny Huang static void otp_print_scu_info(void) 9210dc9a440SJohnny Huang { 9220dc9a440SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 9230dc9a440SJohnny Huang u32 OTPCFG[2]; 9240dc9a440SJohnny Huang u32 scu_offset; 9250dc9a440SJohnny Huang u32 bit_offset; 9260dc9a440SJohnny Huang u32 reg_p; 9270dc9a440SJohnny Huang u32 length; 9280dc9a440SJohnny Huang int i, j; 9290dc9a440SJohnny Huang 9300dc9a440SJohnny Huang otp_soak(0); 9310dc9a440SJohnny Huang otp_read_conf(28, &OTPCFG[0]); 9320dc9a440SJohnny Huang otp_read_conf(29, &OTPCFG[1]); 9330dc9a440SJohnny Huang printf("SCU BIT reg_protect Description\n"); 9340dc9a440SJohnny Huang printf("____________________________________________________________________\n"); 9350dc9a440SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 9360dc9a440SJohnny Huang length = scu_info[i].length; 9370dc9a440SJohnny Huang for (j = 0; j < length; j++) { 9380dc9a440SJohnny Huang if (scu_info[i].bit_offset + j < 32) { 9390dc9a440SJohnny Huang scu_offset = 0x500; 9400dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j; 9410dc9a440SJohnny Huang reg_p = (OTPCFG[0] >> bit_offset) & 0x1; 9420dc9a440SJohnny Huang } else { 9430dc9a440SJohnny Huang scu_offset = 0x510; 9440dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j - 32; 9450dc9a440SJohnny Huang reg_p = (OTPCFG[1] >> bit_offset) & 0x1; 9460dc9a440SJohnny Huang } 9470dc9a440SJohnny Huang printf("0x%-6X", scu_offset); 9480dc9a440SJohnny Huang printf("0x%-4X", bit_offset); 9490dc9a440SJohnny Huang printf("0x%-13X", reg_p); 9500dc9a440SJohnny Huang if (length == 1) { 9510dc9a440SJohnny Huang printf(" %s\n", scu_info[i].information); 9520dc9a440SJohnny Huang continue; 9530dc9a440SJohnny Huang } 9540dc9a440SJohnny Huang 9550dc9a440SJohnny Huang if (j == 0) 9560dc9a440SJohnny Huang printf("/%s\n", scu_info[i].information); 9570dc9a440SJohnny Huang else if (j == length - 1) 9580dc9a440SJohnny Huang printf("\\ \"\n"); 9590dc9a440SJohnny Huang else 9600dc9a440SJohnny Huang printf("| \"\n"); 9610dc9a440SJohnny Huang } 9620dc9a440SJohnny Huang } 9630dc9a440SJohnny Huang } 9640dc9a440SJohnny Huang 965696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 96669d5fd8fSJohnny Huang { 96779e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 968a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 969a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 970a219f6deSJohnny Huang u32 mask; 971a219f6deSJohnny Huang u32 dw_offset; 972a219f6deSJohnny Huang u32 bit_offset; 973a219f6deSJohnny Huang u32 otp_value; 974a219f6deSJohnny Huang u32 otp_ignore; 975b458cd62SJohnny Huang int fail = 0; 9767adec5f6SJohnny Huang int mask_err; 977794e27ecSJohnny Huang int rid_num = 0; 97873f11549SJohnny Huang char valid_bit[20]; 979794e27ecSJohnny Huang int fz; 98066f2f8e5SJohnny Huang int i; 98173f11549SJohnny Huang int j; 98266f2f8e5SJohnny Huang 983737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 98466f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 9853cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 9867adec5f6SJohnny Huang mask_err = 0; 9873cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 9883cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 9893cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 990b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 991696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 992b458cd62SJohnny Huang 9937adec5f6SJohnny Huang if (conf_info[i].value == OTP_REG_VALID_BIT) { 9947adec5f6SJohnny Huang if (((otp_value + otp_ignore) & mask) != mask) { 995b458cd62SJohnny Huang fail = 1; 9967adec5f6SJohnny Huang mask_err = 1; 9977adec5f6SJohnny Huang } 9987adec5f6SJohnny Huang } else { 9997adec5f6SJohnny Huang if (otp_ignore == mask) { 10007adec5f6SJohnny Huang continue; 10017adec5f6SJohnny Huang } else if (otp_ignore != 0) { 10027adec5f6SJohnny Huang fail = 1; 10037adec5f6SJohnny Huang mask_err = 1; 10047adec5f6SJohnny Huang } 10057adec5f6SJohnny Huang } 1006b458cd62SJohnny Huang 1007a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 10083cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 10093cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 10103cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1011b458cd62SJohnny Huang continue; 1012b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1013b458cd62SJohnny Huang 10143cb28812SJohnny Huang if (conf_info[i].length == 1) { 10153cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 101666f2f8e5SJohnny Huang } else { 1017b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 10183cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 10193cb28812SJohnny Huang conf_info[i].bit_offset); 102066f2f8e5SJohnny Huang } 1021b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1022b458cd62SJohnny Huang 10237adec5f6SJohnny Huang if (mask_err) { 10247adec5f6SJohnny Huang printf("Ignore, mask error\n"); 1025a219f6deSJohnny Huang continue; 1026a219f6deSJohnny Huang } 10273cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1028b458cd62SJohnny Huang printf("Reserved\n"); 10293cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 10303cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1031b458cd62SJohnny Huang printf("\n"); 10323cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1033b458cd62SJohnny Huang if (otp_value != 0) { 103473f11549SJohnny Huang for (j = 0; j < 7; j++) { 1035e2b82258SJohnny Huang if (otp_value & (1 << j)) 103673f11549SJohnny Huang valid_bit[j * 2] = '1'; 1037a219f6deSJohnny Huang else 103873f11549SJohnny Huang valid_bit[j * 2] = '0'; 103973f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 104073f11549SJohnny Huang } 104173f11549SJohnny Huang valid_bit[15] = 0; 104273f11549SJohnny Huang } else { 104373f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1044b458cd62SJohnny Huang } 10453cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1046b458cd62SJohnny Huang printf("\n"); 1047b458cd62SJohnny Huang } else { 10483cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1049b458cd62SJohnny Huang } 1050b458cd62SJohnny Huang } 1051b458cd62SJohnny Huang 1052794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) { 1053794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) { 1054794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1055794e27ecSJohnny Huang fail = 1; 1056794e27ecSJohnny Huang } else { 1057794e27ecSJohnny Huang fz = 0; 1058794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 1059794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) { 1060794e27ecSJohnny Huang if (!fz) 1061794e27ecSJohnny Huang fz = 1; 1062794e27ecSJohnny Huang } else { 1063794e27ecSJohnny Huang rid_num++; 1064794e27ecSJohnny Huang if (fz) { 1065794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1066794e27ecSJohnny Huang fail = 1; 1067794e27ecSJohnny Huang break; 1068794e27ecSJohnny Huang } 1069794e27ecSJohnny Huang } 1070794e27ecSJohnny Huang } 1071794e27ecSJohnny Huang } 1072794e27ecSJohnny Huang if (fail) 1073794e27ecSJohnny Huang printf("OTP revision ID\n"); 1074794e27ecSJohnny Huang else 1075794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1076794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]); 1077794e27ecSJohnny Huang } 1078794e27ecSJohnny Huang 1079b458cd62SJohnny Huang if (fail) 1080b458cd62SJohnny Huang return OTP_FAILURE; 1081b458cd62SJohnny Huang 108266f2f8e5SJohnny Huang return OTP_SUCCESS; 108366f2f8e5SJohnny Huang } 108466f2f8e5SJohnny Huang 10852d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 108666f2f8e5SJohnny Huang { 108779e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1088a219f6deSJohnny Huang u32 OTPCFG[16]; 1089a219f6deSJohnny Huang u32 mask; 1090a219f6deSJohnny Huang u32 dw_offset; 1091a219f6deSJohnny Huang u32 bit_offset; 1092a219f6deSJohnny Huang u32 otp_value; 109373f11549SJohnny Huang char valid_bit[20]; 109466f2f8e5SJohnny Huang int i; 109573f11549SJohnny Huang int j; 109666f2f8e5SJohnny Huang 1097dacbba92SJohnny Huang otp_soak(0); 1098bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 1099f347c284SJohnny Huang otp_read_conf(i, &OTPCFG[i]); 110066f2f8e5SJohnny Huang 1101b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 1102b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 11033cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 11043cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 11052d4b0742SJohnny Huang continue; 11063cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 11073cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 11083cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1109b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1110b458cd62SJohnny Huang 1111a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 11123cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 11133cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 11143cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1115b458cd62SJohnny Huang continue; 1116b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1117b458cd62SJohnny Huang 11183cb28812SJohnny Huang if (conf_info[i].length == 1) { 11193cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 1120b458cd62SJohnny Huang } else { 1121b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 11223cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 11233cb28812SJohnny Huang conf_info[i].bit_offset); 1124b458cd62SJohnny Huang } 1125b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1126b458cd62SJohnny Huang 11273cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1128b458cd62SJohnny Huang printf("Reserved\n"); 11293cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 11303cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1131b458cd62SJohnny Huang printf("\n"); 11323cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1133b458cd62SJohnny Huang if (otp_value != 0) { 113473f11549SJohnny Huang for (j = 0; j < 7; j++) { 1135030cb4a7SJohnny Huang if (otp_value & (1 << j)) 113673f11549SJohnny Huang valid_bit[j * 2] = '1'; 1137a219f6deSJohnny Huang else 113873f11549SJohnny Huang valid_bit[j * 2] = '0'; 113973f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 114073f11549SJohnny Huang } 114173f11549SJohnny Huang valid_bit[15] = 0; 114273f11549SJohnny Huang } else { 114373f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1144b458cd62SJohnny Huang } 11453cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1146b458cd62SJohnny Huang printf("\n"); 1147b458cd62SJohnny Huang } else { 11483cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1149b458cd62SJohnny Huang } 1150b458cd62SJohnny Huang } 1151b458cd62SJohnny Huang return OTP_SUCCESS; 115266f2f8e5SJohnny Huang } 115366f2f8e5SJohnny Huang 11545010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 115576d13988SJohnny Huang { 115679e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 1157a219f6deSJohnny Huang u32 *OTPSTRAP; 1158a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 1159a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 116076d13988SJohnny Huang int i; 1161a8bd6d8cSJohnny Huang int fail = 0; 1162a219f6deSJohnny Huang u32 bit_offset; 1163a219f6deSJohnny Huang u32 dw_offset; 1164a219f6deSJohnny Huang u32 mask; 1165a219f6deSJohnny Huang u32 otp_value; 1166a219f6deSJohnny Huang u32 otp_protect; 1167a219f6deSJohnny Huang u32 otp_ignore; 116876d13988SJohnny Huang 1169a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 1170a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 1171a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 11727e523e3bSJohnny Huang 1173a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 1174de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 1175b458cd62SJohnny Huang 11763cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 11777adec5f6SJohnny Huang fail = 0; 1178696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 1179a8bd6d8cSJohnny Huang dw_offset = 1; 11803cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 1181a8bd6d8cSJohnny Huang } else { 1182a8bd6d8cSJohnny Huang dw_offset = 0; 11833cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 1184a8bd6d8cSJohnny Huang } 118576d13988SJohnny Huang 11863cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 1187a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 1188a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 1189696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 1190a8bd6d8cSJohnny Huang 1191a219f6deSJohnny Huang if (otp_ignore == mask) 1192a8bd6d8cSJohnny Huang continue; 1193a219f6deSJohnny Huang else if (otp_ignore != 0) 1194a8bd6d8cSJohnny Huang fail = 1; 1195a8bd6d8cSJohnny Huang 1196a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 11973cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1198a8bd6d8cSJohnny Huang continue; 1199a8bd6d8cSJohnny Huang 12003cb28812SJohnny Huang if (strap_info[i].length == 1) { 12013cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1202a8bd6d8cSJohnny Huang } else { 1203b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 12043cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 12053cb28812SJohnny Huang strap_info[i].bit_offset); 1206a8bd6d8cSJohnny Huang } 1207a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 1208a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 1209a8bd6d8cSJohnny Huang 1210a8bd6d8cSJohnny Huang if (fail) { 1211696656c6SJohnny Huang printf("Ignore mask error\n"); 1212a8bd6d8cSJohnny Huang } else { 12133cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12143cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1215a8bd6d8cSJohnny Huang else 1216a8bd6d8cSJohnny Huang printf("Reserved\n"); 1217a8bd6d8cSJohnny Huang } 1218a8bd6d8cSJohnny Huang } 1219a8bd6d8cSJohnny Huang 1220a8bd6d8cSJohnny Huang if (fail) 122176d13988SJohnny Huang return OTP_FAILURE; 122276d13988SJohnny Huang 122376d13988SJohnny Huang return OTP_SUCCESS; 122476d13988SJohnny Huang } 122576d13988SJohnny Huang 1226b458cd62SJohnny Huang static int otp_print_strap_info(int view) 122776d13988SJohnny Huang { 122879e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 122976d13988SJohnny Huang struct otpstrap_status strap_status[64]; 123007baa4e8SJohnny Huang int i, j; 1231b458cd62SJohnny Huang int fail = 0; 1232a219f6deSJohnny Huang u32 bit_offset; 1233a219f6deSJohnny Huang u32 length; 1234a219f6deSJohnny Huang u32 otp_value; 1235a219f6deSJohnny Huang u32 otp_protect; 123676d13988SJohnny Huang 1237541eb887SJohnny Huang otp_strap_status(strap_status); 123876d13988SJohnny Huang 1239b458cd62SJohnny Huang if (view) { 124007baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 124107baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 1242b458cd62SJohnny Huang } else { 1243b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 1244b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 124576d13988SJohnny Huang } 12463cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 1247b458cd62SJohnny Huang otp_value = 0; 12483cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 12493cb28812SJohnny Huang length = strap_info[i].length; 1250b458cd62SJohnny Huang for (j = 0; j < length; j++) { 1251c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 1252c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 1253b458cd62SJohnny Huang } 1254a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 12553cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1256b458cd62SJohnny Huang continue; 1257b458cd62SJohnny Huang if (view) { 1258b458cd62SJohnny Huang for (j = 0; j < length; j++) { 12593cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 1260b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 126107baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 1262e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 12633cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 1264b458cd62SJohnny Huang printf(" Reserved\n"); 1265b458cd62SJohnny Huang continue; 1266b458cd62SJohnny Huang } 1267b458cd62SJohnny Huang if (length == 1) { 12683cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 1269b458cd62SJohnny Huang continue; 127076d13988SJohnny Huang } 127176d13988SJohnny Huang 1272b458cd62SJohnny Huang if (j == 0) 12733cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 1274b458cd62SJohnny Huang else if (j == length - 1) 1275b458cd62SJohnny Huang printf("\\ \"\n"); 1276b458cd62SJohnny Huang else 1277b458cd62SJohnny Huang printf("| \"\n"); 127876d13988SJohnny Huang } 1279b458cd62SJohnny Huang } else { 1280c947ef08SJohnny Huang if (length == 1) { 12813cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1282b458cd62SJohnny Huang } else { 1283b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 1284b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 1285b458cd62SJohnny Huang } 1286b458cd62SJohnny Huang 1287b458cd62SJohnny Huang printf("0x%-10X", otp_value); 1288b458cd62SJohnny Huang 12893cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12903cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1291b458cd62SJohnny Huang else 1292b458cd62SJohnny Huang printf("Reserved\n"); 1293b458cd62SJohnny Huang } 1294b458cd62SJohnny Huang } 1295b458cd62SJohnny Huang 1296b458cd62SJohnny Huang if (fail) 1297b458cd62SJohnny Huang return OTP_FAILURE; 1298b458cd62SJohnny Huang 1299b458cd62SJohnny Huang return OTP_SUCCESS; 1300b458cd62SJohnny Huang } 1301b458cd62SJohnny Huang 130288bd7d58SJohnny Huang static void _otp_print_key(u32 *data) 130369d5fd8fSJohnny Huang { 130488bd7d58SJohnny Huang int i, j; 130569d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 13069a4fe690SJohnny Huang struct otpkey_type key_info; 130788bd7d58SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 130888bd7d58SJohnny Huang int len = 0; 1309a219f6deSJohnny Huang u8 *byte_buf; 131088bd7d58SJohnny Huang int empty; 131154552c69SJohnny Huang 131288bd7d58SJohnny Huang byte_buf = (u8 *)data; 13139d998018SJohnny Huang 131488bd7d58SJohnny Huang empty = 1; 13159d998018SJohnny Huang for (i = 0; i < 16; i++) { 131688bd7d58SJohnny Huang if (i % 2) { 131788bd7d58SJohnny Huang if (data[i] != 0xffffffff) 131888bd7d58SJohnny Huang empty = 0; 131988bd7d58SJohnny Huang } else { 132088bd7d58SJohnny Huang if (data[i] != 0) 13219d998018SJohnny Huang empty = 0; 13229d998018SJohnny Huang } 132388bd7d58SJohnny Huang } 132488bd7d58SJohnny Huang if (empty) { 132588bd7d58SJohnny Huang printf("OTP data header is empty\n"); 132688bd7d58SJohnny Huang return; 132788bd7d58SJohnny Huang } 13289d998018SJohnny Huang 132988bd7d58SJohnny Huang for (i = 0; i < 16; i++) { 133088bd7d58SJohnny Huang key_id = data[i] & 0x7; 133188bd7d58SJohnny Huang key_offset = data[i] & 0x1ff8; 133288bd7d58SJohnny Huang last = (data[i] >> 13) & 1; 133388bd7d58SJohnny Huang key_type = (data[i] >> 14) & 0xf; 133488bd7d58SJohnny Huang key_length = (data[i] >> 18) & 0x3; 133588bd7d58SJohnny Huang exp_length = (data[i] >> 20) & 0xfff; 13369a4fe690SJohnny Huang 133788bd7d58SJohnny Huang key_info.value = -1; 13389a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 13399a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 13409a4fe690SJohnny Huang key_info = key_info_array[j]; 13419a4fe690SJohnny Huang break; 13429a4fe690SJohnny Huang } 13439a4fe690SJohnny Huang } 134488bd7d58SJohnny Huang if (key_info.value == -1) 134588bd7d58SJohnny Huang break; 13469a4fe690SJohnny Huang 13477f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 134869d5fd8fSJohnny Huang printf("Key Type: "); 13499a4fe690SJohnny Huang printf("%s\n", key_info.information); 13509a4fe690SJohnny Huang 13519a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 135269d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 135369d5fd8fSJohnny Huang switch (key_length) { 135469d5fd8fSJohnny Huang case 0: 135569d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 135669d5fd8fSJohnny Huang break; 135769d5fd8fSJohnny Huang case 1: 135869d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 135969d5fd8fSJohnny Huang break; 136069d5fd8fSJohnny Huang case 2: 136169d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 136269d5fd8fSJohnny Huang break; 136369d5fd8fSJohnny Huang case 3: 136469d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 136569d5fd8fSJohnny Huang break; 136669d5fd8fSJohnny Huang } 1367181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1368181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 136969d5fd8fSJohnny Huang printf("RSA SHA Type: "); 137069d5fd8fSJohnny Huang switch (key_length) { 137169d5fd8fSJohnny Huang case 0: 137269d5fd8fSJohnny Huang printf("RSA1024\n"); 137369d5fd8fSJohnny Huang len = 0x100; 137469d5fd8fSJohnny Huang break; 137569d5fd8fSJohnny Huang case 1: 137669d5fd8fSJohnny Huang printf("RSA2048\n"); 137769d5fd8fSJohnny Huang len = 0x200; 137869d5fd8fSJohnny Huang break; 137969d5fd8fSJohnny Huang case 2: 138069d5fd8fSJohnny Huang printf("RSA3072\n"); 138169d5fd8fSJohnny Huang len = 0x300; 138269d5fd8fSJohnny Huang break; 138369d5fd8fSJohnny Huang case 3: 138469d5fd8fSJohnny Huang printf("RSA4096\n"); 138569d5fd8fSJohnny Huang len = 0x400; 138669d5fd8fSJohnny Huang break; 138769d5fd8fSJohnny Huang } 138869d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 138969d5fd8fSJohnny Huang } 13909a4fe690SJohnny Huang if (key_info.need_id) 139169d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 139269d5fd8fSJohnny Huang printf("Key Value:\n"); 13939a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 139469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 13959a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 13969a4fe690SJohnny Huang printf("AES Key:\n"); 13979a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 1398e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 13999a4fe690SJohnny Huang printf("AES IV:\n"); 14009a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 14019a4fe690SJohnny Huang } 14029a4fe690SJohnny Huang 14039a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1404e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 140569d5fd8fSJohnny Huang printf("AES Key:\n"); 140669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 140769d5fd8fSJohnny Huang printf("AES IV:\n"); 140869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 14095fdde29fSJohnny Huang } else { 14109a4fe690SJohnny Huang printf("AES Key 1:\n"); 14119a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 14129a4fe690SJohnny Huang printf("AES Key 2:\n"); 14139a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 14149a4fe690SJohnny Huang } 1415181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 141669d5fd8fSJohnny Huang printf("RSA mod:\n"); 141769d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 141869d5fd8fSJohnny Huang printf("RSA exp:\n"); 141969d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1420181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1421181f72d8SJohnny Huang printf("RSA mod:\n"); 1422181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1423181f72d8SJohnny Huang printf("RSA exp:\n"); 1424a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 142569d5fd8fSJohnny Huang } 142669d5fd8fSJohnny Huang if (last) 142769d5fd8fSJohnny Huang break; 142869d5fd8fSJohnny Huang } 142988bd7d58SJohnny Huang } 143088bd7d58SJohnny Huang 143188bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 143288bd7d58SJohnny Huang { 143388bd7d58SJohnny Huang u32 *buf; 143488bd7d58SJohnny Huang 143588bd7d58SJohnny Huang buf = (u32 *)image_layout->data; 143688bd7d58SJohnny Huang _otp_print_key(buf); 143788bd7d58SJohnny Huang 1438f347c284SJohnny Huang return OTP_SUCCESS; 1439f347c284SJohnny Huang } 1440f347c284SJohnny Huang 144188bd7d58SJohnny Huang static void otp_print_key_info(void) 144288bd7d58SJohnny Huang { 144388bd7d58SJohnny Huang u32 data[2048]; 144488bd7d58SJohnny Huang int i; 144588bd7d58SJohnny Huang 144688bd7d58SJohnny Huang for (i = 0; i < 2048 ; i += 2) 144788bd7d58SJohnny Huang otp_read_data(i, &data[i]); 144888bd7d58SJohnny Huang 144988bd7d58SJohnny Huang _otp_print_key(data); 145088bd7d58SJohnny Huang } 145188bd7d58SJohnny Huang 1452b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data) 1453f347c284SJohnny Huang { 1454f347c284SJohnny Huang int i; 1455f347c284SJohnny Huang int ret; 1456f347c284SJohnny Huang u32 *buf; 1457f347c284SJohnny Huang u32 *buf_ignore; 1458f347c284SJohnny Huang 1459f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1460f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1461f347c284SJohnny Huang printf("Start Programing...\n"); 1462f347c284SJohnny Huang 1463f347c284SJohnny Huang // programing ecc region first 1464f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1465f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1466f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1467f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1468f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1469f347c284SJohnny Huang return ret; 1470f347c284SJohnny Huang } 1471f347c284SJohnny Huang } 1472f347c284SJohnny Huang 1473f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1474f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1475f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1476f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1477f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1478f347c284SJohnny Huang return ret; 1479f347c284SJohnny Huang } 1480f347c284SJohnny Huang } 1481f347c284SJohnny Huang otp_soak(0); 1482f347c284SJohnny Huang return OTP_SUCCESS; 1483f347c284SJohnny Huang } 1484f347c284SJohnny Huang 1485b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1486f347c284SJohnny Huang { 1487f347c284SJohnny Huang u32 *strap; 1488f347c284SJohnny Huang u32 *strap_ignore; 1489f347c284SJohnny Huang u32 *strap_pro; 1490f347c284SJohnny Huang u32 prog_address; 1491f347c284SJohnny Huang int i; 14927e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1493f347c284SJohnny Huang int fail = 0; 1494f347c284SJohnny Huang int ret; 1495f347c284SJohnny Huang int prog_flag = 0; 1496f347c284SJohnny Huang 1497f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1498f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1499f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1500f347c284SJohnny Huang 1501f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1502f347c284SJohnny Huang prog_address = 0x800; 1503f347c284SJohnny Huang if (i < 32) { 1504f347c284SJohnny Huang offset = i; 1505f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1506f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1507f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1508f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1509f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1510f347c284SJohnny Huang 1511f347c284SJohnny Huang } else { 1512f347c284SJohnny Huang offset = (i - 32); 1513f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1514f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1515f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1516f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1517f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1518f347c284SJohnny Huang } 1519f347c284SJohnny Huang 1520f347c284SJohnny Huang if (ibit == 1) 1521f347c284SJohnny Huang continue; 1522f347c284SJohnny Huang if (bit == otpstrap[i].value) 1523f347c284SJohnny Huang prog_flag = 0; 1524f347c284SJohnny Huang else 1525f347c284SJohnny Huang prog_flag = 1; 1526f347c284SJohnny Huang 1527f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1528f347c284SJohnny Huang fail = 1; 1529f347c284SJohnny Huang continue; 1530f347c284SJohnny Huang } 1531f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1532f347c284SJohnny Huang fail = 1; 1533f347c284SJohnny Huang continue; 1534f347c284SJohnny Huang } 1535f347c284SJohnny Huang 1536f347c284SJohnny Huang if (prog_flag) { 1537f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1538f347c284SJohnny Huang if (ret) 1539f347c284SJohnny Huang return OTP_FAILURE; 1540f347c284SJohnny Huang } 1541f347c284SJohnny Huang 1542f347c284SJohnny Huang if (pbit != 0) { 1543f347c284SJohnny Huang prog_address = 0x800; 1544f347c284SJohnny Huang if (i < 32) 1545f347c284SJohnny Huang prog_address |= 0x60c; 1546f347c284SJohnny Huang else 1547f347c284SJohnny Huang prog_address |= 0x60e; 1548f347c284SJohnny Huang 1549f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1550f347c284SJohnny Huang if (ret) 1551f347c284SJohnny Huang return OTP_FAILURE; 1552f347c284SJohnny Huang } 1553f347c284SJohnny Huang } 1554f347c284SJohnny Huang otp_soak(0); 1555f347c284SJohnny Huang if (fail == 1) 1556f347c284SJohnny Huang return OTP_FAILURE; 1557f347c284SJohnny Huang return OTP_SUCCESS; 155869d5fd8fSJohnny Huang } 155969d5fd8fSJohnny Huang 1560b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf) 156169d5fd8fSJohnny Huang { 1562a6d0d645SJohnny Huang int i, k; 1563d90825e2SJohnny Huang int pass = 0; 1564a219f6deSJohnny Huang u32 prog_address; 1565a219f6deSJohnny Huang u32 compare[2]; 1566a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1567a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1568a219f6deSJohnny Huang u32 data_masked; 1569a219f6deSJohnny Huang u32 buf_masked; 157069d5fd8fSJohnny Huang 1571a6d0d645SJohnny Huang printf("Start Programing...\n"); 1572d90825e2SJohnny Huang otp_soak(0); 1573bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 1574b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 15755010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1576a6d0d645SJohnny Huang prog_address = 0x800; 1577a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1578a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1579bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1580bb34a7bfSJohnny Huang pass = 1; 1581a6d0d645SJohnny Huang continue; 1582bb34a7bfSJohnny Huang } 1583de6fbf1cSJohnny Huang 1584de6fbf1cSJohnny Huang otp_soak(1); 15855010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1586a6d0d645SJohnny Huang 158769d5fd8fSJohnny Huang pass = 0; 158869d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 15895010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1590de6fbf1cSJohnny Huang otp_soak(2); 1591feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 15925010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1593de6fbf1cSJohnny Huang otp_soak(1); 1594de6fbf1cSJohnny Huang } else { 1595de6fbf1cSJohnny Huang pass = 1; 1596de6fbf1cSJohnny Huang break; 1597de6fbf1cSJohnny Huang } 1598a6d0d645SJohnny Huang } else { 159969d5fd8fSJohnny Huang pass = 1; 160069d5fd8fSJohnny Huang break; 160169d5fd8fSJohnny Huang } 160269d5fd8fSJohnny Huang } 1603bb34a7bfSJohnny Huang if (pass == 0) { 1604b64ca396SJohnny Huang printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n", 1605b64ca396SJohnny Huang i, otp_conf[i], conf[i], conf_ignore[i]); 1606bb34a7bfSJohnny Huang break; 1607bb34a7bfSJohnny Huang } 1608a6d0d645SJohnny Huang } 1609a6d0d645SJohnny Huang 1610de6fbf1cSJohnny Huang otp_soak(0); 161169d5fd8fSJohnny Huang if (!pass) 16122a856b9aSJohnny Huang return OTP_FAILURE; 1613a6d0d645SJohnny Huang 16142a856b9aSJohnny Huang return OTP_SUCCESS; 161569d5fd8fSJohnny Huang } 161669d5fd8fSJohnny Huang 1617b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro) 1618b25f02d2SJohnny Huang { 1619b25f02d2SJohnny Huang int i, k; 1620b25f02d2SJohnny Huang int pass = 0; 1621b25f02d2SJohnny Huang u32 prog_address; 1622b25f02d2SJohnny Huang u32 compare[2]; 1623b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1624b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1625b25f02d2SJohnny Huang u32 data_masked; 1626b25f02d2SJohnny Huang u32 buf_masked; 1627b25f02d2SJohnny Huang 1628b25f02d2SJohnny Huang printf("Start Programing...\n"); 1629b25f02d2SJohnny Huang otp_soak(0); 1630b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1631b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1632b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1633b25f02d2SJohnny Huang prog_address = 0xe08 + i * 2; 1634b25f02d2SJohnny Huang if (data_masked == buf_masked) { 1635b25f02d2SJohnny Huang pass = 1; 1636b25f02d2SJohnny Huang continue; 1637b25f02d2SJohnny Huang } 1638b25f02d2SJohnny Huang 1639b25f02d2SJohnny Huang otp_soak(1); 1640b25f02d2SJohnny Huang otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address); 1641b25f02d2SJohnny Huang 1642b25f02d2SJohnny Huang pass = 0; 1643b25f02d2SJohnny Huang for (k = 0; k < RETRY; k++) { 1644b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1645b25f02d2SJohnny Huang otp_soak(2); 1646b25f02d2SJohnny Huang otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address); 1647b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1648b25f02d2SJohnny Huang otp_soak(1); 1649b25f02d2SJohnny Huang } else { 1650b25f02d2SJohnny Huang pass = 1; 1651b25f02d2SJohnny Huang break; 1652b25f02d2SJohnny Huang } 1653b25f02d2SJohnny Huang } else { 1654b25f02d2SJohnny Huang pass = 1; 1655b25f02d2SJohnny Huang break; 1656b25f02d2SJohnny Huang } 1657b25f02d2SJohnny Huang } 1658b25f02d2SJohnny Huang if (pass == 0) { 1659b489486eSJohnny Huang printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n", 1660b25f02d2SJohnny Huang i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]); 1661b25f02d2SJohnny Huang break; 1662b25f02d2SJohnny Huang } 1663b25f02d2SJohnny Huang } 1664b25f02d2SJohnny Huang 1665b25f02d2SJohnny Huang otp_soak(0); 1666b25f02d2SJohnny Huang if (!pass) 1667b25f02d2SJohnny Huang return OTP_FAILURE; 1668b25f02d2SJohnny Huang 1669b25f02d2SJohnny Huang return OTP_SUCCESS; 1670b25f02d2SJohnny Huang } 1671b25f02d2SJohnny Huang 1672b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data) 1673b64ca396SJohnny Huang { 1674b64ca396SJohnny Huang int data_dw; 1675b64ca396SJohnny Huang u32 data_masked; 1676b64ca396SJohnny Huang u32 buf_masked; 1677b64ca396SJohnny Huang u32 *buf = (u32 *)image_layout->data; 1678b64ca396SJohnny Huang u32 *buf_ignore = (u32 *)image_layout->data_ignore; 1679b64ca396SJohnny Huang int i; 1680b64ca396SJohnny Huang 1681b64ca396SJohnny Huang data_dw = image_layout->data_length / 4; 1682b64ca396SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1683b64ca396SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1684b64ca396SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1685b64ca396SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1686b64ca396SJohnny Huang if (data_masked == buf_masked) 1687b64ca396SJohnny Huang continue; 1688b64ca396SJohnny Huang if (i % 2 == 0) { 1689b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1690b64ca396SJohnny Huang continue; 1691b64ca396SJohnny Huang } else { 1692b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1693b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1694b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1695b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1696b64ca396SJohnny Huang return OTP_FAILURE; 1697b64ca396SJohnny Huang } 1698b64ca396SJohnny Huang } else { 1699b64ca396SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1700b64ca396SJohnny Huang continue; 1701b64ca396SJohnny Huang } else { 1702b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1703b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1704b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1705b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1706b64ca396SJohnny Huang return OTP_FAILURE; 1707b64ca396SJohnny Huang } 1708b64ca396SJohnny Huang } 1709b64ca396SJohnny Huang } 1710b64ca396SJohnny Huang return OTP_SUCCESS; 1711b64ca396SJohnny Huang } 1712b64ca396SJohnny Huang 1713b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1714b64ca396SJohnny Huang { 1715b64ca396SJohnny Huang int i; 1716b64ca396SJohnny Huang u32 *strap; 1717b64ca396SJohnny Huang u32 *strap_ignore; 1718b64ca396SJohnny Huang u32 *strap_pro; 1719b64ca396SJohnny Huang int bit, pbit, ibit; 1720b64ca396SJohnny Huang int fail = 0; 1721b64ca396SJohnny Huang int ret; 1722b64ca396SJohnny Huang 1723b64ca396SJohnny Huang strap = (u32 *)image_layout->strap; 1724b64ca396SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1725b64ca396SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1726b64ca396SJohnny Huang 1727b64ca396SJohnny Huang for (i = 0; i < 64; i++) { 1728b64ca396SJohnny Huang if (i < 32) { 1729b64ca396SJohnny Huang bit = (strap[0] >> i) & 0x1; 1730b64ca396SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1731b64ca396SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1732b64ca396SJohnny Huang } else { 1733b64ca396SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1734b64ca396SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1735b64ca396SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1736b64ca396SJohnny Huang } 1737b64ca396SJohnny Huang 1738b64ca396SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1739b64ca396SJohnny Huang 1740b64ca396SJohnny Huang if (ret == OTP_FAILURE) 1741b64ca396SJohnny Huang fail = 1; 1742b64ca396SJohnny Huang } 1743b64ca396SJohnny Huang if (fail == 1) { 1744b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1745b64ca396SJohnny Huang return OTP_FAILURE; 1746b64ca396SJohnny Huang } 1747b64ca396SJohnny Huang return OTP_SUCCESS; 1748b64ca396SJohnny Huang } 1749b64ca396SJohnny Huang 1750b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf) 1751b64ca396SJohnny Huang { 1752b64ca396SJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1753b64ca396SJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1754b64ca396SJohnny Huang u32 data_masked; 1755b64ca396SJohnny Huang u32 buf_masked; 1756b64ca396SJohnny Huang int i; 1757b64ca396SJohnny Huang 1758b64ca396SJohnny Huang for (i = 0; i < 16; i++) { 1759b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 1760b64ca396SJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1761b64ca396SJohnny Huang if (data_masked == buf_masked) 1762b64ca396SJohnny Huang continue; 1763b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1764b64ca396SJohnny Huang continue; 1765b64ca396SJohnny Huang } else { 1766b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1767b64ca396SJohnny Huang printf("OTPCFG[%X] = %x\n", i, otp_conf[i]); 1768b64ca396SJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 1769b64ca396SJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 1770b64ca396SJohnny Huang return OTP_FAILURE; 1771b64ca396SJohnny Huang } 1772b64ca396SJohnny Huang } 1773b64ca396SJohnny Huang return OTP_SUCCESS; 1774b64ca396SJohnny Huang } 1775b64ca396SJohnny Huang 1776b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro) 1777b25f02d2SJohnny Huang { 1778b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1779b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1780b25f02d2SJohnny Huang u32 data_masked; 1781b25f02d2SJohnny Huang u32 buf_masked; 1782b25f02d2SJohnny Huang int i; 1783b25f02d2SJohnny Huang 1784b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1785b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1786b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1787b25f02d2SJohnny Huang if (data_masked == buf_masked) 1788b25f02d2SJohnny Huang continue; 1789b25f02d2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1790b25f02d2SJohnny Huang continue; 1791b25f02d2SJohnny Huang } else { 1792b25f02d2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1793b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]); 1794b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]); 1795b489486eSJohnny Huang printf("Mask [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]); 1796b25f02d2SJohnny Huang return OTP_FAILURE; 1797b25f02d2SJohnny Huang } 1798b25f02d2SJohnny Huang } 1799b25f02d2SJohnny Huang return OTP_SUCCESS; 1800b25f02d2SJohnny Huang } 1801b25f02d2SJohnny Huang 1802f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf) 1803696656c6SJohnny Huang { 1804696656c6SJohnny Huang sha256_context ctx; 1805696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1806696656c6SJohnny Huang 1807696656c6SJohnny Huang sha256_starts(&ctx); 1808696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1809696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1810696656c6SJohnny Huang 1811696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1812f347c284SJohnny Huang return OTP_SUCCESS; 1813f347c284SJohnny Huang return OTP_FAILURE; 1814696656c6SJohnny Huang } 1815696656c6SJohnny Huang 1816f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 181769d5fd8fSJohnny Huang { 181869d5fd8fSJohnny Huang int ret; 181961a6cda7SJohnny Huang int image_soc_ver = 0; 1820696656c6SJohnny Huang struct otp_header *otp_header; 1821696656c6SJohnny Huang struct otp_image_layout image_layout; 1822696656c6SJohnny Huang int image_size; 1823a219f6deSJohnny Huang u8 *buf; 1824a219f6deSJohnny Huang u8 *checksum; 1825b64ca396SJohnny Huang int i; 1826b64ca396SJohnny Huang u32 data[2048]; 1827b64ca396SJohnny Huang u32 conf[16]; 1828b25f02d2SJohnny Huang u32 scu_pro[2]; 1829b64ca396SJohnny Huang struct otpstrap_status otpstrap[64]; 183069d5fd8fSJohnny Huang 1831696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1832696656c6SJohnny Huang if (!otp_header) { 1833030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 18342a856b9aSJohnny Huang return OTP_FAILURE; 183569d5fd8fSJohnny Huang } 1836d90825e2SJohnny Huang 1837696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1838696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1839696656c6SJohnny Huang 1840696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1841696656c6SJohnny Huang 1842696656c6SJohnny Huang if (!buf) { 1843030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 1844696656c6SJohnny Huang return OTP_FAILURE; 1845696656c6SJohnny Huang } 1846696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1847696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1848696656c6SJohnny Huang 1849696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1850030cb4a7SJohnny Huang printf("Image is invalid\n"); 1851696656c6SJohnny Huang return OTP_FAILURE; 1852696656c6SJohnny Huang } 1853696656c6SJohnny Huang 18545010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 18555010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 18565010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 18575010032bSJohnny Huang 18585010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1859696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 18605010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1861696656c6SJohnny Huang 1862696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 18635010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 18645010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 18655010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 18667e523e3bSJohnny Huang 1867b25f02d2SJohnny Huang image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info); 1868b25f02d2SJohnny Huang image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2); 1869b25f02d2SJohnny Huang image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length; 1870b25f02d2SJohnny Huang 18717e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 18727e523e3bSJohnny Huang image_soc_ver = OTP_A0; 187361a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 187461a6cda7SJohnny Huang image_soc_ver = OTP_A1; 187561a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 187661a6cda7SJohnny Huang image_soc_ver = OTP_A2; 187761a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 187861a6cda7SJohnny Huang image_soc_ver = OTP_A3; 1879696656c6SJohnny Huang } else { 1880030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n"); 1881696656c6SJohnny Huang return OTP_FAILURE; 1882696656c6SJohnny Huang } 1883696656c6SJohnny Huang 188461a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 1885*5e096f11SJohnny Huang printf("Image SOC version is not match to HW SOC version\n"); 18869a4fe690SJohnny Huang return OTP_FAILURE; 18879a4fe690SJohnny Huang } 18889a4fe690SJohnny Huang 1889*5e096f11SJohnny Huang if (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver) != OTPTOOL_COMPT_VERSION) { 1890*5e096f11SJohnny Huang printf("OTP image is not generated by otptool v1.x.x\n"); 189161a6cda7SJohnny Huang return OTP_FAILURE; 189261a6cda7SJohnny Huang } 189361a6cda7SJohnny Huang 1894f347c284SJohnny Huang if (otp_verify_image(buf, image_size, checksum)) { 1895030cb4a7SJohnny Huang printf("checksum is invalid\n"); 1896696656c6SJohnny Huang return OTP_FAILURE; 1897d90825e2SJohnny Huang } 18987332532cSJohnny Huang 1899030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 1900030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 1901030cb4a7SJohnny Huang return OTP_FAILURE; 1902030cb4a7SJohnny Huang } 1903b64ca396SJohnny Huang ret = 0; 1904030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 1905030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 1906030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 1907030cb4a7SJohnny Huang ret = -1; 1908030cb4a7SJohnny Huang } 1909030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 1910030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 1911030cb4a7SJohnny Huang ret = -1; 1912030cb4a7SJohnny Huang } 1913b64ca396SJohnny Huang printf("Read OTP Data Region:\n"); 1914b64ca396SJohnny Huang for (i = 0; i < 2048 ; i += 2) 1915b64ca396SJohnny Huang otp_read_data(i, &data[i]); 1916b64ca396SJohnny Huang 1917b64ca396SJohnny Huang printf("Check writable...\n"); 1918b64ca396SJohnny Huang if (otp_check_data_image(&image_layout, data) == OTP_FAILURE) 1919b64ca396SJohnny Huang ret = -1; 1920030cb4a7SJohnny Huang } 1921030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 1922030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 1923030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 1924030cb4a7SJohnny Huang ret = -1; 1925030cb4a7SJohnny Huang } 1926b64ca396SJohnny Huang printf("Read OTP Config Region:\n"); 1927b64ca396SJohnny Huang for (i = 0; i < 16 ; i++) 1928b64ca396SJohnny Huang otp_read_conf(i, &conf[i]); 1929b64ca396SJohnny Huang 1930b64ca396SJohnny Huang printf("Check writable...\n"); 1931b64ca396SJohnny Huang if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE) 1932b64ca396SJohnny Huang ret = -1; 1933030cb4a7SJohnny Huang } 1934030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 1935030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 1936030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 1937030cb4a7SJohnny Huang ret = -1; 1938030cb4a7SJohnny Huang } 1939b64ca396SJohnny Huang printf("Read OTP Strap Region:\n"); 1940b64ca396SJohnny Huang otp_strap_status(otpstrap); 1941b64ca396SJohnny Huang 1942b64ca396SJohnny Huang printf("Check writable...\n"); 1943b64ca396SJohnny Huang if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE) 1944b64ca396SJohnny Huang ret = -1; 1945030cb4a7SJohnny Huang } 1946b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 1947b25f02d2SJohnny Huang if (info_cb.pro_sts.pro_strap) { 1948b25f02d2SJohnny Huang printf("OTP strap region is protected\n"); 1949b25f02d2SJohnny Huang ret = -1; 1950b25f02d2SJohnny Huang } 1951b25f02d2SJohnny Huang printf("Read SCU Protect Region:\n"); 1952b25f02d2SJohnny Huang otp_read_conf(28, &scu_pro[0]); 1953b25f02d2SJohnny Huang otp_read_conf(29, &scu_pro[1]); 1954b25f02d2SJohnny Huang 1955b25f02d2SJohnny Huang printf("Check writable...\n"); 1956b25f02d2SJohnny Huang if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE) 1957b25f02d2SJohnny Huang ret = -1; 1958b25f02d2SJohnny Huang } 1959030cb4a7SJohnny Huang if (ret == -1) 1960030cb4a7SJohnny Huang return OTP_FAILURE; 1961b64ca396SJohnny Huang 196269d5fd8fSJohnny Huang if (!nconfirm) { 1963696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 19647f795e57SJohnny Huang printf("\nOTP data region :\n"); 1965f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 196669d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 19672a856b9aSJohnny Huang return OTP_FAILURE; 196869d5fd8fSJohnny Huang } 196969d5fd8fSJohnny Huang } 1970696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 19717332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1972696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 19737332532cSJohnny Huang printf("OTP config error, please check.\n"); 19747332532cSJohnny Huang return OTP_FAILURE; 19757332532cSJohnny Huang } 19767332532cSJohnny Huang } 19777adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 19787adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 19797adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 19807adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 19817adec5f6SJohnny Huang return OTP_FAILURE; 19827adec5f6SJohnny Huang } 19837adec5f6SJohnny Huang } 1984b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 1985b25f02d2SJohnny Huang printf("\nOTP scu protect region :\n"); 1986b25f02d2SJohnny Huang if (otp_print_scu_image(&image_layout) < 0) { 1987b25f02d2SJohnny Huang printf("OTP scu protect error, please check.\n"); 1988b25f02d2SJohnny Huang return OTP_FAILURE; 1989b25f02d2SJohnny Huang } 1990b25f02d2SJohnny Huang } 19917332532cSJohnny Huang 199269d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 199369d5fd8fSJohnny Huang if (!confirm_yesno()) { 199469d5fd8fSJohnny Huang printf(" Aborting\n"); 19952a856b9aSJohnny Huang return OTP_FAILURE; 199669d5fd8fSJohnny Huang } 199769d5fd8fSJohnny Huang } 19987332532cSJohnny Huang 19995010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 20005010032bSJohnny Huang printf("programing data region ...\n"); 2001b64ca396SJohnny Huang ret = otp_prog_data(&image_layout, data); 20025010032bSJohnny Huang if (ret != 0) { 20035010032bSJohnny Huang printf("Error\n"); 20045010032bSJohnny Huang return ret; 20055010032bSJohnny Huang } 2006a219f6deSJohnny Huang printf("Done\n"); 20075010032bSJohnny Huang } 20085010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 20095010032bSJohnny Huang printf("programing strap region ...\n"); 2010b64ca396SJohnny Huang ret = otp_prog_strap(&image_layout, otpstrap); 20115010032bSJohnny Huang if (ret != 0) { 20125010032bSJohnny Huang printf("Error\n"); 20135010032bSJohnny Huang return ret; 20145010032bSJohnny Huang } 2015a219f6deSJohnny Huang printf("Done\n"); 20165010032bSJohnny Huang } 2017b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2018b25f02d2SJohnny Huang printf("programing scu protect region ...\n"); 2019b25f02d2SJohnny Huang ret = otp_prog_scu_protect(&image_layout, scu_pro); 2020b25f02d2SJohnny Huang if (ret != 0) { 2021b25f02d2SJohnny Huang printf("Error\n"); 2022b25f02d2SJohnny Huang return ret; 2023b25f02d2SJohnny Huang } 2024b25f02d2SJohnny Huang printf("Done\n"); 2025b25f02d2SJohnny Huang } 20265010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 20275010032bSJohnny Huang printf("programing configuration region ...\n"); 2028b64ca396SJohnny Huang ret = otp_prog_conf(&image_layout, conf); 20295010032bSJohnny Huang if (ret != 0) { 20305010032bSJohnny Huang printf("Error\n"); 20315010032bSJohnny Huang return ret; 20325010032bSJohnny Huang } 20335010032bSJohnny Huang printf("Done\n"); 20345010032bSJohnny Huang } 2035cd1610b4SJohnny Huang 20367332532cSJohnny Huang return OTP_SUCCESS; 20372a856b9aSJohnny Huang } 20382a856b9aSJohnny Huang 2039f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 2040cd1610b4SJohnny Huang { 2041a219f6deSJohnny Huang u32 read[2]; 2042a219f6deSJohnny Huang u32 prog_address = 0; 204366f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 2044cd1610b4SJohnny Huang int otp_bit; 204583655e91SJohnny Huang int ret = 0; 2046cd1610b4SJohnny Huang 2047dacbba92SJohnny Huang otp_soak(0); 2048cd1610b4SJohnny Huang switch (mode) { 2049a6d0d645SJohnny Huang case OTP_REGION_CONF: 2050f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 2051cd1610b4SJohnny Huang prog_address = 0x800; 2052cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 2053cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 2054a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2055cd1610b4SJohnny Huang if (otp_bit == value) { 2056b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2057cd1610b4SJohnny Huang printf("No need to program\n"); 20582a856b9aSJohnny Huang return OTP_SUCCESS; 2059cd1610b4SJohnny Huang } 2060cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 2061b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 20620dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 20632a856b9aSJohnny Huang return OTP_FAILURE; 2064cd1610b4SJohnny Huang } 2065b489486eSJohnny Huang printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2066cd1610b4SJohnny Huang break; 2067a6d0d645SJohnny Huang case OTP_REGION_DATA: 2068cd1610b4SJohnny Huang prog_address = otp_dw_offset; 2069cd1610b4SJohnny Huang 2070cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 2071a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 2072a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2073643b9cfdSJohnny Huang 2074643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 2075b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2076b64ca396SJohnny Huang printf("OTP is programmed, which can't be cleared\n"); 2077643b9cfdSJohnny Huang return OTP_FAILURE; 2078643b9cfdSJohnny Huang } 2079cd1610b4SJohnny Huang } else { 2080a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 2081a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 2082643b9cfdSJohnny Huang 2083643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 2084b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2085b64ca396SJohnny Huang printf("OTP is programmed, which can't be written\n"); 2086643b9cfdSJohnny Huang return OTP_FAILURE; 2087643b9cfdSJohnny Huang } 2088cd1610b4SJohnny Huang } 2089cd1610b4SJohnny Huang if (otp_bit == value) { 2090b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2091cd1610b4SJohnny Huang printf("No need to program\n"); 20922a856b9aSJohnny Huang return OTP_SUCCESS; 2093cd1610b4SJohnny Huang } 2094643b9cfdSJohnny Huang 2095b489486eSJohnny Huang printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2096cd1610b4SJohnny Huang break; 2097a6d0d645SJohnny Huang case OTP_REGION_STRAP: 20988848d5dcSJohnny Huang otp_strap_status(otpstrap); 20998848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 21007e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 21018848d5dcSJohnny Huang if (ret == OTP_FAILURE) 21028848d5dcSJohnny Huang return OTP_FAILURE; 21038848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 21048848d5dcSJohnny Huang return OTP_SUCCESS; 2105a6af4a17SJohnny Huang 2106cd1610b4SJohnny Huang break; 2107cd1610b4SJohnny Huang } 2108cd1610b4SJohnny Huang 2109cd1610b4SJohnny Huang if (!nconfirm) { 2110cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2111cd1610b4SJohnny Huang if (!confirm_yesno()) { 2112cd1610b4SJohnny Huang printf(" Aborting\n"); 21132a856b9aSJohnny Huang return OTP_FAILURE; 2114cd1610b4SJohnny Huang } 2115cd1610b4SJohnny Huang } 2116cd1610b4SJohnny Huang 2117cd1610b4SJohnny Huang switch (mode) { 2118a6d0d645SJohnny Huang case OTP_REGION_STRAP: 2119f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 212083655e91SJohnny Huang break; 2121a6d0d645SJohnny Huang case OTP_REGION_CONF: 2122a6d0d645SJohnny Huang case OTP_REGION_DATA: 2123f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 2124de6fbf1cSJohnny Huang break; 2125de6fbf1cSJohnny Huang } 2126de6fbf1cSJohnny Huang otp_soak(0); 212783655e91SJohnny Huang if (ret) { 21280dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 2129794e27ecSJohnny Huang printf("FAILURE\n"); 2130794e27ecSJohnny Huang return OTP_FAILURE; 2131794e27ecSJohnny Huang } 2132794e27ecSJohnny Huang 21339009c25dSJohnny Huang printf("SUCCESS\n"); 21342a856b9aSJohnny Huang return OTP_SUCCESS; 2135a219f6deSJohnny Huang } 2136a219f6deSJohnny Huang 2137794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 2138794e27ecSJohnny Huang { 2139794e27ecSJohnny Huang u32 otp_rid[2]; 2140a8789b47SJohnny Huang u32 sw_rid[2]; 2141794e27ecSJohnny Huang int rid_num = 0; 2142a8789b47SJohnny Huang int sw_rid_num = 0; 2143794e27ecSJohnny Huang int bit_offset; 2144794e27ecSJohnny Huang int dw_offset; 2145794e27ecSJohnny Huang int i; 2146794e27ecSJohnny Huang int ret; 2147794e27ecSJohnny Huang 2148f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2149f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2150794e27ecSJohnny Huang 2151a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2152a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2153a8789b47SJohnny Huang 2154794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2155a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2156a8789b47SJohnny Huang 2157a8789b47SJohnny Huang if (sw_rid_num < 0) { 2158a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2159a8789b47SJohnny Huang return OTP_FAILURE; 2160a8789b47SJohnny Huang } 2161a8789b47SJohnny Huang 2162a8789b47SJohnny Huang if (update_num > sw_rid_num) { 2163a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2164a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2165a8789b47SJohnny Huang return OTP_FAILURE; 2166a8789b47SJohnny Huang } 2167794e27ecSJohnny Huang 2168794e27ecSJohnny Huang if (rid_num < 0) { 2169b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by this command,\n" 2170b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n"); 2171794e27ecSJohnny Huang otp_print_revid(otp_rid); 21729009c25dSJohnny Huang return OTP_FAILURE; 21739009c25dSJohnny Huang } 2174cd1610b4SJohnny Huang 2175794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2176794e27ecSJohnny Huang otp_print_revid(otp_rid); 2177794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 2178794e27ecSJohnny Huang 2179a8789b47SJohnny Huang if (rid_num > update_num) { 2180a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 2181a8789b47SJohnny Huang printf("Skip\n"); 2182a8789b47SJohnny Huang return OTP_FAILURE; 2183a8789b47SJohnny Huang } else if (rid_num == update_num) { 2184a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 2185794e27ecSJohnny Huang printf("Skip\n"); 2186794e27ecSJohnny Huang return OTP_FAILURE; 2187794e27ecSJohnny Huang } 2188794e27ecSJohnny Huang 2189794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2190794e27ecSJohnny Huang if (i < 32) { 2191794e27ecSJohnny Huang dw_offset = 0xa; 2192794e27ecSJohnny Huang bit_offset = i; 2193794e27ecSJohnny Huang } else { 2194794e27ecSJohnny Huang dw_offset = 0xb; 2195794e27ecSJohnny Huang bit_offset = i - 32; 2196794e27ecSJohnny Huang } 2197b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset); 2198794e27ecSJohnny Huang if (i + 1 != update_num) 2199794e27ecSJohnny Huang printf(", "); 2200794e27ecSJohnny Huang } 2201794e27ecSJohnny Huang 2202794e27ecSJohnny Huang printf(" will be programmed\n"); 2203794e27ecSJohnny Huang if (force == 0) { 2204794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2205794e27ecSJohnny Huang if (!confirm_yesno()) { 2206794e27ecSJohnny Huang printf(" Aborting\n"); 2207794e27ecSJohnny Huang return OTP_FAILURE; 2208794e27ecSJohnny Huang } 2209794e27ecSJohnny Huang } 2210794e27ecSJohnny Huang 2211794e27ecSJohnny Huang ret = 0; 2212794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2213794e27ecSJohnny Huang if (i < 32) { 2214794e27ecSJohnny Huang dw_offset = 0xa04; 2215794e27ecSJohnny Huang bit_offset = i; 2216794e27ecSJohnny Huang } else { 2217794e27ecSJohnny Huang dw_offset = 0xa06; 2218794e27ecSJohnny Huang bit_offset = i - 32; 2219794e27ecSJohnny Huang } 2220f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 2221b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset); 2222794e27ecSJohnny Huang ret = OTP_FAILURE; 2223794e27ecSJohnny Huang break; 2224794e27ecSJohnny Huang } 2225794e27ecSJohnny Huang } 2226061d3279SJohnny Huang otp_soak(0); 2227f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2228f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2229794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2230794e27ecSJohnny Huang if (rid_num >= 0) 2231794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 2232794e27ecSJohnny Huang else 2233794e27ecSJohnny Huang printf("OTP revision ID\n"); 2234794e27ecSJohnny Huang otp_print_revid(otp_rid); 2235794e27ecSJohnny Huang if (!ret) 2236794e27ecSJohnny Huang printf("SUCCESS\n"); 2237794e27ecSJohnny Huang else 2238794e27ecSJohnny Huang printf("FAILED\n"); 2239794e27ecSJohnny Huang return ret; 2240794e27ecSJohnny Huang } 2241794e27ecSJohnny Huang 2242883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force) 2243883625c5SJohnny Huang { 2244883625c5SJohnny Huang u32 otpcfg4; 2245883625c5SJohnny Huang u32 krb; 2246883625c5SJohnny Huang u32 krb_b; 2247883625c5SJohnny Huang u32 krb_or; 2248883625c5SJohnny Huang u32 current_id; 2249883625c5SJohnny Huang 2250883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2251883625c5SJohnny Huang current_id = readl(SEC_KEY_NUM) & 7; 2252883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2253883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2254883625c5SJohnny Huang krb_or = krb | krb_b; 2255883625c5SJohnny Huang 2256883625c5SJohnny Huang printf("current Key ID: 0x%x\n", current_id); 2257883625c5SJohnny Huang printf("input retire ID: 0x%x\n", retire_id); 2258883625c5SJohnny Huang printf("OTPCFG0x4 = 0x%X\n", otpcfg4); 2259883625c5SJohnny Huang 2260883625c5SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2261883625c5SJohnny Huang printf("OTPCFG4 is protected\n"); 2262883625c5SJohnny Huang return OTP_FAILURE; 2263883625c5SJohnny Huang } 2264883625c5SJohnny Huang 2265883625c5SJohnny Huang if (retire_id >= current_id) { 2266883625c5SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2267883625c5SJohnny Huang return OTP_FAILURE; 2268883625c5SJohnny Huang } 2269883625c5SJohnny Huang 2270883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2271883625c5SJohnny Huang printf("Key 0x%X already retired\n", retire_id); 2272883625c5SJohnny Huang return OTP_SUCCESS; 2273883625c5SJohnny Huang } 2274883625c5SJohnny Huang 2275883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id); 2276883625c5SJohnny Huang if (force == 0) { 2277883625c5SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2278883625c5SJohnny Huang if (!confirm_yesno()) { 2279883625c5SJohnny Huang printf(" Aborting\n"); 2280883625c5SJohnny Huang return OTP_FAILURE; 2281883625c5SJohnny Huang } 2282883625c5SJohnny Huang } 2283883625c5SJohnny Huang 2284883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) { 2285883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed\n", retire_id); 2286883625c5SJohnny Huang printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16); 2287883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE) 2288883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16); 2289883625c5SJohnny Huang } 2290883625c5SJohnny Huang 2291883625c5SJohnny Huang otp_soak(0); 2292883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2293883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2294883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2295883625c5SJohnny Huang krb_or = krb | krb_b; 2296883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2297883625c5SJohnny Huang printf("SUCCESS\n"); 2298883625c5SJohnny Huang return OTP_SUCCESS; 2299883625c5SJohnny Huang } 2300883625c5SJohnny Huang printf("FAILED\n"); 2301883625c5SJohnny Huang return OTP_FAILURE; 2302883625c5SJohnny Huang } 2303883625c5SJohnny Huang 23042a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 230569d5fd8fSJohnny Huang { 2306a219f6deSJohnny Huang u32 offset, count; 23072a856b9aSJohnny Huang int ret; 230869d5fd8fSJohnny Huang 23092a856b9aSJohnny Huang if (argc == 4) { 23102a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 23112a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 23122a856b9aSJohnny Huang } else if (argc == 3) { 23132a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 23142a856b9aSJohnny Huang count = 1; 23152a856b9aSJohnny Huang } else { 231669d5fd8fSJohnny Huang return CMD_RET_USAGE; 231769d5fd8fSJohnny Huang } 231869d5fd8fSJohnny Huang 2319030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2320f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2321030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 23222a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2323030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 23242a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2325030cb4a7SJohnny Huang else 23262a856b9aSJohnny Huang return CMD_RET_USAGE; 232769d5fd8fSJohnny Huang 23282a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 23292a856b9aSJohnny Huang return CMD_RET_SUCCESS; 23302a856b9aSJohnny Huang return CMD_RET_USAGE; 23312a856b9aSJohnny Huang } 23322a856b9aSJohnny Huang 23332a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 23342a856b9aSJohnny Huang { 23352a856b9aSJohnny Huang phys_addr_t addr; 23362a856b9aSJohnny Huang int ret; 23372a856b9aSJohnny Huang 2338de6b0cc4SJohnny Huang if (argc == 3) { 2339ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 23402a856b9aSJohnny Huang return CMD_RET_USAGE; 23412a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2342f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2343de6b0cc4SJohnny Huang } else if (argc == 2) { 23442a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2345f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 23462a856b9aSJohnny Huang } else { 23472a856b9aSJohnny Huang return CMD_RET_USAGE; 23482a856b9aSJohnny Huang } 23492a856b9aSJohnny Huang 23502a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 23512a856b9aSJohnny Huang return CMD_RET_SUCCESS; 23522a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 23532a856b9aSJohnny Huang return CMD_RET_FAILURE; 23542a856b9aSJohnny Huang else 23552a856b9aSJohnny Huang return CMD_RET_USAGE; 23562a856b9aSJohnny Huang } 23572a856b9aSJohnny Huang 23582a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 23592a856b9aSJohnny Huang { 23602a856b9aSJohnny Huang int mode = 0; 23612a856b9aSJohnny Huang int nconfirm = 0; 23622a856b9aSJohnny Huang int otp_addr = 0; 23632a856b9aSJohnny Huang int bit_offset; 23642a856b9aSJohnny Huang int value; 23652a856b9aSJohnny Huang int ret; 2366030cb4a7SJohnny Huang u32 otp_strap_pro; 23672a856b9aSJohnny Huang 23682a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 23692a856b9aSJohnny Huang return CMD_RET_USAGE; 23702a856b9aSJohnny Huang 23712a856b9aSJohnny Huang /* Drop the pb cmd */ 23722a856b9aSJohnny Huang argc--; 23732a856b9aSJohnny Huang argv++; 23742a856b9aSJohnny Huang 23752a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2376a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 23772a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2378a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 23792a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2380a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2381cd1610b4SJohnny Huang else 23822a856b9aSJohnny Huang return CMD_RET_USAGE; 23832a856b9aSJohnny Huang 23842a856b9aSJohnny Huang /* Drop the region cmd */ 23852a856b9aSJohnny Huang argc--; 23862a856b9aSJohnny Huang argv++; 23872a856b9aSJohnny Huang 2388ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2389cd1610b4SJohnny Huang nconfirm = 1; 23902a856b9aSJohnny Huang /* Drop the force option */ 23912a856b9aSJohnny Huang argc--; 23922a856b9aSJohnny Huang argv++; 23932a856b9aSJohnny Huang } 2394cd1610b4SJohnny Huang 2395a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 23962a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 23972a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 23980808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 23992a856b9aSJohnny Huang return CMD_RET_USAGE; 2400cd1610b4SJohnny Huang } else { 24012a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 24022a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 24032a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 24040808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 24052a856b9aSJohnny Huang return CMD_RET_USAGE; 24060808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 240778855207SJohnny Huang if (otp_addr >= 0x800) 24080808cc55SJohnny Huang return CMD_RET_USAGE; 24090808cc55SJohnny Huang } else { 241078855207SJohnny Huang if (otp_addr >= 0x20) 24110808cc55SJohnny Huang return CMD_RET_USAGE; 24120808cc55SJohnny Huang } 2413cd1610b4SJohnny Huang } 2414cd1610b4SJohnny Huang if (value != 0 && value != 1) 24152a856b9aSJohnny Huang return CMD_RET_USAGE; 2416cd1610b4SJohnny Huang 2417030cb4a7SJohnny Huang ret = 0; 2418030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2419030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2420030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2421030cb4a7SJohnny Huang } 2422030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2423030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2424030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2425030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2426030cb4a7SJohnny Huang ret = -1; 2427030cb4a7SJohnny Huang } 2428030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2429030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2430030cb4a7SJohnny Huang ret = -1; 2431030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2432030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2433030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2434030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2435030cb4a7SJohnny Huang ret = -1; 2436030cb4a7SJohnny Huang } 2437030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2438030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2439030cb4a7SJohnny Huang ret = -1; 2440030cb4a7SJohnny Huang } 2441030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2442030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2443030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2444030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2445030cb4a7SJohnny Huang ret = -1; 2446030cb4a7SJohnny Huang } 2447030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2448030cb4a7SJohnny Huang u32 otp_rid[2]; 2449030cb4a7SJohnny Huang u32 sw_rid[2]; 2450030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2451030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2452030cb4a7SJohnny Huang 2453030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2454030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2455030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2456030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2457030cb4a7SJohnny Huang 2458030cb4a7SJohnny Huang if (otp_addr == 10) 2459030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2460030cb4a7SJohnny Huang else 2461030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2462030cb4a7SJohnny Huang 2463030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2464030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2465030cb4a7SJohnny Huang ret = -1; 2466030cb4a7SJohnny Huang } 2467030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2468030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2469030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2470030cb4a7SJohnny Huang ret = -1; 2471030cb4a7SJohnny Huang } else { 2472030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2473030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2474030cb4a7SJohnny Huang u32 key_num; 2475030cb4a7SJohnny Huang u32 retire; 2476030cb4a7SJohnny Huang 2477030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2478030cb4a7SJohnny Huang if (bit_offset >= 16) 2479030cb4a7SJohnny Huang retire = bit_offset - 16; 2480030cb4a7SJohnny Huang else 2481030cb4a7SJohnny Huang retire = bit_offset; 2482030cb4a7SJohnny Huang if (retire >= key_num) { 2483030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2484030cb4a7SJohnny Huang ret = -1; 2485030cb4a7SJohnny Huang } 2486030cb4a7SJohnny Huang } 2487030cb4a7SJohnny Huang } 2488030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2489030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2490030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2491030cb4a7SJohnny Huang ret = -1; 2492030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2493030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2494030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2495030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2496030cb4a7SJohnny Huang else 2497030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2498030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2499b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset); 2500030cb4a7SJohnny Huang ret = -1; 2501030cb4a7SJohnny Huang } 2502030cb4a7SJohnny Huang } 2503030cb4a7SJohnny Huang } 2504030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2505030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2506030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2507030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2508030cb4a7SJohnny Huang ret = -1; 2509030cb4a7SJohnny Huang } 2510030cb4a7SJohnny Huang } 2511030cb4a7SJohnny Huang 2512030cb4a7SJohnny Huang if (ret == -1) 2513030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2514030cb4a7SJohnny Huang 2515f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 25162a856b9aSJohnny Huang 25172a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 25182a856b9aSJohnny Huang return CMD_RET_SUCCESS; 25192a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 25202a856b9aSJohnny Huang return CMD_RET_FAILURE; 25212a856b9aSJohnny Huang else 25222a856b9aSJohnny Huang return CMD_RET_USAGE; 25232a856b9aSJohnny Huang } 25242a856b9aSJohnny Huang 25252a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 25262a856b9aSJohnny Huang { 25272a856b9aSJohnny Huang phys_addr_t addr; 25282a856b9aSJohnny Huang int otp_addr = 0; 2529b8590031SJohnny Huang int ret; 25302a856b9aSJohnny Huang 25312a856b9aSJohnny Huang if (argc != 3) 25322a856b9aSJohnny Huang return CMD_RET_USAGE; 25332a856b9aSJohnny Huang 25342a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 25352a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 2536b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 2537b8590031SJohnny Huang if (ret == 0) { 253869d5fd8fSJohnny Huang printf("Compare pass\n"); 25392a856b9aSJohnny Huang return CMD_RET_SUCCESS; 2540a219f6deSJohnny Huang } 254169d5fd8fSJohnny Huang printf("Compare fail\n"); 25422a856b9aSJohnny Huang return CMD_RET_FAILURE; 254369d5fd8fSJohnny Huang } 254469d5fd8fSJohnny Huang 254566f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 254666f2f8e5SJohnny Huang { 2547a8bd6d8cSJohnny Huang int view = 0; 25482d4b0742SJohnny Huang int input; 2549a8bd6d8cSJohnny Huang 2550a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 255166f2f8e5SJohnny Huang return CMD_RET_USAGE; 255266f2f8e5SJohnny Huang 25532d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 25542d4b0742SJohnny Huang if (argc == 3) { 25552d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 25562d4b0742SJohnny Huang otp_print_conf_info(input); 25572d4b0742SJohnny Huang } else { 25582d4b0742SJohnny Huang otp_print_conf_info(-1); 25592d4b0742SJohnny Huang } 25602d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 25612d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 2562a8bd6d8cSJohnny Huang view = 1; 2563a8bd6d8cSJohnny Huang /* Drop the view option */ 2564a8bd6d8cSJohnny Huang argc--; 2565a8bd6d8cSJohnny Huang argv++; 2566a8bd6d8cSJohnny Huang } 2567b458cd62SJohnny Huang otp_print_strap_info(view); 25680dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 25690dc9a440SJohnny Huang otp_print_scu_info(); 257088bd7d58SJohnny Huang } else if (!strcmp(argv[1], "key")) { 257188bd7d58SJohnny Huang otp_print_key_info(); 257266f2f8e5SJohnny Huang } else { 257366f2f8e5SJohnny Huang return CMD_RET_USAGE; 257466f2f8e5SJohnny Huang } 25752d4b0742SJohnny Huang 257666f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 257766f2f8e5SJohnny Huang } 257866f2f8e5SJohnny Huang 25790dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2580737ed20bSJohnny Huang { 25810dc9a440SJohnny Huang u32 input; 25820dc9a440SJohnny Huang u32 bit_offset; 2583e14b073cSJohnny Huang u32 prog_address; 2584030cb4a7SJohnny Huang char force; 258583655e91SJohnny Huang int ret; 2586a219f6deSJohnny Huang 2587737ed20bSJohnny Huang if (argc != 3 && argc != 2) 2588737ed20bSJohnny Huang return CMD_RET_USAGE; 2589737ed20bSJohnny Huang 2590e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 2591737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 2592030cb4a7SJohnny Huang force = 1; 2593737ed20bSJohnny Huang } else { 2594737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 2595030cb4a7SJohnny Huang force = 0; 2596737ed20bSJohnny Huang } 2597737ed20bSJohnny Huang 2598737ed20bSJohnny Huang if (input < 32) { 2599737ed20bSJohnny Huang bit_offset = input; 26000dc9a440SJohnny Huang prog_address = 0xe0c; 2601737ed20bSJohnny Huang } else if (input < 64) { 2602737ed20bSJohnny Huang bit_offset = input - 32; 26030dc9a440SJohnny Huang prog_address = 0xe0e; 2604737ed20bSJohnny Huang } else { 2605737ed20bSJohnny Huang return CMD_RET_USAGE; 2606737ed20bSJohnny Huang } 2607737ed20bSJohnny Huang 2608030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2609030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2610030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2611030cb4a7SJohnny Huang } 2612030cb4a7SJohnny Huang 2613030cb4a7SJohnny Huang if (!force) { 2614b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input); 2615030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2616030cb4a7SJohnny Huang if (!confirm_yesno()) { 2617030cb4a7SJohnny Huang printf(" Aborting\n"); 2618030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2619030cb4a7SJohnny Huang } 2620030cb4a7SJohnny Huang } 2621030cb4a7SJohnny Huang 2622e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2623b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input); 2624e14b073cSJohnny Huang return CMD_RET_SUCCESS; 2625e14b073cSJohnny Huang } 2626de6fbf1cSJohnny Huang 2627f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 2628de6fbf1cSJohnny Huang otp_soak(0); 262983655e91SJohnny Huang 263083655e91SJohnny Huang if (ret) { 2631b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input); 2632737ed20bSJohnny Huang return CMD_RET_FAILURE; 2633737ed20bSJohnny Huang } 26349a4fe690SJohnny Huang 2635b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input); 2636794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2637794e27ecSJohnny Huang } 2638794e27ecSJohnny Huang 26390dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2640e14b073cSJohnny Huang { 26410dc9a440SJohnny Huang u32 scu_offset; 26420dc9a440SJohnny Huang u32 bit_offset; 26430dc9a440SJohnny Huang u32 conf_offset; 26440dc9a440SJohnny Huang u32 prog_address; 26450dc9a440SJohnny Huang char force; 26460dc9a440SJohnny Huang int ret; 26470dc9a440SJohnny Huang 26480dc9a440SJohnny Huang if (argc != 4 && argc != 3) 26490dc9a440SJohnny Huang return CMD_RET_USAGE; 26500dc9a440SJohnny Huang 26510dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 26520dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 26530dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 26540dc9a440SJohnny Huang force = 1; 26550dc9a440SJohnny Huang } else { 26560dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 26570dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 26580dc9a440SJohnny Huang force = 0; 26590dc9a440SJohnny Huang } 26600dc9a440SJohnny Huang if (scu_offset == 0x500) { 26610dc9a440SJohnny Huang prog_address = 0xe08; 26620dc9a440SJohnny Huang conf_offset = 28; 26630dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 26640dc9a440SJohnny Huang prog_address = 0xe0a; 26650dc9a440SJohnny Huang conf_offset = 29; 26660dc9a440SJohnny Huang } else { 26670dc9a440SJohnny Huang return CMD_RET_USAGE; 26680dc9a440SJohnny Huang } 26690dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 26700dc9a440SJohnny Huang return CMD_RET_USAGE; 2671030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2672030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2673030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2674030cb4a7SJohnny Huang } 26750dc9a440SJohnny Huang if (!force) { 2676b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset); 2677b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset); 26780dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 26790dc9a440SJohnny Huang if (!confirm_yesno()) { 26800dc9a440SJohnny Huang printf(" Aborting\n"); 26810dc9a440SJohnny Huang return CMD_RET_FAILURE; 26820dc9a440SJohnny Huang } 2683e14b073cSJohnny Huang } 2684e14b073cSJohnny Huang 26850dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2686b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset); 26870dc9a440SJohnny Huang return CMD_RET_SUCCESS; 26880dc9a440SJohnny Huang } 26890dc9a440SJohnny Huang 26900dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 26910dc9a440SJohnny Huang otp_soak(0); 26920dc9a440SJohnny Huang 26930dc9a440SJohnny Huang if (ret) { 2694b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset); 26950dc9a440SJohnny Huang return CMD_RET_FAILURE; 26960dc9a440SJohnny Huang } 26970dc9a440SJohnny Huang 2698b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset); 26990dc9a440SJohnny Huang return CMD_RET_SUCCESS; 2700e14b073cSJohnny Huang } 2701e14b073cSJohnny Huang 2702f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2703f67375f7SJohnny Huang { 2704e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 2705f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2706f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2707f67375f7SJohnny Huang 2708f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2709f67375f7SJohnny Huang } 2710f67375f7SJohnny Huang 2711794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2712794e27ecSJohnny Huang { 2713794e27ecSJohnny Huang u32 update_num; 2714794e27ecSJohnny Huang int force = 0; 2715794e27ecSJohnny Huang int ret; 2716794e27ecSJohnny Huang 2717794e27ecSJohnny Huang if (argc == 3) { 2718794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 2719794e27ecSJohnny Huang return CMD_RET_USAGE; 2720794e27ecSJohnny Huang force = 1; 2721794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 2722794e27ecSJohnny Huang } else if (argc == 2) { 2723794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 2724794e27ecSJohnny Huang } else { 2725794e27ecSJohnny Huang return CMD_RET_USAGE; 2726794e27ecSJohnny Huang } 2727794e27ecSJohnny Huang 2728794e27ecSJohnny Huang if (update_num > 64) 2729794e27ecSJohnny Huang return CMD_RET_USAGE; 2730794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 2731b8590031SJohnny Huang 2732794e27ecSJohnny Huang if (ret) 2733794e27ecSJohnny Huang return CMD_RET_FAILURE; 2734794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2735794e27ecSJohnny Huang } 2736794e27ecSJohnny Huang 2737794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2738794e27ecSJohnny Huang { 2739794e27ecSJohnny Huang u32 otp_rid[2]; 2740a8789b47SJohnny Huang u32 sw_rid[2]; 2741794e27ecSJohnny Huang int rid_num = 0; 2742a8789b47SJohnny Huang int sw_rid_num = 0; 2743794e27ecSJohnny Huang int ret; 2744794e27ecSJohnny Huang 2745794e27ecSJohnny Huang if (argc != 1) 2746794e27ecSJohnny Huang return CMD_RET_USAGE; 2747794e27ecSJohnny Huang 2748f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2749f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2750794e27ecSJohnny Huang 2751a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2752a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2753794e27ecSJohnny Huang 2754a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 2755a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2756a8789b47SJohnny Huang 2757030cb4a7SJohnny Huang if (sw_rid_num < 0) { 2758030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2759030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 2760030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 2761030cb4a7SJohnny Huang } else { 2762a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2763030cb4a7SJohnny Huang } 2764794e27ecSJohnny Huang if (rid_num >= 0) { 2765794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2766794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 2767794e27ecSJohnny Huang } else { 2768b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n" 2769b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n" 2770794e27ecSJohnny Huang "current OTP revision ID\n"); 2771794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 2772794e27ecSJohnny Huang } 2773794e27ecSJohnny Huang otp_print_revid(otp_rid); 2774794e27ecSJohnny Huang 2775794e27ecSJohnny Huang return ret; 2776794e27ecSJohnny Huang } 2777794e27ecSJohnny Huang 2778883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2779883625c5SJohnny Huang { 2780883625c5SJohnny Huang u32 retire_id; 2781883625c5SJohnny Huang int force = 0; 2782883625c5SJohnny Huang int ret; 2783883625c5SJohnny Huang 2784883625c5SJohnny Huang if (argc == 3) { 2785883625c5SJohnny Huang if (strcmp(argv[1], "o")) 2786883625c5SJohnny Huang return CMD_RET_USAGE; 2787883625c5SJohnny Huang force = 1; 2788883625c5SJohnny Huang retire_id = simple_strtoul(argv[2], NULL, 16); 2789883625c5SJohnny Huang } else if (argc == 2) { 2790883625c5SJohnny Huang retire_id = simple_strtoul(argv[1], NULL, 16); 2791883625c5SJohnny Huang } else { 2792883625c5SJohnny Huang return CMD_RET_USAGE; 2793883625c5SJohnny Huang } 2794883625c5SJohnny Huang 2795883625c5SJohnny Huang if (retire_id > 7) 2796883625c5SJohnny Huang return CMD_RET_USAGE; 2797883625c5SJohnny Huang ret = otp_retire_key(retire_id, force); 2798883625c5SJohnny Huang 2799883625c5SJohnny Huang if (ret) 2800883625c5SJohnny Huang return CMD_RET_FAILURE; 2801883625c5SJohnny Huang return CMD_RET_SUCCESS; 2802883625c5SJohnny Huang } 2803883625c5SJohnny Huang 28042a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2805f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 28062a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2807a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2808de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 28092a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2810737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 28110dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 28122a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 2813794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 2814794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 2815883625c5SJohnny Huang U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""), 28162a856b9aSJohnny Huang }; 28172a856b9aSJohnny Huang 28182a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 28192a856b9aSJohnny Huang { 2820030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 28212a856b9aSJohnny Huang cmd_tbl_t *cp; 2822a219f6deSJohnny Huang u32 ver; 2823e14b073cSJohnny Huang int ret; 2824030cb4a7SJohnny Huang u32 otp_conf0; 28252a856b9aSJohnny Huang 28262a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 28272a856b9aSJohnny Huang 2828737ed20bSJohnny Huang /* Drop the otp command */ 28292a856b9aSJohnny Huang argc--; 28302a856b9aSJohnny Huang argv++; 28312a856b9aSJohnny Huang 2832a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 28332a856b9aSJohnny Huang return CMD_RET_USAGE; 28342a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 28352a856b9aSJohnny Huang return CMD_RET_SUCCESS; 28362a856b9aSJohnny Huang 28370dae9d52SJohnny Huang ver = chip_version(); 28380dae9d52SJohnny Huang switch (ver) { 2839e417205bSJohnny Huang case OTP_A0: 2840e417205bSJohnny Huang info_cb.version = OTP_A0; 28419a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 28429a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 28439a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 28449a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 28459a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 28469a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 2847e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 28480dae9d52SJohnny Huang break; 2849e417205bSJohnny Huang case OTP_A1: 2850e417205bSJohnny Huang info_cb.version = OTP_A1; 28513cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 28523cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 28533cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 28543cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 28559a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 28569a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 28570dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28580dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2859e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 28600dae9d52SJohnny Huang break; 2861e417205bSJohnny Huang case OTP_A2: 2862e417205bSJohnny Huang info_cb.version = OTP_A2; 28635fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 28645fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 2865fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2866fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 28675fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 28685fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 28690dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28700dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2871e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 28720dae9d52SJohnny Huang break; 2873e417205bSJohnny Huang case OTP_A3: 2874e417205bSJohnny Huang info_cb.version = OTP_A3; 2875b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 2876b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 2877fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2878fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 2879181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2880181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 28810dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28820dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2883e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 288464b66712SJohnny Huang break; 28850dae9d52SJohnny Huang default: 2886f1be5099SJohnny Huang printf("SOC is not supported\n"); 28870dae9d52SJohnny Huang return CMD_RET_FAILURE; 28889a4fe690SJohnny Huang } 28899a4fe690SJohnny Huang 2890030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2891030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 2892030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 2893030cb4a7SJohnny Huang 2894030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 2895030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 2896030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 2897030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 2898030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 2899030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 2900030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 2901030cb4a7SJohnny Huang 2902e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 2903b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 2904e14b073cSJohnny Huang 2905e14b073cSJohnny Huang return ret; 290669d5fd8fSJohnny Huang } 290769d5fd8fSJohnny Huang 2908a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 290969d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2910f67375f7SJohnny Huang "version\n" 2911f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 29122a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 29132d4b0742SJohnny Huang "otp info strap [v]\n" 29142d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 29150dc9a440SJohnny Huang "otp info scu\n" 291688bd7d58SJohnny Huang "otp info key\n" 2917de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2918ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2919ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2920ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 29210dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 2922794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 2923794e27ecSJohnny Huang "otp rid\n" 2924883625c5SJohnny Huang "otp retire [o] <key_id>\n" 292569d5fd8fSJohnny Huang ); 2926