1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+ 269d5fd8fSJohnny Huang /* 3a219f6deSJohnny Huang * Copyright 2021 Aspeed Technology Inc. 469d5fd8fSJohnny Huang */ 5e417205bSJohnny Huang 64c1c9b35SJohnny Huang #include <stdlib.h> 769d5fd8fSJohnny Huang #include <common.h> 869d5fd8fSJohnny Huang #include <console.h> 969d5fd8fSJohnny Huang #include <bootretry.h> 1069d5fd8fSJohnny Huang #include <cli.h> 1169d5fd8fSJohnny Huang #include <command.h> 1269d5fd8fSJohnny Huang #include <console.h> 134c1c9b35SJohnny Huang #include <malloc.h> 1469d5fd8fSJohnny Huang #include <inttypes.h> 1569d5fd8fSJohnny Huang #include <mapmem.h> 1669d5fd8fSJohnny Huang #include <asm/io.h> 1769d5fd8fSJohnny Huang #include <linux/compiler.h> 18696656c6SJohnny Huang #include <u-boot/sha256.h> 190cee9a95SJohnny Huang #include "otp_info.h" 2069d5fd8fSJohnny Huang 2169d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2269d5fd8fSJohnny Huang 23f347c284SJohnny Huang #define OTP_VER "1.1.0" 24f67375f7SJohnny Huang 2569d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 26dacbba92SJohnny Huang #define RETRY 20 277332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 287332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 297332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 3069d5fd8fSJohnny Huang 312a856b9aSJohnny Huang #define OTP_USAGE -1 322a856b9aSJohnny Huang #define OTP_FAILURE -2 332a856b9aSJohnny Huang #define OTP_SUCCESS 0 342a856b9aSJohnny Huang 35a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 36a6af4a17SJohnny Huang 37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB 1 38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV 2 39181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES 3 40181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT 4 41181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC 5 429a4fe690SJohnny Huang 434c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 444c1c9b35SJohnny Huang #define PBWIDTH 60 454c1c9b35SJohnny Huang 463d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 473d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 483d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 493d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 503d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 513d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 523d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 533d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 543d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 553d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 56a8789b47SJohnny Huang #define SW_REV_ID0 OTP_BASE + 0x68 57a8789b47SJohnny Huang #define SW_REV_ID1 OTP_BASE + 0x6c 583d3688adSJohnny Huang 59696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 60696656c6SJohnny Huang #define CHECKSUM_LEN 32 61a219f6deSJohnny Huang #define OTP_INC_DATA BIT(31) 62a219f6deSJohnny Huang #define OTP_INC_CONFIG BIT(30) 63a219f6deSJohnny Huang #define OTP_INC_STRAP BIT(29) 64a219f6deSJohnny Huang #define OTP_ECC_EN BIT(28) 65696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 66696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 67696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 68696656c6SJohnny Huang 69e417205bSJohnny Huang #define OTP_A0 0 70e417205bSJohnny Huang #define OTP_A1 1 71e417205bSJohnny Huang #define OTP_A2 2 72e417205bSJohnny Huang #define OTP_A3 3 73e417205bSJohnny Huang 74e417205bSJohnny Huang #define ID0_AST2600A0 0x05000303 75e417205bSJohnny Huang #define ID1_AST2600A0 0x05000303 76e417205bSJohnny Huang #define ID0_AST2600A1 0x05010303 7721a8cfceSJohnny Huang #define ID1_AST2600A1 0x05010303 78e417205bSJohnny Huang #define ID0_AST2600A2 0x05010303 79e417205bSJohnny Huang #define ID1_AST2600A2 0x05020303 80e417205bSJohnny Huang #define ID0_AST2600A3 0x05030303 81e417205bSJohnny Huang #define ID1_AST2600A3 0x05030303 82e417205bSJohnny Huang #define ID0_AST2620A1 0x05010203 83e417205bSJohnny Huang #define ID1_AST2620A1 0x05010203 84e417205bSJohnny Huang #define ID0_AST2620A2 0x05010203 85e417205bSJohnny Huang #define ID1_AST2620A2 0x05020203 86e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 87e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 88e417205bSJohnny Huang #define ID0_AST2620A3 0x05030203 89e417205bSJohnny Huang #define ID1_AST2620A3 0x05030203 90e417205bSJohnny Huang #define ID0_AST2605A2 0x05010103 91e417205bSJohnny Huang #define ID1_AST2605A2 0x05020103 92e417205bSJohnny Huang #define ID0_AST2605A3 0x05030103 93e417205bSJohnny Huang #define ID1_AST2605A3 0x05030103 94e417205bSJohnny Huang #define ID0_AST2625A3 0x05030403 95e417205bSJohnny Huang #define ID1_AST2625A3 0x05030403 96696656c6SJohnny Huang 9761a6cda7SJohnny Huang #define SOC_AST2600A0 0 9861a6cda7SJohnny Huang #define SOC_AST2600A1 1 9961a6cda7SJohnny Huang #define SOC_AST2600A2 2 10061a6cda7SJohnny Huang #define SOC_AST2600A3 3 10161a6cda7SJohnny Huang 10261a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c)) 10361a6cda7SJohnny Huang 104696656c6SJohnny Huang struct otp_header { 105696656c6SJohnny Huang u8 otp_magic[8]; 10661a6cda7SJohnny Huang u32 soc_ver; 10761a6cda7SJohnny Huang u32 otptool_ver; 108696656c6SJohnny Huang u32 image_info; 109696656c6SJohnny Huang u32 data_info; 110696656c6SJohnny Huang u32 config_info; 111696656c6SJohnny Huang u32 strap_info; 1127e523e3bSJohnny Huang u32 scu_protect_info; 113696656c6SJohnny Huang u32 checksum_offset; 114a219f6deSJohnny Huang } __packed; 115696656c6SJohnny Huang 11666f2f8e5SJohnny Huang struct otpstrap_status { 11769d5fd8fSJohnny Huang int value; 11869d5fd8fSJohnny Huang int option_array[7]; 11969d5fd8fSJohnny Huang int remain_times; 12069d5fd8fSJohnny Huang int writeable_option; 12169d5fd8fSJohnny Huang int protected; 12269d5fd8fSJohnny Huang }; 12369d5fd8fSJohnny Huang 1249a4fe690SJohnny Huang struct otpkey_type { 1259a4fe690SJohnny Huang int value; 1269a4fe690SJohnny Huang int key_type; 1279a4fe690SJohnny Huang int need_id; 1289a4fe690SJohnny Huang char information[110]; 1299a4fe690SJohnny Huang }; 1309a4fe690SJohnny Huang 1319a4fe690SJohnny Huang struct otp_info_cb { 1329a4fe690SJohnny Huang int version; 133e417205bSJohnny Huang char ver_name[3]; 13479e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1359a4fe690SJohnny Huang int strap_info_len; 13679e42a59SJoel Stanley const struct otpconf_info *conf_info; 1379a4fe690SJohnny Huang int conf_info_len; 13879e42a59SJoel Stanley const struct otpkey_type *key_info; 1399a4fe690SJohnny Huang int key_info_len; 140*0dc9a440SJohnny Huang const struct scu_info *scu_info; 141*0dc9a440SJohnny Huang int scu_info_len; 1429a4fe690SJohnny Huang }; 1439a4fe690SJohnny Huang 144696656c6SJohnny Huang struct otp_image_layout { 1455010032bSJohnny Huang int data_length; 1465010032bSJohnny Huang int conf_length; 1475010032bSJohnny Huang int strap_length; 148a219f6deSJohnny Huang u8 *data; 149a219f6deSJohnny Huang u8 *data_ignore; 150a219f6deSJohnny Huang u8 *conf; 151a219f6deSJohnny Huang u8 *conf_ignore; 152a219f6deSJohnny Huang u8 *strap; 153a219f6deSJohnny Huang u8 *strap_pro; 154a219f6deSJohnny Huang u8 *strap_ignore; 155696656c6SJohnny Huang }; 156696656c6SJohnny Huang 1579a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1589a4fe690SJohnny Huang 15979e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1609a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1619a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1629a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 163181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 164181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as SOC public key"}, 165181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 166181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as SOC private key"}, 167181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1689a4fe690SJohnny Huang }; 1699a4fe690SJohnny Huang 17079e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1719a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1729a4fe690SJohnny 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"}, 173181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 174181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 175181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1769a4fe690SJohnny Huang }; 1779a4fe690SJohnny Huang 1785fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1795fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1805fdde29fSJohnny 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"}, 181181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 182181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 183181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 184181f72d8SJohnny Huang }; 185181f72d8SJohnny Huang 186181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = { 187181f72d8SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 188181f72d8SJohnny 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"}, 189181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 190181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 191181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 192181f72d8SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key(big endian)"}, 193181f72d8SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 194181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key(big endian)"}, 1955fdde29fSJohnny Huang }; 1965fdde29fSJohnny Huang 197f347c284SJohnny Huang static void buf_print(u8 *buf, int len) 198f347c284SJohnny Huang { 199f347c284SJohnny Huang int i; 200f347c284SJohnny Huang 201f347c284SJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 202f347c284SJohnny Huang for (i = 0; i < len; i++) { 203f347c284SJohnny Huang if (i % 16 == 0) 204f347c284SJohnny Huang printf("%04X: ", i); 205f347c284SJohnny Huang printf("%02X ", buf[i]); 206f347c284SJohnny Huang if ((i + 1) % 16 == 0) 207f347c284SJohnny Huang printf("\n"); 208f347c284SJohnny Huang } 209f347c284SJohnny Huang } 210f347c284SJohnny Huang 211794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset) 212794e27ecSJohnny Huang { 213794e27ecSJohnny Huang int bit_offset; 214794e27ecSJohnny Huang int i; 215794e27ecSJohnny Huang 216794e27ecSJohnny Huang if (offset < 32) { 217794e27ecSJohnny Huang i = 0; 218794e27ecSJohnny Huang bit_offset = offset; 219794e27ecSJohnny Huang } else { 220794e27ecSJohnny Huang i = 1; 221794e27ecSJohnny Huang bit_offset = offset - 32; 222794e27ecSJohnny Huang } 223794e27ecSJohnny Huang if ((rid[i] >> bit_offset) & 0x1) 224794e27ecSJohnny Huang return 1; 225794e27ecSJohnny Huang else 226794e27ecSJohnny Huang return 0; 227794e27ecSJohnny Huang } 228794e27ecSJohnny Huang 229794e27ecSJohnny Huang static int get_rid_num(u32 *rid) 230794e27ecSJohnny Huang { 231794e27ecSJohnny Huang int i; 232794e27ecSJohnny Huang int fz = 0; 233794e27ecSJohnny Huang int rid_num = 0; 234794e27ecSJohnny Huang int ret = 0; 235794e27ecSJohnny Huang 236794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 237794e27ecSJohnny Huang if (get_dw_bit(rid, i) == 0) { 238794e27ecSJohnny Huang if (!fz) 239794e27ecSJohnny Huang fz = 1; 240794e27ecSJohnny Huang 241794e27ecSJohnny Huang } else { 242794e27ecSJohnny Huang rid_num++; 243794e27ecSJohnny Huang if (fz) 244794e27ecSJohnny Huang ret = OTP_FAILURE; 245794e27ecSJohnny Huang } 246794e27ecSJohnny Huang } 247794e27ecSJohnny Huang if (ret) 248794e27ecSJohnny Huang return ret; 249794e27ecSJohnny Huang 250794e27ecSJohnny Huang return rid_num; 251794e27ecSJohnny Huang } 252794e27ecSJohnny Huang 253a219f6deSJohnny Huang static u32 chip_version(void) 2549a4fe690SJohnny Huang { 255e417205bSJohnny Huang u32 revid0, revid1; 2569a4fe690SJohnny Huang 257e417205bSJohnny Huang revid0 = readl(ASPEED_REVISION_ID0); 258e417205bSJohnny Huang revid1 = readl(ASPEED_REVISION_ID1); 2599a4fe690SJohnny Huang 260e417205bSJohnny Huang if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) { 261badd21c2SJohnny Huang /* AST2600-A0 */ 262e417205bSJohnny Huang return OTP_A0; 263e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) { 264badd21c2SJohnny Huang /* AST2600-A1 */ 265e417205bSJohnny Huang return OTP_A1; 266e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) { 267badd21c2SJohnny Huang /* AST2600-A2 */ 268e417205bSJohnny Huang return OTP_A2; 269e417205bSJohnny Huang } else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) { 27064b66712SJohnny Huang /* AST2600-A3 */ 271e417205bSJohnny Huang return OTP_A3; 272e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) { 273e417205bSJohnny Huang /* AST2620-A1 */ 274e417205bSJohnny Huang return OTP_A1; 275e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) { 276e417205bSJohnny Huang /* AST2620-A2 */ 277e417205bSJohnny Huang return OTP_A2; 278e417205bSJohnny Huang } else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) { 27964b66712SJohnny Huang /* AST2620-A3 */ 280e417205bSJohnny Huang return OTP_A3; 281e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) { 282e417205bSJohnny Huang /* AST2605-A2 */ 283e417205bSJohnny Huang return OTP_A2; 284e417205bSJohnny Huang } else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) { 285e417205bSJohnny Huang /* AST2605-A3 */ 286e417205bSJohnny Huang return OTP_A3; 287e417205bSJohnny Huang } else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) { 288e417205bSJohnny Huang /* AST2605-A3 */ 289e417205bSJohnny Huang return OTP_A3; 2900dae9d52SJohnny Huang } 291f347c284SJohnny Huang return OTP_FAILURE; 2929a4fe690SJohnny Huang } 2939a4fe690SJohnny Huang 2943d3688adSJohnny Huang static void wait_complete(void) 2953d3688adSJohnny Huang { 2963d3688adSJohnny Huang int reg; 2973d3688adSJohnny Huang 2983d3688adSJohnny Huang do { 2993d3688adSJohnny Huang reg = readl(OTP_STATUS); 3003d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 3013d3688adSJohnny Huang } 3023d3688adSJohnny Huang 303a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 304dacbba92SJohnny Huang { 305dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 306dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 307dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 308dacbba92SJohnny Huang wait_complete(); 309dacbba92SJohnny Huang } 310dacbba92SJohnny Huang 311dacbba92SJohnny Huang static void otp_soak(int soak) 312dacbba92SJohnny Huang { 313e417205bSJohnny Huang if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) { 314dacbba92SJohnny Huang switch (soak) { 315dacbba92SJohnny Huang case 0: //default 316377f8cd7SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 317377f8cd7SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 318dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 319dacbba92SJohnny Huang break; 320dacbba92SJohnny Huang case 1: //normal program 321377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 322377f8cd7SJohnny Huang otp_write(0x5000, 0x1008); // Write MRB 323377f8cd7SJohnny Huang otp_write(0x1000, 0x0024); // Write MR 324feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 325dacbba92SJohnny Huang break; 326dacbba92SJohnny Huang case 2: //soak program 327377f8cd7SJohnny Huang otp_write(0x3000, 0x1320); // Write MRA 328377f8cd7SJohnny Huang otp_write(0x5000, 0x0007); // Write MRB 329377f8cd7SJohnny Huang otp_write(0x1000, 0x0100); // Write MR 330feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 331dacbba92SJohnny Huang break; 332dacbba92SJohnny Huang } 333dacbba92SJohnny Huang } else { 334dacbba92SJohnny Huang switch (soak) { 335dacbba92SJohnny Huang case 0: //default 336dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 337dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 338dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 339dacbba92SJohnny Huang break; 340dacbba92SJohnny Huang case 1: //normal program 341dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 342dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 343dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 344feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 345dacbba92SJohnny Huang break; 346dacbba92SJohnny Huang case 2: //soak program 347dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 348dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 349dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 350feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 351dacbba92SJohnny Huang break; 352dacbba92SJohnny Huang } 353dacbba92SJohnny Huang } 354dacbba92SJohnny Huang 355dacbba92SJohnny Huang wait_complete(); 356dacbba92SJohnny Huang } 357dacbba92SJohnny Huang 358a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 35969d5fd8fSJohnny Huang { 3603d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 3613d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3623d3688adSJohnny Huang wait_complete(); 3633d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 3643d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 36569d5fd8fSJohnny Huang } 36669d5fd8fSJohnny Huang 367f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data) 36869d5fd8fSJohnny Huang { 36969d5fd8fSJohnny Huang int config_offset; 37069d5fd8fSJohnny Huang 37169d5fd8fSJohnny Huang config_offset = 0x800; 37269d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 37369d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 37469d5fd8fSJohnny Huang 3753d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 3763d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3773d3688adSJohnny Huang wait_complete(); 3783d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 37969d5fd8fSJohnny Huang } 38069d5fd8fSJohnny Huang 381a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 38269d5fd8fSJohnny Huang { 383a219f6deSJohnny Huang u32 ret; 384a219f6deSJohnny Huang u32 *buf; 38569d5fd8fSJohnny Huang 38669d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 38769d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 38869d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 38969d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 39069d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 3913d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 3923d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 3933d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 3943d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 3953d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 3963d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 3973d3688adSJohnny Huang wait_complete(); 3983d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 39969d5fd8fSJohnny Huang if (ret & 0x1) 400f347c284SJohnny Huang return OTP_SUCCESS; 40169d5fd8fSJohnny Huang else 402f347c284SJohnny Huang return OTP_FAILURE; 40369d5fd8fSJohnny Huang } 40469d5fd8fSJohnny Huang 405a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 40669d5fd8fSJohnny Huang { 407a219f6deSJohnny Huang u32 ret[2]; 40869d5fd8fSJohnny Huang 40930a8c590SJohnny Huang if (otp_addr % 2 == 0) 4103d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 41130a8c590SJohnny Huang else 4123d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 41330a8c590SJohnny Huang 4143d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4153d3688adSJohnny Huang wait_complete(); 4163d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4173d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 41883655e91SJohnny Huang 41930a8c590SJohnny Huang if (otp_addr % 2 == 0) { 42030a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 421f347c284SJohnny Huang return OTP_SUCCESS; 42269d5fd8fSJohnny Huang else 423f347c284SJohnny Huang return OTP_FAILURE; 42430a8c590SJohnny Huang } else { 42530a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 426f347c284SJohnny Huang return OTP_SUCCESS; 42730a8c590SJohnny Huang else 428f347c284SJohnny Huang return OTP_FAILURE; 42930a8c590SJohnny Huang } 43069d5fd8fSJohnny Huang } 43169d5fd8fSJohnny Huang 432a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 4334c1c9b35SJohnny Huang { 434a219f6deSJohnny Huang u32 ret[2]; 4354c1c9b35SJohnny Huang 4364c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 4374c1c9b35SJohnny Huang 4384c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 4393d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 4404c1c9b35SJohnny Huang else 4413d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 4423d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 4433d3688adSJohnny Huang wait_complete(); 4443d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 4453d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 4464c1c9b35SJohnny Huang if (size == 1) { 4474c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 4484c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 449696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 4504c1c9b35SJohnny Huang compare[0] = 0; 451f347c284SJohnny Huang return OTP_SUCCESS; 452a219f6deSJohnny Huang } 4534c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 454f347c284SJohnny Huang return OTP_FAILURE; 4554c1c9b35SJohnny Huang 4564c1c9b35SJohnny Huang } else { 4574c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 458696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4594c1c9b35SJohnny Huang compare[0] = ~0; 460f347c284SJohnny Huang return OTP_SUCCESS; 461a219f6deSJohnny Huang } 462d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 463f347c284SJohnny Huang return OTP_FAILURE; 4644c1c9b35SJohnny Huang } 4654c1c9b35SJohnny Huang } else if (size == 2) { 4664c1c9b35SJohnny Huang // otp_addr should be even 467696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 4684c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4694c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4704c1c9b35SJohnny Huang compare[0] = 0; 4714c1c9b35SJohnny Huang compare[1] = ~0; 472f347c284SJohnny Huang return OTP_SUCCESS; 473a219f6deSJohnny Huang } 4744c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4754c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4764c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4774c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 478f347c284SJohnny Huang return OTP_FAILURE; 4794c1c9b35SJohnny Huang } else { 480f347c284SJohnny Huang return OTP_FAILURE; 4814c1c9b35SJohnny Huang } 4824c1c9b35SJohnny Huang } 4834c1c9b35SJohnny Huang 484a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit) 48583655e91SJohnny Huang { 48690965bb3SJohnny Huang otp_write(0x0, prog_bit); 48783655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 48883655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 48983655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 49083655e91SJohnny Huang wait_complete(); 49183655e91SJohnny Huang } 49283655e91SJohnny Huang 493a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 49483655e91SJohnny Huang { 49583655e91SJohnny Huang int prog_bit; 49683655e91SJohnny Huang 49783655e91SJohnny Huang if (prog_address % 2 == 0) { 49883655e91SJohnny Huang if (value) 49983655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 50083655e91SJohnny Huang else 50183655e91SJohnny Huang return; 50283655e91SJohnny Huang } else { 503e417205bSJohnny Huang if (info_cb.version != OTP_A3) 50483655e91SJohnny Huang prog_address |= 1 << 15; 50583655e91SJohnny Huang if (!value) 50683655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 50783655e91SJohnny Huang else 50883655e91SJohnny Huang return; 50983655e91SJohnny Huang } 51083655e91SJohnny Huang otp_prog(prog_address, prog_bit); 51183655e91SJohnny Huang } 51283655e91SJohnny Huang 513f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset) 51483655e91SJohnny Huang { 51583655e91SJohnny Huang int pass; 51683655e91SJohnny Huang int i; 51783655e91SJohnny Huang 51883655e91SJohnny Huang otp_soak(1); 51983655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 52083655e91SJohnny Huang pass = 0; 52183655e91SJohnny Huang 52283655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 52383655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 52483655e91SJohnny Huang otp_soak(2); 52583655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 52683655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 52783655e91SJohnny Huang otp_soak(1); 52883655e91SJohnny Huang } else { 52983655e91SJohnny Huang pass = 1; 53083655e91SJohnny Huang break; 53183655e91SJohnny Huang } 53283655e91SJohnny Huang } else { 53383655e91SJohnny Huang pass = 1; 53483655e91SJohnny Huang break; 53583655e91SJohnny Huang } 53683655e91SJohnny Huang } 537794e27ecSJohnny Huang if (pass) 538794e27ecSJohnny Huang return OTP_SUCCESS; 53983655e91SJohnny Huang 540794e27ecSJohnny Huang return OTP_FAILURE; 54183655e91SJohnny Huang } 54283655e91SJohnny Huang 543a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 544d90825e2SJohnny Huang { 545d90825e2SJohnny Huang int j, bit_value, prog_bit; 546d90825e2SJohnny Huang 547d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 548696656c6SJohnny Huang if ((ignore >> j) & 0x1) 549d90825e2SJohnny Huang continue; 550d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 551d90825e2SJohnny Huang if (prog_address % 2 == 0) { 552d90825e2SJohnny Huang if (bit_value) 553d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 554d90825e2SJohnny Huang else 555d90825e2SJohnny Huang continue; 556d90825e2SJohnny Huang } else { 557e417205bSJohnny Huang if (info_cb.version != OTP_A3) 558d90825e2SJohnny Huang prog_address |= 1 << 15; 559d90825e2SJohnny Huang if (bit_value) 560d90825e2SJohnny Huang continue; 561d90825e2SJohnny Huang else 562d90825e2SJohnny Huang prog_bit = 0x1 << j; 563d90825e2SJohnny Huang } 564d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 565d90825e2SJohnny Huang } 566d90825e2SJohnny Huang } 567d90825e2SJohnny Huang 568a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 56954552c69SJohnny Huang { 57054552c69SJohnny Huang int pass; 57154552c69SJohnny Huang int i; 572a219f6deSJohnny Huang u32 data0_masked; 573a219f6deSJohnny Huang u32 data1_masked; 574a219f6deSJohnny Huang u32 buf0_masked; 575a219f6deSJohnny Huang u32 buf1_masked; 576a219f6deSJohnny Huang u32 compare[2]; 57754552c69SJohnny Huang 57854552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 57954552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 58054552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 58154552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 582a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 583f347c284SJohnny Huang return OTP_SUCCESS; 58454552c69SJohnny Huang 58554552c69SJohnny Huang otp_soak(1); 58654552c69SJohnny Huang if (data0_masked != buf0_masked) 58754552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 58854552c69SJohnny Huang if (data1_masked != buf1_masked) 58954552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 59054552c69SJohnny Huang 59154552c69SJohnny Huang pass = 0; 59254552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 59354552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 59454552c69SJohnny Huang otp_soak(2); 595a219f6deSJohnny Huang if (compare[0] != 0) 59654552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 597a219f6deSJohnny Huang if (compare[1] != ~0) 5985537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 59954552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 60054552c69SJohnny Huang otp_soak(1); 60154552c69SJohnny Huang } else { 60254552c69SJohnny Huang pass = 1; 60354552c69SJohnny Huang break; 60454552c69SJohnny Huang } 60554552c69SJohnny Huang } else { 60654552c69SJohnny Huang pass = 1; 60754552c69SJohnny Huang break; 60854552c69SJohnny Huang } 60954552c69SJohnny Huang } 61054552c69SJohnny Huang 61154552c69SJohnny Huang if (!pass) { 61254552c69SJohnny Huang otp_soak(0); 61354552c69SJohnny Huang return OTP_FAILURE; 61454552c69SJohnny Huang } 61554552c69SJohnny Huang return OTP_SUCCESS; 61654552c69SJohnny Huang } 61754552c69SJohnny Huang 618541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 61976d13988SJohnny Huang { 620a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 6215010032bSJohnny Huang int strap_end; 62276d13988SJohnny Huang int i, j; 62376d13988SJohnny Huang 624e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 62576d13988SJohnny Huang for (j = 0; j < 64; j++) { 62676d13988SJohnny Huang otpstrap[j].value = 0; 62776d13988SJohnny Huang otpstrap[j].remain_times = 7; 62876d13988SJohnny Huang otpstrap[j].writeable_option = -1; 62976d13988SJohnny Huang otpstrap[j].protected = 0; 63076d13988SJohnny Huang } 6315010032bSJohnny Huang strap_end = 30; 6325010032bSJohnny Huang } else { 6335010032bSJohnny Huang for (j = 0; j < 64; j++) { 6345010032bSJohnny Huang otpstrap[j].value = 0; 6355010032bSJohnny Huang otpstrap[j].remain_times = 6; 6365010032bSJohnny Huang otpstrap[j].writeable_option = -1; 6375010032bSJohnny Huang otpstrap[j].protected = 0; 6385010032bSJohnny Huang } 6395010032bSJohnny Huang strap_end = 28; 6405010032bSJohnny Huang } 64176d13988SJohnny Huang 642dacbba92SJohnny Huang otp_soak(0); 6435010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 64476d13988SJohnny Huang int option = (i - 16) / 2; 645a219f6deSJohnny Huang 646f347c284SJohnny Huang otp_read_conf(i, &OTPSTRAP_RAW[0]); 647f347c284SJohnny Huang otp_read_conf(i + 1, &OTPSTRAP_RAW[1]); 64876d13988SJohnny Huang for (j = 0; j < 32; j++) { 64976d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 650a219f6deSJohnny Huang 651a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 65276d13988SJohnny Huang otpstrap[j].writeable_option = option; 65376d13988SJohnny Huang if (bit_value == 1) 65476d13988SJohnny Huang otpstrap[j].remain_times--; 65576d13988SJohnny Huang otpstrap[j].value ^= bit_value; 65676d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 65776d13988SJohnny Huang } 65876d13988SJohnny Huang for (j = 32; j < 64; j++) { 65976d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 660a219f6deSJohnny Huang 661a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 66276d13988SJohnny Huang otpstrap[j].writeable_option = option; 66376d13988SJohnny Huang if (bit_value == 1) 66476d13988SJohnny Huang otpstrap[j].remain_times--; 66576d13988SJohnny Huang otpstrap[j].value ^= bit_value; 66676d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 66776d13988SJohnny Huang } 66876d13988SJohnny Huang } 6695010032bSJohnny Huang 670f347c284SJohnny Huang otp_read_conf(30, &OTPSTRAP_RAW[0]); 671f347c284SJohnny Huang otp_read_conf(31, &OTPSTRAP_RAW[1]); 67276d13988SJohnny Huang for (j = 0; j < 32; j++) { 67376d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 67476d13988SJohnny Huang otpstrap[j].protected = 1; 67576d13988SJohnny Huang } 67676d13988SJohnny Huang for (j = 32; j < 64; j++) { 67776d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 67876d13988SJohnny Huang otpstrap[j].protected = 1; 67976d13988SJohnny Huang } 68076d13988SJohnny Huang } 68176d13988SJohnny Huang 6827e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit) 683f347c284SJohnny Huang { 684f347c284SJohnny Huang int prog_flag = 0; 685f347c284SJohnny Huang 686f347c284SJohnny Huang // ignore this bit 687f347c284SJohnny Huang if (ibit == 1) 688f347c284SJohnny Huang return OTP_SUCCESS; 689f347c284SJohnny Huang printf("OTPSTRAP[%X]:\n", offset); 690f347c284SJohnny Huang 691f347c284SJohnny Huang if (bit == otpstrap->value) { 6927e523e3bSJohnny Huang if (!pbit) { 693f347c284SJohnny Huang printf(" The value is same as before, skip it.\n"); 694f347c284SJohnny Huang return OTP_PROG_SKIP; 695f347c284SJohnny Huang } 696f347c284SJohnny Huang printf(" The value is same as before.\n"); 697f347c284SJohnny Huang } else { 698f347c284SJohnny Huang prog_flag = 1; 699f347c284SJohnny Huang } 700f347c284SJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 701f347c284SJohnny Huang printf(" This bit is protected and is not writable\n"); 702f347c284SJohnny Huang return OTP_FAILURE; 703f347c284SJohnny Huang } 704f347c284SJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 705f347c284SJohnny Huang printf(" This bit is no remaining times to write.\n"); 706f347c284SJohnny Huang return OTP_FAILURE; 707f347c284SJohnny Huang } 708f347c284SJohnny Huang if (pbit == 1) 709f347c284SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 710f347c284SJohnny Huang if (prog_flag) 711f347c284SJohnny Huang printf(" Write 1 to OTPSTRAP[%X] OPTION[%X], that value becomes from %d to %d.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1); 712f347c284SJohnny Huang 713f347c284SJohnny Huang return OTP_SUCCESS; 714f347c284SJohnny Huang } 715f347c284SJohnny Huang 716f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value) 717f347c284SJohnny Huang { 718f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 719f347c284SJohnny Huang u32 prog_address; 720f347c284SJohnny Huang int offset; 721f347c284SJohnny Huang int ret; 722f347c284SJohnny Huang 723f347c284SJohnny Huang otp_strap_status(otpstrap); 724f347c284SJohnny Huang 7257e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 726f347c284SJohnny Huang 727f347c284SJohnny Huang if (ret != OTP_SUCCESS) 728f347c284SJohnny Huang return ret; 729f347c284SJohnny Huang 730f347c284SJohnny Huang prog_address = 0x800; 731f347c284SJohnny Huang if (bit_offset < 32) { 732f347c284SJohnny Huang offset = bit_offset; 733f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 734f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 735f347c284SJohnny Huang 736f347c284SJohnny Huang } else { 737f347c284SJohnny Huang offset = (bit_offset - 32); 738f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 739f347c284SJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 740f347c284SJohnny Huang } 741f347c284SJohnny Huang 742f347c284SJohnny Huang return otp_prog_dc_b(1, prog_address, offset); 743f347c284SJohnny Huang } 744f347c284SJohnny Huang 745f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count) 746f347c284SJohnny Huang { 747f347c284SJohnny Huang int i; 748f347c284SJohnny Huang u32 ret[1]; 749f347c284SJohnny Huang 750f347c284SJohnny Huang if (offset + dw_count > 32) 751f347c284SJohnny Huang return OTP_USAGE; 752f347c284SJohnny Huang otp_soak(0); 753f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i++) { 754f347c284SJohnny Huang otp_read_conf(i, ret); 755f347c284SJohnny Huang printf("OTPCFG%X: %08X\n", i, ret[0]); 756f347c284SJohnny Huang } 757f347c284SJohnny Huang printf("\n"); 758f347c284SJohnny Huang return OTP_SUCCESS; 759f347c284SJohnny Huang } 760f347c284SJohnny Huang 761f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count) 762f347c284SJohnny Huang { 763f347c284SJohnny Huang int i; 764f347c284SJohnny Huang u32 ret[2]; 765f347c284SJohnny Huang 766f347c284SJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 767f347c284SJohnny Huang return OTP_USAGE; 768f347c284SJohnny Huang otp_soak(0); 769f347c284SJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 770f347c284SJohnny Huang otp_read_data(i, ret); 771f347c284SJohnny Huang if (i % 4 == 0) 772f347c284SJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 773f347c284SJohnny Huang else 774f347c284SJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 775f347c284SJohnny Huang } 776f347c284SJohnny Huang printf("\n"); 777f347c284SJohnny Huang return OTP_SUCCESS; 778f347c284SJohnny Huang } 779f347c284SJohnny Huang 780f347c284SJohnny Huang static int otp_print_strap(int start, int count) 781f347c284SJohnny Huang { 782f347c284SJohnny Huang int i, j; 783f347c284SJohnny Huang int remains; 784f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 785f347c284SJohnny Huang 786f347c284SJohnny Huang if (start < 0 || start > 64) 787f347c284SJohnny Huang return OTP_USAGE; 788f347c284SJohnny Huang 789f347c284SJohnny Huang if ((start + count) < 0 || (start + count) > 64) 790f347c284SJohnny Huang return OTP_USAGE; 791f347c284SJohnny Huang 792f347c284SJohnny Huang otp_strap_status(otpstrap); 793f347c284SJohnny Huang 7947e523e3bSJohnny Huang if (info_cb.version == OTP_A0) 795f347c284SJohnny Huang remains = 7; 7967e523e3bSJohnny Huang else 797f347c284SJohnny Huang remains = 6; 7987e523e3bSJohnny Huang printf("BIT(hex) Value Option Status\n"); 799f347c284SJohnny Huang printf("______________________________________________________________________________\n"); 800f347c284SJohnny Huang 801f347c284SJohnny Huang for (i = start; i < start + count; i++) { 802f347c284SJohnny Huang printf("0x%-8X", i); 803f347c284SJohnny Huang printf("%-7d", otpstrap[i].value); 804f347c284SJohnny Huang for (j = 0; j < remains; j++) 805f347c284SJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 806f347c284SJohnny Huang printf(" "); 807f347c284SJohnny Huang if (otpstrap[i].protected == 1) { 808f347c284SJohnny Huang printf("protected and not writable"); 809f347c284SJohnny Huang } else { 810f347c284SJohnny Huang printf("not protected "); 811f347c284SJohnny Huang if (otpstrap[i].remain_times == 0) 812f347c284SJohnny Huang printf("and no remaining times to write."); 813f347c284SJohnny Huang else 814f347c284SJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 815f347c284SJohnny Huang } 816f347c284SJohnny Huang printf("\n"); 817f347c284SJohnny Huang } 818f347c284SJohnny Huang 819f347c284SJohnny Huang return OTP_SUCCESS; 820f347c284SJohnny Huang } 821f347c284SJohnny Huang 822794e27ecSJohnny Huang static void otp_print_revid(u32 *rid) 823794e27ecSJohnny Huang { 824794e27ecSJohnny Huang int bit_offset; 825794e27ecSJohnny Huang int i, j; 826794e27ecSJohnny Huang 827794e27ecSJohnny Huang printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 828794e27ecSJohnny Huang printf("___________________________________________________\n"); 829794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 830794e27ecSJohnny Huang if (i < 32) { 831794e27ecSJohnny Huang j = 0; 832794e27ecSJohnny Huang bit_offset = i; 833794e27ecSJohnny Huang } else { 834794e27ecSJohnny Huang j = 1; 835794e27ecSJohnny Huang bit_offset = i - 32; 836794e27ecSJohnny Huang } 837794e27ecSJohnny Huang if (i % 16 == 0) 838794e27ecSJohnny Huang printf("%2x | ", i); 839794e27ecSJohnny Huang printf("%d ", (rid[j] >> bit_offset) & 0x1); 840794e27ecSJohnny Huang if ((i + 1) % 16 == 0) 841794e27ecSJohnny Huang printf("\n"); 842794e27ecSJohnny Huang } 843794e27ecSJohnny Huang } 844794e27ecSJohnny Huang 845*0dc9a440SJohnny Huang static void otp_print_scu_info(void) 846*0dc9a440SJohnny Huang { 847*0dc9a440SJohnny Huang const struct scu_info *scu_info = info_cb.scu_info; 848*0dc9a440SJohnny Huang u32 OTPCFG[2]; 849*0dc9a440SJohnny Huang u32 scu_offset; 850*0dc9a440SJohnny Huang u32 bit_offset; 851*0dc9a440SJohnny Huang u32 reg_p; 852*0dc9a440SJohnny Huang u32 length; 853*0dc9a440SJohnny Huang int i, j; 854*0dc9a440SJohnny Huang 855*0dc9a440SJohnny Huang otp_soak(0); 856*0dc9a440SJohnny Huang otp_read_conf(28, &OTPCFG[0]); 857*0dc9a440SJohnny Huang otp_read_conf(29, &OTPCFG[1]); 858*0dc9a440SJohnny Huang printf("SCU BIT reg_protect Description\n"); 859*0dc9a440SJohnny Huang printf("____________________________________________________________________\n"); 860*0dc9a440SJohnny Huang for (i = 0; i < info_cb.scu_info_len; i++) { 861*0dc9a440SJohnny Huang length = scu_info[i].length; 862*0dc9a440SJohnny Huang for (j = 0; j < length; j++) { 863*0dc9a440SJohnny Huang if (scu_info[i].bit_offset + j < 32) { 864*0dc9a440SJohnny Huang scu_offset = 0x500; 865*0dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j; 866*0dc9a440SJohnny Huang reg_p = (OTPCFG[0] >> bit_offset) & 0x1; 867*0dc9a440SJohnny Huang } else { 868*0dc9a440SJohnny Huang scu_offset = 0x510; 869*0dc9a440SJohnny Huang bit_offset = scu_info[i].bit_offset + j - 32; 870*0dc9a440SJohnny Huang reg_p = (OTPCFG[1] >> bit_offset) & 0x1; 871*0dc9a440SJohnny Huang } 872*0dc9a440SJohnny Huang printf("0x%-6X", scu_offset); 873*0dc9a440SJohnny Huang printf("0x%-4X", bit_offset); 874*0dc9a440SJohnny Huang printf("0x%-13X", reg_p); 875*0dc9a440SJohnny Huang if (length == 1) { 876*0dc9a440SJohnny Huang printf(" %s\n", scu_info[i].information); 877*0dc9a440SJohnny Huang continue; 878*0dc9a440SJohnny Huang } 879*0dc9a440SJohnny Huang 880*0dc9a440SJohnny Huang if (j == 0) 881*0dc9a440SJohnny Huang printf("/%s\n", scu_info[i].information); 882*0dc9a440SJohnny Huang else if (j == length - 1) 883*0dc9a440SJohnny Huang printf("\\ \"\n"); 884*0dc9a440SJohnny Huang else 885*0dc9a440SJohnny Huang printf("| \"\n"); 886*0dc9a440SJohnny Huang } 887*0dc9a440SJohnny Huang } 888*0dc9a440SJohnny Huang } 889*0dc9a440SJohnny Huang 890696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 89169d5fd8fSJohnny Huang { 89279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 893a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 894a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 895a219f6deSJohnny Huang u32 mask; 896a219f6deSJohnny Huang u32 dw_offset; 897a219f6deSJohnny Huang u32 bit_offset; 898a219f6deSJohnny Huang u32 otp_value; 899a219f6deSJohnny Huang u32 otp_ignore; 900b458cd62SJohnny Huang int fail = 0; 9017adec5f6SJohnny Huang int mask_err; 902794e27ecSJohnny Huang int rid_num = 0; 90373f11549SJohnny Huang char valid_bit[20]; 904794e27ecSJohnny Huang int fz; 90566f2f8e5SJohnny Huang int i; 90673f11549SJohnny Huang int j; 90766f2f8e5SJohnny Huang 908737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 90966f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 9103cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 9117adec5f6SJohnny Huang mask_err = 0; 9123cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 9133cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 9143cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 915b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 916696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 917b458cd62SJohnny Huang 9187adec5f6SJohnny Huang if (conf_info[i].value == OTP_REG_VALID_BIT) { 9197adec5f6SJohnny Huang if (((otp_value + otp_ignore) & mask) != mask) { 920b458cd62SJohnny Huang fail = 1; 9217adec5f6SJohnny Huang mask_err = 1; 9227adec5f6SJohnny Huang } 9237adec5f6SJohnny Huang } else { 9247adec5f6SJohnny Huang if (otp_ignore == mask) { 9257adec5f6SJohnny Huang continue; 9267adec5f6SJohnny Huang } else if (otp_ignore != 0) { 9277adec5f6SJohnny Huang fail = 1; 9287adec5f6SJohnny Huang mask_err = 1; 9297adec5f6SJohnny Huang } 9307adec5f6SJohnny Huang } 931b458cd62SJohnny Huang 932a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 9333cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 9343cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 9353cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 936b458cd62SJohnny Huang continue; 937b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 938b458cd62SJohnny Huang 9393cb28812SJohnny Huang if (conf_info[i].length == 1) { 9403cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 94166f2f8e5SJohnny Huang } else { 942b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 9433cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 9443cb28812SJohnny Huang conf_info[i].bit_offset); 94566f2f8e5SJohnny Huang } 946b458cd62SJohnny Huang printf("0x%-10x", otp_value); 947b458cd62SJohnny Huang 9487adec5f6SJohnny Huang if (mask_err) { 9497adec5f6SJohnny Huang printf("Ignore, mask error\n"); 950a219f6deSJohnny Huang continue; 951a219f6deSJohnny Huang } 9523cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 953b458cd62SJohnny Huang printf("Reserved\n"); 9543cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 9553cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 956b458cd62SJohnny Huang printf("\n"); 9573cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 958b458cd62SJohnny Huang if (otp_value != 0) { 95973f11549SJohnny Huang for (j = 0; j < 7; j++) { 960a219f6deSJohnny Huang if (otp_value == (1 << j)) 96173f11549SJohnny Huang valid_bit[j * 2] = '1'; 962a219f6deSJohnny Huang else 96373f11549SJohnny Huang valid_bit[j * 2] = '0'; 96473f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 96573f11549SJohnny Huang } 96673f11549SJohnny Huang valid_bit[15] = 0; 96773f11549SJohnny Huang } else { 96873f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 969b458cd62SJohnny Huang } 9703cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 971b458cd62SJohnny Huang printf("\n"); 972b458cd62SJohnny Huang } else { 9733cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 974b458cd62SJohnny Huang } 975b458cd62SJohnny Huang } 976b458cd62SJohnny Huang 977794e27ecSJohnny Huang if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) { 978794e27ecSJohnny Huang if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) { 979794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 980794e27ecSJohnny Huang fail = 1; 981794e27ecSJohnny Huang } else { 982794e27ecSJohnny Huang fz = 0; 983794e27ecSJohnny Huang for (i = 0; i < 64; i++) { 984794e27ecSJohnny Huang if (get_dw_bit(&OTPCFG[0xa], i) == 0) { 985794e27ecSJohnny Huang if (!fz) 986794e27ecSJohnny Huang fz = 1; 987794e27ecSJohnny Huang } else { 988794e27ecSJohnny Huang rid_num++; 989794e27ecSJohnny Huang if (fz) { 990794e27ecSJohnny Huang printf("OTP revision ID is invalid.\n"); 991794e27ecSJohnny Huang fail = 1; 992794e27ecSJohnny Huang break; 993794e27ecSJohnny Huang } 994794e27ecSJohnny Huang } 995794e27ecSJohnny Huang } 996794e27ecSJohnny Huang } 997794e27ecSJohnny Huang if (fail) 998794e27ecSJohnny Huang printf("OTP revision ID\n"); 999794e27ecSJohnny Huang else 1000794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1001794e27ecSJohnny Huang otp_print_revid(&OTPCFG[0xa]); 1002794e27ecSJohnny Huang } 1003794e27ecSJohnny Huang 1004b458cd62SJohnny Huang if (fail) 1005b458cd62SJohnny Huang return OTP_FAILURE; 1006b458cd62SJohnny Huang 100766f2f8e5SJohnny Huang return OTP_SUCCESS; 100866f2f8e5SJohnny Huang } 100966f2f8e5SJohnny Huang 10102d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 101166f2f8e5SJohnny Huang { 101279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 1013a219f6deSJohnny Huang u32 OTPCFG[16]; 1014a219f6deSJohnny Huang u32 mask; 1015a219f6deSJohnny Huang u32 dw_offset; 1016a219f6deSJohnny Huang u32 bit_offset; 1017a219f6deSJohnny Huang u32 otp_value; 101873f11549SJohnny Huang char valid_bit[20]; 101966f2f8e5SJohnny Huang int i; 102073f11549SJohnny Huang int j; 102166f2f8e5SJohnny Huang 1022dacbba92SJohnny Huang otp_soak(0); 1023bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 1024f347c284SJohnny Huang otp_read_conf(i, &OTPCFG[i]); 102566f2f8e5SJohnny Huang 1026b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 1027b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 10283cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 10293cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 10302d4b0742SJohnny Huang continue; 10313cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 10323cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 10333cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 1034b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 1035b458cd62SJohnny Huang 1036a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 10373cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 10383cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 10393cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 1040b458cd62SJohnny Huang continue; 1041b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 1042b458cd62SJohnny Huang 10433cb28812SJohnny Huang if (conf_info[i].length == 1) { 10443cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 1045b458cd62SJohnny Huang } else { 1046b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 10473cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 10483cb28812SJohnny Huang conf_info[i].bit_offset); 1049b458cd62SJohnny Huang } 1050b458cd62SJohnny Huang printf("0x%-10x", otp_value); 1051b458cd62SJohnny Huang 10523cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 1053b458cd62SJohnny Huang printf("Reserved\n"); 10543cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 10553cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 1056b458cd62SJohnny Huang printf("\n"); 10573cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 1058b458cd62SJohnny Huang if (otp_value != 0) { 105973f11549SJohnny Huang for (j = 0; j < 7; j++) { 1060a219f6deSJohnny Huang if (otp_value == (1 << j)) 106173f11549SJohnny Huang valid_bit[j * 2] = '1'; 1062a219f6deSJohnny Huang else 106373f11549SJohnny Huang valid_bit[j * 2] = '0'; 106473f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 106573f11549SJohnny Huang } 106673f11549SJohnny Huang valid_bit[15] = 0; 106773f11549SJohnny Huang } else { 106873f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 1069b458cd62SJohnny Huang } 10703cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 1071b458cd62SJohnny Huang printf("\n"); 1072b458cd62SJohnny Huang } else { 10733cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 1074b458cd62SJohnny Huang } 1075b458cd62SJohnny Huang } 1076b458cd62SJohnny Huang return OTP_SUCCESS; 107766f2f8e5SJohnny Huang } 107866f2f8e5SJohnny Huang 10795010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 108076d13988SJohnny Huang { 108179e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 1082a219f6deSJohnny Huang u32 *OTPSTRAP; 1083a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 1084a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 108576d13988SJohnny Huang int i; 1086a8bd6d8cSJohnny Huang int fail = 0; 1087a219f6deSJohnny Huang u32 bit_offset; 1088a219f6deSJohnny Huang u32 dw_offset; 1089a219f6deSJohnny Huang u32 mask; 1090a219f6deSJohnny Huang u32 otp_value; 1091a219f6deSJohnny Huang u32 otp_protect; 1092a219f6deSJohnny Huang u32 otp_ignore; 109376d13988SJohnny Huang 1094a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 1095a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 1096a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 10977e523e3bSJohnny Huang 1098a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 1099de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 1100b458cd62SJohnny Huang 11013cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 11027adec5f6SJohnny Huang fail = 0; 1103696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 1104a8bd6d8cSJohnny Huang dw_offset = 1; 11053cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 1106a8bd6d8cSJohnny Huang } else { 1107a8bd6d8cSJohnny Huang dw_offset = 0; 11083cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 1109a8bd6d8cSJohnny Huang } 111076d13988SJohnny Huang 11113cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 1112a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 1113a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 1114696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 1115a8bd6d8cSJohnny Huang 1116a219f6deSJohnny Huang if (otp_ignore == mask) 1117a8bd6d8cSJohnny Huang continue; 1118a219f6deSJohnny Huang else if (otp_ignore != 0) 1119a8bd6d8cSJohnny Huang fail = 1; 1120a8bd6d8cSJohnny Huang 1121a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 11223cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1123a8bd6d8cSJohnny Huang continue; 1124a8bd6d8cSJohnny Huang 11253cb28812SJohnny Huang if (strap_info[i].length == 1) { 11263cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1127a8bd6d8cSJohnny Huang } else { 1128b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 11293cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 11303cb28812SJohnny Huang strap_info[i].bit_offset); 1131a8bd6d8cSJohnny Huang } 1132a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 1133a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 1134a8bd6d8cSJohnny Huang 1135a8bd6d8cSJohnny Huang if (fail) { 1136696656c6SJohnny Huang printf("Ignore mask error\n"); 1137a8bd6d8cSJohnny Huang } else { 11383cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 11393cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1140a8bd6d8cSJohnny Huang else 1141a8bd6d8cSJohnny Huang printf("Reserved\n"); 1142a8bd6d8cSJohnny Huang } 1143a8bd6d8cSJohnny Huang } 1144a8bd6d8cSJohnny Huang 1145a8bd6d8cSJohnny Huang if (fail) 114676d13988SJohnny Huang return OTP_FAILURE; 114776d13988SJohnny Huang 114876d13988SJohnny Huang return OTP_SUCCESS; 114976d13988SJohnny Huang } 115076d13988SJohnny Huang 1151b458cd62SJohnny Huang static int otp_print_strap_info(int view) 115276d13988SJohnny Huang { 115379e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 115476d13988SJohnny Huang struct otpstrap_status strap_status[64]; 115507baa4e8SJohnny Huang int i, j; 1156b458cd62SJohnny Huang int fail = 0; 1157a219f6deSJohnny Huang u32 bit_offset; 1158a219f6deSJohnny Huang u32 length; 1159a219f6deSJohnny Huang u32 otp_value; 1160a219f6deSJohnny Huang u32 otp_protect; 116176d13988SJohnny Huang 1162541eb887SJohnny Huang otp_strap_status(strap_status); 116376d13988SJohnny Huang 1164b458cd62SJohnny Huang if (view) { 116507baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 116607baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 1167b458cd62SJohnny Huang } else { 1168b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 1169b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 117076d13988SJohnny Huang } 11713cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 1172b458cd62SJohnny Huang otp_value = 0; 11733cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 11743cb28812SJohnny Huang length = strap_info[i].length; 1175b458cd62SJohnny Huang for (j = 0; j < length; j++) { 1176c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 1177c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 1178b458cd62SJohnny Huang } 1179a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 11803cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 1181b458cd62SJohnny Huang continue; 1182b458cd62SJohnny Huang if (view) { 1183b458cd62SJohnny Huang for (j = 0; j < length; j++) { 11843cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 1185b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 118607baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 1187e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 11883cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 1189b458cd62SJohnny Huang printf(" Reserved\n"); 1190b458cd62SJohnny Huang continue; 1191b458cd62SJohnny Huang } 1192b458cd62SJohnny Huang if (length == 1) { 11933cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 1194b458cd62SJohnny Huang continue; 119576d13988SJohnny Huang } 119676d13988SJohnny Huang 1197b458cd62SJohnny Huang if (j == 0) 11983cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 1199b458cd62SJohnny Huang else if (j == length - 1) 1200b458cd62SJohnny Huang printf("\\ \"\n"); 1201b458cd62SJohnny Huang else 1202b458cd62SJohnny Huang printf("| \"\n"); 120376d13988SJohnny Huang } 1204b458cd62SJohnny Huang } else { 1205c947ef08SJohnny Huang if (length == 1) { 12063cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 1207b458cd62SJohnny Huang } else { 1208b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 1209b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 1210b458cd62SJohnny Huang } 1211b458cd62SJohnny Huang 1212b458cd62SJohnny Huang printf("0x%-10X", otp_value); 1213b458cd62SJohnny Huang 12143cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 12153cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 1216b458cd62SJohnny Huang else 1217b458cd62SJohnny Huang printf("Reserved\n"); 1218b458cd62SJohnny Huang } 1219b458cd62SJohnny Huang } 1220b458cd62SJohnny Huang 1221b458cd62SJohnny Huang if (fail) 1222b458cd62SJohnny Huang return OTP_FAILURE; 1223b458cd62SJohnny Huang 1224b458cd62SJohnny Huang return OTP_SUCCESS; 1225b458cd62SJohnny Huang } 1226b458cd62SJohnny Huang 1227f347c284SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout) 122869d5fd8fSJohnny Huang { 122969d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 123079e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 12319a4fe690SJohnny Huang struct otpkey_type key_info; 1232a219f6deSJohnny Huang u32 *buf; 1233a219f6deSJohnny Huang u8 *byte_buf; 12349d998018SJohnny Huang char empty = 1; 123569d5fd8fSJohnny Huang int i = 0, len = 0; 12369a4fe690SJohnny Huang int j; 123754552c69SJohnny Huang 1238696656c6SJohnny Huang byte_buf = image_layout->data; 1239a219f6deSJohnny Huang buf = (u32 *)byte_buf; 12409d998018SJohnny Huang 12419d998018SJohnny Huang for (i = 0; i < 16; i++) { 1242a219f6deSJohnny Huang if (buf[i] != 0) 12439d998018SJohnny Huang empty = 0; 12449d998018SJohnny Huang } 12459d998018SJohnny Huang if (empty) 1246f347c284SJohnny Huang return OTP_SUCCESS; 12479d998018SJohnny Huang 12489d998018SJohnny Huang i = 0; 124969d5fd8fSJohnny Huang while (1) { 125069d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 125169d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 125269d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 125369d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 125469d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 125569d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 12569a4fe690SJohnny Huang 12579a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 12589a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 12599a4fe690SJohnny Huang key_info = key_info_array[j]; 12609a4fe690SJohnny Huang break; 12619a4fe690SJohnny Huang } 12629a4fe690SJohnny Huang } 12639a4fe690SJohnny Huang 12647f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 126569d5fd8fSJohnny Huang printf("Key Type: "); 12669a4fe690SJohnny Huang printf("%s\n", key_info.information); 12679a4fe690SJohnny Huang 12689a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 126969d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 127069d5fd8fSJohnny Huang switch (key_length) { 127169d5fd8fSJohnny Huang case 0: 127269d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 127369d5fd8fSJohnny Huang break; 127469d5fd8fSJohnny Huang case 1: 127569d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 127669d5fd8fSJohnny Huang break; 127769d5fd8fSJohnny Huang case 2: 127869d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 127969d5fd8fSJohnny Huang break; 128069d5fd8fSJohnny Huang case 3: 128169d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 128269d5fd8fSJohnny Huang break; 128369d5fd8fSJohnny Huang } 1284181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1285181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 128669d5fd8fSJohnny Huang printf("RSA SHA Type: "); 128769d5fd8fSJohnny Huang switch (key_length) { 128869d5fd8fSJohnny Huang case 0: 128969d5fd8fSJohnny Huang printf("RSA1024\n"); 129069d5fd8fSJohnny Huang len = 0x100; 129169d5fd8fSJohnny Huang break; 129269d5fd8fSJohnny Huang case 1: 129369d5fd8fSJohnny Huang printf("RSA2048\n"); 129469d5fd8fSJohnny Huang len = 0x200; 129569d5fd8fSJohnny Huang break; 129669d5fd8fSJohnny Huang case 2: 129769d5fd8fSJohnny Huang printf("RSA3072\n"); 129869d5fd8fSJohnny Huang len = 0x300; 129969d5fd8fSJohnny Huang break; 130069d5fd8fSJohnny Huang case 3: 130169d5fd8fSJohnny Huang printf("RSA4096\n"); 130269d5fd8fSJohnny Huang len = 0x400; 130369d5fd8fSJohnny Huang break; 130469d5fd8fSJohnny Huang } 130569d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 130669d5fd8fSJohnny Huang } 13079a4fe690SJohnny Huang if (key_info.need_id) 130869d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 130969d5fd8fSJohnny Huang printf("Key Value:\n"); 13109a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 131169d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 13129a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 13139a4fe690SJohnny Huang printf("AES Key:\n"); 13149a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 1315e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 13169a4fe690SJohnny Huang printf("AES IV:\n"); 13179a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 13189a4fe690SJohnny Huang } 13199a4fe690SJohnny Huang 13209a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 1321e417205bSJohnny Huang if (info_cb.version == OTP_A0) { 132269d5fd8fSJohnny Huang printf("AES Key:\n"); 132369d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 132469d5fd8fSJohnny Huang printf("AES IV:\n"); 132569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 13265fdde29fSJohnny Huang } else { 13279a4fe690SJohnny Huang printf("AES Key 1:\n"); 13289a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 13299a4fe690SJohnny Huang printf("AES Key 2:\n"); 13309a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 13319a4fe690SJohnny Huang } 1332181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 133369d5fd8fSJohnny Huang printf("RSA mod:\n"); 133469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 133569d5fd8fSJohnny Huang printf("RSA exp:\n"); 133669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1337181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1338181f72d8SJohnny Huang printf("RSA mod:\n"); 1339181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1340181f72d8SJohnny Huang printf("RSA exp:\n"); 1341a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 134269d5fd8fSJohnny Huang } 134369d5fd8fSJohnny Huang if (last) 134469d5fd8fSJohnny Huang break; 134569d5fd8fSJohnny Huang i++; 134669d5fd8fSJohnny Huang } 1347f347c284SJohnny Huang return OTP_SUCCESS; 1348f347c284SJohnny Huang } 1349f347c284SJohnny Huang 1350f347c284SJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout) 1351f347c284SJohnny Huang { 1352f347c284SJohnny Huang int i; 1353f347c284SJohnny Huang u32 *strap; 1354f347c284SJohnny Huang u32 *strap_ignore; 1355f347c284SJohnny Huang u32 *strap_pro; 13567e523e3bSJohnny Huang int bit, pbit, ibit; 1357f347c284SJohnny Huang int fail = 0; 1358f347c284SJohnny Huang int ret; 1359f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 1360f347c284SJohnny Huang 1361f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1362f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1363f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1364f347c284SJohnny Huang 1365f347c284SJohnny Huang otp_strap_status(otpstrap); 1366f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1367f347c284SJohnny Huang if (i < 32) { 1368f347c284SJohnny Huang bit = (strap[0] >> i) & 0x1; 1369f347c284SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 1370f347c284SJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 1371f347c284SJohnny Huang } else { 1372f347c284SJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1373f347c284SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 1374f347c284SJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 1375f347c284SJohnny Huang } 1376f347c284SJohnny Huang 13777e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit); 1378f347c284SJohnny Huang 1379f347c284SJohnny Huang if (ret == OTP_FAILURE) 1380f347c284SJohnny Huang fail = 1; 1381f347c284SJohnny Huang } 1382f347c284SJohnny Huang if (fail == 1) 1383f347c284SJohnny Huang return OTP_FAILURE; 1384f347c284SJohnny Huang else 1385f347c284SJohnny Huang return OTP_SUCCESS; 1386f347c284SJohnny Huang } 1387f347c284SJohnny Huang 1388f347c284SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout) 1389f347c284SJohnny Huang { 1390f347c284SJohnny Huang int i; 1391f347c284SJohnny Huang int ret; 1392f347c284SJohnny Huang int data_dw; 1393f347c284SJohnny Huang u32 data[2048]; 1394f347c284SJohnny Huang u32 *buf; 1395f347c284SJohnny Huang u32 *buf_ignore; 1396f347c284SJohnny Huang u32 data_masked; 1397f347c284SJohnny Huang u32 buf_masked; 1398f347c284SJohnny Huang 1399f347c284SJohnny Huang buf = (u32 *)image_layout->data; 1400f347c284SJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 1401f347c284SJohnny Huang 1402f347c284SJohnny Huang data_dw = image_layout->data_length / 4; 1403f347c284SJohnny Huang 1404f347c284SJohnny Huang printf("Read OTP Data:\n"); 1405f347c284SJohnny Huang 1406f347c284SJohnny Huang for (i = 0; i < data_dw - 2 ; i += 2) 1407f347c284SJohnny Huang otp_read_data(i, &data[i]); 1408f347c284SJohnny Huang 1409f347c284SJohnny Huang printf("Check writable...\n"); 1410f347c284SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 1411f347c284SJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1412f347c284SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1413f347c284SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 1414f347c284SJohnny Huang if (data_masked == buf_masked) 1415f347c284SJohnny Huang continue; 1416f347c284SJohnny Huang if (i % 2 == 0) { 1417f347c284SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1418f347c284SJohnny Huang continue; 1419f347c284SJohnny Huang } else { 1420f347c284SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1421f347c284SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1422f347c284SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1423f347c284SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 1424f347c284SJohnny Huang return OTP_FAILURE; 1425f347c284SJohnny Huang } 1426f347c284SJohnny Huang } else { 1427f347c284SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1428f347c284SJohnny Huang continue; 1429f347c284SJohnny Huang } else { 1430f347c284SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1431f347c284SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1432f347c284SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1433f347c284SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 1434f347c284SJohnny Huang return OTP_FAILURE; 1435f347c284SJohnny Huang } 1436f347c284SJohnny Huang } 1437f347c284SJohnny Huang } 1438f347c284SJohnny Huang 1439f347c284SJohnny Huang printf("Start Programing...\n"); 1440f347c284SJohnny Huang 1441f347c284SJohnny Huang // programing ecc region first 1442f347c284SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1443f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1444f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1445f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1446f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1447f347c284SJohnny Huang return ret; 1448f347c284SJohnny Huang } 1449f347c284SJohnny Huang } 1450f347c284SJohnny Huang 1451f347c284SJohnny Huang for (i = 0; i < 1792; i += 2) { 1452f347c284SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 1453f347c284SJohnny Huang if (ret != OTP_SUCCESS) { 1454f347c284SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1455f347c284SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 1456f347c284SJohnny Huang return ret; 1457f347c284SJohnny Huang } 1458f347c284SJohnny Huang } 1459f347c284SJohnny Huang otp_soak(0); 1460f347c284SJohnny Huang return OTP_SUCCESS; 1461f347c284SJohnny Huang } 1462f347c284SJohnny Huang 1463f347c284SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout) 1464f347c284SJohnny Huang { 1465f347c284SJohnny Huang u32 *strap; 1466f347c284SJohnny Huang u32 *strap_ignore; 1467f347c284SJohnny Huang u32 *strap_pro; 1468f347c284SJohnny Huang u32 prog_address; 1469f347c284SJohnny Huang int i; 14707e523e3bSJohnny Huang int bit, pbit, ibit, offset; 1471f347c284SJohnny Huang int fail = 0; 1472f347c284SJohnny Huang int ret; 1473f347c284SJohnny Huang int prog_flag = 0; 1474f347c284SJohnny Huang struct otpstrap_status otpstrap[64]; 1475f347c284SJohnny Huang 1476f347c284SJohnny Huang strap = (u32 *)image_layout->strap; 1477f347c284SJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1478f347c284SJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1479f347c284SJohnny Huang 1480f347c284SJohnny Huang printf("Read OTP Strap Region:\n"); 1481f347c284SJohnny Huang otp_strap_status(otpstrap); 1482f347c284SJohnny Huang 1483f347c284SJohnny Huang printf("Check writable...\n"); 1484f347c284SJohnny Huang if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) { 1485f347c284SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1486f347c284SJohnny Huang return OTP_FAILURE; 1487f347c284SJohnny Huang } 1488f347c284SJohnny Huang 1489f347c284SJohnny Huang for (i = 0; i < 64; i++) { 1490f347c284SJohnny Huang prog_address = 0x800; 1491f347c284SJohnny Huang if (i < 32) { 1492f347c284SJohnny Huang offset = i; 1493f347c284SJohnny Huang bit = (strap[0] >> offset) & 0x1; 1494f347c284SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 1495f347c284SJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 1496f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 1497f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 1498f347c284SJohnny Huang 1499f347c284SJohnny Huang } else { 1500f347c284SJohnny Huang offset = (i - 32); 1501f347c284SJohnny Huang bit = (strap[1] >> offset) & 0x1; 1502f347c284SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 1503f347c284SJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 1504f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 1505f347c284SJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 1506f347c284SJohnny Huang } 1507f347c284SJohnny Huang 1508f347c284SJohnny Huang if (ibit == 1) 1509f347c284SJohnny Huang continue; 1510f347c284SJohnny Huang if (bit == otpstrap[i].value) 1511f347c284SJohnny Huang prog_flag = 0; 1512f347c284SJohnny Huang else 1513f347c284SJohnny Huang prog_flag = 1; 1514f347c284SJohnny Huang 1515f347c284SJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 1516f347c284SJohnny Huang fail = 1; 1517f347c284SJohnny Huang continue; 1518f347c284SJohnny Huang } 1519f347c284SJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 1520f347c284SJohnny Huang fail = 1; 1521f347c284SJohnny Huang continue; 1522f347c284SJohnny Huang } 1523f347c284SJohnny Huang 1524f347c284SJohnny Huang if (prog_flag) { 1525f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1526f347c284SJohnny Huang if (ret) 1527f347c284SJohnny Huang return OTP_FAILURE; 1528f347c284SJohnny Huang } 1529f347c284SJohnny Huang 1530f347c284SJohnny Huang if (pbit != 0) { 1531f347c284SJohnny Huang prog_address = 0x800; 1532f347c284SJohnny Huang if (i < 32) 1533f347c284SJohnny Huang prog_address |= 0x60c; 1534f347c284SJohnny Huang else 1535f347c284SJohnny Huang prog_address |= 0x60e; 1536f347c284SJohnny Huang 1537f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, offset); 1538f347c284SJohnny Huang if (ret) 1539f347c284SJohnny Huang return OTP_FAILURE; 1540f347c284SJohnny Huang } 1541f347c284SJohnny Huang } 1542f347c284SJohnny Huang otp_soak(0); 1543f347c284SJohnny Huang if (fail == 1) 1544f347c284SJohnny Huang return OTP_FAILURE; 1545f347c284SJohnny Huang return OTP_SUCCESS; 154669d5fd8fSJohnny Huang } 154769d5fd8fSJohnny Huang 15485010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout) 154969d5fd8fSJohnny Huang { 1550a6d0d645SJohnny Huang int i, k; 1551d90825e2SJohnny Huang int pass = 0; 1552a219f6deSJohnny Huang u32 prog_address; 1553a219f6deSJohnny Huang u32 data[16]; 1554a219f6deSJohnny Huang u32 compare[2]; 1555a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1556a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1557a219f6deSJohnny Huang u32 data_masked; 1558a219f6deSJohnny Huang u32 buf_masked; 155969d5fd8fSJohnny Huang 1560a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 1561a6d0d645SJohnny Huang 1562bb34a7bfSJohnny Huang for (i = 0; i < 16 ; i++) { 156369d5fd8fSJohnny Huang prog_address = 0x800; 1564a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1565a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1566a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 1567a6d0d645SJohnny Huang } 1568a6d0d645SJohnny Huang 1569a6d0d645SJohnny Huang printf("Check writable...\n"); 1570bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 15715010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 15725010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1573d90825e2SJohnny Huang if (data_masked == buf_masked) 157469d5fd8fSJohnny Huang continue; 1575d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1576a6d0d645SJohnny Huang continue; 1577a6d0d645SJohnny Huang } else { 1578a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1579a6af4a17SJohnny Huang printf("OTPCFG[%X] = %x\n", i, data[i]); 15805010032bSJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 15815010032bSJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 15822a856b9aSJohnny Huang return OTP_FAILURE; 1583a6d0d645SJohnny Huang } 1584a6d0d645SJohnny Huang } 1585a6d0d645SJohnny Huang 1586a6d0d645SJohnny Huang printf("Start Programing...\n"); 1587d90825e2SJohnny Huang otp_soak(0); 1588bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 15895010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 15905010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1591a6d0d645SJohnny Huang prog_address = 0x800; 1592a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1593a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1594bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1595bb34a7bfSJohnny Huang pass = 1; 1596a6d0d645SJohnny Huang continue; 1597bb34a7bfSJohnny Huang } 1598de6fbf1cSJohnny Huang 1599de6fbf1cSJohnny Huang otp_soak(1); 16005010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1601a6d0d645SJohnny Huang 160269d5fd8fSJohnny Huang pass = 0; 160369d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 16045010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1605de6fbf1cSJohnny Huang otp_soak(2); 1606feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 16075010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1608de6fbf1cSJohnny Huang otp_soak(1); 1609de6fbf1cSJohnny Huang } else { 1610de6fbf1cSJohnny Huang pass = 1; 1611de6fbf1cSJohnny Huang break; 1612de6fbf1cSJohnny Huang } 1613a6d0d645SJohnny Huang } else { 161469d5fd8fSJohnny Huang pass = 1; 161569d5fd8fSJohnny Huang break; 161669d5fd8fSJohnny Huang } 161769d5fd8fSJohnny Huang } 1618bb34a7bfSJohnny Huang if (pass == 0) { 1619bb34a7bfSJohnny Huang printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n", 16205010032bSJohnny Huang i, data[i], conf[i], conf_ignore[i]); 1621bb34a7bfSJohnny Huang break; 1622bb34a7bfSJohnny Huang } 1623a6d0d645SJohnny Huang } 1624a6d0d645SJohnny Huang 1625de6fbf1cSJohnny Huang otp_soak(0); 162669d5fd8fSJohnny Huang if (!pass) 16272a856b9aSJohnny Huang return OTP_FAILURE; 1628a6d0d645SJohnny Huang 16292a856b9aSJohnny Huang return OTP_SUCCESS; 163069d5fd8fSJohnny Huang } 163169d5fd8fSJohnny Huang 1632f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf) 1633696656c6SJohnny Huang { 1634696656c6SJohnny Huang sha256_context ctx; 1635696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1636696656c6SJohnny Huang 1637696656c6SJohnny Huang sha256_starts(&ctx); 1638696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1639696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1640696656c6SJohnny Huang 1641696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1642f347c284SJohnny Huang return OTP_SUCCESS; 1643f347c284SJohnny Huang return OTP_FAILURE; 1644696656c6SJohnny Huang } 1645696656c6SJohnny Huang 1646f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm) 164769d5fd8fSJohnny Huang { 164869d5fd8fSJohnny Huang int ret; 164961a6cda7SJohnny Huang int image_soc_ver = 0; 1650696656c6SJohnny Huang struct otp_header *otp_header; 1651696656c6SJohnny Huang struct otp_image_layout image_layout; 1652696656c6SJohnny Huang int image_size; 1653a219f6deSJohnny Huang u8 *buf; 1654a219f6deSJohnny Huang u8 *checksum; 165569d5fd8fSJohnny Huang 1656696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1657696656c6SJohnny Huang if (!otp_header) { 165869d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 16592a856b9aSJohnny Huang return OTP_FAILURE; 166069d5fd8fSJohnny Huang } 1661d90825e2SJohnny Huang 1662696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1663696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1664696656c6SJohnny Huang 1665696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1666696656c6SJohnny Huang 1667696656c6SJohnny Huang if (!buf) { 1668696656c6SJohnny Huang puts("Failed to map physical memory\n"); 1669696656c6SJohnny Huang return OTP_FAILURE; 1670696656c6SJohnny Huang } 1671696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1672696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1673696656c6SJohnny Huang 1674696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1675696656c6SJohnny Huang puts("Image is invalid\n"); 1676696656c6SJohnny Huang return OTP_FAILURE; 1677696656c6SJohnny Huang } 1678696656c6SJohnny Huang 16795010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 16805010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 16815010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 16825010032bSJohnny Huang 16835010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1684696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 16855010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1686696656c6SJohnny Huang 1687696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 16885010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 16895010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 16905010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 16917e523e3bSJohnny Huang 16927e523e3bSJohnny Huang if (otp_header->soc_ver == SOC_AST2600A0) { 16937e523e3bSJohnny Huang image_soc_ver = OTP_A0; 169461a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A1) { 169561a6cda7SJohnny Huang image_soc_ver = OTP_A1; 169661a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A2) { 169761a6cda7SJohnny Huang image_soc_ver = OTP_A2; 169861a6cda7SJohnny Huang } else if (otp_header->soc_ver == SOC_AST2600A3) { 169961a6cda7SJohnny Huang image_soc_ver = OTP_A3; 1700696656c6SJohnny Huang } else { 170161a6cda7SJohnny Huang puts("Image SOC Version is not supported\n"); 1702696656c6SJohnny Huang return OTP_FAILURE; 1703696656c6SJohnny Huang } 1704696656c6SJohnny Huang 170561a6cda7SJohnny Huang if (image_soc_ver != info_cb.version) { 17069a4fe690SJohnny Huang puts("Version is not match\n"); 17079a4fe690SJohnny Huang return OTP_FAILURE; 17089a4fe690SJohnny Huang } 17099a4fe690SJohnny Huang 171061a6cda7SJohnny Huang if (otp_header->otptool_ver != OTPTOOL_VERSION(1, 0, 0)) { 171161a6cda7SJohnny Huang puts("OTP image is not generated by otptool v1.0.0\n"); 171261a6cda7SJohnny Huang return OTP_FAILURE; 171361a6cda7SJohnny Huang } 171461a6cda7SJohnny Huang 1715f347c284SJohnny Huang if (otp_verify_image(buf, image_size, checksum)) { 1716696656c6SJohnny Huang puts("checksum is invalid\n"); 1717696656c6SJohnny Huang return OTP_FAILURE; 1718d90825e2SJohnny Huang } 17197332532cSJohnny Huang 172069d5fd8fSJohnny Huang if (!nconfirm) { 1721696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 17227f795e57SJohnny Huang printf("\nOTP data region :\n"); 1723f347c284SJohnny Huang if (otp_print_data_image(&image_layout) < 0) { 172469d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 17252a856b9aSJohnny Huang return OTP_FAILURE; 172669d5fd8fSJohnny Huang } 172769d5fd8fSJohnny Huang } 1728696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 17297332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1730696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 17317332532cSJohnny Huang printf("OTP config error, please check.\n"); 17327332532cSJohnny Huang return OTP_FAILURE; 17337332532cSJohnny Huang } 17347332532cSJohnny Huang } 17357adec5f6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 17367adec5f6SJohnny Huang printf("\nOTP strap region :\n"); 17377adec5f6SJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 17387adec5f6SJohnny Huang printf("OTP strap error, please check.\n"); 17397adec5f6SJohnny Huang return OTP_FAILURE; 17407adec5f6SJohnny Huang } 17417adec5f6SJohnny Huang } 17427332532cSJohnny Huang 174369d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 174469d5fd8fSJohnny Huang if (!confirm_yesno()) { 174569d5fd8fSJohnny Huang printf(" Aborting\n"); 17462a856b9aSJohnny Huang return OTP_FAILURE; 174769d5fd8fSJohnny Huang } 174869d5fd8fSJohnny Huang } 17497332532cSJohnny Huang 17505010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 17515010032bSJohnny Huang printf("programing data region ...\n"); 17525010032bSJohnny Huang ret = otp_prog_data(&image_layout); 17535010032bSJohnny Huang if (ret != 0) { 17545010032bSJohnny Huang printf("Error\n"); 17555010032bSJohnny Huang return ret; 17565010032bSJohnny Huang } 1757a219f6deSJohnny Huang printf("Done\n"); 17585010032bSJohnny Huang } 17595010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 17605010032bSJohnny Huang printf("programing strap region ...\n"); 17615010032bSJohnny Huang ret = otp_prog_strap(&image_layout); 17625010032bSJohnny Huang if (ret != 0) { 17635010032bSJohnny Huang printf("Error\n"); 17645010032bSJohnny Huang return ret; 17655010032bSJohnny Huang } 1766a219f6deSJohnny Huang printf("Done\n"); 17675010032bSJohnny Huang } 17685010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 17695010032bSJohnny Huang printf("programing configuration region ...\n"); 17705010032bSJohnny Huang ret = otp_prog_conf(&image_layout); 17715010032bSJohnny Huang if (ret != 0) { 17725010032bSJohnny Huang printf("Error\n"); 17735010032bSJohnny Huang return ret; 17745010032bSJohnny Huang } 17755010032bSJohnny Huang printf("Done\n"); 17765010032bSJohnny Huang } 1777cd1610b4SJohnny Huang 17787332532cSJohnny Huang return OTP_SUCCESS; 17792a856b9aSJohnny Huang } 17802a856b9aSJohnny Huang 1781f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1782cd1610b4SJohnny Huang { 1783a219f6deSJohnny Huang u32 read[2]; 1784a219f6deSJohnny Huang u32 prog_address = 0; 178566f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 1786cd1610b4SJohnny Huang int otp_bit; 178783655e91SJohnny Huang int ret = 0; 1788cd1610b4SJohnny Huang 1789dacbba92SJohnny Huang otp_soak(0); 1790cd1610b4SJohnny Huang switch (mode) { 1791a6d0d645SJohnny Huang case OTP_REGION_CONF: 1792f347c284SJohnny Huang otp_read_conf(otp_dw_offset, read); 1793cd1610b4SJohnny Huang prog_address = 0x800; 1794cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1795cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1796a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1797cd1610b4SJohnny Huang if (otp_bit == value) { 1798a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1799cd1610b4SJohnny Huang printf("No need to program\n"); 18002a856b9aSJohnny Huang return OTP_SUCCESS; 1801cd1610b4SJohnny Huang } 1802cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1803a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset); 1804*0dc9a440SJohnny Huang printf("OTP is programmed, which can't be clean\n"); 18052a856b9aSJohnny Huang return OTP_FAILURE; 1806cd1610b4SJohnny Huang } 1807a6af4a17SJohnny Huang printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset); 1808cd1610b4SJohnny Huang break; 1809a6d0d645SJohnny Huang case OTP_REGION_DATA: 1810cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1811cd1610b4SJohnny Huang 1812cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1813a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 1814a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1815643b9cfdSJohnny Huang 1816643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 1817643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1818*0dc9a440SJohnny Huang printf("OTP is programmed, which can't be cleaned\n"); 1819643b9cfdSJohnny Huang return OTP_FAILURE; 1820643b9cfdSJohnny Huang } 1821cd1610b4SJohnny Huang } else { 1822a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 1823a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 1824643b9cfdSJohnny Huang 1825643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 1826643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1827*0dc9a440SJohnny Huang printf("OTP is programmed, which can't be writen\n"); 1828643b9cfdSJohnny Huang return OTP_FAILURE; 1829643b9cfdSJohnny Huang } 1830cd1610b4SJohnny Huang } 1831cd1610b4SJohnny Huang if (otp_bit == value) { 1832a6af4a17SJohnny Huang printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1833cd1610b4SJohnny Huang printf("No need to program\n"); 18342a856b9aSJohnny Huang return OTP_SUCCESS; 1835cd1610b4SJohnny Huang } 1836643b9cfdSJohnny Huang 1837a6af4a17SJohnny Huang printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset); 1838cd1610b4SJohnny Huang break; 1839a6d0d645SJohnny Huang case OTP_REGION_STRAP: 18408848d5dcSJohnny Huang otp_strap_status(otpstrap); 18418848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 18427e523e3bSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0); 18438848d5dcSJohnny Huang if (ret == OTP_FAILURE) 18448848d5dcSJohnny Huang return OTP_FAILURE; 18458848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 18468848d5dcSJohnny Huang return OTP_SUCCESS; 1847a6af4a17SJohnny Huang 1848cd1610b4SJohnny Huang break; 1849cd1610b4SJohnny Huang } 1850cd1610b4SJohnny Huang 1851cd1610b4SJohnny Huang if (!nconfirm) { 1852cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1853cd1610b4SJohnny Huang if (!confirm_yesno()) { 1854cd1610b4SJohnny Huang printf(" Aborting\n"); 18552a856b9aSJohnny Huang return OTP_FAILURE; 1856cd1610b4SJohnny Huang } 1857cd1610b4SJohnny Huang } 1858cd1610b4SJohnny Huang 1859cd1610b4SJohnny Huang switch (mode) { 1860a6d0d645SJohnny Huang case OTP_REGION_STRAP: 1861f347c284SJohnny Huang ret = otp_prog_strap_b(bit_offset, value); 186283655e91SJohnny Huang break; 1863a6d0d645SJohnny Huang case OTP_REGION_CONF: 1864a6d0d645SJohnny Huang case OTP_REGION_DATA: 1865f347c284SJohnny Huang ret = otp_prog_dc_b(value, prog_address, bit_offset); 1866de6fbf1cSJohnny Huang break; 1867de6fbf1cSJohnny Huang } 1868de6fbf1cSJohnny Huang otp_soak(0); 186983655e91SJohnny Huang if (ret) { 1870*0dc9a440SJohnny Huang printf("OTP cannot be programmed\n"); 1871794e27ecSJohnny Huang printf("FAILURE\n"); 1872794e27ecSJohnny Huang return OTP_FAILURE; 1873794e27ecSJohnny Huang } 1874794e27ecSJohnny Huang 18759009c25dSJohnny Huang printf("SUCCESS\n"); 18762a856b9aSJohnny Huang return OTP_SUCCESS; 1877a219f6deSJohnny Huang } 1878a219f6deSJohnny Huang 1879794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force) 1880794e27ecSJohnny Huang { 1881794e27ecSJohnny Huang u32 otp_rid[2]; 1882a8789b47SJohnny Huang u32 sw_rid[2]; 1883794e27ecSJohnny Huang int rid_num = 0; 1884a8789b47SJohnny Huang int sw_rid_num = 0; 1885794e27ecSJohnny Huang int bit_offset; 1886794e27ecSJohnny Huang int dw_offset; 1887794e27ecSJohnny Huang int i; 1888794e27ecSJohnny Huang int ret; 1889794e27ecSJohnny Huang 1890f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 1891f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 1892794e27ecSJohnny Huang 1893a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 1894a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 1895a8789b47SJohnny Huang 1896794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 1897a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 1898a8789b47SJohnny Huang 1899a8789b47SJohnny Huang if (sw_rid_num < 0) { 1900a8789b47SJohnny Huang printf("SW revision id is invalid, please check.\n"); 1901a8789b47SJohnny Huang return OTP_FAILURE; 1902a8789b47SJohnny Huang } 1903a8789b47SJohnny Huang 1904a8789b47SJohnny Huang if (update_num > sw_rid_num) { 1905a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 1906a8789b47SJohnny Huang printf("update number could not bigger than current SW revision id\n"); 1907a8789b47SJohnny Huang return OTP_FAILURE; 1908a8789b47SJohnny Huang } 1909794e27ecSJohnny Huang 1910794e27ecSJohnny Huang if (rid_num < 0) { 1911794e27ecSJohnny Huang printf("Currennt OTP revision ID cannot handle by this command,\n" 1912794e27ecSJohnny Huang "plase use 'otp pb' command to update it manually\n"); 1913794e27ecSJohnny Huang otp_print_revid(otp_rid); 19149009c25dSJohnny Huang return OTP_FAILURE; 19159009c25dSJohnny Huang } 1916cd1610b4SJohnny Huang 1917794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 1918794e27ecSJohnny Huang otp_print_revid(otp_rid); 1919794e27ecSJohnny Huang printf("input update number: 0x%x\n", update_num); 1920794e27ecSJohnny Huang 1921a8789b47SJohnny Huang if (rid_num > update_num) { 1922a8789b47SJohnny Huang printf("OTP rev_id is bigger than 0x%X\n", update_num); 1923a8789b47SJohnny Huang printf("Skip\n"); 1924a8789b47SJohnny Huang return OTP_FAILURE; 1925a8789b47SJohnny Huang } else if (rid_num == update_num) { 1926a8789b47SJohnny Huang printf("OTP rev_id is same as input\n"); 1927794e27ecSJohnny Huang printf("Skip\n"); 1928794e27ecSJohnny Huang return OTP_FAILURE; 1929794e27ecSJohnny Huang } 1930794e27ecSJohnny Huang 1931794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 1932794e27ecSJohnny Huang if (i < 32) { 1933794e27ecSJohnny Huang dw_offset = 0xa; 1934794e27ecSJohnny Huang bit_offset = i; 1935794e27ecSJohnny Huang } else { 1936794e27ecSJohnny Huang dw_offset = 0xb; 1937794e27ecSJohnny Huang bit_offset = i - 32; 1938794e27ecSJohnny Huang } 1939*0dc9a440SJohnny Huang printf("OTPCFG%X[%X]", dw_offset, bit_offset); 1940794e27ecSJohnny Huang if (i + 1 != update_num) 1941794e27ecSJohnny Huang printf(", "); 1942794e27ecSJohnny Huang } 1943794e27ecSJohnny Huang 1944794e27ecSJohnny Huang printf(" will be programmed\n"); 1945794e27ecSJohnny Huang if (force == 0) { 1946794e27ecSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1947794e27ecSJohnny Huang if (!confirm_yesno()) { 1948794e27ecSJohnny Huang printf(" Aborting\n"); 1949794e27ecSJohnny Huang return OTP_FAILURE; 1950794e27ecSJohnny Huang } 1951794e27ecSJohnny Huang } 1952794e27ecSJohnny Huang 1953794e27ecSJohnny Huang ret = 0; 1954794e27ecSJohnny Huang for (i = rid_num; i < update_num; i++) { 1955794e27ecSJohnny Huang if (i < 32) { 1956794e27ecSJohnny Huang dw_offset = 0xa04; 1957794e27ecSJohnny Huang bit_offset = i; 1958794e27ecSJohnny Huang } else { 1959794e27ecSJohnny Huang dw_offset = 0xa06; 1960794e27ecSJohnny Huang bit_offset = i - 32; 1961794e27ecSJohnny Huang } 1962f347c284SJohnny Huang if (otp_prog_dc_b(1, dw_offset, bit_offset)) { 1963*0dc9a440SJohnny Huang printf("OTPCFG%X[%X] programming failed\n", dw_offset, bit_offset); 1964794e27ecSJohnny Huang ret = OTP_FAILURE; 1965794e27ecSJohnny Huang break; 1966794e27ecSJohnny Huang } 1967794e27ecSJohnny Huang } 1968794e27ecSJohnny Huang 1969f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 1970f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 1971794e27ecSJohnny Huang rid_num = get_rid_num(otp_rid); 1972794e27ecSJohnny Huang if (rid_num >= 0) 1973794e27ecSJohnny Huang printf("OTP revision ID: 0x%x\n", rid_num); 1974794e27ecSJohnny Huang else 1975794e27ecSJohnny Huang printf("OTP revision ID\n"); 1976794e27ecSJohnny Huang otp_print_revid(otp_rid); 1977794e27ecSJohnny Huang if (!ret) 1978794e27ecSJohnny Huang printf("SUCCESS\n"); 1979794e27ecSJohnny Huang else 1980794e27ecSJohnny Huang printf("FAILED\n"); 1981794e27ecSJohnny Huang return ret; 1982794e27ecSJohnny Huang } 1983794e27ecSJohnny Huang 19842a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 198569d5fd8fSJohnny Huang { 1986a219f6deSJohnny Huang u32 offset, count; 19872a856b9aSJohnny Huang int ret; 198869d5fd8fSJohnny Huang 19892a856b9aSJohnny Huang if (argc == 4) { 19902a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 19912a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 19922a856b9aSJohnny Huang } else if (argc == 3) { 19932a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 19942a856b9aSJohnny Huang count = 1; 19952a856b9aSJohnny Huang } else { 199669d5fd8fSJohnny Huang return CMD_RET_USAGE; 199769d5fd8fSJohnny Huang } 199869d5fd8fSJohnny Huang 19992a856b9aSJohnny Huang if (!strcmp(argv[1], "conf")) { 20003d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2001f347c284SJohnny Huang ret = otp_print_conf(offset, count); 20022a856b9aSJohnny Huang } else if (!strcmp(argv[1], "data")) { 20033d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 20042a856b9aSJohnny Huang ret = otp_print_data(offset, count); 20052a856b9aSJohnny Huang } else if (!strcmp(argv[1], "strap")) { 20063d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 20072a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 20082a856b9aSJohnny Huang } else { 20092a856b9aSJohnny Huang return CMD_RET_USAGE; 201069d5fd8fSJohnny Huang } 201169d5fd8fSJohnny Huang 20122a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 20132a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20142a856b9aSJohnny Huang return CMD_RET_USAGE; 20152a856b9aSJohnny Huang } 20162a856b9aSJohnny Huang 20172a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20182a856b9aSJohnny Huang { 20192a856b9aSJohnny Huang phys_addr_t addr; 20202a856b9aSJohnny Huang int ret; 20212a856b9aSJohnny Huang 2022de6b0cc4SJohnny Huang if (argc == 3) { 2023ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 20242a856b9aSJohnny Huang return CMD_RET_USAGE; 20252a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 20263d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2027f347c284SJohnny Huang ret = otp_prog_image(addr, 1); 2028de6b0cc4SJohnny Huang } else if (argc == 2) { 20292a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 20303d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2031f347c284SJohnny Huang ret = otp_prog_image(addr, 0); 20322a856b9aSJohnny Huang } else { 20332a856b9aSJohnny Huang return CMD_RET_USAGE; 20342a856b9aSJohnny Huang } 20352a856b9aSJohnny Huang 20362a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 20372a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20382a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 20392a856b9aSJohnny Huang return CMD_RET_FAILURE; 20402a856b9aSJohnny Huang else 20412a856b9aSJohnny Huang return CMD_RET_USAGE; 20422a856b9aSJohnny Huang } 20432a856b9aSJohnny Huang 20442a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20452a856b9aSJohnny Huang { 20462a856b9aSJohnny Huang int mode = 0; 20472a856b9aSJohnny Huang int nconfirm = 0; 20482a856b9aSJohnny Huang int otp_addr = 0; 20492a856b9aSJohnny Huang int bit_offset; 20502a856b9aSJohnny Huang int value; 20512a856b9aSJohnny Huang int ret; 20522a856b9aSJohnny Huang 20532a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 20542a856b9aSJohnny Huang return CMD_RET_USAGE; 20552a856b9aSJohnny Huang 20562a856b9aSJohnny Huang /* Drop the pb cmd */ 20572a856b9aSJohnny Huang argc--; 20582a856b9aSJohnny Huang argv++; 20592a856b9aSJohnny Huang 20602a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 2061a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 20622a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 2063a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 20642a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 2065a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 2066cd1610b4SJohnny Huang else 20672a856b9aSJohnny Huang return CMD_RET_USAGE; 20682a856b9aSJohnny Huang 20692a856b9aSJohnny Huang /* Drop the region cmd */ 20702a856b9aSJohnny Huang argc--; 20712a856b9aSJohnny Huang argv++; 20722a856b9aSJohnny Huang 2073ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 2074cd1610b4SJohnny Huang nconfirm = 1; 20752a856b9aSJohnny Huang /* Drop the force option */ 20762a856b9aSJohnny Huang argc--; 20772a856b9aSJohnny Huang argv++; 20782a856b9aSJohnny Huang } 2079cd1610b4SJohnny Huang 2080a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 20812a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 20822a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 20830808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 20842a856b9aSJohnny Huang return CMD_RET_USAGE; 2085cd1610b4SJohnny Huang } else { 20862a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 20872a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 20882a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 20890808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 20902a856b9aSJohnny Huang return CMD_RET_USAGE; 20910808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 209278855207SJohnny Huang if (otp_addr >= 0x800) 20930808cc55SJohnny Huang return CMD_RET_USAGE; 20940808cc55SJohnny Huang } else { 209578855207SJohnny Huang if (otp_addr >= 0x20) 20960808cc55SJohnny Huang return CMD_RET_USAGE; 20970808cc55SJohnny Huang } 2098cd1610b4SJohnny Huang } 2099cd1610b4SJohnny Huang if (value != 0 && value != 1) 21002a856b9aSJohnny Huang return CMD_RET_USAGE; 2101cd1610b4SJohnny Huang 21023d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2103f347c284SJohnny Huang ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 21042a856b9aSJohnny Huang 21052a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 21062a856b9aSJohnny Huang return CMD_RET_SUCCESS; 21072a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 21082a856b9aSJohnny Huang return CMD_RET_FAILURE; 21092a856b9aSJohnny Huang else 21102a856b9aSJohnny Huang return CMD_RET_USAGE; 21112a856b9aSJohnny Huang } 21122a856b9aSJohnny Huang 21132a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 21142a856b9aSJohnny Huang { 21152a856b9aSJohnny Huang phys_addr_t addr; 21162a856b9aSJohnny Huang int otp_addr = 0; 21172a856b9aSJohnny Huang 21182a856b9aSJohnny Huang if (argc != 3) 21192a856b9aSJohnny Huang return CMD_RET_USAGE; 21202a856b9aSJohnny Huang 21213d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 21222a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 21232a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 21242a856b9aSJohnny Huang if (otp_compare(otp_addr, addr) == 0) { 212569d5fd8fSJohnny Huang printf("Compare pass\n"); 21262a856b9aSJohnny Huang return CMD_RET_SUCCESS; 2127a219f6deSJohnny Huang } 212869d5fd8fSJohnny Huang printf("Compare fail\n"); 21292a856b9aSJohnny Huang return CMD_RET_FAILURE; 213069d5fd8fSJohnny Huang } 213169d5fd8fSJohnny Huang 213266f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 213366f2f8e5SJohnny Huang { 2134a8bd6d8cSJohnny Huang int view = 0; 21352d4b0742SJohnny Huang int input; 2136a8bd6d8cSJohnny Huang 2137a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 213866f2f8e5SJohnny Huang return CMD_RET_USAGE; 213966f2f8e5SJohnny Huang 21402d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 21413d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 21422d4b0742SJohnny Huang if (argc == 3) { 21432d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 21442d4b0742SJohnny Huang otp_print_conf_info(input); 21452d4b0742SJohnny Huang } else { 21462d4b0742SJohnny Huang otp_print_conf_info(-1); 21472d4b0742SJohnny Huang } 21482d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 21492d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 2150a8bd6d8cSJohnny Huang view = 1; 2151a8bd6d8cSJohnny Huang /* Drop the view option */ 2152a8bd6d8cSJohnny Huang argc--; 2153a8bd6d8cSJohnny Huang argv++; 2154a8bd6d8cSJohnny Huang } 21553d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2156b458cd62SJohnny Huang otp_print_strap_info(view); 2157*0dc9a440SJohnny Huang } else if (!strcmp(argv[1], "scu")) { 2158*0dc9a440SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2159*0dc9a440SJohnny Huang otp_print_scu_info(); 216066f2f8e5SJohnny Huang } else { 216166f2f8e5SJohnny Huang return CMD_RET_USAGE; 216266f2f8e5SJohnny Huang } 21632d4b0742SJohnny Huang 216466f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 216566f2f8e5SJohnny Huang } 216666f2f8e5SJohnny Huang 2167*0dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2168737ed20bSJohnny Huang { 2169*0dc9a440SJohnny Huang u32 input; 2170*0dc9a440SJohnny Huang u32 bit_offset; 2171e14b073cSJohnny Huang u32 prog_address; 217283655e91SJohnny Huang int ret; 2173a219f6deSJohnny Huang 2174737ed20bSJohnny Huang if (argc != 3 && argc != 2) 2175737ed20bSJohnny Huang return CMD_RET_USAGE; 2176737ed20bSJohnny Huang 2177e14b073cSJohnny Huang if (!strcmp(argv[1], "o")) { 2178737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 2179737ed20bSJohnny Huang } else { 2180737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 2181*0dc9a440SJohnny Huang printf("OTPSTRAP[%X] will be protected\n", input); 2182737ed20bSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2183737ed20bSJohnny Huang if (!confirm_yesno()) { 2184737ed20bSJohnny Huang printf(" Aborting\n"); 2185737ed20bSJohnny Huang return CMD_RET_FAILURE; 2186737ed20bSJohnny Huang } 2187737ed20bSJohnny Huang } 2188737ed20bSJohnny Huang 2189737ed20bSJohnny Huang if (input < 32) { 2190737ed20bSJohnny Huang bit_offset = input; 2191*0dc9a440SJohnny Huang prog_address = 0xe0c; 2192737ed20bSJohnny Huang } else if (input < 64) { 2193737ed20bSJohnny Huang bit_offset = input - 32; 2194*0dc9a440SJohnny Huang prog_address = 0xe0e; 2195737ed20bSJohnny Huang } else { 2196737ed20bSJohnny Huang return CMD_RET_USAGE; 2197737ed20bSJohnny Huang } 2198737ed20bSJohnny Huang 2199e14b073cSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2200e14b073cSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2201*0dc9a440SJohnny Huang printf("OTPSTRAP[%X] already protected\n", input); 2202e14b073cSJohnny Huang return CMD_RET_SUCCESS; 2203e14b073cSJohnny Huang } 2204de6fbf1cSJohnny Huang 2205f347c284SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 2206de6fbf1cSJohnny Huang otp_soak(0); 220783655e91SJohnny Huang 220883655e91SJohnny Huang if (ret) { 2209*0dc9a440SJohnny Huang printf("Protect OTPSTRAP[%X] fail\n", input); 2210737ed20bSJohnny Huang return CMD_RET_FAILURE; 2211737ed20bSJohnny Huang } 22129a4fe690SJohnny Huang 2213*0dc9a440SJohnny Huang printf("OTPSTRAP[%X] is protected\n", input); 2214794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2215794e27ecSJohnny Huang } 2216794e27ecSJohnny Huang 2217*0dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2218e14b073cSJohnny Huang { 2219*0dc9a440SJohnny Huang u32 scu_offset; 2220*0dc9a440SJohnny Huang u32 bit_offset; 2221*0dc9a440SJohnny Huang u32 conf_offset; 2222*0dc9a440SJohnny Huang u32 prog_address; 2223*0dc9a440SJohnny Huang char force; 2224*0dc9a440SJohnny Huang int ret; 2225*0dc9a440SJohnny Huang 2226*0dc9a440SJohnny Huang if (argc != 4 && argc != 3) 2227*0dc9a440SJohnny Huang return CMD_RET_USAGE; 2228*0dc9a440SJohnny Huang 2229*0dc9a440SJohnny Huang if (!strcmp(argv[1], "o")) { 2230*0dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[2], NULL, 16); 2231*0dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[3], NULL, 16); 2232*0dc9a440SJohnny Huang force = 1; 2233*0dc9a440SJohnny Huang } else { 2234*0dc9a440SJohnny Huang scu_offset = simple_strtoul(argv[1], NULL, 16); 2235*0dc9a440SJohnny Huang bit_offset = simple_strtoul(argv[2], NULL, 16); 2236*0dc9a440SJohnny Huang force = 0; 2237*0dc9a440SJohnny Huang } 2238*0dc9a440SJohnny Huang if (scu_offset == 0x500) { 2239*0dc9a440SJohnny Huang prog_address = 0xe08; 2240*0dc9a440SJohnny Huang conf_offset = 28; 2241*0dc9a440SJohnny Huang } else if (scu_offset == 0x510) { 2242*0dc9a440SJohnny Huang prog_address = 0xe0a; 2243*0dc9a440SJohnny Huang conf_offset = 29; 2244*0dc9a440SJohnny Huang } else { 2245*0dc9a440SJohnny Huang return CMD_RET_USAGE; 2246*0dc9a440SJohnny Huang } 2247*0dc9a440SJohnny Huang if (bit_offset < 0 || bit_offset > 31) 2248*0dc9a440SJohnny Huang return CMD_RET_USAGE; 2249*0dc9a440SJohnny Huang 2250*0dc9a440SJohnny Huang if (!force) { 2251*0dc9a440SJohnny Huang printf("OTPCONF%X[%X] will be programmed\n", conf_offset, bit_offset); 2252*0dc9a440SJohnny Huang printf("SCU%X[%X] will be protected\n", scu_offset, bit_offset); 2253*0dc9a440SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 2254*0dc9a440SJohnny Huang if (!confirm_yesno()) { 2255*0dc9a440SJohnny Huang printf(" Aborting\n"); 2256*0dc9a440SJohnny Huang return CMD_RET_FAILURE; 2257*0dc9a440SJohnny Huang } 2258e14b073cSJohnny Huang } 2259e14b073cSJohnny Huang 2260*0dc9a440SJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2261*0dc9a440SJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2262*0dc9a440SJohnny Huang printf("OTPCONF%X[%X] already programmed\n", conf_offset, bit_offset); 2263*0dc9a440SJohnny Huang return CMD_RET_SUCCESS; 2264*0dc9a440SJohnny Huang } 2265*0dc9a440SJohnny Huang 2266*0dc9a440SJohnny Huang ret = otp_prog_dc_b(1, prog_address, bit_offset); 2267*0dc9a440SJohnny Huang otp_soak(0); 2268*0dc9a440SJohnny Huang writel(1, OTP_PROTECT_KEY); // controller protect 2269*0dc9a440SJohnny Huang 2270*0dc9a440SJohnny Huang if (ret) { 2271*0dc9a440SJohnny Huang printf("Program OTPCONF%X[%X] fail\n", conf_offset, bit_offset); 2272*0dc9a440SJohnny Huang return CMD_RET_FAILURE; 2273*0dc9a440SJohnny Huang } 2274*0dc9a440SJohnny Huang 2275*0dc9a440SJohnny Huang printf("OTPCONF%X[%X] programmed success\n", conf_offset, bit_offset); 2276*0dc9a440SJohnny Huang return CMD_RET_SUCCESS; 2277e14b073cSJohnny Huang } 2278e14b073cSJohnny Huang 2279f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2280f67375f7SJohnny Huang { 2281e417205bSJohnny Huang printf("SOC OTP version: %s\n", info_cb.ver_name); 2282f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2283f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2284f67375f7SJohnny Huang 2285f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2286f67375f7SJohnny Huang } 2287f67375f7SJohnny Huang 2288794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2289794e27ecSJohnny Huang { 2290794e27ecSJohnny Huang u32 update_num; 2291794e27ecSJohnny Huang int force = 0; 2292794e27ecSJohnny Huang int ret; 2293794e27ecSJohnny Huang 2294794e27ecSJohnny Huang if (argc == 3) { 2295794e27ecSJohnny Huang if (strcmp(argv[1], "o")) 2296794e27ecSJohnny Huang return CMD_RET_USAGE; 2297794e27ecSJohnny Huang force = 1; 2298794e27ecSJohnny Huang update_num = simple_strtoul(argv[2], NULL, 16); 2299794e27ecSJohnny Huang } else if (argc == 2) { 2300794e27ecSJohnny Huang update_num = simple_strtoul(argv[1], NULL, 16); 2301794e27ecSJohnny Huang } else { 2302794e27ecSJohnny Huang return CMD_RET_USAGE; 2303794e27ecSJohnny Huang } 2304794e27ecSJohnny Huang 2305794e27ecSJohnny Huang if (update_num > 64) 2306794e27ecSJohnny Huang return CMD_RET_USAGE; 2307794e27ecSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2308794e27ecSJohnny Huang ret = otp_update_rid(update_num, force); 2309794e27ecSJohnny Huang if (ret) 2310794e27ecSJohnny Huang return CMD_RET_FAILURE; 2311794e27ecSJohnny Huang return CMD_RET_SUCCESS; 2312794e27ecSJohnny Huang } 2313794e27ecSJohnny Huang 2314794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2315794e27ecSJohnny Huang { 2316794e27ecSJohnny Huang u32 otp_rid[2]; 2317a8789b47SJohnny Huang u32 sw_rid[2]; 2318794e27ecSJohnny Huang int rid_num = 0; 2319a8789b47SJohnny Huang int sw_rid_num = 0; 2320794e27ecSJohnny Huang int ret; 2321794e27ecSJohnny Huang 2322794e27ecSJohnny Huang if (argc != 1) 2323794e27ecSJohnny Huang return CMD_RET_USAGE; 2324794e27ecSJohnny Huang 2325794e27ecSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 2326f347c284SJohnny Huang otp_read_conf(10, &otp_rid[0]); 2327f347c284SJohnny Huang otp_read_conf(11, &otp_rid[1]); 2328794e27ecSJohnny Huang 2329a8789b47SJohnny Huang sw_rid[0] = readl(SW_REV_ID0); 2330a8789b47SJohnny Huang sw_rid[1] = readl(SW_REV_ID1); 2331794e27ecSJohnny Huang 2332a8789b47SJohnny Huang rid_num = get_rid_num(otp_rid); 2333a8789b47SJohnny Huang sw_rid_num = get_rid_num(sw_rid); 2334a8789b47SJohnny Huang 2335a8789b47SJohnny Huang printf("current SW revision ID: 0x%x\n", sw_rid_num); 2336794e27ecSJohnny Huang if (rid_num >= 0) { 2337794e27ecSJohnny Huang printf("current OTP revision ID: 0x%x\n", rid_num); 2338794e27ecSJohnny Huang ret = CMD_RET_SUCCESS; 2339794e27ecSJohnny Huang } else { 2340794e27ecSJohnny Huang printf("Currennt OTP revision ID cannot handle by 'otp update',\n" 2341794e27ecSJohnny Huang "plase use 'otp pb' command to update it manually\n" 2342794e27ecSJohnny Huang "current OTP revision ID\n"); 2343794e27ecSJohnny Huang ret = CMD_RET_FAILURE; 2344794e27ecSJohnny Huang } 2345794e27ecSJohnny Huang otp_print_revid(otp_rid); 2346794e27ecSJohnny Huang 2347794e27ecSJohnny Huang return ret; 2348794e27ecSJohnny Huang } 2349794e27ecSJohnny Huang 23502a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2351f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 23522a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2353a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2354de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 23552a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2356737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 2357*0dc9a440SJohnny Huang U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""), 23582a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 2359794e27ecSJohnny Huang U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""), 2360794e27ecSJohnny Huang U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""), 23612a856b9aSJohnny Huang }; 23622a856b9aSJohnny Huang 23632a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 23642a856b9aSJohnny Huang { 23652a856b9aSJohnny Huang cmd_tbl_t *cp; 2366a219f6deSJohnny Huang u32 ver; 2367e14b073cSJohnny Huang int ret; 23682a856b9aSJohnny Huang 23692a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 23702a856b9aSJohnny Huang 2371737ed20bSJohnny Huang /* Drop the otp command */ 23722a856b9aSJohnny Huang argc--; 23732a856b9aSJohnny Huang argv++; 23742a856b9aSJohnny Huang 2375a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 23762a856b9aSJohnny Huang return CMD_RET_USAGE; 23772a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 23782a856b9aSJohnny Huang return CMD_RET_SUCCESS; 23792a856b9aSJohnny Huang 23800dae9d52SJohnny Huang ver = chip_version(); 23810dae9d52SJohnny Huang switch (ver) { 2382e417205bSJohnny Huang case OTP_A0: 2383e417205bSJohnny Huang info_cb.version = OTP_A0; 23849a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 23859a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 23869a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 23879a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 23889a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 23899a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 2390e417205bSJohnny Huang sprintf(info_cb.ver_name, "A0"); 23910dae9d52SJohnny Huang break; 2392e417205bSJohnny Huang case OTP_A1: 2393e417205bSJohnny Huang info_cb.version = OTP_A1; 23943cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 23953cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 23963cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 23973cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 23989a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 23999a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 2400*0dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 2401*0dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2402e417205bSJohnny Huang sprintf(info_cb.ver_name, "A1"); 24030dae9d52SJohnny Huang break; 2404e417205bSJohnny Huang case OTP_A2: 2405e417205bSJohnny Huang info_cb.version = OTP_A2; 24065fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 24075fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 2408fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2409fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 24105fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 24115fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 2412*0dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 2413*0dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2414e417205bSJohnny Huang sprintf(info_cb.ver_name, "A2"); 24150dae9d52SJohnny Huang break; 2416e417205bSJohnny Huang case OTP_A3: 2417e417205bSJohnny Huang info_cb.version = OTP_A3; 2418b63af886SJohnny Huang info_cb.conf_info = a3_conf_info; 2419b63af886SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info); 2420fed30023SJohnny Huang info_cb.strap_info = a1_strap_info; 2421fed30023SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 2422181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2423181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 2424*0dc9a440SJohnny Huang info_cb.scu_info = a1_scu_info; 2425*0dc9a440SJohnny Huang info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info); 2426e417205bSJohnny Huang sprintf(info_cb.ver_name, "A3"); 242764b66712SJohnny Huang break; 24280dae9d52SJohnny Huang default: 2429f1be5099SJohnny Huang printf("SOC is not supported\n"); 24300dae9d52SJohnny Huang return CMD_RET_FAILURE; 24319a4fe690SJohnny Huang } 24329a4fe690SJohnny Huang 2433e14b073cSJohnny Huang ret = cp->cmd(cmdtp, flag, argc, argv); 2434e14b073cSJohnny Huang writel(1, OTP_PROTECT_KEY); //password 2435e14b073cSJohnny Huang 2436e14b073cSJohnny Huang return ret; 243769d5fd8fSJohnny Huang } 243869d5fd8fSJohnny Huang 2439a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 244069d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2441f67375f7SJohnny Huang "version\n" 2442f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 24432a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 24442d4b0742SJohnny Huang "otp info strap [v]\n" 24452d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 2446*0dc9a440SJohnny Huang "otp info scu\n" 2447de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2448ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2449ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2450ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 2451*0dc9a440SJohnny Huang "otp scuprotect [o] <scu_offset> <bit_offset>\n" 2452794e27ecSJohnny Huang "otp update [o] <revision_id>\n" 2453794e27ecSJohnny Huang "otp rid\n" 245469d5fd8fSJohnny Huang ); 2455