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 280dae9d52SJohnny Huang #define OTP_VER "1.0.1" 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 74696656c6SJohnny Huang 75696656c6SJohnny Huang struct otp_header { 76696656c6SJohnny Huang u8 otp_magic[8]; 77696656c6SJohnny Huang u8 otp_version[8]; 78696656c6SJohnny Huang u32 image_info; 79696656c6SJohnny Huang u32 data_info; 80696656c6SJohnny Huang u32 config_info; 81696656c6SJohnny Huang u32 strap_info; 82696656c6SJohnny Huang u32 checksum_offset; 83696656c6SJohnny Huang } __attribute__((packed)); 84696656c6SJohnny Huang 8566f2f8e5SJohnny Huang struct otpstrap_status { 8669d5fd8fSJohnny Huang int value; 8769d5fd8fSJohnny Huang int option_array[7]; 8869d5fd8fSJohnny Huang int remain_times; 8969d5fd8fSJohnny Huang int writeable_option; 905010032bSJohnny Huang int reg_protected; 9169d5fd8fSJohnny Huang int protected; 9269d5fd8fSJohnny Huang }; 9369d5fd8fSJohnny Huang 9466f2f8e5SJohnny Huang struct otpconf_parse { 9566f2f8e5SJohnny Huang int dw_offset; 9666f2f8e5SJohnny Huang int bit; 9766f2f8e5SJohnny Huang int length; 9866f2f8e5SJohnny Huang int value; 99696656c6SJohnny Huang int ignore; 10066f2f8e5SJohnny Huang char status[80]; 10166f2f8e5SJohnny Huang }; 10266f2f8e5SJohnny Huang 1039a4fe690SJohnny Huang struct otpkey_type { 1049a4fe690SJohnny Huang int value; 1059a4fe690SJohnny Huang int key_type; 1069a4fe690SJohnny Huang int need_id; 1079a4fe690SJohnny Huang char information[110]; 1089a4fe690SJohnny Huang }; 1099a4fe690SJohnny Huang 1109a4fe690SJohnny Huang struct otp_info_cb { 1119a4fe690SJohnny Huang int version; 11279e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1139a4fe690SJohnny Huang int strap_info_len; 11479e42a59SJoel Stanley const struct otpconf_info *conf_info; 1159a4fe690SJohnny Huang int conf_info_len; 11679e42a59SJoel Stanley const struct otpkey_type *key_info; 1179a4fe690SJohnny Huang int key_info_len; 1185010032bSJohnny Huang 1199a4fe690SJohnny Huang }; 1209a4fe690SJohnny Huang 121696656c6SJohnny Huang struct otp_image_layout { 1225010032bSJohnny Huang int data_length; 1235010032bSJohnny Huang int conf_length; 1245010032bSJohnny Huang int strap_length; 125696656c6SJohnny Huang uint8_t *data; 126696656c6SJohnny Huang uint8_t *data_ignore; 127696656c6SJohnny Huang uint8_t *conf; 128696656c6SJohnny Huang uint8_t *conf_ignore; 129696656c6SJohnny Huang uint8_t *strap; 130696656c6SJohnny Huang uint8_t *strap_reg_pro; 131696656c6SJohnny Huang uint8_t *strap_pro; 132696656c6SJohnny Huang uint8_t *strap_ignore; 133696656c6SJohnny Huang }; 134696656c6SJohnny Huang 1359a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1369a4fe690SJohnny Huang 13779e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1389a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1399a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1409a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 1419a4fe690SJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1429a4fe690SJohnny Huang {9, OTP_KEY_TYPE_RSA, 0, "RSA-public as SOC public key"}, 1439a4fe690SJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1449a4fe690SJohnny Huang {13, OTP_KEY_TYPE_RSA, 0, "RSA-private as SOC private key"}, 1459a4fe690SJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1469a4fe690SJohnny Huang }; 1479a4fe690SJohnny Huang 14879e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1499a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1509a4fe690SJohnny 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"}, 1519a4fe690SJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1529a4fe690SJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1539a4fe690SJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1549a4fe690SJohnny Huang }; 1559a4fe690SJohnny Huang 1565fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1575fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1585fdde29fSJohnny 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"}, 1595fdde29fSJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1605fdde29fSJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1615fdde29fSJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1625fdde29fSJohnny Huang }; 1635fdde29fSJohnny Huang 1649a4fe690SJohnny Huang static uint32_t chip_version(void) 1659a4fe690SJohnny Huang { 1660dae9d52SJohnny Huang uint32_t rev_id[2]; 1679a4fe690SJohnny Huang 1680dae9d52SJohnny Huang rev_id[0] = readl(0x1e6e2004); 1690dae9d52SJohnny Huang rev_id[1] = readl(0x1e6e2014); 1709a4fe690SJohnny Huang 1710dae9d52SJohnny Huang if (rev_id[0] == 0x05000303 && rev_id[1] == 0x05000303) { 1720dae9d52SJohnny Huang return OTP_AST2600A0; 1730dae9d52SJohnny Huang } else if (rev_id[0] == 0x05010303 && rev_id[1] == 0x05010303) { 1740dae9d52SJohnny Huang return OTP_AST2600A1; 1750dae9d52SJohnny Huang } else if (rev_id[0] == 0x05010303 && rev_id[1] == 0x05020303) { 1760dae9d52SJohnny Huang return OTP_AST2600A2; 1770dae9d52SJohnny Huang } else if (rev_id[0] == 0x05010203 && rev_id[1] == 0x05010203) { 1780dae9d52SJohnny Huang return OTP_AST2600A1; 1790dae9d52SJohnny Huang } else if (rev_id[0] == 0x05010203 && rev_id[1] == 0x05020203) { 1800dae9d52SJohnny Huang return OTP_AST2600A2; 1810dae9d52SJohnny Huang } 1820dae9d52SJohnny Huang 1835fdde29fSJohnny Huang return -1; 1849a4fe690SJohnny Huang } 1859a4fe690SJohnny Huang 1863d3688adSJohnny Huang static void wait_complete(void) 1873d3688adSJohnny Huang { 1883d3688adSJohnny Huang int reg; 1893d3688adSJohnny Huang 1903d3688adSJohnny Huang do { 1913d3688adSJohnny Huang reg = readl(OTP_STATUS); 1923d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 1933d3688adSJohnny Huang } 1943d3688adSJohnny Huang 195dacbba92SJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data) 196dacbba92SJohnny Huang { 197dacbba92SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 198dacbba92SJohnny Huang writel(data, OTP_COMPARE_1); //write data 199dacbba92SJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 200dacbba92SJohnny Huang wait_complete(); 201dacbba92SJohnny Huang } 202dacbba92SJohnny Huang 203dacbba92SJohnny Huang static void otp_soak(int soak) 204dacbba92SJohnny Huang { 205dacbba92SJohnny Huang if (info_cb.version == OTP_AST2600A2) { 206dacbba92SJohnny Huang switch (soak) { 207dacbba92SJohnny Huang case 0: //default 208dacbba92SJohnny Huang otp_write(0x3000, 0x0210); // Write MRA 209dacbba92SJohnny Huang otp_write(0x5000, 0x2000); // Write MRB 210dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 211dacbba92SJohnny Huang break; 212dacbba92SJohnny Huang case 1: //normal program 213dacbba92SJohnny Huang otp_write(0x3000, 0x1200); // Write MRA 214*feea3fdfSJohnny Huang otp_write(0x5000, 0x107F); // Write MRB 215dacbba92SJohnny Huang otp_write(0x1000, 0x1024); // Write MR 216*feea3fdfSJohnny Huang writel(0x04191388, OTP_TIMING); // 200us 217dacbba92SJohnny Huang break; 218dacbba92SJohnny Huang case 2: //soak program 219dacbba92SJohnny Huang otp_write(0x3000, 0x1220); // Write MRA 220*feea3fdfSJohnny Huang otp_write(0x5000, 0x2074); // Write MRB 221dacbba92SJohnny Huang otp_write(0x1000, 0x08a4); // Write MR 222*feea3fdfSJohnny Huang writel(0x04193a98, OTP_TIMING); // 600us 223dacbba92SJohnny Huang break; 224dacbba92SJohnny Huang } 225dacbba92SJohnny Huang } else { 226dacbba92SJohnny Huang switch (soak) { 227dacbba92SJohnny Huang case 0: //default 228dacbba92SJohnny Huang otp_write(0x3000, 0x0); // Write MRA 229dacbba92SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 230dacbba92SJohnny Huang otp_write(0x1000, 0x0); // Write MR 231dacbba92SJohnny Huang break; 232dacbba92SJohnny Huang case 1: //normal program 233dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 234dacbba92SJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 235dacbba92SJohnny Huang otp_write(0x1000, 0x4020); // Write MR 236*feea3fdfSJohnny Huang writel(0x04190760, OTP_TIMING); // 75us 237dacbba92SJohnny Huang break; 238dacbba92SJohnny Huang case 2: //soak program 239dacbba92SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 240dacbba92SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 241dacbba92SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 242*feea3fdfSJohnny Huang writel(0x041930d4, OTP_TIMING); // 500us 243dacbba92SJohnny Huang break; 244dacbba92SJohnny Huang } 245dacbba92SJohnny Huang } 246dacbba92SJohnny Huang 247dacbba92SJohnny Huang wait_complete(); 248dacbba92SJohnny Huang } 249dacbba92SJohnny Huang 2502a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data) 25169d5fd8fSJohnny Huang { 2523d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 2533d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2543d3688adSJohnny Huang wait_complete(); 2553d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 2563d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 25769d5fd8fSJohnny Huang } 25869d5fd8fSJohnny Huang 2592a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data) 26069d5fd8fSJohnny Huang { 26169d5fd8fSJohnny Huang int config_offset; 26269d5fd8fSJohnny Huang 26369d5fd8fSJohnny Huang config_offset = 0x800; 26469d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 26569d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 26669d5fd8fSJohnny Huang 2673d3688adSJohnny Huang writel(config_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); 27169d5fd8fSJohnny Huang } 27269d5fd8fSJohnny Huang 27369d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count) 27469d5fd8fSJohnny Huang { 27569d5fd8fSJohnny Huang int i; 27669d5fd8fSJohnny Huang uint32_t ret[1]; 27769d5fd8fSJohnny Huang 27869d5fd8fSJohnny Huang if (offset + dw_count > 32) 2792a856b9aSJohnny Huang return OTP_USAGE; 280dacbba92SJohnny Huang otp_soak(0); 28169d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i ++) { 28269d5fd8fSJohnny Huang otp_read_config(i, ret); 283a6af4a17SJohnny Huang printf("OTPCFG%X: %08X\n", i, ret[0]); 28469d5fd8fSJohnny Huang } 28569d5fd8fSJohnny Huang printf("\n"); 2862a856b9aSJohnny Huang return OTP_SUCCESS; 28769d5fd8fSJohnny Huang } 28869d5fd8fSJohnny Huang 28969d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count) 29069d5fd8fSJohnny Huang { 29169d5fd8fSJohnny Huang int i; 29269d5fd8fSJohnny Huang uint32_t ret[2]; 29369d5fd8fSJohnny Huang 29469d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 2952a856b9aSJohnny Huang return OTP_USAGE; 296dacbba92SJohnny Huang otp_soak(0); 29769d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 29869d5fd8fSJohnny Huang otp_read_data(i, ret); 29969d5fd8fSJohnny Huang if (i % 4 == 0) 30069d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 30169d5fd8fSJohnny Huang else 30269d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 30369d5fd8fSJohnny Huang 30469d5fd8fSJohnny Huang } 30569d5fd8fSJohnny Huang printf("\n"); 3062a856b9aSJohnny Huang return OTP_SUCCESS; 30769d5fd8fSJohnny Huang } 30869d5fd8fSJohnny Huang 30969d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr) 31069d5fd8fSJohnny Huang { 31169d5fd8fSJohnny Huang uint32_t ret; 31269d5fd8fSJohnny Huang uint32_t *buf; 31369d5fd8fSJohnny Huang 31469d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 31569d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 31669d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 31769d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 31869d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 3193d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 3203d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 3213d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 3223d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 3233d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 3243d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 3253d3688adSJohnny Huang wait_complete(); 3263d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 32769d5fd8fSJohnny Huang if (ret & 0x1) 32869d5fd8fSJohnny Huang return 0; 32969d5fd8fSJohnny Huang else 33069d5fd8fSJohnny Huang return -1; 33169d5fd8fSJohnny Huang } 33269d5fd8fSJohnny Huang 333a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value) 33469d5fd8fSJohnny Huang { 33530a8c590SJohnny Huang uint32_t ret[2]; 33669d5fd8fSJohnny Huang 33730a8c590SJohnny Huang if (otp_addr % 2 == 0) 3383d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 33930a8c590SJohnny Huang else 3403d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 34130a8c590SJohnny Huang 3423d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3433d3688adSJohnny Huang wait_complete(); 3443d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 3453d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 34683655e91SJohnny Huang 34730a8c590SJohnny Huang if (otp_addr % 2 == 0) { 34830a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 34969d5fd8fSJohnny Huang return 0; 35069d5fd8fSJohnny Huang else 35169d5fd8fSJohnny Huang return -1; 35230a8c590SJohnny Huang } else { 35330a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 35430a8c590SJohnny Huang return 0; 35530a8c590SJohnny Huang else 35630a8c590SJohnny Huang return -1; 35730a8c590SJohnny Huang } 35830a8c590SJohnny Huang 35969d5fd8fSJohnny Huang } 36069d5fd8fSJohnny Huang 361696656c6SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *ignore, uint32_t *compare, int size) 3624c1c9b35SJohnny Huang { 3634c1c9b35SJohnny Huang uint32_t ret[2]; 3644c1c9b35SJohnny Huang 3654c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 3664c1c9b35SJohnny Huang 3674c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 3683d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 3694c1c9b35SJohnny Huang else 3703d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 3713d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3723d3688adSJohnny Huang wait_complete(); 3733d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 3743d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 3754c1c9b35SJohnny Huang if (size == 1) { 3764c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 3774c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 378696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 3794c1c9b35SJohnny Huang compare[0] = 0; 3804c1c9b35SJohnny Huang return 0; 3814c1c9b35SJohnny Huang } else { 3824c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 3834c1c9b35SJohnny Huang return -1; 3844c1c9b35SJohnny Huang } 3854c1c9b35SJohnny Huang 3864c1c9b35SJohnny Huang } else { 3874c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 388696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 3894c1c9b35SJohnny Huang compare[0] = ~0; 3904c1c9b35SJohnny Huang return 0; 3914c1c9b35SJohnny Huang } else { 392d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 3934c1c9b35SJohnny Huang return -1; 3944c1c9b35SJohnny Huang } 3954c1c9b35SJohnny Huang } 3964c1c9b35SJohnny Huang } else if (size == 2) { 3974c1c9b35SJohnny Huang // otp_addr should be even 398696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 3994c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4004c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4014c1c9b35SJohnny Huang compare[0] = 0; 4024c1c9b35SJohnny Huang compare[1] = ~0; 4034c1c9b35SJohnny Huang return 0; 4044c1c9b35SJohnny Huang } else { 4054c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 4064c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 4074c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 4084c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 4094c1c9b35SJohnny Huang return -1; 4104c1c9b35SJohnny Huang } 4114c1c9b35SJohnny Huang } else { 4124c1c9b35SJohnny Huang return -1; 4134c1c9b35SJohnny Huang } 4144c1c9b35SJohnny Huang } 4154c1c9b35SJohnny Huang 41683655e91SJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit) 41783655e91SJohnny Huang { 41883655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 41983655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 42083655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 42183655e91SJohnny Huang wait_complete(); 42283655e91SJohnny Huang } 42383655e91SJohnny Huang 42483655e91SJohnny Huang static void _otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset) 42583655e91SJohnny Huang { 42683655e91SJohnny Huang int prog_bit; 42783655e91SJohnny Huang 42883655e91SJohnny Huang if (prog_address % 2 == 0) { 42983655e91SJohnny Huang if (value) 43083655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 43183655e91SJohnny Huang else 43283655e91SJohnny Huang return; 43383655e91SJohnny Huang } else { 43483655e91SJohnny Huang prog_address |= 1 << 15; 43583655e91SJohnny Huang if (!value) 43683655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 43783655e91SJohnny Huang else 43883655e91SJohnny Huang return; 43983655e91SJohnny Huang } 44083655e91SJohnny Huang otp_prog(prog_address, prog_bit); 44183655e91SJohnny Huang } 44283655e91SJohnny Huang 44383655e91SJohnny Huang static int otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset) 44483655e91SJohnny Huang { 44583655e91SJohnny Huang int pass; 44683655e91SJohnny Huang int i; 44783655e91SJohnny Huang 44883655e91SJohnny Huang otp_soak(1); 44983655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 45083655e91SJohnny Huang pass = 0; 45183655e91SJohnny Huang 45283655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 45383655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 45483655e91SJohnny Huang otp_soak(2); 45583655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 45683655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 45783655e91SJohnny Huang otp_soak(1); 45883655e91SJohnny Huang } else { 45983655e91SJohnny Huang pass = 1; 46083655e91SJohnny Huang break; 46183655e91SJohnny Huang } 46283655e91SJohnny Huang } else { 46383655e91SJohnny Huang pass = 1; 46483655e91SJohnny Huang break; 46583655e91SJohnny Huang } 46683655e91SJohnny Huang } 46783655e91SJohnny Huang 46883655e91SJohnny Huang return pass; 46983655e91SJohnny Huang } 47083655e91SJohnny Huang 471696656c6SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t ignore, uint32_t prog_address) 472d90825e2SJohnny Huang { 473d90825e2SJohnny Huang int j, bit_value, prog_bit; 474d90825e2SJohnny Huang 475d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 476696656c6SJohnny Huang if ((ignore >> j) & 0x1) 477d90825e2SJohnny Huang continue; 478d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 479d90825e2SJohnny Huang if (prog_address % 2 == 0) { 480d90825e2SJohnny Huang if (bit_value) 481d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 482d90825e2SJohnny Huang else 483d90825e2SJohnny Huang continue; 484d90825e2SJohnny Huang } else { 485d90825e2SJohnny Huang prog_address |= 1 << 15; 486d90825e2SJohnny Huang if (bit_value) 487d90825e2SJohnny Huang continue; 488d90825e2SJohnny Huang else 489d90825e2SJohnny Huang prog_bit = 0x1 << j; 490d90825e2SJohnny Huang } 491d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 492d90825e2SJohnny Huang } 493d90825e2SJohnny Huang } 494d90825e2SJohnny Huang 49554552c69SJohnny Huang static int otp_prog_verify_2dw(uint32_t *data, uint32_t *buf, uint32_t *ignore_mask, uint32_t prog_address) 49654552c69SJohnny Huang { 49754552c69SJohnny Huang int pass; 49854552c69SJohnny Huang int i; 49954552c69SJohnny Huang uint32_t data0_masked; 50054552c69SJohnny Huang uint32_t data1_masked; 50154552c69SJohnny Huang uint32_t buf0_masked; 50254552c69SJohnny Huang uint32_t buf1_masked; 50354552c69SJohnny Huang uint32_t compare[2]; 50454552c69SJohnny Huang 50554552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 50654552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 50754552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 50854552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 50954552c69SJohnny Huang if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) 51054552c69SJohnny Huang return 0; 51154552c69SJohnny Huang 51254552c69SJohnny Huang otp_soak(1); 51354552c69SJohnny Huang if (data0_masked != buf0_masked) 51454552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 51554552c69SJohnny Huang if (data1_masked != buf1_masked) 51654552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 51754552c69SJohnny Huang 51854552c69SJohnny Huang pass = 0; 51954552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 52054552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 52154552c69SJohnny Huang otp_soak(2); 52254552c69SJohnny Huang if (compare[0] != 0) { 52354552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 52454552c69SJohnny Huang } 52554552c69SJohnny Huang if (compare[1] != ~0) { 5265537bc72SJohnny Huang otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1); 52754552c69SJohnny Huang } 52854552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 52954552c69SJohnny Huang otp_soak(1); 53054552c69SJohnny Huang } else { 53154552c69SJohnny Huang pass = 1; 53254552c69SJohnny Huang break; 53354552c69SJohnny Huang } 53454552c69SJohnny Huang } else { 53554552c69SJohnny Huang pass = 1; 53654552c69SJohnny Huang break; 53754552c69SJohnny Huang } 53854552c69SJohnny Huang } 53954552c69SJohnny Huang 54054552c69SJohnny Huang if (!pass) { 54154552c69SJohnny Huang otp_soak(0); 54254552c69SJohnny Huang return OTP_FAILURE; 54354552c69SJohnny Huang } 54454552c69SJohnny Huang return OTP_SUCCESS; 54554552c69SJohnny Huang } 54654552c69SJohnny Huang 547541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 54876d13988SJohnny Huang { 54976d13988SJohnny Huang uint32_t OTPSTRAP_RAW[2]; 5505010032bSJohnny Huang int strap_end; 55176d13988SJohnny Huang int i, j; 55276d13988SJohnny Huang 5535010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 55476d13988SJohnny Huang for (j = 0; j < 64; j++) { 55576d13988SJohnny Huang otpstrap[j].value = 0; 55676d13988SJohnny Huang otpstrap[j].remain_times = 7; 55776d13988SJohnny Huang otpstrap[j].writeable_option = -1; 55876d13988SJohnny Huang otpstrap[j].protected = 0; 55976d13988SJohnny Huang } 5605010032bSJohnny Huang strap_end = 30; 5615010032bSJohnny Huang } else { 5625010032bSJohnny Huang for (j = 0; j < 64; j++) { 5635010032bSJohnny Huang otpstrap[j].value = 0; 5645010032bSJohnny Huang otpstrap[j].remain_times = 6; 5655010032bSJohnny Huang otpstrap[j].writeable_option = -1; 5665010032bSJohnny Huang otpstrap[j].reg_protected = 0; 5675010032bSJohnny Huang otpstrap[j].protected = 0; 5685010032bSJohnny Huang } 5695010032bSJohnny Huang strap_end = 28; 5705010032bSJohnny Huang } 57176d13988SJohnny Huang 572dacbba92SJohnny Huang otp_soak(0); 5735010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 57476d13988SJohnny Huang int option = (i - 16) / 2; 57576d13988SJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 57676d13988SJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 57776d13988SJohnny Huang for (j = 0; j < 32; j++) { 57876d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 57976d13988SJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 58076d13988SJohnny Huang otpstrap[j].writeable_option = option; 58176d13988SJohnny Huang } 58276d13988SJohnny Huang if (bit_value == 1) 58376d13988SJohnny Huang otpstrap[j].remain_times --; 58476d13988SJohnny Huang otpstrap[j].value ^= bit_value; 58576d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 58676d13988SJohnny Huang } 58776d13988SJohnny Huang for (j = 32; j < 64; j++) { 58876d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 58976d13988SJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 59076d13988SJohnny Huang otpstrap[j].writeable_option = option; 59176d13988SJohnny Huang } 59276d13988SJohnny Huang if (bit_value == 1) 59376d13988SJohnny Huang otpstrap[j].remain_times --; 59476d13988SJohnny Huang otpstrap[j].value ^= bit_value; 59576d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 59676d13988SJohnny Huang } 59776d13988SJohnny Huang } 5985010032bSJohnny Huang 5995010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 6005010032bSJohnny Huang otp_read_config(28, &OTPSTRAP_RAW[0]); 6015010032bSJohnny Huang otp_read_config(29, &OTPSTRAP_RAW[1]); 6025010032bSJohnny Huang for (j = 0; j < 32; j++) { 6035010032bSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 6045010032bSJohnny Huang otpstrap[j].reg_protected = 1; 6055010032bSJohnny Huang } 6065010032bSJohnny Huang for (j = 32; j < 64; j++) { 6075010032bSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 6085010032bSJohnny Huang otpstrap[j].reg_protected = 1; 6095010032bSJohnny Huang } 6105010032bSJohnny Huang 6115010032bSJohnny Huang } 6125010032bSJohnny Huang 61376d13988SJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 61476d13988SJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 61576d13988SJohnny Huang for (j = 0; j < 32; j++) { 61676d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 61776d13988SJohnny Huang otpstrap[j].protected = 1; 61876d13988SJohnny Huang } 61976d13988SJohnny Huang for (j = 32; j < 64; j++) { 62076d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 62176d13988SJohnny Huang otpstrap[j].protected = 1; 62276d13988SJohnny Huang } 62376d13988SJohnny Huang } 62476d13988SJohnny Huang 625696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 62669d5fd8fSJohnny Huang { 62779e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 628696656c6SJohnny Huang uint32_t *OTPCFG = (uint32_t *)image_layout->conf; 629696656c6SJohnny Huang uint32_t *OTPCFG_IGNORE = (uint32_t *)image_layout->conf_ignore; 630b458cd62SJohnny Huang uint32_t mask; 631b458cd62SJohnny Huang uint32_t dw_offset; 632b458cd62SJohnny Huang uint32_t bit_offset; 633b458cd62SJohnny Huang uint32_t otp_value; 634696656c6SJohnny Huang uint32_t otp_ignore; 635b458cd62SJohnny Huang int fail = 0; 63673f11549SJohnny Huang char valid_bit[20]; 63766f2f8e5SJohnny Huang int i; 63873f11549SJohnny Huang int j; 63966f2f8e5SJohnny Huang 640737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 64166f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 6423cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 6433cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 6443cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 6453cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 646b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 647696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 648b458cd62SJohnny Huang 649696656c6SJohnny Huang if (otp_ignore == mask) { 650b458cd62SJohnny Huang continue; 651696656c6SJohnny Huang } else if (otp_ignore != 0) { 652b458cd62SJohnny Huang fail = 1; 653b458cd62SJohnny Huang } 654b458cd62SJohnny Huang 6553cb28812SJohnny Huang if ((otp_value != conf_info[i].value) && 6563cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 6573cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 6583cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 659b458cd62SJohnny Huang continue; 660b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 661b458cd62SJohnny Huang 6623cb28812SJohnny Huang if (conf_info[i].length == 1) { 6633cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 66466f2f8e5SJohnny Huang } else { 665b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 6663cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 6673cb28812SJohnny Huang conf_info[i].bit_offset); 66866f2f8e5SJohnny Huang } 669b458cd62SJohnny Huang printf("0x%-10x", otp_value); 670b458cd62SJohnny Huang 671b458cd62SJohnny Huang if (fail) { 672696656c6SJohnny Huang printf("Ignore mask error\n"); 673b458cd62SJohnny Huang } else { 6743cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 675b458cd62SJohnny Huang printf("Reserved\n"); 6763cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 6773cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 678b458cd62SJohnny Huang printf("\n"); 6793cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 680b458cd62SJohnny Huang if (otp_value != 0) { 68173f11549SJohnny Huang for (j = 0; j < 7; j++) { 68273f11549SJohnny Huang if (otp_value == (1 << j)) { 68373f11549SJohnny Huang valid_bit[j * 2] = '1'; 684b458cd62SJohnny Huang } else { 68573f11549SJohnny Huang valid_bit[j * 2] = '0'; 68673f11549SJohnny Huang } 68773f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 68873f11549SJohnny Huang } 68973f11549SJohnny Huang valid_bit[15] = 0; 69073f11549SJohnny Huang } else { 69173f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 692b458cd62SJohnny Huang } 6933cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 694b458cd62SJohnny Huang printf("\n"); 695b458cd62SJohnny Huang } else { 6963cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 697b458cd62SJohnny Huang } 698b458cd62SJohnny Huang } 699b458cd62SJohnny Huang } 700b458cd62SJohnny Huang 701b458cd62SJohnny Huang if (fail) 702b458cd62SJohnny Huang return OTP_FAILURE; 703b458cd62SJohnny Huang 70466f2f8e5SJohnny Huang return OTP_SUCCESS; 70566f2f8e5SJohnny Huang } 70666f2f8e5SJohnny Huang 7072d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 70866f2f8e5SJohnny Huang { 70979e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 710bb34a7bfSJohnny Huang uint32_t OTPCFG[16]; 711b458cd62SJohnny Huang uint32_t mask; 712b458cd62SJohnny Huang uint32_t dw_offset; 713b458cd62SJohnny Huang uint32_t bit_offset; 714b458cd62SJohnny Huang uint32_t otp_value; 71573f11549SJohnny Huang char valid_bit[20]; 71666f2f8e5SJohnny Huang int i; 71773f11549SJohnny Huang int j; 71866f2f8e5SJohnny Huang 719dacbba92SJohnny Huang otp_soak(0); 720bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 72166f2f8e5SJohnny Huang otp_read_config(i, &OTPCFG[i]); 72266f2f8e5SJohnny Huang 72366f2f8e5SJohnny Huang 724b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 725b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 7263cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 7273cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 7282d4b0742SJohnny Huang continue; 7293cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 7303cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 7313cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 732b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 733b458cd62SJohnny Huang 7343cb28812SJohnny Huang if ((otp_value != conf_info[i].value) && 7353cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 7363cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 7373cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 738b458cd62SJohnny Huang continue; 739b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 740b458cd62SJohnny Huang 7413cb28812SJohnny Huang if (conf_info[i].length == 1) { 7423cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 743b458cd62SJohnny Huang } else { 744b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 7453cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 7463cb28812SJohnny Huang conf_info[i].bit_offset); 747b458cd62SJohnny Huang } 748b458cd62SJohnny Huang printf("0x%-10x", otp_value); 749b458cd62SJohnny Huang 7503cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 751b458cd62SJohnny Huang printf("Reserved\n"); 7523cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 7533cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 754b458cd62SJohnny Huang printf("\n"); 7553cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 756b458cd62SJohnny Huang if (otp_value != 0) { 75773f11549SJohnny Huang for (j = 0; j < 7; j++) { 75873f11549SJohnny Huang if (otp_value == (1 << j)) { 75973f11549SJohnny Huang valid_bit[j * 2] = '1'; 760b458cd62SJohnny Huang } else { 76173f11549SJohnny Huang valid_bit[j * 2] = '0'; 76273f11549SJohnny Huang } 76373f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 76473f11549SJohnny Huang } 76573f11549SJohnny Huang valid_bit[15] = 0; 76673f11549SJohnny Huang } else { 76773f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 768b458cd62SJohnny Huang } 7693cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 770b458cd62SJohnny Huang printf("\n"); 771b458cd62SJohnny Huang } else { 7723cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 773b458cd62SJohnny Huang } 774b458cd62SJohnny Huang } 775b458cd62SJohnny Huang return OTP_SUCCESS; 77666f2f8e5SJohnny Huang } 77766f2f8e5SJohnny Huang 7785010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 77976d13988SJohnny Huang { 78079e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 781696656c6SJohnny Huang uint32_t *OTPSTRAP; 782696656c6SJohnny Huang uint32_t *OTPSTRAP_REG_PRO; 783696656c6SJohnny Huang uint32_t *OTPSTRAP_PRO; 784696656c6SJohnny Huang uint32_t *OTPSTRAP_IGNORE; 78576d13988SJohnny Huang int i; 786a8bd6d8cSJohnny Huang int fail = 0; 787a8bd6d8cSJohnny Huang uint32_t bit_offset; 788a8bd6d8cSJohnny Huang uint32_t dw_offset; 789a8bd6d8cSJohnny Huang uint32_t mask; 790a8bd6d8cSJohnny Huang uint32_t otp_value; 791696656c6SJohnny Huang uint32_t otp_reg_protect; 792a8bd6d8cSJohnny Huang uint32_t otp_protect; 793696656c6SJohnny Huang uint32_t otp_ignore; 79476d13988SJohnny Huang 795696656c6SJohnny Huang OTPSTRAP = (uint32_t *)image_layout->strap; 796696656c6SJohnny Huang OTPSTRAP_PRO = (uint32_t *)image_layout->strap_pro; 797696656c6SJohnny Huang OTPSTRAP_IGNORE = (uint32_t *)image_layout->strap_ignore; 7985010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 799696656c6SJohnny Huang OTPSTRAP_REG_PRO = NULL; 800a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 801696656c6SJohnny Huang } else { 802696656c6SJohnny Huang OTPSTRAP_REG_PRO = (uint32_t *)image_layout->strap_reg_pro; 803de6b0cc4SJohnny Huang printf("BIT(hex) Value Reg_Protect Protect Description\n"); 804696656c6SJohnny Huang } 805de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 806b458cd62SJohnny Huang 8073cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 808696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 809a8bd6d8cSJohnny Huang dw_offset = 1; 8103cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 811a8bd6d8cSJohnny Huang } else { 812a8bd6d8cSJohnny Huang dw_offset = 0; 8133cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 814a8bd6d8cSJohnny Huang } 81576d13988SJohnny Huang 8163cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 817a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 818a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 819696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 820a8bd6d8cSJohnny Huang 8215010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 822696656c6SJohnny Huang otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask; 8235010032bSJohnny Huang else 8245010032bSJohnny Huang otp_reg_protect = 0; 825696656c6SJohnny Huang 826696656c6SJohnny Huang if (otp_ignore == mask) { 827a8bd6d8cSJohnny Huang continue; 828696656c6SJohnny Huang } else if (otp_ignore != 0) { 829a8bd6d8cSJohnny Huang fail = 1; 830a8bd6d8cSJohnny Huang } 831a8bd6d8cSJohnny Huang 8323cb28812SJohnny Huang if ((otp_value != strap_info[i].value) && 8333cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 834a8bd6d8cSJohnny Huang continue; 835a8bd6d8cSJohnny Huang 8363cb28812SJohnny Huang if (strap_info[i].length == 1) { 8373cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 838a8bd6d8cSJohnny Huang } else { 839b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 8403cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 8413cb28812SJohnny Huang strap_info[i].bit_offset); 842a8bd6d8cSJohnny Huang } 843a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 8445010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 845696656c6SJohnny Huang printf("0x%-10x", otp_reg_protect); 846a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 847a8bd6d8cSJohnny Huang 848a8bd6d8cSJohnny Huang if (fail) { 849696656c6SJohnny Huang printf("Ignore mask error\n"); 850a8bd6d8cSJohnny Huang } else { 8513cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 8523cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 853a8bd6d8cSJohnny Huang else 854a8bd6d8cSJohnny Huang printf("Reserved\n"); 855a8bd6d8cSJohnny Huang } 856a8bd6d8cSJohnny Huang } 857a8bd6d8cSJohnny Huang 858a8bd6d8cSJohnny Huang if (fail) 85976d13988SJohnny Huang return OTP_FAILURE; 86076d13988SJohnny Huang 86176d13988SJohnny Huang return OTP_SUCCESS; 86276d13988SJohnny Huang } 86376d13988SJohnny Huang 864b458cd62SJohnny Huang static int otp_print_strap_info(int view) 86576d13988SJohnny Huang { 86679e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 86776d13988SJohnny Huang struct otpstrap_status strap_status[64]; 86807baa4e8SJohnny Huang int i, j; 869b458cd62SJohnny Huang int fail = 0; 870b458cd62SJohnny Huang uint32_t bit_offset; 871b458cd62SJohnny Huang uint32_t length; 872b458cd62SJohnny Huang uint32_t otp_value; 873b458cd62SJohnny Huang uint32_t otp_protect; 87476d13988SJohnny Huang 875541eb887SJohnny Huang otp_strap_status(strap_status); 87676d13988SJohnny Huang 877b458cd62SJohnny Huang if (view) { 87883655e91SJohnny Huang if (info_cb.version == OTP_AST2600A0) 87907baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 88083655e91SJohnny Huang else 88183655e91SJohnny Huang printf("BIT(hex) Value Remains Reg_Protect Protect Description\n"); 88207baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 883b458cd62SJohnny Huang } else { 884b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 885b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 88676d13988SJohnny Huang } 8873cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 888b458cd62SJohnny Huang otp_value = 0; 8893cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 8903cb28812SJohnny Huang length = strap_info[i].length; 891b458cd62SJohnny Huang for (j = 0; j < length; j++) { 892c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 893c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 894b458cd62SJohnny Huang } 8953cb28812SJohnny Huang if ((otp_value != strap_info[i].value) && 8963cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 897b458cd62SJohnny Huang continue; 898b458cd62SJohnny Huang if (view) { 899b458cd62SJohnny Huang for (j = 0; j < length; j++) { 9003cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 901b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 90207baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 90383655e91SJohnny Huang if (info_cb.version != OTP_AST2600A0) 904e1a7245eSJohnny Huang printf("0x%-10X", strap_status[bit_offset + j].reg_protected); 905e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 9063cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 907b458cd62SJohnny Huang printf(" Reserved\n"); 908b458cd62SJohnny Huang continue; 909b458cd62SJohnny Huang } 910b458cd62SJohnny Huang if (length == 1) { 9113cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 912b458cd62SJohnny Huang continue; 91376d13988SJohnny Huang } 91476d13988SJohnny Huang 915b458cd62SJohnny Huang if (j == 0) 9163cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 917b458cd62SJohnny Huang else if (j == length - 1) 918b458cd62SJohnny Huang printf("\\ \"\n"); 919b458cd62SJohnny Huang else 920b458cd62SJohnny Huang printf("| \"\n"); 92176d13988SJohnny Huang } 922b458cd62SJohnny Huang } else { 923c947ef08SJohnny Huang if (length == 1) { 9243cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 925b458cd62SJohnny Huang } else { 926b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 927b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 928b458cd62SJohnny Huang } 929b458cd62SJohnny Huang 930b458cd62SJohnny Huang printf("0x%-10X", otp_value); 931b458cd62SJohnny Huang 9323cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 9333cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 934b458cd62SJohnny Huang else 935b458cd62SJohnny Huang printf("Reserved\n"); 936b458cd62SJohnny Huang } 937b458cd62SJohnny Huang } 938b458cd62SJohnny Huang 939b458cd62SJohnny Huang if (fail) 940b458cd62SJohnny Huang return OTP_FAILURE; 941b458cd62SJohnny Huang 942b458cd62SJohnny Huang return OTP_SUCCESS; 943b458cd62SJohnny Huang } 944b458cd62SJohnny Huang 945696656c6SJohnny Huang static void buf_print(uint8_t *buf, int len) 94669d5fd8fSJohnny Huang { 94769d5fd8fSJohnny Huang int i; 94869d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 94969d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 95069d5fd8fSJohnny Huang if (i % 16 == 0) { 95169d5fd8fSJohnny Huang printf("%04X: ", i); 95269d5fd8fSJohnny Huang } 95369d5fd8fSJohnny Huang printf("%02X ", buf[i]); 95469d5fd8fSJohnny Huang if ((i + 1) % 16 == 0) { 95569d5fd8fSJohnny Huang printf("\n"); 95669d5fd8fSJohnny Huang } 95769d5fd8fSJohnny Huang } 95869d5fd8fSJohnny Huang } 95969d5fd8fSJohnny Huang 960696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout) 96169d5fd8fSJohnny Huang { 96269d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 96379e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 9649a4fe690SJohnny Huang struct otpkey_type key_info; 965696656c6SJohnny Huang uint32_t *buf; 966696656c6SJohnny Huang uint8_t *byte_buf; 9679d998018SJohnny Huang char empty = 1; 96869d5fd8fSJohnny Huang int i = 0, len = 0; 9699a4fe690SJohnny Huang int j; 97054552c69SJohnny Huang 971696656c6SJohnny Huang byte_buf = image_layout->data; 972696656c6SJohnny Huang buf = (uint32_t *)byte_buf; 9739d998018SJohnny Huang 9749d998018SJohnny Huang for (i = 0; i < 16; i++) { 9759d998018SJohnny Huang if (buf[i] != 0) { 9769d998018SJohnny Huang empty = 0; 9779d998018SJohnny Huang } 9789d998018SJohnny Huang } 9799d998018SJohnny Huang if (empty) 9809d998018SJohnny Huang return 0; 9819d998018SJohnny Huang 9829d998018SJohnny Huang i = 0; 98369d5fd8fSJohnny Huang while (1) { 98469d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 98569d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 98669d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 98769d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 98869d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 98969d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 9909a4fe690SJohnny Huang 9919a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 9929a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 9939a4fe690SJohnny Huang key_info = key_info_array[j]; 9949a4fe690SJohnny Huang break; 9959a4fe690SJohnny Huang } 9969a4fe690SJohnny Huang } 9979a4fe690SJohnny Huang 9987f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 99969d5fd8fSJohnny Huang printf("Key Type: "); 10009a4fe690SJohnny Huang printf("%s\n", key_info.information); 10019a4fe690SJohnny Huang 10029a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 100369d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 100469d5fd8fSJohnny Huang switch (key_length) { 100569d5fd8fSJohnny Huang case 0: 100669d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 100769d5fd8fSJohnny Huang break; 100869d5fd8fSJohnny Huang case 1: 100969d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 101069d5fd8fSJohnny Huang break; 101169d5fd8fSJohnny Huang case 2: 101269d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 101369d5fd8fSJohnny Huang break; 101469d5fd8fSJohnny Huang case 3: 101569d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 101669d5fd8fSJohnny Huang break; 101769d5fd8fSJohnny Huang } 10189a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA) { 101969d5fd8fSJohnny Huang printf("RSA SHA Type: "); 102069d5fd8fSJohnny Huang switch (key_length) { 102169d5fd8fSJohnny Huang case 0: 102269d5fd8fSJohnny Huang printf("RSA1024\n"); 102369d5fd8fSJohnny Huang len = 0x100; 102469d5fd8fSJohnny Huang break; 102569d5fd8fSJohnny Huang case 1: 102669d5fd8fSJohnny Huang printf("RSA2048\n"); 102769d5fd8fSJohnny Huang len = 0x200; 102869d5fd8fSJohnny Huang break; 102969d5fd8fSJohnny Huang case 2: 103069d5fd8fSJohnny Huang printf("RSA3072\n"); 103169d5fd8fSJohnny Huang len = 0x300; 103269d5fd8fSJohnny Huang break; 103369d5fd8fSJohnny Huang case 3: 103469d5fd8fSJohnny Huang printf("RSA4096\n"); 103569d5fd8fSJohnny Huang len = 0x400; 103669d5fd8fSJohnny Huang break; 103769d5fd8fSJohnny Huang } 103869d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 103969d5fd8fSJohnny Huang } 10409a4fe690SJohnny Huang if (key_info.need_id) 104169d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 104269d5fd8fSJohnny Huang printf("Key Value:\n"); 10439a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 104469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 10459a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 10469a4fe690SJohnny Huang printf("AES Key:\n"); 10479a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10485fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 10499a4fe690SJohnny Huang printf("AES IV:\n"); 10509a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10519a4fe690SJohnny Huang } 10529a4fe690SJohnny Huang 10539a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 10545fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 105569d5fd8fSJohnny Huang printf("AES Key:\n"); 105669d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 105769d5fd8fSJohnny Huang printf("AES IV:\n"); 105869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10595fdde29fSJohnny Huang } else { 10609a4fe690SJohnny Huang printf("AES Key 1:\n"); 10619a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10629a4fe690SJohnny Huang printf("AES Key 2:\n"); 10639a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 10649a4fe690SJohnny Huang } 106569d5fd8fSJohnny Huang 10669a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA) { 106769d5fd8fSJohnny Huang printf("RSA mod:\n"); 106869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 106969d5fd8fSJohnny Huang printf("RSA exp:\n"); 107069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 107169d5fd8fSJohnny Huang } 107269d5fd8fSJohnny Huang if (last) 107369d5fd8fSJohnny Huang break; 107469d5fd8fSJohnny Huang i++; 107569d5fd8fSJohnny Huang } 107669d5fd8fSJohnny Huang return 0; 107769d5fd8fSJohnny Huang } 107869d5fd8fSJohnny Huang 10795010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout) 108069d5fd8fSJohnny Huang { 1081a6d0d645SJohnny Huang int i, k; 1082d90825e2SJohnny Huang int pass = 0; 1083a6d0d645SJohnny Huang uint32_t prog_address; 1084bb34a7bfSJohnny Huang uint32_t data[16]; 1085a6d0d645SJohnny Huang uint32_t compare[2]; 10865010032bSJohnny Huang uint32_t *conf = (uint32_t *)image_layout->conf; 10875010032bSJohnny Huang uint32_t *conf_ignore = (uint32_t *)image_layout->conf_ignore; 1088d90825e2SJohnny Huang uint32_t data_masked; 1089d90825e2SJohnny Huang uint32_t buf_masked; 109069d5fd8fSJohnny Huang 1091a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 1092a6d0d645SJohnny Huang 1093bb34a7bfSJohnny Huang for (i = 0; i < 16 ; i ++) { 109469d5fd8fSJohnny Huang prog_address = 0x800; 1095a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1096a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1097a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 1098a6d0d645SJohnny Huang } 1099a6d0d645SJohnny Huang 1100a6d0d645SJohnny Huang printf("Check writable...\n"); 1101bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 11025010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 11035010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1104d90825e2SJohnny Huang if (data_masked == buf_masked) 110569d5fd8fSJohnny Huang continue; 1106d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1107a6d0d645SJohnny Huang continue; 1108a6d0d645SJohnny Huang } else { 1109a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1110a6af4a17SJohnny Huang printf("OTPCFG[%X] = %x\n", i, data[i]); 11115010032bSJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 11125010032bSJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 11132a856b9aSJohnny Huang return OTP_FAILURE; 1114a6d0d645SJohnny Huang } 1115a6d0d645SJohnny Huang } 1116a6d0d645SJohnny Huang 1117a6d0d645SJohnny Huang printf("Start Programing...\n"); 1118d90825e2SJohnny Huang otp_soak(0); 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]; 1122a6d0d645SJohnny Huang prog_address = 0x800; 1123a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1124a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1125bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1126bb34a7bfSJohnny Huang pass = 1; 1127a6d0d645SJohnny Huang continue; 1128bb34a7bfSJohnny Huang } 1129de6fbf1cSJohnny Huang 1130a6d0d645SJohnny Huang 1131de6fbf1cSJohnny Huang otp_soak(1); 11325010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1133a6d0d645SJohnny Huang 113469d5fd8fSJohnny Huang pass = 0; 113569d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 11365010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1137de6fbf1cSJohnny Huang otp_soak(2); 1138*feea3fdfSJohnny Huang otp_prog_dw(compare[0], conf_ignore[i], prog_address); 11395010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1140de6fbf1cSJohnny Huang otp_soak(1); 1141de6fbf1cSJohnny Huang } else { 1142de6fbf1cSJohnny Huang pass = 1; 1143de6fbf1cSJohnny Huang break; 1144de6fbf1cSJohnny Huang } 1145a6d0d645SJohnny Huang } else { 114669d5fd8fSJohnny Huang pass = 1; 114769d5fd8fSJohnny Huang break; 114869d5fd8fSJohnny Huang } 114969d5fd8fSJohnny Huang } 1150bb34a7bfSJohnny Huang if (pass == 0) { 1151bb34a7bfSJohnny Huang printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n", 11525010032bSJohnny Huang i, data[i], conf[i], conf_ignore[i]); 1153bb34a7bfSJohnny Huang break; 1154bb34a7bfSJohnny Huang } 1155a6d0d645SJohnny Huang } 1156a6d0d645SJohnny Huang 1157de6fbf1cSJohnny Huang otp_soak(0); 115869d5fd8fSJohnny Huang if (!pass) 11592a856b9aSJohnny Huang return OTP_FAILURE; 1160a6d0d645SJohnny Huang 11612a856b9aSJohnny Huang return OTP_SUCCESS; 1162d90825e2SJohnny Huang 116369d5fd8fSJohnny Huang } 116469d5fd8fSJohnny Huang 1165eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit) 1166eda10d61SJohnny Huang { 1167eda10d61SJohnny Huang if (ibit == 1) { 1168eda10d61SJohnny Huang return OTP_SUCCESS; 1169eda10d61SJohnny Huang } else { 1170eda10d61SJohnny Huang printf("OTPSTRAP[%X]:\n", offset); 1171eda10d61SJohnny Huang } 1172eda10d61SJohnny Huang if (bit == otpstrap->value) { 1173eda10d61SJohnny Huang printf(" The value is same as before, skip it.\n"); 1174eda10d61SJohnny Huang return OTP_PROG_SKIP; 1175eda10d61SJohnny Huang } 1176eda10d61SJohnny Huang if (otpstrap->protected == 1) { 1177eda10d61SJohnny Huang printf(" This bit is protected and is not writable\n"); 1178eda10d61SJohnny Huang return OTP_FAILURE; 1179eda10d61SJohnny Huang } 1180eda10d61SJohnny Huang if (otpstrap->remain_times == 0) { 1181eda10d61SJohnny Huang printf(" This bit is no remaining times to write.\n"); 1182eda10d61SJohnny Huang return OTP_FAILURE; 1183eda10d61SJohnny Huang } 1184eda10d61SJohnny Huang if (pbit == 1) { 1185eda10d61SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 1186eda10d61SJohnny Huang } 1187eda10d61SJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 1188eda10d61SJohnny Huang printf(" The relative register will be protected.\n"); 1189eda10d61SJohnny Huang } 1190eda10d61SJohnny 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); 1191eda10d61SJohnny Huang return OTP_SUCCESS; 1192eda10d61SJohnny Huang } 1193eda10d61SJohnny Huang 11945010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout) 119569d5fd8fSJohnny Huang { 119669d5fd8fSJohnny Huang int i; 11975010032bSJohnny Huang uint32_t *strap; 11985010032bSJohnny Huang uint32_t *strap_ignore; 11995010032bSJohnny Huang uint32_t *strap_reg_protect; 12005010032bSJohnny Huang uint32_t *strap_pro; 1201eda10d61SJohnny Huang int bit, pbit, ibit, rpbit; 120269d5fd8fSJohnny Huang int fail = 0; 1203a6af4a17SJohnny Huang int skip = -1; 1204eda10d61SJohnny Huang int ret; 120566f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 120669d5fd8fSJohnny Huang 12075010032bSJohnny Huang strap = (uint32_t *)image_layout->strap; 12085010032bSJohnny Huang strap_pro = (uint32_t *)image_layout->strap_pro; 12095010032bSJohnny Huang strap_ignore = (uint32_t *)image_layout->strap_ignore; 12105010032bSJohnny Huang strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro; 12115010032bSJohnny Huang 1212541eb887SJohnny Huang otp_strap_status(otpstrap); 121369d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 121469d5fd8fSJohnny Huang if (i < 32) { 12155010032bSJohnny Huang bit = (strap[0] >> i) & 0x1; 1216eda10d61SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 12175010032bSJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 121869d5fd8fSJohnny Huang } else { 12195010032bSJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1220eda10d61SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 12215010032bSJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 12225010032bSJohnny Huang } 12235010032bSJohnny Huang 12245010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 12255010032bSJohnny Huang if (i < 32) { 12265010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 12275010032bSJohnny Huang } else { 12285010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 12295010032bSJohnny Huang } 12305010032bSJohnny Huang } else { 12315010032bSJohnny Huang rpbit = 0; 123269d5fd8fSJohnny Huang } 1233eda10d61SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit); 1234eda10d61SJohnny Huang if (ret == OTP_PROG_SKIP) { 1235a6af4a17SJohnny Huang if (skip == -1) 1236a6af4a17SJohnny Huang skip = 1; 123769d5fd8fSJohnny Huang continue; 1238a6af4a17SJohnny Huang } else { 1239eda10d61SJohnny Huang skip = 1; 124069d5fd8fSJohnny Huang } 1241eda10d61SJohnny Huang 1242eda10d61SJohnny Huang if (ret == OTP_FAILURE) 124369d5fd8fSJohnny Huang fail = 1; 124469d5fd8fSJohnny Huang } 124569d5fd8fSJohnny Huang if (fail == 1) 1246a6af4a17SJohnny Huang return OTP_FAILURE; 1247a6af4a17SJohnny Huang else if (skip == 1) 1248a6af4a17SJohnny Huang return OTP_PROG_SKIP; 12497e22f42dSJohnny Huang 1250eda10d61SJohnny Huang return OTP_SUCCESS; 125169d5fd8fSJohnny Huang } 125269d5fd8fSJohnny Huang 12532a856b9aSJohnny Huang static int otp_print_strap(int start, int count) 125469d5fd8fSJohnny Huang { 125569d5fd8fSJohnny Huang int i, j; 1256de6b0cc4SJohnny Huang int remains; 125766f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 125869d5fd8fSJohnny Huang 12592a856b9aSJohnny Huang if (start < 0 || start > 64) 12602a856b9aSJohnny Huang return OTP_USAGE; 12612a856b9aSJohnny Huang 12622a856b9aSJohnny Huang if ((start + count) < 0 || (start + count) > 64) 12632a856b9aSJohnny Huang return OTP_USAGE; 12642a856b9aSJohnny Huang 1265541eb887SJohnny Huang otp_strap_status(otpstrap); 126669d5fd8fSJohnny Huang 1267de6b0cc4SJohnny Huang if (info_cb.version == OTP_AST2600A0) { 1268de6b0cc4SJohnny Huang remains = 7; 126907baa4e8SJohnny Huang printf("BIT(hex) Value Option Status\n"); 1270de6b0cc4SJohnny Huang } else { 1271de6b0cc4SJohnny Huang remains = 6; 1272de6b0cc4SJohnny Huang printf("BIT(hex) Value Option Reg_Protect Status\n"); 1273de6b0cc4SJohnny Huang } 1274de6b0cc4SJohnny Huang printf("______________________________________________________________________________\n"); 1275737ed20bSJohnny Huang 1276cd1610b4SJohnny Huang for (i = start; i < start + count; i++) { 127707baa4e8SJohnny Huang printf("0x%-8X", i); 1278737ed20bSJohnny Huang printf("%-7d", otpstrap[i].value); 1279de6b0cc4SJohnny Huang for (j = 0; j < remains; j++) 1280737ed20bSJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 1281737ed20bSJohnny Huang printf(" "); 1282de6b0cc4SJohnny Huang if (info_cb.version != OTP_AST2600A0) { 1283de6b0cc4SJohnny Huang printf("%d ", otpstrap[i].reg_protected); 1284de6b0cc4SJohnny Huang } 128569d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 1286737ed20bSJohnny Huang printf("protected and not writable"); 128769d5fd8fSJohnny Huang } else { 1288737ed20bSJohnny Huang printf("not protected "); 128969d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 1290737ed20bSJohnny Huang printf("and no remaining times to write."); 129169d5fd8fSJohnny Huang } else { 1292737ed20bSJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 129369d5fd8fSJohnny Huang } 129469d5fd8fSJohnny Huang } 1295737ed20bSJohnny Huang printf("\n"); 129669d5fd8fSJohnny Huang } 12972a856b9aSJohnny Huang 12982a856b9aSJohnny Huang return OTP_SUCCESS; 129969d5fd8fSJohnny Huang } 130069d5fd8fSJohnny Huang 13018848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value) 13028848d5dcSJohnny Huang { 13038848d5dcSJohnny Huang struct otpstrap_status otpstrap[64]; 130483655e91SJohnny Huang uint32_t prog_address; 13058848d5dcSJohnny Huang int offset; 13068848d5dcSJohnny Huang int ret; 13078848d5dcSJohnny Huang 13088848d5dcSJohnny Huang 13098848d5dcSJohnny Huang otp_strap_status(otpstrap); 13108848d5dcSJohnny Huang 13118848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 13128848d5dcSJohnny Huang 13138848d5dcSJohnny Huang if (ret != OTP_SUCCESS) { 13148848d5dcSJohnny Huang return ret; 13158848d5dcSJohnny Huang } 13168848d5dcSJohnny Huang 13178848d5dcSJohnny Huang prog_address = 0x800; 13188848d5dcSJohnny Huang if (bit_offset < 32) { 13198848d5dcSJohnny Huang offset = bit_offset; 13208848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 13218848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 13228848d5dcSJohnny Huang 13238848d5dcSJohnny Huang } else { 13248848d5dcSJohnny Huang offset = (bit_offset - 32); 13258848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 13268848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 13278848d5dcSJohnny Huang } 13288848d5dcSJohnny Huang 13298848d5dcSJohnny Huang 133083655e91SJohnny Huang return otp_prog_bit(1, prog_address, offset); 13318848d5dcSJohnny Huang } 13328848d5dcSJohnny Huang 13335010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout) 133469d5fd8fSJohnny Huang { 13355010032bSJohnny Huang uint32_t *strap; 13365010032bSJohnny Huang uint32_t *strap_ignore; 13375010032bSJohnny Huang uint32_t *strap_pro; 13385010032bSJohnny Huang uint32_t *strap_reg_protect; 133983655e91SJohnny Huang uint32_t prog_address; 134083655e91SJohnny Huang int i; 1341eda10d61SJohnny Huang int bit, pbit, ibit, offset, rpbit; 134269d5fd8fSJohnny Huang int fail = 0; 134383655e91SJohnny Huang int ret; 134466f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 134569d5fd8fSJohnny Huang 13465010032bSJohnny Huang strap = (uint32_t *)image_layout->strap; 13475010032bSJohnny Huang strap_pro = (uint32_t *)image_layout->strap_pro; 13485010032bSJohnny Huang strap_ignore = (uint32_t *)image_layout->strap_ignore; 13495010032bSJohnny Huang strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro; 13505010032bSJohnny Huang 13517f795e57SJohnny Huang printf("Read OTP Strap Region:\n"); 1352541eb887SJohnny Huang otp_strap_status(otpstrap); 135369d5fd8fSJohnny Huang 13547f795e57SJohnny Huang printf("Check writable...\n"); 13555010032bSJohnny Huang if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) { 13567f795e57SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 13577f795e57SJohnny Huang return OTP_FAILURE; 13587f795e57SJohnny Huang } 13597e22f42dSJohnny Huang 136069d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 136169d5fd8fSJohnny Huang prog_address = 0x800; 136269d5fd8fSJohnny Huang if (i < 32) { 136369d5fd8fSJohnny Huang offset = i; 13645010032bSJohnny Huang bit = (strap[0] >> offset) & 0x1; 1365eda10d61SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 13665010032bSJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 136769d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 136869d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 136969d5fd8fSJohnny Huang 137069d5fd8fSJohnny Huang } else { 137169d5fd8fSJohnny Huang offset = (i - 32); 13725010032bSJohnny Huang bit = (strap[1] >> offset) & 0x1; 1373eda10d61SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 13745010032bSJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 137569d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 137669d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 137769d5fd8fSJohnny Huang } 13785010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 13795010032bSJohnny Huang if (i < 32) { 13805010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 13815010032bSJohnny Huang } else { 13825010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 13835010032bSJohnny Huang } 13845010032bSJohnny Huang } else { 13855010032bSJohnny Huang rpbit = 0; 13865010032bSJohnny Huang } 138769d5fd8fSJohnny Huang 1388eda10d61SJohnny Huang if (ibit == 1) { 138969d5fd8fSJohnny Huang continue; 139069d5fd8fSJohnny Huang } 139169d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 139269d5fd8fSJohnny Huang continue; 139369d5fd8fSJohnny Huang } 139469d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 139569d5fd8fSJohnny Huang fail = 1; 139669d5fd8fSJohnny Huang continue; 139769d5fd8fSJohnny Huang } 139869d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 139969d5fd8fSJohnny Huang fail = 1; 140069d5fd8fSJohnny Huang continue; 140169d5fd8fSJohnny Huang } 14027e22f42dSJohnny Huang 140383655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 140483655e91SJohnny Huang if (!ret) 14052a856b9aSJohnny Huang return OTP_FAILURE; 140669d5fd8fSJohnny Huang 14075010032bSJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 140869d5fd8fSJohnny Huang prog_address = 0x800; 140969d5fd8fSJohnny Huang if (i < 32) 14105010032bSJohnny Huang prog_address |= 0x608; 141169d5fd8fSJohnny Huang else 14125010032bSJohnny Huang prog_address |= 0x60a; 14137e22f42dSJohnny Huang 141483655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 141583655e91SJohnny Huang if (!ret) 14162a856b9aSJohnny Huang return OTP_FAILURE; 14175010032bSJohnny Huang } 14185010032bSJohnny Huang 14195010032bSJohnny Huang if (pbit != 0) { 14205010032bSJohnny Huang prog_address = 0x800; 14215010032bSJohnny Huang if (i < 32) 14225010032bSJohnny Huang prog_address |= 0x60c; 14235010032bSJohnny Huang else 14245010032bSJohnny Huang prog_address |= 0x60e; 14255010032bSJohnny Huang 142683655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 142783655e91SJohnny Huang if (!ret) 14285010032bSJohnny Huang return OTP_FAILURE; 14295010032bSJohnny Huang } 143069d5fd8fSJohnny Huang 143169d5fd8fSJohnny Huang } 1432de6fbf1cSJohnny Huang otp_soak(0); 143369d5fd8fSJohnny Huang if (fail == 1) 14342a856b9aSJohnny Huang return OTP_FAILURE; 143569d5fd8fSJohnny Huang else 14362a856b9aSJohnny Huang return OTP_SUCCESS; 143769d5fd8fSJohnny Huang 143869d5fd8fSJohnny Huang } 143969d5fd8fSJohnny Huang 14405010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout) 14414c1c9b35SJohnny Huang { 144254552c69SJohnny Huang int i; 144354552c69SJohnny Huang int ret; 14445010032bSJohnny Huang int data_dw; 1445d90825e2SJohnny Huang uint32_t data[2048]; 14465010032bSJohnny Huang uint32_t *buf; 14475010032bSJohnny Huang uint32_t *buf_ignore; 14484c1c9b35SJohnny Huang 144954552c69SJohnny Huang uint32_t data_masked; 145054552c69SJohnny Huang uint32_t buf_masked; 14514c1c9b35SJohnny Huang 14525010032bSJohnny Huang buf = (uint32_t *)image_layout->data; 14535010032bSJohnny Huang buf_ignore = (uint32_t *)image_layout->data_ignore; 14545010032bSJohnny Huang 14555010032bSJohnny Huang data_dw = image_layout->data_length / 4; 14565010032bSJohnny Huang 14574c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 14584c1c9b35SJohnny Huang 14595010032bSJohnny Huang for (i = 0; i < data_dw - 2 ; i += 2) { 1460d90825e2SJohnny Huang otp_read_data(i, &data[i]); 14614c1c9b35SJohnny Huang } 1462d90825e2SJohnny Huang 14634c1c9b35SJohnny Huang printf("Check writable...\n"); 146454552c69SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 14655010032bSJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1466696656c6SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1467696656c6SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 146854552c69SJohnny Huang if (data_masked == buf_masked) 14694c1c9b35SJohnny Huang continue; 1470d90825e2SJohnny Huang if (i % 2 == 0) { 147154552c69SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 14724c1c9b35SJohnny Huang continue; 14734c1c9b35SJohnny Huang } else { 14744c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1475d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 14764c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1477696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 14782a856b9aSJohnny Huang return OTP_FAILURE; 147969d5fd8fSJohnny Huang } 1480d90825e2SJohnny Huang } else { 148154552c69SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1482d90825e2SJohnny Huang continue; 1483d90825e2SJohnny Huang } else { 1484d90825e2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1485d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1486d90825e2SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1487696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 14882a856b9aSJohnny Huang return OTP_FAILURE; 1489d90825e2SJohnny Huang } 1490d90825e2SJohnny Huang } 1491d90825e2SJohnny Huang } 149269d5fd8fSJohnny Huang 1493d90825e2SJohnny Huang printf("Start Programing...\n"); 1494d90825e2SJohnny Huang 149554552c69SJohnny Huang // programing ecc region first 149654552c69SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1497696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 149854552c69SJohnny Huang if (ret != OTP_SUCCESS) { 149954552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1500696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 150154552c69SJohnny Huang return ret; 1502d90825e2SJohnny Huang } 1503d90825e2SJohnny Huang } 1504d90825e2SJohnny Huang 150554552c69SJohnny Huang for (i = 0; i < 1792; i += 2) { 1506696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 150754552c69SJohnny Huang if (ret != OTP_SUCCESS) { 150854552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1509696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 151054552c69SJohnny Huang return ret; 1511d90825e2SJohnny Huang } 1512de6fbf1cSJohnny Huang } 1513de6fbf1cSJohnny Huang otp_soak(0); 15142a856b9aSJohnny Huang return OTP_SUCCESS; 1515d90825e2SJohnny Huang 1516d90825e2SJohnny Huang } 1517d90825e2SJohnny Huang 1518696656c6SJohnny Huang static int otp_image_verify(uint8_t *src_buf, uint32_t length, uint8_t *digest_buf) 1519696656c6SJohnny Huang { 1520696656c6SJohnny Huang sha256_context ctx; 1521696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1522696656c6SJohnny Huang 1523696656c6SJohnny Huang sha256_starts(&ctx); 1524696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1525696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1526696656c6SJohnny Huang 1527696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1528696656c6SJohnny Huang return 0; 1529696656c6SJohnny Huang else 1530696656c6SJohnny Huang return -1; 1531696656c6SJohnny Huang 1532696656c6SJohnny Huang } 1533696656c6SJohnny Huang 1534de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm) 153569d5fd8fSJohnny Huang { 153669d5fd8fSJohnny Huang int ret; 15379a4fe690SJohnny Huang int image_version = 0; 1538696656c6SJohnny Huang struct otp_header *otp_header; 1539696656c6SJohnny Huang struct otp_image_layout image_layout; 1540696656c6SJohnny Huang int image_size; 1541696656c6SJohnny Huang uint8_t *buf; 1542696656c6SJohnny Huang uint8_t *checksum; 154369d5fd8fSJohnny Huang 1544696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1545696656c6SJohnny Huang if (!otp_header) { 154669d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 15472a856b9aSJohnny Huang return OTP_FAILURE; 154869d5fd8fSJohnny Huang } 1549d90825e2SJohnny Huang 1550696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1551696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1552696656c6SJohnny Huang 1553696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1554696656c6SJohnny Huang 1555696656c6SJohnny Huang if (!buf) { 1556696656c6SJohnny Huang puts("Failed to map physical memory\n"); 1557696656c6SJohnny Huang return OTP_FAILURE; 1558696656c6SJohnny Huang } 1559696656c6SJohnny Huang otp_header = (struct otp_header *) buf; 1560696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1561696656c6SJohnny Huang 1562696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1563696656c6SJohnny Huang puts("Image is invalid\n"); 1564696656c6SJohnny Huang return OTP_FAILURE; 1565696656c6SJohnny Huang } 1566696656c6SJohnny Huang 1567696656c6SJohnny Huang 15685010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 15695010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 15705010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 15715010032bSJohnny Huang 15725010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1573696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 15745010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1575696656c6SJohnny Huang 1576696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 1577696656c6SJohnny Huang 1578696656c6SJohnny Huang if (!strcmp("A0", (char *)otp_header->otp_version)) { 1579696656c6SJohnny Huang image_version = OTP_AST2600A0; 15805010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 15815010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 15825010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 1583696656c6SJohnny Huang } else if (!strcmp("A1", (char *)otp_header->otp_version)) { 1584696656c6SJohnny Huang image_version = OTP_AST2600A1; 15855010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 15865010032bSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 15875010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 15885010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 15895fdde29fSJohnny Huang } else if (!strcmp("A2", (char *)otp_header->otp_version)) { 15905fdde29fSJohnny Huang image_version = OTP_AST2600A2; 15915fdde29fSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 15925fdde29fSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 15935fdde29fSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 15945fdde29fSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 1595696656c6SJohnny Huang } else { 1596696656c6SJohnny Huang puts("Version is not supported\n"); 1597696656c6SJohnny Huang return OTP_FAILURE; 1598696656c6SJohnny Huang } 1599696656c6SJohnny Huang 16009a4fe690SJohnny Huang if (image_version != info_cb.version) { 16019a4fe690SJohnny Huang puts("Version is not match\n"); 16029a4fe690SJohnny Huang return OTP_FAILURE; 16039a4fe690SJohnny Huang } 16049a4fe690SJohnny Huang 1605696656c6SJohnny Huang if (otp_image_verify(buf, image_size, checksum)) { 1606696656c6SJohnny Huang puts("checksum is invalid\n"); 1607696656c6SJohnny Huang return OTP_FAILURE; 1608d90825e2SJohnny Huang } 16097332532cSJohnny Huang 161069d5fd8fSJohnny Huang if (!nconfirm) { 1611696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16127f795e57SJohnny Huang printf("\nOTP data region :\n"); 1613696656c6SJohnny Huang if (otp_print_data_info(&image_layout) < 0) { 161469d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 16152a856b9aSJohnny Huang return OTP_FAILURE; 161669d5fd8fSJohnny Huang } 161769d5fd8fSJohnny Huang } 1618696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16197332532cSJohnny Huang printf("\nOTP strap region :\n"); 16205010032bSJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 16217332532cSJohnny Huang printf("OTP strap error, please check.\n"); 16227332532cSJohnny Huang return OTP_FAILURE; 16237332532cSJohnny Huang } 16247332532cSJohnny Huang } 1625696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16267332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1627696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 16287332532cSJohnny Huang printf("OTP config error, please check.\n"); 16297332532cSJohnny Huang return OTP_FAILURE; 16307332532cSJohnny Huang } 16317332532cSJohnny Huang } 16327332532cSJohnny Huang 163369d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 163469d5fd8fSJohnny Huang if (!confirm_yesno()) { 163569d5fd8fSJohnny Huang printf(" Aborting\n"); 16362a856b9aSJohnny Huang return OTP_FAILURE; 163769d5fd8fSJohnny Huang } 163869d5fd8fSJohnny Huang } 16397332532cSJohnny Huang 16405010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16415010032bSJohnny Huang printf("programing data region ...\n"); 16425010032bSJohnny Huang ret = otp_prog_data(&image_layout); 16435010032bSJohnny Huang if (ret != 0) { 16445010032bSJohnny Huang printf("Error\n"); 16455010032bSJohnny Huang return ret; 16465010032bSJohnny Huang } else { 16475010032bSJohnny Huang printf("Done\n"); 16485010032bSJohnny Huang } 16495010032bSJohnny Huang } 16505010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16515010032bSJohnny Huang printf("programing strap region ...\n"); 16525010032bSJohnny Huang ret = otp_prog_strap(&image_layout); 16535010032bSJohnny Huang if (ret != 0) { 16545010032bSJohnny Huang printf("Error\n"); 16555010032bSJohnny Huang return ret; 16565010032bSJohnny Huang } else { 16575010032bSJohnny Huang printf("Done\n"); 16585010032bSJohnny Huang } 16595010032bSJohnny Huang } 16605010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16615010032bSJohnny Huang printf("programing configuration region ...\n"); 16625010032bSJohnny Huang ret = otp_prog_conf(&image_layout); 16635010032bSJohnny Huang if (ret != 0) { 16645010032bSJohnny Huang printf("Error\n"); 16655010032bSJohnny Huang return ret; 16665010032bSJohnny Huang } 16675010032bSJohnny Huang printf("Done\n"); 16685010032bSJohnny Huang } 1669cd1610b4SJohnny Huang 16707332532cSJohnny Huang return OTP_SUCCESS; 16712a856b9aSJohnny Huang } 16722a856b9aSJohnny Huang 16732a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1674cd1610b4SJohnny Huang { 1675a6af4a17SJohnny Huang uint32_t read[2]; 1676d90825e2SJohnny Huang uint32_t prog_address = 0; 167766f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 1678cd1610b4SJohnny Huang int otp_bit; 167983655e91SJohnny Huang int ret = 0; 1680cd1610b4SJohnny Huang 1681dacbba92SJohnny Huang otp_soak(0); 1682cd1610b4SJohnny Huang switch (mode) { 1683a6d0d645SJohnny Huang case OTP_REGION_CONF: 1684a6af4a17SJohnny Huang otp_read_config(otp_dw_offset, read); 1685cd1610b4SJohnny Huang prog_address = 0x800; 1686cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1687cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1688a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1689cd1610b4SJohnny Huang if (otp_bit == value) { 1690a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1691cd1610b4SJohnny Huang printf("No need to program\n"); 16922a856b9aSJohnny Huang return OTP_SUCCESS; 1693cd1610b4SJohnny Huang } 1694cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1695a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset); 1696cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 16972a856b9aSJohnny Huang return OTP_FAILURE; 1698cd1610b4SJohnny Huang } 1699a6af4a17SJohnny Huang printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset); 1700cd1610b4SJohnny Huang break; 1701a6d0d645SJohnny Huang case OTP_REGION_DATA: 1702cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1703cd1610b4SJohnny Huang 1704cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1705a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 1706a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1707643b9cfdSJohnny Huang 1708643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 1709643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1710643b9cfdSJohnny Huang printf("OTP is programed, which can't be cleaned\n"); 1711643b9cfdSJohnny Huang return OTP_FAILURE; 1712643b9cfdSJohnny Huang } 1713cd1610b4SJohnny Huang } else { 1714a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 1715a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 1716643b9cfdSJohnny Huang 1717643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 1718643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1719643b9cfdSJohnny Huang printf("OTP is programed, which can't be writen\n"); 1720643b9cfdSJohnny Huang return OTP_FAILURE; 1721643b9cfdSJohnny Huang } 1722cd1610b4SJohnny Huang } 1723cd1610b4SJohnny Huang if (otp_bit == value) { 1724a6af4a17SJohnny Huang printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1725cd1610b4SJohnny Huang printf("No need to program\n"); 17262a856b9aSJohnny Huang return OTP_SUCCESS; 1727cd1610b4SJohnny Huang } 1728643b9cfdSJohnny Huang 1729a6af4a17SJohnny Huang printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset); 1730cd1610b4SJohnny Huang break; 1731a6d0d645SJohnny Huang case OTP_REGION_STRAP: 17328848d5dcSJohnny Huang otp_strap_status(otpstrap); 17338848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 17348848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 17358848d5dcSJohnny Huang if (ret == OTP_FAILURE) 17368848d5dcSJohnny Huang return OTP_FAILURE; 17378848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 17388848d5dcSJohnny Huang return OTP_SUCCESS; 1739a6af4a17SJohnny Huang 1740cd1610b4SJohnny Huang break; 1741cd1610b4SJohnny Huang } 1742cd1610b4SJohnny Huang 1743cd1610b4SJohnny Huang if (!nconfirm) { 1744cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1745cd1610b4SJohnny Huang if (!confirm_yesno()) { 1746cd1610b4SJohnny Huang printf(" Aborting\n"); 17472a856b9aSJohnny Huang return OTP_FAILURE; 1748cd1610b4SJohnny Huang } 1749cd1610b4SJohnny Huang } 1750cd1610b4SJohnny Huang 1751cd1610b4SJohnny Huang switch (mode) { 1752a6d0d645SJohnny Huang case OTP_REGION_STRAP: 175383655e91SJohnny Huang ret = otp_prog_strap_bit(bit_offset, value); 175483655e91SJohnny Huang break; 1755a6d0d645SJohnny Huang case OTP_REGION_CONF: 1756a6d0d645SJohnny Huang case OTP_REGION_DATA: 175783655e91SJohnny Huang ret = otp_prog_bit(value, prog_address, bit_offset); 1758de6fbf1cSJohnny Huang break; 1759de6fbf1cSJohnny Huang } 1760de6fbf1cSJohnny Huang otp_soak(0); 176183655e91SJohnny Huang if (ret) { 17629009c25dSJohnny Huang printf("SUCCESS\n"); 17632a856b9aSJohnny Huang return OTP_SUCCESS; 17649009c25dSJohnny Huang } else { 17659009c25dSJohnny Huang printf("OTP cannot be programed\n"); 17669009c25dSJohnny Huang printf("FAILED\n"); 17679009c25dSJohnny Huang return OTP_FAILURE; 17689009c25dSJohnny Huang } 1769cd1610b4SJohnny Huang 17702a856b9aSJohnny Huang return OTP_USAGE; 1771cd1610b4SJohnny Huang } 1772cd1610b4SJohnny Huang 17732a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 177469d5fd8fSJohnny Huang { 17752a856b9aSJohnny Huang uint32_t offset, count; 17762a856b9aSJohnny Huang int ret; 177769d5fd8fSJohnny Huang 17782a856b9aSJohnny Huang if (argc == 4) { 17792a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 17802a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 17812a856b9aSJohnny Huang } else if (argc == 3) { 17822a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 17832a856b9aSJohnny Huang count = 1; 17842a856b9aSJohnny Huang } else { 178569d5fd8fSJohnny Huang return CMD_RET_USAGE; 178669d5fd8fSJohnny Huang } 178769d5fd8fSJohnny Huang 178869d5fd8fSJohnny Huang 17892a856b9aSJohnny Huang if (!strcmp(argv[1], "conf")) { 17903d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17912a856b9aSJohnny Huang ret = otp_print_config(offset, count); 17922a856b9aSJohnny Huang } else if (!strcmp(argv[1], "data")) { 17933d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17942a856b9aSJohnny Huang ret = otp_print_data(offset, count); 17952a856b9aSJohnny Huang } else if (!strcmp(argv[1], "strap")) { 17963d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17972a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 17982a856b9aSJohnny Huang } else { 17992a856b9aSJohnny Huang return CMD_RET_USAGE; 180069d5fd8fSJohnny Huang } 180169d5fd8fSJohnny Huang 18022a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18032a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18042a856b9aSJohnny Huang else 18052a856b9aSJohnny Huang return CMD_RET_USAGE; 18062a856b9aSJohnny Huang 18072a856b9aSJohnny Huang } 18082a856b9aSJohnny Huang 18092a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18102a856b9aSJohnny Huang { 18112a856b9aSJohnny Huang phys_addr_t addr; 18122a856b9aSJohnny Huang int ret; 18132a856b9aSJohnny Huang 1814de6b0cc4SJohnny Huang if (argc == 3) { 1815ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 18162a856b9aSJohnny Huang return CMD_RET_USAGE; 18172a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 18183d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1819de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 1); 1820de6b0cc4SJohnny Huang } else if (argc == 2) { 18212a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 18223d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1823de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 0); 18242a856b9aSJohnny Huang } else { 18252a856b9aSJohnny Huang return CMD_RET_USAGE; 18262a856b9aSJohnny Huang } 18272a856b9aSJohnny Huang 18282a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18292a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18302a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 18312a856b9aSJohnny Huang return CMD_RET_FAILURE; 18322a856b9aSJohnny Huang else 18332a856b9aSJohnny Huang return CMD_RET_USAGE; 18342a856b9aSJohnny Huang } 18352a856b9aSJohnny Huang 18362a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18372a856b9aSJohnny Huang { 18382a856b9aSJohnny Huang int mode = 0; 18392a856b9aSJohnny Huang int nconfirm = 0; 18402a856b9aSJohnny Huang int otp_addr = 0; 18412a856b9aSJohnny Huang int bit_offset; 18422a856b9aSJohnny Huang int value; 18432a856b9aSJohnny Huang int ret; 18442a856b9aSJohnny Huang 18452a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 18462a856b9aSJohnny Huang return CMD_RET_USAGE; 18472a856b9aSJohnny Huang 18482a856b9aSJohnny Huang /* Drop the pb cmd */ 18492a856b9aSJohnny Huang argc--; 18502a856b9aSJohnny Huang argv++; 18512a856b9aSJohnny Huang 18522a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 1853a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 18542a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 1855a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 18562a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 1857a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 1858cd1610b4SJohnny Huang else 18592a856b9aSJohnny Huang return CMD_RET_USAGE; 18602a856b9aSJohnny Huang 18612a856b9aSJohnny Huang /* Drop the region cmd */ 18622a856b9aSJohnny Huang argc--; 18632a856b9aSJohnny Huang argv++; 18642a856b9aSJohnny Huang 1865ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1866cd1610b4SJohnny Huang nconfirm = 1; 18672a856b9aSJohnny Huang /* Drop the force option */ 18682a856b9aSJohnny Huang argc--; 18692a856b9aSJohnny Huang argv++; 18702a856b9aSJohnny Huang } 1871cd1610b4SJohnny Huang 1872a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 18732a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 18742a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 18750808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 18762a856b9aSJohnny Huang return CMD_RET_USAGE; 1877cd1610b4SJohnny Huang } else { 18782a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 18792a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 18802a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 18810808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 18822a856b9aSJohnny Huang return CMD_RET_USAGE; 18830808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 188478855207SJohnny Huang if (otp_addr >= 0x800) 18850808cc55SJohnny Huang return CMD_RET_USAGE; 18860808cc55SJohnny Huang } else { 188778855207SJohnny Huang if (otp_addr >= 0x20) 18880808cc55SJohnny Huang return CMD_RET_USAGE; 18890808cc55SJohnny Huang } 1890cd1610b4SJohnny Huang } 1891cd1610b4SJohnny Huang if (value != 0 && value != 1) 18922a856b9aSJohnny Huang return CMD_RET_USAGE; 1893cd1610b4SJohnny Huang 18943d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18952a856b9aSJohnny Huang ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 18962a856b9aSJohnny Huang 18972a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18982a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18992a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 19002a856b9aSJohnny Huang return CMD_RET_FAILURE; 19012a856b9aSJohnny Huang else 19022a856b9aSJohnny Huang return CMD_RET_USAGE; 19032a856b9aSJohnny Huang } 19042a856b9aSJohnny Huang 19052a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 19062a856b9aSJohnny Huang { 19072a856b9aSJohnny Huang phys_addr_t addr; 19082a856b9aSJohnny Huang int otp_addr = 0; 19092a856b9aSJohnny Huang 19102a856b9aSJohnny Huang if (argc != 3) 19112a856b9aSJohnny Huang return CMD_RET_USAGE; 19122a856b9aSJohnny Huang 19133d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19142a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 19152a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 19162a856b9aSJohnny Huang if (otp_compare(otp_addr, addr) == 0) { 191769d5fd8fSJohnny Huang printf("Compare pass\n"); 19182a856b9aSJohnny Huang return CMD_RET_SUCCESS; 191969d5fd8fSJohnny Huang } else { 192069d5fd8fSJohnny Huang printf("Compare fail\n"); 19212a856b9aSJohnny Huang return CMD_RET_FAILURE; 192269d5fd8fSJohnny Huang } 192369d5fd8fSJohnny Huang } 192469d5fd8fSJohnny Huang 192566f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 192666f2f8e5SJohnny Huang { 1927a8bd6d8cSJohnny Huang int view = 0; 19282d4b0742SJohnny Huang int input; 1929a8bd6d8cSJohnny Huang 1930a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 193166f2f8e5SJohnny Huang return CMD_RET_USAGE; 193266f2f8e5SJohnny Huang 19332d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 193466f2f8e5SJohnny Huang 19353d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19362d4b0742SJohnny Huang if (argc == 3) { 19372d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 19382d4b0742SJohnny Huang otp_print_conf_info(input); 19392d4b0742SJohnny Huang } else { 19402d4b0742SJohnny Huang otp_print_conf_info(-1); 19412d4b0742SJohnny Huang } 19422d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 19432d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 1944a8bd6d8cSJohnny Huang view = 1; 1945a8bd6d8cSJohnny Huang /* Drop the view option */ 1946a8bd6d8cSJohnny Huang argc--; 1947a8bd6d8cSJohnny Huang argv++; 1948a8bd6d8cSJohnny Huang } 19493d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1950b458cd62SJohnny Huang otp_print_strap_info(view); 195166f2f8e5SJohnny Huang } else { 195266f2f8e5SJohnny Huang return CMD_RET_USAGE; 195366f2f8e5SJohnny Huang } 19542d4b0742SJohnny Huang 195566f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 195666f2f8e5SJohnny Huang } 195766f2f8e5SJohnny Huang 1958737ed20bSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1959737ed20bSJohnny Huang { 1960737ed20bSJohnny Huang int input; 1961737ed20bSJohnny Huang int bit_offset; 1962737ed20bSJohnny Huang int prog_address; 196383655e91SJohnny Huang int ret; 1964737ed20bSJohnny Huang if (argc != 3 && argc != 2) 1965737ed20bSJohnny Huang return CMD_RET_USAGE; 1966737ed20bSJohnny Huang 1967ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1968737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 1969737ed20bSJohnny Huang } else { 1970737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 1971737ed20bSJohnny Huang printf("OTPSTRAP[%d] will be protected\n", input); 1972737ed20bSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1973737ed20bSJohnny Huang if (!confirm_yesno()) { 1974737ed20bSJohnny Huang printf(" Aborting\n"); 1975737ed20bSJohnny Huang return CMD_RET_FAILURE; 1976737ed20bSJohnny Huang } 1977737ed20bSJohnny Huang } 1978737ed20bSJohnny Huang 1979737ed20bSJohnny Huang prog_address = 0x800; 1980737ed20bSJohnny Huang if (input < 32) { 1981737ed20bSJohnny Huang bit_offset = input; 1982737ed20bSJohnny Huang prog_address |= 0x60c; 1983737ed20bSJohnny Huang } else if (input < 64) { 1984737ed20bSJohnny Huang bit_offset = input - 32; 1985737ed20bSJohnny Huang prog_address |= 0x60e; 1986737ed20bSJohnny Huang } else { 1987737ed20bSJohnny Huang return CMD_RET_USAGE; 1988737ed20bSJohnny Huang } 1989737ed20bSJohnny Huang 1990737ed20bSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 1991737ed20bSJohnny Huang printf("OTPSTRAP[%d] already protected\n", input); 1992737ed20bSJohnny Huang } 1993de6fbf1cSJohnny Huang 199483655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, bit_offset); 1995de6fbf1cSJohnny Huang otp_soak(0); 199683655e91SJohnny Huang 199783655e91SJohnny Huang if (ret) { 1998737ed20bSJohnny Huang printf("OTPSTRAP[%d] is protected\n", input); 1999737ed20bSJohnny Huang return CMD_RET_SUCCESS; 2000737ed20bSJohnny Huang } 2001737ed20bSJohnny Huang 2002737ed20bSJohnny Huang printf("Protect OTPSTRAP[%d] fail\n", input); 2003737ed20bSJohnny Huang return CMD_RET_FAILURE; 2004737ed20bSJohnny Huang 2005737ed20bSJohnny Huang } 20069a4fe690SJohnny Huang 2007f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 2008f67375f7SJohnny Huang { 2009f67375f7SJohnny Huang printf("OTP tool version: %s\n", OTP_VER); 2010f67375f7SJohnny Huang printf("OTP info version: %s\n", OTP_INFO_VER); 2011f67375f7SJohnny Huang 2012f67375f7SJohnny Huang return CMD_RET_SUCCESS; 2013f67375f7SJohnny Huang } 2014f67375f7SJohnny Huang 20152a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 2016f67375f7SJohnny Huang U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""), 20172a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 2018a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 2019de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 20202a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 2021737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 20222a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 20232a856b9aSJohnny Huang }; 20242a856b9aSJohnny Huang 20252a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20262a856b9aSJohnny Huang { 20272a856b9aSJohnny Huang cmd_tbl_t *cp; 20280dae9d52SJohnny Huang uint32_t ver; 20292a856b9aSJohnny Huang 20302a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 20312a856b9aSJohnny Huang 2032737ed20bSJohnny Huang /* Drop the otp command */ 20332a856b9aSJohnny Huang argc--; 20342a856b9aSJohnny Huang argv++; 20352a856b9aSJohnny Huang 20362a856b9aSJohnny Huang if (cp == NULL || argc > cp->maxargs) 20372a856b9aSJohnny Huang return CMD_RET_USAGE; 20382a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 20392a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20402a856b9aSJohnny Huang 20410dae9d52SJohnny Huang ver = chip_version(); 20420dae9d52SJohnny Huang switch (ver) { 20430dae9d52SJohnny Huang case OTP_AST2600A0: 2044696656c6SJohnny Huang info_cb.version = OTP_AST2600A0; 20459a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 20469a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 20479a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 20489a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 20499a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 20509a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 20510dae9d52SJohnny Huang break; 20520dae9d52SJohnny Huang case OTP_AST2600A1: 2053696656c6SJohnny Huang info_cb.version = OTP_AST2600A1; 20543cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 20553cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 20563cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 20573cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 20589a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 20599a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 20600dae9d52SJohnny Huang break; 20610dae9d52SJohnny Huang case OTP_AST2600A2: 20625fdde29fSJohnny Huang info_cb.version = OTP_AST2600A2; 20635fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 20645fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 20655fdde29fSJohnny Huang info_cb.strap_info = a2_strap_info; 20665fdde29fSJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 20675fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 20685fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 20690dae9d52SJohnny Huang break; 20700dae9d52SJohnny Huang default: 20710dae9d52SJohnny Huang return CMD_RET_FAILURE; 20729a4fe690SJohnny Huang } 20739a4fe690SJohnny Huang 20742a856b9aSJohnny Huang return cp->cmd(cmdtp, flag, argc, argv); 207569d5fd8fSJohnny Huang } 207669d5fd8fSJohnny Huang 207769d5fd8fSJohnny Huang U_BOOT_CMD( 207869d5fd8fSJohnny Huang otp, 7, 0, do_ast_otp, 207969d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 2080f67375f7SJohnny Huang "version\n" 2081f67375f7SJohnny Huang "otp read conf|data <otp_dw_offset> <dw_count>\n" 20822a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 20832d4b0742SJohnny Huang "otp info strap [v]\n" 20842d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 2085de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2086ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2087ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2088ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 20892a856b9aSJohnny Huang "otp cmp <addr> <otp_dw_offset>\n" 209069d5fd8fSJohnny Huang ); 2091