1*a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+ 269d5fd8fSJohnny Huang /* 3*a219f6deSJohnny Huang * Copyright 2021 Aspeed Technology Inc. 469d5fd8fSJohnny Huang */ 54c1c9b35SJohnny Huang #include <stdlib.h> 669d5fd8fSJohnny Huang #include <common.h> 769d5fd8fSJohnny Huang #include <console.h> 869d5fd8fSJohnny Huang #include <bootretry.h> 969d5fd8fSJohnny Huang #include <cli.h> 1069d5fd8fSJohnny Huang #include <command.h> 1169d5fd8fSJohnny Huang #include <console.h> 124c1c9b35SJohnny Huang #include <malloc.h> 1369d5fd8fSJohnny Huang #include <inttypes.h> 1469d5fd8fSJohnny Huang #include <mapmem.h> 1569d5fd8fSJohnny Huang #include <asm/io.h> 1669d5fd8fSJohnny Huang #include <linux/compiler.h> 17696656c6SJohnny Huang #include <u-boot/sha256.h> 180cee9a95SJohnny Huang #include "otp_info.h" 1969d5fd8fSJohnny Huang 2069d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2169d5fd8fSJohnny Huang 2264b66712SJohnny Huang #define OTP_VER "1.0.3" 23f67375f7SJohnny Huang 2469d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 25dacbba92SJohnny Huang #define RETRY 20 267332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 277332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 287332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 2969d5fd8fSJohnny Huang 302a856b9aSJohnny Huang #define OTP_USAGE -1 312a856b9aSJohnny Huang #define OTP_FAILURE -2 322a856b9aSJohnny Huang #define OTP_SUCCESS 0 332a856b9aSJohnny Huang 34a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 35a6af4a17SJohnny Huang 36181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB 1 37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV 2 38181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES 3 39181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT 4 40181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC 5 419a4fe690SJohnny Huang 424c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 434c1c9b35SJohnny Huang #define PBWIDTH 60 444c1c9b35SJohnny Huang 453d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 463d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 473d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 483d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 493d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 503d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 513d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 523d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 533d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 543d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 553d3688adSJohnny Huang 56696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 57696656c6SJohnny Huang #define CHECKSUM_LEN 32 58*a219f6deSJohnny Huang #define OTP_INC_DATA BIT(31) 59*a219f6deSJohnny Huang #define OTP_INC_CONFIG BIT(30) 60*a219f6deSJohnny Huang #define OTP_INC_STRAP BIT(29) 61*a219f6deSJohnny Huang #define OTP_ECC_EN BIT(28) 62696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 63696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 64696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 65696656c6SJohnny Huang 66696656c6SJohnny Huang #define OTP_AST2600A0 0 67696656c6SJohnny Huang #define OTP_AST2600A1 1 680dae9d52SJohnny Huang #define OTP_AST2600A2 2 6964b66712SJohnny Huang #define OTP_AST2600A3 3 70696656c6SJohnny Huang 71696656c6SJohnny Huang struct otp_header { 72696656c6SJohnny Huang u8 otp_magic[8]; 73696656c6SJohnny Huang u8 otp_version[8]; 74696656c6SJohnny Huang u32 image_info; 75696656c6SJohnny Huang u32 data_info; 76696656c6SJohnny Huang u32 config_info; 77696656c6SJohnny Huang u32 strap_info; 78696656c6SJohnny Huang u32 checksum_offset; 79*a219f6deSJohnny Huang } __packed; 80696656c6SJohnny Huang 8166f2f8e5SJohnny Huang struct otpstrap_status { 8269d5fd8fSJohnny Huang int value; 8369d5fd8fSJohnny Huang int option_array[7]; 8469d5fd8fSJohnny Huang int remain_times; 8569d5fd8fSJohnny Huang int writeable_option; 865010032bSJohnny Huang int reg_protected; 8769d5fd8fSJohnny Huang int protected; 8869d5fd8fSJohnny Huang }; 8969d5fd8fSJohnny Huang 9066f2f8e5SJohnny Huang struct otpconf_parse { 9166f2f8e5SJohnny Huang int dw_offset; 9266f2f8e5SJohnny Huang int bit; 9366f2f8e5SJohnny Huang int length; 9466f2f8e5SJohnny Huang int value; 95696656c6SJohnny Huang int ignore; 9666f2f8e5SJohnny Huang char status[80]; 9766f2f8e5SJohnny Huang }; 9866f2f8e5SJohnny Huang 999a4fe690SJohnny Huang struct otpkey_type { 1009a4fe690SJohnny Huang int value; 1019a4fe690SJohnny Huang int key_type; 1029a4fe690SJohnny Huang int need_id; 1039a4fe690SJohnny Huang char information[110]; 1049a4fe690SJohnny Huang }; 1059a4fe690SJohnny Huang 1069a4fe690SJohnny Huang struct otp_info_cb { 1079a4fe690SJohnny Huang int version; 10879e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1099a4fe690SJohnny Huang int strap_info_len; 11079e42a59SJoel Stanley const struct otpconf_info *conf_info; 1119a4fe690SJohnny Huang int conf_info_len; 11279e42a59SJoel Stanley const struct otpkey_type *key_info; 1139a4fe690SJohnny Huang int key_info_len; 1145010032bSJohnny Huang 1159a4fe690SJohnny Huang }; 1169a4fe690SJohnny Huang 117696656c6SJohnny Huang struct otp_image_layout { 1185010032bSJohnny Huang int data_length; 1195010032bSJohnny Huang int conf_length; 1205010032bSJohnny Huang int strap_length; 121*a219f6deSJohnny Huang u8 *data; 122*a219f6deSJohnny Huang u8 *data_ignore; 123*a219f6deSJohnny Huang u8 *conf; 124*a219f6deSJohnny Huang u8 *conf_ignore; 125*a219f6deSJohnny Huang u8 *strap; 126*a219f6deSJohnny Huang u8 *strap_reg_pro; 127*a219f6deSJohnny Huang u8 *strap_pro; 128*a219f6deSJohnny Huang u8 *strap_ignore; 129696656c6SJohnny Huang }; 130696656c6SJohnny Huang 1319a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1329a4fe690SJohnny Huang 13379e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1349a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1359a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1369a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 137181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 138181f72d8SJohnny Huang {9, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as SOC public key"}, 139181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 140181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as SOC private key"}, 141181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1429a4fe690SJohnny Huang }; 1439a4fe690SJohnny Huang 14479e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1459a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1469a4fe690SJohnny 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"}, 147181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 148181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 149181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 1509a4fe690SJohnny Huang }; 1519a4fe690SJohnny Huang 1525fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1535fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1545fdde29fSJohnny 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"}, 155181f72d8SJohnny Huang {8, OTP_KEY_TYPE_RSA_PUB, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 156181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 157181f72d8SJohnny Huang {14, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 158181f72d8SJohnny Huang }; 159181f72d8SJohnny Huang 160181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = { 161181f72d8SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 162181f72d8SJohnny 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"}, 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, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"}, 165181f72d8SJohnny Huang {10, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key"}, 166181f72d8SJohnny Huang {11, OTP_KEY_TYPE_RSA_PUB, 0, "RSA-public as AES key decryption key(big endian)"}, 167181f72d8SJohnny Huang {12, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key"}, 168181f72d8SJohnny Huang {13, OTP_KEY_TYPE_RSA_PRIV, 0, "RSA-private as AES key decryption key(big endian)"}, 1695fdde29fSJohnny Huang }; 1705fdde29fSJohnny Huang 171*a219f6deSJohnny Huang static u32 chip_version(void) 1729a4fe690SJohnny Huang { 173badd21c2SJohnny Huang u64 rev_id; 1749a4fe690SJohnny Huang 175badd21c2SJohnny Huang rev_id = readl(ASPEED_REVISION_ID0); 176badd21c2SJohnny Huang rev_id = ((u64)readl(ASPEED_REVISION_ID1) << 32) | rev_id; 1779a4fe690SJohnny Huang 178badd21c2SJohnny Huang if (rev_id == 0x0500030305000303) { 179badd21c2SJohnny Huang /* AST2600-A0 */ 1800dae9d52SJohnny Huang return OTP_AST2600A0; 181badd21c2SJohnny Huang } else if (rev_id == 0x0501030305010303) { 182badd21c2SJohnny Huang /* AST2600-A1 */ 1830dae9d52SJohnny Huang return OTP_AST2600A1; 184badd21c2SJohnny Huang } else if (rev_id == 0x0501020305010203) { 185badd21c2SJohnny Huang /* AST2620-A1 */ 186badd21c2SJohnny Huang return OTP_AST2600A1; 187badd21c2SJohnny Huang } else if (rev_id == 0x0502030305010303) { 188badd21c2SJohnny Huang /* AST2600-A2 */ 1890dae9d52SJohnny Huang return OTP_AST2600A2; 190badd21c2SJohnny Huang } else if (rev_id == 0x0502020305010203) { 191badd21c2SJohnny Huang /* AST2620-A2 */ 192badd21c2SJohnny Huang return OTP_AST2600A2; 193badd21c2SJohnny Huang } else if (rev_id == 0x0502010305010103) { 194badd21c2SJohnny Huang /* AST2605-A2 */ 1950dae9d52SJohnny Huang return OTP_AST2600A2; 19664b66712SJohnny Huang } else if (rev_id == 0x0503030305030303) { 19764b66712SJohnny Huang /* AST2600-A3 */ 19864b66712SJohnny Huang return OTP_AST2600A3; 19964b66712SJohnny Huang } else if (rev_id == 0x0503020305030203) { 20064b66712SJohnny Huang /* AST2620-A3 */ 20164b66712SJohnny Huang return OTP_AST2600A3; 2020dae9d52SJohnny Huang } 2030dae9d52SJohnny Huang 2045fdde29fSJohnny Huang return -1; 2059a4fe690SJohnny Huang } 2069a4fe690SJohnny Huang 2073d3688adSJohnny Huang static void wait_complete(void) 2083d3688adSJohnny Huang { 2093d3688adSJohnny Huang int reg; 2103d3688adSJohnny Huang 2113d3688adSJohnny Huang do { 2123d3688adSJohnny Huang reg = readl(OTP_STATUS); 2133d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 2143d3688adSJohnny Huang } 2153d3688adSJohnny Huang 216*a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data) 217dacbba92SJohnny Huang { 218dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 219dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 220dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 221dacbba92SJohnny Huang wait_complete(); 222dacbba92SJohnny Huang } 223dacbba92SJohnny Huang 224dacbba92SJohnny Huang static void otp_soak(int soak) 225dacbba92SJohnny Huang { 22664b66712SJohnny Huang if (info_cb.version == OTP_AST2600A2 || info_cb.version == OTP_AST2600A3) { 227dacbba92SJohnny Huang switch (soak) { 228dacbba92SJohnny Huang case 0: //default 229dacbba92SJohnny Huang otp_write(0x3000, 0x0210); // Write MRA 230dacbba92SJohnny Huang otp_write(0x5000, 0x2000); // Write MRB 231dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 232dacbba92SJohnny Huang break; 233dacbba92SJohnny Huang case 1: //normal program 234dacbba92SJohnny Huang otp_write(0x3000, 0x1200); // Write MRA 235feea3fdfSJohnny Huang otp_write(0x5000, 0x107F); // Write MRB 236dacbba92SJohnny Huang otp_write(0x1000, 0x1024); // Write MR 237feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 238dacbba92SJohnny Huang break; 239dacbba92SJohnny Huang case 2: //soak program 240dacbba92SJohnny Huang otp_write(0x3000, 0x1220); // Write MRA 241feea3fdfSJohnny Huang otp_write(0x5000, 0x2074); // Write MRB 242dacbba92SJohnny Huang otp_write(0x1000, 0x08a4); // Write MR 243feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 244dacbba92SJohnny Huang break; 245dacbba92SJohnny Huang } 246dacbba92SJohnny Huang } else { 247dacbba92SJohnny Huang switch (soak) { 248dacbba92SJohnny Huang case 0: //default 249dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 250dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 251dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 252dacbba92SJohnny Huang break; 253dacbba92SJohnny Huang case 1: //normal program 254dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 255dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 256dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 257feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 258dacbba92SJohnny Huang break; 259dacbba92SJohnny Huang case 2: //soak program 260dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 261dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 262dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 263feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 264dacbba92SJohnny Huang break; 265dacbba92SJohnny Huang } 266dacbba92SJohnny Huang } 267dacbba92SJohnny Huang 268dacbba92SJohnny Huang wait_complete(); 269dacbba92SJohnny Huang } 270dacbba92SJohnny Huang 271*a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data) 27269d5fd8fSJohnny Huang { 2733d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 2743d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2753d3688adSJohnny Huang wait_complete(); 2763d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 2773d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 27869d5fd8fSJohnny Huang } 27969d5fd8fSJohnny Huang 280*a219f6deSJohnny Huang static void otp_read_config(u32 offset, u32 *data) 28169d5fd8fSJohnny Huang { 28269d5fd8fSJohnny Huang int config_offset; 28369d5fd8fSJohnny Huang 28469d5fd8fSJohnny Huang config_offset = 0x800; 28569d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 28669d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 28769d5fd8fSJohnny Huang 2883d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 2893d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2903d3688adSJohnny Huang wait_complete(); 2913d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 29269d5fd8fSJohnny Huang } 29369d5fd8fSJohnny Huang 294*a219f6deSJohnny Huang static int otp_print_config(u32 offset, int dw_count) 29569d5fd8fSJohnny Huang { 29669d5fd8fSJohnny Huang int i; 297*a219f6deSJohnny Huang u32 ret[1]; 29869d5fd8fSJohnny Huang 29969d5fd8fSJohnny Huang if (offset + dw_count > 32) 3002a856b9aSJohnny Huang return OTP_USAGE; 301dacbba92SJohnny Huang otp_soak(0); 30269d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i++) { 30369d5fd8fSJohnny Huang otp_read_config(i, ret); 304a6af4a17SJohnny Huang printf("OTPCFG%X: %08X\n", i, ret[0]); 30569d5fd8fSJohnny Huang } 30669d5fd8fSJohnny Huang printf("\n"); 3072a856b9aSJohnny Huang return OTP_SUCCESS; 30869d5fd8fSJohnny Huang } 30969d5fd8fSJohnny Huang 310*a219f6deSJohnny Huang static int otp_print_data(u32 offset, int dw_count) 31169d5fd8fSJohnny Huang { 31269d5fd8fSJohnny Huang int i; 313*a219f6deSJohnny Huang u32 ret[2]; 31469d5fd8fSJohnny Huang 31569d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 3162a856b9aSJohnny Huang return OTP_USAGE; 317dacbba92SJohnny Huang otp_soak(0); 31869d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 31969d5fd8fSJohnny Huang otp_read_data(i, ret); 32069d5fd8fSJohnny Huang if (i % 4 == 0) 32169d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 32269d5fd8fSJohnny Huang else 32369d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 32469d5fd8fSJohnny Huang } 32569d5fd8fSJohnny Huang printf("\n"); 3262a856b9aSJohnny Huang return OTP_SUCCESS; 32769d5fd8fSJohnny Huang } 32869d5fd8fSJohnny Huang 329*a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr) 33069d5fd8fSJohnny Huang { 331*a219f6deSJohnny Huang u32 ret; 332*a219f6deSJohnny Huang u32 *buf; 33369d5fd8fSJohnny Huang 33469d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 33569d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 33669d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 33769d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 33869d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 3393d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 3403d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 3413d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 3423d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 3433d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 3443d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 3453d3688adSJohnny Huang wait_complete(); 3463d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 34769d5fd8fSJohnny Huang if (ret & 0x1) 34869d5fd8fSJohnny Huang return 0; 34969d5fd8fSJohnny Huang else 35069d5fd8fSJohnny Huang return -1; 35169d5fd8fSJohnny Huang } 35269d5fd8fSJohnny Huang 353*a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value) 35469d5fd8fSJohnny Huang { 355*a219f6deSJohnny Huang u32 ret[2]; 35669d5fd8fSJohnny Huang 35730a8c590SJohnny Huang if (otp_addr % 2 == 0) 3583d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 35930a8c590SJohnny Huang else 3603d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 36130a8c590SJohnny Huang 3623d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3633d3688adSJohnny Huang wait_complete(); 3643d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 3653d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 36683655e91SJohnny Huang 36730a8c590SJohnny Huang if (otp_addr % 2 == 0) { 36830a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 36969d5fd8fSJohnny Huang return 0; 37069d5fd8fSJohnny Huang else 37169d5fd8fSJohnny Huang return -1; 37230a8c590SJohnny Huang } else { 37330a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 37430a8c590SJohnny Huang return 0; 37530a8c590SJohnny Huang else 37630a8c590SJohnny Huang return -1; 37730a8c590SJohnny Huang } 37869d5fd8fSJohnny Huang } 37969d5fd8fSJohnny Huang 380*a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size) 3814c1c9b35SJohnny Huang { 382*a219f6deSJohnny Huang u32 ret[2]; 3834c1c9b35SJohnny Huang 3844c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 3854c1c9b35SJohnny Huang 3864c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 3873d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 3884c1c9b35SJohnny Huang else 3893d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 3903d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3913d3688adSJohnny Huang wait_complete(); 3923d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 3933d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 3944c1c9b35SJohnny Huang if (size == 1) { 3954c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 3964c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 397696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 3984c1c9b35SJohnny Huang compare[0] = 0; 3994c1c9b35SJohnny Huang return 0; 400*a219f6deSJohnny Huang } 4014c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4024c1c9b35SJohnny Huang return -1; 4034c1c9b35SJohnny Huang 4044c1c9b35SJohnny Huang } else { 4054c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 406696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4074c1c9b35SJohnny Huang compare[0] = ~0; 4084c1c9b35SJohnny Huang return 0; 409*a219f6deSJohnny Huang } 410d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 4114c1c9b35SJohnny Huang return -1; 4124c1c9b35SJohnny Huang } 4134c1c9b35SJohnny Huang } else if (size == 2) { 4144c1c9b35SJohnny Huang // otp_addr should be even 415696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 4164c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4174c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4184c1c9b35SJohnny Huang compare[0] = 0; 4194c1c9b35SJohnny Huang compare[1] = ~0; 4204c1c9b35SJohnny Huang return 0; 421*a219f6deSJohnny Huang } 4224c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4234c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4244c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4254c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 4264c1c9b35SJohnny Huang return -1; 4274c1c9b35SJohnny Huang } else { 4284c1c9b35SJohnny Huang return -1; 4294c1c9b35SJohnny Huang } 4304c1c9b35SJohnny Huang } 4314c1c9b35SJohnny Huang 432*a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit) 43383655e91SJohnny Huang { 43490965bb3SJohnny Huang otp_write(0x0, prog_bit); 43583655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 43683655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 43783655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 43883655e91SJohnny Huang wait_complete(); 43983655e91SJohnny Huang } 44083655e91SJohnny Huang 441*a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 44283655e91SJohnny Huang { 44383655e91SJohnny Huang int prog_bit; 44483655e91SJohnny Huang 44583655e91SJohnny Huang if (prog_address % 2 == 0) { 44683655e91SJohnny Huang if (value) 44783655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 44883655e91SJohnny Huang else 44983655e91SJohnny Huang return; 45083655e91SJohnny Huang } else { 45164b66712SJohnny Huang if (info_cb.version != OTP_AST2600A3) 45283655e91SJohnny Huang prog_address |= 1 << 15; 45383655e91SJohnny Huang if (!value) 45483655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 45583655e91SJohnny Huang else 45683655e91SJohnny Huang return; 45783655e91SJohnny Huang } 45883655e91SJohnny Huang otp_prog(prog_address, prog_bit); 45983655e91SJohnny Huang } 46083655e91SJohnny Huang 461*a219f6deSJohnny Huang static int otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset) 46283655e91SJohnny Huang { 46383655e91SJohnny Huang int pass; 46483655e91SJohnny Huang int i; 46583655e91SJohnny Huang 46683655e91SJohnny Huang otp_soak(1); 46783655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 46883655e91SJohnny Huang pass = 0; 46983655e91SJohnny Huang 47083655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 47183655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 47283655e91SJohnny Huang otp_soak(2); 47383655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 47483655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 47583655e91SJohnny Huang otp_soak(1); 47683655e91SJohnny Huang } else { 47783655e91SJohnny Huang pass = 1; 47883655e91SJohnny Huang break; 47983655e91SJohnny Huang } 48083655e91SJohnny Huang } else { 48183655e91SJohnny Huang pass = 1; 48283655e91SJohnny Huang break; 48383655e91SJohnny Huang } 48483655e91SJohnny Huang } 48583655e91SJohnny Huang 48683655e91SJohnny Huang return pass; 48783655e91SJohnny Huang } 48883655e91SJohnny Huang 489*a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address) 490d90825e2SJohnny Huang { 491d90825e2SJohnny Huang int j, bit_value, prog_bit; 492d90825e2SJohnny Huang 493d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 494696656c6SJohnny Huang if ((ignore >> j) & 0x1) 495d90825e2SJohnny Huang continue; 496d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 497d90825e2SJohnny Huang if (prog_address % 2 == 0) { 498d90825e2SJohnny Huang if (bit_value) 499d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 500d90825e2SJohnny Huang else 501d90825e2SJohnny Huang continue; 502d90825e2SJohnny Huang } else { 50364b66712SJohnny Huang if (info_cb.version != OTP_AST2600A3) 504d90825e2SJohnny Huang prog_address |= 1 << 15; 505d90825e2SJohnny Huang if (bit_value) 506d90825e2SJohnny Huang continue; 507d90825e2SJohnny Huang else 508d90825e2SJohnny Huang prog_bit = 0x1 << j; 509d90825e2SJohnny Huang } 510d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 511d90825e2SJohnny Huang } 512d90825e2SJohnny Huang } 513d90825e2SJohnny Huang 514*a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address) 51554552c69SJohnny Huang { 51654552c69SJohnny Huang int pass; 51754552c69SJohnny Huang int i; 518*a219f6deSJohnny Huang u32 data0_masked; 519*a219f6deSJohnny Huang u32 data1_masked; 520*a219f6deSJohnny Huang u32 buf0_masked; 521*a219f6deSJohnny Huang u32 buf1_masked; 522*a219f6deSJohnny Huang u32 compare[2]; 52354552c69SJohnny Huang 52454552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 52554552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 52654552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 52754552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 528*a219f6deSJohnny Huang if (data0_masked == buf0_masked && data1_masked == buf1_masked) 52954552c69SJohnny Huang return 0; 53054552c69SJohnny Huang 53154552c69SJohnny Huang otp_soak(1); 53254552c69SJohnny Huang if (data0_masked != buf0_masked) 53354552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 53454552c69SJohnny Huang if (data1_masked != buf1_masked) 53554552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 53654552c69SJohnny Huang 53754552c69SJohnny Huang pass = 0; 53854552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 53954552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 54054552c69SJohnny Huang otp_soak(2); 541*a219f6deSJohnny Huang if (compare[0] != 0) 54254552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 543*a219f6deSJohnny Huang if (compare[1] != ~0) 5445537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 54554552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 54654552c69SJohnny Huang otp_soak(1); 54754552c69SJohnny Huang } else { 54854552c69SJohnny Huang pass = 1; 54954552c69SJohnny Huang break; 55054552c69SJohnny Huang } 55154552c69SJohnny Huang } else { 55254552c69SJohnny Huang pass = 1; 55354552c69SJohnny Huang break; 55454552c69SJohnny Huang } 55554552c69SJohnny Huang } 55654552c69SJohnny Huang 55754552c69SJohnny Huang if (!pass) { 55854552c69SJohnny Huang otp_soak(0); 55954552c69SJohnny Huang return OTP_FAILURE; 56054552c69SJohnny Huang } 56154552c69SJohnny Huang return OTP_SUCCESS; 56254552c69SJohnny Huang } 56354552c69SJohnny Huang 564541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 56576d13988SJohnny Huang { 566*a219f6deSJohnny Huang u32 OTPSTRAP_RAW[2]; 5675010032bSJohnny Huang int strap_end; 56876d13988SJohnny Huang int i, j; 56976d13988SJohnny Huang 5705010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 57176d13988SJohnny Huang for (j = 0; j < 64; j++) { 57276d13988SJohnny Huang otpstrap[j].value = 0; 57376d13988SJohnny Huang otpstrap[j].remain_times = 7; 57476d13988SJohnny Huang otpstrap[j].writeable_option = -1; 57576d13988SJohnny Huang otpstrap[j].protected = 0; 57676d13988SJohnny Huang } 5775010032bSJohnny Huang strap_end = 30; 5785010032bSJohnny Huang } else { 5795010032bSJohnny Huang for (j = 0; j < 64; j++) { 5805010032bSJohnny Huang otpstrap[j].value = 0; 5815010032bSJohnny Huang otpstrap[j].remain_times = 6; 5825010032bSJohnny Huang otpstrap[j].writeable_option = -1; 5835010032bSJohnny Huang otpstrap[j].reg_protected = 0; 5845010032bSJohnny Huang otpstrap[j].protected = 0; 5855010032bSJohnny Huang } 5865010032bSJohnny Huang strap_end = 28; 5875010032bSJohnny Huang } 58876d13988SJohnny Huang 589dacbba92SJohnny Huang otp_soak(0); 5905010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 59176d13988SJohnny Huang int option = (i - 16) / 2; 592*a219f6deSJohnny Huang 59376d13988SJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 59476d13988SJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 59576d13988SJohnny Huang for (j = 0; j < 32; j++) { 59676d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 597*a219f6deSJohnny Huang 598*a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 59976d13988SJohnny Huang otpstrap[j].writeable_option = option; 60076d13988SJohnny Huang if (bit_value == 1) 60176d13988SJohnny Huang otpstrap[j].remain_times--; 60276d13988SJohnny Huang otpstrap[j].value ^= bit_value; 60376d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 60476d13988SJohnny Huang } 60576d13988SJohnny Huang for (j = 32; j < 64; j++) { 60676d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 607*a219f6deSJohnny Huang 608*a219f6deSJohnny Huang if (bit_value == 0 && otpstrap[j].writeable_option == -1) 60976d13988SJohnny Huang otpstrap[j].writeable_option = option; 61076d13988SJohnny Huang if (bit_value == 1) 61176d13988SJohnny Huang otpstrap[j].remain_times--; 61276d13988SJohnny Huang otpstrap[j].value ^= bit_value; 61376d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 61476d13988SJohnny Huang } 61576d13988SJohnny Huang } 6165010032bSJohnny Huang 6175010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 6185010032bSJohnny Huang otp_read_config(28, &OTPSTRAP_RAW[0]); 6195010032bSJohnny Huang otp_read_config(29, &OTPSTRAP_RAW[1]); 6205010032bSJohnny Huang for (j = 0; j < 32; j++) { 6215010032bSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 6225010032bSJohnny Huang otpstrap[j].reg_protected = 1; 6235010032bSJohnny Huang } 6245010032bSJohnny Huang for (j = 32; j < 64; j++) { 6255010032bSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 6265010032bSJohnny Huang otpstrap[j].reg_protected = 1; 6275010032bSJohnny Huang } 6285010032bSJohnny Huang } 6295010032bSJohnny Huang 63076d13988SJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 63176d13988SJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 63276d13988SJohnny Huang for (j = 0; j < 32; j++) { 63376d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 63476d13988SJohnny Huang otpstrap[j].protected = 1; 63576d13988SJohnny Huang } 63676d13988SJohnny Huang for (j = 32; j < 64; j++) { 63776d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 63876d13988SJohnny Huang otpstrap[j].protected = 1; 63976d13988SJohnny Huang } 64076d13988SJohnny Huang } 64176d13988SJohnny Huang 642696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 64369d5fd8fSJohnny Huang { 64479e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 645*a219f6deSJohnny Huang u32 *OTPCFG = (u32 *)image_layout->conf; 646*a219f6deSJohnny Huang u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore; 647*a219f6deSJohnny Huang u32 mask; 648*a219f6deSJohnny Huang u32 dw_offset; 649*a219f6deSJohnny Huang u32 bit_offset; 650*a219f6deSJohnny Huang u32 otp_value; 651*a219f6deSJohnny Huang u32 otp_ignore; 652b458cd62SJohnny Huang int fail = 0; 65373f11549SJohnny Huang char valid_bit[20]; 65466f2f8e5SJohnny Huang int i; 65573f11549SJohnny Huang int j; 65666f2f8e5SJohnny Huang 657737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 65866f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 6593cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 6603cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 6613cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 6623cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 663b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 664696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 665b458cd62SJohnny Huang 666*a219f6deSJohnny Huang if (otp_ignore == mask) 667b458cd62SJohnny Huang continue; 668*a219f6deSJohnny Huang else if (otp_ignore != 0) 669b458cd62SJohnny Huang fail = 1; 670b458cd62SJohnny Huang 671*a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 6723cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 6733cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 6743cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 675b458cd62SJohnny Huang continue; 676b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 677b458cd62SJohnny Huang 6783cb28812SJohnny Huang if (conf_info[i].length == 1) { 6793cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 68066f2f8e5SJohnny Huang } else { 681b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 6823cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 6833cb28812SJohnny Huang conf_info[i].bit_offset); 68466f2f8e5SJohnny Huang } 685b458cd62SJohnny Huang printf("0x%-10x", otp_value); 686b458cd62SJohnny Huang 687b458cd62SJohnny Huang if (fail) { 688696656c6SJohnny Huang printf("Ignore mask error\n"); 689*a219f6deSJohnny Huang continue; 690*a219f6deSJohnny Huang } 6913cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 692b458cd62SJohnny Huang printf("Reserved\n"); 6933cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 6943cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 695b458cd62SJohnny Huang printf("\n"); 6963cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 697b458cd62SJohnny Huang if (otp_value != 0) { 69873f11549SJohnny Huang for (j = 0; j < 7; j++) { 699*a219f6deSJohnny Huang if (otp_value == (1 << j)) 70073f11549SJohnny Huang valid_bit[j * 2] = '1'; 701*a219f6deSJohnny Huang else 70273f11549SJohnny Huang valid_bit[j * 2] = '0'; 70373f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 70473f11549SJohnny Huang } 70573f11549SJohnny Huang valid_bit[15] = 0; 70673f11549SJohnny Huang } else { 70773f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 708b458cd62SJohnny Huang } 7093cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 710b458cd62SJohnny Huang printf("\n"); 711b458cd62SJohnny Huang } else { 7123cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 713b458cd62SJohnny Huang } 714b458cd62SJohnny Huang } 715b458cd62SJohnny Huang 716b458cd62SJohnny Huang if (fail) 717b458cd62SJohnny Huang return OTP_FAILURE; 718b458cd62SJohnny Huang 71966f2f8e5SJohnny Huang return OTP_SUCCESS; 72066f2f8e5SJohnny Huang } 72166f2f8e5SJohnny Huang 7222d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 72366f2f8e5SJohnny Huang { 72479e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 725*a219f6deSJohnny Huang u32 OTPCFG[16]; 726*a219f6deSJohnny Huang u32 mask; 727*a219f6deSJohnny Huang u32 dw_offset; 728*a219f6deSJohnny Huang u32 bit_offset; 729*a219f6deSJohnny Huang u32 otp_value; 73073f11549SJohnny Huang char valid_bit[20]; 73166f2f8e5SJohnny Huang int i; 73273f11549SJohnny Huang int j; 73366f2f8e5SJohnny Huang 734dacbba92SJohnny Huang otp_soak(0); 735bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 73666f2f8e5SJohnny Huang otp_read_config(i, &OTPCFG[i]); 73766f2f8e5SJohnny Huang 738b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 739b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 7403cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 7413cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 7422d4b0742SJohnny Huang continue; 7433cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 7443cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 7453cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 746b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 747b458cd62SJohnny Huang 748*a219f6deSJohnny Huang if (otp_value != conf_info[i].value && 7493cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 7503cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 7513cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 752b458cd62SJohnny Huang continue; 753b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 754b458cd62SJohnny Huang 7553cb28812SJohnny Huang if (conf_info[i].length == 1) { 7563cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 757b458cd62SJohnny Huang } else { 758b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 7593cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 7603cb28812SJohnny Huang conf_info[i].bit_offset); 761b458cd62SJohnny Huang } 762b458cd62SJohnny Huang printf("0x%-10x", otp_value); 763b458cd62SJohnny Huang 7643cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 765b458cd62SJohnny Huang printf("Reserved\n"); 7663cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 7673cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 768b458cd62SJohnny Huang printf("\n"); 7693cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 770b458cd62SJohnny Huang if (otp_value != 0) { 77173f11549SJohnny Huang for (j = 0; j < 7; j++) { 772*a219f6deSJohnny Huang if (otp_value == (1 << j)) 77373f11549SJohnny Huang valid_bit[j * 2] = '1'; 774*a219f6deSJohnny Huang else 77573f11549SJohnny Huang valid_bit[j * 2] = '0'; 77673f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 77773f11549SJohnny Huang } 77873f11549SJohnny Huang valid_bit[15] = 0; 77973f11549SJohnny Huang } else { 78073f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 781b458cd62SJohnny Huang } 7823cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 783b458cd62SJohnny Huang printf("\n"); 784b458cd62SJohnny Huang } else { 7853cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 786b458cd62SJohnny Huang } 787b458cd62SJohnny Huang } 788b458cd62SJohnny Huang return OTP_SUCCESS; 78966f2f8e5SJohnny Huang } 79066f2f8e5SJohnny Huang 7915010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 79276d13988SJohnny Huang { 79379e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 794*a219f6deSJohnny Huang u32 *OTPSTRAP; 795*a219f6deSJohnny Huang u32 *OTPSTRAP_REG_PRO; 796*a219f6deSJohnny Huang u32 *OTPSTRAP_PRO; 797*a219f6deSJohnny Huang u32 *OTPSTRAP_IGNORE; 79876d13988SJohnny Huang int i; 799a8bd6d8cSJohnny Huang int fail = 0; 800*a219f6deSJohnny Huang u32 bit_offset; 801*a219f6deSJohnny Huang u32 dw_offset; 802*a219f6deSJohnny Huang u32 mask; 803*a219f6deSJohnny Huang u32 otp_value; 804*a219f6deSJohnny Huang u32 otp_reg_protect; 805*a219f6deSJohnny Huang u32 otp_protect; 806*a219f6deSJohnny Huang u32 otp_ignore; 80776d13988SJohnny Huang 808*a219f6deSJohnny Huang OTPSTRAP = (u32 *)image_layout->strap; 809*a219f6deSJohnny Huang OTPSTRAP_PRO = (u32 *)image_layout->strap_pro; 810*a219f6deSJohnny Huang OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore; 8115010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 812696656c6SJohnny Huang OTPSTRAP_REG_PRO = NULL; 813a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 814696656c6SJohnny Huang } else { 815*a219f6deSJohnny Huang OTPSTRAP_REG_PRO = (u32 *)image_layout->strap_reg_pro; 816de6b0cc4SJohnny Huang printf("BIT(hex) Value Reg_Protect Protect Description\n"); 817696656c6SJohnny Huang } 818de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 819b458cd62SJohnny Huang 8203cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 821696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 822a8bd6d8cSJohnny Huang dw_offset = 1; 8233cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 824a8bd6d8cSJohnny Huang } else { 825a8bd6d8cSJohnny Huang dw_offset = 0; 8263cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 827a8bd6d8cSJohnny Huang } 82876d13988SJohnny Huang 8293cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 830a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 831a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 832696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 833a8bd6d8cSJohnny Huang 8345010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 835696656c6SJohnny Huang otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask; 8365010032bSJohnny Huang else 8375010032bSJohnny Huang otp_reg_protect = 0; 838696656c6SJohnny Huang 839*a219f6deSJohnny Huang if (otp_ignore == mask) 840a8bd6d8cSJohnny Huang continue; 841*a219f6deSJohnny Huang else if (otp_ignore != 0) 842a8bd6d8cSJohnny Huang fail = 1; 843a8bd6d8cSJohnny Huang 844*a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 8453cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 846a8bd6d8cSJohnny Huang continue; 847a8bd6d8cSJohnny Huang 8483cb28812SJohnny Huang if (strap_info[i].length == 1) { 8493cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 850a8bd6d8cSJohnny Huang } else { 851b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 8523cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 8533cb28812SJohnny Huang strap_info[i].bit_offset); 854a8bd6d8cSJohnny Huang } 855a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 8565010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 857696656c6SJohnny Huang printf("0x%-10x", otp_reg_protect); 858a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 859a8bd6d8cSJohnny Huang 860a8bd6d8cSJohnny Huang if (fail) { 861696656c6SJohnny Huang printf("Ignore mask error\n"); 862a8bd6d8cSJohnny Huang } else { 8633cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 8643cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 865a8bd6d8cSJohnny Huang else 866a8bd6d8cSJohnny Huang printf("Reserved\n"); 867a8bd6d8cSJohnny Huang } 868a8bd6d8cSJohnny Huang } 869a8bd6d8cSJohnny Huang 870a8bd6d8cSJohnny Huang if (fail) 87176d13988SJohnny Huang return OTP_FAILURE; 87276d13988SJohnny Huang 87376d13988SJohnny Huang return OTP_SUCCESS; 87476d13988SJohnny Huang } 87576d13988SJohnny Huang 876b458cd62SJohnny Huang static int otp_print_strap_info(int view) 87776d13988SJohnny Huang { 87879e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 87976d13988SJohnny Huang struct otpstrap_status strap_status[64]; 88007baa4e8SJohnny Huang int i, j; 881b458cd62SJohnny Huang int fail = 0; 882*a219f6deSJohnny Huang u32 bit_offset; 883*a219f6deSJohnny Huang u32 length; 884*a219f6deSJohnny Huang u32 otp_value; 885*a219f6deSJohnny Huang u32 otp_protect; 88676d13988SJohnny Huang 887541eb887SJohnny Huang otp_strap_status(strap_status); 88876d13988SJohnny Huang 889b458cd62SJohnny Huang if (view) { 89083655e91SJohnny Huang if (info_cb.version == OTP_AST2600A0) 89107baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 89283655e91SJohnny Huang else 89383655e91SJohnny Huang printf("BIT(hex) Value Remains Reg_Protect Protect Description\n"); 89407baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 895b458cd62SJohnny Huang } else { 896b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 897b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 89876d13988SJohnny Huang } 8993cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 900b458cd62SJohnny Huang otp_value = 0; 9013cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 9023cb28812SJohnny Huang length = strap_info[i].length; 903b458cd62SJohnny Huang for (j = 0; j < length; j++) { 904c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 905c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 906b458cd62SJohnny Huang } 907*a219f6deSJohnny Huang if (otp_value != strap_info[i].value && 9083cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 909b458cd62SJohnny Huang continue; 910b458cd62SJohnny Huang if (view) { 911b458cd62SJohnny Huang for (j = 0; j < length; j++) { 9123cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 913b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 91407baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 91583655e91SJohnny Huang if (info_cb.version != OTP_AST2600A0) 916e1a7245eSJohnny Huang printf("0x%-10X", strap_status[bit_offset + j].reg_protected); 917e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 9183cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 919b458cd62SJohnny Huang printf(" Reserved\n"); 920b458cd62SJohnny Huang continue; 921b458cd62SJohnny Huang } 922b458cd62SJohnny Huang if (length == 1) { 9233cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 924b458cd62SJohnny Huang continue; 92576d13988SJohnny Huang } 92676d13988SJohnny Huang 927b458cd62SJohnny Huang if (j == 0) 9283cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 929b458cd62SJohnny Huang else if (j == length - 1) 930b458cd62SJohnny Huang printf("\\ \"\n"); 931b458cd62SJohnny Huang else 932b458cd62SJohnny Huang printf("| \"\n"); 93376d13988SJohnny Huang } 934b458cd62SJohnny Huang } else { 935c947ef08SJohnny Huang if (length == 1) { 9363cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 937b458cd62SJohnny Huang } else { 938b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 939b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 940b458cd62SJohnny Huang } 941b458cd62SJohnny Huang 942b458cd62SJohnny Huang printf("0x%-10X", otp_value); 943b458cd62SJohnny Huang 9443cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 9453cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 946b458cd62SJohnny Huang else 947b458cd62SJohnny Huang printf("Reserved\n"); 948b458cd62SJohnny Huang } 949b458cd62SJohnny Huang } 950b458cd62SJohnny Huang 951b458cd62SJohnny Huang if (fail) 952b458cd62SJohnny Huang return OTP_FAILURE; 953b458cd62SJohnny Huang 954b458cd62SJohnny Huang return OTP_SUCCESS; 955b458cd62SJohnny Huang } 956b458cd62SJohnny Huang 957*a219f6deSJohnny Huang static void buf_print(u8 *buf, int len) 95869d5fd8fSJohnny Huang { 95969d5fd8fSJohnny Huang int i; 960*a219f6deSJohnny Huang 96169d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 96269d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 963*a219f6deSJohnny Huang if (i % 16 == 0) 96469d5fd8fSJohnny Huang printf("%04X: ", i); 96569d5fd8fSJohnny Huang printf("%02X ", buf[i]); 966*a219f6deSJohnny Huang if ((i + 1) % 16 == 0) 96769d5fd8fSJohnny Huang printf("\n"); 96869d5fd8fSJohnny Huang } 96969d5fd8fSJohnny Huang } 97069d5fd8fSJohnny Huang 971696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout) 97269d5fd8fSJohnny Huang { 97369d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 97479e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 9759a4fe690SJohnny Huang struct otpkey_type key_info; 976*a219f6deSJohnny Huang u32 *buf; 977*a219f6deSJohnny Huang u8 *byte_buf; 9789d998018SJohnny Huang char empty = 1; 97969d5fd8fSJohnny Huang int i = 0, len = 0; 9809a4fe690SJohnny Huang int j; 98154552c69SJohnny Huang 982696656c6SJohnny Huang byte_buf = image_layout->data; 983*a219f6deSJohnny Huang buf = (u32 *)byte_buf; 9849d998018SJohnny Huang 9859d998018SJohnny Huang for (i = 0; i < 16; i++) { 986*a219f6deSJohnny Huang if (buf[i] != 0) 9879d998018SJohnny Huang empty = 0; 9889d998018SJohnny Huang } 9899d998018SJohnny Huang if (empty) 9909d998018SJohnny Huang return 0; 9919d998018SJohnny Huang 9929d998018SJohnny Huang i = 0; 99369d5fd8fSJohnny Huang while (1) { 99469d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 99569d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 99669d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 99769d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 99869d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 99969d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 10009a4fe690SJohnny Huang 10019a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 10029a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 10039a4fe690SJohnny Huang key_info = key_info_array[j]; 10049a4fe690SJohnny Huang break; 10059a4fe690SJohnny Huang } 10069a4fe690SJohnny Huang } 10079a4fe690SJohnny Huang 10087f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 100969d5fd8fSJohnny Huang printf("Key Type: "); 10109a4fe690SJohnny Huang printf("%s\n", key_info.information); 10119a4fe690SJohnny Huang 10129a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 101369d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 101469d5fd8fSJohnny Huang switch (key_length) { 101569d5fd8fSJohnny Huang case 0: 101669d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 101769d5fd8fSJohnny Huang break; 101869d5fd8fSJohnny Huang case 1: 101969d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 102069d5fd8fSJohnny Huang break; 102169d5fd8fSJohnny Huang case 2: 102269d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 102369d5fd8fSJohnny Huang break; 102469d5fd8fSJohnny Huang case 3: 102569d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 102669d5fd8fSJohnny Huang break; 102769d5fd8fSJohnny Huang } 1028181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV || 1029181f72d8SJohnny Huang key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 103069d5fd8fSJohnny Huang printf("RSA SHA Type: "); 103169d5fd8fSJohnny Huang switch (key_length) { 103269d5fd8fSJohnny Huang case 0: 103369d5fd8fSJohnny Huang printf("RSA1024\n"); 103469d5fd8fSJohnny Huang len = 0x100; 103569d5fd8fSJohnny Huang break; 103669d5fd8fSJohnny Huang case 1: 103769d5fd8fSJohnny Huang printf("RSA2048\n"); 103869d5fd8fSJohnny Huang len = 0x200; 103969d5fd8fSJohnny Huang break; 104069d5fd8fSJohnny Huang case 2: 104169d5fd8fSJohnny Huang printf("RSA3072\n"); 104269d5fd8fSJohnny Huang len = 0x300; 104369d5fd8fSJohnny Huang break; 104469d5fd8fSJohnny Huang case 3: 104569d5fd8fSJohnny Huang printf("RSA4096\n"); 104669d5fd8fSJohnny Huang len = 0x400; 104769d5fd8fSJohnny Huang break; 104869d5fd8fSJohnny Huang } 104969d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 105069d5fd8fSJohnny Huang } 10519a4fe690SJohnny Huang if (key_info.need_id) 105269d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 105369d5fd8fSJohnny Huang printf("Key Value:\n"); 10549a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 105569d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 10569a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 10579a4fe690SJohnny Huang printf("AES Key:\n"); 10589a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10595fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 10609a4fe690SJohnny Huang printf("AES IV:\n"); 10619a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10629a4fe690SJohnny Huang } 10639a4fe690SJohnny Huang 10649a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 10655fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 106669d5fd8fSJohnny Huang printf("AES Key:\n"); 106769d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 106869d5fd8fSJohnny Huang printf("AES IV:\n"); 106969d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10705fdde29fSJohnny Huang } else { 10719a4fe690SJohnny Huang printf("AES Key 1:\n"); 10729a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10739a4fe690SJohnny Huang printf("AES Key 2:\n"); 10749a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 10759a4fe690SJohnny Huang } 1076181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) { 107769d5fd8fSJohnny Huang printf("RSA mod:\n"); 107869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 107969d5fd8fSJohnny Huang printf("RSA exp:\n"); 108069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 1081181f72d8SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) { 1082181f72d8SJohnny Huang printf("RSA mod:\n"); 1083181f72d8SJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 1084181f72d8SJohnny Huang printf("RSA exp:\n"); 1085*a219f6deSJohnny Huang buf_print((u8 *)"\x01\x00\x01", 3); 108669d5fd8fSJohnny Huang } 108769d5fd8fSJohnny Huang if (last) 108869d5fd8fSJohnny Huang break; 108969d5fd8fSJohnny Huang i++; 109069d5fd8fSJohnny Huang } 109169d5fd8fSJohnny Huang return 0; 109269d5fd8fSJohnny Huang } 109369d5fd8fSJohnny Huang 10945010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout) 109569d5fd8fSJohnny Huang { 1096a6d0d645SJohnny Huang int i, k; 1097d90825e2SJohnny Huang int pass = 0; 1098*a219f6deSJohnny Huang u32 prog_address; 1099*a219f6deSJohnny Huang u32 data[16]; 1100*a219f6deSJohnny Huang u32 compare[2]; 1101*a219f6deSJohnny Huang u32 *conf = (u32 *)image_layout->conf; 1102*a219f6deSJohnny Huang u32 *conf_ignore = (u32 *)image_layout->conf_ignore; 1103*a219f6deSJohnny Huang u32 data_masked; 1104*a219f6deSJohnny Huang u32 buf_masked; 110569d5fd8fSJohnny Huang 1106a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 1107a6d0d645SJohnny Huang 1108bb34a7bfSJohnny Huang for (i = 0; i < 16 ; i++) { 110969d5fd8fSJohnny Huang prog_address = 0x800; 1110a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1111a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1112a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 1113a6d0d645SJohnny Huang } 1114a6d0d645SJohnny Huang 1115a6d0d645SJohnny Huang printf("Check writable...\n"); 1116bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 11175010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 11185010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1119d90825e2SJohnny Huang if (data_masked == buf_masked) 112069d5fd8fSJohnny Huang continue; 1121d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1122a6d0d645SJohnny Huang continue; 1123a6d0d645SJohnny Huang } else { 1124a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1125a6af4a17SJohnny Huang printf("OTPCFG[%X] = %x\n", i, data[i]); 11265010032bSJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 11275010032bSJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 11282a856b9aSJohnny Huang return OTP_FAILURE; 1129a6d0d645SJohnny Huang } 1130a6d0d645SJohnny Huang } 1131a6d0d645SJohnny Huang 1132a6d0d645SJohnny Huang printf("Start Programing...\n"); 1133d90825e2SJohnny Huang otp_soak(0); 1134bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 11355010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 11365010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1137a6d0d645SJohnny Huang prog_address = 0x800; 1138a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1139a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1140bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1141bb34a7bfSJohnny Huang pass = 1; 1142a6d0d645SJohnny Huang continue; 1143bb34a7bfSJohnny Huang } 1144de6fbf1cSJohnny Huang 1145de6fbf1cSJohnny Huang otp_soak(1); 11465010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1147a6d0d645SJohnny Huang 114869d5fd8fSJohnny Huang pass = 0; 114969d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 11505010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1151de6fbf1cSJohnny Huang otp_soak(2); 1152feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 11535010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1154de6fbf1cSJohnny Huang otp_soak(1); 1155de6fbf1cSJohnny Huang } else { 1156de6fbf1cSJohnny Huang pass = 1; 1157de6fbf1cSJohnny Huang break; 1158de6fbf1cSJohnny Huang } 1159a6d0d645SJohnny Huang } else { 116069d5fd8fSJohnny Huang pass = 1; 116169d5fd8fSJohnny Huang break; 116269d5fd8fSJohnny Huang } 116369d5fd8fSJohnny Huang } 1164bb34a7bfSJohnny Huang if (pass == 0) { 1165bb34a7bfSJohnny Huang printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n", 11665010032bSJohnny Huang i, data[i], conf[i], conf_ignore[i]); 1167bb34a7bfSJohnny Huang break; 1168bb34a7bfSJohnny Huang } 1169a6d0d645SJohnny Huang } 1170a6d0d645SJohnny Huang 1171de6fbf1cSJohnny Huang otp_soak(0); 117269d5fd8fSJohnny Huang if (!pass) 11732a856b9aSJohnny Huang return OTP_FAILURE; 1174a6d0d645SJohnny Huang 11752a856b9aSJohnny Huang return OTP_SUCCESS; 117669d5fd8fSJohnny Huang } 117769d5fd8fSJohnny Huang 1178eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit) 1179eda10d61SJohnny Huang { 11809901d43aSJohnny Huang int prog_flag = 0; 11819901d43aSJohnny Huang 11829901d43aSJohnny Huang // ignore this bit 11839901d43aSJohnny Huang if (ibit == 1) 1184eda10d61SJohnny Huang return OTP_SUCCESS; 1185eda10d61SJohnny Huang printf("OTPSTRAP[%X]:\n", offset); 11869901d43aSJohnny Huang 1187eda10d61SJohnny Huang if (bit == otpstrap->value) { 11889901d43aSJohnny Huang if (!pbit && !rpbit) { 1189eda10d61SJohnny Huang printf(" The value is same as before, skip it.\n"); 1190eda10d61SJohnny Huang return OTP_PROG_SKIP; 1191eda10d61SJohnny Huang } 11929901d43aSJohnny Huang printf(" The value is same as before.\n"); 11939901d43aSJohnny Huang } else { 11949901d43aSJohnny Huang prog_flag = 1; 11959901d43aSJohnny Huang } 11969901d43aSJohnny Huang if (otpstrap->protected == 1 && prog_flag) { 1197eda10d61SJohnny Huang printf(" This bit is protected and is not writable\n"); 1198eda10d61SJohnny Huang return OTP_FAILURE; 1199eda10d61SJohnny Huang } 12009901d43aSJohnny Huang if (otpstrap->remain_times == 0 && prog_flag) { 1201eda10d61SJohnny Huang printf(" This bit is no remaining times to write.\n"); 1202eda10d61SJohnny Huang return OTP_FAILURE; 1203eda10d61SJohnny Huang } 12049901d43aSJohnny Huang if (pbit == 1) 1205eda10d61SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 12069901d43aSJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) 1207eda10d61SJohnny Huang printf(" The relative register will be protected.\n"); 12089901d43aSJohnny Huang if (prog_flag) 1209eda10d61SJohnny 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); 12109901d43aSJohnny Huang 1211eda10d61SJohnny Huang return OTP_SUCCESS; 1212eda10d61SJohnny Huang } 1213eda10d61SJohnny Huang 12145010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout) 121569d5fd8fSJohnny Huang { 121669d5fd8fSJohnny Huang int i; 1217*a219f6deSJohnny Huang u32 *strap; 1218*a219f6deSJohnny Huang u32 *strap_ignore; 1219*a219f6deSJohnny Huang u32 *strap_reg_protect; 1220*a219f6deSJohnny Huang u32 *strap_pro; 1221eda10d61SJohnny Huang int bit, pbit, ibit, rpbit; 122269d5fd8fSJohnny Huang int fail = 0; 1223eda10d61SJohnny Huang int ret; 122466f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 122569d5fd8fSJohnny Huang 1226*a219f6deSJohnny Huang strap = (u32 *)image_layout->strap; 1227*a219f6deSJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1228*a219f6deSJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1229*a219f6deSJohnny Huang strap_reg_protect = (u32 *)image_layout->strap_reg_pro; 12305010032bSJohnny Huang 1231541eb887SJohnny Huang otp_strap_status(otpstrap); 123269d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 123369d5fd8fSJohnny Huang if (i < 32) { 12345010032bSJohnny Huang bit = (strap[0] >> i) & 0x1; 1235eda10d61SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 12365010032bSJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 123769d5fd8fSJohnny Huang } else { 12385010032bSJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1239eda10d61SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 12405010032bSJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 12415010032bSJohnny Huang } 12425010032bSJohnny Huang 12435010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 1244*a219f6deSJohnny Huang if (i < 32) 12455010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 1246*a219f6deSJohnny Huang else 12475010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 12485010032bSJohnny Huang } else { 12495010032bSJohnny Huang rpbit = 0; 125069d5fd8fSJohnny Huang } 1251eda10d61SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit); 1252eda10d61SJohnny Huang 1253eda10d61SJohnny Huang if (ret == OTP_FAILURE) 125469d5fd8fSJohnny Huang fail = 1; 125569d5fd8fSJohnny Huang } 125669d5fd8fSJohnny Huang if (fail == 1) 1257a6af4a17SJohnny Huang return OTP_FAILURE; 12589901d43aSJohnny Huang else 1259eda10d61SJohnny Huang return OTP_SUCCESS; 126069d5fd8fSJohnny Huang } 126169d5fd8fSJohnny Huang 12622a856b9aSJohnny Huang static int otp_print_strap(int start, int count) 126369d5fd8fSJohnny Huang { 126469d5fd8fSJohnny Huang int i, j; 1265de6b0cc4SJohnny Huang int remains; 126666f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 126769d5fd8fSJohnny Huang 12682a856b9aSJohnny Huang if (start < 0 || start > 64) 12692a856b9aSJohnny Huang return OTP_USAGE; 12702a856b9aSJohnny Huang 12712a856b9aSJohnny Huang if ((start + count) < 0 || (start + count) > 64) 12722a856b9aSJohnny Huang return OTP_USAGE; 12732a856b9aSJohnny Huang 1274541eb887SJohnny Huang otp_strap_status(otpstrap); 127569d5fd8fSJohnny Huang 1276de6b0cc4SJohnny Huang if (info_cb.version == OTP_AST2600A0) { 1277de6b0cc4SJohnny Huang remains = 7; 127807baa4e8SJohnny Huang printf("BIT(hex) Value Option Status\n"); 1279de6b0cc4SJohnny Huang } else { 1280de6b0cc4SJohnny Huang remains = 6; 1281de6b0cc4SJohnny Huang printf("BIT(hex) Value Option Reg_Protect Status\n"); 1282de6b0cc4SJohnny Huang } 1283de6b0cc4SJohnny Huang printf("______________________________________________________________________________\n"); 1284737ed20bSJohnny Huang 1285cd1610b4SJohnny Huang for (i = start; i < start + count; i++) { 128607baa4e8SJohnny Huang printf("0x%-8X", i); 1287737ed20bSJohnny Huang printf("%-7d", otpstrap[i].value); 1288de6b0cc4SJohnny Huang for (j = 0; j < remains; j++) 1289737ed20bSJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 1290737ed20bSJohnny Huang printf(" "); 1291*a219f6deSJohnny Huang if (info_cb.version != OTP_AST2600A0) 1292de6b0cc4SJohnny Huang printf("%d ", otpstrap[i].reg_protected); 129369d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 1294737ed20bSJohnny Huang printf("protected and not writable"); 129569d5fd8fSJohnny Huang } else { 1296737ed20bSJohnny Huang printf("not protected "); 1297*a219f6deSJohnny Huang if (otpstrap[i].remain_times == 0) 1298737ed20bSJohnny Huang printf("and no remaining times to write."); 1299*a219f6deSJohnny Huang else 1300737ed20bSJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 130169d5fd8fSJohnny Huang } 1302737ed20bSJohnny Huang printf("\n"); 130369d5fd8fSJohnny Huang } 13042a856b9aSJohnny Huang 13052a856b9aSJohnny Huang return OTP_SUCCESS; 130669d5fd8fSJohnny Huang } 130769d5fd8fSJohnny Huang 13088848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value) 13098848d5dcSJohnny Huang { 13108848d5dcSJohnny Huang struct otpstrap_status otpstrap[64]; 1311*a219f6deSJohnny Huang u32 prog_address; 13128848d5dcSJohnny Huang int offset; 13138848d5dcSJohnny Huang int ret; 13148848d5dcSJohnny Huang 13158848d5dcSJohnny Huang otp_strap_status(otpstrap); 13168848d5dcSJohnny Huang 13178848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 13188848d5dcSJohnny Huang 1319*a219f6deSJohnny Huang if (ret != OTP_SUCCESS) 13208848d5dcSJohnny Huang return ret; 13218848d5dcSJohnny Huang 13228848d5dcSJohnny Huang prog_address = 0x800; 13238848d5dcSJohnny Huang if (bit_offset < 32) { 13248848d5dcSJohnny Huang offset = bit_offset; 13258848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 13268848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 13278848d5dcSJohnny Huang 13288848d5dcSJohnny Huang } else { 13298848d5dcSJohnny Huang offset = (bit_offset - 32); 13308848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 13318848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 13328848d5dcSJohnny Huang } 13338848d5dcSJohnny Huang 133483655e91SJohnny Huang return otp_prog_bit(1, prog_address, offset); 13358848d5dcSJohnny Huang } 13368848d5dcSJohnny Huang 13375010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout) 133869d5fd8fSJohnny Huang { 1339*a219f6deSJohnny Huang u32 *strap; 1340*a219f6deSJohnny Huang u32 *strap_ignore; 1341*a219f6deSJohnny Huang u32 *strap_pro; 1342*a219f6deSJohnny Huang u32 *strap_reg_protect; 1343*a219f6deSJohnny Huang u32 prog_address; 134483655e91SJohnny Huang int i; 1345eda10d61SJohnny Huang int bit, pbit, ibit, offset, rpbit; 134669d5fd8fSJohnny Huang int fail = 0; 134783655e91SJohnny Huang int ret; 13489901d43aSJohnny Huang int prog_flag = 0; 134966f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 135069d5fd8fSJohnny Huang 1351*a219f6deSJohnny Huang strap = (u32 *)image_layout->strap; 1352*a219f6deSJohnny Huang strap_pro = (u32 *)image_layout->strap_pro; 1353*a219f6deSJohnny Huang strap_ignore = (u32 *)image_layout->strap_ignore; 1354*a219f6deSJohnny Huang strap_reg_protect = (u32 *)image_layout->strap_reg_pro; 13555010032bSJohnny Huang 13567f795e57SJohnny Huang printf("Read OTP Strap Region:\n"); 1357541eb887SJohnny Huang otp_strap_status(otpstrap); 135869d5fd8fSJohnny Huang 13597f795e57SJohnny Huang printf("Check writable...\n"); 13605010032bSJohnny Huang if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) { 13617f795e57SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 13627f795e57SJohnny Huang return OTP_FAILURE; 13637f795e57SJohnny Huang } 13647e22f42dSJohnny Huang 136569d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 136669d5fd8fSJohnny Huang prog_address = 0x800; 136769d5fd8fSJohnny Huang if (i < 32) { 136869d5fd8fSJohnny Huang offset = i; 13695010032bSJohnny Huang bit = (strap[0] >> offset) & 0x1; 1370eda10d61SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 13715010032bSJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 137269d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 137369d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 137469d5fd8fSJohnny Huang 137569d5fd8fSJohnny Huang } else { 137669d5fd8fSJohnny Huang offset = (i - 32); 13775010032bSJohnny Huang bit = (strap[1] >> offset) & 0x1; 1378eda10d61SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 13795010032bSJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 138069d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 138169d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 138269d5fd8fSJohnny Huang } 13835010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 1384*a219f6deSJohnny Huang if (i < 32) 13855010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 1386*a219f6deSJohnny Huang else 13875010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 13885010032bSJohnny Huang } else { 13895010032bSJohnny Huang rpbit = 0; 13905010032bSJohnny Huang } 139169d5fd8fSJohnny Huang 1392*a219f6deSJohnny Huang if (ibit == 1) 139369d5fd8fSJohnny Huang continue; 13949901d43aSJohnny Huang if (bit == otpstrap[i].value) 13959901d43aSJohnny Huang prog_flag = 0; 13969901d43aSJohnny Huang else 13979901d43aSJohnny Huang prog_flag = 1; 13989901d43aSJohnny Huang 13999901d43aSJohnny Huang if (otpstrap[i].protected == 1 && prog_flag) { 140069d5fd8fSJohnny Huang fail = 1; 140169d5fd8fSJohnny Huang continue; 140269d5fd8fSJohnny Huang } 14039901d43aSJohnny Huang if (otpstrap[i].remain_times == 0 && prog_flag) { 140469d5fd8fSJohnny Huang fail = 1; 140569d5fd8fSJohnny Huang continue; 140669d5fd8fSJohnny Huang } 14077e22f42dSJohnny Huang 14089901d43aSJohnny Huang if (prog_flag) { 140983655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 141083655e91SJohnny Huang if (!ret) 14112a856b9aSJohnny Huang return OTP_FAILURE; 14129901d43aSJohnny Huang } 141369d5fd8fSJohnny Huang 14145010032bSJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 141569d5fd8fSJohnny Huang prog_address = 0x800; 141669d5fd8fSJohnny Huang if (i < 32) 14175010032bSJohnny Huang prog_address |= 0x608; 141869d5fd8fSJohnny Huang else 14195010032bSJohnny Huang prog_address |= 0x60a; 14207e22f42dSJohnny Huang 142183655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 142283655e91SJohnny Huang if (!ret) 14232a856b9aSJohnny Huang return OTP_FAILURE; 14245010032bSJohnny Huang } 14255010032bSJohnny Huang 14265010032bSJohnny Huang if (pbit != 0) { 14275010032bSJohnny Huang prog_address = 0x800; 14285010032bSJohnny Huang if (i < 32) 14295010032bSJohnny Huang prog_address |= 0x60c; 14305010032bSJohnny Huang else 14315010032bSJohnny Huang prog_address |= 0x60e; 14325010032bSJohnny Huang 143383655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 143483655e91SJohnny Huang if (!ret) 14355010032bSJohnny Huang return OTP_FAILURE; 14365010032bSJohnny Huang } 143769d5fd8fSJohnny Huang } 1438de6fbf1cSJohnny Huang otp_soak(0); 143969d5fd8fSJohnny Huang if (fail == 1) 14402a856b9aSJohnny Huang return OTP_FAILURE; 14412a856b9aSJohnny Huang return OTP_SUCCESS; 144269d5fd8fSJohnny Huang } 144369d5fd8fSJohnny Huang 14445010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout) 14454c1c9b35SJohnny Huang { 144654552c69SJohnny Huang int i; 144754552c69SJohnny Huang int ret; 14485010032bSJohnny Huang int data_dw; 1449*a219f6deSJohnny Huang u32 data[2048]; 1450*a219f6deSJohnny Huang u32 *buf; 1451*a219f6deSJohnny Huang u32 *buf_ignore; 1452*a219f6deSJohnny Huang u32 data_masked; 1453*a219f6deSJohnny Huang u32 buf_masked; 14544c1c9b35SJohnny Huang 1455*a219f6deSJohnny Huang buf = (u32 *)image_layout->data; 1456*a219f6deSJohnny Huang buf_ignore = (u32 *)image_layout->data_ignore; 14575010032bSJohnny Huang 14585010032bSJohnny Huang data_dw = image_layout->data_length / 4; 14595010032bSJohnny Huang 14604c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 14614c1c9b35SJohnny Huang 1462*a219f6deSJohnny Huang for (i = 0; i < data_dw - 2 ; i += 2) 1463d90825e2SJohnny Huang otp_read_data(i, &data[i]); 1464d90825e2SJohnny Huang 14654c1c9b35SJohnny Huang printf("Check writable...\n"); 146654552c69SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 14675010032bSJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1468696656c6SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1469696656c6SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 147054552c69SJohnny Huang if (data_masked == buf_masked) 14714c1c9b35SJohnny Huang continue; 1472d90825e2SJohnny Huang if (i % 2 == 0) { 147354552c69SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 14744c1c9b35SJohnny Huang continue; 14754c1c9b35SJohnny Huang } else { 14764c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1477d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 14784c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1479696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 14802a856b9aSJohnny Huang return OTP_FAILURE; 148169d5fd8fSJohnny Huang } 1482d90825e2SJohnny Huang } else { 148354552c69SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1484d90825e2SJohnny Huang continue; 1485d90825e2SJohnny Huang } else { 1486d90825e2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1487d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1488d90825e2SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1489696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 14902a856b9aSJohnny Huang return OTP_FAILURE; 1491d90825e2SJohnny Huang } 1492d90825e2SJohnny Huang } 1493d90825e2SJohnny Huang } 149469d5fd8fSJohnny Huang 1495d90825e2SJohnny Huang printf("Start Programing...\n"); 1496d90825e2SJohnny Huang 149754552c69SJohnny Huang // programing ecc region first 149854552c69SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1499696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 150054552c69SJohnny Huang if (ret != OTP_SUCCESS) { 150154552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1502696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 150354552c69SJohnny Huang return ret; 1504d90825e2SJohnny Huang } 1505d90825e2SJohnny Huang } 1506d90825e2SJohnny Huang 150754552c69SJohnny Huang for (i = 0; i < 1792; i += 2) { 1508696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 150954552c69SJohnny Huang if (ret != OTP_SUCCESS) { 151054552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1511696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 151254552c69SJohnny Huang return ret; 1513d90825e2SJohnny Huang } 1514de6fbf1cSJohnny Huang } 1515de6fbf1cSJohnny Huang otp_soak(0); 15162a856b9aSJohnny Huang return OTP_SUCCESS; 1517d90825e2SJohnny Huang } 1518d90825e2SJohnny Huang 1519*a219f6deSJohnny Huang static int otp_image_verify(u8 *src_buf, u32 length, u8 *digest_buf) 1520696656c6SJohnny Huang { 1521696656c6SJohnny Huang sha256_context ctx; 1522696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1523696656c6SJohnny Huang 1524696656c6SJohnny Huang sha256_starts(&ctx); 1525696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1526696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1527696656c6SJohnny Huang 1528696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1529696656c6SJohnny Huang return 0; 1530696656c6SJohnny Huang return -1; 1531696656c6SJohnny Huang } 1532696656c6SJohnny Huang 1533de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm) 153469d5fd8fSJohnny Huang { 153569d5fd8fSJohnny Huang int ret; 15369a4fe690SJohnny Huang int image_version = 0; 1537696656c6SJohnny Huang struct otp_header *otp_header; 1538696656c6SJohnny Huang struct otp_image_layout image_layout; 1539696656c6SJohnny Huang int image_size; 1540*a219f6deSJohnny Huang u8 *buf; 1541*a219f6deSJohnny Huang u8 *checksum; 154269d5fd8fSJohnny Huang 1543696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1544696656c6SJohnny Huang if (!otp_header) { 154569d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 15462a856b9aSJohnny Huang return OTP_FAILURE; 154769d5fd8fSJohnny Huang } 1548d90825e2SJohnny Huang 1549696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1550696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1551696656c6SJohnny Huang 1552696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1553696656c6SJohnny Huang 1554696656c6SJohnny Huang if (!buf) { 1555696656c6SJohnny Huang puts("Failed to map physical memory\n"); 1556696656c6SJohnny Huang return OTP_FAILURE; 1557696656c6SJohnny Huang } 1558696656c6SJohnny Huang otp_header = (struct otp_header *)buf; 1559696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1560696656c6SJohnny Huang 1561696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1562696656c6SJohnny Huang puts("Image is invalid\n"); 1563696656c6SJohnny Huang return OTP_FAILURE; 1564696656c6SJohnny Huang } 1565696656c6SJohnny Huang 15665010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 15675010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 15685010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 15695010032bSJohnny Huang 15705010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1571696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 15725010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1573696656c6SJohnny Huang 1574696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 1575696656c6SJohnny Huang 1576696656c6SJohnny Huang if (!strcmp("A0", (char *)otp_header->otp_version)) { 1577696656c6SJohnny Huang image_version = OTP_AST2600A0; 15785010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 15795010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 15805010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 1581696656c6SJohnny Huang } else if (!strcmp("A1", (char *)otp_header->otp_version)) { 1582696656c6SJohnny Huang image_version = OTP_AST2600A1; 15835010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 15845010032bSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 15855010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 15865010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 15875fdde29fSJohnny Huang } else if (!strcmp("A2", (char *)otp_header->otp_version)) { 15885fdde29fSJohnny Huang image_version = OTP_AST2600A2; 15895fdde29fSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 15905fdde29fSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 15915fdde29fSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 15925fdde29fSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 159364b66712SJohnny Huang } else if (!strcmp("A3", (char *)otp_header->otp_version)) { 159464b66712SJohnny Huang image_version = OTP_AST2600A3; 159564b66712SJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 159664b66712SJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 159764b66712SJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 159864b66712SJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 1599696656c6SJohnny Huang } else { 1600696656c6SJohnny Huang puts("Version is not supported\n"); 1601696656c6SJohnny Huang return OTP_FAILURE; 1602696656c6SJohnny Huang } 1603696656c6SJohnny Huang 16049a4fe690SJohnny Huang if (image_version != info_cb.version) { 16059a4fe690SJohnny Huang puts("Version is not match\n"); 16069a4fe690SJohnny Huang return OTP_FAILURE; 16079a4fe690SJohnny Huang } 16089a4fe690SJohnny Huang 1609696656c6SJohnny Huang if (otp_image_verify(buf, image_size, checksum)) { 1610696656c6SJohnny Huang puts("checksum is invalid\n"); 1611696656c6SJohnny Huang return OTP_FAILURE; 1612d90825e2SJohnny Huang } 16137332532cSJohnny Huang 161469d5fd8fSJohnny Huang if (!nconfirm) { 1615696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16167f795e57SJohnny Huang printf("\nOTP data region :\n"); 1617696656c6SJohnny Huang if (otp_print_data_info(&image_layout) < 0) { 161869d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 16192a856b9aSJohnny Huang return OTP_FAILURE; 162069d5fd8fSJohnny Huang } 162169d5fd8fSJohnny Huang } 1622696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16237332532cSJohnny Huang printf("\nOTP strap region :\n"); 16245010032bSJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 16257332532cSJohnny Huang printf("OTP strap error, please check.\n"); 16267332532cSJohnny Huang return OTP_FAILURE; 16277332532cSJohnny Huang } 16287332532cSJohnny Huang } 1629696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16307332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1631696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 16327332532cSJohnny Huang printf("OTP config error, please check.\n"); 16337332532cSJohnny Huang return OTP_FAILURE; 16347332532cSJohnny Huang } 16357332532cSJohnny Huang } 16367332532cSJohnny Huang 163769d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 163869d5fd8fSJohnny Huang if (!confirm_yesno()) { 163969d5fd8fSJohnny Huang printf(" Aborting\n"); 16402a856b9aSJohnny Huang return OTP_FAILURE; 164169d5fd8fSJohnny Huang } 164269d5fd8fSJohnny Huang } 16437332532cSJohnny Huang 16445010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16455010032bSJohnny Huang printf("programing data region ...\n"); 16465010032bSJohnny Huang ret = otp_prog_data(&image_layout); 16475010032bSJohnny Huang if (ret != 0) { 16485010032bSJohnny Huang printf("Error\n"); 16495010032bSJohnny Huang return ret; 16505010032bSJohnny Huang } 1651*a219f6deSJohnny Huang printf("Done\n"); 16525010032bSJohnny Huang } 16535010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16545010032bSJohnny Huang printf("programing strap region ...\n"); 16555010032bSJohnny Huang ret = otp_prog_strap(&image_layout); 16565010032bSJohnny Huang if (ret != 0) { 16575010032bSJohnny Huang printf("Error\n"); 16585010032bSJohnny Huang return ret; 16595010032bSJohnny Huang } 1660*a219f6deSJohnny Huang printf("Done\n"); 16615010032bSJohnny Huang } 16625010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16635010032bSJohnny Huang printf("programing configuration region ...\n"); 16645010032bSJohnny Huang ret = otp_prog_conf(&image_layout); 16655010032bSJohnny Huang if (ret != 0) { 16665010032bSJohnny Huang printf("Error\n"); 16675010032bSJohnny Huang return ret; 16685010032bSJohnny Huang } 16695010032bSJohnny Huang printf("Done\n"); 16705010032bSJohnny Huang } 1671cd1610b4SJohnny Huang 16727332532cSJohnny Huang return OTP_SUCCESS; 16732a856b9aSJohnny Huang } 16742a856b9aSJohnny Huang 16752a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1676cd1610b4SJohnny Huang { 1677*a219f6deSJohnny Huang u32 read[2]; 1678*a219f6deSJohnny Huang u32 prog_address = 0; 167966f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 1680cd1610b4SJohnny Huang int otp_bit; 168183655e91SJohnny Huang int ret = 0; 1682cd1610b4SJohnny Huang 1683dacbba92SJohnny Huang otp_soak(0); 1684cd1610b4SJohnny Huang switch (mode) { 1685a6d0d645SJohnny Huang case OTP_REGION_CONF: 1686a6af4a17SJohnny Huang otp_read_config(otp_dw_offset, read); 1687cd1610b4SJohnny Huang prog_address = 0x800; 1688cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1689cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1690a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1691cd1610b4SJohnny Huang if (otp_bit == value) { 1692a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1693cd1610b4SJohnny Huang printf("No need to program\n"); 16942a856b9aSJohnny Huang return OTP_SUCCESS; 1695cd1610b4SJohnny Huang } 1696cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1697a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset); 1698cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 16992a856b9aSJohnny Huang return OTP_FAILURE; 1700cd1610b4SJohnny Huang } 1701a6af4a17SJohnny Huang printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset); 1702cd1610b4SJohnny Huang break; 1703a6d0d645SJohnny Huang case OTP_REGION_DATA: 1704cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1705cd1610b4SJohnny Huang 1706cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1707a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 1708a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1709643b9cfdSJohnny Huang 1710643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 1711643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1712643b9cfdSJohnny Huang printf("OTP is programed, which can't be cleaned\n"); 1713643b9cfdSJohnny Huang return OTP_FAILURE; 1714643b9cfdSJohnny Huang } 1715cd1610b4SJohnny Huang } else { 1716a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 1717a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 1718643b9cfdSJohnny Huang 1719643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 1720643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1721643b9cfdSJohnny Huang printf("OTP is programed, which can't be writen\n"); 1722643b9cfdSJohnny Huang return OTP_FAILURE; 1723643b9cfdSJohnny Huang } 1724cd1610b4SJohnny Huang } 1725cd1610b4SJohnny Huang if (otp_bit == value) { 1726a6af4a17SJohnny Huang printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1727cd1610b4SJohnny Huang printf("No need to program\n"); 17282a856b9aSJohnny Huang return OTP_SUCCESS; 1729cd1610b4SJohnny Huang } 1730643b9cfdSJohnny Huang 1731a6af4a17SJohnny Huang printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset); 1732cd1610b4SJohnny Huang break; 1733a6d0d645SJohnny Huang case OTP_REGION_STRAP: 17348848d5dcSJohnny Huang otp_strap_status(otpstrap); 17358848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 17368848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 17378848d5dcSJohnny Huang if (ret == OTP_FAILURE) 17388848d5dcSJohnny Huang return OTP_FAILURE; 17398848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 17408848d5dcSJohnny Huang return OTP_SUCCESS; 1741a6af4a17SJohnny Huang 1742cd1610b4SJohnny Huang break; 1743cd1610b4SJohnny Huang } 1744cd1610b4SJohnny Huang 1745cd1610b4SJohnny Huang if (!nconfirm) { 1746cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1747cd1610b4SJohnny Huang if (!confirm_yesno()) { 1748cd1610b4SJohnny Huang printf(" Aborting\n"); 17492a856b9aSJohnny Huang return OTP_FAILURE; 1750cd1610b4SJohnny Huang } 1751cd1610b4SJohnny Huang } 1752cd1610b4SJohnny Huang 1753cd1610b4SJohnny Huang switch (mode) { 1754a6d0d645SJohnny Huang case OTP_REGION_STRAP: 175583655e91SJohnny Huang ret = otp_prog_strap_bit(bit_offset, value); 175683655e91SJohnny Huang break; 1757a6d0d645SJohnny Huang case OTP_REGION_CONF: 1758a6d0d645SJohnny Huang case OTP_REGION_DATA: 175983655e91SJohnny Huang ret = otp_prog_bit(value, prog_address, bit_offset); 1760de6fbf1cSJohnny Huang break; 1761de6fbf1cSJohnny Huang } 1762de6fbf1cSJohnny Huang otp_soak(0); 176383655e91SJohnny Huang if (ret) { 17649009c25dSJohnny Huang printf("SUCCESS\n"); 17652a856b9aSJohnny Huang return OTP_SUCCESS; 1766*a219f6deSJohnny Huang } 1767*a219f6deSJohnny Huang 17689009c25dSJohnny Huang printf("OTP cannot be programed\n"); 17699009c25dSJohnny Huang printf("FAILED\n"); 17709009c25dSJohnny Huang return OTP_FAILURE; 17719009c25dSJohnny Huang } 1772cd1610b4SJohnny Huang 17732a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 177469d5fd8fSJohnny Huang { 1775*a219f6deSJohnny Huang u32 offset, count; 17762a856b9aSJohnny Huang int ret; 177769d5fd8fSJohnny Huang 17782a856b9aSJohnny Huang if (argc == 4) { 17792a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 17802a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 17812a856b9aSJohnny Huang } else if (argc == 3) { 17822a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 17832a856b9aSJohnny Huang count = 1; 17842a856b9aSJohnny Huang } else { 178569d5fd8fSJohnny Huang return CMD_RET_USAGE; 178669d5fd8fSJohnny Huang } 178769d5fd8fSJohnny Huang 17882a856b9aSJohnny Huang if (!strcmp(argv[1], "conf")) { 17893d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17902a856b9aSJohnny Huang ret = otp_print_config(offset, count); 17912a856b9aSJohnny Huang } else if (!strcmp(argv[1], "data")) { 17923d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17932a856b9aSJohnny Huang ret = otp_print_data(offset, count); 17942a856b9aSJohnny Huang } else if (!strcmp(argv[1], "strap")) { 17953d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17962a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 17972a856b9aSJohnny Huang } else { 17982a856b9aSJohnny Huang return CMD_RET_USAGE; 179969d5fd8fSJohnny Huang } 180069d5fd8fSJohnny Huang 18012a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18022a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18032a856b9aSJohnny Huang return CMD_RET_USAGE; 18042a856b9aSJohnny Huang } 18052a856b9aSJohnny Huang 18062a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18072a856b9aSJohnny Huang { 18082a856b9aSJohnny Huang phys_addr_t addr; 18092a856b9aSJohnny Huang int ret; 18102a856b9aSJohnny Huang 1811de6b0cc4SJohnny Huang if (argc == 3) { 1812ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 18132a856b9aSJohnny Huang return CMD_RET_USAGE; 18142a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 18153d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1816de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 1); 1817de6b0cc4SJohnny Huang } else if (argc == 2) { 18182a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 18193d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1820de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 0); 18212a856b9aSJohnny Huang } else { 18222a856b9aSJohnny Huang return CMD_RET_USAGE; 18232a856b9aSJohnny Huang } 18242a856b9aSJohnny Huang 18252a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18262a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18272a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 18282a856b9aSJohnny Huang return CMD_RET_FAILURE; 18292a856b9aSJohnny Huang else 18302a856b9aSJohnny Huang return CMD_RET_USAGE; 18312a856b9aSJohnny Huang } 18322a856b9aSJohnny Huang 18332a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18342a856b9aSJohnny Huang { 18352a856b9aSJohnny Huang int mode = 0; 18362a856b9aSJohnny Huang int nconfirm = 0; 18372a856b9aSJohnny Huang int otp_addr = 0; 18382a856b9aSJohnny Huang int bit_offset; 18392a856b9aSJohnny Huang int value; 18402a856b9aSJohnny Huang int ret; 18412a856b9aSJohnny Huang 18422a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 18432a856b9aSJohnny Huang return CMD_RET_USAGE; 18442a856b9aSJohnny Huang 18452a856b9aSJohnny Huang /* Drop the pb cmd */ 18462a856b9aSJohnny Huang argc--; 18472a856b9aSJohnny Huang argv++; 18482a856b9aSJohnny Huang 18492a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 1850a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 18512a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 1852a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 18532a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 1854a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 1855cd1610b4SJohnny Huang else 18562a856b9aSJohnny Huang return CMD_RET_USAGE; 18572a856b9aSJohnny Huang 18582a856b9aSJohnny Huang /* Drop the region cmd */ 18592a856b9aSJohnny Huang argc--; 18602a856b9aSJohnny Huang argv++; 18612a856b9aSJohnny Huang 1862ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1863cd1610b4SJohnny Huang nconfirm = 1; 18642a856b9aSJohnny Huang /* Drop the force option */ 18652a856b9aSJohnny Huang argc--; 18662a856b9aSJohnny Huang argv++; 18672a856b9aSJohnny Huang } 1868cd1610b4SJohnny Huang 1869a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 18702a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 18712a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 18720808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 18732a856b9aSJohnny Huang return CMD_RET_USAGE; 1874cd1610b4SJohnny Huang } else { 18752a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 18762a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 18772a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 18780808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 18792a856b9aSJohnny Huang return CMD_RET_USAGE; 18800808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 188178855207SJohnny Huang if (otp_addr >= 0x800) 18820808cc55SJohnny Huang return CMD_RET_USAGE; 18830808cc55SJohnny Huang } else { 188478855207SJohnny Huang if (otp_addr >= 0x20) 18850808cc55SJohnny Huang return CMD_RET_USAGE; 18860808cc55SJohnny Huang } 1887cd1610b4SJohnny Huang } 1888cd1610b4SJohnny Huang if (value != 0 && value != 1) 18892a856b9aSJohnny Huang return CMD_RET_USAGE; 1890cd1610b4SJohnny Huang 18913d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18922a856b9aSJohnny Huang ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 18932a856b9aSJohnny Huang 18942a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18952a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18962a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 18972a856b9aSJohnny Huang return CMD_RET_FAILURE; 18982a856b9aSJohnny Huang else 18992a856b9aSJohnny Huang return CMD_RET_USAGE; 19002a856b9aSJohnny Huang } 19012a856b9aSJohnny Huang 19022a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 19032a856b9aSJohnny Huang { 19042a856b9aSJohnny Huang phys_addr_t addr; 19052a856b9aSJohnny Huang int otp_addr = 0; 19062a856b9aSJohnny Huang 19072a856b9aSJohnny Huang if (argc != 3) 19082a856b9aSJohnny Huang return CMD_RET_USAGE; 19092a856b9aSJohnny Huang 19103d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19112a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 19122a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 19132a856b9aSJohnny Huang if (otp_compare(otp_addr, addr) == 0) { 191469d5fd8fSJohnny Huang printf("Compare pass\n"); 19152a856b9aSJohnny Huang return CMD_RET_SUCCESS; 1916*a219f6deSJohnny Huang } 191769d5fd8fSJohnny Huang printf("Compare fail\n"); 19182a856b9aSJohnny Huang return CMD_RET_FAILURE; 191969d5fd8fSJohnny Huang } 192069d5fd8fSJohnny Huang 192166f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 192266f2f8e5SJohnny Huang { 1923a8bd6d8cSJohnny Huang int view = 0; 19242d4b0742SJohnny Huang int input; 1925a8bd6d8cSJohnny Huang 1926a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 192766f2f8e5SJohnny Huang return CMD_RET_USAGE; 192866f2f8e5SJohnny Huang 19292d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 19303d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19312d4b0742SJohnny Huang if (argc == 3) { 19322d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 19332d4b0742SJohnny Huang otp_print_conf_info(input); 19342d4b0742SJohnny Huang } else { 19352d4b0742SJohnny Huang otp_print_conf_info(-1); 19362d4b0742SJohnny Huang } 19372d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 19382d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 1939a8bd6d8cSJohnny Huang view = 1; 1940a8bd6d8cSJohnny Huang /* Drop the view option */ 1941a8bd6d8cSJohnny Huang argc--; 1942a8bd6d8cSJohnny Huang argv++; 1943a8bd6d8cSJohnny Huang } 19443d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1945b458cd62SJohnny Huang otp_print_strap_info(view); 194666f2f8e5SJohnny Huang } else { 194766f2f8e5SJohnny Huang return CMD_RET_USAGE; 194866f2f8e5SJohnny Huang } 19492d4b0742SJohnny Huang 195066f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 195166f2f8e5SJohnny Huang } 195266f2f8e5SJohnny Huang 1953737ed20bSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1954737ed20bSJohnny Huang { 1955737ed20bSJohnny Huang int input; 1956737ed20bSJohnny Huang int bit_offset; 1957737ed20bSJohnny Huang int prog_address; 195883655e91SJohnny Huang int ret; 1959*a219f6deSJohnny Huang 1960737ed20bSJohnny Huang if (argc != 3 && argc != 2) 1961737ed20bSJohnny Huang return CMD_RET_USAGE; 1962737ed20bSJohnny Huang 1963ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1964737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 1965737ed20bSJohnny Huang } else { 1966737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 1967737ed20bSJohnny Huang printf("OTPSTRAP[%d] will be protected\n", input); 1968737ed20bSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1969737ed20bSJohnny Huang if (!confirm_yesno()) { 1970737ed20bSJohnny Huang printf(" Aborting\n"); 1971737ed20bSJohnny Huang return CMD_RET_FAILURE; 1972737ed20bSJohnny Huang } 1973737ed20bSJohnny Huang } 1974737ed20bSJohnny Huang 1975737ed20bSJohnny Huang prog_address = 0x800; 1976737ed20bSJohnny Huang if (input < 32) { 1977737ed20bSJohnny Huang bit_offset = input; 1978737ed20bSJohnny Huang prog_address |= 0x60c; 1979737ed20bSJohnny Huang } else if (input < 64) { 1980737ed20bSJohnny Huang bit_offset = input - 32; 1981737ed20bSJohnny Huang prog_address |= 0x60e; 1982737ed20bSJohnny Huang } else { 1983737ed20bSJohnny Huang return CMD_RET_USAGE; 1984737ed20bSJohnny Huang } 1985737ed20bSJohnny Huang 1986*a219f6deSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) 1987737ed20bSJohnny Huang printf("OTPSTRAP[%d] already protected\n", input); 1988de6fbf1cSJohnny Huang 198983655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, bit_offset); 1990de6fbf1cSJohnny Huang otp_soak(0); 199183655e91SJohnny Huang 199283655e91SJohnny Huang if (ret) { 1993737ed20bSJohnny Huang printf("OTPSTRAP[%d] is protected\n", input); 1994737ed20bSJohnny Huang return CMD_RET_SUCCESS; 1995737ed20bSJohnny Huang } 1996737ed20bSJohnny Huang 1997737ed20bSJohnny Huang printf("Protect OTPSTRAP[%d] fail\n", input); 1998737ed20bSJohnny Huang return CMD_RET_FAILURE; 1999737ed20bSJohnny Huang } 20009a4fe690SJohnny Huang 2001f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2002f67375f7SJohnny Huang { 2003f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2004f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2005f67375f7SJohnny Huang 2006f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2007f67375f7SJohnny Huang } 2008f67375f7SJohnny Huang 20092a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2010f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 20112a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2012a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2013de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 20142a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2015737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 20162a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 20172a856b9aSJohnny Huang }; 20182a856b9aSJohnny Huang 20192a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20202a856b9aSJohnny Huang { 20212a856b9aSJohnny Huang cmd_tbl_t *cp; 2022*a219f6deSJohnny Huang u32 ver; 20232a856b9aSJohnny Huang 20242a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 20252a856b9aSJohnny Huang 2026737ed20bSJohnny Huang /* Drop the otp command */ 20272a856b9aSJohnny Huang argc--; 20282a856b9aSJohnny Huang argv++; 20292a856b9aSJohnny Huang 2030*a219f6deSJohnny Huang if (!cp || argc > cp->maxargs) 20312a856b9aSJohnny Huang return CMD_RET_USAGE; 20322a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 20332a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20342a856b9aSJohnny Huang 20350dae9d52SJohnny Huang ver = chip_version(); 20360dae9d52SJohnny Huang switch (ver) { 20370dae9d52SJohnny Huang case OTP_AST2600A0: 2038696656c6SJohnny Huang info_cb.version = OTP_AST2600A0; 20399a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 20409a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 20419a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 20429a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 20439a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 20449a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 20450dae9d52SJohnny Huang break; 20460dae9d52SJohnny Huang case OTP_AST2600A1: 2047696656c6SJohnny Huang info_cb.version = OTP_AST2600A1; 20483cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 20493cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 20503cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 20513cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 20529a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 20539a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 20540dae9d52SJohnny Huang break; 20550dae9d52SJohnny Huang case OTP_AST2600A2: 20565fdde29fSJohnny Huang info_cb.version = OTP_AST2600A2; 20575fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 20585fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 20595fdde29fSJohnny Huang info_cb.strap_info = a2_strap_info; 20605fdde29fSJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 20615fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 20625fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 20630dae9d52SJohnny Huang break; 206464b66712SJohnny Huang case OTP_AST2600A3: 206564b66712SJohnny Huang info_cb.version = OTP_AST2600A3; 206664b66712SJohnny Huang info_cb.conf_info = a2_conf_info; 206764b66712SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 206864b66712SJohnny Huang info_cb.strap_info = a2_strap_info; 206964b66712SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 2070181f72d8SJohnny Huang info_cb.key_info = a3_key_type; 2071181f72d8SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a3_key_type); 207264b66712SJohnny Huang break; 20730dae9d52SJohnny Huang default: 2074f1be5099SJohnny Huang printf("SOC is not supported\n"); 20750dae9d52SJohnny Huang return CMD_RET_FAILURE; 20769a4fe690SJohnny Huang } 20779a4fe690SJohnny Huang 20782a856b9aSJohnny Huang return cp->cmd(cmdtp, flag, argc, argv); 207969d5fd8fSJohnny Huang } 208069d5fd8fSJohnny Huang 2081*a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0, do_ast_otp, 208269d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2083f67375f7SJohnny Huang "version\n" 2084f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 20852a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 20862d4b0742SJohnny Huang "otp info strap [v]\n" 20872d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 2088de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2089ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2090ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2091ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 20922a856b9aSJohnny Huang "otp cmp <addr> <otp_dw_offset>\n" 209369d5fd8fSJohnny Huang ); 2094