1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+ 269d5fd8fSJohnny Huang /* 3a219f6deSJohnny Huang * Copyright 2021 Aspeed Technology Inc. 469d5fd8fSJohnny Huang */ 5e417205bSJohnny Huang 64c1c9b35SJohnny Huang #include <stdlib.h> 769d5fd8fSJohnny Huang #include <common.h> 869d5fd8fSJohnny Huang #include <console.h> 969d5fd8fSJohnny Huang #include <bootretry.h> 1069d5fd8fSJohnny Huang #include <cli.h> 1169d5fd8fSJohnny Huang #include <command.h> 1269d5fd8fSJohnny Huang #include <console.h> 134c1c9b35SJohnny Huang #include <malloc.h> 1469d5fd8fSJohnny Huang #include <inttypes.h> 1569d5fd8fSJohnny Huang #include <mapmem.h> 1669d5fd8fSJohnny Huang #include <asm/io.h> 1769d5fd8fSJohnny Huang #include <linux/compiler.h> 18696656c6SJohnny Huang #include <u-boot/sha256.h> 190cee9a95SJohnny Huang #include "otp_info.h" 2069d5fd8fSJohnny Huang 2169d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2269d5fd8fSJohnny Huang 23f347c284SJohnny Huang #define OTP_VER "1.1.0" 24f67375f7SJohnny Huang 2569d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 26dacbba92SJohnny Huang #define RETRY 20 277332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 287332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 297332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 3069d5fd8fSJohnny Huang 312a856b9aSJohnny Huang #define OTP_USAGE -1 322a856b9aSJohnny Huang #define OTP_FAILURE -2 332a856b9aSJohnny Huang #define OTP_SUCCESS 0 342a856b9aSJohnny Huang 35a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 36a6af4a17SJohnny Huang 37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB 1 38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV 2 39181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES 3 40181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT 4 41181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC 5 429a4fe690SJohnny Huang 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 56a8789b47SJohnny Huang #define SW_REV_ID0 OTP_BASE + 0x68 57a8789b47SJohnny Huang #define SW_REV_ID1 OTP_BASE + 0x6c 58*030cb4a7SJohnny Huang #define SEC_KEY_NUM OTP_BASE + 0x78 593d3688adSJohnny Huang 60696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 61696656c6SJohnny Huang #define CHECKSUM_LEN 32 62a219f6deSJohnny Huang #define OTP_INC_DATA BIT(31) 63a219f6deSJohnny Huang #define OTP_INC_CONFIG BIT(30) 64a219f6deSJohnny Huang #define OTP_INC_STRAP BIT(29) 65a219f6deSJohnny Huang #define OTP_ECC_EN BIT(28) 66696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 67696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 68696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 69696656c6SJohnny Huang 70e417205bSJohnny Huang #define OTP_A0 0 71e417205bSJohnny Huang #define OTP_A1 1 72e417205bSJohnny Huang #define OTP_A2 2 73e417205bSJohnny Huang #define OTP_A3 3 74e417205bSJohnny Huang 75e417205bSJohnny Huang #define ID0_AST2600A0 0x05000303 76e417205bSJohnny Huang #define ID1_AST2600A0 0x05000303 77e417205bSJohnny Huang #define ID0_AST2600A1 0x05010303 7821a8cfceSJohnny Huang #define ID1_AST2600A1 0x05010303 79e417205bSJohnny Huang #define ID0_AST2600A2 0x05010303 80e417205bSJohnny Huang #define ID1_AST2600A2 0x05020303 81e417205bSJohnny Huang #define ID0_AST2600A3 0x05030303 82e417205bSJohnny Huang #define ID1_AST2600A3 0x05030303 83e417205bSJohnny Huang #define ID0_AST2620A1 0x05010203 84e417205bSJohnny Huang #define ID1_AST2620A1 0x05010203 85e417205bSJohnny Huang #define ID0_AST2620A2 0x05010203 86e417205bSJohnny Huang #define ID1_AST2620A2 0x05020203 87e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 88e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 89e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 90e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 91e417205bSJohnny Huang #define ID0_AST2605A2 0x05010103 92e417205bSJohnny Huang #define ID1_AST2605A2 0x05020103 93e417205bSJohnny Huang #define ID0_AST2605A3 0x05030103 94e417205bSJohnny Huang #define ID1_AST2605A3 0x05030103 95e417205bSJohnny Huang #define ID0_AST2625A3 0x05030403 96e417205bSJohnny Huang #define ID1_AST2625A3 0x05030403 97696656c6SJohnny Huang 9861a6cda7SJohnny Huang #define SOC_AST2600A0 0 9961a6cda7SJohnny Huang #define SOC_AST2600A1 1 10061a6cda7SJohnny Huang #define SOC_AST2600A2 2 10161a6cda7SJohnny Huang #define SOC_AST2600A3 3 10261a6cda7SJohnny Huang 10361a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c)) 10461a6cda7SJohnny Huang 105696656c6SJohnny Huang struct otp_header { 106696656c6SJohnny Huang u8 otp_magic[8]; 10761a6cda7SJohnny Huang u32 soc_ver; 10861a6cda7SJohnny Huang u32 otptool_ver; 109696656c6SJohnny Huang u32 image_info; 110696656c6SJohnny Huang u32 data_info; 111696656c6SJohnny Huang u32 config_info; 112696656c6SJohnny Huang u32 strap_info; 1137e523e3bSJohnny Huang u32 scu_protect_info; 114696656c6SJohnny Huang u32 checksum_offset; 115a219f6deSJohnny Huang } __packed; 116696656c6SJohnny Huang 11766f2f8e5SJohnny Huang struct otpstrap_status { 11869d5fd8fSJohnny Huang int value; 11969d5fd8fSJohnny Huang int option_array[7]; 12069d5fd8fSJohnny Huang int remain_times; 12169d5fd8fSJohnny Huang int writeable_option; 12269d5fd8fSJohnny Huang int protected; 12369d5fd8fSJohnny Huang }; 12469d5fd8fSJohnny Huang 1259a4fe690SJohnny Huang struct otpkey_type { 1269a4fe690SJohnny Huang int value; 1279a4fe690SJohnny Huang int key_type; 1289a4fe690SJohnny Huang int need_id; 1299a4fe690SJohnny Huang char information[110]; 1309a4fe690SJohnny Huang }; 1319a4fe690SJohnny Huang 132*030cb4a7SJohnny Huang struct otp_pro_sts { 133*030cb4a7SJohnny Huang char mem_lock; 134*030cb4a7SJohnny Huang char pro_key_ret; 135*030cb4a7SJohnny Huang char pro_strap; 136*030cb4a7SJohnny Huang char pro_conf; 137*030cb4a7SJohnny Huang char pro_data; 138*030cb4a7SJohnny Huang char pro_sec; 139*030cb4a7SJohnny Huang u32 sec_size; 140*030cb4a7SJohnny Huang }; 141*030cb4a7SJohnny Huang 1429a4fe690SJohnny Huang struct otp_info_cb { 1439a4fe690SJohnny Huang int version; 144e417205bSJohnny Huang char ver_name[3]; 14579e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1469a4fe690SJohnny Huang int strap_info_len; 14779e42a59SJoel Stanley const struct otpconf_info *conf_info; 1489a4fe690SJohnny Huang int conf_info_len; 14979e42a59SJoel Stanley const struct otpkey_type *key_info; 1509a4fe690SJohnny Huang int key_info_len; 1510dc9a440SJohnny Huang const struct scu_info *scu_info; 1520dc9a440SJohnny Huang int scu_info_len; 153*030cb4a7SJohnny Huang struct otp_pro_sts pro_sts; 1549a4fe690SJohnny Huang }; 1559a4fe690SJohnny Huang 156696656c6SJohnny Huang struct otp_image_layout { 1575010032bSJohnny Huang int data_length; 1585010032bSJohnny Huang int conf_length; 1595010032bSJohnny Huang int strap_length; 160a219f6deSJohnny Huang u8 *data; 161a219f6deSJohnny Huang u8 *data_ignore; 162a219f6deSJohnny Huang u8 *conf; 163a219f6deSJohnny Huang u8 *conf_ignore; 164a219f6deSJohnny Huang u8 *strap; 165a219f6deSJohnny Huang u8 *strap_pro; 166a219f6deSJohnny Huang u8 *strap_ignore; 167696656c6SJohnny Huang }; 168696656c6SJohnny Huang 1699a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1709a4fe690SJohnny Huang 17179e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1729a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1739a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1749a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 175181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 176181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as SOC public key"}, 177181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 178181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as SOC private key"}, 179181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1809a4fe690SJohnny Huang }; 1819a4fe690SJohnny Huang 18279e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1839a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1849a4fe690SJohnny 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"}, 185181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 186181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 187181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1889a4fe690SJohnny Huang }; 1899a4fe690SJohnny Huang 1905fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1915fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1925fdde29fSJohnny 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"}, 193181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 194181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 195181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 196181f72d8SJohnny Huang }; 197181f72d8SJohnny Huang 198181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = { 199181f72d8SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 200181f72d8SJohnny 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"}, 201181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 202181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 203181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 204181f72d8SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key(big endian)"}, 205181f72d8SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 206181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key(big endian)"}, 2075fdde29fSJohnny Huang }; 2085fdde29fSJohnny Huang 209f347c284SJohnny Huang static void buf_print(u8 *buf, int len) 210f347c284SJohnny Huang { 211f347c284SJohnny Huang int i; 212f347c284SJohnny Huang 213f347c284SJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 214f347c284SJohnny Huang for (i = 0; i < len; i++) { 215f347c284SJohnny Huang if (i % 16 == 0) 216f347c284SJohnny Huang printf("%04X: ", i); 217f347c284SJohnny Huang printf("%02X ", buf[i]); 218f347c284SJohnny Huang if ((i + 1) % 16 == 0) 219f347c284SJohnny Huang printf("\n"); 220f347c284SJohnny Huang } 221f347c284SJohnny Huang } 222f347c284SJohnny Huang 223794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset) 224794e27ecSJohnny Huang { 225794e27ecSJohnny Huang int bit_offset; 226794e27ecSJohnny Huang int i; 227794e27ecSJohnny Huang 228794e27ecSJohnny Huang if (offset < 32) { 229794e27ecSJohnny Huang i = 0; 230794e27ecSJohnny Huang bit_offset = offset; 231794e27ecSJohnny Huang } else { 232794e27ecSJohnny Huang i = 1; 233794e27ecSJohnny Huang bit_offset = offset - 32; 234794e27ecSJohnny Huang } 235794e27ecSJohnny Huang if ((rid[i] >> bit_offset) & 0x1) 236794e27ecSJohnny Huang return 1; 237794e27ecSJohnny Huang else 238794e27ecSJohnny Huang return 0; 239794e27ecSJohnny Huang } 240794e27ecSJohnny Huang 241794e27ecSJohnny Huang static int get_rid_num(u32 *rid) 242794e27ecSJohnny Huang { 243794e27ecSJohnny Huang int i; 244794e27ecSJohnny Huang int fz = 0; 245794e27ecSJohnny Huang int rid_num = 0; 246794e27ecSJohnny Huang int ret = 0; 247794e27ecSJohnny Huang 248794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 249794e27ecSJohnny Huang if (get_dw_bit(rid, i) == 0) { 250794e27ecSJohnny Huang if (!fz) 251794e27ecSJohnny Huang fz = 1; 252794e27ecSJohnny Huang 253794e27ecSJohnny Huang } else { 254794e27ecSJohnny Huang rid_num++; 255794e27ecSJohnny Huang if (fz) 256794e27ecSJohnny Huang ret = OTP_FAILURE; 257794e27ecSJohnny Huang } 258794e27ecSJohnny Huang } 259794e27ecSJohnny Huang if (ret) 260794e27ecSJohnny Huang return ret; 261794e27ecSJohnny Huang 262794e27ecSJohnny Huang return rid_num; 263794e27ecSJohnny Huang } 264794e27ecSJohnny Huang 265a219f6deSJohnny Huang static u32 chip_version(void) 2669a4fe690SJohnny Huang { 267e417205bSJohnny Huang u32 revid0, revid1; 2689a4fe690SJohnny Huang 269e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0); 270e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1); 2719a4fe690SJohnny Huang 272e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { 273badd21c2SJohnny Huang /* AST2600-A0 */ 274e417205bSJohnny Huang return OTP_A0; 275e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { 276badd21c2SJohnny Huang /* AST2600-A1 */ 277e417205bSJohnny Huang return OTP_A1; 278e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { 279badd21c2SJohnny Huang /* AST2600-A2 */ 280e417205bSJohnny Huang return OTP_A2; 281e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { 28264b66712SJohnny Huang /* AST2600-A3 */ 283e417205bSJohnny Huang return OTP_A3; 284e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { 285e417205bSJohnny Huang /* AST2620-A1 */ 286e417205bSJohnny Huang return OTP_A1; 287e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { 288e417205bSJohnny Huang /* AST2620-A2 */ 289e417205bSJohnny Huang return OTP_A2; 290e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { 29164b66712SJohnny Huang /* AST2620-A3 */ 292e417205bSJohnny Huang return OTP_A3; 293e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { 294e417205bSJohnny Huang /* AST2605-A2 */ 295e417205bSJohnny Huang return OTP_A2; 296e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { 297e417205bSJohnny Huang /* AST2605-A3 */ 298e417205bSJohnny Huang return OTP_A3; 299e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { 300e417205bSJohnny Huang /* AST2605-A3 */ 301e417205bSJohnny Huang return OTP_A3; 3020dae9d52SJohnny Huang } 303f347c284SJohnny Huang return OTP_FAILURE; 3049a4fe690SJohnny Huang } 3059a4fe690SJohnny Huang 3063d3688adSJohnny Huang static void wait_complete(void) 3073d3688adSJohnny Huang { 3083d3688adSJohnny Huang int reg; 3093d3688adSJohnny Huang 3103d3688adSJohnny Huang do { 3113d3688adSJohnny Huang reg = readl(OTP_STATUS); 3123d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 3133d3688adSJohnny Huang } 3143d3688adSJohnny Huang 315a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 316dacbba92SJohnny Huang { 317dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 318dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 319dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 320dacbba92SJohnny Huang wait_complete(); 321dacbba92SJohnny Huang } 322dacbba92SJohnny Huang 323dacbba92SJohnny Huang static void otp_soak(int soak) 324dacbba92SJohnny Huang { 325e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) { 326dacbba92SJohnny Huang switch (soak) { 327dacbba92SJohnny Huang case 0: //default 328377f8cd7SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 329377f8cd7SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 330dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 331dacbba92SJohnny Huang break; 332dacbba92SJohnny Huang case 1: //normal program 333377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 334377f8cd7SJohnny Huang otp_write(0x5000, 0x1008); // Write MRB 335377f8cd7SJohnny Huang otp_write(0x1000, 0x0024); // Write MR 336feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 337dacbba92SJohnny Huang break; 338dacbba92SJohnny Huang case 2: //soak program 339377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 340377f8cd7SJohnny Huang otp_write(0x5000, 0x0007); // Write MRB 341377f8cd7SJohnny Huang otp_write(0x1000, 0x0100); // Write MR 342feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 343dacbba92SJohnny Huang break; 344dacbba92SJohnny Huang } 345dacbba92SJohnny Huang } else { 346dacbba92SJohnny Huang switch (soak) { 347dacbba92SJohnny Huang case 0: //default 348dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 349dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 350dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 351dacbba92SJohnny Huang break; 352dacbba92SJohnny Huang case 1: //normal program 353dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 354dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 355dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 356feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 357dacbba92SJohnny Huang break; 358dacbba92SJohnny Huang case 2: //soak program 359dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 360dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 361dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 362feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 363dacbba92SJohnny Huang break; 364dacbba92SJohnny Huang } 365dacbba92SJohnny Huang } 366dacbba92SJohnny Huang 367dacbba92SJohnny Huang wait_complete(); 368dacbba92SJohnny Huang } 369dacbba92SJohnny Huang 370a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 37169d5fd8fSJohnny Huang { 3723d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 3733d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3743d3688adSJohnny Huang wait_complete(); 3753d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 3763d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 37769d5fd8fSJohnny Huang } 37869d5fd8fSJohnny Huang 379f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data) 38069d5fd8fSJohnny Huang { 38169d5fd8fSJohnny Huang int config_offset; 38269d5fd8fSJohnny Huang 38369d5fd8fSJohnny Huang config_offset = 0x800; 38469d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 38569d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 38669d5fd8fSJohnny Huang 3873d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 3883d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3893d3688adSJohnny Huang wait_complete(); 3903d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 39169d5fd8fSJohnny Huang } 39269d5fd8fSJohnny Huang 393a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 39469d5fd8fSJohnny Huang { 395a219f6deSJohnny Huang u32 ret; 396a219f6deSJohnny Huang u32 *buf; 39769d5fd8fSJohnny Huang 39869d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 39969d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 40069d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 40169d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 40269d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 4033d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 4043d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 4053d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 4063d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 4073d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 4083d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 4093d3688adSJohnny Huang wait_complete(); 4103d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 41169d5fd8fSJohnny Huang if (ret & 0x1) 412f347c284SJohnny Huang return OTP_SUCCESS; 41369d5fd8fSJohnny Huang else 414f347c284SJohnny Huang return OTP_FAILURE; 41569d5fd8fSJohnny Huang } 41669d5fd8fSJohnny Huang 417a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 41869d5fd8fSJohnny Huang { 419a219f6deSJohnny Huang u32 ret[2]; 42069d5fd8fSJohnny Huang 42130a8c590SJohnny Huang if (otp_addr % 2 == 0) 4223d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 42330a8c590SJohnny Huang else 4243d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 42530a8c590SJohnny Huang 4263d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4273d3688adSJohnny Huang wait_complete(); 4283d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4293d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 43083655e91SJohnny Huang 43130a8c590SJohnny Huang if (otp_addr % 2 == 0) { 43230a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 433f347c284SJohnny Huang return OTP_SUCCESS; 43469d5fd8fSJohnny Huang else 435f347c284SJohnny Huang return OTP_FAILURE; 43630a8c590SJohnny Huang } else { 43730a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 438f347c284SJohnny Huang return OTP_SUCCESS; 43930a8c590SJohnny Huang else 440f347c284SJohnny Huang return OTP_FAILURE; 44130a8c590SJohnny Huang } 44269d5fd8fSJohnny Huang } 44369d5fd8fSJohnny Huang 444a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 4454c1c9b35SJohnny Huang { 446a219f6deSJohnny Huang u32 ret[2]; 4474c1c9b35SJohnny Huang 4484c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 4494c1c9b35SJohnny Huang 4504c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 4513d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 4524c1c9b35SJohnny Huang else 4533d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 4543d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4553d3688adSJohnny Huang wait_complete(); 4563d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4573d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 4584c1c9b35SJohnny Huang if (size == 1) { 4594c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 4604c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 461696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 4624c1c9b35SJohnny Huang compare[0] = 0; 463f347c284SJohnny Huang return OTP_SUCCESS; 464a219f6deSJohnny Huang } 4654c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 466f347c284SJohnny Huang return OTP_FAILURE; 4674c1c9b35SJohnny Huang 4684c1c9b35SJohnny Huang } else { 4694c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 470696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4714c1c9b35SJohnny Huang compare[0] = ~0; 472f347c284SJohnny Huang return OTP_SUCCESS; 473a219f6deSJohnny Huang } 474d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 475f347c284SJohnny Huang return OTP_FAILURE; 4764c1c9b35SJohnny Huang } 4774c1c9b35SJohnny Huang } else if (size == 2) { 4784c1c9b35SJohnny Huang // otp_addr should be even 479696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 4804c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4814c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4824c1c9b35SJohnny Huang compare[0] = 0; 4834c1c9b35SJohnny Huang compare[1] = ~0; 484f347c284SJohnny Huang return OTP_SUCCESS; 485a219f6deSJohnny Huang } 4864c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4874c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4884c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4894c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 490f347c284SJohnny Huang return OTP_FAILURE; 4914c1c9b35SJohnny Huang } else { 492f347c284SJohnny Huang return OTP_FAILURE; 4934c1c9b35SJohnny Huang } 4944c1c9b35SJohnny Huang } 4954c1c9b35SJohnny Huang 496a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit) 49783655e91SJohnny Huang { 49890965bb3SJohnny Huang otp_write(0x0, prog_bit); 49983655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 50083655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 50183655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 50283655e91SJohnny Huang wait_complete(); 50383655e91SJohnny Huang } 50483655e91SJohnny Huang 505a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 50683655e91SJohnny Huang { 50783655e91SJohnny Huang int prog_bit; 50883655e91SJohnny Huang 50983655e91SJohnny Huang if (prog_address % 2 == 0) { 51083655e91SJohnny Huang if (value) 51183655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 51283655e91SJohnny Huang else 51383655e91SJohnny Huang return; 51483655e91SJohnny Huang } else { 515e417205bSJohnny Huang if (info_cb.version != OTP_A3) 51683655e91SJohnny Huang prog_address |= 1 << 15; 51783655e91SJohnny Huang if (!value) 51883655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 51983655e91SJohnny Huang else 52083655e91SJohnny Huang return; 52183655e91SJohnny Huang } 52283655e91SJohnny Huang otp_prog(prog_address, prog_bit); 52383655e91SJohnny Huang } 52483655e91SJohnny Huang 525f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset) 52683655e91SJohnny Huang { 52783655e91SJohnny Huang int pass; 52883655e91SJohnny Huang int i; 52983655e91SJohnny Huang 53083655e91SJohnny Huang otp_soak(1); 53183655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 53283655e91SJohnny Huang pass = 0; 53383655e91SJohnny Huang 53483655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 53583655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 53683655e91SJohnny Huang otp_soak(2); 53783655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 53883655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 53983655e91SJohnny Huang otp_soak(1); 54083655e91SJohnny Huang } else { 54183655e91SJohnny Huang pass = 1; 54283655e91SJohnny Huang break; 54383655e91SJohnny Huang } 54483655e91SJohnny Huang } else { 54583655e91SJohnny Huang pass = 1; 54683655e91SJohnny Huang break; 54783655e91SJohnny Huang } 54883655e91SJohnny Huang } 549794e27ecSJohnny Huang if (pass) 550794e27ecSJohnny Huang return OTP_SUCCESS; 55183655e91SJohnny Huang 552794e27ecSJohnny Huang return OTP_FAILURE; 55383655e91SJohnny Huang } 55483655e91SJohnny Huang 555a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 556d90825e2SJohnny Huang { 557d90825e2SJohnny Huang int j, bit_value, prog_bit; 558d90825e2SJohnny Huang 559d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 560696656c6SJohnny Huang if ((ignore >> j) & 0x1) 561d90825e2SJohnny Huang continue; 562d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 563d90825e2SJohnny Huang if (prog_address % 2 == 0) { 564d90825e2SJohnny Huang if (bit_value) 565d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 566d90825e2SJohnny Huang else 567d90825e2SJohnny Huang continue; 568d90825e2SJohnny Huang } else { 569e417205bSJohnny Huang if (info_cb.version != OTP_A3) 570d90825e2SJohnny Huang prog_address |= 1 << 15; 571d90825e2SJohnny Huang if (bit_value) 572d90825e2SJohnny Huang continue; 573d90825e2SJohnny Huang else 574d90825e2SJohnny Huang prog_bit = 0x1 << j; 575d90825e2SJohnny Huang } 576d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 577d90825e2SJohnny Huang } 578d90825e2SJohnny Huang } 579d90825e2SJohnny Huang 580a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 58154552c69SJohnny Huang { 58254552c69SJohnny Huang int pass; 58354552c69SJohnny Huang int i; 584a219f6deSJohnny Huang u32 data0_masked; 585a219f6deSJohnny Huang u32 data1_masked; 586a219f6deSJohnny Huang u32 buf0_masked; 587a219f6deSJohnny Huang u32 buf1_masked; 588a219f6deSJohnny Huang u32 compare[2]; 58954552c69SJohnny Huang 59054552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 59154552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 59254552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 59354552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 594a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 595f347c284SJohnny Huang return OTP_SUCCESS; 59654552c69SJohnny Huang 59754552c69SJohnny Huang otp_soak(1); 59854552c69SJohnny Huang if (data0_masked != buf0_masked) 59954552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 60054552c69SJohnny Huang if (data1_masked != buf1_masked) 60154552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 60254552c69SJohnny Huang 60354552c69SJohnny Huang pass = 0; 60454552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 60554552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 60654552c69SJohnny Huang otp_soak(2); 607a219f6deSJohnny Huang if (compare[0] != 0) 60854552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 609a219f6deSJohnny Huang if (compare[1] != ~0) 6105537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 61154552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 61254552c69SJohnny Huang otp_soak(1); 61354552c69SJohnny Huang } else { 61454552c69SJohnny Huang pass = 1; 61554552c69SJohnny Huang break; 61654552c69SJohnny Huang } 61754552c69SJohnny Huang } else { 61854552c69SJohnny Huang pass = 1; 61954552c69SJohnny Huang break; 62054552c69SJohnny Huang } 62154552c69SJohnny Huang } 62254552c69SJohnny Huang 62354552c69SJohnny Huang if (!pass) { 62454552c69SJohnny Huang otp_soak(0); 62554552c69SJohnny Huang return OTP_FAILURE; 62654552c69SJohnny Huang } 62754552c69SJohnny Huang return OTP_SUCCESS; 62854552c69SJohnny Huang } 62954552c69SJohnny Huang 630541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 63176d13988SJohnny Huang { 632a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 6335010032bSJohnny Huang int strap_end; 63476d13988SJohnny Huang int i, j; 63576d13988SJohnny Huang 636e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 63776d13988SJohnny Huang for (j = 0; j < 64; j++) { 63876d13988SJohnny Huang otpstrap[j].value = 0; 63976d13988SJohnny Huang otpstrap[j].remain_times = 7; 64076d13988SJohnny Huang otpstrap[j].writeable_option = -1; 64176d13988SJohnny Huang otpstrap[j].protected = 0; 64276d13988SJohnny Huang } 6435010032bSJohnny Huang strap_end = 30; 6445010032bSJohnny Huang } else { 6455010032bSJohnny Huang for (j = 0; j < 64; j++) { 6465010032bSJohnny Huang otpstrap[j].value = 0; 6475010032bSJohnny Huang otpstrap[j].remain_times = 6; 6485010032bSJohnny Huang otpstrap[j].writeable_option = -1; 6495010032bSJohnny Huang otpstrap[j].protected = 0; 6505010032bSJohnny Huang } 6515010032bSJohnny Huang strap_end = 28; 6525010032bSJohnny Huang } 65376d13988SJohnny Huang 654dacbba92SJohnny Huang otp_soak(0); 6555010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 65676d13988SJohnny Huang int option = (i - 16) / 2; 657a219f6deSJohnny Huang 658f347c284SJohnny Huang otp_read_conf(i, &OTPSTRAP_RAW[0]); 659f347c284SJohnny Huang otp_read_conf(i + 1, &OTPSTRAP_RAW[1]); 66076d13988SJohnny Huang for (j = 0; j < 32; j++) { 66176d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 662a219f6deSJohnny Huang 663a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 66476d13988SJohnny Huang otpstrap[j].writeable_option = option; 66576d13988SJohnny Huang if (bit_value == 1) 66676d13988SJohnny Huang otpstrap[j].remain_times--; 66776d13988SJohnny Huang otpstrap[j].value ^= bit_value; 66876d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 66976d13988SJohnny Huang } 67076d13988SJohnny Huang for (j = 32; j < 64; j++) { 67176d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 672a219f6deSJohnny Huang 673a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 67476d13988SJohnny Huang otpstrap[j].writeable_option = option; 67576d13988SJohnny Huang if (bit_value == 1) 67676d13988SJohnny Huang otpstrap[j].remain_times--; 67776d13988SJohnny Huang otpstrap[j].value ^= bit_value; 67876d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 67976d13988SJohnny Huang } 68076d13988SJohnny Huang } 6815010032bSJohnny Huang 682f347c284SJohnny Huang otp_read_conf(30, &OTPSTRAP_RAW[0]); 683f347c284SJohnny Huang otp_read_conf(31, &OTPSTRAP_RAW[1]); 68476d13988SJohnny Huang for (j = 0; j < 32; j++) { 68576d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 68676d13988SJohnny Huang otpstrap[j].protected = 1; 68776d13988SJohnny Huang } 68876d13988SJohnny Huang for (j = 32; j < 64; j++) { 68976d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 69076d13988SJohnny Huang otpstrap[j].protected = 1; 69176d13988SJohnny Huang } 69276d13988SJohnny Huang } 69376d13988SJohnny Huang 6947e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit) 695f347c284SJohnny Huang { 696f347c284SJohnny Huang int prog_flag = 0; 697f347c284SJohnny Huang 698f347c284SJohnny Huang // ignore this bit 699f347c284SJohnny Huang if (ibit == 1) 700f347c284SJohnny Huang return OTP_SUCCESS; 701f347c284SJohnny Huang printf("OTPSTRAP[%X]:\n", offset); 702f347c284SJohnny Huang 703f347c284SJohnny Huang if (bit == otpstrap->value) { 7047e523e3bSJohnny Huang if (!pbit) { 705f347c284SJohnny Huang printf(" The value is same as before, skip it.\n"); 706f347c284SJohnny Huang return OTP_PROG_SKIP; 707f347c284SJohnny Huang } 708f347c284SJohnny Huang printf(" The value is same as before.\n"); 709f347c284SJohnny Huang } else { 710f347c284SJohnny Huang prog_flag = 1; 711f347c284SJohnny Huang } 712f347c284SJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 713f347c284SJohnny Huang printf(" This bit is protected and is not writable\n"); 714f347c284SJohnny Huang return OTP_FAILURE; 715f347c284SJohnny Huang } 716f347c284SJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 717f347c284SJohnny Huang printf(" This bit is no remaining times to write.\n"); 718f347c284SJohnny Huang return OTP_FAILURE; 719f347c284SJohnny Huang } 720f347c284SJohnny Huang if (pbit == 1) 721f347c284SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 722f347c284SJohnny Huang if (prog_flag) 723f347c284SJohnny 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); 724f347c284SJohnny Huang 725f347c284SJohnny Huang return OTP_SUCCESS; 726f347c284SJohnny Huang } 727f347c284SJohnny Huang 728f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value) 729f347c284SJohnny Huang { 730f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 731f347c284SJohnny Huang u32 prog_address; 732f347c284SJohnny Huang int offset; 733f347c284SJohnny Huang int ret; 734f347c284SJohnny Huang 735f347c284SJohnny Huang otp_strap_status(otpstrap); 736f347c284SJohnny Huang 7377e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 738f347c284SJohnny Huang 739f347c284SJohnny Huang if (ret != OTP_SUCCESS) 740f347c284SJohnny Huang return ret; 741f347c284SJohnny Huang 742f347c284SJohnny Huang prog_address = 0x800; 743f347c284SJohnny Huang if (bit_offset < 32) { 744f347c284SJohnny Huang offset = bit_offset; 745f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 746f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 747f347c284SJohnny Huang 748f347c284SJohnny Huang } else { 749f347c284SJohnny Huang offset = (bit_offset - 32); 750f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 751f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 752f347c284SJohnny Huang } 753f347c284SJohnny Huang 754f347c284SJohnny Huang return otp_prog_dc_b(1, prog_address, offset); 755f347c284SJohnny Huang } 756f347c284SJohnny Huang 757f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count) 758f347c284SJohnny Huang { 759f347c284SJohnny Huang int i; 760f347c284SJohnny Huang u32 ret[1]; 761f347c284SJohnny Huang 762f347c284SJohnny Huang if (offset + dw_count > 32) 763f347c284SJohnny Huang return OTP_USAGE; 764f347c284SJohnny Huang otp_soak(0); 765f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i++) { 766f347c284SJohnny Huang otp_read_conf(i, ret); 767f347c284SJohnny Huang printf("OTPCFG%X: %08X\n", i, ret[0]); 768f347c284SJohnny Huang } 769f347c284SJohnny Huang printf("\n"); 770f347c284SJohnny Huang return OTP_SUCCESS; 771f347c284SJohnny Huang } 772f347c284SJohnny Huang 773f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count) 774f347c284SJohnny Huang { 775f347c284SJohnny Huang int i; 776f347c284SJohnny Huang u32 ret[2]; 777f347c284SJohnny Huang 778f347c284SJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 779f347c284SJohnny Huang return OTP_USAGE; 780f347c284SJohnny Huang otp_soak(0); 781f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 782f347c284SJohnny Huang otp_read_data(i, ret); 783f347c284SJohnny Huang if (i % 4 == 0) 784f347c284SJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 785f347c284SJohnny Huang else 786f347c284SJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 787f347c284SJohnny Huang } 788f347c284SJohnny Huang printf("\n"); 789f347c284SJohnny Huang return OTP_SUCCESS; 790f347c284SJohnny Huang } 791f347c284SJohnny Huang 792f347c284SJohnny Huang static int otp_print_strap(int start, int count) 793f347c284SJohnny Huang { 794f347c284SJohnny Huang int i, j; 795f347c284SJohnny Huang int remains; 796f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 797f347c284SJohnny Huang 798f347c284SJohnny Huang if (start < 0 || start > 64) 799f347c284SJohnny Huang return OTP_USAGE; 800f347c284SJohnny Huang 801f347c284SJohnny Huang if ((start + count) < 0 || (start + count) > 64) 802f347c284SJohnny Huang return OTP_USAGE; 803f347c284SJohnny Huang 804f347c284SJohnny Huang otp_strap_status(otpstrap); 805f347c284SJohnny Huang 8067e523e3bSJohnny Huang if (info_cb.version == OTP_A0) 807f347c284SJohnny Huang remains = 7; 8087e523e3bSJohnny Huang else 809f347c284SJohnny Huang remains = 6; 8107e523e3bSJohnny Huang printf("BIT(hex) Value Option Status\n"); 811f347c284SJohnny Huang printf("______________________________________________________________________________\n"); 812f347c284SJohnny Huang 813f347c284SJohnny Huang for (i = start; i < start + count; i++) { 814f347c284SJohnny Huang printf("0x%-8X", i); 815f347c284SJohnny Huang printf("%-7d", otpstrap[i].value); 816f347c284SJohnny Huang for (j = 0; j < remains; j++) 817f347c284SJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 818f347c284SJohnny Huang printf(" "); 819f347c284SJohnny Huang if (otpstrap[i].protected == 1) { 820f347c284SJohnny Huang printf("protected and not writable"); 821f347c284SJohnny Huang } else { 822f347c284SJohnny Huang printf("not protected "); 823f347c284SJohnny Huang if (otpstrap[i].remain_times == 0) 824f347c284SJohnny Huang printf("and no remaining times to write."); 825f347c284SJohnny Huang else 826f347c284SJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 827f347c284SJohnny Huang } 828f347c284SJohnny Huang printf("\n"); 829f347c284SJohnny Huang } 830f347c284SJohnny Huang 831f347c284SJohnny Huang return OTP_SUCCESS; 832f347c284SJohnny Huang } 833f347c284SJohnny Huang 834794e27ecSJohnny Huang static void otp_print_revid(u32 *rid) 835794e27ecSJohnny Huang { 836794e27ecSJohnny Huang int bit_offset; 837794e27ecSJohnny Huang int i, j; 838794e27ecSJohnny Huang 839794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 840794e27ecSJohnny Huang printf("___________________________________________________\n"); 841794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 842794e27ecSJohnny Huang if (i < 32) { 843794e27ecSJohnny Huang j = 0; 844794e27ecSJohnny Huang bit_offset = i; 845794e27ecSJohnny Huang } else { 846794e27ecSJohnny Huang j = 1; 847794e27ecSJohnny Huang bit_offset = i - 32; 848794e27ecSJohnny Huang } 849794e27ecSJohnny Huang if (i % 16 == 0) 850794e27ecSJohnny Huang printf("%2x | ", i); 851794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1); 852794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 853794e27ecSJohnny Huang printf("\n"); 854794e27ecSJohnny Huang } 855794e27ecSJohnny Huang } 856794e27ecSJohnny Huang 8570dc9a440SJohnny Huang static void otp_print_scu_info(void) 8580dc9a440SJohnny Huang { 8590dc9a440SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 8600dc9a440SJohnny Huang u32 OTPCFG[2]; 8610dc9a440SJohnny Huang u32 scu_offset; 8620dc9a440SJohnny Huang u32 bit_offset; 8630dc9a440SJohnny Huang u32 reg_p; 8640dc9a440SJohnny Huang u32 length; 8650dc9a440SJohnny Huang int i, j; 8660dc9a440SJohnny Huang 8670dc9a440SJohnny Huang otp_soak(0); 8680dc9a440SJohnny Huang otp_read_conf(28, &OTPCFG[0]); 8690dc9a440SJohnny Huang otp_read_conf(29, &OTPCFG[1]); 8700dc9a440SJohnny Huang printf("SCU BIT reg_protect Description\n"); 8710dc9a440SJohnny Huang printf("____________________________________________________________________\n"); 8720dc9a440SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 8730dc9a440SJohnny Huang length = scu_info[i].length; 8740dc9a440SJohnny Huang for (j = 0; j < length; j++) { 8750dc9a440SJohnny Huang if (scu_info[i].bit_offset + j < 32) { 8760dc9a440SJohnny Huang scu_offset = 0x500; 8770dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j; 8780dc9a440SJohnny Huang reg_p = (OTPCFG[0] >> bit_offset) & 0x1; 8790dc9a440SJohnny Huang } else { 8800dc9a440SJohnny Huang scu_offset = 0x510; 8810dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j - 32; 8820dc9a440SJohnny Huang reg_p = (OTPCFG[1] >> bit_offset) & 0x1; 8830dc9a440SJohnny Huang } 8840dc9a440SJohnny Huang printf("0x%-6X", scu_offset); 8850dc9a440SJohnny Huang printf("0x%-4X", bit_offset); 8860dc9a440SJohnny Huang printf("0x%-13X", reg_p); 8870dc9a440SJohnny Huang if (length == 1) { 8880dc9a440SJohnny Huang printf(" %s\n", scu_info[i].information); 8890dc9a440SJohnny Huang continue; 8900dc9a440SJohnny Huang } 8910dc9a440SJohnny Huang 8920dc9a440SJohnny Huang if (j == 0) 8930dc9a440SJohnny Huang printf("/%s\n", scu_info[i].information); 8940dc9a440SJohnny Huang else if (j == length - 1) 8950dc9a440SJohnny Huang printf("\\ \"\n"); 8960dc9a440SJohnny Huang else 8970dc9a440SJohnny Huang printf("| \"\n"); 8980dc9a440SJohnny Huang } 8990dc9a440SJohnny Huang } 9000dc9a440SJohnny Huang } 9010dc9a440SJohnny Huang 902696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 90369d5fd8fSJohnny Huang { 90479e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 905a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 906a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 907a219f6deSJohnny Huang u32 mask; 908a219f6deSJohnny Huang u32 dw_offset; 909a219f6deSJohnny Huang u32 bit_offset; 910a219f6deSJohnny Huang u32 otp_value; 911a219f6deSJohnny Huang u32 otp_ignore; 912b458cd62SJohnny Huang int fail = 0; 9137adec5f6SJohnny Huang int mask_err; 914794e27ecSJohnny Huang int rid_num = 0; 91573f11549SJohnny Huang char valid_bit[20]; 916794e27ecSJohnny Huang int fz; 91766f2f8e5SJohnny Huang int i; 91873f11549SJohnny Huang int j; 91966f2f8e5SJohnny Huang 920737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 92166f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 9223cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 9237adec5f6SJohnny Huang mask_err = 0; 9243cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 9253cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 9263cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 927b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 928696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 929b458cd62SJohnny Huang 9307adec5f6SJohnny Huang if (conf_info[i].value == OTP_REG_VALID_BIT) { 9317adec5f6SJohnny Huang if (((otp_value + otp_ignore) & mask) != mask) { 932b458cd62SJohnny Huang fail = 1; 9337adec5f6SJohnny Huang mask_err = 1; 9347adec5f6SJohnny Huang } 9357adec5f6SJohnny Huang } else { 9367adec5f6SJohnny Huang if (otp_ignore == mask) { 9377adec5f6SJohnny Huang continue; 9387adec5f6SJohnny Huang } else if (otp_ignore != 0) { 9397adec5f6SJohnny Huang fail = 1; 9407adec5f6SJohnny Huang mask_err = 1; 9417adec5f6SJohnny Huang } 9427adec5f6SJohnny Huang } 943b458cd62SJohnny Huang 944a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 9453cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 9463cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 9473cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 948b458cd62SJohnny Huang continue; 949b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 950b458cd62SJohnny Huang 9513cb28812SJohnny Huang if (conf_info[i].length == 1) { 9523cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 95366f2f8e5SJohnny Huang } else { 954b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 9553cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 9563cb28812SJohnny Huang conf_info[i].bit_offset); 95766f2f8e5SJohnny Huang } 958b458cd62SJohnny Huang printf("0x%-10x", otp_value); 959b458cd62SJohnny Huang 9607adec5f6SJohnny Huang if (mask_err) { 9617adec5f6SJohnny Huang printf("Ignore, mask error\n"); 962a219f6deSJohnny Huang continue; 963a219f6deSJohnny Huang } 9643cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 965b458cd62SJohnny Huang printf("Reserved\n"); 9663cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 9673cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 968b458cd62SJohnny Huang printf("\n"); 9693cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 970b458cd62SJohnny Huang if (otp_value != 0) { 97173f11549SJohnny Huang for (j = 0; j < 7; j++) { 972a219f6deSJohnny Huang if (otp_value == (1 << j)) 97373f11549SJohnny Huang valid_bit[j * 2] = '1'; 974a219f6deSJohnny Huang else 97573f11549SJohnny Huang valid_bit[j * 2] = '0'; 97673f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 97773f11549SJohnny Huang } 97873f11549SJohnny Huang valid_bit[15] = 0; 97973f11549SJohnny Huang } else { 98073f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 981b458cd62SJohnny Huang } 9823cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 983b458cd62SJohnny Huang printf("\n"); 984b458cd62SJohnny Huang } else { 9853cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 986b458cd62SJohnny Huang } 987b458cd62SJohnny Huang } 988b458cd62SJohnny Huang 989794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) { 990794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) { 991794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 992794e27ecSJohnny Huang fail = 1; 993794e27ecSJohnny Huang } else { 994794e27ecSJohnny Huang fz = 0; 995794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 996794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) { 997794e27ecSJohnny Huang if (!fz) 998794e27ecSJohnny Huang fz = 1; 999794e27ecSJohnny Huang } else { 1000794e27ecSJohnny Huang rid_num++; 1001794e27ecSJohnny Huang if (fz) { 1002794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1003794e27ecSJohnny Huang fail = 1; 1004794e27ecSJohnny Huang break; 1005794e27ecSJohnny Huang } 1006794e27ecSJohnny Huang } 1007794e27ecSJohnny Huang } 1008794e27ecSJohnny Huang } 1009794e27ecSJohnny Huang if (fail) 1010794e27ecSJohnny Huang printf("OTP revision ID\n"); 1011794e27ecSJohnny Huang else 1012794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1013794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]); 1014794e27ecSJohnny Huang } 1015794e27ecSJohnny Huang 1016b458cd62SJohnny Huang if (fail) 1017b458cd62SJohnny Huang return OTP_FAILURE; 1018b458cd62SJohnny Huang 101966f2f8e5SJohnny Huang return OTP_SUCCESS; 102066f2f8e5SJohnny Huang } 102166f2f8e5SJohnny Huang 10222d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 102366f2f8e5SJohnny Huang { 102479e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1025a219f6deSJohnny Huang u32 OTPCFG[16]; 1026a219f6deSJohnny Huang u32 mask; 1027a219f6deSJohnny Huang u32 dw_offset; 1028a219f6deSJohnny Huang u32 bit_offset; 1029a219f6deSJohnny Huang u32 otp_value; 103073f11549SJohnny Huang char valid_bit[20]; 103166f2f8e5SJohnny Huang int i; 103273f11549SJohnny Huang int j; 103366f2f8e5SJohnny Huang 1034dacbba92SJohnny Huang otp_soak(0); 1035bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 1036f347c284SJohnny Huang otp_read_conf(i, &OTPCFG[i]); 103766f2f8e5SJohnny Huang 1038b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 1039b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 10403cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 10413cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 10422d4b0742SJohnny Huang continue; 10433cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 10443cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 10453cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1046b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1047b458cd62SJohnny Huang 1048a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 10493cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 10503cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 10513cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1052b458cd62SJohnny Huang continue; 1053b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1054b458cd62SJohnny Huang 10553cb28812SJohnny Huang if (conf_info[i].length == 1) { 10563cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 1057b458cd62SJohnny Huang } else { 1058b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 10593cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 10603cb28812SJohnny Huang conf_info[i].bit_offset); 1061b458cd62SJohnny Huang } 1062b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1063b458cd62SJohnny Huang 10643cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1065b458cd62SJohnny Huang printf("Reserved\n"); 10663cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 10673cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1068b458cd62SJohnny Huang printf("\n"); 10693cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1070b458cd62SJohnny Huang if (otp_value != 0) { 107173f11549SJohnny Huang for (j = 0; j < 7; j++) { 1072*030cb4a7SJohnny Huang if (otp_value & (1 << j)) 107373f11549SJohnny Huang valid_bit[j * 2] = '1'; 1074a219f6deSJohnny Huang else 107573f11549SJohnny Huang valid_bit[j * 2] = '0'; 107673f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 107773f11549SJohnny Huang } 107873f11549SJohnny Huang valid_bit[15] = 0; 107973f11549SJohnny Huang } else { 108073f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1081b458cd62SJohnny Huang } 10823cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1083b458cd62SJohnny Huang printf("\n"); 1084b458cd62SJohnny Huang } else { 10853cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1086b458cd62SJohnny Huang } 1087b458cd62SJohnny Huang } 1088b458cd62SJohnny Huang return OTP_SUCCESS; 108966f2f8e5SJohnny Huang } 109066f2f8e5SJohnny Huang 10915010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 109276d13988SJohnny Huang { 109379e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 1094a219f6deSJohnny Huang u32 *OTPSTRAP; 1095a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 1096a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 109776d13988SJohnny Huang int i; 1098a8bd6d8cSJohnny Huang int fail = 0; 1099a219f6deSJohnny Huang u32 bit_offset; 1100a219f6deSJohnny Huang u32 dw_offset; 1101a219f6deSJohnny Huang u32 mask; 1102a219f6deSJohnny Huang u32 otp_value; 1103a219f6deSJohnny Huang u32 otp_protect; 1104a219f6deSJohnny Huang u32 otp_ignore; 110576d13988SJohnny Huang 1106a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 1107a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 1108a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 11097e523e3bSJohnny Huang 1110a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 1111de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 1112b458cd62SJohnny Huang 11133cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 11147adec5f6SJohnny Huang fail = 0; 1115696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 1116a8bd6d8cSJohnny Huang dw_offset = 1; 11173cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 1118a8bd6d8cSJohnny Huang } else { 1119a8bd6d8cSJohnny Huang dw_offset = 0; 11203cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 1121a8bd6d8cSJohnny Huang } 112276d13988SJohnny Huang 11233cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 1124a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 1125a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 1126696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 1127a8bd6d8cSJohnny Huang 1128a219f6deSJohnny Huang if (otp_ignore == mask) 1129a8bd6d8cSJohnny Huang continue; 1130a219f6deSJohnny Huang else if (otp_ignore != 0) 1131a8bd6d8cSJohnny Huang fail = 1; 1132a8bd6d8cSJohnny Huang 1133a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 11343cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1135a8bd6d8cSJohnny Huang continue; 1136a8bd6d8cSJohnny Huang 11373cb28812SJohnny Huang if (strap_info[i].length == 1) { 11383cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1139a8bd6d8cSJohnny Huang } else { 1140b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 11413cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 11423cb28812SJohnny Huang strap_info[i].bit_offset); 1143a8bd6d8cSJohnny Huang } 1144a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 1145a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 1146a8bd6d8cSJohnny Huang 1147a8bd6d8cSJohnny Huang if (fail) { 1148696656c6SJohnny Huang printf("Ignore mask error\n"); 1149a8bd6d8cSJohnny Huang } else { 11503cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 11513cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1152a8bd6d8cSJohnny Huang else 1153a8bd6d8cSJohnny Huang printf("Reserved\n"); 1154a8bd6d8cSJohnny Huang } 1155a8bd6d8cSJohnny Huang } 1156a8bd6d8cSJohnny Huang 1157a8bd6d8cSJohnny Huang if (fail) 115876d13988SJohnny Huang return OTP_FAILURE; 115976d13988SJohnny Huang 116076d13988SJohnny Huang return OTP_SUCCESS; 116176d13988SJohnny Huang } 116276d13988SJohnny Huang 1163b458cd62SJohnny Huang static int otp_print_strap_info(int view) 116476d13988SJohnny Huang { 116579e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 116676d13988SJohnny Huang struct otpstrap_status strap_status[64]; 116707baa4e8SJohnny Huang int i, j; 1168b458cd62SJohnny Huang int fail = 0; 1169a219f6deSJohnny Huang u32 bit_offset; 1170a219f6deSJohnny Huang u32 length; 1171a219f6deSJohnny Huang u32 otp_value; 1172a219f6deSJohnny Huang u32 otp_protect; 117376d13988SJohnny Huang 1174541eb887SJohnny Huang otp_strap_status(strap_status); 117576d13988SJohnny Huang 1176b458cd62SJohnny Huang if (view) { 117707baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 117807baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 1179b458cd62SJohnny Huang } else { 1180b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 1181b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 118276d13988SJohnny Huang } 11833cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 1184b458cd62SJohnny Huang otp_value = 0; 11853cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 11863cb28812SJohnny Huang length = strap_info[i].length; 1187b458cd62SJohnny Huang for (j = 0; j < length; j++) { 1188c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 1189c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 1190b458cd62SJohnny Huang } 1191a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 11923cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1193b458cd62SJohnny Huang continue; 1194b458cd62SJohnny Huang if (view) { 1195b458cd62SJohnny Huang for (j = 0; j < length; j++) { 11963cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 1197b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 119807baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 1199e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 12003cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 1201b458cd62SJohnny Huang printf(" Reserved\n"); 1202b458cd62SJohnny Huang continue; 1203b458cd62SJohnny Huang } 1204b458cd62SJohnny Huang if (length == 1) { 12053cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 1206b458cd62SJohnny Huang continue; 120776d13988SJohnny Huang } 120876d13988SJohnny Huang 1209b458cd62SJohnny Huang if (j == 0) 12103cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 1211b458cd62SJohnny Huang else if (j == length - 1) 1212b458cd62SJohnny Huang printf("\\ \"\n"); 1213b458cd62SJohnny Huang else 1214b458cd62SJohnny Huang printf("| \"\n"); 121576d13988SJohnny Huang } 1216b458cd62SJohnny Huang } else { 1217c947ef08SJohnny Huang if (length == 1) { 12183cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1219b458cd62SJohnny Huang } else { 1220b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 1221b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 1222b458cd62SJohnny Huang } 1223b458cd62SJohnny Huang 1224b458cd62SJohnny Huang printf("0x%-10X", otp_value); 1225b458cd62SJohnny Huang 12263cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12273cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1228b458cd62SJohnny Huang else 1229b458cd62SJohnny Huang printf("Reserved\n"); 1230b458cd62SJohnny Huang } 1231b458cd62SJohnny Huang } 1232b458cd62SJohnny Huang 1233b458cd62SJohnny Huang if (fail) 1234b458cd62SJohnny Huang return OTP_FAILURE; 1235b458cd62SJohnny Huang 1236b458cd62SJohnny Huang return OTP_SUCCESS; 1237b458cd62SJohnny Huang } 1238b458cd62SJohnny Huang 1239f347c284SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 124069d5fd8fSJohnny Huang { 124169d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 124279e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 12439a4fe690SJohnny Huang struct otpkey_type key_info; 1244a219f6deSJohnny Huang u32 *buf; 1245a219f6deSJohnny Huang u8 *byte_buf; 12469d998018SJohnny Huang char empty = 1; 124769d5fd8fSJohnny Huang int i = 0, len = 0; 12489a4fe690SJohnny Huang int j; 124954552c69SJohnny Huang 1250696656c6SJohnny Huang byte_buf = image_layout->data; 1251a219f6deSJohnny Huang buf = (u32 *)byte_buf; 12529d998018SJohnny Huang 12539d998018SJohnny Huang for (i = 0; i < 16; i++) { 1254a219f6deSJohnny Huang if (buf[i] != 0) 12559d998018SJohnny Huang empty = 0; 12569d998018SJohnny Huang } 12579d998018SJohnny Huang if (empty) 1258f347c284SJohnny Huang return OTP_SUCCESS; 12599d998018SJohnny Huang 12609d998018SJohnny Huang i = 0; 126169d5fd8fSJohnny Huang while (1) { 126269d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 126369d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 126469d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 126569d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 126669d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 126769d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 12689a4fe690SJohnny Huang 12699a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 12709a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 12719a4fe690SJohnny Huang key_info = key_info_array[j]; 12729a4fe690SJohnny Huang break; 12739a4fe690SJohnny Huang } 12749a4fe690SJohnny Huang } 12759a4fe690SJohnny Huang 12767f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 127769d5fd8fSJohnny Huang printf("Key Type: "); 12789a4fe690SJohnny Huang printf("%s\n", key_info.information); 12799a4fe690SJohnny Huang 12809a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 128169d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 128269d5fd8fSJohnny Huang switch (key_length) { 128369d5fd8fSJohnny Huang case 0: 128469d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 128569d5fd8fSJohnny Huang break; 128669d5fd8fSJohnny Huang case 1: 128769d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 128869d5fd8fSJohnny Huang break; 128969d5fd8fSJohnny Huang case 2: 129069d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 129169d5fd8fSJohnny Huang break; 129269d5fd8fSJohnny Huang case 3: 129369d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 129469d5fd8fSJohnny Huang break; 129569d5fd8fSJohnny Huang } 1296181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1297181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 129869d5fd8fSJohnny Huang printf("RSA SHA Type: "); 129969d5fd8fSJohnny Huang switch (key_length) { 130069d5fd8fSJohnny Huang case 0: 130169d5fd8fSJohnny Huang printf("RSA1024\n"); 130269d5fd8fSJohnny Huang len = 0x100; 130369d5fd8fSJohnny Huang break; 130469d5fd8fSJohnny Huang case 1: 130569d5fd8fSJohnny Huang printf("RSA2048\n"); 130669d5fd8fSJohnny Huang len = 0x200; 130769d5fd8fSJohnny Huang break; 130869d5fd8fSJohnny Huang case 2: 130969d5fd8fSJohnny Huang printf("RSA3072\n"); 131069d5fd8fSJohnny Huang len = 0x300; 131169d5fd8fSJohnny Huang break; 131269d5fd8fSJohnny Huang case 3: 131369d5fd8fSJohnny Huang printf("RSA4096\n"); 131469d5fd8fSJohnny Huang len = 0x400; 131569d5fd8fSJohnny Huang break; 131669d5fd8fSJohnny Huang } 131769d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 131869d5fd8fSJohnny Huang } 13199a4fe690SJohnny Huang if (key_info.need_id) 132069d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 132169d5fd8fSJohnny Huang printf("Key Value:\n"); 13229a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 132369d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 13249a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 13259a4fe690SJohnny Huang printf("AES Key:\n"); 13269a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 1327e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 13289a4fe690SJohnny Huang printf("AES IV:\n"); 13299a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 13309a4fe690SJohnny Huang } 13319a4fe690SJohnny Huang 13329a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1333e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 133469d5fd8fSJohnny Huang printf("AES Key:\n"); 133569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 133669d5fd8fSJohnny Huang printf("AES IV:\n"); 133769d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 13385fdde29fSJohnny Huang } else { 13399a4fe690SJohnny Huang printf("AES Key 1:\n"); 13409a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 13419a4fe690SJohnny Huang printf("AES Key 2:\n"); 13429a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 13439a4fe690SJohnny Huang } 1344181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 134569d5fd8fSJohnny Huang printf("RSA mod:\n"); 134669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 134769d5fd8fSJohnny Huang printf("RSA exp:\n"); 134869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1349181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1350181f72d8SJohnny Huang printf("RSA mod:\n"); 1351181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1352181f72d8SJohnny Huang printf("RSA exp:\n"); 1353a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 135469d5fd8fSJohnny Huang } 135569d5fd8fSJohnny Huang if (last) 135669d5fd8fSJohnny Huang break; 135769d5fd8fSJohnny Huang i++; 135869d5fd8fSJohnny Huang } 1359f347c284SJohnny Huang return OTP_SUCCESS; 1360f347c284SJohnny Huang } 1361f347c284SJohnny Huang 1362f347c284SJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout) 1363f347c284SJohnny Huang { 1364f347c284SJohnny Huang int i; 1365f347c284SJohnny Huang u32 *strap; 1366f347c284SJohnny Huang u32 *strap_ignore; 1367f347c284SJohnny Huang u32 *strap_pro; 13687e523e3bSJohnny Huang int bit, pbit, ibit; 1369f347c284SJohnny Huang int fail = 0; 1370f347c284SJohnny Huang int ret; 1371f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 1372f347c284SJohnny Huang 1373f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1374f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1375f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1376f347c284SJohnny Huang 1377f347c284SJohnny Huang otp_strap_status(otpstrap); 1378f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1379f347c284SJohnny Huang if (i < 32) { 1380f347c284SJohnny Huang bit = (strap[0] >> i) & 0x1; 1381f347c284SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1382f347c284SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1383f347c284SJohnny Huang } else { 1384f347c284SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1385f347c284SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1386f347c284SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1387f347c284SJohnny Huang } 1388f347c284SJohnny Huang 13897e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1390f347c284SJohnny Huang 1391f347c284SJohnny Huang if (ret == OTP_FAILURE) 1392f347c284SJohnny Huang fail = 1; 1393f347c284SJohnny Huang } 1394f347c284SJohnny Huang if (fail == 1) 1395f347c284SJohnny Huang return OTP_FAILURE; 1396f347c284SJohnny Huang else 1397f347c284SJohnny Huang return OTP_SUCCESS; 1398f347c284SJohnny Huang } 1399f347c284SJohnny Huang 1400f347c284SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout) 1401f347c284SJohnny Huang { 1402f347c284SJohnny Huang int i; 1403f347c284SJohnny Huang int ret; 1404f347c284SJohnny Huang int data_dw; 1405f347c284SJohnny Huang u32 data[2048]; 1406f347c284SJohnny Huang u32 *buf; 1407f347c284SJohnny Huang u32 *buf_ignore; 1408f347c284SJohnny Huang u32 data_masked; 1409f347c284SJohnny Huang u32 buf_masked; 1410f347c284SJohnny Huang 1411f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1412f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1413f347c284SJohnny Huang 1414f347c284SJohnny Huang data_dw = image_layout->data_length / 4; 1415f347c284SJohnny Huang 1416f347c284SJohnny Huang printf("Read OTP Data:\n"); 1417f347c284SJohnny Huang 1418f347c284SJohnny Huang for (i = 0; i < data_dw - 2 ; i += 2) 1419f347c284SJohnny Huang otp_read_data(i, &data[i]); 1420f347c284SJohnny Huang 1421f347c284SJohnny Huang printf("Check writable...\n"); 1422f347c284SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1423f347c284SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1424f347c284SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1425f347c284SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1426f347c284SJohnny Huang if (data_masked == buf_masked) 1427f347c284SJohnny Huang continue; 1428f347c284SJohnny Huang if (i % 2 == 0) { 1429f347c284SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1430f347c284SJohnny Huang continue; 1431f347c284SJohnny Huang } else { 1432f347c284SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1433f347c284SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1434f347c284SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1435f347c284SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 1436f347c284SJohnny Huang return OTP_FAILURE; 1437f347c284SJohnny Huang } 1438f347c284SJohnny Huang } else { 1439f347c284SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1440f347c284SJohnny Huang continue; 1441f347c284SJohnny Huang } else { 1442f347c284SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1443f347c284SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1444f347c284SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1445f347c284SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 1446f347c284SJohnny Huang return OTP_FAILURE; 1447f347c284SJohnny Huang } 1448f347c284SJohnny Huang } 1449f347c284SJohnny Huang } 1450f347c284SJohnny Huang 1451f347c284SJohnny Huang printf("Start Programing...\n"); 1452f347c284SJohnny Huang 1453f347c284SJohnny Huang // programing ecc region first 1454f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1455f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1456f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1457f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1458f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1459f347c284SJohnny Huang return ret; 1460f347c284SJohnny Huang } 1461f347c284SJohnny Huang } 1462f347c284SJohnny Huang 1463f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1464f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1465f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1466f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1467f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1468f347c284SJohnny Huang return ret; 1469f347c284SJohnny Huang } 1470f347c284SJohnny Huang } 1471f347c284SJohnny Huang otp_soak(0); 1472f347c284SJohnny Huang return OTP_SUCCESS; 1473f347c284SJohnny Huang } 1474f347c284SJohnny Huang 1475f347c284SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout) 1476f347c284SJohnny Huang { 1477f347c284SJohnny Huang u32 *strap; 1478f347c284SJohnny Huang u32 *strap_ignore; 1479f347c284SJohnny Huang u32 *strap_pro; 1480f347c284SJohnny Huang u32 prog_address; 1481f347c284SJohnny Huang int i; 14827e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1483f347c284SJohnny Huang int fail = 0; 1484f347c284SJohnny Huang int ret; 1485f347c284SJohnny Huang int prog_flag = 0; 1486f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 1487f347c284SJohnny Huang 1488f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1489f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1490f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1491f347c284SJohnny Huang 1492f347c284SJohnny Huang printf("Read OTP Strap Region:\n"); 1493f347c284SJohnny Huang otp_strap_status(otpstrap); 1494f347c284SJohnny Huang 1495f347c284SJohnny Huang printf("Check writable...\n"); 1496f347c284SJohnny Huang if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) { 1497f347c284SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1498f347c284SJohnny Huang return OTP_FAILURE; 1499f347c284SJohnny Huang } 1500f347c284SJohnny Huang 1501f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1502f347c284SJohnny Huang prog_address = 0x800; 1503f347c284SJohnny Huang if (i < 32) { 1504f347c284SJohnny Huang offset = i; 1505f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1506f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1507f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1508f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1509f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1510f347c284SJohnny Huang 1511f347c284SJohnny Huang } else { 1512f347c284SJohnny Huang offset = (i - 32); 1513f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1514f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1515f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1516f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1517f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1518f347c284SJohnny Huang } 1519f347c284SJohnny Huang 1520f347c284SJohnny Huang if (ibit == 1) 1521f347c284SJohnny Huang continue; 1522f347c284SJohnny Huang if (bit == otpstrap[i].value) 1523f347c284SJohnny Huang prog_flag = 0; 1524f347c284SJohnny Huang else 1525f347c284SJohnny Huang prog_flag = 1; 1526f347c284SJohnny Huang 1527f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1528f347c284SJohnny Huang fail = 1; 1529f347c284SJohnny Huang continue; 1530f347c284SJohnny Huang } 1531f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1532f347c284SJohnny Huang fail = 1; 1533f347c284SJohnny Huang continue; 1534f347c284SJohnny Huang } 1535f347c284SJohnny Huang 1536f347c284SJohnny Huang if (prog_flag) { 1537f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1538f347c284SJohnny Huang if (ret) 1539f347c284SJohnny Huang return OTP_FAILURE; 1540f347c284SJohnny Huang } 1541f347c284SJohnny Huang 1542f347c284SJohnny Huang if (pbit != 0) { 1543f347c284SJohnny Huang prog_address = 0x800; 1544f347c284SJohnny Huang if (i < 32) 1545f347c284SJohnny Huang prog_address |= 0x60c; 1546f347c284SJohnny Huang else 1547f347c284SJohnny Huang prog_address |= 0x60e; 1548f347c284SJohnny Huang 1549f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1550f347c284SJohnny Huang if (ret) 1551f347c284SJohnny Huang return OTP_FAILURE; 1552f347c284SJohnny Huang } 1553f347c284SJohnny Huang } 1554f347c284SJohnny Huang otp_soak(0); 1555f347c284SJohnny Huang if (fail == 1) 1556f347c284SJohnny Huang return OTP_FAILURE; 1557f347c284SJohnny Huang return OTP_SUCCESS; 155869d5fd8fSJohnny Huang } 155969d5fd8fSJohnny Huang 15605010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout) 156169d5fd8fSJohnny Huang { 1562a6d0d645SJohnny Huang int i, k; 1563d90825e2SJohnny Huang int pass = 0; 1564a219f6deSJohnny Huang u32 prog_address; 1565a219f6deSJohnny Huang u32 data[16]; 1566a219f6deSJohnny Huang u32 compare[2]; 1567a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1568a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1569a219f6deSJohnny Huang u32 data_masked; 1570a219f6deSJohnny Huang u32 buf_masked; 157169d5fd8fSJohnny Huang 1572a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 1573a6d0d645SJohnny Huang 1574bb34a7bfSJohnny Huang for (i = 0; i < 16 ; i++) { 157569d5fd8fSJohnny Huang prog_address = 0x800; 1576a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1577a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1578a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 1579a6d0d645SJohnny Huang } 1580a6d0d645SJohnny Huang 1581a6d0d645SJohnny Huang printf("Check writable...\n"); 1582bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 15835010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 15845010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1585d90825e2SJohnny Huang if (data_masked == buf_masked) 158669d5fd8fSJohnny Huang continue; 1587d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1588a6d0d645SJohnny Huang continue; 1589a6d0d645SJohnny Huang } else { 1590a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1591a6af4a17SJohnny Huang printf("OTPCFG[%X] = %x\n", i, data[i]); 15925010032bSJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 15935010032bSJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 15942a856b9aSJohnny Huang return OTP_FAILURE; 1595a6d0d645SJohnny Huang } 1596a6d0d645SJohnny Huang } 1597a6d0d645SJohnny Huang 1598a6d0d645SJohnny Huang printf("Start Programing...\n"); 1599d90825e2SJohnny Huang otp_soak(0); 1600bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 16015010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 16025010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1603a6d0d645SJohnny Huang prog_address = 0x800; 1604a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1605a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1606bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1607bb34a7bfSJohnny Huang pass = 1; 1608a6d0d645SJohnny Huang continue; 1609bb34a7bfSJohnny Huang } 1610de6fbf1cSJohnny Huang 1611de6fbf1cSJohnny Huang otp_soak(1); 16125010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1613a6d0d645SJohnny Huang 161469d5fd8fSJohnny Huang pass = 0; 161569d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 16165010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1617de6fbf1cSJohnny Huang otp_soak(2); 1618feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 16195010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1620de6fbf1cSJohnny Huang otp_soak(1); 1621de6fbf1cSJohnny Huang } else { 1622de6fbf1cSJohnny Huang pass = 1; 1623de6fbf1cSJohnny Huang break; 1624de6fbf1cSJohnny Huang } 1625a6d0d645SJohnny Huang } else { 162669d5fd8fSJohnny Huang pass = 1; 162769d5fd8fSJohnny Huang break; 162869d5fd8fSJohnny Huang } 162969d5fd8fSJohnny Huang } 1630bb34a7bfSJohnny Huang if (pass == 0) { 1631bb34a7bfSJohnny Huang printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n", 16325010032bSJohnny Huang i, data[i], conf[i], conf_ignore[i]); 1633bb34a7bfSJohnny Huang break; 1634bb34a7bfSJohnny Huang } 1635a6d0d645SJohnny Huang } 1636a6d0d645SJohnny Huang 1637de6fbf1cSJohnny Huang otp_soak(0); 163869d5fd8fSJohnny Huang if (!pass) 16392a856b9aSJohnny Huang return OTP_FAILURE; 1640a6d0d645SJohnny Huang 16412a856b9aSJohnny Huang return OTP_SUCCESS; 164269d5fd8fSJohnny Huang } 164369d5fd8fSJohnny Huang 1644f347c284SJohnny Huang static int otp_verify_image(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)) 1654f347c284SJohnny Huang return OTP_SUCCESS; 1655f347c284SJohnny Huang return OTP_FAILURE; 1656696656c6SJohnny Huang } 1657696656c6SJohnny Huang 1658f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 165969d5fd8fSJohnny Huang { 166069d5fd8fSJohnny Huang int ret; 166161a6cda7SJohnny Huang int image_soc_ver = 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) { 1670*030cb4a7SJohnny Huang printf("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) { 1680*030cb4a7SJohnny Huang printf("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) { 1687*030cb4a7SJohnny Huang printf("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); 17005010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 17015010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 17025010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 17037e523e3bSJohnny Huang 17047e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 17057e523e3bSJohnny Huang image_soc_ver = OTP_A0; 170661a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 170761a6cda7SJohnny Huang image_soc_ver = OTP_A1; 170861a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 170961a6cda7SJohnny Huang image_soc_ver = OTP_A2; 171061a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 171161a6cda7SJohnny Huang image_soc_ver = OTP_A3; 1712696656c6SJohnny Huang } else { 1713*030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n"); 1714696656c6SJohnny Huang return OTP_FAILURE; 1715696656c6SJohnny Huang } 1716696656c6SJohnny Huang 171761a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 1718*030cb4a7SJohnny Huang printf("Version is not match\n"); 17199a4fe690SJohnny Huang return OTP_FAILURE; 17209a4fe690SJohnny Huang } 17219a4fe690SJohnny Huang 172261a6cda7SJohnny Huang if (otp_header->otptool_ver != OTPTOOL_VERSION(1, 0, 0)) { 1723*030cb4a7SJohnny Huang printf("OTP image is not generated by otptool v1.0.0\n"); 172461a6cda7SJohnny Huang return OTP_FAILURE; 172561a6cda7SJohnny Huang } 172661a6cda7SJohnny Huang 1727f347c284SJohnny Huang if (otp_verify_image(buf, image_size, checksum)) { 1728*030cb4a7SJohnny Huang printf("checksum is invalid\n"); 1729696656c6SJohnny Huang return OTP_FAILURE; 1730d90825e2SJohnny Huang } 17317332532cSJohnny Huang 1732*030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 1733*030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 1734*030cb4a7SJohnny Huang return OTP_FAILURE; 1735*030cb4a7SJohnny Huang } 1736*030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 1737*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 1738*030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 1739*030cb4a7SJohnny Huang ret = -1; 1740*030cb4a7SJohnny Huang } 1741*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 1742*030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 1743*030cb4a7SJohnny Huang ret = -1; 1744*030cb4a7SJohnny Huang } 1745*030cb4a7SJohnny Huang } 1746*030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 1747*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 1748*030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 1749*030cb4a7SJohnny Huang ret = -1; 1750*030cb4a7SJohnny Huang } 1751*030cb4a7SJohnny Huang } 1752*030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 1753*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 1754*030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 1755*030cb4a7SJohnny Huang ret = -1; 1756*030cb4a7SJohnny Huang } 1757*030cb4a7SJohnny Huang } 1758*030cb4a7SJohnny Huang if (ret == -1) 1759*030cb4a7SJohnny Huang return OTP_FAILURE; 176069d5fd8fSJohnny Huang if (!nconfirm) { 1761696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 17627f795e57SJohnny Huang printf("\nOTP data region :\n"); 1763f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 176469d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 17652a856b9aSJohnny Huang return OTP_FAILURE; 176669d5fd8fSJohnny Huang } 176769d5fd8fSJohnny Huang } 1768696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 17697332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1770696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 17717332532cSJohnny Huang printf("OTP config error, please check.\n"); 17727332532cSJohnny Huang return OTP_FAILURE; 17737332532cSJohnny Huang } 17747332532cSJohnny Huang } 17757adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 17767adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 17777adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 17787adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 17797adec5f6SJohnny Huang return OTP_FAILURE; 17807adec5f6SJohnny Huang } 17817adec5f6SJohnny Huang } 17827332532cSJohnny Huang 178369d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 178469d5fd8fSJohnny Huang if (!confirm_yesno()) { 178569d5fd8fSJohnny Huang printf(" Aborting\n"); 17862a856b9aSJohnny Huang return OTP_FAILURE; 178769d5fd8fSJohnny Huang } 178869d5fd8fSJohnny Huang } 17897332532cSJohnny Huang 17905010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 17915010032bSJohnny Huang printf("programing data region ...\n"); 17925010032bSJohnny Huang ret = otp_prog_data(&image_layout); 17935010032bSJohnny Huang if (ret != 0) { 17945010032bSJohnny Huang printf("Error\n"); 17955010032bSJohnny Huang return ret; 17965010032bSJohnny Huang } 1797a219f6deSJohnny Huang printf("Done\n"); 17985010032bSJohnny Huang } 17995010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 18005010032bSJohnny Huang printf("programing strap region ...\n"); 18015010032bSJohnny Huang ret = otp_prog_strap(&image_layout); 18025010032bSJohnny Huang if (ret != 0) { 18035010032bSJohnny Huang printf("Error\n"); 18045010032bSJohnny Huang return ret; 18055010032bSJohnny Huang } 1806a219f6deSJohnny Huang printf("Done\n"); 18075010032bSJohnny Huang } 18085010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 18095010032bSJohnny Huang printf("programing configuration region ...\n"); 18105010032bSJohnny Huang ret = otp_prog_conf(&image_layout); 18115010032bSJohnny Huang if (ret != 0) { 18125010032bSJohnny Huang printf("Error\n"); 18135010032bSJohnny Huang return ret; 18145010032bSJohnny Huang } 18155010032bSJohnny Huang printf("Done\n"); 18165010032bSJohnny Huang } 1817cd1610b4SJohnny Huang 18187332532cSJohnny Huang return OTP_SUCCESS; 18192a856b9aSJohnny Huang } 18202a856b9aSJohnny Huang 1821f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1822cd1610b4SJohnny Huang { 1823a219f6deSJohnny Huang u32 read[2]; 1824a219f6deSJohnny Huang u32 prog_address = 0; 182566f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 1826cd1610b4SJohnny Huang int otp_bit; 182783655e91SJohnny Huang int ret = 0; 1828cd1610b4SJohnny Huang 1829dacbba92SJohnny Huang otp_soak(0); 1830cd1610b4SJohnny Huang switch (mode) { 1831a6d0d645SJohnny Huang case OTP_REGION_CONF: 1832f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 1833cd1610b4SJohnny Huang prog_address = 0x800; 1834cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1835cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1836a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1837cd1610b4SJohnny Huang if (otp_bit == value) { 1838a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1839cd1610b4SJohnny Huang printf("No need to program\n"); 18402a856b9aSJohnny Huang return OTP_SUCCESS; 1841cd1610b4SJohnny Huang } 1842cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1843a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset); 18440dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 18452a856b9aSJohnny Huang return OTP_FAILURE; 1846cd1610b4SJohnny Huang } 1847a6af4a17SJohnny Huang printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset); 1848cd1610b4SJohnny Huang break; 1849a6d0d645SJohnny Huang case OTP_REGION_DATA: 1850cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1851cd1610b4SJohnny Huang 1852cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1853a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 1854a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1855643b9cfdSJohnny Huang 1856643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 1857643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 18580dc9a440SJohnny Huang printf("OTP is programmed, which can't be cleaned\n"); 1859643b9cfdSJohnny Huang return OTP_FAILURE; 1860643b9cfdSJohnny Huang } 1861cd1610b4SJohnny Huang } else { 1862a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 1863a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 1864643b9cfdSJohnny Huang 1865643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 1866643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 18670dc9a440SJohnny Huang printf("OTP is programmed, which can't be writen\n"); 1868643b9cfdSJohnny Huang return OTP_FAILURE; 1869643b9cfdSJohnny Huang } 1870cd1610b4SJohnny Huang } 1871cd1610b4SJohnny Huang if (otp_bit == value) { 1872a6af4a17SJohnny Huang printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1873cd1610b4SJohnny Huang printf("No need to program\n"); 18742a856b9aSJohnny Huang return OTP_SUCCESS; 1875cd1610b4SJohnny Huang } 1876643b9cfdSJohnny Huang 1877a6af4a17SJohnny Huang printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset); 1878cd1610b4SJohnny Huang break; 1879a6d0d645SJohnny Huang case OTP_REGION_STRAP: 18808848d5dcSJohnny Huang otp_strap_status(otpstrap); 18818848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 18827e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 18838848d5dcSJohnny Huang if (ret == OTP_FAILURE) 18848848d5dcSJohnny Huang return OTP_FAILURE; 18858848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 18868848d5dcSJohnny Huang return OTP_SUCCESS; 1887a6af4a17SJohnny Huang 1888cd1610b4SJohnny Huang break; 1889cd1610b4SJohnny Huang } 1890cd1610b4SJohnny Huang 1891cd1610b4SJohnny Huang if (!nconfirm) { 1892cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1893cd1610b4SJohnny Huang if (!confirm_yesno()) { 1894cd1610b4SJohnny Huang printf(" Aborting\n"); 18952a856b9aSJohnny Huang return OTP_FAILURE; 1896cd1610b4SJohnny Huang } 1897cd1610b4SJohnny Huang } 1898cd1610b4SJohnny Huang 1899cd1610b4SJohnny Huang switch (mode) { 1900a6d0d645SJohnny Huang case OTP_REGION_STRAP: 1901f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 190283655e91SJohnny Huang break; 1903a6d0d645SJohnny Huang case OTP_REGION_CONF: 1904a6d0d645SJohnny Huang case OTP_REGION_DATA: 1905f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 1906de6fbf1cSJohnny Huang break; 1907de6fbf1cSJohnny Huang } 1908de6fbf1cSJohnny Huang otp_soak(0); 190983655e91SJohnny Huang if (ret) { 19100dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 1911794e27ecSJohnny Huang printf("FAILURE\n"); 1912794e27ecSJohnny Huang return OTP_FAILURE; 1913794e27ecSJohnny Huang } 1914794e27ecSJohnny Huang 19159009c25dSJohnny Huang printf("SUCCESS\n"); 19162a856b9aSJohnny Huang return OTP_SUCCESS; 1917a219f6deSJohnny Huang } 1918a219f6deSJohnny Huang 1919794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 1920794e27ecSJohnny Huang { 1921794e27ecSJohnny Huang u32 otp_rid[2]; 1922a8789b47SJohnny Huang u32 sw_rid[2]; 1923794e27ecSJohnny Huang int rid_num = 0; 1924a8789b47SJohnny Huang int sw_rid_num = 0; 1925794e27ecSJohnny Huang int bit_offset; 1926794e27ecSJohnny Huang int dw_offset; 1927794e27ecSJohnny Huang int i; 1928794e27ecSJohnny Huang int ret; 1929794e27ecSJohnny Huang 1930f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 1931f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 1932794e27ecSJohnny Huang 1933a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 1934a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 1935a8789b47SJohnny Huang 1936794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 1937a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 1938a8789b47SJohnny Huang 1939a8789b47SJohnny Huang if (sw_rid_num < 0) { 1940a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 1941a8789b47SJohnny Huang return OTP_FAILURE; 1942a8789b47SJohnny Huang } 1943a8789b47SJohnny Huang 1944a8789b47SJohnny Huang if (update_num > sw_rid_num) { 1945a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 1946a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 1947a8789b47SJohnny Huang return OTP_FAILURE; 1948a8789b47SJohnny Huang } 1949794e27ecSJohnny Huang 1950794e27ecSJohnny Huang if (rid_num < 0) { 1951794e27ecSJohnny Huang printf("Currennt OTP revision ID cannot handle by this command,\n" 1952794e27ecSJohnny Huang "plase use 'otp pb' command to update it manually\n"); 1953794e27ecSJohnny Huang otp_print_revid(otp_rid); 19549009c25dSJohnny Huang return OTP_FAILURE; 19559009c25dSJohnny Huang } 1956cd1610b4SJohnny Huang 1957794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 1958794e27ecSJohnny Huang otp_print_revid(otp_rid); 1959794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 1960794e27ecSJohnny Huang 1961a8789b47SJohnny Huang if (rid_num > update_num) { 1962a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 1963a8789b47SJohnny Huang printf("Skip\n"); 1964a8789b47SJohnny Huang return OTP_FAILURE; 1965a8789b47SJohnny Huang } else if (rid_num == update_num) { 1966a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 1967794e27ecSJohnny Huang printf("Skip\n"); 1968794e27ecSJohnny Huang return OTP_FAILURE; 1969794e27ecSJohnny Huang } 1970794e27ecSJohnny Huang 1971794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 1972794e27ecSJohnny Huang if (i < 32) { 1973794e27ecSJohnny Huang dw_offset = 0xa; 1974794e27ecSJohnny Huang bit_offset = i; 1975794e27ecSJohnny Huang } else { 1976794e27ecSJohnny Huang dw_offset = 0xb; 1977794e27ecSJohnny Huang bit_offset = i - 32; 1978794e27ecSJohnny Huang } 19790dc9a440SJohnny Huang printf("OTPCFG%X[%X]", dw_offset, bit_offset); 1980794e27ecSJohnny Huang if (i + 1 != update_num) 1981794e27ecSJohnny Huang printf(", "); 1982794e27ecSJohnny Huang } 1983794e27ecSJohnny Huang 1984794e27ecSJohnny Huang printf(" will be programmed\n"); 1985794e27ecSJohnny Huang if (force == 0) { 1986794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1987794e27ecSJohnny Huang if (!confirm_yesno()) { 1988794e27ecSJohnny Huang printf(" Aborting\n"); 1989794e27ecSJohnny Huang return OTP_FAILURE; 1990794e27ecSJohnny Huang } 1991794e27ecSJohnny Huang } 1992794e27ecSJohnny Huang 1993794e27ecSJohnny Huang ret = 0; 1994794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 1995794e27ecSJohnny Huang if (i < 32) { 1996794e27ecSJohnny Huang dw_offset = 0xa04; 1997794e27ecSJohnny Huang bit_offset = i; 1998794e27ecSJohnny Huang } else { 1999794e27ecSJohnny Huang dw_offset = 0xa06; 2000794e27ecSJohnny Huang bit_offset = i - 32; 2001794e27ecSJohnny Huang } 2002f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 20030dc9a440SJohnny Huang printf("OTPCFG%X[%X] programming failed\n", dw_offset, bit_offset); 2004794e27ecSJohnny Huang ret = OTP_FAILURE; 2005794e27ecSJohnny Huang break; 2006794e27ecSJohnny Huang } 2007794e27ecSJohnny Huang } 2008061d3279SJohnny Huang otp_soak(0); 2009f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2010f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2011794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2012794e27ecSJohnny Huang if (rid_num >= 0) 2013794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 2014794e27ecSJohnny Huang else 2015794e27ecSJohnny Huang printf("OTP revision ID\n"); 2016794e27ecSJohnny Huang otp_print_revid(otp_rid); 2017794e27ecSJohnny Huang if (!ret) 2018794e27ecSJohnny Huang printf("SUCCESS\n"); 2019794e27ecSJohnny Huang else 2020794e27ecSJohnny Huang printf("FAILED\n"); 2021794e27ecSJohnny Huang return ret; 2022794e27ecSJohnny Huang } 2023794e27ecSJohnny Huang 20242a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 202569d5fd8fSJohnny Huang { 2026a219f6deSJohnny Huang u32 offset, count; 20272a856b9aSJohnny Huang int ret; 202869d5fd8fSJohnny Huang 20292a856b9aSJohnny Huang if (argc == 4) { 20302a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 20312a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 20322a856b9aSJohnny Huang } else if (argc == 3) { 20332a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 20342a856b9aSJohnny Huang count = 1; 20352a856b9aSJohnny Huang } else { 203669d5fd8fSJohnny Huang return CMD_RET_USAGE; 203769d5fd8fSJohnny Huang } 203869d5fd8fSJohnny Huang 2039*030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2040f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2041*030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 20422a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2043*030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 20442a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2045*030cb4a7SJohnny Huang else 20462a856b9aSJohnny Huang return CMD_RET_USAGE; 204769d5fd8fSJohnny Huang 20482a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 20492a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20502a856b9aSJohnny Huang return CMD_RET_USAGE; 20512a856b9aSJohnny Huang } 20522a856b9aSJohnny Huang 20532a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20542a856b9aSJohnny Huang { 20552a856b9aSJohnny Huang phys_addr_t addr; 20562a856b9aSJohnny Huang int ret; 20572a856b9aSJohnny Huang 2058de6b0cc4SJohnny Huang if (argc == 3) { 2059ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 20602a856b9aSJohnny Huang return CMD_RET_USAGE; 20612a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2062f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2063de6b0cc4SJohnny Huang } else if (argc == 2) { 20642a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2065f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 20662a856b9aSJohnny Huang } else { 20672a856b9aSJohnny Huang return CMD_RET_USAGE; 20682a856b9aSJohnny Huang } 20692a856b9aSJohnny Huang 20702a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 20712a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20722a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 20732a856b9aSJohnny Huang return CMD_RET_FAILURE; 20742a856b9aSJohnny Huang else 20752a856b9aSJohnny Huang return CMD_RET_USAGE; 20762a856b9aSJohnny Huang } 20772a856b9aSJohnny Huang 20782a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20792a856b9aSJohnny Huang { 20802a856b9aSJohnny Huang int mode = 0; 20812a856b9aSJohnny Huang int nconfirm = 0; 20822a856b9aSJohnny Huang int otp_addr = 0; 20832a856b9aSJohnny Huang int bit_offset; 20842a856b9aSJohnny Huang int value; 20852a856b9aSJohnny Huang int ret; 2086*030cb4a7SJohnny Huang u32 otp_strap_pro; 20872a856b9aSJohnny Huang 20882a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 20892a856b9aSJohnny Huang return CMD_RET_USAGE; 20902a856b9aSJohnny Huang 20912a856b9aSJohnny Huang /* Drop the pb cmd */ 20922a856b9aSJohnny Huang argc--; 20932a856b9aSJohnny Huang argv++; 20942a856b9aSJohnny Huang 20952a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2096a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 20972a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2098a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 20992a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2100a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2101cd1610b4SJohnny Huang else 21022a856b9aSJohnny Huang return CMD_RET_USAGE; 21032a856b9aSJohnny Huang 21042a856b9aSJohnny Huang /* Drop the region cmd */ 21052a856b9aSJohnny Huang argc--; 21062a856b9aSJohnny Huang argv++; 21072a856b9aSJohnny Huang 2108ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2109cd1610b4SJohnny Huang nconfirm = 1; 21102a856b9aSJohnny Huang /* Drop the force option */ 21112a856b9aSJohnny Huang argc--; 21122a856b9aSJohnny Huang argv++; 21132a856b9aSJohnny Huang } 2114cd1610b4SJohnny Huang 2115a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 21162a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 21172a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 21180808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 21192a856b9aSJohnny Huang return CMD_RET_USAGE; 2120cd1610b4SJohnny Huang } else { 21212a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 21222a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 21232a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 21240808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 21252a856b9aSJohnny Huang return CMD_RET_USAGE; 21260808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 212778855207SJohnny Huang if (otp_addr >= 0x800) 21280808cc55SJohnny Huang return CMD_RET_USAGE; 21290808cc55SJohnny Huang } else { 213078855207SJohnny Huang if (otp_addr >= 0x20) 21310808cc55SJohnny Huang return CMD_RET_USAGE; 21320808cc55SJohnny Huang } 2133cd1610b4SJohnny Huang } 2134cd1610b4SJohnny Huang if (value != 0 && value != 1) 21352a856b9aSJohnny Huang return CMD_RET_USAGE; 2136cd1610b4SJohnny Huang 2137*030cb4a7SJohnny Huang ret = 0; 2138*030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2139*030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2140*030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2141*030cb4a7SJohnny Huang } 2142*030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2143*030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2144*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2145*030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2146*030cb4a7SJohnny Huang ret = -1; 2147*030cb4a7SJohnny Huang } 2148*030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2149*030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2150*030cb4a7SJohnny Huang ret = -1; 2151*030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2152*030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2153*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2154*030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2155*030cb4a7SJohnny Huang ret = -1; 2156*030cb4a7SJohnny Huang } 2157*030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2158*030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2159*030cb4a7SJohnny Huang ret = -1; 2160*030cb4a7SJohnny Huang } 2161*030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2162*030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2163*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2164*030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2165*030cb4a7SJohnny Huang ret = -1; 2166*030cb4a7SJohnny Huang } 2167*030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2168*030cb4a7SJohnny Huang u32 otp_rid[2]; 2169*030cb4a7SJohnny Huang u32 sw_rid[2]; 2170*030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2171*030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2172*030cb4a7SJohnny Huang 2173*030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2174*030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2175*030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2176*030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2177*030cb4a7SJohnny Huang 2178*030cb4a7SJohnny Huang if (otp_addr == 10) 2179*030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2180*030cb4a7SJohnny Huang else 2181*030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2182*030cb4a7SJohnny Huang 2183*030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2184*030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2185*030cb4a7SJohnny Huang ret = -1; 2186*030cb4a7SJohnny Huang } 2187*030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2188*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2189*030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2190*030cb4a7SJohnny Huang ret = -1; 2191*030cb4a7SJohnny Huang } else { 2192*030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2193*030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2194*030cb4a7SJohnny Huang u32 key_num; 2195*030cb4a7SJohnny Huang u32 retire; 2196*030cb4a7SJohnny Huang 2197*030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2198*030cb4a7SJohnny Huang if (bit_offset >= 16) 2199*030cb4a7SJohnny Huang retire = bit_offset - 16; 2200*030cb4a7SJohnny Huang else 2201*030cb4a7SJohnny Huang retire = bit_offset; 2202*030cb4a7SJohnny Huang if (retire >= key_num) { 2203*030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2204*030cb4a7SJohnny Huang ret = -1; 2205*030cb4a7SJohnny Huang } 2206*030cb4a7SJohnny Huang } 2207*030cb4a7SJohnny Huang } 2208*030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2209*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2210*030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2211*030cb4a7SJohnny Huang ret = -1; 2212*030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2213*030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2214*030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2215*030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2216*030cb4a7SJohnny Huang else 2217*030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2218*030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2219*030cb4a7SJohnny Huang printf("OTPCFG%X[%X] is protected\n", otp_addr, bit_offset); 2220*030cb4a7SJohnny Huang ret = -1; 2221*030cb4a7SJohnny Huang } 2222*030cb4a7SJohnny Huang } 2223*030cb4a7SJohnny Huang } 2224*030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2225*030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2226*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2227*030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2228*030cb4a7SJohnny Huang ret = -1; 2229*030cb4a7SJohnny Huang } 2230*030cb4a7SJohnny Huang } 2231*030cb4a7SJohnny Huang 2232*030cb4a7SJohnny Huang if (ret == -1) 2233*030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2234*030cb4a7SJohnny Huang 2235f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 22362a856b9aSJohnny Huang 22372a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 22382a856b9aSJohnny Huang return CMD_RET_SUCCESS; 22392a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 22402a856b9aSJohnny Huang return CMD_RET_FAILURE; 22412a856b9aSJohnny Huang else 22422a856b9aSJohnny Huang return CMD_RET_USAGE; 22432a856b9aSJohnny Huang } 22442a856b9aSJohnny Huang 22452a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 22462a856b9aSJohnny Huang { 22472a856b9aSJohnny Huang phys_addr_t addr; 22482a856b9aSJohnny Huang int otp_addr = 0; 2249b8590031SJohnny Huang int ret; 22502a856b9aSJohnny Huang 22512a856b9aSJohnny Huang if (argc != 3) 22522a856b9aSJohnny Huang return CMD_RET_USAGE; 22532a856b9aSJohnny Huang 22542a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 22552a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 2256b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 2257b8590031SJohnny Huang if (ret == 0) { 225869d5fd8fSJohnny Huang printf("Compare pass\n"); 22592a856b9aSJohnny Huang return CMD_RET_SUCCESS; 2260a219f6deSJohnny Huang } 226169d5fd8fSJohnny Huang printf("Compare fail\n"); 22622a856b9aSJohnny Huang return CMD_RET_FAILURE; 226369d5fd8fSJohnny Huang } 226469d5fd8fSJohnny Huang 226566f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 226666f2f8e5SJohnny Huang { 2267a8bd6d8cSJohnny Huang int view = 0; 22682d4b0742SJohnny Huang int input; 2269a8bd6d8cSJohnny Huang 2270a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 227166f2f8e5SJohnny Huang return CMD_RET_USAGE; 227266f2f8e5SJohnny Huang 22732d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 22742d4b0742SJohnny Huang if (argc == 3) { 22752d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 22762d4b0742SJohnny Huang otp_print_conf_info(input); 22772d4b0742SJohnny Huang } else { 22782d4b0742SJohnny Huang otp_print_conf_info(-1); 22792d4b0742SJohnny Huang } 22802d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 22812d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 2282a8bd6d8cSJohnny Huang view = 1; 2283a8bd6d8cSJohnny Huang /* Drop the view option */ 2284a8bd6d8cSJohnny Huang argc--; 2285a8bd6d8cSJohnny Huang argv++; 2286a8bd6d8cSJohnny Huang } 2287b458cd62SJohnny Huang otp_print_strap_info(view); 22880dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 22890dc9a440SJohnny Huang otp_print_scu_info(); 229066f2f8e5SJohnny Huang } else { 229166f2f8e5SJohnny Huang return CMD_RET_USAGE; 229266f2f8e5SJohnny Huang } 22932d4b0742SJohnny Huang 229466f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 229566f2f8e5SJohnny Huang } 229666f2f8e5SJohnny Huang 22970dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2298737ed20bSJohnny Huang { 22990dc9a440SJohnny Huang u32 input; 23000dc9a440SJohnny Huang u32 bit_offset; 2301e14b073cSJohnny Huang u32 prog_address; 2302*030cb4a7SJohnny Huang char force; 230383655e91SJohnny Huang int ret; 2304a219f6deSJohnny Huang 2305737ed20bSJohnny Huang if (argc != 3 && argc != 2) 2306737ed20bSJohnny Huang return CMD_RET_USAGE; 2307737ed20bSJohnny Huang 2308e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 2309737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 2310*030cb4a7SJohnny Huang force = 1; 2311737ed20bSJohnny Huang } else { 2312737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 2313*030cb4a7SJohnny Huang force = 0; 2314737ed20bSJohnny Huang } 2315737ed20bSJohnny Huang 2316737ed20bSJohnny Huang if (input < 32) { 2317737ed20bSJohnny Huang bit_offset = input; 23180dc9a440SJohnny Huang prog_address = 0xe0c; 2319737ed20bSJohnny Huang } else if (input < 64) { 2320737ed20bSJohnny Huang bit_offset = input - 32; 23210dc9a440SJohnny Huang prog_address = 0xe0e; 2322737ed20bSJohnny Huang } else { 2323737ed20bSJohnny Huang return CMD_RET_USAGE; 2324737ed20bSJohnny Huang } 2325737ed20bSJohnny Huang 2326*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2327*030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2328*030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2329*030cb4a7SJohnny Huang } 2330*030cb4a7SJohnny Huang 2331*030cb4a7SJohnny Huang if (!force) { 2332*030cb4a7SJohnny Huang printf("OTPSTRAP[%X] will be protected\n", input); 2333*030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2334*030cb4a7SJohnny Huang if (!confirm_yesno()) { 2335*030cb4a7SJohnny Huang printf(" Aborting\n"); 2336*030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2337*030cb4a7SJohnny Huang } 2338*030cb4a7SJohnny Huang } 2339*030cb4a7SJohnny Huang 2340e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 23410dc9a440SJohnny Huang printf("OTPSTRAP[%X] already protected\n", input); 2342e14b073cSJohnny Huang return CMD_RET_SUCCESS; 2343e14b073cSJohnny Huang } 2344de6fbf1cSJohnny Huang 2345f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 2346de6fbf1cSJohnny Huang otp_soak(0); 234783655e91SJohnny Huang 234883655e91SJohnny Huang if (ret) { 23490dc9a440SJohnny Huang printf("Protect OTPSTRAP[%X] fail\n", input); 2350737ed20bSJohnny Huang return CMD_RET_FAILURE; 2351737ed20bSJohnny Huang } 23529a4fe690SJohnny Huang 23530dc9a440SJohnny Huang printf("OTPSTRAP[%X] is protected\n", input); 2354794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2355794e27ecSJohnny Huang } 2356794e27ecSJohnny Huang 23570dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2358e14b073cSJohnny Huang { 23590dc9a440SJohnny Huang u32 scu_offset; 23600dc9a440SJohnny Huang u32 bit_offset; 23610dc9a440SJohnny Huang u32 conf_offset; 23620dc9a440SJohnny Huang u32 prog_address; 23630dc9a440SJohnny Huang char force; 23640dc9a440SJohnny Huang int ret; 23650dc9a440SJohnny Huang 23660dc9a440SJohnny Huang if (argc != 4 && argc != 3) 23670dc9a440SJohnny Huang return CMD_RET_USAGE; 23680dc9a440SJohnny Huang 23690dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 23700dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 23710dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 23720dc9a440SJohnny Huang force = 1; 23730dc9a440SJohnny Huang } else { 23740dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 23750dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 23760dc9a440SJohnny Huang force = 0; 23770dc9a440SJohnny Huang } 23780dc9a440SJohnny Huang if (scu_offset == 0x500) { 23790dc9a440SJohnny Huang prog_address = 0xe08; 23800dc9a440SJohnny Huang conf_offset = 28; 23810dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 23820dc9a440SJohnny Huang prog_address = 0xe0a; 23830dc9a440SJohnny Huang conf_offset = 29; 23840dc9a440SJohnny Huang } else { 23850dc9a440SJohnny Huang return CMD_RET_USAGE; 23860dc9a440SJohnny Huang } 23870dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 23880dc9a440SJohnny Huang return CMD_RET_USAGE; 2389*030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2390*030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2391*030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2392*030cb4a7SJohnny Huang } 23930dc9a440SJohnny Huang if (!force) { 23940dc9a440SJohnny Huang printf("OTPCONF%X[%X] will be programmed\n", conf_offset, bit_offset); 23950dc9a440SJohnny Huang printf("SCU%X[%X] will be protected\n", scu_offset, bit_offset); 23960dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 23970dc9a440SJohnny Huang if (!confirm_yesno()) { 23980dc9a440SJohnny Huang printf(" Aborting\n"); 23990dc9a440SJohnny Huang return CMD_RET_FAILURE; 24000dc9a440SJohnny Huang } 2401e14b073cSJohnny Huang } 2402e14b073cSJohnny Huang 24030dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 24040dc9a440SJohnny Huang printf("OTPCONF%X[%X] already programmed\n", conf_offset, bit_offset); 24050dc9a440SJohnny Huang return CMD_RET_SUCCESS; 24060dc9a440SJohnny Huang } 24070dc9a440SJohnny Huang 24080dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 24090dc9a440SJohnny Huang otp_soak(0); 24100dc9a440SJohnny Huang 24110dc9a440SJohnny Huang if (ret) { 24120dc9a440SJohnny Huang printf("Program OTPCONF%X[%X] fail\n", conf_offset, bit_offset); 24130dc9a440SJohnny Huang return CMD_RET_FAILURE; 24140dc9a440SJohnny Huang } 24150dc9a440SJohnny Huang 24160dc9a440SJohnny Huang printf("OTPCONF%X[%X] programmed success\n", conf_offset, bit_offset); 24170dc9a440SJohnny Huang return CMD_RET_SUCCESS; 2418e14b073cSJohnny Huang } 2419e14b073cSJohnny Huang 2420f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2421f67375f7SJohnny Huang { 2422e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 2423f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2424f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2425f67375f7SJohnny Huang 2426f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2427f67375f7SJohnny Huang } 2428f67375f7SJohnny Huang 2429794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2430794e27ecSJohnny Huang { 2431794e27ecSJohnny Huang u32 update_num; 2432794e27ecSJohnny Huang int force = 0; 2433794e27ecSJohnny Huang int ret; 2434794e27ecSJohnny Huang 2435794e27ecSJohnny Huang if (argc == 3) { 2436794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 2437794e27ecSJohnny Huang return CMD_RET_USAGE; 2438794e27ecSJohnny Huang force = 1; 2439794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 2440794e27ecSJohnny Huang } else if (argc == 2) { 2441794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 2442794e27ecSJohnny Huang } else { 2443794e27ecSJohnny Huang return CMD_RET_USAGE; 2444794e27ecSJohnny Huang } 2445794e27ecSJohnny Huang 2446794e27ecSJohnny Huang if (update_num > 64) 2447794e27ecSJohnny Huang return CMD_RET_USAGE; 2448794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 2449b8590031SJohnny Huang 2450794e27ecSJohnny Huang if (ret) 2451794e27ecSJohnny Huang return CMD_RET_FAILURE; 2452794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2453794e27ecSJohnny Huang } 2454794e27ecSJohnny Huang 2455794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2456794e27ecSJohnny Huang { 2457794e27ecSJohnny Huang u32 otp_rid[2]; 2458a8789b47SJohnny Huang u32 sw_rid[2]; 2459794e27ecSJohnny Huang int rid_num = 0; 2460a8789b47SJohnny Huang int sw_rid_num = 0; 2461794e27ecSJohnny Huang int ret; 2462794e27ecSJohnny Huang 2463794e27ecSJohnny Huang if (argc != 1) 2464794e27ecSJohnny Huang return CMD_RET_USAGE; 2465794e27ecSJohnny Huang 2466f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2467f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2468794e27ecSJohnny Huang 2469a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2470a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2471794e27ecSJohnny Huang 2472a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 2473a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2474a8789b47SJohnny Huang 2475*030cb4a7SJohnny Huang if (sw_rid_num < 0) { 2476*030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2477*030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 2478*030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 2479*030cb4a7SJohnny Huang } else { 2480a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2481*030cb4a7SJohnny Huang } 2482794e27ecSJohnny Huang if (rid_num >= 0) { 2483794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2484794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 2485794e27ecSJohnny Huang } else { 2486794e27ecSJohnny Huang printf("Currennt OTP revision ID cannot handle by 'otp update',\n" 2487794e27ecSJohnny Huang "plase use 'otp pb' command to update it manually\n" 2488794e27ecSJohnny Huang "current OTP revision ID\n"); 2489794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 2490794e27ecSJohnny Huang } 2491794e27ecSJohnny Huang otp_print_revid(otp_rid); 2492794e27ecSJohnny Huang 2493794e27ecSJohnny Huang return ret; 2494794e27ecSJohnny Huang } 2495794e27ecSJohnny Huang 24962a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2497f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 24982a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2499a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2500de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 25012a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2502737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 25030dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 25042a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 2505794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 2506794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 25072a856b9aSJohnny Huang }; 25082a856b9aSJohnny Huang 25092a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 25102a856b9aSJohnny Huang { 2511*030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 25122a856b9aSJohnny Huang cmd_tbl_t *cp; 2513a219f6deSJohnny Huang u32 ver; 2514e14b073cSJohnny Huang int ret; 2515*030cb4a7SJohnny Huang u32 otp_conf0; 25162a856b9aSJohnny Huang 25172a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 25182a856b9aSJohnny Huang 2519737ed20bSJohnny Huang /* Drop the otp command */ 25202a856b9aSJohnny Huang argc--; 25212a856b9aSJohnny Huang argv++; 25222a856b9aSJohnny Huang 2523a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 25242a856b9aSJohnny Huang return CMD_RET_USAGE; 25252a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 25262a856b9aSJohnny Huang return CMD_RET_SUCCESS; 25272a856b9aSJohnny Huang 25280dae9d52SJohnny Huang ver = chip_version(); 25290dae9d52SJohnny Huang switch (ver) { 2530e417205bSJohnny Huang case OTP_A0: 2531e417205bSJohnny Huang info_cb.version = OTP_A0; 25329a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 25339a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 25349a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 25359a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 25369a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 25379a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 2538e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 25390dae9d52SJohnny Huang break; 2540e417205bSJohnny Huang case OTP_A1: 2541e417205bSJohnny Huang info_cb.version = OTP_A1; 25423cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 25433cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 25443cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 25453cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 25469a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 25479a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 25480dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 25490dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2550e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 25510dae9d52SJohnny Huang break; 2552e417205bSJohnny Huang case OTP_A2: 2553e417205bSJohnny Huang info_cb.version = OTP_A2; 25545fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 25555fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 2556fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2557fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 25585fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 25595fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 25600dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 25610dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2562e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 25630dae9d52SJohnny Huang break; 2564e417205bSJohnny Huang case OTP_A3: 2565e417205bSJohnny Huang info_cb.version = OTP_A3; 2566b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 2567b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 2568fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2569fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 2570181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2571181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 25720dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 25730dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2574e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 257564b66712SJohnny Huang break; 25760dae9d52SJohnny Huang default: 2577f1be5099SJohnny Huang printf("SOC is not supported\n"); 25780dae9d52SJohnny Huang return CMD_RET_FAILURE; 25799a4fe690SJohnny Huang } 25809a4fe690SJohnny Huang 2581*030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2582*030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 2583*030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 2584*030cb4a7SJohnny Huang 2585*030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 2586*030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 2587*030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 2588*030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 2589*030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 2590*030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 2591*030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 2592*030cb4a7SJohnny Huang 2593e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 2594b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 2595e14b073cSJohnny Huang 2596e14b073cSJohnny Huang return ret; 259769d5fd8fSJohnny Huang } 259869d5fd8fSJohnny Huang 2599a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 260069d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2601f67375f7SJohnny Huang "version\n" 2602f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 26032a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 26042d4b0742SJohnny Huang "otp info strap [v]\n" 26052d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 26060dc9a440SJohnny Huang "otp info scu\n" 2607de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2608ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2609ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2610ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 26110dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 2612794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 2613794e27ecSJohnny Huang "otp rid\n" 261469d5fd8fSJohnny Huang ); 2615