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; 709*b489486eSJohnny 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) { 725*b489486eSJohnny 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) 731*b489486eSJohnny 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); 775*b489486eSJohnny 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) { 1627*b489486eSJohnny 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"); 1661*b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1662*b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1663*b489486eSJohnny 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"); 1671*b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1672*b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1673*b489486eSJohnny 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"); 1761*b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]); 1762*b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]); 1763*b489486eSJohnny 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) { 2024*b489486eSJohnny 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) { 2029*b489486eSJohnny 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 } 2033*b489486eSJohnny 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) { 2043*b489486eSJohnny 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) { 2052*b489486eSJohnny 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) { 2058*b489486eSJohnny 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 2063*b489486eSJohnny 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 } 2165*b489486eSJohnny 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)) { 2189*b489486eSJohnny 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 22102a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 221169d5fd8fSJohnny Huang { 2212a219f6deSJohnny Huang u32 offset, count; 22132a856b9aSJohnny Huang int ret; 221469d5fd8fSJohnny Huang 22152a856b9aSJohnny Huang if (argc == 4) { 22162a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 22172a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 22182a856b9aSJohnny Huang } else if (argc == 3) { 22192a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 22202a856b9aSJohnny Huang count = 1; 22212a856b9aSJohnny Huang } else { 222269d5fd8fSJohnny Huang return CMD_RET_USAGE; 222369d5fd8fSJohnny Huang } 222469d5fd8fSJohnny Huang 2225030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2226f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2227030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 22282a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2229030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 22302a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2231030cb4a7SJohnny Huang else 22322a856b9aSJohnny Huang return CMD_RET_USAGE; 223369d5fd8fSJohnny Huang 22342a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 22352a856b9aSJohnny Huang return CMD_RET_SUCCESS; 22362a856b9aSJohnny Huang return CMD_RET_USAGE; 22372a856b9aSJohnny Huang } 22382a856b9aSJohnny Huang 22392a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 22402a856b9aSJohnny Huang { 22412a856b9aSJohnny Huang phys_addr_t addr; 22422a856b9aSJohnny Huang int ret; 22432a856b9aSJohnny Huang 2244de6b0cc4SJohnny Huang if (argc == 3) { 2245ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 22462a856b9aSJohnny Huang return CMD_RET_USAGE; 22472a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2248f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2249de6b0cc4SJohnny Huang } else if (argc == 2) { 22502a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2251f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 22522a856b9aSJohnny Huang } else { 22532a856b9aSJohnny Huang return CMD_RET_USAGE; 22542a856b9aSJohnny Huang } 22552a856b9aSJohnny Huang 22562a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 22572a856b9aSJohnny Huang return CMD_RET_SUCCESS; 22582a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 22592a856b9aSJohnny Huang return CMD_RET_FAILURE; 22602a856b9aSJohnny Huang else 22612a856b9aSJohnny Huang return CMD_RET_USAGE; 22622a856b9aSJohnny Huang } 22632a856b9aSJohnny Huang 22642a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 22652a856b9aSJohnny Huang { 22662a856b9aSJohnny Huang int mode = 0; 22672a856b9aSJohnny Huang int nconfirm = 0; 22682a856b9aSJohnny Huang int otp_addr = 0; 22692a856b9aSJohnny Huang int bit_offset; 22702a856b9aSJohnny Huang int value; 22712a856b9aSJohnny Huang int ret; 2272030cb4a7SJohnny Huang u32 otp_strap_pro; 22732a856b9aSJohnny Huang 22742a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 22752a856b9aSJohnny Huang return CMD_RET_USAGE; 22762a856b9aSJohnny Huang 22772a856b9aSJohnny Huang /* Drop the pb cmd */ 22782a856b9aSJohnny Huang argc--; 22792a856b9aSJohnny Huang argv++; 22802a856b9aSJohnny Huang 22812a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2282a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 22832a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2284a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 22852a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2286a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2287cd1610b4SJohnny Huang else 22882a856b9aSJohnny Huang return CMD_RET_USAGE; 22892a856b9aSJohnny Huang 22902a856b9aSJohnny Huang /* Drop the region cmd */ 22912a856b9aSJohnny Huang argc--; 22922a856b9aSJohnny Huang argv++; 22932a856b9aSJohnny Huang 2294ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2295cd1610b4SJohnny Huang nconfirm = 1; 22962a856b9aSJohnny Huang /* Drop the force option */ 22972a856b9aSJohnny Huang argc--; 22982a856b9aSJohnny Huang argv++; 22992a856b9aSJohnny Huang } 2300cd1610b4SJohnny Huang 2301a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 23022a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 23032a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 23040808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 23052a856b9aSJohnny Huang return CMD_RET_USAGE; 2306cd1610b4SJohnny Huang } else { 23072a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 23082a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 23092a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 23100808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 23112a856b9aSJohnny Huang return CMD_RET_USAGE; 23120808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 231378855207SJohnny Huang if (otp_addr >= 0x800) 23140808cc55SJohnny Huang return CMD_RET_USAGE; 23150808cc55SJohnny Huang } else { 231678855207SJohnny Huang if (otp_addr >= 0x20) 23170808cc55SJohnny Huang return CMD_RET_USAGE; 23180808cc55SJohnny Huang } 2319cd1610b4SJohnny Huang } 2320cd1610b4SJohnny Huang if (value != 0 && value != 1) 23212a856b9aSJohnny Huang return CMD_RET_USAGE; 2322cd1610b4SJohnny Huang 2323030cb4a7SJohnny Huang ret = 0; 2324030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2325030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2326030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2327030cb4a7SJohnny Huang } 2328030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2329030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2330030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2331030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2332030cb4a7SJohnny Huang ret = -1; 2333030cb4a7SJohnny Huang } 2334030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2335030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2336030cb4a7SJohnny Huang ret = -1; 2337030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2338030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2339030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2340030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2341030cb4a7SJohnny Huang ret = -1; 2342030cb4a7SJohnny Huang } 2343030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2344030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2345030cb4a7SJohnny Huang ret = -1; 2346030cb4a7SJohnny Huang } 2347030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2348030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2349030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2350030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2351030cb4a7SJohnny Huang ret = -1; 2352030cb4a7SJohnny Huang } 2353030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2354030cb4a7SJohnny Huang u32 otp_rid[2]; 2355030cb4a7SJohnny Huang u32 sw_rid[2]; 2356030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2357030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2358030cb4a7SJohnny Huang 2359030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2360030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2361030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2362030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2363030cb4a7SJohnny Huang 2364030cb4a7SJohnny Huang if (otp_addr == 10) 2365030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2366030cb4a7SJohnny Huang else 2367030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2368030cb4a7SJohnny Huang 2369030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2370030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2371030cb4a7SJohnny Huang ret = -1; 2372030cb4a7SJohnny Huang } 2373030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2374030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2375030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2376030cb4a7SJohnny Huang ret = -1; 2377030cb4a7SJohnny Huang } else { 2378030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2379030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2380030cb4a7SJohnny Huang u32 key_num; 2381030cb4a7SJohnny Huang u32 retire; 2382030cb4a7SJohnny Huang 2383030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2384030cb4a7SJohnny Huang if (bit_offset >= 16) 2385030cb4a7SJohnny Huang retire = bit_offset - 16; 2386030cb4a7SJohnny Huang else 2387030cb4a7SJohnny Huang retire = bit_offset; 2388030cb4a7SJohnny Huang if (retire >= key_num) { 2389030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2390030cb4a7SJohnny Huang ret = -1; 2391030cb4a7SJohnny Huang } 2392030cb4a7SJohnny Huang } 2393030cb4a7SJohnny Huang } 2394030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2395030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2396030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2397030cb4a7SJohnny Huang ret = -1; 2398030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2399030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2400030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2401030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2402030cb4a7SJohnny Huang else 2403030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2404030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2405*b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset); 2406030cb4a7SJohnny Huang ret = -1; 2407030cb4a7SJohnny Huang } 2408030cb4a7SJohnny Huang } 2409030cb4a7SJohnny Huang } 2410030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2411030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2412030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2413030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2414030cb4a7SJohnny Huang ret = -1; 2415030cb4a7SJohnny Huang } 2416030cb4a7SJohnny Huang } 2417030cb4a7SJohnny Huang 2418030cb4a7SJohnny Huang if (ret == -1) 2419030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2420030cb4a7SJohnny Huang 2421f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 24222a856b9aSJohnny Huang 24232a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 24242a856b9aSJohnny Huang return CMD_RET_SUCCESS; 24252a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 24262a856b9aSJohnny Huang return CMD_RET_FAILURE; 24272a856b9aSJohnny Huang else 24282a856b9aSJohnny Huang return CMD_RET_USAGE; 24292a856b9aSJohnny Huang } 24302a856b9aSJohnny Huang 24312a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 24322a856b9aSJohnny Huang { 24332a856b9aSJohnny Huang phys_addr_t addr; 24342a856b9aSJohnny Huang int otp_addr = 0; 2435b8590031SJohnny Huang int ret; 24362a856b9aSJohnny Huang 24372a856b9aSJohnny Huang if (argc != 3) 24382a856b9aSJohnny Huang return CMD_RET_USAGE; 24392a856b9aSJohnny Huang 24402a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 24412a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 2442b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 2443b8590031SJohnny Huang if (ret == 0) { 244469d5fd8fSJohnny Huang printf("Compare pass\n"); 24452a856b9aSJohnny Huang return CMD_RET_SUCCESS; 2446a219f6deSJohnny Huang } 244769d5fd8fSJohnny Huang printf("Compare fail\n"); 24482a856b9aSJohnny Huang return CMD_RET_FAILURE; 244969d5fd8fSJohnny Huang } 245069d5fd8fSJohnny Huang 245166f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 245266f2f8e5SJohnny Huang { 2453a8bd6d8cSJohnny Huang int view = 0; 24542d4b0742SJohnny Huang int input; 2455a8bd6d8cSJohnny Huang 2456a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 245766f2f8e5SJohnny Huang return CMD_RET_USAGE; 245866f2f8e5SJohnny Huang 24592d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 24602d4b0742SJohnny Huang if (argc == 3) { 24612d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 24622d4b0742SJohnny Huang otp_print_conf_info(input); 24632d4b0742SJohnny Huang } else { 24642d4b0742SJohnny Huang otp_print_conf_info(-1); 24652d4b0742SJohnny Huang } 24662d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 24672d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 2468a8bd6d8cSJohnny Huang view = 1; 2469a8bd6d8cSJohnny Huang /* Drop the view option */ 2470a8bd6d8cSJohnny Huang argc--; 2471a8bd6d8cSJohnny Huang argv++; 2472a8bd6d8cSJohnny Huang } 2473b458cd62SJohnny Huang otp_print_strap_info(view); 24740dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 24750dc9a440SJohnny Huang otp_print_scu_info(); 247666f2f8e5SJohnny Huang } else { 247766f2f8e5SJohnny Huang return CMD_RET_USAGE; 247866f2f8e5SJohnny Huang } 24792d4b0742SJohnny Huang 248066f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 248166f2f8e5SJohnny Huang } 248266f2f8e5SJohnny Huang 24830dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2484737ed20bSJohnny Huang { 24850dc9a440SJohnny Huang u32 input; 24860dc9a440SJohnny Huang u32 bit_offset; 2487e14b073cSJohnny Huang u32 prog_address; 2488030cb4a7SJohnny Huang char force; 248983655e91SJohnny Huang int ret; 2490a219f6deSJohnny Huang 2491737ed20bSJohnny Huang if (argc != 3 && argc != 2) 2492737ed20bSJohnny Huang return CMD_RET_USAGE; 2493737ed20bSJohnny Huang 2494e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 2495737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 2496030cb4a7SJohnny Huang force = 1; 2497737ed20bSJohnny Huang } else { 2498737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 2499030cb4a7SJohnny Huang force = 0; 2500737ed20bSJohnny Huang } 2501737ed20bSJohnny Huang 2502737ed20bSJohnny Huang if (input < 32) { 2503737ed20bSJohnny Huang bit_offset = input; 25040dc9a440SJohnny Huang prog_address = 0xe0c; 2505737ed20bSJohnny Huang } else if (input < 64) { 2506737ed20bSJohnny Huang bit_offset = input - 32; 25070dc9a440SJohnny Huang prog_address = 0xe0e; 2508737ed20bSJohnny Huang } else { 2509737ed20bSJohnny Huang return CMD_RET_USAGE; 2510737ed20bSJohnny Huang } 2511737ed20bSJohnny Huang 2512030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2513030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2514030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2515030cb4a7SJohnny Huang } 2516030cb4a7SJohnny Huang 2517030cb4a7SJohnny Huang if (!force) { 2518*b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input); 2519030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2520030cb4a7SJohnny Huang if (!confirm_yesno()) { 2521030cb4a7SJohnny Huang printf(" Aborting\n"); 2522030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2523030cb4a7SJohnny Huang } 2524030cb4a7SJohnny Huang } 2525030cb4a7SJohnny Huang 2526e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2527*b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input); 2528e14b073cSJohnny Huang return CMD_RET_SUCCESS; 2529e14b073cSJohnny Huang } 2530de6fbf1cSJohnny Huang 2531f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 2532de6fbf1cSJohnny Huang otp_soak(0); 253383655e91SJohnny Huang 253483655e91SJohnny Huang if (ret) { 2535*b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input); 2536737ed20bSJohnny Huang return CMD_RET_FAILURE; 2537737ed20bSJohnny Huang } 25389a4fe690SJohnny Huang 2539*b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input); 2540794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2541794e27ecSJohnny Huang } 2542794e27ecSJohnny Huang 25430dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2544e14b073cSJohnny Huang { 25450dc9a440SJohnny Huang u32 scu_offset; 25460dc9a440SJohnny Huang u32 bit_offset; 25470dc9a440SJohnny Huang u32 conf_offset; 25480dc9a440SJohnny Huang u32 prog_address; 25490dc9a440SJohnny Huang char force; 25500dc9a440SJohnny Huang int ret; 25510dc9a440SJohnny Huang 25520dc9a440SJohnny Huang if (argc != 4 && argc != 3) 25530dc9a440SJohnny Huang return CMD_RET_USAGE; 25540dc9a440SJohnny Huang 25550dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 25560dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 25570dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 25580dc9a440SJohnny Huang force = 1; 25590dc9a440SJohnny Huang } else { 25600dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 25610dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 25620dc9a440SJohnny Huang force = 0; 25630dc9a440SJohnny Huang } 25640dc9a440SJohnny Huang if (scu_offset == 0x500) { 25650dc9a440SJohnny Huang prog_address = 0xe08; 25660dc9a440SJohnny Huang conf_offset = 28; 25670dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 25680dc9a440SJohnny Huang prog_address = 0xe0a; 25690dc9a440SJohnny Huang conf_offset = 29; 25700dc9a440SJohnny Huang } else { 25710dc9a440SJohnny Huang return CMD_RET_USAGE; 25720dc9a440SJohnny Huang } 25730dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 25740dc9a440SJohnny Huang return CMD_RET_USAGE; 2575030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2576030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2577030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2578030cb4a7SJohnny Huang } 25790dc9a440SJohnny Huang if (!force) { 2580*b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset); 2581*b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset); 25820dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 25830dc9a440SJohnny Huang if (!confirm_yesno()) { 25840dc9a440SJohnny Huang printf(" Aborting\n"); 25850dc9a440SJohnny Huang return CMD_RET_FAILURE; 25860dc9a440SJohnny Huang } 2587e14b073cSJohnny Huang } 2588e14b073cSJohnny Huang 25890dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2590*b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset); 25910dc9a440SJohnny Huang return CMD_RET_SUCCESS; 25920dc9a440SJohnny Huang } 25930dc9a440SJohnny Huang 25940dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 25950dc9a440SJohnny Huang otp_soak(0); 25960dc9a440SJohnny Huang 25970dc9a440SJohnny Huang if (ret) { 2598*b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset); 25990dc9a440SJohnny Huang return CMD_RET_FAILURE; 26000dc9a440SJohnny Huang } 26010dc9a440SJohnny Huang 2602*b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset); 26030dc9a440SJohnny Huang return CMD_RET_SUCCESS; 2604e14b073cSJohnny Huang } 2605e14b073cSJohnny Huang 2606f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2607f67375f7SJohnny Huang { 2608e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 2609f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2610f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2611f67375f7SJohnny Huang 2612f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2613f67375f7SJohnny Huang } 2614f67375f7SJohnny Huang 2615794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2616794e27ecSJohnny Huang { 2617794e27ecSJohnny Huang u32 update_num; 2618794e27ecSJohnny Huang int force = 0; 2619794e27ecSJohnny Huang int ret; 2620794e27ecSJohnny Huang 2621794e27ecSJohnny Huang if (argc == 3) { 2622794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 2623794e27ecSJohnny Huang return CMD_RET_USAGE; 2624794e27ecSJohnny Huang force = 1; 2625794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 2626794e27ecSJohnny Huang } else if (argc == 2) { 2627794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 2628794e27ecSJohnny Huang } else { 2629794e27ecSJohnny Huang return CMD_RET_USAGE; 2630794e27ecSJohnny Huang } 2631794e27ecSJohnny Huang 2632794e27ecSJohnny Huang if (update_num > 64) 2633794e27ecSJohnny Huang return CMD_RET_USAGE; 2634794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 2635b8590031SJohnny Huang 2636794e27ecSJohnny Huang if (ret) 2637794e27ecSJohnny Huang return CMD_RET_FAILURE; 2638794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2639794e27ecSJohnny Huang } 2640794e27ecSJohnny Huang 2641794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2642794e27ecSJohnny Huang { 2643794e27ecSJohnny Huang u32 otp_rid[2]; 2644a8789b47SJohnny Huang u32 sw_rid[2]; 2645794e27ecSJohnny Huang int rid_num = 0; 2646a8789b47SJohnny Huang int sw_rid_num = 0; 2647794e27ecSJohnny Huang int ret; 2648794e27ecSJohnny Huang 2649794e27ecSJohnny Huang if (argc != 1) 2650794e27ecSJohnny Huang return CMD_RET_USAGE; 2651794e27ecSJohnny Huang 2652f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2653f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2654794e27ecSJohnny Huang 2655a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2656a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2657794e27ecSJohnny Huang 2658a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 2659a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2660a8789b47SJohnny Huang 2661030cb4a7SJohnny Huang if (sw_rid_num < 0) { 2662030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2663030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 2664030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 2665030cb4a7SJohnny Huang } else { 2666a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2667030cb4a7SJohnny Huang } 2668794e27ecSJohnny Huang if (rid_num >= 0) { 2669794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2670794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 2671794e27ecSJohnny Huang } else { 2672b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n" 2673b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n" 2674794e27ecSJohnny Huang "current OTP revision ID\n"); 2675794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 2676794e27ecSJohnny Huang } 2677794e27ecSJohnny Huang otp_print_revid(otp_rid); 2678794e27ecSJohnny Huang 2679794e27ecSJohnny Huang return ret; 2680794e27ecSJohnny Huang } 2681794e27ecSJohnny Huang 26822a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2683f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 26842a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2685a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2686de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 26872a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2688737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 26890dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 26902a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 2691794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 2692794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 26932a856b9aSJohnny Huang }; 26942a856b9aSJohnny Huang 26952a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 26962a856b9aSJohnny Huang { 2697030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 26982a856b9aSJohnny Huang cmd_tbl_t *cp; 2699a219f6deSJohnny Huang u32 ver; 2700e14b073cSJohnny Huang int ret; 2701030cb4a7SJohnny Huang u32 otp_conf0; 27022a856b9aSJohnny Huang 27032a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 27042a856b9aSJohnny Huang 2705737ed20bSJohnny Huang /* Drop the otp command */ 27062a856b9aSJohnny Huang argc--; 27072a856b9aSJohnny Huang argv++; 27082a856b9aSJohnny Huang 2709a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 27102a856b9aSJohnny Huang return CMD_RET_USAGE; 27112a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 27122a856b9aSJohnny Huang return CMD_RET_SUCCESS; 27132a856b9aSJohnny Huang 27140dae9d52SJohnny Huang ver = chip_version(); 27150dae9d52SJohnny Huang switch (ver) { 2716e417205bSJohnny Huang case OTP_A0: 2717e417205bSJohnny Huang info_cb.version = OTP_A0; 27189a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 27199a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 27209a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 27219a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 27229a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 27239a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 2724e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 27250dae9d52SJohnny Huang break; 2726e417205bSJohnny Huang case OTP_A1: 2727e417205bSJohnny Huang info_cb.version = OTP_A1; 27283cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 27293cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 27303cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 27313cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 27329a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 27339a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 27340dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 27350dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2736e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 27370dae9d52SJohnny Huang break; 2738e417205bSJohnny Huang case OTP_A2: 2739e417205bSJohnny Huang info_cb.version = OTP_A2; 27405fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 27415fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 2742fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2743fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 27445fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 27455fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 27460dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 27470dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2748e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 27490dae9d52SJohnny Huang break; 2750e417205bSJohnny Huang case OTP_A3: 2751e417205bSJohnny Huang info_cb.version = OTP_A3; 2752b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 2753b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 2754fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2755fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 2756181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2757181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 27580dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 27590dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2760e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 276164b66712SJohnny Huang break; 27620dae9d52SJohnny Huang default: 2763f1be5099SJohnny Huang printf("SOC is not supported\n"); 27640dae9d52SJohnny Huang return CMD_RET_FAILURE; 27659a4fe690SJohnny Huang } 27669a4fe690SJohnny Huang 2767030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2768030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 2769030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 2770030cb4a7SJohnny Huang 2771030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 2772030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 2773030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 2774030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 2775030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 2776030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 2777030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 2778030cb4a7SJohnny Huang 2779e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 2780b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 2781e14b073cSJohnny Huang 2782e14b073cSJohnny Huang return ret; 278369d5fd8fSJohnny Huang } 278469d5fd8fSJohnny Huang 2785a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 278669d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2787f67375f7SJohnny Huang "version\n" 2788f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 27892a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 27902d4b0742SJohnny Huang "otp info strap [v]\n" 27912d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 27920dc9a440SJohnny Huang "otp info scu\n" 2793de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2794ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2795ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2796ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 27970dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 2798794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 2799794e27ecSJohnny Huang "otp rid\n" 280069d5fd8fSJohnny Huang ); 2801