xref: /openbmc/u-boot/cmd/otp.c (revision 181f72d8)
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 
2864b66712SJohnny Huang #define OTP_VER				"1.0.3"
29f67375f7SJohnny Huang 
3069d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
31dacbba92SJohnny Huang #define RETRY				20
327332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
337332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
347332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3569d5fd8fSJohnny Huang 
362a856b9aSJohnny Huang #define OTP_USAGE			-1
372a856b9aSJohnny Huang #define OTP_FAILURE			-2
382a856b9aSJohnny Huang #define OTP_SUCCESS			0
392a856b9aSJohnny Huang 
40a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
41a6af4a17SJohnny Huang 
42*181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB		1
43*181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV		2
44*181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES		3
45*181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT		4
46*181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC		5
479a4fe690SJohnny Huang 
484c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
494c1c9b35SJohnny Huang #define PBWIDTH 60
504c1c9b35SJohnny Huang 
513d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
523d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
533d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
543d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
553d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
563d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
573d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
583d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
593d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
603d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
613d3688adSJohnny Huang 
62696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
63696656c6SJohnny Huang #define CHECKSUM_LEN		32
64696656c6SJohnny Huang #define OTP_INC_DATA		(1 << 31)
65696656c6SJohnny Huang #define OTP_INC_CONFIG		(1 << 30)
66696656c6SJohnny Huang #define OTP_INC_STRAP		(1 << 29)
67696656c6SJohnny Huang #define OTP_ECC_EN		(1 << 28)
68696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
69696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
70696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
71696656c6SJohnny Huang 
72696656c6SJohnny Huang #define OTP_AST2600A0		0
73696656c6SJohnny Huang #define OTP_AST2600A1		1
740dae9d52SJohnny Huang #define OTP_AST2600A2		2
7564b66712SJohnny Huang #define OTP_AST2600A3		3
76696656c6SJohnny Huang 
77696656c6SJohnny Huang struct otp_header {
78696656c6SJohnny Huang 	u8	otp_magic[8];
79696656c6SJohnny Huang 	u8	otp_version[8];
80696656c6SJohnny Huang 	u32	image_info;
81696656c6SJohnny Huang 	u32	data_info;
82696656c6SJohnny Huang 	u32	config_info;
83696656c6SJohnny Huang 	u32	strap_info;
84696656c6SJohnny Huang 	u32	checksum_offset;
85696656c6SJohnny Huang } __attribute__((packed));
86696656c6SJohnny Huang 
8766f2f8e5SJohnny Huang struct otpstrap_status {
8869d5fd8fSJohnny Huang 	int value;
8969d5fd8fSJohnny Huang 	int option_array[7];
9069d5fd8fSJohnny Huang 	int remain_times;
9169d5fd8fSJohnny Huang 	int writeable_option;
925010032bSJohnny Huang 	int reg_protected;
9369d5fd8fSJohnny Huang 	int protected;
9469d5fd8fSJohnny Huang };
9569d5fd8fSJohnny Huang 
9666f2f8e5SJohnny Huang struct otpconf_parse {
9766f2f8e5SJohnny Huang 	int dw_offset;
9866f2f8e5SJohnny Huang 	int bit;
9966f2f8e5SJohnny Huang 	int length;
10066f2f8e5SJohnny Huang 	int value;
101696656c6SJohnny Huang 	int ignore;
10266f2f8e5SJohnny Huang 	char status[80];
10366f2f8e5SJohnny Huang };
10466f2f8e5SJohnny Huang 
1059a4fe690SJohnny Huang struct otpkey_type {
1069a4fe690SJohnny Huang 	int value;
1079a4fe690SJohnny Huang 	int key_type;
1089a4fe690SJohnny Huang 	int need_id;
1099a4fe690SJohnny Huang 	char information[110];
1109a4fe690SJohnny Huang };
1119a4fe690SJohnny Huang 
1129a4fe690SJohnny Huang struct otp_info_cb {
1139a4fe690SJohnny Huang 	int version;
11479e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1159a4fe690SJohnny Huang 	int strap_info_len;
11679e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1179a4fe690SJohnny Huang 	int conf_info_len;
11879e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1199a4fe690SJohnny Huang 	int key_info_len;
1205010032bSJohnny Huang 
1219a4fe690SJohnny Huang };
1229a4fe690SJohnny Huang 
123696656c6SJohnny Huang struct otp_image_layout {
1245010032bSJohnny Huang 	int data_length;
1255010032bSJohnny Huang 	int conf_length;
1265010032bSJohnny Huang 	int strap_length;
127696656c6SJohnny Huang 	uint8_t *data;
128696656c6SJohnny Huang 	uint8_t *data_ignore;
129696656c6SJohnny Huang 	uint8_t *conf;
130696656c6SJohnny Huang 	uint8_t *conf_ignore;
131696656c6SJohnny Huang 	uint8_t *strap;
132696656c6SJohnny Huang 	uint8_t *strap_reg_pro;
133696656c6SJohnny Huang 	uint8_t *strap_pro;
134696656c6SJohnny Huang 	uint8_t *strap_ignore;
135696656c6SJohnny Huang };
136696656c6SJohnny Huang 
1379a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1389a4fe690SJohnny Huang 
13979e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1409a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1419a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1429a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
143*181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
144*181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   0, "RSA-public as SOC public key"},
145*181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
146*181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as SOC private key"},
147*181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1489a4fe690SJohnny Huang };
1499a4fe690SJohnny Huang 
15079e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1519a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1529a4fe690SJohnny 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"},
153*181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
154*181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
155*181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1569a4fe690SJohnny Huang };
1579a4fe690SJohnny Huang 
1585fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1595fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1605fdde29fSJohnny 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"},
161*181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
162*181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
163*181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
164*181f72d8SJohnny Huang };
165*181f72d8SJohnny Huang 
166*181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
167*181f72d8SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
168*181f72d8SJohnny 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"},
169*181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
170*181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
171*181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
172*181f72d8SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key(big endian)"},
173*181f72d8SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
174*181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key(big endian)"},
1755fdde29fSJohnny Huang };
1765fdde29fSJohnny Huang 
1779a4fe690SJohnny Huang static uint32_t  chip_version(void)
1789a4fe690SJohnny Huang {
179badd21c2SJohnny Huang 	u64 rev_id;
1809a4fe690SJohnny Huang 
181badd21c2SJohnny Huang 	rev_id = readl(ASPEED_REVISION_ID0);
182badd21c2SJohnny Huang 	rev_id = ((u64)readl(ASPEED_REVISION_ID1) << 32) | rev_id;
1839a4fe690SJohnny Huang 
184badd21c2SJohnny Huang 	if (rev_id == 0x0500030305000303) {
185badd21c2SJohnny Huang 		/* AST2600-A0 */
1860dae9d52SJohnny Huang 		return OTP_AST2600A0;
187badd21c2SJohnny Huang 	} else if (rev_id == 0x0501030305010303) {
188badd21c2SJohnny Huang 		/* AST2600-A1 */
1890dae9d52SJohnny Huang 		return OTP_AST2600A1;
190badd21c2SJohnny Huang 	} else if (rev_id == 0x0501020305010203) {
191badd21c2SJohnny Huang 		/* AST2620-A1 */
192badd21c2SJohnny Huang 		return OTP_AST2600A1;
193badd21c2SJohnny Huang 	} else if (rev_id == 0x0502030305010303) {
194badd21c2SJohnny Huang 		/* AST2600-A2 */
1950dae9d52SJohnny Huang 		return OTP_AST2600A2;
196badd21c2SJohnny Huang 	} else if (rev_id == 0x0502020305010203) {
197badd21c2SJohnny Huang 		/* AST2620-A2 */
198badd21c2SJohnny Huang 		return OTP_AST2600A2;
199badd21c2SJohnny Huang 	} else if (rev_id == 0x0502010305010103) {
200badd21c2SJohnny Huang 		/* AST2605-A2 */
2010dae9d52SJohnny Huang 		return OTP_AST2600A2;
20264b66712SJohnny Huang 	} else if (rev_id == 0x0503030305030303) {
20364b66712SJohnny Huang 		/* AST2600-A3 */
20464b66712SJohnny Huang 		return OTP_AST2600A3;
20564b66712SJohnny Huang 	} else if (rev_id == 0x0503020305030203) {
20664b66712SJohnny Huang 		/* AST2620-A3 */
20764b66712SJohnny Huang 		return OTP_AST2600A3;
2080dae9d52SJohnny Huang 	}
2090dae9d52SJohnny Huang 
2105fdde29fSJohnny Huang 	return -1;
2119a4fe690SJohnny Huang }
2129a4fe690SJohnny Huang 
2133d3688adSJohnny Huang static void wait_complete(void)
2143d3688adSJohnny Huang {
2153d3688adSJohnny Huang 	int reg;
2163d3688adSJohnny Huang 
2173d3688adSJohnny Huang 	do {
2183d3688adSJohnny Huang 		reg = readl(OTP_STATUS);
2193d3688adSJohnny Huang 	} while ((reg & 0x6) != 0x6);
2203d3688adSJohnny Huang }
2213d3688adSJohnny Huang 
222dacbba92SJohnny Huang static void otp_write(uint32_t otp_addr, uint32_t data)
223dacbba92SJohnny Huang {
224dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
225dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
226dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
227dacbba92SJohnny Huang 	wait_complete();
228dacbba92SJohnny Huang }
229dacbba92SJohnny Huang 
230dacbba92SJohnny Huang static void otp_soak(int soak)
231dacbba92SJohnny Huang {
23264b66712SJohnny Huang 	if (info_cb.version == OTP_AST2600A2 || info_cb.version == OTP_AST2600A3) {
233dacbba92SJohnny Huang 		switch (soak) {
234dacbba92SJohnny Huang 		case 0: //default
235dacbba92SJohnny Huang 			otp_write(0x3000, 0x0210); // Write MRA
236dacbba92SJohnny Huang 			otp_write(0x5000, 0x2000); // Write MRB
237dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
238dacbba92SJohnny Huang 			break;
239dacbba92SJohnny Huang 		case 1: //normal program
240dacbba92SJohnny Huang 			otp_write(0x3000, 0x1200); // Write MRA
241feea3fdfSJohnny Huang 			otp_write(0x5000, 0x107F); // Write MRB
242dacbba92SJohnny Huang 			otp_write(0x1000, 0x1024); // Write MR
243feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
244dacbba92SJohnny Huang 			break;
245dacbba92SJohnny Huang 		case 2: //soak program
246dacbba92SJohnny Huang 			otp_write(0x3000, 0x1220); // Write MRA
247feea3fdfSJohnny Huang 			otp_write(0x5000, 0x2074); // Write MRB
248dacbba92SJohnny Huang 			otp_write(0x1000, 0x08a4); // Write MR
249feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
250dacbba92SJohnny Huang 			break;
251dacbba92SJohnny Huang 		}
252dacbba92SJohnny Huang 	} else {
253dacbba92SJohnny Huang 		switch (soak) {
254dacbba92SJohnny Huang 		case 0: //default
255dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
256dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
257dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
258dacbba92SJohnny Huang 			break;
259dacbba92SJohnny Huang 		case 1: //normal program
260dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
261dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
262dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
263feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
264dacbba92SJohnny Huang 			break;
265dacbba92SJohnny Huang 		case 2: //soak program
266dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
267dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
268dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
269feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
270dacbba92SJohnny Huang 			break;
271dacbba92SJohnny Huang 		}
272dacbba92SJohnny Huang 	}
273dacbba92SJohnny Huang 
274dacbba92SJohnny Huang 	wait_complete();
275dacbba92SJohnny Huang }
276dacbba92SJohnny Huang 
2772a856b9aSJohnny Huang static void otp_read_data(uint32_t offset, uint32_t *data)
27869d5fd8fSJohnny Huang {
2793d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
2803d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
2813d3688adSJohnny Huang 	wait_complete();
2823d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
2833d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
28469d5fd8fSJohnny Huang }
28569d5fd8fSJohnny Huang 
2862a856b9aSJohnny Huang static void otp_read_config(uint32_t offset, uint32_t *data)
28769d5fd8fSJohnny Huang {
28869d5fd8fSJohnny Huang 	int config_offset;
28969d5fd8fSJohnny Huang 
29069d5fd8fSJohnny Huang 	config_offset = 0x800;
29169d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
29269d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
29369d5fd8fSJohnny Huang 
2943d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
2953d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
2963d3688adSJohnny Huang 	wait_complete();
2973d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
29869d5fd8fSJohnny Huang }
29969d5fd8fSJohnny Huang 
30069d5fd8fSJohnny Huang static int otp_print_config(uint32_t offset, int dw_count)
30169d5fd8fSJohnny Huang {
30269d5fd8fSJohnny Huang 	int i;
30369d5fd8fSJohnny Huang 	uint32_t ret[1];
30469d5fd8fSJohnny Huang 
30569d5fd8fSJohnny Huang 	if (offset + dw_count > 32)
3062a856b9aSJohnny Huang 		return OTP_USAGE;
307dacbba92SJohnny Huang 	otp_soak(0);
30869d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i ++) {
30969d5fd8fSJohnny Huang 		otp_read_config(i, ret);
310a6af4a17SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
31169d5fd8fSJohnny Huang 	}
31269d5fd8fSJohnny Huang 	printf("\n");
3132a856b9aSJohnny Huang 	return OTP_SUCCESS;
31469d5fd8fSJohnny Huang }
31569d5fd8fSJohnny Huang 
31669d5fd8fSJohnny Huang static int otp_print_data(uint32_t offset, int dw_count)
31769d5fd8fSJohnny Huang {
31869d5fd8fSJohnny Huang 	int i;
31969d5fd8fSJohnny Huang 	uint32_t ret[2];
32069d5fd8fSJohnny Huang 
32169d5fd8fSJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
3222a856b9aSJohnny Huang 		return OTP_USAGE;
323dacbba92SJohnny Huang 	otp_soak(0);
32469d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
32569d5fd8fSJohnny Huang 		otp_read_data(i, ret);
32669d5fd8fSJohnny Huang 		if (i % 4 == 0)
32769d5fd8fSJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
32869d5fd8fSJohnny Huang 		else
32969d5fd8fSJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
33069d5fd8fSJohnny Huang 
33169d5fd8fSJohnny Huang 	}
33269d5fd8fSJohnny Huang 	printf("\n");
3332a856b9aSJohnny Huang 	return OTP_SUCCESS;
33469d5fd8fSJohnny Huang }
33569d5fd8fSJohnny Huang 
33669d5fd8fSJohnny Huang static int otp_compare(uint32_t otp_addr, uint32_t addr)
33769d5fd8fSJohnny Huang {
33869d5fd8fSJohnny Huang 	uint32_t ret;
33969d5fd8fSJohnny Huang 	uint32_t *buf;
34069d5fd8fSJohnny Huang 
34169d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
34269d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
34369d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
34469d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
34569d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
3463d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
3473d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
3483d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
3493d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
3503d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
3513d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
3523d3688adSJohnny Huang 	wait_complete();
3533d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
35469d5fd8fSJohnny Huang 	if (ret & 0x1)
35569d5fd8fSJohnny Huang 		return 0;
35669d5fd8fSJohnny Huang 	else
35769d5fd8fSJohnny Huang 		return -1;
35869d5fd8fSJohnny Huang }
35969d5fd8fSJohnny Huang 
360a6d0d645SJohnny Huang static int verify_bit(uint32_t otp_addr, int bit_offset, int value)
36169d5fd8fSJohnny Huang {
36230a8c590SJohnny Huang 	uint32_t ret[2];
36369d5fd8fSJohnny Huang 
36430a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
3653d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
36630a8c590SJohnny Huang 	else
3673d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
36830a8c590SJohnny Huang 
3693d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3703d3688adSJohnny Huang 	wait_complete();
3713d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
3723d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
37383655e91SJohnny Huang 
37430a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
37530a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
37669d5fd8fSJohnny Huang 			return 0;
37769d5fd8fSJohnny Huang 		else
37869d5fd8fSJohnny Huang 			return -1;
37930a8c590SJohnny Huang 	} else {
38030a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
38130a8c590SJohnny Huang 			return 0;
38230a8c590SJohnny Huang 		else
38330a8c590SJohnny Huang 			return -1;
38430a8c590SJohnny Huang 	}
38530a8c590SJohnny Huang 
38669d5fd8fSJohnny Huang }
38769d5fd8fSJohnny Huang 
388696656c6SJohnny Huang static uint32_t verify_dw(uint32_t otp_addr, uint32_t *value, uint32_t *ignore, uint32_t *compare, int size)
3894c1c9b35SJohnny Huang {
3904c1c9b35SJohnny Huang 	uint32_t ret[2];
3914c1c9b35SJohnny Huang 
3924c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
3934c1c9b35SJohnny Huang 
3944c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
3953d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
3964c1c9b35SJohnny Huang 	else
3973d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
3983d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3993d3688adSJohnny Huang 	wait_complete();
4003d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4013d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4024c1c9b35SJohnny Huang 	if (size == 1) {
4034c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4044c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
405696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4064c1c9b35SJohnny Huang 				compare[0] = 0;
4074c1c9b35SJohnny Huang 				return 0;
4084c1c9b35SJohnny Huang 			} else {
4094c1c9b35SJohnny Huang 				compare[0] = value[0] ^ ret[0];
4104c1c9b35SJohnny Huang 				return -1;
4114c1c9b35SJohnny Huang 			}
4124c1c9b35SJohnny Huang 
4134c1c9b35SJohnny Huang 		} else {
4144c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
415696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4164c1c9b35SJohnny Huang 				compare[0] = ~0;
4174c1c9b35SJohnny Huang 				return 0;
4184c1c9b35SJohnny Huang 			} else {
419d90825e2SJohnny Huang 				compare[0] = ~(value[0] ^ ret[1]);
4204c1c9b35SJohnny Huang 				return -1;
4214c1c9b35SJohnny Huang 			}
4224c1c9b35SJohnny Huang 		}
4234c1c9b35SJohnny Huang 	} else if (size == 2) {
4244c1c9b35SJohnny Huang 		// otp_addr should be even
425696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
4264c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4274c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4284c1c9b35SJohnny Huang 			compare[0] = 0;
4294c1c9b35SJohnny Huang 			compare[1] = ~0;
4304c1c9b35SJohnny Huang 			return 0;
4314c1c9b35SJohnny Huang 		} else {
4324c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4334c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4344c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
4354c1c9b35SJohnny Huang 			compare[1] = ~(value[1] ^ ret[1]);
4364c1c9b35SJohnny Huang 			return -1;
4374c1c9b35SJohnny Huang 		}
4384c1c9b35SJohnny Huang 	} else {
4394c1c9b35SJohnny Huang 		return -1;
4404c1c9b35SJohnny Huang 	}
4414c1c9b35SJohnny Huang }
4424c1c9b35SJohnny Huang 
44383655e91SJohnny Huang static void otp_prog(uint32_t otp_addr, uint32_t prog_bit)
44483655e91SJohnny Huang {
44590965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
44683655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
44783655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
44883655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
44983655e91SJohnny Huang 	wait_complete();
45083655e91SJohnny Huang }
45183655e91SJohnny Huang 
45283655e91SJohnny Huang static void _otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset)
45383655e91SJohnny Huang {
45483655e91SJohnny Huang 	int prog_bit;
45583655e91SJohnny Huang 
45683655e91SJohnny Huang 	if (prog_address % 2 == 0) {
45783655e91SJohnny Huang 		if (value)
45883655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
45983655e91SJohnny Huang 		else
46083655e91SJohnny Huang 			return;
46183655e91SJohnny Huang 	} else {
46264b66712SJohnny Huang 		if (info_cb.version != OTP_AST2600A3)
46383655e91SJohnny Huang 			prog_address |= 1 << 15;
46483655e91SJohnny Huang 		if (!value)
46583655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
46683655e91SJohnny Huang 		else
46783655e91SJohnny Huang 			return;
46883655e91SJohnny Huang 	}
46983655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
47083655e91SJohnny Huang }
47183655e91SJohnny Huang 
47283655e91SJohnny Huang static int otp_prog_bit(uint32_t value, uint32_t prog_address, uint32_t bit_offset)
47383655e91SJohnny Huang {
47483655e91SJohnny Huang 	int pass;
47583655e91SJohnny Huang 	int i;
47683655e91SJohnny Huang 
47783655e91SJohnny Huang 	otp_soak(1);
47883655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
47983655e91SJohnny Huang 	pass = 0;
48083655e91SJohnny Huang 
48183655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
48283655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
48383655e91SJohnny Huang 			otp_soak(2);
48483655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
48583655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
48683655e91SJohnny Huang 				otp_soak(1);
48783655e91SJohnny Huang 			} else {
48883655e91SJohnny Huang 				pass = 1;
48983655e91SJohnny Huang 				break;
49083655e91SJohnny Huang 			}
49183655e91SJohnny Huang 		} else {
49283655e91SJohnny Huang 			pass = 1;
49383655e91SJohnny Huang 			break;
49483655e91SJohnny Huang 		}
49583655e91SJohnny Huang 	}
49683655e91SJohnny Huang 
49783655e91SJohnny Huang 	return pass;
49883655e91SJohnny Huang }
49983655e91SJohnny Huang 
500696656c6SJohnny Huang static void otp_prog_dw(uint32_t value, uint32_t ignore, uint32_t prog_address)
501d90825e2SJohnny Huang {
502d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
503d90825e2SJohnny Huang 
504d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
505696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
506d90825e2SJohnny Huang 			continue;
507d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
508d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
509d90825e2SJohnny Huang 			if (bit_value)
510d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
511d90825e2SJohnny Huang 			else
512d90825e2SJohnny Huang 				continue;
513d90825e2SJohnny Huang 		} else {
51464b66712SJohnny Huang 			if (info_cb.version != OTP_AST2600A3)
515d90825e2SJohnny Huang 				prog_address |= 1 << 15;
516d90825e2SJohnny Huang 			if (bit_value)
517d90825e2SJohnny Huang 				continue;
518d90825e2SJohnny Huang 			else
519d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
520d90825e2SJohnny Huang 		}
521d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
522d90825e2SJohnny Huang 	}
523d90825e2SJohnny Huang }
524d90825e2SJohnny Huang 
52554552c69SJohnny Huang static int otp_prog_verify_2dw(uint32_t *data, uint32_t *buf, uint32_t *ignore_mask, uint32_t prog_address)
52654552c69SJohnny Huang {
52754552c69SJohnny Huang 	int pass;
52854552c69SJohnny Huang 	int i;
52954552c69SJohnny Huang 	uint32_t data0_masked;
53054552c69SJohnny Huang 	uint32_t data1_masked;
53154552c69SJohnny Huang 	uint32_t buf0_masked;
53254552c69SJohnny Huang 	uint32_t buf1_masked;
53354552c69SJohnny Huang 	uint32_t compare[2];
53454552c69SJohnny Huang 
53554552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
53654552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
53754552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
53854552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
53954552c69SJohnny Huang 	if ((data0_masked == buf0_masked) && (data1_masked == buf1_masked))
54054552c69SJohnny Huang 		return 0;
54154552c69SJohnny Huang 
54254552c69SJohnny Huang 	otp_soak(1);
54354552c69SJohnny Huang 	if (data0_masked != buf0_masked)
54454552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
54554552c69SJohnny Huang 	if (data1_masked != buf1_masked)
54654552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
54754552c69SJohnny Huang 
54854552c69SJohnny Huang 	pass = 0;
54954552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
55054552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
55154552c69SJohnny Huang 			otp_soak(2);
55254552c69SJohnny Huang 			if (compare[0] != 0) {
55354552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
55454552c69SJohnny Huang 			}
55554552c69SJohnny Huang 			if (compare[1] != ~0) {
5565537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
55754552c69SJohnny Huang 			}
55854552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
55954552c69SJohnny Huang 				otp_soak(1);
56054552c69SJohnny Huang 			} else {
56154552c69SJohnny Huang 				pass = 1;
56254552c69SJohnny Huang 				break;
56354552c69SJohnny Huang 			}
56454552c69SJohnny Huang 		} else {
56554552c69SJohnny Huang 			pass = 1;
56654552c69SJohnny Huang 			break;
56754552c69SJohnny Huang 		}
56854552c69SJohnny Huang 	}
56954552c69SJohnny Huang 
57054552c69SJohnny Huang 	if (!pass) {
57154552c69SJohnny Huang 		otp_soak(0);
57254552c69SJohnny Huang 		return OTP_FAILURE;
57354552c69SJohnny Huang 	}
57454552c69SJohnny Huang 	return OTP_SUCCESS;
57554552c69SJohnny Huang }
57654552c69SJohnny Huang 
577541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
57876d13988SJohnny Huang {
57976d13988SJohnny Huang 	uint32_t OTPSTRAP_RAW[2];
5805010032bSJohnny Huang 	int strap_end;
58176d13988SJohnny Huang 	int i, j;
58276d13988SJohnny Huang 
5835010032bSJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
58476d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
58576d13988SJohnny Huang 			otpstrap[j].value = 0;
58676d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
58776d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
58876d13988SJohnny Huang 			otpstrap[j].protected = 0;
58976d13988SJohnny Huang 		}
5905010032bSJohnny Huang 		strap_end = 30;
5915010032bSJohnny Huang 	} else {
5925010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
5935010032bSJohnny Huang 			otpstrap[j].value = 0;
5945010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
5955010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
5965010032bSJohnny Huang 			otpstrap[j].reg_protected = 0;
5975010032bSJohnny Huang 			otpstrap[j].protected = 0;
5985010032bSJohnny Huang 		}
5995010032bSJohnny Huang 		strap_end = 28;
6005010032bSJohnny Huang 	}
60176d13988SJohnny Huang 
602dacbba92SJohnny Huang 	otp_soak(0);
6035010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
60476d13988SJohnny Huang 		int option = (i - 16) / 2;
60576d13988SJohnny Huang 		otp_read_config(i, &OTPSTRAP_RAW[0]);
60676d13988SJohnny Huang 		otp_read_config(i + 1, &OTPSTRAP_RAW[1]);
60776d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
60876d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
60976d13988SJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
61076d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
61176d13988SJohnny Huang 			}
61276d13988SJohnny Huang 			if (bit_value == 1)
61376d13988SJohnny Huang 				otpstrap[j].remain_times --;
61476d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
61576d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
61676d13988SJohnny Huang 		}
61776d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
61876d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
61976d13988SJohnny Huang 			if ((bit_value == 0) && (otpstrap[j].writeable_option == -1)) {
62076d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
62176d13988SJohnny Huang 			}
62276d13988SJohnny Huang 			if (bit_value == 1)
62376d13988SJohnny Huang 				otpstrap[j].remain_times --;
62476d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
62576d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
62676d13988SJohnny Huang 		}
62776d13988SJohnny Huang 	}
6285010032bSJohnny Huang 
6295010032bSJohnny Huang 	if (info_cb.version != OTP_AST2600A0) {
6305010032bSJohnny Huang 		otp_read_config(28, &OTPSTRAP_RAW[0]);
6315010032bSJohnny Huang 		otp_read_config(29, &OTPSTRAP_RAW[1]);
6325010032bSJohnny Huang 		for (j = 0; j < 32; j++) {
6335010032bSJohnny Huang 			if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
6345010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
6355010032bSJohnny Huang 		}
6365010032bSJohnny Huang 		for (j = 32; j < 64; j++) {
6375010032bSJohnny Huang 			if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
6385010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
6395010032bSJohnny Huang 		}
6405010032bSJohnny Huang 
6415010032bSJohnny Huang 	}
6425010032bSJohnny Huang 
64376d13988SJohnny Huang 	otp_read_config(30, &OTPSTRAP_RAW[0]);
64476d13988SJohnny Huang 	otp_read_config(31, &OTPSTRAP_RAW[1]);
64576d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
64676d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
64776d13988SJohnny Huang 			otpstrap[j].protected = 1;
64876d13988SJohnny Huang 	}
64976d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
65076d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
65176d13988SJohnny Huang 			otpstrap[j].protected = 1;
65276d13988SJohnny Huang 	}
65376d13988SJohnny Huang }
65476d13988SJohnny Huang 
655696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
65669d5fd8fSJohnny Huang {
65779e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
658696656c6SJohnny Huang 	uint32_t *OTPCFG = (uint32_t *)image_layout->conf;
659696656c6SJohnny Huang 	uint32_t *OTPCFG_IGNORE = (uint32_t *)image_layout->conf_ignore;
660b458cd62SJohnny Huang 	uint32_t mask;
661b458cd62SJohnny Huang 	uint32_t dw_offset;
662b458cd62SJohnny Huang 	uint32_t bit_offset;
663b458cd62SJohnny Huang 	uint32_t otp_value;
664696656c6SJohnny Huang 	uint32_t otp_ignore;
665b458cd62SJohnny Huang 	int fail = 0;
66673f11549SJohnny Huang 	char valid_bit[20];
66766f2f8e5SJohnny Huang 	int i;
66873f11549SJohnny Huang 	int j;
66966f2f8e5SJohnny Huang 
670737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
67166f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
6723cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
6733cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
6743cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
6753cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
676b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
677696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
678b458cd62SJohnny Huang 
679696656c6SJohnny Huang 		if (otp_ignore == mask) {
680b458cd62SJohnny Huang 			continue;
681696656c6SJohnny Huang 		} else if (otp_ignore != 0) {
682b458cd62SJohnny Huang 			fail = 1;
683b458cd62SJohnny Huang 		}
684b458cd62SJohnny Huang 
6853cb28812SJohnny Huang 		if ((otp_value != conf_info[i].value) &&
6863cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
6873cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
6883cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
689b458cd62SJohnny Huang 			continue;
690b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
691b458cd62SJohnny Huang 
6923cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
6933cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
69466f2f8e5SJohnny Huang 		} else {
695b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
6963cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
6973cb28812SJohnny Huang 			       conf_info[i].bit_offset);
69866f2f8e5SJohnny Huang 		}
699b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
700b458cd62SJohnny Huang 
701b458cd62SJohnny Huang 		if (fail) {
702696656c6SJohnny Huang 			printf("Ignore mask error\n");
703b458cd62SJohnny Huang 		} else {
7043cb28812SJohnny Huang 			if (conf_info[i].value == OTP_REG_RESERVED) {
705b458cd62SJohnny Huang 				printf("Reserved\n");
7063cb28812SJohnny Huang 			} else if (conf_info[i].value == OTP_REG_VALUE) {
7073cb28812SJohnny Huang 				printf(conf_info[i].information, otp_value);
708b458cd62SJohnny Huang 				printf("\n");
7093cb28812SJohnny Huang 			} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
710b458cd62SJohnny Huang 				if (otp_value != 0) {
71173f11549SJohnny Huang 					for (j = 0; j < 7; j++) {
71273f11549SJohnny Huang 						if (otp_value == (1 << j)) {
71373f11549SJohnny Huang 							valid_bit[j * 2] = '1';
714b458cd62SJohnny Huang 						} else {
71573f11549SJohnny Huang 							valid_bit[j * 2] = '0';
71673f11549SJohnny Huang 						}
71773f11549SJohnny Huang 						valid_bit[j * 2 + 1] = ' ';
71873f11549SJohnny Huang 					}
71973f11549SJohnny Huang 					valid_bit[15] = 0;
72073f11549SJohnny Huang 				} else {
72173f11549SJohnny Huang 					strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
722b458cd62SJohnny Huang 				}
7233cb28812SJohnny Huang 				printf(conf_info[i].information, valid_bit);
724b458cd62SJohnny Huang 				printf("\n");
725b458cd62SJohnny Huang 			} else {
7263cb28812SJohnny Huang 				printf("%s\n", conf_info[i].information);
727b458cd62SJohnny Huang 			}
728b458cd62SJohnny Huang 		}
729b458cd62SJohnny Huang 	}
730b458cd62SJohnny Huang 
731b458cd62SJohnny Huang 	if (fail)
732b458cd62SJohnny Huang 		return OTP_FAILURE;
733b458cd62SJohnny Huang 
73466f2f8e5SJohnny Huang 	return OTP_SUCCESS;
73566f2f8e5SJohnny Huang }
73666f2f8e5SJohnny Huang 
7372d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
73866f2f8e5SJohnny Huang {
73979e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
740bb34a7bfSJohnny Huang 	uint32_t OTPCFG[16];
741b458cd62SJohnny Huang 	uint32_t mask;
742b458cd62SJohnny Huang 	uint32_t dw_offset;
743b458cd62SJohnny Huang 	uint32_t bit_offset;
744b458cd62SJohnny Huang 	uint32_t otp_value;
74573f11549SJohnny Huang 	char valid_bit[20];
74666f2f8e5SJohnny Huang 	int i;
74773f11549SJohnny Huang 	int j;
74866f2f8e5SJohnny Huang 
749dacbba92SJohnny Huang 	otp_soak(0);
750bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
75166f2f8e5SJohnny Huang 		otp_read_config(i, &OTPCFG[i]);
75266f2f8e5SJohnny Huang 
75366f2f8e5SJohnny Huang 
754b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
755b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
7563cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
7573cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
7582d4b0742SJohnny Huang 			continue;
7593cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
7603cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
7613cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
762b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
763b458cd62SJohnny Huang 
7643cb28812SJohnny Huang 		if ((otp_value != conf_info[i].value) &&
7653cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
7663cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
7673cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
768b458cd62SJohnny Huang 			continue;
769b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
770b458cd62SJohnny Huang 
7713cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
7723cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
773b458cd62SJohnny Huang 		} else {
774b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
7753cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
7763cb28812SJohnny Huang 			       conf_info[i].bit_offset);
777b458cd62SJohnny Huang 		}
778b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
779b458cd62SJohnny Huang 
7803cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
781b458cd62SJohnny Huang 			printf("Reserved\n");
7823cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
7833cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
784b458cd62SJohnny Huang 			printf("\n");
7853cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
786b458cd62SJohnny Huang 			if (otp_value != 0) {
78773f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
78873f11549SJohnny Huang 					if (otp_value == (1 << j)) {
78973f11549SJohnny Huang 						valid_bit[j * 2] = '1';
790b458cd62SJohnny Huang 					} else {
79173f11549SJohnny Huang 						valid_bit[j * 2] = '0';
79273f11549SJohnny Huang 					}
79373f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
79473f11549SJohnny Huang 				}
79573f11549SJohnny Huang 				valid_bit[15] = 0;
79673f11549SJohnny Huang 			} else {
79773f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
798b458cd62SJohnny Huang 			}
7993cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
800b458cd62SJohnny Huang 			printf("\n");
801b458cd62SJohnny Huang 		} else {
8023cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
803b458cd62SJohnny Huang 		}
804b458cd62SJohnny Huang 	}
805b458cd62SJohnny Huang 	return OTP_SUCCESS;
80666f2f8e5SJohnny Huang }
80766f2f8e5SJohnny Huang 
8085010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
80976d13988SJohnny Huang {
81079e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
811696656c6SJohnny Huang 	uint32_t *OTPSTRAP;
812696656c6SJohnny Huang 	uint32_t *OTPSTRAP_REG_PRO;
813696656c6SJohnny Huang 	uint32_t *OTPSTRAP_PRO;
814696656c6SJohnny Huang 	uint32_t *OTPSTRAP_IGNORE;
81576d13988SJohnny Huang 	int i;
816a8bd6d8cSJohnny Huang 	int fail = 0;
817a8bd6d8cSJohnny Huang 	uint32_t bit_offset;
818a8bd6d8cSJohnny Huang 	uint32_t dw_offset;
819a8bd6d8cSJohnny Huang 	uint32_t mask;
820a8bd6d8cSJohnny Huang 	uint32_t otp_value;
821696656c6SJohnny Huang 	uint32_t otp_reg_protect;
822a8bd6d8cSJohnny Huang 	uint32_t otp_protect;
823696656c6SJohnny Huang 	uint32_t otp_ignore;
82476d13988SJohnny Huang 
825696656c6SJohnny Huang 	OTPSTRAP = (uint32_t *)image_layout->strap;
826696656c6SJohnny Huang 	OTPSTRAP_PRO = (uint32_t *)image_layout->strap_pro;
827696656c6SJohnny Huang 	OTPSTRAP_IGNORE = (uint32_t *)image_layout->strap_ignore;
8285010032bSJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
829696656c6SJohnny Huang 		OTPSTRAP_REG_PRO = NULL;
830a8bd6d8cSJohnny Huang 		printf("BIT(hex)   Value       Protect     Description\n");
831696656c6SJohnny Huang 	} else {
832696656c6SJohnny Huang 		OTPSTRAP_REG_PRO = (uint32_t *)image_layout->strap_reg_pro;
833de6b0cc4SJohnny Huang 		printf("BIT(hex)   Value       Reg_Protect Protect     Description\n");
834696656c6SJohnny Huang 	}
835de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
836b458cd62SJohnny Huang 
8373cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
838696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
839a8bd6d8cSJohnny Huang 			dw_offset = 1;
8403cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
841a8bd6d8cSJohnny Huang 		} else {
842a8bd6d8cSJohnny Huang 			dw_offset = 0;
8433cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
844a8bd6d8cSJohnny Huang 		}
84576d13988SJohnny Huang 
8463cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
847a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
848a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
849696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
850a8bd6d8cSJohnny Huang 
8515010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0)
852696656c6SJohnny Huang 			otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask;
8535010032bSJohnny Huang 		else
8545010032bSJohnny Huang 			otp_reg_protect = 0;
855696656c6SJohnny Huang 
856696656c6SJohnny Huang 		if (otp_ignore == mask) {
857a8bd6d8cSJohnny Huang 			continue;
858696656c6SJohnny Huang 		} else if (otp_ignore != 0) {
859a8bd6d8cSJohnny Huang 			fail = 1;
860a8bd6d8cSJohnny Huang 		}
861a8bd6d8cSJohnny Huang 
8623cb28812SJohnny Huang 		if ((otp_value != strap_info[i].value) &&
8633cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
864a8bd6d8cSJohnny Huang 			continue;
865a8bd6d8cSJohnny Huang 
8663cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
8673cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
868a8bd6d8cSJohnny Huang 		} else {
869b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
8703cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
8713cb28812SJohnny Huang 			       strap_info[i].bit_offset);
872a8bd6d8cSJohnny Huang 		}
873a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
8745010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0)
875696656c6SJohnny Huang 			printf("0x%-10x", otp_reg_protect);
876a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
877a8bd6d8cSJohnny Huang 
878a8bd6d8cSJohnny Huang 		if (fail) {
879696656c6SJohnny Huang 			printf("Ignore mask error\n");
880a8bd6d8cSJohnny Huang 		} else {
8813cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
8823cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
883a8bd6d8cSJohnny Huang 			else
884a8bd6d8cSJohnny Huang 				printf("Reserved\n");
885a8bd6d8cSJohnny Huang 		}
886a8bd6d8cSJohnny Huang 	}
887a8bd6d8cSJohnny Huang 
888a8bd6d8cSJohnny Huang 	if (fail)
88976d13988SJohnny Huang 		return OTP_FAILURE;
89076d13988SJohnny Huang 
89176d13988SJohnny Huang 	return OTP_SUCCESS;
89276d13988SJohnny Huang }
89376d13988SJohnny Huang 
894b458cd62SJohnny Huang static int otp_print_strap_info(int view)
89576d13988SJohnny Huang {
89679e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
89776d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
89807baa4e8SJohnny Huang 	int i, j;
899b458cd62SJohnny Huang 	int fail = 0;
900b458cd62SJohnny Huang 	uint32_t bit_offset;
901b458cd62SJohnny Huang 	uint32_t length;
902b458cd62SJohnny Huang 	uint32_t otp_value;
903b458cd62SJohnny Huang 	uint32_t otp_protect;
90476d13988SJohnny Huang 
905541eb887SJohnny Huang 	otp_strap_status(strap_status);
90676d13988SJohnny Huang 
907b458cd62SJohnny Huang 	if (view) {
90883655e91SJohnny Huang 		if (info_cb.version == OTP_AST2600A0)
90907baa4e8SJohnny Huang 			printf("BIT(hex) Value  Remains  Protect   Description\n");
91083655e91SJohnny Huang 		else
91183655e91SJohnny Huang 			printf("BIT(hex) Value  Remains  Reg_Protect Protect   Description\n");
91207baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
913b458cd62SJohnny Huang 	} else {
914b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
915b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
91676d13988SJohnny Huang 	}
9173cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
918b458cd62SJohnny Huang 		otp_value = 0;
9193cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
9203cb28812SJohnny Huang 		length = strap_info[i].length;
921b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
922c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
923c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
924b458cd62SJohnny Huang 		}
9253cb28812SJohnny Huang 		if ((otp_value != strap_info[i].value) &&
9263cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
927b458cd62SJohnny Huang 			continue;
928b458cd62SJohnny Huang 		if (view) {
929b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
9303cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
931b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
93207baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
93383655e91SJohnny Huang 				if (info_cb.version != OTP_AST2600A0)
934e1a7245eSJohnny Huang 					printf("0x%-10X", strap_status[bit_offset + j].reg_protected);
935e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
9363cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
937b458cd62SJohnny Huang 					printf(" Reserved\n");
938b458cd62SJohnny Huang 					continue;
939b458cd62SJohnny Huang 				}
940b458cd62SJohnny Huang 				if (length == 1) {
9413cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
942b458cd62SJohnny Huang 					continue;
94376d13988SJohnny Huang 				}
94476d13988SJohnny Huang 
945b458cd62SJohnny Huang 				if (j == 0)
9463cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
947b458cd62SJohnny Huang 				else if (j == length - 1)
948b458cd62SJohnny Huang 					printf("\\ \"\n");
949b458cd62SJohnny Huang 				else
950b458cd62SJohnny Huang 					printf("| \"\n");
95176d13988SJohnny Huang 			}
952b458cd62SJohnny Huang 		} else {
953c947ef08SJohnny Huang 			if (length == 1) {
9543cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
955b458cd62SJohnny Huang 			} else {
956b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
957b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
958b458cd62SJohnny Huang 			}
959b458cd62SJohnny Huang 
960b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
961b458cd62SJohnny Huang 
9623cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
9633cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
964b458cd62SJohnny Huang 			else
965b458cd62SJohnny Huang 				printf("Reserved\n");
966b458cd62SJohnny Huang 		}
967b458cd62SJohnny Huang 	}
968b458cd62SJohnny Huang 
969b458cd62SJohnny Huang 	if (fail)
970b458cd62SJohnny Huang 		return OTP_FAILURE;
971b458cd62SJohnny Huang 
972b458cd62SJohnny Huang 	return OTP_SUCCESS;
973b458cd62SJohnny Huang }
974b458cd62SJohnny Huang 
975696656c6SJohnny Huang static void buf_print(uint8_t *buf, int len)
97669d5fd8fSJohnny Huang {
97769d5fd8fSJohnny Huang 	int i;
97869d5fd8fSJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
97969d5fd8fSJohnny Huang 	for (i = 0; i < len; i++) {
98069d5fd8fSJohnny Huang 		if (i % 16 == 0) {
98169d5fd8fSJohnny Huang 			printf("%04X: ", i);
98269d5fd8fSJohnny Huang 		}
98369d5fd8fSJohnny Huang 		printf("%02X ", buf[i]);
98469d5fd8fSJohnny Huang 		if ((i + 1) % 16 == 0) {
98569d5fd8fSJohnny Huang 			printf("\n");
98669d5fd8fSJohnny Huang 		}
98769d5fd8fSJohnny Huang 	}
98869d5fd8fSJohnny Huang }
98969d5fd8fSJohnny Huang 
990696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout)
99169d5fd8fSJohnny Huang {
99269d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
99379e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
9949a4fe690SJohnny Huang 	struct otpkey_type key_info;
995696656c6SJohnny Huang 	uint32_t *buf;
996696656c6SJohnny Huang 	uint8_t *byte_buf;
9979d998018SJohnny Huang 	char empty = 1;
99869d5fd8fSJohnny Huang 	int i = 0, len = 0;
9999a4fe690SJohnny Huang 	int j;
100054552c69SJohnny Huang 
1001696656c6SJohnny Huang 	byte_buf = image_layout->data;
1002696656c6SJohnny Huang 	buf = (uint32_t *)byte_buf;
10039d998018SJohnny Huang 
10049d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
10059d998018SJohnny Huang 		if (buf[i] != 0) {
10069d998018SJohnny Huang 			empty = 0;
10079d998018SJohnny Huang 		}
10089d998018SJohnny Huang 	}
10099d998018SJohnny Huang 	if (empty)
10109d998018SJohnny Huang 		return 0;
10119d998018SJohnny Huang 
10129d998018SJohnny Huang 	i = 0;
101369d5fd8fSJohnny Huang 	while (1) {
101469d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
101569d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
101669d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
101769d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
101869d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
101969d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
10209a4fe690SJohnny Huang 
10219a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
10229a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
10239a4fe690SJohnny Huang 				key_info = key_info_array[j];
10249a4fe690SJohnny Huang 				break;
10259a4fe690SJohnny Huang 			}
10269a4fe690SJohnny Huang 		}
10279a4fe690SJohnny Huang 
10287f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
102969d5fd8fSJohnny Huang 		printf("Key Type: ");
10309a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
10319a4fe690SJohnny Huang 
10329a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
103369d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
103469d5fd8fSJohnny Huang 			switch (key_length) {
103569d5fd8fSJohnny Huang 			case 0:
103669d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
103769d5fd8fSJohnny Huang 				break;
103869d5fd8fSJohnny Huang 			case 1:
103969d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
104069d5fd8fSJohnny Huang 				break;
104169d5fd8fSJohnny Huang 			case 2:
104269d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
104369d5fd8fSJohnny Huang 				break;
104469d5fd8fSJohnny Huang 			case 3:
104569d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
104669d5fd8fSJohnny Huang 				break;
104769d5fd8fSJohnny Huang 			}
1048*181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1049*181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
105069d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
105169d5fd8fSJohnny Huang 			switch (key_length) {
105269d5fd8fSJohnny Huang 			case 0:
105369d5fd8fSJohnny Huang 				printf("RSA1024\n");
105469d5fd8fSJohnny Huang 				len = 0x100;
105569d5fd8fSJohnny Huang 				break;
105669d5fd8fSJohnny Huang 			case 1:
105769d5fd8fSJohnny Huang 				printf("RSA2048\n");
105869d5fd8fSJohnny Huang 				len = 0x200;
105969d5fd8fSJohnny Huang 				break;
106069d5fd8fSJohnny Huang 			case 2:
106169d5fd8fSJohnny Huang 				printf("RSA3072\n");
106269d5fd8fSJohnny Huang 				len = 0x300;
106369d5fd8fSJohnny Huang 				break;
106469d5fd8fSJohnny Huang 			case 3:
106569d5fd8fSJohnny Huang 				printf("RSA4096\n");
106669d5fd8fSJohnny Huang 				len = 0x400;
106769d5fd8fSJohnny Huang 				break;
106869d5fd8fSJohnny Huang 			}
106969d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
107069d5fd8fSJohnny Huang 		}
10719a4fe690SJohnny Huang 		if (key_info.need_id)
107269d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
107369d5fd8fSJohnny Huang 		printf("Key Value:\n");
10749a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
107569d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
10769a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
10779a4fe690SJohnny Huang 			printf("AES Key:\n");
10789a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
10795fdde29fSJohnny Huang 			if (info_cb.version == OTP_AST2600A0) {
10809a4fe690SJohnny Huang 				printf("AES IV:\n");
10819a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
10829a4fe690SJohnny Huang 			}
10839a4fe690SJohnny Huang 
10849a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
10855fdde29fSJohnny Huang 			if (info_cb.version == OTP_AST2600A0) {
108669d5fd8fSJohnny Huang 				printf("AES Key:\n");
108769d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
108869d5fd8fSJohnny Huang 				printf("AES IV:\n");
108969d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
10905fdde29fSJohnny Huang 			} else {
10919a4fe690SJohnny Huang 				printf("AES Key 1:\n");
10929a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
10939a4fe690SJohnny Huang 				printf("AES Key 2:\n");
10949a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
10959a4fe690SJohnny Huang 			}
1096*181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
109769d5fd8fSJohnny Huang 			printf("RSA mod:\n");
109869d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
109969d5fd8fSJohnny Huang 			printf("RSA exp:\n");
110069d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1101*181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1102*181f72d8SJohnny Huang 			printf("RSA mod:\n");
1103*181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1104*181f72d8SJohnny Huang 			printf("RSA exp:\n");
1105*181f72d8SJohnny Huang 			buf_print((uint8_t *)"\x01\x00\x01", 3);
110669d5fd8fSJohnny Huang 		}
110769d5fd8fSJohnny Huang 		if (last)
110869d5fd8fSJohnny Huang 			break;
110969d5fd8fSJohnny Huang 		i++;
111069d5fd8fSJohnny Huang 	}
111169d5fd8fSJohnny Huang 	return 0;
111269d5fd8fSJohnny Huang }
111369d5fd8fSJohnny Huang 
11145010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout)
111569d5fd8fSJohnny Huang {
1116a6d0d645SJohnny Huang 	int i, k;
1117d90825e2SJohnny Huang 	int pass = 0;
1118a6d0d645SJohnny Huang 	uint32_t prog_address;
1119bb34a7bfSJohnny Huang 	uint32_t data[16];
1120a6d0d645SJohnny Huang 	uint32_t compare[2];
11215010032bSJohnny Huang 	uint32_t *conf = (uint32_t *)image_layout->conf;
11225010032bSJohnny Huang 	uint32_t *conf_ignore = (uint32_t *)image_layout->conf_ignore;
1123d90825e2SJohnny Huang 	uint32_t data_masked;
1124d90825e2SJohnny Huang 	uint32_t buf_masked;
112569d5fd8fSJohnny Huang 
1126a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1127a6d0d645SJohnny Huang 
1128bb34a7bfSJohnny Huang 	for (i = 0; i < 16 ; i ++) {
112969d5fd8fSJohnny Huang 		prog_address = 0x800;
1130a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1131a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1132a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1133a6d0d645SJohnny Huang 	}
1134a6d0d645SJohnny Huang 
1135a6d0d645SJohnny Huang 	printf("Check writable...\n");
1136bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
11375010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
11385010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1139d90825e2SJohnny Huang 		if (data_masked == buf_masked)
114069d5fd8fSJohnny Huang 			continue;
1141d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1142a6d0d645SJohnny Huang 			continue;
1143a6d0d645SJohnny Huang 		} else {
1144a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1145a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
11465010032bSJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
11475010032bSJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
11482a856b9aSJohnny Huang 			return OTP_FAILURE;
1149a6d0d645SJohnny Huang 		}
1150a6d0d645SJohnny Huang 	}
1151a6d0d645SJohnny Huang 
1152a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1153d90825e2SJohnny Huang 	otp_soak(0);
1154bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
11555010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
11565010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1157a6d0d645SJohnny Huang 		prog_address = 0x800;
1158a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1159a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1160bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1161bb34a7bfSJohnny Huang 			pass = 1;
1162a6d0d645SJohnny Huang 			continue;
1163bb34a7bfSJohnny Huang 		}
1164de6fbf1cSJohnny Huang 
1165a6d0d645SJohnny Huang 
1166de6fbf1cSJohnny Huang 		otp_soak(1);
11675010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1168a6d0d645SJohnny Huang 
116969d5fd8fSJohnny Huang 		pass = 0;
117069d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
11715010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1172de6fbf1cSJohnny Huang 				otp_soak(2);
1173feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
11745010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1175de6fbf1cSJohnny Huang 					otp_soak(1);
1176de6fbf1cSJohnny Huang 				} else {
1177de6fbf1cSJohnny Huang 					pass = 1;
1178de6fbf1cSJohnny Huang 					break;
1179de6fbf1cSJohnny Huang 				}
1180a6d0d645SJohnny Huang 			} else {
118169d5fd8fSJohnny Huang 				pass = 1;
118269d5fd8fSJohnny Huang 				break;
118369d5fd8fSJohnny Huang 			}
118469d5fd8fSJohnny Huang 		}
1185bb34a7bfSJohnny Huang 		if (pass == 0) {
1186bb34a7bfSJohnny Huang 			printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
11875010032bSJohnny Huang 			       i, data[i], conf[i], conf_ignore[i]);
1188bb34a7bfSJohnny Huang 			break;
1189bb34a7bfSJohnny Huang 		}
1190a6d0d645SJohnny Huang 	}
1191a6d0d645SJohnny Huang 
1192de6fbf1cSJohnny Huang 	otp_soak(0);
119369d5fd8fSJohnny Huang 	if (!pass)
11942a856b9aSJohnny Huang 		return OTP_FAILURE;
1195a6d0d645SJohnny Huang 
11962a856b9aSJohnny Huang 	return OTP_SUCCESS;
1197d90825e2SJohnny Huang 
119869d5fd8fSJohnny Huang }
119969d5fd8fSJohnny Huang 
1200eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit)
1201eda10d61SJohnny Huang {
1202eda10d61SJohnny Huang 	if (ibit == 1) {
1203eda10d61SJohnny Huang 		return OTP_SUCCESS;
1204eda10d61SJohnny Huang 	} else {
1205eda10d61SJohnny Huang 		printf("OTPSTRAP[%X]:\n", offset);
1206eda10d61SJohnny Huang 	}
1207eda10d61SJohnny Huang 	if (bit == otpstrap->value) {
1208eda10d61SJohnny Huang 		printf("    The value is same as before, skip it.\n");
1209eda10d61SJohnny Huang 		return OTP_PROG_SKIP;
1210eda10d61SJohnny Huang 	}
1211eda10d61SJohnny Huang 	if (otpstrap->protected == 1) {
1212eda10d61SJohnny Huang 		printf("    This bit is protected and is not writable\n");
1213eda10d61SJohnny Huang 		return OTP_FAILURE;
1214eda10d61SJohnny Huang 	}
1215eda10d61SJohnny Huang 	if (otpstrap->remain_times == 0) {
1216eda10d61SJohnny Huang 		printf("    This bit is no remaining times to write.\n");
1217eda10d61SJohnny Huang 		return OTP_FAILURE;
1218eda10d61SJohnny Huang 	}
1219eda10d61SJohnny Huang 	if (pbit == 1) {
1220eda10d61SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
1221eda10d61SJohnny Huang 	}
1222eda10d61SJohnny Huang 	if (rpbit == 1 && info_cb.version != OTP_AST2600A0) {
1223eda10d61SJohnny Huang 		printf("    The relative register will be protected.\n");
1224eda10d61SJohnny Huang 	}
1225eda10d61SJohnny 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);
1226eda10d61SJohnny Huang 	return OTP_SUCCESS;
1227eda10d61SJohnny Huang }
1228eda10d61SJohnny Huang 
12295010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
123069d5fd8fSJohnny Huang {
123169d5fd8fSJohnny Huang 	int i;
12325010032bSJohnny Huang 	uint32_t *strap;
12335010032bSJohnny Huang 	uint32_t *strap_ignore;
12345010032bSJohnny Huang 	uint32_t *strap_reg_protect;
12355010032bSJohnny Huang 	uint32_t *strap_pro;
1236eda10d61SJohnny Huang 	int bit, pbit, ibit, rpbit;
123769d5fd8fSJohnny Huang 	int fail = 0;
1238a6af4a17SJohnny Huang 	int skip = -1;
1239eda10d61SJohnny Huang 	int ret;
124066f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
124169d5fd8fSJohnny Huang 
12425010032bSJohnny Huang 	strap = (uint32_t *)image_layout->strap;
12435010032bSJohnny Huang 	strap_pro = (uint32_t *)image_layout->strap_pro;
12445010032bSJohnny Huang 	strap_ignore = (uint32_t *)image_layout->strap_ignore;
12455010032bSJohnny Huang 	strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro;
12465010032bSJohnny Huang 
1247541eb887SJohnny Huang 	otp_strap_status(otpstrap);
124869d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
124969d5fd8fSJohnny Huang 		if (i < 32) {
12505010032bSJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1251eda10d61SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
12525010032bSJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
125369d5fd8fSJohnny Huang 		} else {
12545010032bSJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1255eda10d61SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
12565010032bSJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
12575010032bSJohnny Huang 		}
12585010032bSJohnny Huang 
12595010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0) {
12605010032bSJohnny Huang 			if (i < 32) {
12615010032bSJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
12625010032bSJohnny Huang 			} else {
12635010032bSJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
12645010032bSJohnny Huang 			}
12655010032bSJohnny Huang 		} else {
12665010032bSJohnny Huang 			rpbit = 0;
126769d5fd8fSJohnny Huang 		}
1268eda10d61SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit);
1269eda10d61SJohnny Huang 		if (ret == OTP_PROG_SKIP) {
1270a6af4a17SJohnny Huang 			if (skip == -1)
1271a6af4a17SJohnny Huang 				skip = 1;
127269d5fd8fSJohnny Huang 			continue;
1273a6af4a17SJohnny Huang 		} else {
1274eda10d61SJohnny Huang 			skip = 1;
127569d5fd8fSJohnny Huang 		}
1276eda10d61SJohnny Huang 
1277eda10d61SJohnny Huang 		if (ret == OTP_FAILURE)
127869d5fd8fSJohnny Huang 			fail = 1;
127969d5fd8fSJohnny Huang 	}
128069d5fd8fSJohnny Huang 	if (fail == 1)
1281a6af4a17SJohnny Huang 		return OTP_FAILURE;
1282a6af4a17SJohnny Huang 	else if (skip == 1)
1283a6af4a17SJohnny Huang 		return OTP_PROG_SKIP;
12847e22f42dSJohnny Huang 
1285eda10d61SJohnny Huang 	return OTP_SUCCESS;
128669d5fd8fSJohnny Huang }
128769d5fd8fSJohnny Huang 
12882a856b9aSJohnny Huang static int otp_print_strap(int start, int count)
128969d5fd8fSJohnny Huang {
129069d5fd8fSJohnny Huang 	int i, j;
1291de6b0cc4SJohnny Huang 	int remains;
129266f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
129369d5fd8fSJohnny Huang 
12942a856b9aSJohnny Huang 	if (start < 0 || start > 64)
12952a856b9aSJohnny Huang 		return OTP_USAGE;
12962a856b9aSJohnny Huang 
12972a856b9aSJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
12982a856b9aSJohnny Huang 		return OTP_USAGE;
12992a856b9aSJohnny Huang 
1300541eb887SJohnny Huang 	otp_strap_status(otpstrap);
130169d5fd8fSJohnny Huang 
1302de6b0cc4SJohnny Huang 	if (info_cb.version == OTP_AST2600A0) {
1303de6b0cc4SJohnny Huang 		remains = 7;
130407baa4e8SJohnny Huang 		printf("BIT(hex)  Value  Option           Status\n");
1305de6b0cc4SJohnny Huang 	} else {
1306de6b0cc4SJohnny Huang 		remains = 6;
1307de6b0cc4SJohnny Huang 		printf("BIT(hex)  Value  Option         Reg_Protect Status\n");
1308de6b0cc4SJohnny Huang 	}
1309de6b0cc4SJohnny Huang 	printf("______________________________________________________________________________\n");
1310737ed20bSJohnny Huang 
1311cd1610b4SJohnny Huang 	for (i = start; i < start + count; i++) {
131207baa4e8SJohnny Huang 		printf("0x%-8X", i);
1313737ed20bSJohnny Huang 		printf("%-7d", otpstrap[i].value);
1314de6b0cc4SJohnny Huang 		for (j = 0; j < remains; j++)
1315737ed20bSJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
1316737ed20bSJohnny Huang 		printf("   ");
1317de6b0cc4SJohnny Huang 		if (info_cb.version != OTP_AST2600A0) {
1318de6b0cc4SJohnny Huang 			printf("%d           ", otpstrap[i].reg_protected);
1319de6b0cc4SJohnny Huang 		}
132069d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
1321737ed20bSJohnny Huang 			printf("protected and not writable");
132269d5fd8fSJohnny Huang 		} else {
1323737ed20bSJohnny Huang 			printf("not protected ");
132469d5fd8fSJohnny Huang 			if (otpstrap[i].remain_times == 0) {
1325737ed20bSJohnny Huang 				printf("and no remaining times to write.");
132669d5fd8fSJohnny Huang 			} else {
1327737ed20bSJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
132869d5fd8fSJohnny Huang 			}
132969d5fd8fSJohnny Huang 		}
1330737ed20bSJohnny Huang 		printf("\n");
133169d5fd8fSJohnny Huang 	}
13322a856b9aSJohnny Huang 
13332a856b9aSJohnny Huang 	return OTP_SUCCESS;
133469d5fd8fSJohnny Huang }
133569d5fd8fSJohnny Huang 
13368848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value)
13378848d5dcSJohnny Huang {
13388848d5dcSJohnny Huang 	struct otpstrap_status otpstrap[64];
133983655e91SJohnny Huang 	uint32_t prog_address;
13408848d5dcSJohnny Huang 	int offset;
13418848d5dcSJohnny Huang 	int ret;
13428848d5dcSJohnny Huang 
13438848d5dcSJohnny Huang 
13448848d5dcSJohnny Huang 	otp_strap_status(otpstrap);
13458848d5dcSJohnny Huang 
13468848d5dcSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
13478848d5dcSJohnny Huang 
13488848d5dcSJohnny Huang 	if (ret != OTP_SUCCESS) {
13498848d5dcSJohnny Huang 		return ret;
13508848d5dcSJohnny Huang 	}
13518848d5dcSJohnny Huang 
13528848d5dcSJohnny Huang 	prog_address = 0x800;
13538848d5dcSJohnny Huang 	if (bit_offset < 32) {
13548848d5dcSJohnny Huang 		offset = bit_offset;
13558848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
13568848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
13578848d5dcSJohnny Huang 
13588848d5dcSJohnny Huang 	} else {
13598848d5dcSJohnny Huang 		offset = (bit_offset - 32);
13608848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
13618848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
13628848d5dcSJohnny Huang 	}
13638848d5dcSJohnny Huang 
13648848d5dcSJohnny Huang 
136583655e91SJohnny Huang 	return otp_prog_bit(1, prog_address, offset);
13668848d5dcSJohnny Huang }
13678848d5dcSJohnny Huang 
13685010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout)
136969d5fd8fSJohnny Huang {
13705010032bSJohnny Huang 	uint32_t *strap;
13715010032bSJohnny Huang 	uint32_t *strap_ignore;
13725010032bSJohnny Huang 	uint32_t *strap_pro;
13735010032bSJohnny Huang 	uint32_t *strap_reg_protect;
137483655e91SJohnny Huang 	uint32_t prog_address;
137583655e91SJohnny Huang 	int i;
1376eda10d61SJohnny Huang 	int bit, pbit, ibit, offset, rpbit;
137769d5fd8fSJohnny Huang 	int fail = 0;
137883655e91SJohnny Huang 	int ret;
137966f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
138069d5fd8fSJohnny Huang 
13815010032bSJohnny Huang 	strap = (uint32_t *)image_layout->strap;
13825010032bSJohnny Huang 	strap_pro = (uint32_t *)image_layout->strap_pro;
13835010032bSJohnny Huang 	strap_ignore = (uint32_t *)image_layout->strap_ignore;
13845010032bSJohnny Huang 	strap_reg_protect = (uint32_t *)image_layout->strap_reg_pro;
13855010032bSJohnny Huang 
13867f795e57SJohnny Huang 	printf("Read OTP Strap Region:\n");
1387541eb887SJohnny Huang 	otp_strap_status(otpstrap);
138869d5fd8fSJohnny Huang 
13897f795e57SJohnny Huang 	printf("Check writable...\n");
13905010032bSJohnny Huang 	if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
13917f795e57SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
13927f795e57SJohnny Huang 		return OTP_FAILURE;
13937f795e57SJohnny Huang 	}
13947e22f42dSJohnny Huang 
139569d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
139669d5fd8fSJohnny Huang 		prog_address = 0x800;
139769d5fd8fSJohnny Huang 		if (i < 32) {
139869d5fd8fSJohnny Huang 			offset = i;
13995010032bSJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1400eda10d61SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
14015010032bSJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
140269d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
140369d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
140469d5fd8fSJohnny Huang 
140569d5fd8fSJohnny Huang 		} else {
140669d5fd8fSJohnny Huang 			offset = (i - 32);
14075010032bSJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1408eda10d61SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
14095010032bSJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
141069d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
141169d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
141269d5fd8fSJohnny Huang 		}
14135010032bSJohnny Huang 		if (info_cb.version != OTP_AST2600A0) {
14145010032bSJohnny Huang 			if (i < 32) {
14155010032bSJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
14165010032bSJohnny Huang 			} else {
14175010032bSJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
14185010032bSJohnny Huang 			}
14195010032bSJohnny Huang 		} else {
14205010032bSJohnny Huang 			rpbit = 0;
14215010032bSJohnny Huang 		}
142269d5fd8fSJohnny Huang 
1423eda10d61SJohnny Huang 		if (ibit == 1) {
142469d5fd8fSJohnny Huang 			continue;
142569d5fd8fSJohnny Huang 		}
142669d5fd8fSJohnny Huang 		if (bit == otpstrap[i].value) {
142769d5fd8fSJohnny Huang 			continue;
142869d5fd8fSJohnny Huang 		}
142969d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
143069d5fd8fSJohnny Huang 			fail = 1;
143169d5fd8fSJohnny Huang 			continue;
143269d5fd8fSJohnny Huang 		}
143369d5fd8fSJohnny Huang 		if (otpstrap[i].remain_times == 0) {
143469d5fd8fSJohnny Huang 			fail = 1;
143569d5fd8fSJohnny Huang 			continue;
143669d5fd8fSJohnny Huang 		}
14377e22f42dSJohnny Huang 
143883655e91SJohnny Huang 		ret = otp_prog_bit(1, prog_address, offset);
143983655e91SJohnny Huang 		if (!ret)
14402a856b9aSJohnny Huang 			return OTP_FAILURE;
144169d5fd8fSJohnny Huang 
14425010032bSJohnny Huang 		if (rpbit == 1 && info_cb.version != OTP_AST2600A0) {
144369d5fd8fSJohnny Huang 			prog_address = 0x800;
144469d5fd8fSJohnny Huang 			if (i < 32)
14455010032bSJohnny Huang 				prog_address |= 0x608;
144669d5fd8fSJohnny Huang 			else
14475010032bSJohnny Huang 				prog_address |= 0x60a;
14487e22f42dSJohnny Huang 
144983655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
145083655e91SJohnny Huang 			if (!ret)
14512a856b9aSJohnny Huang 				return OTP_FAILURE;
14525010032bSJohnny Huang 		}
14535010032bSJohnny Huang 
14545010032bSJohnny Huang 		if (pbit != 0) {
14555010032bSJohnny Huang 			prog_address = 0x800;
14565010032bSJohnny Huang 			if (i < 32)
14575010032bSJohnny Huang 				prog_address |= 0x60c;
14585010032bSJohnny Huang 			else
14595010032bSJohnny Huang 				prog_address |= 0x60e;
14605010032bSJohnny Huang 
146183655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
146283655e91SJohnny Huang 			if (!ret)
14635010032bSJohnny Huang 				return OTP_FAILURE;
14645010032bSJohnny Huang 		}
146569d5fd8fSJohnny Huang 
146669d5fd8fSJohnny Huang 	}
1467de6fbf1cSJohnny Huang 	otp_soak(0);
146869d5fd8fSJohnny Huang 	if (fail == 1)
14692a856b9aSJohnny Huang 		return OTP_FAILURE;
147069d5fd8fSJohnny Huang 	else
14712a856b9aSJohnny Huang 		return OTP_SUCCESS;
147269d5fd8fSJohnny Huang 
147369d5fd8fSJohnny Huang }
147469d5fd8fSJohnny Huang 
14755010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout)
14764c1c9b35SJohnny Huang {
147754552c69SJohnny Huang 	int i;
147854552c69SJohnny Huang 	int ret;
14795010032bSJohnny Huang 	int data_dw;
1480d90825e2SJohnny Huang 	uint32_t data[2048];
14815010032bSJohnny Huang 	uint32_t *buf;
14825010032bSJohnny Huang 	uint32_t *buf_ignore;
14834c1c9b35SJohnny Huang 
148454552c69SJohnny Huang 	uint32_t data_masked;
148554552c69SJohnny Huang 	uint32_t buf_masked;
14864c1c9b35SJohnny Huang 
14875010032bSJohnny Huang 	buf = (uint32_t *)image_layout->data;
14885010032bSJohnny Huang 	buf_ignore = (uint32_t *)image_layout->data_ignore;
14895010032bSJohnny Huang 
14905010032bSJohnny Huang 	data_dw = image_layout->data_length / 4;
14915010032bSJohnny Huang 
14924c1c9b35SJohnny Huang 	printf("Read OTP Data:\n");
14934c1c9b35SJohnny Huang 
14945010032bSJohnny Huang 	for (i = 0; i < data_dw - 2 ; i += 2) {
1495d90825e2SJohnny Huang 		otp_read_data(i, &data[i]);
14964c1c9b35SJohnny Huang 	}
1497d90825e2SJohnny Huang 
14984c1c9b35SJohnny Huang 	printf("Check writable...\n");
149954552c69SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
15005010032bSJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1501696656c6SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1502696656c6SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
150354552c69SJohnny Huang 		if (data_masked == buf_masked)
15044c1c9b35SJohnny Huang 			continue;
1505d90825e2SJohnny Huang 		if (i % 2 == 0) {
150654552c69SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
15074c1c9b35SJohnny Huang 				continue;
15084c1c9b35SJohnny Huang 			} else {
15094c1c9b35SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1510d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
15114c1c9b35SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1512696656c6SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
15132a856b9aSJohnny Huang 				return OTP_FAILURE;
151469d5fd8fSJohnny Huang 			}
1515d90825e2SJohnny Huang 		} else {
151654552c69SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1517d90825e2SJohnny Huang 				continue;
1518d90825e2SJohnny Huang 			} else {
1519d90825e2SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1520d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1521d90825e2SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1522696656c6SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
15232a856b9aSJohnny Huang 				return OTP_FAILURE;
1524d90825e2SJohnny Huang 			}
1525d90825e2SJohnny Huang 		}
1526d90825e2SJohnny Huang 	}
152769d5fd8fSJohnny Huang 
1528d90825e2SJohnny Huang 	printf("Start Programing...\n");
1529d90825e2SJohnny Huang 
153054552c69SJohnny Huang 	// programing ecc region first
153154552c69SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1532696656c6SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
153354552c69SJohnny Huang 		if (ret != OTP_SUCCESS) {
153454552c69SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1535696656c6SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
153654552c69SJohnny Huang 			return ret;
1537d90825e2SJohnny Huang 		}
1538d90825e2SJohnny Huang 	}
1539d90825e2SJohnny Huang 
154054552c69SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1541696656c6SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
154254552c69SJohnny Huang 		if (ret != OTP_SUCCESS) {
154354552c69SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1544696656c6SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
154554552c69SJohnny Huang 			return ret;
1546d90825e2SJohnny Huang 		}
1547de6fbf1cSJohnny Huang 	}
1548de6fbf1cSJohnny Huang 	otp_soak(0);
15492a856b9aSJohnny Huang 	return OTP_SUCCESS;
1550d90825e2SJohnny Huang 
1551d90825e2SJohnny Huang }
1552d90825e2SJohnny Huang 
1553696656c6SJohnny Huang static int otp_image_verify(uint8_t *src_buf, uint32_t length, uint8_t *digest_buf)
1554696656c6SJohnny Huang {
1555696656c6SJohnny Huang 	sha256_context ctx;
1556696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1557696656c6SJohnny Huang 
1558696656c6SJohnny Huang 	sha256_starts(&ctx);
1559696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1560696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1561696656c6SJohnny Huang 
1562696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1563696656c6SJohnny Huang 		return 0;
1564696656c6SJohnny Huang 	else
1565696656c6SJohnny Huang 		return -1;
1566696656c6SJohnny Huang 
1567696656c6SJohnny Huang }
1568696656c6SJohnny Huang 
1569de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm)
157069d5fd8fSJohnny Huang {
157169d5fd8fSJohnny Huang 	int ret;
15729a4fe690SJohnny Huang 	int image_version = 0;
1573696656c6SJohnny Huang 	struct otp_header *otp_header;
1574696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1575696656c6SJohnny Huang 	int image_size;
1576696656c6SJohnny Huang 	uint8_t *buf;
1577696656c6SJohnny Huang 	uint8_t *checksum;
157869d5fd8fSJohnny Huang 
1579696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1580696656c6SJohnny Huang 	if (!otp_header) {
158169d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
15822a856b9aSJohnny Huang 		return OTP_FAILURE;
158369d5fd8fSJohnny Huang 	}
1584d90825e2SJohnny Huang 
1585696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1586696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1587696656c6SJohnny Huang 
1588696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1589696656c6SJohnny Huang 
1590696656c6SJohnny Huang 	if (!buf) {
1591696656c6SJohnny Huang 		puts("Failed to map physical memory\n");
1592696656c6SJohnny Huang 		return OTP_FAILURE;
1593696656c6SJohnny Huang 	}
1594696656c6SJohnny Huang 	otp_header = (struct otp_header *) buf;
1595696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1596696656c6SJohnny Huang 
1597696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1598696656c6SJohnny Huang 		puts("Image is invalid\n");
1599696656c6SJohnny Huang 		return OTP_FAILURE;
1600696656c6SJohnny Huang 	}
1601696656c6SJohnny Huang 
1602696656c6SJohnny Huang 
16035010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
16045010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
16055010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
16065010032bSJohnny Huang 
16075010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1608696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
16095010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1610696656c6SJohnny Huang 
1611696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
1612696656c6SJohnny Huang 
1613696656c6SJohnny Huang 	if (!strcmp("A0", (char *)otp_header->otp_version)) {
1614696656c6SJohnny Huang 		image_version = OTP_AST2600A0;
16155010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
16165010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
16175010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
1618696656c6SJohnny Huang 	} else if (!strcmp("A1", (char *)otp_header->otp_version)) {
1619696656c6SJohnny Huang 		image_version = OTP_AST2600A1;
16205010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
16215010032bSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
16225010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
16235010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
16245fdde29fSJohnny Huang 	} else if (!strcmp("A2", (char *)otp_header->otp_version)) {
16255fdde29fSJohnny Huang 		image_version = OTP_AST2600A2;
16265fdde29fSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
16275fdde29fSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
16285fdde29fSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
16295fdde29fSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
163064b66712SJohnny Huang 	} else if (!strcmp("A3", (char *)otp_header->otp_version)) {
163164b66712SJohnny Huang 		image_version = OTP_AST2600A3;
163264b66712SJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
163364b66712SJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
163464b66712SJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
163564b66712SJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
1636696656c6SJohnny Huang 	} else {
1637696656c6SJohnny Huang 		puts("Version is not supported\n");
1638696656c6SJohnny Huang 		return OTP_FAILURE;
1639696656c6SJohnny Huang 	}
1640696656c6SJohnny Huang 
16419a4fe690SJohnny Huang 	if (image_version != info_cb.version) {
16429a4fe690SJohnny Huang 		puts("Version is not match\n");
16439a4fe690SJohnny Huang 		return OTP_FAILURE;
16449a4fe690SJohnny Huang 	}
16459a4fe690SJohnny Huang 
1646696656c6SJohnny Huang 	if (otp_image_verify(buf, image_size, checksum)) {
1647696656c6SJohnny Huang 		puts("checksum is invalid\n");
1648696656c6SJohnny Huang 		return OTP_FAILURE;
1649d90825e2SJohnny Huang 	}
16507332532cSJohnny Huang 
165169d5fd8fSJohnny Huang 	if (!nconfirm) {
1652696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
16537f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1654696656c6SJohnny Huang 			if (otp_print_data_info(&image_layout) < 0) {
165569d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
16562a856b9aSJohnny Huang 				return OTP_FAILURE;
165769d5fd8fSJohnny Huang 			}
165869d5fd8fSJohnny Huang 		}
1659696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
16607332532cSJohnny Huang 			printf("\nOTP strap region :\n");
16615010032bSJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
16627332532cSJohnny Huang 				printf("OTP strap error, please check.\n");
16637332532cSJohnny Huang 				return OTP_FAILURE;
16647332532cSJohnny Huang 			}
16657332532cSJohnny Huang 		}
1666696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
16677332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1668696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
16697332532cSJohnny Huang 				printf("OTP config error, please check.\n");
16707332532cSJohnny Huang 				return OTP_FAILURE;
16717332532cSJohnny Huang 			}
16727332532cSJohnny Huang 		}
16737332532cSJohnny Huang 
167469d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
167569d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
167669d5fd8fSJohnny Huang 			printf(" Aborting\n");
16772a856b9aSJohnny Huang 			return OTP_FAILURE;
167869d5fd8fSJohnny Huang 		}
167969d5fd8fSJohnny Huang 	}
16807332532cSJohnny Huang 
16815010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
16825010032bSJohnny Huang 		printf("programing data region ...\n");
16835010032bSJohnny Huang 		ret = otp_prog_data(&image_layout);
16845010032bSJohnny Huang 		if (ret != 0) {
16855010032bSJohnny Huang 			printf("Error\n");
16865010032bSJohnny Huang 			return ret;
16875010032bSJohnny Huang 		} else {
16885010032bSJohnny Huang 			printf("Done\n");
16895010032bSJohnny Huang 		}
16905010032bSJohnny Huang 	}
16915010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
16925010032bSJohnny Huang 		printf("programing strap region ...\n");
16935010032bSJohnny Huang 		ret = otp_prog_strap(&image_layout);
16945010032bSJohnny Huang 		if (ret != 0) {
16955010032bSJohnny Huang 			printf("Error\n");
16965010032bSJohnny Huang 			return ret;
16975010032bSJohnny Huang 		} else {
16985010032bSJohnny Huang 			printf("Done\n");
16995010032bSJohnny Huang 		}
17005010032bSJohnny Huang 	}
17015010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
17025010032bSJohnny Huang 		printf("programing configuration region ...\n");
17035010032bSJohnny Huang 		ret = otp_prog_conf(&image_layout);
17045010032bSJohnny Huang 		if (ret != 0) {
17055010032bSJohnny Huang 			printf("Error\n");
17065010032bSJohnny Huang 			return ret;
17075010032bSJohnny Huang 		}
17085010032bSJohnny Huang 		printf("Done\n");
17095010032bSJohnny Huang 	}
1710cd1610b4SJohnny Huang 
17117332532cSJohnny Huang 	return OTP_SUCCESS;
17122a856b9aSJohnny Huang }
17132a856b9aSJohnny Huang 
17142a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1715cd1610b4SJohnny Huang {
1716a6af4a17SJohnny Huang 	uint32_t read[2];
1717d90825e2SJohnny Huang 	uint32_t prog_address = 0;
171866f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1719cd1610b4SJohnny Huang 	int otp_bit;
172083655e91SJohnny Huang 	int ret = 0;
1721cd1610b4SJohnny Huang 
1722dacbba92SJohnny Huang 	otp_soak(0);
1723cd1610b4SJohnny Huang 	switch (mode) {
1724a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1725a6af4a17SJohnny Huang 		otp_read_config(otp_dw_offset, read);
1726cd1610b4SJohnny Huang 		prog_address = 0x800;
1727cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1728cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1729a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1730cd1610b4SJohnny Huang 		if (otp_bit == value) {
1731a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1732cd1610b4SJohnny Huang 			printf("No need to program\n");
17332a856b9aSJohnny Huang 			return OTP_SUCCESS;
1734cd1610b4SJohnny Huang 		}
1735cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1736a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
1737cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
17382a856b9aSJohnny Huang 			return OTP_FAILURE;
1739cd1610b4SJohnny Huang 		}
1740a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1741cd1610b4SJohnny Huang 		break;
1742a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1743cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1744cd1610b4SJohnny Huang 
1745cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1746a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1747a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1748643b9cfdSJohnny Huang 
1749643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
1750643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1751643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be cleaned\n");
1752643b9cfdSJohnny Huang 				return OTP_FAILURE;
1753643b9cfdSJohnny Huang 			}
1754cd1610b4SJohnny Huang 		} else {
1755a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1756a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1757643b9cfdSJohnny Huang 
1758643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
1759643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1760643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be writen\n");
1761643b9cfdSJohnny Huang 				return OTP_FAILURE;
1762643b9cfdSJohnny Huang 			}
1763cd1610b4SJohnny Huang 		}
1764cd1610b4SJohnny Huang 		if (otp_bit == value) {
1765a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1766cd1610b4SJohnny Huang 			printf("No need to program\n");
17672a856b9aSJohnny Huang 			return OTP_SUCCESS;
1768cd1610b4SJohnny Huang 		}
1769643b9cfdSJohnny Huang 
1770a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1771cd1610b4SJohnny Huang 		break;
1772a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
17738848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
17748848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
17758848d5dcSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
17768848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
17778848d5dcSJohnny Huang 			return OTP_FAILURE;
17788848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
17798848d5dcSJohnny Huang 			return OTP_SUCCESS;
1780a6af4a17SJohnny Huang 
1781cd1610b4SJohnny Huang 		break;
1782cd1610b4SJohnny Huang 	}
1783cd1610b4SJohnny Huang 
1784cd1610b4SJohnny Huang 	if (!nconfirm) {
1785cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1786cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1787cd1610b4SJohnny Huang 			printf(" Aborting\n");
17882a856b9aSJohnny Huang 			return OTP_FAILURE;
1789cd1610b4SJohnny Huang 		}
1790cd1610b4SJohnny Huang 	}
1791cd1610b4SJohnny Huang 
1792cd1610b4SJohnny Huang 	switch (mode) {
1793a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
179483655e91SJohnny Huang 		ret =  otp_prog_strap_bit(bit_offset, value);
179583655e91SJohnny Huang 		break;
1796a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1797a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
179883655e91SJohnny Huang 		ret = otp_prog_bit(value, prog_address, bit_offset);
1799de6fbf1cSJohnny Huang 		break;
1800de6fbf1cSJohnny Huang 	}
1801de6fbf1cSJohnny Huang 	otp_soak(0);
180283655e91SJohnny Huang 	if (ret) {
18039009c25dSJohnny Huang 		printf("SUCCESS\n");
18042a856b9aSJohnny Huang 		return OTP_SUCCESS;
18059009c25dSJohnny Huang 	} else {
18069009c25dSJohnny Huang 		printf("OTP cannot be programed\n");
18079009c25dSJohnny Huang 		printf("FAILED\n");
18089009c25dSJohnny Huang 		return OTP_FAILURE;
18099009c25dSJohnny Huang 	}
1810cd1610b4SJohnny Huang 
18112a856b9aSJohnny Huang 	return OTP_USAGE;
1812cd1610b4SJohnny Huang }
1813cd1610b4SJohnny Huang 
18142a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
181569d5fd8fSJohnny Huang {
18162a856b9aSJohnny Huang 	uint32_t offset, count;
18172a856b9aSJohnny Huang 	int ret;
181869d5fd8fSJohnny Huang 
18192a856b9aSJohnny Huang 	if (argc == 4) {
18202a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
18212a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
18222a856b9aSJohnny Huang 	} else if (argc == 3) {
18232a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
18242a856b9aSJohnny Huang 		count = 1;
18252a856b9aSJohnny Huang 	} else {
182669d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
182769d5fd8fSJohnny Huang 	}
182869d5fd8fSJohnny Huang 
182969d5fd8fSJohnny Huang 
18302a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
18313d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
18322a856b9aSJohnny Huang 		ret = otp_print_config(offset, count);
18332a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
18343d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
18352a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
18362a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
18373d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
18382a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
18392a856b9aSJohnny Huang 	} else {
18402a856b9aSJohnny Huang 		return CMD_RET_USAGE;
184169d5fd8fSJohnny Huang 	}
184269d5fd8fSJohnny Huang 
18432a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
18442a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
18452a856b9aSJohnny Huang 	else
18462a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18472a856b9aSJohnny Huang 
18482a856b9aSJohnny Huang }
18492a856b9aSJohnny Huang 
18502a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
18512a856b9aSJohnny Huang {
18522a856b9aSJohnny Huang 	phys_addr_t addr;
18532a856b9aSJohnny Huang 	int ret;
18542a856b9aSJohnny Huang 
1855de6b0cc4SJohnny Huang 	if (argc == 3) {
1856ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
18572a856b9aSJohnny Huang 			return CMD_RET_USAGE;
18582a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
18593d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1860de6b0cc4SJohnny Huang 		ret = do_otp_prog(addr, 1);
1861de6b0cc4SJohnny Huang 	} else if (argc == 2) {
18622a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
18633d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1864de6b0cc4SJohnny Huang 		ret = do_otp_prog(addr, 0);
18652a856b9aSJohnny Huang 	} else {
18662a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18672a856b9aSJohnny Huang 	}
18682a856b9aSJohnny Huang 
18692a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
18702a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
18712a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
18722a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
18732a856b9aSJohnny Huang 	else
18742a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18752a856b9aSJohnny Huang }
18762a856b9aSJohnny Huang 
18772a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
18782a856b9aSJohnny Huang {
18792a856b9aSJohnny Huang 	int mode = 0;
18802a856b9aSJohnny Huang 	int nconfirm = 0;
18812a856b9aSJohnny Huang 	int otp_addr = 0;
18822a856b9aSJohnny Huang 	int bit_offset;
18832a856b9aSJohnny Huang 	int value;
18842a856b9aSJohnny Huang 	int ret;
18852a856b9aSJohnny Huang 
18862a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
18872a856b9aSJohnny Huang 		return CMD_RET_USAGE;
18882a856b9aSJohnny Huang 
18892a856b9aSJohnny Huang 	/* Drop the pb cmd */
18902a856b9aSJohnny Huang 	argc--;
18912a856b9aSJohnny Huang 	argv++;
18922a856b9aSJohnny Huang 
18932a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
1894a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
18952a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
1896a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
18972a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
1898a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
1899cd1610b4SJohnny Huang 	else
19002a856b9aSJohnny Huang 		return CMD_RET_USAGE;
19012a856b9aSJohnny Huang 
19022a856b9aSJohnny Huang 	/* Drop the region cmd */
19032a856b9aSJohnny Huang 	argc--;
19042a856b9aSJohnny Huang 	argv++;
19052a856b9aSJohnny Huang 
1906ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
1907cd1610b4SJohnny Huang 		nconfirm = 1;
19082a856b9aSJohnny Huang 		/* Drop the force option */
19092a856b9aSJohnny Huang 		argc--;
19102a856b9aSJohnny Huang 		argv++;
19112a856b9aSJohnny Huang 	}
1912cd1610b4SJohnny Huang 
1913a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
19142a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
19152a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
19160808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
19172a856b9aSJohnny Huang 			return CMD_RET_USAGE;
1918cd1610b4SJohnny Huang 	} else {
19192a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
19202a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
19212a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
19220808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
19232a856b9aSJohnny Huang 			return CMD_RET_USAGE;
19240808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
192578855207SJohnny Huang 			if (otp_addr >= 0x800)
19260808cc55SJohnny Huang 				return CMD_RET_USAGE;
19270808cc55SJohnny Huang 		} else {
192878855207SJohnny Huang 			if (otp_addr >= 0x20)
19290808cc55SJohnny Huang 				return CMD_RET_USAGE;
19300808cc55SJohnny Huang 		}
1931cd1610b4SJohnny Huang 	}
1932cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
19332a856b9aSJohnny Huang 		return CMD_RET_USAGE;
1934cd1610b4SJohnny Huang 
19353d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19362a856b9aSJohnny Huang 	ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
19372a856b9aSJohnny Huang 
19382a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
19392a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
19402a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
19412a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
19422a856b9aSJohnny Huang 	else
19432a856b9aSJohnny Huang 		return CMD_RET_USAGE;
19442a856b9aSJohnny Huang }
19452a856b9aSJohnny Huang 
19462a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
19472a856b9aSJohnny Huang {
19482a856b9aSJohnny Huang 	phys_addr_t addr;
19492a856b9aSJohnny Huang 	int otp_addr = 0;
19502a856b9aSJohnny Huang 
19512a856b9aSJohnny Huang 	if (argc != 3)
19522a856b9aSJohnny Huang 		return CMD_RET_USAGE;
19532a856b9aSJohnny Huang 
19543d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19552a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
19562a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
19572a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
195869d5fd8fSJohnny Huang 		printf("Compare pass\n");
19592a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
196069d5fd8fSJohnny Huang 	} else {
196169d5fd8fSJohnny Huang 		printf("Compare fail\n");
19622a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
196369d5fd8fSJohnny Huang 	}
196469d5fd8fSJohnny Huang }
196569d5fd8fSJohnny Huang 
196666f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
196766f2f8e5SJohnny Huang {
1968a8bd6d8cSJohnny Huang 	int view = 0;
19692d4b0742SJohnny Huang 	int input;
1970a8bd6d8cSJohnny Huang 
1971a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
197266f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
197366f2f8e5SJohnny Huang 
19742d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
197566f2f8e5SJohnny Huang 
19763d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19772d4b0742SJohnny Huang 		if (argc == 3) {
19782d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
19792d4b0742SJohnny Huang 			otp_print_conf_info(input);
19802d4b0742SJohnny Huang 		} else {
19812d4b0742SJohnny Huang 			otp_print_conf_info(-1);
19822d4b0742SJohnny Huang 		}
19832d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
19842d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
1985a8bd6d8cSJohnny Huang 			view = 1;
1986a8bd6d8cSJohnny Huang 			/* Drop the view option */
1987a8bd6d8cSJohnny Huang 			argc--;
1988a8bd6d8cSJohnny Huang 			argv++;
1989a8bd6d8cSJohnny Huang 		}
19903d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1991b458cd62SJohnny Huang 		otp_print_strap_info(view);
199266f2f8e5SJohnny Huang 	} else {
199366f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
199466f2f8e5SJohnny Huang 	}
19952d4b0742SJohnny Huang 
199666f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
199766f2f8e5SJohnny Huang }
199866f2f8e5SJohnny Huang 
1999737ed20bSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2000737ed20bSJohnny Huang {
2001737ed20bSJohnny Huang 	int input;
2002737ed20bSJohnny Huang 	int bit_offset;
2003737ed20bSJohnny Huang 	int prog_address;
200483655e91SJohnny Huang 	int ret;
2005737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2006737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2007737ed20bSJohnny Huang 
2008ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2009737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2010737ed20bSJohnny Huang 	} else {
2011737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2012737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] will be protected\n", input);
2013737ed20bSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2014737ed20bSJohnny Huang 		if (!confirm_yesno()) {
2015737ed20bSJohnny Huang 			printf(" Aborting\n");
2016737ed20bSJohnny Huang 			return CMD_RET_FAILURE;
2017737ed20bSJohnny Huang 		}
2018737ed20bSJohnny Huang 	}
2019737ed20bSJohnny Huang 
2020737ed20bSJohnny Huang 	prog_address = 0x800;
2021737ed20bSJohnny Huang 	if (input < 32) {
2022737ed20bSJohnny Huang 		bit_offset = input;
2023737ed20bSJohnny Huang 		prog_address |= 0x60c;
2024737ed20bSJohnny Huang 	} else if (input < 64) {
2025737ed20bSJohnny Huang 		bit_offset = input - 32;
2026737ed20bSJohnny Huang 		prog_address |= 0x60e;
2027737ed20bSJohnny Huang 	} else {
2028737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2029737ed20bSJohnny Huang 	}
2030737ed20bSJohnny Huang 
2031737ed20bSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2032737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] already protected\n", input);
2033737ed20bSJohnny Huang 	}
2034de6fbf1cSJohnny Huang 
203583655e91SJohnny Huang 	ret = otp_prog_bit(1, prog_address, bit_offset);
2036de6fbf1cSJohnny Huang 	otp_soak(0);
203783655e91SJohnny Huang 
203883655e91SJohnny Huang 	if (ret) {
2039737ed20bSJohnny Huang 		printf("OTPSTRAP[%d] is protected\n", input);
2040737ed20bSJohnny Huang 		return CMD_RET_SUCCESS;
2041737ed20bSJohnny Huang 	}
2042737ed20bSJohnny Huang 
2043737ed20bSJohnny Huang 	printf("Protect OTPSTRAP[%d] fail\n", input);
2044737ed20bSJohnny Huang 	return CMD_RET_FAILURE;
2045737ed20bSJohnny Huang 
2046737ed20bSJohnny Huang }
20479a4fe690SJohnny Huang 
2048f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2049f67375f7SJohnny Huang {
2050f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2051f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2052f67375f7SJohnny Huang 
2053f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2054f67375f7SJohnny Huang }
2055f67375f7SJohnny Huang 
20562a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2057f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
20582a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2059a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2060de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
20612a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2062737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
20632a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
20642a856b9aSJohnny Huang };
20652a856b9aSJohnny Huang 
20662a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20672a856b9aSJohnny Huang {
20682a856b9aSJohnny Huang 	cmd_tbl_t *cp;
20690dae9d52SJohnny Huang 	uint32_t ver;
20702a856b9aSJohnny Huang 
20712a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
20722a856b9aSJohnny Huang 
2073737ed20bSJohnny Huang 	/* Drop the otp command */
20742a856b9aSJohnny Huang 	argc--;
20752a856b9aSJohnny Huang 	argv++;
20762a856b9aSJohnny Huang 
20772a856b9aSJohnny Huang 	if (cp == NULL || argc > cp->maxargs)
20782a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20792a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
20802a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20812a856b9aSJohnny Huang 
20820dae9d52SJohnny Huang 	ver = chip_version();
20830dae9d52SJohnny Huang 	switch (ver) {
20840dae9d52SJohnny Huang 	case OTP_AST2600A0:
2085696656c6SJohnny Huang 		info_cb.version = OTP_AST2600A0;
20869a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
20879a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
20889a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
20899a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
20909a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
20919a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
20920dae9d52SJohnny Huang 		break;
20930dae9d52SJohnny Huang 	case OTP_AST2600A1:
2094696656c6SJohnny Huang 		info_cb.version = OTP_AST2600A1;
20953cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
20963cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
20973cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
20983cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
20999a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
21009a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
21010dae9d52SJohnny Huang 		break;
21020dae9d52SJohnny Huang 	case OTP_AST2600A2:
21035fdde29fSJohnny Huang 		info_cb.version = OTP_AST2600A2;
21045fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
21055fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
21065fdde29fSJohnny Huang 		info_cb.strap_info = a2_strap_info;
21075fdde29fSJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
21085fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
21095fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
21100dae9d52SJohnny Huang 		break;
211164b66712SJohnny Huang 	case OTP_AST2600A3:
211264b66712SJohnny Huang 		info_cb.version = OTP_AST2600A3;
211364b66712SJohnny Huang 		info_cb.conf_info = a2_conf_info;
211464b66712SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
211564b66712SJohnny Huang 		info_cb.strap_info = a2_strap_info;
211664b66712SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
2117*181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2118*181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
211964b66712SJohnny Huang 		break;
21200dae9d52SJohnny Huang 	default:
2121f1be5099SJohnny Huang 		printf("SOC is not supported\n");
21220dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
21239a4fe690SJohnny Huang 	}
21249a4fe690SJohnny Huang 
21252a856b9aSJohnny Huang 	return cp->cmd(cmdtp, flag, argc, argv);
212669d5fd8fSJohnny Huang }
212769d5fd8fSJohnny Huang 
212869d5fd8fSJohnny Huang U_BOOT_CMD(
212969d5fd8fSJohnny Huang 	otp, 7, 0,  do_ast_otp,
213069d5fd8fSJohnny Huang 	"ASPEED One-Time-Programmable sub-system",
2131f67375f7SJohnny Huang 	"version\n"
2132f67375f7SJohnny Huang 	"otp read conf|data <otp_dw_offset> <dw_count>\n"
21332a856b9aSJohnny Huang 	"otp read strap <strap_bit_offset> <bit_count>\n"
21342d4b0742SJohnny Huang 	"otp info strap [v]\n"
21352d4b0742SJohnny Huang 	"otp info conf [otp_dw_offset]\n"
2136de6b0cc4SJohnny Huang 	"otp prog [o] <addr>\n"
2137ed071a2bSJohnny Huang 	"otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2138ed071a2bSJohnny Huang 	"otp pb strap [o] <bit_offset> <value>\n"
2139ed071a2bSJohnny Huang 	"otp protect [o] <bit_offset>\n"
21402a856b9aSJohnny Huang 	"otp cmp <addr> <otp_dw_offset>\n"
214169d5fd8fSJohnny Huang );
2142