169d5fd8fSJohnny Huang /* 269d5fd8fSJohnny Huang * This program is distributed in the hope that it will be useful, 369d5fd8fSJohnny Huang * but WITHOUT ANY WARRANTY; without even the implied warranty of 469d5fd8fSJohnny Huang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 569d5fd8fSJohnny Huang * GNU General Public License for more details. 669d5fd8fSJohnny Huang * 769d5fd8fSJohnny Huang * You should have received a copy of the GNU General Public License 869d5fd8fSJohnny Huang * along with this program; if not, write to the Free Software 969d5fd8fSJohnny Huang * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1069d5fd8fSJohnny Huang */ 114c1c9b35SJohnny Huang #include <stdlib.h> 1269d5fd8fSJohnny Huang #include <common.h> 1369d5fd8fSJohnny Huang #include <console.h> 1469d5fd8fSJohnny Huang #include <bootretry.h> 1569d5fd8fSJohnny Huang #include <cli.h> 1669d5fd8fSJohnny Huang #include <command.h> 1769d5fd8fSJohnny Huang #include <console.h> 184c1c9b35SJohnny Huang #include <malloc.h> 1969d5fd8fSJohnny Huang #include <inttypes.h> 2069d5fd8fSJohnny Huang #include <mapmem.h> 2169d5fd8fSJohnny Huang #include <asm/io.h> 2269d5fd8fSJohnny Huang #include <linux/compiler.h> 23696656c6SJohnny Huang #include <u-boot/sha256.h> 240cee9a95SJohnny Huang #include "otp_info.h" 2569d5fd8fSJohnny Huang 2669d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2769d5fd8fSJohnny Huang 28*64b66712SJohnny Huang #define OTP_VER "1.0.3" 29f67375f7SJohnny Huang 3069d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 31dacbba92SJohnny Huang #define RETRY 20 327332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 337332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 347332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 3569d5fd8fSJohnny Huang 362a856b9aSJohnny Huang #define OTP_USAGE -1 372a856b9aSJohnny Huang #define OTP_FAILURE -2 382a856b9aSJohnny Huang #define OTP_SUCCESS 0 392a856b9aSJohnny Huang 40a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 41a6af4a17SJohnny Huang 429a4fe690SJohnny Huang #define OTP_KEY_TYPE_RSA 1 439a4fe690SJohnny Huang #define OTP_KEY_TYPE_AES 2 449a4fe690SJohnny Huang #define OTP_KEY_TYPE_VAULT 3 459a4fe690SJohnny Huang #define OTP_KEY_TYPE_HMAC 4 469a4fe690SJohnny Huang 474c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 484c1c9b35SJohnny Huang #define PBWIDTH 60 494c1c9b35SJohnny Huang 503d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 513d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 523d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 533d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 543d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 553d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 563d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 573d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 583d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 593d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 603d3688adSJohnny Huang 61696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 62696656c6SJohnny Huang #define CHECKSUM_LEN 32 63696656c6SJohnny Huang #define OTP_INC_DATA (1 << 31) 64696656c6SJohnny Huang #define OTP_INC_CONFIG (1 << 30) 65696656c6SJohnny Huang #define OTP_INC_STRAP (1 << 29) 66696656c6SJohnny Huang #define OTP_ECC_EN (1 << 28) 67696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 68696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 69696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 70696656c6SJohnny Huang 71696656c6SJohnny Huang #define OTP_AST2600A0 0 72696656c6SJohnny Huang #define OTP_AST2600A1 1 730dae9d52SJohnny Huang #define OTP_AST2600A2 2 74*64b66712SJohnny Huang #define OTP_AST2600A3 3 75696656c6SJohnny Huang 76696656c6SJohnny Huang struct otp_header { 77696656c6SJohnny Huang u8 otp_magic[8]; 78696656c6SJohnny Huang u8 otp_version[8]; 79696656c6SJohnny Huang u32 image_info; 80696656c6SJohnny Huang u32 data_info; 81696656c6SJohnny Huang u32 config_info; 82696656c6SJohnny Huang u32 strap_info; 83696656c6SJohnny Huang u32 checksum_offset; 84696656c6SJohnny Huang } __attribute__((packed)); 85696656c6SJohnny Huang 8666f2f8e5SJohnny Huang struct otpstrap_status { 8769d5fd8fSJohnny Huang int value; 8869d5fd8fSJohnny Huang int option_array[7]; 8969d5fd8fSJohnny Huang int remain_times; 9069d5fd8fSJohnny Huang int writeable_option; 915010032bSJohnny Huang int reg_protected; 9269d5fd8fSJohnny Huang int protected; 9369d5fd8fSJohnny Huang }; 9469d5fd8fSJohnny Huang 9566f2f8e5SJohnny Huang struct otpconf_parse { 9666f2f8e5SJohnny Huang int dw_offset; 9766f2f8e5SJohnny Huang int bit; 9866f2f8e5SJohnny Huang int length; 9966f2f8e5SJohnny Huang int value; 100696656c6SJohnny Huang int ignore; 10166f2f8e5SJohnny Huang char status[80]; 10266f2f8e5SJohnny Huang }; 10366f2f8e5SJohnny Huang 1049a4fe690SJohnny Huang struct otpkey_type { 1059a4fe690SJohnny Huang int value; 1069a4fe690SJohnny Huang int key_type; 1079a4fe690SJohnny Huang int need_id; 1089a4fe690SJohnny Huang char information[110]; 1099a4fe690SJohnny Huang }; 1109a4fe690SJohnny Huang 1119a4fe690SJohnny Huang struct otp_info_cb { 1129a4fe690SJohnny Huang int version; 11379e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1149a4fe690SJohnny Huang int strap_info_len; 11579e42a59SJoel Stanley const struct otpconf_info *conf_info; 1169a4fe690SJohnny Huang int conf_info_len; 11779e42a59SJoel Stanley const struct otpkey_type *key_info; 1189a4fe690SJohnny Huang int key_info_len; 1195010032bSJohnny Huang 1209a4fe690SJohnny Huang }; 1219a4fe690SJohnny Huang 122696656c6SJohnny Huang struct otp_image_layout { 1235010032bSJohnny Huang int data_length; 1245010032bSJohnny Huang int conf_length; 1255010032bSJohnny Huang int strap_length; 126696656c6SJohnny Huang uint8_t *data; 127696656c6SJohnny Huang uint8_t *data_ignore; 128696656c6SJohnny Huang uint8_t *conf; 129696656c6SJohnny Huang uint8_t *conf_ignore; 130696656c6SJohnny Huang uint8_t *strap; 131696656c6SJohnny Huang uint8_t *strap_reg_pro; 132696656c6SJohnny Huang uint8_t *strap_pro; 133696656c6SJohnny Huang uint8_t *strap_ignore; 134696656c6SJohnny Huang }; 135696656c6SJohnny Huang 1369a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1379a4fe690SJohnny Huang 13879e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1399a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1409a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1419a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 1429a4fe690SJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1439a4fe690SJohnny Huang {9, OTP_KEY_TYPE_RSA, 0, "RSA-public as SOC public key"}, 1449a4fe690SJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1459a4fe690SJohnny Huang {13, OTP_KEY_TYPE_RSA, 0, "RSA-private as SOC private key"}, 1469a4fe690SJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1479a4fe690SJohnny Huang }; 1489a4fe690SJohnny Huang 14979e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1509a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1519a4fe690SJohnny 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"}, 1529a4fe690SJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1539a4fe690SJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1549a4fe690SJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1559a4fe690SJohnny Huang }; 1569a4fe690SJohnny Huang 1575fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1585fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1595fdde29fSJohnny 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"}, 1605fdde29fSJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1615fdde29fSJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1625fdde29fSJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1635fdde29fSJohnny Huang }; 1645fdde29fSJohnny Huang 1659a4fe690SJohnny Huang static uint32_t chip_version(void) 1669a4fe690SJohnny Huang { 167badd21c2SJohnny Huang u64 rev_id; 1689a4fe690SJohnny Huang 169badd21c2SJohnny Huang rev_id = readl(ASPEED_REVISION_ID0); 170badd21c2SJohnny Huang rev_id = ((u64)readl(ASPEED_REVISION_ID1) << 32) | rev_id; 1719a4fe690SJohnny Huang 172badd21c2SJohnny Huang if (rev_id == 0x0500030305000303) { 173badd21c2SJohnny Huang /* AST2600-A0 */ 1740dae9d52SJohnny Huang return OTP_AST2600A0; 175badd21c2SJohnny Huang } else if (rev_id == 0x0501030305010303) { 176badd21c2SJohnny Huang /* AST2600-A1 */ 1770dae9d52SJohnny Huang return OTP_AST2600A1; 178badd21c2SJohnny Huang } else if (rev_id == 0x0501020305010203) { 179badd21c2SJohnny Huang /* AST2620-A1 */ 180badd21c2SJohnny Huang return OTP_AST2600A1; 181badd21c2SJohnny Huang } else if (rev_id == 0x0502030305010303) { 182badd21c2SJohnny Huang /* AST2600-A2 */ 1830dae9d52SJohnny Huang return OTP_AST2600A2; 184badd21c2SJohnny Huang } else if (rev_id == 0x0502020305010203) { 185badd21c2SJohnny Huang /* AST2620-A2 */ 186badd21c2SJohnny Huang return OTP_AST2600A2; 187badd21c2SJohnny Huang } else if (rev_id == 0x0502010305010103) { 188badd21c2SJohnny Huang /* AST2605-A2 */ 1890dae9d52SJohnny Huang return OTP_AST2600A2; 190*64b66712SJohnny Huang } else if (rev_id == 0x0503030305030303) { 191*64b66712SJohnny Huang /* AST2600-A3 */ 192*64b66712SJohnny Huang return OTP_AST2600A3; 193*64b66712SJohnny Huang } else if (rev_id == 0x0503020305030203) { 194*64b66712SJohnny Huang /* AST2620-A3 */ 195*64b66712SJohnny Huang return OTP_AST2600A3; 1960dae9d52SJohnny Huang } 1970dae9d52SJohnny Huang 1985fdde29fSJohnny Huang return -1; 1999a4fe690SJohnny Huang } 2009a4fe690SJohnny Huang 2013d3688adSJohnny Huang static void wait_complete(void) 2023d3688adSJohnny Huang { 2033d3688adSJohnny Huang int reg; 2043d3688adSJohnny Huang 2053d3688adSJohnny Huang do { 2063d3688adSJohnny Huang reg = readl(OTP_STATUS); 2073d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 2083d3688adSJohnny Huang } 2093d3688adSJohnny Huang 210dacbba92SJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data) 211dacbba92SJohnny Huang { 212dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 213dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 214dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 215dacbba92SJohnny Huang wait_complete(); 216dacbba92SJohnny Huang } 217dacbba92SJohnny Huang 218dacbba92SJohnny Huang static void otp_soak(int soak) 219dacbba92SJohnny Huang { 220*64b66712SJohnny Huang if (info_cb.version == OTP_AST2600A2 || info_cb.version == OTP_AST2600A3) { 221dacbba92SJohnny Huang switch (soak) { 222dacbba92SJohnny Huang case 0: //default 223dacbba92SJohnny Huang otp_write(0x3000, 0x0210); // Write MRA 224dacbba92SJohnny Huang otp_write(0x5000, 0x2000); // Write MRB 225dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 226dacbba92SJohnny Huang break; 227dacbba92SJohnny Huang case 1: //normal program 228dacbba92SJohnny Huang otp_write(0x3000, 0x1200); // Write MRA 229feea3fdfSJohnny Huang otp_write(0x5000, 0x107F); // Write MRB 230dacbba92SJohnny Huang otp_write(0x1000, 0x1024); // Write MR 231feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 232dacbba92SJohnny Huang break; 233dacbba92SJohnny Huang case 2: //soak program 234dacbba92SJohnny Huang otp_write(0x3000, 0x1220); // Write MRA 235feea3fdfSJohnny Huang otp_write(0x5000, 0x2074); // Write MRB 236dacbba92SJohnny Huang otp_write(0x1000, 0x08a4); // Write MR 237feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 238dacbba92SJohnny Huang break; 239dacbba92SJohnny Huang } 240dacbba92SJohnny Huang } else { 241dacbba92SJohnny Huang switch (soak) { 242dacbba92SJohnny Huang case 0: //default 243dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 244dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 245dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 246dacbba92SJohnny Huang break; 247dacbba92SJohnny Huang case 1: //normal program 248dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 249dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 250dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 251feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 252dacbba92SJohnny Huang break; 253dacbba92SJohnny Huang case 2: //soak program 254dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 255dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 256dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 257feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 258dacbba92SJohnny Huang break; 259dacbba92SJohnny Huang } 260dacbba92SJohnny Huang } 261dacbba92SJohnny Huang 262dacbba92SJohnny Huang wait_complete(); 263dacbba92SJohnny Huang } 264dacbba92SJohnny Huang 2652a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data) 26669d5fd8fSJohnny Huang { 2673d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 2683d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2693d3688adSJohnny Huang wait_complete(); 2703d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 2713d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 27269d5fd8fSJohnny Huang } 27369d5fd8fSJohnny Huang 2742a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data) 27569d5fd8fSJohnny Huang { 27669d5fd8fSJohnny Huang int config_offset; 27769d5fd8fSJohnny Huang 27869d5fd8fSJohnny Huang config_offset = 0x800; 27969d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 28069d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 28169d5fd8fSJohnny Huang 2823d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 2833d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2843d3688adSJohnny Huang wait_complete(); 2853d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 28669d5fd8fSJohnny Huang } 28769d5fd8fSJohnny Huang 28869d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count) 28969d5fd8fSJohnny Huang { 29069d5fd8fSJohnny Huang int i; 29169d5fd8fSJohnny Huang uint32_t ret[1]; 29269d5fd8fSJohnny Huang 29369d5fd8fSJohnny Huang if (offset + dw_count > 32) 2942a856b9aSJohnny Huang return OTP_USAGE; 295dacbba92SJohnny Huang otp_soak(0); 29669d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i ++) { 29769d5fd8fSJohnny Huang otp_read_config(i, ret); 298a6af4a17SJohnny Huang printf("OTPCFG%X: %08X\n", i, ret[0]); 29969d5fd8fSJohnny Huang } 30069d5fd8fSJohnny Huang printf("\n"); 3012a856b9aSJohnny Huang return OTP_SUCCESS; 30269d5fd8fSJohnny Huang } 30369d5fd8fSJohnny Huang 30469d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count) 30569d5fd8fSJohnny Huang { 30669d5fd8fSJohnny Huang int i; 30769d5fd8fSJohnny Huang uint32_t ret[2]; 30869d5fd8fSJohnny Huang 30969d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 3102a856b9aSJohnny Huang return OTP_USAGE; 311dacbba92SJohnny Huang otp_soak(0); 31269d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 31369d5fd8fSJohnny Huang otp_read_data(i, ret); 31469d5fd8fSJohnny Huang if (i % 4 == 0) 31569d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 31669d5fd8fSJohnny Huang else 31769d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 31869d5fd8fSJohnny Huang 31969d5fd8fSJohnny Huang } 32069d5fd8fSJohnny Huang printf("\n"); 3212a856b9aSJohnny Huang return OTP_SUCCESS; 32269d5fd8fSJohnny Huang } 32369d5fd8fSJohnny Huang 32469d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr) 32569d5fd8fSJohnny Huang { 32669d5fd8fSJohnny Huang uint32_t ret; 32769d5fd8fSJohnny Huang uint32_t *buf; 32869d5fd8fSJohnny Huang 32969d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 33069d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 33169d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 33269d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 33369d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 3343d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 3353d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 3363d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 3373d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 3383d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 3393d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 3403d3688adSJohnny Huang wait_complete(); 3413d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 34269d5fd8fSJohnny Huang if (ret & 0x1) 34369d5fd8fSJohnny Huang return 0; 34469d5fd8fSJohnny Huang else 34569d5fd8fSJohnny Huang return -1; 34669d5fd8fSJohnny Huang } 34769d5fd8fSJohnny Huang 348a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value) 34969d5fd8fSJohnny Huang { 35030a8c590SJohnny Huang uint32_t ret[2]; 35169d5fd8fSJohnny Huang 35230a8c590SJohnny Huang if (otp_addr % 2 == 0) 3533d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 35430a8c590SJohnny Huang else 3553d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 35630a8c590SJohnny Huang 3573d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3583d3688adSJohnny Huang wait_complete(); 3593d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 3603d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 36183655e91SJohnny Huang 36230a8c590SJohnny Huang if (otp_addr % 2 == 0) { 36330a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 36469d5fd8fSJohnny Huang return 0; 36569d5fd8fSJohnny Huang else 36669d5fd8fSJohnny Huang return -1; 36730a8c590SJohnny Huang } else { 36830a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 36930a8c590SJohnny Huang return 0; 37030a8c590SJohnny Huang else 37130a8c590SJohnny Huang return -1; 37230a8c590SJohnny Huang } 37330a8c590SJohnny Huang 37469d5fd8fSJohnny Huang } 37569d5fd8fSJohnny Huang 376696656c6SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *ignore, uint32_t *compare, int size) 3774c1c9b35SJohnny Huang { 3784c1c9b35SJohnny Huang uint32_t ret[2]; 3794c1c9b35SJohnny Huang 3804c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 3814c1c9b35SJohnny Huang 3824c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 3833d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 3844c1c9b35SJohnny Huang else 3853d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 3863d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3873d3688adSJohnny Huang wait_complete(); 3883d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 3893d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 3904c1c9b35SJohnny Huang if (size == 1) { 3914c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 3924c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 393696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 3944c1c9b35SJohnny Huang compare[0] = 0; 3954c1c9b35SJohnny Huang return 0; 3964c1c9b35SJohnny Huang } else { 3974c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 3984c1c9b35SJohnny Huang return -1; 3994c1c9b35SJohnny Huang } 4004c1c9b35SJohnny Huang 4014c1c9b35SJohnny Huang } else { 4024c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 403696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 4044c1c9b35SJohnny Huang compare[0] = ~0; 4054c1c9b35SJohnny Huang return 0; 4064c1c9b35SJohnny Huang } else { 407d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 4084c1c9b35SJohnny Huang return -1; 4094c1c9b35SJohnny Huang } 4104c1c9b35SJohnny Huang } 4114c1c9b35SJohnny Huang } else if (size == 2) { 4124c1c9b35SJohnny Huang // otp_addr should be even 413696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 4144c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4154c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4164c1c9b35SJohnny Huang compare[0] = 0; 4174c1c9b35SJohnny Huang compare[1] = ~0; 4184c1c9b35SJohnny Huang return 0; 4194c1c9b35SJohnny Huang } else { 4204c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4214c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4224c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4234c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 4244c1c9b35SJohnny Huang return -1; 4254c1c9b35SJohnny Huang } 4264c1c9b35SJohnny Huang } else { 4274c1c9b35SJohnny Huang return -1; 4284c1c9b35SJohnny Huang } 4294c1c9b35SJohnny Huang } 4304c1c9b35SJohnny Huang 43183655e91SJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit) 43283655e91SJohnny Huang { 43390965bb3SJohnny Huang otp_write(0x0, prog_bit); 43483655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 43583655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 43683655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 43783655e91SJohnny Huang wait_complete(); 43883655e91SJohnny Huang } 43983655e91SJohnny Huang 44083655e91SJohnny Huang static void _otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset) 44183655e91SJohnny Huang { 44283655e91SJohnny Huang int prog_bit; 44383655e91SJohnny Huang 44483655e91SJohnny Huang if (prog_address % 2 == 0) { 44583655e91SJohnny Huang if (value) 44683655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 44783655e91SJohnny Huang else 44883655e91SJohnny Huang return; 44983655e91SJohnny Huang } else { 450*64b66712SJohnny Huang if (info_cb.version != OTP_AST2600A3) 45183655e91SJohnny Huang prog_address |= 1 << 15; 45283655e91SJohnny Huang if (!value) 45383655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 45483655e91SJohnny Huang else 45583655e91SJohnny Huang return; 45683655e91SJohnny Huang } 45783655e91SJohnny Huang otp_prog(prog_address, prog_bit); 45883655e91SJohnny Huang } 45983655e91SJohnny Huang 46083655e91SJohnny Huang static int otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset) 46183655e91SJohnny Huang { 46283655e91SJohnny Huang int pass; 46383655e91SJohnny Huang int i; 46483655e91SJohnny Huang 46583655e91SJohnny Huang otp_soak(1); 46683655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 46783655e91SJohnny Huang pass = 0; 46883655e91SJohnny Huang 46983655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 47083655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 47183655e91SJohnny Huang otp_soak(2); 47283655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 47383655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 47483655e91SJohnny Huang otp_soak(1); 47583655e91SJohnny Huang } else { 47683655e91SJohnny Huang pass = 1; 47783655e91SJohnny Huang break; 47883655e91SJohnny Huang } 47983655e91SJohnny Huang } else { 48083655e91SJohnny Huang pass = 1; 48183655e91SJohnny Huang break; 48283655e91SJohnny Huang } 48383655e91SJohnny Huang } 48483655e91SJohnny Huang 48583655e91SJohnny Huang return pass; 48683655e91SJohnny Huang } 48783655e91SJohnny Huang 488696656c6SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t ignore, uint32_t prog_address) 489d90825e2SJohnny Huang { 490d90825e2SJohnny Huang int j, bit_value, prog_bit; 491d90825e2SJohnny Huang 492d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 493696656c6SJohnny Huang if ((ignore >> j) & 0x1) 494d90825e2SJohnny Huang continue; 495d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 496d90825e2SJohnny Huang if (prog_address % 2 == 0) { 497d90825e2SJohnny Huang if (bit_value) 498d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 499d90825e2SJohnny Huang else 500d90825e2SJohnny Huang continue; 501d90825e2SJohnny Huang } else { 502*64b66712SJohnny Huang if (info_cb.version != OTP_AST2600A3) 503d90825e2SJohnny Huang prog_address |= 1 << 15; 504d90825e2SJohnny Huang if (bit_value) 505d90825e2SJohnny Huang continue; 506d90825e2SJohnny Huang else 507d90825e2SJohnny Huang prog_bit = 0x1 << j; 508d90825e2SJohnny Huang } 509d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 510d90825e2SJohnny Huang } 511d90825e2SJohnny Huang } 512d90825e2SJohnny Huang 51354552c69SJohnny Huang static int otp_prog_verify_2dw(uint32_t *data, uint32_t *buf, uint32_t *ignore_mask, uint32_t prog_address) 51454552c69SJohnny Huang { 51554552c69SJohnny Huang int pass; 51654552c69SJohnny Huang int i; 51754552c69SJohnny Huang uint32_t data0_masked; 51854552c69SJohnny Huang uint32_t data1_masked; 51954552c69SJohnny Huang uint32_t buf0_masked; 52054552c69SJohnny Huang uint32_t buf1_masked; 52154552c69SJohnny Huang uint32_t compare[2]; 52254552c69SJohnny Huang 52354552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 52454552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 52554552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 52654552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 52754552c69SJohnny Huang if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) 52854552c69SJohnny Huang return 0; 52954552c69SJohnny Huang 53054552c69SJohnny Huang otp_soak(1); 53154552c69SJohnny Huang if (data0_masked != buf0_masked) 53254552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 53354552c69SJohnny Huang if (data1_masked != buf1_masked) 53454552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 53554552c69SJohnny Huang 53654552c69SJohnny Huang pass = 0; 53754552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 53854552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 53954552c69SJohnny Huang otp_soak(2); 54054552c69SJohnny Huang if (compare[0] != 0) { 54154552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 54254552c69SJohnny Huang } 54354552c69SJohnny Huang if (compare[1] != ~0) { 5445537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 54554552c69SJohnny Huang } 54654552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 54754552c69SJohnny Huang otp_soak(1); 54854552c69SJohnny Huang } else { 54954552c69SJohnny Huang pass = 1; 55054552c69SJohnny Huang break; 55154552c69SJohnny Huang } 55254552c69SJohnny Huang } else { 55354552c69SJohnny Huang pass = 1; 55454552c69SJohnny Huang break; 55554552c69SJohnny Huang } 55654552c69SJohnny Huang } 55754552c69SJohnny Huang 55854552c69SJohnny Huang if (!pass) { 55954552c69SJohnny Huang otp_soak(0); 56054552c69SJohnny Huang return OTP_FAILURE; 56154552c69SJohnny Huang } 56254552c69SJohnny Huang return OTP_SUCCESS; 56354552c69SJohnny Huang } 56454552c69SJohnny Huang 565541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 56676d13988SJohnny Huang { 56776d13988SJohnny Huang uint32_t OTPSTRAP_RAW[2]; 5685010032bSJohnny Huang int strap_end; 56976d13988SJohnny Huang int i, j; 57076d13988SJohnny Huang 5715010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 57276d13988SJohnny Huang for (j = 0; j < 64; j++) { 57376d13988SJohnny Huang otpstrap[j].value = 0; 57476d13988SJohnny Huang otpstrap[j].remain_times = 7; 57576d13988SJohnny Huang otpstrap[j].writeable_option = -1; 57676d13988SJohnny Huang otpstrap[j].protected = 0; 57776d13988SJohnny Huang } 5785010032bSJohnny Huang strap_end = 30; 5795010032bSJohnny Huang } else { 5805010032bSJohnny Huang for (j = 0; j < 64; j++) { 5815010032bSJohnny Huang otpstrap[j].value = 0; 5825010032bSJohnny Huang otpstrap[j].remain_times = 6; 5835010032bSJohnny Huang otpstrap[j].writeable_option = -1; 5845010032bSJohnny Huang otpstrap[j].reg_protected = 0; 5855010032bSJohnny Huang otpstrap[j].protected = 0; 5865010032bSJohnny Huang } 5875010032bSJohnny Huang strap_end = 28; 5885010032bSJohnny Huang } 58976d13988SJohnny Huang 590dacbba92SJohnny Huang otp_soak(0); 5915010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 59276d13988SJohnny Huang int option = (i - 16) / 2; 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); 59776d13988SJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 59876d13988SJohnny Huang otpstrap[j].writeable_option = option; 59976d13988SJohnny Huang } 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); 60776d13988SJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 60876d13988SJohnny Huang otpstrap[j].writeable_option = option; 60976d13988SJohnny Huang } 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 } 6305010032bSJohnny Huang 63176d13988SJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 63276d13988SJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 63376d13988SJohnny Huang for (j = 0; j < 32; j++) { 63476d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 63576d13988SJohnny Huang otpstrap[j].protected = 1; 63676d13988SJohnny Huang } 63776d13988SJohnny Huang for (j = 32; j < 64; j++) { 63876d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 63976d13988SJohnny Huang otpstrap[j].protected = 1; 64076d13988SJohnny Huang } 64176d13988SJohnny Huang } 64276d13988SJohnny Huang 643696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 64469d5fd8fSJohnny Huang { 64579e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 646696656c6SJohnny Huang uint32_t *OTPCFG = (uint32_t *)image_layout->conf; 647696656c6SJohnny Huang uint32_t *OTPCFG_IGNORE = (uint32_t *)image_layout->conf_ignore; 648b458cd62SJohnny Huang uint32_t mask; 649b458cd62SJohnny Huang uint32_t dw_offset; 650b458cd62SJohnny Huang uint32_t bit_offset; 651b458cd62SJohnny Huang uint32_t otp_value; 652696656c6SJohnny Huang uint32_t otp_ignore; 653b458cd62SJohnny Huang int fail = 0; 65473f11549SJohnny Huang char valid_bit[20]; 65566f2f8e5SJohnny Huang int i; 65673f11549SJohnny Huang int j; 65766f2f8e5SJohnny Huang 658737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 65966f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 6603cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 6613cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 6623cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 6633cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 664b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 665696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 666b458cd62SJohnny Huang 667696656c6SJohnny Huang if (otp_ignore == mask) { 668b458cd62SJohnny Huang continue; 669696656c6SJohnny Huang } else if (otp_ignore != 0) { 670b458cd62SJohnny Huang fail = 1; 671b458cd62SJohnny Huang } 672b458cd62SJohnny Huang 6733cb28812SJohnny Huang if ((otp_value != conf_info[i].value) && 6743cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 6753cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 6763cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 677b458cd62SJohnny Huang continue; 678b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 679b458cd62SJohnny Huang 6803cb28812SJohnny Huang if (conf_info[i].length == 1) { 6813cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 68266f2f8e5SJohnny Huang } else { 683b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 6843cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 6853cb28812SJohnny Huang conf_info[i].bit_offset); 68666f2f8e5SJohnny Huang } 687b458cd62SJohnny Huang printf("0x%-10x", otp_value); 688b458cd62SJohnny Huang 689b458cd62SJohnny Huang if (fail) { 690696656c6SJohnny Huang printf("Ignore mask error\n"); 691b458cd62SJohnny Huang } else { 6923cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 693b458cd62SJohnny Huang printf("Reserved\n"); 6943cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 6953cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 696b458cd62SJohnny Huang printf("\n"); 6973cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 698b458cd62SJohnny Huang if (otp_value != 0) { 69973f11549SJohnny Huang for (j = 0; j < 7; j++) { 70073f11549SJohnny Huang if (otp_value == (1 << j)) { 70173f11549SJohnny Huang valid_bit[j * 2] = '1'; 702b458cd62SJohnny Huang } else { 70373f11549SJohnny Huang valid_bit[j * 2] = '0'; 70473f11549SJohnny Huang } 70573f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 70673f11549SJohnny Huang } 70773f11549SJohnny Huang valid_bit[15] = 0; 70873f11549SJohnny Huang } else { 70973f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 710b458cd62SJohnny Huang } 7113cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 712b458cd62SJohnny Huang printf("\n"); 713b458cd62SJohnny Huang } else { 7143cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 715b458cd62SJohnny Huang } 716b458cd62SJohnny Huang } 717b458cd62SJohnny Huang } 718b458cd62SJohnny Huang 719b458cd62SJohnny Huang if (fail) 720b458cd62SJohnny Huang return OTP_FAILURE; 721b458cd62SJohnny Huang 72266f2f8e5SJohnny Huang return OTP_SUCCESS; 72366f2f8e5SJohnny Huang } 72466f2f8e5SJohnny Huang 7252d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 72666f2f8e5SJohnny Huang { 72779e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 728bb34a7bfSJohnny Huang uint32_t OTPCFG[16]; 729b458cd62SJohnny Huang uint32_t mask; 730b458cd62SJohnny Huang uint32_t dw_offset; 731b458cd62SJohnny Huang uint32_t bit_offset; 732b458cd62SJohnny Huang uint32_t otp_value; 73373f11549SJohnny Huang char valid_bit[20]; 73466f2f8e5SJohnny Huang int i; 73573f11549SJohnny Huang int j; 73666f2f8e5SJohnny Huang 737dacbba92SJohnny Huang otp_soak(0); 738bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 73966f2f8e5SJohnny Huang otp_read_config(i, &OTPCFG[i]); 74066f2f8e5SJohnny Huang 74166f2f8e5SJohnny Huang 742b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 743b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 7443cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 7453cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 7462d4b0742SJohnny Huang continue; 7473cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 7483cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 7493cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 750b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 751b458cd62SJohnny Huang 7523cb28812SJohnny Huang if ((otp_value != conf_info[i].value) && 7533cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 7543cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 7553cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 756b458cd62SJohnny Huang continue; 757b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 758b458cd62SJohnny Huang 7593cb28812SJohnny Huang if (conf_info[i].length == 1) { 7603cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 761b458cd62SJohnny Huang } else { 762b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 7633cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 7643cb28812SJohnny Huang conf_info[i].bit_offset); 765b458cd62SJohnny Huang } 766b458cd62SJohnny Huang printf("0x%-10x", otp_value); 767b458cd62SJohnny Huang 7683cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 769b458cd62SJohnny Huang printf("Reserved\n"); 7703cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 7713cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 772b458cd62SJohnny Huang printf("\n"); 7733cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 774b458cd62SJohnny Huang if (otp_value != 0) { 77573f11549SJohnny Huang for (j = 0; j < 7; j++) { 77673f11549SJohnny Huang if (otp_value == (1 << j)) { 77773f11549SJohnny Huang valid_bit[j * 2] = '1'; 778b458cd62SJohnny Huang } else { 77973f11549SJohnny Huang valid_bit[j * 2] = '0'; 78073f11549SJohnny Huang } 78173f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 78273f11549SJohnny Huang } 78373f11549SJohnny Huang valid_bit[15] = 0; 78473f11549SJohnny Huang } else { 78573f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 786b458cd62SJohnny Huang } 7873cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 788b458cd62SJohnny Huang printf("\n"); 789b458cd62SJohnny Huang } else { 7903cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 791b458cd62SJohnny Huang } 792b458cd62SJohnny Huang } 793b458cd62SJohnny Huang return OTP_SUCCESS; 79466f2f8e5SJohnny Huang } 79566f2f8e5SJohnny Huang 7965010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 79776d13988SJohnny Huang { 79879e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 799696656c6SJohnny Huang uint32_t *OTPSTRAP; 800696656c6SJohnny Huang uint32_t *OTPSTRAP_REG_PRO; 801696656c6SJohnny Huang uint32_t *OTPSTRAP_PRO; 802696656c6SJohnny Huang uint32_t *OTPSTRAP_IGNORE; 80376d13988SJohnny Huang int i; 804a8bd6d8cSJohnny Huang int fail = 0; 805a8bd6d8cSJohnny Huang uint32_t bit_offset; 806a8bd6d8cSJohnny Huang uint32_t dw_offset; 807a8bd6d8cSJohnny Huang uint32_t mask; 808a8bd6d8cSJohnny Huang uint32_t otp_value; 809696656c6SJohnny Huang uint32_t otp_reg_protect; 810a8bd6d8cSJohnny Huang uint32_t otp_protect; 811696656c6SJohnny Huang uint32_t otp_ignore; 81276d13988SJohnny Huang 813696656c6SJohnny Huang OTPSTRAP = (uint32_t *)image_layout->strap; 814696656c6SJohnny Huang OTPSTRAP_PRO = (uint32_t *)image_layout->strap_pro; 815696656c6SJohnny Huang OTPSTRAP_IGNORE = (uint32_t *)image_layout->strap_ignore; 8165010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 817696656c6SJohnny Huang OTPSTRAP_REG_PRO = NULL; 818a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 819696656c6SJohnny Huang } else { 820696656c6SJohnny Huang OTPSTRAP_REG_PRO = (uint32_t *)image_layout->strap_reg_pro; 821de6b0cc4SJohnny Huang printf("BIT(hex) Value Reg_Protect Protect Description\n"); 822696656c6SJohnny Huang } 823de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 824b458cd62SJohnny Huang 8253cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 826696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 827a8bd6d8cSJohnny Huang dw_offset = 1; 8283cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 829a8bd6d8cSJohnny Huang } else { 830a8bd6d8cSJohnny Huang dw_offset = 0; 8313cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 832a8bd6d8cSJohnny Huang } 83376d13988SJohnny Huang 8343cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 835a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 836a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 837696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 838a8bd6d8cSJohnny Huang 8395010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 840696656c6SJohnny Huang otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask; 8415010032bSJohnny Huang else 8425010032bSJohnny Huang otp_reg_protect = 0; 843696656c6SJohnny Huang 844696656c6SJohnny Huang if (otp_ignore == mask) { 845a8bd6d8cSJohnny Huang continue; 846696656c6SJohnny Huang } else if (otp_ignore != 0) { 847a8bd6d8cSJohnny Huang fail = 1; 848a8bd6d8cSJohnny Huang } 849a8bd6d8cSJohnny Huang 8503cb28812SJohnny Huang if ((otp_value != strap_info[i].value) && 8513cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 852a8bd6d8cSJohnny Huang continue; 853a8bd6d8cSJohnny Huang 8543cb28812SJohnny Huang if (strap_info[i].length == 1) { 8553cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 856a8bd6d8cSJohnny Huang } else { 857b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 8583cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 8593cb28812SJohnny Huang strap_info[i].bit_offset); 860a8bd6d8cSJohnny Huang } 861a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 8625010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 863696656c6SJohnny Huang printf("0x%-10x", otp_reg_protect); 864a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 865a8bd6d8cSJohnny Huang 866a8bd6d8cSJohnny Huang if (fail) { 867696656c6SJohnny Huang printf("Ignore mask error\n"); 868a8bd6d8cSJohnny Huang } else { 8693cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 8703cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 871a8bd6d8cSJohnny Huang else 872a8bd6d8cSJohnny Huang printf("Reserved\n"); 873a8bd6d8cSJohnny Huang } 874a8bd6d8cSJohnny Huang } 875a8bd6d8cSJohnny Huang 876a8bd6d8cSJohnny Huang if (fail) 87776d13988SJohnny Huang return OTP_FAILURE; 87876d13988SJohnny Huang 87976d13988SJohnny Huang return OTP_SUCCESS; 88076d13988SJohnny Huang } 88176d13988SJohnny Huang 882b458cd62SJohnny Huang static int otp_print_strap_info(int view) 88376d13988SJohnny Huang { 88479e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 88576d13988SJohnny Huang struct otpstrap_status strap_status[64]; 88607baa4e8SJohnny Huang int i, j; 887b458cd62SJohnny Huang int fail = 0; 888b458cd62SJohnny Huang uint32_t bit_offset; 889b458cd62SJohnny Huang uint32_t length; 890b458cd62SJohnny Huang uint32_t otp_value; 891b458cd62SJohnny Huang uint32_t otp_protect; 89276d13988SJohnny Huang 893541eb887SJohnny Huang otp_strap_status(strap_status); 89476d13988SJohnny Huang 895b458cd62SJohnny Huang if (view) { 89683655e91SJohnny Huang if (info_cb.version == OTP_AST2600A0) 89707baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 89883655e91SJohnny Huang else 89983655e91SJohnny Huang printf("BIT(hex) Value Remains Reg_Protect Protect Description\n"); 90007baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 901b458cd62SJohnny Huang } else { 902b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 903b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 90476d13988SJohnny Huang } 9053cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 906b458cd62SJohnny Huang otp_value = 0; 9073cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 9083cb28812SJohnny Huang length = strap_info[i].length; 909b458cd62SJohnny Huang for (j = 0; j < length; j++) { 910c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 911c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 912b458cd62SJohnny Huang } 9133cb28812SJohnny Huang if ((otp_value != strap_info[i].value) && 9143cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 915b458cd62SJohnny Huang continue; 916b458cd62SJohnny Huang if (view) { 917b458cd62SJohnny Huang for (j = 0; j < length; j++) { 9183cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 919b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 92007baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 92183655e91SJohnny Huang if (info_cb.version != OTP_AST2600A0) 922e1a7245eSJohnny Huang printf("0x%-10X", strap_status[bit_offset + j].reg_protected); 923e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 9243cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 925b458cd62SJohnny Huang printf(" Reserved\n"); 926b458cd62SJohnny Huang continue; 927b458cd62SJohnny Huang } 928b458cd62SJohnny Huang if (length == 1) { 9293cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 930b458cd62SJohnny Huang continue; 93176d13988SJohnny Huang } 93276d13988SJohnny Huang 933b458cd62SJohnny Huang if (j == 0) 9343cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 935b458cd62SJohnny Huang else if (j == length - 1) 936b458cd62SJohnny Huang printf("\\ \"\n"); 937b458cd62SJohnny Huang else 938b458cd62SJohnny Huang printf("| \"\n"); 93976d13988SJohnny Huang } 940b458cd62SJohnny Huang } else { 941c947ef08SJohnny Huang if (length == 1) { 9423cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 943b458cd62SJohnny Huang } else { 944b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 945b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 946b458cd62SJohnny Huang } 947b458cd62SJohnny Huang 948b458cd62SJohnny Huang printf("0x%-10X", otp_value); 949b458cd62SJohnny Huang 9503cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 9513cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 952b458cd62SJohnny Huang else 953b458cd62SJohnny Huang printf("Reserved\n"); 954b458cd62SJohnny Huang } 955b458cd62SJohnny Huang } 956b458cd62SJohnny Huang 957b458cd62SJohnny Huang if (fail) 958b458cd62SJohnny Huang return OTP_FAILURE; 959b458cd62SJohnny Huang 960b458cd62SJohnny Huang return OTP_SUCCESS; 961b458cd62SJohnny Huang } 962b458cd62SJohnny Huang 963696656c6SJohnny Huang static void buf_print(uint8_t *buf, int len) 96469d5fd8fSJohnny Huang { 96569d5fd8fSJohnny Huang int i; 96669d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 96769d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 96869d5fd8fSJohnny Huang if (i % 16 == 0) { 96969d5fd8fSJohnny Huang printf("%04X: ", i); 97069d5fd8fSJohnny Huang } 97169d5fd8fSJohnny Huang printf("%02X ", buf[i]); 97269d5fd8fSJohnny Huang if ((i + 1) % 16 == 0) { 97369d5fd8fSJohnny Huang printf("\n"); 97469d5fd8fSJohnny Huang } 97569d5fd8fSJohnny Huang } 97669d5fd8fSJohnny Huang } 97769d5fd8fSJohnny Huang 978696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout) 97969d5fd8fSJohnny Huang { 98069d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 98179e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 9829a4fe690SJohnny Huang struct otpkey_type key_info; 983696656c6SJohnny Huang uint32_t *buf; 984696656c6SJohnny Huang uint8_t *byte_buf; 9859d998018SJohnny Huang char empty = 1; 98669d5fd8fSJohnny Huang int i = 0, len = 0; 9879a4fe690SJohnny Huang int j; 98854552c69SJohnny Huang 989696656c6SJohnny Huang byte_buf = image_layout->data; 990696656c6SJohnny Huang buf = (uint32_t *)byte_buf; 9919d998018SJohnny Huang 9929d998018SJohnny Huang for (i = 0; i < 16; i++) { 9939d998018SJohnny Huang if (buf[i] != 0) { 9949d998018SJohnny Huang empty = 0; 9959d998018SJohnny Huang } 9969d998018SJohnny Huang } 9979d998018SJohnny Huang if (empty) 9989d998018SJohnny Huang return 0; 9999d998018SJohnny Huang 10009d998018SJohnny Huang i = 0; 100169d5fd8fSJohnny Huang while (1) { 100269d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 100369d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 100469d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 100569d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 100669d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 100769d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 10089a4fe690SJohnny Huang 10099a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 10109a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 10119a4fe690SJohnny Huang key_info = key_info_array[j]; 10129a4fe690SJohnny Huang break; 10139a4fe690SJohnny Huang } 10149a4fe690SJohnny Huang } 10159a4fe690SJohnny Huang 10167f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 101769d5fd8fSJohnny Huang printf("Key Type: "); 10189a4fe690SJohnny Huang printf("%s\n", key_info.information); 10199a4fe690SJohnny Huang 10209a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 102169d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 102269d5fd8fSJohnny Huang switch (key_length) { 102369d5fd8fSJohnny Huang case 0: 102469d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 102569d5fd8fSJohnny Huang break; 102669d5fd8fSJohnny Huang case 1: 102769d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 102869d5fd8fSJohnny Huang break; 102969d5fd8fSJohnny Huang case 2: 103069d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 103169d5fd8fSJohnny Huang break; 103269d5fd8fSJohnny Huang case 3: 103369d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 103469d5fd8fSJohnny Huang break; 103569d5fd8fSJohnny Huang } 10369a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA) { 103769d5fd8fSJohnny Huang printf("RSA SHA Type: "); 103869d5fd8fSJohnny Huang switch (key_length) { 103969d5fd8fSJohnny Huang case 0: 104069d5fd8fSJohnny Huang printf("RSA1024\n"); 104169d5fd8fSJohnny Huang len = 0x100; 104269d5fd8fSJohnny Huang break; 104369d5fd8fSJohnny Huang case 1: 104469d5fd8fSJohnny Huang printf("RSA2048\n"); 104569d5fd8fSJohnny Huang len = 0x200; 104669d5fd8fSJohnny Huang break; 104769d5fd8fSJohnny Huang case 2: 104869d5fd8fSJohnny Huang printf("RSA3072\n"); 104969d5fd8fSJohnny Huang len = 0x300; 105069d5fd8fSJohnny Huang break; 105169d5fd8fSJohnny Huang case 3: 105269d5fd8fSJohnny Huang printf("RSA4096\n"); 105369d5fd8fSJohnny Huang len = 0x400; 105469d5fd8fSJohnny Huang break; 105569d5fd8fSJohnny Huang } 105669d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 105769d5fd8fSJohnny Huang } 10589a4fe690SJohnny Huang if (key_info.need_id) 105969d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 106069d5fd8fSJohnny Huang printf("Key Value:\n"); 10619a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 106269d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 10639a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 10649a4fe690SJohnny Huang printf("AES Key:\n"); 10659a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10665fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 10679a4fe690SJohnny Huang printf("AES IV:\n"); 10689a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10699a4fe690SJohnny Huang } 10709a4fe690SJohnny Huang 10719a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 10725fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 107369d5fd8fSJohnny Huang printf("AES Key:\n"); 107469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 107569d5fd8fSJohnny Huang printf("AES IV:\n"); 107669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10775fdde29fSJohnny Huang } else { 10789a4fe690SJohnny Huang printf("AES Key 1:\n"); 10799a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10809a4fe690SJohnny Huang printf("AES Key 2:\n"); 10819a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 10829a4fe690SJohnny Huang } 108369d5fd8fSJohnny Huang 10849a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA) { 108569d5fd8fSJohnny Huang printf("RSA mod:\n"); 108669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 108769d5fd8fSJohnny Huang printf("RSA exp:\n"); 108869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 108969d5fd8fSJohnny Huang } 109069d5fd8fSJohnny Huang if (last) 109169d5fd8fSJohnny Huang break; 109269d5fd8fSJohnny Huang i++; 109369d5fd8fSJohnny Huang } 109469d5fd8fSJohnny Huang return 0; 109569d5fd8fSJohnny Huang } 109669d5fd8fSJohnny Huang 10975010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout) 109869d5fd8fSJohnny Huang { 1099a6d0d645SJohnny Huang int i, k; 1100d90825e2SJohnny Huang int pass = 0; 1101a6d0d645SJohnny Huang uint32_t prog_address; 1102bb34a7bfSJohnny Huang uint32_t data[16]; 1103a6d0d645SJohnny Huang uint32_t compare[2]; 11045010032bSJohnny Huang uint32_t *conf = (uint32_t *)image_layout->conf; 11055010032bSJohnny Huang uint32_t *conf_ignore = (uint32_t *)image_layout->conf_ignore; 1106d90825e2SJohnny Huang uint32_t data_masked; 1107d90825e2SJohnny Huang uint32_t buf_masked; 110869d5fd8fSJohnny Huang 1109a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 1110a6d0d645SJohnny Huang 1111bb34a7bfSJohnny Huang for (i = 0; i < 16 ; i ++) { 111269d5fd8fSJohnny Huang prog_address = 0x800; 1113a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1114a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1115a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 1116a6d0d645SJohnny Huang } 1117a6d0d645SJohnny Huang 1118a6d0d645SJohnny Huang printf("Check writable...\n"); 1119bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 11205010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 11215010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1122d90825e2SJohnny Huang if (data_masked == buf_masked) 112369d5fd8fSJohnny Huang continue; 1124d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1125a6d0d645SJohnny Huang continue; 1126a6d0d645SJohnny Huang } else { 1127a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1128a6af4a17SJohnny Huang printf("OTPCFG[%X] = %x\n", i, data[i]); 11295010032bSJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 11305010032bSJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 11312a856b9aSJohnny Huang return OTP_FAILURE; 1132a6d0d645SJohnny Huang } 1133a6d0d645SJohnny Huang } 1134a6d0d645SJohnny Huang 1135a6d0d645SJohnny Huang printf("Start Programing...\n"); 1136d90825e2SJohnny Huang otp_soak(0); 1137bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 11385010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 11395010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1140a6d0d645SJohnny Huang prog_address = 0x800; 1141a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1142a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1143bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1144bb34a7bfSJohnny Huang pass = 1; 1145a6d0d645SJohnny Huang continue; 1146bb34a7bfSJohnny Huang } 1147de6fbf1cSJohnny Huang 1148a6d0d645SJohnny Huang 1149de6fbf1cSJohnny Huang otp_soak(1); 11505010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1151a6d0d645SJohnny Huang 115269d5fd8fSJohnny Huang pass = 0; 115369d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 11545010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1155de6fbf1cSJohnny Huang otp_soak(2); 1156feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 11575010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1158de6fbf1cSJohnny Huang otp_soak(1); 1159de6fbf1cSJohnny Huang } else { 1160de6fbf1cSJohnny Huang pass = 1; 1161de6fbf1cSJohnny Huang break; 1162de6fbf1cSJohnny Huang } 1163a6d0d645SJohnny Huang } else { 116469d5fd8fSJohnny Huang pass = 1; 116569d5fd8fSJohnny Huang break; 116669d5fd8fSJohnny Huang } 116769d5fd8fSJohnny Huang } 1168bb34a7bfSJohnny Huang if (pass == 0) { 1169bb34a7bfSJohnny Huang printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n", 11705010032bSJohnny Huang i, data[i], conf[i], conf_ignore[i]); 1171bb34a7bfSJohnny Huang break; 1172bb34a7bfSJohnny Huang } 1173a6d0d645SJohnny Huang } 1174a6d0d645SJohnny Huang 1175de6fbf1cSJohnny Huang otp_soak(0); 117669d5fd8fSJohnny Huang if (!pass) 11772a856b9aSJohnny Huang return OTP_FAILURE; 1178a6d0d645SJohnny Huang 11792a856b9aSJohnny Huang return OTP_SUCCESS; 1180d90825e2SJohnny Huang 118169d5fd8fSJohnny Huang } 118269d5fd8fSJohnny Huang 1183eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit) 1184eda10d61SJohnny Huang { 1185eda10d61SJohnny Huang if (ibit == 1) { 1186eda10d61SJohnny Huang return OTP_SUCCESS; 1187eda10d61SJohnny Huang } else { 1188eda10d61SJohnny Huang printf("OTPSTRAP[%X]:\n", offset); 1189eda10d61SJohnny Huang } 1190eda10d61SJohnny Huang if (bit == otpstrap->value) { 1191eda10d61SJohnny Huang printf(" The value is same as before, skip it.\n"); 1192eda10d61SJohnny Huang return OTP_PROG_SKIP; 1193eda10d61SJohnny Huang } 1194eda10d61SJohnny Huang if (otpstrap->protected == 1) { 1195eda10d61SJohnny Huang printf(" This bit is protected and is not writable\n"); 1196eda10d61SJohnny Huang return OTP_FAILURE; 1197eda10d61SJohnny Huang } 1198eda10d61SJohnny Huang if (otpstrap->remain_times == 0) { 1199eda10d61SJohnny Huang printf(" This bit is no remaining times to write.\n"); 1200eda10d61SJohnny Huang return OTP_FAILURE; 1201eda10d61SJohnny Huang } 1202eda10d61SJohnny Huang if (pbit == 1) { 1203eda10d61SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 1204eda10d61SJohnny Huang } 1205eda10d61SJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 1206eda10d61SJohnny Huang printf(" The relative register will be protected.\n"); 1207eda10d61SJohnny Huang } 1208eda10d61SJohnny 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); 1209eda10d61SJohnny Huang return OTP_SUCCESS; 1210eda10d61SJohnny Huang } 1211eda10d61SJohnny Huang 12125010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout) 121369d5fd8fSJohnny Huang { 121469d5fd8fSJohnny Huang int i; 12155010032bSJohnny Huang uint32_t *strap; 12165010032bSJohnny Huang uint32_t *strap_ignore; 12175010032bSJohnny Huang uint32_t *strap_reg_protect; 12185010032bSJohnny Huang uint32_t *strap_pro; 1219eda10d61SJohnny Huang int bit, pbit, ibit, rpbit; 122069d5fd8fSJohnny Huang int fail = 0; 1221a6af4a17SJohnny Huang int skip = -1; 1222eda10d61SJohnny Huang int ret; 122366f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 122469d5fd8fSJohnny Huang 12255010032bSJohnny Huang strap = (uint32_t *)image_layout->strap; 12265010032bSJohnny Huang strap_pro = (uint32_t *)image_layout->strap_pro; 12275010032bSJohnny Huang strap_ignore = (uint32_t *)image_layout->strap_ignore; 12285010032bSJohnny Huang strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro; 12295010032bSJohnny Huang 1230541eb887SJohnny Huang otp_strap_status(otpstrap); 123169d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 123269d5fd8fSJohnny Huang if (i < 32) { 12335010032bSJohnny Huang bit = (strap[0] >> i) & 0x1; 1234eda10d61SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 12355010032bSJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 123669d5fd8fSJohnny Huang } else { 12375010032bSJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1238eda10d61SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 12395010032bSJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 12405010032bSJohnny Huang } 12415010032bSJohnny Huang 12425010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 12435010032bSJohnny Huang if (i < 32) { 12445010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 12455010032bSJohnny Huang } else { 12465010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 12475010032bSJohnny Huang } 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 if (ret == OTP_PROG_SKIP) { 1253a6af4a17SJohnny Huang if (skip == -1) 1254a6af4a17SJohnny Huang skip = 1; 125569d5fd8fSJohnny Huang continue; 1256a6af4a17SJohnny Huang } else { 1257eda10d61SJohnny Huang skip = 1; 125869d5fd8fSJohnny Huang } 1259eda10d61SJohnny Huang 1260eda10d61SJohnny Huang if (ret == OTP_FAILURE) 126169d5fd8fSJohnny Huang fail = 1; 126269d5fd8fSJohnny Huang } 126369d5fd8fSJohnny Huang if (fail == 1) 1264a6af4a17SJohnny Huang return OTP_FAILURE; 1265a6af4a17SJohnny Huang else if (skip == 1) 1266a6af4a17SJohnny Huang return OTP_PROG_SKIP; 12677e22f42dSJohnny Huang 1268eda10d61SJohnny Huang return OTP_SUCCESS; 126969d5fd8fSJohnny Huang } 127069d5fd8fSJohnny Huang 12712a856b9aSJohnny Huang static int otp_print_strap(int start, int count) 127269d5fd8fSJohnny Huang { 127369d5fd8fSJohnny Huang int i, j; 1274de6b0cc4SJohnny Huang int remains; 127566f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 127669d5fd8fSJohnny Huang 12772a856b9aSJohnny Huang if (start < 0 || start > 64) 12782a856b9aSJohnny Huang return OTP_USAGE; 12792a856b9aSJohnny Huang 12802a856b9aSJohnny Huang if ((start + count) < 0 || (start + count) > 64) 12812a856b9aSJohnny Huang return OTP_USAGE; 12822a856b9aSJohnny Huang 1283541eb887SJohnny Huang otp_strap_status(otpstrap); 128469d5fd8fSJohnny Huang 1285de6b0cc4SJohnny Huang if (info_cb.version == OTP_AST2600A0) { 1286de6b0cc4SJohnny Huang remains = 7; 128707baa4e8SJohnny Huang printf("BIT(hex) Value Option Status\n"); 1288de6b0cc4SJohnny Huang } else { 1289de6b0cc4SJohnny Huang remains = 6; 1290de6b0cc4SJohnny Huang printf("BIT(hex) Value Option Reg_Protect Status\n"); 1291de6b0cc4SJohnny Huang } 1292de6b0cc4SJohnny Huang printf("______________________________________________________________________________\n"); 1293737ed20bSJohnny Huang 1294cd1610b4SJohnny Huang for (i = start; i < start + count; i++) { 129507baa4e8SJohnny Huang printf("0x%-8X", i); 1296737ed20bSJohnny Huang printf("%-7d", otpstrap[i].value); 1297de6b0cc4SJohnny Huang for (j = 0; j < remains; j++) 1298737ed20bSJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 1299737ed20bSJohnny Huang printf(" "); 1300de6b0cc4SJohnny Huang if (info_cb.version != OTP_AST2600A0) { 1301de6b0cc4SJohnny Huang printf("%d ", otpstrap[i].reg_protected); 1302de6b0cc4SJohnny Huang } 130369d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 1304737ed20bSJohnny Huang printf("protected and not writable"); 130569d5fd8fSJohnny Huang } else { 1306737ed20bSJohnny Huang printf("not protected "); 130769d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 1308737ed20bSJohnny Huang printf("and no remaining times to write."); 130969d5fd8fSJohnny Huang } else { 1310737ed20bSJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 131169d5fd8fSJohnny Huang } 131269d5fd8fSJohnny Huang } 1313737ed20bSJohnny Huang printf("\n"); 131469d5fd8fSJohnny Huang } 13152a856b9aSJohnny Huang 13162a856b9aSJohnny Huang return OTP_SUCCESS; 131769d5fd8fSJohnny Huang } 131869d5fd8fSJohnny Huang 13198848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value) 13208848d5dcSJohnny Huang { 13218848d5dcSJohnny Huang struct otpstrap_status otpstrap[64]; 132283655e91SJohnny Huang uint32_t prog_address; 13238848d5dcSJohnny Huang int offset; 13248848d5dcSJohnny Huang int ret; 13258848d5dcSJohnny Huang 13268848d5dcSJohnny Huang 13278848d5dcSJohnny Huang otp_strap_status(otpstrap); 13288848d5dcSJohnny Huang 13298848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 13308848d5dcSJohnny Huang 13318848d5dcSJohnny Huang if (ret != OTP_SUCCESS) { 13328848d5dcSJohnny Huang return ret; 13338848d5dcSJohnny Huang } 13348848d5dcSJohnny Huang 13358848d5dcSJohnny Huang prog_address = 0x800; 13368848d5dcSJohnny Huang if (bit_offset < 32) { 13378848d5dcSJohnny Huang offset = bit_offset; 13388848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 13398848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 13408848d5dcSJohnny Huang 13418848d5dcSJohnny Huang } else { 13428848d5dcSJohnny Huang offset = (bit_offset - 32); 13438848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 13448848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 13458848d5dcSJohnny Huang } 13468848d5dcSJohnny Huang 13478848d5dcSJohnny Huang 134883655e91SJohnny Huang return otp_prog_bit(1, prog_address, offset); 13498848d5dcSJohnny Huang } 13508848d5dcSJohnny Huang 13515010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout) 135269d5fd8fSJohnny Huang { 13535010032bSJohnny Huang uint32_t *strap; 13545010032bSJohnny Huang uint32_t *strap_ignore; 13555010032bSJohnny Huang uint32_t *strap_pro; 13565010032bSJohnny Huang uint32_t *strap_reg_protect; 135783655e91SJohnny Huang uint32_t prog_address; 135883655e91SJohnny Huang int i; 1359eda10d61SJohnny Huang int bit, pbit, ibit, offset, rpbit; 136069d5fd8fSJohnny Huang int fail = 0; 136183655e91SJohnny Huang int ret; 136266f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 136369d5fd8fSJohnny Huang 13645010032bSJohnny Huang strap = (uint32_t *)image_layout->strap; 13655010032bSJohnny Huang strap_pro = (uint32_t *)image_layout->strap_pro; 13665010032bSJohnny Huang strap_ignore = (uint32_t *)image_layout->strap_ignore; 13675010032bSJohnny Huang strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro; 13685010032bSJohnny Huang 13697f795e57SJohnny Huang printf("Read OTP Strap Region:\n"); 1370541eb887SJohnny Huang otp_strap_status(otpstrap); 137169d5fd8fSJohnny Huang 13727f795e57SJohnny Huang printf("Check writable...\n"); 13735010032bSJohnny Huang if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) { 13747f795e57SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 13757f795e57SJohnny Huang return OTP_FAILURE; 13767f795e57SJohnny Huang } 13777e22f42dSJohnny Huang 137869d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 137969d5fd8fSJohnny Huang prog_address = 0x800; 138069d5fd8fSJohnny Huang if (i < 32) { 138169d5fd8fSJohnny Huang offset = i; 13825010032bSJohnny Huang bit = (strap[0] >> offset) & 0x1; 1383eda10d61SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 13845010032bSJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 138569d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 138669d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 138769d5fd8fSJohnny Huang 138869d5fd8fSJohnny Huang } else { 138969d5fd8fSJohnny Huang offset = (i - 32); 13905010032bSJohnny Huang bit = (strap[1] >> offset) & 0x1; 1391eda10d61SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 13925010032bSJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 139369d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 139469d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 139569d5fd8fSJohnny Huang } 13965010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 13975010032bSJohnny Huang if (i < 32) { 13985010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 13995010032bSJohnny Huang } else { 14005010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 14015010032bSJohnny Huang } 14025010032bSJohnny Huang } else { 14035010032bSJohnny Huang rpbit = 0; 14045010032bSJohnny Huang } 140569d5fd8fSJohnny Huang 1406eda10d61SJohnny Huang if (ibit == 1) { 140769d5fd8fSJohnny Huang continue; 140869d5fd8fSJohnny Huang } 140969d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 141069d5fd8fSJohnny Huang continue; 141169d5fd8fSJohnny Huang } 141269d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 141369d5fd8fSJohnny Huang fail = 1; 141469d5fd8fSJohnny Huang continue; 141569d5fd8fSJohnny Huang } 141669d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 141769d5fd8fSJohnny Huang fail = 1; 141869d5fd8fSJohnny Huang continue; 141969d5fd8fSJohnny Huang } 14207e22f42dSJohnny Huang 142183655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 142283655e91SJohnny Huang if (!ret) 14232a856b9aSJohnny Huang return OTP_FAILURE; 142469d5fd8fSJohnny Huang 14255010032bSJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 142669d5fd8fSJohnny Huang prog_address = 0x800; 142769d5fd8fSJohnny Huang if (i < 32) 14285010032bSJohnny Huang prog_address |= 0x608; 142969d5fd8fSJohnny Huang else 14305010032bSJohnny Huang prog_address |= 0x60a; 14317e22f42dSJohnny Huang 143283655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 143383655e91SJohnny Huang if (!ret) 14342a856b9aSJohnny Huang return OTP_FAILURE; 14355010032bSJohnny Huang } 14365010032bSJohnny Huang 14375010032bSJohnny Huang if (pbit != 0) { 14385010032bSJohnny Huang prog_address = 0x800; 14395010032bSJohnny Huang if (i < 32) 14405010032bSJohnny Huang prog_address |= 0x60c; 14415010032bSJohnny Huang else 14425010032bSJohnny Huang prog_address |= 0x60e; 14435010032bSJohnny Huang 144483655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 144583655e91SJohnny Huang if (!ret) 14465010032bSJohnny Huang return OTP_FAILURE; 14475010032bSJohnny Huang } 144869d5fd8fSJohnny Huang 144969d5fd8fSJohnny Huang } 1450de6fbf1cSJohnny Huang otp_soak(0); 145169d5fd8fSJohnny Huang if (fail == 1) 14522a856b9aSJohnny Huang return OTP_FAILURE; 145369d5fd8fSJohnny Huang else 14542a856b9aSJohnny Huang return OTP_SUCCESS; 145569d5fd8fSJohnny Huang 145669d5fd8fSJohnny Huang } 145769d5fd8fSJohnny Huang 14585010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout) 14594c1c9b35SJohnny Huang { 146054552c69SJohnny Huang int i; 146154552c69SJohnny Huang int ret; 14625010032bSJohnny Huang int data_dw; 1463d90825e2SJohnny Huang uint32_t data[2048]; 14645010032bSJohnny Huang uint32_t *buf; 14655010032bSJohnny Huang uint32_t *buf_ignore; 14664c1c9b35SJohnny Huang 146754552c69SJohnny Huang uint32_t data_masked; 146854552c69SJohnny Huang uint32_t buf_masked; 14694c1c9b35SJohnny Huang 14705010032bSJohnny Huang buf = (uint32_t *)image_layout->data; 14715010032bSJohnny Huang buf_ignore = (uint32_t *)image_layout->data_ignore; 14725010032bSJohnny Huang 14735010032bSJohnny Huang data_dw = image_layout->data_length / 4; 14745010032bSJohnny Huang 14754c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 14764c1c9b35SJohnny Huang 14775010032bSJohnny Huang for (i = 0; i < data_dw - 2 ; i += 2) { 1478d90825e2SJohnny Huang otp_read_data(i, &data[i]); 14794c1c9b35SJohnny Huang } 1480d90825e2SJohnny Huang 14814c1c9b35SJohnny Huang printf("Check writable...\n"); 148254552c69SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 14835010032bSJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1484696656c6SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1485696656c6SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 148654552c69SJohnny Huang if (data_masked == buf_masked) 14874c1c9b35SJohnny Huang continue; 1488d90825e2SJohnny Huang if (i % 2 == 0) { 148954552c69SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 14904c1c9b35SJohnny Huang continue; 14914c1c9b35SJohnny Huang } else { 14924c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1493d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 14944c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1495696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 14962a856b9aSJohnny Huang return OTP_FAILURE; 149769d5fd8fSJohnny Huang } 1498d90825e2SJohnny Huang } else { 149954552c69SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1500d90825e2SJohnny Huang continue; 1501d90825e2SJohnny Huang } else { 1502d90825e2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1503d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1504d90825e2SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1505696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 15062a856b9aSJohnny Huang return OTP_FAILURE; 1507d90825e2SJohnny Huang } 1508d90825e2SJohnny Huang } 1509d90825e2SJohnny Huang } 151069d5fd8fSJohnny Huang 1511d90825e2SJohnny Huang printf("Start Programing...\n"); 1512d90825e2SJohnny Huang 151354552c69SJohnny Huang // programing ecc region first 151454552c69SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1515696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 151654552c69SJohnny Huang if (ret != OTP_SUCCESS) { 151754552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1518696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 151954552c69SJohnny Huang return ret; 1520d90825e2SJohnny Huang } 1521d90825e2SJohnny Huang } 1522d90825e2SJohnny Huang 152354552c69SJohnny Huang for (i = 0; i < 1792; i += 2) { 1524696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 152554552c69SJohnny Huang if (ret != OTP_SUCCESS) { 152654552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1527696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 152854552c69SJohnny Huang return ret; 1529d90825e2SJohnny Huang } 1530de6fbf1cSJohnny Huang } 1531de6fbf1cSJohnny Huang otp_soak(0); 15322a856b9aSJohnny Huang return OTP_SUCCESS; 1533d90825e2SJohnny Huang 1534d90825e2SJohnny Huang } 1535d90825e2SJohnny Huang 1536696656c6SJohnny Huang static int otp_image_verify(uint8_t *src_buf, uint32_t length, uint8_t *digest_buf) 1537696656c6SJohnny Huang { 1538696656c6SJohnny Huang sha256_context ctx; 1539696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1540696656c6SJohnny Huang 1541696656c6SJohnny Huang sha256_starts(&ctx); 1542696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1543696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1544696656c6SJohnny Huang 1545696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1546696656c6SJohnny Huang return 0; 1547696656c6SJohnny Huang else 1548696656c6SJohnny Huang return -1; 1549696656c6SJohnny Huang 1550696656c6SJohnny Huang } 1551696656c6SJohnny Huang 1552de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm) 155369d5fd8fSJohnny Huang { 155469d5fd8fSJohnny Huang int ret; 15559a4fe690SJohnny Huang int image_version = 0; 1556696656c6SJohnny Huang struct otp_header *otp_header; 1557696656c6SJohnny Huang struct otp_image_layout image_layout; 1558696656c6SJohnny Huang int image_size; 1559696656c6SJohnny Huang uint8_t *buf; 1560696656c6SJohnny Huang uint8_t *checksum; 156169d5fd8fSJohnny Huang 1562696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1563696656c6SJohnny Huang if (!otp_header) { 156469d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 15652a856b9aSJohnny Huang return OTP_FAILURE; 156669d5fd8fSJohnny Huang } 1567d90825e2SJohnny Huang 1568696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1569696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1570696656c6SJohnny Huang 1571696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1572696656c6SJohnny Huang 1573696656c6SJohnny Huang if (!buf) { 1574696656c6SJohnny Huang puts("Failed to map physical memory\n"); 1575696656c6SJohnny Huang return OTP_FAILURE; 1576696656c6SJohnny Huang } 1577696656c6SJohnny Huang otp_header = (struct otp_header *) buf; 1578696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1579696656c6SJohnny Huang 1580696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1581696656c6SJohnny Huang puts("Image is invalid\n"); 1582696656c6SJohnny Huang return OTP_FAILURE; 1583696656c6SJohnny Huang } 1584696656c6SJohnny Huang 1585696656c6SJohnny Huang 15865010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 15875010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 15885010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 15895010032bSJohnny Huang 15905010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1591696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 15925010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1593696656c6SJohnny Huang 1594696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 1595696656c6SJohnny Huang 1596696656c6SJohnny Huang if (!strcmp("A0", (char *)otp_header->otp_version)) { 1597696656c6SJohnny Huang image_version = OTP_AST2600A0; 15985010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 15995010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 16005010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 1601696656c6SJohnny Huang } else if (!strcmp("A1", (char *)otp_header->otp_version)) { 1602696656c6SJohnny Huang image_version = OTP_AST2600A1; 16035010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 16045010032bSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 16055010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 16065010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 16075fdde29fSJohnny Huang } else if (!strcmp("A2", (char *)otp_header->otp_version)) { 16085fdde29fSJohnny Huang image_version = OTP_AST2600A2; 16095fdde29fSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 16105fdde29fSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 16115fdde29fSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 16125fdde29fSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 1613*64b66712SJohnny Huang } else if (!strcmp("A3", (char *)otp_header->otp_version)) { 1614*64b66712SJohnny Huang image_version = OTP_AST2600A3; 1615*64b66712SJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 1616*64b66712SJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 1617*64b66712SJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 1618*64b66712SJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 1619696656c6SJohnny Huang } else { 1620696656c6SJohnny Huang puts("Version is not supported\n"); 1621696656c6SJohnny Huang return OTP_FAILURE; 1622696656c6SJohnny Huang } 1623696656c6SJohnny Huang 16249a4fe690SJohnny Huang if (image_version != info_cb.version) { 16259a4fe690SJohnny Huang puts("Version is not match\n"); 16269a4fe690SJohnny Huang return OTP_FAILURE; 16279a4fe690SJohnny Huang } 16289a4fe690SJohnny Huang 1629696656c6SJohnny Huang if (otp_image_verify(buf, image_size, checksum)) { 1630696656c6SJohnny Huang puts("checksum is invalid\n"); 1631696656c6SJohnny Huang return OTP_FAILURE; 1632d90825e2SJohnny Huang } 16337332532cSJohnny Huang 163469d5fd8fSJohnny Huang if (!nconfirm) { 1635696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16367f795e57SJohnny Huang printf("\nOTP data region :\n"); 1637696656c6SJohnny Huang if (otp_print_data_info(&image_layout) < 0) { 163869d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 16392a856b9aSJohnny Huang return OTP_FAILURE; 164069d5fd8fSJohnny Huang } 164169d5fd8fSJohnny Huang } 1642696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16437332532cSJohnny Huang printf("\nOTP strap region :\n"); 16445010032bSJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 16457332532cSJohnny Huang printf("OTP strap error, please check.\n"); 16467332532cSJohnny Huang return OTP_FAILURE; 16477332532cSJohnny Huang } 16487332532cSJohnny Huang } 1649696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16507332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1651696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 16527332532cSJohnny Huang printf("OTP config error, please check.\n"); 16537332532cSJohnny Huang return OTP_FAILURE; 16547332532cSJohnny Huang } 16557332532cSJohnny Huang } 16567332532cSJohnny Huang 165769d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 165869d5fd8fSJohnny Huang if (!confirm_yesno()) { 165969d5fd8fSJohnny Huang printf(" Aborting\n"); 16602a856b9aSJohnny Huang return OTP_FAILURE; 166169d5fd8fSJohnny Huang } 166269d5fd8fSJohnny Huang } 16637332532cSJohnny Huang 16645010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16655010032bSJohnny Huang printf("programing data region ...\n"); 16665010032bSJohnny Huang ret = otp_prog_data(&image_layout); 16675010032bSJohnny Huang if (ret != 0) { 16685010032bSJohnny Huang printf("Error\n"); 16695010032bSJohnny Huang return ret; 16705010032bSJohnny Huang } else { 16715010032bSJohnny Huang printf("Done\n"); 16725010032bSJohnny Huang } 16735010032bSJohnny Huang } 16745010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16755010032bSJohnny Huang printf("programing strap region ...\n"); 16765010032bSJohnny Huang ret = otp_prog_strap(&image_layout); 16775010032bSJohnny Huang if (ret != 0) { 16785010032bSJohnny Huang printf("Error\n"); 16795010032bSJohnny Huang return ret; 16805010032bSJohnny Huang } else { 16815010032bSJohnny Huang printf("Done\n"); 16825010032bSJohnny Huang } 16835010032bSJohnny Huang } 16845010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16855010032bSJohnny Huang printf("programing configuration region ...\n"); 16865010032bSJohnny Huang ret = otp_prog_conf(&image_layout); 16875010032bSJohnny Huang if (ret != 0) { 16885010032bSJohnny Huang printf("Error\n"); 16895010032bSJohnny Huang return ret; 16905010032bSJohnny Huang } 16915010032bSJohnny Huang printf("Done\n"); 16925010032bSJohnny Huang } 1693cd1610b4SJohnny Huang 16947332532cSJohnny Huang return OTP_SUCCESS; 16952a856b9aSJohnny Huang } 16962a856b9aSJohnny Huang 16972a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1698cd1610b4SJohnny Huang { 1699a6af4a17SJohnny Huang uint32_t read[2]; 1700d90825e2SJohnny Huang uint32_t prog_address = 0; 170166f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 1702cd1610b4SJohnny Huang int otp_bit; 170383655e91SJohnny Huang int ret = 0; 1704cd1610b4SJohnny Huang 1705dacbba92SJohnny Huang otp_soak(0); 1706cd1610b4SJohnny Huang switch (mode) { 1707a6d0d645SJohnny Huang case OTP_REGION_CONF: 1708a6af4a17SJohnny Huang otp_read_config(otp_dw_offset, read); 1709cd1610b4SJohnny Huang prog_address = 0x800; 1710cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1711cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1712a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1713cd1610b4SJohnny Huang if (otp_bit == value) { 1714a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1715cd1610b4SJohnny Huang printf("No need to program\n"); 17162a856b9aSJohnny Huang return OTP_SUCCESS; 1717cd1610b4SJohnny Huang } 1718cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1719a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset); 1720cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 17212a856b9aSJohnny Huang return OTP_FAILURE; 1722cd1610b4SJohnny Huang } 1723a6af4a17SJohnny Huang printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset); 1724cd1610b4SJohnny Huang break; 1725a6d0d645SJohnny Huang case OTP_REGION_DATA: 1726cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1727cd1610b4SJohnny Huang 1728cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1729a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 1730a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1731643b9cfdSJohnny Huang 1732643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 1733643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1734643b9cfdSJohnny Huang printf("OTP is programed, which can't be cleaned\n"); 1735643b9cfdSJohnny Huang return OTP_FAILURE; 1736643b9cfdSJohnny Huang } 1737cd1610b4SJohnny Huang } else { 1738a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 1739a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 1740643b9cfdSJohnny Huang 1741643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 1742643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1743643b9cfdSJohnny Huang printf("OTP is programed, which can't be writen\n"); 1744643b9cfdSJohnny Huang return OTP_FAILURE; 1745643b9cfdSJohnny Huang } 1746cd1610b4SJohnny Huang } 1747cd1610b4SJohnny Huang if (otp_bit == value) { 1748a6af4a17SJohnny Huang printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1749cd1610b4SJohnny Huang printf("No need to program\n"); 17502a856b9aSJohnny Huang return OTP_SUCCESS; 1751cd1610b4SJohnny Huang } 1752643b9cfdSJohnny Huang 1753a6af4a17SJohnny Huang printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset); 1754cd1610b4SJohnny Huang break; 1755a6d0d645SJohnny Huang case OTP_REGION_STRAP: 17568848d5dcSJohnny Huang otp_strap_status(otpstrap); 17578848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 17588848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 17598848d5dcSJohnny Huang if (ret == OTP_FAILURE) 17608848d5dcSJohnny Huang return OTP_FAILURE; 17618848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 17628848d5dcSJohnny Huang return OTP_SUCCESS; 1763a6af4a17SJohnny Huang 1764cd1610b4SJohnny Huang break; 1765cd1610b4SJohnny Huang } 1766cd1610b4SJohnny Huang 1767cd1610b4SJohnny Huang if (!nconfirm) { 1768cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1769cd1610b4SJohnny Huang if (!confirm_yesno()) { 1770cd1610b4SJohnny Huang printf(" Aborting\n"); 17712a856b9aSJohnny Huang return OTP_FAILURE; 1772cd1610b4SJohnny Huang } 1773cd1610b4SJohnny Huang } 1774cd1610b4SJohnny Huang 1775cd1610b4SJohnny Huang switch (mode) { 1776a6d0d645SJohnny Huang case OTP_REGION_STRAP: 177783655e91SJohnny Huang ret = otp_prog_strap_bit(bit_offset, value); 177883655e91SJohnny Huang break; 1779a6d0d645SJohnny Huang case OTP_REGION_CONF: 1780a6d0d645SJohnny Huang case OTP_REGION_DATA: 178183655e91SJohnny Huang ret = otp_prog_bit(value, prog_address, bit_offset); 1782de6fbf1cSJohnny Huang break; 1783de6fbf1cSJohnny Huang } 1784de6fbf1cSJohnny Huang otp_soak(0); 178583655e91SJohnny Huang if (ret) { 17869009c25dSJohnny Huang printf("SUCCESS\n"); 17872a856b9aSJohnny Huang return OTP_SUCCESS; 17889009c25dSJohnny Huang } else { 17899009c25dSJohnny Huang printf("OTP cannot be programed\n"); 17909009c25dSJohnny Huang printf("FAILED\n"); 17919009c25dSJohnny Huang return OTP_FAILURE; 17929009c25dSJohnny Huang } 1793cd1610b4SJohnny Huang 17942a856b9aSJohnny Huang return OTP_USAGE; 1795cd1610b4SJohnny Huang } 1796cd1610b4SJohnny Huang 17972a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 179869d5fd8fSJohnny Huang { 17992a856b9aSJohnny Huang uint32_t offset, count; 18002a856b9aSJohnny Huang int ret; 180169d5fd8fSJohnny Huang 18022a856b9aSJohnny Huang if (argc == 4) { 18032a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 18042a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 18052a856b9aSJohnny Huang } else if (argc == 3) { 18062a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 18072a856b9aSJohnny Huang count = 1; 18082a856b9aSJohnny Huang } else { 180969d5fd8fSJohnny Huang return CMD_RET_USAGE; 181069d5fd8fSJohnny Huang } 181169d5fd8fSJohnny Huang 181269d5fd8fSJohnny Huang 18132a856b9aSJohnny Huang if (!strcmp(argv[1], "conf")) { 18143d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18152a856b9aSJohnny Huang ret = otp_print_config(offset, count); 18162a856b9aSJohnny Huang } else if (!strcmp(argv[1], "data")) { 18173d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18182a856b9aSJohnny Huang ret = otp_print_data(offset, count); 18192a856b9aSJohnny Huang } else if (!strcmp(argv[1], "strap")) { 18203d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18212a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 18222a856b9aSJohnny Huang } else { 18232a856b9aSJohnny Huang return CMD_RET_USAGE; 182469d5fd8fSJohnny Huang } 182569d5fd8fSJohnny Huang 18262a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18272a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18282a856b9aSJohnny Huang else 18292a856b9aSJohnny Huang return CMD_RET_USAGE; 18302a856b9aSJohnny Huang 18312a856b9aSJohnny Huang } 18322a856b9aSJohnny Huang 18332a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18342a856b9aSJohnny Huang { 18352a856b9aSJohnny Huang phys_addr_t addr; 18362a856b9aSJohnny Huang int ret; 18372a856b9aSJohnny Huang 1838de6b0cc4SJohnny Huang if (argc == 3) { 1839ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 18402a856b9aSJohnny Huang return CMD_RET_USAGE; 18412a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 18423d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1843de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 1); 1844de6b0cc4SJohnny Huang } else if (argc == 2) { 18452a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 18463d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1847de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 0); 18482a856b9aSJohnny Huang } else { 18492a856b9aSJohnny Huang return CMD_RET_USAGE; 18502a856b9aSJohnny Huang } 18512a856b9aSJohnny Huang 18522a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18532a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18542a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 18552a856b9aSJohnny Huang return CMD_RET_FAILURE; 18562a856b9aSJohnny Huang else 18572a856b9aSJohnny Huang return CMD_RET_USAGE; 18582a856b9aSJohnny Huang } 18592a856b9aSJohnny Huang 18602a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18612a856b9aSJohnny Huang { 18622a856b9aSJohnny Huang int mode = 0; 18632a856b9aSJohnny Huang int nconfirm = 0; 18642a856b9aSJohnny Huang int otp_addr = 0; 18652a856b9aSJohnny Huang int bit_offset; 18662a856b9aSJohnny Huang int value; 18672a856b9aSJohnny Huang int ret; 18682a856b9aSJohnny Huang 18692a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 18702a856b9aSJohnny Huang return CMD_RET_USAGE; 18712a856b9aSJohnny Huang 18722a856b9aSJohnny Huang /* Drop the pb cmd */ 18732a856b9aSJohnny Huang argc--; 18742a856b9aSJohnny Huang argv++; 18752a856b9aSJohnny Huang 18762a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 1877a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 18782a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 1879a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 18802a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 1881a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 1882cd1610b4SJohnny Huang else 18832a856b9aSJohnny Huang return CMD_RET_USAGE; 18842a856b9aSJohnny Huang 18852a856b9aSJohnny Huang /* Drop the region cmd */ 18862a856b9aSJohnny Huang argc--; 18872a856b9aSJohnny Huang argv++; 18882a856b9aSJohnny Huang 1889ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1890cd1610b4SJohnny Huang nconfirm = 1; 18912a856b9aSJohnny Huang /* Drop the force option */ 18922a856b9aSJohnny Huang argc--; 18932a856b9aSJohnny Huang argv++; 18942a856b9aSJohnny Huang } 1895cd1610b4SJohnny Huang 1896a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 18972a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 18982a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 18990808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 19002a856b9aSJohnny Huang return CMD_RET_USAGE; 1901cd1610b4SJohnny Huang } else { 19022a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 19032a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 19042a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 19050808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 19062a856b9aSJohnny Huang return CMD_RET_USAGE; 19070808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 190878855207SJohnny Huang if (otp_addr >= 0x800) 19090808cc55SJohnny Huang return CMD_RET_USAGE; 19100808cc55SJohnny Huang } else { 191178855207SJohnny Huang if (otp_addr >= 0x20) 19120808cc55SJohnny Huang return CMD_RET_USAGE; 19130808cc55SJohnny Huang } 1914cd1610b4SJohnny Huang } 1915cd1610b4SJohnny Huang if (value != 0 && value != 1) 19162a856b9aSJohnny Huang return CMD_RET_USAGE; 1917cd1610b4SJohnny Huang 19183d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19192a856b9aSJohnny Huang ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 19202a856b9aSJohnny Huang 19212a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 19222a856b9aSJohnny Huang return CMD_RET_SUCCESS; 19232a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 19242a856b9aSJohnny Huang return CMD_RET_FAILURE; 19252a856b9aSJohnny Huang else 19262a856b9aSJohnny Huang return CMD_RET_USAGE; 19272a856b9aSJohnny Huang } 19282a856b9aSJohnny Huang 19292a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 19302a856b9aSJohnny Huang { 19312a856b9aSJohnny Huang phys_addr_t addr; 19322a856b9aSJohnny Huang int otp_addr = 0; 19332a856b9aSJohnny Huang 19342a856b9aSJohnny Huang if (argc != 3) 19352a856b9aSJohnny Huang return CMD_RET_USAGE; 19362a856b9aSJohnny Huang 19373d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19382a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 19392a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 19402a856b9aSJohnny Huang if (otp_compare(otp_addr, addr) == 0) { 194169d5fd8fSJohnny Huang printf("Compare pass\n"); 19422a856b9aSJohnny Huang return CMD_RET_SUCCESS; 194369d5fd8fSJohnny Huang } else { 194469d5fd8fSJohnny Huang printf("Compare fail\n"); 19452a856b9aSJohnny Huang return CMD_RET_FAILURE; 194669d5fd8fSJohnny Huang } 194769d5fd8fSJohnny Huang } 194869d5fd8fSJohnny Huang 194966f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 195066f2f8e5SJohnny Huang { 1951a8bd6d8cSJohnny Huang int view = 0; 19522d4b0742SJohnny Huang int input; 1953a8bd6d8cSJohnny Huang 1954a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 195566f2f8e5SJohnny Huang return CMD_RET_USAGE; 195666f2f8e5SJohnny Huang 19572d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 195866f2f8e5SJohnny Huang 19593d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19602d4b0742SJohnny Huang if (argc == 3) { 19612d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 19622d4b0742SJohnny Huang otp_print_conf_info(input); 19632d4b0742SJohnny Huang } else { 19642d4b0742SJohnny Huang otp_print_conf_info(-1); 19652d4b0742SJohnny Huang } 19662d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 19672d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 1968a8bd6d8cSJohnny Huang view = 1; 1969a8bd6d8cSJohnny Huang /* Drop the view option */ 1970a8bd6d8cSJohnny Huang argc--; 1971a8bd6d8cSJohnny Huang argv++; 1972a8bd6d8cSJohnny Huang } 19733d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1974b458cd62SJohnny Huang otp_print_strap_info(view); 197566f2f8e5SJohnny Huang } else { 197666f2f8e5SJohnny Huang return CMD_RET_USAGE; 197766f2f8e5SJohnny Huang } 19782d4b0742SJohnny Huang 197966f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 198066f2f8e5SJohnny Huang } 198166f2f8e5SJohnny Huang 1982737ed20bSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1983737ed20bSJohnny Huang { 1984737ed20bSJohnny Huang int input; 1985737ed20bSJohnny Huang int bit_offset; 1986737ed20bSJohnny Huang int prog_address; 198783655e91SJohnny Huang int ret; 1988737ed20bSJohnny Huang if (argc != 3 && argc != 2) 1989737ed20bSJohnny Huang return CMD_RET_USAGE; 1990737ed20bSJohnny Huang 1991ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1992737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 1993737ed20bSJohnny Huang } else { 1994737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 1995737ed20bSJohnny Huang printf("OTPSTRAP[%d] will be protected\n", input); 1996737ed20bSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1997737ed20bSJohnny Huang if (!confirm_yesno()) { 1998737ed20bSJohnny Huang printf(" Aborting\n"); 1999737ed20bSJohnny Huang return CMD_RET_FAILURE; 2000737ed20bSJohnny Huang } 2001737ed20bSJohnny Huang } 2002737ed20bSJohnny Huang 2003737ed20bSJohnny Huang prog_address = 0x800; 2004737ed20bSJohnny Huang if (input < 32) { 2005737ed20bSJohnny Huang bit_offset = input; 2006737ed20bSJohnny Huang prog_address |= 0x60c; 2007737ed20bSJohnny Huang } else if (input < 64) { 2008737ed20bSJohnny Huang bit_offset = input - 32; 2009737ed20bSJohnny Huang prog_address |= 0x60e; 2010737ed20bSJohnny Huang } else { 2011737ed20bSJohnny Huang return CMD_RET_USAGE; 2012737ed20bSJohnny Huang } 2013737ed20bSJohnny Huang 2014737ed20bSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 2015737ed20bSJohnny Huang printf("OTPSTRAP[%d] already protected\n", input); 2016737ed20bSJohnny Huang } 2017de6fbf1cSJohnny Huang 201883655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, bit_offset); 2019de6fbf1cSJohnny Huang otp_soak(0); 202083655e91SJohnny Huang 202183655e91SJohnny Huang if (ret) { 2022737ed20bSJohnny Huang printf("OTPSTRAP[%d] is protected\n", input); 2023737ed20bSJohnny Huang return CMD_RET_SUCCESS; 2024737ed20bSJohnny Huang } 2025737ed20bSJohnny Huang 2026737ed20bSJohnny Huang printf("Protect OTPSTRAP[%d] fail\n", input); 2027737ed20bSJohnny Huang return CMD_RET_FAILURE; 2028737ed20bSJohnny Huang 2029737ed20bSJohnny Huang } 20309a4fe690SJohnny Huang 2031f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2032f67375f7SJohnny Huang { 2033f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2034f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2035f67375f7SJohnny Huang 2036f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2037f67375f7SJohnny Huang } 2038f67375f7SJohnny Huang 20392a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2040f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 20412a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2042a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2043de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 20442a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2045737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 20462a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 20472a856b9aSJohnny Huang }; 20482a856b9aSJohnny Huang 20492a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20502a856b9aSJohnny Huang { 20512a856b9aSJohnny Huang cmd_tbl_t *cp; 20520dae9d52SJohnny Huang uint32_t ver; 20532a856b9aSJohnny Huang 20542a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 20552a856b9aSJohnny Huang 2056737ed20bSJohnny Huang /* Drop the otp command */ 20572a856b9aSJohnny Huang argc--; 20582a856b9aSJohnny Huang argv++; 20592a856b9aSJohnny Huang 20602a856b9aSJohnny Huang if (cp == NULL || argc > cp->maxargs) 20612a856b9aSJohnny Huang return CMD_RET_USAGE; 20622a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 20632a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20642a856b9aSJohnny Huang 20650dae9d52SJohnny Huang ver = chip_version(); 20660dae9d52SJohnny Huang switch (ver) { 20670dae9d52SJohnny Huang case OTP_AST2600A0: 2068696656c6SJohnny Huang info_cb.version = OTP_AST2600A0; 20699a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 20709a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 20719a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 20729a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 20739a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 20749a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 20750dae9d52SJohnny Huang break; 20760dae9d52SJohnny Huang case OTP_AST2600A1: 2077696656c6SJohnny Huang info_cb.version = OTP_AST2600A1; 20783cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 20793cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 20803cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 20813cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 20829a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 20839a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 20840dae9d52SJohnny Huang break; 20850dae9d52SJohnny Huang case OTP_AST2600A2: 20865fdde29fSJohnny Huang info_cb.version = OTP_AST2600A2; 20875fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 20885fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 20895fdde29fSJohnny Huang info_cb.strap_info = a2_strap_info; 20905fdde29fSJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 20915fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 20925fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 20930dae9d52SJohnny Huang break; 2094*64b66712SJohnny Huang case OTP_AST2600A3: 2095*64b66712SJohnny Huang info_cb.version = OTP_AST2600A3; 2096*64b66712SJohnny Huang info_cb.conf_info = a2_conf_info; 2097*64b66712SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 2098*64b66712SJohnny Huang info_cb.strap_info = a2_strap_info; 2099*64b66712SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 2100*64b66712SJohnny Huang info_cb.key_info = a2_key_type; 2101*64b66712SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 2102*64b66712SJohnny Huang break; 21030dae9d52SJohnny Huang default: 2104f1be5099SJohnny Huang printf("SOC is not supported\n"); 21050dae9d52SJohnny Huang return CMD_RET_FAILURE; 21069a4fe690SJohnny Huang } 21079a4fe690SJohnny Huang 21082a856b9aSJohnny Huang return cp->cmd(cmdtp, flag, argc, argv); 210969d5fd8fSJohnny Huang } 211069d5fd8fSJohnny Huang 211169d5fd8fSJohnny Huang U_BOOT_CMD( 211269d5fd8fSJohnny Huang otp, 7, 0, do_ast_otp, 211369d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2114f67375f7SJohnny Huang "version\n" 2115f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 21162a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 21172d4b0742SJohnny Huang "otp info strap [v]\n" 21182d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 2119de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2120ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2121ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2122ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 21232a856b9aSJohnny Huang "otp cmp <addr> <otp_dw_offset>\n" 212469d5fd8fSJohnny Huang ); 2125