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 433d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 443d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 453d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 463d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 473d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 483d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 493d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 503d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 513d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 523d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 53a8789b47SJohnny Huang #define SW_REV_ID0 OTP_BASE + 0x68 54a8789b47SJohnny Huang #define SW_REV_ID1 OTP_BASE + 0x6c 55030cb4a7SJohnny Huang #define SEC_KEY_NUM OTP_BASE + 0x78 563d3688adSJohnny Huang 57696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 58696656c6SJohnny Huang #define CHECKSUM_LEN 32 59a219f6deSJohnny Huang #define OTP_INC_DATA BIT(31) 60a219f6deSJohnny Huang #define OTP_INC_CONFIG BIT(30) 61a219f6deSJohnny Huang #define OTP_INC_STRAP BIT(29) 62a219f6deSJohnny Huang #define OTP_ECC_EN BIT(28) 63b25f02d2SJohnny Huang #define OTP_INC_SCU_PRO BIT(25) 64696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 65696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 66696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 67696656c6SJohnny Huang 68e417205bSJohnny Huang #define OTP_A0 0 69e417205bSJohnny Huang #define OTP_A1 1 70e417205bSJohnny Huang #define OTP_A2 2 71e417205bSJohnny Huang #define OTP_A3 3 72e417205bSJohnny Huang 73e417205bSJohnny Huang #define ID0_AST2600A0 0x05000303 74e417205bSJohnny Huang #define ID1_AST2600A0 0x05000303 75e417205bSJohnny Huang #define ID0_AST2600A1 0x05010303 7621a8cfceSJohnny Huang #define ID1_AST2600A1 0x05010303 77e417205bSJohnny Huang #define ID0_AST2600A2 0x05010303 78e417205bSJohnny Huang #define ID1_AST2600A2 0x05020303 79e417205bSJohnny Huang #define ID0_AST2600A3 0x05030303 80e417205bSJohnny Huang #define ID1_AST2600A3 0x05030303 81e417205bSJohnny Huang #define ID0_AST2620A1 0x05010203 82e417205bSJohnny Huang #define ID1_AST2620A1 0x05010203 83e417205bSJohnny Huang #define ID0_AST2620A2 0x05010203 84e417205bSJohnny Huang #define ID1_AST2620A2 0x05020203 85e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 86e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 87e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 88e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 89e417205bSJohnny Huang #define ID0_AST2605A2 0x05010103 90e417205bSJohnny Huang #define ID1_AST2605A2 0x05020103 91e417205bSJohnny Huang #define ID0_AST2605A3 0x05030103 92e417205bSJohnny Huang #define ID1_AST2605A3 0x05030103 93e417205bSJohnny Huang #define ID0_AST2625A3 0x05030403 94e417205bSJohnny Huang #define ID1_AST2625A3 0x05030403 95696656c6SJohnny Huang 9661a6cda7SJohnny Huang #define SOC_AST2600A0 0 9761a6cda7SJohnny Huang #define SOC_AST2600A1 1 9861a6cda7SJohnny Huang #define SOC_AST2600A2 2 9961a6cda7SJohnny Huang #define SOC_AST2600A3 3 10061a6cda7SJohnny Huang 10161a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c)) 10261a6cda7SJohnny Huang 103696656c6SJohnny Huang struct otp_header { 104696656c6SJohnny Huang u8 otp_magic[8]; 10561a6cda7SJohnny Huang u32 soc_ver; 10661a6cda7SJohnny Huang u32 otptool_ver; 107696656c6SJohnny Huang u32 image_info; 108696656c6SJohnny Huang u32 data_info; 109696656c6SJohnny Huang u32 config_info; 110696656c6SJohnny Huang u32 strap_info; 1117e523e3bSJohnny Huang u32 scu_protect_info; 112696656c6SJohnny Huang u32 checksum_offset; 113a219f6deSJohnny Huang } __packed; 114696656c6SJohnny Huang 11566f2f8e5SJohnny Huang struct otpstrap_status { 11669d5fd8fSJohnny Huang int value; 11769d5fd8fSJohnny Huang int option_array[7]; 11869d5fd8fSJohnny Huang int remain_times; 11969d5fd8fSJohnny Huang int writeable_option; 12069d5fd8fSJohnny Huang int protected; 12169d5fd8fSJohnny Huang }; 12269d5fd8fSJohnny Huang 1239a4fe690SJohnny Huang struct otpkey_type { 1249a4fe690SJohnny Huang int value; 1259a4fe690SJohnny Huang int key_type; 1269a4fe690SJohnny Huang int need_id; 1279a4fe690SJohnny Huang char information[110]; 1289a4fe690SJohnny Huang }; 1299a4fe690SJohnny Huang 130030cb4a7SJohnny Huang struct otp_pro_sts { 131030cb4a7SJohnny Huang char mem_lock; 132030cb4a7SJohnny Huang char pro_key_ret; 133030cb4a7SJohnny Huang char pro_strap; 134030cb4a7SJohnny Huang char pro_conf; 135030cb4a7SJohnny Huang char pro_data; 136030cb4a7SJohnny Huang char pro_sec; 137030cb4a7SJohnny Huang u32 sec_size; 138030cb4a7SJohnny Huang }; 139030cb4a7SJohnny Huang 1409a4fe690SJohnny Huang struct otp_info_cb { 1419a4fe690SJohnny Huang int version; 142e417205bSJohnny Huang char ver_name[3]; 14379e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1449a4fe690SJohnny Huang int strap_info_len; 14579e42a59SJoel Stanley const struct otpconf_info *conf_info; 1469a4fe690SJohnny Huang int conf_info_len; 14779e42a59SJoel Stanley const struct otpkey_type *key_info; 1489a4fe690SJohnny Huang int key_info_len; 1490dc9a440SJohnny Huang const struct scu_info *scu_info; 1500dc9a440SJohnny Huang int scu_info_len; 151030cb4a7SJohnny Huang struct otp_pro_sts pro_sts; 1529a4fe690SJohnny Huang }; 1539a4fe690SJohnny Huang 154696656c6SJohnny Huang struct otp_image_layout { 1555010032bSJohnny Huang int data_length; 1565010032bSJohnny Huang int conf_length; 1575010032bSJohnny Huang int strap_length; 158b25f02d2SJohnny Huang int scu_pro_length; 159a219f6deSJohnny Huang u8 *data; 160a219f6deSJohnny Huang u8 *data_ignore; 161a219f6deSJohnny Huang u8 *conf; 162a219f6deSJohnny Huang u8 *conf_ignore; 163a219f6deSJohnny Huang u8 *strap; 164a219f6deSJohnny Huang u8 *strap_pro; 165a219f6deSJohnny Huang u8 *strap_ignore; 166b25f02d2SJohnny Huang u8 *scu_pro; 167b25f02d2SJohnny Huang u8 *scu_pro_ignore; 168696656c6SJohnny Huang }; 169696656c6SJohnny Huang 1709a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1719a4fe690SJohnny Huang 17279e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1739a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1749a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1759a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 176181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 177181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as SOC public key"}, 178181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 179181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as SOC private key"}, 180181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1819a4fe690SJohnny Huang }; 1829a4fe690SJohnny Huang 18379e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1849a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1859a4fe690SJohnny 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"}, 186181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 187181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 188181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1899a4fe690SJohnny Huang }; 1909a4fe690SJohnny Huang 1915fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1925fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1935fdde29fSJohnny 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"}, 194181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 195181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 196181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 197181f72d8SJohnny Huang }; 198181f72d8SJohnny Huang 199181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = { 200181f72d8SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 201181f72d8SJohnny 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"}, 202181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 203181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 204181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 205181f72d8SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key(big endian)"}, 206181f72d8SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 207181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key(big endian)"}, 2085fdde29fSJohnny Huang }; 2095fdde29fSJohnny Huang 210f347c284SJohnny Huang static void buf_print(u8 *buf, int len) 211f347c284SJohnny Huang { 212f347c284SJohnny Huang int i; 213f347c284SJohnny Huang 214f347c284SJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 215f347c284SJohnny Huang for (i = 0; i < len; i++) { 216f347c284SJohnny Huang if (i % 16 == 0) 217f347c284SJohnny Huang printf("%04X: ", i); 218f347c284SJohnny Huang printf("%02X ", buf[i]); 219f347c284SJohnny Huang if ((i + 1) % 16 == 0) 220f347c284SJohnny Huang printf("\n"); 221f347c284SJohnny Huang } 222f347c284SJohnny Huang } 223f347c284SJohnny Huang 224794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset) 225794e27ecSJohnny Huang { 226794e27ecSJohnny Huang int bit_offset; 227794e27ecSJohnny Huang int i; 228794e27ecSJohnny Huang 229794e27ecSJohnny Huang if (offset < 32) { 230794e27ecSJohnny Huang i = 0; 231794e27ecSJohnny Huang bit_offset = offset; 232794e27ecSJohnny Huang } else { 233794e27ecSJohnny Huang i = 1; 234794e27ecSJohnny Huang bit_offset = offset - 32; 235794e27ecSJohnny Huang } 236794e27ecSJohnny Huang if ((rid[i] >> bit_offset) & 0x1) 237794e27ecSJohnny Huang return 1; 238794e27ecSJohnny Huang else 239794e27ecSJohnny Huang return 0; 240794e27ecSJohnny Huang } 241794e27ecSJohnny Huang 242794e27ecSJohnny Huang static int get_rid_num(u32 *rid) 243794e27ecSJohnny Huang { 244794e27ecSJohnny Huang int i; 245794e27ecSJohnny Huang int fz = 0; 246794e27ecSJohnny Huang int rid_num = 0; 247794e27ecSJohnny Huang int ret = 0; 248794e27ecSJohnny Huang 249794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 250794e27ecSJohnny Huang if (get_dw_bit(rid, i) == 0) { 251794e27ecSJohnny Huang if (!fz) 252794e27ecSJohnny Huang fz = 1; 253794e27ecSJohnny Huang 254794e27ecSJohnny Huang } else { 255794e27ecSJohnny Huang rid_num++; 256794e27ecSJohnny Huang if (fz) 257794e27ecSJohnny Huang ret = OTP_FAILURE; 258794e27ecSJohnny Huang } 259794e27ecSJohnny Huang } 260794e27ecSJohnny Huang if (ret) 261794e27ecSJohnny Huang return ret; 262794e27ecSJohnny Huang 263794e27ecSJohnny Huang return rid_num; 264794e27ecSJohnny Huang } 265794e27ecSJohnny Huang 266a219f6deSJohnny Huang static u32 chip_version(void) 2679a4fe690SJohnny Huang { 268e417205bSJohnny Huang u32 revid0, revid1; 2699a4fe690SJohnny Huang 270e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0); 271e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1); 2729a4fe690SJohnny Huang 273e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { 274badd21c2SJohnny Huang /* AST2600-A0 */ 275e417205bSJohnny Huang return OTP_A0; 276e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { 277badd21c2SJohnny Huang /* AST2600-A1 */ 278e417205bSJohnny Huang return OTP_A1; 279e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { 280badd21c2SJohnny Huang /* AST2600-A2 */ 281e417205bSJohnny Huang return OTP_A2; 282e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { 28364b66712SJohnny Huang /* AST2600-A3 */ 284e417205bSJohnny Huang return OTP_A3; 285e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { 286e417205bSJohnny Huang /* AST2620-A1 */ 287e417205bSJohnny Huang return OTP_A1; 288e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { 289e417205bSJohnny Huang /* AST2620-A2 */ 290e417205bSJohnny Huang return OTP_A2; 291e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { 29264b66712SJohnny Huang /* AST2620-A3 */ 293e417205bSJohnny Huang return OTP_A3; 294e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { 295e417205bSJohnny Huang /* AST2605-A2 */ 296e417205bSJohnny Huang return OTP_A2; 297e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { 298e417205bSJohnny Huang /* AST2605-A3 */ 299e417205bSJohnny Huang return OTP_A3; 300e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { 301e417205bSJohnny Huang /* AST2605-A3 */ 302e417205bSJohnny Huang return OTP_A3; 3030dae9d52SJohnny Huang } 304f347c284SJohnny Huang return OTP_FAILURE; 3059a4fe690SJohnny Huang } 3069a4fe690SJohnny Huang 3073d3688adSJohnny Huang static void wait_complete(void) 3083d3688adSJohnny Huang { 3093d3688adSJohnny Huang int reg; 3103d3688adSJohnny Huang 3113d3688adSJohnny Huang do { 3123d3688adSJohnny Huang reg = readl(OTP_STATUS); 3133d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 3143d3688adSJohnny Huang } 3153d3688adSJohnny Huang 316a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 317dacbba92SJohnny Huang { 318dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 319dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 320dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 321dacbba92SJohnny Huang wait_complete(); 322dacbba92SJohnny Huang } 323dacbba92SJohnny Huang 324dacbba92SJohnny Huang static void otp_soak(int soak) 325dacbba92SJohnny Huang { 326e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) { 327dacbba92SJohnny Huang switch (soak) { 328dacbba92SJohnny Huang case 0: //default 329377f8cd7SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 330377f8cd7SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 331dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 332dacbba92SJohnny Huang break; 333dacbba92SJohnny Huang case 1: //normal program 334377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 335377f8cd7SJohnny Huang otp_write(0x5000, 0x1008); // Write MRB 336377f8cd7SJohnny Huang otp_write(0x1000, 0x0024); // Write MR 337feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 338dacbba92SJohnny Huang break; 339dacbba92SJohnny Huang case 2: //soak program 340377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 341377f8cd7SJohnny Huang otp_write(0x5000, 0x0007); // Write MRB 342377f8cd7SJohnny Huang otp_write(0x1000, 0x0100); // Write MR 343feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 344dacbba92SJohnny Huang break; 345dacbba92SJohnny Huang } 346dacbba92SJohnny Huang } else { 347dacbba92SJohnny Huang switch (soak) { 348dacbba92SJohnny Huang case 0: //default 349dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 350dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 351dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 352dacbba92SJohnny Huang break; 353dacbba92SJohnny Huang case 1: //normal program 354dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 355dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 356dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 357feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 358dacbba92SJohnny Huang break; 359dacbba92SJohnny Huang case 2: //soak program 360dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 361dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 362dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 363feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 364dacbba92SJohnny Huang break; 365dacbba92SJohnny Huang } 366dacbba92SJohnny Huang } 367dacbba92SJohnny Huang 368dacbba92SJohnny Huang wait_complete(); 369dacbba92SJohnny Huang } 370dacbba92SJohnny Huang 371a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 37269d5fd8fSJohnny Huang { 3733d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 3743d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3753d3688adSJohnny Huang wait_complete(); 3763d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 3773d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 37869d5fd8fSJohnny Huang } 37969d5fd8fSJohnny Huang 380f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data) 38169d5fd8fSJohnny Huang { 38269d5fd8fSJohnny Huang int config_offset; 38369d5fd8fSJohnny Huang 38469d5fd8fSJohnny Huang config_offset = 0x800; 38569d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 38669d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 38769d5fd8fSJohnny Huang 3883d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 3893d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3903d3688adSJohnny Huang wait_complete(); 3913d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 39269d5fd8fSJohnny Huang } 39369d5fd8fSJohnny Huang 394a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 39569d5fd8fSJohnny Huang { 396a219f6deSJohnny Huang u32 ret; 397a219f6deSJohnny Huang u32 *buf; 39869d5fd8fSJohnny Huang 39969d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 40069d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 40169d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 40269d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 40369d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 4043d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 4053d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 4063d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 4073d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 4083d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 4093d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 4103d3688adSJohnny Huang wait_complete(); 4113d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 41269d5fd8fSJohnny Huang if (ret & 0x1) 413f347c284SJohnny Huang return OTP_SUCCESS; 41469d5fd8fSJohnny Huang else 415f347c284SJohnny Huang return OTP_FAILURE; 41669d5fd8fSJohnny Huang } 41769d5fd8fSJohnny Huang 418a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 41969d5fd8fSJohnny Huang { 420a219f6deSJohnny Huang u32 ret[2]; 42169d5fd8fSJohnny Huang 42230a8c590SJohnny Huang if (otp_addr % 2 == 0) 4233d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 42430a8c590SJohnny Huang else 4253d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 42630a8c590SJohnny Huang 4273d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4283d3688adSJohnny Huang wait_complete(); 4293d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4303d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 43183655e91SJohnny Huang 43230a8c590SJohnny Huang if (otp_addr % 2 == 0) { 43330a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 434f347c284SJohnny Huang return OTP_SUCCESS; 43569d5fd8fSJohnny Huang else 436f347c284SJohnny Huang return OTP_FAILURE; 43730a8c590SJohnny Huang } else { 43830a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 439f347c284SJohnny Huang return OTP_SUCCESS; 44030a8c590SJohnny Huang else 441f347c284SJohnny Huang return OTP_FAILURE; 44230a8c590SJohnny Huang } 44369d5fd8fSJohnny Huang } 44469d5fd8fSJohnny Huang 445a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 4464c1c9b35SJohnny Huang { 447a219f6deSJohnny Huang u32 ret[2]; 4484c1c9b35SJohnny Huang 4494c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 4504c1c9b35SJohnny Huang 4514c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 4523d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 4534c1c9b35SJohnny Huang else 4543d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 4553d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4563d3688adSJohnny Huang wait_complete(); 4573d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4583d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 4594c1c9b35SJohnny Huang if (size == 1) { 4604c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 4614c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 462696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 4634c1c9b35SJohnny Huang compare[0] = 0; 464f347c284SJohnny Huang return OTP_SUCCESS; 465a219f6deSJohnny Huang } 4664c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 467f347c284SJohnny Huang return OTP_FAILURE; 4684c1c9b35SJohnny Huang 4694c1c9b35SJohnny Huang } else { 4704c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 471696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4724c1c9b35SJohnny Huang compare[0] = ~0; 473f347c284SJohnny Huang return OTP_SUCCESS; 474a219f6deSJohnny Huang } 475d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 476f347c284SJohnny Huang return OTP_FAILURE; 4774c1c9b35SJohnny Huang } 4784c1c9b35SJohnny Huang } else if (size == 2) { 4794c1c9b35SJohnny Huang // otp_addr should be even 480696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 4814c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4824c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4834c1c9b35SJohnny Huang compare[0] = 0; 4844c1c9b35SJohnny Huang compare[1] = ~0; 485f347c284SJohnny Huang return OTP_SUCCESS; 486a219f6deSJohnny Huang } 4874c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4884c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4894c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4904c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 491f347c284SJohnny Huang return OTP_FAILURE; 4924c1c9b35SJohnny Huang } else { 493f347c284SJohnny Huang return OTP_FAILURE; 4944c1c9b35SJohnny Huang } 4954c1c9b35SJohnny Huang } 4964c1c9b35SJohnny Huang 497a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit) 49883655e91SJohnny Huang { 49990965bb3SJohnny Huang otp_write(0x0, prog_bit); 50083655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 50183655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 50283655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 50383655e91SJohnny Huang wait_complete(); 50483655e91SJohnny Huang } 50583655e91SJohnny Huang 506a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 50783655e91SJohnny Huang { 50883655e91SJohnny Huang int prog_bit; 50983655e91SJohnny Huang 51083655e91SJohnny Huang if (prog_address % 2 == 0) { 51183655e91SJohnny Huang if (value) 51283655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 51383655e91SJohnny Huang else 51483655e91SJohnny Huang return; 51583655e91SJohnny Huang } else { 516e417205bSJohnny Huang if (info_cb.version != OTP_A3) 51783655e91SJohnny Huang prog_address |= 1 << 15; 51883655e91SJohnny Huang if (!value) 51983655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 52083655e91SJohnny Huang else 52183655e91SJohnny Huang return; 52283655e91SJohnny Huang } 52383655e91SJohnny Huang otp_prog(prog_address, prog_bit); 52483655e91SJohnny Huang } 52583655e91SJohnny Huang 526f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset) 52783655e91SJohnny Huang { 52883655e91SJohnny Huang int pass; 52983655e91SJohnny Huang int i; 53083655e91SJohnny Huang 53183655e91SJohnny Huang otp_soak(1); 53283655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 53383655e91SJohnny Huang pass = 0; 53483655e91SJohnny Huang 53583655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 53683655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 53783655e91SJohnny Huang otp_soak(2); 53883655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 53983655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 54083655e91SJohnny Huang otp_soak(1); 54183655e91SJohnny Huang } else { 54283655e91SJohnny Huang pass = 1; 54383655e91SJohnny Huang break; 54483655e91SJohnny Huang } 54583655e91SJohnny Huang } else { 54683655e91SJohnny Huang pass = 1; 54783655e91SJohnny Huang break; 54883655e91SJohnny Huang } 54983655e91SJohnny Huang } 550794e27ecSJohnny Huang if (pass) 551794e27ecSJohnny Huang return OTP_SUCCESS; 55283655e91SJohnny Huang 553794e27ecSJohnny Huang return OTP_FAILURE; 55483655e91SJohnny Huang } 55583655e91SJohnny Huang 556a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 557d90825e2SJohnny Huang { 558d90825e2SJohnny Huang int j, bit_value, prog_bit; 559d90825e2SJohnny Huang 560d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 561696656c6SJohnny Huang if ((ignore >> j) & 0x1) 562d90825e2SJohnny Huang continue; 563d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 564d90825e2SJohnny Huang if (prog_address % 2 == 0) { 565d90825e2SJohnny Huang if (bit_value) 566d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 567d90825e2SJohnny Huang else 568d90825e2SJohnny Huang continue; 569d90825e2SJohnny Huang } else { 570e417205bSJohnny Huang if (info_cb.version != OTP_A3) 571d90825e2SJohnny Huang prog_address |= 1 << 15; 572d90825e2SJohnny Huang if (bit_value) 573d90825e2SJohnny Huang continue; 574d90825e2SJohnny Huang else 575d90825e2SJohnny Huang prog_bit = 0x1 << j; 576d90825e2SJohnny Huang } 577d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 578d90825e2SJohnny Huang } 579d90825e2SJohnny Huang } 580d90825e2SJohnny Huang 581a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 58254552c69SJohnny Huang { 58354552c69SJohnny Huang int pass; 58454552c69SJohnny Huang int i; 585a219f6deSJohnny Huang u32 data0_masked; 586a219f6deSJohnny Huang u32 data1_masked; 587a219f6deSJohnny Huang u32 buf0_masked; 588a219f6deSJohnny Huang u32 buf1_masked; 589a219f6deSJohnny Huang u32 compare[2]; 59054552c69SJohnny Huang 59154552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 59254552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 59354552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 59454552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 595a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 596f347c284SJohnny Huang return OTP_SUCCESS; 59754552c69SJohnny Huang 598b64ca396SJohnny Huang for (i = 0; i < 32; i++) { 599b64ca396SJohnny Huang if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0) 600b64ca396SJohnny Huang return OTP_FAILURE; 601b64ca396SJohnny Huang if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1) 602b64ca396SJohnny Huang return OTP_FAILURE; 603b64ca396SJohnny Huang } 604b64ca396SJohnny Huang 60554552c69SJohnny Huang otp_soak(1); 60654552c69SJohnny Huang if (data0_masked != buf0_masked) 60754552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 60854552c69SJohnny Huang if (data1_masked != buf1_masked) 60954552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 61054552c69SJohnny Huang 61154552c69SJohnny Huang pass = 0; 61254552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 61354552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 61454552c69SJohnny Huang otp_soak(2); 615a219f6deSJohnny Huang if (compare[0] != 0) 61654552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 617a219f6deSJohnny Huang if (compare[1] != ~0) 6185537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 61954552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 62054552c69SJohnny Huang otp_soak(1); 62154552c69SJohnny Huang } else { 62254552c69SJohnny Huang pass = 1; 62354552c69SJohnny Huang break; 62454552c69SJohnny Huang } 62554552c69SJohnny Huang } else { 62654552c69SJohnny Huang pass = 1; 62754552c69SJohnny Huang break; 62854552c69SJohnny Huang } 62954552c69SJohnny Huang } 63054552c69SJohnny Huang 63154552c69SJohnny Huang if (!pass) { 63254552c69SJohnny Huang otp_soak(0); 63354552c69SJohnny Huang return OTP_FAILURE; 63454552c69SJohnny Huang } 63554552c69SJohnny Huang return OTP_SUCCESS; 63654552c69SJohnny Huang } 63754552c69SJohnny Huang 638541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 63976d13988SJohnny Huang { 640a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 6415010032bSJohnny Huang int strap_end; 64276d13988SJohnny Huang int i, j; 64376d13988SJohnny Huang 644e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 64576d13988SJohnny Huang for (j = 0; j < 64; j++) { 64676d13988SJohnny Huang otpstrap[j].value = 0; 64776d13988SJohnny Huang otpstrap[j].remain_times = 7; 64876d13988SJohnny Huang otpstrap[j].writeable_option = -1; 64976d13988SJohnny Huang otpstrap[j].protected = 0; 65076d13988SJohnny Huang } 6515010032bSJohnny Huang strap_end = 30; 6525010032bSJohnny Huang } else { 6535010032bSJohnny Huang for (j = 0; j < 64; j++) { 6545010032bSJohnny Huang otpstrap[j].value = 0; 6555010032bSJohnny Huang otpstrap[j].remain_times = 6; 6565010032bSJohnny Huang otpstrap[j].writeable_option = -1; 6575010032bSJohnny Huang otpstrap[j].protected = 0; 6585010032bSJohnny Huang } 6595010032bSJohnny Huang strap_end = 28; 6605010032bSJohnny Huang } 66176d13988SJohnny Huang 662dacbba92SJohnny Huang otp_soak(0); 6635010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 66476d13988SJohnny Huang int option = (i - 16) / 2; 665a219f6deSJohnny Huang 666f347c284SJohnny Huang otp_read_conf(i, &OTPSTRAP_RAW[0]); 667f347c284SJohnny Huang otp_read_conf(i + 1, &OTPSTRAP_RAW[1]); 66876d13988SJohnny Huang for (j = 0; j < 32; j++) { 66976d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 670a219f6deSJohnny Huang 671a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 67276d13988SJohnny Huang otpstrap[j].writeable_option = option; 67376d13988SJohnny Huang if (bit_value == 1) 67476d13988SJohnny Huang otpstrap[j].remain_times--; 67576d13988SJohnny Huang otpstrap[j].value ^= bit_value; 67676d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 67776d13988SJohnny Huang } 67876d13988SJohnny Huang for (j = 32; j < 64; j++) { 67976d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 680a219f6deSJohnny Huang 681a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 68276d13988SJohnny Huang otpstrap[j].writeable_option = option; 68376d13988SJohnny Huang if (bit_value == 1) 68476d13988SJohnny Huang otpstrap[j].remain_times--; 68576d13988SJohnny Huang otpstrap[j].value ^= bit_value; 68676d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 68776d13988SJohnny Huang } 68876d13988SJohnny Huang } 6895010032bSJohnny Huang 690f347c284SJohnny Huang otp_read_conf(30, &OTPSTRAP_RAW[0]); 691f347c284SJohnny Huang otp_read_conf(31, &OTPSTRAP_RAW[1]); 69276d13988SJohnny Huang for (j = 0; j < 32; j++) { 69376d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 69476d13988SJohnny Huang otpstrap[j].protected = 1; 69576d13988SJohnny Huang } 69676d13988SJohnny Huang for (j = 32; j < 64; j++) { 69776d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 69876d13988SJohnny Huang otpstrap[j].protected = 1; 69976d13988SJohnny Huang } 70076d13988SJohnny Huang } 70176d13988SJohnny Huang 7027e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit) 703f347c284SJohnny Huang { 704f347c284SJohnny Huang int prog_flag = 0; 705f347c284SJohnny Huang 706f347c284SJohnny Huang // ignore this bit 707f347c284SJohnny Huang if (ibit == 1) 708f347c284SJohnny Huang return OTP_SUCCESS; 709b489486eSJohnny Huang printf("OTPSTRAP[0x%X]:\n", offset); 710f347c284SJohnny Huang 711f347c284SJohnny Huang if (bit == otpstrap->value) { 7127e523e3bSJohnny Huang if (!pbit) { 713f347c284SJohnny Huang printf(" The value is same as before, skip it.\n"); 714f347c284SJohnny Huang return OTP_PROG_SKIP; 715f347c284SJohnny Huang } 716f347c284SJohnny Huang printf(" The value is same as before.\n"); 717f347c284SJohnny Huang } else { 718f347c284SJohnny Huang prog_flag = 1; 719f347c284SJohnny Huang } 720f347c284SJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 721f347c284SJohnny Huang printf(" This bit is protected and is not writable\n"); 722f347c284SJohnny Huang return OTP_FAILURE; 723f347c284SJohnny Huang } 724f347c284SJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 725b489486eSJohnny Huang printf(" This bit has no remaining chance to write.\n"); 726f347c284SJohnny Huang return OTP_FAILURE; 727f347c284SJohnny Huang } 728f347c284SJohnny Huang if (pbit == 1) 729f347c284SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 730f347c284SJohnny Huang if (prog_flag) 731b489486eSJohnny Huang printf(" Write 1 to OTPSTRAP[0x%X] OPTION[0x%X], that value becomes from 0x%X to 0x%X.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1); 732f347c284SJohnny Huang 733f347c284SJohnny Huang return OTP_SUCCESS; 734f347c284SJohnny Huang } 735f347c284SJohnny Huang 736f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value) 737f347c284SJohnny Huang { 738f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 739f347c284SJohnny Huang u32 prog_address; 740f347c284SJohnny Huang int offset; 741f347c284SJohnny Huang int ret; 742f347c284SJohnny Huang 743f347c284SJohnny Huang otp_strap_status(otpstrap); 744f347c284SJohnny Huang 7457e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 746f347c284SJohnny Huang 747f347c284SJohnny Huang if (ret != OTP_SUCCESS) 748f347c284SJohnny Huang return ret; 749f347c284SJohnny Huang 750f347c284SJohnny Huang prog_address = 0x800; 751f347c284SJohnny Huang if (bit_offset < 32) { 752f347c284SJohnny Huang offset = bit_offset; 753f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 754f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 755f347c284SJohnny Huang 756f347c284SJohnny Huang } else { 757f347c284SJohnny Huang offset = (bit_offset - 32); 758f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 759f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 760f347c284SJohnny Huang } 761f347c284SJohnny Huang 762f347c284SJohnny Huang return otp_prog_dc_b(1, prog_address, offset); 763f347c284SJohnny Huang } 764f347c284SJohnny Huang 765f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count) 766f347c284SJohnny Huang { 767f347c284SJohnny Huang int i; 768f347c284SJohnny Huang u32 ret[1]; 769f347c284SJohnny Huang 770f347c284SJohnny Huang if (offset + dw_count > 32) 771f347c284SJohnny Huang return OTP_USAGE; 772f347c284SJohnny Huang otp_soak(0); 773f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i++) { 774f347c284SJohnny Huang otp_read_conf(i, ret); 775b489486eSJohnny Huang printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]); 776f347c284SJohnny Huang } 777f347c284SJohnny Huang printf("\n"); 778f347c284SJohnny Huang return OTP_SUCCESS; 779f347c284SJohnny Huang } 780f347c284SJohnny Huang 781f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count) 782f347c284SJohnny Huang { 783f347c284SJohnny Huang int i; 784f347c284SJohnny Huang u32 ret[2]; 785f347c284SJohnny Huang 786f347c284SJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 787f347c284SJohnny Huang return OTP_USAGE; 788f347c284SJohnny Huang otp_soak(0); 789f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 790f347c284SJohnny Huang otp_read_data(i, ret); 791f347c284SJohnny Huang if (i % 4 == 0) 792f347c284SJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 793f347c284SJohnny Huang else 794f347c284SJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 795f347c284SJohnny Huang } 796f347c284SJohnny Huang printf("\n"); 797f347c284SJohnny Huang return OTP_SUCCESS; 798f347c284SJohnny Huang } 799f347c284SJohnny Huang 800f347c284SJohnny Huang static int otp_print_strap(int start, int count) 801f347c284SJohnny Huang { 802f347c284SJohnny Huang int i, j; 803f347c284SJohnny Huang int remains; 804f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 805f347c284SJohnny Huang 806f347c284SJohnny Huang if (start < 0 || start > 64) 807f347c284SJohnny Huang return OTP_USAGE; 808f347c284SJohnny Huang 809f347c284SJohnny Huang if ((start + count) < 0 || (start + count) > 64) 810f347c284SJohnny Huang return OTP_USAGE; 811f347c284SJohnny Huang 812f347c284SJohnny Huang otp_strap_status(otpstrap); 813f347c284SJohnny Huang 8147e523e3bSJohnny Huang if (info_cb.version == OTP_A0) 815f347c284SJohnny Huang remains = 7; 8167e523e3bSJohnny Huang else 817f347c284SJohnny Huang remains = 6; 8187e523e3bSJohnny Huang printf("BIT(hex) Value Option Status\n"); 819f347c284SJohnny Huang printf("______________________________________________________________________________\n"); 820f347c284SJohnny Huang 821f347c284SJohnny Huang for (i = start; i < start + count; i++) { 822f347c284SJohnny Huang printf("0x%-8X", i); 823f347c284SJohnny Huang printf("%-7d", otpstrap[i].value); 824f347c284SJohnny Huang for (j = 0; j < remains; j++) 825f347c284SJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 826f347c284SJohnny Huang printf(" "); 827f347c284SJohnny Huang if (otpstrap[i].protected == 1) { 828f347c284SJohnny Huang printf("protected and not writable"); 829f347c284SJohnny Huang } else { 830f347c284SJohnny Huang printf("not protected "); 831f347c284SJohnny Huang if (otpstrap[i].remain_times == 0) 832f347c284SJohnny Huang printf("and no remaining times to write."); 833f347c284SJohnny Huang else 834f347c284SJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 835f347c284SJohnny Huang } 836f347c284SJohnny Huang printf("\n"); 837f347c284SJohnny Huang } 838f347c284SJohnny Huang 839f347c284SJohnny Huang return OTP_SUCCESS; 840f347c284SJohnny Huang } 841f347c284SJohnny Huang 842794e27ecSJohnny Huang static void otp_print_revid(u32 *rid) 843794e27ecSJohnny Huang { 844794e27ecSJohnny Huang int bit_offset; 845794e27ecSJohnny Huang int i, j; 846794e27ecSJohnny Huang 847794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 848794e27ecSJohnny Huang printf("___________________________________________________\n"); 849794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 850794e27ecSJohnny Huang if (i < 32) { 851794e27ecSJohnny Huang j = 0; 852794e27ecSJohnny Huang bit_offset = i; 853794e27ecSJohnny Huang } else { 854794e27ecSJohnny Huang j = 1; 855794e27ecSJohnny Huang bit_offset = i - 32; 856794e27ecSJohnny Huang } 857794e27ecSJohnny Huang if (i % 16 == 0) 858794e27ecSJohnny Huang printf("%2x | ", i); 859794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1); 860794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 861794e27ecSJohnny Huang printf("\n"); 862794e27ecSJohnny Huang } 863794e27ecSJohnny Huang } 864794e27ecSJohnny Huang 865b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout) 866b25f02d2SJohnny Huang { 867b25f02d2SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 868b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 869b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 870b25f02d2SJohnny Huang int i; 871b25f02d2SJohnny Huang u32 scu_offset; 872b25f02d2SJohnny Huang u32 dw_offset; 873b25f02d2SJohnny Huang u32 bit_offset; 874b25f02d2SJohnny Huang u32 mask; 875b25f02d2SJohnny Huang u32 otp_value; 876b25f02d2SJohnny Huang u32 otp_ignore; 877b25f02d2SJohnny Huang 878b25f02d2SJohnny Huang printf("SCU BIT reg_protect Description\n"); 879b25f02d2SJohnny Huang printf("____________________________________________________________________\n"); 880b25f02d2SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 881b25f02d2SJohnny Huang mask = BIT(scu_info[i].length) - 1; 882b25f02d2SJohnny Huang 883b25f02d2SJohnny Huang if (scu_info[i].bit_offset > 31) { 884b25f02d2SJohnny Huang scu_offset = 0x510; 885b25f02d2SJohnny Huang dw_offset = 1; 886b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset - 32; 887b25f02d2SJohnny Huang } else { 888b25f02d2SJohnny Huang scu_offset = 0x500; 889b25f02d2SJohnny Huang dw_offset = 0; 890b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset; 891b25f02d2SJohnny Huang } 892b25f02d2SJohnny Huang 893b25f02d2SJohnny Huang otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask; 894b25f02d2SJohnny Huang otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask; 895b25f02d2SJohnny Huang 896b25f02d2SJohnny Huang if (otp_ignore == mask) 897b25f02d2SJohnny Huang continue; 898b25f02d2SJohnny Huang else if (otp_ignore != 0) 899b25f02d2SJohnny Huang return OTP_FAILURE; 900b25f02d2SJohnny Huang 901b25f02d2SJohnny Huang if (otp_value != 0 && otp_value != mask) 902b25f02d2SJohnny Huang return OTP_FAILURE; 903b25f02d2SJohnny Huang 904b25f02d2SJohnny Huang printf("0x%-6X", scu_offset); 905b25f02d2SJohnny Huang if (scu_info[i].length == 1) 906b25f02d2SJohnny Huang printf("0x%-11X", bit_offset); 907b25f02d2SJohnny Huang else 908b25f02d2SJohnny Huang printf("0x%-2X:0x%-4x", bit_offset, bit_offset + scu_info[i].length - 1); 909b25f02d2SJohnny Huang printf("0x%-14X", otp_value); 910b25f02d2SJohnny Huang printf("%s\n", scu_info[i].information); 911b25f02d2SJohnny Huang } 912b25f02d2SJohnny Huang return OTP_SUCCESS; 913b25f02d2SJohnny Huang } 914b25f02d2SJohnny Huang 9150dc9a440SJohnny Huang static void otp_print_scu_info(void) 9160dc9a440SJohnny Huang { 9170dc9a440SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 9180dc9a440SJohnny Huang u32 OTPCFG[2]; 9190dc9a440SJohnny Huang u32 scu_offset; 9200dc9a440SJohnny Huang u32 bit_offset; 9210dc9a440SJohnny Huang u32 reg_p; 9220dc9a440SJohnny Huang u32 length; 9230dc9a440SJohnny Huang int i, j; 9240dc9a440SJohnny Huang 9250dc9a440SJohnny Huang otp_soak(0); 9260dc9a440SJohnny Huang otp_read_conf(28, &OTPCFG[0]); 9270dc9a440SJohnny Huang otp_read_conf(29, &OTPCFG[1]); 9280dc9a440SJohnny Huang printf("SCU BIT reg_protect Description\n"); 9290dc9a440SJohnny Huang printf("____________________________________________________________________\n"); 9300dc9a440SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 9310dc9a440SJohnny Huang length = scu_info[i].length; 9320dc9a440SJohnny Huang for (j = 0; j < length; j++) { 9330dc9a440SJohnny Huang if (scu_info[i].bit_offset + j < 32) { 9340dc9a440SJohnny Huang scu_offset = 0x500; 9350dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j; 9360dc9a440SJohnny Huang reg_p = (OTPCFG[0] >> bit_offset) & 0x1; 9370dc9a440SJohnny Huang } else { 9380dc9a440SJohnny Huang scu_offset = 0x510; 9390dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j - 32; 9400dc9a440SJohnny Huang reg_p = (OTPCFG[1] >> bit_offset) & 0x1; 9410dc9a440SJohnny Huang } 9420dc9a440SJohnny Huang printf("0x%-6X", scu_offset); 9430dc9a440SJohnny Huang printf("0x%-4X", bit_offset); 9440dc9a440SJohnny Huang printf("0x%-13X", reg_p); 9450dc9a440SJohnny Huang if (length == 1) { 9460dc9a440SJohnny Huang printf(" %s\n", scu_info[i].information); 9470dc9a440SJohnny Huang continue; 9480dc9a440SJohnny Huang } 9490dc9a440SJohnny Huang 9500dc9a440SJohnny Huang if (j == 0) 9510dc9a440SJohnny Huang printf("/%s\n", scu_info[i].information); 9520dc9a440SJohnny Huang else if (j == length - 1) 9530dc9a440SJohnny Huang printf("\\ \"\n"); 9540dc9a440SJohnny Huang else 9550dc9a440SJohnny Huang printf("| \"\n"); 9560dc9a440SJohnny Huang } 9570dc9a440SJohnny Huang } 9580dc9a440SJohnny Huang } 9590dc9a440SJohnny Huang 960696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 96169d5fd8fSJohnny Huang { 96279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 963a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 964a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 965a219f6deSJohnny Huang u32 mask; 966a219f6deSJohnny Huang u32 dw_offset; 967a219f6deSJohnny Huang u32 bit_offset; 968a219f6deSJohnny Huang u32 otp_value; 969a219f6deSJohnny Huang u32 otp_ignore; 970b458cd62SJohnny Huang int fail = 0; 9717adec5f6SJohnny Huang int mask_err; 972794e27ecSJohnny Huang int rid_num = 0; 97373f11549SJohnny Huang char valid_bit[20]; 974794e27ecSJohnny Huang int fz; 97566f2f8e5SJohnny Huang int i; 97673f11549SJohnny Huang int j; 97766f2f8e5SJohnny Huang 978737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 97966f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 9803cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 9817adec5f6SJohnny Huang mask_err = 0; 9823cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 9833cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 9843cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 985b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 986696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 987b458cd62SJohnny Huang 9887adec5f6SJohnny Huang if (conf_info[i].value == OTP_REG_VALID_BIT) { 9897adec5f6SJohnny Huang if (((otp_value + otp_ignore) & mask) != mask) { 990b458cd62SJohnny Huang fail = 1; 9917adec5f6SJohnny Huang mask_err = 1; 9927adec5f6SJohnny Huang } 9937adec5f6SJohnny Huang } else { 9947adec5f6SJohnny Huang if (otp_ignore == mask) { 9957adec5f6SJohnny Huang continue; 9967adec5f6SJohnny Huang } else if (otp_ignore != 0) { 9977adec5f6SJohnny Huang fail = 1; 9987adec5f6SJohnny Huang mask_err = 1; 9997adec5f6SJohnny Huang } 10007adec5f6SJohnny Huang } 1001b458cd62SJohnny Huang 1002a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 10033cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 10043cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 10053cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1006b458cd62SJohnny Huang continue; 1007b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1008b458cd62SJohnny Huang 10093cb28812SJohnny Huang if (conf_info[i].length == 1) { 10103cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 101166f2f8e5SJohnny Huang } else { 1012b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 10133cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 10143cb28812SJohnny Huang conf_info[i].bit_offset); 101566f2f8e5SJohnny Huang } 1016b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1017b458cd62SJohnny Huang 10187adec5f6SJohnny Huang if (mask_err) { 10197adec5f6SJohnny Huang printf("Ignore, mask error\n"); 1020a219f6deSJohnny Huang continue; 1021a219f6deSJohnny Huang } 10223cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1023b458cd62SJohnny Huang printf("Reserved\n"); 10243cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 10253cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1026b458cd62SJohnny Huang printf("\n"); 10273cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1028b458cd62SJohnny Huang if (otp_value != 0) { 102973f11549SJohnny Huang for (j = 0; j < 7; j++) { 1030a219f6deSJohnny Huang if (otp_value == (1 << j)) 103173f11549SJohnny Huang valid_bit[j * 2] = '1'; 1032a219f6deSJohnny Huang else 103373f11549SJohnny Huang valid_bit[j * 2] = '0'; 103473f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 103573f11549SJohnny Huang } 103673f11549SJohnny Huang valid_bit[15] = 0; 103773f11549SJohnny Huang } else { 103873f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1039b458cd62SJohnny Huang } 10403cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1041b458cd62SJohnny Huang printf("\n"); 1042b458cd62SJohnny Huang } else { 10433cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1044b458cd62SJohnny Huang } 1045b458cd62SJohnny Huang } 1046b458cd62SJohnny Huang 1047794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) { 1048794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) { 1049794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1050794e27ecSJohnny Huang fail = 1; 1051794e27ecSJohnny Huang } else { 1052794e27ecSJohnny Huang fz = 0; 1053794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 1054794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) { 1055794e27ecSJohnny Huang if (!fz) 1056794e27ecSJohnny Huang fz = 1; 1057794e27ecSJohnny Huang } else { 1058794e27ecSJohnny Huang rid_num++; 1059794e27ecSJohnny Huang if (fz) { 1060794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1061794e27ecSJohnny Huang fail = 1; 1062794e27ecSJohnny Huang break; 1063794e27ecSJohnny Huang } 1064794e27ecSJohnny Huang } 1065794e27ecSJohnny Huang } 1066794e27ecSJohnny Huang } 1067794e27ecSJohnny Huang if (fail) 1068794e27ecSJohnny Huang printf("OTP revision ID\n"); 1069794e27ecSJohnny Huang else 1070794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1071794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]); 1072794e27ecSJohnny Huang } 1073794e27ecSJohnny Huang 1074b458cd62SJohnny Huang if (fail) 1075b458cd62SJohnny Huang return OTP_FAILURE; 1076b458cd62SJohnny Huang 107766f2f8e5SJohnny Huang return OTP_SUCCESS; 107866f2f8e5SJohnny Huang } 107966f2f8e5SJohnny Huang 10802d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 108166f2f8e5SJohnny Huang { 108279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1083a219f6deSJohnny Huang u32 OTPCFG[16]; 1084a219f6deSJohnny Huang u32 mask; 1085a219f6deSJohnny Huang u32 dw_offset; 1086a219f6deSJohnny Huang u32 bit_offset; 1087a219f6deSJohnny Huang u32 otp_value; 108873f11549SJohnny Huang char valid_bit[20]; 108966f2f8e5SJohnny Huang int i; 109073f11549SJohnny Huang int j; 109166f2f8e5SJohnny Huang 1092dacbba92SJohnny Huang otp_soak(0); 1093bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 1094f347c284SJohnny Huang otp_read_conf(i, &OTPCFG[i]); 109566f2f8e5SJohnny Huang 1096b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 1097b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 10983cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 10993cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 11002d4b0742SJohnny Huang continue; 11013cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 11023cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 11033cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1104b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1105b458cd62SJohnny Huang 1106a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 11073cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 11083cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 11093cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1110b458cd62SJohnny Huang continue; 1111b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1112b458cd62SJohnny Huang 11133cb28812SJohnny Huang if (conf_info[i].length == 1) { 11143cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 1115b458cd62SJohnny Huang } else { 1116b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 11173cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 11183cb28812SJohnny Huang conf_info[i].bit_offset); 1119b458cd62SJohnny Huang } 1120b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1121b458cd62SJohnny Huang 11223cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1123b458cd62SJohnny Huang printf("Reserved\n"); 11243cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 11253cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1126b458cd62SJohnny Huang printf("\n"); 11273cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1128b458cd62SJohnny Huang if (otp_value != 0) { 112973f11549SJohnny Huang for (j = 0; j < 7; j++) { 1130030cb4a7SJohnny Huang if (otp_value & (1 << j)) 113173f11549SJohnny Huang valid_bit[j * 2] = '1'; 1132a219f6deSJohnny Huang else 113373f11549SJohnny Huang valid_bit[j * 2] = '0'; 113473f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 113573f11549SJohnny Huang } 113673f11549SJohnny Huang valid_bit[15] = 0; 113773f11549SJohnny Huang } else { 113873f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1139b458cd62SJohnny Huang } 11403cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1141b458cd62SJohnny Huang printf("\n"); 1142b458cd62SJohnny Huang } else { 11433cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1144b458cd62SJohnny Huang } 1145b458cd62SJohnny Huang } 1146b458cd62SJohnny Huang return OTP_SUCCESS; 114766f2f8e5SJohnny Huang } 114866f2f8e5SJohnny Huang 11495010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 115076d13988SJohnny Huang { 115179e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 1152a219f6deSJohnny Huang u32 *OTPSTRAP; 1153a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 1154a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 115576d13988SJohnny Huang int i; 1156a8bd6d8cSJohnny Huang int fail = 0; 1157a219f6deSJohnny Huang u32 bit_offset; 1158a219f6deSJohnny Huang u32 dw_offset; 1159a219f6deSJohnny Huang u32 mask; 1160a219f6deSJohnny Huang u32 otp_value; 1161a219f6deSJohnny Huang u32 otp_protect; 1162a219f6deSJohnny Huang u32 otp_ignore; 116376d13988SJohnny Huang 1164a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 1165a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 1166a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 11677e523e3bSJohnny Huang 1168a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 1169de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 1170b458cd62SJohnny Huang 11713cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 11727adec5f6SJohnny Huang fail = 0; 1173696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 1174a8bd6d8cSJohnny Huang dw_offset = 1; 11753cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 1176a8bd6d8cSJohnny Huang } else { 1177a8bd6d8cSJohnny Huang dw_offset = 0; 11783cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 1179a8bd6d8cSJohnny Huang } 118076d13988SJohnny Huang 11813cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 1182a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 1183a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 1184696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 1185a8bd6d8cSJohnny Huang 1186a219f6deSJohnny Huang if (otp_ignore == mask) 1187a8bd6d8cSJohnny Huang continue; 1188a219f6deSJohnny Huang else if (otp_ignore != 0) 1189a8bd6d8cSJohnny Huang fail = 1; 1190a8bd6d8cSJohnny Huang 1191a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 11923cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1193a8bd6d8cSJohnny Huang continue; 1194a8bd6d8cSJohnny Huang 11953cb28812SJohnny Huang if (strap_info[i].length == 1) { 11963cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1197a8bd6d8cSJohnny Huang } else { 1198b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 11993cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 12003cb28812SJohnny Huang strap_info[i].bit_offset); 1201a8bd6d8cSJohnny Huang } 1202a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 1203a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 1204a8bd6d8cSJohnny Huang 1205a8bd6d8cSJohnny Huang if (fail) { 1206696656c6SJohnny Huang printf("Ignore mask error\n"); 1207a8bd6d8cSJohnny Huang } else { 12083cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12093cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1210a8bd6d8cSJohnny Huang else 1211a8bd6d8cSJohnny Huang printf("Reserved\n"); 1212a8bd6d8cSJohnny Huang } 1213a8bd6d8cSJohnny Huang } 1214a8bd6d8cSJohnny Huang 1215a8bd6d8cSJohnny Huang if (fail) 121676d13988SJohnny Huang return OTP_FAILURE; 121776d13988SJohnny Huang 121876d13988SJohnny Huang return OTP_SUCCESS; 121976d13988SJohnny Huang } 122076d13988SJohnny Huang 1221b458cd62SJohnny Huang static int otp_print_strap_info(int view) 122276d13988SJohnny Huang { 122379e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 122476d13988SJohnny Huang struct otpstrap_status strap_status[64]; 122507baa4e8SJohnny Huang int i, j; 1226b458cd62SJohnny Huang int fail = 0; 1227a219f6deSJohnny Huang u32 bit_offset; 1228a219f6deSJohnny Huang u32 length; 1229a219f6deSJohnny Huang u32 otp_value; 1230a219f6deSJohnny Huang u32 otp_protect; 123176d13988SJohnny Huang 1232541eb887SJohnny Huang otp_strap_status(strap_status); 123376d13988SJohnny Huang 1234b458cd62SJohnny Huang if (view) { 123507baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 123607baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 1237b458cd62SJohnny Huang } else { 1238b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 1239b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 124076d13988SJohnny Huang } 12413cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 1242b458cd62SJohnny Huang otp_value = 0; 12433cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 12443cb28812SJohnny Huang length = strap_info[i].length; 1245b458cd62SJohnny Huang for (j = 0; j < length; j++) { 1246c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 1247c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 1248b458cd62SJohnny Huang } 1249a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 12503cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1251b458cd62SJohnny Huang continue; 1252b458cd62SJohnny Huang if (view) { 1253b458cd62SJohnny Huang for (j = 0; j < length; j++) { 12543cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 1255b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 125607baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 1257e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 12583cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 1259b458cd62SJohnny Huang printf(" Reserved\n"); 1260b458cd62SJohnny Huang continue; 1261b458cd62SJohnny Huang } 1262b458cd62SJohnny Huang if (length == 1) { 12633cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 1264b458cd62SJohnny Huang continue; 126576d13988SJohnny Huang } 126676d13988SJohnny Huang 1267b458cd62SJohnny Huang if (j == 0) 12683cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 1269b458cd62SJohnny Huang else if (j == length - 1) 1270b458cd62SJohnny Huang printf("\\ \"\n"); 1271b458cd62SJohnny Huang else 1272b458cd62SJohnny Huang printf("| \"\n"); 127376d13988SJohnny Huang } 1274b458cd62SJohnny Huang } else { 1275c947ef08SJohnny Huang if (length == 1) { 12763cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1277b458cd62SJohnny Huang } else { 1278b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 1279b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 1280b458cd62SJohnny Huang } 1281b458cd62SJohnny Huang 1282b458cd62SJohnny Huang printf("0x%-10X", otp_value); 1283b458cd62SJohnny Huang 12843cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12853cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1286b458cd62SJohnny Huang else 1287b458cd62SJohnny Huang printf("Reserved\n"); 1288b458cd62SJohnny Huang } 1289b458cd62SJohnny Huang } 1290b458cd62SJohnny Huang 1291b458cd62SJohnny Huang if (fail) 1292b458cd62SJohnny Huang return OTP_FAILURE; 1293b458cd62SJohnny Huang 1294b458cd62SJohnny Huang return OTP_SUCCESS; 1295b458cd62SJohnny Huang } 1296b458cd62SJohnny Huang 1297f347c284SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 129869d5fd8fSJohnny Huang { 129969d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 130079e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 13019a4fe690SJohnny Huang struct otpkey_type key_info; 1302a219f6deSJohnny Huang u32 *buf; 1303a219f6deSJohnny Huang u8 *byte_buf; 13049d998018SJohnny Huang char empty = 1; 130569d5fd8fSJohnny Huang int i = 0, len = 0; 13069a4fe690SJohnny Huang int j; 130754552c69SJohnny Huang 1308696656c6SJohnny Huang byte_buf = image_layout->data; 1309a219f6deSJohnny Huang buf = (u32 *)byte_buf; 13109d998018SJohnny Huang 13119d998018SJohnny Huang for (i = 0; i < 16; i++) { 1312a219f6deSJohnny Huang if (buf[i] != 0) 13139d998018SJohnny Huang empty = 0; 13149d998018SJohnny Huang } 13159d998018SJohnny Huang if (empty) 1316f347c284SJohnny Huang return OTP_SUCCESS; 13179d998018SJohnny Huang 13189d998018SJohnny Huang i = 0; 131969d5fd8fSJohnny Huang while (1) { 132069d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 132169d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 132269d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 132369d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 132469d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 132569d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 13269a4fe690SJohnny Huang 13279a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 13289a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 13299a4fe690SJohnny Huang key_info = key_info_array[j]; 13309a4fe690SJohnny Huang break; 13319a4fe690SJohnny Huang } 13329a4fe690SJohnny Huang } 13339a4fe690SJohnny Huang 13347f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 133569d5fd8fSJohnny Huang printf("Key Type: "); 13369a4fe690SJohnny Huang printf("%s\n", key_info.information); 13379a4fe690SJohnny Huang 13389a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 133969d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 134069d5fd8fSJohnny Huang switch (key_length) { 134169d5fd8fSJohnny Huang case 0: 134269d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 134369d5fd8fSJohnny Huang break; 134469d5fd8fSJohnny Huang case 1: 134569d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 134669d5fd8fSJohnny Huang break; 134769d5fd8fSJohnny Huang case 2: 134869d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 134969d5fd8fSJohnny Huang break; 135069d5fd8fSJohnny Huang case 3: 135169d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 135269d5fd8fSJohnny Huang break; 135369d5fd8fSJohnny Huang } 1354181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1355181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 135669d5fd8fSJohnny Huang printf("RSA SHA Type: "); 135769d5fd8fSJohnny Huang switch (key_length) { 135869d5fd8fSJohnny Huang case 0: 135969d5fd8fSJohnny Huang printf("RSA1024\n"); 136069d5fd8fSJohnny Huang len = 0x100; 136169d5fd8fSJohnny Huang break; 136269d5fd8fSJohnny Huang case 1: 136369d5fd8fSJohnny Huang printf("RSA2048\n"); 136469d5fd8fSJohnny Huang len = 0x200; 136569d5fd8fSJohnny Huang break; 136669d5fd8fSJohnny Huang case 2: 136769d5fd8fSJohnny Huang printf("RSA3072\n"); 136869d5fd8fSJohnny Huang len = 0x300; 136969d5fd8fSJohnny Huang break; 137069d5fd8fSJohnny Huang case 3: 137169d5fd8fSJohnny Huang printf("RSA4096\n"); 137269d5fd8fSJohnny Huang len = 0x400; 137369d5fd8fSJohnny Huang break; 137469d5fd8fSJohnny Huang } 137569d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 137669d5fd8fSJohnny Huang } 13779a4fe690SJohnny Huang if (key_info.need_id) 137869d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 137969d5fd8fSJohnny Huang printf("Key Value:\n"); 13809a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 138169d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 13829a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 13839a4fe690SJohnny Huang printf("AES Key:\n"); 13849a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 1385e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 13869a4fe690SJohnny Huang printf("AES IV:\n"); 13879a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 13889a4fe690SJohnny Huang } 13899a4fe690SJohnny Huang 13909a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1391e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 139269d5fd8fSJohnny Huang printf("AES Key:\n"); 139369d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 139469d5fd8fSJohnny Huang printf("AES IV:\n"); 139569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 13965fdde29fSJohnny Huang } else { 13979a4fe690SJohnny Huang printf("AES Key 1:\n"); 13989a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 13999a4fe690SJohnny Huang printf("AES Key 2:\n"); 14009a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 14019a4fe690SJohnny Huang } 1402181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 140369d5fd8fSJohnny Huang printf("RSA mod:\n"); 140469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 140569d5fd8fSJohnny Huang printf("RSA exp:\n"); 140669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1407181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1408181f72d8SJohnny Huang printf("RSA mod:\n"); 1409181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1410181f72d8SJohnny Huang printf("RSA exp:\n"); 1411a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 141269d5fd8fSJohnny Huang } 141369d5fd8fSJohnny Huang if (last) 141469d5fd8fSJohnny Huang break; 141569d5fd8fSJohnny Huang i++; 141669d5fd8fSJohnny Huang } 1417f347c284SJohnny Huang return OTP_SUCCESS; 1418f347c284SJohnny Huang } 1419f347c284SJohnny Huang 1420b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data) 1421f347c284SJohnny Huang { 1422f347c284SJohnny Huang int i; 1423f347c284SJohnny Huang int ret; 1424f347c284SJohnny Huang u32 *buf; 1425f347c284SJohnny Huang u32 *buf_ignore; 1426f347c284SJohnny Huang 1427f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1428f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1429f347c284SJohnny Huang printf("Start Programing...\n"); 1430f347c284SJohnny Huang 1431f347c284SJohnny Huang // programing ecc region first 1432f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1433f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1434f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1435f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1436f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1437f347c284SJohnny Huang return ret; 1438f347c284SJohnny Huang } 1439f347c284SJohnny Huang } 1440f347c284SJohnny Huang 1441f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1442f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1443f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1444f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1445f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1446f347c284SJohnny Huang return ret; 1447f347c284SJohnny Huang } 1448f347c284SJohnny Huang } 1449f347c284SJohnny Huang otp_soak(0); 1450f347c284SJohnny Huang return OTP_SUCCESS; 1451f347c284SJohnny Huang } 1452f347c284SJohnny Huang 1453b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1454f347c284SJohnny Huang { 1455f347c284SJohnny Huang u32 *strap; 1456f347c284SJohnny Huang u32 *strap_ignore; 1457f347c284SJohnny Huang u32 *strap_pro; 1458f347c284SJohnny Huang u32 prog_address; 1459f347c284SJohnny Huang int i; 14607e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1461f347c284SJohnny Huang int fail = 0; 1462f347c284SJohnny Huang int ret; 1463f347c284SJohnny Huang int prog_flag = 0; 1464f347c284SJohnny Huang 1465f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1466f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1467f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1468f347c284SJohnny Huang 1469f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1470f347c284SJohnny Huang prog_address = 0x800; 1471f347c284SJohnny Huang if (i < 32) { 1472f347c284SJohnny Huang offset = i; 1473f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1474f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1475f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1476f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1477f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1478f347c284SJohnny Huang 1479f347c284SJohnny Huang } else { 1480f347c284SJohnny Huang offset = (i - 32); 1481f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1482f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1483f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1484f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1485f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1486f347c284SJohnny Huang } 1487f347c284SJohnny Huang 1488f347c284SJohnny Huang if (ibit == 1) 1489f347c284SJohnny Huang continue; 1490f347c284SJohnny Huang if (bit == otpstrap[i].value) 1491f347c284SJohnny Huang prog_flag = 0; 1492f347c284SJohnny Huang else 1493f347c284SJohnny Huang prog_flag = 1; 1494f347c284SJohnny Huang 1495f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1496f347c284SJohnny Huang fail = 1; 1497f347c284SJohnny Huang continue; 1498f347c284SJohnny Huang } 1499f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1500f347c284SJohnny Huang fail = 1; 1501f347c284SJohnny Huang continue; 1502f347c284SJohnny Huang } 1503f347c284SJohnny Huang 1504f347c284SJohnny Huang if (prog_flag) { 1505f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1506f347c284SJohnny Huang if (ret) 1507f347c284SJohnny Huang return OTP_FAILURE; 1508f347c284SJohnny Huang } 1509f347c284SJohnny Huang 1510f347c284SJohnny Huang if (pbit != 0) { 1511f347c284SJohnny Huang prog_address = 0x800; 1512f347c284SJohnny Huang if (i < 32) 1513f347c284SJohnny Huang prog_address |= 0x60c; 1514f347c284SJohnny Huang else 1515f347c284SJohnny Huang prog_address |= 0x60e; 1516f347c284SJohnny Huang 1517f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1518f347c284SJohnny Huang if (ret) 1519f347c284SJohnny Huang return OTP_FAILURE; 1520f347c284SJohnny Huang } 1521f347c284SJohnny Huang } 1522f347c284SJohnny Huang otp_soak(0); 1523f347c284SJohnny Huang if (fail == 1) 1524f347c284SJohnny Huang return OTP_FAILURE; 1525f347c284SJohnny Huang return OTP_SUCCESS; 152669d5fd8fSJohnny Huang } 152769d5fd8fSJohnny Huang 1528b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf) 152969d5fd8fSJohnny Huang { 1530a6d0d645SJohnny Huang int i, k; 1531d90825e2SJohnny Huang int pass = 0; 1532a219f6deSJohnny Huang u32 prog_address; 1533a219f6deSJohnny Huang u32 compare[2]; 1534a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1535a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1536a219f6deSJohnny Huang u32 data_masked; 1537a219f6deSJohnny Huang u32 buf_masked; 153869d5fd8fSJohnny Huang 1539a6d0d645SJohnny Huang printf("Start Programing...\n"); 1540d90825e2SJohnny Huang otp_soak(0); 1541bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 1542b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 15435010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1544a6d0d645SJohnny Huang prog_address = 0x800; 1545a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1546a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1547bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1548bb34a7bfSJohnny Huang pass = 1; 1549a6d0d645SJohnny Huang continue; 1550bb34a7bfSJohnny Huang } 1551de6fbf1cSJohnny Huang 1552de6fbf1cSJohnny Huang otp_soak(1); 15535010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1554a6d0d645SJohnny Huang 155569d5fd8fSJohnny Huang pass = 0; 155669d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 15575010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1558de6fbf1cSJohnny Huang otp_soak(2); 1559feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 15605010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1561de6fbf1cSJohnny Huang otp_soak(1); 1562de6fbf1cSJohnny Huang } else { 1563de6fbf1cSJohnny Huang pass = 1; 1564de6fbf1cSJohnny Huang break; 1565de6fbf1cSJohnny Huang } 1566a6d0d645SJohnny Huang } else { 156769d5fd8fSJohnny Huang pass = 1; 156869d5fd8fSJohnny Huang break; 156969d5fd8fSJohnny Huang } 157069d5fd8fSJohnny Huang } 1571bb34a7bfSJohnny Huang if (pass == 0) { 1572b64ca396SJohnny Huang printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n", 1573b64ca396SJohnny Huang i, otp_conf[i], conf[i], conf_ignore[i]); 1574bb34a7bfSJohnny Huang break; 1575bb34a7bfSJohnny Huang } 1576a6d0d645SJohnny Huang } 1577a6d0d645SJohnny Huang 1578de6fbf1cSJohnny Huang otp_soak(0); 157969d5fd8fSJohnny Huang if (!pass) 15802a856b9aSJohnny Huang return OTP_FAILURE; 1581a6d0d645SJohnny Huang 15822a856b9aSJohnny Huang return OTP_SUCCESS; 158369d5fd8fSJohnny Huang } 158469d5fd8fSJohnny Huang 1585b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro) 1586b25f02d2SJohnny Huang { 1587b25f02d2SJohnny Huang int i, k; 1588b25f02d2SJohnny Huang int pass = 0; 1589b25f02d2SJohnny Huang u32 prog_address; 1590b25f02d2SJohnny Huang u32 compare[2]; 1591b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1592b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1593b25f02d2SJohnny Huang u32 data_masked; 1594b25f02d2SJohnny Huang u32 buf_masked; 1595b25f02d2SJohnny Huang 1596b25f02d2SJohnny Huang printf("Start Programing...\n"); 1597b25f02d2SJohnny Huang otp_soak(0); 1598b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1599b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1600b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1601b25f02d2SJohnny Huang prog_address = 0xe08 + i * 2; 1602b25f02d2SJohnny Huang if (data_masked == buf_masked) { 1603b25f02d2SJohnny Huang pass = 1; 1604b25f02d2SJohnny Huang continue; 1605b25f02d2SJohnny Huang } 1606b25f02d2SJohnny Huang 1607b25f02d2SJohnny Huang otp_soak(1); 1608b25f02d2SJohnny Huang otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address); 1609b25f02d2SJohnny Huang 1610b25f02d2SJohnny Huang pass = 0; 1611b25f02d2SJohnny Huang for (k = 0; k < RETRY; k++) { 1612b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1613b25f02d2SJohnny Huang otp_soak(2); 1614b25f02d2SJohnny Huang otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address); 1615b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1616b25f02d2SJohnny Huang otp_soak(1); 1617b25f02d2SJohnny Huang } else { 1618b25f02d2SJohnny Huang pass = 1; 1619b25f02d2SJohnny Huang break; 1620b25f02d2SJohnny Huang } 1621b25f02d2SJohnny Huang } else { 1622b25f02d2SJohnny Huang pass = 1; 1623b25f02d2SJohnny Huang break; 1624b25f02d2SJohnny Huang } 1625b25f02d2SJohnny Huang } 1626b25f02d2SJohnny Huang if (pass == 0) { 1627b489486eSJohnny Huang printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n", 1628b25f02d2SJohnny Huang i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]); 1629b25f02d2SJohnny Huang break; 1630b25f02d2SJohnny Huang } 1631b25f02d2SJohnny Huang } 1632b25f02d2SJohnny Huang 1633b25f02d2SJohnny Huang otp_soak(0); 1634b25f02d2SJohnny Huang if (!pass) 1635b25f02d2SJohnny Huang return OTP_FAILURE; 1636b25f02d2SJohnny Huang 1637b25f02d2SJohnny Huang return OTP_SUCCESS; 1638b25f02d2SJohnny Huang } 1639b25f02d2SJohnny Huang 1640b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data) 1641b64ca396SJohnny Huang { 1642b64ca396SJohnny Huang int data_dw; 1643b64ca396SJohnny Huang u32 data_masked; 1644b64ca396SJohnny Huang u32 buf_masked; 1645b64ca396SJohnny Huang u32 *buf = (u32 *)image_layout->data; 1646b64ca396SJohnny Huang u32 *buf_ignore = (u32 *)image_layout->data_ignore; 1647b64ca396SJohnny Huang int i; 1648b64ca396SJohnny Huang 1649b64ca396SJohnny Huang data_dw = image_layout->data_length / 4; 1650b64ca396SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1651b64ca396SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1652b64ca396SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1653b64ca396SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1654b64ca396SJohnny Huang if (data_masked == buf_masked) 1655b64ca396SJohnny Huang continue; 1656b64ca396SJohnny Huang if (i % 2 == 0) { 1657b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1658b64ca396SJohnny Huang continue; 1659b64ca396SJohnny Huang } else { 1660b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1661b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1662b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1663b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1664b64ca396SJohnny Huang return OTP_FAILURE; 1665b64ca396SJohnny Huang } 1666b64ca396SJohnny Huang } else { 1667b64ca396SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1668b64ca396SJohnny Huang continue; 1669b64ca396SJohnny Huang } else { 1670b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1671b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1672b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1673b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1674b64ca396SJohnny Huang return OTP_FAILURE; 1675b64ca396SJohnny Huang } 1676b64ca396SJohnny Huang } 1677b64ca396SJohnny Huang } 1678b64ca396SJohnny Huang return OTP_SUCCESS; 1679b64ca396SJohnny Huang } 1680b64ca396SJohnny Huang 1681b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1682b64ca396SJohnny Huang { 1683b64ca396SJohnny Huang int i; 1684b64ca396SJohnny Huang u32 *strap; 1685b64ca396SJohnny Huang u32 *strap_ignore; 1686b64ca396SJohnny Huang u32 *strap_pro; 1687b64ca396SJohnny Huang int bit, pbit, ibit; 1688b64ca396SJohnny Huang int fail = 0; 1689b64ca396SJohnny Huang int ret; 1690b64ca396SJohnny Huang 1691b64ca396SJohnny Huang strap = (u32 *)image_layout->strap; 1692b64ca396SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1693b64ca396SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1694b64ca396SJohnny Huang 1695b64ca396SJohnny Huang for (i = 0; i < 64; i++) { 1696b64ca396SJohnny Huang if (i < 32) { 1697b64ca396SJohnny Huang bit = (strap[0] >> i) & 0x1; 1698b64ca396SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1699b64ca396SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1700b64ca396SJohnny Huang } else { 1701b64ca396SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1702b64ca396SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1703b64ca396SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1704b64ca396SJohnny Huang } 1705b64ca396SJohnny Huang 1706b64ca396SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1707b64ca396SJohnny Huang 1708b64ca396SJohnny Huang if (ret == OTP_FAILURE) 1709b64ca396SJohnny Huang fail = 1; 1710b64ca396SJohnny Huang } 1711b64ca396SJohnny Huang if (fail == 1) { 1712b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1713b64ca396SJohnny Huang return OTP_FAILURE; 1714b64ca396SJohnny Huang } 1715b64ca396SJohnny Huang return OTP_SUCCESS; 1716b64ca396SJohnny Huang } 1717b64ca396SJohnny Huang 1718b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf) 1719b64ca396SJohnny Huang { 1720b64ca396SJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1721b64ca396SJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1722b64ca396SJohnny Huang u32 data_masked; 1723b64ca396SJohnny Huang u32 buf_masked; 1724b64ca396SJohnny Huang int i; 1725b64ca396SJohnny Huang 1726b64ca396SJohnny Huang for (i = 0; i < 16; i++) { 1727b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 1728b64ca396SJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1729b64ca396SJohnny Huang if (data_masked == buf_masked) 1730b64ca396SJohnny Huang continue; 1731b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1732b64ca396SJohnny Huang continue; 1733b64ca396SJohnny Huang } else { 1734b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1735b64ca396SJohnny Huang printf("OTPCFG[%X] = %x\n", i, otp_conf[i]); 1736b64ca396SJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 1737b64ca396SJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 1738b64ca396SJohnny Huang return OTP_FAILURE; 1739b64ca396SJohnny Huang } 1740b64ca396SJohnny Huang } 1741b64ca396SJohnny Huang return OTP_SUCCESS; 1742b64ca396SJohnny Huang } 1743b64ca396SJohnny Huang 1744b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro) 1745b25f02d2SJohnny Huang { 1746b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1747b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1748b25f02d2SJohnny Huang u32 data_masked; 1749b25f02d2SJohnny Huang u32 buf_masked; 1750b25f02d2SJohnny Huang int i; 1751b25f02d2SJohnny Huang 1752b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1753b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1754b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1755b25f02d2SJohnny Huang if (data_masked == buf_masked) 1756b25f02d2SJohnny Huang continue; 1757b25f02d2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1758b25f02d2SJohnny Huang continue; 1759b25f02d2SJohnny Huang } else { 1760b25f02d2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1761b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]); 1762b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]); 1763b489486eSJohnny Huang printf("Mask [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]); 1764b25f02d2SJohnny Huang return OTP_FAILURE; 1765b25f02d2SJohnny Huang } 1766b25f02d2SJohnny Huang } 1767b25f02d2SJohnny Huang return OTP_SUCCESS; 1768b25f02d2SJohnny Huang } 1769b25f02d2SJohnny Huang 1770f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf) 1771696656c6SJohnny Huang { 1772696656c6SJohnny Huang sha256_context ctx; 1773696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1774696656c6SJohnny Huang 1775696656c6SJohnny Huang sha256_starts(&ctx); 1776696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1777696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1778696656c6SJohnny Huang 1779696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1780f347c284SJohnny Huang return OTP_SUCCESS; 1781f347c284SJohnny Huang return OTP_FAILURE; 1782696656c6SJohnny Huang } 1783696656c6SJohnny Huang 1784f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 178569d5fd8fSJohnny Huang { 178669d5fd8fSJohnny Huang int ret; 178761a6cda7SJohnny Huang int image_soc_ver = 0; 1788696656c6SJohnny Huang struct otp_header *otp_header; 1789696656c6SJohnny Huang struct otp_image_layout image_layout; 1790696656c6SJohnny Huang int image_size; 1791a219f6deSJohnny Huang u8 *buf; 1792a219f6deSJohnny Huang u8 *checksum; 1793b64ca396SJohnny Huang int i; 1794b64ca396SJohnny Huang u32 data[2048]; 1795b64ca396SJohnny Huang u32 conf[16]; 1796b25f02d2SJohnny Huang u32 scu_pro[2]; 1797b64ca396SJohnny Huang struct otpstrap_status otpstrap[64]; 179869d5fd8fSJohnny Huang 1799696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1800696656c6SJohnny Huang if (!otp_header) { 1801030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 18022a856b9aSJohnny Huang return OTP_FAILURE; 180369d5fd8fSJohnny Huang } 1804d90825e2SJohnny Huang 1805696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1806696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1807696656c6SJohnny Huang 1808696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1809696656c6SJohnny Huang 1810696656c6SJohnny Huang if (!buf) { 1811030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 1812696656c6SJohnny Huang return OTP_FAILURE; 1813696656c6SJohnny Huang } 1814696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1815696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1816696656c6SJohnny Huang 1817696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1818030cb4a7SJohnny Huang printf("Image is invalid\n"); 1819696656c6SJohnny Huang return OTP_FAILURE; 1820696656c6SJohnny Huang } 1821696656c6SJohnny Huang 18225010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 18235010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 18245010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 18255010032bSJohnny Huang 18265010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1827696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 18285010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1829696656c6SJohnny Huang 1830696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 18315010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 18325010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 18335010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 18347e523e3bSJohnny Huang 1835b25f02d2SJohnny Huang image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info); 1836b25f02d2SJohnny Huang image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2); 1837b25f02d2SJohnny Huang image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length; 1838b25f02d2SJohnny Huang 18397e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 18407e523e3bSJohnny Huang image_soc_ver = OTP_A0; 184161a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 184261a6cda7SJohnny Huang image_soc_ver = OTP_A1; 184361a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 184461a6cda7SJohnny Huang image_soc_ver = OTP_A2; 184561a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 184661a6cda7SJohnny Huang image_soc_ver = OTP_A3; 1847696656c6SJohnny Huang } else { 1848030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n"); 1849696656c6SJohnny Huang return OTP_FAILURE; 1850696656c6SJohnny Huang } 1851696656c6SJohnny Huang 185261a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 1853030cb4a7SJohnny Huang printf("Version is not match\n"); 18549a4fe690SJohnny Huang return OTP_FAILURE; 18559a4fe690SJohnny Huang } 18569a4fe690SJohnny Huang 185761a6cda7SJohnny Huang if (otp_header->otptool_ver != OTPTOOL_VERSION(1, 0, 0)) { 1858030cb4a7SJohnny Huang printf("OTP image is not generated by otptool v1.0.0\n"); 185961a6cda7SJohnny Huang return OTP_FAILURE; 186061a6cda7SJohnny Huang } 186161a6cda7SJohnny Huang 1862f347c284SJohnny Huang if (otp_verify_image(buf, image_size, checksum)) { 1863030cb4a7SJohnny Huang printf("checksum is invalid\n"); 1864696656c6SJohnny Huang return OTP_FAILURE; 1865d90825e2SJohnny Huang } 18667332532cSJohnny Huang 1867030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 1868030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 1869030cb4a7SJohnny Huang return OTP_FAILURE; 1870030cb4a7SJohnny Huang } 1871b64ca396SJohnny Huang ret = 0; 1872030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 1873030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 1874030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 1875030cb4a7SJohnny Huang ret = -1; 1876030cb4a7SJohnny Huang } 1877030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 1878030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 1879030cb4a7SJohnny Huang ret = -1; 1880030cb4a7SJohnny Huang } 1881b64ca396SJohnny Huang printf("Read OTP Data Region:\n"); 1882b64ca396SJohnny Huang for (i = 0; i < 2048 ; i += 2) 1883b64ca396SJohnny Huang otp_read_data(i, &data[i]); 1884b64ca396SJohnny Huang 1885b64ca396SJohnny Huang printf("Check writable...\n"); 1886b64ca396SJohnny Huang if (otp_check_data_image(&image_layout, data) == OTP_FAILURE) 1887b64ca396SJohnny Huang ret = -1; 1888030cb4a7SJohnny Huang } 1889030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 1890030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 1891030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 1892030cb4a7SJohnny Huang ret = -1; 1893030cb4a7SJohnny Huang } 1894b64ca396SJohnny Huang printf("Read OTP Config Region:\n"); 1895b64ca396SJohnny Huang for (i = 0; i < 16 ; i++) 1896b64ca396SJohnny Huang otp_read_conf(i, &conf[i]); 1897b64ca396SJohnny Huang 1898b64ca396SJohnny Huang printf("Check writable...\n"); 1899b64ca396SJohnny Huang if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE) 1900b64ca396SJohnny Huang ret = -1; 1901030cb4a7SJohnny Huang } 1902030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 1903030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 1904030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 1905030cb4a7SJohnny Huang ret = -1; 1906030cb4a7SJohnny Huang } 1907b64ca396SJohnny Huang printf("Read OTP Strap Region:\n"); 1908b64ca396SJohnny Huang otp_strap_status(otpstrap); 1909b64ca396SJohnny Huang 1910b64ca396SJohnny Huang printf("Check writable...\n"); 1911b64ca396SJohnny Huang if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE) 1912b64ca396SJohnny Huang ret = -1; 1913030cb4a7SJohnny Huang } 1914b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 1915b25f02d2SJohnny Huang if (info_cb.pro_sts.pro_strap) { 1916b25f02d2SJohnny Huang printf("OTP strap region is protected\n"); 1917b25f02d2SJohnny Huang ret = -1; 1918b25f02d2SJohnny Huang } 1919b25f02d2SJohnny Huang printf("Read SCU Protect Region:\n"); 1920b25f02d2SJohnny Huang otp_read_conf(28, &scu_pro[0]); 1921b25f02d2SJohnny Huang otp_read_conf(29, &scu_pro[1]); 1922b25f02d2SJohnny Huang 1923b25f02d2SJohnny Huang printf("Check writable...\n"); 1924b25f02d2SJohnny Huang if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE) 1925b25f02d2SJohnny Huang ret = -1; 1926b25f02d2SJohnny Huang } 1927030cb4a7SJohnny Huang if (ret == -1) 1928030cb4a7SJohnny Huang return OTP_FAILURE; 1929b64ca396SJohnny Huang 193069d5fd8fSJohnny Huang if (!nconfirm) { 1931696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 19327f795e57SJohnny Huang printf("\nOTP data region :\n"); 1933f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 193469d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 19352a856b9aSJohnny Huang return OTP_FAILURE; 193669d5fd8fSJohnny Huang } 193769d5fd8fSJohnny Huang } 1938696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 19397332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1940696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 19417332532cSJohnny Huang printf("OTP config error, please check.\n"); 19427332532cSJohnny Huang return OTP_FAILURE; 19437332532cSJohnny Huang } 19447332532cSJohnny Huang } 19457adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 19467adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 19477adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 19487adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 19497adec5f6SJohnny Huang return OTP_FAILURE; 19507adec5f6SJohnny Huang } 19517adec5f6SJohnny Huang } 1952b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 1953b25f02d2SJohnny Huang printf("\nOTP scu protect region :\n"); 1954b25f02d2SJohnny Huang if (otp_print_scu_image(&image_layout) < 0) { 1955b25f02d2SJohnny Huang printf("OTP scu protect error, please check.\n"); 1956b25f02d2SJohnny Huang return OTP_FAILURE; 1957b25f02d2SJohnny Huang } 1958b25f02d2SJohnny Huang } 19597332532cSJohnny Huang 196069d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 196169d5fd8fSJohnny Huang if (!confirm_yesno()) { 196269d5fd8fSJohnny Huang printf(" Aborting\n"); 19632a856b9aSJohnny Huang return OTP_FAILURE; 196469d5fd8fSJohnny Huang } 196569d5fd8fSJohnny Huang } 19667332532cSJohnny Huang 19675010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 19685010032bSJohnny Huang printf("programing data region ...\n"); 1969b64ca396SJohnny Huang ret = otp_prog_data(&image_layout, data); 19705010032bSJohnny Huang if (ret != 0) { 19715010032bSJohnny Huang printf("Error\n"); 19725010032bSJohnny Huang return ret; 19735010032bSJohnny Huang } 1974a219f6deSJohnny Huang printf("Done\n"); 19755010032bSJohnny Huang } 19765010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 19775010032bSJohnny Huang printf("programing strap region ...\n"); 1978b64ca396SJohnny Huang ret = otp_prog_strap(&image_layout, otpstrap); 19795010032bSJohnny Huang if (ret != 0) { 19805010032bSJohnny Huang printf("Error\n"); 19815010032bSJohnny Huang return ret; 19825010032bSJohnny Huang } 1983a219f6deSJohnny Huang printf("Done\n"); 19845010032bSJohnny Huang } 1985b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 1986b25f02d2SJohnny Huang printf("programing scu protect region ...\n"); 1987b25f02d2SJohnny Huang ret = otp_prog_scu_protect(&image_layout, scu_pro); 1988b25f02d2SJohnny Huang if (ret != 0) { 1989b25f02d2SJohnny Huang printf("Error\n"); 1990b25f02d2SJohnny Huang return ret; 1991b25f02d2SJohnny Huang } 1992b25f02d2SJohnny Huang printf("Done\n"); 1993b25f02d2SJohnny Huang } 19945010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 19955010032bSJohnny Huang printf("programing configuration region ...\n"); 1996b64ca396SJohnny Huang ret = otp_prog_conf(&image_layout, conf); 19975010032bSJohnny Huang if (ret != 0) { 19985010032bSJohnny Huang printf("Error\n"); 19995010032bSJohnny Huang return ret; 20005010032bSJohnny Huang } 20015010032bSJohnny Huang printf("Done\n"); 20025010032bSJohnny Huang } 2003cd1610b4SJohnny Huang 20047332532cSJohnny Huang return OTP_SUCCESS; 20052a856b9aSJohnny Huang } 20062a856b9aSJohnny Huang 2007f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 2008cd1610b4SJohnny Huang { 2009a219f6deSJohnny Huang u32 read[2]; 2010a219f6deSJohnny Huang u32 prog_address = 0; 201166f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 2012cd1610b4SJohnny Huang int otp_bit; 201383655e91SJohnny Huang int ret = 0; 2014cd1610b4SJohnny Huang 2015dacbba92SJohnny Huang otp_soak(0); 2016cd1610b4SJohnny Huang switch (mode) { 2017a6d0d645SJohnny Huang case OTP_REGION_CONF: 2018f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 2019cd1610b4SJohnny Huang prog_address = 0x800; 2020cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 2021cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 2022a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2023cd1610b4SJohnny Huang if (otp_bit == value) { 2024b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2025cd1610b4SJohnny Huang printf("No need to program\n"); 20262a856b9aSJohnny Huang return OTP_SUCCESS; 2027cd1610b4SJohnny Huang } 2028cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 2029b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 20300dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 20312a856b9aSJohnny Huang return OTP_FAILURE; 2032cd1610b4SJohnny Huang } 2033b489486eSJohnny Huang printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2034cd1610b4SJohnny Huang break; 2035a6d0d645SJohnny Huang case OTP_REGION_DATA: 2036cd1610b4SJohnny Huang prog_address = otp_dw_offset; 2037cd1610b4SJohnny Huang 2038cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 2039a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 2040a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2041643b9cfdSJohnny Huang 2042643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 2043b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2044b64ca396SJohnny Huang printf("OTP is programmed, which can't be cleared\n"); 2045643b9cfdSJohnny Huang return OTP_FAILURE; 2046643b9cfdSJohnny Huang } 2047cd1610b4SJohnny Huang } else { 2048a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 2049a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 2050643b9cfdSJohnny Huang 2051643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 2052b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2053b64ca396SJohnny Huang printf("OTP is programmed, which can't be written\n"); 2054643b9cfdSJohnny Huang return OTP_FAILURE; 2055643b9cfdSJohnny Huang } 2056cd1610b4SJohnny Huang } 2057cd1610b4SJohnny Huang if (otp_bit == value) { 2058b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2059cd1610b4SJohnny Huang printf("No need to program\n"); 20602a856b9aSJohnny Huang return OTP_SUCCESS; 2061cd1610b4SJohnny Huang } 2062643b9cfdSJohnny Huang 2063b489486eSJohnny Huang printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2064cd1610b4SJohnny Huang break; 2065a6d0d645SJohnny Huang case OTP_REGION_STRAP: 20668848d5dcSJohnny Huang otp_strap_status(otpstrap); 20678848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 20687e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 20698848d5dcSJohnny Huang if (ret == OTP_FAILURE) 20708848d5dcSJohnny Huang return OTP_FAILURE; 20718848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 20728848d5dcSJohnny Huang return OTP_SUCCESS; 2073a6af4a17SJohnny Huang 2074cd1610b4SJohnny Huang break; 2075cd1610b4SJohnny Huang } 2076cd1610b4SJohnny Huang 2077cd1610b4SJohnny Huang if (!nconfirm) { 2078cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2079cd1610b4SJohnny Huang if (!confirm_yesno()) { 2080cd1610b4SJohnny Huang printf(" Aborting\n"); 20812a856b9aSJohnny Huang return OTP_FAILURE; 2082cd1610b4SJohnny Huang } 2083cd1610b4SJohnny Huang } 2084cd1610b4SJohnny Huang 2085cd1610b4SJohnny Huang switch (mode) { 2086a6d0d645SJohnny Huang case OTP_REGION_STRAP: 2087f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 208883655e91SJohnny Huang break; 2089a6d0d645SJohnny Huang case OTP_REGION_CONF: 2090a6d0d645SJohnny Huang case OTP_REGION_DATA: 2091f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 2092de6fbf1cSJohnny Huang break; 2093de6fbf1cSJohnny Huang } 2094de6fbf1cSJohnny Huang otp_soak(0); 209583655e91SJohnny Huang if (ret) { 20960dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 2097794e27ecSJohnny Huang printf("FAILURE\n"); 2098794e27ecSJohnny Huang return OTP_FAILURE; 2099794e27ecSJohnny Huang } 2100794e27ecSJohnny Huang 21019009c25dSJohnny Huang printf("SUCCESS\n"); 21022a856b9aSJohnny Huang return OTP_SUCCESS; 2103a219f6deSJohnny Huang } 2104a219f6deSJohnny Huang 2105794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 2106794e27ecSJohnny Huang { 2107794e27ecSJohnny Huang u32 otp_rid[2]; 2108a8789b47SJohnny Huang u32 sw_rid[2]; 2109794e27ecSJohnny Huang int rid_num = 0; 2110a8789b47SJohnny Huang int sw_rid_num = 0; 2111794e27ecSJohnny Huang int bit_offset; 2112794e27ecSJohnny Huang int dw_offset; 2113794e27ecSJohnny Huang int i; 2114794e27ecSJohnny Huang int ret; 2115794e27ecSJohnny Huang 2116f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2117f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2118794e27ecSJohnny Huang 2119a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2120a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2121a8789b47SJohnny Huang 2122794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2123a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2124a8789b47SJohnny Huang 2125a8789b47SJohnny Huang if (sw_rid_num < 0) { 2126a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2127a8789b47SJohnny Huang return OTP_FAILURE; 2128a8789b47SJohnny Huang } 2129a8789b47SJohnny Huang 2130a8789b47SJohnny Huang if (update_num > sw_rid_num) { 2131a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2132a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2133a8789b47SJohnny Huang return OTP_FAILURE; 2134a8789b47SJohnny Huang } 2135794e27ecSJohnny Huang 2136794e27ecSJohnny Huang if (rid_num < 0) { 2137b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by this command,\n" 2138b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n"); 2139794e27ecSJohnny Huang otp_print_revid(otp_rid); 21409009c25dSJohnny Huang return OTP_FAILURE; 21419009c25dSJohnny Huang } 2142cd1610b4SJohnny Huang 2143794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2144794e27ecSJohnny Huang otp_print_revid(otp_rid); 2145794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 2146794e27ecSJohnny Huang 2147a8789b47SJohnny Huang if (rid_num > update_num) { 2148a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 2149a8789b47SJohnny Huang printf("Skip\n"); 2150a8789b47SJohnny Huang return OTP_FAILURE; 2151a8789b47SJohnny Huang } else if (rid_num == update_num) { 2152a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 2153794e27ecSJohnny Huang printf("Skip\n"); 2154794e27ecSJohnny Huang return OTP_FAILURE; 2155794e27ecSJohnny Huang } 2156794e27ecSJohnny Huang 2157794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2158794e27ecSJohnny Huang if (i < 32) { 2159794e27ecSJohnny Huang dw_offset = 0xa; 2160794e27ecSJohnny Huang bit_offset = i; 2161794e27ecSJohnny Huang } else { 2162794e27ecSJohnny Huang dw_offset = 0xb; 2163794e27ecSJohnny Huang bit_offset = i - 32; 2164794e27ecSJohnny Huang } 2165b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset); 2166794e27ecSJohnny Huang if (i + 1 != update_num) 2167794e27ecSJohnny Huang printf(", "); 2168794e27ecSJohnny Huang } 2169794e27ecSJohnny Huang 2170794e27ecSJohnny Huang printf(" will be programmed\n"); 2171794e27ecSJohnny Huang if (force == 0) { 2172794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2173794e27ecSJohnny Huang if (!confirm_yesno()) { 2174794e27ecSJohnny Huang printf(" Aborting\n"); 2175794e27ecSJohnny Huang return OTP_FAILURE; 2176794e27ecSJohnny Huang } 2177794e27ecSJohnny Huang } 2178794e27ecSJohnny Huang 2179794e27ecSJohnny Huang ret = 0; 2180794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2181794e27ecSJohnny Huang if (i < 32) { 2182794e27ecSJohnny Huang dw_offset = 0xa04; 2183794e27ecSJohnny Huang bit_offset = i; 2184794e27ecSJohnny Huang } else { 2185794e27ecSJohnny Huang dw_offset = 0xa06; 2186794e27ecSJohnny Huang bit_offset = i - 32; 2187794e27ecSJohnny Huang } 2188f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 2189b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset); 2190794e27ecSJohnny Huang ret = OTP_FAILURE; 2191794e27ecSJohnny Huang break; 2192794e27ecSJohnny Huang } 2193794e27ecSJohnny Huang } 2194061d3279SJohnny Huang otp_soak(0); 2195f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2196f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2197794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2198794e27ecSJohnny Huang if (rid_num >= 0) 2199794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 2200794e27ecSJohnny Huang else 2201794e27ecSJohnny Huang printf("OTP revision ID\n"); 2202794e27ecSJohnny Huang otp_print_revid(otp_rid); 2203794e27ecSJohnny Huang if (!ret) 2204794e27ecSJohnny Huang printf("SUCCESS\n"); 2205794e27ecSJohnny Huang else 2206794e27ecSJohnny Huang printf("FAILED\n"); 2207794e27ecSJohnny Huang return ret; 2208794e27ecSJohnny Huang } 2209794e27ecSJohnny Huang 2210*883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force) 2211*883625c5SJohnny Huang { 2212*883625c5SJohnny Huang u32 otpcfg4; 2213*883625c5SJohnny Huang u32 krb; 2214*883625c5SJohnny Huang u32 krb_b; 2215*883625c5SJohnny Huang u32 krb_or; 2216*883625c5SJohnny Huang u32 current_id; 2217*883625c5SJohnny Huang 2218*883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2219*883625c5SJohnny Huang current_id = readl(SEC_KEY_NUM) & 7; 2220*883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2221*883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2222*883625c5SJohnny Huang krb_or = krb | krb_b; 2223*883625c5SJohnny Huang 2224*883625c5SJohnny Huang printf("current Key ID: 0x%x\n", current_id); 2225*883625c5SJohnny Huang printf("input retire ID: 0x%x\n", retire_id); 2226*883625c5SJohnny Huang printf("OTPCFG0x4 = 0x%X\n", otpcfg4); 2227*883625c5SJohnny Huang 2228*883625c5SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2229*883625c5SJohnny Huang printf("OTPCFG4 is protected\n"); 2230*883625c5SJohnny Huang return OTP_FAILURE; 2231*883625c5SJohnny Huang } 2232*883625c5SJohnny Huang 2233*883625c5SJohnny Huang if (retire_id >= current_id) { 2234*883625c5SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2235*883625c5SJohnny Huang return OTP_FAILURE; 2236*883625c5SJohnny Huang } 2237*883625c5SJohnny Huang 2238*883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2239*883625c5SJohnny Huang printf("Key 0x%X already retired\n", retire_id); 2240*883625c5SJohnny Huang return OTP_SUCCESS; 2241*883625c5SJohnny Huang } 2242*883625c5SJohnny Huang 2243*883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id); 2244*883625c5SJohnny Huang if (force == 0) { 2245*883625c5SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2246*883625c5SJohnny Huang if (!confirm_yesno()) { 2247*883625c5SJohnny Huang printf(" Aborting\n"); 2248*883625c5SJohnny Huang return OTP_FAILURE; 2249*883625c5SJohnny Huang } 2250*883625c5SJohnny Huang } 2251*883625c5SJohnny Huang 2252*883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) { 2253*883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed\n", retire_id); 2254*883625c5SJohnny Huang printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16); 2255*883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE) 2256*883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16); 2257*883625c5SJohnny Huang } 2258*883625c5SJohnny Huang 2259*883625c5SJohnny Huang otp_soak(0); 2260*883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2261*883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2262*883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2263*883625c5SJohnny Huang krb_or = krb | krb_b; 2264*883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2265*883625c5SJohnny Huang printf("SUCCESS\n"); 2266*883625c5SJohnny Huang return OTP_SUCCESS; 2267*883625c5SJohnny Huang } 2268*883625c5SJohnny Huang printf("FAILED\n"); 2269*883625c5SJohnny Huang return OTP_FAILURE; 2270*883625c5SJohnny Huang } 2271*883625c5SJohnny Huang 22722a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 227369d5fd8fSJohnny Huang { 2274a219f6deSJohnny Huang u32 offset, count; 22752a856b9aSJohnny Huang int ret; 227669d5fd8fSJohnny Huang 22772a856b9aSJohnny Huang if (argc == 4) { 22782a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 22792a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 22802a856b9aSJohnny Huang } else if (argc == 3) { 22812a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 22822a856b9aSJohnny Huang count = 1; 22832a856b9aSJohnny Huang } else { 228469d5fd8fSJohnny Huang return CMD_RET_USAGE; 228569d5fd8fSJohnny Huang } 228669d5fd8fSJohnny Huang 2287030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2288f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2289030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 22902a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2291030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 22922a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2293030cb4a7SJohnny Huang else 22942a856b9aSJohnny Huang return CMD_RET_USAGE; 229569d5fd8fSJohnny Huang 22962a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 22972a856b9aSJohnny Huang return CMD_RET_SUCCESS; 22982a856b9aSJohnny Huang return CMD_RET_USAGE; 22992a856b9aSJohnny Huang } 23002a856b9aSJohnny Huang 23012a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 23022a856b9aSJohnny Huang { 23032a856b9aSJohnny Huang phys_addr_t addr; 23042a856b9aSJohnny Huang int ret; 23052a856b9aSJohnny Huang 2306de6b0cc4SJohnny Huang if (argc == 3) { 2307ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 23082a856b9aSJohnny Huang return CMD_RET_USAGE; 23092a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2310f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2311de6b0cc4SJohnny Huang } else if (argc == 2) { 23122a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2313f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 23142a856b9aSJohnny Huang } else { 23152a856b9aSJohnny Huang return CMD_RET_USAGE; 23162a856b9aSJohnny Huang } 23172a856b9aSJohnny Huang 23182a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 23192a856b9aSJohnny Huang return CMD_RET_SUCCESS; 23202a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 23212a856b9aSJohnny Huang return CMD_RET_FAILURE; 23222a856b9aSJohnny Huang else 23232a856b9aSJohnny Huang return CMD_RET_USAGE; 23242a856b9aSJohnny Huang } 23252a856b9aSJohnny Huang 23262a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 23272a856b9aSJohnny Huang { 23282a856b9aSJohnny Huang int mode = 0; 23292a856b9aSJohnny Huang int nconfirm = 0; 23302a856b9aSJohnny Huang int otp_addr = 0; 23312a856b9aSJohnny Huang int bit_offset; 23322a856b9aSJohnny Huang int value; 23332a856b9aSJohnny Huang int ret; 2334030cb4a7SJohnny Huang u32 otp_strap_pro; 23352a856b9aSJohnny Huang 23362a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 23372a856b9aSJohnny Huang return CMD_RET_USAGE; 23382a856b9aSJohnny Huang 23392a856b9aSJohnny Huang /* Drop the pb cmd */ 23402a856b9aSJohnny Huang argc--; 23412a856b9aSJohnny Huang argv++; 23422a856b9aSJohnny Huang 23432a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2344a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 23452a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2346a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 23472a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2348a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2349cd1610b4SJohnny Huang else 23502a856b9aSJohnny Huang return CMD_RET_USAGE; 23512a856b9aSJohnny Huang 23522a856b9aSJohnny Huang /* Drop the region cmd */ 23532a856b9aSJohnny Huang argc--; 23542a856b9aSJohnny Huang argv++; 23552a856b9aSJohnny Huang 2356ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2357cd1610b4SJohnny Huang nconfirm = 1; 23582a856b9aSJohnny Huang /* Drop the force option */ 23592a856b9aSJohnny Huang argc--; 23602a856b9aSJohnny Huang argv++; 23612a856b9aSJohnny Huang } 2362cd1610b4SJohnny Huang 2363a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 23642a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 23652a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 23660808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 23672a856b9aSJohnny Huang return CMD_RET_USAGE; 2368cd1610b4SJohnny Huang } else { 23692a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 23702a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 23712a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 23720808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 23732a856b9aSJohnny Huang return CMD_RET_USAGE; 23740808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 237578855207SJohnny Huang if (otp_addr >= 0x800) 23760808cc55SJohnny Huang return CMD_RET_USAGE; 23770808cc55SJohnny Huang } else { 237878855207SJohnny Huang if (otp_addr >= 0x20) 23790808cc55SJohnny Huang return CMD_RET_USAGE; 23800808cc55SJohnny Huang } 2381cd1610b4SJohnny Huang } 2382cd1610b4SJohnny Huang if (value != 0 && value != 1) 23832a856b9aSJohnny Huang return CMD_RET_USAGE; 2384cd1610b4SJohnny Huang 2385030cb4a7SJohnny Huang ret = 0; 2386030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2387030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2388030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2389030cb4a7SJohnny Huang } 2390030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2391030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2392030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2393030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2394030cb4a7SJohnny Huang ret = -1; 2395030cb4a7SJohnny Huang } 2396030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2397030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2398030cb4a7SJohnny Huang ret = -1; 2399030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2400030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2401030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2402030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2403030cb4a7SJohnny Huang ret = -1; 2404030cb4a7SJohnny Huang } 2405030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2406030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2407030cb4a7SJohnny Huang ret = -1; 2408030cb4a7SJohnny Huang } 2409030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2410030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2411030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2412030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2413030cb4a7SJohnny Huang ret = -1; 2414030cb4a7SJohnny Huang } 2415030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2416030cb4a7SJohnny Huang u32 otp_rid[2]; 2417030cb4a7SJohnny Huang u32 sw_rid[2]; 2418030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2419030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2420030cb4a7SJohnny Huang 2421030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2422030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2423030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2424030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2425030cb4a7SJohnny Huang 2426030cb4a7SJohnny Huang if (otp_addr == 10) 2427030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2428030cb4a7SJohnny Huang else 2429030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2430030cb4a7SJohnny Huang 2431030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2432030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2433030cb4a7SJohnny Huang ret = -1; 2434030cb4a7SJohnny Huang } 2435030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2436030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2437030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2438030cb4a7SJohnny Huang ret = -1; 2439030cb4a7SJohnny Huang } else { 2440030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2441030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2442030cb4a7SJohnny Huang u32 key_num; 2443030cb4a7SJohnny Huang u32 retire; 2444030cb4a7SJohnny Huang 2445030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2446030cb4a7SJohnny Huang if (bit_offset >= 16) 2447030cb4a7SJohnny Huang retire = bit_offset - 16; 2448030cb4a7SJohnny Huang else 2449030cb4a7SJohnny Huang retire = bit_offset; 2450030cb4a7SJohnny Huang if (retire >= key_num) { 2451030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2452030cb4a7SJohnny Huang ret = -1; 2453030cb4a7SJohnny Huang } 2454030cb4a7SJohnny Huang } 2455030cb4a7SJohnny Huang } 2456030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2457030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2458030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2459030cb4a7SJohnny Huang ret = -1; 2460030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2461030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2462030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2463030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2464030cb4a7SJohnny Huang else 2465030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2466030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2467b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset); 2468030cb4a7SJohnny Huang ret = -1; 2469030cb4a7SJohnny Huang } 2470030cb4a7SJohnny Huang } 2471030cb4a7SJohnny Huang } 2472030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2473030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2474030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2475030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2476030cb4a7SJohnny Huang ret = -1; 2477030cb4a7SJohnny Huang } 2478030cb4a7SJohnny Huang } 2479030cb4a7SJohnny Huang 2480030cb4a7SJohnny Huang if (ret == -1) 2481030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2482030cb4a7SJohnny Huang 2483f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 24842a856b9aSJohnny Huang 24852a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 24862a856b9aSJohnny Huang return CMD_RET_SUCCESS; 24872a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 24882a856b9aSJohnny Huang return CMD_RET_FAILURE; 24892a856b9aSJohnny Huang else 24902a856b9aSJohnny Huang return CMD_RET_USAGE; 24912a856b9aSJohnny Huang } 24922a856b9aSJohnny Huang 24932a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 24942a856b9aSJohnny Huang { 24952a856b9aSJohnny Huang phys_addr_t addr; 24962a856b9aSJohnny Huang int otp_addr = 0; 2497b8590031SJohnny Huang int ret; 24982a856b9aSJohnny Huang 24992a856b9aSJohnny Huang if (argc != 3) 25002a856b9aSJohnny Huang return CMD_RET_USAGE; 25012a856b9aSJohnny Huang 25022a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 25032a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 2504b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 2505b8590031SJohnny Huang if (ret == 0) { 250669d5fd8fSJohnny Huang printf("Compare pass\n"); 25072a856b9aSJohnny Huang return CMD_RET_SUCCESS; 2508a219f6deSJohnny Huang } 250969d5fd8fSJohnny Huang printf("Compare fail\n"); 25102a856b9aSJohnny Huang return CMD_RET_FAILURE; 251169d5fd8fSJohnny Huang } 251269d5fd8fSJohnny Huang 251366f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 251466f2f8e5SJohnny Huang { 2515a8bd6d8cSJohnny Huang int view = 0; 25162d4b0742SJohnny Huang int input; 2517a8bd6d8cSJohnny Huang 2518a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 251966f2f8e5SJohnny Huang return CMD_RET_USAGE; 252066f2f8e5SJohnny Huang 25212d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 25222d4b0742SJohnny Huang if (argc == 3) { 25232d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 25242d4b0742SJohnny Huang otp_print_conf_info(input); 25252d4b0742SJohnny Huang } else { 25262d4b0742SJohnny Huang otp_print_conf_info(-1); 25272d4b0742SJohnny Huang } 25282d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 25292d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 2530a8bd6d8cSJohnny Huang view = 1; 2531a8bd6d8cSJohnny Huang /* Drop the view option */ 2532a8bd6d8cSJohnny Huang argc--; 2533a8bd6d8cSJohnny Huang argv++; 2534a8bd6d8cSJohnny Huang } 2535b458cd62SJohnny Huang otp_print_strap_info(view); 25360dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 25370dc9a440SJohnny Huang otp_print_scu_info(); 253866f2f8e5SJohnny Huang } else { 253966f2f8e5SJohnny Huang return CMD_RET_USAGE; 254066f2f8e5SJohnny Huang } 25412d4b0742SJohnny Huang 254266f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 254366f2f8e5SJohnny Huang } 254466f2f8e5SJohnny Huang 25450dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2546737ed20bSJohnny Huang { 25470dc9a440SJohnny Huang u32 input; 25480dc9a440SJohnny Huang u32 bit_offset; 2549e14b073cSJohnny Huang u32 prog_address; 2550030cb4a7SJohnny Huang char force; 255183655e91SJohnny Huang int ret; 2552a219f6deSJohnny Huang 2553737ed20bSJohnny Huang if (argc != 3 && argc != 2) 2554737ed20bSJohnny Huang return CMD_RET_USAGE; 2555737ed20bSJohnny Huang 2556e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 2557737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 2558030cb4a7SJohnny Huang force = 1; 2559737ed20bSJohnny Huang } else { 2560737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 2561030cb4a7SJohnny Huang force = 0; 2562737ed20bSJohnny Huang } 2563737ed20bSJohnny Huang 2564737ed20bSJohnny Huang if (input < 32) { 2565737ed20bSJohnny Huang bit_offset = input; 25660dc9a440SJohnny Huang prog_address = 0xe0c; 2567737ed20bSJohnny Huang } else if (input < 64) { 2568737ed20bSJohnny Huang bit_offset = input - 32; 25690dc9a440SJohnny Huang prog_address = 0xe0e; 2570737ed20bSJohnny Huang } else { 2571737ed20bSJohnny Huang return CMD_RET_USAGE; 2572737ed20bSJohnny Huang } 2573737ed20bSJohnny Huang 2574030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2575030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2576030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2577030cb4a7SJohnny Huang } 2578030cb4a7SJohnny Huang 2579030cb4a7SJohnny Huang if (!force) { 2580b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input); 2581030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2582030cb4a7SJohnny Huang if (!confirm_yesno()) { 2583030cb4a7SJohnny Huang printf(" Aborting\n"); 2584030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2585030cb4a7SJohnny Huang } 2586030cb4a7SJohnny Huang } 2587030cb4a7SJohnny Huang 2588e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2589b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input); 2590e14b073cSJohnny Huang return CMD_RET_SUCCESS; 2591e14b073cSJohnny Huang } 2592de6fbf1cSJohnny Huang 2593f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 2594de6fbf1cSJohnny Huang otp_soak(0); 259583655e91SJohnny Huang 259683655e91SJohnny Huang if (ret) { 2597b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input); 2598737ed20bSJohnny Huang return CMD_RET_FAILURE; 2599737ed20bSJohnny Huang } 26009a4fe690SJohnny Huang 2601b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input); 2602794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2603794e27ecSJohnny Huang } 2604794e27ecSJohnny Huang 26050dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2606e14b073cSJohnny Huang { 26070dc9a440SJohnny Huang u32 scu_offset; 26080dc9a440SJohnny Huang u32 bit_offset; 26090dc9a440SJohnny Huang u32 conf_offset; 26100dc9a440SJohnny Huang u32 prog_address; 26110dc9a440SJohnny Huang char force; 26120dc9a440SJohnny Huang int ret; 26130dc9a440SJohnny Huang 26140dc9a440SJohnny Huang if (argc != 4 && argc != 3) 26150dc9a440SJohnny Huang return CMD_RET_USAGE; 26160dc9a440SJohnny Huang 26170dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 26180dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 26190dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 26200dc9a440SJohnny Huang force = 1; 26210dc9a440SJohnny Huang } else { 26220dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 26230dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 26240dc9a440SJohnny Huang force = 0; 26250dc9a440SJohnny Huang } 26260dc9a440SJohnny Huang if (scu_offset == 0x500) { 26270dc9a440SJohnny Huang prog_address = 0xe08; 26280dc9a440SJohnny Huang conf_offset = 28; 26290dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 26300dc9a440SJohnny Huang prog_address = 0xe0a; 26310dc9a440SJohnny Huang conf_offset = 29; 26320dc9a440SJohnny Huang } else { 26330dc9a440SJohnny Huang return CMD_RET_USAGE; 26340dc9a440SJohnny Huang } 26350dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 26360dc9a440SJohnny Huang return CMD_RET_USAGE; 2637030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2638030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2639030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2640030cb4a7SJohnny Huang } 26410dc9a440SJohnny Huang if (!force) { 2642b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset); 2643b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset); 26440dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 26450dc9a440SJohnny Huang if (!confirm_yesno()) { 26460dc9a440SJohnny Huang printf(" Aborting\n"); 26470dc9a440SJohnny Huang return CMD_RET_FAILURE; 26480dc9a440SJohnny Huang } 2649e14b073cSJohnny Huang } 2650e14b073cSJohnny Huang 26510dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2652b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset); 26530dc9a440SJohnny Huang return CMD_RET_SUCCESS; 26540dc9a440SJohnny Huang } 26550dc9a440SJohnny Huang 26560dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 26570dc9a440SJohnny Huang otp_soak(0); 26580dc9a440SJohnny Huang 26590dc9a440SJohnny Huang if (ret) { 2660b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset); 26610dc9a440SJohnny Huang return CMD_RET_FAILURE; 26620dc9a440SJohnny Huang } 26630dc9a440SJohnny Huang 2664b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset); 26650dc9a440SJohnny Huang return CMD_RET_SUCCESS; 2666e14b073cSJohnny Huang } 2667e14b073cSJohnny Huang 2668f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2669f67375f7SJohnny Huang { 2670e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 2671f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2672f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2673f67375f7SJohnny Huang 2674f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2675f67375f7SJohnny Huang } 2676f67375f7SJohnny Huang 2677794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2678794e27ecSJohnny Huang { 2679794e27ecSJohnny Huang u32 update_num; 2680794e27ecSJohnny Huang int force = 0; 2681794e27ecSJohnny Huang int ret; 2682794e27ecSJohnny Huang 2683794e27ecSJohnny Huang if (argc == 3) { 2684794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 2685794e27ecSJohnny Huang return CMD_RET_USAGE; 2686794e27ecSJohnny Huang force = 1; 2687794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 2688794e27ecSJohnny Huang } else if (argc == 2) { 2689794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 2690794e27ecSJohnny Huang } else { 2691794e27ecSJohnny Huang return CMD_RET_USAGE; 2692794e27ecSJohnny Huang } 2693794e27ecSJohnny Huang 2694794e27ecSJohnny Huang if (update_num > 64) 2695794e27ecSJohnny Huang return CMD_RET_USAGE; 2696794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 2697b8590031SJohnny Huang 2698794e27ecSJohnny Huang if (ret) 2699794e27ecSJohnny Huang return CMD_RET_FAILURE; 2700794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2701794e27ecSJohnny Huang } 2702794e27ecSJohnny Huang 2703794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2704794e27ecSJohnny Huang { 2705794e27ecSJohnny Huang u32 otp_rid[2]; 2706a8789b47SJohnny Huang u32 sw_rid[2]; 2707794e27ecSJohnny Huang int rid_num = 0; 2708a8789b47SJohnny Huang int sw_rid_num = 0; 2709794e27ecSJohnny Huang int ret; 2710794e27ecSJohnny Huang 2711794e27ecSJohnny Huang if (argc != 1) 2712794e27ecSJohnny Huang return CMD_RET_USAGE; 2713794e27ecSJohnny Huang 2714f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2715f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2716794e27ecSJohnny Huang 2717a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2718a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2719794e27ecSJohnny Huang 2720a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 2721a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2722a8789b47SJohnny Huang 2723030cb4a7SJohnny Huang if (sw_rid_num < 0) { 2724030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2725030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 2726030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 2727030cb4a7SJohnny Huang } else { 2728a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2729030cb4a7SJohnny Huang } 2730794e27ecSJohnny Huang if (rid_num >= 0) { 2731794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2732794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 2733794e27ecSJohnny Huang } else { 2734b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n" 2735b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n" 2736794e27ecSJohnny Huang "current OTP revision ID\n"); 2737794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 2738794e27ecSJohnny Huang } 2739794e27ecSJohnny Huang otp_print_revid(otp_rid); 2740794e27ecSJohnny Huang 2741794e27ecSJohnny Huang return ret; 2742794e27ecSJohnny Huang } 2743794e27ecSJohnny Huang 2744*883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2745*883625c5SJohnny Huang { 2746*883625c5SJohnny Huang u32 retire_id; 2747*883625c5SJohnny Huang int force = 0; 2748*883625c5SJohnny Huang int ret; 2749*883625c5SJohnny Huang 2750*883625c5SJohnny Huang if (argc == 3) { 2751*883625c5SJohnny Huang if (strcmp(argv[1], "o")) 2752*883625c5SJohnny Huang return CMD_RET_USAGE; 2753*883625c5SJohnny Huang force = 1; 2754*883625c5SJohnny Huang retire_id = simple_strtoul(argv[2], NULL, 16); 2755*883625c5SJohnny Huang } else if (argc == 2) { 2756*883625c5SJohnny Huang retire_id = simple_strtoul(argv[1], NULL, 16); 2757*883625c5SJohnny Huang } else { 2758*883625c5SJohnny Huang return CMD_RET_USAGE; 2759*883625c5SJohnny Huang } 2760*883625c5SJohnny Huang 2761*883625c5SJohnny Huang if (retire_id > 7) 2762*883625c5SJohnny Huang return CMD_RET_USAGE; 2763*883625c5SJohnny Huang ret = otp_retire_key(retire_id, force); 2764*883625c5SJohnny Huang 2765*883625c5SJohnny Huang if (ret) 2766*883625c5SJohnny Huang return CMD_RET_FAILURE; 2767*883625c5SJohnny Huang return CMD_RET_SUCCESS; 2768*883625c5SJohnny Huang } 2769*883625c5SJohnny Huang 27702a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2771f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 27722a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2773a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2774de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 27752a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2776737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 27770dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 27782a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 2779794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 2780794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 2781*883625c5SJohnny Huang U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""), 27822a856b9aSJohnny Huang }; 27832a856b9aSJohnny Huang 27842a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 27852a856b9aSJohnny Huang { 2786030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 27872a856b9aSJohnny Huang cmd_tbl_t *cp; 2788a219f6deSJohnny Huang u32 ver; 2789e14b073cSJohnny Huang int ret; 2790030cb4a7SJohnny Huang u32 otp_conf0; 27912a856b9aSJohnny Huang 27922a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 27932a856b9aSJohnny Huang 2794737ed20bSJohnny Huang /* Drop the otp command */ 27952a856b9aSJohnny Huang argc--; 27962a856b9aSJohnny Huang argv++; 27972a856b9aSJohnny Huang 2798a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 27992a856b9aSJohnny Huang return CMD_RET_USAGE; 28002a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 28012a856b9aSJohnny Huang return CMD_RET_SUCCESS; 28022a856b9aSJohnny Huang 28030dae9d52SJohnny Huang ver = chip_version(); 28040dae9d52SJohnny Huang switch (ver) { 2805e417205bSJohnny Huang case OTP_A0: 2806e417205bSJohnny Huang info_cb.version = OTP_A0; 28079a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 28089a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 28099a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 28109a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 28119a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 28129a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 2813e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 28140dae9d52SJohnny Huang break; 2815e417205bSJohnny Huang case OTP_A1: 2816e417205bSJohnny Huang info_cb.version = OTP_A1; 28173cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 28183cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 28193cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 28203cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 28219a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 28229a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 28230dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28240dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2825e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 28260dae9d52SJohnny Huang break; 2827e417205bSJohnny Huang case OTP_A2: 2828e417205bSJohnny Huang info_cb.version = OTP_A2; 28295fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 28305fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 2831fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2832fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 28335fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 28345fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 28350dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28360dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2837e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 28380dae9d52SJohnny Huang break; 2839e417205bSJohnny Huang case OTP_A3: 2840e417205bSJohnny Huang info_cb.version = OTP_A3; 2841b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 2842b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 2843fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2844fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 2845181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2846181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 28470dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28480dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2849e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 285064b66712SJohnny Huang break; 28510dae9d52SJohnny Huang default: 2852f1be5099SJohnny Huang printf("SOC is not supported\n"); 28530dae9d52SJohnny Huang return CMD_RET_FAILURE; 28549a4fe690SJohnny Huang } 28559a4fe690SJohnny Huang 2856030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2857030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 2858030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 2859030cb4a7SJohnny Huang 2860030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 2861030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 2862030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 2863030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 2864030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 2865030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 2866030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 2867030cb4a7SJohnny Huang 2868e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 2869b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 2870e14b073cSJohnny Huang 2871e14b073cSJohnny Huang return ret; 287269d5fd8fSJohnny Huang } 287369d5fd8fSJohnny Huang 2874a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 287569d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2876f67375f7SJohnny Huang "version\n" 2877f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 28782a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 28792d4b0742SJohnny Huang "otp info strap [v]\n" 28802d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 28810dc9a440SJohnny Huang "otp info scu\n" 2882de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2883ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2884ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2885ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 28860dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 2887794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 2888794e27ecSJohnny Huang "otp rid\n" 2889*883625c5SJohnny Huang "otp retire [o] <key_id>\n" 289069d5fd8fSJohnny Huang ); 2891