xref: /openbmc/u-boot/cmd/otp.c (revision 0dae9d52fbae74196e19aaa725f857f4f78efea3)
169d5fd8fSJohnny Huang /*
269d5fd8fSJohnny Huang  *  This program is distributed in the hope that it will be useful,
369d5fd8fSJohnny Huang  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
469d5fd8fSJohnny Huang  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
569d5fd8fSJohnny Huang  *  GNU General Public License for more details.
669d5fd8fSJohnny Huang  *
769d5fd8fSJohnny Huang  *  You should have received a copy of the GNU General Public License
869d5fd8fSJohnny Huang  *  along with this program; if not, write to the Free Software
969d5fd8fSJohnny Huang  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1069d5fd8fSJohnny Huang  */
114c1c9b35SJohnny Huang #include <stdlib.h>
1269d5fd8fSJohnny Huang #include <common.h>
1369d5fd8fSJohnny Huang #include <console.h>
1469d5fd8fSJohnny Huang #include <bootretry.h>
1569d5fd8fSJohnny Huang #include <cli.h>
1669d5fd8fSJohnny Huang #include <command.h>
1769d5fd8fSJohnny Huang #include <console.h>
184c1c9b35SJohnny Huang #include <malloc.h>
1969d5fd8fSJohnny Huang #include <inttypes.h>
2069d5fd8fSJohnny Huang #include <mapmem.h>
2169d5fd8fSJohnny Huang #include <asm/io.h>
2269d5fd8fSJohnny Huang #include <linux/compiler.h>
23696656c6SJohnny Huang #include <u-boot/sha256.h>
240cee9a95SJohnny Huang #include "otp_info.h"
2569d5fd8fSJohnny Huang 
2669d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2769d5fd8fSJohnny Huang 
28*0dae9d52SJohnny Huang #define OTP_VER				"1.0.1"
29f67375f7SJohnny Huang 
3069d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
3169d5fd8fSJohnny Huang #define RETRY				3
327332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
337332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
347332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3569d5fd8fSJohnny Huang 
362a856b9aSJohnny Huang #define OTP_USAGE			-1
372a856b9aSJohnny Huang #define OTP_FAILURE			-2
382a856b9aSJohnny Huang #define OTP_SUCCESS			0
392a856b9aSJohnny Huang 
40a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
41a6af4a17SJohnny Huang 
429a4fe690SJohnny Huang #define OTP_KEY_TYPE_RSA		1
439a4fe690SJohnny Huang #define OTP_KEY_TYPE_AES		2
449a4fe690SJohnny Huang #define OTP_KEY_TYPE_VAULT		3
459a4fe690SJohnny Huang #define OTP_KEY_TYPE_HMAC		4
469a4fe690SJohnny Huang 
474c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
484c1c9b35SJohnny Huang #define PBWIDTH 60
494c1c9b35SJohnny Huang 
503d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
513d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
523d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
533d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
543d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
553d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
563d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
573d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
583d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
593d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
603d3688adSJohnny Huang 
61696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
62696656c6SJohnny Huang #define CHECKSUM_LEN		32
63696656c6SJohnny Huang #define OTP_INC_DATA		(1 << 31)
64696656c6SJohnny Huang #define OTP_INC_CONFIG		(1 << 30)
65696656c6SJohnny Huang #define OTP_INC_STRAP		(1 << 29)
66696656c6SJohnny Huang #define OTP_ECC_EN		(1 << 28)
67696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
68696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
69696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
70696656c6SJohnny Huang 
71696656c6SJohnny Huang #define OTP_AST2600A0		0
72696656c6SJohnny Huang #define OTP_AST2600A1		1
73*0dae9d52SJohnny Huang #define OTP_AST2600A2		2
74696656c6SJohnny Huang 
75696656c6SJohnny Huang struct otp_header {
76696656c6SJohnny Huang 	u8	otp_magic[8];
77696656c6SJohnny Huang 	u8	otp_version[8];
78696656c6SJohnny Huang 	u32	image_info;
79696656c6SJohnny Huang 	u32	data_info;
80696656c6SJohnny Huang 	u32	config_info;
81696656c6SJohnny Huang 	u32	strap_info;
82696656c6SJohnny Huang 	u32	checksum_offset;
83696656c6SJohnny Huang } __attribute__((packed));
84696656c6SJohnny Huang 
8566f2f8e5SJohnny Huang struct otpstrap_status {
8669d5fd8fSJohnny Huang 	int value;
8769d5fd8fSJohnny Huang 	int option_array[7];
8869d5fd8fSJohnny Huang 	int remain_times;
8969d5fd8fSJohnny Huang 	int writeable_option;
905010032bSJohnny Huang 	int reg_protected;
9169d5fd8fSJohnny Huang 	int protected;
9269d5fd8fSJohnny Huang };
9369d5fd8fSJohnny Huang 
9466f2f8e5SJohnny Huang struct otpconf_parse {
9566f2f8e5SJohnny Huang 	int dw_offset;
9666f2f8e5SJohnny Huang 	int bit;
9766f2f8e5SJohnny Huang 	int length;
9866f2f8e5SJohnny Huang 	int value;
99696656c6SJohnny Huang 	int ignore;
10066f2f8e5SJohnny Huang 	char status[80];
10166f2f8e5SJohnny Huang };
10266f2f8e5SJohnny Huang 
1039a4fe690SJohnny Huang struct otpkey_type {
1049a4fe690SJohnny Huang 	int value;
1059a4fe690SJohnny Huang 	int key_type;
1069a4fe690SJohnny Huang 	int need_id;
1079a4fe690SJohnny Huang 	char information[110];
1089a4fe690SJohnny Huang };
1099a4fe690SJohnny Huang 
1109a4fe690SJohnny Huang struct otp_info_cb {
1119a4fe690SJohnny Huang 	int version;
11279e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1139a4fe690SJohnny Huang 	int strap_info_len;
11479e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1159a4fe690SJohnny Huang 	int conf_info_len;
11679e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1179a4fe690SJohnny Huang 	int key_info_len;
1185010032bSJohnny Huang 
1199a4fe690SJohnny Huang };
1209a4fe690SJohnny Huang 
121696656c6SJohnny Huang struct otp_image_layout {
1225010032bSJohnny Huang 	int data_length;
1235010032bSJohnny Huang 	int conf_length;
1245010032bSJohnny Huang 	int strap_length;
125696656c6SJohnny Huang 	uint8_t *data;
126696656c6SJohnny Huang 	uint8_t *data_ignore;
127696656c6SJohnny Huang 	uint8_t *conf;
128696656c6SJohnny Huang 	uint8_t *conf_ignore;
129696656c6SJohnny Huang 	uint8_t *strap;
130696656c6SJohnny Huang 	uint8_t *strap_reg_pro;
131696656c6SJohnny Huang 	uint8_t *strap_pro;
132696656c6SJohnny Huang 	uint8_t *strap_ignore;
133696656c6SJohnny Huang };
134696656c6SJohnny Huang 
1359a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1369a4fe690SJohnny Huang 
13779e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1389a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1399a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1409a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
1419a4fe690SJohnny Huang 	{8, OTP_KEY_TYPE_RSA,   1, "RSA-public as OEM DSS public keys in Mode 2"},
1429a4fe690SJohnny Huang 	{9, OTP_KEY_TYPE_RSA,   0, "RSA-public as SOC public key"},
1439a4fe690SJohnny Huang 	{10, OTP_KEY_TYPE_RSA,  0, "RSA-public as AES key decryption key"},
1449a4fe690SJohnny Huang 	{13, OTP_KEY_TYPE_RSA,  0, "RSA-private as SOC private key"},
1459a4fe690SJohnny Huang 	{14, OTP_KEY_TYPE_RSA,  0, "RSA-private as AES key decryption key"},
1469a4fe690SJohnny Huang };
1479a4fe690SJohnny Huang 
14879e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1499a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1509a4fe690SJohnny Huang 	{2, OTP_KEY_TYPE_AES,   1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
1519a4fe690SJohnny Huang 	{8, OTP_KEY_TYPE_RSA,   1, "RSA-public as OEM DSS public keys in Mode 2"},
1529a4fe690SJohnny Huang 	{10, OTP_KEY_TYPE_RSA,  0, "RSA-public as AES key decryption key"},
1539a4fe690SJohnny Huang 	{14, OTP_KEY_TYPE_RSA,  0, "RSA-private as AES key decryption key"},
1549a4fe690SJohnny Huang };
1559a4fe690SJohnny Huang 
1565fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1575fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1585fdde29fSJohnny Huang 	{2, OTP_KEY_TYPE_AES,   1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
1595fdde29fSJohnny Huang 	{8, OTP_KEY_TYPE_RSA,   1, "RSA-public as OEM DSS public keys in Mode 2"},
1605fdde29fSJohnny Huang 	{10, OTP_KEY_TYPE_RSA,  0, "RSA-public as AES key decryption key"},
1615fdde29fSJohnny Huang 	{14, OTP_KEY_TYPE_RSA,  0, "RSA-private as AES key decryption key"},
1625fdde29fSJohnny Huang };
1635fdde29fSJohnny Huang 
1649a4fe690SJohnny Huang static uint32_t  chip_version(void)
1659a4fe690SJohnny Huang {
166*0dae9d52SJohnny Huang 	uint32_t rev_id[2];
1679a4fe690SJohnny Huang 
168*0dae9d52SJohnny Huang 	rev_id[0] = readl(0x1e6e2004);
169*0dae9d52SJohnny Huang 	rev_id[1] = readl(0x1e6e2014);
1709a4fe690SJohnny Huang 
171*0dae9d52SJohnny Huang 	if (rev_id[0] == 0x05000303 && rev_id[1] == 0x05000303) {
172*0dae9d52SJohnny Huang 		return OTP_AST2600A0;
173*0dae9d52SJohnny Huang 	} else if (rev_id[0] == 0x05010303 && rev_id[1] == 0x05010303) {
174*0dae9d52SJohnny Huang 		return OTP_AST2600A1;
175*0dae9d52SJohnny Huang 	} else if (rev_id[0] == 0x05010303 && rev_id[1] == 0x05020303) {
176*0dae9d52SJohnny Huang 		return OTP_AST2600A2;
177*0dae9d52SJohnny Huang 	} else if (rev_id[0] == 0x05010203 && rev_id[1] == 0x05010203) {
178*0dae9d52SJohnny Huang 		return OTP_AST2600A1;
179*0dae9d52SJohnny Huang 	} else if (rev_id[0] == 0x05010203 && rev_id[1] == 0x05020203) {
180*0dae9d52SJohnny Huang 		return OTP_AST2600A2;
181*0dae9d52SJohnny Huang 	}
182*0dae9d52SJohnny Huang 
1835fdde29fSJohnny Huang 	return -1;
1849a4fe690SJohnny Huang }
1859a4fe690SJohnny Huang 
1863d3688adSJohnny Huang static void wait_complete(void)
1873d3688adSJohnny Huang {
1883d3688adSJohnny Huang 	int reg;
1893d3688adSJohnny Huang 
1903d3688adSJohnny Huang 	do {
1913d3688adSJohnny Huang 		reg = readl(OTP_STATUS);
1923d3688adSJohnny Huang 	} while ((reg & 0x6) != 0x6);
1933d3688adSJohnny Huang }
1943d3688adSJohnny Huang 
1952a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data)
19669d5fd8fSJohnny Huang {
1973d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
1983d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
1993d3688adSJohnny Huang 	wait_complete();
2003d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
2013d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
20269d5fd8fSJohnny Huang }
20369d5fd8fSJohnny Huang 
2042a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data)
20569d5fd8fSJohnny Huang {
20669d5fd8fSJohnny Huang 	int config_offset;
20769d5fd8fSJohnny Huang 
20869d5fd8fSJohnny Huang 	config_offset = 0x800;
20969d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
21069d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
21169d5fd8fSJohnny Huang 
2123d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
2133d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
2143d3688adSJohnny Huang 	wait_complete();
2153d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
21669d5fd8fSJohnny Huang }
21769d5fd8fSJohnny Huang 
21869d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count)
21969d5fd8fSJohnny Huang {
22069d5fd8fSJohnny Huang 	int i;
22169d5fd8fSJohnny Huang 	uint32_t ret[1];
22269d5fd8fSJohnny Huang 
22369d5fd8fSJohnny Huang 	if (offset + dw_count > 32)
2242a856b9aSJohnny Huang 		return OTP_USAGE;
22569d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i ++) {
22669d5fd8fSJohnny Huang 		otp_read_config(i, ret);
227a6af4a17SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
22869d5fd8fSJohnny Huang 	}
22969d5fd8fSJohnny Huang 	printf("\n");
2302a856b9aSJohnny Huang 	return OTP_SUCCESS;
23169d5fd8fSJohnny Huang }
23269d5fd8fSJohnny Huang 
23369d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count)
23469d5fd8fSJohnny Huang {
23569d5fd8fSJohnny Huang 	int i;
23669d5fd8fSJohnny Huang 	uint32_t ret[2];
23769d5fd8fSJohnny Huang 
23869d5fd8fSJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
2392a856b9aSJohnny Huang 		return OTP_USAGE;
24069d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
24169d5fd8fSJohnny Huang 		otp_read_data(i, ret);
24269d5fd8fSJohnny Huang 		if (i % 4 == 0)
24369d5fd8fSJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
24469d5fd8fSJohnny Huang 		else
24569d5fd8fSJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
24669d5fd8fSJohnny Huang 
24769d5fd8fSJohnny Huang 	}
24869d5fd8fSJohnny Huang 	printf("\n");
2492a856b9aSJohnny Huang 	return OTP_SUCCESS;
25069d5fd8fSJohnny Huang }
25169d5fd8fSJohnny Huang 
25269d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr)
25369d5fd8fSJohnny Huang {
25469d5fd8fSJohnny Huang 	uint32_t ret;
25569d5fd8fSJohnny Huang 	uint32_t *buf;
25669d5fd8fSJohnny Huang 
25769d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
25869d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
25969d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
26069d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
26169d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
2623d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
2633d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
2643d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
2653d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
2663d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
2673d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
2683d3688adSJohnny Huang 	wait_complete();
2693d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
27069d5fd8fSJohnny Huang 	if (ret & 0x1)
27169d5fd8fSJohnny Huang 		return 0;
27269d5fd8fSJohnny Huang 	else
27369d5fd8fSJohnny Huang 		return -1;
27469d5fd8fSJohnny Huang }
27569d5fd8fSJohnny Huang 
27669d5fd8fSJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data)
27769d5fd8fSJohnny Huang {
2783d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
2793d3688adSJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
2803d3688adSJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
2813d3688adSJohnny Huang 	wait_complete();
28269d5fd8fSJohnny Huang }
28369d5fd8fSJohnny Huang 
284a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value)
28569d5fd8fSJohnny Huang {
28630a8c590SJohnny Huang 	uint32_t ret[2];
28769d5fd8fSJohnny Huang 
28830a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
2893d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
29030a8c590SJohnny Huang 	else
2913d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
29230a8c590SJohnny Huang 
2933d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
2943d3688adSJohnny Huang 	wait_complete();
2953d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
2963d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
29783655e91SJohnny Huang 
29830a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
29930a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
30069d5fd8fSJohnny Huang 			return 0;
30169d5fd8fSJohnny Huang 		else
30269d5fd8fSJohnny Huang 			return -1;
30330a8c590SJohnny Huang 	} else {
30430a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
30530a8c590SJohnny Huang 			return 0;
30630a8c590SJohnny Huang 		else
30730a8c590SJohnny Huang 			return -1;
30830a8c590SJohnny Huang 	}
30930a8c590SJohnny Huang 
31069d5fd8fSJohnny Huang }
31169d5fd8fSJohnny Huang 
312696656c6SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *ignore, uint32_t *compare, int size)
3134c1c9b35SJohnny Huang {
3144c1c9b35SJohnny Huang 	uint32_t ret[2];
3154c1c9b35SJohnny Huang 
3164c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
3174c1c9b35SJohnny Huang 
3184c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
3193d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
3204c1c9b35SJohnny Huang 	else
3213d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
3223d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3233d3688adSJohnny Huang 	wait_complete();
3243d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
3253d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
3264c1c9b35SJohnny Huang 	if (size == 1) {
3274c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
3284c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
329696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
3304c1c9b35SJohnny Huang 				compare[0] = 0;
3314c1c9b35SJohnny Huang 				return 0;
3324c1c9b35SJohnny Huang 			} else {
3334c1c9b35SJohnny Huang 				compare[0] = value[0] ^ ret[0];
3344c1c9b35SJohnny Huang 				return -1;
3354c1c9b35SJohnny Huang 			}
3364c1c9b35SJohnny Huang 
3374c1c9b35SJohnny Huang 		} else {
3384c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
339696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
3404c1c9b35SJohnny Huang 				compare[0] = ~0;
3414c1c9b35SJohnny Huang 				return 0;
3424c1c9b35SJohnny Huang 			} else {
343d90825e2SJohnny Huang 				compare[0] = ~(value[0] ^ ret[1]);
3444c1c9b35SJohnny Huang 				return -1;
3454c1c9b35SJohnny Huang 			}
3464c1c9b35SJohnny Huang 		}
3474c1c9b35SJohnny Huang 	} else if (size == 2) {
3484c1c9b35SJohnny Huang 		// otp_addr should be even
349696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
3504c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
3514c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
3524c1c9b35SJohnny Huang 			compare[0] = 0;
3534c1c9b35SJohnny Huang 			compare[1] = ~0;
3544c1c9b35SJohnny Huang 			return 0;
3554c1c9b35SJohnny Huang 		} else {
3564c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
3574c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
3584c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
3594c1c9b35SJohnny Huang 			compare[1] = ~(value[1] ^ ret[1]);
3604c1c9b35SJohnny Huang 			return -1;
3614c1c9b35SJohnny Huang 		}
3624c1c9b35SJohnny Huang 	} else {
3634c1c9b35SJohnny Huang 		return -1;
3644c1c9b35SJohnny Huang 	}
3654c1c9b35SJohnny Huang }
3664c1c9b35SJohnny Huang 
3677e22f42dSJohnny Huang static void otp_soak(int soak)
368d90825e2SJohnny Huang {
3699d734279SJohnny Huang 	if (info_cb.version == OTP_AST2600A2) {
3709d734279SJohnny Huang 		switch (soak) {
3719d734279SJohnny Huang 		case 0: //default
3729d734279SJohnny Huang 			otp_write(0x3000, 0x0210); // Write MRA
3739d734279SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
3749d734279SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
3759d734279SJohnny Huang 			break;
3769d734279SJohnny Huang 		case 1: //normal program
3779d734279SJohnny Huang 			otp_write(0x3000, 0x1200); // Write MRA
3789d734279SJohnny Huang 			otp_write(0x5000, 0x100F); // Write MRB
3799d734279SJohnny Huang 			otp_write(0x1000, 0x1024); // Write MR
3809d734279SJohnny Huang 			writel(0x04190760, OTP_TIMING);
3819d734279SJohnny Huang 			break;
3829d734279SJohnny Huang 		case 2: //soak program
3839d734279SJohnny Huang 			otp_write(0x3000, 0x1220); // Write MRA
3849d734279SJohnny Huang 			otp_write(0x5000, 0x2004); // Write MRB
3859d734279SJohnny Huang 			otp_write(0x1000, 0x08a4); // Write MR
3869d734279SJohnny Huang 			writel(0x041930d4, OTP_TIMING);
3879d734279SJohnny Huang 			break;
3889d734279SJohnny Huang 		}
3899d734279SJohnny Huang 	} else {
390de6fbf1cSJohnny Huang 		switch (soak) {
391de6fbf1cSJohnny Huang 		case 0: //default
392de6fbf1cSJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
393de6fbf1cSJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
394de6fbf1cSJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
395de6fbf1cSJohnny Huang 			break;
396de6fbf1cSJohnny Huang 		case 1: //normal program
397de6fbf1cSJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
398de6fbf1cSJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
399de6fbf1cSJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
400de6fbf1cSJohnny Huang 			writel(0x04190760, OTP_TIMING);
401de6fbf1cSJohnny Huang 			break;
402de6fbf1cSJohnny Huang 		case 2: //soak program
403d90825e2SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
404d90825e2SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
405d90825e2SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
406de6fbf1cSJohnny Huang 			writel(0x041930d4, OTP_TIMING);
407de6fbf1cSJohnny Huang 			break;
408d90825e2SJohnny Huang 		}
4099d734279SJohnny Huang 	}
410de6fbf1cSJohnny Huang 
4113d3688adSJohnny Huang 	wait_complete();
412d90825e2SJohnny Huang }
413d90825e2SJohnny Huang 
41483655e91SJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit)
41583655e91SJohnny Huang {
41683655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
41783655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
41883655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
41983655e91SJohnny Huang 	wait_complete();
42083655e91SJohnny Huang }
42183655e91SJohnny Huang 
42283655e91SJohnny Huang static void _otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset)
42383655e91SJohnny Huang {
42483655e91SJohnny Huang 	int prog_bit;
42583655e91SJohnny Huang 
42683655e91SJohnny Huang 	if (prog_address % 2 == 0) {
42783655e91SJohnny Huang 		if (value)
42883655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
42983655e91SJohnny Huang 		else
43083655e91SJohnny Huang 			return;
43183655e91SJohnny Huang 	} else {
43283655e91SJohnny Huang 		prog_address |= 1 << 15;
43383655e91SJohnny Huang 		if (!value)
43483655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
43583655e91SJohnny Huang 		else
43683655e91SJohnny Huang 			return;
43783655e91SJohnny Huang 	}
43883655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
43983655e91SJohnny Huang }
44083655e91SJohnny Huang 
44183655e91SJohnny Huang static int otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset)
44283655e91SJohnny Huang {
44383655e91SJohnny Huang 	int pass;
44483655e91SJohnny Huang 	int i;
44583655e91SJohnny Huang 
44683655e91SJohnny Huang 	otp_soak(1);
44783655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
44883655e91SJohnny Huang 	pass = 0;
44983655e91SJohnny Huang 
45083655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
45183655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
45283655e91SJohnny Huang 			otp_soak(2);
45383655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
45483655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
45583655e91SJohnny Huang 				otp_soak(1);
45683655e91SJohnny Huang 			} else {
45783655e91SJohnny Huang 				pass = 1;
45883655e91SJohnny Huang 				break;
45983655e91SJohnny Huang 			}
46083655e91SJohnny Huang 		} else {
46183655e91SJohnny Huang 			pass = 1;
46283655e91SJohnny Huang 			break;
46383655e91SJohnny Huang 		}
46483655e91SJohnny Huang 	}
46583655e91SJohnny Huang 
46683655e91SJohnny Huang 	return pass;
46783655e91SJohnny Huang }
46883655e91SJohnny Huang 
469696656c6SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t ignore, uint32_t prog_address)
470d90825e2SJohnny Huang {
471d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
472d90825e2SJohnny Huang 
473d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
474696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
475d90825e2SJohnny Huang 			continue;
476d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
477d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
478d90825e2SJohnny Huang 			if (bit_value)
479d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
480d90825e2SJohnny Huang 			else
481d90825e2SJohnny Huang 				continue;
482d90825e2SJohnny Huang 		} else {
483d90825e2SJohnny Huang 			prog_address |= 1 << 15;
484d90825e2SJohnny Huang 			if (bit_value)
485d90825e2SJohnny Huang 				continue;
486d90825e2SJohnny Huang 			else
487d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
488d90825e2SJohnny Huang 		}
489d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
490d90825e2SJohnny Huang 	}
491d90825e2SJohnny Huang }
492d90825e2SJohnny Huang 
49354552c69SJohnny Huang static int otp_prog_verify_2dw(uint32_t *data, uint32_t *buf, uint32_t *ignore_mask, uint32_t prog_address)
49454552c69SJohnny Huang {
49554552c69SJohnny Huang 	int pass;
49654552c69SJohnny Huang 	int i;
49754552c69SJohnny Huang 	uint32_t data0_masked;
49854552c69SJohnny Huang 	uint32_t data1_masked;
49954552c69SJohnny Huang 	uint32_t buf0_masked;
50054552c69SJohnny Huang 	uint32_t buf1_masked;
50154552c69SJohnny Huang 	uint32_t compare[2];
50254552c69SJohnny Huang 
50354552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
50454552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
50554552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
50654552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
50754552c69SJohnny Huang 	if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked))
50854552c69SJohnny Huang 		return 0;
50954552c69SJohnny Huang 
51054552c69SJohnny Huang 	otp_soak(1);
51154552c69SJohnny Huang 	if (data0_masked != buf0_masked)
51254552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
51354552c69SJohnny Huang 	if (data1_masked != buf1_masked)
51454552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
51554552c69SJohnny Huang 
51654552c69SJohnny Huang 	pass = 0;
51754552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
51854552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
51954552c69SJohnny Huang 			otp_soak(2);
52054552c69SJohnny Huang 			if (compare[0] != 0) {
52154552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
52254552c69SJohnny Huang 			}
52354552c69SJohnny Huang 			if (compare[1] != ~0) {
5245537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
52554552c69SJohnny Huang 			}
52654552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
52754552c69SJohnny Huang 				otp_soak(1);
52854552c69SJohnny Huang 			} else {
52954552c69SJohnny Huang 				pass = 1;
53054552c69SJohnny Huang 				break;
53154552c69SJohnny Huang 			}
53254552c69SJohnny Huang 		} else {
53354552c69SJohnny Huang 			pass = 1;
53454552c69SJohnny Huang 			break;
53554552c69SJohnny Huang 		}
53654552c69SJohnny Huang 	}
53754552c69SJohnny Huang 
53854552c69SJohnny Huang 	if (!pass) {
53954552c69SJohnny Huang 		otp_soak(0);
54054552c69SJohnny Huang 		return OTP_FAILURE;
54154552c69SJohnny Huang 	}
54254552c69SJohnny Huang 	return OTP_SUCCESS;
54354552c69SJohnny Huang }
54454552c69SJohnny Huang 
545541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
54676d13988SJohnny Huang {
54776d13988SJohnny Huang 	uint32_t OTPSTRAP_RAW[2];
5485010032bSJohnny Huang 	int strap_end;
54976d13988SJohnny Huang 	int i, j;
55076d13988SJohnny Huang 
5515010032bSJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
55276d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
55376d13988SJohnny Huang 			otpstrap[j].value = 0;
55476d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
55576d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
55676d13988SJohnny Huang 			otpstrap[j].protected = 0;
55776d13988SJohnny Huang 		}
5585010032bSJohnny Huang 		strap_end = 30;
5595010032bSJohnny Huang 	} else {
5605010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
5615010032bSJohnny Huang 			otpstrap[j].value = 0;
5625010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
5635010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
5645010032bSJohnny Huang 			otpstrap[j].reg_protected = 0;
5655010032bSJohnny Huang 			otpstrap[j].protected = 0;
5665010032bSJohnny Huang 		}
5675010032bSJohnny Huang 		strap_end = 28;
5685010032bSJohnny Huang 	}
56976d13988SJohnny Huang 
5705010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
57176d13988SJohnny Huang 		int option = (i - 16) / 2;
57276d13988SJohnny Huang 		otp_read_config(i, &OTPSTRAP_RAW[0]);
57376d13988SJohnny Huang 		otp_read_config(i + 1, &OTPSTRAP_RAW[1]);
57476d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
57576d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
57676d13988SJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
57776d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
57876d13988SJohnny Huang 			}
57976d13988SJohnny Huang 			if (bit_value == 1)
58076d13988SJohnny Huang 				otpstrap[j].remain_times --;
58176d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
58276d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
58376d13988SJohnny Huang 		}
58476d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
58576d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
58676d13988SJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
58776d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
58876d13988SJohnny Huang 			}
58976d13988SJohnny Huang 			if (bit_value == 1)
59076d13988SJohnny Huang 				otpstrap[j].remain_times --;
59176d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
59276d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
59376d13988SJohnny Huang 		}
59476d13988SJohnny Huang 	}
5955010032bSJohnny Huang 
5965010032bSJohnny Huang 	if (info_cb.version != OTP_AST2600A0) {
5975010032bSJohnny Huang 		otp_read_config(28, &OTPSTRAP_RAW[0]);
5985010032bSJohnny Huang 		otp_read_config(29, &OTPSTRAP_RAW[1]);
5995010032bSJohnny Huang 		for (j = 0; j < 32; j++) {
6005010032bSJohnny Huang 			if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
6015010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
6025010032bSJohnny Huang 		}
6035010032bSJohnny Huang 		for (j = 32; j < 64; j++) {
6045010032bSJohnny Huang 			if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
6055010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
6065010032bSJohnny Huang 		}
6075010032bSJohnny Huang 
6085010032bSJohnny Huang 	}
6095010032bSJohnny Huang 
61076d13988SJohnny Huang 	otp_read_config(30, &OTPSTRAP_RAW[0]);
61176d13988SJohnny Huang 	otp_read_config(31, &OTPSTRAP_RAW[1]);
61276d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
61376d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
61476d13988SJohnny Huang 			otpstrap[j].protected = 1;
61576d13988SJohnny Huang 	}
61676d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
61776d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
61876d13988SJohnny Huang 			otpstrap[j].protected = 1;
61976d13988SJohnny Huang 	}
62076d13988SJohnny Huang }
62176d13988SJohnny Huang 
622696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
62369d5fd8fSJohnny Huang {
62479e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
625696656c6SJohnny Huang 	uint32_t *OTPCFG = (uint32_t *)image_layout->conf;
626696656c6SJohnny Huang 	uint32_t *OTPCFG_IGNORE = (uint32_t *)image_layout->conf_ignore;
627b458cd62SJohnny Huang 	uint32_t mask;
628b458cd62SJohnny Huang 	uint32_t dw_offset;
629b458cd62SJohnny Huang 	uint32_t bit_offset;
630b458cd62SJohnny Huang 	uint32_t otp_value;
631696656c6SJohnny Huang 	uint32_t otp_ignore;
632b458cd62SJohnny Huang 	int fail = 0;
63373f11549SJohnny Huang 	char valid_bit[20];
63466f2f8e5SJohnny Huang 	int i;
63573f11549SJohnny Huang 	int j;
63666f2f8e5SJohnny Huang 
637737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
63866f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
6393cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
6403cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
6413cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
6423cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
643b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
644696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
645b458cd62SJohnny Huang 
646696656c6SJohnny Huang 		if (otp_ignore == mask) {
647b458cd62SJohnny Huang 			continue;
648696656c6SJohnny Huang 		} else if (otp_ignore != 0) {
649b458cd62SJohnny Huang 			fail = 1;
650b458cd62SJohnny Huang 		}
651b458cd62SJohnny Huang 
6523cb28812SJohnny Huang 		if ((otp_value != conf_info[i].value) &&
6533cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
6543cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
6553cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
656b458cd62SJohnny Huang 			continue;
657b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
658b458cd62SJohnny Huang 
6593cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
6603cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
66166f2f8e5SJohnny Huang 		} else {
662b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
6633cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
6643cb28812SJohnny Huang 			       conf_info[i].bit_offset);
66566f2f8e5SJohnny Huang 		}
666b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
667b458cd62SJohnny Huang 
668b458cd62SJohnny Huang 		if (fail) {
669696656c6SJohnny Huang 			printf("Ignore mask error\n");
670b458cd62SJohnny Huang 		} else {
6713cb28812SJohnny Huang 			if (conf_info[i].value == OTP_REG_RESERVED) {
672b458cd62SJohnny Huang 				printf("Reserved\n");
6733cb28812SJohnny Huang 			} else if (conf_info[i].value == OTP_REG_VALUE) {
6743cb28812SJohnny Huang 				printf(conf_info[i].information, otp_value);
675b458cd62SJohnny Huang 				printf("\n");
6763cb28812SJohnny Huang 			} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
677b458cd62SJohnny Huang 				if (otp_value != 0) {
67873f11549SJohnny Huang 					for (j = 0; j < 7; j++) {
67973f11549SJohnny Huang 						if (otp_value == (1 << j)) {
68073f11549SJohnny Huang 							valid_bit[j * 2] = '1';
681b458cd62SJohnny Huang 						} else {
68273f11549SJohnny Huang 							valid_bit[j * 2] = '0';
68373f11549SJohnny Huang 						}
68473f11549SJohnny Huang 						valid_bit[j * 2 + 1] = ' ';
68573f11549SJohnny Huang 					}
68673f11549SJohnny Huang 					valid_bit[15] = 0;
68773f11549SJohnny Huang 				} else {
68873f11549SJohnny Huang 					strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
689b458cd62SJohnny Huang 				}
6903cb28812SJohnny Huang 				printf(conf_info[i].information, valid_bit);
691b458cd62SJohnny Huang 				printf("\n");
692b458cd62SJohnny Huang 			} else {
6933cb28812SJohnny Huang 				printf("%s\n", conf_info[i].information);
694b458cd62SJohnny Huang 			}
695b458cd62SJohnny Huang 		}
696b458cd62SJohnny Huang 	}
697b458cd62SJohnny Huang 
698b458cd62SJohnny Huang 	if (fail)
699b458cd62SJohnny Huang 		return OTP_FAILURE;
700b458cd62SJohnny Huang 
70166f2f8e5SJohnny Huang 	return OTP_SUCCESS;
70266f2f8e5SJohnny Huang }
70366f2f8e5SJohnny Huang 
7042d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
70566f2f8e5SJohnny Huang {
70679e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
707bb34a7bfSJohnny Huang 	uint32_t OTPCFG[16];
708b458cd62SJohnny Huang 	uint32_t mask;
709b458cd62SJohnny Huang 	uint32_t dw_offset;
710b458cd62SJohnny Huang 	uint32_t bit_offset;
711b458cd62SJohnny Huang 	uint32_t otp_value;
71273f11549SJohnny Huang 	char valid_bit[20];
71366f2f8e5SJohnny Huang 	int i;
71473f11549SJohnny Huang 	int j;
71566f2f8e5SJohnny Huang 
716bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
71766f2f8e5SJohnny Huang 		otp_read_config(i, &OTPCFG[i]);
71866f2f8e5SJohnny Huang 
71966f2f8e5SJohnny Huang 
720b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
721b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
7223cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
7233cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
7242d4b0742SJohnny Huang 			continue;
7253cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
7263cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
7273cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
728b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
729b458cd62SJohnny Huang 
7303cb28812SJohnny Huang 		if ((otp_value != conf_info[i].value) &&
7313cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
7323cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
7333cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
734b458cd62SJohnny Huang 			continue;
735b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
736b458cd62SJohnny Huang 
7373cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
7383cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
739b458cd62SJohnny Huang 		} else {
740b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
7413cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
7423cb28812SJohnny Huang 			       conf_info[i].bit_offset);
743b458cd62SJohnny Huang 		}
744b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
745b458cd62SJohnny Huang 
7463cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
747b458cd62SJohnny Huang 			printf("Reserved\n");
7483cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
7493cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
750b458cd62SJohnny Huang 			printf("\n");
7513cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
752b458cd62SJohnny Huang 			if (otp_value != 0) {
75373f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
75473f11549SJohnny Huang 					if (otp_value == (1 << j)) {
75573f11549SJohnny Huang 						valid_bit[j * 2] = '1';
756b458cd62SJohnny Huang 					} else {
75773f11549SJohnny Huang 						valid_bit[j * 2] = '0';
75873f11549SJohnny Huang 					}
75973f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
76073f11549SJohnny Huang 				}
76173f11549SJohnny Huang 				valid_bit[15] = 0;
76273f11549SJohnny Huang 			} else {
76373f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
764b458cd62SJohnny Huang 			}
7653cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
766b458cd62SJohnny Huang 			printf("\n");
767b458cd62SJohnny Huang 		} else {
7683cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
769b458cd62SJohnny Huang 		}
770b458cd62SJohnny Huang 	}
771b458cd62SJohnny Huang 	return OTP_SUCCESS;
77266f2f8e5SJohnny Huang }
77366f2f8e5SJohnny Huang 
7745010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
77576d13988SJohnny Huang {
77679e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
777696656c6SJohnny Huang 	uint32_t *OTPSTRAP;
778696656c6SJohnny Huang 	uint32_t *OTPSTRAP_REG_PRO;
779696656c6SJohnny Huang 	uint32_t *OTPSTRAP_PRO;
780696656c6SJohnny Huang 	uint32_t *OTPSTRAP_IGNORE;
78176d13988SJohnny Huang 	int i;
782a8bd6d8cSJohnny Huang 	int fail = 0;
783a8bd6d8cSJohnny Huang 	uint32_t bit_offset;
784a8bd6d8cSJohnny Huang 	uint32_t dw_offset;
785a8bd6d8cSJohnny Huang 	uint32_t mask;
786a8bd6d8cSJohnny Huang 	uint32_t otp_value;
787696656c6SJohnny Huang 	uint32_t otp_reg_protect;
788a8bd6d8cSJohnny Huang 	uint32_t otp_protect;
789696656c6SJohnny Huang 	uint32_t otp_ignore;
79076d13988SJohnny Huang 
791696656c6SJohnny Huang 	OTPSTRAP = (uint32_t *)image_layout->strap;
792696656c6SJohnny Huang 	OTPSTRAP_PRO = (uint32_t *)image_layout->strap_pro;
793696656c6SJohnny Huang 	OTPSTRAP_IGNORE = (uint32_t *)image_layout->strap_ignore;
7945010032bSJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
795696656c6SJohnny Huang 		OTPSTRAP_REG_PRO = NULL;
796a8bd6d8cSJohnny Huang 		printf("BIT(hex)   Value       Protect     Description\n");
797696656c6SJohnny Huang 	} else {
798696656c6SJohnny Huang 		OTPSTRAP_REG_PRO = (uint32_t *)image_layout->strap_reg_pro;
799de6b0cc4SJohnny Huang 		printf("BIT(hex)   Value       Reg_Protect Protect     Description\n");
800696656c6SJohnny Huang 	}
801de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
802b458cd62SJohnny Huang 
8033cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
804696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
805a8bd6d8cSJohnny Huang 			dw_offset = 1;
8063cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
807a8bd6d8cSJohnny Huang 		} else {
808a8bd6d8cSJohnny Huang 			dw_offset = 0;
8093cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
810a8bd6d8cSJohnny Huang 		}
81176d13988SJohnny Huang 
8123cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
813a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
814a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
815696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
816a8bd6d8cSJohnny Huang 
8175010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0)
818696656c6SJohnny Huang 			otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask;
8195010032bSJohnny Huang 		else
8205010032bSJohnny Huang 			otp_reg_protect = 0;
821696656c6SJohnny Huang 
822696656c6SJohnny Huang 		if (otp_ignore == mask) {
823a8bd6d8cSJohnny Huang 			continue;
824696656c6SJohnny Huang 		} else if (otp_ignore != 0) {
825a8bd6d8cSJohnny Huang 			fail = 1;
826a8bd6d8cSJohnny Huang 		}
827a8bd6d8cSJohnny Huang 
8283cb28812SJohnny Huang 		if ((otp_value != strap_info[i].value) &&
8293cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
830a8bd6d8cSJohnny Huang 			continue;
831a8bd6d8cSJohnny Huang 
8323cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
8333cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
834a8bd6d8cSJohnny Huang 		} else {
835b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
8363cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
8373cb28812SJohnny Huang 			       strap_info[i].bit_offset);
838a8bd6d8cSJohnny Huang 		}
839a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
8405010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0)
841696656c6SJohnny Huang 			printf("0x%-10x", otp_reg_protect);
842a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
843a8bd6d8cSJohnny Huang 
844a8bd6d8cSJohnny Huang 		if (fail) {
845696656c6SJohnny Huang 			printf("Ignore mask error\n");
846a8bd6d8cSJohnny Huang 		} else {
8473cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
8483cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
849a8bd6d8cSJohnny Huang 			else
850a8bd6d8cSJohnny Huang 				printf("Reserved\n");
851a8bd6d8cSJohnny Huang 		}
852a8bd6d8cSJohnny Huang 	}
853a8bd6d8cSJohnny Huang 
854a8bd6d8cSJohnny Huang 	if (fail)
85576d13988SJohnny Huang 		return OTP_FAILURE;
85676d13988SJohnny Huang 
85776d13988SJohnny Huang 	return OTP_SUCCESS;
85876d13988SJohnny Huang }
85976d13988SJohnny Huang 
860b458cd62SJohnny Huang static int otp_print_strap_info(int view)
86176d13988SJohnny Huang {
86279e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
86376d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
86407baa4e8SJohnny Huang 	int i, j;
865b458cd62SJohnny Huang 	int fail = 0;
866b458cd62SJohnny Huang 	uint32_t bit_offset;
867b458cd62SJohnny Huang 	uint32_t length;
868b458cd62SJohnny Huang 	uint32_t otp_value;
869b458cd62SJohnny Huang 	uint32_t otp_protect;
87076d13988SJohnny Huang 
871541eb887SJohnny Huang 	otp_strap_status(strap_status);
87276d13988SJohnny Huang 
873b458cd62SJohnny Huang 	if (view) {
87483655e91SJohnny Huang 		if (info_cb.version == OTP_AST2600A0)
87507baa4e8SJohnny Huang 			printf("BIT(hex) Value  Remains  Protect   Description\n");
87683655e91SJohnny Huang 		else
87783655e91SJohnny Huang 			printf("BIT(hex) Value  Remains  Reg_Protect Protect   Description\n");
87807baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
879b458cd62SJohnny Huang 	} else {
880b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
881b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
88276d13988SJohnny Huang 	}
8833cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
884b458cd62SJohnny Huang 		otp_value = 0;
8853cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
8863cb28812SJohnny Huang 		length = strap_info[i].length;
887b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
888c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
889c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
890b458cd62SJohnny Huang 		}
8913cb28812SJohnny Huang 		if ((otp_value != strap_info[i].value) &&
8923cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
893b458cd62SJohnny Huang 			continue;
894b458cd62SJohnny Huang 		if (view) {
895b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
8963cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
897b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
89807baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
89983655e91SJohnny Huang 				if (info_cb.version != OTP_AST2600A0)
900e1a7245eSJohnny Huang 					printf("0x%-10X", strap_status[bit_offset + j].reg_protected);
901e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
9023cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
903b458cd62SJohnny Huang 					printf(" Reserved\n");
904b458cd62SJohnny Huang 					continue;
905b458cd62SJohnny Huang 				}
906b458cd62SJohnny Huang 				if (length == 1) {
9073cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
908b458cd62SJohnny Huang 					continue;
90976d13988SJohnny Huang 				}
91076d13988SJohnny Huang 
911b458cd62SJohnny Huang 				if (j == 0)
9123cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
913b458cd62SJohnny Huang 				else if (j == length - 1)
914b458cd62SJohnny Huang 					printf("\\ \"\n");
915b458cd62SJohnny Huang 				else
916b458cd62SJohnny Huang 					printf("| \"\n");
91776d13988SJohnny Huang 			}
918b458cd62SJohnny Huang 		} else {
919c947ef08SJohnny Huang 			if (length == 1) {
9203cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
921b458cd62SJohnny Huang 			} else {
922b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
923b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
924b458cd62SJohnny Huang 			}
925b458cd62SJohnny Huang 
926b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
927b458cd62SJohnny Huang 
9283cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
9293cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
930b458cd62SJohnny Huang 			else
931b458cd62SJohnny Huang 				printf("Reserved\n");
932b458cd62SJohnny Huang 		}
933b458cd62SJohnny Huang 	}
934b458cd62SJohnny Huang 
935b458cd62SJohnny Huang 	if (fail)
936b458cd62SJohnny Huang 		return OTP_FAILURE;
937b458cd62SJohnny Huang 
938b458cd62SJohnny Huang 	return OTP_SUCCESS;
939b458cd62SJohnny Huang }
940b458cd62SJohnny Huang 
941696656c6SJohnny Huang static void buf_print(uint8_t *buf, int len)
94269d5fd8fSJohnny Huang {
94369d5fd8fSJohnny Huang 	int i;
94469d5fd8fSJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
94569d5fd8fSJohnny Huang 	for (i = 0; i < len; i++) {
94669d5fd8fSJohnny Huang 		if (i % 16 == 0) {
94769d5fd8fSJohnny Huang 			printf("%04X: ", i);
94869d5fd8fSJohnny Huang 		}
94969d5fd8fSJohnny Huang 		printf("%02X ", buf[i]);
95069d5fd8fSJohnny Huang 		if ((i + 1) % 16 == 0) {
95169d5fd8fSJohnny Huang 			printf("\n");
95269d5fd8fSJohnny Huang 		}
95369d5fd8fSJohnny Huang 	}
95469d5fd8fSJohnny Huang }
95569d5fd8fSJohnny Huang 
956696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout)
95769d5fd8fSJohnny Huang {
95869d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
95979e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
9609a4fe690SJohnny Huang 	struct otpkey_type key_info;
961696656c6SJohnny Huang 	uint32_t *buf;
962696656c6SJohnny Huang 	uint8_t *byte_buf;
9639d998018SJohnny Huang 	char empty = 1;
96469d5fd8fSJohnny Huang 	int i = 0, len = 0;
9659a4fe690SJohnny Huang 	int j;
96654552c69SJohnny Huang 
967696656c6SJohnny Huang 	byte_buf = image_layout->data;
968696656c6SJohnny Huang 	buf = (uint32_t *)byte_buf;
9699d998018SJohnny Huang 
9709d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
9719d998018SJohnny Huang 		if (buf[i] != 0) {
9729d998018SJohnny Huang 			empty = 0;
9739d998018SJohnny Huang 		}
9749d998018SJohnny Huang 	}
9759d998018SJohnny Huang 	if (empty)
9769d998018SJohnny Huang 		return 0;
9779d998018SJohnny Huang 
9789d998018SJohnny Huang 	i = 0;
97969d5fd8fSJohnny Huang 	while (1) {
98069d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
98169d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
98269d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
98369d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
98469d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
98569d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
9869a4fe690SJohnny Huang 
9879a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
9889a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
9899a4fe690SJohnny Huang 				key_info = key_info_array[j];
9909a4fe690SJohnny Huang 				break;
9919a4fe690SJohnny Huang 			}
9929a4fe690SJohnny Huang 		}
9939a4fe690SJohnny Huang 
9947f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
99569d5fd8fSJohnny Huang 		printf("Key Type: ");
9969a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
9979a4fe690SJohnny Huang 
9989a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
99969d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
100069d5fd8fSJohnny Huang 			switch (key_length) {
100169d5fd8fSJohnny Huang 			case 0:
100269d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
100369d5fd8fSJohnny Huang 				break;
100469d5fd8fSJohnny Huang 			case 1:
100569d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
100669d5fd8fSJohnny Huang 				break;
100769d5fd8fSJohnny Huang 			case 2:
100869d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
100969d5fd8fSJohnny Huang 				break;
101069d5fd8fSJohnny Huang 			case 3:
101169d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
101269d5fd8fSJohnny Huang 				break;
101369d5fd8fSJohnny Huang 			}
10149a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA) {
101569d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
101669d5fd8fSJohnny Huang 			switch (key_length) {
101769d5fd8fSJohnny Huang 			case 0:
101869d5fd8fSJohnny Huang 				printf("RSA1024\n");
101969d5fd8fSJohnny Huang 				len = 0x100;
102069d5fd8fSJohnny Huang 				break;
102169d5fd8fSJohnny Huang 			case 1:
102269d5fd8fSJohnny Huang 				printf("RSA2048\n");
102369d5fd8fSJohnny Huang 				len = 0x200;
102469d5fd8fSJohnny Huang 				break;
102569d5fd8fSJohnny Huang 			case 2:
102669d5fd8fSJohnny Huang 				printf("RSA3072\n");
102769d5fd8fSJohnny Huang 				len = 0x300;
102869d5fd8fSJohnny Huang 				break;
102969d5fd8fSJohnny Huang 			case 3:
103069d5fd8fSJohnny Huang 				printf("RSA4096\n");
103169d5fd8fSJohnny Huang 				len = 0x400;
103269d5fd8fSJohnny Huang 				break;
103369d5fd8fSJohnny Huang 			}
103469d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
103569d5fd8fSJohnny Huang 		}
10369a4fe690SJohnny Huang 		if (key_info.need_id)
103769d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
103869d5fd8fSJohnny Huang 		printf("Key Value:\n");
10399a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
104069d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
10419a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
10429a4fe690SJohnny Huang 			printf("AES Key:\n");
10439a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
10445fdde29fSJohnny Huang 			if (info_cb.version == OTP_AST2600A0) {
10459a4fe690SJohnny Huang 				printf("AES IV:\n");
10469a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
10479a4fe690SJohnny Huang 			}
10489a4fe690SJohnny Huang 
10499a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
10505fdde29fSJohnny Huang 			if (info_cb.version == OTP_AST2600A0) {
105169d5fd8fSJohnny Huang 				printf("AES Key:\n");
105269d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
105369d5fd8fSJohnny Huang 				printf("AES IV:\n");
105469d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
10555fdde29fSJohnny Huang 			} else {
10569a4fe690SJohnny Huang 				printf("AES Key 1:\n");
10579a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
10589a4fe690SJohnny Huang 				printf("AES Key 2:\n");
10599a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
10609a4fe690SJohnny Huang 			}
106169d5fd8fSJohnny Huang 
10629a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA) {
106369d5fd8fSJohnny Huang 			printf("RSA mod:\n");
106469d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
106569d5fd8fSJohnny Huang 			printf("RSA exp:\n");
106669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
106769d5fd8fSJohnny Huang 		}
106869d5fd8fSJohnny Huang 		if (last)
106969d5fd8fSJohnny Huang 			break;
107069d5fd8fSJohnny Huang 		i++;
107169d5fd8fSJohnny Huang 	}
107269d5fd8fSJohnny Huang 	return 0;
107369d5fd8fSJohnny Huang }
107469d5fd8fSJohnny Huang 
10755010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout)
107669d5fd8fSJohnny Huang {
1077a6d0d645SJohnny Huang 	int i, k;
1078d90825e2SJohnny Huang 	int pass = 0;
1079a6d0d645SJohnny Huang 	uint32_t prog_address;
1080bb34a7bfSJohnny Huang 	uint32_t data[16];
1081a6d0d645SJohnny Huang 	uint32_t compare[2];
10825010032bSJohnny Huang 	uint32_t *conf = (uint32_t *)image_layout->conf;
10835010032bSJohnny Huang 	uint32_t *conf_ignore = (uint32_t *)image_layout->conf_ignore;
1084d90825e2SJohnny Huang 	uint32_t data_masked;
1085d90825e2SJohnny Huang 	uint32_t buf_masked;
108669d5fd8fSJohnny Huang 
1087a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1088a6d0d645SJohnny Huang 
1089bb34a7bfSJohnny Huang 	for (i = 0; i < 16 ; i ++) {
109069d5fd8fSJohnny Huang 		prog_address = 0x800;
1091a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1092a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1093a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1094a6d0d645SJohnny Huang 	}
1095a6d0d645SJohnny Huang 
1096a6d0d645SJohnny Huang 	printf("Check writable...\n");
1097bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
10985010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
10995010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1100d90825e2SJohnny Huang 		if (data_masked == buf_masked)
110169d5fd8fSJohnny Huang 			continue;
1102d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1103a6d0d645SJohnny Huang 			continue;
1104a6d0d645SJohnny Huang 		} else {
1105a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1106a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
11075010032bSJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
11085010032bSJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
11092a856b9aSJohnny Huang 			return OTP_FAILURE;
1110a6d0d645SJohnny Huang 		}
1111a6d0d645SJohnny Huang 	}
1112a6d0d645SJohnny Huang 
1113a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1114d90825e2SJohnny Huang 	otp_soak(0);
1115bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
11165010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
11175010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1118a6d0d645SJohnny Huang 		prog_address = 0x800;
1119a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1120a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1121bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1122bb34a7bfSJohnny Huang 			pass = 1;
1123a6d0d645SJohnny Huang 			continue;
1124bb34a7bfSJohnny Huang 		}
1125de6fbf1cSJohnny Huang 
1126a6d0d645SJohnny Huang 
1127de6fbf1cSJohnny Huang 		otp_soak(1);
11285010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1129a6d0d645SJohnny Huang 
113069d5fd8fSJohnny Huang 		pass = 0;
113169d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
11325010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1133de6fbf1cSJohnny Huang 				otp_soak(2);
1134a6d0d645SJohnny Huang 				otp_prog_dw(compare[0], prog_address, 1);
11355010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1136de6fbf1cSJohnny Huang 					otp_soak(1);
1137de6fbf1cSJohnny Huang 				} else {
1138de6fbf1cSJohnny Huang 					pass = 1;
1139de6fbf1cSJohnny Huang 					break;
1140de6fbf1cSJohnny Huang 				}
1141a6d0d645SJohnny Huang 			} else {
114269d5fd8fSJohnny Huang 				pass = 1;
114369d5fd8fSJohnny Huang 				break;
114469d5fd8fSJohnny Huang 			}
114569d5fd8fSJohnny Huang 		}
1146bb34a7bfSJohnny Huang 		if (pass == 0) {
1147bb34a7bfSJohnny Huang 			printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
11485010032bSJohnny Huang 			       i, data[i], conf[i], conf_ignore[i]);
1149bb34a7bfSJohnny Huang 			break;
1150bb34a7bfSJohnny Huang 		}
1151a6d0d645SJohnny Huang 	}
1152a6d0d645SJohnny Huang 
1153de6fbf1cSJohnny Huang 	otp_soak(0);
115469d5fd8fSJohnny Huang 	if (!pass)
11552a856b9aSJohnny Huang 		return OTP_FAILURE;
1156a6d0d645SJohnny Huang 
11572a856b9aSJohnny Huang 	return OTP_SUCCESS;
1158d90825e2SJohnny Huang 
115969d5fd8fSJohnny Huang }
116069d5fd8fSJohnny Huang 
1161eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit)
1162eda10d61SJohnny Huang {
1163eda10d61SJohnny Huang 	if (ibit == 1) {
1164eda10d61SJohnny Huang 		return OTP_SUCCESS;
1165eda10d61SJohnny Huang 	} else {
1166eda10d61SJohnny Huang 		printf("OTPSTRAP[%X]:\n", offset);
1167eda10d61SJohnny Huang 	}
1168eda10d61SJohnny Huang 	if (bit == otpstrap->value) {
1169eda10d61SJohnny Huang 		printf("    The value is same as before, skip it.\n");
1170eda10d61SJohnny Huang 		return OTP_PROG_SKIP;
1171eda10d61SJohnny Huang 	}
1172eda10d61SJohnny Huang 	if (otpstrap->protected == 1) {
1173eda10d61SJohnny Huang 		printf("    This bit is protected and is not writable\n");
1174eda10d61SJohnny Huang 		return OTP_FAILURE;
1175eda10d61SJohnny Huang 	}
1176eda10d61SJohnny Huang 	if (otpstrap->remain_times == 0) {
1177eda10d61SJohnny Huang 		printf("    This bit is no remaining times to write.\n");
1178eda10d61SJohnny Huang 		return OTP_FAILURE;
1179eda10d61SJohnny Huang 	}
1180eda10d61SJohnny Huang 	if (pbit == 1) {
1181eda10d61SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
1182eda10d61SJohnny Huang 	}
1183eda10d61SJohnny Huang 	if (rpbit == 1 && info_cb.version != OTP_AST2600A0) {
1184eda10d61SJohnny Huang 		printf("    The relative register will be protected.\n");
1185eda10d61SJohnny Huang 	}
1186eda10d61SJohnny 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);
1187eda10d61SJohnny Huang 	return OTP_SUCCESS;
1188eda10d61SJohnny Huang }
1189eda10d61SJohnny Huang 
11905010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
119169d5fd8fSJohnny Huang {
119269d5fd8fSJohnny Huang 	int i;
11935010032bSJohnny Huang 	uint32_t *strap;
11945010032bSJohnny Huang 	uint32_t *strap_ignore;
11955010032bSJohnny Huang 	uint32_t *strap_reg_protect;
11965010032bSJohnny Huang 	uint32_t *strap_pro;
1197eda10d61SJohnny Huang 	int bit, pbit, ibit, rpbit;
119869d5fd8fSJohnny Huang 	int fail = 0;
1199a6af4a17SJohnny Huang 	int skip = -1;
1200eda10d61SJohnny Huang 	int ret;
120166f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
120269d5fd8fSJohnny Huang 
12035010032bSJohnny Huang 	strap = (uint32_t *)image_layout->strap;
12045010032bSJohnny Huang 	strap_pro = (uint32_t *)image_layout->strap_pro;
12055010032bSJohnny Huang 	strap_ignore = (uint32_t *)image_layout->strap_ignore;
12065010032bSJohnny Huang 	strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro;
12075010032bSJohnny Huang 
1208541eb887SJohnny Huang 	otp_strap_status(otpstrap);
120969d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
121069d5fd8fSJohnny Huang 		if (i < 32) {
12115010032bSJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1212eda10d61SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
12135010032bSJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
121469d5fd8fSJohnny Huang 		} else {
12155010032bSJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1216eda10d61SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
12175010032bSJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
12185010032bSJohnny Huang 		}
12195010032bSJohnny Huang 
12205010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0) {
12215010032bSJohnny Huang 			if (i < 32) {
12225010032bSJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
12235010032bSJohnny Huang 			} else {
12245010032bSJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
12255010032bSJohnny Huang 			}
12265010032bSJohnny Huang 		} else {
12275010032bSJohnny Huang 			rpbit = 0;
122869d5fd8fSJohnny Huang 		}
1229eda10d61SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit);
1230eda10d61SJohnny Huang 		if (ret == OTP_PROG_SKIP) {
1231a6af4a17SJohnny Huang 			if (skip == -1)
1232a6af4a17SJohnny Huang 				skip = 1;
123369d5fd8fSJohnny Huang 			continue;
1234a6af4a17SJohnny Huang 		} else {
1235eda10d61SJohnny Huang 			skip = 1;
123669d5fd8fSJohnny Huang 		}
1237eda10d61SJohnny Huang 
1238eda10d61SJohnny Huang 		if (ret == OTP_FAILURE)
123969d5fd8fSJohnny Huang 			fail = 1;
124069d5fd8fSJohnny Huang 	}
124169d5fd8fSJohnny Huang 	if (fail == 1)
1242a6af4a17SJohnny Huang 		return OTP_FAILURE;
1243a6af4a17SJohnny Huang 	else if (skip == 1)
1244a6af4a17SJohnny Huang 		return OTP_PROG_SKIP;
12457e22f42dSJohnny Huang 
1246eda10d61SJohnny Huang 	return OTP_SUCCESS;
124769d5fd8fSJohnny Huang }
124869d5fd8fSJohnny Huang 
12492a856b9aSJohnny Huang static int otp_print_strap(int start, int count)
125069d5fd8fSJohnny Huang {
125169d5fd8fSJohnny Huang 	int i, j;
1252de6b0cc4SJohnny Huang 	int remains;
125366f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
125469d5fd8fSJohnny Huang 
12552a856b9aSJohnny Huang 	if (start < 0 || start > 64)
12562a856b9aSJohnny Huang 		return OTP_USAGE;
12572a856b9aSJohnny Huang 
12582a856b9aSJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
12592a856b9aSJohnny Huang 		return OTP_USAGE;
12602a856b9aSJohnny Huang 
1261541eb887SJohnny Huang 	otp_strap_status(otpstrap);
126269d5fd8fSJohnny Huang 
1263de6b0cc4SJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
1264de6b0cc4SJohnny Huang 		remains = 7;
126507baa4e8SJohnny Huang 		printf("BIT(hex)  Value  Option           Status\n");
1266de6b0cc4SJohnny Huang 	} else {
1267de6b0cc4SJohnny Huang 		remains = 6;
1268de6b0cc4SJohnny Huang 		printf("BIT(hex)  Value  Option         Reg_Protect Status\n");
1269de6b0cc4SJohnny Huang 	}
1270de6b0cc4SJohnny Huang 	printf("______________________________________________________________________________\n");
1271737ed20bSJohnny Huang 
1272cd1610b4SJohnny Huang 	for (i = start; i < start + count; i++) {
127307baa4e8SJohnny Huang 		printf("0x%-8X", i);
1274737ed20bSJohnny Huang 		printf("%-7d", otpstrap[i].value);
1275de6b0cc4SJohnny Huang 		for (j = 0; j < remains; j++)
1276737ed20bSJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
1277737ed20bSJohnny Huang 		printf("   ");
1278de6b0cc4SJohnny Huang 		if (info_cb.version != OTP_AST2600A0) {
1279de6b0cc4SJohnny Huang 			printf("%d           ", otpstrap[i].reg_protected);
1280de6b0cc4SJohnny Huang 		}
128169d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
1282737ed20bSJohnny Huang 			printf("protected and not writable");
128369d5fd8fSJohnny Huang 		} else {
1284737ed20bSJohnny Huang 			printf("not protected ");
128569d5fd8fSJohnny Huang 			if (otpstrap[i].remain_times == 0) {
1286737ed20bSJohnny Huang 				printf("and no remaining times to write.");
128769d5fd8fSJohnny Huang 			} else {
1288737ed20bSJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
128969d5fd8fSJohnny Huang 			}
129069d5fd8fSJohnny Huang 		}
1291737ed20bSJohnny Huang 		printf("\n");
129269d5fd8fSJohnny Huang 	}
12932a856b9aSJohnny Huang 
12942a856b9aSJohnny Huang 	return OTP_SUCCESS;
129569d5fd8fSJohnny Huang }
129669d5fd8fSJohnny Huang 
12978848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value)
12988848d5dcSJohnny Huang {
12998848d5dcSJohnny Huang 	struct otpstrap_status otpstrap[64];
130083655e91SJohnny Huang 	uint32_t prog_address;
13018848d5dcSJohnny Huang 	int offset;
13028848d5dcSJohnny Huang 	int ret;
13038848d5dcSJohnny Huang 
13048848d5dcSJohnny Huang 
13058848d5dcSJohnny Huang 	otp_strap_status(otpstrap);
13068848d5dcSJohnny Huang 
13078848d5dcSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
13088848d5dcSJohnny Huang 
13098848d5dcSJohnny Huang 	if (ret != OTP_SUCCESS) {
13108848d5dcSJohnny Huang 		return ret;
13118848d5dcSJohnny Huang 	}
13128848d5dcSJohnny Huang 
13138848d5dcSJohnny Huang 	prog_address = 0x800;
13148848d5dcSJohnny Huang 	if (bit_offset < 32) {
13158848d5dcSJohnny Huang 		offset = bit_offset;
13168848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
13178848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
13188848d5dcSJohnny Huang 
13198848d5dcSJohnny Huang 	} else {
13208848d5dcSJohnny Huang 		offset = (bit_offset - 32);
13218848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
13228848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
13238848d5dcSJohnny Huang 	}
13248848d5dcSJohnny Huang 
13258848d5dcSJohnny Huang 
132683655e91SJohnny Huang 	return otp_prog_bit(1, prog_address, offset);
13278848d5dcSJohnny Huang }
13288848d5dcSJohnny Huang 
13295010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout)
133069d5fd8fSJohnny Huang {
13315010032bSJohnny Huang 	uint32_t *strap;
13325010032bSJohnny Huang 	uint32_t *strap_ignore;
13335010032bSJohnny Huang 	uint32_t *strap_pro;
13345010032bSJohnny Huang 	uint32_t *strap_reg_protect;
133583655e91SJohnny Huang 	uint32_t prog_address;
133683655e91SJohnny Huang 	int i;
1337eda10d61SJohnny Huang 	int bit, pbit, ibit, offset, rpbit;
133869d5fd8fSJohnny Huang 	int fail = 0;
133983655e91SJohnny Huang 	int ret;
134066f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
134169d5fd8fSJohnny Huang 
13425010032bSJohnny Huang 	strap = (uint32_t *)image_layout->strap;
13435010032bSJohnny Huang 	strap_pro = (uint32_t *)image_layout->strap_pro;
13445010032bSJohnny Huang 	strap_ignore = (uint32_t *)image_layout->strap_ignore;
13455010032bSJohnny Huang 	strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro;
13465010032bSJohnny Huang 
13477f795e57SJohnny Huang 	printf("Read OTP Strap Region:\n");
1348541eb887SJohnny Huang 	otp_strap_status(otpstrap);
134969d5fd8fSJohnny Huang 
13507f795e57SJohnny Huang 	printf("Check writable...\n");
13515010032bSJohnny Huang 	if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
13527f795e57SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
13537f795e57SJohnny Huang 		return OTP_FAILURE;
13547f795e57SJohnny Huang 	}
13557e22f42dSJohnny Huang 
135669d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
135769d5fd8fSJohnny Huang 		prog_address = 0x800;
135869d5fd8fSJohnny Huang 		if (i < 32) {
135969d5fd8fSJohnny Huang 			offset = i;
13605010032bSJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1361eda10d61SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
13625010032bSJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
136369d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
136469d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
136569d5fd8fSJohnny Huang 
136669d5fd8fSJohnny Huang 		} else {
136769d5fd8fSJohnny Huang 			offset = (i - 32);
13685010032bSJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1369eda10d61SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
13705010032bSJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
137169d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
137269d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
137369d5fd8fSJohnny Huang 		}
13745010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0) {
13755010032bSJohnny Huang 			if (i < 32) {
13765010032bSJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
13775010032bSJohnny Huang 			} else {
13785010032bSJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
13795010032bSJohnny Huang 			}
13805010032bSJohnny Huang 		} else {
13815010032bSJohnny Huang 			rpbit = 0;
13825010032bSJohnny Huang 		}
138369d5fd8fSJohnny Huang 
1384eda10d61SJohnny Huang 		if (ibit == 1) {
138569d5fd8fSJohnny Huang 			continue;
138669d5fd8fSJohnny Huang 		}
138769d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
138869d5fd8fSJohnny Huang 			continue;
138969d5fd8fSJohnny Huang 		}
139069d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
139169d5fd8fSJohnny Huang 			fail = 1;
139269d5fd8fSJohnny Huang 			continue;
139369d5fd8fSJohnny Huang 		}
139469d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
139569d5fd8fSJohnny Huang 			fail = 1;
139669d5fd8fSJohnny Huang 			continue;
139769d5fd8fSJohnny Huang 		}
13987e22f42dSJohnny Huang 
139983655e91SJohnny Huang 		ret = otp_prog_bit(1, prog_address, offset);
140083655e91SJohnny Huang 		if (!ret)
14012a856b9aSJohnny Huang 			return OTP_FAILURE;
140269d5fd8fSJohnny Huang 
14035010032bSJohnny Huang 		if (rpbit == 1 && info_cb.version != OTP_AST2600A0) {
140469d5fd8fSJohnny Huang 			prog_address = 0x800;
140569d5fd8fSJohnny Huang 			if (i < 32)
14065010032bSJohnny Huang 				prog_address |= 0x608;
140769d5fd8fSJohnny Huang 			else
14085010032bSJohnny Huang 				prog_address |= 0x60a;
14097e22f42dSJohnny Huang 
141083655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
141183655e91SJohnny Huang 			if (!ret)
14122a856b9aSJohnny Huang 				return OTP_FAILURE;
14135010032bSJohnny Huang 		}
14145010032bSJohnny Huang 
14155010032bSJohnny Huang 		if (pbit != 0) {
14165010032bSJohnny Huang 			prog_address = 0x800;
14175010032bSJohnny Huang 			if (i < 32)
14185010032bSJohnny Huang 				prog_address |= 0x60c;
14195010032bSJohnny Huang 			else
14205010032bSJohnny Huang 				prog_address |= 0x60e;
14215010032bSJohnny Huang 
142283655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
142383655e91SJohnny Huang 			if (!ret)
14245010032bSJohnny Huang 				return OTP_FAILURE;
14255010032bSJohnny Huang 		}
142669d5fd8fSJohnny Huang 
142769d5fd8fSJohnny Huang 	}
1428de6fbf1cSJohnny Huang 	otp_soak(0);
142969d5fd8fSJohnny Huang 	if (fail == 1)
14302a856b9aSJohnny Huang 		return OTP_FAILURE;
143169d5fd8fSJohnny Huang 	else
14322a856b9aSJohnny Huang 		return OTP_SUCCESS;
143369d5fd8fSJohnny Huang 
143469d5fd8fSJohnny Huang }
143569d5fd8fSJohnny Huang 
14365010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout)
14374c1c9b35SJohnny Huang {
143854552c69SJohnny Huang 	int i;
143954552c69SJohnny Huang 	int ret;
14405010032bSJohnny Huang 	int data_dw;
1441d90825e2SJohnny Huang 	uint32_t data[2048];
14425010032bSJohnny Huang 	uint32_t *buf;
14435010032bSJohnny Huang 	uint32_t *buf_ignore;
14444c1c9b35SJohnny Huang 
144554552c69SJohnny Huang 	uint32_t data_masked;
144654552c69SJohnny Huang 	uint32_t buf_masked;
14474c1c9b35SJohnny Huang 
14485010032bSJohnny Huang 	buf = (uint32_t *)image_layout->data;
14495010032bSJohnny Huang 	buf_ignore = (uint32_t *)image_layout->data_ignore;
14505010032bSJohnny Huang 
14515010032bSJohnny Huang 	data_dw = image_layout->data_length / 4;
14525010032bSJohnny Huang 
14534c1c9b35SJohnny Huang 	printf("Read OTP Data:\n");
14544c1c9b35SJohnny Huang 
14555010032bSJohnny Huang 	for (i = 0; i < data_dw - 2 ; i += 2) {
1456d90825e2SJohnny Huang 		otp_read_data(i, &data[i]);
14574c1c9b35SJohnny Huang 	}
1458d90825e2SJohnny Huang 
14594c1c9b35SJohnny Huang 	printf("Check writable...\n");
146054552c69SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
14615010032bSJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1462696656c6SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1463696656c6SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
146454552c69SJohnny Huang 		if (data_masked == buf_masked)
14654c1c9b35SJohnny Huang 			continue;
1466d90825e2SJohnny Huang 		if (i % 2 == 0) {
146754552c69SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
14684c1c9b35SJohnny Huang 				continue;
14694c1c9b35SJohnny Huang 			} else {
14704c1c9b35SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1471d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
14724c1c9b35SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1473696656c6SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
14742a856b9aSJohnny Huang 				return OTP_FAILURE;
147569d5fd8fSJohnny Huang 			}
1476d90825e2SJohnny Huang 		} else {
147754552c69SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1478d90825e2SJohnny Huang 				continue;
1479d90825e2SJohnny Huang 			} else {
1480d90825e2SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1481d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1482d90825e2SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1483696656c6SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
14842a856b9aSJohnny Huang 				return OTP_FAILURE;
1485d90825e2SJohnny Huang 			}
1486d90825e2SJohnny Huang 		}
1487d90825e2SJohnny Huang 	}
148869d5fd8fSJohnny Huang 
1489d90825e2SJohnny Huang 	printf("Start Programing...\n");
1490d90825e2SJohnny Huang 
149154552c69SJohnny Huang 	// programing ecc region first
149254552c69SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1493696656c6SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
149454552c69SJohnny Huang 		if (ret != OTP_SUCCESS) {
149554552c69SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1496696656c6SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
149754552c69SJohnny Huang 			return ret;
1498d90825e2SJohnny Huang 		}
1499d90825e2SJohnny Huang 	}
1500d90825e2SJohnny Huang 
150154552c69SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1502696656c6SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
150354552c69SJohnny Huang 		if (ret != OTP_SUCCESS) {
150454552c69SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1505696656c6SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
150654552c69SJohnny Huang 			return ret;
1507d90825e2SJohnny Huang 		}
1508de6fbf1cSJohnny Huang 	}
1509de6fbf1cSJohnny Huang 	otp_soak(0);
15102a856b9aSJohnny Huang 	return OTP_SUCCESS;
1511d90825e2SJohnny Huang 
1512d90825e2SJohnny Huang }
1513d90825e2SJohnny Huang 
1514696656c6SJohnny Huang static int otp_image_verify(uint8_t *src_buf, uint32_t length, uint8_t *digest_buf)
1515696656c6SJohnny Huang {
1516696656c6SJohnny Huang 	sha256_context ctx;
1517696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1518696656c6SJohnny Huang 
1519696656c6SJohnny Huang 	sha256_starts(&ctx);
1520696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1521696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1522696656c6SJohnny Huang 
1523696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1524696656c6SJohnny Huang 		return 0;
1525696656c6SJohnny Huang 	else
1526696656c6SJohnny Huang 		return -1;
1527696656c6SJohnny Huang 
1528696656c6SJohnny Huang }
1529696656c6SJohnny Huang 
1530de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm)
153169d5fd8fSJohnny Huang {
153269d5fd8fSJohnny Huang 	int ret;
15339a4fe690SJohnny Huang 	int image_version = 0;
1534696656c6SJohnny Huang 	struct otp_header *otp_header;
1535696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1536696656c6SJohnny Huang 	int image_size;
1537696656c6SJohnny Huang 	uint8_t *buf;
1538696656c6SJohnny Huang 	uint8_t *checksum;
153969d5fd8fSJohnny Huang 
1540696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1541696656c6SJohnny Huang 	if (!otp_header) {
154269d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
15432a856b9aSJohnny Huang 		return OTP_FAILURE;
154469d5fd8fSJohnny Huang 	}
1545d90825e2SJohnny Huang 
1546696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1547696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1548696656c6SJohnny Huang 
1549696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1550696656c6SJohnny Huang 
1551696656c6SJohnny Huang 	if (!buf) {
1552696656c6SJohnny Huang 		puts("Failed to map physical memory\n");
1553696656c6SJohnny Huang 		return OTP_FAILURE;
1554696656c6SJohnny Huang 	}
1555696656c6SJohnny Huang 	otp_header = (struct otp_header *) buf;
1556696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1557696656c6SJohnny Huang 
1558696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1559696656c6SJohnny Huang 		puts("Image is invalid\n");
1560696656c6SJohnny Huang 		return OTP_FAILURE;
1561696656c6SJohnny Huang 	}
1562696656c6SJohnny Huang 
1563696656c6SJohnny Huang 
15645010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
15655010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
15665010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
15675010032bSJohnny Huang 
15685010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1569696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
15705010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1571696656c6SJohnny Huang 
1572696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
1573696656c6SJohnny Huang 
1574696656c6SJohnny Huang 	if (!strcmp("A0", (char *)otp_header->otp_version)) {
1575696656c6SJohnny Huang 		image_version = OTP_AST2600A0;
15765010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
15775010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
15785010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
1579696656c6SJohnny Huang 	} else if (!strcmp("A1", (char *)otp_header->otp_version)) {
1580696656c6SJohnny Huang 		image_version = OTP_AST2600A1;
15815010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
15825010032bSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
15835010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
15845010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
15855fdde29fSJohnny Huang 	} else if (!strcmp("A2", (char *)otp_header->otp_version)) {
15865fdde29fSJohnny Huang 		image_version = OTP_AST2600A2;
15875fdde29fSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
15885fdde29fSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
15895fdde29fSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
15905fdde29fSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
1591696656c6SJohnny Huang 	} else {
1592696656c6SJohnny Huang 		puts("Version is not supported\n");
1593696656c6SJohnny Huang 		return OTP_FAILURE;
1594696656c6SJohnny Huang 	}
1595696656c6SJohnny Huang 
15969a4fe690SJohnny Huang 	if (image_version != info_cb.version) {
15979a4fe690SJohnny Huang 		puts("Version is not match\n");
15989a4fe690SJohnny Huang 		return OTP_FAILURE;
15999a4fe690SJohnny Huang 	}
16009a4fe690SJohnny Huang 
1601696656c6SJohnny Huang 	if (otp_image_verify(buf, image_size, checksum)) {
1602696656c6SJohnny Huang 		puts("checksum is invalid\n");
1603696656c6SJohnny Huang 		return OTP_FAILURE;
1604d90825e2SJohnny Huang 	}
16057332532cSJohnny Huang 
160669d5fd8fSJohnny Huang 	if (!nconfirm) {
1607696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
16087f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1609696656c6SJohnny Huang 			if (otp_print_data_info(&image_layout) < 0) {
161069d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
16112a856b9aSJohnny Huang 				return OTP_FAILURE;
161269d5fd8fSJohnny Huang 			}
161369d5fd8fSJohnny Huang 		}
1614696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
16157332532cSJohnny Huang 			printf("\nOTP strap region :\n");
16165010032bSJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
16177332532cSJohnny Huang 				printf("OTP strap error, please check.\n");
16187332532cSJohnny Huang 				return OTP_FAILURE;
16197332532cSJohnny Huang 			}
16207332532cSJohnny Huang 		}
1621696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
16227332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1623696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
16247332532cSJohnny Huang 				printf("OTP config error, please check.\n");
16257332532cSJohnny Huang 				return OTP_FAILURE;
16267332532cSJohnny Huang 			}
16277332532cSJohnny Huang 		}
16287332532cSJohnny Huang 
162969d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
163069d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
163169d5fd8fSJohnny Huang 			printf(" Aborting\n");
16322a856b9aSJohnny Huang 			return OTP_FAILURE;
163369d5fd8fSJohnny Huang 		}
163469d5fd8fSJohnny Huang 	}
16357332532cSJohnny Huang 
16365010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
16375010032bSJohnny Huang 		printf("programing data region ...\n");
16385010032bSJohnny Huang 		ret = otp_prog_data(&image_layout);
16395010032bSJohnny Huang 		if (ret != 0) {
16405010032bSJohnny Huang 			printf("Error\n");
16415010032bSJohnny Huang 			return ret;
16425010032bSJohnny Huang 		} else {
16435010032bSJohnny Huang 			printf("Done\n");
16445010032bSJohnny Huang 		}
16455010032bSJohnny Huang 	}
16465010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
16475010032bSJohnny Huang 		printf("programing strap region ...\n");
16485010032bSJohnny Huang 		ret = otp_prog_strap(&image_layout);
16495010032bSJohnny Huang 		if (ret != 0) {
16505010032bSJohnny Huang 			printf("Error\n");
16515010032bSJohnny Huang 			return ret;
16525010032bSJohnny Huang 		} else {
16535010032bSJohnny Huang 			printf("Done\n");
16545010032bSJohnny Huang 		}
16555010032bSJohnny Huang 	}
16565010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
16575010032bSJohnny Huang 		printf("programing configuration region ...\n");
16585010032bSJohnny Huang 		ret = otp_prog_conf(&image_layout);
16595010032bSJohnny Huang 		if (ret != 0) {
16605010032bSJohnny Huang 			printf("Error\n");
16615010032bSJohnny Huang 			return ret;
16625010032bSJohnny Huang 		}
16635010032bSJohnny Huang 		printf("Done\n");
16645010032bSJohnny Huang 	}
1665cd1610b4SJohnny Huang 
16667332532cSJohnny Huang 	return OTP_SUCCESS;
16672a856b9aSJohnny Huang }
16682a856b9aSJohnny Huang 
16692a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1670cd1610b4SJohnny Huang {
1671a6af4a17SJohnny Huang 	uint32_t read[2];
1672d90825e2SJohnny Huang 	uint32_t prog_address = 0;
167366f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1674cd1610b4SJohnny Huang 	int otp_bit;
167583655e91SJohnny Huang 	int ret = 0;
1676cd1610b4SJohnny Huang 
1677cd1610b4SJohnny Huang 	switch (mode) {
1678a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1679a6af4a17SJohnny Huang 		otp_read_config(otp_dw_offset, read);
1680cd1610b4SJohnny Huang 		prog_address = 0x800;
1681cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1682cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1683a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1684cd1610b4SJohnny Huang 		if (otp_bit == value) {
1685a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1686cd1610b4SJohnny Huang 			printf("No need to program\n");
16872a856b9aSJohnny Huang 			return OTP_SUCCESS;
1688cd1610b4SJohnny Huang 		}
1689cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1690a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
1691cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
16922a856b9aSJohnny Huang 			return OTP_FAILURE;
1693cd1610b4SJohnny Huang 		}
1694a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1695cd1610b4SJohnny Huang 		break;
1696a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1697cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1698cd1610b4SJohnny Huang 
1699cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1700a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1701a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1702643b9cfdSJohnny Huang 
1703643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
1704643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1705643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be cleaned\n");
1706643b9cfdSJohnny Huang 				return OTP_FAILURE;
1707643b9cfdSJohnny Huang 			}
1708cd1610b4SJohnny Huang 		} else {
1709a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1710a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1711643b9cfdSJohnny Huang 
1712643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
1713643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1714643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be writen\n");
1715643b9cfdSJohnny Huang 				return OTP_FAILURE;
1716643b9cfdSJohnny Huang 			}
1717cd1610b4SJohnny Huang 		}
1718cd1610b4SJohnny Huang 		if (otp_bit == value) {
1719a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1720cd1610b4SJohnny Huang 			printf("No need to program\n");
17212a856b9aSJohnny Huang 			return OTP_SUCCESS;
1722cd1610b4SJohnny Huang 		}
1723643b9cfdSJohnny Huang 
1724a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1725cd1610b4SJohnny Huang 		break;
1726a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
17278848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
17288848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
17298848d5dcSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
17308848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
17318848d5dcSJohnny Huang 			return OTP_FAILURE;
17328848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
17338848d5dcSJohnny Huang 			return OTP_SUCCESS;
1734a6af4a17SJohnny Huang 
1735cd1610b4SJohnny Huang 		break;
1736cd1610b4SJohnny Huang 	}
1737cd1610b4SJohnny Huang 
1738cd1610b4SJohnny Huang 	if (!nconfirm) {
1739cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1740cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1741cd1610b4SJohnny Huang 			printf(" Aborting\n");
17422a856b9aSJohnny Huang 			return OTP_FAILURE;
1743cd1610b4SJohnny Huang 		}
1744cd1610b4SJohnny Huang 	}
1745cd1610b4SJohnny Huang 
1746cd1610b4SJohnny Huang 	switch (mode) {
1747a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
174883655e91SJohnny Huang 		ret =  otp_prog_strap_bit(bit_offset, value);
174983655e91SJohnny Huang 		break;
1750a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1751a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
175283655e91SJohnny Huang 		ret = otp_prog_bit(value, prog_address, bit_offset);
1753de6fbf1cSJohnny Huang 		break;
1754de6fbf1cSJohnny Huang 	}
1755de6fbf1cSJohnny Huang 	otp_soak(0);
175683655e91SJohnny Huang 	if (ret) {
17579009c25dSJohnny Huang 		printf("SUCCESS\n");
17582a856b9aSJohnny Huang 		return OTP_SUCCESS;
17599009c25dSJohnny Huang 	} else {
17609009c25dSJohnny Huang 		printf("OTP cannot be programed\n");
17619009c25dSJohnny Huang 		printf("FAILED\n");
17629009c25dSJohnny Huang 		return OTP_FAILURE;
17639009c25dSJohnny Huang 	}
1764cd1610b4SJohnny Huang 
17652a856b9aSJohnny Huang 	return OTP_USAGE;
1766cd1610b4SJohnny Huang }
1767cd1610b4SJohnny Huang 
17682a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
176969d5fd8fSJohnny Huang {
17702a856b9aSJohnny Huang 	uint32_t offset, count;
17712a856b9aSJohnny Huang 	int ret;
177269d5fd8fSJohnny Huang 
17732a856b9aSJohnny Huang 	if (argc == 4) {
17742a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
17752a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
17762a856b9aSJohnny Huang 	} else if (argc == 3) {
17772a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
17782a856b9aSJohnny Huang 		count = 1;
17792a856b9aSJohnny Huang 	} else {
178069d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
178169d5fd8fSJohnny Huang 	}
178269d5fd8fSJohnny Huang 
178369d5fd8fSJohnny Huang 
17842a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
17853d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
17862a856b9aSJohnny Huang 		ret = otp_print_config(offset, count);
17872a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
17883d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
17892a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
17902a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
17913d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
17922a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
17932a856b9aSJohnny Huang 	} else {
17942a856b9aSJohnny Huang 		return CMD_RET_USAGE;
179569d5fd8fSJohnny Huang 	}
179669d5fd8fSJohnny Huang 
17972a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
17982a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
17992a856b9aSJohnny Huang 	else
18002a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18012a856b9aSJohnny Huang 
18022a856b9aSJohnny Huang }
18032a856b9aSJohnny Huang 
18042a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
18052a856b9aSJohnny Huang {
18062a856b9aSJohnny Huang 	phys_addr_t addr;
18072a856b9aSJohnny Huang 	int ret;
18082a856b9aSJohnny Huang 
1809de6b0cc4SJohnny Huang 	if (argc == 3) {
1810ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
18112a856b9aSJohnny Huang 			return CMD_RET_USAGE;
18122a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
18133d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1814de6b0cc4SJohnny Huang 		ret = do_otp_prog(addr, 1);
1815de6b0cc4SJohnny Huang 	} else if (argc == 2) {
18162a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
18173d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1818de6b0cc4SJohnny Huang 		ret = do_otp_prog(addr, 0);
18192a856b9aSJohnny Huang 	} else {
18202a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18212a856b9aSJohnny Huang 	}
18222a856b9aSJohnny Huang 
18232a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
18242a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
18252a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
18262a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
18272a856b9aSJohnny Huang 	else
18282a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18292a856b9aSJohnny Huang }
18302a856b9aSJohnny Huang 
18312a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
18322a856b9aSJohnny Huang {
18332a856b9aSJohnny Huang 	int mode = 0;
18342a856b9aSJohnny Huang 	int nconfirm = 0;
18352a856b9aSJohnny Huang 	int otp_addr = 0;
18362a856b9aSJohnny Huang 	int bit_offset;
18372a856b9aSJohnny Huang 	int value;
18382a856b9aSJohnny Huang 	int ret;
18392a856b9aSJohnny Huang 
18402a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
18412a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18422a856b9aSJohnny Huang 
18432a856b9aSJohnny Huang 	/* Drop the pb cmd */
18442a856b9aSJohnny Huang 	argc--;
18452a856b9aSJohnny Huang 	argv++;
18462a856b9aSJohnny Huang 
18472a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
1848a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
18492a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
1850a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
18512a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
1852a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
1853cd1610b4SJohnny Huang 	else
18542a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18552a856b9aSJohnny Huang 
18562a856b9aSJohnny Huang 	/* Drop the region cmd */
18572a856b9aSJohnny Huang 	argc--;
18582a856b9aSJohnny Huang 	argv++;
18592a856b9aSJohnny Huang 
1860ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
1861cd1610b4SJohnny Huang 		nconfirm = 1;
18622a856b9aSJohnny Huang 		/* Drop the force option */
18632a856b9aSJohnny Huang 		argc--;
18642a856b9aSJohnny Huang 		argv++;
18652a856b9aSJohnny Huang 	}
1866cd1610b4SJohnny Huang 
1867a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
18682a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
18692a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
18700808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
18712a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1872cd1610b4SJohnny Huang 	} else {
18732a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
18742a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
18752a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
18760808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
18772a856b9aSJohnny Huang 			return CMD_RET_USAGE;
18780808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
187978855207SJohnny Huang 			if (otp_addr >= 0x800)
18800808cc55SJohnny Huang 				return CMD_RET_USAGE;
18810808cc55SJohnny Huang 		} else {
188278855207SJohnny Huang 			if (otp_addr >= 0x20)
18830808cc55SJohnny Huang 				return CMD_RET_USAGE;
18840808cc55SJohnny Huang 		}
1885cd1610b4SJohnny Huang 	}
1886cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
18872a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1888cd1610b4SJohnny Huang 
18893d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
18902a856b9aSJohnny Huang 	ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
18912a856b9aSJohnny Huang 
18922a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
18932a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
18942a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
18952a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
18962a856b9aSJohnny Huang 	else
18972a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18982a856b9aSJohnny Huang }
18992a856b9aSJohnny Huang 
19002a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
19012a856b9aSJohnny Huang {
19022a856b9aSJohnny Huang 	phys_addr_t addr;
19032a856b9aSJohnny Huang 	int otp_addr = 0;
19042a856b9aSJohnny Huang 
19052a856b9aSJohnny Huang 	if (argc != 3)
19062a856b9aSJohnny Huang 		return CMD_RET_USAGE;
19072a856b9aSJohnny Huang 
19083d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19092a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
19102a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
19112a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
191269d5fd8fSJohnny Huang 		printf("Compare pass\n");
19132a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
191469d5fd8fSJohnny Huang 	} else {
191569d5fd8fSJohnny Huang 		printf("Compare fail\n");
19162a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
191769d5fd8fSJohnny Huang 	}
191869d5fd8fSJohnny Huang }
191969d5fd8fSJohnny Huang 
192066f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
192166f2f8e5SJohnny Huang {
1922a8bd6d8cSJohnny Huang 	int view = 0;
19232d4b0742SJohnny Huang 	int input;
1924a8bd6d8cSJohnny Huang 
1925a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
192666f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
192766f2f8e5SJohnny Huang 
19282d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
192966f2f8e5SJohnny Huang 
19303d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19312d4b0742SJohnny Huang 		if (argc == 3) {
19322d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
19332d4b0742SJohnny Huang 			otp_print_conf_info(input);
19342d4b0742SJohnny Huang 		} else {
19352d4b0742SJohnny Huang 			otp_print_conf_info(-1);
19362d4b0742SJohnny Huang 		}
19372d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
19382d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
1939a8bd6d8cSJohnny Huang 			view = 1;
1940a8bd6d8cSJohnny Huang 			/* Drop the view option */
1941a8bd6d8cSJohnny Huang 			argc--;
1942a8bd6d8cSJohnny Huang 			argv++;
1943a8bd6d8cSJohnny Huang 		}
19443d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1945b458cd62SJohnny Huang 		otp_print_strap_info(view);
194666f2f8e5SJohnny Huang 	} else {
194766f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
194866f2f8e5SJohnny Huang 	}
19492d4b0742SJohnny Huang 
195066f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
195166f2f8e5SJohnny Huang }
195266f2f8e5SJohnny Huang 
1953737ed20bSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1954737ed20bSJohnny Huang {
1955737ed20bSJohnny Huang 	int input;
1956737ed20bSJohnny Huang 	int bit_offset;
1957737ed20bSJohnny Huang 	int prog_address;
195883655e91SJohnny Huang 	int ret;
1959737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
1960737ed20bSJohnny Huang 		return CMD_RET_USAGE;
1961737ed20bSJohnny Huang 
1962ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
1963737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
1964737ed20bSJohnny Huang 	} else {
1965737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
1966737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] will be protected\n", input);
1967737ed20bSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1968737ed20bSJohnny Huang 		if (!confirm_yesno()) {
1969737ed20bSJohnny Huang 			printf(" Aborting\n");
1970737ed20bSJohnny Huang 			return CMD_RET_FAILURE;
1971737ed20bSJohnny Huang 		}
1972737ed20bSJohnny Huang 	}
1973737ed20bSJohnny Huang 
1974737ed20bSJohnny Huang 	prog_address = 0x800;
1975737ed20bSJohnny Huang 	if (input < 32) {
1976737ed20bSJohnny Huang 		bit_offset = input;
1977737ed20bSJohnny Huang 		prog_address |= 0x60c;
1978737ed20bSJohnny Huang 	} else if (input < 64) {
1979737ed20bSJohnny Huang 		bit_offset = input - 32;
1980737ed20bSJohnny Huang 		prog_address |= 0x60e;
1981737ed20bSJohnny Huang 	} else {
1982737ed20bSJohnny Huang 		return CMD_RET_USAGE;
1983737ed20bSJohnny Huang 	}
1984737ed20bSJohnny Huang 
1985737ed20bSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
1986737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] already protected\n", input);
1987737ed20bSJohnny Huang 	}
1988de6fbf1cSJohnny Huang 
198983655e91SJohnny Huang 	ret = otp_prog_bit(1, prog_address, bit_offset);
1990de6fbf1cSJohnny Huang 	otp_soak(0);
199183655e91SJohnny Huang 
199283655e91SJohnny Huang 	if (ret) {
1993737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] is protected\n", input);
1994737ed20bSJohnny Huang 		return CMD_RET_SUCCESS;
1995737ed20bSJohnny Huang 	}
1996737ed20bSJohnny Huang 
1997737ed20bSJohnny Huang 	printf("Protect OTPSTRAP[%d] fail\n", input);
1998737ed20bSJohnny Huang 	return CMD_RET_FAILURE;
1999737ed20bSJohnny Huang 
2000737ed20bSJohnny Huang }
20019a4fe690SJohnny Huang 
2002f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2003f67375f7SJohnny Huang {
2004f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2005f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2006f67375f7SJohnny Huang 
2007f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2008f67375f7SJohnny Huang }
2009f67375f7SJohnny Huang 
20102a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2011f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
20122a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2013a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2014de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
20152a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2016737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
20172a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
20182a856b9aSJohnny Huang };
20192a856b9aSJohnny Huang 
20202a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20212a856b9aSJohnny Huang {
20222a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2023*0dae9d52SJohnny Huang 	uint32_t ver;
20242a856b9aSJohnny Huang 
20252a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
20262a856b9aSJohnny Huang 
2027737ed20bSJohnny Huang 	/* Drop the otp command */
20282a856b9aSJohnny Huang 	argc--;
20292a856b9aSJohnny Huang 	argv++;
20302a856b9aSJohnny Huang 
20312a856b9aSJohnny Huang 	if (cp == NULL || argc > cp->maxargs)
20322a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20332a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
20342a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20352a856b9aSJohnny Huang 
2036*0dae9d52SJohnny Huang 	ver = chip_version();
2037*0dae9d52SJohnny Huang 	switch (ver) {
2038*0dae9d52SJohnny Huang 	case OTP_AST2600A0:
2039696656c6SJohnny Huang 		info_cb.version = OTP_AST2600A0;
20409a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
20419a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
20429a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
20439a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
20449a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
20459a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2046*0dae9d52SJohnny Huang 		break;
2047*0dae9d52SJohnny Huang 	case OTP_AST2600A1:
2048696656c6SJohnny Huang 		info_cb.version = OTP_AST2600A1;
20493cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
20503cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
20513cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
20523cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
20539a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
20549a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
2055*0dae9d52SJohnny Huang 		break;
2056*0dae9d52SJohnny Huang 	case OTP_AST2600A2:
20575fdde29fSJohnny Huang 		info_cb.version = OTP_AST2600A2;
20585fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
20595fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
20605fdde29fSJohnny Huang 		info_cb.strap_info = a2_strap_info;
20615fdde29fSJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
20625fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
20635fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
2064*0dae9d52SJohnny Huang 		break;
2065*0dae9d52SJohnny Huang 	default:
2066*0dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
20679a4fe690SJohnny Huang 	}
20689a4fe690SJohnny Huang 
20692a856b9aSJohnny Huang 	return cp->cmd(cmdtp, flag, argc, argv);
207069d5fd8fSJohnny Huang }
207169d5fd8fSJohnny Huang 
207269d5fd8fSJohnny Huang U_BOOT_CMD(
207369d5fd8fSJohnny Huang 	otp, 7, 0,  do_ast_otp,
207469d5fd8fSJohnny Huang 	"ASPEED One-Time-Programmable sub-system",
2075f67375f7SJohnny Huang 	"version\n"
2076f67375f7SJohnny Huang 	"otp read conf|data <otp_dw_offset> <dw_count>\n"
20772a856b9aSJohnny Huang 	"otp read strap <strap_bit_offset> <bit_count>\n"
20782d4b0742SJohnny Huang 	"otp info strap [v]\n"
20792d4b0742SJohnny Huang 	"otp info conf [otp_dw_offset]\n"
2080de6b0cc4SJohnny Huang 	"otp prog [o] <addr>\n"
2081ed071a2bSJohnny Huang 	"otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2082ed071a2bSJohnny Huang 	"otp pb strap [o] <bit_offset> <value>\n"
2083ed071a2bSJohnny Huang 	"otp protect [o] <bit_offset>\n"
20842a856b9aSJohnny Huang 	"otp cmp <addr> <otp_dw_offset>\n"
208569d5fd8fSJohnny Huang );
2086