1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+ 269d5fd8fSJohnny Huang /* 3a219f6deSJohnny Huang * Copyright 2021 Aspeed Technology Inc. 469d5fd8fSJohnny Huang */ 5*e417205bSJohnny 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 2364b66712SJohnny Huang #define OTP_VER "1.0.3" 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 434c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 444c1c9b35SJohnny Huang #define PBWIDTH 60 454c1c9b35SJohnny Huang 463d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 473d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 483d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 493d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 503d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 513d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 523d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 533d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 543d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 553d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 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) 63696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 64696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 65696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 66696656c6SJohnny Huang 67*e417205bSJohnny Huang #define OTP_A0 0 68*e417205bSJohnny Huang #define OTP_A1 1 69*e417205bSJohnny Huang #define OTP_A2 2 70*e417205bSJohnny Huang #define OTP_A3 3 71*e417205bSJohnny Huang 72*e417205bSJohnny Huang #define ID0_AST2600A0 0x05000303 73*e417205bSJohnny Huang #define ID1_AST2600A0 0x05000303 74*e417205bSJohnny Huang #define ID0_AST2600A1 0x05010303 75*e417205bSJohnny Huang #define ID1_AST2600A1 0x05010203 76*e417205bSJohnny Huang #define ID0_AST2600A2 0x05010303 77*e417205bSJohnny Huang #define ID1_AST2600A2 0x05020303 78*e417205bSJohnny Huang #define ID0_AST2600A3 0x05030303 79*e417205bSJohnny Huang #define ID1_AST2600A3 0x05030303 80*e417205bSJohnny Huang #define ID0_AST2620A1 0x05010203 81*e417205bSJohnny Huang #define ID1_AST2620A1 0x05010203 82*e417205bSJohnny Huang #define ID0_AST2620A2 0x05010203 83*e417205bSJohnny Huang #define ID1_AST2620A2 0x05020203 84*e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 85*e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 86*e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 87*e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 88*e417205bSJohnny Huang #define ID0_AST2605A2 0x05010103 89*e417205bSJohnny Huang #define ID1_AST2605A2 0x05020103 90*e417205bSJohnny Huang #define ID0_AST2605A3 0x05030103 91*e417205bSJohnny Huang #define ID1_AST2605A3 0x05030103 92*e417205bSJohnny Huang #define ID0_AST2625A3 0x05030403 93*e417205bSJohnny Huang #define ID1_AST2625A3 0x05030403 94696656c6SJohnny Huang 95696656c6SJohnny Huang struct otp_header { 96696656c6SJohnny Huang u8 otp_magic[8]; 97696656c6SJohnny Huang u8 otp_version[8]; 98696656c6SJohnny Huang u32 image_info; 99696656c6SJohnny Huang u32 data_info; 100696656c6SJohnny Huang u32 config_info; 101696656c6SJohnny Huang u32 strap_info; 102696656c6SJohnny Huang u32 checksum_offset; 103a219f6deSJohnny Huang } __packed; 104696656c6SJohnny Huang 10566f2f8e5SJohnny Huang struct otpstrap_status { 10669d5fd8fSJohnny Huang int value; 10769d5fd8fSJohnny Huang int option_array[7]; 10869d5fd8fSJohnny Huang int remain_times; 10969d5fd8fSJohnny Huang int writeable_option; 1105010032bSJohnny Huang int reg_protected; 11169d5fd8fSJohnny Huang int protected; 11269d5fd8fSJohnny Huang }; 11369d5fd8fSJohnny Huang 11466f2f8e5SJohnny Huang struct otpconf_parse { 11566f2f8e5SJohnny Huang int dw_offset; 11666f2f8e5SJohnny Huang int bit; 11766f2f8e5SJohnny Huang int length; 11866f2f8e5SJohnny Huang int value; 119696656c6SJohnny Huang int ignore; 12066f2f8e5SJohnny Huang char status[80]; 12166f2f8e5SJohnny Huang }; 12266f2f8e5SJohnny Huang 1239a4fe690SJohnny Huang struct otpkey_type { 1249a4fe690SJohnny Huang int value; 1259a4fe690SJohnny Huang int key_type; 1269a4fe690SJohnny Huang int need_id; 1279a4fe690SJohnny Huang char information[110]; 1289a4fe690SJohnny Huang }; 1299a4fe690SJohnny Huang 1309a4fe690SJohnny Huang struct otp_info_cb { 1319a4fe690SJohnny Huang int version; 132*e417205bSJohnny Huang char ver_name[3]; 13379e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1349a4fe690SJohnny Huang int strap_info_len; 13579e42a59SJoel Stanley const struct otpconf_info *conf_info; 1369a4fe690SJohnny Huang int conf_info_len; 13779e42a59SJoel Stanley const struct otpkey_type *key_info; 1389a4fe690SJohnny Huang int key_info_len; 1399a4fe690SJohnny Huang }; 1409a4fe690SJohnny Huang 141696656c6SJohnny Huang struct otp_image_layout { 1425010032bSJohnny Huang int data_length; 1435010032bSJohnny Huang int conf_length; 1445010032bSJohnny Huang int strap_length; 145a219f6deSJohnny Huang u8 *data; 146a219f6deSJohnny Huang u8 *data_ignore; 147a219f6deSJohnny Huang u8 *conf; 148a219f6deSJohnny Huang u8 *conf_ignore; 149a219f6deSJohnny Huang u8 *strap; 150a219f6deSJohnny Huang u8 *strap_reg_pro; 151a219f6deSJohnny Huang u8 *strap_pro; 152a219f6deSJohnny Huang u8 *strap_ignore; 153696656c6SJohnny Huang }; 154696656c6SJohnny Huang 1559a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1569a4fe690SJohnny Huang 15779e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1589a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1599a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1609a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 161181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 162181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as SOC public key"}, 163181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 164181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as SOC private key"}, 165181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1669a4fe690SJohnny Huang }; 1679a4fe690SJohnny Huang 16879e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1699a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1709a4fe690SJohnny 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"}, 171181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 172181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 173181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1749a4fe690SJohnny Huang }; 1759a4fe690SJohnny Huang 1765fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1775fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1785fdde29fSJohnny 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"}, 179181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 180181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 181181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 182181f72d8SJohnny Huang }; 183181f72d8SJohnny Huang 184181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = { 185181f72d8SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 186181f72d8SJohnny 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"}, 187181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 188181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 189181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 190181f72d8SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key(big endian)"}, 191181f72d8SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 192181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key(big endian)"}, 1935fdde29fSJohnny Huang }; 1945fdde29fSJohnny Huang 195794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset) 196794e27ecSJohnny Huang { 197794e27ecSJohnny Huang int bit_offset; 198794e27ecSJohnny Huang int i; 199794e27ecSJohnny Huang 200794e27ecSJohnny Huang if (offset < 32) { 201794e27ecSJohnny Huang i = 0; 202794e27ecSJohnny Huang bit_offset = offset; 203794e27ecSJohnny Huang } else { 204794e27ecSJohnny Huang i = 1; 205794e27ecSJohnny Huang bit_offset = offset - 32; 206794e27ecSJohnny Huang } 207794e27ecSJohnny Huang if ((rid[i] >> bit_offset) & 0x1) 208794e27ecSJohnny Huang return 1; 209794e27ecSJohnny Huang else 210794e27ecSJohnny Huang return 0; 211794e27ecSJohnny Huang } 212794e27ecSJohnny Huang 213794e27ecSJohnny Huang static int get_rid_num(u32 *rid) 214794e27ecSJohnny Huang { 215794e27ecSJohnny Huang int i; 216794e27ecSJohnny Huang int fz = 0; 217794e27ecSJohnny Huang int rid_num = 0; 218794e27ecSJohnny Huang int ret = 0; 219794e27ecSJohnny Huang 220794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 221794e27ecSJohnny Huang if (get_dw_bit(rid, i) == 0) { 222794e27ecSJohnny Huang if (!fz) 223794e27ecSJohnny Huang fz = 1; 224794e27ecSJohnny Huang 225794e27ecSJohnny Huang } else { 226794e27ecSJohnny Huang rid_num++; 227794e27ecSJohnny Huang if (fz) 228794e27ecSJohnny Huang ret = OTP_FAILURE; 229794e27ecSJohnny Huang } 230794e27ecSJohnny Huang } 231794e27ecSJohnny Huang if (ret) 232794e27ecSJohnny Huang return ret; 233794e27ecSJohnny Huang 234794e27ecSJohnny Huang return rid_num; 235794e27ecSJohnny Huang } 236794e27ecSJohnny Huang 237794e27ecSJohnny Huang static void buf_print(u8 *buf, int len) 238794e27ecSJohnny Huang { 239794e27ecSJohnny Huang int i; 240794e27ecSJohnny Huang 241794e27ecSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 242794e27ecSJohnny Huang for (i = 0; i < len; i++) { 243794e27ecSJohnny Huang if (i % 16 == 0) 244794e27ecSJohnny Huang printf("%04X: ", i); 245794e27ecSJohnny Huang printf("%02X ", buf[i]); 246794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 247794e27ecSJohnny Huang printf("\n"); 248794e27ecSJohnny Huang } 249794e27ecSJohnny Huang } 250794e27ecSJohnny Huang 251a219f6deSJohnny Huang static u32 chip_version(void) 2529a4fe690SJohnny Huang { 253*e417205bSJohnny Huang u32 revid0, revid1; 2549a4fe690SJohnny Huang 255*e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0); 256*e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1); 2579a4fe690SJohnny Huang 258*e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { 259badd21c2SJohnny Huang /* AST2600-A0 */ 260*e417205bSJohnny Huang return OTP_A0; 261*e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { 262badd21c2SJohnny Huang /* AST2600-A1 */ 263*e417205bSJohnny Huang return OTP_A1; 264*e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { 265badd21c2SJohnny Huang /* AST2600-A2 */ 266*e417205bSJohnny Huang return OTP_A2; 267*e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { 26864b66712SJohnny Huang /* AST2600-A3 */ 269*e417205bSJohnny Huang return OTP_A3; 270*e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { 271*e417205bSJohnny Huang /* AST2620-A1 */ 272*e417205bSJohnny Huang return OTP_A1; 273*e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { 274*e417205bSJohnny Huang /* AST2620-A2 */ 275*e417205bSJohnny Huang return OTP_A2; 276*e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { 27764b66712SJohnny Huang /* AST2620-A3 */ 278*e417205bSJohnny Huang return OTP_A3; 279*e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { 280*e417205bSJohnny Huang /* AST2605-A2 */ 281*e417205bSJohnny Huang return OTP_A2; 282*e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { 283*e417205bSJohnny Huang /* AST2605-A3 */ 284*e417205bSJohnny Huang return OTP_A3; 285*e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { 286*e417205bSJohnny Huang /* AST2605-A3 */ 287*e417205bSJohnny Huang return OTP_A3; 2880dae9d52SJohnny Huang } 2895fdde29fSJohnny Huang return -1; 2909a4fe690SJohnny Huang } 2919a4fe690SJohnny Huang 2923d3688adSJohnny Huang static void wait_complete(void) 2933d3688adSJohnny Huang { 2943d3688adSJohnny Huang int reg; 2953d3688adSJohnny Huang 2963d3688adSJohnny Huang do { 2973d3688adSJohnny Huang reg = readl(OTP_STATUS); 2983d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 2993d3688adSJohnny Huang } 3003d3688adSJohnny Huang 301a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 302dacbba92SJohnny Huang { 303dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 304dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 305dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 306dacbba92SJohnny Huang wait_complete(); 307dacbba92SJohnny Huang } 308dacbba92SJohnny Huang 309dacbba92SJohnny Huang static void otp_soak(int soak) 310dacbba92SJohnny Huang { 311*e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) { 312dacbba92SJohnny Huang switch (soak) { 313dacbba92SJohnny Huang case 0: //default 314dacbba92SJohnny Huang otp_write(0x3000, 0x0210); // Write MRA 315dacbba92SJohnny Huang otp_write(0x5000, 0x2000); // Write MRB 316dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 317dacbba92SJohnny Huang break; 318dacbba92SJohnny Huang case 1: //normal program 319dacbba92SJohnny Huang otp_write(0x3000, 0x1200); // Write MRA 320feea3fdfSJohnny Huang otp_write(0x5000, 0x107F); // Write MRB 321dacbba92SJohnny Huang otp_write(0x1000, 0x1024); // Write MR 322feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 323dacbba92SJohnny Huang break; 324dacbba92SJohnny Huang case 2: //soak program 325dacbba92SJohnny Huang otp_write(0x3000, 0x1220); // Write MRA 326feea3fdfSJohnny Huang otp_write(0x5000, 0x2074); // Write MRB 327dacbba92SJohnny Huang otp_write(0x1000, 0x08a4); // Write MR 328feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 329dacbba92SJohnny Huang break; 330dacbba92SJohnny Huang } 331dacbba92SJohnny Huang } else { 332dacbba92SJohnny Huang switch (soak) { 333dacbba92SJohnny Huang case 0: //default 334dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 335dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 336dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 337dacbba92SJohnny Huang break; 338dacbba92SJohnny Huang case 1: //normal program 339dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 340dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 341dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 342feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 343dacbba92SJohnny Huang break; 344dacbba92SJohnny Huang case 2: //soak program 345dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 346dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 347dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 348feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 349dacbba92SJohnny Huang break; 350dacbba92SJohnny Huang } 351dacbba92SJohnny Huang } 352dacbba92SJohnny Huang 353dacbba92SJohnny Huang wait_complete(); 354dacbba92SJohnny Huang } 355dacbba92SJohnny Huang 356a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 35769d5fd8fSJohnny Huang { 3583d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 3593d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3603d3688adSJohnny Huang wait_complete(); 3613d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 3623d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 36369d5fd8fSJohnny Huang } 36469d5fd8fSJohnny Huang 365a219f6deSJohnny Huang static void otp_read_config(u32 offset, u32 *data) 36669d5fd8fSJohnny Huang { 36769d5fd8fSJohnny Huang int config_offset; 36869d5fd8fSJohnny Huang 36969d5fd8fSJohnny Huang config_offset = 0x800; 37069d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 37169d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 37269d5fd8fSJohnny Huang 3733d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 3743d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3753d3688adSJohnny Huang wait_complete(); 3763d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 37769d5fd8fSJohnny Huang } 37869d5fd8fSJohnny Huang 379a219f6deSJohnny Huang static int otp_print_config(u32 offset, int dw_count) 38069d5fd8fSJohnny Huang { 38169d5fd8fSJohnny Huang int i; 382a219f6deSJohnny Huang u32 ret[1]; 38369d5fd8fSJohnny Huang 38469d5fd8fSJohnny Huang if (offset + dw_count > 32) 3852a856b9aSJohnny Huang return OTP_USAGE; 386dacbba92SJohnny Huang otp_soak(0); 38769d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i++) { 38869d5fd8fSJohnny Huang otp_read_config(i, ret); 389a6af4a17SJohnny Huang printf("OTPCFG%X: %08X\n", i, ret[0]); 39069d5fd8fSJohnny Huang } 39169d5fd8fSJohnny Huang printf("\n"); 3922a856b9aSJohnny Huang return OTP_SUCCESS; 39369d5fd8fSJohnny Huang } 39469d5fd8fSJohnny Huang 395a219f6deSJohnny Huang static int otp_print_data(u32 offset, int dw_count) 39669d5fd8fSJohnny Huang { 39769d5fd8fSJohnny Huang int i; 398a219f6deSJohnny Huang u32 ret[2]; 39969d5fd8fSJohnny Huang 40069d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 4012a856b9aSJohnny Huang return OTP_USAGE; 402dacbba92SJohnny Huang otp_soak(0); 40369d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 40469d5fd8fSJohnny Huang otp_read_data(i, ret); 40569d5fd8fSJohnny Huang if (i % 4 == 0) 40669d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 40769d5fd8fSJohnny Huang else 40869d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 40969d5fd8fSJohnny Huang } 41069d5fd8fSJohnny Huang printf("\n"); 4112a856b9aSJohnny Huang return OTP_SUCCESS; 41269d5fd8fSJohnny Huang } 41369d5fd8fSJohnny Huang 414a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 41569d5fd8fSJohnny Huang { 416a219f6deSJohnny Huang u32 ret; 417a219f6deSJohnny Huang u32 *buf; 41869d5fd8fSJohnny Huang 41969d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 42069d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 42169d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 42269d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 42369d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 4243d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 4253d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 4263d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 4273d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 4283d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 4293d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 4303d3688adSJohnny Huang wait_complete(); 4313d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 43269d5fd8fSJohnny Huang if (ret & 0x1) 43369d5fd8fSJohnny Huang return 0; 43469d5fd8fSJohnny Huang else 43569d5fd8fSJohnny Huang return -1; 43669d5fd8fSJohnny Huang } 43769d5fd8fSJohnny Huang 438a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 43969d5fd8fSJohnny Huang { 440a219f6deSJohnny Huang u32 ret[2]; 44169d5fd8fSJohnny Huang 44230a8c590SJohnny Huang if (otp_addr % 2 == 0) 4433d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 44430a8c590SJohnny Huang else 4453d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 44630a8c590SJohnny Huang 4473d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4483d3688adSJohnny Huang wait_complete(); 4493d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4503d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 45183655e91SJohnny Huang 45230a8c590SJohnny Huang if (otp_addr % 2 == 0) { 45330a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 45469d5fd8fSJohnny Huang return 0; 45569d5fd8fSJohnny Huang else 45669d5fd8fSJohnny Huang return -1; 45730a8c590SJohnny Huang } else { 45830a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 45930a8c590SJohnny Huang return 0; 46030a8c590SJohnny Huang else 46130a8c590SJohnny Huang return -1; 46230a8c590SJohnny Huang } 46369d5fd8fSJohnny Huang } 46469d5fd8fSJohnny Huang 465a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 4664c1c9b35SJohnny Huang { 467a219f6deSJohnny Huang u32 ret[2]; 4684c1c9b35SJohnny Huang 4694c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 4704c1c9b35SJohnny Huang 4714c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 4723d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 4734c1c9b35SJohnny Huang else 4743d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 4753d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4763d3688adSJohnny Huang wait_complete(); 4773d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4783d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 4794c1c9b35SJohnny Huang if (size == 1) { 4804c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 4814c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 482696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 4834c1c9b35SJohnny Huang compare[0] = 0; 4844c1c9b35SJohnny Huang return 0; 485a219f6deSJohnny Huang } 4864c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4874c1c9b35SJohnny Huang return -1; 4884c1c9b35SJohnny Huang 4894c1c9b35SJohnny Huang } else { 4904c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 491696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4924c1c9b35SJohnny Huang compare[0] = ~0; 4934c1c9b35SJohnny Huang return 0; 494a219f6deSJohnny Huang } 495d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 4964c1c9b35SJohnny Huang return -1; 4974c1c9b35SJohnny Huang } 4984c1c9b35SJohnny Huang } else if (size == 2) { 4994c1c9b35SJohnny Huang // otp_addr should be even 500696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 5014c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 5024c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 5034c1c9b35SJohnny Huang compare[0] = 0; 5044c1c9b35SJohnny Huang compare[1] = ~0; 5054c1c9b35SJohnny Huang return 0; 506a219f6deSJohnny Huang } 5074c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 5084c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 5094c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 5104c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 5114c1c9b35SJohnny Huang return -1; 5124c1c9b35SJohnny Huang } else { 5134c1c9b35SJohnny Huang return -1; 5144c1c9b35SJohnny Huang } 5154c1c9b35SJohnny Huang } 5164c1c9b35SJohnny Huang 517a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit) 51883655e91SJohnny Huang { 51990965bb3SJohnny Huang otp_write(0x0, prog_bit); 52083655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 52183655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 52283655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 52383655e91SJohnny Huang wait_complete(); 52483655e91SJohnny Huang } 52583655e91SJohnny Huang 526a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 52783655e91SJohnny Huang { 52883655e91SJohnny Huang int prog_bit; 52983655e91SJohnny Huang 53083655e91SJohnny Huang if (prog_address % 2 == 0) { 53183655e91SJohnny Huang if (value) 53283655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 53383655e91SJohnny Huang else 53483655e91SJohnny Huang return; 53583655e91SJohnny Huang } else { 536*e417205bSJohnny Huang if (info_cb.version != OTP_A3) 53783655e91SJohnny Huang prog_address |= 1 << 15; 53883655e91SJohnny Huang if (!value) 53983655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 54083655e91SJohnny Huang else 54183655e91SJohnny Huang return; 54283655e91SJohnny Huang } 54383655e91SJohnny Huang otp_prog(prog_address, prog_bit); 54483655e91SJohnny Huang } 54583655e91SJohnny Huang 546a219f6deSJohnny Huang static int otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 54783655e91SJohnny Huang { 54883655e91SJohnny Huang int pass; 54983655e91SJohnny Huang int i; 55083655e91SJohnny Huang 55183655e91SJohnny Huang otp_soak(1); 55283655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 55383655e91SJohnny Huang pass = 0; 55483655e91SJohnny Huang 55583655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 55683655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 55783655e91SJohnny Huang otp_soak(2); 55883655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 55983655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 56083655e91SJohnny Huang otp_soak(1); 56183655e91SJohnny Huang } else { 56283655e91SJohnny Huang pass = 1; 56383655e91SJohnny Huang break; 56483655e91SJohnny Huang } 56583655e91SJohnny Huang } else { 56683655e91SJohnny Huang pass = 1; 56783655e91SJohnny Huang break; 56883655e91SJohnny Huang } 56983655e91SJohnny Huang } 570794e27ecSJohnny Huang if (pass) 571794e27ecSJohnny Huang return OTP_SUCCESS; 57283655e91SJohnny Huang 573794e27ecSJohnny Huang return OTP_FAILURE; 57483655e91SJohnny Huang } 57583655e91SJohnny Huang 576a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 577d90825e2SJohnny Huang { 578d90825e2SJohnny Huang int j, bit_value, prog_bit; 579d90825e2SJohnny Huang 580d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 581696656c6SJohnny Huang if ((ignore >> j) & 0x1) 582d90825e2SJohnny Huang continue; 583d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 584d90825e2SJohnny Huang if (prog_address % 2 == 0) { 585d90825e2SJohnny Huang if (bit_value) 586d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 587d90825e2SJohnny Huang else 588d90825e2SJohnny Huang continue; 589d90825e2SJohnny Huang } else { 590*e417205bSJohnny Huang if (info_cb.version != OTP_A3) 591d90825e2SJohnny Huang prog_address |= 1 << 15; 592d90825e2SJohnny Huang if (bit_value) 593d90825e2SJohnny Huang continue; 594d90825e2SJohnny Huang else 595d90825e2SJohnny Huang prog_bit = 0x1 << j; 596d90825e2SJohnny Huang } 597d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 598d90825e2SJohnny Huang } 599d90825e2SJohnny Huang } 600d90825e2SJohnny Huang 601a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 60254552c69SJohnny Huang { 60354552c69SJohnny Huang int pass; 60454552c69SJohnny Huang int i; 605a219f6deSJohnny Huang u32 data0_masked; 606a219f6deSJohnny Huang u32 data1_masked; 607a219f6deSJohnny Huang u32 buf0_masked; 608a219f6deSJohnny Huang u32 buf1_masked; 609a219f6deSJohnny Huang u32 compare[2]; 61054552c69SJohnny Huang 61154552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 61254552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 61354552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 61454552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 615a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 61654552c69SJohnny Huang return 0; 61754552c69SJohnny Huang 61854552c69SJohnny Huang otp_soak(1); 61954552c69SJohnny Huang if (data0_masked != buf0_masked) 62054552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 62154552c69SJohnny Huang if (data1_masked != buf1_masked) 62254552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 62354552c69SJohnny Huang 62454552c69SJohnny Huang pass = 0; 62554552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 62654552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 62754552c69SJohnny Huang otp_soak(2); 628a219f6deSJohnny Huang if (compare[0] != 0) 62954552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 630a219f6deSJohnny Huang if (compare[1] != ~0) 6315537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 63254552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 63354552c69SJohnny Huang otp_soak(1); 63454552c69SJohnny Huang } else { 63554552c69SJohnny Huang pass = 1; 63654552c69SJohnny Huang break; 63754552c69SJohnny Huang } 63854552c69SJohnny Huang } else { 63954552c69SJohnny Huang pass = 1; 64054552c69SJohnny Huang break; 64154552c69SJohnny Huang } 64254552c69SJohnny Huang } 64354552c69SJohnny Huang 64454552c69SJohnny Huang if (!pass) { 64554552c69SJohnny Huang otp_soak(0); 64654552c69SJohnny Huang return OTP_FAILURE; 64754552c69SJohnny Huang } 64854552c69SJohnny Huang return OTP_SUCCESS; 64954552c69SJohnny Huang } 65054552c69SJohnny Huang 651541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 65276d13988SJohnny Huang { 653a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 6545010032bSJohnny Huang int strap_end; 65576d13988SJohnny Huang int i, j; 65676d13988SJohnny Huang 657*e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 65876d13988SJohnny Huang for (j = 0; j < 64; j++) { 65976d13988SJohnny Huang otpstrap[j].value = 0; 66076d13988SJohnny Huang otpstrap[j].remain_times = 7; 66176d13988SJohnny Huang otpstrap[j].writeable_option = -1; 66276d13988SJohnny Huang otpstrap[j].protected = 0; 66376d13988SJohnny Huang } 6645010032bSJohnny Huang strap_end = 30; 6655010032bSJohnny Huang } else { 6665010032bSJohnny Huang for (j = 0; j < 64; j++) { 6675010032bSJohnny Huang otpstrap[j].value = 0; 6685010032bSJohnny Huang otpstrap[j].remain_times = 6; 6695010032bSJohnny Huang otpstrap[j].writeable_option = -1; 6705010032bSJohnny Huang otpstrap[j].reg_protected = 0; 6715010032bSJohnny Huang otpstrap[j].protected = 0; 6725010032bSJohnny Huang } 6735010032bSJohnny Huang strap_end = 28; 6745010032bSJohnny Huang } 67576d13988SJohnny Huang 676dacbba92SJohnny Huang otp_soak(0); 6775010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 67876d13988SJohnny Huang int option = (i - 16) / 2; 679a219f6deSJohnny Huang 68076d13988SJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 68176d13988SJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 68276d13988SJohnny Huang for (j = 0; j < 32; j++) { 68376d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 684a219f6deSJohnny Huang 685a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 68676d13988SJohnny Huang otpstrap[j].writeable_option = option; 68776d13988SJohnny Huang if (bit_value == 1) 68876d13988SJohnny Huang otpstrap[j].remain_times--; 68976d13988SJohnny Huang otpstrap[j].value ^= bit_value; 69076d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 69176d13988SJohnny Huang } 69276d13988SJohnny Huang for (j = 32; j < 64; j++) { 69376d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 694a219f6deSJohnny Huang 695a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 69676d13988SJohnny Huang otpstrap[j].writeable_option = option; 69776d13988SJohnny Huang if (bit_value == 1) 69876d13988SJohnny Huang otpstrap[j].remain_times--; 69976d13988SJohnny Huang otpstrap[j].value ^= bit_value; 70076d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 70176d13988SJohnny Huang } 70276d13988SJohnny Huang } 7035010032bSJohnny Huang 704*e417205bSJohnny Huang if (info_cb.version != OTP_A0) { 7055010032bSJohnny Huang otp_read_config(28, &OTPSTRAP_RAW[0]); 7065010032bSJohnny Huang otp_read_config(29, &OTPSTRAP_RAW[1]); 7075010032bSJohnny Huang for (j = 0; j < 32; j++) { 7085010032bSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 7095010032bSJohnny Huang otpstrap[j].reg_protected = 1; 7105010032bSJohnny Huang } 7115010032bSJohnny Huang for (j = 32; j < 64; j++) { 7125010032bSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 7135010032bSJohnny Huang otpstrap[j].reg_protected = 1; 7145010032bSJohnny Huang } 7155010032bSJohnny Huang } 7165010032bSJohnny Huang 71776d13988SJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 71876d13988SJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 71976d13988SJohnny Huang for (j = 0; j < 32; j++) { 72076d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 72176d13988SJohnny Huang otpstrap[j].protected = 1; 72276d13988SJohnny Huang } 72376d13988SJohnny Huang for (j = 32; j < 64; j++) { 72476d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 72576d13988SJohnny Huang otpstrap[j].protected = 1; 72676d13988SJohnny Huang } 72776d13988SJohnny Huang } 72876d13988SJohnny Huang 729794e27ecSJohnny Huang static void otp_print_revid(u32 *rid) 730794e27ecSJohnny Huang { 731794e27ecSJohnny Huang int bit_offset; 732794e27ecSJohnny Huang int i, j; 733794e27ecSJohnny Huang 734794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 735794e27ecSJohnny Huang printf("___________________________________________________\n"); 736794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 737794e27ecSJohnny Huang if (i < 32) { 738794e27ecSJohnny Huang j = 0; 739794e27ecSJohnny Huang bit_offset = i; 740794e27ecSJohnny Huang } else { 741794e27ecSJohnny Huang j = 1; 742794e27ecSJohnny Huang bit_offset = i - 32; 743794e27ecSJohnny Huang } 744794e27ecSJohnny Huang if (i % 16 == 0) 745794e27ecSJohnny Huang printf("%2x | ", i); 746794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1); 747794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 748794e27ecSJohnny Huang printf("\n"); 749794e27ecSJohnny Huang } 750794e27ecSJohnny Huang } 751794e27ecSJohnny Huang 752696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 75369d5fd8fSJohnny Huang { 75479e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 755a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 756a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 757a219f6deSJohnny Huang u32 mask; 758a219f6deSJohnny Huang u32 dw_offset; 759a219f6deSJohnny Huang u32 bit_offset; 760a219f6deSJohnny Huang u32 otp_value; 761a219f6deSJohnny Huang u32 otp_ignore; 762b458cd62SJohnny Huang int fail = 0; 763794e27ecSJohnny Huang int rid_num = 0; 76473f11549SJohnny Huang char valid_bit[20]; 765794e27ecSJohnny Huang int fz; 76666f2f8e5SJohnny Huang int i; 76773f11549SJohnny Huang int j; 76866f2f8e5SJohnny Huang 769737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 77066f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 7713cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 7723cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 7733cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 7743cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 775b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 776696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 777b458cd62SJohnny Huang 778a219f6deSJohnny Huang if (otp_ignore == mask) 779b458cd62SJohnny Huang continue; 780a219f6deSJohnny Huang else if (otp_ignore != 0) 781b458cd62SJohnny Huang fail = 1; 782b458cd62SJohnny Huang 783a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 7843cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 7853cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 7863cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 787b458cd62SJohnny Huang continue; 788b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 789b458cd62SJohnny Huang 7903cb28812SJohnny Huang if (conf_info[i].length == 1) { 7913cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 79266f2f8e5SJohnny Huang } else { 793b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 7943cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 7953cb28812SJohnny Huang conf_info[i].bit_offset); 79666f2f8e5SJohnny Huang } 797b458cd62SJohnny Huang printf("0x%-10x", otp_value); 798b458cd62SJohnny Huang 799b458cd62SJohnny Huang if (fail) { 800696656c6SJohnny Huang printf("Ignore mask error\n"); 801a219f6deSJohnny Huang continue; 802a219f6deSJohnny Huang } 8033cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 804b458cd62SJohnny Huang printf("Reserved\n"); 8053cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 8063cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 807b458cd62SJohnny Huang printf("\n"); 8083cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 809b458cd62SJohnny Huang if (otp_value != 0) { 81073f11549SJohnny Huang for (j = 0; j < 7; j++) { 811a219f6deSJohnny Huang if (otp_value == (1 << j)) 81273f11549SJohnny Huang valid_bit[j * 2] = '1'; 813a219f6deSJohnny Huang else 81473f11549SJohnny Huang valid_bit[j * 2] = '0'; 81573f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 81673f11549SJohnny Huang } 81773f11549SJohnny Huang valid_bit[15] = 0; 81873f11549SJohnny Huang } else { 81973f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 820b458cd62SJohnny Huang } 8213cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 822b458cd62SJohnny Huang printf("\n"); 823b458cd62SJohnny Huang } else { 8243cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 825b458cd62SJohnny Huang } 826b458cd62SJohnny Huang } 827b458cd62SJohnny Huang 828794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) { 829794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) { 830794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 831794e27ecSJohnny Huang fail = 1; 832794e27ecSJohnny Huang } else { 833794e27ecSJohnny Huang fz = 0; 834794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 835794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) { 836794e27ecSJohnny Huang if (!fz) 837794e27ecSJohnny Huang fz = 1; 838794e27ecSJohnny Huang } else { 839794e27ecSJohnny Huang rid_num++; 840794e27ecSJohnny Huang if (fz) { 841794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 842794e27ecSJohnny Huang fail = 1; 843794e27ecSJohnny Huang break; 844794e27ecSJohnny Huang } 845794e27ecSJohnny Huang } 846794e27ecSJohnny Huang } 847794e27ecSJohnny Huang } 848794e27ecSJohnny Huang if (fail) 849794e27ecSJohnny Huang printf("OTP revision ID\n"); 850794e27ecSJohnny Huang else 851794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 852794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]); 853794e27ecSJohnny Huang } 854794e27ecSJohnny Huang 855b458cd62SJohnny Huang if (fail) 856b458cd62SJohnny Huang return OTP_FAILURE; 857b458cd62SJohnny Huang 85866f2f8e5SJohnny Huang return OTP_SUCCESS; 85966f2f8e5SJohnny Huang } 86066f2f8e5SJohnny Huang 8612d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 86266f2f8e5SJohnny Huang { 86379e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 864a219f6deSJohnny Huang u32 OTPCFG[16]; 865a219f6deSJohnny Huang u32 mask; 866a219f6deSJohnny Huang u32 dw_offset; 867a219f6deSJohnny Huang u32 bit_offset; 868a219f6deSJohnny Huang u32 otp_value; 86973f11549SJohnny Huang char valid_bit[20]; 87066f2f8e5SJohnny Huang int i; 87173f11549SJohnny Huang int j; 87266f2f8e5SJohnny Huang 873dacbba92SJohnny Huang otp_soak(0); 874bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 87566f2f8e5SJohnny Huang otp_read_config(i, &OTPCFG[i]); 87666f2f8e5SJohnny Huang 877b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 878b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 8793cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 8803cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 8812d4b0742SJohnny Huang continue; 8823cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 8833cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 8843cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 885b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 886b458cd62SJohnny Huang 887a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 8883cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 8893cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 8903cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 891b458cd62SJohnny Huang continue; 892b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 893b458cd62SJohnny Huang 8943cb28812SJohnny Huang if (conf_info[i].length == 1) { 8953cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 896b458cd62SJohnny Huang } else { 897b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 8983cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 8993cb28812SJohnny Huang conf_info[i].bit_offset); 900b458cd62SJohnny Huang } 901b458cd62SJohnny Huang printf("0x%-10x", otp_value); 902b458cd62SJohnny Huang 9033cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 904b458cd62SJohnny Huang printf("Reserved\n"); 9053cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 9063cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 907b458cd62SJohnny Huang printf("\n"); 9083cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 909b458cd62SJohnny Huang if (otp_value != 0) { 91073f11549SJohnny Huang for (j = 0; j < 7; j++) { 911a219f6deSJohnny Huang if (otp_value == (1 << j)) 91273f11549SJohnny Huang valid_bit[j * 2] = '1'; 913a219f6deSJohnny Huang else 91473f11549SJohnny Huang valid_bit[j * 2] = '0'; 91573f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 91673f11549SJohnny Huang } 91773f11549SJohnny Huang valid_bit[15] = 0; 91873f11549SJohnny Huang } else { 91973f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 920b458cd62SJohnny Huang } 9213cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 922b458cd62SJohnny Huang printf("\n"); 923b458cd62SJohnny Huang } else { 9243cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 925b458cd62SJohnny Huang } 926b458cd62SJohnny Huang } 927b458cd62SJohnny Huang return OTP_SUCCESS; 92866f2f8e5SJohnny Huang } 92966f2f8e5SJohnny Huang 9305010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 93176d13988SJohnny Huang { 93279e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 933a219f6deSJohnny Huang u32 *OTPSTRAP; 934a219f6deSJohnny Huang u32 *OTPSTRAP_REG_PRO; 935a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 936a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 93776d13988SJohnny Huang int i; 938a8bd6d8cSJohnny Huang int fail = 0; 939a219f6deSJohnny Huang u32 bit_offset; 940a219f6deSJohnny Huang u32 dw_offset; 941a219f6deSJohnny Huang u32 mask; 942a219f6deSJohnny Huang u32 otp_value; 943a219f6deSJohnny Huang u32 otp_reg_protect; 944a219f6deSJohnny Huang u32 otp_protect; 945a219f6deSJohnny Huang u32 otp_ignore; 94676d13988SJohnny Huang 947a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 948a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 949a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 950*e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 951696656c6SJohnny Huang OTPSTRAP_REG_PRO = NULL; 952a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 953696656c6SJohnny Huang } else { 954a219f6deSJohnny Huang OTPSTRAP_REG_PRO = (u32 *)image_layout->strap_reg_pro; 955de6b0cc4SJohnny Huang printf("BIT(hex) Value Reg_Protect Protect Description\n"); 956696656c6SJohnny Huang } 957de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 958b458cd62SJohnny Huang 9593cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 960696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 961a8bd6d8cSJohnny Huang dw_offset = 1; 9623cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 963a8bd6d8cSJohnny Huang } else { 964a8bd6d8cSJohnny Huang dw_offset = 0; 9653cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 966a8bd6d8cSJohnny Huang } 96776d13988SJohnny Huang 9683cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 969a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 970a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 971696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 972a8bd6d8cSJohnny Huang 973*e417205bSJohnny Huang if (info_cb.version != OTP_A0) 974696656c6SJohnny Huang otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask; 9755010032bSJohnny Huang else 9765010032bSJohnny Huang otp_reg_protect = 0; 977696656c6SJohnny Huang 978a219f6deSJohnny Huang if (otp_ignore == mask) 979a8bd6d8cSJohnny Huang continue; 980a219f6deSJohnny Huang else if (otp_ignore != 0) 981a8bd6d8cSJohnny Huang fail = 1; 982a8bd6d8cSJohnny Huang 983a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 9843cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 985a8bd6d8cSJohnny Huang continue; 986a8bd6d8cSJohnny Huang 9873cb28812SJohnny Huang if (strap_info[i].length == 1) { 9883cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 989a8bd6d8cSJohnny Huang } else { 990b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 9913cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 9923cb28812SJohnny Huang strap_info[i].bit_offset); 993a8bd6d8cSJohnny Huang } 994a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 995*e417205bSJohnny Huang if (info_cb.version != OTP_A0) 996696656c6SJohnny Huang printf("0x%-10x", otp_reg_protect); 997a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 998a8bd6d8cSJohnny Huang 999a8bd6d8cSJohnny Huang if (fail) { 1000696656c6SJohnny Huang printf("Ignore mask error\n"); 1001a8bd6d8cSJohnny Huang } else { 10023cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 10033cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1004a8bd6d8cSJohnny Huang else 1005a8bd6d8cSJohnny Huang printf("Reserved\n"); 1006a8bd6d8cSJohnny Huang } 1007a8bd6d8cSJohnny Huang } 1008a8bd6d8cSJohnny Huang 1009a8bd6d8cSJohnny Huang if (fail) 101076d13988SJohnny Huang return OTP_FAILURE; 101176d13988SJohnny Huang 101276d13988SJohnny Huang return OTP_SUCCESS; 101376d13988SJohnny Huang } 101476d13988SJohnny Huang 1015b458cd62SJohnny Huang static int otp_print_strap_info(int view) 101676d13988SJohnny Huang { 101779e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 101876d13988SJohnny Huang struct otpstrap_status strap_status[64]; 101907baa4e8SJohnny Huang int i, j; 1020b458cd62SJohnny Huang int fail = 0; 1021a219f6deSJohnny Huang u32 bit_offset; 1022a219f6deSJohnny Huang u32 length; 1023a219f6deSJohnny Huang u32 otp_value; 1024a219f6deSJohnny Huang u32 otp_protect; 102576d13988SJohnny Huang 1026541eb887SJohnny Huang otp_strap_status(strap_status); 102776d13988SJohnny Huang 1028b458cd62SJohnny Huang if (view) { 1029*e417205bSJohnny Huang if (info_cb.version == OTP_A0) 103007baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 103183655e91SJohnny Huang else 103283655e91SJohnny Huang printf("BIT(hex) Value Remains Reg_Protect Protect Description\n"); 103307baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 1034b458cd62SJohnny Huang } else { 1035b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 1036b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 103776d13988SJohnny Huang } 10383cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 1039b458cd62SJohnny Huang otp_value = 0; 10403cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 10413cb28812SJohnny Huang length = strap_info[i].length; 1042b458cd62SJohnny Huang for (j = 0; j < length; j++) { 1043c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 1044c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 1045b458cd62SJohnny Huang } 1046a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 10473cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1048b458cd62SJohnny Huang continue; 1049b458cd62SJohnny Huang if (view) { 1050b458cd62SJohnny Huang for (j = 0; j < length; j++) { 10513cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 1052b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 105307baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 1054*e417205bSJohnny Huang if (info_cb.version != OTP_A0) 1055e1a7245eSJohnny Huang printf("0x%-10X", strap_status[bit_offset + j].reg_protected); 1056e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 10573cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 1058b458cd62SJohnny Huang printf(" Reserved\n"); 1059b458cd62SJohnny Huang continue; 1060b458cd62SJohnny Huang } 1061b458cd62SJohnny Huang if (length == 1) { 10623cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 1063b458cd62SJohnny Huang continue; 106476d13988SJohnny Huang } 106576d13988SJohnny Huang 1066b458cd62SJohnny Huang if (j == 0) 10673cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 1068b458cd62SJohnny Huang else if (j == length - 1) 1069b458cd62SJohnny Huang printf("\\ \"\n"); 1070b458cd62SJohnny Huang else 1071b458cd62SJohnny Huang printf("| \"\n"); 107276d13988SJohnny Huang } 1073b458cd62SJohnny Huang } else { 1074c947ef08SJohnny Huang if (length == 1) { 10753cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1076b458cd62SJohnny Huang } else { 1077b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 1078b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 1079b458cd62SJohnny Huang } 1080b458cd62SJohnny Huang 1081b458cd62SJohnny Huang printf("0x%-10X", otp_value); 1082b458cd62SJohnny Huang 10833cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 10843cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1085b458cd62SJohnny Huang else 1086b458cd62SJohnny Huang printf("Reserved\n"); 1087b458cd62SJohnny Huang } 1088b458cd62SJohnny Huang } 1089b458cd62SJohnny Huang 1090b458cd62SJohnny Huang if (fail) 1091b458cd62SJohnny Huang return OTP_FAILURE; 1092b458cd62SJohnny Huang 1093b458cd62SJohnny Huang return OTP_SUCCESS; 1094b458cd62SJohnny Huang } 1095b458cd62SJohnny Huang 1096696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout) 109769d5fd8fSJohnny Huang { 109869d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 109979e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 11009a4fe690SJohnny Huang struct otpkey_type key_info; 1101a219f6deSJohnny Huang u32 *buf; 1102a219f6deSJohnny Huang u8 *byte_buf; 11039d998018SJohnny Huang char empty = 1; 110469d5fd8fSJohnny Huang int i = 0, len = 0; 11059a4fe690SJohnny Huang int j; 110654552c69SJohnny Huang 1107696656c6SJohnny Huang byte_buf = image_layout->data; 1108a219f6deSJohnny Huang buf = (u32 *)byte_buf; 11099d998018SJohnny Huang 11109d998018SJohnny Huang for (i = 0; i < 16; i++) { 1111a219f6deSJohnny Huang if (buf[i] != 0) 11129d998018SJohnny Huang empty = 0; 11139d998018SJohnny Huang } 11149d998018SJohnny Huang if (empty) 11159d998018SJohnny Huang return 0; 11169d998018SJohnny Huang 11179d998018SJohnny Huang i = 0; 111869d5fd8fSJohnny Huang while (1) { 111969d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 112069d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 112169d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 112269d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 112369d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 112469d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 11259a4fe690SJohnny Huang 11269a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 11279a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 11289a4fe690SJohnny Huang key_info = key_info_array[j]; 11299a4fe690SJohnny Huang break; 11309a4fe690SJohnny Huang } 11319a4fe690SJohnny Huang } 11329a4fe690SJohnny Huang 11337f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 113469d5fd8fSJohnny Huang printf("Key Type: "); 11359a4fe690SJohnny Huang printf("%s\n", key_info.information); 11369a4fe690SJohnny Huang 11379a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 113869d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 113969d5fd8fSJohnny Huang switch (key_length) { 114069d5fd8fSJohnny Huang case 0: 114169d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 114269d5fd8fSJohnny Huang break; 114369d5fd8fSJohnny Huang case 1: 114469d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 114569d5fd8fSJohnny Huang break; 114669d5fd8fSJohnny Huang case 2: 114769d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 114869d5fd8fSJohnny Huang break; 114969d5fd8fSJohnny Huang case 3: 115069d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 115169d5fd8fSJohnny Huang break; 115269d5fd8fSJohnny Huang } 1153181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1154181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 115569d5fd8fSJohnny Huang printf("RSA SHA Type: "); 115669d5fd8fSJohnny Huang switch (key_length) { 115769d5fd8fSJohnny Huang case 0: 115869d5fd8fSJohnny Huang printf("RSA1024\n"); 115969d5fd8fSJohnny Huang len = 0x100; 116069d5fd8fSJohnny Huang break; 116169d5fd8fSJohnny Huang case 1: 116269d5fd8fSJohnny Huang printf("RSA2048\n"); 116369d5fd8fSJohnny Huang len = 0x200; 116469d5fd8fSJohnny Huang break; 116569d5fd8fSJohnny Huang case 2: 116669d5fd8fSJohnny Huang printf("RSA3072\n"); 116769d5fd8fSJohnny Huang len = 0x300; 116869d5fd8fSJohnny Huang break; 116969d5fd8fSJohnny Huang case 3: 117069d5fd8fSJohnny Huang printf("RSA4096\n"); 117169d5fd8fSJohnny Huang len = 0x400; 117269d5fd8fSJohnny Huang break; 117369d5fd8fSJohnny Huang } 117469d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 117569d5fd8fSJohnny Huang } 11769a4fe690SJohnny Huang if (key_info.need_id) 117769d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 117869d5fd8fSJohnny Huang printf("Key Value:\n"); 11799a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 118069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 11819a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 11829a4fe690SJohnny Huang printf("AES Key:\n"); 11839a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 1184*e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 11859a4fe690SJohnny Huang printf("AES IV:\n"); 11869a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 11879a4fe690SJohnny Huang } 11889a4fe690SJohnny Huang 11899a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1190*e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 119169d5fd8fSJohnny Huang printf("AES Key:\n"); 119269d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 119369d5fd8fSJohnny Huang printf("AES IV:\n"); 119469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 11955fdde29fSJohnny Huang } else { 11969a4fe690SJohnny Huang printf("AES Key 1:\n"); 11979a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 11989a4fe690SJohnny Huang printf("AES Key 2:\n"); 11999a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 12009a4fe690SJohnny Huang } 1201181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 120269d5fd8fSJohnny Huang printf("RSA mod:\n"); 120369d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 120469d5fd8fSJohnny Huang printf("RSA exp:\n"); 120569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1206181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1207181f72d8SJohnny Huang printf("RSA mod:\n"); 1208181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1209181f72d8SJohnny Huang printf("RSA exp:\n"); 1210a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 121169d5fd8fSJohnny Huang } 121269d5fd8fSJohnny Huang if (last) 121369d5fd8fSJohnny Huang break; 121469d5fd8fSJohnny Huang i++; 121569d5fd8fSJohnny Huang } 121669d5fd8fSJohnny Huang return 0; 121769d5fd8fSJohnny Huang } 121869d5fd8fSJohnny Huang 12195010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout) 122069d5fd8fSJohnny Huang { 1221a6d0d645SJohnny Huang int i, k; 1222d90825e2SJohnny Huang int pass = 0; 1223a219f6deSJohnny Huang u32 prog_address; 1224a219f6deSJohnny Huang u32 data[16]; 1225a219f6deSJohnny Huang u32 compare[2]; 1226a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1227a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1228a219f6deSJohnny Huang u32 data_masked; 1229a219f6deSJohnny Huang u32 buf_masked; 123069d5fd8fSJohnny Huang 1231a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 1232a6d0d645SJohnny Huang 1233bb34a7bfSJohnny Huang for (i = 0; i < 16 ; i++) { 123469d5fd8fSJohnny Huang prog_address = 0x800; 1235a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1236a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1237a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 1238a6d0d645SJohnny Huang } 1239a6d0d645SJohnny Huang 1240a6d0d645SJohnny Huang printf("Check writable...\n"); 1241bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 12425010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 12435010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1244d90825e2SJohnny Huang if (data_masked == buf_masked) 124569d5fd8fSJohnny Huang continue; 1246d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1247a6d0d645SJohnny Huang continue; 1248a6d0d645SJohnny Huang } else { 1249a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1250a6af4a17SJohnny Huang printf("OTPCFG[%X] = %x\n", i, data[i]); 12515010032bSJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 12525010032bSJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 12532a856b9aSJohnny Huang return OTP_FAILURE; 1254a6d0d645SJohnny Huang } 1255a6d0d645SJohnny Huang } 1256a6d0d645SJohnny Huang 1257a6d0d645SJohnny Huang printf("Start Programing...\n"); 1258d90825e2SJohnny Huang otp_soak(0); 1259bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 12605010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 12615010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1262a6d0d645SJohnny Huang prog_address = 0x800; 1263a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1264a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1265bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1266bb34a7bfSJohnny Huang pass = 1; 1267a6d0d645SJohnny Huang continue; 1268bb34a7bfSJohnny Huang } 1269de6fbf1cSJohnny Huang 1270de6fbf1cSJohnny Huang otp_soak(1); 12715010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1272a6d0d645SJohnny Huang 127369d5fd8fSJohnny Huang pass = 0; 127469d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 12755010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1276de6fbf1cSJohnny Huang otp_soak(2); 1277feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 12785010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1279de6fbf1cSJohnny Huang otp_soak(1); 1280de6fbf1cSJohnny Huang } else { 1281de6fbf1cSJohnny Huang pass = 1; 1282de6fbf1cSJohnny Huang break; 1283de6fbf1cSJohnny Huang } 1284a6d0d645SJohnny Huang } else { 128569d5fd8fSJohnny Huang pass = 1; 128669d5fd8fSJohnny Huang break; 128769d5fd8fSJohnny Huang } 128869d5fd8fSJohnny Huang } 1289bb34a7bfSJohnny Huang if (pass == 0) { 1290bb34a7bfSJohnny Huang printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n", 12915010032bSJohnny Huang i, data[i], conf[i], conf_ignore[i]); 1292bb34a7bfSJohnny Huang break; 1293bb34a7bfSJohnny Huang } 1294a6d0d645SJohnny Huang } 1295a6d0d645SJohnny Huang 1296de6fbf1cSJohnny Huang otp_soak(0); 129769d5fd8fSJohnny Huang if (!pass) 12982a856b9aSJohnny Huang return OTP_FAILURE; 1299a6d0d645SJohnny Huang 13002a856b9aSJohnny Huang return OTP_SUCCESS; 130169d5fd8fSJohnny Huang } 130269d5fd8fSJohnny Huang 1303eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit) 1304eda10d61SJohnny Huang { 13059901d43aSJohnny Huang int prog_flag = 0; 13069901d43aSJohnny Huang 13079901d43aSJohnny Huang // ignore this bit 13089901d43aSJohnny Huang if (ibit == 1) 1309eda10d61SJohnny Huang return OTP_SUCCESS; 1310eda10d61SJohnny Huang printf("OTPSTRAP[%X]:\n", offset); 13119901d43aSJohnny Huang 1312eda10d61SJohnny Huang if (bit == otpstrap->value) { 13139901d43aSJohnny Huang if (!pbit && !rpbit) { 1314eda10d61SJohnny Huang printf(" The value is same as before, skip it.\n"); 1315eda10d61SJohnny Huang return OTP_PROG_SKIP; 1316eda10d61SJohnny Huang } 13179901d43aSJohnny Huang printf(" The value is same as before.\n"); 13189901d43aSJohnny Huang } else { 13199901d43aSJohnny Huang prog_flag = 1; 13209901d43aSJohnny Huang } 13219901d43aSJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 1322eda10d61SJohnny Huang printf(" This bit is protected and is not writable\n"); 1323eda10d61SJohnny Huang return OTP_FAILURE; 1324eda10d61SJohnny Huang } 13259901d43aSJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 1326eda10d61SJohnny Huang printf(" This bit is no remaining times to write.\n"); 1327eda10d61SJohnny Huang return OTP_FAILURE; 1328eda10d61SJohnny Huang } 13299901d43aSJohnny Huang if (pbit == 1) 1330eda10d61SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 1331*e417205bSJohnny Huang if (rpbit == 1 && info_cb.version != OTP_A0) 1332eda10d61SJohnny Huang printf(" The relative register will be protected.\n"); 13339901d43aSJohnny Huang if (prog_flag) 1334eda10d61SJohnny Huang printf(" Write 1 to OTPSTRAP[%X] OPTION[%X], that value becomes from %d to %d.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1); 13359901d43aSJohnny Huang 1336eda10d61SJohnny Huang return OTP_SUCCESS; 1337eda10d61SJohnny Huang } 1338eda10d61SJohnny Huang 13395010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout) 134069d5fd8fSJohnny Huang { 134169d5fd8fSJohnny Huang int i; 1342a219f6deSJohnny Huang u32 *strap; 1343a219f6deSJohnny Huang u32 *strap_ignore; 1344a219f6deSJohnny Huang u32 *strap_reg_protect; 1345a219f6deSJohnny Huang u32 *strap_pro; 1346eda10d61SJohnny Huang int bit, pbit, ibit, rpbit; 134769d5fd8fSJohnny Huang int fail = 0; 1348eda10d61SJohnny Huang int ret; 134966f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 135069d5fd8fSJohnny Huang 1351a219f6deSJohnny Huang strap = (u32 *)image_layout->strap; 1352a219f6deSJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1353a219f6deSJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1354a219f6deSJohnny Huang strap_reg_protect = (u32 *)image_layout->strap_reg_pro; 13555010032bSJohnny Huang 1356541eb887SJohnny Huang otp_strap_status(otpstrap); 135769d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 135869d5fd8fSJohnny Huang if (i < 32) { 13595010032bSJohnny Huang bit = (strap[0] >> i) & 0x1; 1360eda10d61SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 13615010032bSJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 136269d5fd8fSJohnny Huang } else { 13635010032bSJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1364eda10d61SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 13655010032bSJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 13665010032bSJohnny Huang } 13675010032bSJohnny Huang 1368*e417205bSJohnny Huang if (info_cb.version != OTP_A0) { 1369a219f6deSJohnny Huang if (i < 32) 13705010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 1371a219f6deSJohnny Huang else 13725010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 13735010032bSJohnny Huang } else { 13745010032bSJohnny Huang rpbit = 0; 137569d5fd8fSJohnny Huang } 1376eda10d61SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit); 1377eda10d61SJohnny Huang 1378eda10d61SJohnny Huang if (ret == OTP_FAILURE) 137969d5fd8fSJohnny Huang fail = 1; 138069d5fd8fSJohnny Huang } 138169d5fd8fSJohnny Huang if (fail == 1) 1382a6af4a17SJohnny Huang return OTP_FAILURE; 13839901d43aSJohnny Huang else 1384eda10d61SJohnny Huang return OTP_SUCCESS; 138569d5fd8fSJohnny Huang } 138669d5fd8fSJohnny Huang 13872a856b9aSJohnny Huang static int otp_print_strap(int start, int count) 138869d5fd8fSJohnny Huang { 138969d5fd8fSJohnny Huang int i, j; 1390de6b0cc4SJohnny Huang int remains; 139166f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 139269d5fd8fSJohnny Huang 13932a856b9aSJohnny Huang if (start < 0 || start > 64) 13942a856b9aSJohnny Huang return OTP_USAGE; 13952a856b9aSJohnny Huang 13962a856b9aSJohnny Huang if ((start + count) < 0 || (start + count) > 64) 13972a856b9aSJohnny Huang return OTP_USAGE; 13982a856b9aSJohnny Huang 1399541eb887SJohnny Huang otp_strap_status(otpstrap); 140069d5fd8fSJohnny Huang 1401*e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 1402de6b0cc4SJohnny Huang remains = 7; 140307baa4e8SJohnny Huang printf("BIT(hex) Value Option Status\n"); 1404de6b0cc4SJohnny Huang } else { 1405de6b0cc4SJohnny Huang remains = 6; 1406de6b0cc4SJohnny Huang printf("BIT(hex) Value Option Reg_Protect Status\n"); 1407de6b0cc4SJohnny Huang } 1408de6b0cc4SJohnny Huang printf("______________________________________________________________________________\n"); 1409737ed20bSJohnny Huang 1410cd1610b4SJohnny Huang for (i = start; i < start + count; i++) { 141107baa4e8SJohnny Huang printf("0x%-8X", i); 1412737ed20bSJohnny Huang printf("%-7d", otpstrap[i].value); 1413de6b0cc4SJohnny Huang for (j = 0; j < remains; j++) 1414737ed20bSJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 1415737ed20bSJohnny Huang printf(" "); 1416*e417205bSJohnny Huang if (info_cb.version != OTP_A0) 1417de6b0cc4SJohnny Huang printf("%d ", otpstrap[i].reg_protected); 141869d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 1419737ed20bSJohnny Huang printf("protected and not writable"); 142069d5fd8fSJohnny Huang } else { 1421737ed20bSJohnny Huang printf("not protected "); 1422a219f6deSJohnny Huang if (otpstrap[i].remain_times == 0) 1423737ed20bSJohnny Huang printf("and no remaining times to write."); 1424a219f6deSJohnny Huang else 1425737ed20bSJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 142669d5fd8fSJohnny Huang } 1427737ed20bSJohnny Huang printf("\n"); 142869d5fd8fSJohnny Huang } 14292a856b9aSJohnny Huang 14302a856b9aSJohnny Huang return OTP_SUCCESS; 143169d5fd8fSJohnny Huang } 143269d5fd8fSJohnny Huang 14338848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value) 14348848d5dcSJohnny Huang { 14358848d5dcSJohnny Huang struct otpstrap_status otpstrap[64]; 1436a219f6deSJohnny Huang u32 prog_address; 14378848d5dcSJohnny Huang int offset; 14388848d5dcSJohnny Huang int ret; 14398848d5dcSJohnny Huang 14408848d5dcSJohnny Huang otp_strap_status(otpstrap); 14418848d5dcSJohnny Huang 14428848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 14438848d5dcSJohnny Huang 1444a219f6deSJohnny Huang if (ret != OTP_SUCCESS) 14458848d5dcSJohnny Huang return ret; 14468848d5dcSJohnny Huang 14478848d5dcSJohnny Huang prog_address = 0x800; 14488848d5dcSJohnny Huang if (bit_offset < 32) { 14498848d5dcSJohnny Huang offset = bit_offset; 14508848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 14518848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 14528848d5dcSJohnny Huang 14538848d5dcSJohnny Huang } else { 14548848d5dcSJohnny Huang offset = (bit_offset - 32); 14558848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 14568848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 14578848d5dcSJohnny Huang } 14588848d5dcSJohnny Huang 145983655e91SJohnny Huang return otp_prog_bit(1, prog_address, offset); 14608848d5dcSJohnny Huang } 14618848d5dcSJohnny Huang 14625010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout) 146369d5fd8fSJohnny Huang { 1464a219f6deSJohnny Huang u32 *strap; 1465a219f6deSJohnny Huang u32 *strap_ignore; 1466a219f6deSJohnny Huang u32 *strap_pro; 1467a219f6deSJohnny Huang u32 *strap_reg_protect; 1468a219f6deSJohnny Huang u32 prog_address; 146983655e91SJohnny Huang int i; 1470eda10d61SJohnny Huang int bit, pbit, ibit, offset, rpbit; 147169d5fd8fSJohnny Huang int fail = 0; 147283655e91SJohnny Huang int ret; 14739901d43aSJohnny Huang int prog_flag = 0; 147466f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 147569d5fd8fSJohnny Huang 1476a219f6deSJohnny Huang strap = (u32 *)image_layout->strap; 1477a219f6deSJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1478a219f6deSJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1479a219f6deSJohnny Huang strap_reg_protect = (u32 *)image_layout->strap_reg_pro; 14805010032bSJohnny Huang 14817f795e57SJohnny Huang printf("Read OTP Strap Region:\n"); 1482541eb887SJohnny Huang otp_strap_status(otpstrap); 148369d5fd8fSJohnny Huang 14847f795e57SJohnny Huang printf("Check writable...\n"); 14855010032bSJohnny Huang if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) { 14867f795e57SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 14877f795e57SJohnny Huang return OTP_FAILURE; 14887f795e57SJohnny Huang } 14897e22f42dSJohnny Huang 149069d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 149169d5fd8fSJohnny Huang prog_address = 0x800; 149269d5fd8fSJohnny Huang if (i < 32) { 149369d5fd8fSJohnny Huang offset = i; 14945010032bSJohnny Huang bit = (strap[0] >> offset) & 0x1; 1495eda10d61SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 14965010032bSJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 149769d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 149869d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 149969d5fd8fSJohnny Huang 150069d5fd8fSJohnny Huang } else { 150169d5fd8fSJohnny Huang offset = (i - 32); 15025010032bSJohnny Huang bit = (strap[1] >> offset) & 0x1; 1503eda10d61SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 15045010032bSJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 150569d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 150669d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 150769d5fd8fSJohnny Huang } 1508*e417205bSJohnny Huang if (info_cb.version != OTP_A0) { 1509a219f6deSJohnny Huang if (i < 32) 15105010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 1511a219f6deSJohnny Huang else 15125010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 15135010032bSJohnny Huang } else { 15145010032bSJohnny Huang rpbit = 0; 15155010032bSJohnny Huang } 151669d5fd8fSJohnny Huang 1517a219f6deSJohnny Huang if (ibit == 1) 151869d5fd8fSJohnny Huang continue; 15199901d43aSJohnny Huang if (bit == otpstrap[i].value) 15209901d43aSJohnny Huang prog_flag = 0; 15219901d43aSJohnny Huang else 15229901d43aSJohnny Huang prog_flag = 1; 15239901d43aSJohnny Huang 15249901d43aSJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 152569d5fd8fSJohnny Huang fail = 1; 152669d5fd8fSJohnny Huang continue; 152769d5fd8fSJohnny Huang } 15289901d43aSJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 152969d5fd8fSJohnny Huang fail = 1; 153069d5fd8fSJohnny Huang continue; 153169d5fd8fSJohnny Huang } 15327e22f42dSJohnny Huang 15339901d43aSJohnny Huang if (prog_flag) { 153483655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 1535794e27ecSJohnny Huang if (ret) 15362a856b9aSJohnny Huang return OTP_FAILURE; 15379901d43aSJohnny Huang } 153869d5fd8fSJohnny Huang 1539*e417205bSJohnny Huang if (rpbit == 1 && info_cb.version != OTP_A0) { 154069d5fd8fSJohnny Huang prog_address = 0x800; 154169d5fd8fSJohnny Huang if (i < 32) 15425010032bSJohnny Huang prog_address |= 0x608; 154369d5fd8fSJohnny Huang else 15445010032bSJohnny Huang prog_address |= 0x60a; 15457e22f42dSJohnny Huang 154683655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 1547794e27ecSJohnny Huang if (ret) 15482a856b9aSJohnny Huang return OTP_FAILURE; 15495010032bSJohnny Huang } 15505010032bSJohnny Huang 15515010032bSJohnny Huang if (pbit != 0) { 15525010032bSJohnny Huang prog_address = 0x800; 15535010032bSJohnny Huang if (i < 32) 15545010032bSJohnny Huang prog_address |= 0x60c; 15555010032bSJohnny Huang else 15565010032bSJohnny Huang prog_address |= 0x60e; 15575010032bSJohnny Huang 155883655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 1559794e27ecSJohnny Huang if (ret) 15605010032bSJohnny Huang return OTP_FAILURE; 15615010032bSJohnny Huang } 156269d5fd8fSJohnny Huang } 1563de6fbf1cSJohnny Huang otp_soak(0); 156469d5fd8fSJohnny Huang if (fail == 1) 15652a856b9aSJohnny Huang return OTP_FAILURE; 15662a856b9aSJohnny Huang return OTP_SUCCESS; 156769d5fd8fSJohnny Huang } 156869d5fd8fSJohnny Huang 15695010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout) 15704c1c9b35SJohnny Huang { 157154552c69SJohnny Huang int i; 157254552c69SJohnny Huang int ret; 15735010032bSJohnny Huang int data_dw; 1574a219f6deSJohnny Huang u32 data[2048]; 1575a219f6deSJohnny Huang u32 *buf; 1576a219f6deSJohnny Huang u32 *buf_ignore; 1577a219f6deSJohnny Huang u32 data_masked; 1578a219f6deSJohnny Huang u32 buf_masked; 15794c1c9b35SJohnny Huang 1580a219f6deSJohnny Huang buf = (u32 *)image_layout->data; 1581a219f6deSJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 15825010032bSJohnny Huang 15835010032bSJohnny Huang data_dw = image_layout->data_length / 4; 15845010032bSJohnny Huang 15854c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 15864c1c9b35SJohnny Huang 1587a219f6deSJohnny Huang for (i = 0; i < data_dw - 2 ; i += 2) 1588d90825e2SJohnny Huang otp_read_data(i, &data[i]); 1589d90825e2SJohnny Huang 15904c1c9b35SJohnny Huang printf("Check writable...\n"); 159154552c69SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 15925010032bSJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1593696656c6SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1594696656c6SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 159554552c69SJohnny Huang if (data_masked == buf_masked) 15964c1c9b35SJohnny Huang continue; 1597d90825e2SJohnny Huang if (i % 2 == 0) { 159854552c69SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 15994c1c9b35SJohnny Huang continue; 16004c1c9b35SJohnny Huang } else { 16014c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1602d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 16034c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1604696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 16052a856b9aSJohnny Huang return OTP_FAILURE; 160669d5fd8fSJohnny Huang } 1607d90825e2SJohnny Huang } else { 160854552c69SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1609d90825e2SJohnny Huang continue; 1610d90825e2SJohnny Huang } else { 1611d90825e2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1612d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1613d90825e2SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1614696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 16152a856b9aSJohnny Huang return OTP_FAILURE; 1616d90825e2SJohnny Huang } 1617d90825e2SJohnny Huang } 1618d90825e2SJohnny Huang } 161969d5fd8fSJohnny Huang 1620d90825e2SJohnny Huang printf("Start Programing...\n"); 1621d90825e2SJohnny Huang 162254552c69SJohnny Huang // programing ecc region first 162354552c69SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1624696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 162554552c69SJohnny Huang if (ret != OTP_SUCCESS) { 162654552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1627696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 162854552c69SJohnny Huang return ret; 1629d90825e2SJohnny Huang } 1630d90825e2SJohnny Huang } 1631d90825e2SJohnny Huang 163254552c69SJohnny Huang for (i = 0; i < 1792; i += 2) { 1633696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 163454552c69SJohnny Huang if (ret != OTP_SUCCESS) { 163554552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1636696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 163754552c69SJohnny Huang return ret; 1638d90825e2SJohnny Huang } 1639de6fbf1cSJohnny Huang } 1640de6fbf1cSJohnny Huang otp_soak(0); 16412a856b9aSJohnny Huang return OTP_SUCCESS; 1642d90825e2SJohnny Huang } 1643d90825e2SJohnny Huang 1644a219f6deSJohnny Huang static int otp_image_verify(u8 *src_buf, u32 length, u8 *digest_buf) 1645696656c6SJohnny Huang { 1646696656c6SJohnny Huang sha256_context ctx; 1647696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1648696656c6SJohnny Huang 1649696656c6SJohnny Huang sha256_starts(&ctx); 1650696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1651696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1652696656c6SJohnny Huang 1653696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1654696656c6SJohnny Huang return 0; 1655696656c6SJohnny Huang return -1; 1656696656c6SJohnny Huang } 1657696656c6SJohnny Huang 1658de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm) 165969d5fd8fSJohnny Huang { 166069d5fd8fSJohnny Huang int ret; 16619a4fe690SJohnny Huang int image_version = 0; 1662696656c6SJohnny Huang struct otp_header *otp_header; 1663696656c6SJohnny Huang struct otp_image_layout image_layout; 1664696656c6SJohnny Huang int image_size; 1665a219f6deSJohnny Huang u8 *buf; 1666a219f6deSJohnny Huang u8 *checksum; 166769d5fd8fSJohnny Huang 1668696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1669696656c6SJohnny Huang if (!otp_header) { 167069d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 16712a856b9aSJohnny Huang return OTP_FAILURE; 167269d5fd8fSJohnny Huang } 1673d90825e2SJohnny Huang 1674696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1675696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1676696656c6SJohnny Huang 1677696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1678696656c6SJohnny Huang 1679696656c6SJohnny Huang if (!buf) { 1680696656c6SJohnny Huang puts("Failed to map physical memory\n"); 1681696656c6SJohnny Huang return OTP_FAILURE; 1682696656c6SJohnny Huang } 1683696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1684696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1685696656c6SJohnny Huang 1686696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1687696656c6SJohnny Huang puts("Image is invalid\n"); 1688696656c6SJohnny Huang return OTP_FAILURE; 1689696656c6SJohnny Huang } 1690696656c6SJohnny Huang 16915010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 16925010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 16935010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 16945010032bSJohnny Huang 16955010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1696696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 16975010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1698696656c6SJohnny Huang 1699696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 1700696656c6SJohnny Huang 1701696656c6SJohnny Huang if (!strcmp("A0", (char *)otp_header->otp_version)) { 1702*e417205bSJohnny Huang image_version = OTP_A0; 17035010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 17045010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 17055010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 1706696656c6SJohnny Huang } else if (!strcmp("A1", (char *)otp_header->otp_version)) { 1707*e417205bSJohnny Huang image_version = OTP_A1; 17085010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 17095010032bSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 17105010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 17115010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 17125fdde29fSJohnny Huang } else if (!strcmp("A2", (char *)otp_header->otp_version)) { 1713*e417205bSJohnny Huang image_version = OTP_A2; 17145fdde29fSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 17155fdde29fSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 17165fdde29fSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 17175fdde29fSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 171864b66712SJohnny Huang } else if (!strcmp("A3", (char *)otp_header->otp_version)) { 1719*e417205bSJohnny Huang image_version = OTP_A3; 172064b66712SJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 172164b66712SJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 172264b66712SJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 172364b66712SJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 1724696656c6SJohnny Huang } else { 1725696656c6SJohnny Huang puts("Version is not supported\n"); 1726696656c6SJohnny Huang return OTP_FAILURE; 1727696656c6SJohnny Huang } 1728696656c6SJohnny Huang 17299a4fe690SJohnny Huang if (image_version != info_cb.version) { 17309a4fe690SJohnny Huang puts("Version is not match\n"); 17319a4fe690SJohnny Huang return OTP_FAILURE; 17329a4fe690SJohnny Huang } 17339a4fe690SJohnny Huang 1734696656c6SJohnny Huang if (otp_image_verify(buf, image_size, checksum)) { 1735696656c6SJohnny Huang puts("checksum is invalid\n"); 1736696656c6SJohnny Huang return OTP_FAILURE; 1737d90825e2SJohnny Huang } 17387332532cSJohnny Huang 173969d5fd8fSJohnny Huang if (!nconfirm) { 1740696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 17417f795e57SJohnny Huang printf("\nOTP data region :\n"); 1742696656c6SJohnny Huang if (otp_print_data_info(&image_layout) < 0) { 174369d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 17442a856b9aSJohnny Huang return OTP_FAILURE; 174569d5fd8fSJohnny Huang } 174669d5fd8fSJohnny Huang } 1747696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 17487332532cSJohnny Huang printf("\nOTP strap region :\n"); 17495010032bSJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 17507332532cSJohnny Huang printf("OTP strap error, please check.\n"); 17517332532cSJohnny Huang return OTP_FAILURE; 17527332532cSJohnny Huang } 17537332532cSJohnny Huang } 1754696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 17557332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1756696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 17577332532cSJohnny Huang printf("OTP config error, please check.\n"); 17587332532cSJohnny Huang return OTP_FAILURE; 17597332532cSJohnny Huang } 17607332532cSJohnny Huang } 17617332532cSJohnny Huang 176269d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 176369d5fd8fSJohnny Huang if (!confirm_yesno()) { 176469d5fd8fSJohnny Huang printf(" Aborting\n"); 17652a856b9aSJohnny Huang return OTP_FAILURE; 176669d5fd8fSJohnny Huang } 176769d5fd8fSJohnny Huang } 17687332532cSJohnny Huang 17695010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 17705010032bSJohnny Huang printf("programing data region ...\n"); 17715010032bSJohnny Huang ret = otp_prog_data(&image_layout); 17725010032bSJohnny Huang if (ret != 0) { 17735010032bSJohnny Huang printf("Error\n"); 17745010032bSJohnny Huang return ret; 17755010032bSJohnny Huang } 1776a219f6deSJohnny Huang printf("Done\n"); 17775010032bSJohnny Huang } 17785010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 17795010032bSJohnny Huang printf("programing strap region ...\n"); 17805010032bSJohnny Huang ret = otp_prog_strap(&image_layout); 17815010032bSJohnny Huang if (ret != 0) { 17825010032bSJohnny Huang printf("Error\n"); 17835010032bSJohnny Huang return ret; 17845010032bSJohnny Huang } 1785a219f6deSJohnny Huang printf("Done\n"); 17865010032bSJohnny Huang } 17875010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 17885010032bSJohnny Huang printf("programing configuration region ...\n"); 17895010032bSJohnny Huang ret = otp_prog_conf(&image_layout); 17905010032bSJohnny Huang if (ret != 0) { 17915010032bSJohnny Huang printf("Error\n"); 17925010032bSJohnny Huang return ret; 17935010032bSJohnny Huang } 17945010032bSJohnny Huang printf("Done\n"); 17955010032bSJohnny Huang } 1796cd1610b4SJohnny Huang 17977332532cSJohnny Huang return OTP_SUCCESS; 17982a856b9aSJohnny Huang } 17992a856b9aSJohnny Huang 18002a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1801cd1610b4SJohnny Huang { 1802a219f6deSJohnny Huang u32 read[2]; 1803a219f6deSJohnny Huang u32 prog_address = 0; 180466f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 1805cd1610b4SJohnny Huang int otp_bit; 180683655e91SJohnny Huang int ret = 0; 1807cd1610b4SJohnny Huang 1808dacbba92SJohnny Huang otp_soak(0); 1809cd1610b4SJohnny Huang switch (mode) { 1810a6d0d645SJohnny Huang case OTP_REGION_CONF: 1811a6af4a17SJohnny Huang otp_read_config(otp_dw_offset, read); 1812cd1610b4SJohnny Huang prog_address = 0x800; 1813cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1814cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1815a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1816cd1610b4SJohnny Huang if (otp_bit == value) { 1817a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1818cd1610b4SJohnny Huang printf("No need to program\n"); 18192a856b9aSJohnny Huang return OTP_SUCCESS; 1820cd1610b4SJohnny Huang } 1821cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1822a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset); 1823cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 18242a856b9aSJohnny Huang return OTP_FAILURE; 1825cd1610b4SJohnny Huang } 1826a6af4a17SJohnny Huang printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset); 1827cd1610b4SJohnny Huang break; 1828a6d0d645SJohnny Huang case OTP_REGION_DATA: 1829cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1830cd1610b4SJohnny Huang 1831cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1832a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 1833a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1834643b9cfdSJohnny Huang 1835643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 1836643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1837643b9cfdSJohnny Huang printf("OTP is programed, which can't be cleaned\n"); 1838643b9cfdSJohnny Huang return OTP_FAILURE; 1839643b9cfdSJohnny Huang } 1840cd1610b4SJohnny Huang } else { 1841a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 1842a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 1843643b9cfdSJohnny Huang 1844643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 1845643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1846643b9cfdSJohnny Huang printf("OTP is programed, which can't be writen\n"); 1847643b9cfdSJohnny Huang return OTP_FAILURE; 1848643b9cfdSJohnny Huang } 1849cd1610b4SJohnny Huang } 1850cd1610b4SJohnny Huang if (otp_bit == value) { 1851a6af4a17SJohnny Huang printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1852cd1610b4SJohnny Huang printf("No need to program\n"); 18532a856b9aSJohnny Huang return OTP_SUCCESS; 1854cd1610b4SJohnny Huang } 1855643b9cfdSJohnny Huang 1856a6af4a17SJohnny Huang printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset); 1857cd1610b4SJohnny Huang break; 1858a6d0d645SJohnny Huang case OTP_REGION_STRAP: 18598848d5dcSJohnny Huang otp_strap_status(otpstrap); 18608848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 18618848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 18628848d5dcSJohnny Huang if (ret == OTP_FAILURE) 18638848d5dcSJohnny Huang return OTP_FAILURE; 18648848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 18658848d5dcSJohnny Huang return OTP_SUCCESS; 1866a6af4a17SJohnny Huang 1867cd1610b4SJohnny Huang break; 1868cd1610b4SJohnny Huang } 1869cd1610b4SJohnny Huang 1870cd1610b4SJohnny Huang if (!nconfirm) { 1871cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1872cd1610b4SJohnny Huang if (!confirm_yesno()) { 1873cd1610b4SJohnny Huang printf(" Aborting\n"); 18742a856b9aSJohnny Huang return OTP_FAILURE; 1875cd1610b4SJohnny Huang } 1876cd1610b4SJohnny Huang } 1877cd1610b4SJohnny Huang 1878cd1610b4SJohnny Huang switch (mode) { 1879a6d0d645SJohnny Huang case OTP_REGION_STRAP: 188083655e91SJohnny Huang ret = otp_prog_strap_bit(bit_offset, value); 188183655e91SJohnny Huang break; 1882a6d0d645SJohnny Huang case OTP_REGION_CONF: 1883a6d0d645SJohnny Huang case OTP_REGION_DATA: 188483655e91SJohnny Huang ret = otp_prog_bit(value, prog_address, bit_offset); 1885de6fbf1cSJohnny Huang break; 1886de6fbf1cSJohnny Huang } 1887de6fbf1cSJohnny Huang otp_soak(0); 188883655e91SJohnny Huang if (ret) { 1889794e27ecSJohnny Huang printf("OTP cannot be programed\n"); 1890794e27ecSJohnny Huang printf("FAILURE\n"); 1891794e27ecSJohnny Huang return OTP_FAILURE; 1892794e27ecSJohnny Huang } 1893794e27ecSJohnny Huang 18949009c25dSJohnny Huang printf("SUCCESS\n"); 18952a856b9aSJohnny Huang return OTP_SUCCESS; 1896a219f6deSJohnny Huang } 1897a219f6deSJohnny Huang 1898794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 1899794e27ecSJohnny Huang { 1900794e27ecSJohnny Huang u32 otp_rid[2]; 1901794e27ecSJohnny Huang int rid_num = 0; 1902794e27ecSJohnny Huang int bit_offset; 1903794e27ecSJohnny Huang int dw_offset; 1904794e27ecSJohnny Huang int i; 1905794e27ecSJohnny Huang int ret; 1906794e27ecSJohnny Huang 1907794e27ecSJohnny Huang otp_read_config(10, &otp_rid[0]); 1908794e27ecSJohnny Huang otp_read_config(11, &otp_rid[1]); 1909794e27ecSJohnny Huang 1910794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 1911794e27ecSJohnny Huang 1912794e27ecSJohnny Huang if (rid_num < 0) { 1913794e27ecSJohnny Huang printf("Currennt OTP revision ID cannot handle by this command,\n" 1914794e27ecSJohnny Huang "plase use 'otp pb' command to update it manually\n"); 1915794e27ecSJohnny Huang otp_print_revid(otp_rid); 19169009c25dSJohnny Huang return OTP_FAILURE; 19179009c25dSJohnny Huang } 1918cd1610b4SJohnny Huang 1919794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 1920794e27ecSJohnny Huang otp_print_revid(otp_rid); 1921794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 1922794e27ecSJohnny Huang 1923794e27ecSJohnny Huang if (rid_num >= update_num) { 1924794e27ecSJohnny Huang printf("OTP rev_id is bigger than 0x%x\n", update_num); 1925794e27ecSJohnny Huang printf("Skip\n"); 1926794e27ecSJohnny Huang return OTP_FAILURE; 1927794e27ecSJohnny Huang } 1928794e27ecSJohnny Huang 1929794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 1930794e27ecSJohnny Huang if (i < 32) { 1931794e27ecSJohnny Huang dw_offset = 0xa; 1932794e27ecSJohnny Huang bit_offset = i; 1933794e27ecSJohnny Huang } else { 1934794e27ecSJohnny Huang dw_offset = 0xb; 1935794e27ecSJohnny Huang bit_offset = i - 32; 1936794e27ecSJohnny Huang } 1937794e27ecSJohnny Huang printf("OTPCFG%X[%d]", dw_offset, bit_offset); 1938794e27ecSJohnny Huang if (i + 1 != update_num) 1939794e27ecSJohnny Huang printf(", "); 1940794e27ecSJohnny Huang } 1941794e27ecSJohnny Huang 1942794e27ecSJohnny Huang printf(" will be programmed\n"); 1943794e27ecSJohnny Huang if (force == 0) { 1944794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1945794e27ecSJohnny Huang if (!confirm_yesno()) { 1946794e27ecSJohnny Huang printf(" Aborting\n"); 1947794e27ecSJohnny Huang return OTP_FAILURE; 1948794e27ecSJohnny Huang } 1949794e27ecSJohnny Huang } 1950794e27ecSJohnny Huang 1951794e27ecSJohnny Huang ret = 0; 1952794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 1953794e27ecSJohnny Huang if (i < 32) { 1954794e27ecSJohnny Huang dw_offset = 0xa04; 1955794e27ecSJohnny Huang bit_offset = i; 1956794e27ecSJohnny Huang } else { 1957794e27ecSJohnny Huang dw_offset = 0xa06; 1958794e27ecSJohnny Huang bit_offset = i - 32; 1959794e27ecSJohnny Huang } 1960794e27ecSJohnny Huang if (otp_prog_bit(1, dw_offset, bit_offset)) { 1961794e27ecSJohnny Huang printf("OTPCFG%X[%d] programming failed\n", dw_offset, bit_offset); 1962794e27ecSJohnny Huang ret = OTP_FAILURE; 1963794e27ecSJohnny Huang break; 1964794e27ecSJohnny Huang } 1965794e27ecSJohnny Huang } 1966794e27ecSJohnny Huang 1967794e27ecSJohnny Huang otp_read_config(10, &otp_rid[0]); 1968794e27ecSJohnny Huang otp_read_config(11, &otp_rid[1]); 1969794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 1970794e27ecSJohnny Huang if (rid_num >= 0) 1971794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1972794e27ecSJohnny Huang else 1973794e27ecSJohnny Huang printf("OTP revision ID\n"); 1974794e27ecSJohnny Huang otp_print_revid(otp_rid); 1975794e27ecSJohnny Huang if (!ret) 1976794e27ecSJohnny Huang printf("SUCCESS\n"); 1977794e27ecSJohnny Huang else 1978794e27ecSJohnny Huang printf("FAILED\n"); 1979794e27ecSJohnny Huang return ret; 1980794e27ecSJohnny Huang } 1981794e27ecSJohnny Huang 19822a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 198369d5fd8fSJohnny Huang { 1984a219f6deSJohnny Huang u32 offset, count; 19852a856b9aSJohnny Huang int ret; 198669d5fd8fSJohnny Huang 19872a856b9aSJohnny Huang if (argc == 4) { 19882a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 19892a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 19902a856b9aSJohnny Huang } else if (argc == 3) { 19912a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 19922a856b9aSJohnny Huang count = 1; 19932a856b9aSJohnny Huang } else { 199469d5fd8fSJohnny Huang return CMD_RET_USAGE; 199569d5fd8fSJohnny Huang } 199669d5fd8fSJohnny Huang 19972a856b9aSJohnny Huang if (!strcmp(argv[1], "conf")) { 19983d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19992a856b9aSJohnny Huang ret = otp_print_config(offset, count); 20002a856b9aSJohnny Huang } else if (!strcmp(argv[1], "data")) { 20013d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 20022a856b9aSJohnny Huang ret = otp_print_data(offset, count); 20032a856b9aSJohnny Huang } else if (!strcmp(argv[1], "strap")) { 20043d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 20052a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 20062a856b9aSJohnny Huang } else { 20072a856b9aSJohnny Huang return CMD_RET_USAGE; 200869d5fd8fSJohnny Huang } 200969d5fd8fSJohnny Huang 20102a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 20112a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20122a856b9aSJohnny Huang return CMD_RET_USAGE; 20132a856b9aSJohnny Huang } 20142a856b9aSJohnny Huang 20152a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20162a856b9aSJohnny Huang { 20172a856b9aSJohnny Huang phys_addr_t addr; 20182a856b9aSJohnny Huang int ret; 20192a856b9aSJohnny Huang 2020de6b0cc4SJohnny Huang if (argc == 3) { 2021ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 20222a856b9aSJohnny Huang return CMD_RET_USAGE; 20232a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 20243d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2025de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 1); 2026de6b0cc4SJohnny Huang } else if (argc == 2) { 20272a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 20283d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2029de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 0); 20302a856b9aSJohnny Huang } else { 20312a856b9aSJohnny Huang return CMD_RET_USAGE; 20322a856b9aSJohnny Huang } 20332a856b9aSJohnny Huang 20342a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 20352a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20362a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 20372a856b9aSJohnny Huang return CMD_RET_FAILURE; 20382a856b9aSJohnny Huang else 20392a856b9aSJohnny Huang return CMD_RET_USAGE; 20402a856b9aSJohnny Huang } 20412a856b9aSJohnny Huang 20422a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20432a856b9aSJohnny Huang { 20442a856b9aSJohnny Huang int mode = 0; 20452a856b9aSJohnny Huang int nconfirm = 0; 20462a856b9aSJohnny Huang int otp_addr = 0; 20472a856b9aSJohnny Huang int bit_offset; 20482a856b9aSJohnny Huang int value; 20492a856b9aSJohnny Huang int ret; 20502a856b9aSJohnny Huang 20512a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 20522a856b9aSJohnny Huang return CMD_RET_USAGE; 20532a856b9aSJohnny Huang 20542a856b9aSJohnny Huang /* Drop the pb cmd */ 20552a856b9aSJohnny Huang argc--; 20562a856b9aSJohnny Huang argv++; 20572a856b9aSJohnny Huang 20582a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2059a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 20602a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2061a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 20622a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2063a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2064cd1610b4SJohnny Huang else 20652a856b9aSJohnny Huang return CMD_RET_USAGE; 20662a856b9aSJohnny Huang 20672a856b9aSJohnny Huang /* Drop the region cmd */ 20682a856b9aSJohnny Huang argc--; 20692a856b9aSJohnny Huang argv++; 20702a856b9aSJohnny Huang 2071ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2072cd1610b4SJohnny Huang nconfirm = 1; 20732a856b9aSJohnny Huang /* Drop the force option */ 20742a856b9aSJohnny Huang argc--; 20752a856b9aSJohnny Huang argv++; 20762a856b9aSJohnny Huang } 2077cd1610b4SJohnny Huang 2078a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 20792a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 20802a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 20810808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 20822a856b9aSJohnny Huang return CMD_RET_USAGE; 2083cd1610b4SJohnny Huang } else { 20842a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 20852a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 20862a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 20870808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 20882a856b9aSJohnny Huang return CMD_RET_USAGE; 20890808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 209078855207SJohnny Huang if (otp_addr >= 0x800) 20910808cc55SJohnny Huang return CMD_RET_USAGE; 20920808cc55SJohnny Huang } else { 209378855207SJohnny Huang if (otp_addr >= 0x20) 20940808cc55SJohnny Huang return CMD_RET_USAGE; 20950808cc55SJohnny Huang } 2096cd1610b4SJohnny Huang } 2097cd1610b4SJohnny Huang if (value != 0 && value != 1) 20982a856b9aSJohnny Huang return CMD_RET_USAGE; 2099cd1610b4SJohnny Huang 21003d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 21012a856b9aSJohnny Huang ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 21022a856b9aSJohnny Huang 21032a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 21042a856b9aSJohnny Huang return CMD_RET_SUCCESS; 21052a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 21062a856b9aSJohnny Huang return CMD_RET_FAILURE; 21072a856b9aSJohnny Huang else 21082a856b9aSJohnny Huang return CMD_RET_USAGE; 21092a856b9aSJohnny Huang } 21102a856b9aSJohnny Huang 21112a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 21122a856b9aSJohnny Huang { 21132a856b9aSJohnny Huang phys_addr_t addr; 21142a856b9aSJohnny Huang int otp_addr = 0; 21152a856b9aSJohnny Huang 21162a856b9aSJohnny Huang if (argc != 3) 21172a856b9aSJohnny Huang return CMD_RET_USAGE; 21182a856b9aSJohnny Huang 21193d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 21202a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 21212a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 21222a856b9aSJohnny Huang if (otp_compare(otp_addr, addr) == 0) { 212369d5fd8fSJohnny Huang printf("Compare pass\n"); 21242a856b9aSJohnny Huang return CMD_RET_SUCCESS; 2125a219f6deSJohnny Huang } 212669d5fd8fSJohnny Huang printf("Compare fail\n"); 21272a856b9aSJohnny Huang return CMD_RET_FAILURE; 212869d5fd8fSJohnny Huang } 212969d5fd8fSJohnny Huang 213066f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 213166f2f8e5SJohnny Huang { 2132a8bd6d8cSJohnny Huang int view = 0; 21332d4b0742SJohnny Huang int input; 2134a8bd6d8cSJohnny Huang 2135a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 213666f2f8e5SJohnny Huang return CMD_RET_USAGE; 213766f2f8e5SJohnny Huang 21382d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 21393d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 21402d4b0742SJohnny Huang if (argc == 3) { 21412d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 21422d4b0742SJohnny Huang otp_print_conf_info(input); 21432d4b0742SJohnny Huang } else { 21442d4b0742SJohnny Huang otp_print_conf_info(-1); 21452d4b0742SJohnny Huang } 21462d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 21472d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 2148a8bd6d8cSJohnny Huang view = 1; 2149a8bd6d8cSJohnny Huang /* Drop the view option */ 2150a8bd6d8cSJohnny Huang argc--; 2151a8bd6d8cSJohnny Huang argv++; 2152a8bd6d8cSJohnny Huang } 21533d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2154b458cd62SJohnny Huang otp_print_strap_info(view); 215566f2f8e5SJohnny Huang } else { 215666f2f8e5SJohnny Huang return CMD_RET_USAGE; 215766f2f8e5SJohnny Huang } 21582d4b0742SJohnny Huang 215966f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 216066f2f8e5SJohnny Huang } 216166f2f8e5SJohnny Huang 2162e14b073cSJohnny Huang static int _do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[], int preg) 2163737ed20bSJohnny Huang { 2164737ed20bSJohnny Huang int input; 2165737ed20bSJohnny Huang int bit_offset; 2166e14b073cSJohnny Huang u32 prog_address; 216783655e91SJohnny Huang int ret; 2168e14b073cSJohnny Huang char info[10]; 2169e14b073cSJohnny Huang 2170e14b073cSJohnny Huang if (preg) { 2171e14b073cSJohnny Huang sprintf(info, "register "); 2172e14b073cSJohnny Huang prog_address = 0xe08; 2173e14b073cSJohnny Huang } else { 2174e14b073cSJohnny Huang info[0] = 0; 2175e14b073cSJohnny Huang prog_address = 0xe0c; 2176e14b073cSJohnny Huang } 2177a219f6deSJohnny Huang 2178737ed20bSJohnny Huang if (argc != 3 && argc != 2) 2179737ed20bSJohnny Huang return CMD_RET_USAGE; 2180737ed20bSJohnny Huang 2181e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 2182737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 2183737ed20bSJohnny Huang } else { 2184737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 2185e14b073cSJohnny Huang printf("OTPSTRAP[%d] %swill be protected\n", input, info); 2186737ed20bSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2187737ed20bSJohnny Huang if (!confirm_yesno()) { 2188737ed20bSJohnny Huang printf(" Aborting\n"); 2189737ed20bSJohnny Huang return CMD_RET_FAILURE; 2190737ed20bSJohnny Huang } 2191737ed20bSJohnny Huang } 2192737ed20bSJohnny Huang 2193737ed20bSJohnny Huang if (input < 32) { 2194737ed20bSJohnny Huang bit_offset = input; 2195737ed20bSJohnny Huang } else if (input < 64) { 2196737ed20bSJohnny Huang bit_offset = input - 32; 2197e14b073cSJohnny Huang prog_address += 2; 2198737ed20bSJohnny Huang } else { 2199737ed20bSJohnny Huang return CMD_RET_USAGE; 2200737ed20bSJohnny Huang } 2201737ed20bSJohnny Huang 2202e14b073cSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2203e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2204e14b073cSJohnny Huang printf("OTPSTRAP[%d] %salready protected\n", input, info); 2205e14b073cSJohnny Huang return CMD_RET_SUCCESS; 2206e14b073cSJohnny Huang } 2207de6fbf1cSJohnny Huang 220883655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, bit_offset); 2209de6fbf1cSJohnny Huang otp_soak(0); 221083655e91SJohnny Huang 221183655e91SJohnny Huang if (ret) { 2212e14b073cSJohnny Huang printf("Protect OTPSTRAP[%d] %sfail\n", input, info); 2213737ed20bSJohnny Huang return CMD_RET_FAILURE; 2214737ed20bSJohnny Huang } 22159a4fe690SJohnny Huang 2216794e27ecSJohnny Huang printf("OTPSTRAP[%d] %sis protected\n", input, info); 2217794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2218794e27ecSJohnny Huang } 2219794e27ecSJohnny Huang 2220e14b073cSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2221e14b073cSJohnny Huang { 2222e14b073cSJohnny Huang return _do_otpprotect(cmdtp, flag, argc, argv, 0); 2223e14b073cSJohnny Huang } 2224e14b073cSJohnny Huang 2225e14b073cSJohnny Huang static int do_otprprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2226e14b073cSJohnny Huang { 2227e14b073cSJohnny Huang return _do_otpprotect(cmdtp, flag, argc, argv, 1); 2228e14b073cSJohnny Huang } 2229e14b073cSJohnny Huang 2230f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2231f67375f7SJohnny Huang { 2232*e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 2233f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2234f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2235f67375f7SJohnny Huang 2236f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2237f67375f7SJohnny Huang } 2238f67375f7SJohnny Huang 2239794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2240794e27ecSJohnny Huang { 2241794e27ecSJohnny Huang u32 update_num; 2242794e27ecSJohnny Huang int force = 0; 2243794e27ecSJohnny Huang int ret; 2244794e27ecSJohnny Huang 2245794e27ecSJohnny Huang if (argc == 3) { 2246794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 2247794e27ecSJohnny Huang return CMD_RET_USAGE; 2248794e27ecSJohnny Huang force = 1; 2249794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 2250794e27ecSJohnny Huang } else if (argc == 2) { 2251794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 2252794e27ecSJohnny Huang } else { 2253794e27ecSJohnny Huang return CMD_RET_USAGE; 2254794e27ecSJohnny Huang } 2255794e27ecSJohnny Huang 2256794e27ecSJohnny Huang if (update_num > 64) 2257794e27ecSJohnny Huang return CMD_RET_USAGE; 2258794e27ecSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2259794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 2260794e27ecSJohnny Huang if (ret) 2261794e27ecSJohnny Huang return CMD_RET_FAILURE; 2262794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2263794e27ecSJohnny Huang } 2264794e27ecSJohnny Huang 2265794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2266794e27ecSJohnny Huang { 2267794e27ecSJohnny Huang u32 otp_rid[2]; 2268794e27ecSJohnny Huang int rid_num = 0; 2269794e27ecSJohnny Huang int ret; 2270794e27ecSJohnny Huang 2271794e27ecSJohnny Huang if (argc != 1) 2272794e27ecSJohnny Huang return CMD_RET_USAGE; 2273794e27ecSJohnny Huang 2274794e27ecSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2275794e27ecSJohnny Huang otp_read_config(10, &otp_rid[0]); 2276794e27ecSJohnny Huang otp_read_config(11, &otp_rid[1]); 2277794e27ecSJohnny Huang 2278794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2279794e27ecSJohnny Huang 2280794e27ecSJohnny Huang if (rid_num >= 0) { 2281794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2282794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 2283794e27ecSJohnny Huang } else { 2284794e27ecSJohnny Huang printf("Currennt OTP revision ID cannot handle by 'otp update',\n" 2285794e27ecSJohnny Huang "plase use 'otp pb' command to update it manually\n" 2286794e27ecSJohnny Huang "current OTP revision ID\n"); 2287794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 2288794e27ecSJohnny Huang } 2289794e27ecSJohnny Huang otp_print_revid(otp_rid); 2290794e27ecSJohnny Huang 2291794e27ecSJohnny Huang return ret; 2292794e27ecSJohnny Huang } 2293794e27ecSJohnny Huang 22942a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2295f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 22962a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2297a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2298de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 22992a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2300737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 2301e14b073cSJohnny Huang U_BOOT_CMD_MKENT(rprotect, 3, 0, do_otprprotect, "", ""), 23022a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 2303794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 2304794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 23052a856b9aSJohnny Huang }; 23062a856b9aSJohnny Huang 23072a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 23082a856b9aSJohnny Huang { 23092a856b9aSJohnny Huang cmd_tbl_t *cp; 2310a219f6deSJohnny Huang u32 ver; 2311e14b073cSJohnny Huang int ret; 23122a856b9aSJohnny Huang 23132a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 23142a856b9aSJohnny Huang 2315737ed20bSJohnny Huang /* Drop the otp command */ 23162a856b9aSJohnny Huang argc--; 23172a856b9aSJohnny Huang argv++; 23182a856b9aSJohnny Huang 2319a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 23202a856b9aSJohnny Huang return CMD_RET_USAGE; 23212a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 23222a856b9aSJohnny Huang return CMD_RET_SUCCESS; 23232a856b9aSJohnny Huang 23240dae9d52SJohnny Huang ver = chip_version(); 23250dae9d52SJohnny Huang switch (ver) { 2326*e417205bSJohnny Huang case OTP_A0: 2327*e417205bSJohnny Huang info_cb.version = OTP_A0; 23289a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 23299a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 23309a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 23319a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 23329a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 23339a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 2334*e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 23350dae9d52SJohnny Huang break; 2336*e417205bSJohnny Huang case OTP_A1: 2337*e417205bSJohnny Huang info_cb.version = OTP_A1; 23383cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 23393cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 23403cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 23413cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 23429a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 23439a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 2344*e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 23450dae9d52SJohnny Huang break; 2346*e417205bSJohnny Huang case OTP_A2: 2347*e417205bSJohnny Huang info_cb.version = OTP_A2; 23485fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 23495fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 23505fdde29fSJohnny Huang info_cb.strap_info = a2_strap_info; 23515fdde29fSJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 23525fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 23535fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 2354*e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 23550dae9d52SJohnny Huang break; 2356*e417205bSJohnny Huang case OTP_A3: 2357*e417205bSJohnny Huang info_cb.version = OTP_A3; 235864b66712SJohnny Huang info_cb.conf_info = a2_conf_info; 235964b66712SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 236064b66712SJohnny Huang info_cb.strap_info = a2_strap_info; 236164b66712SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 2362181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2363181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 2364*e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 236564b66712SJohnny Huang break; 23660dae9d52SJohnny Huang default: 2367f1be5099SJohnny Huang printf("SOC is not supported\n"); 23680dae9d52SJohnny Huang return CMD_RET_FAILURE; 23699a4fe690SJohnny Huang } 23709a4fe690SJohnny Huang 2371e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 2372e14b073cSJohnny Huang writel(1, OTP_PROTECT_KEY); //password 2373e14b073cSJohnny Huang 2374e14b073cSJohnny Huang return ret; 237569d5fd8fSJohnny Huang } 237669d5fd8fSJohnny Huang 2377a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 237869d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2379f67375f7SJohnny Huang "version\n" 2380f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 23812a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 23822d4b0742SJohnny Huang "otp info strap [v]\n" 23832d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 2384de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2385ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2386ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2387ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 2388e14b073cSJohnny Huang "otp rprotect [o] <bit_offset>\n" 2389794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 2390794e27ecSJohnny Huang "otp rid\n" 239169d5fd8fSJohnny Huang ); 2392