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> 24*0cee9a95SJohnny Huang #include "otp_info.h" 2569d5fd8fSJohnny Huang 2669d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR; 2769d5fd8fSJohnny Huang 2869d5fd8fSJohnny Huang #define OTP_PASSWD 0x349fe38a 2969d5fd8fSJohnny Huang #define RETRY 3 307332532cSJohnny Huang #define OTP_REGION_STRAP BIT(0) 317332532cSJohnny Huang #define OTP_REGION_CONF BIT(1) 327332532cSJohnny Huang #define OTP_REGION_DATA BIT(2) 3369d5fd8fSJohnny Huang 342a856b9aSJohnny Huang #define OTP_USAGE -1 352a856b9aSJohnny Huang #define OTP_FAILURE -2 362a856b9aSJohnny Huang #define OTP_SUCCESS 0 372a856b9aSJohnny Huang 38a6af4a17SJohnny Huang #define OTP_PROG_SKIP 1 39a6af4a17SJohnny Huang 409a4fe690SJohnny Huang #define OTP_KEY_TYPE_RSA 1 419a4fe690SJohnny Huang #define OTP_KEY_TYPE_AES 2 429a4fe690SJohnny Huang #define OTP_KEY_TYPE_VAULT 3 439a4fe690SJohnny Huang #define OTP_KEY_TYPE_HMAC 4 449a4fe690SJohnny Huang 454c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 464c1c9b35SJohnny Huang #define PBWIDTH 60 474c1c9b35SJohnny Huang 483d3688adSJohnny Huang #define OTP_BASE 0x1e6f2000 493d3688adSJohnny Huang #define OTP_PROTECT_KEY OTP_BASE 503d3688adSJohnny Huang #define OTP_COMMAND OTP_BASE + 0x4 513d3688adSJohnny Huang #define OTP_TIMING OTP_BASE + 0x8 523d3688adSJohnny Huang #define OTP_ADDR OTP_BASE + 0x10 533d3688adSJohnny Huang #define OTP_STATUS OTP_BASE + 0x14 543d3688adSJohnny Huang #define OTP_COMPARE_1 OTP_BASE + 0x20 553d3688adSJohnny Huang #define OTP_COMPARE_2 OTP_BASE + 0x24 563d3688adSJohnny Huang #define OTP_COMPARE_3 OTP_BASE + 0x28 573d3688adSJohnny Huang #define OTP_COMPARE_4 OTP_BASE + 0x2c 583d3688adSJohnny Huang 59696656c6SJohnny Huang #define OTP_MAGIC "SOCOTP" 60696656c6SJohnny Huang #define CHECKSUM_LEN 32 61696656c6SJohnny Huang #define OTP_INC_DATA (1 << 31) 62696656c6SJohnny Huang #define OTP_INC_CONFIG (1 << 30) 63696656c6SJohnny Huang #define OTP_INC_STRAP (1 << 29) 64696656c6SJohnny Huang #define OTP_ECC_EN (1 << 28) 65696656c6SJohnny Huang #define OTP_REGION_SIZE(info) ((info >> 16) & 0xffff) 66696656c6SJohnny Huang #define OTP_REGION_OFFSET(info) (info & 0xffff) 67696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info) (info & 0xffff) 68696656c6SJohnny Huang 69696656c6SJohnny Huang #define OTP_AST2600A0 0 70696656c6SJohnny Huang #define OTP_AST2600A1 1 715fdde29fSJohnny Huang #define OTP_AST2600A2 7 // fpga 72696656c6SJohnny Huang 73696656c6SJohnny Huang struct otp_header { 74696656c6SJohnny Huang u8 otp_magic[8]; 75696656c6SJohnny Huang u8 otp_version[8]; 76696656c6SJohnny Huang u32 image_info; 77696656c6SJohnny Huang u32 data_info; 78696656c6SJohnny Huang u32 config_info; 79696656c6SJohnny Huang u32 strap_info; 80696656c6SJohnny Huang u32 checksum_offset; 81696656c6SJohnny Huang } __attribute__((packed)); 82696656c6SJohnny Huang 8366f2f8e5SJohnny Huang struct otpstrap_status { 8469d5fd8fSJohnny Huang int value; 8569d5fd8fSJohnny Huang int option_array[7]; 8669d5fd8fSJohnny Huang int remain_times; 8769d5fd8fSJohnny Huang int writeable_option; 885010032bSJohnny Huang int reg_protected; 8969d5fd8fSJohnny Huang int protected; 9069d5fd8fSJohnny Huang }; 9169d5fd8fSJohnny Huang 9266f2f8e5SJohnny Huang struct otpconf_parse { 9366f2f8e5SJohnny Huang int dw_offset; 9466f2f8e5SJohnny Huang int bit; 9566f2f8e5SJohnny Huang int length; 9666f2f8e5SJohnny Huang int value; 97696656c6SJohnny Huang int ignore; 9866f2f8e5SJohnny Huang char status[80]; 9966f2f8e5SJohnny Huang }; 10066f2f8e5SJohnny Huang 1019a4fe690SJohnny Huang struct otpkey_type { 1029a4fe690SJohnny Huang int value; 1039a4fe690SJohnny Huang int key_type; 1049a4fe690SJohnny Huang int need_id; 1059a4fe690SJohnny Huang char information[110]; 1069a4fe690SJohnny Huang }; 1079a4fe690SJohnny Huang 1089a4fe690SJohnny Huang struct otp_info_cb { 1099a4fe690SJohnny Huang int version; 11079e42a59SJoel Stanley const struct otpstrap_info *strap_info; 1119a4fe690SJohnny Huang int strap_info_len; 11279e42a59SJoel Stanley const struct otpconf_info *conf_info; 1139a4fe690SJohnny Huang int conf_info_len; 11479e42a59SJoel Stanley const struct otpkey_type *key_info; 1159a4fe690SJohnny Huang int key_info_len; 1165010032bSJohnny Huang 1179a4fe690SJohnny Huang }; 1189a4fe690SJohnny Huang 119696656c6SJohnny Huang struct otp_image_layout { 1205010032bSJohnny Huang int data_length; 1215010032bSJohnny Huang int conf_length; 1225010032bSJohnny Huang int strap_length; 123696656c6SJohnny Huang uint8_t *data; 124696656c6SJohnny Huang uint8_t *data_ignore; 125696656c6SJohnny Huang uint8_t *conf; 126696656c6SJohnny Huang uint8_t *conf_ignore; 127696656c6SJohnny Huang uint8_t *strap; 128696656c6SJohnny Huang uint8_t *strap_reg_pro; 129696656c6SJohnny Huang uint8_t *strap_pro; 130696656c6SJohnny Huang uint8_t *strap_ignore; 131696656c6SJohnny Huang }; 132696656c6SJohnny Huang 1339a4fe690SJohnny Huang static struct otp_info_cb info_cb; 1349a4fe690SJohnny Huang 13579e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = { 1369a4fe690SJohnny Huang {0, OTP_KEY_TYPE_AES, 0, "AES-256 as OEM platform key for image encryption/decryption"}, 1379a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1389a4fe690SJohnny Huang {4, OTP_KEY_TYPE_HMAC, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"}, 1399a4fe690SJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1409a4fe690SJohnny Huang {9, OTP_KEY_TYPE_RSA, 0, "RSA-public as SOC public key"}, 1419a4fe690SJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1429a4fe690SJohnny Huang {13, OTP_KEY_TYPE_RSA, 0, "RSA-private as SOC private key"}, 1439a4fe690SJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1449a4fe690SJohnny Huang }; 1459a4fe690SJohnny Huang 14679e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = { 1479a4fe690SJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1489a4fe690SJohnny 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"}, 1499a4fe690SJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1509a4fe690SJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1519a4fe690SJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1529a4fe690SJohnny Huang }; 1539a4fe690SJohnny Huang 1545fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = { 1555fdde29fSJohnny Huang {1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"}, 1565fdde29fSJohnny 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"}, 1575fdde29fSJohnny Huang {8, OTP_KEY_TYPE_RSA, 1, "RSA-public as OEM DSS public keys in Mode 2"}, 1585fdde29fSJohnny Huang {10, OTP_KEY_TYPE_RSA, 0, "RSA-public as AES key decryption key"}, 1595fdde29fSJohnny Huang {14, OTP_KEY_TYPE_RSA, 0, "RSA-private as AES key decryption key"}, 1605fdde29fSJohnny Huang }; 1615fdde29fSJohnny Huang 1629a4fe690SJohnny Huang static uint32_t chip_version(void) 1639a4fe690SJohnny Huang { 1649a4fe690SJohnny Huang uint32_t rev_id; 1659a4fe690SJohnny Huang 1665fdde29fSJohnny Huang rev_id = readl(0x1e6e2014); 1679a4fe690SJohnny Huang 168cfa54635SJohnny Huang if (((rev_id >> 24) & 0xf) != 0x5) 1695fdde29fSJohnny Huang return -1; 1705fdde29fSJohnny Huang 1715fdde29fSJohnny Huang return (rev_id >> 16) & 0xf; 1729a4fe690SJohnny Huang } 1739a4fe690SJohnny Huang 1743d3688adSJohnny Huang static void wait_complete(void) 1753d3688adSJohnny Huang { 1763d3688adSJohnny Huang int reg; 1773d3688adSJohnny Huang 1783d3688adSJohnny Huang do { 1793d3688adSJohnny Huang reg = readl(OTP_STATUS); 1803d3688adSJohnny Huang } while ((reg & 0x6) != 0x6); 1813d3688adSJohnny Huang } 1823d3688adSJohnny Huang 1832a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data) 18469d5fd8fSJohnny Huang { 1853d3688adSJohnny Huang writel(offset, OTP_ADDR); //Read address 1863d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 1873d3688adSJohnny Huang wait_complete(); 1883d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 1893d3688adSJohnny Huang data[1] = readl(OTP_COMPARE_2); 19069d5fd8fSJohnny Huang } 19169d5fd8fSJohnny Huang 1922a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data) 19369d5fd8fSJohnny Huang { 19469d5fd8fSJohnny Huang int config_offset; 19569d5fd8fSJohnny Huang 19669d5fd8fSJohnny Huang config_offset = 0x800; 19769d5fd8fSJohnny Huang config_offset |= (offset / 8) * 0x200; 19869d5fd8fSJohnny Huang config_offset |= (offset % 8) * 0x2; 19969d5fd8fSJohnny Huang 2003d3688adSJohnny Huang writel(config_offset, OTP_ADDR); //Read address 2013d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2023d3688adSJohnny Huang wait_complete(); 2033d3688adSJohnny Huang data[0] = readl(OTP_COMPARE_1); 20469d5fd8fSJohnny Huang } 20569d5fd8fSJohnny Huang 20669d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count) 20769d5fd8fSJohnny Huang { 20869d5fd8fSJohnny Huang int i; 20969d5fd8fSJohnny Huang uint32_t ret[1]; 21069d5fd8fSJohnny Huang 21169d5fd8fSJohnny Huang if (offset + dw_count > 32) 2122a856b9aSJohnny Huang return OTP_USAGE; 21369d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i ++) { 21469d5fd8fSJohnny Huang otp_read_config(i, ret); 215a6af4a17SJohnny Huang printf("OTPCFG%X: %08X\n", i, ret[0]); 21669d5fd8fSJohnny Huang } 21769d5fd8fSJohnny Huang printf("\n"); 2182a856b9aSJohnny Huang return OTP_SUCCESS; 21969d5fd8fSJohnny Huang } 22069d5fd8fSJohnny Huang 22169d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count) 22269d5fd8fSJohnny Huang { 22369d5fd8fSJohnny Huang int i; 22469d5fd8fSJohnny Huang uint32_t ret[2]; 22569d5fd8fSJohnny Huang 22669d5fd8fSJohnny Huang if (offset + dw_count > 2048 || offset % 4 != 0) 2272a856b9aSJohnny Huang return OTP_USAGE; 22869d5fd8fSJohnny Huang for (i = offset; i < offset + dw_count; i += 2) { 22969d5fd8fSJohnny Huang otp_read_data(i, ret); 23069d5fd8fSJohnny Huang if (i % 4 == 0) 23169d5fd8fSJohnny Huang printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]); 23269d5fd8fSJohnny Huang else 23369d5fd8fSJohnny Huang printf("%08X %08X\n", ret[0], ret[1]); 23469d5fd8fSJohnny Huang 23569d5fd8fSJohnny Huang } 23669d5fd8fSJohnny Huang printf("\n"); 2372a856b9aSJohnny Huang return OTP_SUCCESS; 23869d5fd8fSJohnny Huang } 23969d5fd8fSJohnny Huang 24069d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr) 24169d5fd8fSJohnny Huang { 24269d5fd8fSJohnny Huang uint32_t ret; 24369d5fd8fSJohnny Huang uint32_t *buf; 24469d5fd8fSJohnny Huang 24569d5fd8fSJohnny Huang buf = map_physmem(addr, 16, MAP_WRBACK); 24669d5fd8fSJohnny Huang printf("%08X\n", buf[0]); 24769d5fd8fSJohnny Huang printf("%08X\n", buf[1]); 24869d5fd8fSJohnny Huang printf("%08X\n", buf[2]); 24969d5fd8fSJohnny Huang printf("%08X\n", buf[3]); 2503d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Compare address 2513d3688adSJohnny Huang writel(buf[0], OTP_COMPARE_1); //Compare data 1 2523d3688adSJohnny Huang writel(buf[1], OTP_COMPARE_2); //Compare data 2 2533d3688adSJohnny Huang writel(buf[2], OTP_COMPARE_3); //Compare data 3 2543d3688adSJohnny Huang writel(buf[3], OTP_COMPARE_4); //Compare data 4 2553d3688adSJohnny Huang writel(0x23b1e363, OTP_COMMAND); //Compare command 2563d3688adSJohnny Huang wait_complete(); 2573d3688adSJohnny Huang ret = readl(OTP_STATUS); //Compare command 25869d5fd8fSJohnny Huang if (ret & 0x1) 25969d5fd8fSJohnny Huang return 0; 26069d5fd8fSJohnny Huang else 26169d5fd8fSJohnny Huang return -1; 26269d5fd8fSJohnny Huang } 26369d5fd8fSJohnny Huang 26469d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data) 26569d5fd8fSJohnny Huang { 2663d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //write address 2673d3688adSJohnny Huang writel(data, OTP_COMPARE_1); //write data 2683d3688adSJohnny Huang writel(0x23b1e362, OTP_COMMAND); //write command 2693d3688adSJohnny Huang wait_complete(); 27069d5fd8fSJohnny Huang } 27169d5fd8fSJohnny Huang 272a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value) 27369d5fd8fSJohnny Huang { 27430a8c590SJohnny Huang uint32_t ret[2]; 27569d5fd8fSJohnny Huang 27630a8c590SJohnny Huang if (otp_addr % 2 == 0) 2773d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 27830a8c590SJohnny Huang else 2793d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 28030a8c590SJohnny Huang 2813d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 2823d3688adSJohnny Huang wait_complete(); 2833d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 2843d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 28583655e91SJohnny Huang 28630a8c590SJohnny Huang if (otp_addr % 2 == 0) { 28730a8c590SJohnny Huang if (((ret[0] >> bit_offset) & 1) == value) 28869d5fd8fSJohnny Huang return 0; 28969d5fd8fSJohnny Huang else 29069d5fd8fSJohnny Huang return -1; 29130a8c590SJohnny Huang } else { 29230a8c590SJohnny Huang if (((ret[1] >> bit_offset) & 1) == value) 29330a8c590SJohnny Huang return 0; 29430a8c590SJohnny Huang else 29530a8c590SJohnny Huang return -1; 29630a8c590SJohnny Huang } 29730a8c590SJohnny Huang 29869d5fd8fSJohnny Huang } 29969d5fd8fSJohnny Huang 300696656c6SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *ignore, uint32_t *compare, int size) 3014c1c9b35SJohnny Huang { 3024c1c9b35SJohnny Huang uint32_t ret[2]; 3034c1c9b35SJohnny Huang 3044c1c9b35SJohnny Huang otp_addr &= ~(1 << 15); 3054c1c9b35SJohnny Huang 3064c1c9b35SJohnny Huang if (otp_addr % 2 == 0) 3073d3688adSJohnny Huang writel(otp_addr, OTP_ADDR); //Read address 3084c1c9b35SJohnny Huang else 3093d3688adSJohnny Huang writel(otp_addr - 1, OTP_ADDR); //Read address 3103d3688adSJohnny Huang writel(0x23b1e361, OTP_COMMAND); //trigger read 3113d3688adSJohnny Huang wait_complete(); 3123d3688adSJohnny Huang ret[0] = readl(OTP_COMPARE_1); 3133d3688adSJohnny Huang ret[1] = readl(OTP_COMPARE_2); 3144c1c9b35SJohnny Huang if (size == 1) { 3154c1c9b35SJohnny Huang if (otp_addr % 2 == 0) { 3164c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]); 317696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) { 3184c1c9b35SJohnny Huang compare[0] = 0; 3194c1c9b35SJohnny Huang return 0; 3204c1c9b35SJohnny Huang } else { 3214c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 3224c1c9b35SJohnny Huang return -1; 3234c1c9b35SJohnny Huang } 3244c1c9b35SJohnny Huang 3254c1c9b35SJohnny Huang } else { 3264c1c9b35SJohnny Huang // printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]); 327696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) { 3284c1c9b35SJohnny Huang compare[0] = ~0; 3294c1c9b35SJohnny Huang return 0; 3304c1c9b35SJohnny Huang } else { 331d90825e2SJohnny Huang compare[0] = ~(value[0] ^ ret[1]); 3324c1c9b35SJohnny Huang return -1; 3334c1c9b35SJohnny Huang } 3344c1c9b35SJohnny Huang } 3354c1c9b35SJohnny Huang } else if (size == 2) { 3364c1c9b35SJohnny Huang // otp_addr should be even 337696656c6SJohnny Huang if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) { 3384c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 3394c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 3404c1c9b35SJohnny Huang compare[0] = 0; 3414c1c9b35SJohnny Huang compare[1] = ~0; 3424c1c9b35SJohnny Huang return 0; 3434c1c9b35SJohnny Huang } else { 3444c1c9b35SJohnny Huang // printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]); 3454c1c9b35SJohnny Huang // printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]); 3464c1c9b35SJohnny Huang compare[0] = value[0] ^ ret[0]; 3474c1c9b35SJohnny Huang compare[1] = ~(value[1] ^ ret[1]); 3484c1c9b35SJohnny Huang return -1; 3494c1c9b35SJohnny Huang } 3504c1c9b35SJohnny Huang } else { 3514c1c9b35SJohnny Huang return -1; 3524c1c9b35SJohnny Huang } 3534c1c9b35SJohnny Huang } 3544c1c9b35SJohnny Huang 3557e22f42dSJohnny Huang static void otp_soak(int soak) 356d90825e2SJohnny Huang { 3579d734279SJohnny Huang if (info_cb.version == OTP_AST2600A2) { 3589d734279SJohnny Huang switch (soak) { 3599d734279SJohnny Huang case 0: //default 3609d734279SJohnny Huang otp_write(0x3000, 0x0210); // Write MRA 3619d734279SJohnny Huang otp_write(0x5000, 0x0); // Write MRB 3629d734279SJohnny Huang otp_write(0x1000, 0x0); // Write MR 3639d734279SJohnny Huang break; 3649d734279SJohnny Huang case 1: //normal program 3659d734279SJohnny Huang otp_write(0x3000, 0x1200); // Write MRA 3669d734279SJohnny Huang otp_write(0x5000, 0x100F); // Write MRB 3679d734279SJohnny Huang otp_write(0x1000, 0x1024); // Write MR 3689d734279SJohnny Huang writel(0x04190760, OTP_TIMING); 3699d734279SJohnny Huang break; 3709d734279SJohnny Huang case 2: //soak program 3719d734279SJohnny Huang otp_write(0x3000, 0x1220); // Write MRA 3729d734279SJohnny Huang otp_write(0x5000, 0x2004); // Write MRB 3739d734279SJohnny Huang otp_write(0x1000, 0x08a4); // Write MR 3749d734279SJohnny Huang writel(0x041930d4, OTP_TIMING); 3759d734279SJohnny Huang break; 3769d734279SJohnny Huang } 3779d734279SJohnny Huang } else { 378de6fbf1cSJohnny Huang switch (soak) { 379de6fbf1cSJohnny Huang case 0: //default 380de6fbf1cSJohnny Huang otp_write(0x3000, 0x0); // Write MRA 381de6fbf1cSJohnny Huang otp_write(0x5000, 0x0); // Write MRB 382de6fbf1cSJohnny Huang otp_write(0x1000, 0x0); // Write MR 383de6fbf1cSJohnny Huang break; 384de6fbf1cSJohnny Huang case 1: //normal program 385de6fbf1cSJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 386de6fbf1cSJohnny Huang otp_write(0x5000, 0x302f); // Write MRB 387de6fbf1cSJohnny Huang otp_write(0x1000, 0x4020); // Write MR 388de6fbf1cSJohnny Huang writel(0x04190760, OTP_TIMING); 389de6fbf1cSJohnny Huang break; 390de6fbf1cSJohnny Huang case 2: //soak program 391d90825e2SJohnny Huang otp_write(0x3000, 0x4021); // Write MRA 392d90825e2SJohnny Huang otp_write(0x5000, 0x1027); // Write MRB 393d90825e2SJohnny Huang otp_write(0x1000, 0x4820); // Write MR 394de6fbf1cSJohnny Huang writel(0x041930d4, OTP_TIMING); 395de6fbf1cSJohnny Huang break; 396d90825e2SJohnny Huang } 3979d734279SJohnny Huang } 398de6fbf1cSJohnny Huang 3993d3688adSJohnny Huang wait_complete(); 400d90825e2SJohnny Huang } 401d90825e2SJohnny Huang 40283655e91SJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit) 40383655e91SJohnny Huang { 40483655e91SJohnny Huang writel(otp_addr, OTP_ADDR); //write address 40583655e91SJohnny Huang writel(prog_bit, OTP_COMPARE_1); //write data 40683655e91SJohnny Huang writel(0x23b1e364, OTP_COMMAND); //write command 40783655e91SJohnny Huang wait_complete(); 40883655e91SJohnny Huang } 40983655e91SJohnny Huang 41083655e91SJohnny Huang static void _otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset) 41183655e91SJohnny Huang { 41283655e91SJohnny Huang int prog_bit; 41383655e91SJohnny Huang 41483655e91SJohnny Huang if (prog_address % 2 == 0) { 41583655e91SJohnny Huang if (value) 41683655e91SJohnny Huang prog_bit = ~(0x1 << bit_offset); 41783655e91SJohnny Huang else 41883655e91SJohnny Huang return; 41983655e91SJohnny Huang } else { 42083655e91SJohnny Huang prog_address |= 1 << 15; 42183655e91SJohnny Huang if (!value) 42283655e91SJohnny Huang prog_bit = 0x1 << bit_offset; 42383655e91SJohnny Huang else 42483655e91SJohnny Huang return; 42583655e91SJohnny Huang } 42683655e91SJohnny Huang otp_prog(prog_address, prog_bit); 42783655e91SJohnny Huang } 42883655e91SJohnny Huang 42983655e91SJohnny Huang static int otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset) 43083655e91SJohnny Huang { 43183655e91SJohnny Huang int pass; 43283655e91SJohnny Huang int i; 43383655e91SJohnny Huang 43483655e91SJohnny Huang otp_soak(1); 43583655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 43683655e91SJohnny Huang pass = 0; 43783655e91SJohnny Huang 43883655e91SJohnny Huang for (i = 0; i < RETRY; i++) { 43983655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 44083655e91SJohnny Huang otp_soak(2); 44183655e91SJohnny Huang _otp_prog_bit(value, prog_address, bit_offset); 44283655e91SJohnny Huang if (verify_bit(prog_address, bit_offset, value) != 0) { 44383655e91SJohnny Huang otp_soak(1); 44483655e91SJohnny Huang } else { 44583655e91SJohnny Huang pass = 1; 44683655e91SJohnny Huang break; 44783655e91SJohnny Huang } 44883655e91SJohnny Huang } else { 44983655e91SJohnny Huang pass = 1; 45083655e91SJohnny Huang break; 45183655e91SJohnny Huang } 45283655e91SJohnny Huang } 45383655e91SJohnny Huang 45483655e91SJohnny Huang return pass; 45583655e91SJohnny Huang } 45683655e91SJohnny Huang 457696656c6SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t ignore, uint32_t prog_address) 458d90825e2SJohnny Huang { 459d90825e2SJohnny Huang int j, bit_value, prog_bit; 460d90825e2SJohnny Huang 461d90825e2SJohnny Huang for (j = 0; j < 32; j++) { 462696656c6SJohnny Huang if ((ignore >> j) & 0x1) 463d90825e2SJohnny Huang continue; 464d90825e2SJohnny Huang bit_value = (value >> j) & 0x1; 465d90825e2SJohnny Huang if (prog_address % 2 == 0) { 466d90825e2SJohnny Huang if (bit_value) 467d90825e2SJohnny Huang prog_bit = ~(0x1 << j); 468d90825e2SJohnny Huang else 469d90825e2SJohnny Huang continue; 470d90825e2SJohnny Huang } else { 471d90825e2SJohnny Huang prog_address |= 1 << 15; 472d90825e2SJohnny Huang if (bit_value) 473d90825e2SJohnny Huang continue; 474d90825e2SJohnny Huang else 475d90825e2SJohnny Huang prog_bit = 0x1 << j; 476d90825e2SJohnny Huang } 477d90825e2SJohnny Huang otp_prog(prog_address, prog_bit); 478d90825e2SJohnny Huang } 479d90825e2SJohnny Huang } 480d90825e2SJohnny Huang 48154552c69SJohnny Huang static int otp_prog_verify_2dw(uint32_t *data, uint32_t *buf, uint32_t *ignore_mask, uint32_t prog_address) 48254552c69SJohnny Huang { 48354552c69SJohnny Huang int pass; 48454552c69SJohnny Huang int i; 48554552c69SJohnny Huang uint32_t data0_masked; 48654552c69SJohnny Huang uint32_t data1_masked; 48754552c69SJohnny Huang uint32_t buf0_masked; 48854552c69SJohnny Huang uint32_t buf1_masked; 48954552c69SJohnny Huang uint32_t compare[2]; 49054552c69SJohnny Huang 49154552c69SJohnny Huang data0_masked = data[0] & ~ignore_mask[0]; 49254552c69SJohnny Huang buf0_masked = buf[0] & ~ignore_mask[0]; 49354552c69SJohnny Huang data1_masked = data[1] & ~ignore_mask[1]; 49454552c69SJohnny Huang buf1_masked = buf[1] & ~ignore_mask[1]; 49554552c69SJohnny Huang if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked)) 49654552c69SJohnny Huang return 0; 49754552c69SJohnny Huang 49854552c69SJohnny Huang otp_soak(1); 49954552c69SJohnny Huang if (data0_masked != buf0_masked) 50054552c69SJohnny Huang otp_prog_dw(buf[0], ignore_mask[0], prog_address); 50154552c69SJohnny Huang if (data1_masked != buf1_masked) 50254552c69SJohnny Huang otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1); 50354552c69SJohnny Huang 50454552c69SJohnny Huang pass = 0; 50554552c69SJohnny Huang for (i = 0; i < RETRY; i++) { 50654552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 50754552c69SJohnny Huang otp_soak(2); 50854552c69SJohnny Huang if (compare[0] != 0) { 50954552c69SJohnny Huang otp_prog_dw(compare[0], ignore_mask[0], prog_address); 51054552c69SJohnny Huang } 51154552c69SJohnny Huang if (compare[1] != ~0) { 51254552c69SJohnny Huang otp_prog_dw(compare[1], ignore_mask[0], prog_address + 1); 51354552c69SJohnny Huang } 51454552c69SJohnny Huang if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) { 51554552c69SJohnny Huang otp_soak(1); 51654552c69SJohnny Huang } else { 51754552c69SJohnny Huang pass = 1; 51854552c69SJohnny Huang break; 51954552c69SJohnny Huang } 52054552c69SJohnny Huang } else { 52154552c69SJohnny Huang pass = 1; 52254552c69SJohnny Huang break; 52354552c69SJohnny Huang } 52454552c69SJohnny Huang } 52554552c69SJohnny Huang 52654552c69SJohnny Huang if (!pass) { 52754552c69SJohnny Huang otp_soak(0); 52854552c69SJohnny Huang return OTP_FAILURE; 52954552c69SJohnny Huang } 53054552c69SJohnny Huang return OTP_SUCCESS; 53154552c69SJohnny Huang } 53254552c69SJohnny Huang 533541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap) 53476d13988SJohnny Huang { 53576d13988SJohnny Huang uint32_t OTPSTRAP_RAW[2]; 5365010032bSJohnny Huang int strap_end; 53776d13988SJohnny Huang int i, j; 53876d13988SJohnny Huang 5395010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 54076d13988SJohnny Huang for (j = 0; j < 64; j++) { 54176d13988SJohnny Huang otpstrap[j].value = 0; 54276d13988SJohnny Huang otpstrap[j].remain_times = 7; 54376d13988SJohnny Huang otpstrap[j].writeable_option = -1; 54476d13988SJohnny Huang otpstrap[j].protected = 0; 54576d13988SJohnny Huang } 5465010032bSJohnny Huang strap_end = 30; 5475010032bSJohnny Huang } else { 5485010032bSJohnny Huang for (j = 0; j < 64; j++) { 5495010032bSJohnny Huang otpstrap[j].value = 0; 5505010032bSJohnny Huang otpstrap[j].remain_times = 6; 5515010032bSJohnny Huang otpstrap[j].writeable_option = -1; 5525010032bSJohnny Huang otpstrap[j].reg_protected = 0; 5535010032bSJohnny Huang otpstrap[j].protected = 0; 5545010032bSJohnny Huang } 5555010032bSJohnny Huang strap_end = 28; 5565010032bSJohnny Huang } 55776d13988SJohnny Huang 5585010032bSJohnny Huang for (i = 16; i < strap_end; i += 2) { 55976d13988SJohnny Huang int option = (i - 16) / 2; 56076d13988SJohnny Huang otp_read_config(i, &OTPSTRAP_RAW[0]); 56176d13988SJohnny Huang otp_read_config(i + 1, &OTPSTRAP_RAW[1]); 56276d13988SJohnny Huang for (j = 0; j < 32; j++) { 56376d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1); 56476d13988SJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 56576d13988SJohnny Huang otpstrap[j].writeable_option = option; 56676d13988SJohnny Huang } 56776d13988SJohnny Huang if (bit_value == 1) 56876d13988SJohnny Huang otpstrap[j].remain_times --; 56976d13988SJohnny Huang otpstrap[j].value ^= bit_value; 57076d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 57176d13988SJohnny Huang } 57276d13988SJohnny Huang for (j = 32; j < 64; j++) { 57376d13988SJohnny Huang char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1); 57476d13988SJohnny Huang if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) { 57576d13988SJohnny Huang otpstrap[j].writeable_option = option; 57676d13988SJohnny Huang } 57776d13988SJohnny Huang if (bit_value == 1) 57876d13988SJohnny Huang otpstrap[j].remain_times --; 57976d13988SJohnny Huang otpstrap[j].value ^= bit_value; 58076d13988SJohnny Huang otpstrap[j].option_array[option] = bit_value; 58176d13988SJohnny Huang } 58276d13988SJohnny Huang } 5835010032bSJohnny Huang 5845010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 5855010032bSJohnny Huang otp_read_config(28, &OTPSTRAP_RAW[0]); 5865010032bSJohnny Huang otp_read_config(29, &OTPSTRAP_RAW[1]); 5875010032bSJohnny Huang for (j = 0; j < 32; j++) { 5885010032bSJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 5895010032bSJohnny Huang otpstrap[j].reg_protected = 1; 5905010032bSJohnny Huang } 5915010032bSJohnny Huang for (j = 32; j < 64; j++) { 5925010032bSJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 5935010032bSJohnny Huang otpstrap[j].reg_protected = 1; 5945010032bSJohnny Huang } 5955010032bSJohnny Huang 5965010032bSJohnny Huang } 5975010032bSJohnny Huang 59876d13988SJohnny Huang otp_read_config(30, &OTPSTRAP_RAW[0]); 59976d13988SJohnny Huang otp_read_config(31, &OTPSTRAP_RAW[1]); 60076d13988SJohnny Huang for (j = 0; j < 32; j++) { 60176d13988SJohnny Huang if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1) 60276d13988SJohnny Huang otpstrap[j].protected = 1; 60376d13988SJohnny Huang } 60476d13988SJohnny Huang for (j = 32; j < 64; j++) { 60576d13988SJohnny Huang if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1) 60676d13988SJohnny Huang otpstrap[j].protected = 1; 60776d13988SJohnny Huang } 60876d13988SJohnny Huang } 60976d13988SJohnny Huang 610696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout) 61169d5fd8fSJohnny Huang { 61279e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 613696656c6SJohnny Huang uint32_t *OTPCFG = (uint32_t *)image_layout->conf; 614696656c6SJohnny Huang uint32_t *OTPCFG_IGNORE = (uint32_t *)image_layout->conf_ignore; 615b458cd62SJohnny Huang uint32_t mask; 616b458cd62SJohnny Huang uint32_t dw_offset; 617b458cd62SJohnny Huang uint32_t bit_offset; 618b458cd62SJohnny Huang uint32_t otp_value; 619696656c6SJohnny Huang uint32_t otp_ignore; 620b458cd62SJohnny Huang int fail = 0; 62173f11549SJohnny Huang char valid_bit[20]; 62266f2f8e5SJohnny Huang int i; 62373f11549SJohnny Huang int j; 62466f2f8e5SJohnny Huang 625737ed20bSJohnny Huang printf("DW BIT Value Description\n"); 62666f2f8e5SJohnny Huang printf("__________________________________________________________________________\n"); 6273cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 6283cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 6293cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 6303cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 631b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 632696656c6SJohnny Huang otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask; 633b458cd62SJohnny Huang 634696656c6SJohnny Huang if (otp_ignore == mask) { 635b458cd62SJohnny Huang continue; 636696656c6SJohnny Huang } else if (otp_ignore != 0) { 637b458cd62SJohnny Huang fail = 1; 638b458cd62SJohnny Huang } 639b458cd62SJohnny Huang 6403cb28812SJohnny Huang if ((otp_value != conf_info[i].value) && 6413cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 6423cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 6433cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 644b458cd62SJohnny Huang continue; 645b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 646b458cd62SJohnny Huang 6473cb28812SJohnny Huang if (conf_info[i].length == 1) { 6483cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 64966f2f8e5SJohnny Huang } else { 650b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 6513cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 6523cb28812SJohnny Huang conf_info[i].bit_offset); 65366f2f8e5SJohnny Huang } 654b458cd62SJohnny Huang printf("0x%-10x", otp_value); 655b458cd62SJohnny Huang 656b458cd62SJohnny Huang if (fail) { 657696656c6SJohnny Huang printf("Ignore mask error\n"); 658b458cd62SJohnny Huang } else { 6593cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 660b458cd62SJohnny Huang printf("Reserved\n"); 6613cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 6623cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 663b458cd62SJohnny Huang printf("\n"); 6643cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 665b458cd62SJohnny Huang if (otp_value != 0) { 66673f11549SJohnny Huang for (j = 0; j < 7; j++) { 66773f11549SJohnny Huang if (otp_value == (1 << j)) { 66873f11549SJohnny Huang valid_bit[j * 2] = '1'; 669b458cd62SJohnny Huang } else { 67073f11549SJohnny Huang valid_bit[j * 2] = '0'; 67173f11549SJohnny Huang } 67273f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 67373f11549SJohnny Huang } 67473f11549SJohnny Huang valid_bit[15] = 0; 67573f11549SJohnny Huang } else { 67673f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 677b458cd62SJohnny Huang } 6783cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 679b458cd62SJohnny Huang printf("\n"); 680b458cd62SJohnny Huang } else { 6813cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 682b458cd62SJohnny Huang } 683b458cd62SJohnny Huang } 684b458cd62SJohnny Huang } 685b458cd62SJohnny Huang 686b458cd62SJohnny Huang if (fail) 687b458cd62SJohnny Huang return OTP_FAILURE; 688b458cd62SJohnny Huang 68966f2f8e5SJohnny Huang return OTP_SUCCESS; 69066f2f8e5SJohnny Huang } 69166f2f8e5SJohnny Huang 6922d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset) 69366f2f8e5SJohnny Huang { 69479e42a59SJoel Stanley const struct otpconf_info *conf_info = info_cb.conf_info; 695bb34a7bfSJohnny Huang uint32_t OTPCFG[16]; 696b458cd62SJohnny Huang uint32_t mask; 697b458cd62SJohnny Huang uint32_t dw_offset; 698b458cd62SJohnny Huang uint32_t bit_offset; 699b458cd62SJohnny Huang uint32_t otp_value; 70073f11549SJohnny Huang char valid_bit[20]; 70166f2f8e5SJohnny Huang int i; 70273f11549SJohnny Huang int j; 70366f2f8e5SJohnny Huang 704bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) 70566f2f8e5SJohnny Huang otp_read_config(i, &OTPCFG[i]); 70666f2f8e5SJohnny Huang 70766f2f8e5SJohnny Huang 708b458cd62SJohnny Huang printf("DW BIT Value Description\n"); 709b458cd62SJohnny Huang printf("__________________________________________________________________________\n"); 7103cb28812SJohnny Huang for (i = 0; i < info_cb.conf_info_len; i++) { 7113cb28812SJohnny Huang if (input_offset != -1 && input_offset != conf_info[i].dw_offset) 7122d4b0742SJohnny Huang continue; 7133cb28812SJohnny Huang dw_offset = conf_info[i].dw_offset; 7143cb28812SJohnny Huang bit_offset = conf_info[i].bit_offset; 7153cb28812SJohnny Huang mask = BIT(conf_info[i].length) - 1; 716b458cd62SJohnny Huang otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask; 717b458cd62SJohnny Huang 7183cb28812SJohnny Huang if ((otp_value != conf_info[i].value) && 7193cb28812SJohnny Huang conf_info[i].value != OTP_REG_RESERVED && 7203cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALUE && 7213cb28812SJohnny Huang conf_info[i].value != OTP_REG_VALID_BIT) 722b458cd62SJohnny Huang continue; 723b458cd62SJohnny Huang printf("0x%-4X", dw_offset); 724b458cd62SJohnny Huang 7253cb28812SJohnny Huang if (conf_info[i].length == 1) { 7263cb28812SJohnny Huang printf("0x%-9X", conf_info[i].bit_offset); 727b458cd62SJohnny Huang } else { 728b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 7293cb28812SJohnny Huang conf_info[i].bit_offset + conf_info[i].length - 1, 7303cb28812SJohnny Huang conf_info[i].bit_offset); 731b458cd62SJohnny Huang } 732b458cd62SJohnny Huang printf("0x%-10x", otp_value); 733b458cd62SJohnny Huang 7343cb28812SJohnny Huang if (conf_info[i].value == OTP_REG_RESERVED) { 735b458cd62SJohnny Huang printf("Reserved\n"); 7363cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALUE) { 7373cb28812SJohnny Huang printf(conf_info[i].information, otp_value); 738b458cd62SJohnny Huang printf("\n"); 7393cb28812SJohnny Huang } else if (conf_info[i].value == OTP_REG_VALID_BIT) { 740b458cd62SJohnny Huang if (otp_value != 0) { 74173f11549SJohnny Huang for (j = 0; j < 7; j++) { 74273f11549SJohnny Huang if (otp_value == (1 << j)) { 74373f11549SJohnny Huang valid_bit[j * 2] = '1'; 744b458cd62SJohnny Huang } else { 74573f11549SJohnny Huang valid_bit[j * 2] = '0'; 74673f11549SJohnny Huang } 74773f11549SJohnny Huang valid_bit[j * 2 + 1] = ' '; 74873f11549SJohnny Huang } 74973f11549SJohnny Huang valid_bit[15] = 0; 75073f11549SJohnny Huang } else { 75173f11549SJohnny Huang strcpy(valid_bit, "0 0 0 0 0 0 0 0\0"); 752b458cd62SJohnny Huang } 7533cb28812SJohnny Huang printf(conf_info[i].information, valid_bit); 754b458cd62SJohnny Huang printf("\n"); 755b458cd62SJohnny Huang } else { 7563cb28812SJohnny Huang printf("%s\n", conf_info[i].information); 757b458cd62SJohnny Huang } 758b458cd62SJohnny Huang } 759b458cd62SJohnny Huang return OTP_SUCCESS; 76066f2f8e5SJohnny Huang } 76166f2f8e5SJohnny Huang 7625010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout) 76376d13988SJohnny Huang { 76479e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 765696656c6SJohnny Huang uint32_t *OTPSTRAP; 766696656c6SJohnny Huang uint32_t *OTPSTRAP_REG_PRO; 767696656c6SJohnny Huang uint32_t *OTPSTRAP_PRO; 768696656c6SJohnny Huang uint32_t *OTPSTRAP_IGNORE; 76976d13988SJohnny Huang int i; 770a8bd6d8cSJohnny Huang int fail = 0; 771a8bd6d8cSJohnny Huang uint32_t bit_offset; 772a8bd6d8cSJohnny Huang uint32_t dw_offset; 773a8bd6d8cSJohnny Huang uint32_t mask; 774a8bd6d8cSJohnny Huang uint32_t otp_value; 775696656c6SJohnny Huang uint32_t otp_reg_protect; 776a8bd6d8cSJohnny Huang uint32_t otp_protect; 777696656c6SJohnny Huang uint32_t otp_ignore; 77876d13988SJohnny Huang 779696656c6SJohnny Huang OTPSTRAP = (uint32_t *)image_layout->strap; 780696656c6SJohnny Huang OTPSTRAP_PRO = (uint32_t *)image_layout->strap_pro; 781696656c6SJohnny Huang OTPSTRAP_IGNORE = (uint32_t *)image_layout->strap_ignore; 7825010032bSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 783696656c6SJohnny Huang OTPSTRAP_REG_PRO = NULL; 784a8bd6d8cSJohnny Huang printf("BIT(hex) Value Protect Description\n"); 785696656c6SJohnny Huang } else { 786696656c6SJohnny Huang OTPSTRAP_REG_PRO = (uint32_t *)image_layout->strap_reg_pro; 787de6b0cc4SJohnny Huang printf("BIT(hex) Value Reg_Protect Protect Description\n"); 788696656c6SJohnny Huang } 789de6b0cc4SJohnny Huang printf("__________________________________________________________________________________________\n"); 790b458cd62SJohnny Huang 7913cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 792696656c6SJohnny Huang if (strap_info[i].bit_offset > 31) { 793a8bd6d8cSJohnny Huang dw_offset = 1; 7943cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset - 32; 795a8bd6d8cSJohnny Huang } else { 796a8bd6d8cSJohnny Huang dw_offset = 0; 7973cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 798a8bd6d8cSJohnny Huang } 79976d13988SJohnny Huang 8003cb28812SJohnny Huang mask = BIT(strap_info[i].length) - 1; 801a8bd6d8cSJohnny Huang otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask; 802a8bd6d8cSJohnny Huang otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask; 803696656c6SJohnny Huang otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask; 804a8bd6d8cSJohnny Huang 8055010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 806696656c6SJohnny Huang otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask; 8075010032bSJohnny Huang else 8085010032bSJohnny Huang otp_reg_protect = 0; 809696656c6SJohnny Huang 810696656c6SJohnny Huang if (otp_ignore == mask) { 811a8bd6d8cSJohnny Huang continue; 812696656c6SJohnny Huang } else if (otp_ignore != 0) { 813a8bd6d8cSJohnny Huang fail = 1; 814a8bd6d8cSJohnny Huang } 815a8bd6d8cSJohnny Huang 8163cb28812SJohnny Huang if ((otp_value != strap_info[i].value) && 8173cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 818a8bd6d8cSJohnny Huang continue; 819a8bd6d8cSJohnny Huang 8203cb28812SJohnny Huang if (strap_info[i].length == 1) { 8213cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 822a8bd6d8cSJohnny Huang } else { 823b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 8243cb28812SJohnny Huang strap_info[i].bit_offset + strap_info[i].length - 1, 8253cb28812SJohnny Huang strap_info[i].bit_offset); 826a8bd6d8cSJohnny Huang } 827a8bd6d8cSJohnny Huang printf("0x%-10x", otp_value); 8285010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) 829696656c6SJohnny Huang printf("0x%-10x", otp_reg_protect); 830a8bd6d8cSJohnny Huang printf("0x%-10x", otp_protect); 831a8bd6d8cSJohnny Huang 832a8bd6d8cSJohnny Huang if (fail) { 833696656c6SJohnny Huang printf("Ignore mask error\n"); 834a8bd6d8cSJohnny Huang } else { 8353cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 8363cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 837a8bd6d8cSJohnny Huang else 838a8bd6d8cSJohnny Huang printf("Reserved\n"); 839a8bd6d8cSJohnny Huang } 840a8bd6d8cSJohnny Huang } 841a8bd6d8cSJohnny Huang 842a8bd6d8cSJohnny Huang if (fail) 84376d13988SJohnny Huang return OTP_FAILURE; 84476d13988SJohnny Huang 84576d13988SJohnny Huang return OTP_SUCCESS; 84676d13988SJohnny Huang } 84776d13988SJohnny Huang 848b458cd62SJohnny Huang static int otp_print_strap_info(int view) 84976d13988SJohnny Huang { 85079e42a59SJoel Stanley const struct otpstrap_info *strap_info = info_cb.strap_info; 85176d13988SJohnny Huang struct otpstrap_status strap_status[64]; 85207baa4e8SJohnny Huang int i, j; 853b458cd62SJohnny Huang int fail = 0; 854b458cd62SJohnny Huang uint32_t bit_offset; 855b458cd62SJohnny Huang uint32_t length; 856b458cd62SJohnny Huang uint32_t otp_value; 857b458cd62SJohnny Huang uint32_t otp_protect; 85876d13988SJohnny Huang 859541eb887SJohnny Huang otp_strap_status(strap_status); 86076d13988SJohnny Huang 861b458cd62SJohnny Huang if (view) { 86283655e91SJohnny Huang if (info_cb.version == OTP_AST2600A0) 86307baa4e8SJohnny Huang printf("BIT(hex) Value Remains Protect Description\n"); 86483655e91SJohnny Huang else 86583655e91SJohnny Huang printf("BIT(hex) Value Remains Reg_Protect Protect Description\n"); 86607baa4e8SJohnny Huang printf("___________________________________________________________________________________________________\n"); 867b458cd62SJohnny Huang } else { 868b458cd62SJohnny Huang printf("BIT(hex) Value Description\n"); 869b458cd62SJohnny Huang printf("________________________________________________________________________________\n"); 87076d13988SJohnny Huang } 8713cb28812SJohnny Huang for (i = 0; i < info_cb.strap_info_len; i++) { 872b458cd62SJohnny Huang otp_value = 0; 8733cb28812SJohnny Huang bit_offset = strap_info[i].bit_offset; 8743cb28812SJohnny Huang length = strap_info[i].length; 875b458cd62SJohnny Huang for (j = 0; j < length; j++) { 876c947ef08SJohnny Huang otp_value |= strap_status[bit_offset + j].value << j; 877c947ef08SJohnny Huang otp_protect |= strap_status[bit_offset + j].protected << j; 878b458cd62SJohnny Huang } 8793cb28812SJohnny Huang if ((otp_value != strap_info[i].value) && 8803cb28812SJohnny Huang strap_info[i].value != OTP_REG_RESERVED) 881b458cd62SJohnny Huang continue; 882b458cd62SJohnny Huang if (view) { 883b458cd62SJohnny Huang for (j = 0; j < length; j++) { 8843cb28812SJohnny Huang printf("0x%-7X", strap_info[i].bit_offset + j); 885b458cd62SJohnny Huang printf("0x%-5X", strap_status[bit_offset + j].value); 88607baa4e8SJohnny Huang printf("%-9d", strap_status[bit_offset + j].remain_times); 88783655e91SJohnny Huang if (info_cb.version != OTP_AST2600A0) 888e1a7245eSJohnny Huang printf("0x%-10X", strap_status[bit_offset + j].reg_protected); 889e1a7245eSJohnny Huang printf("0x%-7X", strap_status[bit_offset + j].protected); 8903cb28812SJohnny Huang if (strap_info[i].value == OTP_REG_RESERVED) { 891b458cd62SJohnny Huang printf(" Reserved\n"); 892b458cd62SJohnny Huang continue; 893b458cd62SJohnny Huang } 894b458cd62SJohnny Huang if (length == 1) { 8953cb28812SJohnny Huang printf(" %s\n", strap_info[i].information); 896b458cd62SJohnny Huang continue; 89776d13988SJohnny Huang } 89876d13988SJohnny Huang 899b458cd62SJohnny Huang if (j == 0) 9003cb28812SJohnny Huang printf("/%s\n", strap_info[i].information); 901b458cd62SJohnny Huang else if (j == length - 1) 902b458cd62SJohnny Huang printf("\\ \"\n"); 903b458cd62SJohnny Huang else 904b458cd62SJohnny Huang printf("| \"\n"); 90576d13988SJohnny Huang } 906b458cd62SJohnny Huang } else { 907c947ef08SJohnny Huang if (length == 1) { 9083cb28812SJohnny Huang printf("0x%-9X", strap_info[i].bit_offset); 909b458cd62SJohnny Huang } else { 910b458cd62SJohnny Huang printf("0x%-2X:0x%-4X", 911b458cd62SJohnny Huang bit_offset + length - 1, bit_offset); 912b458cd62SJohnny Huang } 913b458cd62SJohnny Huang 914b458cd62SJohnny Huang printf("0x%-10X", otp_value); 915b458cd62SJohnny Huang 9163cb28812SJohnny Huang if (strap_info[i].value != OTP_REG_RESERVED) 9173cb28812SJohnny Huang printf("%s\n", strap_info[i].information); 918b458cd62SJohnny Huang else 919b458cd62SJohnny Huang printf("Reserved\n"); 920b458cd62SJohnny Huang } 921b458cd62SJohnny Huang } 922b458cd62SJohnny Huang 923b458cd62SJohnny Huang if (fail) 924b458cd62SJohnny Huang return OTP_FAILURE; 925b458cd62SJohnny Huang 926b458cd62SJohnny Huang return OTP_SUCCESS; 927b458cd62SJohnny Huang } 928b458cd62SJohnny Huang 929696656c6SJohnny Huang static void buf_print(uint8_t *buf, int len) 93069d5fd8fSJohnny Huang { 93169d5fd8fSJohnny Huang int i; 93269d5fd8fSJohnny Huang printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); 93369d5fd8fSJohnny Huang for (i = 0; i < len; i++) { 93469d5fd8fSJohnny Huang if (i % 16 == 0) { 93569d5fd8fSJohnny Huang printf("%04X: ", i); 93669d5fd8fSJohnny Huang } 93769d5fd8fSJohnny Huang printf("%02X ", buf[i]); 93869d5fd8fSJohnny Huang if ((i + 1) % 16 == 0) { 93969d5fd8fSJohnny Huang printf("\n"); 94069d5fd8fSJohnny Huang } 94169d5fd8fSJohnny Huang } 94269d5fd8fSJohnny Huang } 94369d5fd8fSJohnny Huang 944696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout) 94569d5fd8fSJohnny Huang { 94669d5fd8fSJohnny Huang int key_id, key_offset, last, key_type, key_length, exp_length; 94779e42a59SJoel Stanley const struct otpkey_type *key_info_array = info_cb.key_info; 9489a4fe690SJohnny Huang struct otpkey_type key_info; 949696656c6SJohnny Huang uint32_t *buf; 950696656c6SJohnny Huang uint8_t *byte_buf; 9519d998018SJohnny Huang char empty = 1; 95269d5fd8fSJohnny Huang int i = 0, len = 0; 9539a4fe690SJohnny Huang int j; 95454552c69SJohnny Huang 955696656c6SJohnny Huang byte_buf = image_layout->data; 956696656c6SJohnny Huang buf = (uint32_t *)byte_buf; 9579d998018SJohnny Huang 9589d998018SJohnny Huang for (i = 0; i < 16; i++) { 9599d998018SJohnny Huang if (buf[i] != 0) { 9609d998018SJohnny Huang empty = 0; 9619d998018SJohnny Huang } 9629d998018SJohnny Huang } 9639d998018SJohnny Huang if (empty) 9649d998018SJohnny Huang return 0; 9659d998018SJohnny Huang 9669d998018SJohnny Huang i = 0; 96769d5fd8fSJohnny Huang while (1) { 96869d5fd8fSJohnny Huang key_id = buf[i] & 0x7; 96969d5fd8fSJohnny Huang key_offset = buf[i] & 0x1ff8; 97069d5fd8fSJohnny Huang last = (buf[i] >> 13) & 1; 97169d5fd8fSJohnny Huang key_type = (buf[i] >> 14) & 0xf; 97269d5fd8fSJohnny Huang key_length = (buf[i] >> 18) & 0x3; 97369d5fd8fSJohnny Huang exp_length = (buf[i] >> 20) & 0xfff; 9749a4fe690SJohnny Huang 9759a4fe690SJohnny Huang for (j = 0; j < info_cb.key_info_len; j++) { 9769a4fe690SJohnny Huang if (key_type == key_info_array[j].value) { 9779a4fe690SJohnny Huang key_info = key_info_array[j]; 9789a4fe690SJohnny Huang break; 9799a4fe690SJohnny Huang } 9809a4fe690SJohnny Huang } 9819a4fe690SJohnny Huang 9827f795e57SJohnny Huang printf("\nKey[%d]:\n", i); 98369d5fd8fSJohnny Huang printf("Key Type: "); 9849a4fe690SJohnny Huang printf("%s\n", key_info.information); 9859a4fe690SJohnny Huang 9869a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 98769d5fd8fSJohnny Huang printf("HMAC SHA Type: "); 98869d5fd8fSJohnny Huang switch (key_length) { 98969d5fd8fSJohnny Huang case 0: 99069d5fd8fSJohnny Huang printf("HMAC(SHA224)\n"); 99169d5fd8fSJohnny Huang break; 99269d5fd8fSJohnny Huang case 1: 99369d5fd8fSJohnny Huang printf("HMAC(SHA256)\n"); 99469d5fd8fSJohnny Huang break; 99569d5fd8fSJohnny Huang case 2: 99669d5fd8fSJohnny Huang printf("HMAC(SHA384)\n"); 99769d5fd8fSJohnny Huang break; 99869d5fd8fSJohnny Huang case 3: 99969d5fd8fSJohnny Huang printf("HMAC(SHA512)\n"); 100069d5fd8fSJohnny Huang break; 100169d5fd8fSJohnny Huang } 10029a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA) { 100369d5fd8fSJohnny Huang printf("RSA SHA Type: "); 100469d5fd8fSJohnny Huang switch (key_length) { 100569d5fd8fSJohnny Huang case 0: 100669d5fd8fSJohnny Huang printf("RSA1024\n"); 100769d5fd8fSJohnny Huang len = 0x100; 100869d5fd8fSJohnny Huang break; 100969d5fd8fSJohnny Huang case 1: 101069d5fd8fSJohnny Huang printf("RSA2048\n"); 101169d5fd8fSJohnny Huang len = 0x200; 101269d5fd8fSJohnny Huang break; 101369d5fd8fSJohnny Huang case 2: 101469d5fd8fSJohnny Huang printf("RSA3072\n"); 101569d5fd8fSJohnny Huang len = 0x300; 101669d5fd8fSJohnny Huang break; 101769d5fd8fSJohnny Huang case 3: 101869d5fd8fSJohnny Huang printf("RSA4096\n"); 101969d5fd8fSJohnny Huang len = 0x400; 102069d5fd8fSJohnny Huang break; 102169d5fd8fSJohnny Huang } 102269d5fd8fSJohnny Huang printf("RSA exponent bit length: %d\n", exp_length); 102369d5fd8fSJohnny Huang } 10249a4fe690SJohnny Huang if (key_info.need_id) 102569d5fd8fSJohnny Huang printf("Key Number ID: %d\n", key_id); 102669d5fd8fSJohnny Huang printf("Key Value:\n"); 10279a4fe690SJohnny Huang if (key_info.key_type == OTP_KEY_TYPE_HMAC) { 102869d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x40); 10299a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_AES) { 10309a4fe690SJohnny Huang printf("AES Key:\n"); 10319a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10325fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 10339a4fe690SJohnny Huang printf("AES IV:\n"); 10349a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10359a4fe690SJohnny Huang } 10369a4fe690SJohnny Huang 10379a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_VAULT) { 10385fdde29fSJohnny Huang if (info_cb.version == OTP_AST2600A0) { 103969d5fd8fSJohnny Huang printf("AES Key:\n"); 104069d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 104169d5fd8fSJohnny Huang printf("AES IV:\n"); 104269d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x10); 10435fdde29fSJohnny Huang } else { 10449a4fe690SJohnny Huang printf("AES Key 1:\n"); 10459a4fe690SJohnny Huang buf_print(&byte_buf[key_offset], 0x20); 10469a4fe690SJohnny Huang printf("AES Key 2:\n"); 10479a4fe690SJohnny Huang buf_print(&byte_buf[key_offset + 0x20], 0x20); 10489a4fe690SJohnny Huang } 104969d5fd8fSJohnny Huang 10509a4fe690SJohnny Huang } else if (key_info.key_type == OTP_KEY_TYPE_RSA) { 105169d5fd8fSJohnny Huang printf("RSA mod:\n"); 105269d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset], len / 2); 105369d5fd8fSJohnny Huang printf("RSA exp:\n"); 105469d5fd8fSJohnny Huang buf_print(&byte_buf[key_offset + (len / 2)], len / 2); 105569d5fd8fSJohnny Huang } 105669d5fd8fSJohnny Huang if (last) 105769d5fd8fSJohnny Huang break; 105869d5fd8fSJohnny Huang i++; 105969d5fd8fSJohnny Huang } 106069d5fd8fSJohnny Huang return 0; 106169d5fd8fSJohnny Huang } 106269d5fd8fSJohnny Huang 10635010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout) 106469d5fd8fSJohnny Huang { 1065a6d0d645SJohnny Huang int i, k; 1066d90825e2SJohnny Huang int pass = 0; 1067a6d0d645SJohnny Huang uint32_t prog_address; 1068bb34a7bfSJohnny Huang uint32_t data[16]; 1069a6d0d645SJohnny Huang uint32_t compare[2]; 10705010032bSJohnny Huang uint32_t *conf = (uint32_t *)image_layout->conf; 10715010032bSJohnny Huang uint32_t *conf_ignore = (uint32_t *)image_layout->conf_ignore; 1072d90825e2SJohnny Huang uint32_t data_masked; 1073d90825e2SJohnny Huang uint32_t buf_masked; 107469d5fd8fSJohnny Huang 1075a6d0d645SJohnny Huang printf("Read OTP Config Region:\n"); 1076a6d0d645SJohnny Huang 1077bb34a7bfSJohnny Huang for (i = 0; i < 16 ; i ++) { 107869d5fd8fSJohnny Huang prog_address = 0x800; 1079a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1080a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1081a6d0d645SJohnny Huang otp_read_data(prog_address, &data[i]); 1082a6d0d645SJohnny Huang } 1083a6d0d645SJohnny Huang 1084a6d0d645SJohnny Huang printf("Check writable...\n"); 1085bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 10865010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 10875010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1088d90825e2SJohnny Huang if (data_masked == buf_masked) 108969d5fd8fSJohnny Huang continue; 1090d90825e2SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 1091a6d0d645SJohnny Huang continue; 1092a6d0d645SJohnny Huang } else { 1093a6d0d645SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1094a6af4a17SJohnny Huang printf("OTPCFG[%X] = %x\n", i, data[i]); 10955010032bSJohnny Huang printf("Input [%X] = %x\n", i, conf[i]); 10965010032bSJohnny Huang printf("Mask [%X] = %x\n", i, ~conf_ignore[i]); 10972a856b9aSJohnny Huang return OTP_FAILURE; 1098a6d0d645SJohnny Huang } 1099a6d0d645SJohnny Huang } 1100a6d0d645SJohnny Huang 1101a6d0d645SJohnny Huang printf("Start Programing...\n"); 1102d90825e2SJohnny Huang otp_soak(0); 1103bb34a7bfSJohnny Huang for (i = 0; i < 16; i++) { 11045010032bSJohnny Huang data_masked = data[i] & ~conf_ignore[i]; 11055010032bSJohnny Huang buf_masked = conf[i] & ~conf_ignore[i]; 1106a6d0d645SJohnny Huang prog_address = 0x800; 1107a6d0d645SJohnny Huang prog_address |= (i / 8) * 0x200; 1108a6d0d645SJohnny Huang prog_address |= (i % 8) * 0x2; 1109bb34a7bfSJohnny Huang if (data_masked == buf_masked) { 1110bb34a7bfSJohnny Huang pass = 1; 1111a6d0d645SJohnny Huang continue; 1112bb34a7bfSJohnny Huang } 1113de6fbf1cSJohnny Huang 1114a6d0d645SJohnny Huang 1115de6fbf1cSJohnny Huang otp_soak(1); 11165010032bSJohnny Huang otp_prog_dw(conf[i], conf_ignore[i], prog_address); 1117a6d0d645SJohnny Huang 111869d5fd8fSJohnny Huang pass = 0; 111969d5fd8fSJohnny Huang for (k = 0; k < RETRY; k++) { 11205010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1121de6fbf1cSJohnny Huang otp_soak(2); 1122a6d0d645SJohnny Huang otp_prog_dw(compare[0], prog_address, 1); 11235010032bSJohnny Huang if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) { 1124de6fbf1cSJohnny Huang otp_soak(1); 1125de6fbf1cSJohnny Huang } else { 1126de6fbf1cSJohnny Huang pass = 1; 1127de6fbf1cSJohnny Huang break; 1128de6fbf1cSJohnny Huang } 1129a6d0d645SJohnny Huang } else { 113069d5fd8fSJohnny Huang pass = 1; 113169d5fd8fSJohnny Huang break; 113269d5fd8fSJohnny Huang } 113369d5fd8fSJohnny Huang } 1134bb34a7bfSJohnny Huang if (pass == 0) { 1135bb34a7bfSJohnny Huang printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n", 11365010032bSJohnny Huang i, data[i], conf[i], conf_ignore[i]); 1137bb34a7bfSJohnny Huang break; 1138bb34a7bfSJohnny Huang } 1139a6d0d645SJohnny Huang } 1140a6d0d645SJohnny Huang 1141de6fbf1cSJohnny Huang otp_soak(0); 114269d5fd8fSJohnny Huang if (!pass) 11432a856b9aSJohnny Huang return OTP_FAILURE; 1144a6d0d645SJohnny Huang 11452a856b9aSJohnny Huang return OTP_SUCCESS; 1146d90825e2SJohnny Huang 114769d5fd8fSJohnny Huang } 114869d5fd8fSJohnny Huang 1149eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit) 1150eda10d61SJohnny Huang { 1151eda10d61SJohnny Huang if (ibit == 1) { 1152eda10d61SJohnny Huang return OTP_SUCCESS; 1153eda10d61SJohnny Huang } else { 1154eda10d61SJohnny Huang printf("OTPSTRAP[%X]:\n", offset); 1155eda10d61SJohnny Huang } 1156eda10d61SJohnny Huang if (bit == otpstrap->value) { 1157eda10d61SJohnny Huang printf(" The value is same as before, skip it.\n"); 1158eda10d61SJohnny Huang return OTP_PROG_SKIP; 1159eda10d61SJohnny Huang } 1160eda10d61SJohnny Huang if (otpstrap->protected == 1) { 1161eda10d61SJohnny Huang printf(" This bit is protected and is not writable\n"); 1162eda10d61SJohnny Huang return OTP_FAILURE; 1163eda10d61SJohnny Huang } 1164eda10d61SJohnny Huang if (otpstrap->remain_times == 0) { 1165eda10d61SJohnny Huang printf(" This bit is no remaining times to write.\n"); 1166eda10d61SJohnny Huang return OTP_FAILURE; 1167eda10d61SJohnny Huang } 1168eda10d61SJohnny Huang if (pbit == 1) { 1169eda10d61SJohnny Huang printf(" This bit will be protected and become non-writable.\n"); 1170eda10d61SJohnny Huang } 1171eda10d61SJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 1172eda10d61SJohnny Huang printf(" The relative register will be protected.\n"); 1173eda10d61SJohnny Huang } 1174eda10d61SJohnny 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); 1175eda10d61SJohnny Huang return OTP_SUCCESS; 1176eda10d61SJohnny Huang } 1177eda10d61SJohnny Huang 11785010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout) 117969d5fd8fSJohnny Huang { 118069d5fd8fSJohnny Huang int i; 11815010032bSJohnny Huang uint32_t *strap; 11825010032bSJohnny Huang uint32_t *strap_ignore; 11835010032bSJohnny Huang uint32_t *strap_reg_protect; 11845010032bSJohnny Huang uint32_t *strap_pro; 1185eda10d61SJohnny Huang int bit, pbit, ibit, rpbit; 118669d5fd8fSJohnny Huang int fail = 0; 1187a6af4a17SJohnny Huang int skip = -1; 1188eda10d61SJohnny Huang int ret; 118966f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 119069d5fd8fSJohnny Huang 11915010032bSJohnny Huang strap = (uint32_t *)image_layout->strap; 11925010032bSJohnny Huang strap_pro = (uint32_t *)image_layout->strap_pro; 11935010032bSJohnny Huang strap_ignore = (uint32_t *)image_layout->strap_ignore; 11945010032bSJohnny Huang strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro; 11955010032bSJohnny Huang 1196541eb887SJohnny Huang otp_strap_status(otpstrap); 119769d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 119869d5fd8fSJohnny Huang if (i < 32) { 11995010032bSJohnny Huang bit = (strap[0] >> i) & 0x1; 1200eda10d61SJohnny Huang ibit = (strap_ignore[0] >> i) & 0x1; 12015010032bSJohnny Huang pbit = (strap_pro[0] >> i) & 0x1; 120269d5fd8fSJohnny Huang } else { 12035010032bSJohnny Huang bit = (strap[1] >> (i - 32)) & 0x1; 1204eda10d61SJohnny Huang ibit = (strap_ignore[1] >> (i - 32)) & 0x1; 12055010032bSJohnny Huang pbit = (strap_pro[1] >> (i - 32)) & 0x1; 12065010032bSJohnny Huang } 12075010032bSJohnny Huang 12085010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 12095010032bSJohnny Huang if (i < 32) { 12105010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 12115010032bSJohnny Huang } else { 12125010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 12135010032bSJohnny Huang } 12145010032bSJohnny Huang } else { 12155010032bSJohnny Huang rpbit = 0; 121669d5fd8fSJohnny Huang } 1217eda10d61SJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit); 1218eda10d61SJohnny Huang if (ret == OTP_PROG_SKIP) { 1219a6af4a17SJohnny Huang if (skip == -1) 1220a6af4a17SJohnny Huang skip = 1; 122169d5fd8fSJohnny Huang continue; 1222a6af4a17SJohnny Huang } else { 1223eda10d61SJohnny Huang skip = 1; 122469d5fd8fSJohnny Huang } 1225eda10d61SJohnny Huang 1226eda10d61SJohnny Huang if (ret == OTP_FAILURE) 122769d5fd8fSJohnny Huang fail = 1; 122869d5fd8fSJohnny Huang } 122969d5fd8fSJohnny Huang if (fail == 1) 1230a6af4a17SJohnny Huang return OTP_FAILURE; 1231a6af4a17SJohnny Huang else if (skip == 1) 1232a6af4a17SJohnny Huang return OTP_PROG_SKIP; 12337e22f42dSJohnny Huang 1234eda10d61SJohnny Huang return OTP_SUCCESS; 123569d5fd8fSJohnny Huang } 123669d5fd8fSJohnny Huang 12372a856b9aSJohnny Huang static int otp_print_strap(int start, int count) 123869d5fd8fSJohnny Huang { 123969d5fd8fSJohnny Huang int i, j; 1240de6b0cc4SJohnny Huang int remains; 124166f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 124269d5fd8fSJohnny Huang 12432a856b9aSJohnny Huang if (start < 0 || start > 64) 12442a856b9aSJohnny Huang return OTP_USAGE; 12452a856b9aSJohnny Huang 12462a856b9aSJohnny Huang if ((start + count) < 0 || (start + count) > 64) 12472a856b9aSJohnny Huang return OTP_USAGE; 12482a856b9aSJohnny Huang 1249541eb887SJohnny Huang otp_strap_status(otpstrap); 125069d5fd8fSJohnny Huang 1251de6b0cc4SJohnny Huang if (info_cb.version == OTP_AST2600A0) { 1252de6b0cc4SJohnny Huang remains = 7; 125307baa4e8SJohnny Huang printf("BIT(hex) Value Option Status\n"); 1254de6b0cc4SJohnny Huang } else { 1255de6b0cc4SJohnny Huang remains = 6; 1256de6b0cc4SJohnny Huang printf("BIT(hex) Value Option Reg_Protect Status\n"); 1257de6b0cc4SJohnny Huang } 1258de6b0cc4SJohnny Huang printf("______________________________________________________________________________\n"); 1259737ed20bSJohnny Huang 1260cd1610b4SJohnny Huang for (i = start; i < start + count; i++) { 126107baa4e8SJohnny Huang printf("0x%-8X", i); 1262737ed20bSJohnny Huang printf("%-7d", otpstrap[i].value); 1263de6b0cc4SJohnny Huang for (j = 0; j < remains; j++) 1264737ed20bSJohnny Huang printf("%d ", otpstrap[i].option_array[j]); 1265737ed20bSJohnny Huang printf(" "); 1266de6b0cc4SJohnny Huang if (info_cb.version != OTP_AST2600A0) { 1267de6b0cc4SJohnny Huang printf("%d ", otpstrap[i].reg_protected); 1268de6b0cc4SJohnny Huang } 126969d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 1270737ed20bSJohnny Huang printf("protected and not writable"); 127169d5fd8fSJohnny Huang } else { 1272737ed20bSJohnny Huang printf("not protected "); 127369d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 1274737ed20bSJohnny Huang printf("and no remaining times to write."); 127569d5fd8fSJohnny Huang } else { 1276737ed20bSJohnny Huang printf("and still can write %d times", otpstrap[i].remain_times); 127769d5fd8fSJohnny Huang } 127869d5fd8fSJohnny Huang } 1279737ed20bSJohnny Huang printf("\n"); 128069d5fd8fSJohnny Huang } 12812a856b9aSJohnny Huang 12822a856b9aSJohnny Huang return OTP_SUCCESS; 128369d5fd8fSJohnny Huang } 128469d5fd8fSJohnny Huang 12858848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value) 12868848d5dcSJohnny Huang { 12878848d5dcSJohnny Huang struct otpstrap_status otpstrap[64]; 128883655e91SJohnny Huang uint32_t prog_address; 12898848d5dcSJohnny Huang int offset; 12908848d5dcSJohnny Huang int ret; 12918848d5dcSJohnny Huang 12928848d5dcSJohnny Huang 12938848d5dcSJohnny Huang otp_strap_status(otpstrap); 12948848d5dcSJohnny Huang 12958848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 12968848d5dcSJohnny Huang 12978848d5dcSJohnny Huang if (ret != OTP_SUCCESS) { 12988848d5dcSJohnny Huang return ret; 12998848d5dcSJohnny Huang } 13008848d5dcSJohnny Huang 13018848d5dcSJohnny Huang prog_address = 0x800; 13028848d5dcSJohnny Huang if (bit_offset < 32) { 13038848d5dcSJohnny Huang offset = bit_offset; 13048848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200; 13058848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2; 13068848d5dcSJohnny Huang 13078848d5dcSJohnny Huang } else { 13088848d5dcSJohnny Huang offset = (bit_offset - 32); 13098848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200; 13108848d5dcSJohnny Huang prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2; 13118848d5dcSJohnny Huang } 13128848d5dcSJohnny Huang 13138848d5dcSJohnny Huang 131483655e91SJohnny Huang return otp_prog_bit(1, prog_address, offset); 13158848d5dcSJohnny Huang } 13168848d5dcSJohnny Huang 13175010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout) 131869d5fd8fSJohnny Huang { 13195010032bSJohnny Huang uint32_t *strap; 13205010032bSJohnny Huang uint32_t *strap_ignore; 13215010032bSJohnny Huang uint32_t *strap_pro; 13225010032bSJohnny Huang uint32_t *strap_reg_protect; 132383655e91SJohnny Huang uint32_t prog_address; 132483655e91SJohnny Huang int i; 1325eda10d61SJohnny Huang int bit, pbit, ibit, offset, rpbit; 132669d5fd8fSJohnny Huang int fail = 0; 132783655e91SJohnny Huang int ret; 132866f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 132969d5fd8fSJohnny Huang 13305010032bSJohnny Huang strap = (uint32_t *)image_layout->strap; 13315010032bSJohnny Huang strap_pro = (uint32_t *)image_layout->strap_pro; 13325010032bSJohnny Huang strap_ignore = (uint32_t *)image_layout->strap_ignore; 13335010032bSJohnny Huang strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro; 13345010032bSJohnny Huang 13357f795e57SJohnny Huang printf("Read OTP Strap Region:\n"); 1336541eb887SJohnny Huang otp_strap_status(otpstrap); 133769d5fd8fSJohnny Huang 13387f795e57SJohnny Huang printf("Check writable...\n"); 13395010032bSJohnny Huang if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) { 13407f795e57SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 13417f795e57SJohnny Huang return OTP_FAILURE; 13427f795e57SJohnny Huang } 13437e22f42dSJohnny Huang 134469d5fd8fSJohnny Huang for (i = 0; i < 64; i++) { 134569d5fd8fSJohnny Huang prog_address = 0x800; 134669d5fd8fSJohnny Huang if (i < 32) { 134769d5fd8fSJohnny Huang offset = i; 13485010032bSJohnny Huang bit = (strap[0] >> offset) & 0x1; 1349eda10d61SJohnny Huang ibit = (strap_ignore[0] >> offset) & 0x1; 13505010032bSJohnny Huang pbit = (strap_pro[0] >> offset) & 0x1; 135169d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200; 135269d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2; 135369d5fd8fSJohnny Huang 135469d5fd8fSJohnny Huang } else { 135569d5fd8fSJohnny Huang offset = (i - 32); 13565010032bSJohnny Huang bit = (strap[1] >> offset) & 0x1; 1357eda10d61SJohnny Huang ibit = (strap_ignore[1] >> offset) & 0x1; 13585010032bSJohnny Huang pbit = (strap_pro[1] >> offset) & 0x1; 135969d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200; 136069d5fd8fSJohnny Huang prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2; 136169d5fd8fSJohnny Huang } 13625010032bSJohnny Huang if (info_cb.version != OTP_AST2600A0) { 13635010032bSJohnny Huang if (i < 32) { 13645010032bSJohnny Huang rpbit = (strap_reg_protect[0] >> i) & 0x1; 13655010032bSJohnny Huang } else { 13665010032bSJohnny Huang rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1; 13675010032bSJohnny Huang } 13685010032bSJohnny Huang } else { 13695010032bSJohnny Huang rpbit = 0; 13705010032bSJohnny Huang } 137169d5fd8fSJohnny Huang 1372eda10d61SJohnny Huang if (ibit == 1) { 137369d5fd8fSJohnny Huang continue; 137469d5fd8fSJohnny Huang } 137569d5fd8fSJohnny Huang if (bit == otpstrap[i].value) { 137669d5fd8fSJohnny Huang continue; 137769d5fd8fSJohnny Huang } 137869d5fd8fSJohnny Huang if (otpstrap[i].protected == 1) { 137969d5fd8fSJohnny Huang fail = 1; 138069d5fd8fSJohnny Huang continue; 138169d5fd8fSJohnny Huang } 138269d5fd8fSJohnny Huang if (otpstrap[i].remain_times == 0) { 138369d5fd8fSJohnny Huang fail = 1; 138469d5fd8fSJohnny Huang continue; 138569d5fd8fSJohnny Huang } 13867e22f42dSJohnny Huang 138783655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 138883655e91SJohnny Huang if (!ret) 13892a856b9aSJohnny Huang return OTP_FAILURE; 139069d5fd8fSJohnny Huang 13915010032bSJohnny Huang if (rpbit == 1 && info_cb.version != OTP_AST2600A0) { 139269d5fd8fSJohnny Huang prog_address = 0x800; 139369d5fd8fSJohnny Huang if (i < 32) 13945010032bSJohnny Huang prog_address |= 0x608; 139569d5fd8fSJohnny Huang else 13965010032bSJohnny Huang prog_address |= 0x60a; 13977e22f42dSJohnny Huang 139883655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 139983655e91SJohnny Huang if (!ret) 14002a856b9aSJohnny Huang return OTP_FAILURE; 14015010032bSJohnny Huang } 14025010032bSJohnny Huang 14035010032bSJohnny Huang if (pbit != 0) { 14045010032bSJohnny Huang prog_address = 0x800; 14055010032bSJohnny Huang if (i < 32) 14065010032bSJohnny Huang prog_address |= 0x60c; 14075010032bSJohnny Huang else 14085010032bSJohnny Huang prog_address |= 0x60e; 14095010032bSJohnny Huang 141083655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, offset); 141183655e91SJohnny Huang if (!ret) 14125010032bSJohnny Huang return OTP_FAILURE; 14135010032bSJohnny Huang } 141469d5fd8fSJohnny Huang 141569d5fd8fSJohnny Huang } 1416de6fbf1cSJohnny Huang otp_soak(0); 141769d5fd8fSJohnny Huang if (fail == 1) 14182a856b9aSJohnny Huang return OTP_FAILURE; 141969d5fd8fSJohnny Huang else 14202a856b9aSJohnny Huang return OTP_SUCCESS; 142169d5fd8fSJohnny Huang 142269d5fd8fSJohnny Huang } 142369d5fd8fSJohnny Huang 14245010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout) 14254c1c9b35SJohnny Huang { 142654552c69SJohnny Huang int i; 142754552c69SJohnny Huang int ret; 14285010032bSJohnny Huang int data_dw; 1429d90825e2SJohnny Huang uint32_t data[2048]; 14305010032bSJohnny Huang uint32_t *buf; 14315010032bSJohnny Huang uint32_t *buf_ignore; 14324c1c9b35SJohnny Huang 143354552c69SJohnny Huang uint32_t data_masked; 143454552c69SJohnny Huang uint32_t buf_masked; 14354c1c9b35SJohnny Huang 14365010032bSJohnny Huang buf = (uint32_t *)image_layout->data; 14375010032bSJohnny Huang buf_ignore = (uint32_t *)image_layout->data_ignore; 14385010032bSJohnny Huang 14395010032bSJohnny Huang data_dw = image_layout->data_length / 4; 14405010032bSJohnny Huang 14414c1c9b35SJohnny Huang printf("Read OTP Data:\n"); 14424c1c9b35SJohnny Huang 14435010032bSJohnny Huang for (i = 0; i < data_dw - 2 ; i += 2) { 1444d90825e2SJohnny Huang otp_read_data(i, &data[i]); 14454c1c9b35SJohnny Huang } 1446d90825e2SJohnny Huang 14474c1c9b35SJohnny Huang printf("Check writable...\n"); 144854552c69SJohnny Huang // ignore last two dw, the last two dw is used for slt otp write check. 14495010032bSJohnny Huang for (i = 0; i < data_dw - 2; i++) { 1450696656c6SJohnny Huang data_masked = data[i] & ~buf_ignore[i]; 1451696656c6SJohnny Huang buf_masked = buf[i] & ~buf_ignore[i]; 145254552c69SJohnny Huang if (data_masked == buf_masked) 14534c1c9b35SJohnny Huang continue; 1454d90825e2SJohnny Huang if (i % 2 == 0) { 145554552c69SJohnny Huang if ((data_masked | buf_masked) == buf_masked) { 14564c1c9b35SJohnny Huang continue; 14574c1c9b35SJohnny Huang } else { 14584c1c9b35SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1459d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 14604c1c9b35SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1461696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 14622a856b9aSJohnny Huang return OTP_FAILURE; 146369d5fd8fSJohnny Huang } 1464d90825e2SJohnny Huang } else { 146554552c69SJohnny Huang if ((data_masked & buf_masked) == buf_masked) { 1466d90825e2SJohnny Huang continue; 1467d90825e2SJohnny Huang } else { 1468d90825e2SJohnny Huang printf("Input image can't program into OTP, please check.\n"); 1469d90825e2SJohnny Huang printf("OTP_ADDR[%x] = %x\n", i, data[i]); 1470d90825e2SJohnny Huang printf("Input [%x] = %x\n", i, buf[i]); 1471696656c6SJohnny Huang printf("Mask [%x] = %x\n", i, ~buf_ignore[i]); 14722a856b9aSJohnny Huang return OTP_FAILURE; 1473d90825e2SJohnny Huang } 1474d90825e2SJohnny Huang } 1475d90825e2SJohnny Huang } 147669d5fd8fSJohnny Huang 1477d90825e2SJohnny Huang printf("Start Programing...\n"); 1478d90825e2SJohnny Huang 147954552c69SJohnny Huang // programing ecc region first 148054552c69SJohnny Huang for (i = 1792; i < 2046; i += 2) { 1481696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 148254552c69SJohnny Huang if (ret != OTP_SUCCESS) { 148354552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1484696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 148554552c69SJohnny Huang return ret; 1486d90825e2SJohnny Huang } 1487d90825e2SJohnny Huang } 1488d90825e2SJohnny Huang 148954552c69SJohnny Huang for (i = 0; i < 1792; i += 2) { 1490696656c6SJohnny Huang ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i); 149154552c69SJohnny Huang if (ret != OTP_SUCCESS) { 149254552c69SJohnny Huang printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n", 1493696656c6SJohnny Huang i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]); 149454552c69SJohnny Huang return ret; 1495d90825e2SJohnny Huang } 1496de6fbf1cSJohnny Huang } 1497de6fbf1cSJohnny Huang otp_soak(0); 14982a856b9aSJohnny Huang return OTP_SUCCESS; 1499d90825e2SJohnny Huang 1500d90825e2SJohnny Huang } 1501d90825e2SJohnny Huang 1502696656c6SJohnny Huang static int otp_image_verify(uint8_t *src_buf, uint32_t length, uint8_t *digest_buf) 1503696656c6SJohnny Huang { 1504696656c6SJohnny Huang sha256_context ctx; 1505696656c6SJohnny Huang u8 digest_ret[CHECKSUM_LEN]; 1506696656c6SJohnny Huang 1507696656c6SJohnny Huang sha256_starts(&ctx); 1508696656c6SJohnny Huang sha256_update(&ctx, src_buf, length); 1509696656c6SJohnny Huang sha256_finish(&ctx, digest_ret); 1510696656c6SJohnny Huang 1511696656c6SJohnny Huang if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN)) 1512696656c6SJohnny Huang return 0; 1513696656c6SJohnny Huang else 1514696656c6SJohnny Huang return -1; 1515696656c6SJohnny Huang 1516696656c6SJohnny Huang } 1517696656c6SJohnny Huang 1518de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm) 151969d5fd8fSJohnny Huang { 152069d5fd8fSJohnny Huang int ret; 15219a4fe690SJohnny Huang int image_version = 0; 1522696656c6SJohnny Huang struct otp_header *otp_header; 1523696656c6SJohnny Huang struct otp_image_layout image_layout; 1524696656c6SJohnny Huang int image_size; 1525696656c6SJohnny Huang uint8_t *buf; 1526696656c6SJohnny Huang uint8_t *checksum; 152769d5fd8fSJohnny Huang 1528696656c6SJohnny Huang otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK); 1529696656c6SJohnny Huang if (!otp_header) { 153069d5fd8fSJohnny Huang puts("Failed to map physical memory\n"); 15312a856b9aSJohnny Huang return OTP_FAILURE; 153269d5fd8fSJohnny Huang } 1533d90825e2SJohnny Huang 1534696656c6SJohnny Huang image_size = OTP_IMAGE_SIZE(otp_header->image_info); 1535696656c6SJohnny Huang unmap_physmem(otp_header, MAP_WRBACK); 1536696656c6SJohnny Huang 1537696656c6SJohnny Huang buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK); 1538696656c6SJohnny Huang 1539696656c6SJohnny Huang if (!buf) { 1540696656c6SJohnny Huang puts("Failed to map physical memory\n"); 1541696656c6SJohnny Huang return OTP_FAILURE; 1542696656c6SJohnny Huang } 1543696656c6SJohnny Huang otp_header = (struct otp_header *) buf; 1544696656c6SJohnny Huang checksum = buf + otp_header->checksum_offset; 1545696656c6SJohnny Huang 1546696656c6SJohnny Huang if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) { 1547696656c6SJohnny Huang puts("Image is invalid\n"); 1548696656c6SJohnny Huang return OTP_FAILURE; 1549696656c6SJohnny Huang } 1550696656c6SJohnny Huang 1551696656c6SJohnny Huang 15525010032bSJohnny Huang image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2); 15535010032bSJohnny Huang image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info); 15545010032bSJohnny Huang image_layout.data_ignore = image_layout.data + image_layout.data_length; 15555010032bSJohnny Huang 15565010032bSJohnny Huang image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2); 1557696656c6SJohnny Huang image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info); 15585010032bSJohnny Huang image_layout.conf_ignore = image_layout.conf + image_layout.conf_length; 1559696656c6SJohnny Huang 1560696656c6SJohnny Huang image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info); 1561696656c6SJohnny Huang 1562696656c6SJohnny Huang if (!strcmp("A0", (char *)otp_header->otp_version)) { 1563696656c6SJohnny Huang image_version = OTP_AST2600A0; 15645010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3); 15655010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + image_layout.strap_length; 15665010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length; 1567696656c6SJohnny Huang } else if (!strcmp("A1", (char *)otp_header->otp_version)) { 1568696656c6SJohnny Huang image_version = OTP_AST2600A1; 15695010032bSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 15705010032bSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 15715010032bSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 15725010032bSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 15735fdde29fSJohnny Huang } else if (!strcmp("A2", (char *)otp_header->otp_version)) { 15745fdde29fSJohnny Huang image_version = OTP_AST2600A2; 15755fdde29fSJohnny Huang image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4); 15765fdde29fSJohnny Huang image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length; 15775fdde29fSJohnny Huang image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length; 15785fdde29fSJohnny Huang image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length; 1579696656c6SJohnny Huang } else { 1580696656c6SJohnny Huang puts("Version is not supported\n"); 1581696656c6SJohnny Huang return OTP_FAILURE; 1582696656c6SJohnny Huang } 1583696656c6SJohnny Huang 15849a4fe690SJohnny Huang if (image_version != info_cb.version) { 15859a4fe690SJohnny Huang puts("Version is not match\n"); 15869a4fe690SJohnny Huang return OTP_FAILURE; 15879a4fe690SJohnny Huang } 15889a4fe690SJohnny Huang 1589696656c6SJohnny Huang if (otp_image_verify(buf, image_size, checksum)) { 1590696656c6SJohnny Huang puts("checksum is invalid\n"); 1591696656c6SJohnny Huang return OTP_FAILURE; 1592d90825e2SJohnny Huang } 15937332532cSJohnny Huang 159469d5fd8fSJohnny Huang if (!nconfirm) { 1595696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 15967f795e57SJohnny Huang printf("\nOTP data region :\n"); 1597696656c6SJohnny Huang if (otp_print_data_info(&image_layout) < 0) { 159869d5fd8fSJohnny Huang printf("OTP data error, please check.\n"); 15992a856b9aSJohnny Huang return OTP_FAILURE; 160069d5fd8fSJohnny Huang } 160169d5fd8fSJohnny Huang } 1602696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16037332532cSJohnny Huang printf("\nOTP strap region :\n"); 16045010032bSJohnny Huang if (otp_print_strap_image(&image_layout) < 0) { 16057332532cSJohnny Huang printf("OTP strap error, please check.\n"); 16067332532cSJohnny Huang return OTP_FAILURE; 16077332532cSJohnny Huang } 16087332532cSJohnny Huang } 1609696656c6SJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16107332532cSJohnny Huang printf("\nOTP configuration region :\n"); 1611696656c6SJohnny Huang if (otp_print_conf_image(&image_layout) < 0) { 16127332532cSJohnny Huang printf("OTP config error, please check.\n"); 16137332532cSJohnny Huang return OTP_FAILURE; 16147332532cSJohnny Huang } 16157332532cSJohnny Huang } 16167332532cSJohnny Huang 161769d5fd8fSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 161869d5fd8fSJohnny Huang if (!confirm_yesno()) { 161969d5fd8fSJohnny Huang printf(" Aborting\n"); 16202a856b9aSJohnny Huang return OTP_FAILURE; 162169d5fd8fSJohnny Huang } 162269d5fd8fSJohnny Huang } 16237332532cSJohnny Huang 16245010032bSJohnny Huang if (otp_header->image_info & OTP_INC_DATA) { 16255010032bSJohnny Huang printf("programing data region ...\n"); 16265010032bSJohnny Huang ret = otp_prog_data(&image_layout); 16275010032bSJohnny Huang if (ret != 0) { 16285010032bSJohnny Huang printf("Error\n"); 16295010032bSJohnny Huang return ret; 16305010032bSJohnny Huang } else { 16315010032bSJohnny Huang printf("Done\n"); 16325010032bSJohnny Huang } 16335010032bSJohnny Huang } 16345010032bSJohnny Huang if (otp_header->image_info & OTP_INC_STRAP) { 16355010032bSJohnny Huang printf("programing strap region ...\n"); 16365010032bSJohnny Huang ret = otp_prog_strap(&image_layout); 16375010032bSJohnny Huang if (ret != 0) { 16385010032bSJohnny Huang printf("Error\n"); 16395010032bSJohnny Huang return ret; 16405010032bSJohnny Huang } else { 16415010032bSJohnny Huang printf("Done\n"); 16425010032bSJohnny Huang } 16435010032bSJohnny Huang } 16445010032bSJohnny Huang if (otp_header->image_info & OTP_INC_CONFIG) { 16455010032bSJohnny Huang printf("programing configuration region ...\n"); 16465010032bSJohnny Huang ret = otp_prog_conf(&image_layout); 16475010032bSJohnny Huang if (ret != 0) { 16485010032bSJohnny Huang printf("Error\n"); 16495010032bSJohnny Huang return ret; 16505010032bSJohnny Huang } 16515010032bSJohnny Huang printf("Done\n"); 16525010032bSJohnny Huang } 1653cd1610b4SJohnny Huang 16547332532cSJohnny Huang return OTP_SUCCESS; 16552a856b9aSJohnny Huang } 16562a856b9aSJohnny Huang 16572a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm) 1658cd1610b4SJohnny Huang { 1659a6af4a17SJohnny Huang uint32_t read[2]; 1660d90825e2SJohnny Huang uint32_t prog_address = 0; 166166f2f8e5SJohnny Huang struct otpstrap_status otpstrap[64]; 1662cd1610b4SJohnny Huang int otp_bit; 166383655e91SJohnny Huang int ret = 0; 1664cd1610b4SJohnny Huang 1665cd1610b4SJohnny Huang switch (mode) { 1666a6d0d645SJohnny Huang case OTP_REGION_CONF: 1667a6af4a17SJohnny Huang otp_read_config(otp_dw_offset, read); 1668cd1610b4SJohnny Huang prog_address = 0x800; 1669cd1610b4SJohnny Huang prog_address |= (otp_dw_offset / 8) * 0x200; 1670cd1610b4SJohnny Huang prog_address |= (otp_dw_offset % 8) * 0x2; 1671a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1672cd1610b4SJohnny Huang if (otp_bit == value) { 1673a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1674cd1610b4SJohnny Huang printf("No need to program\n"); 16752a856b9aSJohnny Huang return OTP_SUCCESS; 1676cd1610b4SJohnny Huang } 1677cd1610b4SJohnny Huang if (otp_bit == 1 && value == 0) { 1678a6af4a17SJohnny Huang printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset); 1679cd1610b4SJohnny Huang printf("OTP is programed, which can't be clean\n"); 16802a856b9aSJohnny Huang return OTP_FAILURE; 1681cd1610b4SJohnny Huang } 1682a6af4a17SJohnny Huang printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset); 1683cd1610b4SJohnny Huang break; 1684a6d0d645SJohnny Huang case OTP_REGION_DATA: 1685cd1610b4SJohnny Huang prog_address = otp_dw_offset; 1686cd1610b4SJohnny Huang 1687cd1610b4SJohnny Huang if (otp_dw_offset % 2 == 0) { 1688a6af4a17SJohnny Huang otp_read_data(otp_dw_offset, read); 1689a6af4a17SJohnny Huang otp_bit = (read[0] >> bit_offset) & 0x1; 1690643b9cfdSJohnny Huang 1691643b9cfdSJohnny Huang if (otp_bit == 1 && value == 0) { 1692643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1693643b9cfdSJohnny Huang printf("OTP is programed, which can't be cleaned\n"); 1694643b9cfdSJohnny Huang return OTP_FAILURE; 1695643b9cfdSJohnny Huang } 1696cd1610b4SJohnny Huang } else { 1697a6af4a17SJohnny Huang otp_read_data(otp_dw_offset - 1, read); 1698a6af4a17SJohnny Huang otp_bit = (read[1] >> bit_offset) & 0x1; 1699643b9cfdSJohnny Huang 1700643b9cfdSJohnny Huang if (otp_bit == 0 && value == 1) { 1701643b9cfdSJohnny Huang printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset); 1702643b9cfdSJohnny Huang printf("OTP is programed, which can't be writen\n"); 1703643b9cfdSJohnny Huang return OTP_FAILURE; 1704643b9cfdSJohnny Huang } 1705cd1610b4SJohnny Huang } 1706cd1610b4SJohnny Huang if (otp_bit == value) { 1707a6af4a17SJohnny Huang printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value); 1708cd1610b4SJohnny Huang printf("No need to program\n"); 17092a856b9aSJohnny Huang return OTP_SUCCESS; 1710cd1610b4SJohnny Huang } 1711643b9cfdSJohnny Huang 1712a6af4a17SJohnny Huang printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset); 1713cd1610b4SJohnny Huang break; 1714a6d0d645SJohnny Huang case OTP_REGION_STRAP: 17158848d5dcSJohnny Huang otp_strap_status(otpstrap); 17168848d5dcSJohnny Huang otp_print_strap(bit_offset, 1); 17178848d5dcSJohnny Huang ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0); 17188848d5dcSJohnny Huang if (ret == OTP_FAILURE) 17198848d5dcSJohnny Huang return OTP_FAILURE; 17208848d5dcSJohnny Huang else if (ret == OTP_PROG_SKIP) 17218848d5dcSJohnny Huang return OTP_SUCCESS; 1722a6af4a17SJohnny Huang 1723cd1610b4SJohnny Huang break; 1724cd1610b4SJohnny Huang } 1725cd1610b4SJohnny Huang 1726cd1610b4SJohnny Huang if (!nconfirm) { 1727cd1610b4SJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1728cd1610b4SJohnny Huang if (!confirm_yesno()) { 1729cd1610b4SJohnny Huang printf(" Aborting\n"); 17302a856b9aSJohnny Huang return OTP_FAILURE; 1731cd1610b4SJohnny Huang } 1732cd1610b4SJohnny Huang } 1733cd1610b4SJohnny Huang 1734cd1610b4SJohnny Huang switch (mode) { 1735a6d0d645SJohnny Huang case OTP_REGION_STRAP: 173683655e91SJohnny Huang ret = otp_prog_strap_bit(bit_offset, value); 173783655e91SJohnny Huang break; 1738a6d0d645SJohnny Huang case OTP_REGION_CONF: 1739a6d0d645SJohnny Huang case OTP_REGION_DATA: 174083655e91SJohnny Huang ret = otp_prog_bit(value, prog_address, bit_offset); 1741de6fbf1cSJohnny Huang break; 1742de6fbf1cSJohnny Huang } 1743de6fbf1cSJohnny Huang otp_soak(0); 174483655e91SJohnny Huang if (ret) { 17459009c25dSJohnny Huang printf("SUCCESS\n"); 17462a856b9aSJohnny Huang return OTP_SUCCESS; 17479009c25dSJohnny Huang } else { 17489009c25dSJohnny Huang printf("OTP cannot be programed\n"); 17499009c25dSJohnny Huang printf("FAILED\n"); 17509009c25dSJohnny Huang return OTP_FAILURE; 17519009c25dSJohnny Huang } 1752cd1610b4SJohnny Huang 17532a856b9aSJohnny Huang return OTP_USAGE; 1754cd1610b4SJohnny Huang } 1755cd1610b4SJohnny Huang 17562a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 175769d5fd8fSJohnny Huang { 17582a856b9aSJohnny Huang uint32_t offset, count; 17592a856b9aSJohnny Huang int ret; 176069d5fd8fSJohnny Huang 17612a856b9aSJohnny Huang if (argc == 4) { 17622a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 17632a856b9aSJohnny Huang count = simple_strtoul(argv[3], NULL, 16); 17642a856b9aSJohnny Huang } else if (argc == 3) { 17652a856b9aSJohnny Huang offset = simple_strtoul(argv[2], NULL, 16); 17662a856b9aSJohnny Huang count = 1; 17672a856b9aSJohnny Huang } else { 176869d5fd8fSJohnny Huang return CMD_RET_USAGE; 176969d5fd8fSJohnny Huang } 177069d5fd8fSJohnny Huang 177169d5fd8fSJohnny Huang 17722a856b9aSJohnny Huang if (!strcmp(argv[1], "conf")) { 17733d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17742a856b9aSJohnny Huang ret = otp_print_config(offset, count); 17752a856b9aSJohnny Huang } else if (!strcmp(argv[1], "data")) { 17763d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17772a856b9aSJohnny Huang ret = otp_print_data(offset, count); 17782a856b9aSJohnny Huang } else if (!strcmp(argv[1], "strap")) { 17793d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 17802a856b9aSJohnny Huang ret = otp_print_strap(offset, count); 17812a856b9aSJohnny Huang } else { 17822a856b9aSJohnny Huang return CMD_RET_USAGE; 178369d5fd8fSJohnny Huang } 178469d5fd8fSJohnny Huang 17852a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 17862a856b9aSJohnny Huang return CMD_RET_SUCCESS; 17872a856b9aSJohnny Huang else 17882a856b9aSJohnny Huang return CMD_RET_USAGE; 17892a856b9aSJohnny Huang 17902a856b9aSJohnny Huang } 17912a856b9aSJohnny Huang 17922a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 17932a856b9aSJohnny Huang { 17942a856b9aSJohnny Huang phys_addr_t addr; 17952a856b9aSJohnny Huang int ret; 17962a856b9aSJohnny Huang 1797de6b0cc4SJohnny Huang if (argc == 3) { 1798ed071a2bSJohnny Huang if (strcmp(argv[1], "o")) 17992a856b9aSJohnny Huang return CMD_RET_USAGE; 18002a856b9aSJohnny Huang addr = simple_strtoul(argv[2], NULL, 16); 18013d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1802de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 1); 1803de6b0cc4SJohnny Huang } else if (argc == 2) { 18042a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 18053d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1806de6b0cc4SJohnny Huang ret = do_otp_prog(addr, 0); 18072a856b9aSJohnny Huang } else { 18082a856b9aSJohnny Huang return CMD_RET_USAGE; 18092a856b9aSJohnny Huang } 18102a856b9aSJohnny Huang 18112a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18122a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18132a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 18142a856b9aSJohnny Huang return CMD_RET_FAILURE; 18152a856b9aSJohnny Huang else 18162a856b9aSJohnny Huang return CMD_RET_USAGE; 18172a856b9aSJohnny Huang } 18182a856b9aSJohnny Huang 18192a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18202a856b9aSJohnny Huang { 18212a856b9aSJohnny Huang int mode = 0; 18222a856b9aSJohnny Huang int nconfirm = 0; 18232a856b9aSJohnny Huang int otp_addr = 0; 18242a856b9aSJohnny Huang int bit_offset; 18252a856b9aSJohnny Huang int value; 18262a856b9aSJohnny Huang int ret; 18272a856b9aSJohnny Huang 18282a856b9aSJohnny Huang if (argc != 4 && argc != 5 && argc != 6) 18292a856b9aSJohnny Huang return CMD_RET_USAGE; 18302a856b9aSJohnny Huang 18312a856b9aSJohnny Huang /* Drop the pb cmd */ 18322a856b9aSJohnny Huang argc--; 18332a856b9aSJohnny Huang argv++; 18342a856b9aSJohnny Huang 18352a856b9aSJohnny Huang if (!strcmp(argv[0], "conf")) 1836a6d0d645SJohnny Huang mode = OTP_REGION_CONF; 18372a856b9aSJohnny Huang else if (!strcmp(argv[0], "strap")) 1838a6d0d645SJohnny Huang mode = OTP_REGION_STRAP; 18392a856b9aSJohnny Huang else if (!strcmp(argv[0], "data")) 1840a6d0d645SJohnny Huang mode = OTP_REGION_DATA; 1841cd1610b4SJohnny Huang else 18422a856b9aSJohnny Huang return CMD_RET_USAGE; 18432a856b9aSJohnny Huang 18442a856b9aSJohnny Huang /* Drop the region cmd */ 18452a856b9aSJohnny Huang argc--; 18462a856b9aSJohnny Huang argv++; 18472a856b9aSJohnny Huang 1848ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1849cd1610b4SJohnny Huang nconfirm = 1; 18502a856b9aSJohnny Huang /* Drop the force option */ 18512a856b9aSJohnny Huang argc--; 18522a856b9aSJohnny Huang argv++; 18532a856b9aSJohnny Huang } 1854cd1610b4SJohnny Huang 1855a6d0d645SJohnny Huang if (mode == OTP_REGION_STRAP) { 18562a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[0], NULL, 16); 18572a856b9aSJohnny Huang value = simple_strtoul(argv[1], NULL, 16); 18580808cc55SJohnny Huang if (bit_offset >= 64 || (value != 0 && value != 1)) 18592a856b9aSJohnny Huang return CMD_RET_USAGE; 1860cd1610b4SJohnny Huang } else { 18612a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[0], NULL, 16); 18622a856b9aSJohnny Huang bit_offset = simple_strtoul(argv[1], NULL, 16); 18632a856b9aSJohnny Huang value = simple_strtoul(argv[2], NULL, 16); 18640808cc55SJohnny Huang if (bit_offset >= 32 || (value != 0 && value != 1)) 18652a856b9aSJohnny Huang return CMD_RET_USAGE; 18660808cc55SJohnny Huang if (mode == OTP_REGION_DATA) { 186778855207SJohnny Huang if (otp_addr >= 0x800) 18680808cc55SJohnny Huang return CMD_RET_USAGE; 18690808cc55SJohnny Huang } else { 187078855207SJohnny Huang if (otp_addr >= 0x20) 18710808cc55SJohnny Huang return CMD_RET_USAGE; 18720808cc55SJohnny Huang } 1873cd1610b4SJohnny Huang } 1874cd1610b4SJohnny Huang if (value != 0 && value != 1) 18752a856b9aSJohnny Huang return CMD_RET_USAGE; 1876cd1610b4SJohnny Huang 18773d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18782a856b9aSJohnny Huang ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm); 18792a856b9aSJohnny Huang 18802a856b9aSJohnny Huang if (ret == OTP_SUCCESS) 18812a856b9aSJohnny Huang return CMD_RET_SUCCESS; 18822a856b9aSJohnny Huang else if (ret == OTP_FAILURE) 18832a856b9aSJohnny Huang return CMD_RET_FAILURE; 18842a856b9aSJohnny Huang else 18852a856b9aSJohnny Huang return CMD_RET_USAGE; 18862a856b9aSJohnny Huang } 18872a856b9aSJohnny Huang 18882a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 18892a856b9aSJohnny Huang { 18902a856b9aSJohnny Huang phys_addr_t addr; 18912a856b9aSJohnny Huang int otp_addr = 0; 18922a856b9aSJohnny Huang 18932a856b9aSJohnny Huang if (argc != 3) 18942a856b9aSJohnny Huang return CMD_RET_USAGE; 18952a856b9aSJohnny Huang 18963d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 18972a856b9aSJohnny Huang addr = simple_strtoul(argv[1], NULL, 16); 18982a856b9aSJohnny Huang otp_addr = simple_strtoul(argv[2], NULL, 16); 18992a856b9aSJohnny Huang if (otp_compare(otp_addr, addr) == 0) { 190069d5fd8fSJohnny Huang printf("Compare pass\n"); 19012a856b9aSJohnny Huang return CMD_RET_SUCCESS; 190269d5fd8fSJohnny Huang } else { 190369d5fd8fSJohnny Huang printf("Compare fail\n"); 19042a856b9aSJohnny Huang return CMD_RET_FAILURE; 190569d5fd8fSJohnny Huang } 190669d5fd8fSJohnny Huang } 190769d5fd8fSJohnny Huang 190866f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 190966f2f8e5SJohnny Huang { 1910a8bd6d8cSJohnny Huang int view = 0; 19112d4b0742SJohnny Huang int input; 1912a8bd6d8cSJohnny Huang 1913a8bd6d8cSJohnny Huang if (argc != 2 && argc != 3) 191466f2f8e5SJohnny Huang return CMD_RET_USAGE; 191566f2f8e5SJohnny Huang 19162d4b0742SJohnny Huang if (!strcmp(argv[1], "conf")) { 191766f2f8e5SJohnny Huang 19183d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 19192d4b0742SJohnny Huang if (argc == 3) { 19202d4b0742SJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 19212d4b0742SJohnny Huang otp_print_conf_info(input); 19222d4b0742SJohnny Huang } else { 19232d4b0742SJohnny Huang otp_print_conf_info(-1); 19242d4b0742SJohnny Huang } 19252d4b0742SJohnny Huang } else if (!strcmp(argv[1], "strap")) { 19262d4b0742SJohnny Huang if (!strcmp(argv[2], "v")) { 1927a8bd6d8cSJohnny Huang view = 1; 1928a8bd6d8cSJohnny Huang /* Drop the view option */ 1929a8bd6d8cSJohnny Huang argc--; 1930a8bd6d8cSJohnny Huang argv++; 1931a8bd6d8cSJohnny Huang } 19323d3688adSJohnny Huang writel(OTP_PASSWD, OTP_PROTECT_KEY); //password 1933b458cd62SJohnny Huang otp_print_strap_info(view); 193466f2f8e5SJohnny Huang } else { 193566f2f8e5SJohnny Huang return CMD_RET_USAGE; 193666f2f8e5SJohnny Huang } 19372d4b0742SJohnny Huang 193866f2f8e5SJohnny Huang return CMD_RET_SUCCESS; 193966f2f8e5SJohnny Huang } 194066f2f8e5SJohnny Huang 1941737ed20bSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 1942737ed20bSJohnny Huang { 1943737ed20bSJohnny Huang int input; 1944737ed20bSJohnny Huang int bit_offset; 1945737ed20bSJohnny Huang int prog_address; 194683655e91SJohnny Huang int ret; 1947737ed20bSJohnny Huang if (argc != 3 && argc != 2) 1948737ed20bSJohnny Huang return CMD_RET_USAGE; 1949737ed20bSJohnny Huang 1950ed071a2bSJohnny Huang if (!strcmp(argv[0], "o")) { 1951737ed20bSJohnny Huang input = simple_strtoul(argv[2], NULL, 16); 1952737ed20bSJohnny Huang } else { 1953737ed20bSJohnny Huang input = simple_strtoul(argv[1], NULL, 16); 1954737ed20bSJohnny Huang printf("OTPSTRAP[%d] will be protected\n", input); 1955737ed20bSJohnny Huang printf("type \"YES\" (no quotes) to continue:\n"); 1956737ed20bSJohnny Huang if (!confirm_yesno()) { 1957737ed20bSJohnny Huang printf(" Aborting\n"); 1958737ed20bSJohnny Huang return CMD_RET_FAILURE; 1959737ed20bSJohnny Huang } 1960737ed20bSJohnny Huang } 1961737ed20bSJohnny Huang 1962737ed20bSJohnny Huang prog_address = 0x800; 1963737ed20bSJohnny Huang if (input < 32) { 1964737ed20bSJohnny Huang bit_offset = input; 1965737ed20bSJohnny Huang prog_address |= 0x60c; 1966737ed20bSJohnny Huang } else if (input < 64) { 1967737ed20bSJohnny Huang bit_offset = input - 32; 1968737ed20bSJohnny Huang prog_address |= 0x60e; 1969737ed20bSJohnny Huang } else { 1970737ed20bSJohnny Huang return CMD_RET_USAGE; 1971737ed20bSJohnny Huang } 1972737ed20bSJohnny Huang 1973737ed20bSJohnny Huang if (verify_bit(prog_address, bit_offset, 1) == 0) { 1974737ed20bSJohnny Huang printf("OTPSTRAP[%d] already protected\n", input); 1975737ed20bSJohnny Huang } 1976de6fbf1cSJohnny Huang 197783655e91SJohnny Huang ret = otp_prog_bit(1, prog_address, bit_offset); 1978de6fbf1cSJohnny Huang otp_soak(0); 197983655e91SJohnny Huang 198083655e91SJohnny Huang if (ret) { 1981737ed20bSJohnny Huang printf("OTPSTRAP[%d] is protected\n", input); 1982737ed20bSJohnny Huang return CMD_RET_SUCCESS; 1983737ed20bSJohnny Huang } 1984737ed20bSJohnny Huang 1985737ed20bSJohnny Huang printf("Protect OTPSTRAP[%d] fail\n", input); 1986737ed20bSJohnny Huang return CMD_RET_FAILURE; 1987737ed20bSJohnny Huang 1988737ed20bSJohnny Huang } 19899a4fe690SJohnny Huang 19902a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = { 19912a856b9aSJohnny Huang U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""), 1992a8bd6d8cSJohnny Huang U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""), 1993de6b0cc4SJohnny Huang U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""), 19942a856b9aSJohnny Huang U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""), 1995737ed20bSJohnny Huang U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""), 19962a856b9aSJohnny Huang U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""), 19972a856b9aSJohnny Huang }; 19982a856b9aSJohnny Huang 19992a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 20002a856b9aSJohnny Huang { 20012a856b9aSJohnny Huang cmd_tbl_t *cp; 20022a856b9aSJohnny Huang 20032a856b9aSJohnny Huang cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp)); 20042a856b9aSJohnny Huang 2005737ed20bSJohnny Huang /* Drop the otp command */ 20062a856b9aSJohnny Huang argc--; 20072a856b9aSJohnny Huang argv++; 20082a856b9aSJohnny Huang 20092a856b9aSJohnny Huang if (cp == NULL || argc > cp->maxargs) 20102a856b9aSJohnny Huang return CMD_RET_USAGE; 20112a856b9aSJohnny Huang if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 20122a856b9aSJohnny Huang return CMD_RET_SUCCESS; 20132a856b9aSJohnny Huang 2014696656c6SJohnny Huang if (chip_version() == OTP_AST2600A0) { 2015696656c6SJohnny Huang info_cb.version = OTP_AST2600A0; 20169a4fe690SJohnny Huang info_cb.conf_info = a0_conf_info; 20179a4fe690SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info); 20189a4fe690SJohnny Huang info_cb.strap_info = a0_strap_info; 20199a4fe690SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info); 20209a4fe690SJohnny Huang info_cb.key_info = a0_key_type; 20219a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a0_key_type); 2022696656c6SJohnny Huang } else if (chip_version() == OTP_AST2600A1) { 2023696656c6SJohnny Huang info_cb.version = OTP_AST2600A1; 20243cb28812SJohnny Huang info_cb.conf_info = a1_conf_info; 20253cb28812SJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info); 20263cb28812SJohnny Huang info_cb.strap_info = a1_strap_info; 20273cb28812SJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info); 20289a4fe690SJohnny Huang info_cb.key_info = a1_key_type; 20299a4fe690SJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a1_key_type); 20305fdde29fSJohnny Huang } else if (chip_version() == OTP_AST2600A2) { 20315fdde29fSJohnny Huang info_cb.version = OTP_AST2600A2; 20325fdde29fSJohnny Huang info_cb.conf_info = a2_conf_info; 20335fdde29fSJohnny Huang info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info); 20345fdde29fSJohnny Huang info_cb.strap_info = a2_strap_info; 20355fdde29fSJohnny Huang info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info); 20365fdde29fSJohnny Huang info_cb.key_info = a2_key_type; 20375fdde29fSJohnny Huang info_cb.key_info_len = ARRAY_SIZE(a2_key_type); 20389a4fe690SJohnny Huang } 20399a4fe690SJohnny Huang 20402a856b9aSJohnny Huang return cp->cmd(cmdtp, flag, argc, argv); 204169d5fd8fSJohnny Huang } 204269d5fd8fSJohnny Huang 204369d5fd8fSJohnny Huang U_BOOT_CMD( 204469d5fd8fSJohnny Huang otp, 7, 0, do_ast_otp, 204569d5fd8fSJohnny Huang "ASPEED One-Time-Programmable sub-system", 20462a856b9aSJohnny Huang "read conf|data <otp_dw_offset> <dw_count>\n" 20472a856b9aSJohnny Huang "otp read strap <strap_bit_offset> <bit_count>\n" 20482d4b0742SJohnny Huang "otp info strap [v]\n" 20492d4b0742SJohnny Huang "otp info conf [otp_dw_offset]\n" 2050de6b0cc4SJohnny Huang "otp prog [o] <addr>\n" 2051ed071a2bSJohnny Huang "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n" 2052ed071a2bSJohnny Huang "otp pb strap [o] <bit_offset> <value>\n" 2053ed071a2bSJohnny Huang "otp protect [o] <bit_offset>\n" 20542a856b9aSJohnny Huang "otp cmp <addr> <otp_dw_offset>\n" 205569d5fd8fSJohnny Huang ); 2056