1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+ 269d5fd8fSJohnny Huang /* 3a219f6deSJohnny Huang * Copyright 2021 Aspeed Technology Inc. 469d5fd8fSJohnny Huang */ 5e417205bSJohnny Huang 64c1c9b35SJohnny Huang #include <stdlib.h> 769d5fd8fSJohnny Huang #include <common.h> 869d5fd8fSJohnny Huang #include <console.h> 969d5fd8fSJohnny Huang #include <bootretry.h> 1069d5fd8fSJohnny Huang #include <cli.h> 1169d5fd8fSJohnny Huang #include <command.h> 1269d5fd8fSJohnny Huang #include <console.h> 134c1c9b35SJohnny Huang #include <malloc.h> 1469d5fd8fSJohnny Huang #include <inttypes.h> 1569d5fd8fSJohnny Huang #include <mapmem.h> 1669d5fd8fSJohnny Huang #include <asm/io.h> 1769d5fd8fSJohnny Huang #include <linux/compiler.h> 18696656c6SJohnny Huang #include <u-boot/sha256.h> 190cee9a95SJohnny Huang #include "otp_info.h" 2069d5fd8fSJohnny Huang 2169d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2269d5fd8fSJohnny Huang 230cc6ef78SJohnny Huang #define OTP_VER "1.2.0" 24f67375f7SJohnny Huang 2569d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 26dacbba92SJohnny Huang #define RETRY 20 277332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 287332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 297332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 3069d5fd8fSJohnny Huang 312a856b9aSJohnny Huang #define OTP_USAGE -1 322a856b9aSJohnny Huang #define OTP_FAILURE -2 332a856b9aSJohnny Huang #define OTP_SUCCESS 0 342a856b9aSJohnny Huang 35a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 36a6af4a17SJohnny Huang 37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB 1 38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV 2 39181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES 3 40181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT 4 41181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC 5 429a4fe690SJohnny Huang 433d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 443d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 453d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 463d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 473d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 483d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 493d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 503d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 513d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 523d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 53a8789b47SJohnny Huang #define SW_REV_ID0 OTP_BASE + 0x68 54a8789b47SJohnny Huang #define SW_REV_ID1 OTP_BASE + 0x6c 55030cb4a7SJohnny Huang #define SEC_KEY_NUM OTP_BASE + 0x78 563d3688adSJohnny Huang 57696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 58696656c6SJohnny Huang #define CHECKSUM_LEN 32 59a219f6deSJohnny Huang #define OTP_INC_DATA BIT(31) 60a219f6deSJohnny Huang #define OTP_INC_CONFIG BIT(30) 61a219f6deSJohnny Huang #define OTP_INC_STRAP BIT(29) 62a219f6deSJohnny Huang #define OTP_ECC_EN BIT(28) 63b25f02d2SJohnny Huang #define OTP_INC_SCU_PRO BIT(25) 64696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 65696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 66696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 67696656c6SJohnny Huang 68e417205bSJohnny Huang #define OTP_A0 0 69e417205bSJohnny Huang #define OTP_A1 1 70e417205bSJohnny Huang #define OTP_A2 2 71e417205bSJohnny Huang #define OTP_A3 3 72e417205bSJohnny Huang 73e417205bSJohnny Huang #define ID0_AST2600A0 0x05000303 74e417205bSJohnny Huang #define ID1_AST2600A0 0x05000303 75e417205bSJohnny Huang #define ID0_AST2600A1 0x05010303 7621a8cfceSJohnny Huang #define ID1_AST2600A1 0x05010303 77e417205bSJohnny Huang #define ID0_AST2600A2 0x05010303 78e417205bSJohnny Huang #define ID1_AST2600A2 0x05020303 79e417205bSJohnny Huang #define ID0_AST2600A3 0x05030303 80e417205bSJohnny Huang #define ID1_AST2600A3 0x05030303 81e417205bSJohnny Huang #define ID0_AST2620A1 0x05010203 82e417205bSJohnny Huang #define ID1_AST2620A1 0x05010203 83e417205bSJohnny Huang #define ID0_AST2620A2 0x05010203 84e417205bSJohnny Huang #define ID1_AST2620A2 0x05020203 85e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 86e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 87e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 88e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 89e417205bSJohnny Huang #define ID0_AST2605A2 0x05010103 90e417205bSJohnny Huang #define ID1_AST2605A2 0x05020103 91e417205bSJohnny Huang #define ID0_AST2605A3 0x05030103 92e417205bSJohnny Huang #define ID1_AST2605A3 0x05030103 93e417205bSJohnny Huang #define ID0_AST2625A3 0x05030403 94e417205bSJohnny Huang #define ID1_AST2625A3 0x05030403 95696656c6SJohnny Huang 9661a6cda7SJohnny Huang #define SOC_AST2600A0 0 9761a6cda7SJohnny Huang #define SOC_AST2600A1 1 9861a6cda7SJohnny Huang #define SOC_AST2600A2 2 9961a6cda7SJohnny Huang #define SOC_AST2600A3 3 10061a6cda7SJohnny Huang 10161a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c)) 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 } 22288bd7d58SJohnny Huang printf("\n"); 223f347c284SJohnny Huang } 224f347c284SJohnny Huang 225794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset) 226794e27ecSJohnny Huang { 227794e27ecSJohnny Huang int bit_offset; 228794e27ecSJohnny Huang int i; 229794e27ecSJohnny Huang 230794e27ecSJohnny Huang if (offset < 32) { 231794e27ecSJohnny Huang i = 0; 232794e27ecSJohnny Huang bit_offset = offset; 233794e27ecSJohnny Huang } else { 234794e27ecSJohnny Huang i = 1; 235794e27ecSJohnny Huang bit_offset = offset - 32; 236794e27ecSJohnny Huang } 237794e27ecSJohnny Huang if ((rid[i] >> bit_offset) & 0x1) 238794e27ecSJohnny Huang return 1; 239794e27ecSJohnny Huang else 240794e27ecSJohnny Huang return 0; 241794e27ecSJohnny Huang } 242794e27ecSJohnny Huang 243794e27ecSJohnny Huang static int get_rid_num(u32 *rid) 244794e27ecSJohnny Huang { 245794e27ecSJohnny Huang int i; 246794e27ecSJohnny Huang int fz = 0; 247794e27ecSJohnny Huang int rid_num = 0; 248794e27ecSJohnny Huang int ret = 0; 249794e27ecSJohnny Huang 250794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 251794e27ecSJohnny Huang if (get_dw_bit(rid, i) == 0) { 252794e27ecSJohnny Huang if (!fz) 253794e27ecSJohnny Huang fz = 1; 254794e27ecSJohnny Huang 255794e27ecSJohnny Huang } else { 256794e27ecSJohnny Huang rid_num++; 257794e27ecSJohnny Huang if (fz) 258794e27ecSJohnny Huang ret = OTP_FAILURE; 259794e27ecSJohnny Huang } 260794e27ecSJohnny Huang } 261794e27ecSJohnny Huang if (ret) 262794e27ecSJohnny Huang return ret; 263794e27ecSJohnny Huang 264794e27ecSJohnny Huang return rid_num; 265794e27ecSJohnny Huang } 266794e27ecSJohnny Huang 267a219f6deSJohnny Huang static u32 chip_version(void) 2689a4fe690SJohnny Huang { 269e417205bSJohnny Huang u32 revid0, revid1; 2709a4fe690SJohnny Huang 271e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0); 272e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1); 2739a4fe690SJohnny Huang 274e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { 275badd21c2SJohnny Huang /* AST2600-A0 */ 276e417205bSJohnny Huang return OTP_A0; 277e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { 278badd21c2SJohnny Huang /* AST2600-A1 */ 279e417205bSJohnny Huang return OTP_A1; 280e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { 281badd21c2SJohnny Huang /* AST2600-A2 */ 282e417205bSJohnny Huang return OTP_A2; 283e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { 28464b66712SJohnny Huang /* AST2600-A3 */ 285e417205bSJohnny Huang return OTP_A3; 286e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { 287e417205bSJohnny Huang /* AST2620-A1 */ 288e417205bSJohnny Huang return OTP_A1; 289e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { 290e417205bSJohnny Huang /* AST2620-A2 */ 291e417205bSJohnny Huang return OTP_A2; 292e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { 29364b66712SJohnny Huang /* AST2620-A3 */ 294e417205bSJohnny Huang return OTP_A3; 295e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { 296e417205bSJohnny Huang /* AST2605-A2 */ 297e417205bSJohnny Huang return OTP_A2; 298e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { 299e417205bSJohnny Huang /* AST2605-A3 */ 300e417205bSJohnny Huang return OTP_A3; 301e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { 302e417205bSJohnny Huang /* AST2605-A3 */ 303e417205bSJohnny Huang return OTP_A3; 3040dae9d52SJohnny Huang } 305f347c284SJohnny Huang return OTP_FAILURE; 3069a4fe690SJohnny Huang } 3079a4fe690SJohnny Huang 3083d3688adSJohnny Huang static void wait_complete(void) 3093d3688adSJohnny Huang { 3103d3688adSJohnny Huang int reg; 3113d3688adSJohnny Huang 3123d3688adSJohnny Huang do { 3133d3688adSJohnny Huang reg = readl(OTP_STATUS); 3143d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 3153d3688adSJohnny Huang } 3163d3688adSJohnny Huang 317a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 318dacbba92SJohnny Huang { 319dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 320dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 321dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 322dacbba92SJohnny Huang wait_complete(); 323dacbba92SJohnny Huang } 324dacbba92SJohnny Huang 325dacbba92SJohnny Huang static void otp_soak(int soak) 326dacbba92SJohnny Huang { 327e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) { 328dacbba92SJohnny Huang switch (soak) { 329dacbba92SJohnny Huang case 0: //default 330377f8cd7SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 331377f8cd7SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 332dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 333dacbba92SJohnny Huang break; 334dacbba92SJohnny Huang case 1: //normal program 335377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 336377f8cd7SJohnny Huang otp_write(0x5000, 0x1008); // Write MRB 337377f8cd7SJohnny Huang otp_write(0x1000, 0x0024); // Write MR 338feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 339dacbba92SJohnny Huang break; 340dacbba92SJohnny Huang case 2: //soak program 341377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 342377f8cd7SJohnny Huang otp_write(0x5000, 0x0007); // Write MRB 343377f8cd7SJohnny Huang otp_write(0x1000, 0x0100); // Write MR 344feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 345dacbba92SJohnny Huang break; 346dacbba92SJohnny Huang } 347dacbba92SJohnny Huang } else { 348dacbba92SJohnny Huang switch (soak) { 349dacbba92SJohnny Huang case 0: //default 350dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 351dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 352dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 353dacbba92SJohnny Huang break; 354dacbba92SJohnny Huang case 1: //normal program 355dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 356dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 357dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 358feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 359dacbba92SJohnny Huang break; 360dacbba92SJohnny Huang case 2: //soak program 361dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 362dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 363dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 364feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 365dacbba92SJohnny Huang break; 366dacbba92SJohnny Huang } 367dacbba92SJohnny Huang } 368dacbba92SJohnny Huang 369dacbba92SJohnny Huang wait_complete(); 370dacbba92SJohnny Huang } 371dacbba92SJohnny Huang 372a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 37369d5fd8fSJohnny Huang { 3743d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 3753d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3763d3688adSJohnny Huang wait_complete(); 3773d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 3783d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 37969d5fd8fSJohnny Huang } 38069d5fd8fSJohnny Huang 381f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data) 38269d5fd8fSJohnny Huang { 38369d5fd8fSJohnny Huang int config_offset; 38469d5fd8fSJohnny Huang 38569d5fd8fSJohnny Huang config_offset = 0x800; 38669d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 38769d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 38869d5fd8fSJohnny Huang 3893d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 3903d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3913d3688adSJohnny Huang wait_complete(); 3923d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 39369d5fd8fSJohnny Huang } 39469d5fd8fSJohnny Huang 395a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 39669d5fd8fSJohnny Huang { 397a219f6deSJohnny Huang u32 ret; 398a219f6deSJohnny Huang u32 *buf; 39969d5fd8fSJohnny Huang 40069d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 40169d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 40269d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 40369d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 40469d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 4053d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 4063d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 4073d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 4083d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 4093d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 4103d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 4113d3688adSJohnny Huang wait_complete(); 4123d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 41369d5fd8fSJohnny Huang if (ret & 0x1) 414f347c284SJohnny Huang return OTP_SUCCESS; 41569d5fd8fSJohnny Huang else 416f347c284SJohnny Huang return OTP_FAILURE; 41769d5fd8fSJohnny Huang } 41869d5fd8fSJohnny Huang 419a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 42069d5fd8fSJohnny Huang { 421a219f6deSJohnny Huang u32 ret[2]; 42269d5fd8fSJohnny Huang 42330a8c590SJohnny Huang if (otp_addr % 2 == 0) 4243d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 42530a8c590SJohnny Huang else 4263d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 42730a8c590SJohnny Huang 4283d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4293d3688adSJohnny Huang wait_complete(); 4303d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4313d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 43283655e91SJohnny Huang 43330a8c590SJohnny Huang if (otp_addr % 2 == 0) { 43430a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 435f347c284SJohnny Huang return OTP_SUCCESS; 43669d5fd8fSJohnny Huang else 437f347c284SJohnny Huang return OTP_FAILURE; 43830a8c590SJohnny Huang } else { 43930a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 440f347c284SJohnny Huang return OTP_SUCCESS; 44130a8c590SJohnny Huang else 442f347c284SJohnny Huang return OTP_FAILURE; 44330a8c590SJohnny Huang } 44469d5fd8fSJohnny Huang } 44569d5fd8fSJohnny Huang 446a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 4474c1c9b35SJohnny Huang { 448a219f6deSJohnny Huang u32 ret[2]; 4494c1c9b35SJohnny Huang 4504c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 4514c1c9b35SJohnny Huang 4524c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 4533d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 4544c1c9b35SJohnny Huang else 4553d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 4563d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4573d3688adSJohnny Huang wait_complete(); 4583d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4593d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 4604c1c9b35SJohnny Huang if (size == 1) { 4614c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 4624c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 463696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 4644c1c9b35SJohnny Huang compare[0] = 0; 465f347c284SJohnny Huang return OTP_SUCCESS; 466a219f6deSJohnny Huang } 4674c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 468f347c284SJohnny Huang return OTP_FAILURE; 4694c1c9b35SJohnny Huang 4704c1c9b35SJohnny Huang } else { 4714c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 472696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4734c1c9b35SJohnny Huang compare[0] = ~0; 474f347c284SJohnny Huang return OTP_SUCCESS; 475a219f6deSJohnny Huang } 476d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 477f347c284SJohnny Huang return OTP_FAILURE; 4784c1c9b35SJohnny Huang } 4794c1c9b35SJohnny Huang } else if (size == 2) { 4804c1c9b35SJohnny Huang // otp_addr should be even 481696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 4824c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4834c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4844c1c9b35SJohnny Huang compare[0] = 0; 4854c1c9b35SJohnny Huang compare[1] = ~0; 486f347c284SJohnny Huang return OTP_SUCCESS; 487a219f6deSJohnny Huang } 4884c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4894c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4904c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4914c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 492f347c284SJohnny Huang return OTP_FAILURE; 4934c1c9b35SJohnny Huang } else { 494f347c284SJohnny Huang return OTP_FAILURE; 4954c1c9b35SJohnny Huang } 4964c1c9b35SJohnny Huang } 4974c1c9b35SJohnny Huang 498a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit) 49983655e91SJohnny Huang { 50090965bb3SJohnny Huang otp_write(0x0, prog_bit); 50183655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 50283655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 50383655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 50483655e91SJohnny Huang wait_complete(); 50583655e91SJohnny Huang } 50683655e91SJohnny Huang 507a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 50883655e91SJohnny Huang { 50983655e91SJohnny Huang int prog_bit; 51083655e91SJohnny Huang 51183655e91SJohnny Huang if (prog_address % 2 == 0) { 51283655e91SJohnny Huang if (value) 51383655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 51483655e91SJohnny Huang else 51583655e91SJohnny Huang return; 51683655e91SJohnny Huang } else { 517e417205bSJohnny Huang if (info_cb.version != OTP_A3) 51883655e91SJohnny Huang prog_address |= 1 << 15; 51983655e91SJohnny Huang if (!value) 52083655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 52183655e91SJohnny Huang else 52283655e91SJohnny Huang return; 52383655e91SJohnny Huang } 52483655e91SJohnny Huang otp_prog(prog_address, prog_bit); 52583655e91SJohnny Huang } 52683655e91SJohnny Huang 527f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset) 52883655e91SJohnny Huang { 52983655e91SJohnny Huang int pass; 53083655e91SJohnny Huang int i; 53183655e91SJohnny Huang 53283655e91SJohnny Huang otp_soak(1); 53383655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 53483655e91SJohnny Huang pass = 0; 53583655e91SJohnny Huang 53683655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 53783655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 53883655e91SJohnny Huang otp_soak(2); 53983655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 54083655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 54183655e91SJohnny Huang otp_soak(1); 54283655e91SJohnny Huang } else { 54383655e91SJohnny Huang pass = 1; 54483655e91SJohnny Huang break; 54583655e91SJohnny Huang } 54683655e91SJohnny Huang } else { 54783655e91SJohnny Huang pass = 1; 54883655e91SJohnny Huang break; 54983655e91SJohnny Huang } 55083655e91SJohnny Huang } 551794e27ecSJohnny Huang if (pass) 552794e27ecSJohnny Huang return OTP_SUCCESS; 55383655e91SJohnny Huang 554794e27ecSJohnny Huang return OTP_FAILURE; 55583655e91SJohnny Huang } 55683655e91SJohnny Huang 557a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 558d90825e2SJohnny Huang { 559d90825e2SJohnny Huang int j, bit_value, prog_bit; 560d90825e2SJohnny Huang 561d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 562696656c6SJohnny Huang if ((ignore >> j) & 0x1) 563d90825e2SJohnny Huang continue; 564d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 565d90825e2SJohnny Huang if (prog_address % 2 == 0) { 566d90825e2SJohnny Huang if (bit_value) 567d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 568d90825e2SJohnny Huang else 569d90825e2SJohnny Huang continue; 570d90825e2SJohnny Huang } else { 571e417205bSJohnny Huang if (info_cb.version != OTP_A3) 572d90825e2SJohnny Huang prog_address |= 1 << 15; 573d90825e2SJohnny Huang if (bit_value) 574d90825e2SJohnny Huang continue; 575d90825e2SJohnny Huang else 576d90825e2SJohnny Huang prog_bit = 0x1 << j; 577d90825e2SJohnny Huang } 578d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 579d90825e2SJohnny Huang } 580d90825e2SJohnny Huang } 581d90825e2SJohnny Huang 582a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 58354552c69SJohnny Huang { 58454552c69SJohnny Huang int pass; 58554552c69SJohnny Huang int i; 586a219f6deSJohnny Huang u32 data0_masked; 587a219f6deSJohnny Huang u32 data1_masked; 588a219f6deSJohnny Huang u32 buf0_masked; 589a219f6deSJohnny Huang u32 buf1_masked; 590a219f6deSJohnny Huang u32 compare[2]; 59154552c69SJohnny Huang 59254552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 59354552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 59454552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 59554552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 596a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 597f347c284SJohnny Huang return OTP_SUCCESS; 59854552c69SJohnny Huang 599b64ca396SJohnny Huang for (i = 0; i < 32; i++) { 600b64ca396SJohnny Huang if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0) 601b64ca396SJohnny Huang return OTP_FAILURE; 602b64ca396SJohnny Huang if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1) 603b64ca396SJohnny Huang return OTP_FAILURE; 604b64ca396SJohnny Huang } 605b64ca396SJohnny Huang 60654552c69SJohnny Huang otp_soak(1); 60754552c69SJohnny Huang if (data0_masked != buf0_masked) 60854552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 60954552c69SJohnny Huang if (data1_masked != buf1_masked) 61054552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 61154552c69SJohnny Huang 61254552c69SJohnny Huang pass = 0; 61354552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 61454552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 61554552c69SJohnny Huang otp_soak(2); 616a219f6deSJohnny Huang if (compare[0] != 0) 61754552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 618a219f6deSJohnny Huang if (compare[1] != ~0) 6195537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 62054552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 62154552c69SJohnny Huang otp_soak(1); 62254552c69SJohnny Huang } else { 62354552c69SJohnny Huang pass = 1; 62454552c69SJohnny Huang break; 62554552c69SJohnny Huang } 62654552c69SJohnny Huang } else { 62754552c69SJohnny Huang pass = 1; 62854552c69SJohnny Huang break; 62954552c69SJohnny Huang } 63054552c69SJohnny Huang } 63154552c69SJohnny Huang 63254552c69SJohnny Huang if (!pass) { 63354552c69SJohnny Huang otp_soak(0); 63454552c69SJohnny Huang return OTP_FAILURE; 63554552c69SJohnny Huang } 63654552c69SJohnny Huang return OTP_SUCCESS; 63754552c69SJohnny Huang } 63854552c69SJohnny Huang 639541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 64076d13988SJohnny Huang { 641a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 6425010032bSJohnny Huang int strap_end; 64376d13988SJohnny Huang int i, j; 64476d13988SJohnny Huang 645e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 64676d13988SJohnny Huang for (j = 0; j < 64; j++) { 64776d13988SJohnny Huang otpstrap[j].value = 0; 64876d13988SJohnny Huang otpstrap[j].remain_times = 7; 64976d13988SJohnny Huang otpstrap[j].writeable_option = -1; 65076d13988SJohnny Huang otpstrap[j].protected = 0; 65176d13988SJohnny Huang } 6525010032bSJohnny Huang strap_end = 30; 6535010032bSJohnny Huang } else { 6545010032bSJohnny Huang for (j = 0; j < 64; j++) { 6555010032bSJohnny Huang otpstrap[j].value = 0; 6565010032bSJohnny Huang otpstrap[j].remain_times = 6; 6575010032bSJohnny Huang otpstrap[j].writeable_option = -1; 6585010032bSJohnny Huang otpstrap[j].protected = 0; 6595010032bSJohnny Huang } 6605010032bSJohnny Huang strap_end = 28; 6615010032bSJohnny Huang } 66276d13988SJohnny Huang 663dacbba92SJohnny Huang otp_soak(0); 6645010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 66576d13988SJohnny Huang int option = (i - 16) / 2; 666a219f6deSJohnny Huang 667f347c284SJohnny Huang otp_read_conf(i, &OTPSTRAP_RAW[0]); 668f347c284SJohnny Huang otp_read_conf(i + 1, &OTPSTRAP_RAW[1]); 66976d13988SJohnny Huang for (j = 0; j < 32; j++) { 67076d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 671a219f6deSJohnny Huang 672a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 67376d13988SJohnny Huang otpstrap[j].writeable_option = option; 67476d13988SJohnny Huang if (bit_value == 1) 67576d13988SJohnny Huang otpstrap[j].remain_times--; 67676d13988SJohnny Huang otpstrap[j].value ^= bit_value; 67776d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 67876d13988SJohnny Huang } 67976d13988SJohnny Huang for (j = 32; j < 64; j++) { 68076d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 681a219f6deSJohnny Huang 682a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 68376d13988SJohnny Huang otpstrap[j].writeable_option = option; 68476d13988SJohnny Huang if (bit_value == 1) 68576d13988SJohnny Huang otpstrap[j].remain_times--; 68676d13988SJohnny Huang otpstrap[j].value ^= bit_value; 68776d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 68876d13988SJohnny Huang } 68976d13988SJohnny Huang } 6905010032bSJohnny Huang 691f347c284SJohnny Huang otp_read_conf(30, &OTPSTRAP_RAW[0]); 692f347c284SJohnny Huang otp_read_conf(31, &OTPSTRAP_RAW[1]); 69376d13988SJohnny Huang for (j = 0; j < 32; j++) { 69476d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 69576d13988SJohnny Huang otpstrap[j].protected = 1; 69676d13988SJohnny Huang } 69776d13988SJohnny Huang for (j = 32; j < 64; j++) { 69876d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 69976d13988SJohnny Huang otpstrap[j].protected = 1; 70076d13988SJohnny Huang } 70176d13988SJohnny Huang } 70276d13988SJohnny Huang 7037e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit) 704f347c284SJohnny Huang { 705f347c284SJohnny Huang int prog_flag = 0; 706f347c284SJohnny Huang 707f347c284SJohnny Huang // ignore this bit 708f347c284SJohnny Huang if (ibit == 1) 709f347c284SJohnny Huang return OTP_SUCCESS; 710b489486eSJohnny Huang printf("OTPSTRAP[0x%X]:\n", offset); 711f347c284SJohnny Huang 712f347c284SJohnny Huang if (bit == otpstrap->value) { 7137e523e3bSJohnny Huang if (!pbit) { 714f347c284SJohnny Huang printf(" The value is same as before, skip it.\n"); 715f347c284SJohnny Huang return OTP_PROG_SKIP; 716f347c284SJohnny Huang } 717f347c284SJohnny Huang printf(" The value is same as before.\n"); 718f347c284SJohnny Huang } else { 719f347c284SJohnny Huang prog_flag = 1; 720f347c284SJohnny Huang } 721f347c284SJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 722f347c284SJohnny Huang printf(" This bit is protected and is not writable\n"); 723f347c284SJohnny Huang return OTP_FAILURE; 724f347c284SJohnny Huang } 725f347c284SJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 726b489486eSJohnny Huang printf(" This bit has no remaining chance to write.\n"); 727f347c284SJohnny Huang return OTP_FAILURE; 728f347c284SJohnny Huang } 729f347c284SJohnny Huang if (pbit == 1) 730f347c284SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 731f347c284SJohnny Huang if (prog_flag) 732b489486eSJohnny 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); 733f347c284SJohnny Huang 734f347c284SJohnny Huang return OTP_SUCCESS; 735f347c284SJohnny Huang } 736f347c284SJohnny Huang 737f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value) 738f347c284SJohnny Huang { 739f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 740f347c284SJohnny Huang u32 prog_address; 741f347c284SJohnny Huang int offset; 742f347c284SJohnny Huang int ret; 743f347c284SJohnny Huang 744f347c284SJohnny Huang otp_strap_status(otpstrap); 745f347c284SJohnny Huang 7467e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 747f347c284SJohnny Huang 748f347c284SJohnny Huang if (ret != OTP_SUCCESS) 749f347c284SJohnny Huang return ret; 750f347c284SJohnny Huang 751f347c284SJohnny Huang prog_address = 0x800; 752f347c284SJohnny Huang if (bit_offset < 32) { 753f347c284SJohnny Huang offset = bit_offset; 754f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 755f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 756f347c284SJohnny Huang 757f347c284SJohnny Huang } else { 758f347c284SJohnny Huang offset = (bit_offset - 32); 759f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 760f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 761f347c284SJohnny Huang } 762f347c284SJohnny Huang 763f347c284SJohnny Huang return otp_prog_dc_b(1, prog_address, offset); 764f347c284SJohnny Huang } 765f347c284SJohnny Huang 766f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count) 767f347c284SJohnny Huang { 768f347c284SJohnny Huang int i; 769f347c284SJohnny Huang u32 ret[1]; 770f347c284SJohnny Huang 771f347c284SJohnny Huang if (offset + dw_count > 32) 772f347c284SJohnny Huang return OTP_USAGE; 773f347c284SJohnny Huang otp_soak(0); 774f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i++) { 775f347c284SJohnny Huang otp_read_conf(i, ret); 776b489486eSJohnny Huang printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]); 777f347c284SJohnny Huang } 778f347c284SJohnny Huang printf("\n"); 779f347c284SJohnny Huang return OTP_SUCCESS; 780f347c284SJohnny Huang } 781f347c284SJohnny Huang 782f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count) 783f347c284SJohnny Huang { 784f347c284SJohnny Huang int i; 785f347c284SJohnny Huang u32 ret[2]; 786f347c284SJohnny Huang 787f347c284SJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 788f347c284SJohnny Huang return OTP_USAGE; 789f347c284SJohnny Huang otp_soak(0); 790f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 791f347c284SJohnny Huang otp_read_data(i, ret); 792f347c284SJohnny Huang if (i % 4 == 0) 793f347c284SJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 794f347c284SJohnny Huang else 795f347c284SJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 796f347c284SJohnny Huang } 797f347c284SJohnny Huang printf("\n"); 798f347c284SJohnny Huang return OTP_SUCCESS; 799f347c284SJohnny Huang } 800f347c284SJohnny Huang 801f347c284SJohnny Huang static int otp_print_strap(int start, int count) 802f347c284SJohnny Huang { 803f347c284SJohnny Huang int i, j; 804f347c284SJohnny Huang int remains; 805f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 806f347c284SJohnny Huang 807f347c284SJohnny Huang if (start < 0 || start > 64) 808f347c284SJohnny Huang return OTP_USAGE; 809f347c284SJohnny Huang 810f347c284SJohnny Huang if ((start + count) < 0 || (start + count) > 64) 811f347c284SJohnny Huang return OTP_USAGE; 812f347c284SJohnny Huang 813f347c284SJohnny Huang otp_strap_status(otpstrap); 814f347c284SJohnny Huang 8157e523e3bSJohnny Huang if (info_cb.version == OTP_A0) 816f347c284SJohnny Huang remains = 7; 8177e523e3bSJohnny Huang else 818f347c284SJohnny Huang remains = 6; 8197e523e3bSJohnny Huang printf("BIT(hex) Value Option Status\n"); 820f347c284SJohnny Huang printf("______________________________________________________________________________\n"); 821f347c284SJohnny Huang 822f347c284SJohnny Huang for (i = start; i < start + count; i++) { 823f347c284SJohnny Huang printf("0x%-8X", i); 824f347c284SJohnny Huang printf("%-7d", otpstrap[i].value); 825f347c284SJohnny Huang for (j = 0; j < remains; j++) 826f347c284SJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 827f347c284SJohnny Huang printf(" "); 828f347c284SJohnny Huang if (otpstrap[i].protected == 1) { 829f347c284SJohnny Huang printf("protected and not writable"); 830f347c284SJohnny Huang } else { 831f347c284SJohnny Huang printf("not protected "); 832f347c284SJohnny Huang if (otpstrap[i].remain_times == 0) 833f347c284SJohnny Huang printf("and no remaining times to write."); 834f347c284SJohnny Huang else 835f347c284SJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 836f347c284SJohnny Huang } 837f347c284SJohnny Huang printf("\n"); 838f347c284SJohnny Huang } 839f347c284SJohnny Huang 840f347c284SJohnny Huang return OTP_SUCCESS; 841f347c284SJohnny Huang } 842f347c284SJohnny Huang 843794e27ecSJohnny Huang static void otp_print_revid(u32 *rid) 844794e27ecSJohnny Huang { 845794e27ecSJohnny Huang int bit_offset; 846794e27ecSJohnny Huang int i, j; 847794e27ecSJohnny Huang 848794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 849794e27ecSJohnny Huang printf("___________________________________________________\n"); 850794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 851794e27ecSJohnny Huang if (i < 32) { 852794e27ecSJohnny Huang j = 0; 853794e27ecSJohnny Huang bit_offset = i; 854794e27ecSJohnny Huang } else { 855794e27ecSJohnny Huang j = 1; 856794e27ecSJohnny Huang bit_offset = i - 32; 857794e27ecSJohnny Huang } 858794e27ecSJohnny Huang if (i % 16 == 0) 859794e27ecSJohnny Huang printf("%2x | ", i); 860794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1); 861794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 862794e27ecSJohnny Huang printf("\n"); 863794e27ecSJohnny Huang } 864794e27ecSJohnny Huang } 865794e27ecSJohnny Huang 866b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout) 867b25f02d2SJohnny Huang { 868b25f02d2SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 869b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 870b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 871b25f02d2SJohnny Huang int i; 872b25f02d2SJohnny Huang u32 scu_offset; 873b25f02d2SJohnny Huang u32 dw_offset; 874b25f02d2SJohnny Huang u32 bit_offset; 875b25f02d2SJohnny Huang u32 mask; 876b25f02d2SJohnny Huang u32 otp_value; 877b25f02d2SJohnny Huang u32 otp_ignore; 878b25f02d2SJohnny Huang 879b25f02d2SJohnny Huang printf("SCU BIT reg_protect Description\n"); 880b25f02d2SJohnny Huang printf("____________________________________________________________________\n"); 881b25f02d2SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 882b25f02d2SJohnny Huang mask = BIT(scu_info[i].length) - 1; 883b25f02d2SJohnny Huang 884b25f02d2SJohnny Huang if (scu_info[i].bit_offset > 31) { 885b25f02d2SJohnny Huang scu_offset = 0x510; 886b25f02d2SJohnny Huang dw_offset = 1; 887b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset - 32; 888b25f02d2SJohnny Huang } else { 889b25f02d2SJohnny Huang scu_offset = 0x500; 890b25f02d2SJohnny Huang dw_offset = 0; 891b25f02d2SJohnny Huang bit_offset = scu_info[i].bit_offset; 892b25f02d2SJohnny Huang } 893b25f02d2SJohnny Huang 894b25f02d2SJohnny Huang otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask; 895b25f02d2SJohnny Huang otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask; 896b25f02d2SJohnny Huang 897b25f02d2SJohnny Huang if (otp_ignore == mask) 898b25f02d2SJohnny Huang continue; 899b25f02d2SJohnny Huang else if (otp_ignore != 0) 900b25f02d2SJohnny Huang return OTP_FAILURE; 901b25f02d2SJohnny Huang 902b25f02d2SJohnny Huang if (otp_value != 0 && otp_value != mask) 903b25f02d2SJohnny Huang return OTP_FAILURE; 904b25f02d2SJohnny Huang 905b25f02d2SJohnny Huang printf("0x%-6X", scu_offset); 906b25f02d2SJohnny Huang if (scu_info[i].length == 1) 907b25f02d2SJohnny Huang printf("0x%-11X", bit_offset); 908b25f02d2SJohnny Huang else 909b25f02d2SJohnny Huang printf("0x%-2X:0x%-4x", bit_offset, bit_offset + scu_info[i].length - 1); 910b25f02d2SJohnny Huang printf("0x%-14X", otp_value); 911b25f02d2SJohnny Huang printf("%s\n", scu_info[i].information); 912b25f02d2SJohnny Huang } 913b25f02d2SJohnny Huang return OTP_SUCCESS; 914b25f02d2SJohnny Huang } 915b25f02d2SJohnny Huang 9160dc9a440SJohnny Huang static void otp_print_scu_info(void) 9170dc9a440SJohnny Huang { 9180dc9a440SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 9190dc9a440SJohnny Huang u32 OTPCFG[2]; 9200dc9a440SJohnny Huang u32 scu_offset; 9210dc9a440SJohnny Huang u32 bit_offset; 9220dc9a440SJohnny Huang u32 reg_p; 9230dc9a440SJohnny Huang u32 length; 9240dc9a440SJohnny Huang int i, j; 9250dc9a440SJohnny Huang 9260dc9a440SJohnny Huang otp_soak(0); 9270dc9a440SJohnny Huang otp_read_conf(28, &OTPCFG[0]); 9280dc9a440SJohnny Huang otp_read_conf(29, &OTPCFG[1]); 9290dc9a440SJohnny Huang printf("SCU BIT reg_protect Description\n"); 9300dc9a440SJohnny Huang printf("____________________________________________________________________\n"); 9310dc9a440SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 9320dc9a440SJohnny Huang length = scu_info[i].length; 9330dc9a440SJohnny Huang for (j = 0; j < length; j++) { 9340dc9a440SJohnny Huang if (scu_info[i].bit_offset + j < 32) { 9350dc9a440SJohnny Huang scu_offset = 0x500; 9360dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j; 9370dc9a440SJohnny Huang reg_p = (OTPCFG[0] >> bit_offset) & 0x1; 9380dc9a440SJohnny Huang } else { 9390dc9a440SJohnny Huang scu_offset = 0x510; 9400dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j - 32; 9410dc9a440SJohnny Huang reg_p = (OTPCFG[1] >> bit_offset) & 0x1; 9420dc9a440SJohnny Huang } 9430dc9a440SJohnny Huang printf("0x%-6X", scu_offset); 9440dc9a440SJohnny Huang printf("0x%-4X", bit_offset); 9450dc9a440SJohnny Huang printf("0x%-13X", reg_p); 9460dc9a440SJohnny Huang if (length == 1) { 9470dc9a440SJohnny Huang printf(" %s\n", scu_info[i].information); 9480dc9a440SJohnny Huang continue; 9490dc9a440SJohnny Huang } 9500dc9a440SJohnny Huang 9510dc9a440SJohnny Huang if (j == 0) 9520dc9a440SJohnny Huang printf("/%s\n", scu_info[i].information); 9530dc9a440SJohnny Huang else if (j == length - 1) 9540dc9a440SJohnny Huang printf("\\ \"\n"); 9550dc9a440SJohnny Huang else 9560dc9a440SJohnny Huang printf("| \"\n"); 9570dc9a440SJohnny Huang } 9580dc9a440SJohnny Huang } 9590dc9a440SJohnny Huang } 9600dc9a440SJohnny Huang 961696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 96269d5fd8fSJohnny Huang { 96379e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 964a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 965a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 966a219f6deSJohnny Huang u32 mask; 967a219f6deSJohnny Huang u32 dw_offset; 968a219f6deSJohnny Huang u32 bit_offset; 969a219f6deSJohnny Huang u32 otp_value; 970a219f6deSJohnny Huang u32 otp_ignore; 971b458cd62SJohnny Huang int fail = 0; 9727adec5f6SJohnny Huang int mask_err; 973794e27ecSJohnny Huang int rid_num = 0; 97473f11549SJohnny Huang char valid_bit[20]; 975794e27ecSJohnny Huang int fz; 97666f2f8e5SJohnny Huang int i; 97773f11549SJohnny Huang int j; 97866f2f8e5SJohnny Huang 979737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 98066f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 9813cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 9827adec5f6SJohnny Huang mask_err = 0; 9833cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 9843cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 9853cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 986b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 987696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 988b458cd62SJohnny Huang 9897adec5f6SJohnny Huang if (conf_info[i].value == OTP_REG_VALID_BIT) { 9907adec5f6SJohnny Huang if (((otp_value + otp_ignore) & mask) != mask) { 991b458cd62SJohnny Huang fail = 1; 9927adec5f6SJohnny Huang mask_err = 1; 9937adec5f6SJohnny Huang } 9947adec5f6SJohnny Huang } else { 9957adec5f6SJohnny Huang if (otp_ignore == mask) { 9967adec5f6SJohnny Huang continue; 9977adec5f6SJohnny Huang } else if (otp_ignore != 0) { 9987adec5f6SJohnny Huang fail = 1; 9997adec5f6SJohnny Huang mask_err = 1; 10007adec5f6SJohnny Huang } 10017adec5f6SJohnny Huang } 1002b458cd62SJohnny Huang 1003a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 10043cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 10053cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 10063cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1007b458cd62SJohnny Huang continue; 1008b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1009b458cd62SJohnny Huang 10103cb28812SJohnny Huang if (conf_info[i].length == 1) { 10113cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 101266f2f8e5SJohnny Huang } else { 1013b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 10143cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 10153cb28812SJohnny Huang conf_info[i].bit_offset); 101666f2f8e5SJohnny Huang } 1017b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1018b458cd62SJohnny Huang 10197adec5f6SJohnny Huang if (mask_err) { 10207adec5f6SJohnny Huang printf("Ignore, mask error\n"); 1021a219f6deSJohnny Huang continue; 1022a219f6deSJohnny Huang } 10233cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1024b458cd62SJohnny Huang printf("Reserved\n"); 10253cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 10263cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1027b458cd62SJohnny Huang printf("\n"); 10283cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1029b458cd62SJohnny Huang if (otp_value != 0) { 103073f11549SJohnny Huang for (j = 0; j < 7; j++) { 1031*e2b82258SJohnny Huang if (otp_value & (1 << j)) 103273f11549SJohnny Huang valid_bit[j * 2] = '1'; 1033a219f6deSJohnny Huang else 103473f11549SJohnny Huang valid_bit[j * 2] = '0'; 103573f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 103673f11549SJohnny Huang } 103773f11549SJohnny Huang valid_bit[15] = 0; 103873f11549SJohnny Huang } else { 103973f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1040b458cd62SJohnny Huang } 10413cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1042b458cd62SJohnny Huang printf("\n"); 1043b458cd62SJohnny Huang } else { 10443cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1045b458cd62SJohnny Huang } 1046b458cd62SJohnny Huang } 1047b458cd62SJohnny Huang 1048794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) { 1049794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) { 1050794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1051794e27ecSJohnny Huang fail = 1; 1052794e27ecSJohnny Huang } else { 1053794e27ecSJohnny Huang fz = 0; 1054794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 1055794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) { 1056794e27ecSJohnny Huang if (!fz) 1057794e27ecSJohnny Huang fz = 1; 1058794e27ecSJohnny Huang } else { 1059794e27ecSJohnny Huang rid_num++; 1060794e27ecSJohnny Huang if (fz) { 1061794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 1062794e27ecSJohnny Huang fail = 1; 1063794e27ecSJohnny Huang break; 1064794e27ecSJohnny Huang } 1065794e27ecSJohnny Huang } 1066794e27ecSJohnny Huang } 1067794e27ecSJohnny Huang } 1068794e27ecSJohnny Huang if (fail) 1069794e27ecSJohnny Huang printf("OTP revision ID\n"); 1070794e27ecSJohnny Huang else 1071794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1072794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]); 1073794e27ecSJohnny Huang } 1074794e27ecSJohnny Huang 1075b458cd62SJohnny Huang if (fail) 1076b458cd62SJohnny Huang return OTP_FAILURE; 1077b458cd62SJohnny Huang 107866f2f8e5SJohnny Huang return OTP_SUCCESS; 107966f2f8e5SJohnny Huang } 108066f2f8e5SJohnny Huang 10812d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 108266f2f8e5SJohnny Huang { 108379e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1084a219f6deSJohnny Huang u32 OTPCFG[16]; 1085a219f6deSJohnny Huang u32 mask; 1086a219f6deSJohnny Huang u32 dw_offset; 1087a219f6deSJohnny Huang u32 bit_offset; 1088a219f6deSJohnny Huang u32 otp_value; 108973f11549SJohnny Huang char valid_bit[20]; 109066f2f8e5SJohnny Huang int i; 109173f11549SJohnny Huang int j; 109266f2f8e5SJohnny Huang 1093dacbba92SJohnny Huang otp_soak(0); 1094bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 1095f347c284SJohnny Huang otp_read_conf(i, &OTPCFG[i]); 109666f2f8e5SJohnny Huang 1097b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 1098b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 10993cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 11003cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 11012d4b0742SJohnny Huang continue; 11023cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 11033cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 11043cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1105b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1106b458cd62SJohnny Huang 1107a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 11083cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 11093cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 11103cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1111b458cd62SJohnny Huang continue; 1112b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1113b458cd62SJohnny Huang 11143cb28812SJohnny Huang if (conf_info[i].length == 1) { 11153cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 1116b458cd62SJohnny Huang } else { 1117b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 11183cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 11193cb28812SJohnny Huang conf_info[i].bit_offset); 1120b458cd62SJohnny Huang } 1121b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1122b458cd62SJohnny Huang 11233cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1124b458cd62SJohnny Huang printf("Reserved\n"); 11253cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 11263cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1127b458cd62SJohnny Huang printf("\n"); 11283cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1129b458cd62SJohnny Huang if (otp_value != 0) { 113073f11549SJohnny Huang for (j = 0; j < 7; j++) { 1131030cb4a7SJohnny Huang if (otp_value & (1 << j)) 113273f11549SJohnny Huang valid_bit[j * 2] = '1'; 1133a219f6deSJohnny Huang else 113473f11549SJohnny Huang valid_bit[j * 2] = '0'; 113573f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 113673f11549SJohnny Huang } 113773f11549SJohnny Huang valid_bit[15] = 0; 113873f11549SJohnny Huang } else { 113973f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1140b458cd62SJohnny Huang } 11413cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1142b458cd62SJohnny Huang printf("\n"); 1143b458cd62SJohnny Huang } else { 11443cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1145b458cd62SJohnny Huang } 1146b458cd62SJohnny Huang } 1147b458cd62SJohnny Huang return OTP_SUCCESS; 114866f2f8e5SJohnny Huang } 114966f2f8e5SJohnny Huang 11505010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 115176d13988SJohnny Huang { 115279e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 1153a219f6deSJohnny Huang u32 *OTPSTRAP; 1154a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 1155a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 115676d13988SJohnny Huang int i; 1157a8bd6d8cSJohnny Huang int fail = 0; 1158a219f6deSJohnny Huang u32 bit_offset; 1159a219f6deSJohnny Huang u32 dw_offset; 1160a219f6deSJohnny Huang u32 mask; 1161a219f6deSJohnny Huang u32 otp_value; 1162a219f6deSJohnny Huang u32 otp_protect; 1163a219f6deSJohnny Huang u32 otp_ignore; 116476d13988SJohnny Huang 1165a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 1166a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 1167a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 11687e523e3bSJohnny Huang 1169a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 1170de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 1171b458cd62SJohnny Huang 11723cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 11737adec5f6SJohnny Huang fail = 0; 1174696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 1175a8bd6d8cSJohnny Huang dw_offset = 1; 11763cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 1177a8bd6d8cSJohnny Huang } else { 1178a8bd6d8cSJohnny Huang dw_offset = 0; 11793cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 1180a8bd6d8cSJohnny Huang } 118176d13988SJohnny Huang 11823cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 1183a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 1184a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 1185696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 1186a8bd6d8cSJohnny Huang 1187a219f6deSJohnny Huang if (otp_ignore == mask) 1188a8bd6d8cSJohnny Huang continue; 1189a219f6deSJohnny Huang else if (otp_ignore != 0) 1190a8bd6d8cSJohnny Huang fail = 1; 1191a8bd6d8cSJohnny Huang 1192a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 11933cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1194a8bd6d8cSJohnny Huang continue; 1195a8bd6d8cSJohnny Huang 11963cb28812SJohnny Huang if (strap_info[i].length == 1) { 11973cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1198a8bd6d8cSJohnny Huang } else { 1199b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 12003cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 12013cb28812SJohnny Huang strap_info[i].bit_offset); 1202a8bd6d8cSJohnny Huang } 1203a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 1204a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 1205a8bd6d8cSJohnny Huang 1206a8bd6d8cSJohnny Huang if (fail) { 1207696656c6SJohnny Huang printf("Ignore mask error\n"); 1208a8bd6d8cSJohnny Huang } else { 12093cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12103cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1211a8bd6d8cSJohnny Huang else 1212a8bd6d8cSJohnny Huang printf("Reserved\n"); 1213a8bd6d8cSJohnny Huang } 1214a8bd6d8cSJohnny Huang } 1215a8bd6d8cSJohnny Huang 1216a8bd6d8cSJohnny Huang if (fail) 121776d13988SJohnny Huang return OTP_FAILURE; 121876d13988SJohnny Huang 121976d13988SJohnny Huang return OTP_SUCCESS; 122076d13988SJohnny Huang } 122176d13988SJohnny Huang 1222b458cd62SJohnny Huang static int otp_print_strap_info(int view) 122376d13988SJohnny Huang { 122479e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 122576d13988SJohnny Huang struct otpstrap_status strap_status[64]; 122607baa4e8SJohnny Huang int i, j; 1227b458cd62SJohnny Huang int fail = 0; 1228a219f6deSJohnny Huang u32 bit_offset; 1229a219f6deSJohnny Huang u32 length; 1230a219f6deSJohnny Huang u32 otp_value; 1231a219f6deSJohnny Huang u32 otp_protect; 123276d13988SJohnny Huang 1233541eb887SJohnny Huang otp_strap_status(strap_status); 123476d13988SJohnny Huang 1235b458cd62SJohnny Huang if (view) { 123607baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 123707baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 1238b458cd62SJohnny Huang } else { 1239b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 1240b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 124176d13988SJohnny Huang } 12423cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 1243b458cd62SJohnny Huang otp_value = 0; 12443cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 12453cb28812SJohnny Huang length = strap_info[i].length; 1246b458cd62SJohnny Huang for (j = 0; j < length; j++) { 1247c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 1248c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 1249b458cd62SJohnny Huang } 1250a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 12513cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1252b458cd62SJohnny Huang continue; 1253b458cd62SJohnny Huang if (view) { 1254b458cd62SJohnny Huang for (j = 0; j < length; j++) { 12553cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 1256b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 125707baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 1258e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 12593cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 1260b458cd62SJohnny Huang printf(" Reserved\n"); 1261b458cd62SJohnny Huang continue; 1262b458cd62SJohnny Huang } 1263b458cd62SJohnny Huang if (length == 1) { 12643cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 1265b458cd62SJohnny Huang continue; 126676d13988SJohnny Huang } 126776d13988SJohnny Huang 1268b458cd62SJohnny Huang if (j == 0) 12693cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 1270b458cd62SJohnny Huang else if (j == length - 1) 1271b458cd62SJohnny Huang printf("\\ \"\n"); 1272b458cd62SJohnny Huang else 1273b458cd62SJohnny Huang printf("| \"\n"); 127476d13988SJohnny Huang } 1275b458cd62SJohnny Huang } else { 1276c947ef08SJohnny Huang if (length == 1) { 12773cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1278b458cd62SJohnny Huang } else { 1279b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 1280b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 1281b458cd62SJohnny Huang } 1282b458cd62SJohnny Huang 1283b458cd62SJohnny Huang printf("0x%-10X", otp_value); 1284b458cd62SJohnny Huang 12853cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12863cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1287b458cd62SJohnny Huang else 1288b458cd62SJohnny Huang printf("Reserved\n"); 1289b458cd62SJohnny Huang } 1290b458cd62SJohnny Huang } 1291b458cd62SJohnny Huang 1292b458cd62SJohnny Huang if (fail) 1293b458cd62SJohnny Huang return OTP_FAILURE; 1294b458cd62SJohnny Huang 1295b458cd62SJohnny Huang return OTP_SUCCESS; 1296b458cd62SJohnny Huang } 1297b458cd62SJohnny Huang 129888bd7d58SJohnny Huang static void _otp_print_key(u32 *data) 129969d5fd8fSJohnny Huang { 130088bd7d58SJohnny Huang int i, j; 130169d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 13029a4fe690SJohnny Huang struct otpkey_type key_info; 130388bd7d58SJohnny Huang const struct otpkey_type *key_info_array = info_cb.key_info; 130488bd7d58SJohnny Huang int len = 0; 1305a219f6deSJohnny Huang u8 *byte_buf; 130688bd7d58SJohnny Huang int empty; 130754552c69SJohnny Huang 130888bd7d58SJohnny Huang byte_buf = (u8 *)data; 13099d998018SJohnny Huang 131088bd7d58SJohnny Huang empty = 1; 13119d998018SJohnny Huang for (i = 0; i < 16; i++) { 131288bd7d58SJohnny Huang if (i % 2) { 131388bd7d58SJohnny Huang if (data[i] != 0xffffffff) 131488bd7d58SJohnny Huang empty = 0; 131588bd7d58SJohnny Huang } else { 131688bd7d58SJohnny Huang if (data[i] != 0) 13179d998018SJohnny Huang empty = 0; 13189d998018SJohnny Huang } 131988bd7d58SJohnny Huang } 132088bd7d58SJohnny Huang if (empty) { 132188bd7d58SJohnny Huang printf("OTP data header is empty\n"); 132288bd7d58SJohnny Huang return; 132388bd7d58SJohnny Huang } 13249d998018SJohnny Huang 132588bd7d58SJohnny Huang for (i = 0; i < 16; i++) { 132688bd7d58SJohnny Huang key_id = data[i] & 0x7; 132788bd7d58SJohnny Huang key_offset = data[i] & 0x1ff8; 132888bd7d58SJohnny Huang last = (data[i] >> 13) & 1; 132988bd7d58SJohnny Huang key_type = (data[i] >> 14) & 0xf; 133088bd7d58SJohnny Huang key_length = (data[i] >> 18) & 0x3; 133188bd7d58SJohnny Huang exp_length = (data[i] >> 20) & 0xfff; 13329a4fe690SJohnny Huang 133388bd7d58SJohnny Huang key_info.value = -1; 13349a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 13359a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 13369a4fe690SJohnny Huang key_info = key_info_array[j]; 13379a4fe690SJohnny Huang break; 13389a4fe690SJohnny Huang } 13399a4fe690SJohnny Huang } 134088bd7d58SJohnny Huang if (key_info.value == -1) 134188bd7d58SJohnny Huang break; 13429a4fe690SJohnny Huang 13437f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 134469d5fd8fSJohnny Huang printf("Key Type: "); 13459a4fe690SJohnny Huang printf("%s\n", key_info.information); 13469a4fe690SJohnny Huang 13479a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 134869d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 134969d5fd8fSJohnny Huang switch (key_length) { 135069d5fd8fSJohnny Huang case 0: 135169d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 135269d5fd8fSJohnny Huang break; 135369d5fd8fSJohnny Huang case 1: 135469d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 135569d5fd8fSJohnny Huang break; 135669d5fd8fSJohnny Huang case 2: 135769d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 135869d5fd8fSJohnny Huang break; 135969d5fd8fSJohnny Huang case 3: 136069d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 136169d5fd8fSJohnny Huang break; 136269d5fd8fSJohnny Huang } 1363181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1364181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 136569d5fd8fSJohnny Huang printf("RSA SHA Type: "); 136669d5fd8fSJohnny Huang switch (key_length) { 136769d5fd8fSJohnny Huang case 0: 136869d5fd8fSJohnny Huang printf("RSA1024\n"); 136969d5fd8fSJohnny Huang len = 0x100; 137069d5fd8fSJohnny Huang break; 137169d5fd8fSJohnny Huang case 1: 137269d5fd8fSJohnny Huang printf("RSA2048\n"); 137369d5fd8fSJohnny Huang len = 0x200; 137469d5fd8fSJohnny Huang break; 137569d5fd8fSJohnny Huang case 2: 137669d5fd8fSJohnny Huang printf("RSA3072\n"); 137769d5fd8fSJohnny Huang len = 0x300; 137869d5fd8fSJohnny Huang break; 137969d5fd8fSJohnny Huang case 3: 138069d5fd8fSJohnny Huang printf("RSA4096\n"); 138169d5fd8fSJohnny Huang len = 0x400; 138269d5fd8fSJohnny Huang break; 138369d5fd8fSJohnny Huang } 138469d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 138569d5fd8fSJohnny Huang } 13869a4fe690SJohnny Huang if (key_info.need_id) 138769d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 138869d5fd8fSJohnny Huang printf("Key Value:\n"); 13899a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 139069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 13919a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 13929a4fe690SJohnny Huang printf("AES Key:\n"); 13939a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 1394e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 13959a4fe690SJohnny Huang printf("AES IV:\n"); 13969a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 13979a4fe690SJohnny Huang } 13989a4fe690SJohnny Huang 13999a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1400e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 140169d5fd8fSJohnny Huang printf("AES Key:\n"); 140269d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 140369d5fd8fSJohnny Huang printf("AES IV:\n"); 140469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 14055fdde29fSJohnny Huang } else { 14069a4fe690SJohnny Huang printf("AES Key 1:\n"); 14079a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 14089a4fe690SJohnny Huang printf("AES Key 2:\n"); 14099a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 14109a4fe690SJohnny Huang } 1411181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 141269d5fd8fSJohnny Huang printf("RSA mod:\n"); 141369d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 141469d5fd8fSJohnny Huang printf("RSA exp:\n"); 141569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1416181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1417181f72d8SJohnny Huang printf("RSA mod:\n"); 1418181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1419181f72d8SJohnny Huang printf("RSA exp:\n"); 1420a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 142169d5fd8fSJohnny Huang } 142269d5fd8fSJohnny Huang if (last) 142369d5fd8fSJohnny Huang break; 142469d5fd8fSJohnny Huang } 142588bd7d58SJohnny Huang } 142688bd7d58SJohnny Huang 142788bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 142888bd7d58SJohnny Huang { 142988bd7d58SJohnny Huang u32 *buf; 143088bd7d58SJohnny Huang 143188bd7d58SJohnny Huang buf = (u32 *)image_layout->data; 143288bd7d58SJohnny Huang _otp_print_key(buf); 143388bd7d58SJohnny Huang 1434f347c284SJohnny Huang return OTP_SUCCESS; 1435f347c284SJohnny Huang } 1436f347c284SJohnny Huang 143788bd7d58SJohnny Huang static void otp_print_key_info(void) 143888bd7d58SJohnny Huang { 143988bd7d58SJohnny Huang u32 data[2048]; 144088bd7d58SJohnny Huang int i; 144188bd7d58SJohnny Huang 144288bd7d58SJohnny Huang for (i = 0; i < 2048 ; i += 2) 144388bd7d58SJohnny Huang otp_read_data(i, &data[i]); 144488bd7d58SJohnny Huang 144588bd7d58SJohnny Huang _otp_print_key(data); 144688bd7d58SJohnny Huang } 144788bd7d58SJohnny Huang 1448b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data) 1449f347c284SJohnny Huang { 1450f347c284SJohnny Huang int i; 1451f347c284SJohnny Huang int ret; 1452f347c284SJohnny Huang u32 *buf; 1453f347c284SJohnny Huang u32 *buf_ignore; 1454f347c284SJohnny Huang 1455f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1456f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1457f347c284SJohnny Huang printf("Start Programing...\n"); 1458f347c284SJohnny Huang 1459f347c284SJohnny Huang // programing ecc region first 1460f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1461f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1462f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1463f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1464f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1465f347c284SJohnny Huang return ret; 1466f347c284SJohnny Huang } 1467f347c284SJohnny Huang } 1468f347c284SJohnny Huang 1469f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1470f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1471f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1472f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1473f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1474f347c284SJohnny Huang return ret; 1475f347c284SJohnny Huang } 1476f347c284SJohnny Huang } 1477f347c284SJohnny Huang otp_soak(0); 1478f347c284SJohnny Huang return OTP_SUCCESS; 1479f347c284SJohnny Huang } 1480f347c284SJohnny Huang 1481b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1482f347c284SJohnny Huang { 1483f347c284SJohnny Huang u32 *strap; 1484f347c284SJohnny Huang u32 *strap_ignore; 1485f347c284SJohnny Huang u32 *strap_pro; 1486f347c284SJohnny Huang u32 prog_address; 1487f347c284SJohnny Huang int i; 14887e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1489f347c284SJohnny Huang int fail = 0; 1490f347c284SJohnny Huang int ret; 1491f347c284SJohnny Huang int prog_flag = 0; 1492f347c284SJohnny Huang 1493f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1494f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1495f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1496f347c284SJohnny Huang 1497f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1498f347c284SJohnny Huang prog_address = 0x800; 1499f347c284SJohnny Huang if (i < 32) { 1500f347c284SJohnny Huang offset = i; 1501f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1502f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1503f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1504f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1505f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1506f347c284SJohnny Huang 1507f347c284SJohnny Huang } else { 1508f347c284SJohnny Huang offset = (i - 32); 1509f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1510f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1511f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1512f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1513f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1514f347c284SJohnny Huang } 1515f347c284SJohnny Huang 1516f347c284SJohnny Huang if (ibit == 1) 1517f347c284SJohnny Huang continue; 1518f347c284SJohnny Huang if (bit == otpstrap[i].value) 1519f347c284SJohnny Huang prog_flag = 0; 1520f347c284SJohnny Huang else 1521f347c284SJohnny Huang prog_flag = 1; 1522f347c284SJohnny Huang 1523f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1524f347c284SJohnny Huang fail = 1; 1525f347c284SJohnny Huang continue; 1526f347c284SJohnny Huang } 1527f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1528f347c284SJohnny Huang fail = 1; 1529f347c284SJohnny Huang continue; 1530f347c284SJohnny Huang } 1531f347c284SJohnny Huang 1532f347c284SJohnny Huang if (prog_flag) { 1533f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1534f347c284SJohnny Huang if (ret) 1535f347c284SJohnny Huang return OTP_FAILURE; 1536f347c284SJohnny Huang } 1537f347c284SJohnny Huang 1538f347c284SJohnny Huang if (pbit != 0) { 1539f347c284SJohnny Huang prog_address = 0x800; 1540f347c284SJohnny Huang if (i < 32) 1541f347c284SJohnny Huang prog_address |= 0x60c; 1542f347c284SJohnny Huang else 1543f347c284SJohnny Huang prog_address |= 0x60e; 1544f347c284SJohnny Huang 1545f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1546f347c284SJohnny Huang if (ret) 1547f347c284SJohnny Huang return OTP_FAILURE; 1548f347c284SJohnny Huang } 1549f347c284SJohnny Huang } 1550f347c284SJohnny Huang otp_soak(0); 1551f347c284SJohnny Huang if (fail == 1) 1552f347c284SJohnny Huang return OTP_FAILURE; 1553f347c284SJohnny Huang return OTP_SUCCESS; 155469d5fd8fSJohnny Huang } 155569d5fd8fSJohnny Huang 1556b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf) 155769d5fd8fSJohnny Huang { 1558a6d0d645SJohnny Huang int i, k; 1559d90825e2SJohnny Huang int pass = 0; 1560a219f6deSJohnny Huang u32 prog_address; 1561a219f6deSJohnny Huang u32 compare[2]; 1562a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1563a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1564a219f6deSJohnny Huang u32 data_masked; 1565a219f6deSJohnny Huang u32 buf_masked; 156669d5fd8fSJohnny Huang 1567a6d0d645SJohnny Huang printf("Start Programing...\n"); 1568d90825e2SJohnny Huang otp_soak(0); 1569bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 1570b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 15715010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1572a6d0d645SJohnny Huang prog_address = 0x800; 1573a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1574a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1575bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1576bb34a7bfSJohnny Huang pass = 1; 1577a6d0d645SJohnny Huang continue; 1578bb34a7bfSJohnny Huang } 1579de6fbf1cSJohnny Huang 1580de6fbf1cSJohnny Huang otp_soak(1); 15815010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1582a6d0d645SJohnny Huang 158369d5fd8fSJohnny Huang pass = 0; 158469d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 15855010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1586de6fbf1cSJohnny Huang otp_soak(2); 1587feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 15885010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1589de6fbf1cSJohnny Huang otp_soak(1); 1590de6fbf1cSJohnny Huang } else { 1591de6fbf1cSJohnny Huang pass = 1; 1592de6fbf1cSJohnny Huang break; 1593de6fbf1cSJohnny Huang } 1594a6d0d645SJohnny Huang } else { 159569d5fd8fSJohnny Huang pass = 1; 159669d5fd8fSJohnny Huang break; 159769d5fd8fSJohnny Huang } 159869d5fd8fSJohnny Huang } 1599bb34a7bfSJohnny Huang if (pass == 0) { 1600b64ca396SJohnny Huang printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n", 1601b64ca396SJohnny Huang i, otp_conf[i], conf[i], conf_ignore[i]); 1602bb34a7bfSJohnny Huang break; 1603bb34a7bfSJohnny Huang } 1604a6d0d645SJohnny Huang } 1605a6d0d645SJohnny Huang 1606de6fbf1cSJohnny Huang otp_soak(0); 160769d5fd8fSJohnny Huang if (!pass) 16082a856b9aSJohnny Huang return OTP_FAILURE; 1609a6d0d645SJohnny Huang 16102a856b9aSJohnny Huang return OTP_SUCCESS; 161169d5fd8fSJohnny Huang } 161269d5fd8fSJohnny Huang 1613b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro) 1614b25f02d2SJohnny Huang { 1615b25f02d2SJohnny Huang int i, k; 1616b25f02d2SJohnny Huang int pass = 0; 1617b25f02d2SJohnny Huang u32 prog_address; 1618b25f02d2SJohnny Huang u32 compare[2]; 1619b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1620b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1621b25f02d2SJohnny Huang u32 data_masked; 1622b25f02d2SJohnny Huang u32 buf_masked; 1623b25f02d2SJohnny Huang 1624b25f02d2SJohnny Huang printf("Start Programing...\n"); 1625b25f02d2SJohnny Huang otp_soak(0); 1626b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1627b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1628b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1629b25f02d2SJohnny Huang prog_address = 0xe08 + i * 2; 1630b25f02d2SJohnny Huang if (data_masked == buf_masked) { 1631b25f02d2SJohnny Huang pass = 1; 1632b25f02d2SJohnny Huang continue; 1633b25f02d2SJohnny Huang } 1634b25f02d2SJohnny Huang 1635b25f02d2SJohnny Huang otp_soak(1); 1636b25f02d2SJohnny Huang otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address); 1637b25f02d2SJohnny Huang 1638b25f02d2SJohnny Huang pass = 0; 1639b25f02d2SJohnny Huang for (k = 0; k < RETRY; k++) { 1640b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1641b25f02d2SJohnny Huang otp_soak(2); 1642b25f02d2SJohnny Huang otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address); 1643b25f02d2SJohnny Huang if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) { 1644b25f02d2SJohnny Huang otp_soak(1); 1645b25f02d2SJohnny Huang } else { 1646b25f02d2SJohnny Huang pass = 1; 1647b25f02d2SJohnny Huang break; 1648b25f02d2SJohnny Huang } 1649b25f02d2SJohnny Huang } else { 1650b25f02d2SJohnny Huang pass = 1; 1651b25f02d2SJohnny Huang break; 1652b25f02d2SJohnny Huang } 1653b25f02d2SJohnny Huang } 1654b25f02d2SJohnny Huang if (pass == 0) { 1655b489486eSJohnny Huang printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n", 1656b25f02d2SJohnny Huang i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]); 1657b25f02d2SJohnny Huang break; 1658b25f02d2SJohnny Huang } 1659b25f02d2SJohnny Huang } 1660b25f02d2SJohnny Huang 1661b25f02d2SJohnny Huang otp_soak(0); 1662b25f02d2SJohnny Huang if (!pass) 1663b25f02d2SJohnny Huang return OTP_FAILURE; 1664b25f02d2SJohnny Huang 1665b25f02d2SJohnny Huang return OTP_SUCCESS; 1666b25f02d2SJohnny Huang } 1667b25f02d2SJohnny Huang 1668b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data) 1669b64ca396SJohnny Huang { 1670b64ca396SJohnny Huang int data_dw; 1671b64ca396SJohnny Huang u32 data_masked; 1672b64ca396SJohnny Huang u32 buf_masked; 1673b64ca396SJohnny Huang u32 *buf = (u32 *)image_layout->data; 1674b64ca396SJohnny Huang u32 *buf_ignore = (u32 *)image_layout->data_ignore; 1675b64ca396SJohnny Huang int i; 1676b64ca396SJohnny Huang 1677b64ca396SJohnny Huang data_dw = image_layout->data_length / 4; 1678b64ca396SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1679b64ca396SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1680b64ca396SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1681b64ca396SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1682b64ca396SJohnny Huang if (data_masked == buf_masked) 1683b64ca396SJohnny Huang continue; 1684b64ca396SJohnny Huang if (i % 2 == 0) { 1685b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1686b64ca396SJohnny Huang continue; 1687b64ca396SJohnny Huang } else { 1688b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1689b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1690b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1691b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1692b64ca396SJohnny Huang return OTP_FAILURE; 1693b64ca396SJohnny Huang } 1694b64ca396SJohnny Huang } else { 1695b64ca396SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1696b64ca396SJohnny Huang continue; 1697b64ca396SJohnny Huang } else { 1698b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1699b489486eSJohnny Huang printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]); 1700b489486eSJohnny Huang printf("Input [0x%x] = 0x%x\n", i, buf[i]); 1701b489486eSJohnny Huang printf("Mask [0x%x] = 0x%x\n", i, ~buf_ignore[i]); 1702b64ca396SJohnny Huang return OTP_FAILURE; 1703b64ca396SJohnny Huang } 1704b64ca396SJohnny Huang } 1705b64ca396SJohnny Huang } 1706b64ca396SJohnny Huang return OTP_SUCCESS; 1707b64ca396SJohnny Huang } 1708b64ca396SJohnny Huang 1709b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap) 1710b64ca396SJohnny Huang { 1711b64ca396SJohnny Huang int i; 1712b64ca396SJohnny Huang u32 *strap; 1713b64ca396SJohnny Huang u32 *strap_ignore; 1714b64ca396SJohnny Huang u32 *strap_pro; 1715b64ca396SJohnny Huang int bit, pbit, ibit; 1716b64ca396SJohnny Huang int fail = 0; 1717b64ca396SJohnny Huang int ret; 1718b64ca396SJohnny Huang 1719b64ca396SJohnny Huang strap = (u32 *)image_layout->strap; 1720b64ca396SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1721b64ca396SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1722b64ca396SJohnny Huang 1723b64ca396SJohnny Huang for (i = 0; i < 64; i++) { 1724b64ca396SJohnny Huang if (i < 32) { 1725b64ca396SJohnny Huang bit = (strap[0] >> i) & 0x1; 1726b64ca396SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1727b64ca396SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1728b64ca396SJohnny Huang } else { 1729b64ca396SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1730b64ca396SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1731b64ca396SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1732b64ca396SJohnny Huang } 1733b64ca396SJohnny Huang 1734b64ca396SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1735b64ca396SJohnny Huang 1736b64ca396SJohnny Huang if (ret == OTP_FAILURE) 1737b64ca396SJohnny Huang fail = 1; 1738b64ca396SJohnny Huang } 1739b64ca396SJohnny Huang if (fail == 1) { 1740b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1741b64ca396SJohnny Huang return OTP_FAILURE; 1742b64ca396SJohnny Huang } 1743b64ca396SJohnny Huang return OTP_SUCCESS; 1744b64ca396SJohnny Huang } 1745b64ca396SJohnny Huang 1746b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf) 1747b64ca396SJohnny Huang { 1748b64ca396SJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1749b64ca396SJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1750b64ca396SJohnny Huang u32 data_masked; 1751b64ca396SJohnny Huang u32 buf_masked; 1752b64ca396SJohnny Huang int i; 1753b64ca396SJohnny Huang 1754b64ca396SJohnny Huang for (i = 0; i < 16; i++) { 1755b64ca396SJohnny Huang data_masked = otp_conf[i] & ~conf_ignore[i]; 1756b64ca396SJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1757b64ca396SJohnny Huang if (data_masked == buf_masked) 1758b64ca396SJohnny Huang continue; 1759b64ca396SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1760b64ca396SJohnny Huang continue; 1761b64ca396SJohnny Huang } else { 1762b64ca396SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1763b64ca396SJohnny Huang printf("OTPCFG[%X] = %x\n", i, otp_conf[i]); 1764b64ca396SJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 1765b64ca396SJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 1766b64ca396SJohnny Huang return OTP_FAILURE; 1767b64ca396SJohnny Huang } 1768b64ca396SJohnny Huang } 1769b64ca396SJohnny Huang return OTP_SUCCESS; 1770b64ca396SJohnny Huang } 1771b64ca396SJohnny Huang 1772b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro) 1773b25f02d2SJohnny Huang { 1774b25f02d2SJohnny Huang u32 *OTPSCU = (u32 *)image_layout->scu_pro; 1775b25f02d2SJohnny Huang u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore; 1776b25f02d2SJohnny Huang u32 data_masked; 1777b25f02d2SJohnny Huang u32 buf_masked; 1778b25f02d2SJohnny Huang int i; 1779b25f02d2SJohnny Huang 1780b25f02d2SJohnny Huang for (i = 0; i < 2; i++) { 1781b25f02d2SJohnny Huang data_masked = scu_pro[i] & ~OTPSCU_IGNORE[i]; 1782b25f02d2SJohnny Huang buf_masked = OTPSCU[i] & ~OTPSCU_IGNORE[i]; 1783b25f02d2SJohnny Huang if (data_masked == buf_masked) 1784b25f02d2SJohnny Huang continue; 1785b25f02d2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1786b25f02d2SJohnny Huang continue; 1787b25f02d2SJohnny Huang } else { 1788b25f02d2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1789b489486eSJohnny Huang printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]); 1790b489486eSJohnny Huang printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]); 1791b489486eSJohnny Huang printf("Mask [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]); 1792b25f02d2SJohnny Huang return OTP_FAILURE; 1793b25f02d2SJohnny Huang } 1794b25f02d2SJohnny Huang } 1795b25f02d2SJohnny Huang return OTP_SUCCESS; 1796b25f02d2SJohnny Huang } 1797b25f02d2SJohnny Huang 1798f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf) 1799696656c6SJohnny Huang { 1800696656c6SJohnny Huang sha256_context ctx; 1801696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1802696656c6SJohnny Huang 1803696656c6SJohnny Huang sha256_starts(&ctx); 1804696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1805696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1806696656c6SJohnny Huang 1807696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1808f347c284SJohnny Huang return OTP_SUCCESS; 1809f347c284SJohnny Huang return OTP_FAILURE; 1810696656c6SJohnny Huang } 1811696656c6SJohnny Huang 1812f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 181369d5fd8fSJohnny Huang { 181469d5fd8fSJohnny Huang int ret; 181561a6cda7SJohnny Huang int image_soc_ver = 0; 1816696656c6SJohnny Huang struct otp_header *otp_header; 1817696656c6SJohnny Huang struct otp_image_layout image_layout; 1818696656c6SJohnny Huang int image_size; 1819a219f6deSJohnny Huang u8 *buf; 1820a219f6deSJohnny Huang u8 *checksum; 1821b64ca396SJohnny Huang int i; 1822b64ca396SJohnny Huang u32 data[2048]; 1823b64ca396SJohnny Huang u32 conf[16]; 1824b25f02d2SJohnny Huang u32 scu_pro[2]; 1825b64ca396SJohnny Huang struct otpstrap_status otpstrap[64]; 182669d5fd8fSJohnny Huang 1827696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1828696656c6SJohnny Huang if (!otp_header) { 1829030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 18302a856b9aSJohnny Huang return OTP_FAILURE; 183169d5fd8fSJohnny Huang } 1832d90825e2SJohnny Huang 1833696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1834696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1835696656c6SJohnny Huang 1836696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1837696656c6SJohnny Huang 1838696656c6SJohnny Huang if (!buf) { 1839030cb4a7SJohnny Huang printf("Failed to map physical memory\n"); 1840696656c6SJohnny Huang return OTP_FAILURE; 1841696656c6SJohnny Huang } 1842696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1843696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1844696656c6SJohnny Huang 1845696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1846030cb4a7SJohnny Huang printf("Image is invalid\n"); 1847696656c6SJohnny Huang return OTP_FAILURE; 1848696656c6SJohnny Huang } 1849696656c6SJohnny Huang 18505010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 18515010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 18525010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 18535010032bSJohnny Huang 18545010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1855696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 18565010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1857696656c6SJohnny Huang 1858696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 18595010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 18605010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 18615010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 18627e523e3bSJohnny Huang 1863b25f02d2SJohnny Huang image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info); 1864b25f02d2SJohnny Huang image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2); 1865b25f02d2SJohnny Huang image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length; 1866b25f02d2SJohnny Huang 18677e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 18687e523e3bSJohnny Huang image_soc_ver = OTP_A0; 186961a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 187061a6cda7SJohnny Huang image_soc_ver = OTP_A1; 187161a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 187261a6cda7SJohnny Huang image_soc_ver = OTP_A2; 187361a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 187461a6cda7SJohnny Huang image_soc_ver = OTP_A3; 1875696656c6SJohnny Huang } else { 1876030cb4a7SJohnny Huang printf("Image SOC Version is not supported\n"); 1877696656c6SJohnny Huang return OTP_FAILURE; 1878696656c6SJohnny Huang } 1879696656c6SJohnny Huang 188061a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 1881030cb4a7SJohnny Huang printf("Version is not match\n"); 18829a4fe690SJohnny Huang return OTP_FAILURE; 18839a4fe690SJohnny Huang } 18849a4fe690SJohnny Huang 188561a6cda7SJohnny Huang if (otp_header->otptool_ver != OTPTOOL_VERSION(1, 0, 0)) { 1886030cb4a7SJohnny Huang printf("OTP image is not generated by otptool v1.0.0\n"); 188761a6cda7SJohnny Huang return OTP_FAILURE; 188861a6cda7SJohnny Huang } 188961a6cda7SJohnny Huang 1890f347c284SJohnny Huang if (otp_verify_image(buf, image_size, checksum)) { 1891030cb4a7SJohnny Huang printf("checksum is invalid\n"); 1892696656c6SJohnny Huang return OTP_FAILURE; 1893d90825e2SJohnny Huang } 18947332532cSJohnny Huang 1895030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 1896030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 1897030cb4a7SJohnny Huang return OTP_FAILURE; 1898030cb4a7SJohnny Huang } 1899b64ca396SJohnny Huang ret = 0; 1900030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 1901030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 1902030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 1903030cb4a7SJohnny Huang ret = -1; 1904030cb4a7SJohnny Huang } 1905030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 1906030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 1907030cb4a7SJohnny Huang ret = -1; 1908030cb4a7SJohnny Huang } 1909b64ca396SJohnny Huang printf("Read OTP Data Region:\n"); 1910b64ca396SJohnny Huang for (i = 0; i < 2048 ; i += 2) 1911b64ca396SJohnny Huang otp_read_data(i, &data[i]); 1912b64ca396SJohnny Huang 1913b64ca396SJohnny Huang printf("Check writable...\n"); 1914b64ca396SJohnny Huang if (otp_check_data_image(&image_layout, data) == OTP_FAILURE) 1915b64ca396SJohnny Huang ret = -1; 1916030cb4a7SJohnny Huang } 1917030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 1918030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 1919030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 1920030cb4a7SJohnny Huang ret = -1; 1921030cb4a7SJohnny Huang } 1922b64ca396SJohnny Huang printf("Read OTP Config Region:\n"); 1923b64ca396SJohnny Huang for (i = 0; i < 16 ; i++) 1924b64ca396SJohnny Huang otp_read_conf(i, &conf[i]); 1925b64ca396SJohnny Huang 1926b64ca396SJohnny Huang printf("Check writable...\n"); 1927b64ca396SJohnny Huang if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE) 1928b64ca396SJohnny Huang ret = -1; 1929030cb4a7SJohnny Huang } 1930030cb4a7SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 1931030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 1932030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 1933030cb4a7SJohnny Huang ret = -1; 1934030cb4a7SJohnny Huang } 1935b64ca396SJohnny Huang printf("Read OTP Strap Region:\n"); 1936b64ca396SJohnny Huang otp_strap_status(otpstrap); 1937b64ca396SJohnny Huang 1938b64ca396SJohnny Huang printf("Check writable...\n"); 1939b64ca396SJohnny Huang if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE) 1940b64ca396SJohnny Huang ret = -1; 1941030cb4a7SJohnny Huang } 1942b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 1943b25f02d2SJohnny Huang if (info_cb.pro_sts.pro_strap) { 1944b25f02d2SJohnny Huang printf("OTP strap region is protected\n"); 1945b25f02d2SJohnny Huang ret = -1; 1946b25f02d2SJohnny Huang } 1947b25f02d2SJohnny Huang printf("Read SCU Protect Region:\n"); 1948b25f02d2SJohnny Huang otp_read_conf(28, &scu_pro[0]); 1949b25f02d2SJohnny Huang otp_read_conf(29, &scu_pro[1]); 1950b25f02d2SJohnny Huang 1951b25f02d2SJohnny Huang printf("Check writable...\n"); 1952b25f02d2SJohnny Huang if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE) 1953b25f02d2SJohnny Huang ret = -1; 1954b25f02d2SJohnny Huang } 1955030cb4a7SJohnny Huang if (ret == -1) 1956030cb4a7SJohnny Huang return OTP_FAILURE; 1957b64ca396SJohnny Huang 195869d5fd8fSJohnny Huang if (!nconfirm) { 1959696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 19607f795e57SJohnny Huang printf("\nOTP data region :\n"); 1961f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 196269d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 19632a856b9aSJohnny Huang return OTP_FAILURE; 196469d5fd8fSJohnny Huang } 196569d5fd8fSJohnny Huang } 1966696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 19677332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1968696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 19697332532cSJohnny Huang printf("OTP config error, please check.\n"); 19707332532cSJohnny Huang return OTP_FAILURE; 19717332532cSJohnny Huang } 19727332532cSJohnny Huang } 19737adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 19747adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 19757adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 19767adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 19777adec5f6SJohnny Huang return OTP_FAILURE; 19787adec5f6SJohnny Huang } 19797adec5f6SJohnny Huang } 1980b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 1981b25f02d2SJohnny Huang printf("\nOTP scu protect region :\n"); 1982b25f02d2SJohnny Huang if (otp_print_scu_image(&image_layout) < 0) { 1983b25f02d2SJohnny Huang printf("OTP scu protect error, please check.\n"); 1984b25f02d2SJohnny Huang return OTP_FAILURE; 1985b25f02d2SJohnny Huang } 1986b25f02d2SJohnny Huang } 19877332532cSJohnny Huang 198869d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 198969d5fd8fSJohnny Huang if (!confirm_yesno()) { 199069d5fd8fSJohnny Huang printf(" Aborting\n"); 19912a856b9aSJohnny Huang return OTP_FAILURE; 199269d5fd8fSJohnny Huang } 199369d5fd8fSJohnny Huang } 19947332532cSJohnny Huang 19955010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 19965010032bSJohnny Huang printf("programing data region ...\n"); 1997b64ca396SJohnny Huang ret = otp_prog_data(&image_layout, data); 19985010032bSJohnny Huang if (ret != 0) { 19995010032bSJohnny Huang printf("Error\n"); 20005010032bSJohnny Huang return ret; 20015010032bSJohnny Huang } 2002a219f6deSJohnny Huang printf("Done\n"); 20035010032bSJohnny Huang } 20045010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 20055010032bSJohnny Huang printf("programing strap region ...\n"); 2006b64ca396SJohnny Huang ret = otp_prog_strap(&image_layout, otpstrap); 20075010032bSJohnny Huang if (ret != 0) { 20085010032bSJohnny Huang printf("Error\n"); 20095010032bSJohnny Huang return ret; 20105010032bSJohnny Huang } 2011a219f6deSJohnny Huang printf("Done\n"); 20125010032bSJohnny Huang } 2013b25f02d2SJohnny Huang if (otp_header->image_info & OTP_INC_SCU_PRO) { 2014b25f02d2SJohnny Huang printf("programing scu protect region ...\n"); 2015b25f02d2SJohnny Huang ret = otp_prog_scu_protect(&image_layout, scu_pro); 2016b25f02d2SJohnny Huang if (ret != 0) { 2017b25f02d2SJohnny Huang printf("Error\n"); 2018b25f02d2SJohnny Huang return ret; 2019b25f02d2SJohnny Huang } 2020b25f02d2SJohnny Huang printf("Done\n"); 2021b25f02d2SJohnny Huang } 20225010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 20235010032bSJohnny Huang printf("programing configuration region ...\n"); 2024b64ca396SJohnny Huang ret = otp_prog_conf(&image_layout, conf); 20255010032bSJohnny Huang if (ret != 0) { 20265010032bSJohnny Huang printf("Error\n"); 20275010032bSJohnny Huang return ret; 20285010032bSJohnny Huang } 20295010032bSJohnny Huang printf("Done\n"); 20305010032bSJohnny Huang } 2031cd1610b4SJohnny Huang 20327332532cSJohnny Huang return OTP_SUCCESS; 20332a856b9aSJohnny Huang } 20342a856b9aSJohnny Huang 2035f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 2036cd1610b4SJohnny Huang { 2037a219f6deSJohnny Huang u32 read[2]; 2038a219f6deSJohnny Huang u32 prog_address = 0; 203966f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 2040cd1610b4SJohnny Huang int otp_bit; 204183655e91SJohnny Huang int ret = 0; 2042cd1610b4SJohnny Huang 2043dacbba92SJohnny Huang otp_soak(0); 2044cd1610b4SJohnny Huang switch (mode) { 2045a6d0d645SJohnny Huang case OTP_REGION_CONF: 2046f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 2047cd1610b4SJohnny Huang prog_address = 0x800; 2048cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 2049cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 2050a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2051cd1610b4SJohnny Huang if (otp_bit == value) { 2052b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2053cd1610b4SJohnny Huang printf("No need to program\n"); 20542a856b9aSJohnny Huang return OTP_SUCCESS; 2055cd1610b4SJohnny Huang } 2056cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 2057b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 20580dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 20592a856b9aSJohnny Huang return OTP_FAILURE; 2060cd1610b4SJohnny Huang } 2061b489486eSJohnny Huang printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2062cd1610b4SJohnny Huang break; 2063a6d0d645SJohnny Huang case OTP_REGION_DATA: 2064cd1610b4SJohnny Huang prog_address = otp_dw_offset; 2065cd1610b4SJohnny Huang 2066cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 2067a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 2068a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 2069643b9cfdSJohnny Huang 2070643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 2071b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2072b64ca396SJohnny Huang printf("OTP is programmed, which can't be cleared\n"); 2073643b9cfdSJohnny Huang return OTP_FAILURE; 2074643b9cfdSJohnny Huang } 2075cd1610b4SJohnny Huang } else { 2076a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 2077a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 2078643b9cfdSJohnny Huang 2079643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 2080b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset); 2081b64ca396SJohnny Huang printf("OTP is programmed, which can't be written\n"); 2082643b9cfdSJohnny Huang return OTP_FAILURE; 2083643b9cfdSJohnny Huang } 2084cd1610b4SJohnny Huang } 2085cd1610b4SJohnny Huang if (otp_bit == value) { 2086b489486eSJohnny Huang printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value); 2087cd1610b4SJohnny Huang printf("No need to program\n"); 20882a856b9aSJohnny Huang return OTP_SUCCESS; 2089cd1610b4SJohnny Huang } 2090643b9cfdSJohnny Huang 2091b489486eSJohnny Huang printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset); 2092cd1610b4SJohnny Huang break; 2093a6d0d645SJohnny Huang case OTP_REGION_STRAP: 20948848d5dcSJohnny Huang otp_strap_status(otpstrap); 20958848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 20967e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 20978848d5dcSJohnny Huang if (ret == OTP_FAILURE) 20988848d5dcSJohnny Huang return OTP_FAILURE; 20998848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 21008848d5dcSJohnny Huang return OTP_SUCCESS; 2101a6af4a17SJohnny Huang 2102cd1610b4SJohnny Huang break; 2103cd1610b4SJohnny Huang } 2104cd1610b4SJohnny Huang 2105cd1610b4SJohnny Huang if (!nconfirm) { 2106cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2107cd1610b4SJohnny Huang if (!confirm_yesno()) { 2108cd1610b4SJohnny Huang printf(" Aborting\n"); 21092a856b9aSJohnny Huang return OTP_FAILURE; 2110cd1610b4SJohnny Huang } 2111cd1610b4SJohnny Huang } 2112cd1610b4SJohnny Huang 2113cd1610b4SJohnny Huang switch (mode) { 2114a6d0d645SJohnny Huang case OTP_REGION_STRAP: 2115f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 211683655e91SJohnny Huang break; 2117a6d0d645SJohnny Huang case OTP_REGION_CONF: 2118a6d0d645SJohnny Huang case OTP_REGION_DATA: 2119f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 2120de6fbf1cSJohnny Huang break; 2121de6fbf1cSJohnny Huang } 2122de6fbf1cSJohnny Huang otp_soak(0); 212383655e91SJohnny Huang if (ret) { 21240dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 2125794e27ecSJohnny Huang printf("FAILURE\n"); 2126794e27ecSJohnny Huang return OTP_FAILURE; 2127794e27ecSJohnny Huang } 2128794e27ecSJohnny Huang 21299009c25dSJohnny Huang printf("SUCCESS\n"); 21302a856b9aSJohnny Huang return OTP_SUCCESS; 2131a219f6deSJohnny Huang } 2132a219f6deSJohnny Huang 2133794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 2134794e27ecSJohnny Huang { 2135794e27ecSJohnny Huang u32 otp_rid[2]; 2136a8789b47SJohnny Huang u32 sw_rid[2]; 2137794e27ecSJohnny Huang int rid_num = 0; 2138a8789b47SJohnny Huang int sw_rid_num = 0; 2139794e27ecSJohnny Huang int bit_offset; 2140794e27ecSJohnny Huang int dw_offset; 2141794e27ecSJohnny Huang int i; 2142794e27ecSJohnny Huang int ret; 2143794e27ecSJohnny Huang 2144f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2145f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2146794e27ecSJohnny Huang 2147a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2148a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2149a8789b47SJohnny Huang 2150794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2151a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2152a8789b47SJohnny Huang 2153a8789b47SJohnny Huang if (sw_rid_num < 0) { 2154a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2155a8789b47SJohnny Huang return OTP_FAILURE; 2156a8789b47SJohnny Huang } 2157a8789b47SJohnny Huang 2158a8789b47SJohnny Huang if (update_num > sw_rid_num) { 2159a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2160a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2161a8789b47SJohnny Huang return OTP_FAILURE; 2162a8789b47SJohnny Huang } 2163794e27ecSJohnny Huang 2164794e27ecSJohnny Huang if (rid_num < 0) { 2165b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by this command,\n" 2166b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n"); 2167794e27ecSJohnny Huang otp_print_revid(otp_rid); 21689009c25dSJohnny Huang return OTP_FAILURE; 21699009c25dSJohnny Huang } 2170cd1610b4SJohnny Huang 2171794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2172794e27ecSJohnny Huang otp_print_revid(otp_rid); 2173794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 2174794e27ecSJohnny Huang 2175a8789b47SJohnny Huang if (rid_num > update_num) { 2176a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 2177a8789b47SJohnny Huang printf("Skip\n"); 2178a8789b47SJohnny Huang return OTP_FAILURE; 2179a8789b47SJohnny Huang } else if (rid_num == update_num) { 2180a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 2181794e27ecSJohnny Huang printf("Skip\n"); 2182794e27ecSJohnny Huang return OTP_FAILURE; 2183794e27ecSJohnny Huang } 2184794e27ecSJohnny Huang 2185794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2186794e27ecSJohnny Huang if (i < 32) { 2187794e27ecSJohnny Huang dw_offset = 0xa; 2188794e27ecSJohnny Huang bit_offset = i; 2189794e27ecSJohnny Huang } else { 2190794e27ecSJohnny Huang dw_offset = 0xb; 2191794e27ecSJohnny Huang bit_offset = i - 32; 2192794e27ecSJohnny Huang } 2193b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset); 2194794e27ecSJohnny Huang if (i + 1 != update_num) 2195794e27ecSJohnny Huang printf(", "); 2196794e27ecSJohnny Huang } 2197794e27ecSJohnny Huang 2198794e27ecSJohnny Huang printf(" will be programmed\n"); 2199794e27ecSJohnny Huang if (force == 0) { 2200794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2201794e27ecSJohnny Huang if (!confirm_yesno()) { 2202794e27ecSJohnny Huang printf(" Aborting\n"); 2203794e27ecSJohnny Huang return OTP_FAILURE; 2204794e27ecSJohnny Huang } 2205794e27ecSJohnny Huang } 2206794e27ecSJohnny Huang 2207794e27ecSJohnny Huang ret = 0; 2208794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 2209794e27ecSJohnny Huang if (i < 32) { 2210794e27ecSJohnny Huang dw_offset = 0xa04; 2211794e27ecSJohnny Huang bit_offset = i; 2212794e27ecSJohnny Huang } else { 2213794e27ecSJohnny Huang dw_offset = 0xa06; 2214794e27ecSJohnny Huang bit_offset = i - 32; 2215794e27ecSJohnny Huang } 2216f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 2217b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset); 2218794e27ecSJohnny Huang ret = OTP_FAILURE; 2219794e27ecSJohnny Huang break; 2220794e27ecSJohnny Huang } 2221794e27ecSJohnny Huang } 2222061d3279SJohnny Huang otp_soak(0); 2223f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2224f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2225794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 2226794e27ecSJohnny Huang if (rid_num >= 0) 2227794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 2228794e27ecSJohnny Huang else 2229794e27ecSJohnny Huang printf("OTP revision ID\n"); 2230794e27ecSJohnny Huang otp_print_revid(otp_rid); 2231794e27ecSJohnny Huang if (!ret) 2232794e27ecSJohnny Huang printf("SUCCESS\n"); 2233794e27ecSJohnny Huang else 2234794e27ecSJohnny Huang printf("FAILED\n"); 2235794e27ecSJohnny Huang return ret; 2236794e27ecSJohnny Huang } 2237794e27ecSJohnny Huang 2238883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force) 2239883625c5SJohnny Huang { 2240883625c5SJohnny Huang u32 otpcfg4; 2241883625c5SJohnny Huang u32 krb; 2242883625c5SJohnny Huang u32 krb_b; 2243883625c5SJohnny Huang u32 krb_or; 2244883625c5SJohnny Huang u32 current_id; 2245883625c5SJohnny Huang 2246883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2247883625c5SJohnny Huang current_id = readl(SEC_KEY_NUM) & 7; 2248883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2249883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2250883625c5SJohnny Huang krb_or = krb | krb_b; 2251883625c5SJohnny Huang 2252883625c5SJohnny Huang printf("current Key ID: 0x%x\n", current_id); 2253883625c5SJohnny Huang printf("input retire ID: 0x%x\n", retire_id); 2254883625c5SJohnny Huang printf("OTPCFG0x4 = 0x%X\n", otpcfg4); 2255883625c5SJohnny Huang 2256883625c5SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2257883625c5SJohnny Huang printf("OTPCFG4 is protected\n"); 2258883625c5SJohnny Huang return OTP_FAILURE; 2259883625c5SJohnny Huang } 2260883625c5SJohnny Huang 2261883625c5SJohnny Huang if (retire_id >= current_id) { 2262883625c5SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2263883625c5SJohnny Huang return OTP_FAILURE; 2264883625c5SJohnny Huang } 2265883625c5SJohnny Huang 2266883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2267883625c5SJohnny Huang printf("Key 0x%X already retired\n", retire_id); 2268883625c5SJohnny Huang return OTP_SUCCESS; 2269883625c5SJohnny Huang } 2270883625c5SJohnny Huang 2271883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id); 2272883625c5SJohnny Huang if (force == 0) { 2273883625c5SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2274883625c5SJohnny Huang if (!confirm_yesno()) { 2275883625c5SJohnny Huang printf(" Aborting\n"); 2276883625c5SJohnny Huang return OTP_FAILURE; 2277883625c5SJohnny Huang } 2278883625c5SJohnny Huang } 2279883625c5SJohnny Huang 2280883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) { 2281883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed\n", retire_id); 2282883625c5SJohnny Huang printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16); 2283883625c5SJohnny Huang if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE) 2284883625c5SJohnny Huang printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16); 2285883625c5SJohnny Huang } 2286883625c5SJohnny Huang 2287883625c5SJohnny Huang otp_soak(0); 2288883625c5SJohnny Huang otp_read_conf(4, &otpcfg4); 2289883625c5SJohnny Huang krb = otpcfg4 & 0xff; 2290883625c5SJohnny Huang krb_b = (otpcfg4 >> 16) & 0xff; 2291883625c5SJohnny Huang krb_or = krb | krb_b; 2292883625c5SJohnny Huang if (krb_or & (1 << retire_id)) { 2293883625c5SJohnny Huang printf("SUCCESS\n"); 2294883625c5SJohnny Huang return OTP_SUCCESS; 2295883625c5SJohnny Huang } 2296883625c5SJohnny Huang printf("FAILED\n"); 2297883625c5SJohnny Huang return OTP_FAILURE; 2298883625c5SJohnny Huang } 2299883625c5SJohnny Huang 23002a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 230169d5fd8fSJohnny Huang { 2302a219f6deSJohnny Huang u32 offset, count; 23032a856b9aSJohnny Huang int ret; 230469d5fd8fSJohnny Huang 23052a856b9aSJohnny Huang if (argc == 4) { 23062a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 23072a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 23082a856b9aSJohnny Huang } else if (argc == 3) { 23092a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 23102a856b9aSJohnny Huang count = 1; 23112a856b9aSJohnny Huang } else { 231269d5fd8fSJohnny Huang return CMD_RET_USAGE; 231369d5fd8fSJohnny Huang } 231469d5fd8fSJohnny Huang 2315030cb4a7SJohnny Huang if (!strcmp(argv[1], "conf")) 2316f347c284SJohnny Huang ret = otp_print_conf(offset, count); 2317030cb4a7SJohnny Huang else if (!strcmp(argv[1], "data")) 23182a856b9aSJohnny Huang ret = otp_print_data(offset, count); 2319030cb4a7SJohnny Huang else if (!strcmp(argv[1], "strap")) 23202a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 2321030cb4a7SJohnny Huang else 23222a856b9aSJohnny Huang return CMD_RET_USAGE; 232369d5fd8fSJohnny Huang 23242a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 23252a856b9aSJohnny Huang return CMD_RET_SUCCESS; 23262a856b9aSJohnny Huang return CMD_RET_USAGE; 23272a856b9aSJohnny Huang } 23282a856b9aSJohnny Huang 23292a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 23302a856b9aSJohnny Huang { 23312a856b9aSJohnny Huang phys_addr_t addr; 23322a856b9aSJohnny Huang int ret; 23332a856b9aSJohnny Huang 2334de6b0cc4SJohnny Huang if (argc == 3) { 2335ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 23362a856b9aSJohnny Huang return CMD_RET_USAGE; 23372a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 2338f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2339de6b0cc4SJohnny Huang } else if (argc == 2) { 23402a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 2341f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 23422a856b9aSJohnny Huang } else { 23432a856b9aSJohnny Huang return CMD_RET_USAGE; 23442a856b9aSJohnny Huang } 23452a856b9aSJohnny Huang 23462a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 23472a856b9aSJohnny Huang return CMD_RET_SUCCESS; 23482a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 23492a856b9aSJohnny Huang return CMD_RET_FAILURE; 23502a856b9aSJohnny Huang else 23512a856b9aSJohnny Huang return CMD_RET_USAGE; 23522a856b9aSJohnny Huang } 23532a856b9aSJohnny Huang 23542a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 23552a856b9aSJohnny Huang { 23562a856b9aSJohnny Huang int mode = 0; 23572a856b9aSJohnny Huang int nconfirm = 0; 23582a856b9aSJohnny Huang int otp_addr = 0; 23592a856b9aSJohnny Huang int bit_offset; 23602a856b9aSJohnny Huang int value; 23612a856b9aSJohnny Huang int ret; 2362030cb4a7SJohnny Huang u32 otp_strap_pro; 23632a856b9aSJohnny Huang 23642a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 23652a856b9aSJohnny Huang return CMD_RET_USAGE; 23662a856b9aSJohnny Huang 23672a856b9aSJohnny Huang /* Drop the pb cmd */ 23682a856b9aSJohnny Huang argc--; 23692a856b9aSJohnny Huang argv++; 23702a856b9aSJohnny Huang 23712a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2372a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 23732a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2374a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 23752a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2376a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2377cd1610b4SJohnny Huang else 23782a856b9aSJohnny Huang return CMD_RET_USAGE; 23792a856b9aSJohnny Huang 23802a856b9aSJohnny Huang /* Drop the region cmd */ 23812a856b9aSJohnny Huang argc--; 23822a856b9aSJohnny Huang argv++; 23832a856b9aSJohnny Huang 2384ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2385cd1610b4SJohnny Huang nconfirm = 1; 23862a856b9aSJohnny Huang /* Drop the force option */ 23872a856b9aSJohnny Huang argc--; 23882a856b9aSJohnny Huang argv++; 23892a856b9aSJohnny Huang } 2390cd1610b4SJohnny Huang 2391a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 23922a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 23932a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 23940808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 23952a856b9aSJohnny Huang return CMD_RET_USAGE; 2396cd1610b4SJohnny Huang } else { 23972a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 23982a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 23992a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 24000808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 24012a856b9aSJohnny Huang return CMD_RET_USAGE; 24020808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 240378855207SJohnny Huang if (otp_addr >= 0x800) 24040808cc55SJohnny Huang return CMD_RET_USAGE; 24050808cc55SJohnny Huang } else { 240678855207SJohnny Huang if (otp_addr >= 0x20) 24070808cc55SJohnny Huang return CMD_RET_USAGE; 24080808cc55SJohnny Huang } 2409cd1610b4SJohnny Huang } 2410cd1610b4SJohnny Huang if (value != 0 && value != 1) 24112a856b9aSJohnny Huang return CMD_RET_USAGE; 2412cd1610b4SJohnny Huang 2413030cb4a7SJohnny Huang ret = 0; 2414030cb4a7SJohnny Huang if (info_cb.pro_sts.mem_lock) { 2415030cb4a7SJohnny Huang printf("OTP memory is locked\n"); 2416030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2417030cb4a7SJohnny Huang } 2418030cb4a7SJohnny Huang if (mode == OTP_REGION_DATA) { 2419030cb4a7SJohnny Huang if (info_cb.pro_sts.sec_size == 0) { 2420030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_data) { 2421030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2422030cb4a7SJohnny Huang ret = -1; 2423030cb4a7SJohnny Huang } 2424030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) { 2425030cb4a7SJohnny Huang printf("OTP secure region is not readable, skip it to prevent unpredictable result\n"); 2426030cb4a7SJohnny Huang ret = -1; 2427030cb4a7SJohnny Huang } else if (otp_addr < info_cb.pro_sts.sec_size) { 2428030cb4a7SJohnny Huang // header region(0x0~0x40) is still readable even secure region is set. 2429030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_sec) { 2430030cb4a7SJohnny Huang printf("OTP secure region is protected\n"); 2431030cb4a7SJohnny Huang ret = -1; 2432030cb4a7SJohnny Huang } 2433030cb4a7SJohnny Huang } else if (info_cb.pro_sts.pro_data) { 2434030cb4a7SJohnny Huang printf("OTP data region is protected\n"); 2435030cb4a7SJohnny Huang ret = -1; 2436030cb4a7SJohnny Huang } 2437030cb4a7SJohnny Huang } else if (mode == OTP_REGION_CONF) { 2438030cb4a7SJohnny Huang if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) { 2439030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_conf) { 2440030cb4a7SJohnny Huang printf("OTP config region is protected\n"); 2441030cb4a7SJohnny Huang ret = -1; 2442030cb4a7SJohnny Huang } 2443030cb4a7SJohnny Huang } else if (otp_addr == 10 || otp_addr == 11) { 2444030cb4a7SJohnny Huang u32 otp_rid[2]; 2445030cb4a7SJohnny Huang u32 sw_rid[2]; 2446030cb4a7SJohnny Huang u64 *otp_rid64 = (u64 *)otp_rid; 2447030cb4a7SJohnny Huang u64 *sw_rid64 = (u64 *)sw_rid; 2448030cb4a7SJohnny Huang 2449030cb4a7SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2450030cb4a7SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2451030cb4a7SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2452030cb4a7SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2453030cb4a7SJohnny Huang 2454030cb4a7SJohnny Huang if (otp_addr == 10) 2455030cb4a7SJohnny Huang otp_rid[0] |= 1 << bit_offset; 2456030cb4a7SJohnny Huang else 2457030cb4a7SJohnny Huang otp_rid[1] |= 1 << bit_offset; 2458030cb4a7SJohnny Huang 2459030cb4a7SJohnny Huang if (*otp_rid64 > *sw_rid64) { 2460030cb4a7SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 2461030cb4a7SJohnny Huang ret = -1; 2462030cb4a7SJohnny Huang } 2463030cb4a7SJohnny Huang } else if (otp_addr == 4) { 2464030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_key_ret) { 2465030cb4a7SJohnny Huang printf("OTPCFG4 is protected\n"); 2466030cb4a7SJohnny Huang ret = -1; 2467030cb4a7SJohnny Huang } else { 2468030cb4a7SJohnny Huang if ((bit_offset >= 0 && bit_offset <= 7) || 2469030cb4a7SJohnny Huang (bit_offset >= 16 && bit_offset <= 23)) { 2470030cb4a7SJohnny Huang u32 key_num; 2471030cb4a7SJohnny Huang u32 retire; 2472030cb4a7SJohnny Huang 2473030cb4a7SJohnny Huang key_num = readl(SEC_KEY_NUM) & 3; 2474030cb4a7SJohnny Huang if (bit_offset >= 16) 2475030cb4a7SJohnny Huang retire = bit_offset - 16; 2476030cb4a7SJohnny Huang else 2477030cb4a7SJohnny Huang retire = bit_offset; 2478030cb4a7SJohnny Huang if (retire >= key_num) { 2479030cb4a7SJohnny Huang printf("Retire key id is equal or bigger than current boot key\n"); 2480030cb4a7SJohnny Huang ret = -1; 2481030cb4a7SJohnny Huang } 2482030cb4a7SJohnny Huang } 2483030cb4a7SJohnny Huang } 2484030cb4a7SJohnny Huang } else if (otp_addr >= 16 && otp_addr <= 31) { 2485030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2486030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2487030cb4a7SJohnny Huang ret = -1; 2488030cb4a7SJohnny Huang } else if ((otp_addr < 30 && info_cb.version == OTP_A0) || 2489030cb4a7SJohnny Huang (otp_addr < 28 && info_cb.version != OTP_A0)) { 2490030cb4a7SJohnny Huang if (otp_addr % 2 == 0) 2491030cb4a7SJohnny Huang otp_read_conf(30, &otp_strap_pro); 2492030cb4a7SJohnny Huang else 2493030cb4a7SJohnny Huang otp_read_conf(31, &otp_strap_pro); 2494030cb4a7SJohnny Huang if (otp_strap_pro >> bit_offset & 0x1) { 2495b489486eSJohnny Huang printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset); 2496030cb4a7SJohnny Huang ret = -1; 2497030cb4a7SJohnny Huang } 2498030cb4a7SJohnny Huang } 2499030cb4a7SJohnny Huang } 2500030cb4a7SJohnny Huang } else if (mode == OTP_REGION_STRAP) { 2501030cb4a7SJohnny Huang // per bit protection will check in otp_strap_bit_confirm 2502030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2503030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2504030cb4a7SJohnny Huang ret = -1; 2505030cb4a7SJohnny Huang } 2506030cb4a7SJohnny Huang } 2507030cb4a7SJohnny Huang 2508030cb4a7SJohnny Huang if (ret == -1) 2509030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2510030cb4a7SJohnny Huang 2511f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 25122a856b9aSJohnny Huang 25132a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 25142a856b9aSJohnny Huang return CMD_RET_SUCCESS; 25152a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 25162a856b9aSJohnny Huang return CMD_RET_FAILURE; 25172a856b9aSJohnny Huang else 25182a856b9aSJohnny Huang return CMD_RET_USAGE; 25192a856b9aSJohnny Huang } 25202a856b9aSJohnny Huang 25212a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 25222a856b9aSJohnny Huang { 25232a856b9aSJohnny Huang phys_addr_t addr; 25242a856b9aSJohnny Huang int otp_addr = 0; 2525b8590031SJohnny Huang int ret; 25262a856b9aSJohnny Huang 25272a856b9aSJohnny Huang if (argc != 3) 25282a856b9aSJohnny Huang return CMD_RET_USAGE; 25292a856b9aSJohnny Huang 25302a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 25312a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 2532b8590031SJohnny Huang ret = otp_compare(otp_addr, addr); 2533b8590031SJohnny Huang if (ret == 0) { 253469d5fd8fSJohnny Huang printf("Compare pass\n"); 25352a856b9aSJohnny Huang return CMD_RET_SUCCESS; 2536a219f6deSJohnny Huang } 253769d5fd8fSJohnny Huang printf("Compare fail\n"); 25382a856b9aSJohnny Huang return CMD_RET_FAILURE; 253969d5fd8fSJohnny Huang } 254069d5fd8fSJohnny Huang 254166f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 254266f2f8e5SJohnny Huang { 2543a8bd6d8cSJohnny Huang int view = 0; 25442d4b0742SJohnny Huang int input; 2545a8bd6d8cSJohnny Huang 2546a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 254766f2f8e5SJohnny Huang return CMD_RET_USAGE; 254866f2f8e5SJohnny Huang 25492d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 25502d4b0742SJohnny Huang if (argc == 3) { 25512d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 25522d4b0742SJohnny Huang otp_print_conf_info(input); 25532d4b0742SJohnny Huang } else { 25542d4b0742SJohnny Huang otp_print_conf_info(-1); 25552d4b0742SJohnny Huang } 25562d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 25572d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 2558a8bd6d8cSJohnny Huang view = 1; 2559a8bd6d8cSJohnny Huang /* Drop the view option */ 2560a8bd6d8cSJohnny Huang argc--; 2561a8bd6d8cSJohnny Huang argv++; 2562a8bd6d8cSJohnny Huang } 2563b458cd62SJohnny Huang otp_print_strap_info(view); 25640dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 25650dc9a440SJohnny Huang otp_print_scu_info(); 256688bd7d58SJohnny Huang } else if (!strcmp(argv[1], "key")) { 256788bd7d58SJohnny Huang otp_print_key_info(); 256866f2f8e5SJohnny Huang } else { 256966f2f8e5SJohnny Huang return CMD_RET_USAGE; 257066f2f8e5SJohnny Huang } 25712d4b0742SJohnny Huang 257266f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 257366f2f8e5SJohnny Huang } 257466f2f8e5SJohnny Huang 25750dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2576737ed20bSJohnny Huang { 25770dc9a440SJohnny Huang u32 input; 25780dc9a440SJohnny Huang u32 bit_offset; 2579e14b073cSJohnny Huang u32 prog_address; 2580030cb4a7SJohnny Huang char force; 258183655e91SJohnny Huang int ret; 2582a219f6deSJohnny Huang 2583737ed20bSJohnny Huang if (argc != 3 && argc != 2) 2584737ed20bSJohnny Huang return CMD_RET_USAGE; 2585737ed20bSJohnny Huang 2586e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 2587737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 2588030cb4a7SJohnny Huang force = 1; 2589737ed20bSJohnny Huang } else { 2590737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 2591030cb4a7SJohnny Huang force = 0; 2592737ed20bSJohnny Huang } 2593737ed20bSJohnny Huang 2594737ed20bSJohnny Huang if (input < 32) { 2595737ed20bSJohnny Huang bit_offset = input; 25960dc9a440SJohnny Huang prog_address = 0xe0c; 2597737ed20bSJohnny Huang } else if (input < 64) { 2598737ed20bSJohnny Huang bit_offset = input - 32; 25990dc9a440SJohnny Huang prog_address = 0xe0e; 2600737ed20bSJohnny Huang } else { 2601737ed20bSJohnny Huang return CMD_RET_USAGE; 2602737ed20bSJohnny Huang } 2603737ed20bSJohnny Huang 2604030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2605030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2606030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2607030cb4a7SJohnny Huang } 2608030cb4a7SJohnny Huang 2609030cb4a7SJohnny Huang if (!force) { 2610b489486eSJohnny Huang printf("OTPSTRAP[0x%X] will be protected\n", input); 2611030cb4a7SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2612030cb4a7SJohnny Huang if (!confirm_yesno()) { 2613030cb4a7SJohnny Huang printf(" Aborting\n"); 2614030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2615030cb4a7SJohnny Huang } 2616030cb4a7SJohnny Huang } 2617030cb4a7SJohnny Huang 2618e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2619b489486eSJohnny Huang printf("OTPSTRAP[0x%X] already protected\n", input); 2620e14b073cSJohnny Huang return CMD_RET_SUCCESS; 2621e14b073cSJohnny Huang } 2622de6fbf1cSJohnny Huang 2623f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 2624de6fbf1cSJohnny Huang otp_soak(0); 262583655e91SJohnny Huang 262683655e91SJohnny Huang if (ret) { 2627b489486eSJohnny Huang printf("Protect OTPSTRAP[0x%X] fail\n", input); 2628737ed20bSJohnny Huang return CMD_RET_FAILURE; 2629737ed20bSJohnny Huang } 26309a4fe690SJohnny Huang 2631b489486eSJohnny Huang printf("OTPSTRAP[0x%X] is protected\n", input); 2632794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2633794e27ecSJohnny Huang } 2634794e27ecSJohnny Huang 26350dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2636e14b073cSJohnny Huang { 26370dc9a440SJohnny Huang u32 scu_offset; 26380dc9a440SJohnny Huang u32 bit_offset; 26390dc9a440SJohnny Huang u32 conf_offset; 26400dc9a440SJohnny Huang u32 prog_address; 26410dc9a440SJohnny Huang char force; 26420dc9a440SJohnny Huang int ret; 26430dc9a440SJohnny Huang 26440dc9a440SJohnny Huang if (argc != 4 && argc != 3) 26450dc9a440SJohnny Huang return CMD_RET_USAGE; 26460dc9a440SJohnny Huang 26470dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 26480dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 26490dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 26500dc9a440SJohnny Huang force = 1; 26510dc9a440SJohnny Huang } else { 26520dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 26530dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 26540dc9a440SJohnny Huang force = 0; 26550dc9a440SJohnny Huang } 26560dc9a440SJohnny Huang if (scu_offset == 0x500) { 26570dc9a440SJohnny Huang prog_address = 0xe08; 26580dc9a440SJohnny Huang conf_offset = 28; 26590dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 26600dc9a440SJohnny Huang prog_address = 0xe0a; 26610dc9a440SJohnny Huang conf_offset = 29; 26620dc9a440SJohnny Huang } else { 26630dc9a440SJohnny Huang return CMD_RET_USAGE; 26640dc9a440SJohnny Huang } 26650dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 26660dc9a440SJohnny Huang return CMD_RET_USAGE; 2667030cb4a7SJohnny Huang if (info_cb.pro_sts.pro_strap) { 2668030cb4a7SJohnny Huang printf("OTP strap region is protected\n"); 2669030cb4a7SJohnny Huang return CMD_RET_FAILURE; 2670030cb4a7SJohnny Huang } 26710dc9a440SJohnny Huang if (!force) { 2672b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset); 2673b489486eSJohnny Huang printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset); 26740dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 26750dc9a440SJohnny Huang if (!confirm_yesno()) { 26760dc9a440SJohnny Huang printf(" Aborting\n"); 26770dc9a440SJohnny Huang return CMD_RET_FAILURE; 26780dc9a440SJohnny Huang } 2679e14b073cSJohnny Huang } 2680e14b073cSJohnny Huang 26810dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2682b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset); 26830dc9a440SJohnny Huang return CMD_RET_SUCCESS; 26840dc9a440SJohnny Huang } 26850dc9a440SJohnny Huang 26860dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 26870dc9a440SJohnny Huang otp_soak(0); 26880dc9a440SJohnny Huang 26890dc9a440SJohnny Huang if (ret) { 2690b489486eSJohnny Huang printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset); 26910dc9a440SJohnny Huang return CMD_RET_FAILURE; 26920dc9a440SJohnny Huang } 26930dc9a440SJohnny Huang 2694b489486eSJohnny Huang printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset); 26950dc9a440SJohnny Huang return CMD_RET_SUCCESS; 2696e14b073cSJohnny Huang } 2697e14b073cSJohnny Huang 2698f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2699f67375f7SJohnny Huang { 2700e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 2701f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2702f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2703f67375f7SJohnny Huang 2704f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2705f67375f7SJohnny Huang } 2706f67375f7SJohnny Huang 2707794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2708794e27ecSJohnny Huang { 2709794e27ecSJohnny Huang u32 update_num; 2710794e27ecSJohnny Huang int force = 0; 2711794e27ecSJohnny Huang int ret; 2712794e27ecSJohnny Huang 2713794e27ecSJohnny Huang if (argc == 3) { 2714794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 2715794e27ecSJohnny Huang return CMD_RET_USAGE; 2716794e27ecSJohnny Huang force = 1; 2717794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 2718794e27ecSJohnny Huang } else if (argc == 2) { 2719794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 2720794e27ecSJohnny Huang } else { 2721794e27ecSJohnny Huang return CMD_RET_USAGE; 2722794e27ecSJohnny Huang } 2723794e27ecSJohnny Huang 2724794e27ecSJohnny Huang if (update_num > 64) 2725794e27ecSJohnny Huang return CMD_RET_USAGE; 2726794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 2727b8590031SJohnny Huang 2728794e27ecSJohnny Huang if (ret) 2729794e27ecSJohnny Huang return CMD_RET_FAILURE; 2730794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2731794e27ecSJohnny Huang } 2732794e27ecSJohnny Huang 2733794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2734794e27ecSJohnny Huang { 2735794e27ecSJohnny Huang u32 otp_rid[2]; 2736a8789b47SJohnny Huang u32 sw_rid[2]; 2737794e27ecSJohnny Huang int rid_num = 0; 2738a8789b47SJohnny Huang int sw_rid_num = 0; 2739794e27ecSJohnny Huang int ret; 2740794e27ecSJohnny Huang 2741794e27ecSJohnny Huang if (argc != 1) 2742794e27ecSJohnny Huang return CMD_RET_USAGE; 2743794e27ecSJohnny Huang 2744f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2745f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2746794e27ecSJohnny Huang 2747a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2748a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2749794e27ecSJohnny Huang 2750a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 2751a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2752a8789b47SJohnny Huang 2753030cb4a7SJohnny Huang if (sw_rid_num < 0) { 2754030cb4a7SJohnny Huang printf("SW revision id is invalid, please check.\n"); 2755030cb4a7SJohnny Huang printf("SEC68:0x%x\n", sw_rid[0]); 2756030cb4a7SJohnny Huang printf("SEC6C:0x%x\n", sw_rid[1]); 2757030cb4a7SJohnny Huang } else { 2758a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2759030cb4a7SJohnny Huang } 2760794e27ecSJohnny Huang if (rid_num >= 0) { 2761794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2762794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 2763794e27ecSJohnny Huang } else { 2764b64ca396SJohnny Huang printf("Current OTP revision ID cannot handle by 'otp update',\n" 2765b64ca396SJohnny Huang "please use 'otp pb' command to update it manually\n" 2766794e27ecSJohnny Huang "current OTP revision ID\n"); 2767794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 2768794e27ecSJohnny Huang } 2769794e27ecSJohnny Huang otp_print_revid(otp_rid); 2770794e27ecSJohnny Huang 2771794e27ecSJohnny Huang return ret; 2772794e27ecSJohnny Huang } 2773794e27ecSJohnny Huang 2774883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2775883625c5SJohnny Huang { 2776883625c5SJohnny Huang u32 retire_id; 2777883625c5SJohnny Huang int force = 0; 2778883625c5SJohnny Huang int ret; 2779883625c5SJohnny Huang 2780883625c5SJohnny Huang if (argc == 3) { 2781883625c5SJohnny Huang if (strcmp(argv[1], "o")) 2782883625c5SJohnny Huang return CMD_RET_USAGE; 2783883625c5SJohnny Huang force = 1; 2784883625c5SJohnny Huang retire_id = simple_strtoul(argv[2], NULL, 16); 2785883625c5SJohnny Huang } else if (argc == 2) { 2786883625c5SJohnny Huang retire_id = simple_strtoul(argv[1], NULL, 16); 2787883625c5SJohnny Huang } else { 2788883625c5SJohnny Huang return CMD_RET_USAGE; 2789883625c5SJohnny Huang } 2790883625c5SJohnny Huang 2791883625c5SJohnny Huang if (retire_id > 7) 2792883625c5SJohnny Huang return CMD_RET_USAGE; 2793883625c5SJohnny Huang ret = otp_retire_key(retire_id, force); 2794883625c5SJohnny Huang 2795883625c5SJohnny Huang if (ret) 2796883625c5SJohnny Huang return CMD_RET_FAILURE; 2797883625c5SJohnny Huang return CMD_RET_SUCCESS; 2798883625c5SJohnny Huang } 2799883625c5SJohnny Huang 28002a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2801f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 28022a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2803a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2804de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 28052a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2806737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 28070dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 28082a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 2809794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 2810794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 2811883625c5SJohnny Huang U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""), 28122a856b9aSJohnny Huang }; 28132a856b9aSJohnny Huang 28142a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 28152a856b9aSJohnny Huang { 2816030cb4a7SJohnny Huang struct otp_pro_sts *pro_sts; 28172a856b9aSJohnny Huang cmd_tbl_t *cp; 2818a219f6deSJohnny Huang u32 ver; 2819e14b073cSJohnny Huang int ret; 2820030cb4a7SJohnny Huang u32 otp_conf0; 28212a856b9aSJohnny Huang 28222a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 28232a856b9aSJohnny Huang 2824737ed20bSJohnny Huang /* Drop the otp command */ 28252a856b9aSJohnny Huang argc--; 28262a856b9aSJohnny Huang argv++; 28272a856b9aSJohnny Huang 2828a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 28292a856b9aSJohnny Huang return CMD_RET_USAGE; 28302a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 28312a856b9aSJohnny Huang return CMD_RET_SUCCESS; 28322a856b9aSJohnny Huang 28330dae9d52SJohnny Huang ver = chip_version(); 28340dae9d52SJohnny Huang switch (ver) { 2835e417205bSJohnny Huang case OTP_A0: 2836e417205bSJohnny Huang info_cb.version = OTP_A0; 28379a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 28389a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 28399a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 28409a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 28419a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 28429a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 2843e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 28440dae9d52SJohnny Huang break; 2845e417205bSJohnny Huang case OTP_A1: 2846e417205bSJohnny Huang info_cb.version = OTP_A1; 28473cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 28483cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 28493cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 28503cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 28519a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 28529a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 28530dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28540dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2855e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 28560dae9d52SJohnny Huang break; 2857e417205bSJohnny Huang case OTP_A2: 2858e417205bSJohnny Huang info_cb.version = OTP_A2; 28595fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 28605fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 2861fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2862fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 28635fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 28645fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 28650dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28660dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2867e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 28680dae9d52SJohnny Huang break; 2869e417205bSJohnny Huang case OTP_A3: 2870e417205bSJohnny Huang info_cb.version = OTP_A3; 2871b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 2872b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 2873fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2874fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 2875181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2876181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 28770dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 28780dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2879e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 288064b66712SJohnny Huang break; 28810dae9d52SJohnny Huang default: 2882f1be5099SJohnny Huang printf("SOC is not supported\n"); 28830dae9d52SJohnny Huang return CMD_RET_FAILURE; 28849a4fe690SJohnny Huang } 28859a4fe690SJohnny Huang 2886030cb4a7SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2887030cb4a7SJohnny Huang otp_read_conf(0, &otp_conf0); 2888030cb4a7SJohnny Huang pro_sts = &info_cb.pro_sts; 2889030cb4a7SJohnny Huang 2890030cb4a7SJohnny Huang pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1; 2891030cb4a7SJohnny Huang pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1; 2892030cb4a7SJohnny Huang pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1; 2893030cb4a7SJohnny Huang pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1; 2894030cb4a7SJohnny Huang pro_sts->pro_data = (otp_conf0 >> 23) & 0x1; 2895030cb4a7SJohnny Huang pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1; 2896030cb4a7SJohnny Huang pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5; 2897030cb4a7SJohnny Huang 2898e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 2899b8590031SJohnny Huang writel(1, OTP_PROTECT_KEY); //protect otp controller 2900e14b073cSJohnny Huang 2901e14b073cSJohnny Huang return ret; 290269d5fd8fSJohnny Huang } 290369d5fd8fSJohnny Huang 2904a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 290569d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2906f67375f7SJohnny Huang "version\n" 2907f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 29082a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 29092d4b0742SJohnny Huang "otp info strap [v]\n" 29102d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 29110dc9a440SJohnny Huang "otp info scu\n" 291288bd7d58SJohnny Huang "otp info key\n" 2913de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2914ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2915ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2916ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 29170dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 2918794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 2919794e27ecSJohnny Huang "otp rid\n" 2920883625c5SJohnny Huang "otp retire [o] <key_id>\n" 292169d5fd8fSJohnny Huang ); 2922