xref: /openbmc/u-boot/cmd/otp.c (revision a3dcef3036395613e9aa4ea4b3b97dee8d51952d)
1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+
269d5fd8fSJohnny Huang /*
3a219f6deSJohnny Huang  * Copyright 2021 Aspeed Technology Inc.
469d5fd8fSJohnny Huang  */
5e417205bSJohnny Huang 
64c1c9b35SJohnny Huang #include <stdlib.h>
769d5fd8fSJohnny Huang #include <common.h>
869d5fd8fSJohnny Huang #include <console.h>
969d5fd8fSJohnny Huang #include <bootretry.h>
1069d5fd8fSJohnny Huang #include <cli.h>
1169d5fd8fSJohnny Huang #include <command.h>
1269d5fd8fSJohnny Huang #include <console.h>
134c1c9b35SJohnny Huang #include <malloc.h>
1469d5fd8fSJohnny Huang #include <inttypes.h>
1569d5fd8fSJohnny Huang #include <mapmem.h>
1669d5fd8fSJohnny Huang #include <asm/io.h>
1769d5fd8fSJohnny Huang #include <linux/compiler.h>
182031a123SJohnny Huang #include <linux/iopoll.h>
19*a3dcef30SJohnny Huang #include <u-boot/sha512.h>
200cee9a95SJohnny Huang #include "otp_info.h"
2169d5fd8fSJohnny Huang 
2269d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2369d5fd8fSJohnny Huang 
24*a3dcef30SJohnny Huang #define OTP_VER				"2.0.0"
25f67375f7SJohnny Huang 
2669d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
27dacbba92SJohnny Huang #define RETRY				20
287332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
297332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
307332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3169d5fd8fSJohnny Huang 
322a856b9aSJohnny Huang #define OTP_USAGE			-1
332a856b9aSJohnny Huang #define OTP_FAILURE			-2
342a856b9aSJohnny Huang #define OTP_SUCCESS			0
352a856b9aSJohnny Huang 
36a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
37a6af4a17SJohnny Huang 
38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB		1
39181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV		2
40181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES		3
41181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT		4
42181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC		5
439a4fe690SJohnny Huang 
443d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
453d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
463d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
473d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
483d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
493d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
503d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
513d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
523d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
533d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
54a8789b47SJohnny Huang #define SW_REV_ID0		OTP_BASE + 0x68
55a8789b47SJohnny Huang #define SW_REV_ID1		OTP_BASE + 0x6c
56030cb4a7SJohnny Huang #define SEC_KEY_NUM		OTP_BASE + 0x78
573d3688adSJohnny Huang 
58696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
59696656c6SJohnny Huang #define CHECKSUM_LEN		32
60a219f6deSJohnny Huang #define OTP_INC_DATA		BIT(31)
61a219f6deSJohnny Huang #define OTP_INC_CONFIG		BIT(30)
62a219f6deSJohnny Huang #define OTP_INC_STRAP		BIT(29)
63a219f6deSJohnny Huang #define OTP_ECC_EN		BIT(28)
64b25f02d2SJohnny Huang #define OTP_INC_SCU_PRO		BIT(25)
65696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
66696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
67696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
68696656c6SJohnny Huang 
69e417205bSJohnny Huang #define OTP_A0		0
70e417205bSJohnny Huang #define OTP_A1		1
71e417205bSJohnny Huang #define OTP_A2		2
72e417205bSJohnny Huang #define OTP_A3		3
73e417205bSJohnny Huang 
74e417205bSJohnny Huang #define ID0_AST2600A0	0x05000303
75e417205bSJohnny Huang #define ID1_AST2600A0	0x05000303
76e417205bSJohnny Huang #define ID0_AST2600A1	0x05010303
7721a8cfceSJohnny Huang #define ID1_AST2600A1	0x05010303
78e417205bSJohnny Huang #define ID0_AST2600A2	0x05010303
79e417205bSJohnny Huang #define ID1_AST2600A2	0x05020303
80e417205bSJohnny Huang #define ID0_AST2600A3	0x05030303
81e417205bSJohnny Huang #define ID1_AST2600A3	0x05030303
82e417205bSJohnny Huang #define ID0_AST2620A1	0x05010203
83e417205bSJohnny Huang #define ID1_AST2620A1	0x05010203
84e417205bSJohnny Huang #define ID0_AST2620A2	0x05010203
85e417205bSJohnny Huang #define ID1_AST2620A2	0x05020203
86e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
87e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
88e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
89e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
90e417205bSJohnny Huang #define ID0_AST2605A2	0x05010103
91e417205bSJohnny Huang #define ID1_AST2605A2	0x05020103
92e417205bSJohnny Huang #define ID0_AST2605A3	0x05030103
93e417205bSJohnny Huang #define ID1_AST2605A3	0x05030103
94e417205bSJohnny Huang #define ID0_AST2625A3	0x05030403
95e417205bSJohnny Huang #define ID1_AST2625A3	0x05030403
96696656c6SJohnny Huang 
9761a6cda7SJohnny Huang #define SOC_AST2600A0	0
9861a6cda7SJohnny Huang #define SOC_AST2600A1	1
9961a6cda7SJohnny Huang #define SOC_AST2600A2	2
10061a6cda7SJohnny Huang #define SOC_AST2600A3	3
10161a6cda7SJohnny Huang 
10261a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c))
1035e096f11SJohnny Huang #define OTPTOOL_VERSION_MAJOR(x) (((x) >> 24) & 0xff)
1045e096f11SJohnny Huang #define OTPTOOL_VERSION_PATCHLEVEL(x) (((x) >> 12) & 0xfff)
1055e096f11SJohnny Huang #define OTPTOOL_VERSION_SUBLEVEL(x) ((x) & 0xfff)
106*a3dcef30SJohnny Huang #define OTPTOOL_COMPT_VERSION 2
10761a6cda7SJohnny Huang 
108696656c6SJohnny Huang struct otp_header {
109696656c6SJohnny Huang 	u8	otp_magic[8];
11061a6cda7SJohnny Huang 	u32	soc_ver;
11161a6cda7SJohnny Huang 	u32	otptool_ver;
112696656c6SJohnny Huang 	u32	image_info;
113696656c6SJohnny Huang 	u32	data_info;
114696656c6SJohnny Huang 	u32	config_info;
115696656c6SJohnny Huang 	u32	strap_info;
1167e523e3bSJohnny Huang 	u32	scu_protect_info;
117696656c6SJohnny Huang 	u32	checksum_offset;
118a219f6deSJohnny Huang } __packed;
119696656c6SJohnny Huang 
12066f2f8e5SJohnny Huang struct otpstrap_status {
12169d5fd8fSJohnny Huang 	int value;
12269d5fd8fSJohnny Huang 	int option_array[7];
12369d5fd8fSJohnny Huang 	int remain_times;
12469d5fd8fSJohnny Huang 	int writeable_option;
12569d5fd8fSJohnny Huang 	int protected;
12669d5fd8fSJohnny Huang };
12769d5fd8fSJohnny Huang 
1289a4fe690SJohnny Huang struct otpkey_type {
1299a4fe690SJohnny Huang 	int value;
1309a4fe690SJohnny Huang 	int key_type;
1319a4fe690SJohnny Huang 	int need_id;
1329a4fe690SJohnny Huang 	char information[110];
1339a4fe690SJohnny Huang };
1349a4fe690SJohnny Huang 
135030cb4a7SJohnny Huang struct otp_pro_sts {
136030cb4a7SJohnny Huang 	char mem_lock;
137030cb4a7SJohnny Huang 	char pro_key_ret;
138030cb4a7SJohnny Huang 	char pro_strap;
139030cb4a7SJohnny Huang 	char pro_conf;
140030cb4a7SJohnny Huang 	char pro_data;
141030cb4a7SJohnny Huang 	char pro_sec;
142030cb4a7SJohnny Huang 	u32 sec_size;
143030cb4a7SJohnny Huang };
144030cb4a7SJohnny Huang 
1459a4fe690SJohnny Huang struct otp_info_cb {
1469a4fe690SJohnny Huang 	int version;
147e417205bSJohnny Huang 	char ver_name[3];
14879e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1499a4fe690SJohnny Huang 	int strap_info_len;
15079e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1519a4fe690SJohnny Huang 	int conf_info_len;
15279e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1539a4fe690SJohnny Huang 	int key_info_len;
1540dc9a440SJohnny Huang 	const struct scu_info *scu_info;
1550dc9a440SJohnny Huang 	int scu_info_len;
156030cb4a7SJohnny Huang 	struct otp_pro_sts pro_sts;
1579a4fe690SJohnny Huang };
1589a4fe690SJohnny Huang 
159696656c6SJohnny Huang struct otp_image_layout {
1605010032bSJohnny Huang 	int data_length;
1615010032bSJohnny Huang 	int conf_length;
1625010032bSJohnny Huang 	int strap_length;
163b25f02d2SJohnny Huang 	int scu_pro_length;
164a219f6deSJohnny Huang 	u8 *data;
165a219f6deSJohnny Huang 	u8 *data_ignore;
166a219f6deSJohnny Huang 	u8 *conf;
167a219f6deSJohnny Huang 	u8 *conf_ignore;
168a219f6deSJohnny Huang 	u8 *strap;
169a219f6deSJohnny Huang 	u8 *strap_pro;
170a219f6deSJohnny Huang 	u8 *strap_ignore;
171b25f02d2SJohnny Huang 	u8 *scu_pro;
172b25f02d2SJohnny Huang 	u8 *scu_pro_ignore;
173696656c6SJohnny Huang };
174696656c6SJohnny Huang 
1759a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1769a4fe690SJohnny Huang 
17779e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1789a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1799a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1809a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
181181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
182181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   0, "RSA-public as SOC public key"},
183181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
184181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as SOC private key"},
185181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1869a4fe690SJohnny Huang };
1879a4fe690SJohnny Huang 
18879e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1899a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1909a4fe690SJohnny 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"},
191181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
192181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
193181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1949a4fe690SJohnny Huang };
1959a4fe690SJohnny Huang 
1965fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1975fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1985fdde29fSJohnny 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"},
199181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
200181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
201181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
202181f72d8SJohnny Huang };
203181f72d8SJohnny Huang 
204181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
205181f72d8SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
206181f72d8SJohnny 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"},
207181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
208181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
209181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
210181f72d8SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key(big endian)"},
211181f72d8SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
212181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key(big endian)"},
2135fdde29fSJohnny Huang };
2145fdde29fSJohnny Huang 
215f347c284SJohnny Huang static void buf_print(u8 *buf, int len)
216f347c284SJohnny Huang {
217f347c284SJohnny Huang 	int i;
218f347c284SJohnny Huang 
219f347c284SJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
220f347c284SJohnny Huang 	for (i = 0; i < len; i++) {
221f347c284SJohnny Huang 		if (i % 16 == 0)
222f347c284SJohnny Huang 			printf("%04X: ", i);
223f347c284SJohnny Huang 		printf("%02X ", buf[i]);
224f347c284SJohnny Huang 		if ((i + 1) % 16 == 0)
225f347c284SJohnny Huang 			printf("\n");
226f347c284SJohnny Huang 	}
22788bd7d58SJohnny Huang 	printf("\n");
228f347c284SJohnny Huang }
229f347c284SJohnny Huang 
230794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
231794e27ecSJohnny Huang {
232794e27ecSJohnny Huang 	int bit_offset;
233794e27ecSJohnny Huang 	int i;
234794e27ecSJohnny Huang 
235794e27ecSJohnny Huang 	if (offset < 32) {
236794e27ecSJohnny Huang 		i = 0;
237794e27ecSJohnny Huang 		bit_offset = offset;
238794e27ecSJohnny Huang 	} else {
239794e27ecSJohnny Huang 		i = 1;
240794e27ecSJohnny Huang 		bit_offset = offset - 32;
241794e27ecSJohnny Huang 	}
242794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
243794e27ecSJohnny Huang 		return 1;
244794e27ecSJohnny Huang 	else
245794e27ecSJohnny Huang 		return 0;
246794e27ecSJohnny Huang }
247794e27ecSJohnny Huang 
248794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
249794e27ecSJohnny Huang {
250794e27ecSJohnny Huang 	int i;
251794e27ecSJohnny Huang 	int fz = 0;
252794e27ecSJohnny Huang 	int rid_num = 0;
253794e27ecSJohnny Huang 	int ret = 0;
254794e27ecSJohnny Huang 
255794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
256794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
257794e27ecSJohnny Huang 			if (!fz)
258794e27ecSJohnny Huang 				fz = 1;
259794e27ecSJohnny Huang 
260794e27ecSJohnny Huang 		} else {
261794e27ecSJohnny Huang 			rid_num++;
262794e27ecSJohnny Huang 			if (fz)
263794e27ecSJohnny Huang 				ret = OTP_FAILURE;
264794e27ecSJohnny Huang 		}
265794e27ecSJohnny Huang 	}
266794e27ecSJohnny Huang 	if (ret)
267794e27ecSJohnny Huang 		return ret;
268794e27ecSJohnny Huang 
269794e27ecSJohnny Huang 	return rid_num;
270794e27ecSJohnny Huang }
271794e27ecSJohnny Huang 
272a219f6deSJohnny Huang static u32 chip_version(void)
2739a4fe690SJohnny Huang {
274e417205bSJohnny Huang 	u32 revid0, revid1;
2759a4fe690SJohnny Huang 
276e417205bSJohnny Huang 	revid0 = readl(ASPEED_REVISION_ID0);
277e417205bSJohnny Huang 	revid1 = readl(ASPEED_REVISION_ID1);
2789a4fe690SJohnny Huang 
279e417205bSJohnny Huang 	if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
280badd21c2SJohnny Huang 		/* AST2600-A0 */
281e417205bSJohnny Huang 		return OTP_A0;
282e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
283badd21c2SJohnny Huang 		/* AST2600-A1 */
284e417205bSJohnny Huang 		return OTP_A1;
285e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
286badd21c2SJohnny Huang 		/* AST2600-A2 */
287e417205bSJohnny Huang 		return OTP_A2;
288e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
28964b66712SJohnny Huang 		/* AST2600-A3 */
290e417205bSJohnny Huang 		return OTP_A3;
291e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
292e417205bSJohnny Huang 		/* AST2620-A1 */
293e417205bSJohnny Huang 		return OTP_A1;
294e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
295e417205bSJohnny Huang 		/* AST2620-A2 */
296e417205bSJohnny Huang 		return OTP_A2;
297e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
29864b66712SJohnny Huang 		/* AST2620-A3 */
299e417205bSJohnny Huang 		return OTP_A3;
300e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
301e417205bSJohnny Huang 		/* AST2605-A2 */
302e417205bSJohnny Huang 		return OTP_A2;
303e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
304e417205bSJohnny Huang 		/* AST2605-A3 */
305e417205bSJohnny Huang 		return OTP_A3;
306e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
307e417205bSJohnny Huang 		/* AST2605-A3 */
308e417205bSJohnny Huang 		return OTP_A3;
3090dae9d52SJohnny Huang 	}
310f347c284SJohnny Huang 	return OTP_FAILURE;
3119a4fe690SJohnny Huang }
3129a4fe690SJohnny Huang 
3132031a123SJohnny Huang static int wait_complete(void)
3143d3688adSJohnny Huang {
3152031a123SJohnny Huang 	u32 val;
3162031a123SJohnny Huang 	int ret;
3173d3688adSJohnny Huang 
3182031a123SJohnny Huang 	udelay(1);
3192031a123SJohnny Huang 	ret = readl_poll_timeout(OTP_STATUS, val, (val & 0x6) == 0x6, 100000);
3202031a123SJohnny Huang 	if (ret)
3212031a123SJohnny Huang 		printf("%s: timeout, SEC14 = 0x%x\n", __func__, val);
3222031a123SJohnny Huang 
3232031a123SJohnny Huang 	return ret;
3243d3688adSJohnny Huang }
3253d3688adSJohnny Huang 
326a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
327dacbba92SJohnny Huang {
328dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
329dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
330dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
331dacbba92SJohnny Huang 	wait_complete();
332dacbba92SJohnny Huang }
333dacbba92SJohnny Huang 
334dacbba92SJohnny Huang static void otp_soak(int soak)
335dacbba92SJohnny Huang {
336e417205bSJohnny Huang 	if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
337dacbba92SJohnny Huang 		switch (soak) {
338dacbba92SJohnny Huang 		case 0: //default
339377f8cd7SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
340377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
341dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
342dacbba92SJohnny Huang 			break;
343dacbba92SJohnny Huang 		case 1: //normal program
344377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
345377f8cd7SJohnny Huang 			otp_write(0x5000, 0x1008); // Write MRB
346377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0024); // Write MR
347feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
348dacbba92SJohnny Huang 			break;
349dacbba92SJohnny Huang 		case 2: //soak program
350377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
351377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0007); // Write MRB
352377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0100); // Write MR
353feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
354dacbba92SJohnny Huang 			break;
355dacbba92SJohnny Huang 		}
356dacbba92SJohnny Huang 	} else {
357dacbba92SJohnny Huang 		switch (soak) {
358dacbba92SJohnny Huang 		case 0: //default
359dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
360dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
361dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
362dacbba92SJohnny Huang 			break;
363dacbba92SJohnny Huang 		case 1: //normal program
364dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
365dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
366dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
367feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
368dacbba92SJohnny Huang 			break;
369dacbba92SJohnny Huang 		case 2: //soak program
370dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
371dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
372dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
373feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
374dacbba92SJohnny Huang 			break;
375dacbba92SJohnny Huang 		}
376dacbba92SJohnny Huang 	}
377dacbba92SJohnny Huang 
378dacbba92SJohnny Huang 	wait_complete();
379dacbba92SJohnny Huang }
380dacbba92SJohnny Huang 
381a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
38269d5fd8fSJohnny Huang {
3833d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
3843d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3853d3688adSJohnny Huang 	wait_complete();
3863d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
3873d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
38869d5fd8fSJohnny Huang }
38969d5fd8fSJohnny Huang 
390f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data)
39169d5fd8fSJohnny Huang {
39269d5fd8fSJohnny Huang 	int config_offset;
39369d5fd8fSJohnny Huang 
39469d5fd8fSJohnny Huang 	config_offset = 0x800;
39569d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
39669d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
39769d5fd8fSJohnny Huang 
3983d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
3993d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4003d3688adSJohnny Huang 	wait_complete();
4013d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
40269d5fd8fSJohnny Huang }
40369d5fd8fSJohnny Huang 
404a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
40569d5fd8fSJohnny Huang {
406a219f6deSJohnny Huang 	u32 ret;
407a219f6deSJohnny Huang 	u32 *buf;
40869d5fd8fSJohnny Huang 
40969d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
41069d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
41169d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
41269d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
41369d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
4143d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
4153d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
4163d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
4173d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
4183d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
4193d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
4203d3688adSJohnny Huang 	wait_complete();
4213d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
42269d5fd8fSJohnny Huang 	if (ret & 0x1)
423f347c284SJohnny Huang 		return OTP_SUCCESS;
42469d5fd8fSJohnny Huang 	else
425f347c284SJohnny Huang 		return OTP_FAILURE;
42669d5fd8fSJohnny Huang }
42769d5fd8fSJohnny Huang 
428a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
42969d5fd8fSJohnny Huang {
430a219f6deSJohnny Huang 	u32 ret[2];
43169d5fd8fSJohnny Huang 
43230a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4333d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
43430a8c590SJohnny Huang 	else
4353d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
43630a8c590SJohnny Huang 
4373d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4383d3688adSJohnny Huang 	wait_complete();
4393d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4403d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
44183655e91SJohnny Huang 
44230a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
44330a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
444f347c284SJohnny Huang 			return OTP_SUCCESS;
44569d5fd8fSJohnny Huang 		else
446f347c284SJohnny Huang 			return OTP_FAILURE;
44730a8c590SJohnny Huang 	} else {
44830a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
449f347c284SJohnny Huang 			return OTP_SUCCESS;
45030a8c590SJohnny Huang 		else
451f347c284SJohnny Huang 			return OTP_FAILURE;
45230a8c590SJohnny Huang 	}
45369d5fd8fSJohnny Huang }
45469d5fd8fSJohnny Huang 
455a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4564c1c9b35SJohnny Huang {
457a219f6deSJohnny Huang 	u32 ret[2];
4584c1c9b35SJohnny Huang 
4594c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4604c1c9b35SJohnny Huang 
4614c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4623d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
4634c1c9b35SJohnny Huang 	else
4643d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
4653d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4663d3688adSJohnny Huang 	wait_complete();
4673d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4683d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4694c1c9b35SJohnny Huang 	if (size == 1) {
4704c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4714c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
472696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4734c1c9b35SJohnny Huang 				compare[0] = 0;
474f347c284SJohnny Huang 				return OTP_SUCCESS;
475a219f6deSJohnny Huang 			}
4764c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
477f347c284SJohnny Huang 			return OTP_FAILURE;
4784c1c9b35SJohnny Huang 
4794c1c9b35SJohnny Huang 		} else {
4804c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
481696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4824c1c9b35SJohnny Huang 				compare[0] = ~0;
483f347c284SJohnny Huang 				return OTP_SUCCESS;
484a219f6deSJohnny Huang 			}
485d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
486f347c284SJohnny Huang 			return OTP_FAILURE;
4874c1c9b35SJohnny Huang 		}
4884c1c9b35SJohnny Huang 	} else if (size == 2) {
4894c1c9b35SJohnny Huang 		// otp_addr should be even
490696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
4914c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4924c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4934c1c9b35SJohnny Huang 			compare[0] = 0;
4944c1c9b35SJohnny Huang 			compare[1] = ~0;
495f347c284SJohnny Huang 			return OTP_SUCCESS;
496a219f6deSJohnny Huang 		}
4974c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4984c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4994c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
5004c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
501f347c284SJohnny Huang 		return OTP_FAILURE;
5024c1c9b35SJohnny Huang 	} else {
503f347c284SJohnny Huang 		return OTP_FAILURE;
5044c1c9b35SJohnny Huang 	}
5054c1c9b35SJohnny Huang }
5064c1c9b35SJohnny Huang 
5072031a123SJohnny Huang static int otp_prog(u32 otp_addr, u32 prog_bit)
50883655e91SJohnny Huang {
50990965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
51083655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
51183655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
51283655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
5132031a123SJohnny Huang 
5142031a123SJohnny Huang 	return wait_complete();
51583655e91SJohnny Huang }
51683655e91SJohnny Huang 
5172031a123SJohnny Huang static int _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
51883655e91SJohnny Huang {
51983655e91SJohnny Huang 	int prog_bit;
52083655e91SJohnny Huang 
52183655e91SJohnny Huang 	if (prog_address % 2 == 0) {
52283655e91SJohnny Huang 		if (value)
52383655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
52483655e91SJohnny Huang 		else
5252031a123SJohnny Huang 			return 0;
52683655e91SJohnny Huang 	} else {
527e417205bSJohnny Huang 		if (info_cb.version != OTP_A3)
52883655e91SJohnny Huang 			prog_address |= 1 << 15;
52983655e91SJohnny Huang 		if (!value)
53083655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
53183655e91SJohnny Huang 		else
5322031a123SJohnny Huang 			return 0;
53383655e91SJohnny Huang 	}
5342031a123SJohnny Huang 	return otp_prog(prog_address, prog_bit);
53583655e91SJohnny Huang }
53683655e91SJohnny Huang 
537f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset)
53883655e91SJohnny Huang {
53983655e91SJohnny Huang 	int pass;
54083655e91SJohnny Huang 	int i;
5412031a123SJohnny Huang 	int ret;
54283655e91SJohnny Huang 
54383655e91SJohnny Huang 	otp_soak(1);
5442031a123SJohnny Huang 	ret = _otp_prog_bit(value, prog_address, bit_offset);
5452031a123SJohnny Huang 	if (ret)
5462031a123SJohnny Huang 		return OTP_FAILURE;
54783655e91SJohnny Huang 	pass = 0;
54883655e91SJohnny Huang 
54983655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
55083655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
55183655e91SJohnny Huang 			otp_soak(2);
5522031a123SJohnny Huang 			ret = _otp_prog_bit(value, prog_address, bit_offset);
5532031a123SJohnny Huang 			if (ret)
5542031a123SJohnny Huang 				return OTP_FAILURE;
55583655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
55683655e91SJohnny Huang 				otp_soak(1);
55783655e91SJohnny Huang 			} else {
55883655e91SJohnny Huang 				pass = 1;
55983655e91SJohnny Huang 				break;
56083655e91SJohnny Huang 			}
56183655e91SJohnny Huang 		} else {
56283655e91SJohnny Huang 			pass = 1;
56383655e91SJohnny Huang 			break;
56483655e91SJohnny Huang 		}
56583655e91SJohnny Huang 	}
566794e27ecSJohnny Huang 	if (pass)
567794e27ecSJohnny Huang 		return OTP_SUCCESS;
56883655e91SJohnny Huang 
569794e27ecSJohnny Huang 	return OTP_FAILURE;
57083655e91SJohnny Huang }
57183655e91SJohnny Huang 
5722031a123SJohnny Huang static int otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
573d90825e2SJohnny Huang {
574d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
5752031a123SJohnny Huang 	int ret;
576d90825e2SJohnny Huang 
577d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
578696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
579d90825e2SJohnny Huang 			continue;
580d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
581d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
582d90825e2SJohnny Huang 			if (bit_value)
583d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
584d90825e2SJohnny Huang 			else
585d90825e2SJohnny Huang 				continue;
586d90825e2SJohnny Huang 		} else {
587e417205bSJohnny Huang 			if (info_cb.version != OTP_A3)
588d90825e2SJohnny Huang 				prog_address |= 1 << 15;
589d90825e2SJohnny Huang 			if (bit_value)
590d90825e2SJohnny Huang 				continue;
591d90825e2SJohnny Huang 			else
592d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
593d90825e2SJohnny Huang 		}
5942031a123SJohnny Huang 		ret = otp_prog(prog_address, prog_bit);
5952031a123SJohnny Huang 		if (ret)
5962031a123SJohnny Huang 			return ret;
597d90825e2SJohnny Huang 	}
5982031a123SJohnny Huang 	return 0;
599d90825e2SJohnny Huang }
600d90825e2SJohnny Huang 
601a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
60254552c69SJohnny Huang {
60354552c69SJohnny Huang 	int pass;
60454552c69SJohnny Huang 	int i;
605a219f6deSJohnny Huang 	u32 data0_masked;
606a219f6deSJohnny Huang 	u32 data1_masked;
607a219f6deSJohnny Huang 	u32 buf0_masked;
608a219f6deSJohnny Huang 	u32 buf1_masked;
609a219f6deSJohnny Huang 	u32 compare[2];
6102031a123SJohnny Huang 	int ret;
61154552c69SJohnny Huang 
61254552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
61354552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
61454552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
61554552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
616a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
617f347c284SJohnny Huang 		return OTP_SUCCESS;
61854552c69SJohnny Huang 
619b64ca396SJohnny Huang 	for (i = 0; i < 32; i++) {
620b64ca396SJohnny Huang 		if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0)
621b64ca396SJohnny Huang 			return OTP_FAILURE;
622b64ca396SJohnny Huang 		if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1)
623b64ca396SJohnny Huang 			return OTP_FAILURE;
624b64ca396SJohnny Huang 	}
625b64ca396SJohnny Huang 
62654552c69SJohnny Huang 	otp_soak(1);
6272031a123SJohnny Huang 	if (data0_masked != buf0_masked) {
6282031a123SJohnny Huang 		ret = otp_prog_dw(buf[0], ignore_mask[0], prog_address);
6292031a123SJohnny Huang 		if (ret)
6302031a123SJohnny Huang 			return OTP_FAILURE;
6312031a123SJohnny Huang 	}
6322031a123SJohnny Huang 
6332031a123SJohnny Huang 	if (data1_masked != buf1_masked) {
6342031a123SJohnny Huang 		ret = otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
6352031a123SJohnny Huang 		if (ret)
6362031a123SJohnny Huang 			return OTP_FAILURE;
6372031a123SJohnny Huang 	}
63854552c69SJohnny Huang 
63954552c69SJohnny Huang 	pass = 0;
64054552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
64154552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
64254552c69SJohnny Huang 			otp_soak(2);
6432031a123SJohnny Huang 			if (compare[0] != 0) {
6442031a123SJohnny Huang 				ret = otp_prog_dw(compare[0], ignore_mask[0], prog_address);
6452031a123SJohnny Huang 				if (ret)
6462031a123SJohnny Huang 					return OTP_FAILURE;
6472031a123SJohnny Huang 			}
6482031a123SJohnny Huang 			if (compare[1] != ~0) {
6492031a123SJohnny Huang 				ret = otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
6502031a123SJohnny Huang 				if (ret)
6512031a123SJohnny Huang 					return OTP_FAILURE;
6522031a123SJohnny Huang 			}
65354552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
65454552c69SJohnny Huang 				otp_soak(1);
65554552c69SJohnny Huang 			} else {
65654552c69SJohnny Huang 				pass = 1;
65754552c69SJohnny Huang 				break;
65854552c69SJohnny Huang 			}
65954552c69SJohnny Huang 		} else {
66054552c69SJohnny Huang 			pass = 1;
66154552c69SJohnny Huang 			break;
66254552c69SJohnny Huang 		}
66354552c69SJohnny Huang 	}
66454552c69SJohnny Huang 
66554552c69SJohnny Huang 	if (!pass) {
66654552c69SJohnny Huang 		otp_soak(0);
66754552c69SJohnny Huang 		return OTP_FAILURE;
66854552c69SJohnny Huang 	}
66954552c69SJohnny Huang 	return OTP_SUCCESS;
67054552c69SJohnny Huang }
67154552c69SJohnny Huang 
672541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
67376d13988SJohnny Huang {
674a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
6755010032bSJohnny Huang 	int strap_end;
67676d13988SJohnny Huang 	int i, j;
67776d13988SJohnny Huang 
678e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
67976d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
68076d13988SJohnny Huang 			otpstrap[j].value = 0;
68176d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
68276d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
68376d13988SJohnny Huang 			otpstrap[j].protected = 0;
68476d13988SJohnny Huang 		}
6855010032bSJohnny Huang 		strap_end = 30;
6865010032bSJohnny Huang 	} else {
6875010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
6885010032bSJohnny Huang 			otpstrap[j].value = 0;
6895010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
6905010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
6915010032bSJohnny Huang 			otpstrap[j].protected = 0;
6925010032bSJohnny Huang 		}
6935010032bSJohnny Huang 		strap_end = 28;
6945010032bSJohnny Huang 	}
69576d13988SJohnny Huang 
696dacbba92SJohnny Huang 	otp_soak(0);
6975010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
69876d13988SJohnny Huang 		int option = (i - 16) / 2;
699a219f6deSJohnny Huang 
700f347c284SJohnny Huang 		otp_read_conf(i, &OTPSTRAP_RAW[0]);
701f347c284SJohnny Huang 		otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
70276d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
70376d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
704a219f6deSJohnny Huang 
705a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
70676d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
70776d13988SJohnny Huang 			if (bit_value == 1)
70876d13988SJohnny Huang 				otpstrap[j].remain_times--;
70976d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
71076d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
71176d13988SJohnny Huang 		}
71276d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
71376d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
714a219f6deSJohnny Huang 
715a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
71676d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
71776d13988SJohnny Huang 			if (bit_value == 1)
71876d13988SJohnny Huang 				otpstrap[j].remain_times--;
71976d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
72076d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
72176d13988SJohnny Huang 		}
72276d13988SJohnny Huang 	}
7235010032bSJohnny Huang 
724f347c284SJohnny Huang 	otp_read_conf(30, &OTPSTRAP_RAW[0]);
725f347c284SJohnny Huang 	otp_read_conf(31, &OTPSTRAP_RAW[1]);
72676d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
72776d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
72876d13988SJohnny Huang 			otpstrap[j].protected = 1;
72976d13988SJohnny Huang 	}
73076d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
73176d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
73276d13988SJohnny Huang 			otpstrap[j].protected = 1;
73376d13988SJohnny Huang 	}
73476d13988SJohnny Huang }
73576d13988SJohnny Huang 
7367e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit)
737f347c284SJohnny Huang {
738f347c284SJohnny Huang 	int prog_flag = 0;
739f347c284SJohnny Huang 
740f347c284SJohnny Huang 	// ignore this bit
741f347c284SJohnny Huang 	if (ibit == 1)
742f347c284SJohnny Huang 		return OTP_SUCCESS;
743b489486eSJohnny Huang 	printf("OTPSTRAP[0x%X]:\n", offset);
744f347c284SJohnny Huang 
745f347c284SJohnny Huang 	if (bit == otpstrap->value) {
7467e523e3bSJohnny Huang 		if (!pbit) {
747f347c284SJohnny Huang 			printf("    The value is same as before, skip it.\n");
748f347c284SJohnny Huang 			return OTP_PROG_SKIP;
749f347c284SJohnny Huang 		}
750f347c284SJohnny Huang 		printf("    The value is same as before.\n");
751f347c284SJohnny Huang 	} else {
752f347c284SJohnny Huang 		prog_flag = 1;
753f347c284SJohnny Huang 	}
754f347c284SJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
755f347c284SJohnny Huang 		printf("    This bit is protected and is not writable\n");
756f347c284SJohnny Huang 		return OTP_FAILURE;
757f347c284SJohnny Huang 	}
758f347c284SJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
759b489486eSJohnny Huang 		printf("    This bit has no remaining chance to write.\n");
760f347c284SJohnny Huang 		return OTP_FAILURE;
761f347c284SJohnny Huang 	}
762f347c284SJohnny Huang 	if (pbit == 1)
763f347c284SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
764f347c284SJohnny Huang 	if (prog_flag)
765b489486eSJohnny Huang 		printf("    Write 1 to OTPSTRAP[0x%X] OPTION[0x%X], that value becomes from 0x%X to 0x%X.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1);
766f347c284SJohnny Huang 
767f347c284SJohnny Huang 	return OTP_SUCCESS;
768f347c284SJohnny Huang }
769f347c284SJohnny Huang 
770f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
771f347c284SJohnny Huang {
772f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
773f347c284SJohnny Huang 	u32 prog_address;
774f347c284SJohnny Huang 	int offset;
775f347c284SJohnny Huang 	int ret;
776f347c284SJohnny Huang 
777f347c284SJohnny Huang 	otp_strap_status(otpstrap);
778f347c284SJohnny Huang 
7797e523e3bSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
780f347c284SJohnny Huang 
781f347c284SJohnny Huang 	if (ret != OTP_SUCCESS)
782f347c284SJohnny Huang 		return ret;
783f347c284SJohnny Huang 
784f347c284SJohnny Huang 	prog_address = 0x800;
785f347c284SJohnny Huang 	if (bit_offset < 32) {
786f347c284SJohnny Huang 		offset = bit_offset;
787f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
788f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
789f347c284SJohnny Huang 
790f347c284SJohnny Huang 	} else {
791f347c284SJohnny Huang 		offset = (bit_offset - 32);
792f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
793f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
794f347c284SJohnny Huang 	}
795f347c284SJohnny Huang 
796f347c284SJohnny Huang 	return otp_prog_dc_b(1, prog_address, offset);
797f347c284SJohnny Huang }
798f347c284SJohnny Huang 
799f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
800f347c284SJohnny Huang {
801f347c284SJohnny Huang 	int i;
802f347c284SJohnny Huang 	u32 ret[1];
803f347c284SJohnny Huang 
804f347c284SJohnny Huang 	if (offset + dw_count > 32)
805f347c284SJohnny Huang 		return OTP_USAGE;
806f347c284SJohnny Huang 	otp_soak(0);
807f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
808f347c284SJohnny Huang 		otp_read_conf(i, ret);
809b489486eSJohnny Huang 		printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]);
810f347c284SJohnny Huang 	}
811f347c284SJohnny Huang 	printf("\n");
812f347c284SJohnny Huang 	return OTP_SUCCESS;
813f347c284SJohnny Huang }
814f347c284SJohnny Huang 
815f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
816f347c284SJohnny Huang {
817f347c284SJohnny Huang 	int i;
818f347c284SJohnny Huang 	u32 ret[2];
819f347c284SJohnny Huang 
820f347c284SJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
821f347c284SJohnny Huang 		return OTP_USAGE;
822f347c284SJohnny Huang 	otp_soak(0);
823f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
824f347c284SJohnny Huang 		otp_read_data(i, ret);
825f347c284SJohnny Huang 		if (i % 4 == 0)
826f347c284SJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
827f347c284SJohnny Huang 		else
828f347c284SJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
829f347c284SJohnny Huang 	}
830f347c284SJohnny Huang 	printf("\n");
831f347c284SJohnny Huang 	return OTP_SUCCESS;
832f347c284SJohnny Huang }
833f347c284SJohnny Huang 
834f347c284SJohnny Huang static int otp_print_strap(int start, int count)
835f347c284SJohnny Huang {
836f347c284SJohnny Huang 	int i, j;
837f347c284SJohnny Huang 	int remains;
838f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
839f347c284SJohnny Huang 
840f347c284SJohnny Huang 	if (start < 0 || start > 64)
841f347c284SJohnny Huang 		return OTP_USAGE;
842f347c284SJohnny Huang 
843f347c284SJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
844f347c284SJohnny Huang 		return OTP_USAGE;
845f347c284SJohnny Huang 
846f347c284SJohnny Huang 	otp_strap_status(otpstrap);
847f347c284SJohnny Huang 
8487e523e3bSJohnny Huang 	if (info_cb.version == OTP_A0)
849f347c284SJohnny Huang 		remains = 7;
8507e523e3bSJohnny Huang 	else
851f347c284SJohnny Huang 		remains = 6;
8527e523e3bSJohnny Huang 	printf("BIT(hex)  Value  Option           Status\n");
853f347c284SJohnny Huang 	printf("______________________________________________________________________________\n");
854f347c284SJohnny Huang 
855f347c284SJohnny Huang 	for (i = start; i < start + count; i++) {
856f347c284SJohnny Huang 		printf("0x%-8X", i);
857f347c284SJohnny Huang 		printf("%-7d", otpstrap[i].value);
858f347c284SJohnny Huang 		for (j = 0; j < remains; j++)
859f347c284SJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
860f347c284SJohnny Huang 		printf("   ");
861f347c284SJohnny Huang 		if (otpstrap[i].protected == 1) {
862f347c284SJohnny Huang 			printf("protected and not writable");
863f347c284SJohnny Huang 		} else {
864f347c284SJohnny Huang 			printf("not protected ");
865f347c284SJohnny Huang 			if (otpstrap[i].remain_times == 0)
866f347c284SJohnny Huang 				printf("and no remaining times to write.");
867f347c284SJohnny Huang 			else
868f347c284SJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
869f347c284SJohnny Huang 		}
870f347c284SJohnny Huang 		printf("\n");
871f347c284SJohnny Huang 	}
872f347c284SJohnny Huang 
873f347c284SJohnny Huang 	return OTP_SUCCESS;
874f347c284SJohnny Huang }
875f347c284SJohnny Huang 
876794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
877794e27ecSJohnny Huang {
878794e27ecSJohnny Huang 	int bit_offset;
879794e27ecSJohnny Huang 	int i, j;
880794e27ecSJohnny Huang 
881794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
882794e27ecSJohnny Huang 	printf("___________________________________________________\n");
883794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
884794e27ecSJohnny Huang 		if (i < 32) {
885794e27ecSJohnny Huang 			j = 0;
886794e27ecSJohnny Huang 			bit_offset = i;
887794e27ecSJohnny Huang 		} else {
888794e27ecSJohnny Huang 			j = 1;
889794e27ecSJohnny Huang 			bit_offset = i - 32;
890794e27ecSJohnny Huang 		}
891794e27ecSJohnny Huang 		if (i % 16 == 0)
892794e27ecSJohnny Huang 			printf("%2x | ", i);
893794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
894794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
895794e27ecSJohnny Huang 			printf("\n");
896794e27ecSJohnny Huang 	}
897794e27ecSJohnny Huang }
898794e27ecSJohnny Huang 
899b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout)
900b25f02d2SJohnny Huang {
901b25f02d2SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
902b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
903b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
904b25f02d2SJohnny Huang 	int i;
905b25f02d2SJohnny Huang 	u32 scu_offset;
906b25f02d2SJohnny Huang 	u32 dw_offset;
907b25f02d2SJohnny Huang 	u32 bit_offset;
908b25f02d2SJohnny Huang 	u32 mask;
909b25f02d2SJohnny Huang 	u32 otp_value;
910b25f02d2SJohnny Huang 	u32 otp_ignore;
911b25f02d2SJohnny Huang 
912b25f02d2SJohnny Huang 	printf("SCU     BIT          reg_protect     Description\n");
913b25f02d2SJohnny Huang 	printf("____________________________________________________________________\n");
914b25f02d2SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
915b25f02d2SJohnny Huang 		mask = BIT(scu_info[i].length) - 1;
916b25f02d2SJohnny Huang 
917b25f02d2SJohnny Huang 		if (scu_info[i].bit_offset > 31) {
918b25f02d2SJohnny Huang 			scu_offset = 0x510;
919b25f02d2SJohnny Huang 			dw_offset = 1;
920b25f02d2SJohnny Huang 			bit_offset = scu_info[i].bit_offset - 32;
921b25f02d2SJohnny Huang 		} else {
922b25f02d2SJohnny Huang 			scu_offset = 0x500;
923b25f02d2SJohnny Huang 			dw_offset = 0;
924b25f02d2SJohnny Huang 			bit_offset = scu_info[i].bit_offset;
925b25f02d2SJohnny Huang 		}
926b25f02d2SJohnny Huang 
927b25f02d2SJohnny Huang 		otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask;
928b25f02d2SJohnny Huang 		otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask;
929b25f02d2SJohnny Huang 
930b25f02d2SJohnny Huang 		if (otp_ignore == mask)
931b25f02d2SJohnny Huang 			continue;
932b25f02d2SJohnny Huang 		else if (otp_ignore != 0)
933b25f02d2SJohnny Huang 			return OTP_FAILURE;
934b25f02d2SJohnny Huang 
935b25f02d2SJohnny Huang 		if (otp_value != 0 && otp_value != mask)
936b25f02d2SJohnny Huang 			return OTP_FAILURE;
937b25f02d2SJohnny Huang 
938b25f02d2SJohnny Huang 		printf("0x%-6X", scu_offset);
939b25f02d2SJohnny Huang 		if (scu_info[i].length == 1)
940b25f02d2SJohnny Huang 			printf("0x%-11X", bit_offset);
941b25f02d2SJohnny Huang 		else
9422131c250SJohnny Huang 			printf("0x%-2X:0x%-6x", bit_offset, bit_offset + scu_info[i].length - 1);
943b25f02d2SJohnny Huang 		printf("0x%-14X", otp_value);
944b25f02d2SJohnny Huang 		printf("%s\n", scu_info[i].information);
945b25f02d2SJohnny Huang 	}
946b25f02d2SJohnny Huang 	return OTP_SUCCESS;
947b25f02d2SJohnny Huang }
948b25f02d2SJohnny Huang 
9490dc9a440SJohnny Huang static void otp_print_scu_info(void)
9500dc9a440SJohnny Huang {
9510dc9a440SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
9520dc9a440SJohnny Huang 	u32 OTPCFG[2];
9530dc9a440SJohnny Huang 	u32 scu_offset;
9540dc9a440SJohnny Huang 	u32 bit_offset;
9550dc9a440SJohnny Huang 	u32 reg_p;
9560dc9a440SJohnny Huang 	u32 length;
9570dc9a440SJohnny Huang 	int i, j;
9580dc9a440SJohnny Huang 
9590dc9a440SJohnny Huang 	otp_soak(0);
9600dc9a440SJohnny Huang 	otp_read_conf(28, &OTPCFG[0]);
9610dc9a440SJohnny Huang 	otp_read_conf(29, &OTPCFG[1]);
9620dc9a440SJohnny Huang 	printf("SCU     BIT   reg_protect     Description\n");
9630dc9a440SJohnny Huang 	printf("____________________________________________________________________\n");
9640dc9a440SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
9650dc9a440SJohnny Huang 		length = scu_info[i].length;
9660dc9a440SJohnny Huang 		for (j = 0; j < length; j++) {
9670dc9a440SJohnny Huang 			if (scu_info[i].bit_offset + j < 32) {
9680dc9a440SJohnny Huang 				scu_offset = 0x500;
9690dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j;
9700dc9a440SJohnny Huang 				reg_p = (OTPCFG[0] >> bit_offset) & 0x1;
9710dc9a440SJohnny Huang 			} else {
9720dc9a440SJohnny Huang 				scu_offset = 0x510;
9730dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j - 32;
9740dc9a440SJohnny Huang 				reg_p = (OTPCFG[1] >> bit_offset) & 0x1;
9750dc9a440SJohnny Huang 			}
9760dc9a440SJohnny Huang 			printf("0x%-6X", scu_offset);
9770dc9a440SJohnny Huang 			printf("0x%-4X", bit_offset);
9780dc9a440SJohnny Huang 			printf("0x%-13X", reg_p);
9790dc9a440SJohnny Huang 			if (length == 1) {
9800dc9a440SJohnny Huang 				printf(" %s\n", scu_info[i].information);
9810dc9a440SJohnny Huang 				continue;
9820dc9a440SJohnny Huang 			}
9830dc9a440SJohnny Huang 
9840dc9a440SJohnny Huang 			if (j == 0)
9850dc9a440SJohnny Huang 				printf("/%s\n", scu_info[i].information);
9860dc9a440SJohnny Huang 			else if (j == length - 1)
9870dc9a440SJohnny Huang 				printf("\\ \"\n");
9880dc9a440SJohnny Huang 			else
9890dc9a440SJohnny Huang 				printf("| \"\n");
9900dc9a440SJohnny Huang 		}
9910dc9a440SJohnny Huang 	}
9920dc9a440SJohnny Huang }
9930dc9a440SJohnny Huang 
994696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
99569d5fd8fSJohnny Huang {
99679e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
997a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
998a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
999a219f6deSJohnny Huang 	u32 mask;
1000a219f6deSJohnny Huang 	u32 dw_offset;
1001a219f6deSJohnny Huang 	u32 bit_offset;
1002a219f6deSJohnny Huang 	u32 otp_value;
1003a219f6deSJohnny Huang 	u32 otp_ignore;
1004b458cd62SJohnny Huang 	int fail = 0;
10057adec5f6SJohnny Huang 	int mask_err;
1006794e27ecSJohnny Huang 	int rid_num = 0;
100773f11549SJohnny Huang 	char valid_bit[20];
1008794e27ecSJohnny Huang 	int fz;
100966f2f8e5SJohnny Huang 	int i;
101073f11549SJohnny Huang 	int j;
101166f2f8e5SJohnny Huang 
1012737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
101366f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
10143cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
10157adec5f6SJohnny Huang 		mask_err = 0;
10163cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
10173cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
10183cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
1019b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1020696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
1021b458cd62SJohnny Huang 
10227adec5f6SJohnny Huang 		if (conf_info[i].value == OTP_REG_VALID_BIT) {
10237adec5f6SJohnny Huang 			if (((otp_value + otp_ignore) & mask) != mask) {
1024b458cd62SJohnny Huang 				fail = 1;
10257adec5f6SJohnny Huang 				mask_err = 1;
10267adec5f6SJohnny Huang 			}
10277adec5f6SJohnny Huang 		} else {
10287adec5f6SJohnny Huang 			if (otp_ignore == mask) {
10297adec5f6SJohnny Huang 				continue;
10307adec5f6SJohnny Huang 			} else if (otp_ignore != 0) {
10317adec5f6SJohnny Huang 				fail = 1;
10327adec5f6SJohnny Huang 				mask_err = 1;
10337adec5f6SJohnny Huang 			}
10347adec5f6SJohnny Huang 		}
1035b458cd62SJohnny Huang 
1036a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
10373cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
10383cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
10393cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1040b458cd62SJohnny Huang 			continue;
1041b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1042b458cd62SJohnny Huang 
10433cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
10443cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
104566f2f8e5SJohnny Huang 		} else {
1046b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
10473cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
10483cb28812SJohnny Huang 			       conf_info[i].bit_offset);
104966f2f8e5SJohnny Huang 		}
1050b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1051b458cd62SJohnny Huang 
10527adec5f6SJohnny Huang 		if (mask_err) {
10537adec5f6SJohnny Huang 			printf("Ignore, mask error\n");
1054a219f6deSJohnny Huang 			continue;
1055a219f6deSJohnny Huang 		}
10563cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1057b458cd62SJohnny Huang 			printf("Reserved\n");
10583cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
10593cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1060b458cd62SJohnny Huang 			printf("\n");
10613cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1062b458cd62SJohnny Huang 			if (otp_value != 0) {
106373f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1064e2b82258SJohnny Huang 					if (otp_value & (1 << j))
106573f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1066a219f6deSJohnny Huang 					else
106773f11549SJohnny Huang 						valid_bit[j * 2] = '0';
106873f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
106973f11549SJohnny Huang 				}
107073f11549SJohnny Huang 				valid_bit[15] = 0;
107173f11549SJohnny Huang 			} else {
107273f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1073b458cd62SJohnny Huang 			}
10743cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1075b458cd62SJohnny Huang 			printf("\n");
1076b458cd62SJohnny Huang 		} else {
10773cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1078b458cd62SJohnny Huang 		}
1079b458cd62SJohnny Huang 	}
1080b458cd62SJohnny Huang 
1081794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
1082794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
1083794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
1084794e27ecSJohnny Huang 			fail = 1;
1085794e27ecSJohnny Huang 		} else {
1086794e27ecSJohnny Huang 			fz = 0;
1087794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
1088794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
1089794e27ecSJohnny Huang 					if (!fz)
1090794e27ecSJohnny Huang 						fz = 1;
1091794e27ecSJohnny Huang 				} else {
1092794e27ecSJohnny Huang 					rid_num++;
1093794e27ecSJohnny Huang 					if (fz) {
1094794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
1095794e27ecSJohnny Huang 						fail = 1;
1096794e27ecSJohnny Huang 						break;
1097794e27ecSJohnny Huang 					}
1098794e27ecSJohnny Huang 				}
1099794e27ecSJohnny Huang 			}
1100794e27ecSJohnny Huang 		}
1101794e27ecSJohnny Huang 		if (fail)
1102794e27ecSJohnny Huang 			printf("OTP revision ID\n");
1103794e27ecSJohnny Huang 		else
1104794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
1105794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
1106794e27ecSJohnny Huang 	}
1107794e27ecSJohnny Huang 
1108b458cd62SJohnny Huang 	if (fail)
1109b458cd62SJohnny Huang 		return OTP_FAILURE;
1110b458cd62SJohnny Huang 
111166f2f8e5SJohnny Huang 	return OTP_SUCCESS;
111266f2f8e5SJohnny Huang }
111366f2f8e5SJohnny Huang 
11142d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
111566f2f8e5SJohnny Huang {
111679e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
1117a219f6deSJohnny Huang 	u32 OTPCFG[16];
1118a219f6deSJohnny Huang 	u32 mask;
1119a219f6deSJohnny Huang 	u32 dw_offset;
1120a219f6deSJohnny Huang 	u32 bit_offset;
1121a219f6deSJohnny Huang 	u32 otp_value;
112273f11549SJohnny Huang 	char valid_bit[20];
112366f2f8e5SJohnny Huang 	int i;
112473f11549SJohnny Huang 	int j;
112566f2f8e5SJohnny Huang 
1126dacbba92SJohnny Huang 	otp_soak(0);
1127bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
1128f347c284SJohnny Huang 		otp_read_conf(i, &OTPCFG[i]);
112966f2f8e5SJohnny Huang 
1130b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
1131b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
11323cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
11333cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
11342d4b0742SJohnny Huang 			continue;
11353cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
11363cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
11373cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
1138b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1139b458cd62SJohnny Huang 
1140a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
11413cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
11423cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
11433cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1144b458cd62SJohnny Huang 			continue;
1145b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1146b458cd62SJohnny Huang 
11473cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
11483cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
1149b458cd62SJohnny Huang 		} else {
1150b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
11513cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
11523cb28812SJohnny Huang 			       conf_info[i].bit_offset);
1153b458cd62SJohnny Huang 		}
1154b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1155b458cd62SJohnny Huang 
11563cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1157b458cd62SJohnny Huang 			printf("Reserved\n");
11583cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
11593cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1160b458cd62SJohnny Huang 			printf("\n");
11613cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1162b458cd62SJohnny Huang 			if (otp_value != 0) {
116373f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1164030cb4a7SJohnny Huang 					if (otp_value & (1 << j))
116573f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1166a219f6deSJohnny Huang 					else
116773f11549SJohnny Huang 						valid_bit[j * 2] = '0';
116873f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
116973f11549SJohnny Huang 				}
117073f11549SJohnny Huang 				valid_bit[15] = 0;
117173f11549SJohnny Huang 			} else {
117273f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1173b458cd62SJohnny Huang 			}
11743cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1175b458cd62SJohnny Huang 			printf("\n");
1176b458cd62SJohnny Huang 		} else {
11773cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1178b458cd62SJohnny Huang 		}
1179b458cd62SJohnny Huang 	}
1180b458cd62SJohnny Huang 	return OTP_SUCCESS;
118166f2f8e5SJohnny Huang }
118266f2f8e5SJohnny Huang 
11835010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
118476d13988SJohnny Huang {
118579e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
1186a219f6deSJohnny Huang 	u32 *OTPSTRAP;
1187a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
1188a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
118976d13988SJohnny Huang 	int i;
1190a8bd6d8cSJohnny Huang 	int fail = 0;
1191a219f6deSJohnny Huang 	u32 bit_offset;
1192a219f6deSJohnny Huang 	u32 dw_offset;
1193a219f6deSJohnny Huang 	u32 mask;
1194a219f6deSJohnny Huang 	u32 otp_value;
1195a219f6deSJohnny Huang 	u32 otp_protect;
1196a219f6deSJohnny Huang 	u32 otp_ignore;
119776d13988SJohnny Huang 
1198a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
1199a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1200a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
12017e523e3bSJohnny Huang 
1202a8bd6d8cSJohnny Huang 	printf("BIT(hex)   Value       Protect     Description\n");
1203de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
1204b458cd62SJohnny Huang 
12053cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
12067adec5f6SJohnny Huang 		fail = 0;
1207696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
1208a8bd6d8cSJohnny Huang 			dw_offset = 1;
12093cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
1210a8bd6d8cSJohnny Huang 		} else {
1211a8bd6d8cSJohnny Huang 			dw_offset = 0;
12123cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
1213a8bd6d8cSJohnny Huang 		}
121476d13988SJohnny Huang 
12153cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
1216a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1217a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1218696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1219a8bd6d8cSJohnny Huang 
1220a219f6deSJohnny Huang 		if (otp_ignore == mask)
1221a8bd6d8cSJohnny Huang 			continue;
1222a219f6deSJohnny Huang 		else if (otp_ignore != 0)
1223a8bd6d8cSJohnny Huang 			fail = 1;
1224a8bd6d8cSJohnny Huang 
1225a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
12263cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1227a8bd6d8cSJohnny Huang 			continue;
1228a8bd6d8cSJohnny Huang 
12293cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
12303cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
1231a8bd6d8cSJohnny Huang 		} else {
1232b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
12333cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
12343cb28812SJohnny Huang 			       strap_info[i].bit_offset);
1235a8bd6d8cSJohnny Huang 		}
1236a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
1237a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
1238a8bd6d8cSJohnny Huang 
1239a8bd6d8cSJohnny Huang 		if (fail) {
1240696656c6SJohnny Huang 			printf("Ignore mask error\n");
1241a8bd6d8cSJohnny Huang 		} else {
12423cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
12433cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1244a8bd6d8cSJohnny Huang 			else
1245a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1246a8bd6d8cSJohnny Huang 		}
1247a8bd6d8cSJohnny Huang 	}
1248a8bd6d8cSJohnny Huang 
1249a8bd6d8cSJohnny Huang 	if (fail)
125076d13988SJohnny Huang 		return OTP_FAILURE;
125176d13988SJohnny Huang 
125276d13988SJohnny Huang 	return OTP_SUCCESS;
125376d13988SJohnny Huang }
125476d13988SJohnny Huang 
1255b458cd62SJohnny Huang static int otp_print_strap_info(int view)
125676d13988SJohnny Huang {
125779e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
125876d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
125907baa4e8SJohnny Huang 	int i, j;
1260b458cd62SJohnny Huang 	int fail = 0;
1261a219f6deSJohnny Huang 	u32 bit_offset;
1262a219f6deSJohnny Huang 	u32 length;
1263a219f6deSJohnny Huang 	u32 otp_value;
1264a219f6deSJohnny Huang 	u32 otp_protect;
126576d13988SJohnny Huang 
1266541eb887SJohnny Huang 	otp_strap_status(strap_status);
126776d13988SJohnny Huang 
1268b458cd62SJohnny Huang 	if (view) {
126907baa4e8SJohnny Huang 		printf("BIT(hex) Value  Remains  Protect   Description\n");
127007baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1271b458cd62SJohnny Huang 	} else {
1272b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1273b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
127476d13988SJohnny Huang 	}
12753cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1276b458cd62SJohnny Huang 		otp_value = 0;
12773cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
12783cb28812SJohnny Huang 		length = strap_info[i].length;
1279b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1280c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1281c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1282b458cd62SJohnny Huang 		}
1283a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
12843cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1285b458cd62SJohnny Huang 			continue;
1286b458cd62SJohnny Huang 		if (view) {
1287b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
12883cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1289b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
129007baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1291e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
12923cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1293b458cd62SJohnny Huang 					printf(" Reserved\n");
1294b458cd62SJohnny Huang 					continue;
1295b458cd62SJohnny Huang 				}
1296b458cd62SJohnny Huang 				if (length == 1) {
12973cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1298b458cd62SJohnny Huang 					continue;
129976d13988SJohnny Huang 				}
130076d13988SJohnny Huang 
1301b458cd62SJohnny Huang 				if (j == 0)
13023cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1303b458cd62SJohnny Huang 				else if (j == length - 1)
1304b458cd62SJohnny Huang 					printf("\\ \"\n");
1305b458cd62SJohnny Huang 				else
1306b458cd62SJohnny Huang 					printf("| \"\n");
130776d13988SJohnny Huang 			}
1308b458cd62SJohnny Huang 		} else {
1309c947ef08SJohnny Huang 			if (length == 1) {
13103cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1311b458cd62SJohnny Huang 			} else {
1312b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1313b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1314b458cd62SJohnny Huang 			}
1315b458cd62SJohnny Huang 
1316b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1317b458cd62SJohnny Huang 
13183cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
13193cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1320b458cd62SJohnny Huang 			else
1321b458cd62SJohnny Huang 				printf("Reserved\n");
1322b458cd62SJohnny Huang 		}
1323b458cd62SJohnny Huang 	}
1324b458cd62SJohnny Huang 
1325b458cd62SJohnny Huang 	if (fail)
1326b458cd62SJohnny Huang 		return OTP_FAILURE;
1327b458cd62SJohnny Huang 
1328b458cd62SJohnny Huang 	return OTP_SUCCESS;
1329b458cd62SJohnny Huang }
1330b458cd62SJohnny Huang 
133188bd7d58SJohnny Huang static void _otp_print_key(u32 *data)
133269d5fd8fSJohnny Huang {
133388bd7d58SJohnny Huang 	int i, j;
133469d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
13359a4fe690SJohnny Huang 	struct otpkey_type key_info;
133688bd7d58SJohnny Huang 	const struct otpkey_type *key_info_array = info_cb.key_info;
133788bd7d58SJohnny Huang 	int len = 0;
1338a219f6deSJohnny Huang 	u8 *byte_buf;
133988bd7d58SJohnny Huang 	int empty;
134054552c69SJohnny Huang 
134188bd7d58SJohnny Huang 	byte_buf = (u8 *)data;
13429d998018SJohnny Huang 
134388bd7d58SJohnny Huang 	empty = 1;
13449d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
134588bd7d58SJohnny Huang 		if (i % 2) {
134688bd7d58SJohnny Huang 			if (data[i] != 0xffffffff)
134788bd7d58SJohnny Huang 				empty = 0;
134888bd7d58SJohnny Huang 		} else {
134988bd7d58SJohnny Huang 			if (data[i] != 0)
13509d998018SJohnny Huang 				empty = 0;
13519d998018SJohnny Huang 		}
135288bd7d58SJohnny Huang 	}
135388bd7d58SJohnny Huang 	if (empty) {
135488bd7d58SJohnny Huang 		printf("OTP data header is empty\n");
135588bd7d58SJohnny Huang 		return;
135688bd7d58SJohnny Huang 	}
13579d998018SJohnny Huang 
135888bd7d58SJohnny Huang 	for (i = 0; i < 16; i++) {
135988bd7d58SJohnny Huang 		key_id = data[i] & 0x7;
136088bd7d58SJohnny Huang 		key_offset = data[i] & 0x1ff8;
136188bd7d58SJohnny Huang 		last = (data[i] >> 13) & 1;
136288bd7d58SJohnny Huang 		key_type = (data[i] >> 14) & 0xf;
136388bd7d58SJohnny Huang 		key_length = (data[i] >> 18) & 0x3;
136488bd7d58SJohnny Huang 		exp_length = (data[i] >> 20) & 0xfff;
13659a4fe690SJohnny Huang 
136688bd7d58SJohnny Huang 		key_info.value = -1;
13679a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
13689a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
13699a4fe690SJohnny Huang 				key_info = key_info_array[j];
13709a4fe690SJohnny Huang 				break;
13719a4fe690SJohnny Huang 			}
13729a4fe690SJohnny Huang 		}
137388bd7d58SJohnny Huang 		if (key_info.value == -1)
137488bd7d58SJohnny Huang 			break;
13759a4fe690SJohnny Huang 
13767f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
137769d5fd8fSJohnny Huang 		printf("Key Type: ");
13789a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
13799a4fe690SJohnny Huang 
13809a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
138169d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
138269d5fd8fSJohnny Huang 			switch (key_length) {
138369d5fd8fSJohnny Huang 			case 0:
138469d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
138569d5fd8fSJohnny Huang 				break;
138669d5fd8fSJohnny Huang 			case 1:
138769d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
138869d5fd8fSJohnny Huang 				break;
138969d5fd8fSJohnny Huang 			case 2:
139069d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
139169d5fd8fSJohnny Huang 				break;
139269d5fd8fSJohnny Huang 			case 3:
139369d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
139469d5fd8fSJohnny Huang 				break;
139569d5fd8fSJohnny Huang 			}
1396181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1397181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
139869d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
139969d5fd8fSJohnny Huang 			switch (key_length) {
140069d5fd8fSJohnny Huang 			case 0:
140169d5fd8fSJohnny Huang 				printf("RSA1024\n");
140269d5fd8fSJohnny Huang 				len = 0x100;
140369d5fd8fSJohnny Huang 				break;
140469d5fd8fSJohnny Huang 			case 1:
140569d5fd8fSJohnny Huang 				printf("RSA2048\n");
140669d5fd8fSJohnny Huang 				len = 0x200;
140769d5fd8fSJohnny Huang 				break;
140869d5fd8fSJohnny Huang 			case 2:
140969d5fd8fSJohnny Huang 				printf("RSA3072\n");
141069d5fd8fSJohnny Huang 				len = 0x300;
141169d5fd8fSJohnny Huang 				break;
141269d5fd8fSJohnny Huang 			case 3:
141369d5fd8fSJohnny Huang 				printf("RSA4096\n");
141469d5fd8fSJohnny Huang 				len = 0x400;
141569d5fd8fSJohnny Huang 				break;
141669d5fd8fSJohnny Huang 			}
141769d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
141869d5fd8fSJohnny Huang 		}
14199a4fe690SJohnny Huang 		if (key_info.need_id)
142069d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
142169d5fd8fSJohnny Huang 		printf("Key Value:\n");
14229a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
142369d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
14249a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
14259a4fe690SJohnny Huang 			printf("AES Key:\n");
14269a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1427e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
14289a4fe690SJohnny Huang 				printf("AES IV:\n");
14299a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
14309a4fe690SJohnny Huang 			}
14319a4fe690SJohnny Huang 
14329a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1433e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
143469d5fd8fSJohnny Huang 				printf("AES Key:\n");
143569d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
143669d5fd8fSJohnny Huang 				printf("AES IV:\n");
143769d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
14385fdde29fSJohnny Huang 			} else {
14399a4fe690SJohnny Huang 				printf("AES Key 1:\n");
14409a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
14419a4fe690SJohnny Huang 				printf("AES Key 2:\n");
14429a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
14439a4fe690SJohnny Huang 			}
1444181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
144569d5fd8fSJohnny Huang 			printf("RSA mod:\n");
144669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
144769d5fd8fSJohnny Huang 			printf("RSA exp:\n");
144869d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1449181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1450181f72d8SJohnny Huang 			printf("RSA mod:\n");
1451181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1452181f72d8SJohnny Huang 			printf("RSA exp:\n");
1453a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
145469d5fd8fSJohnny Huang 		}
145569d5fd8fSJohnny Huang 		if (last)
145669d5fd8fSJohnny Huang 			break;
145769d5fd8fSJohnny Huang 	}
145888bd7d58SJohnny Huang }
145988bd7d58SJohnny Huang 
146088bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
146188bd7d58SJohnny Huang {
146288bd7d58SJohnny Huang 	u32 *buf;
146388bd7d58SJohnny Huang 
146488bd7d58SJohnny Huang 	buf = (u32 *)image_layout->data;
146588bd7d58SJohnny Huang 	_otp_print_key(buf);
146688bd7d58SJohnny Huang 
1467f347c284SJohnny Huang 	return OTP_SUCCESS;
1468f347c284SJohnny Huang }
1469f347c284SJohnny Huang 
147088bd7d58SJohnny Huang static void otp_print_key_info(void)
147188bd7d58SJohnny Huang {
147288bd7d58SJohnny Huang 	u32 data[2048];
147388bd7d58SJohnny Huang 	int i;
147488bd7d58SJohnny Huang 
147588bd7d58SJohnny Huang 	for (i = 0; i < 2048 ; i += 2)
147688bd7d58SJohnny Huang 		otp_read_data(i, &data[i]);
147788bd7d58SJohnny Huang 
147888bd7d58SJohnny Huang 	_otp_print_key(data);
147988bd7d58SJohnny Huang }
148088bd7d58SJohnny Huang 
1481b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data)
1482f347c284SJohnny Huang {
1483f347c284SJohnny Huang 	int i;
1484f347c284SJohnny Huang 	int ret;
1485f347c284SJohnny Huang 	u32 *buf;
1486f347c284SJohnny Huang 	u32 *buf_ignore;
1487f347c284SJohnny Huang 
1488f347c284SJohnny Huang 	buf = (u32 *)image_layout->data;
1489f347c284SJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
1490f347c284SJohnny Huang 	printf("Start Programing...\n");
1491f347c284SJohnny Huang 
1492f347c284SJohnny Huang 	// programing ecc region first
1493f347c284SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1494f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1495f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1496f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1497f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1498f347c284SJohnny Huang 			return ret;
1499f347c284SJohnny Huang 		}
1500f347c284SJohnny Huang 	}
1501f347c284SJohnny Huang 
1502f347c284SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1503f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1504f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1505f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1506f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1507f347c284SJohnny Huang 			return ret;
1508f347c284SJohnny Huang 		}
1509f347c284SJohnny Huang 	}
1510f347c284SJohnny Huang 	otp_soak(0);
1511f347c284SJohnny Huang 	return OTP_SUCCESS;
1512f347c284SJohnny Huang }
1513f347c284SJohnny Huang 
1514b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1515f347c284SJohnny Huang {
1516f347c284SJohnny Huang 	u32 *strap;
1517f347c284SJohnny Huang 	u32 *strap_ignore;
1518f347c284SJohnny Huang 	u32 *strap_pro;
1519f347c284SJohnny Huang 	u32 prog_address;
1520f347c284SJohnny Huang 	int i;
15217e523e3bSJohnny Huang 	int bit, pbit, ibit, offset;
1522f347c284SJohnny Huang 	int fail = 0;
1523f347c284SJohnny Huang 	int ret;
1524f347c284SJohnny Huang 	int prog_flag = 0;
1525f347c284SJohnny Huang 
1526f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1527f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1528f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1529f347c284SJohnny Huang 
1530f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1531f347c284SJohnny Huang 		prog_address = 0x800;
1532f347c284SJohnny Huang 		if (i < 32) {
1533f347c284SJohnny Huang 			offset = i;
1534f347c284SJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1535f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
1536f347c284SJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
1537f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1538f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1539f347c284SJohnny Huang 
1540f347c284SJohnny Huang 		} else {
1541f347c284SJohnny Huang 			offset = (i - 32);
1542f347c284SJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1543f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
1544f347c284SJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
1545f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1546f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1547f347c284SJohnny Huang 		}
1548f347c284SJohnny Huang 
1549f347c284SJohnny Huang 		if (ibit == 1)
1550f347c284SJohnny Huang 			continue;
1551f347c284SJohnny Huang 		if (bit == otpstrap[i].value)
1552f347c284SJohnny Huang 			prog_flag = 0;
1553f347c284SJohnny Huang 		else
1554f347c284SJohnny Huang 			prog_flag = 1;
1555f347c284SJohnny Huang 
1556f347c284SJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
1557f347c284SJohnny Huang 			fail = 1;
1558f347c284SJohnny Huang 			continue;
1559f347c284SJohnny Huang 		}
1560f347c284SJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
1561f347c284SJohnny Huang 			fail = 1;
1562f347c284SJohnny Huang 			continue;
1563f347c284SJohnny Huang 		}
1564f347c284SJohnny Huang 
1565f347c284SJohnny Huang 		if (prog_flag) {
1566f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1567f347c284SJohnny Huang 			if (ret)
1568f347c284SJohnny Huang 				return OTP_FAILURE;
1569f347c284SJohnny Huang 		}
1570f347c284SJohnny Huang 
1571f347c284SJohnny Huang 		if (pbit != 0) {
1572f347c284SJohnny Huang 			prog_address = 0x800;
1573f347c284SJohnny Huang 			if (i < 32)
1574f347c284SJohnny Huang 				prog_address |= 0x60c;
1575f347c284SJohnny Huang 			else
1576f347c284SJohnny Huang 				prog_address |= 0x60e;
1577f347c284SJohnny Huang 
1578f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1579f347c284SJohnny Huang 			if (ret)
1580f347c284SJohnny Huang 				return OTP_FAILURE;
1581f347c284SJohnny Huang 		}
1582f347c284SJohnny Huang 	}
1583f347c284SJohnny Huang 	otp_soak(0);
1584f347c284SJohnny Huang 	if (fail == 1)
1585f347c284SJohnny Huang 		return OTP_FAILURE;
1586f347c284SJohnny Huang 	return OTP_SUCCESS;
158769d5fd8fSJohnny Huang }
158869d5fd8fSJohnny Huang 
1589b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf)
159069d5fd8fSJohnny Huang {
1591a6d0d645SJohnny Huang 	int i, k;
1592d90825e2SJohnny Huang 	int pass = 0;
1593a219f6deSJohnny Huang 	u32 prog_address;
1594a219f6deSJohnny Huang 	u32 compare[2];
1595a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1596a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1597a219f6deSJohnny Huang 	u32 data_masked;
1598a219f6deSJohnny Huang 	u32 buf_masked;
15992031a123SJohnny Huang 	int ret;
160069d5fd8fSJohnny Huang 
1601a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1602d90825e2SJohnny Huang 	otp_soak(0);
1603bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
1604b64ca396SJohnny Huang 		data_masked = otp_conf[i]  & ~conf_ignore[i];
16055010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1606a6d0d645SJohnny Huang 		prog_address = 0x800;
1607a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1608a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1609bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1610bb34a7bfSJohnny Huang 			pass = 1;
1611a6d0d645SJohnny Huang 			continue;
1612bb34a7bfSJohnny Huang 		}
1613de6fbf1cSJohnny Huang 
1614de6fbf1cSJohnny Huang 		otp_soak(1);
16152031a123SJohnny Huang 		ret = otp_prog_dw(conf[i], conf_ignore[i], prog_address);
16162031a123SJohnny Huang 		if (ret)
16172031a123SJohnny Huang 			return OTP_FAILURE;
1618a6d0d645SJohnny Huang 
161969d5fd8fSJohnny Huang 		pass = 0;
162069d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
16215010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1622de6fbf1cSJohnny Huang 				otp_soak(2);
16232031a123SJohnny Huang 				ret = otp_prog_dw(compare[0], conf_ignore[i], prog_address);
16242031a123SJohnny Huang 				if (ret)
16252031a123SJohnny Huang 					return OTP_FAILURE;
16265010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1627de6fbf1cSJohnny Huang 					otp_soak(1);
1628de6fbf1cSJohnny Huang 				} else {
1629de6fbf1cSJohnny Huang 					pass = 1;
1630de6fbf1cSJohnny Huang 					break;
1631de6fbf1cSJohnny Huang 				}
1632a6d0d645SJohnny Huang 			} else {
163369d5fd8fSJohnny Huang 				pass = 1;
163469d5fd8fSJohnny Huang 				break;
163569d5fd8fSJohnny Huang 			}
163669d5fd8fSJohnny Huang 		}
1637bb34a7bfSJohnny Huang 		if (pass == 0) {
1638b64ca396SJohnny Huang 			printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n",
1639b64ca396SJohnny Huang 			       i, otp_conf[i], conf[i], conf_ignore[i]);
1640bb34a7bfSJohnny Huang 			break;
1641bb34a7bfSJohnny Huang 		}
1642a6d0d645SJohnny Huang 	}
1643a6d0d645SJohnny Huang 
1644de6fbf1cSJohnny Huang 	otp_soak(0);
164569d5fd8fSJohnny Huang 	if (!pass)
16462a856b9aSJohnny Huang 		return OTP_FAILURE;
1647a6d0d645SJohnny Huang 
16482a856b9aSJohnny Huang 	return OTP_SUCCESS;
164969d5fd8fSJohnny Huang }
165069d5fd8fSJohnny Huang 
1651b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro)
1652b25f02d2SJohnny Huang {
1653b25f02d2SJohnny Huang 	int i, k;
1654b25f02d2SJohnny Huang 	int pass = 0;
1655b25f02d2SJohnny Huang 	u32 prog_address;
1656b25f02d2SJohnny Huang 	u32 compare[2];
1657b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1658b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1659b25f02d2SJohnny Huang 	u32 data_masked;
1660b25f02d2SJohnny Huang 	u32 buf_masked;
16612031a123SJohnny Huang 	int ret;
1662b25f02d2SJohnny Huang 
1663b25f02d2SJohnny Huang 	printf("Start Programing...\n");
1664b25f02d2SJohnny Huang 	otp_soak(0);
1665b25f02d2SJohnny Huang 	for (i = 0; i < 2; i++) {
1666b25f02d2SJohnny Huang 		data_masked = scu_pro[i]  & ~OTPSCU_IGNORE[i];
1667b25f02d2SJohnny Huang 		buf_masked  = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1668b25f02d2SJohnny Huang 		prog_address = 0xe08 + i * 2;
1669b25f02d2SJohnny Huang 		if (data_masked == buf_masked) {
1670b25f02d2SJohnny Huang 			pass = 1;
1671b25f02d2SJohnny Huang 			continue;
1672b25f02d2SJohnny Huang 		}
1673b25f02d2SJohnny Huang 
1674b25f02d2SJohnny Huang 		otp_soak(1);
16752031a123SJohnny Huang 		ret = otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address);
16762031a123SJohnny Huang 		if (ret)
16772031a123SJohnny Huang 			return OTP_FAILURE;
1678b25f02d2SJohnny Huang 		pass = 0;
1679b25f02d2SJohnny Huang 		for (k = 0; k < RETRY; k++) {
1680b25f02d2SJohnny Huang 			if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1681b25f02d2SJohnny Huang 				otp_soak(2);
16822031a123SJohnny Huang 				ret = otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address);
16832031a123SJohnny Huang 				if (ret)
16842031a123SJohnny Huang 					return OTP_FAILURE;
1685b25f02d2SJohnny Huang 				if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1686b25f02d2SJohnny Huang 					otp_soak(1);
1687b25f02d2SJohnny Huang 				} else {
1688b25f02d2SJohnny Huang 					pass = 1;
1689b25f02d2SJohnny Huang 					break;
1690b25f02d2SJohnny Huang 				}
1691b25f02d2SJohnny Huang 			} else {
1692b25f02d2SJohnny Huang 				pass = 1;
1693b25f02d2SJohnny Huang 				break;
1694b25f02d2SJohnny Huang 			}
1695b25f02d2SJohnny Huang 		}
1696b25f02d2SJohnny Huang 		if (pass == 0) {
1697b489486eSJohnny Huang 			printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n",
1698b25f02d2SJohnny Huang 			       i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]);
1699b25f02d2SJohnny Huang 			break;
1700b25f02d2SJohnny Huang 		}
1701b25f02d2SJohnny Huang 	}
1702b25f02d2SJohnny Huang 
1703b25f02d2SJohnny Huang 	otp_soak(0);
1704b25f02d2SJohnny Huang 	if (!pass)
1705b25f02d2SJohnny Huang 		return OTP_FAILURE;
1706b25f02d2SJohnny Huang 
1707b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1708b25f02d2SJohnny Huang }
1709b25f02d2SJohnny Huang 
1710b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data)
1711b64ca396SJohnny Huang {
1712b64ca396SJohnny Huang 	int data_dw;
1713b64ca396SJohnny Huang 	u32 data_masked;
1714b64ca396SJohnny Huang 	u32 buf_masked;
1715b64ca396SJohnny Huang 	u32 *buf = (u32 *)image_layout->data;
1716b64ca396SJohnny Huang 	u32 *buf_ignore = (u32 *)image_layout->data_ignore;
1717b64ca396SJohnny Huang 	int i;
1718b64ca396SJohnny Huang 
1719b64ca396SJohnny Huang 	data_dw = image_layout->data_length / 4;
1720b64ca396SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
1721b64ca396SJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1722b64ca396SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1723b64ca396SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
1724b64ca396SJohnny Huang 		if (data_masked == buf_masked)
1725b64ca396SJohnny Huang 			continue;
1726b64ca396SJohnny Huang 		if (i % 2 == 0) {
1727b64ca396SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
1728b64ca396SJohnny Huang 				continue;
1729b64ca396SJohnny Huang 			} else {
1730b64ca396SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1731b489486eSJohnny Huang 				printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1732b489486eSJohnny Huang 				printf("Input   [0x%x] = 0x%x\n", i, buf[i]);
1733b489486eSJohnny Huang 				printf("Mask    [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1734b64ca396SJohnny Huang 				return OTP_FAILURE;
1735b64ca396SJohnny Huang 			}
1736b64ca396SJohnny Huang 		} else {
1737b64ca396SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1738b64ca396SJohnny Huang 				continue;
1739b64ca396SJohnny Huang 			} else {
1740b64ca396SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1741b489486eSJohnny Huang 				printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1742b489486eSJohnny Huang 				printf("Input   [0x%x] = 0x%x\n", i, buf[i]);
1743b489486eSJohnny Huang 				printf("Mask    [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1744b64ca396SJohnny Huang 				return OTP_FAILURE;
1745b64ca396SJohnny Huang 			}
1746b64ca396SJohnny Huang 		}
1747b64ca396SJohnny Huang 	}
1748b64ca396SJohnny Huang 	return OTP_SUCCESS;
1749b64ca396SJohnny Huang }
1750b64ca396SJohnny Huang 
1751b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1752b64ca396SJohnny Huang {
1753b64ca396SJohnny Huang 	int i;
1754b64ca396SJohnny Huang 	u32 *strap;
1755b64ca396SJohnny Huang 	u32 *strap_ignore;
1756b64ca396SJohnny Huang 	u32 *strap_pro;
1757b64ca396SJohnny Huang 	int bit, pbit, ibit;
1758b64ca396SJohnny Huang 	int fail = 0;
1759b64ca396SJohnny Huang 	int ret;
1760b64ca396SJohnny Huang 
1761b64ca396SJohnny Huang 	strap = (u32 *)image_layout->strap;
1762b64ca396SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1763b64ca396SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1764b64ca396SJohnny Huang 
1765b64ca396SJohnny Huang 	for (i = 0; i < 64; i++) {
1766b64ca396SJohnny Huang 		if (i < 32) {
1767b64ca396SJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1768b64ca396SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
1769b64ca396SJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
1770b64ca396SJohnny Huang 		} else {
1771b64ca396SJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1772b64ca396SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1773b64ca396SJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1774b64ca396SJohnny Huang 		}
1775b64ca396SJohnny Huang 
1776b64ca396SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit);
1777b64ca396SJohnny Huang 
1778b64ca396SJohnny Huang 		if (ret == OTP_FAILURE)
1779b64ca396SJohnny Huang 			fail = 1;
1780b64ca396SJohnny Huang 	}
1781b64ca396SJohnny Huang 	if (fail == 1) {
1782b64ca396SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
1783b64ca396SJohnny Huang 		return OTP_FAILURE;
1784b64ca396SJohnny Huang 	}
1785b64ca396SJohnny Huang 	return OTP_SUCCESS;
1786b64ca396SJohnny Huang }
1787b64ca396SJohnny Huang 
1788b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf)
1789b64ca396SJohnny Huang {
1790b64ca396SJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1791b64ca396SJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1792b64ca396SJohnny Huang 	u32 data_masked;
1793b64ca396SJohnny Huang 	u32 buf_masked;
1794b64ca396SJohnny Huang 	int i;
1795b64ca396SJohnny Huang 
1796b64ca396SJohnny Huang 	for (i = 0; i < 16; i++) {
1797b64ca396SJohnny Huang 		data_masked = otp_conf[i]  & ~conf_ignore[i];
1798b64ca396SJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1799b64ca396SJohnny Huang 		if (data_masked == buf_masked)
1800b64ca396SJohnny Huang 			continue;
1801b64ca396SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1802b64ca396SJohnny Huang 			continue;
1803b64ca396SJohnny Huang 		} else {
1804b64ca396SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1805b64ca396SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, otp_conf[i]);
1806b64ca396SJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
1807b64ca396SJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
1808b64ca396SJohnny Huang 			return OTP_FAILURE;
1809b64ca396SJohnny Huang 		}
1810b64ca396SJohnny Huang 	}
1811b64ca396SJohnny Huang 	return OTP_SUCCESS;
1812b64ca396SJohnny Huang }
1813b64ca396SJohnny Huang 
1814b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro)
1815b25f02d2SJohnny Huang {
1816b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1817b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1818b25f02d2SJohnny Huang 	u32 data_masked;
1819b25f02d2SJohnny Huang 	u32 buf_masked;
1820b25f02d2SJohnny Huang 	int i;
1821b25f02d2SJohnny Huang 
1822b25f02d2SJohnny Huang 	for (i = 0; i < 2; i++) {
1823b25f02d2SJohnny Huang 		data_masked = scu_pro[i]  & ~OTPSCU_IGNORE[i];
1824b25f02d2SJohnny Huang 		buf_masked  = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1825b25f02d2SJohnny Huang 		if (data_masked == buf_masked)
1826b25f02d2SJohnny Huang 			continue;
1827b25f02d2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1828b25f02d2SJohnny Huang 			continue;
1829b25f02d2SJohnny Huang 		} else {
1830b25f02d2SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1831b489486eSJohnny Huang 			printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]);
1832b489486eSJohnny Huang 			printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]);
1833b489486eSJohnny Huang 			printf("Mask  [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]);
1834b25f02d2SJohnny Huang 			return OTP_FAILURE;
1835b25f02d2SJohnny Huang 		}
1836b25f02d2SJohnny Huang 	}
1837b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1838b25f02d2SJohnny Huang }
1839b25f02d2SJohnny Huang 
1840f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf)
1841696656c6SJohnny Huang {
1842*a3dcef30SJohnny Huang 	sha512_context ctx;
1843696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1844696656c6SJohnny Huang 
1845*a3dcef30SJohnny Huang 	sha384_starts(&ctx);
1846*a3dcef30SJohnny Huang 	sha384_update(&ctx, src_buf, length);
1847*a3dcef30SJohnny Huang 	sha384_finish(&ctx, digest_ret);
1848696656c6SJohnny Huang 
1849696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1850f347c284SJohnny Huang 		return OTP_SUCCESS;
1851f347c284SJohnny Huang 	return OTP_FAILURE;
1852696656c6SJohnny Huang }
1853696656c6SJohnny Huang 
1854f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
185569d5fd8fSJohnny Huang {
185669d5fd8fSJohnny Huang 	int ret;
185761a6cda7SJohnny Huang 	int image_soc_ver = 0;
1858696656c6SJohnny Huang 	struct otp_header *otp_header;
1859696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1860696656c6SJohnny Huang 	int image_size;
1861a219f6deSJohnny Huang 	u8 *buf;
1862a219f6deSJohnny Huang 	u8 *checksum;
1863b64ca396SJohnny Huang 	int i;
1864b64ca396SJohnny Huang 	u32 data[2048];
1865b64ca396SJohnny Huang 	u32 conf[16];
1866b25f02d2SJohnny Huang 	u32 scu_pro[2];
1867b64ca396SJohnny Huang 	struct otpstrap_status otpstrap[64];
186869d5fd8fSJohnny Huang 
1869696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1870696656c6SJohnny Huang 	if (!otp_header) {
1871030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
18722a856b9aSJohnny Huang 		return OTP_FAILURE;
187369d5fd8fSJohnny Huang 	}
1874d90825e2SJohnny Huang 
1875696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1876696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1877696656c6SJohnny Huang 
1878696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1879696656c6SJohnny Huang 
1880696656c6SJohnny Huang 	if (!buf) {
1881030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
1882696656c6SJohnny Huang 		return OTP_FAILURE;
1883696656c6SJohnny Huang 	}
1884696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1885696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1886696656c6SJohnny Huang 
1887696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1888030cb4a7SJohnny Huang 		printf("Image is invalid\n");
1889696656c6SJohnny Huang 		return OTP_FAILURE;
1890696656c6SJohnny Huang 	}
1891696656c6SJohnny Huang 
18925010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
18935010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
18945010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
18955010032bSJohnny Huang 
18965010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1897696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
18985010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1899696656c6SJohnny Huang 
1900696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
19015010032bSJohnny Huang 	image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
19025010032bSJohnny Huang 	image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
19035010032bSJohnny Huang 	image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
19047e523e3bSJohnny Huang 
1905b25f02d2SJohnny Huang 	image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info);
1906b25f02d2SJohnny Huang 	image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2);
1907b25f02d2SJohnny Huang 	image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length;
1908b25f02d2SJohnny Huang 
19097e523e3bSJohnny Huang 	if (otp_header->soc_ver == SOC_AST2600A0) {
19107e523e3bSJohnny Huang 		image_soc_ver = OTP_A0;
191161a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A1) {
191261a6cda7SJohnny Huang 		image_soc_ver = OTP_A1;
191361a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A2) {
191461a6cda7SJohnny Huang 		image_soc_ver = OTP_A2;
191561a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A3) {
191661a6cda7SJohnny Huang 		image_soc_ver = OTP_A3;
1917696656c6SJohnny Huang 	} else {
1918030cb4a7SJohnny Huang 		printf("Image SOC Version is not supported\n");
1919696656c6SJohnny Huang 		return OTP_FAILURE;
1920696656c6SJohnny Huang 	}
1921696656c6SJohnny Huang 
192261a6cda7SJohnny Huang 	if (image_soc_ver != info_cb.version) {
19235e096f11SJohnny Huang 		printf("Image SOC version is not match to HW SOC version\n");
19249a4fe690SJohnny Huang 		return OTP_FAILURE;
19259a4fe690SJohnny Huang 	}
19269a4fe690SJohnny Huang 
19275e096f11SJohnny Huang 	if (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver) != OTPTOOL_COMPT_VERSION) {
1928*a3dcef30SJohnny Huang 		printf("OTP image is not generated by otptool v2.x.x\n");
192961a6cda7SJohnny Huang 		return OTP_FAILURE;
193061a6cda7SJohnny Huang 	}
193161a6cda7SJohnny Huang 
1932f347c284SJohnny Huang 	if (otp_verify_image(buf, image_size, checksum)) {
1933030cb4a7SJohnny Huang 		printf("checksum is invalid\n");
1934696656c6SJohnny Huang 		return OTP_FAILURE;
1935d90825e2SJohnny Huang 	}
19367332532cSJohnny Huang 
1937030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
1938030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
1939030cb4a7SJohnny Huang 		return OTP_FAILURE;
1940030cb4a7SJohnny Huang 	}
1941b64ca396SJohnny Huang 	ret = 0;
1942030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
1943030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_data) {
1944030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
1945030cb4a7SJohnny Huang 			ret = -1;
1946030cb4a7SJohnny Huang 		}
1947030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_sec) {
1948030cb4a7SJohnny Huang 			printf("OTP secure region is protected\n");
1949030cb4a7SJohnny Huang 			ret = -1;
1950030cb4a7SJohnny Huang 		}
1951b64ca396SJohnny Huang 		printf("Read OTP Data Region:\n");
1952b64ca396SJohnny Huang 		for (i = 0; i < 2048 ; i += 2)
1953b64ca396SJohnny Huang 			otp_read_data(i, &data[i]);
1954b64ca396SJohnny Huang 
1955b64ca396SJohnny Huang 		printf("Check writable...\n");
1956b64ca396SJohnny Huang 		if (otp_check_data_image(&image_layout, data) == OTP_FAILURE)
1957b64ca396SJohnny Huang 			ret = -1;
1958030cb4a7SJohnny Huang 	}
1959030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
1960030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_conf) {
1961030cb4a7SJohnny Huang 			printf("OTP config region is protected\n");
1962030cb4a7SJohnny Huang 			ret = -1;
1963030cb4a7SJohnny Huang 		}
1964b64ca396SJohnny Huang 		printf("Read OTP Config Region:\n");
1965b64ca396SJohnny Huang 		for (i = 0; i < 16 ; i++)
1966b64ca396SJohnny Huang 			otp_read_conf(i, &conf[i]);
1967b64ca396SJohnny Huang 
1968b64ca396SJohnny Huang 		printf("Check writable...\n");
1969b64ca396SJohnny Huang 		if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE)
1970b64ca396SJohnny Huang 			ret = -1;
1971030cb4a7SJohnny Huang 	}
1972030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
1973030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
1974030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
1975030cb4a7SJohnny Huang 			ret = -1;
1976030cb4a7SJohnny Huang 		}
1977b64ca396SJohnny Huang 		printf("Read OTP Strap Region:\n");
1978b64ca396SJohnny Huang 		otp_strap_status(otpstrap);
1979b64ca396SJohnny Huang 
1980b64ca396SJohnny Huang 		printf("Check writable...\n");
1981b64ca396SJohnny Huang 		if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE)
1982b64ca396SJohnny Huang 			ret = -1;
1983030cb4a7SJohnny Huang 	}
1984b25f02d2SJohnny Huang 	if (otp_header->image_info & OTP_INC_SCU_PRO) {
1985b25f02d2SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
1986b25f02d2SJohnny Huang 			printf("OTP strap region is protected\n");
1987b25f02d2SJohnny Huang 			ret = -1;
1988b25f02d2SJohnny Huang 		}
1989b25f02d2SJohnny Huang 		printf("Read SCU Protect Region:\n");
1990b25f02d2SJohnny Huang 		otp_read_conf(28, &scu_pro[0]);
1991b25f02d2SJohnny Huang 		otp_read_conf(29, &scu_pro[1]);
1992b25f02d2SJohnny Huang 
1993b25f02d2SJohnny Huang 		printf("Check writable...\n");
1994b25f02d2SJohnny Huang 		if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE)
1995b25f02d2SJohnny Huang 			ret = -1;
1996b25f02d2SJohnny Huang 	}
1997030cb4a7SJohnny Huang 	if (ret == -1)
1998030cb4a7SJohnny Huang 		return OTP_FAILURE;
1999b64ca396SJohnny Huang 
200069d5fd8fSJohnny Huang 	if (!nconfirm) {
2001696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
20027f795e57SJohnny Huang 			printf("\nOTP data region :\n");
2003f347c284SJohnny Huang 			if (otp_print_data_image(&image_layout) < 0) {
200469d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
20052a856b9aSJohnny Huang 				return OTP_FAILURE;
200669d5fd8fSJohnny Huang 			}
200769d5fd8fSJohnny Huang 		}
2008696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
20097332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
2010696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
20117332532cSJohnny Huang 				printf("OTP config error, please check.\n");
20127332532cSJohnny Huang 				return OTP_FAILURE;
20137332532cSJohnny Huang 			}
20147332532cSJohnny Huang 		}
20157adec5f6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
20167adec5f6SJohnny Huang 			printf("\nOTP strap region :\n");
20177adec5f6SJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
20187adec5f6SJohnny Huang 				printf("OTP strap error, please check.\n");
20197adec5f6SJohnny Huang 				return OTP_FAILURE;
20207adec5f6SJohnny Huang 			}
20217adec5f6SJohnny Huang 		}
2022b25f02d2SJohnny Huang 		if (otp_header->image_info & OTP_INC_SCU_PRO) {
2023b25f02d2SJohnny Huang 			printf("\nOTP scu protect region :\n");
2024b25f02d2SJohnny Huang 			if (otp_print_scu_image(&image_layout) < 0) {
2025b25f02d2SJohnny Huang 				printf("OTP scu protect error, please check.\n");
2026b25f02d2SJohnny Huang 				return OTP_FAILURE;
2027b25f02d2SJohnny Huang 			}
2028b25f02d2SJohnny Huang 		}
20297332532cSJohnny Huang 
203069d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
203169d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
203269d5fd8fSJohnny Huang 			printf(" Aborting\n");
20332a856b9aSJohnny Huang 			return OTP_FAILURE;
203469d5fd8fSJohnny Huang 		}
203569d5fd8fSJohnny Huang 	}
20367332532cSJohnny Huang 
20375010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
20385010032bSJohnny Huang 		printf("programing data region ...\n");
2039b64ca396SJohnny Huang 		ret = otp_prog_data(&image_layout, data);
20405010032bSJohnny Huang 		if (ret != 0) {
20415010032bSJohnny Huang 			printf("Error\n");
20425010032bSJohnny Huang 			return ret;
20435010032bSJohnny Huang 		}
2044a219f6deSJohnny Huang 		printf("Done\n");
20455010032bSJohnny Huang 	}
20465010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
20475010032bSJohnny Huang 		printf("programing strap region ...\n");
2048b64ca396SJohnny Huang 		ret = otp_prog_strap(&image_layout, otpstrap);
20495010032bSJohnny Huang 		if (ret != 0) {
20505010032bSJohnny Huang 			printf("Error\n");
20515010032bSJohnny Huang 			return ret;
20525010032bSJohnny Huang 		}
2053a219f6deSJohnny Huang 		printf("Done\n");
20545010032bSJohnny Huang 	}
2055b25f02d2SJohnny Huang 	if (otp_header->image_info & OTP_INC_SCU_PRO) {
2056b25f02d2SJohnny Huang 		printf("programing scu protect region ...\n");
2057b25f02d2SJohnny Huang 		ret = otp_prog_scu_protect(&image_layout, scu_pro);
2058b25f02d2SJohnny Huang 		if (ret != 0) {
2059b25f02d2SJohnny Huang 			printf("Error\n");
2060b25f02d2SJohnny Huang 			return ret;
2061b25f02d2SJohnny Huang 		}
2062b25f02d2SJohnny Huang 		printf("Done\n");
2063b25f02d2SJohnny Huang 	}
20645010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
20655010032bSJohnny Huang 		printf("programing configuration region ...\n");
2066b64ca396SJohnny Huang 		ret = otp_prog_conf(&image_layout, conf);
20675010032bSJohnny Huang 		if (ret != 0) {
20685010032bSJohnny Huang 			printf("Error\n");
20695010032bSJohnny Huang 			return ret;
20705010032bSJohnny Huang 		}
20715010032bSJohnny Huang 		printf("Done\n");
20725010032bSJohnny Huang 	}
2073cd1610b4SJohnny Huang 
20747332532cSJohnny Huang 	return OTP_SUCCESS;
20752a856b9aSJohnny Huang }
20762a856b9aSJohnny Huang 
2077f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
2078cd1610b4SJohnny Huang {
2079a219f6deSJohnny Huang 	u32 read[2];
2080a219f6deSJohnny Huang 	u32 prog_address = 0;
208166f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
2082cd1610b4SJohnny Huang 	int otp_bit;
208383655e91SJohnny Huang 	int ret = 0;
2084cd1610b4SJohnny Huang 
2085dacbba92SJohnny Huang 	otp_soak(0);
2086cd1610b4SJohnny Huang 	switch (mode) {
2087a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
2088f347c284SJohnny Huang 		otp_read_conf(otp_dw_offset, read);
2089cd1610b4SJohnny Huang 		prog_address = 0x800;
2090cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
2091cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
2092a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
2093cd1610b4SJohnny Huang 		if (otp_bit == value) {
2094b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2095cd1610b4SJohnny Huang 			printf("No need to program\n");
20962a856b9aSJohnny Huang 			return OTP_SUCCESS;
2097cd1610b4SJohnny Huang 		}
2098cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
2099b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
21000dc9a440SJohnny Huang 			printf("OTP is programmed, which can't be clean\n");
21012a856b9aSJohnny Huang 			return OTP_FAILURE;
2102cd1610b4SJohnny Huang 		}
2103b489486eSJohnny Huang 		printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2104cd1610b4SJohnny Huang 		break;
2105a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
2106cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
2107cd1610b4SJohnny Huang 
2108cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
2109a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
2110a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
2111643b9cfdSJohnny Huang 
2112643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
2113b489486eSJohnny Huang 				printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2114b64ca396SJohnny Huang 				printf("OTP is programmed, which can't be cleared\n");
2115643b9cfdSJohnny Huang 				return OTP_FAILURE;
2116643b9cfdSJohnny Huang 			}
2117cd1610b4SJohnny Huang 		} else {
2118a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
2119a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
2120643b9cfdSJohnny Huang 
2121643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
2122b489486eSJohnny Huang 				printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2123b64ca396SJohnny Huang 				printf("OTP is programmed, which can't be written\n");
2124643b9cfdSJohnny Huang 				return OTP_FAILURE;
2125643b9cfdSJohnny Huang 			}
2126cd1610b4SJohnny Huang 		}
2127cd1610b4SJohnny Huang 		if (otp_bit == value) {
2128b489486eSJohnny Huang 			printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2129cd1610b4SJohnny Huang 			printf("No need to program\n");
21302a856b9aSJohnny Huang 			return OTP_SUCCESS;
2131cd1610b4SJohnny Huang 		}
2132643b9cfdSJohnny Huang 
2133b489486eSJohnny Huang 		printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2134cd1610b4SJohnny Huang 		break;
2135a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
21368848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
21378848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
21387e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
21398848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
21408848d5dcSJohnny Huang 			return OTP_FAILURE;
21418848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
21428848d5dcSJohnny Huang 			return OTP_SUCCESS;
2143a6af4a17SJohnny Huang 
2144cd1610b4SJohnny Huang 		break;
2145cd1610b4SJohnny Huang 	}
2146cd1610b4SJohnny Huang 
2147cd1610b4SJohnny Huang 	if (!nconfirm) {
2148cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2149cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
2150cd1610b4SJohnny Huang 			printf(" Aborting\n");
21512a856b9aSJohnny Huang 			return OTP_FAILURE;
2152cd1610b4SJohnny Huang 		}
2153cd1610b4SJohnny Huang 	}
2154cd1610b4SJohnny Huang 
2155cd1610b4SJohnny Huang 	switch (mode) {
2156a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
2157f347c284SJohnny Huang 		ret =  otp_prog_strap_b(bit_offset, value);
215883655e91SJohnny Huang 		break;
2159a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
2160a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
2161f347c284SJohnny Huang 		ret = otp_prog_dc_b(value, prog_address, bit_offset);
2162de6fbf1cSJohnny Huang 		break;
2163de6fbf1cSJohnny Huang 	}
2164de6fbf1cSJohnny Huang 	otp_soak(0);
216583655e91SJohnny Huang 	if (ret) {
21660dc9a440SJohnny Huang 		printf("OTP cannot be programmed\n");
2167794e27ecSJohnny Huang 		printf("FAILURE\n");
2168794e27ecSJohnny Huang 		return OTP_FAILURE;
2169794e27ecSJohnny Huang 	}
2170794e27ecSJohnny Huang 
21719009c25dSJohnny Huang 	printf("SUCCESS\n");
21722a856b9aSJohnny Huang 	return OTP_SUCCESS;
2173a219f6deSJohnny Huang }
2174a219f6deSJohnny Huang 
2175794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
2176794e27ecSJohnny Huang {
2177794e27ecSJohnny Huang 	u32 otp_rid[2];
2178a8789b47SJohnny Huang 	u32 sw_rid[2];
2179794e27ecSJohnny Huang 	int rid_num = 0;
2180a8789b47SJohnny Huang 	int sw_rid_num = 0;
2181794e27ecSJohnny Huang 	int bit_offset;
2182794e27ecSJohnny Huang 	int dw_offset;
2183794e27ecSJohnny Huang 	int i;
2184794e27ecSJohnny Huang 	int ret;
2185794e27ecSJohnny Huang 
2186f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2187f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2188794e27ecSJohnny Huang 
2189a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2190a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2191a8789b47SJohnny Huang 
2192794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2193a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2194a8789b47SJohnny Huang 
2195a8789b47SJohnny Huang 	if (sw_rid_num < 0) {
2196a8789b47SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
2197a8789b47SJohnny Huang 		return OTP_FAILURE;
2198a8789b47SJohnny Huang 	}
2199a8789b47SJohnny Huang 
2200a8789b47SJohnny Huang 	if (update_num > sw_rid_num) {
2201a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
2202a8789b47SJohnny Huang 		printf("update number could not bigger than current SW revision id\n");
2203a8789b47SJohnny Huang 		return OTP_FAILURE;
2204a8789b47SJohnny Huang 	}
2205794e27ecSJohnny Huang 
2206794e27ecSJohnny Huang 	if (rid_num < 0) {
2207b64ca396SJohnny Huang 		printf("Current OTP revision ID cannot handle by this command,\n"
2208b64ca396SJohnny Huang 		       "please use 'otp pb' command to update it manually\n");
2209794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
22109009c25dSJohnny Huang 		return OTP_FAILURE;
22119009c25dSJohnny Huang 	}
2212cd1610b4SJohnny Huang 
2213794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
2214794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2215794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
2216794e27ecSJohnny Huang 
2217a8789b47SJohnny Huang 	if (rid_num > update_num) {
2218a8789b47SJohnny Huang 		printf("OTP rev_id is bigger than 0x%X\n", update_num);
2219a8789b47SJohnny Huang 		printf("Skip\n");
2220a8789b47SJohnny Huang 		return OTP_FAILURE;
2221a8789b47SJohnny Huang 	} else if (rid_num == update_num) {
2222a8789b47SJohnny Huang 		printf("OTP rev_id is same as input\n");
2223794e27ecSJohnny Huang 		printf("Skip\n");
2224794e27ecSJohnny Huang 		return OTP_FAILURE;
2225794e27ecSJohnny Huang 	}
2226794e27ecSJohnny Huang 
2227794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
2228794e27ecSJohnny Huang 		if (i < 32) {
2229794e27ecSJohnny Huang 			dw_offset = 0xa;
2230794e27ecSJohnny Huang 			bit_offset = i;
2231794e27ecSJohnny Huang 		} else {
2232794e27ecSJohnny Huang 			dw_offset = 0xb;
2233794e27ecSJohnny Huang 			bit_offset = i - 32;
2234794e27ecSJohnny Huang 		}
2235b489486eSJohnny Huang 		printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset);
2236794e27ecSJohnny Huang 		if (i + 1 != update_num)
2237794e27ecSJohnny Huang 			printf(", ");
2238794e27ecSJohnny Huang 	}
2239794e27ecSJohnny Huang 
2240794e27ecSJohnny Huang 	printf(" will be programmed\n");
2241794e27ecSJohnny Huang 	if (force == 0) {
2242794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2243794e27ecSJohnny Huang 		if (!confirm_yesno()) {
2244794e27ecSJohnny Huang 			printf(" Aborting\n");
2245794e27ecSJohnny Huang 			return OTP_FAILURE;
2246794e27ecSJohnny Huang 		}
2247794e27ecSJohnny Huang 	}
2248794e27ecSJohnny Huang 
2249794e27ecSJohnny Huang 	ret = 0;
2250794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
2251794e27ecSJohnny Huang 		if (i < 32) {
2252794e27ecSJohnny Huang 			dw_offset = 0xa04;
2253794e27ecSJohnny Huang 			bit_offset = i;
2254794e27ecSJohnny Huang 		} else {
2255794e27ecSJohnny Huang 			dw_offset = 0xa06;
2256794e27ecSJohnny Huang 			bit_offset = i - 32;
2257794e27ecSJohnny Huang 		}
2258f347c284SJohnny Huang 		if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
2259b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset);
2260794e27ecSJohnny Huang 			ret = OTP_FAILURE;
2261794e27ecSJohnny Huang 			break;
2262794e27ecSJohnny Huang 		}
2263794e27ecSJohnny Huang 	}
2264061d3279SJohnny Huang 	otp_soak(0);
2265f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2266f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2267794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2268794e27ecSJohnny Huang 	if (rid_num >= 0)
2269794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
2270794e27ecSJohnny Huang 	else
2271794e27ecSJohnny Huang 		printf("OTP revision ID\n");
2272794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2273794e27ecSJohnny Huang 	if (!ret)
2274794e27ecSJohnny Huang 		printf("SUCCESS\n");
2275794e27ecSJohnny Huang 	else
2276794e27ecSJohnny Huang 		printf("FAILED\n");
2277794e27ecSJohnny Huang 	return ret;
2278794e27ecSJohnny Huang }
2279794e27ecSJohnny Huang 
2280883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force)
2281883625c5SJohnny Huang {
2282883625c5SJohnny Huang 	u32 otpcfg4;
2283883625c5SJohnny Huang 	u32 krb;
2284883625c5SJohnny Huang 	u32 krb_b;
2285883625c5SJohnny Huang 	u32 krb_or;
2286883625c5SJohnny Huang 	u32 current_id;
2287883625c5SJohnny Huang 
2288883625c5SJohnny Huang 	otp_read_conf(4, &otpcfg4);
2289883625c5SJohnny Huang 	current_id = readl(SEC_KEY_NUM) & 7;
2290883625c5SJohnny Huang 	krb = otpcfg4 & 0xff;
2291883625c5SJohnny Huang 	krb_b = (otpcfg4 >> 16) & 0xff;
2292883625c5SJohnny Huang 	krb_or = krb | krb_b;
2293883625c5SJohnny Huang 
2294883625c5SJohnny Huang 	printf("current Key ID: 0x%x\n", current_id);
2295883625c5SJohnny Huang 	printf("input retire ID: 0x%x\n", retire_id);
2296883625c5SJohnny Huang 	printf("OTPCFG0x4 = 0x%X\n", otpcfg4);
2297883625c5SJohnny Huang 
2298883625c5SJohnny Huang 	if (info_cb.pro_sts.pro_key_ret) {
2299883625c5SJohnny Huang 		printf("OTPCFG4 is protected\n");
2300883625c5SJohnny Huang 		return OTP_FAILURE;
2301883625c5SJohnny Huang 	}
2302883625c5SJohnny Huang 
2303883625c5SJohnny Huang 	if (retire_id >= current_id) {
2304883625c5SJohnny Huang 		printf("Retire key id is equal or bigger than current boot key\n");
2305883625c5SJohnny Huang 		return OTP_FAILURE;
2306883625c5SJohnny Huang 	}
2307883625c5SJohnny Huang 
2308883625c5SJohnny Huang 	if (krb_or & (1 << retire_id)) {
2309883625c5SJohnny Huang 		printf("Key 0x%X already retired\n", retire_id);
2310883625c5SJohnny Huang 		return OTP_SUCCESS;
2311883625c5SJohnny Huang 	}
2312883625c5SJohnny Huang 
2313883625c5SJohnny Huang 	printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id);
2314883625c5SJohnny Huang 	if (force == 0) {
2315883625c5SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2316883625c5SJohnny Huang 		if (!confirm_yesno()) {
2317883625c5SJohnny Huang 			printf(" Aborting\n");
2318883625c5SJohnny Huang 			return OTP_FAILURE;
2319883625c5SJohnny Huang 		}
2320883625c5SJohnny Huang 	}
2321883625c5SJohnny Huang 
2322883625c5SJohnny Huang 	if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) {
2323883625c5SJohnny Huang 		printf("OTPCFG0x4[0x%X] programming failed\n", retire_id);
2324883625c5SJohnny Huang 		printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16);
2325883625c5SJohnny Huang 		if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE)
2326883625c5SJohnny Huang 			printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16);
2327883625c5SJohnny Huang 	}
2328883625c5SJohnny Huang 
2329883625c5SJohnny Huang 	otp_soak(0);
2330883625c5SJohnny Huang 	otp_read_conf(4, &otpcfg4);
2331883625c5SJohnny Huang 	krb = otpcfg4 & 0xff;
2332883625c5SJohnny Huang 	krb_b = (otpcfg4 >> 16) & 0xff;
2333883625c5SJohnny Huang 	krb_or = krb | krb_b;
2334883625c5SJohnny Huang 	if (krb_or & (1 << retire_id)) {
2335883625c5SJohnny Huang 		printf("SUCCESS\n");
2336883625c5SJohnny Huang 		return OTP_SUCCESS;
2337883625c5SJohnny Huang 	}
2338883625c5SJohnny Huang 	printf("FAILED\n");
2339883625c5SJohnny Huang 	return OTP_FAILURE;
2340883625c5SJohnny Huang }
2341883625c5SJohnny Huang 
23422a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
234369d5fd8fSJohnny Huang {
2344a219f6deSJohnny Huang 	u32 offset, count;
23452a856b9aSJohnny Huang 	int ret;
234669d5fd8fSJohnny Huang 
23472a856b9aSJohnny Huang 	if (argc == 4) {
23482a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
23492a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
23502a856b9aSJohnny Huang 	} else if (argc == 3) {
23512a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
23522a856b9aSJohnny Huang 		count = 1;
23532a856b9aSJohnny Huang 	} else {
235469d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
235569d5fd8fSJohnny Huang 	}
235669d5fd8fSJohnny Huang 
2357030cb4a7SJohnny Huang 	if (!strcmp(argv[1], "conf"))
2358f347c284SJohnny Huang 		ret = otp_print_conf(offset, count);
2359030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "data"))
23602a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
2361030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "strap"))
23622a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
2363030cb4a7SJohnny Huang 	else
23642a856b9aSJohnny Huang 		return CMD_RET_USAGE;
236569d5fd8fSJohnny Huang 
23662a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
23672a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
23682a856b9aSJohnny Huang 	return CMD_RET_USAGE;
23692a856b9aSJohnny Huang }
23702a856b9aSJohnny Huang 
23712a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
23722a856b9aSJohnny Huang {
23732a856b9aSJohnny Huang 	phys_addr_t addr;
23742a856b9aSJohnny Huang 	int ret;
23752a856b9aSJohnny Huang 
2376de6b0cc4SJohnny Huang 	if (argc == 3) {
2377ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
23782a856b9aSJohnny Huang 			return CMD_RET_USAGE;
23792a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
2380f347c284SJohnny Huang 		ret = otp_prog_image(addr, 1);
2381de6b0cc4SJohnny Huang 	} else if (argc == 2) {
23822a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
2383f347c284SJohnny Huang 		ret = otp_prog_image(addr, 0);
23842a856b9aSJohnny Huang 	} else {
23852a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23862a856b9aSJohnny Huang 	}
23872a856b9aSJohnny Huang 
23882a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
23892a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
23902a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
23912a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
23922a856b9aSJohnny Huang 	else
23932a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23942a856b9aSJohnny Huang }
23952a856b9aSJohnny Huang 
23962a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
23972a856b9aSJohnny Huang {
23982a856b9aSJohnny Huang 	int mode = 0;
23992a856b9aSJohnny Huang 	int nconfirm = 0;
24002a856b9aSJohnny Huang 	int otp_addr = 0;
24012a856b9aSJohnny Huang 	int bit_offset;
24022a856b9aSJohnny Huang 	int value;
24032a856b9aSJohnny Huang 	int ret;
2404030cb4a7SJohnny Huang 	u32 otp_strap_pro;
24052a856b9aSJohnny Huang 
24062a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
24072a856b9aSJohnny Huang 		return CMD_RET_USAGE;
24082a856b9aSJohnny Huang 
24092a856b9aSJohnny Huang 	/* Drop the pb cmd */
24102a856b9aSJohnny Huang 	argc--;
24112a856b9aSJohnny Huang 	argv++;
24122a856b9aSJohnny Huang 
24132a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2414a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
24152a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2416a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
24172a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2418a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2419cd1610b4SJohnny Huang 	else
24202a856b9aSJohnny Huang 		return CMD_RET_USAGE;
24212a856b9aSJohnny Huang 
24222a856b9aSJohnny Huang 	/* Drop the region cmd */
24232a856b9aSJohnny Huang 	argc--;
24242a856b9aSJohnny Huang 	argv++;
24252a856b9aSJohnny Huang 
2426ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2427cd1610b4SJohnny Huang 		nconfirm = 1;
24282a856b9aSJohnny Huang 		/* Drop the force option */
24292a856b9aSJohnny Huang 		argc--;
24302a856b9aSJohnny Huang 		argv++;
24312a856b9aSJohnny Huang 	}
2432cd1610b4SJohnny Huang 
2433a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
24342a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
24352a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
24360808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
24372a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2438cd1610b4SJohnny Huang 	} else {
24392a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
24402a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
24412a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
24420808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
24432a856b9aSJohnny Huang 			return CMD_RET_USAGE;
24440808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
244578855207SJohnny Huang 			if (otp_addr >= 0x800)
24460808cc55SJohnny Huang 				return CMD_RET_USAGE;
24470808cc55SJohnny Huang 		} else {
244878855207SJohnny Huang 			if (otp_addr >= 0x20)
24490808cc55SJohnny Huang 				return CMD_RET_USAGE;
24500808cc55SJohnny Huang 		}
2451cd1610b4SJohnny Huang 	}
2452cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
24532a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2454cd1610b4SJohnny Huang 
2455030cb4a7SJohnny Huang 	ret = 0;
2456030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
2457030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
2458030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2459030cb4a7SJohnny Huang 	}
2460030cb4a7SJohnny Huang 	if (mode == OTP_REGION_DATA) {
2461030cb4a7SJohnny Huang 		if (info_cb.pro_sts.sec_size == 0) {
2462030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_data) {
2463030cb4a7SJohnny Huang 				printf("OTP data region is protected\n");
2464030cb4a7SJohnny Huang 				ret = -1;
2465030cb4a7SJohnny Huang 			}
2466030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) {
2467030cb4a7SJohnny Huang 			printf("OTP secure region is not readable, skip it to prevent unpredictable result\n");
2468030cb4a7SJohnny Huang 			ret = -1;
2469030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size) {
2470030cb4a7SJohnny Huang 			// header region(0x0~0x40) is still readable even secure region is set.
2471030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_sec) {
2472030cb4a7SJohnny Huang 				printf("OTP secure region is protected\n");
2473030cb4a7SJohnny Huang 				ret = -1;
2474030cb4a7SJohnny Huang 			}
2475030cb4a7SJohnny Huang 		} else if (info_cb.pro_sts.pro_data) {
2476030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
2477030cb4a7SJohnny Huang 			ret = -1;
2478030cb4a7SJohnny Huang 		}
2479030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_CONF) {
2480030cb4a7SJohnny Huang 		if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) {
2481030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_conf) {
2482030cb4a7SJohnny Huang 				printf("OTP config region is protected\n");
2483030cb4a7SJohnny Huang 				ret = -1;
2484030cb4a7SJohnny Huang 			}
2485030cb4a7SJohnny Huang 		} else if (otp_addr == 10 || otp_addr == 11) {
2486030cb4a7SJohnny Huang 			u32 otp_rid[2];
2487030cb4a7SJohnny Huang 			u32 sw_rid[2];
2488030cb4a7SJohnny Huang 			u64 *otp_rid64 = (u64 *)otp_rid;
2489030cb4a7SJohnny Huang 			u64 *sw_rid64 = (u64 *)sw_rid;
2490030cb4a7SJohnny Huang 
2491030cb4a7SJohnny Huang 			otp_read_conf(10, &otp_rid[0]);
2492030cb4a7SJohnny Huang 			otp_read_conf(11, &otp_rid[1]);
2493030cb4a7SJohnny Huang 			sw_rid[0] = readl(SW_REV_ID0);
2494030cb4a7SJohnny Huang 			sw_rid[1] = readl(SW_REV_ID1);
2495030cb4a7SJohnny Huang 
2496030cb4a7SJohnny Huang 			if (otp_addr == 10)
2497030cb4a7SJohnny Huang 				otp_rid[0] |= 1 << bit_offset;
2498030cb4a7SJohnny Huang 			else
2499030cb4a7SJohnny Huang 				otp_rid[1] |= 1 << bit_offset;
2500030cb4a7SJohnny Huang 
2501030cb4a7SJohnny Huang 			if (*otp_rid64 > *sw_rid64) {
2502030cb4a7SJohnny Huang 				printf("update number could not bigger than current SW revision id\n");
2503030cb4a7SJohnny Huang 				ret = -1;
2504030cb4a7SJohnny Huang 			}
2505030cb4a7SJohnny Huang 		} else if (otp_addr == 4) {
2506030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_key_ret) {
2507030cb4a7SJohnny Huang 				printf("OTPCFG4 is protected\n");
2508030cb4a7SJohnny Huang 				ret = -1;
2509030cb4a7SJohnny Huang 			} else {
2510030cb4a7SJohnny Huang 				if ((bit_offset >= 0 && bit_offset <= 7) ||
2511030cb4a7SJohnny Huang 				    (bit_offset >= 16 && bit_offset <= 23)) {
2512030cb4a7SJohnny Huang 					u32 key_num;
2513030cb4a7SJohnny Huang 					u32 retire;
2514030cb4a7SJohnny Huang 
2515030cb4a7SJohnny Huang 					key_num = readl(SEC_KEY_NUM) & 3;
2516030cb4a7SJohnny Huang 					if (bit_offset >= 16)
2517030cb4a7SJohnny Huang 						retire = bit_offset - 16;
2518030cb4a7SJohnny Huang 					else
2519030cb4a7SJohnny Huang 						retire = bit_offset;
2520030cb4a7SJohnny Huang 					if (retire >= key_num) {
2521030cb4a7SJohnny Huang 						printf("Retire key id is equal or bigger than current boot key\n");
2522030cb4a7SJohnny Huang 						ret = -1;
2523030cb4a7SJohnny Huang 					}
2524030cb4a7SJohnny Huang 				}
2525030cb4a7SJohnny Huang 			}
2526030cb4a7SJohnny Huang 		} else if (otp_addr >= 16 && otp_addr <= 31) {
2527030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_strap) {
2528030cb4a7SJohnny Huang 				printf("OTP strap region is protected\n");
2529030cb4a7SJohnny Huang 				ret = -1;
2530030cb4a7SJohnny Huang 			} else if ((otp_addr < 30 && info_cb.version == OTP_A0) ||
2531030cb4a7SJohnny Huang 				   (otp_addr < 28 && info_cb.version != OTP_A0)) {
2532030cb4a7SJohnny Huang 				if (otp_addr % 2 == 0)
2533030cb4a7SJohnny Huang 					otp_read_conf(30, &otp_strap_pro);
2534030cb4a7SJohnny Huang 				else
2535030cb4a7SJohnny Huang 					otp_read_conf(31, &otp_strap_pro);
2536030cb4a7SJohnny Huang 				if (otp_strap_pro >> bit_offset & 0x1) {
2537b489486eSJohnny Huang 					printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset);
2538030cb4a7SJohnny Huang 					ret = -1;
2539030cb4a7SJohnny Huang 				}
2540030cb4a7SJohnny Huang 			}
2541030cb4a7SJohnny Huang 		}
2542030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_STRAP) {
2543030cb4a7SJohnny Huang 		// per bit protection will check in otp_strap_bit_confirm
2544030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
2545030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
2546030cb4a7SJohnny Huang 			ret = -1;
2547030cb4a7SJohnny Huang 		}
2548030cb4a7SJohnny Huang 	}
2549030cb4a7SJohnny Huang 
2550030cb4a7SJohnny Huang 	if (ret == -1)
2551030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2552030cb4a7SJohnny Huang 
2553f347c284SJohnny Huang 	ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
25542a856b9aSJohnny Huang 
25552a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
25562a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
25572a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
25582a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
25592a856b9aSJohnny Huang 	else
25602a856b9aSJohnny Huang 		return CMD_RET_USAGE;
25612a856b9aSJohnny Huang }
25622a856b9aSJohnny Huang 
25632a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
25642a856b9aSJohnny Huang {
25652a856b9aSJohnny Huang 	phys_addr_t addr;
25662a856b9aSJohnny Huang 	int otp_addr = 0;
2567b8590031SJohnny Huang 	int ret;
25682a856b9aSJohnny Huang 
25692a856b9aSJohnny Huang 	if (argc != 3)
25702a856b9aSJohnny Huang 		return CMD_RET_USAGE;
25712a856b9aSJohnny Huang 
25722a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
25732a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
2574b8590031SJohnny Huang 	ret = otp_compare(otp_addr, addr);
2575b8590031SJohnny Huang 	if (ret == 0) {
257669d5fd8fSJohnny Huang 		printf("Compare pass\n");
25772a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2578a219f6deSJohnny Huang 	}
257969d5fd8fSJohnny Huang 	printf("Compare fail\n");
25802a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
258169d5fd8fSJohnny Huang }
258269d5fd8fSJohnny Huang 
258366f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
258466f2f8e5SJohnny Huang {
2585a8bd6d8cSJohnny Huang 	int view = 0;
25862d4b0742SJohnny Huang 	int input;
2587a8bd6d8cSJohnny Huang 
2588a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
258966f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
259066f2f8e5SJohnny Huang 
25912d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
25922d4b0742SJohnny Huang 		if (argc == 3) {
25932d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
25942d4b0742SJohnny Huang 			otp_print_conf_info(input);
25952d4b0742SJohnny Huang 		} else {
25962d4b0742SJohnny Huang 			otp_print_conf_info(-1);
25972d4b0742SJohnny Huang 		}
25982d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
25992d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2600a8bd6d8cSJohnny Huang 			view = 1;
2601a8bd6d8cSJohnny Huang 			/* Drop the view option */
2602a8bd6d8cSJohnny Huang 			argc--;
2603a8bd6d8cSJohnny Huang 			argv++;
2604a8bd6d8cSJohnny Huang 		}
2605b458cd62SJohnny Huang 		otp_print_strap_info(view);
26060dc9a440SJohnny Huang 	} else if (!strcmp(argv[1], "scu")) {
26070dc9a440SJohnny Huang 		otp_print_scu_info();
260888bd7d58SJohnny Huang 	} else if (!strcmp(argv[1], "key")) {
260988bd7d58SJohnny Huang 		otp_print_key_info();
261066f2f8e5SJohnny Huang 	} else {
261166f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
261266f2f8e5SJohnny Huang 	}
26132d4b0742SJohnny Huang 
261466f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
261566f2f8e5SJohnny Huang }
261666f2f8e5SJohnny Huang 
26170dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2618737ed20bSJohnny Huang {
26190dc9a440SJohnny Huang 	u32 input;
26200dc9a440SJohnny Huang 	u32 bit_offset;
2621e14b073cSJohnny Huang 	u32 prog_address;
2622030cb4a7SJohnny Huang 	char force;
262383655e91SJohnny Huang 	int ret;
2624a219f6deSJohnny Huang 
2625737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2626737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2627737ed20bSJohnny Huang 
2628e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2629737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2630030cb4a7SJohnny Huang 		force = 1;
2631737ed20bSJohnny Huang 	} else {
2632737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2633030cb4a7SJohnny Huang 		force = 0;
2634737ed20bSJohnny Huang 	}
2635737ed20bSJohnny Huang 
2636737ed20bSJohnny Huang 	if (input < 32) {
2637737ed20bSJohnny Huang 		bit_offset = input;
26380dc9a440SJohnny Huang 		prog_address = 0xe0c;
2639737ed20bSJohnny Huang 	} else if (input < 64) {
2640737ed20bSJohnny Huang 		bit_offset = input - 32;
26410dc9a440SJohnny Huang 		prog_address = 0xe0e;
2642737ed20bSJohnny Huang 	} else {
2643737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2644737ed20bSJohnny Huang 	}
2645737ed20bSJohnny Huang 
2646030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
2647030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
2648030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2649030cb4a7SJohnny Huang 	}
2650030cb4a7SJohnny Huang 
2651030cb4a7SJohnny Huang 	if (!force) {
2652b489486eSJohnny Huang 		printf("OTPSTRAP[0x%X] will be protected\n", input);
2653030cb4a7SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2654030cb4a7SJohnny Huang 		if (!confirm_yesno()) {
2655030cb4a7SJohnny Huang 			printf(" Aborting\n");
2656030cb4a7SJohnny Huang 			return CMD_RET_FAILURE;
2657030cb4a7SJohnny Huang 		}
2658030cb4a7SJohnny Huang 	}
2659030cb4a7SJohnny Huang 
2660e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2661b489486eSJohnny Huang 		printf("OTPSTRAP[0x%X] already protected\n", input);
2662e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2663e14b073cSJohnny Huang 	}
2664de6fbf1cSJohnny Huang 
2665f347c284SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
2666de6fbf1cSJohnny Huang 	otp_soak(0);
266783655e91SJohnny Huang 
266883655e91SJohnny Huang 	if (ret) {
2669b489486eSJohnny Huang 		printf("Protect OTPSTRAP[0x%X] fail\n", input);
2670737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2671737ed20bSJohnny Huang 	}
26729a4fe690SJohnny Huang 
2673b489486eSJohnny Huang 	printf("OTPSTRAP[0x%X] is protected\n", input);
2674794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2675794e27ecSJohnny Huang }
2676794e27ecSJohnny Huang 
26770dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2678e14b073cSJohnny Huang {
26790dc9a440SJohnny Huang 	u32 scu_offset;
26800dc9a440SJohnny Huang 	u32 bit_offset;
26810dc9a440SJohnny Huang 	u32 conf_offset;
26820dc9a440SJohnny Huang 	u32 prog_address;
26830dc9a440SJohnny Huang 	char force;
26840dc9a440SJohnny Huang 	int ret;
26850dc9a440SJohnny Huang 
26860dc9a440SJohnny Huang 	if (argc != 4 && argc != 3)
26870dc9a440SJohnny Huang 		return CMD_RET_USAGE;
26880dc9a440SJohnny Huang 
26890dc9a440SJohnny Huang 	if (!strcmp(argv[1], "o")) {
26900dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[2], NULL, 16);
26910dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[3], NULL, 16);
26920dc9a440SJohnny Huang 		force = 1;
26930dc9a440SJohnny Huang 	} else {
26940dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[1], NULL, 16);
26950dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[2], NULL, 16);
26960dc9a440SJohnny Huang 		force = 0;
26970dc9a440SJohnny Huang 	}
26980dc9a440SJohnny Huang 	if (scu_offset == 0x500) {
26990dc9a440SJohnny Huang 		prog_address = 0xe08;
27000dc9a440SJohnny Huang 		conf_offset = 28;
27010dc9a440SJohnny Huang 	} else if (scu_offset == 0x510) {
27020dc9a440SJohnny Huang 		prog_address = 0xe0a;
27030dc9a440SJohnny Huang 		conf_offset = 29;
27040dc9a440SJohnny Huang 	} else {
27050dc9a440SJohnny Huang 		return CMD_RET_USAGE;
27060dc9a440SJohnny Huang 	}
27070dc9a440SJohnny Huang 	if (bit_offset < 0 || bit_offset > 31)
27080dc9a440SJohnny Huang 		return CMD_RET_USAGE;
2709030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
2710030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
2711030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2712030cb4a7SJohnny Huang 	}
27130dc9a440SJohnny Huang 	if (!force) {
2714b489486eSJohnny Huang 		printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset);
2715b489486eSJohnny Huang 		printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset);
27160dc9a440SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
27170dc9a440SJohnny Huang 		if (!confirm_yesno()) {
27180dc9a440SJohnny Huang 			printf(" Aborting\n");
27190dc9a440SJohnny Huang 			return CMD_RET_FAILURE;
27200dc9a440SJohnny Huang 		}
2721e14b073cSJohnny Huang 	}
2722e14b073cSJohnny Huang 
27230dc9a440SJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2724b489486eSJohnny Huang 		printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset);
27250dc9a440SJohnny Huang 		return CMD_RET_SUCCESS;
27260dc9a440SJohnny Huang 	}
27270dc9a440SJohnny Huang 
27280dc9a440SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
27290dc9a440SJohnny Huang 	otp_soak(0);
27300dc9a440SJohnny Huang 
27310dc9a440SJohnny Huang 	if (ret) {
2732b489486eSJohnny Huang 		printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset);
27330dc9a440SJohnny Huang 		return CMD_RET_FAILURE;
27340dc9a440SJohnny Huang 	}
27350dc9a440SJohnny Huang 
2736b489486eSJohnny Huang 	printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset);
27370dc9a440SJohnny Huang 	return CMD_RET_SUCCESS;
2738e14b073cSJohnny Huang }
2739e14b073cSJohnny Huang 
2740f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2741f67375f7SJohnny Huang {
2742e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
2743f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2744f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2745f67375f7SJohnny Huang 
2746f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2747f67375f7SJohnny Huang }
2748f67375f7SJohnny Huang 
2749794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2750794e27ecSJohnny Huang {
2751794e27ecSJohnny Huang 	u32 update_num;
2752794e27ecSJohnny Huang 	int force = 0;
2753794e27ecSJohnny Huang 	int ret;
2754794e27ecSJohnny Huang 
2755794e27ecSJohnny Huang 	if (argc == 3) {
2756794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2757794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2758794e27ecSJohnny Huang 		force = 1;
2759794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2760794e27ecSJohnny Huang 	} else if (argc == 2) {
2761794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2762794e27ecSJohnny Huang 	} else {
2763794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2764794e27ecSJohnny Huang 	}
2765794e27ecSJohnny Huang 
2766794e27ecSJohnny Huang 	if (update_num > 64)
2767794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2768794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2769b8590031SJohnny Huang 
2770794e27ecSJohnny Huang 	if (ret)
2771794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2772794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2773794e27ecSJohnny Huang }
2774794e27ecSJohnny Huang 
2775794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2776794e27ecSJohnny Huang {
2777794e27ecSJohnny Huang 	u32 otp_rid[2];
2778a8789b47SJohnny Huang 	u32 sw_rid[2];
2779794e27ecSJohnny Huang 	int rid_num = 0;
2780a8789b47SJohnny Huang 	int sw_rid_num = 0;
2781794e27ecSJohnny Huang 	int ret;
2782794e27ecSJohnny Huang 
2783794e27ecSJohnny Huang 	if (argc != 1)
2784794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2785794e27ecSJohnny Huang 
2786f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2787f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2788794e27ecSJohnny Huang 
2789a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2790a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2791794e27ecSJohnny Huang 
2792a8789b47SJohnny Huang 	rid_num = get_rid_num(otp_rid);
2793a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2794a8789b47SJohnny Huang 
2795030cb4a7SJohnny Huang 	if (sw_rid_num < 0) {
2796030cb4a7SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
2797030cb4a7SJohnny Huang 		printf("SEC68:0x%x\n", sw_rid[0]);
2798030cb4a7SJohnny Huang 		printf("SEC6C:0x%x\n", sw_rid[1]);
2799030cb4a7SJohnny Huang 	} else {
2800a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
2801030cb4a7SJohnny Huang 	}
2802794e27ecSJohnny Huang 	if (rid_num >= 0) {
2803794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2804794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2805794e27ecSJohnny Huang 	} else {
2806b64ca396SJohnny Huang 		printf("Current OTP revision ID cannot handle by 'otp update',\n"
2807b64ca396SJohnny Huang 		       "please use 'otp pb' command to update it manually\n"
2808794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2809794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2810794e27ecSJohnny Huang 	}
2811794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2812794e27ecSJohnny Huang 
2813794e27ecSJohnny Huang 	return ret;
2814794e27ecSJohnny Huang }
2815794e27ecSJohnny Huang 
2816883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2817883625c5SJohnny Huang {
2818883625c5SJohnny Huang 	u32 retire_id;
2819883625c5SJohnny Huang 	int force = 0;
2820883625c5SJohnny Huang 	int ret;
2821883625c5SJohnny Huang 
2822883625c5SJohnny Huang 	if (argc == 3) {
2823883625c5SJohnny Huang 		if (strcmp(argv[1], "o"))
2824883625c5SJohnny Huang 			return CMD_RET_USAGE;
2825883625c5SJohnny Huang 		force = 1;
2826883625c5SJohnny Huang 		retire_id = simple_strtoul(argv[2], NULL, 16);
2827883625c5SJohnny Huang 	} else if (argc == 2) {
2828883625c5SJohnny Huang 		retire_id = simple_strtoul(argv[1], NULL, 16);
2829883625c5SJohnny Huang 	} else {
2830883625c5SJohnny Huang 		return CMD_RET_USAGE;
2831883625c5SJohnny Huang 	}
2832883625c5SJohnny Huang 
2833883625c5SJohnny Huang 	if (retire_id > 7)
2834883625c5SJohnny Huang 		return CMD_RET_USAGE;
2835883625c5SJohnny Huang 	ret = otp_retire_key(retire_id, force);
2836883625c5SJohnny Huang 
2837883625c5SJohnny Huang 	if (ret)
2838883625c5SJohnny Huang 		return CMD_RET_FAILURE;
2839883625c5SJohnny Huang 	return CMD_RET_SUCCESS;
2840883625c5SJohnny Huang }
2841883625c5SJohnny Huang 
28422a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2843f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
28442a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2845a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2846de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
28472a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2848737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
28490dc9a440SJohnny Huang 	U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""),
28502a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2851794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2852794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
2853883625c5SJohnny Huang 	U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""),
28542a856b9aSJohnny Huang };
28552a856b9aSJohnny Huang 
28562a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
28572a856b9aSJohnny Huang {
2858030cb4a7SJohnny Huang 	struct otp_pro_sts *pro_sts;
28592a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2860a219f6deSJohnny Huang 	u32 ver;
2861e14b073cSJohnny Huang 	int ret;
2862030cb4a7SJohnny Huang 	u32 otp_conf0;
28632a856b9aSJohnny Huang 
28642a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
28652a856b9aSJohnny Huang 
2866737ed20bSJohnny Huang 	/* Drop the otp command */
28672a856b9aSJohnny Huang 	argc--;
28682a856b9aSJohnny Huang 	argv++;
28692a856b9aSJohnny Huang 
2870a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
28712a856b9aSJohnny Huang 		return CMD_RET_USAGE;
28722a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
28732a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
28742a856b9aSJohnny Huang 
28750dae9d52SJohnny Huang 	ver = chip_version();
28760dae9d52SJohnny Huang 	switch (ver) {
2877e417205bSJohnny Huang 	case OTP_A0:
2878e417205bSJohnny Huang 		info_cb.version = OTP_A0;
28799a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
28809a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
28819a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
28829a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
28839a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
28849a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2885e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
28860dae9d52SJohnny Huang 		break;
2887e417205bSJohnny Huang 	case OTP_A1:
2888e417205bSJohnny Huang 		info_cb.version = OTP_A1;
28893cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
28903cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
28913cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
28923cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
28939a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
28949a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
28950dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
28960dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2897e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
28980dae9d52SJohnny Huang 		break;
2899e417205bSJohnny Huang 	case OTP_A2:
2900e417205bSJohnny Huang 		info_cb.version = OTP_A2;
29015fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
29025fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
2903fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2904fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
29055fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
29065fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
29070dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
29080dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2909e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
29100dae9d52SJohnny Huang 		break;
2911e417205bSJohnny Huang 	case OTP_A3:
2912e417205bSJohnny Huang 		info_cb.version = OTP_A3;
2913b63af886SJohnny Huang 		info_cb.conf_info = a3_conf_info;
2914b63af886SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
2915fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2916fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
2917181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2918181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
29190dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
29200dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2921e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
292264b66712SJohnny Huang 		break;
29230dae9d52SJohnny Huang 	default:
2924f1be5099SJohnny Huang 		printf("SOC is not supported\n");
29250dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
29269a4fe690SJohnny Huang 	}
29279a4fe690SJohnny Huang 
2928030cb4a7SJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2929030cb4a7SJohnny Huang 	otp_read_conf(0, &otp_conf0);
2930030cb4a7SJohnny Huang 	pro_sts = &info_cb.pro_sts;
2931030cb4a7SJohnny Huang 
2932030cb4a7SJohnny Huang 	pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1;
2933030cb4a7SJohnny Huang 	pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1;
2934030cb4a7SJohnny Huang 	pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1;
2935030cb4a7SJohnny Huang 	pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1;
2936030cb4a7SJohnny Huang 	pro_sts->pro_data = (otp_conf0 >> 23) & 0x1;
2937030cb4a7SJohnny Huang 	pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1;
2938030cb4a7SJohnny Huang 	pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5;
2939030cb4a7SJohnny Huang 
2940e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2941b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
2942e14b073cSJohnny Huang 
2943e14b073cSJohnny Huang 	return ret;
294469d5fd8fSJohnny Huang }
294569d5fd8fSJohnny Huang 
2946a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
294769d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2948f67375f7SJohnny Huang 	   "version\n"
2949f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
29502a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
29512d4b0742SJohnny Huang 	   "otp info strap [v]\n"
29522d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
29530dc9a440SJohnny Huang 	   "otp info scu\n"
295488bd7d58SJohnny Huang 	   "otp info key\n"
2955de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2956ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2957ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2958ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
29590dc9a440SJohnny Huang 	   "otp scuprotect [o] <scu_offset> <bit_offset>\n"
2960794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2961794e27ecSJohnny Huang 	   "otp rid\n"
2962883625c5SJohnny Huang 	   "otp retire [o] <key_id>\n"
296369d5fd8fSJohnny Huang 	  );
2964