xref: /openbmc/u-boot/cmd/otp.c (revision 5e096f11498d7d94c27260e09af2f43b4a41916f)
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>
18696656c6SJohnny Huang #include <u-boot/sha256.h>
190cee9a95SJohnny Huang #include "otp_info.h"
2069d5fd8fSJohnny Huang 
2169d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2269d5fd8fSJohnny Huang 
230cc6ef78SJohnny Huang #define OTP_VER				"1.2.0"
24f67375f7SJohnny Huang 
2569d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
26dacbba92SJohnny Huang #define RETRY				20
277332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
287332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
297332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3069d5fd8fSJohnny Huang 
312a856b9aSJohnny Huang #define OTP_USAGE			-1
322a856b9aSJohnny Huang #define OTP_FAILURE			-2
332a856b9aSJohnny Huang #define OTP_SUCCESS			0
342a856b9aSJohnny Huang 
35a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
36a6af4a17SJohnny Huang 
37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB		1
38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV		2
39181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES		3
40181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT		4
41181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC		5
429a4fe690SJohnny Huang 
433d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
443d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
453d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
463d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
473d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
483d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
493d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
503d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
513d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
523d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
53a8789b47SJohnny Huang #define SW_REV_ID0		OTP_BASE + 0x68
54a8789b47SJohnny Huang #define SW_REV_ID1		OTP_BASE + 0x6c
55030cb4a7SJohnny Huang #define SEC_KEY_NUM		OTP_BASE + 0x78
563d3688adSJohnny Huang 
57696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
58696656c6SJohnny Huang #define CHECKSUM_LEN		32
59a219f6deSJohnny Huang #define OTP_INC_DATA		BIT(31)
60a219f6deSJohnny Huang #define OTP_INC_CONFIG		BIT(30)
61a219f6deSJohnny Huang #define OTP_INC_STRAP		BIT(29)
62a219f6deSJohnny Huang #define OTP_ECC_EN		BIT(28)
63b25f02d2SJohnny Huang #define OTP_INC_SCU_PRO		BIT(25)
64696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
65696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
66696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
67696656c6SJohnny Huang 
68e417205bSJohnny Huang #define OTP_A0		0
69e417205bSJohnny Huang #define OTP_A1		1
70e417205bSJohnny Huang #define OTP_A2		2
71e417205bSJohnny Huang #define OTP_A3		3
72e417205bSJohnny Huang 
73e417205bSJohnny Huang #define ID0_AST2600A0	0x05000303
74e417205bSJohnny Huang #define ID1_AST2600A0	0x05000303
75e417205bSJohnny Huang #define ID0_AST2600A1	0x05010303
7621a8cfceSJohnny Huang #define ID1_AST2600A1	0x05010303
77e417205bSJohnny Huang #define ID0_AST2600A2	0x05010303
78e417205bSJohnny Huang #define ID1_AST2600A2	0x05020303
79e417205bSJohnny Huang #define ID0_AST2600A3	0x05030303
80e417205bSJohnny Huang #define ID1_AST2600A3	0x05030303
81e417205bSJohnny Huang #define ID0_AST2620A1	0x05010203
82e417205bSJohnny Huang #define ID1_AST2620A1	0x05010203
83e417205bSJohnny Huang #define ID0_AST2620A2	0x05010203
84e417205bSJohnny Huang #define ID1_AST2620A2	0x05020203
85e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
86e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
87e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
88e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
89e417205bSJohnny Huang #define ID0_AST2605A2	0x05010103
90e417205bSJohnny Huang #define ID1_AST2605A2	0x05020103
91e417205bSJohnny Huang #define ID0_AST2605A3	0x05030103
92e417205bSJohnny Huang #define ID1_AST2605A3	0x05030103
93e417205bSJohnny Huang #define ID0_AST2625A3	0x05030403
94e417205bSJohnny Huang #define ID1_AST2625A3	0x05030403
95696656c6SJohnny Huang 
9661a6cda7SJohnny Huang #define SOC_AST2600A0	0
9761a6cda7SJohnny Huang #define SOC_AST2600A1	1
9861a6cda7SJohnny Huang #define SOC_AST2600A2	2
9961a6cda7SJohnny Huang #define SOC_AST2600A3	3
10061a6cda7SJohnny Huang 
10161a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c))
102*5e096f11SJohnny Huang #define OTPTOOL_VERSION_MAJOR(x) (((x) >> 24) & 0xff)
103*5e096f11SJohnny Huang #define OTPTOOL_VERSION_PATCHLEVEL(x) (((x) >> 12) & 0xfff)
104*5e096f11SJohnny Huang #define OTPTOOL_VERSION_SUBLEVEL(x) ((x) & 0xfff)
105*5e096f11SJohnny Huang #define OTPTOOL_COMPT_VERSION 1
10661a6cda7SJohnny Huang 
107696656c6SJohnny Huang struct otp_header {
108696656c6SJohnny Huang 	u8	otp_magic[8];
10961a6cda7SJohnny Huang 	u32	soc_ver;
11061a6cda7SJohnny Huang 	u32	otptool_ver;
111696656c6SJohnny Huang 	u32	image_info;
112696656c6SJohnny Huang 	u32	data_info;
113696656c6SJohnny Huang 	u32	config_info;
114696656c6SJohnny Huang 	u32	strap_info;
1157e523e3bSJohnny Huang 	u32	scu_protect_info;
116696656c6SJohnny Huang 	u32	checksum_offset;
117a219f6deSJohnny Huang } __packed;
118696656c6SJohnny Huang 
11966f2f8e5SJohnny Huang struct otpstrap_status {
12069d5fd8fSJohnny Huang 	int value;
12169d5fd8fSJohnny Huang 	int option_array[7];
12269d5fd8fSJohnny Huang 	int remain_times;
12369d5fd8fSJohnny Huang 	int writeable_option;
12469d5fd8fSJohnny Huang 	int protected;
12569d5fd8fSJohnny Huang };
12669d5fd8fSJohnny Huang 
1279a4fe690SJohnny Huang struct otpkey_type {
1289a4fe690SJohnny Huang 	int value;
1299a4fe690SJohnny Huang 	int key_type;
1309a4fe690SJohnny Huang 	int need_id;
1319a4fe690SJohnny Huang 	char information[110];
1329a4fe690SJohnny Huang };
1339a4fe690SJohnny Huang 
134030cb4a7SJohnny Huang struct otp_pro_sts {
135030cb4a7SJohnny Huang 	char mem_lock;
136030cb4a7SJohnny Huang 	char pro_key_ret;
137030cb4a7SJohnny Huang 	char pro_strap;
138030cb4a7SJohnny Huang 	char pro_conf;
139030cb4a7SJohnny Huang 	char pro_data;
140030cb4a7SJohnny Huang 	char pro_sec;
141030cb4a7SJohnny Huang 	u32 sec_size;
142030cb4a7SJohnny Huang };
143030cb4a7SJohnny Huang 
1449a4fe690SJohnny Huang struct otp_info_cb {
1459a4fe690SJohnny Huang 	int version;
146e417205bSJohnny Huang 	char ver_name[3];
14779e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1489a4fe690SJohnny Huang 	int strap_info_len;
14979e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1509a4fe690SJohnny Huang 	int conf_info_len;
15179e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1529a4fe690SJohnny Huang 	int key_info_len;
1530dc9a440SJohnny Huang 	const struct scu_info *scu_info;
1540dc9a440SJohnny Huang 	int scu_info_len;
155030cb4a7SJohnny Huang 	struct otp_pro_sts pro_sts;
1569a4fe690SJohnny Huang };
1579a4fe690SJohnny Huang 
158696656c6SJohnny Huang struct otp_image_layout {
1595010032bSJohnny Huang 	int data_length;
1605010032bSJohnny Huang 	int conf_length;
1615010032bSJohnny Huang 	int strap_length;
162b25f02d2SJohnny Huang 	int scu_pro_length;
163a219f6deSJohnny Huang 	u8 *data;
164a219f6deSJohnny Huang 	u8 *data_ignore;
165a219f6deSJohnny Huang 	u8 *conf;
166a219f6deSJohnny Huang 	u8 *conf_ignore;
167a219f6deSJohnny Huang 	u8 *strap;
168a219f6deSJohnny Huang 	u8 *strap_pro;
169a219f6deSJohnny Huang 	u8 *strap_ignore;
170b25f02d2SJohnny Huang 	u8 *scu_pro;
171b25f02d2SJohnny Huang 	u8 *scu_pro_ignore;
172696656c6SJohnny Huang };
173696656c6SJohnny Huang 
1749a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1759a4fe690SJohnny Huang 
17679e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1779a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1789a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1799a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
180181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
181181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   0, "RSA-public as SOC public key"},
182181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
183181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as SOC private key"},
184181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1859a4fe690SJohnny Huang };
1869a4fe690SJohnny Huang 
18779e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1889a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1899a4fe690SJohnny 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"},
190181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
191181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
192181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1939a4fe690SJohnny Huang };
1949a4fe690SJohnny Huang 
1955fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1965fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1975fdde29fSJohnny 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"},
198181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
199181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
200181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
201181f72d8SJohnny Huang };
202181f72d8SJohnny Huang 
203181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
204181f72d8SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
205181f72d8SJohnny 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"},
206181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
207181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
208181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
209181f72d8SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key(big endian)"},
210181f72d8SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
211181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key(big endian)"},
2125fdde29fSJohnny Huang };
2135fdde29fSJohnny Huang 
214f347c284SJohnny Huang static void buf_print(u8 *buf, int len)
215f347c284SJohnny Huang {
216f347c284SJohnny Huang 	int i;
217f347c284SJohnny Huang 
218f347c284SJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
219f347c284SJohnny Huang 	for (i = 0; i < len; i++) {
220f347c284SJohnny Huang 		if (i % 16 == 0)
221f347c284SJohnny Huang 			printf("%04X: ", i);
222f347c284SJohnny Huang 		printf("%02X ", buf[i]);
223f347c284SJohnny Huang 		if ((i + 1) % 16 == 0)
224f347c284SJohnny Huang 			printf("\n");
225f347c284SJohnny Huang 	}
22688bd7d58SJohnny Huang 	printf("\n");
227f347c284SJohnny Huang }
228f347c284SJohnny Huang 
229794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
230794e27ecSJohnny Huang {
231794e27ecSJohnny Huang 	int bit_offset;
232794e27ecSJohnny Huang 	int i;
233794e27ecSJohnny Huang 
234794e27ecSJohnny Huang 	if (offset < 32) {
235794e27ecSJohnny Huang 		i = 0;
236794e27ecSJohnny Huang 		bit_offset = offset;
237794e27ecSJohnny Huang 	} else {
238794e27ecSJohnny Huang 		i = 1;
239794e27ecSJohnny Huang 		bit_offset = offset - 32;
240794e27ecSJohnny Huang 	}
241794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
242794e27ecSJohnny Huang 		return 1;
243794e27ecSJohnny Huang 	else
244794e27ecSJohnny Huang 		return 0;
245794e27ecSJohnny Huang }
246794e27ecSJohnny Huang 
247794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
248794e27ecSJohnny Huang {
249794e27ecSJohnny Huang 	int i;
250794e27ecSJohnny Huang 	int fz = 0;
251794e27ecSJohnny Huang 	int rid_num = 0;
252794e27ecSJohnny Huang 	int ret = 0;
253794e27ecSJohnny Huang 
254794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
255794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
256794e27ecSJohnny Huang 			if (!fz)
257794e27ecSJohnny Huang 				fz = 1;
258794e27ecSJohnny Huang 
259794e27ecSJohnny Huang 		} else {
260794e27ecSJohnny Huang 			rid_num++;
261794e27ecSJohnny Huang 			if (fz)
262794e27ecSJohnny Huang 				ret = OTP_FAILURE;
263794e27ecSJohnny Huang 		}
264794e27ecSJohnny Huang 	}
265794e27ecSJohnny Huang 	if (ret)
266794e27ecSJohnny Huang 		return ret;
267794e27ecSJohnny Huang 
268794e27ecSJohnny Huang 	return rid_num;
269794e27ecSJohnny Huang }
270794e27ecSJohnny Huang 
271a219f6deSJohnny Huang static u32 chip_version(void)
2729a4fe690SJohnny Huang {
273e417205bSJohnny Huang 	u32 revid0, revid1;
2749a4fe690SJohnny Huang 
275e417205bSJohnny Huang 	revid0 = readl(ASPEED_REVISION_ID0);
276e417205bSJohnny Huang 	revid1 = readl(ASPEED_REVISION_ID1);
2779a4fe690SJohnny Huang 
278e417205bSJohnny Huang 	if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
279badd21c2SJohnny Huang 		/* AST2600-A0 */
280e417205bSJohnny Huang 		return OTP_A0;
281e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
282badd21c2SJohnny Huang 		/* AST2600-A1 */
283e417205bSJohnny Huang 		return OTP_A1;
284e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
285badd21c2SJohnny Huang 		/* AST2600-A2 */
286e417205bSJohnny Huang 		return OTP_A2;
287e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
28864b66712SJohnny Huang 		/* AST2600-A3 */
289e417205bSJohnny Huang 		return OTP_A3;
290e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
291e417205bSJohnny Huang 		/* AST2620-A1 */
292e417205bSJohnny Huang 		return OTP_A1;
293e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
294e417205bSJohnny Huang 		/* AST2620-A2 */
295e417205bSJohnny Huang 		return OTP_A2;
296e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
29764b66712SJohnny Huang 		/* AST2620-A3 */
298e417205bSJohnny Huang 		return OTP_A3;
299e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
300e417205bSJohnny Huang 		/* AST2605-A2 */
301e417205bSJohnny Huang 		return OTP_A2;
302e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
303e417205bSJohnny Huang 		/* AST2605-A3 */
304e417205bSJohnny Huang 		return OTP_A3;
305e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
306e417205bSJohnny Huang 		/* AST2605-A3 */
307e417205bSJohnny Huang 		return OTP_A3;
3080dae9d52SJohnny Huang 	}
309f347c284SJohnny Huang 	return OTP_FAILURE;
3109a4fe690SJohnny Huang }
3119a4fe690SJohnny Huang 
3123d3688adSJohnny Huang static void wait_complete(void)
3133d3688adSJohnny Huang {
3143d3688adSJohnny Huang 	int reg;
3153d3688adSJohnny Huang 
3163d3688adSJohnny Huang 	do {
3173d3688adSJohnny Huang 		reg = readl(OTP_STATUS);
3183d3688adSJohnny Huang 	} while ((reg & 0x6) != 0x6);
3193d3688adSJohnny Huang }
3203d3688adSJohnny Huang 
321a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
322dacbba92SJohnny Huang {
323dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
324dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
325dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
326dacbba92SJohnny Huang 	wait_complete();
327dacbba92SJohnny Huang }
328dacbba92SJohnny Huang 
329dacbba92SJohnny Huang static void otp_soak(int soak)
330dacbba92SJohnny Huang {
331e417205bSJohnny Huang 	if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
332dacbba92SJohnny Huang 		switch (soak) {
333dacbba92SJohnny Huang 		case 0: //default
334377f8cd7SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
335377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
336dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
337dacbba92SJohnny Huang 			break;
338dacbba92SJohnny Huang 		case 1: //normal program
339377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
340377f8cd7SJohnny Huang 			otp_write(0x5000, 0x1008); // Write MRB
341377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0024); // Write MR
342feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
343dacbba92SJohnny Huang 			break;
344dacbba92SJohnny Huang 		case 2: //soak program
345377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
346377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0007); // Write MRB
347377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0100); // Write MR
348feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
349dacbba92SJohnny Huang 			break;
350dacbba92SJohnny Huang 		}
351dacbba92SJohnny Huang 	} else {
352dacbba92SJohnny Huang 		switch (soak) {
353dacbba92SJohnny Huang 		case 0: //default
354dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
355dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
356dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
357dacbba92SJohnny Huang 			break;
358dacbba92SJohnny Huang 		case 1: //normal program
359dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
360dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
361dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
362feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
363dacbba92SJohnny Huang 			break;
364dacbba92SJohnny Huang 		case 2: //soak program
365dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
366dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
367dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
368feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
369dacbba92SJohnny Huang 			break;
370dacbba92SJohnny Huang 		}
371dacbba92SJohnny Huang 	}
372dacbba92SJohnny Huang 
373dacbba92SJohnny Huang 	wait_complete();
374dacbba92SJohnny Huang }
375dacbba92SJohnny Huang 
376a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
37769d5fd8fSJohnny Huang {
3783d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
3793d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3803d3688adSJohnny Huang 	wait_complete();
3813d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
3823d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
38369d5fd8fSJohnny Huang }
38469d5fd8fSJohnny Huang 
385f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data)
38669d5fd8fSJohnny Huang {
38769d5fd8fSJohnny Huang 	int config_offset;
38869d5fd8fSJohnny Huang 
38969d5fd8fSJohnny Huang 	config_offset = 0x800;
39069d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
39169d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
39269d5fd8fSJohnny Huang 
3933d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
3943d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3953d3688adSJohnny Huang 	wait_complete();
3963d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
39769d5fd8fSJohnny Huang }
39869d5fd8fSJohnny Huang 
399a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
40069d5fd8fSJohnny Huang {
401a219f6deSJohnny Huang 	u32 ret;
402a219f6deSJohnny Huang 	u32 *buf;
40369d5fd8fSJohnny Huang 
40469d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
40569d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
40669d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
40769d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
40869d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
4093d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
4103d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
4113d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
4123d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
4133d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
4143d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
4153d3688adSJohnny Huang 	wait_complete();
4163d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
41769d5fd8fSJohnny Huang 	if (ret & 0x1)
418f347c284SJohnny Huang 		return OTP_SUCCESS;
41969d5fd8fSJohnny Huang 	else
420f347c284SJohnny Huang 		return OTP_FAILURE;
42169d5fd8fSJohnny Huang }
42269d5fd8fSJohnny Huang 
423a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
42469d5fd8fSJohnny Huang {
425a219f6deSJohnny Huang 	u32 ret[2];
42669d5fd8fSJohnny Huang 
42730a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4283d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
42930a8c590SJohnny Huang 	else
4303d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
43130a8c590SJohnny Huang 
4323d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4333d3688adSJohnny Huang 	wait_complete();
4343d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4353d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
43683655e91SJohnny Huang 
43730a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
43830a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
439f347c284SJohnny Huang 			return OTP_SUCCESS;
44069d5fd8fSJohnny Huang 		else
441f347c284SJohnny Huang 			return OTP_FAILURE;
44230a8c590SJohnny Huang 	} else {
44330a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
444f347c284SJohnny Huang 			return OTP_SUCCESS;
44530a8c590SJohnny Huang 		else
446f347c284SJohnny Huang 			return OTP_FAILURE;
44730a8c590SJohnny Huang 	}
44869d5fd8fSJohnny Huang }
44969d5fd8fSJohnny Huang 
450a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4514c1c9b35SJohnny Huang {
452a219f6deSJohnny Huang 	u32 ret[2];
4534c1c9b35SJohnny Huang 
4544c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4554c1c9b35SJohnny Huang 
4564c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4573d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
4584c1c9b35SJohnny Huang 	else
4593d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
4603d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4613d3688adSJohnny Huang 	wait_complete();
4623d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4633d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4644c1c9b35SJohnny Huang 	if (size == 1) {
4654c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4664c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
467696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4684c1c9b35SJohnny Huang 				compare[0] = 0;
469f347c284SJohnny Huang 				return OTP_SUCCESS;
470a219f6deSJohnny Huang 			}
4714c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
472f347c284SJohnny Huang 			return OTP_FAILURE;
4734c1c9b35SJohnny Huang 
4744c1c9b35SJohnny Huang 		} else {
4754c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
476696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4774c1c9b35SJohnny Huang 				compare[0] = ~0;
478f347c284SJohnny Huang 				return OTP_SUCCESS;
479a219f6deSJohnny Huang 			}
480d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
481f347c284SJohnny Huang 			return OTP_FAILURE;
4824c1c9b35SJohnny Huang 		}
4834c1c9b35SJohnny Huang 	} else if (size == 2) {
4844c1c9b35SJohnny Huang 		// otp_addr should be even
485696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
4864c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4874c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4884c1c9b35SJohnny Huang 			compare[0] = 0;
4894c1c9b35SJohnny Huang 			compare[1] = ~0;
490f347c284SJohnny Huang 			return OTP_SUCCESS;
491a219f6deSJohnny Huang 		}
4924c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4934c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4944c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
4954c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
496f347c284SJohnny Huang 		return OTP_FAILURE;
4974c1c9b35SJohnny Huang 	} else {
498f347c284SJohnny Huang 		return OTP_FAILURE;
4994c1c9b35SJohnny Huang 	}
5004c1c9b35SJohnny Huang }
5014c1c9b35SJohnny Huang 
502a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit)
50383655e91SJohnny Huang {
50490965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
50583655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
50683655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
50783655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
50883655e91SJohnny Huang 	wait_complete();
50983655e91SJohnny Huang }
51083655e91SJohnny Huang 
511a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
51283655e91SJohnny Huang {
51383655e91SJohnny Huang 	int prog_bit;
51483655e91SJohnny Huang 
51583655e91SJohnny Huang 	if (prog_address % 2 == 0) {
51683655e91SJohnny Huang 		if (value)
51783655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
51883655e91SJohnny Huang 		else
51983655e91SJohnny Huang 			return;
52083655e91SJohnny Huang 	} else {
521e417205bSJohnny Huang 		if (info_cb.version != OTP_A3)
52283655e91SJohnny Huang 			prog_address |= 1 << 15;
52383655e91SJohnny Huang 		if (!value)
52483655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
52583655e91SJohnny Huang 		else
52683655e91SJohnny Huang 			return;
52783655e91SJohnny Huang 	}
52883655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
52983655e91SJohnny Huang }
53083655e91SJohnny Huang 
531f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset)
53283655e91SJohnny Huang {
53383655e91SJohnny Huang 	int pass;
53483655e91SJohnny Huang 	int i;
53583655e91SJohnny Huang 
53683655e91SJohnny Huang 	otp_soak(1);
53783655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
53883655e91SJohnny Huang 	pass = 0;
53983655e91SJohnny Huang 
54083655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
54183655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
54283655e91SJohnny Huang 			otp_soak(2);
54383655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
54483655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
54583655e91SJohnny Huang 				otp_soak(1);
54683655e91SJohnny Huang 			} else {
54783655e91SJohnny Huang 				pass = 1;
54883655e91SJohnny Huang 				break;
54983655e91SJohnny Huang 			}
55083655e91SJohnny Huang 		} else {
55183655e91SJohnny Huang 			pass = 1;
55283655e91SJohnny Huang 			break;
55383655e91SJohnny Huang 		}
55483655e91SJohnny Huang 	}
555794e27ecSJohnny Huang 	if (pass)
556794e27ecSJohnny Huang 		return OTP_SUCCESS;
55783655e91SJohnny Huang 
558794e27ecSJohnny Huang 	return OTP_FAILURE;
55983655e91SJohnny Huang }
56083655e91SJohnny Huang 
561a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
562d90825e2SJohnny Huang {
563d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
564d90825e2SJohnny Huang 
565d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
566696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
567d90825e2SJohnny Huang 			continue;
568d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
569d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
570d90825e2SJohnny Huang 			if (bit_value)
571d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
572d90825e2SJohnny Huang 			else
573d90825e2SJohnny Huang 				continue;
574d90825e2SJohnny Huang 		} else {
575e417205bSJohnny Huang 			if (info_cb.version != OTP_A3)
576d90825e2SJohnny Huang 				prog_address |= 1 << 15;
577d90825e2SJohnny Huang 			if (bit_value)
578d90825e2SJohnny Huang 				continue;
579d90825e2SJohnny Huang 			else
580d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
581d90825e2SJohnny Huang 		}
582d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
583d90825e2SJohnny Huang 	}
584d90825e2SJohnny Huang }
585d90825e2SJohnny Huang 
586a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
58754552c69SJohnny Huang {
58854552c69SJohnny Huang 	int pass;
58954552c69SJohnny Huang 	int i;
590a219f6deSJohnny Huang 	u32 data0_masked;
591a219f6deSJohnny Huang 	u32 data1_masked;
592a219f6deSJohnny Huang 	u32 buf0_masked;
593a219f6deSJohnny Huang 	u32 buf1_masked;
594a219f6deSJohnny Huang 	u32 compare[2];
59554552c69SJohnny Huang 
59654552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
59754552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
59854552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
59954552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
600a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
601f347c284SJohnny Huang 		return OTP_SUCCESS;
60254552c69SJohnny Huang 
603b64ca396SJohnny Huang 	for (i = 0; i < 32; i++) {
604b64ca396SJohnny Huang 		if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0)
605b64ca396SJohnny Huang 			return OTP_FAILURE;
606b64ca396SJohnny Huang 		if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1)
607b64ca396SJohnny Huang 			return OTP_FAILURE;
608b64ca396SJohnny Huang 	}
609b64ca396SJohnny Huang 
61054552c69SJohnny Huang 	otp_soak(1);
61154552c69SJohnny Huang 	if (data0_masked != buf0_masked)
61254552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
61354552c69SJohnny Huang 	if (data1_masked != buf1_masked)
61454552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
61554552c69SJohnny Huang 
61654552c69SJohnny Huang 	pass = 0;
61754552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
61854552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
61954552c69SJohnny Huang 			otp_soak(2);
620a219f6deSJohnny Huang 			if (compare[0] != 0)
62154552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
622a219f6deSJohnny Huang 			if (compare[1] != ~0)
6235537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
62454552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
62554552c69SJohnny Huang 				otp_soak(1);
62654552c69SJohnny Huang 			} else {
62754552c69SJohnny Huang 				pass = 1;
62854552c69SJohnny Huang 				break;
62954552c69SJohnny Huang 			}
63054552c69SJohnny Huang 		} else {
63154552c69SJohnny Huang 			pass = 1;
63254552c69SJohnny Huang 			break;
63354552c69SJohnny Huang 		}
63454552c69SJohnny Huang 	}
63554552c69SJohnny Huang 
63654552c69SJohnny Huang 	if (!pass) {
63754552c69SJohnny Huang 		otp_soak(0);
63854552c69SJohnny Huang 		return OTP_FAILURE;
63954552c69SJohnny Huang 	}
64054552c69SJohnny Huang 	return OTP_SUCCESS;
64154552c69SJohnny Huang }
64254552c69SJohnny Huang 
643541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
64476d13988SJohnny Huang {
645a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
6465010032bSJohnny Huang 	int strap_end;
64776d13988SJohnny Huang 	int i, j;
64876d13988SJohnny Huang 
649e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
65076d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
65176d13988SJohnny Huang 			otpstrap[j].value = 0;
65276d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
65376d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
65476d13988SJohnny Huang 			otpstrap[j].protected = 0;
65576d13988SJohnny Huang 		}
6565010032bSJohnny Huang 		strap_end = 30;
6575010032bSJohnny Huang 	} else {
6585010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
6595010032bSJohnny Huang 			otpstrap[j].value = 0;
6605010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
6615010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
6625010032bSJohnny Huang 			otpstrap[j].protected = 0;
6635010032bSJohnny Huang 		}
6645010032bSJohnny Huang 		strap_end = 28;
6655010032bSJohnny Huang 	}
66676d13988SJohnny Huang 
667dacbba92SJohnny Huang 	otp_soak(0);
6685010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
66976d13988SJohnny Huang 		int option = (i - 16) / 2;
670a219f6deSJohnny Huang 
671f347c284SJohnny Huang 		otp_read_conf(i, &OTPSTRAP_RAW[0]);
672f347c284SJohnny Huang 		otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
67376d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
67476d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
675a219f6deSJohnny Huang 
676a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
67776d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
67876d13988SJohnny Huang 			if (bit_value == 1)
67976d13988SJohnny Huang 				otpstrap[j].remain_times--;
68076d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
68176d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
68276d13988SJohnny Huang 		}
68376d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
68476d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
685a219f6deSJohnny Huang 
686a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
68776d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
68876d13988SJohnny Huang 			if (bit_value == 1)
68976d13988SJohnny Huang 				otpstrap[j].remain_times--;
69076d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
69176d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
69276d13988SJohnny Huang 		}
69376d13988SJohnny Huang 	}
6945010032bSJohnny Huang 
695f347c284SJohnny Huang 	otp_read_conf(30, &OTPSTRAP_RAW[0]);
696f347c284SJohnny Huang 	otp_read_conf(31, &OTPSTRAP_RAW[1]);
69776d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
69876d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
69976d13988SJohnny Huang 			otpstrap[j].protected = 1;
70076d13988SJohnny Huang 	}
70176d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
70276d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
70376d13988SJohnny Huang 			otpstrap[j].protected = 1;
70476d13988SJohnny Huang 	}
70576d13988SJohnny Huang }
70676d13988SJohnny Huang 
7077e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit)
708f347c284SJohnny Huang {
709f347c284SJohnny Huang 	int prog_flag = 0;
710f347c284SJohnny Huang 
711f347c284SJohnny Huang 	// ignore this bit
712f347c284SJohnny Huang 	if (ibit == 1)
713f347c284SJohnny Huang 		return OTP_SUCCESS;
714b489486eSJohnny Huang 	printf("OTPSTRAP[0x%X]:\n", offset);
715f347c284SJohnny Huang 
716f347c284SJohnny Huang 	if (bit == otpstrap->value) {
7177e523e3bSJohnny Huang 		if (!pbit) {
718f347c284SJohnny Huang 			printf("    The value is same as before, skip it.\n");
719f347c284SJohnny Huang 			return OTP_PROG_SKIP;
720f347c284SJohnny Huang 		}
721f347c284SJohnny Huang 		printf("    The value is same as before.\n");
722f347c284SJohnny Huang 	} else {
723f347c284SJohnny Huang 		prog_flag = 1;
724f347c284SJohnny Huang 	}
725f347c284SJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
726f347c284SJohnny Huang 		printf("    This bit is protected and is not writable\n");
727f347c284SJohnny Huang 		return OTP_FAILURE;
728f347c284SJohnny Huang 	}
729f347c284SJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
730b489486eSJohnny Huang 		printf("    This bit has no remaining chance to write.\n");
731f347c284SJohnny Huang 		return OTP_FAILURE;
732f347c284SJohnny Huang 	}
733f347c284SJohnny Huang 	if (pbit == 1)
734f347c284SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
735f347c284SJohnny Huang 	if (prog_flag)
736b489486eSJohnny 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);
737f347c284SJohnny Huang 
738f347c284SJohnny Huang 	return OTP_SUCCESS;
739f347c284SJohnny Huang }
740f347c284SJohnny Huang 
741f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
742f347c284SJohnny Huang {
743f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
744f347c284SJohnny Huang 	u32 prog_address;
745f347c284SJohnny Huang 	int offset;
746f347c284SJohnny Huang 	int ret;
747f347c284SJohnny Huang 
748f347c284SJohnny Huang 	otp_strap_status(otpstrap);
749f347c284SJohnny Huang 
7507e523e3bSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
751f347c284SJohnny Huang 
752f347c284SJohnny Huang 	if (ret != OTP_SUCCESS)
753f347c284SJohnny Huang 		return ret;
754f347c284SJohnny Huang 
755f347c284SJohnny Huang 	prog_address = 0x800;
756f347c284SJohnny Huang 	if (bit_offset < 32) {
757f347c284SJohnny Huang 		offset = bit_offset;
758f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
759f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
760f347c284SJohnny Huang 
761f347c284SJohnny Huang 	} else {
762f347c284SJohnny Huang 		offset = (bit_offset - 32);
763f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
764f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
765f347c284SJohnny Huang 	}
766f347c284SJohnny Huang 
767f347c284SJohnny Huang 	return otp_prog_dc_b(1, prog_address, offset);
768f347c284SJohnny Huang }
769f347c284SJohnny Huang 
770f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
771f347c284SJohnny Huang {
772f347c284SJohnny Huang 	int i;
773f347c284SJohnny Huang 	u32 ret[1];
774f347c284SJohnny Huang 
775f347c284SJohnny Huang 	if (offset + dw_count > 32)
776f347c284SJohnny Huang 		return OTP_USAGE;
777f347c284SJohnny Huang 	otp_soak(0);
778f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
779f347c284SJohnny Huang 		otp_read_conf(i, ret);
780b489486eSJohnny Huang 		printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]);
781f347c284SJohnny Huang 	}
782f347c284SJohnny Huang 	printf("\n");
783f347c284SJohnny Huang 	return OTP_SUCCESS;
784f347c284SJohnny Huang }
785f347c284SJohnny Huang 
786f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
787f347c284SJohnny Huang {
788f347c284SJohnny Huang 	int i;
789f347c284SJohnny Huang 	u32 ret[2];
790f347c284SJohnny Huang 
791f347c284SJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
792f347c284SJohnny Huang 		return OTP_USAGE;
793f347c284SJohnny Huang 	otp_soak(0);
794f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
795f347c284SJohnny Huang 		otp_read_data(i, ret);
796f347c284SJohnny Huang 		if (i % 4 == 0)
797f347c284SJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
798f347c284SJohnny Huang 		else
799f347c284SJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
800f347c284SJohnny Huang 	}
801f347c284SJohnny Huang 	printf("\n");
802f347c284SJohnny Huang 	return OTP_SUCCESS;
803f347c284SJohnny Huang }
804f347c284SJohnny Huang 
805f347c284SJohnny Huang static int otp_print_strap(int start, int count)
806f347c284SJohnny Huang {
807f347c284SJohnny Huang 	int i, j;
808f347c284SJohnny Huang 	int remains;
809f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
810f347c284SJohnny Huang 
811f347c284SJohnny Huang 	if (start < 0 || start > 64)
812f347c284SJohnny Huang 		return OTP_USAGE;
813f347c284SJohnny Huang 
814f347c284SJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
815f347c284SJohnny Huang 		return OTP_USAGE;
816f347c284SJohnny Huang 
817f347c284SJohnny Huang 	otp_strap_status(otpstrap);
818f347c284SJohnny Huang 
8197e523e3bSJohnny Huang 	if (info_cb.version == OTP_A0)
820f347c284SJohnny Huang 		remains = 7;
8217e523e3bSJohnny Huang 	else
822f347c284SJohnny Huang 		remains = 6;
8237e523e3bSJohnny Huang 	printf("BIT(hex)  Value  Option           Status\n");
824f347c284SJohnny Huang 	printf("______________________________________________________________________________\n");
825f347c284SJohnny Huang 
826f347c284SJohnny Huang 	for (i = start; i < start + count; i++) {
827f347c284SJohnny Huang 		printf("0x%-8X", i);
828f347c284SJohnny Huang 		printf("%-7d", otpstrap[i].value);
829f347c284SJohnny Huang 		for (j = 0; j < remains; j++)
830f347c284SJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
831f347c284SJohnny Huang 		printf("   ");
832f347c284SJohnny Huang 		if (otpstrap[i].protected == 1) {
833f347c284SJohnny Huang 			printf("protected and not writable");
834f347c284SJohnny Huang 		} else {
835f347c284SJohnny Huang 			printf("not protected ");
836f347c284SJohnny Huang 			if (otpstrap[i].remain_times == 0)
837f347c284SJohnny Huang 				printf("and no remaining times to write.");
838f347c284SJohnny Huang 			else
839f347c284SJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
840f347c284SJohnny Huang 		}
841f347c284SJohnny Huang 		printf("\n");
842f347c284SJohnny Huang 	}
843f347c284SJohnny Huang 
844f347c284SJohnny Huang 	return OTP_SUCCESS;
845f347c284SJohnny Huang }
846f347c284SJohnny Huang 
847794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
848794e27ecSJohnny Huang {
849794e27ecSJohnny Huang 	int bit_offset;
850794e27ecSJohnny Huang 	int i, j;
851794e27ecSJohnny Huang 
852794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
853794e27ecSJohnny Huang 	printf("___________________________________________________\n");
854794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
855794e27ecSJohnny Huang 		if (i < 32) {
856794e27ecSJohnny Huang 			j = 0;
857794e27ecSJohnny Huang 			bit_offset = i;
858794e27ecSJohnny Huang 		} else {
859794e27ecSJohnny Huang 			j = 1;
860794e27ecSJohnny Huang 			bit_offset = i - 32;
861794e27ecSJohnny Huang 		}
862794e27ecSJohnny Huang 		if (i % 16 == 0)
863794e27ecSJohnny Huang 			printf("%2x | ", i);
864794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
865794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
866794e27ecSJohnny Huang 			printf("\n");
867794e27ecSJohnny Huang 	}
868794e27ecSJohnny Huang }
869794e27ecSJohnny Huang 
870b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout)
871b25f02d2SJohnny Huang {
872b25f02d2SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
873b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
874b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
875b25f02d2SJohnny Huang 	int i;
876b25f02d2SJohnny Huang 	u32 scu_offset;
877b25f02d2SJohnny Huang 	u32 dw_offset;
878b25f02d2SJohnny Huang 	u32 bit_offset;
879b25f02d2SJohnny Huang 	u32 mask;
880b25f02d2SJohnny Huang 	u32 otp_value;
881b25f02d2SJohnny Huang 	u32 otp_ignore;
882b25f02d2SJohnny Huang 
883b25f02d2SJohnny Huang 	printf("SCU     BIT          reg_protect     Description\n");
884b25f02d2SJohnny Huang 	printf("____________________________________________________________________\n");
885b25f02d2SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
886b25f02d2SJohnny Huang 		mask = BIT(scu_info[i].length) - 1;
887b25f02d2SJohnny Huang 
888b25f02d2SJohnny Huang 		if (scu_info[i].bit_offset > 31) {
889b25f02d2SJohnny Huang 			scu_offset = 0x510;
890b25f02d2SJohnny Huang 			dw_offset = 1;
891b25f02d2SJohnny Huang 			bit_offset = scu_info[i].bit_offset - 32;
892b25f02d2SJohnny Huang 		} else {
893b25f02d2SJohnny Huang 			scu_offset = 0x500;
894b25f02d2SJohnny Huang 			dw_offset = 0;
895b25f02d2SJohnny Huang 			bit_offset = scu_info[i].bit_offset;
896b25f02d2SJohnny Huang 		}
897b25f02d2SJohnny Huang 
898b25f02d2SJohnny Huang 		otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask;
899b25f02d2SJohnny Huang 		otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask;
900b25f02d2SJohnny Huang 
901b25f02d2SJohnny Huang 		if (otp_ignore == mask)
902b25f02d2SJohnny Huang 			continue;
903b25f02d2SJohnny Huang 		else if (otp_ignore != 0)
904b25f02d2SJohnny Huang 			return OTP_FAILURE;
905b25f02d2SJohnny Huang 
906b25f02d2SJohnny Huang 		if (otp_value != 0 && otp_value != mask)
907b25f02d2SJohnny Huang 			return OTP_FAILURE;
908b25f02d2SJohnny Huang 
909b25f02d2SJohnny Huang 		printf("0x%-6X", scu_offset);
910b25f02d2SJohnny Huang 		if (scu_info[i].length == 1)
911b25f02d2SJohnny Huang 			printf("0x%-11X", bit_offset);
912b25f02d2SJohnny Huang 		else
9132131c250SJohnny Huang 			printf("0x%-2X:0x%-6x", bit_offset, bit_offset + scu_info[i].length - 1);
914b25f02d2SJohnny Huang 		printf("0x%-14X", otp_value);
915b25f02d2SJohnny Huang 		printf("%s\n", scu_info[i].information);
916b25f02d2SJohnny Huang 	}
917b25f02d2SJohnny Huang 	return OTP_SUCCESS;
918b25f02d2SJohnny Huang }
919b25f02d2SJohnny Huang 
9200dc9a440SJohnny Huang static void otp_print_scu_info(void)
9210dc9a440SJohnny Huang {
9220dc9a440SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
9230dc9a440SJohnny Huang 	u32 OTPCFG[2];
9240dc9a440SJohnny Huang 	u32 scu_offset;
9250dc9a440SJohnny Huang 	u32 bit_offset;
9260dc9a440SJohnny Huang 	u32 reg_p;
9270dc9a440SJohnny Huang 	u32 length;
9280dc9a440SJohnny Huang 	int i, j;
9290dc9a440SJohnny Huang 
9300dc9a440SJohnny Huang 	otp_soak(0);
9310dc9a440SJohnny Huang 	otp_read_conf(28, &OTPCFG[0]);
9320dc9a440SJohnny Huang 	otp_read_conf(29, &OTPCFG[1]);
9330dc9a440SJohnny Huang 	printf("SCU     BIT   reg_protect     Description\n");
9340dc9a440SJohnny Huang 	printf("____________________________________________________________________\n");
9350dc9a440SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
9360dc9a440SJohnny Huang 		length = scu_info[i].length;
9370dc9a440SJohnny Huang 		for (j = 0; j < length; j++) {
9380dc9a440SJohnny Huang 			if (scu_info[i].bit_offset + j < 32) {
9390dc9a440SJohnny Huang 				scu_offset = 0x500;
9400dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j;
9410dc9a440SJohnny Huang 				reg_p = (OTPCFG[0] >> bit_offset) & 0x1;
9420dc9a440SJohnny Huang 			} else {
9430dc9a440SJohnny Huang 				scu_offset = 0x510;
9440dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j - 32;
9450dc9a440SJohnny Huang 				reg_p = (OTPCFG[1] >> bit_offset) & 0x1;
9460dc9a440SJohnny Huang 			}
9470dc9a440SJohnny Huang 			printf("0x%-6X", scu_offset);
9480dc9a440SJohnny Huang 			printf("0x%-4X", bit_offset);
9490dc9a440SJohnny Huang 			printf("0x%-13X", reg_p);
9500dc9a440SJohnny Huang 			if (length == 1) {
9510dc9a440SJohnny Huang 				printf(" %s\n", scu_info[i].information);
9520dc9a440SJohnny Huang 				continue;
9530dc9a440SJohnny Huang 			}
9540dc9a440SJohnny Huang 
9550dc9a440SJohnny Huang 			if (j == 0)
9560dc9a440SJohnny Huang 				printf("/%s\n", scu_info[i].information);
9570dc9a440SJohnny Huang 			else if (j == length - 1)
9580dc9a440SJohnny Huang 				printf("\\ \"\n");
9590dc9a440SJohnny Huang 			else
9600dc9a440SJohnny Huang 				printf("| \"\n");
9610dc9a440SJohnny Huang 		}
9620dc9a440SJohnny Huang 	}
9630dc9a440SJohnny Huang }
9640dc9a440SJohnny Huang 
965696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
96669d5fd8fSJohnny Huang {
96779e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
968a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
969a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
970a219f6deSJohnny Huang 	u32 mask;
971a219f6deSJohnny Huang 	u32 dw_offset;
972a219f6deSJohnny Huang 	u32 bit_offset;
973a219f6deSJohnny Huang 	u32 otp_value;
974a219f6deSJohnny Huang 	u32 otp_ignore;
975b458cd62SJohnny Huang 	int fail = 0;
9767adec5f6SJohnny Huang 	int mask_err;
977794e27ecSJohnny Huang 	int rid_num = 0;
97873f11549SJohnny Huang 	char valid_bit[20];
979794e27ecSJohnny Huang 	int fz;
98066f2f8e5SJohnny Huang 	int i;
98173f11549SJohnny Huang 	int j;
98266f2f8e5SJohnny Huang 
983737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
98466f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
9853cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
9867adec5f6SJohnny Huang 		mask_err = 0;
9873cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
9883cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
9893cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
990b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
991696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
992b458cd62SJohnny Huang 
9937adec5f6SJohnny Huang 		if (conf_info[i].value == OTP_REG_VALID_BIT) {
9947adec5f6SJohnny Huang 			if (((otp_value + otp_ignore) & mask) != mask) {
995b458cd62SJohnny Huang 				fail = 1;
9967adec5f6SJohnny Huang 				mask_err = 1;
9977adec5f6SJohnny Huang 			}
9987adec5f6SJohnny Huang 		} else {
9997adec5f6SJohnny Huang 			if (otp_ignore == mask) {
10007adec5f6SJohnny Huang 				continue;
10017adec5f6SJohnny Huang 			} else if (otp_ignore != 0) {
10027adec5f6SJohnny Huang 				fail = 1;
10037adec5f6SJohnny Huang 				mask_err = 1;
10047adec5f6SJohnny Huang 			}
10057adec5f6SJohnny Huang 		}
1006b458cd62SJohnny Huang 
1007a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
10083cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
10093cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
10103cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1011b458cd62SJohnny Huang 			continue;
1012b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1013b458cd62SJohnny Huang 
10143cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
10153cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
101666f2f8e5SJohnny Huang 		} else {
1017b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
10183cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
10193cb28812SJohnny Huang 			       conf_info[i].bit_offset);
102066f2f8e5SJohnny Huang 		}
1021b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1022b458cd62SJohnny Huang 
10237adec5f6SJohnny Huang 		if (mask_err) {
10247adec5f6SJohnny Huang 			printf("Ignore, mask error\n");
1025a219f6deSJohnny Huang 			continue;
1026a219f6deSJohnny Huang 		}
10273cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1028b458cd62SJohnny Huang 			printf("Reserved\n");
10293cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
10303cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1031b458cd62SJohnny Huang 			printf("\n");
10323cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1033b458cd62SJohnny Huang 			if (otp_value != 0) {
103473f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1035e2b82258SJohnny Huang 					if (otp_value & (1 << j))
103673f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1037a219f6deSJohnny Huang 					else
103873f11549SJohnny Huang 						valid_bit[j * 2] = '0';
103973f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
104073f11549SJohnny Huang 				}
104173f11549SJohnny Huang 				valid_bit[15] = 0;
104273f11549SJohnny Huang 			} else {
104373f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1044b458cd62SJohnny Huang 			}
10453cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1046b458cd62SJohnny Huang 			printf("\n");
1047b458cd62SJohnny Huang 		} else {
10483cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1049b458cd62SJohnny Huang 		}
1050b458cd62SJohnny Huang 	}
1051b458cd62SJohnny Huang 
1052794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
1053794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
1054794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
1055794e27ecSJohnny Huang 			fail = 1;
1056794e27ecSJohnny Huang 		} else {
1057794e27ecSJohnny Huang 			fz = 0;
1058794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
1059794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
1060794e27ecSJohnny Huang 					if (!fz)
1061794e27ecSJohnny Huang 						fz = 1;
1062794e27ecSJohnny Huang 				} else {
1063794e27ecSJohnny Huang 					rid_num++;
1064794e27ecSJohnny Huang 					if (fz) {
1065794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
1066794e27ecSJohnny Huang 						fail = 1;
1067794e27ecSJohnny Huang 						break;
1068794e27ecSJohnny Huang 					}
1069794e27ecSJohnny Huang 				}
1070794e27ecSJohnny Huang 			}
1071794e27ecSJohnny Huang 		}
1072794e27ecSJohnny Huang 		if (fail)
1073794e27ecSJohnny Huang 			printf("OTP revision ID\n");
1074794e27ecSJohnny Huang 		else
1075794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
1076794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
1077794e27ecSJohnny Huang 	}
1078794e27ecSJohnny Huang 
1079b458cd62SJohnny Huang 	if (fail)
1080b458cd62SJohnny Huang 		return OTP_FAILURE;
1081b458cd62SJohnny Huang 
108266f2f8e5SJohnny Huang 	return OTP_SUCCESS;
108366f2f8e5SJohnny Huang }
108466f2f8e5SJohnny Huang 
10852d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
108666f2f8e5SJohnny Huang {
108779e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
1088a219f6deSJohnny Huang 	u32 OTPCFG[16];
1089a219f6deSJohnny Huang 	u32 mask;
1090a219f6deSJohnny Huang 	u32 dw_offset;
1091a219f6deSJohnny Huang 	u32 bit_offset;
1092a219f6deSJohnny Huang 	u32 otp_value;
109373f11549SJohnny Huang 	char valid_bit[20];
109466f2f8e5SJohnny Huang 	int i;
109573f11549SJohnny Huang 	int j;
109666f2f8e5SJohnny Huang 
1097dacbba92SJohnny Huang 	otp_soak(0);
1098bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
1099f347c284SJohnny Huang 		otp_read_conf(i, &OTPCFG[i]);
110066f2f8e5SJohnny Huang 
1101b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
1102b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
11033cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
11043cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
11052d4b0742SJohnny Huang 			continue;
11063cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
11073cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
11083cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
1109b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1110b458cd62SJohnny Huang 
1111a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
11123cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
11133cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
11143cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1115b458cd62SJohnny Huang 			continue;
1116b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1117b458cd62SJohnny Huang 
11183cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
11193cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
1120b458cd62SJohnny Huang 		} else {
1121b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
11223cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
11233cb28812SJohnny Huang 			       conf_info[i].bit_offset);
1124b458cd62SJohnny Huang 		}
1125b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1126b458cd62SJohnny Huang 
11273cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1128b458cd62SJohnny Huang 			printf("Reserved\n");
11293cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
11303cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1131b458cd62SJohnny Huang 			printf("\n");
11323cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1133b458cd62SJohnny Huang 			if (otp_value != 0) {
113473f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1135030cb4a7SJohnny Huang 					if (otp_value & (1 << j))
113673f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1137a219f6deSJohnny Huang 					else
113873f11549SJohnny Huang 						valid_bit[j * 2] = '0';
113973f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
114073f11549SJohnny Huang 				}
114173f11549SJohnny Huang 				valid_bit[15] = 0;
114273f11549SJohnny Huang 			} else {
114373f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1144b458cd62SJohnny Huang 			}
11453cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1146b458cd62SJohnny Huang 			printf("\n");
1147b458cd62SJohnny Huang 		} else {
11483cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1149b458cd62SJohnny Huang 		}
1150b458cd62SJohnny Huang 	}
1151b458cd62SJohnny Huang 	return OTP_SUCCESS;
115266f2f8e5SJohnny Huang }
115366f2f8e5SJohnny Huang 
11545010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
115576d13988SJohnny Huang {
115679e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
1157a219f6deSJohnny Huang 	u32 *OTPSTRAP;
1158a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
1159a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
116076d13988SJohnny Huang 	int i;
1161a8bd6d8cSJohnny Huang 	int fail = 0;
1162a219f6deSJohnny Huang 	u32 bit_offset;
1163a219f6deSJohnny Huang 	u32 dw_offset;
1164a219f6deSJohnny Huang 	u32 mask;
1165a219f6deSJohnny Huang 	u32 otp_value;
1166a219f6deSJohnny Huang 	u32 otp_protect;
1167a219f6deSJohnny Huang 	u32 otp_ignore;
116876d13988SJohnny Huang 
1169a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
1170a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1171a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
11727e523e3bSJohnny Huang 
1173a8bd6d8cSJohnny Huang 	printf("BIT(hex)   Value       Protect     Description\n");
1174de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
1175b458cd62SJohnny Huang 
11763cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
11777adec5f6SJohnny Huang 		fail = 0;
1178696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
1179a8bd6d8cSJohnny Huang 			dw_offset = 1;
11803cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
1181a8bd6d8cSJohnny Huang 		} else {
1182a8bd6d8cSJohnny Huang 			dw_offset = 0;
11833cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
1184a8bd6d8cSJohnny Huang 		}
118576d13988SJohnny Huang 
11863cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
1187a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1188a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1189696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1190a8bd6d8cSJohnny Huang 
1191a219f6deSJohnny Huang 		if (otp_ignore == mask)
1192a8bd6d8cSJohnny Huang 			continue;
1193a219f6deSJohnny Huang 		else if (otp_ignore != 0)
1194a8bd6d8cSJohnny Huang 			fail = 1;
1195a8bd6d8cSJohnny Huang 
1196a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
11973cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1198a8bd6d8cSJohnny Huang 			continue;
1199a8bd6d8cSJohnny Huang 
12003cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
12013cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
1202a8bd6d8cSJohnny Huang 		} else {
1203b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
12043cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
12053cb28812SJohnny Huang 			       strap_info[i].bit_offset);
1206a8bd6d8cSJohnny Huang 		}
1207a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
1208a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
1209a8bd6d8cSJohnny Huang 
1210a8bd6d8cSJohnny Huang 		if (fail) {
1211696656c6SJohnny Huang 			printf("Ignore mask error\n");
1212a8bd6d8cSJohnny Huang 		} else {
12133cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
12143cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1215a8bd6d8cSJohnny Huang 			else
1216a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1217a8bd6d8cSJohnny Huang 		}
1218a8bd6d8cSJohnny Huang 	}
1219a8bd6d8cSJohnny Huang 
1220a8bd6d8cSJohnny Huang 	if (fail)
122176d13988SJohnny Huang 		return OTP_FAILURE;
122276d13988SJohnny Huang 
122376d13988SJohnny Huang 	return OTP_SUCCESS;
122476d13988SJohnny Huang }
122576d13988SJohnny Huang 
1226b458cd62SJohnny Huang static int otp_print_strap_info(int view)
122776d13988SJohnny Huang {
122879e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
122976d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
123007baa4e8SJohnny Huang 	int i, j;
1231b458cd62SJohnny Huang 	int fail = 0;
1232a219f6deSJohnny Huang 	u32 bit_offset;
1233a219f6deSJohnny Huang 	u32 length;
1234a219f6deSJohnny Huang 	u32 otp_value;
1235a219f6deSJohnny Huang 	u32 otp_protect;
123676d13988SJohnny Huang 
1237541eb887SJohnny Huang 	otp_strap_status(strap_status);
123876d13988SJohnny Huang 
1239b458cd62SJohnny Huang 	if (view) {
124007baa4e8SJohnny Huang 		printf("BIT(hex) Value  Remains  Protect   Description\n");
124107baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1242b458cd62SJohnny Huang 	} else {
1243b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1244b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
124576d13988SJohnny Huang 	}
12463cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1247b458cd62SJohnny Huang 		otp_value = 0;
12483cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
12493cb28812SJohnny Huang 		length = strap_info[i].length;
1250b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1251c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1252c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1253b458cd62SJohnny Huang 		}
1254a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
12553cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1256b458cd62SJohnny Huang 			continue;
1257b458cd62SJohnny Huang 		if (view) {
1258b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
12593cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1260b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
126107baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1262e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
12633cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1264b458cd62SJohnny Huang 					printf(" Reserved\n");
1265b458cd62SJohnny Huang 					continue;
1266b458cd62SJohnny Huang 				}
1267b458cd62SJohnny Huang 				if (length == 1) {
12683cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1269b458cd62SJohnny Huang 					continue;
127076d13988SJohnny Huang 				}
127176d13988SJohnny Huang 
1272b458cd62SJohnny Huang 				if (j == 0)
12733cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1274b458cd62SJohnny Huang 				else if (j == length - 1)
1275b458cd62SJohnny Huang 					printf("\\ \"\n");
1276b458cd62SJohnny Huang 				else
1277b458cd62SJohnny Huang 					printf("| \"\n");
127876d13988SJohnny Huang 			}
1279b458cd62SJohnny Huang 		} else {
1280c947ef08SJohnny Huang 			if (length == 1) {
12813cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1282b458cd62SJohnny Huang 			} else {
1283b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1284b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1285b458cd62SJohnny Huang 			}
1286b458cd62SJohnny Huang 
1287b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1288b458cd62SJohnny Huang 
12893cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
12903cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1291b458cd62SJohnny Huang 			else
1292b458cd62SJohnny Huang 				printf("Reserved\n");
1293b458cd62SJohnny Huang 		}
1294b458cd62SJohnny Huang 	}
1295b458cd62SJohnny Huang 
1296b458cd62SJohnny Huang 	if (fail)
1297b458cd62SJohnny Huang 		return OTP_FAILURE;
1298b458cd62SJohnny Huang 
1299b458cd62SJohnny Huang 	return OTP_SUCCESS;
1300b458cd62SJohnny Huang }
1301b458cd62SJohnny Huang 
130288bd7d58SJohnny Huang static void _otp_print_key(u32 *data)
130369d5fd8fSJohnny Huang {
130488bd7d58SJohnny Huang 	int i, j;
130569d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
13069a4fe690SJohnny Huang 	struct otpkey_type key_info;
130788bd7d58SJohnny Huang 	const struct otpkey_type *key_info_array = info_cb.key_info;
130888bd7d58SJohnny Huang 	int len = 0;
1309a219f6deSJohnny Huang 	u8 *byte_buf;
131088bd7d58SJohnny Huang 	int empty;
131154552c69SJohnny Huang 
131288bd7d58SJohnny Huang 	byte_buf = (u8 *)data;
13139d998018SJohnny Huang 
131488bd7d58SJohnny Huang 	empty = 1;
13159d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
131688bd7d58SJohnny Huang 		if (i % 2) {
131788bd7d58SJohnny Huang 			if (data[i] != 0xffffffff)
131888bd7d58SJohnny Huang 				empty = 0;
131988bd7d58SJohnny Huang 		} else {
132088bd7d58SJohnny Huang 			if (data[i] != 0)
13219d998018SJohnny Huang 				empty = 0;
13229d998018SJohnny Huang 		}
132388bd7d58SJohnny Huang 	}
132488bd7d58SJohnny Huang 	if (empty) {
132588bd7d58SJohnny Huang 		printf("OTP data header is empty\n");
132688bd7d58SJohnny Huang 		return;
132788bd7d58SJohnny Huang 	}
13289d998018SJohnny Huang 
132988bd7d58SJohnny Huang 	for (i = 0; i < 16; i++) {
133088bd7d58SJohnny Huang 		key_id = data[i] & 0x7;
133188bd7d58SJohnny Huang 		key_offset = data[i] & 0x1ff8;
133288bd7d58SJohnny Huang 		last = (data[i] >> 13) & 1;
133388bd7d58SJohnny Huang 		key_type = (data[i] >> 14) & 0xf;
133488bd7d58SJohnny Huang 		key_length = (data[i] >> 18) & 0x3;
133588bd7d58SJohnny Huang 		exp_length = (data[i] >> 20) & 0xfff;
13369a4fe690SJohnny Huang 
133788bd7d58SJohnny Huang 		key_info.value = -1;
13389a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
13399a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
13409a4fe690SJohnny Huang 				key_info = key_info_array[j];
13419a4fe690SJohnny Huang 				break;
13429a4fe690SJohnny Huang 			}
13439a4fe690SJohnny Huang 		}
134488bd7d58SJohnny Huang 		if (key_info.value == -1)
134588bd7d58SJohnny Huang 			break;
13469a4fe690SJohnny Huang 
13477f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
134869d5fd8fSJohnny Huang 		printf("Key Type: ");
13499a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
13509a4fe690SJohnny Huang 
13519a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
135269d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
135369d5fd8fSJohnny Huang 			switch (key_length) {
135469d5fd8fSJohnny Huang 			case 0:
135569d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
135669d5fd8fSJohnny Huang 				break;
135769d5fd8fSJohnny Huang 			case 1:
135869d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
135969d5fd8fSJohnny Huang 				break;
136069d5fd8fSJohnny Huang 			case 2:
136169d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
136269d5fd8fSJohnny Huang 				break;
136369d5fd8fSJohnny Huang 			case 3:
136469d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
136569d5fd8fSJohnny Huang 				break;
136669d5fd8fSJohnny Huang 			}
1367181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1368181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
136969d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
137069d5fd8fSJohnny Huang 			switch (key_length) {
137169d5fd8fSJohnny Huang 			case 0:
137269d5fd8fSJohnny Huang 				printf("RSA1024\n");
137369d5fd8fSJohnny Huang 				len = 0x100;
137469d5fd8fSJohnny Huang 				break;
137569d5fd8fSJohnny Huang 			case 1:
137669d5fd8fSJohnny Huang 				printf("RSA2048\n");
137769d5fd8fSJohnny Huang 				len = 0x200;
137869d5fd8fSJohnny Huang 				break;
137969d5fd8fSJohnny Huang 			case 2:
138069d5fd8fSJohnny Huang 				printf("RSA3072\n");
138169d5fd8fSJohnny Huang 				len = 0x300;
138269d5fd8fSJohnny Huang 				break;
138369d5fd8fSJohnny Huang 			case 3:
138469d5fd8fSJohnny Huang 				printf("RSA4096\n");
138569d5fd8fSJohnny Huang 				len = 0x400;
138669d5fd8fSJohnny Huang 				break;
138769d5fd8fSJohnny Huang 			}
138869d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
138969d5fd8fSJohnny Huang 		}
13909a4fe690SJohnny Huang 		if (key_info.need_id)
139169d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
139269d5fd8fSJohnny Huang 		printf("Key Value:\n");
13939a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
139469d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
13959a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
13969a4fe690SJohnny Huang 			printf("AES Key:\n");
13979a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1398e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
13999a4fe690SJohnny Huang 				printf("AES IV:\n");
14009a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
14019a4fe690SJohnny Huang 			}
14029a4fe690SJohnny Huang 
14039a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1404e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
140569d5fd8fSJohnny Huang 				printf("AES Key:\n");
140669d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
140769d5fd8fSJohnny Huang 				printf("AES IV:\n");
140869d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
14095fdde29fSJohnny Huang 			} else {
14109a4fe690SJohnny Huang 				printf("AES Key 1:\n");
14119a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
14129a4fe690SJohnny Huang 				printf("AES Key 2:\n");
14139a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
14149a4fe690SJohnny Huang 			}
1415181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
141669d5fd8fSJohnny Huang 			printf("RSA mod:\n");
141769d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
141869d5fd8fSJohnny Huang 			printf("RSA exp:\n");
141969d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1420181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1421181f72d8SJohnny Huang 			printf("RSA mod:\n");
1422181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1423181f72d8SJohnny Huang 			printf("RSA exp:\n");
1424a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
142569d5fd8fSJohnny Huang 		}
142669d5fd8fSJohnny Huang 		if (last)
142769d5fd8fSJohnny Huang 			break;
142869d5fd8fSJohnny Huang 	}
142988bd7d58SJohnny Huang }
143088bd7d58SJohnny Huang 
143188bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
143288bd7d58SJohnny Huang {
143388bd7d58SJohnny Huang 	u32 *buf;
143488bd7d58SJohnny Huang 
143588bd7d58SJohnny Huang 	buf = (u32 *)image_layout->data;
143688bd7d58SJohnny Huang 	_otp_print_key(buf);
143788bd7d58SJohnny Huang 
1438f347c284SJohnny Huang 	return OTP_SUCCESS;
1439f347c284SJohnny Huang }
1440f347c284SJohnny Huang 
144188bd7d58SJohnny Huang static void otp_print_key_info(void)
144288bd7d58SJohnny Huang {
144388bd7d58SJohnny Huang 	u32 data[2048];
144488bd7d58SJohnny Huang 	int i;
144588bd7d58SJohnny Huang 
144688bd7d58SJohnny Huang 	for (i = 0; i < 2048 ; i += 2)
144788bd7d58SJohnny Huang 		otp_read_data(i, &data[i]);
144888bd7d58SJohnny Huang 
144988bd7d58SJohnny Huang 	_otp_print_key(data);
145088bd7d58SJohnny Huang }
145188bd7d58SJohnny Huang 
1452b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data)
1453f347c284SJohnny Huang {
1454f347c284SJohnny Huang 	int i;
1455f347c284SJohnny Huang 	int ret;
1456f347c284SJohnny Huang 	u32 *buf;
1457f347c284SJohnny Huang 	u32 *buf_ignore;
1458f347c284SJohnny Huang 
1459f347c284SJohnny Huang 	buf = (u32 *)image_layout->data;
1460f347c284SJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
1461f347c284SJohnny Huang 	printf("Start Programing...\n");
1462f347c284SJohnny Huang 
1463f347c284SJohnny Huang 	// programing ecc region first
1464f347c284SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1465f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1466f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1467f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1468f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1469f347c284SJohnny Huang 			return ret;
1470f347c284SJohnny Huang 		}
1471f347c284SJohnny Huang 	}
1472f347c284SJohnny Huang 
1473f347c284SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1474f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1475f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1476f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1477f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1478f347c284SJohnny Huang 			return ret;
1479f347c284SJohnny Huang 		}
1480f347c284SJohnny Huang 	}
1481f347c284SJohnny Huang 	otp_soak(0);
1482f347c284SJohnny Huang 	return OTP_SUCCESS;
1483f347c284SJohnny Huang }
1484f347c284SJohnny Huang 
1485b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1486f347c284SJohnny Huang {
1487f347c284SJohnny Huang 	u32 *strap;
1488f347c284SJohnny Huang 	u32 *strap_ignore;
1489f347c284SJohnny Huang 	u32 *strap_pro;
1490f347c284SJohnny Huang 	u32 prog_address;
1491f347c284SJohnny Huang 	int i;
14927e523e3bSJohnny Huang 	int bit, pbit, ibit, offset;
1493f347c284SJohnny Huang 	int fail = 0;
1494f347c284SJohnny Huang 	int ret;
1495f347c284SJohnny Huang 	int prog_flag = 0;
1496f347c284SJohnny Huang 
1497f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1498f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1499f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1500f347c284SJohnny Huang 
1501f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1502f347c284SJohnny Huang 		prog_address = 0x800;
1503f347c284SJohnny Huang 		if (i < 32) {
1504f347c284SJohnny Huang 			offset = i;
1505f347c284SJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1506f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
1507f347c284SJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
1508f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1509f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1510f347c284SJohnny Huang 
1511f347c284SJohnny Huang 		} else {
1512f347c284SJohnny Huang 			offset = (i - 32);
1513f347c284SJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1514f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
1515f347c284SJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
1516f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1517f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1518f347c284SJohnny Huang 		}
1519f347c284SJohnny Huang 
1520f347c284SJohnny Huang 		if (ibit == 1)
1521f347c284SJohnny Huang 			continue;
1522f347c284SJohnny Huang 		if (bit == otpstrap[i].value)
1523f347c284SJohnny Huang 			prog_flag = 0;
1524f347c284SJohnny Huang 		else
1525f347c284SJohnny Huang 			prog_flag = 1;
1526f347c284SJohnny Huang 
1527f347c284SJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
1528f347c284SJohnny Huang 			fail = 1;
1529f347c284SJohnny Huang 			continue;
1530f347c284SJohnny Huang 		}
1531f347c284SJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
1532f347c284SJohnny Huang 			fail = 1;
1533f347c284SJohnny Huang 			continue;
1534f347c284SJohnny Huang 		}
1535f347c284SJohnny Huang 
1536f347c284SJohnny Huang 		if (prog_flag) {
1537f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1538f347c284SJohnny Huang 			if (ret)
1539f347c284SJohnny Huang 				return OTP_FAILURE;
1540f347c284SJohnny Huang 		}
1541f347c284SJohnny Huang 
1542f347c284SJohnny Huang 		if (pbit != 0) {
1543f347c284SJohnny Huang 			prog_address = 0x800;
1544f347c284SJohnny Huang 			if (i < 32)
1545f347c284SJohnny Huang 				prog_address |= 0x60c;
1546f347c284SJohnny Huang 			else
1547f347c284SJohnny Huang 				prog_address |= 0x60e;
1548f347c284SJohnny Huang 
1549f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1550f347c284SJohnny Huang 			if (ret)
1551f347c284SJohnny Huang 				return OTP_FAILURE;
1552f347c284SJohnny Huang 		}
1553f347c284SJohnny Huang 	}
1554f347c284SJohnny Huang 	otp_soak(0);
1555f347c284SJohnny Huang 	if (fail == 1)
1556f347c284SJohnny Huang 		return OTP_FAILURE;
1557f347c284SJohnny Huang 	return OTP_SUCCESS;
155869d5fd8fSJohnny Huang }
155969d5fd8fSJohnny Huang 
1560b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf)
156169d5fd8fSJohnny Huang {
1562a6d0d645SJohnny Huang 	int i, k;
1563d90825e2SJohnny Huang 	int pass = 0;
1564a219f6deSJohnny Huang 	u32 prog_address;
1565a219f6deSJohnny Huang 	u32 compare[2];
1566a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1567a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1568a219f6deSJohnny Huang 	u32 data_masked;
1569a219f6deSJohnny Huang 	u32 buf_masked;
157069d5fd8fSJohnny Huang 
1571a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1572d90825e2SJohnny Huang 	otp_soak(0);
1573bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
1574b64ca396SJohnny Huang 		data_masked = otp_conf[i]  & ~conf_ignore[i];
15755010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1576a6d0d645SJohnny Huang 		prog_address = 0x800;
1577a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1578a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1579bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1580bb34a7bfSJohnny Huang 			pass = 1;
1581a6d0d645SJohnny Huang 			continue;
1582bb34a7bfSJohnny Huang 		}
1583de6fbf1cSJohnny Huang 
1584de6fbf1cSJohnny Huang 		otp_soak(1);
15855010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1586a6d0d645SJohnny Huang 
158769d5fd8fSJohnny Huang 		pass = 0;
158869d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
15895010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1590de6fbf1cSJohnny Huang 				otp_soak(2);
1591feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
15925010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1593de6fbf1cSJohnny Huang 					otp_soak(1);
1594de6fbf1cSJohnny Huang 				} else {
1595de6fbf1cSJohnny Huang 					pass = 1;
1596de6fbf1cSJohnny Huang 					break;
1597de6fbf1cSJohnny Huang 				}
1598a6d0d645SJohnny Huang 			} else {
159969d5fd8fSJohnny Huang 				pass = 1;
160069d5fd8fSJohnny Huang 				break;
160169d5fd8fSJohnny Huang 			}
160269d5fd8fSJohnny Huang 		}
1603bb34a7bfSJohnny Huang 		if (pass == 0) {
1604b64ca396SJohnny Huang 			printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n",
1605b64ca396SJohnny Huang 			       i, otp_conf[i], conf[i], conf_ignore[i]);
1606bb34a7bfSJohnny Huang 			break;
1607bb34a7bfSJohnny Huang 		}
1608a6d0d645SJohnny Huang 	}
1609a6d0d645SJohnny Huang 
1610de6fbf1cSJohnny Huang 	otp_soak(0);
161169d5fd8fSJohnny Huang 	if (!pass)
16122a856b9aSJohnny Huang 		return OTP_FAILURE;
1613a6d0d645SJohnny Huang 
16142a856b9aSJohnny Huang 	return OTP_SUCCESS;
161569d5fd8fSJohnny Huang }
161669d5fd8fSJohnny Huang 
1617b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro)
1618b25f02d2SJohnny Huang {
1619b25f02d2SJohnny Huang 	int i, k;
1620b25f02d2SJohnny Huang 	int pass = 0;
1621b25f02d2SJohnny Huang 	u32 prog_address;
1622b25f02d2SJohnny Huang 	u32 compare[2];
1623b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1624b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1625b25f02d2SJohnny Huang 	u32 data_masked;
1626b25f02d2SJohnny Huang 	u32 buf_masked;
1627b25f02d2SJohnny Huang 
1628b25f02d2SJohnny Huang 	printf("Start Programing...\n");
1629b25f02d2SJohnny Huang 	otp_soak(0);
1630b25f02d2SJohnny Huang 	for (i = 0; i < 2; i++) {
1631b25f02d2SJohnny Huang 		data_masked = scu_pro[i]  & ~OTPSCU_IGNORE[i];
1632b25f02d2SJohnny Huang 		buf_masked  = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1633b25f02d2SJohnny Huang 		prog_address = 0xe08 + i * 2;
1634b25f02d2SJohnny Huang 		if (data_masked == buf_masked) {
1635b25f02d2SJohnny Huang 			pass = 1;
1636b25f02d2SJohnny Huang 			continue;
1637b25f02d2SJohnny Huang 		}
1638b25f02d2SJohnny Huang 
1639b25f02d2SJohnny Huang 		otp_soak(1);
1640b25f02d2SJohnny Huang 		otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address);
1641b25f02d2SJohnny Huang 
1642b25f02d2SJohnny Huang 		pass = 0;
1643b25f02d2SJohnny Huang 		for (k = 0; k < RETRY; k++) {
1644b25f02d2SJohnny Huang 			if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1645b25f02d2SJohnny Huang 				otp_soak(2);
1646b25f02d2SJohnny Huang 				otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address);
1647b25f02d2SJohnny Huang 				if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1648b25f02d2SJohnny Huang 					otp_soak(1);
1649b25f02d2SJohnny Huang 				} else {
1650b25f02d2SJohnny Huang 					pass = 1;
1651b25f02d2SJohnny Huang 					break;
1652b25f02d2SJohnny Huang 				}
1653b25f02d2SJohnny Huang 			} else {
1654b25f02d2SJohnny Huang 				pass = 1;
1655b25f02d2SJohnny Huang 				break;
1656b25f02d2SJohnny Huang 			}
1657b25f02d2SJohnny Huang 		}
1658b25f02d2SJohnny Huang 		if (pass == 0) {
1659b489486eSJohnny Huang 			printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n",
1660b25f02d2SJohnny Huang 			       i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]);
1661b25f02d2SJohnny Huang 			break;
1662b25f02d2SJohnny Huang 		}
1663b25f02d2SJohnny Huang 	}
1664b25f02d2SJohnny Huang 
1665b25f02d2SJohnny Huang 	otp_soak(0);
1666b25f02d2SJohnny Huang 	if (!pass)
1667b25f02d2SJohnny Huang 		return OTP_FAILURE;
1668b25f02d2SJohnny Huang 
1669b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1670b25f02d2SJohnny Huang }
1671b25f02d2SJohnny Huang 
1672b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data)
1673b64ca396SJohnny Huang {
1674b64ca396SJohnny Huang 	int data_dw;
1675b64ca396SJohnny Huang 	u32 data_masked;
1676b64ca396SJohnny Huang 	u32 buf_masked;
1677b64ca396SJohnny Huang 	u32 *buf = (u32 *)image_layout->data;
1678b64ca396SJohnny Huang 	u32 *buf_ignore = (u32 *)image_layout->data_ignore;
1679b64ca396SJohnny Huang 	int i;
1680b64ca396SJohnny Huang 
1681b64ca396SJohnny Huang 	data_dw = image_layout->data_length / 4;
1682b64ca396SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
1683b64ca396SJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1684b64ca396SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1685b64ca396SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
1686b64ca396SJohnny Huang 		if (data_masked == buf_masked)
1687b64ca396SJohnny Huang 			continue;
1688b64ca396SJohnny Huang 		if (i % 2 == 0) {
1689b64ca396SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
1690b64ca396SJohnny Huang 				continue;
1691b64ca396SJohnny Huang 			} else {
1692b64ca396SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1693b489486eSJohnny Huang 				printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1694b489486eSJohnny Huang 				printf("Input   [0x%x] = 0x%x\n", i, buf[i]);
1695b489486eSJohnny Huang 				printf("Mask    [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1696b64ca396SJohnny Huang 				return OTP_FAILURE;
1697b64ca396SJohnny Huang 			}
1698b64ca396SJohnny Huang 		} else {
1699b64ca396SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1700b64ca396SJohnny Huang 				continue;
1701b64ca396SJohnny Huang 			} else {
1702b64ca396SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1703b489486eSJohnny Huang 				printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1704b489486eSJohnny Huang 				printf("Input   [0x%x] = 0x%x\n", i, buf[i]);
1705b489486eSJohnny Huang 				printf("Mask    [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1706b64ca396SJohnny Huang 				return OTP_FAILURE;
1707b64ca396SJohnny Huang 			}
1708b64ca396SJohnny Huang 		}
1709b64ca396SJohnny Huang 	}
1710b64ca396SJohnny Huang 	return OTP_SUCCESS;
1711b64ca396SJohnny Huang }
1712b64ca396SJohnny Huang 
1713b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1714b64ca396SJohnny Huang {
1715b64ca396SJohnny Huang 	int i;
1716b64ca396SJohnny Huang 	u32 *strap;
1717b64ca396SJohnny Huang 	u32 *strap_ignore;
1718b64ca396SJohnny Huang 	u32 *strap_pro;
1719b64ca396SJohnny Huang 	int bit, pbit, ibit;
1720b64ca396SJohnny Huang 	int fail = 0;
1721b64ca396SJohnny Huang 	int ret;
1722b64ca396SJohnny Huang 
1723b64ca396SJohnny Huang 	strap = (u32 *)image_layout->strap;
1724b64ca396SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1725b64ca396SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1726b64ca396SJohnny Huang 
1727b64ca396SJohnny Huang 	for (i = 0; i < 64; i++) {
1728b64ca396SJohnny Huang 		if (i < 32) {
1729b64ca396SJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1730b64ca396SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
1731b64ca396SJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
1732b64ca396SJohnny Huang 		} else {
1733b64ca396SJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1734b64ca396SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1735b64ca396SJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1736b64ca396SJohnny Huang 		}
1737b64ca396SJohnny Huang 
1738b64ca396SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit);
1739b64ca396SJohnny Huang 
1740b64ca396SJohnny Huang 		if (ret == OTP_FAILURE)
1741b64ca396SJohnny Huang 			fail = 1;
1742b64ca396SJohnny Huang 	}
1743b64ca396SJohnny Huang 	if (fail == 1) {
1744b64ca396SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
1745b64ca396SJohnny Huang 		return OTP_FAILURE;
1746b64ca396SJohnny Huang 	}
1747b64ca396SJohnny Huang 	return OTP_SUCCESS;
1748b64ca396SJohnny Huang }
1749b64ca396SJohnny Huang 
1750b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf)
1751b64ca396SJohnny Huang {
1752b64ca396SJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1753b64ca396SJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1754b64ca396SJohnny Huang 	u32 data_masked;
1755b64ca396SJohnny Huang 	u32 buf_masked;
1756b64ca396SJohnny Huang 	int i;
1757b64ca396SJohnny Huang 
1758b64ca396SJohnny Huang 	for (i = 0; i < 16; i++) {
1759b64ca396SJohnny Huang 		data_masked = otp_conf[i]  & ~conf_ignore[i];
1760b64ca396SJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1761b64ca396SJohnny Huang 		if (data_masked == buf_masked)
1762b64ca396SJohnny Huang 			continue;
1763b64ca396SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1764b64ca396SJohnny Huang 			continue;
1765b64ca396SJohnny Huang 		} else {
1766b64ca396SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1767b64ca396SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, otp_conf[i]);
1768b64ca396SJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
1769b64ca396SJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
1770b64ca396SJohnny Huang 			return OTP_FAILURE;
1771b64ca396SJohnny Huang 		}
1772b64ca396SJohnny Huang 	}
1773b64ca396SJohnny Huang 	return OTP_SUCCESS;
1774b64ca396SJohnny Huang }
1775b64ca396SJohnny Huang 
1776b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro)
1777b25f02d2SJohnny Huang {
1778b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1779b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1780b25f02d2SJohnny Huang 	u32 data_masked;
1781b25f02d2SJohnny Huang 	u32 buf_masked;
1782b25f02d2SJohnny Huang 	int i;
1783b25f02d2SJohnny Huang 
1784b25f02d2SJohnny Huang 	for (i = 0; i < 2; i++) {
1785b25f02d2SJohnny Huang 		data_masked = scu_pro[i]  & ~OTPSCU_IGNORE[i];
1786b25f02d2SJohnny Huang 		buf_masked  = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1787b25f02d2SJohnny Huang 		if (data_masked == buf_masked)
1788b25f02d2SJohnny Huang 			continue;
1789b25f02d2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1790b25f02d2SJohnny Huang 			continue;
1791b25f02d2SJohnny Huang 		} else {
1792b25f02d2SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1793b489486eSJohnny Huang 			printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]);
1794b489486eSJohnny Huang 			printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]);
1795b489486eSJohnny Huang 			printf("Mask  [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]);
1796b25f02d2SJohnny Huang 			return OTP_FAILURE;
1797b25f02d2SJohnny Huang 		}
1798b25f02d2SJohnny Huang 	}
1799b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1800b25f02d2SJohnny Huang }
1801b25f02d2SJohnny Huang 
1802f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf)
1803696656c6SJohnny Huang {
1804696656c6SJohnny Huang 	sha256_context ctx;
1805696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1806696656c6SJohnny Huang 
1807696656c6SJohnny Huang 	sha256_starts(&ctx);
1808696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1809696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1810696656c6SJohnny Huang 
1811696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1812f347c284SJohnny Huang 		return OTP_SUCCESS;
1813f347c284SJohnny Huang 	return OTP_FAILURE;
1814696656c6SJohnny Huang }
1815696656c6SJohnny Huang 
1816f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
181769d5fd8fSJohnny Huang {
181869d5fd8fSJohnny Huang 	int ret;
181961a6cda7SJohnny Huang 	int image_soc_ver = 0;
1820696656c6SJohnny Huang 	struct otp_header *otp_header;
1821696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1822696656c6SJohnny Huang 	int image_size;
1823a219f6deSJohnny Huang 	u8 *buf;
1824a219f6deSJohnny Huang 	u8 *checksum;
1825b64ca396SJohnny Huang 	int i;
1826b64ca396SJohnny Huang 	u32 data[2048];
1827b64ca396SJohnny Huang 	u32 conf[16];
1828b25f02d2SJohnny Huang 	u32 scu_pro[2];
1829b64ca396SJohnny Huang 	struct otpstrap_status otpstrap[64];
183069d5fd8fSJohnny Huang 
1831696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1832696656c6SJohnny Huang 	if (!otp_header) {
1833030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
18342a856b9aSJohnny Huang 		return OTP_FAILURE;
183569d5fd8fSJohnny Huang 	}
1836d90825e2SJohnny Huang 
1837696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1838696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1839696656c6SJohnny Huang 
1840696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1841696656c6SJohnny Huang 
1842696656c6SJohnny Huang 	if (!buf) {
1843030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
1844696656c6SJohnny Huang 		return OTP_FAILURE;
1845696656c6SJohnny Huang 	}
1846696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1847696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1848696656c6SJohnny Huang 
1849696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1850030cb4a7SJohnny Huang 		printf("Image is invalid\n");
1851696656c6SJohnny Huang 		return OTP_FAILURE;
1852696656c6SJohnny Huang 	}
1853696656c6SJohnny Huang 
18545010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
18555010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
18565010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
18575010032bSJohnny Huang 
18585010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1859696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
18605010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1861696656c6SJohnny Huang 
1862696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
18635010032bSJohnny Huang 	image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
18645010032bSJohnny Huang 	image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
18655010032bSJohnny Huang 	image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
18667e523e3bSJohnny Huang 
1867b25f02d2SJohnny Huang 	image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info);
1868b25f02d2SJohnny Huang 	image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2);
1869b25f02d2SJohnny Huang 	image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length;
1870b25f02d2SJohnny Huang 
18717e523e3bSJohnny Huang 	if (otp_header->soc_ver == SOC_AST2600A0) {
18727e523e3bSJohnny Huang 		image_soc_ver = OTP_A0;
187361a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A1) {
187461a6cda7SJohnny Huang 		image_soc_ver = OTP_A1;
187561a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A2) {
187661a6cda7SJohnny Huang 		image_soc_ver = OTP_A2;
187761a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A3) {
187861a6cda7SJohnny Huang 		image_soc_ver = OTP_A3;
1879696656c6SJohnny Huang 	} else {
1880030cb4a7SJohnny Huang 		printf("Image SOC Version is not supported\n");
1881696656c6SJohnny Huang 		return OTP_FAILURE;
1882696656c6SJohnny Huang 	}
1883696656c6SJohnny Huang 
188461a6cda7SJohnny Huang 	if (image_soc_ver != info_cb.version) {
1885*5e096f11SJohnny Huang 		printf("Image SOC version is not match to HW SOC version\n");
18869a4fe690SJohnny Huang 		return OTP_FAILURE;
18879a4fe690SJohnny Huang 	}
18889a4fe690SJohnny Huang 
1889*5e096f11SJohnny Huang 	if (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver) != OTPTOOL_COMPT_VERSION) {
1890*5e096f11SJohnny Huang 		printf("OTP image is not generated by otptool v1.x.x\n");
189161a6cda7SJohnny Huang 		return OTP_FAILURE;
189261a6cda7SJohnny Huang 	}
189361a6cda7SJohnny Huang 
1894f347c284SJohnny Huang 	if (otp_verify_image(buf, image_size, checksum)) {
1895030cb4a7SJohnny Huang 		printf("checksum is invalid\n");
1896696656c6SJohnny Huang 		return OTP_FAILURE;
1897d90825e2SJohnny Huang 	}
18987332532cSJohnny Huang 
1899030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
1900030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
1901030cb4a7SJohnny Huang 		return OTP_FAILURE;
1902030cb4a7SJohnny Huang 	}
1903b64ca396SJohnny Huang 	ret = 0;
1904030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
1905030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_data) {
1906030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
1907030cb4a7SJohnny Huang 			ret = -1;
1908030cb4a7SJohnny Huang 		}
1909030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_sec) {
1910030cb4a7SJohnny Huang 			printf("OTP secure region is protected\n");
1911030cb4a7SJohnny Huang 			ret = -1;
1912030cb4a7SJohnny Huang 		}
1913b64ca396SJohnny Huang 		printf("Read OTP Data Region:\n");
1914b64ca396SJohnny Huang 		for (i = 0; i < 2048 ; i += 2)
1915b64ca396SJohnny Huang 			otp_read_data(i, &data[i]);
1916b64ca396SJohnny Huang 
1917b64ca396SJohnny Huang 		printf("Check writable...\n");
1918b64ca396SJohnny Huang 		if (otp_check_data_image(&image_layout, data) == OTP_FAILURE)
1919b64ca396SJohnny Huang 			ret = -1;
1920030cb4a7SJohnny Huang 	}
1921030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
1922030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_conf) {
1923030cb4a7SJohnny Huang 			printf("OTP config region is protected\n");
1924030cb4a7SJohnny Huang 			ret = -1;
1925030cb4a7SJohnny Huang 		}
1926b64ca396SJohnny Huang 		printf("Read OTP Config Region:\n");
1927b64ca396SJohnny Huang 		for (i = 0; i < 16 ; i++)
1928b64ca396SJohnny Huang 			otp_read_conf(i, &conf[i]);
1929b64ca396SJohnny Huang 
1930b64ca396SJohnny Huang 		printf("Check writable...\n");
1931b64ca396SJohnny Huang 		if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE)
1932b64ca396SJohnny Huang 			ret = -1;
1933030cb4a7SJohnny Huang 	}
1934030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
1935030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
1936030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
1937030cb4a7SJohnny Huang 			ret = -1;
1938030cb4a7SJohnny Huang 		}
1939b64ca396SJohnny Huang 		printf("Read OTP Strap Region:\n");
1940b64ca396SJohnny Huang 		otp_strap_status(otpstrap);
1941b64ca396SJohnny Huang 
1942b64ca396SJohnny Huang 		printf("Check writable...\n");
1943b64ca396SJohnny Huang 		if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE)
1944b64ca396SJohnny Huang 			ret = -1;
1945030cb4a7SJohnny Huang 	}
1946b25f02d2SJohnny Huang 	if (otp_header->image_info & OTP_INC_SCU_PRO) {
1947b25f02d2SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
1948b25f02d2SJohnny Huang 			printf("OTP strap region is protected\n");
1949b25f02d2SJohnny Huang 			ret = -1;
1950b25f02d2SJohnny Huang 		}
1951b25f02d2SJohnny Huang 		printf("Read SCU Protect Region:\n");
1952b25f02d2SJohnny Huang 		otp_read_conf(28, &scu_pro[0]);
1953b25f02d2SJohnny Huang 		otp_read_conf(29, &scu_pro[1]);
1954b25f02d2SJohnny Huang 
1955b25f02d2SJohnny Huang 		printf("Check writable...\n");
1956b25f02d2SJohnny Huang 		if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE)
1957b25f02d2SJohnny Huang 			ret = -1;
1958b25f02d2SJohnny Huang 	}
1959030cb4a7SJohnny Huang 	if (ret == -1)
1960030cb4a7SJohnny Huang 		return OTP_FAILURE;
1961b64ca396SJohnny Huang 
196269d5fd8fSJohnny Huang 	if (!nconfirm) {
1963696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
19647f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1965f347c284SJohnny Huang 			if (otp_print_data_image(&image_layout) < 0) {
196669d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
19672a856b9aSJohnny Huang 				return OTP_FAILURE;
196869d5fd8fSJohnny Huang 			}
196969d5fd8fSJohnny Huang 		}
1970696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
19717332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1972696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
19737332532cSJohnny Huang 				printf("OTP config error, please check.\n");
19747332532cSJohnny Huang 				return OTP_FAILURE;
19757332532cSJohnny Huang 			}
19767332532cSJohnny Huang 		}
19777adec5f6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
19787adec5f6SJohnny Huang 			printf("\nOTP strap region :\n");
19797adec5f6SJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
19807adec5f6SJohnny Huang 				printf("OTP strap error, please check.\n");
19817adec5f6SJohnny Huang 				return OTP_FAILURE;
19827adec5f6SJohnny Huang 			}
19837adec5f6SJohnny Huang 		}
1984b25f02d2SJohnny Huang 		if (otp_header->image_info & OTP_INC_SCU_PRO) {
1985b25f02d2SJohnny Huang 			printf("\nOTP scu protect region :\n");
1986b25f02d2SJohnny Huang 			if (otp_print_scu_image(&image_layout) < 0) {
1987b25f02d2SJohnny Huang 				printf("OTP scu protect error, please check.\n");
1988b25f02d2SJohnny Huang 				return OTP_FAILURE;
1989b25f02d2SJohnny Huang 			}
1990b25f02d2SJohnny Huang 		}
19917332532cSJohnny Huang 
199269d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
199369d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
199469d5fd8fSJohnny Huang 			printf(" Aborting\n");
19952a856b9aSJohnny Huang 			return OTP_FAILURE;
199669d5fd8fSJohnny Huang 		}
199769d5fd8fSJohnny Huang 	}
19987332532cSJohnny Huang 
19995010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
20005010032bSJohnny Huang 		printf("programing data region ...\n");
2001b64ca396SJohnny Huang 		ret = otp_prog_data(&image_layout, data);
20025010032bSJohnny Huang 		if (ret != 0) {
20035010032bSJohnny Huang 			printf("Error\n");
20045010032bSJohnny Huang 			return ret;
20055010032bSJohnny Huang 		}
2006a219f6deSJohnny Huang 		printf("Done\n");
20075010032bSJohnny Huang 	}
20085010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
20095010032bSJohnny Huang 		printf("programing strap region ...\n");
2010b64ca396SJohnny Huang 		ret = otp_prog_strap(&image_layout, otpstrap);
20115010032bSJohnny Huang 		if (ret != 0) {
20125010032bSJohnny Huang 			printf("Error\n");
20135010032bSJohnny Huang 			return ret;
20145010032bSJohnny Huang 		}
2015a219f6deSJohnny Huang 		printf("Done\n");
20165010032bSJohnny Huang 	}
2017b25f02d2SJohnny Huang 	if (otp_header->image_info & OTP_INC_SCU_PRO) {
2018b25f02d2SJohnny Huang 		printf("programing scu protect region ...\n");
2019b25f02d2SJohnny Huang 		ret = otp_prog_scu_protect(&image_layout, scu_pro);
2020b25f02d2SJohnny Huang 		if (ret != 0) {
2021b25f02d2SJohnny Huang 			printf("Error\n");
2022b25f02d2SJohnny Huang 			return ret;
2023b25f02d2SJohnny Huang 		}
2024b25f02d2SJohnny Huang 		printf("Done\n");
2025b25f02d2SJohnny Huang 	}
20265010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
20275010032bSJohnny Huang 		printf("programing configuration region ...\n");
2028b64ca396SJohnny Huang 		ret = otp_prog_conf(&image_layout, conf);
20295010032bSJohnny Huang 		if (ret != 0) {
20305010032bSJohnny Huang 			printf("Error\n");
20315010032bSJohnny Huang 			return ret;
20325010032bSJohnny Huang 		}
20335010032bSJohnny Huang 		printf("Done\n");
20345010032bSJohnny Huang 	}
2035cd1610b4SJohnny Huang 
20367332532cSJohnny Huang 	return OTP_SUCCESS;
20372a856b9aSJohnny Huang }
20382a856b9aSJohnny Huang 
2039f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
2040cd1610b4SJohnny Huang {
2041a219f6deSJohnny Huang 	u32 read[2];
2042a219f6deSJohnny Huang 	u32 prog_address = 0;
204366f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
2044cd1610b4SJohnny Huang 	int otp_bit;
204583655e91SJohnny Huang 	int ret = 0;
2046cd1610b4SJohnny Huang 
2047dacbba92SJohnny Huang 	otp_soak(0);
2048cd1610b4SJohnny Huang 	switch (mode) {
2049a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
2050f347c284SJohnny Huang 		otp_read_conf(otp_dw_offset, read);
2051cd1610b4SJohnny Huang 		prog_address = 0x800;
2052cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
2053cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
2054a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
2055cd1610b4SJohnny Huang 		if (otp_bit == value) {
2056b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2057cd1610b4SJohnny Huang 			printf("No need to program\n");
20582a856b9aSJohnny Huang 			return OTP_SUCCESS;
2059cd1610b4SJohnny Huang 		}
2060cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
2061b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
20620dc9a440SJohnny Huang 			printf("OTP is programmed, which can't be clean\n");
20632a856b9aSJohnny Huang 			return OTP_FAILURE;
2064cd1610b4SJohnny Huang 		}
2065b489486eSJohnny Huang 		printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2066cd1610b4SJohnny Huang 		break;
2067a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
2068cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
2069cd1610b4SJohnny Huang 
2070cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
2071a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
2072a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
2073643b9cfdSJohnny Huang 
2074643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
2075b489486eSJohnny Huang 				printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2076b64ca396SJohnny Huang 				printf("OTP is programmed, which can't be cleared\n");
2077643b9cfdSJohnny Huang 				return OTP_FAILURE;
2078643b9cfdSJohnny Huang 			}
2079cd1610b4SJohnny Huang 		} else {
2080a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
2081a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
2082643b9cfdSJohnny Huang 
2083643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
2084b489486eSJohnny Huang 				printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2085b64ca396SJohnny Huang 				printf("OTP is programmed, which can't be written\n");
2086643b9cfdSJohnny Huang 				return OTP_FAILURE;
2087643b9cfdSJohnny Huang 			}
2088cd1610b4SJohnny Huang 		}
2089cd1610b4SJohnny Huang 		if (otp_bit == value) {
2090b489486eSJohnny Huang 			printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2091cd1610b4SJohnny Huang 			printf("No need to program\n");
20922a856b9aSJohnny Huang 			return OTP_SUCCESS;
2093cd1610b4SJohnny Huang 		}
2094643b9cfdSJohnny Huang 
2095b489486eSJohnny Huang 		printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2096cd1610b4SJohnny Huang 		break;
2097a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
20988848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
20998848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
21007e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
21018848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
21028848d5dcSJohnny Huang 			return OTP_FAILURE;
21038848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
21048848d5dcSJohnny Huang 			return OTP_SUCCESS;
2105a6af4a17SJohnny Huang 
2106cd1610b4SJohnny Huang 		break;
2107cd1610b4SJohnny Huang 	}
2108cd1610b4SJohnny Huang 
2109cd1610b4SJohnny Huang 	if (!nconfirm) {
2110cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2111cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
2112cd1610b4SJohnny Huang 			printf(" Aborting\n");
21132a856b9aSJohnny Huang 			return OTP_FAILURE;
2114cd1610b4SJohnny Huang 		}
2115cd1610b4SJohnny Huang 	}
2116cd1610b4SJohnny Huang 
2117cd1610b4SJohnny Huang 	switch (mode) {
2118a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
2119f347c284SJohnny Huang 		ret =  otp_prog_strap_b(bit_offset, value);
212083655e91SJohnny Huang 		break;
2121a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
2122a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
2123f347c284SJohnny Huang 		ret = otp_prog_dc_b(value, prog_address, bit_offset);
2124de6fbf1cSJohnny Huang 		break;
2125de6fbf1cSJohnny Huang 	}
2126de6fbf1cSJohnny Huang 	otp_soak(0);
212783655e91SJohnny Huang 	if (ret) {
21280dc9a440SJohnny Huang 		printf("OTP cannot be programmed\n");
2129794e27ecSJohnny Huang 		printf("FAILURE\n");
2130794e27ecSJohnny Huang 		return OTP_FAILURE;
2131794e27ecSJohnny Huang 	}
2132794e27ecSJohnny Huang 
21339009c25dSJohnny Huang 	printf("SUCCESS\n");
21342a856b9aSJohnny Huang 	return OTP_SUCCESS;
2135a219f6deSJohnny Huang }
2136a219f6deSJohnny Huang 
2137794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
2138794e27ecSJohnny Huang {
2139794e27ecSJohnny Huang 	u32 otp_rid[2];
2140a8789b47SJohnny Huang 	u32 sw_rid[2];
2141794e27ecSJohnny Huang 	int rid_num = 0;
2142a8789b47SJohnny Huang 	int sw_rid_num = 0;
2143794e27ecSJohnny Huang 	int bit_offset;
2144794e27ecSJohnny Huang 	int dw_offset;
2145794e27ecSJohnny Huang 	int i;
2146794e27ecSJohnny Huang 	int ret;
2147794e27ecSJohnny Huang 
2148f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2149f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2150794e27ecSJohnny Huang 
2151a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2152a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2153a8789b47SJohnny Huang 
2154794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2155a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2156a8789b47SJohnny Huang 
2157a8789b47SJohnny Huang 	if (sw_rid_num < 0) {
2158a8789b47SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
2159a8789b47SJohnny Huang 		return OTP_FAILURE;
2160a8789b47SJohnny Huang 	}
2161a8789b47SJohnny Huang 
2162a8789b47SJohnny Huang 	if (update_num > sw_rid_num) {
2163a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
2164a8789b47SJohnny Huang 		printf("update number could not bigger than current SW revision id\n");
2165a8789b47SJohnny Huang 		return OTP_FAILURE;
2166a8789b47SJohnny Huang 	}
2167794e27ecSJohnny Huang 
2168794e27ecSJohnny Huang 	if (rid_num < 0) {
2169b64ca396SJohnny Huang 		printf("Current OTP revision ID cannot handle by this command,\n"
2170b64ca396SJohnny Huang 		       "please use 'otp pb' command to update it manually\n");
2171794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
21729009c25dSJohnny Huang 		return OTP_FAILURE;
21739009c25dSJohnny Huang 	}
2174cd1610b4SJohnny Huang 
2175794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
2176794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2177794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
2178794e27ecSJohnny Huang 
2179a8789b47SJohnny Huang 	if (rid_num > update_num) {
2180a8789b47SJohnny Huang 		printf("OTP rev_id is bigger than 0x%X\n", update_num);
2181a8789b47SJohnny Huang 		printf("Skip\n");
2182a8789b47SJohnny Huang 		return OTP_FAILURE;
2183a8789b47SJohnny Huang 	} else if (rid_num == update_num) {
2184a8789b47SJohnny Huang 		printf("OTP rev_id is same as input\n");
2185794e27ecSJohnny Huang 		printf("Skip\n");
2186794e27ecSJohnny Huang 		return OTP_FAILURE;
2187794e27ecSJohnny Huang 	}
2188794e27ecSJohnny Huang 
2189794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
2190794e27ecSJohnny Huang 		if (i < 32) {
2191794e27ecSJohnny Huang 			dw_offset = 0xa;
2192794e27ecSJohnny Huang 			bit_offset = i;
2193794e27ecSJohnny Huang 		} else {
2194794e27ecSJohnny Huang 			dw_offset = 0xb;
2195794e27ecSJohnny Huang 			bit_offset = i - 32;
2196794e27ecSJohnny Huang 		}
2197b489486eSJohnny Huang 		printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset);
2198794e27ecSJohnny Huang 		if (i + 1 != update_num)
2199794e27ecSJohnny Huang 			printf(", ");
2200794e27ecSJohnny Huang 	}
2201794e27ecSJohnny Huang 
2202794e27ecSJohnny Huang 	printf(" will be programmed\n");
2203794e27ecSJohnny Huang 	if (force == 0) {
2204794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2205794e27ecSJohnny Huang 		if (!confirm_yesno()) {
2206794e27ecSJohnny Huang 			printf(" Aborting\n");
2207794e27ecSJohnny Huang 			return OTP_FAILURE;
2208794e27ecSJohnny Huang 		}
2209794e27ecSJohnny Huang 	}
2210794e27ecSJohnny Huang 
2211794e27ecSJohnny Huang 	ret = 0;
2212794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
2213794e27ecSJohnny Huang 		if (i < 32) {
2214794e27ecSJohnny Huang 			dw_offset = 0xa04;
2215794e27ecSJohnny Huang 			bit_offset = i;
2216794e27ecSJohnny Huang 		} else {
2217794e27ecSJohnny Huang 			dw_offset = 0xa06;
2218794e27ecSJohnny Huang 			bit_offset = i - 32;
2219794e27ecSJohnny Huang 		}
2220f347c284SJohnny Huang 		if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
2221b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset);
2222794e27ecSJohnny Huang 			ret = OTP_FAILURE;
2223794e27ecSJohnny Huang 			break;
2224794e27ecSJohnny Huang 		}
2225794e27ecSJohnny Huang 	}
2226061d3279SJohnny Huang 	otp_soak(0);
2227f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2228f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2229794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2230794e27ecSJohnny Huang 	if (rid_num >= 0)
2231794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
2232794e27ecSJohnny Huang 	else
2233794e27ecSJohnny Huang 		printf("OTP revision ID\n");
2234794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2235794e27ecSJohnny Huang 	if (!ret)
2236794e27ecSJohnny Huang 		printf("SUCCESS\n");
2237794e27ecSJohnny Huang 	else
2238794e27ecSJohnny Huang 		printf("FAILED\n");
2239794e27ecSJohnny Huang 	return ret;
2240794e27ecSJohnny Huang }
2241794e27ecSJohnny Huang 
2242883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force)
2243883625c5SJohnny Huang {
2244883625c5SJohnny Huang 	u32 otpcfg4;
2245883625c5SJohnny Huang 	u32 krb;
2246883625c5SJohnny Huang 	u32 krb_b;
2247883625c5SJohnny Huang 	u32 krb_or;
2248883625c5SJohnny Huang 	u32 current_id;
2249883625c5SJohnny Huang 
2250883625c5SJohnny Huang 	otp_read_conf(4, &otpcfg4);
2251883625c5SJohnny Huang 	current_id = readl(SEC_KEY_NUM) & 7;
2252883625c5SJohnny Huang 	krb = otpcfg4 & 0xff;
2253883625c5SJohnny Huang 	krb_b = (otpcfg4 >> 16) & 0xff;
2254883625c5SJohnny Huang 	krb_or = krb | krb_b;
2255883625c5SJohnny Huang 
2256883625c5SJohnny Huang 	printf("current Key ID: 0x%x\n", current_id);
2257883625c5SJohnny Huang 	printf("input retire ID: 0x%x\n", retire_id);
2258883625c5SJohnny Huang 	printf("OTPCFG0x4 = 0x%X\n", otpcfg4);
2259883625c5SJohnny Huang 
2260883625c5SJohnny Huang 	if (info_cb.pro_sts.pro_key_ret) {
2261883625c5SJohnny Huang 		printf("OTPCFG4 is protected\n");
2262883625c5SJohnny Huang 		return OTP_FAILURE;
2263883625c5SJohnny Huang 	}
2264883625c5SJohnny Huang 
2265883625c5SJohnny Huang 	if (retire_id >= current_id) {
2266883625c5SJohnny Huang 		printf("Retire key id is equal or bigger than current boot key\n");
2267883625c5SJohnny Huang 		return OTP_FAILURE;
2268883625c5SJohnny Huang 	}
2269883625c5SJohnny Huang 
2270883625c5SJohnny Huang 	if (krb_or & (1 << retire_id)) {
2271883625c5SJohnny Huang 		printf("Key 0x%X already retired\n", retire_id);
2272883625c5SJohnny Huang 		return OTP_SUCCESS;
2273883625c5SJohnny Huang 	}
2274883625c5SJohnny Huang 
2275883625c5SJohnny Huang 	printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id);
2276883625c5SJohnny Huang 	if (force == 0) {
2277883625c5SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2278883625c5SJohnny Huang 		if (!confirm_yesno()) {
2279883625c5SJohnny Huang 			printf(" Aborting\n");
2280883625c5SJohnny Huang 			return OTP_FAILURE;
2281883625c5SJohnny Huang 		}
2282883625c5SJohnny Huang 	}
2283883625c5SJohnny Huang 
2284883625c5SJohnny Huang 	if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) {
2285883625c5SJohnny Huang 		printf("OTPCFG0x4[0x%X] programming failed\n", retire_id);
2286883625c5SJohnny Huang 		printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16);
2287883625c5SJohnny Huang 		if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE)
2288883625c5SJohnny Huang 			printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16);
2289883625c5SJohnny Huang 	}
2290883625c5SJohnny Huang 
2291883625c5SJohnny Huang 	otp_soak(0);
2292883625c5SJohnny Huang 	otp_read_conf(4, &otpcfg4);
2293883625c5SJohnny Huang 	krb = otpcfg4 & 0xff;
2294883625c5SJohnny Huang 	krb_b = (otpcfg4 >> 16) & 0xff;
2295883625c5SJohnny Huang 	krb_or = krb | krb_b;
2296883625c5SJohnny Huang 	if (krb_or & (1 << retire_id)) {
2297883625c5SJohnny Huang 		printf("SUCCESS\n");
2298883625c5SJohnny Huang 		return OTP_SUCCESS;
2299883625c5SJohnny Huang 	}
2300883625c5SJohnny Huang 	printf("FAILED\n");
2301883625c5SJohnny Huang 	return OTP_FAILURE;
2302883625c5SJohnny Huang }
2303883625c5SJohnny Huang 
23042a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
230569d5fd8fSJohnny Huang {
2306a219f6deSJohnny Huang 	u32 offset, count;
23072a856b9aSJohnny Huang 	int ret;
230869d5fd8fSJohnny Huang 
23092a856b9aSJohnny Huang 	if (argc == 4) {
23102a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
23112a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
23122a856b9aSJohnny Huang 	} else if (argc == 3) {
23132a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
23142a856b9aSJohnny Huang 		count = 1;
23152a856b9aSJohnny Huang 	} else {
231669d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
231769d5fd8fSJohnny Huang 	}
231869d5fd8fSJohnny Huang 
2319030cb4a7SJohnny Huang 	if (!strcmp(argv[1], "conf"))
2320f347c284SJohnny Huang 		ret = otp_print_conf(offset, count);
2321030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "data"))
23222a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
2323030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "strap"))
23242a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
2325030cb4a7SJohnny Huang 	else
23262a856b9aSJohnny Huang 		return CMD_RET_USAGE;
232769d5fd8fSJohnny Huang 
23282a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
23292a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
23302a856b9aSJohnny Huang 	return CMD_RET_USAGE;
23312a856b9aSJohnny Huang }
23322a856b9aSJohnny Huang 
23332a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
23342a856b9aSJohnny Huang {
23352a856b9aSJohnny Huang 	phys_addr_t addr;
23362a856b9aSJohnny Huang 	int ret;
23372a856b9aSJohnny Huang 
2338de6b0cc4SJohnny Huang 	if (argc == 3) {
2339ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
23402a856b9aSJohnny Huang 			return CMD_RET_USAGE;
23412a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
2342f347c284SJohnny Huang 		ret = otp_prog_image(addr, 1);
2343de6b0cc4SJohnny Huang 	} else if (argc == 2) {
23442a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
2345f347c284SJohnny Huang 		ret = otp_prog_image(addr, 0);
23462a856b9aSJohnny Huang 	} else {
23472a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23482a856b9aSJohnny Huang 	}
23492a856b9aSJohnny Huang 
23502a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
23512a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
23522a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
23532a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
23542a856b9aSJohnny Huang 	else
23552a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23562a856b9aSJohnny Huang }
23572a856b9aSJohnny Huang 
23582a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
23592a856b9aSJohnny Huang {
23602a856b9aSJohnny Huang 	int mode = 0;
23612a856b9aSJohnny Huang 	int nconfirm = 0;
23622a856b9aSJohnny Huang 	int otp_addr = 0;
23632a856b9aSJohnny Huang 	int bit_offset;
23642a856b9aSJohnny Huang 	int value;
23652a856b9aSJohnny Huang 	int ret;
2366030cb4a7SJohnny Huang 	u32 otp_strap_pro;
23672a856b9aSJohnny Huang 
23682a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
23692a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23702a856b9aSJohnny Huang 
23712a856b9aSJohnny Huang 	/* Drop the pb cmd */
23722a856b9aSJohnny Huang 	argc--;
23732a856b9aSJohnny Huang 	argv++;
23742a856b9aSJohnny Huang 
23752a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2376a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
23772a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2378a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
23792a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2380a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2381cd1610b4SJohnny Huang 	else
23822a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23832a856b9aSJohnny Huang 
23842a856b9aSJohnny Huang 	/* Drop the region cmd */
23852a856b9aSJohnny Huang 	argc--;
23862a856b9aSJohnny Huang 	argv++;
23872a856b9aSJohnny Huang 
2388ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2389cd1610b4SJohnny Huang 		nconfirm = 1;
23902a856b9aSJohnny Huang 		/* Drop the force option */
23912a856b9aSJohnny Huang 		argc--;
23922a856b9aSJohnny Huang 		argv++;
23932a856b9aSJohnny Huang 	}
2394cd1610b4SJohnny Huang 
2395a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
23962a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
23972a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
23980808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
23992a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2400cd1610b4SJohnny Huang 	} else {
24012a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
24022a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
24032a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
24040808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
24052a856b9aSJohnny Huang 			return CMD_RET_USAGE;
24060808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
240778855207SJohnny Huang 			if (otp_addr >= 0x800)
24080808cc55SJohnny Huang 				return CMD_RET_USAGE;
24090808cc55SJohnny Huang 		} else {
241078855207SJohnny Huang 			if (otp_addr >= 0x20)
24110808cc55SJohnny Huang 				return CMD_RET_USAGE;
24120808cc55SJohnny Huang 		}
2413cd1610b4SJohnny Huang 	}
2414cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
24152a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2416cd1610b4SJohnny Huang 
2417030cb4a7SJohnny Huang 	ret = 0;
2418030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
2419030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
2420030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2421030cb4a7SJohnny Huang 	}
2422030cb4a7SJohnny Huang 	if (mode == OTP_REGION_DATA) {
2423030cb4a7SJohnny Huang 		if (info_cb.pro_sts.sec_size == 0) {
2424030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_data) {
2425030cb4a7SJohnny Huang 				printf("OTP data region is protected\n");
2426030cb4a7SJohnny Huang 				ret = -1;
2427030cb4a7SJohnny Huang 			}
2428030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) {
2429030cb4a7SJohnny Huang 			printf("OTP secure region is not readable, skip it to prevent unpredictable result\n");
2430030cb4a7SJohnny Huang 			ret = -1;
2431030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size) {
2432030cb4a7SJohnny Huang 			// header region(0x0~0x40) is still readable even secure region is set.
2433030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_sec) {
2434030cb4a7SJohnny Huang 				printf("OTP secure region is protected\n");
2435030cb4a7SJohnny Huang 				ret = -1;
2436030cb4a7SJohnny Huang 			}
2437030cb4a7SJohnny Huang 		} else if (info_cb.pro_sts.pro_data) {
2438030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
2439030cb4a7SJohnny Huang 			ret = -1;
2440030cb4a7SJohnny Huang 		}
2441030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_CONF) {
2442030cb4a7SJohnny Huang 		if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) {
2443030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_conf) {
2444030cb4a7SJohnny Huang 				printf("OTP config region is protected\n");
2445030cb4a7SJohnny Huang 				ret = -1;
2446030cb4a7SJohnny Huang 			}
2447030cb4a7SJohnny Huang 		} else if (otp_addr == 10 || otp_addr == 11) {
2448030cb4a7SJohnny Huang 			u32 otp_rid[2];
2449030cb4a7SJohnny Huang 			u32 sw_rid[2];
2450030cb4a7SJohnny Huang 			u64 *otp_rid64 = (u64 *)otp_rid;
2451030cb4a7SJohnny Huang 			u64 *sw_rid64 = (u64 *)sw_rid;
2452030cb4a7SJohnny Huang 
2453030cb4a7SJohnny Huang 			otp_read_conf(10, &otp_rid[0]);
2454030cb4a7SJohnny Huang 			otp_read_conf(11, &otp_rid[1]);
2455030cb4a7SJohnny Huang 			sw_rid[0] = readl(SW_REV_ID0);
2456030cb4a7SJohnny Huang 			sw_rid[1] = readl(SW_REV_ID1);
2457030cb4a7SJohnny Huang 
2458030cb4a7SJohnny Huang 			if (otp_addr == 10)
2459030cb4a7SJohnny Huang 				otp_rid[0] |= 1 << bit_offset;
2460030cb4a7SJohnny Huang 			else
2461030cb4a7SJohnny Huang 				otp_rid[1] |= 1 << bit_offset;
2462030cb4a7SJohnny Huang 
2463030cb4a7SJohnny Huang 			if (*otp_rid64 > *sw_rid64) {
2464030cb4a7SJohnny Huang 				printf("update number could not bigger than current SW revision id\n");
2465030cb4a7SJohnny Huang 				ret = -1;
2466030cb4a7SJohnny Huang 			}
2467030cb4a7SJohnny Huang 		} else if (otp_addr == 4) {
2468030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_key_ret) {
2469030cb4a7SJohnny Huang 				printf("OTPCFG4 is protected\n");
2470030cb4a7SJohnny Huang 				ret = -1;
2471030cb4a7SJohnny Huang 			} else {
2472030cb4a7SJohnny Huang 				if ((bit_offset >= 0 && bit_offset <= 7) ||
2473030cb4a7SJohnny Huang 				    (bit_offset >= 16 && bit_offset <= 23)) {
2474030cb4a7SJohnny Huang 					u32 key_num;
2475030cb4a7SJohnny Huang 					u32 retire;
2476030cb4a7SJohnny Huang 
2477030cb4a7SJohnny Huang 					key_num = readl(SEC_KEY_NUM) & 3;
2478030cb4a7SJohnny Huang 					if (bit_offset >= 16)
2479030cb4a7SJohnny Huang 						retire = bit_offset - 16;
2480030cb4a7SJohnny Huang 					else
2481030cb4a7SJohnny Huang 						retire = bit_offset;
2482030cb4a7SJohnny Huang 					if (retire >= key_num) {
2483030cb4a7SJohnny Huang 						printf("Retire key id is equal or bigger than current boot key\n");
2484030cb4a7SJohnny Huang 						ret = -1;
2485030cb4a7SJohnny Huang 					}
2486030cb4a7SJohnny Huang 				}
2487030cb4a7SJohnny Huang 			}
2488030cb4a7SJohnny Huang 		} else if (otp_addr >= 16 && otp_addr <= 31) {
2489030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_strap) {
2490030cb4a7SJohnny Huang 				printf("OTP strap region is protected\n");
2491030cb4a7SJohnny Huang 				ret = -1;
2492030cb4a7SJohnny Huang 			} else if ((otp_addr < 30 && info_cb.version == OTP_A0) ||
2493030cb4a7SJohnny Huang 				   (otp_addr < 28 && info_cb.version != OTP_A0)) {
2494030cb4a7SJohnny Huang 				if (otp_addr % 2 == 0)
2495030cb4a7SJohnny Huang 					otp_read_conf(30, &otp_strap_pro);
2496030cb4a7SJohnny Huang 				else
2497030cb4a7SJohnny Huang 					otp_read_conf(31, &otp_strap_pro);
2498030cb4a7SJohnny Huang 				if (otp_strap_pro >> bit_offset & 0x1) {
2499b489486eSJohnny Huang 					printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset);
2500030cb4a7SJohnny Huang 					ret = -1;
2501030cb4a7SJohnny Huang 				}
2502030cb4a7SJohnny Huang 			}
2503030cb4a7SJohnny Huang 		}
2504030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_STRAP) {
2505030cb4a7SJohnny Huang 		// per bit protection will check in otp_strap_bit_confirm
2506030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
2507030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
2508030cb4a7SJohnny Huang 			ret = -1;
2509030cb4a7SJohnny Huang 		}
2510030cb4a7SJohnny Huang 	}
2511030cb4a7SJohnny Huang 
2512030cb4a7SJohnny Huang 	if (ret == -1)
2513030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2514030cb4a7SJohnny Huang 
2515f347c284SJohnny Huang 	ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
25162a856b9aSJohnny Huang 
25172a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
25182a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
25192a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
25202a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
25212a856b9aSJohnny Huang 	else
25222a856b9aSJohnny Huang 		return CMD_RET_USAGE;
25232a856b9aSJohnny Huang }
25242a856b9aSJohnny Huang 
25252a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
25262a856b9aSJohnny Huang {
25272a856b9aSJohnny Huang 	phys_addr_t addr;
25282a856b9aSJohnny Huang 	int otp_addr = 0;
2529b8590031SJohnny Huang 	int ret;
25302a856b9aSJohnny Huang 
25312a856b9aSJohnny Huang 	if (argc != 3)
25322a856b9aSJohnny Huang 		return CMD_RET_USAGE;
25332a856b9aSJohnny Huang 
25342a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
25352a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
2536b8590031SJohnny Huang 	ret = otp_compare(otp_addr, addr);
2537b8590031SJohnny Huang 	if (ret == 0) {
253869d5fd8fSJohnny Huang 		printf("Compare pass\n");
25392a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2540a219f6deSJohnny Huang 	}
254169d5fd8fSJohnny Huang 	printf("Compare fail\n");
25422a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
254369d5fd8fSJohnny Huang }
254469d5fd8fSJohnny Huang 
254566f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
254666f2f8e5SJohnny Huang {
2547a8bd6d8cSJohnny Huang 	int view = 0;
25482d4b0742SJohnny Huang 	int input;
2549a8bd6d8cSJohnny Huang 
2550a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
255166f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
255266f2f8e5SJohnny Huang 
25532d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
25542d4b0742SJohnny Huang 		if (argc == 3) {
25552d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
25562d4b0742SJohnny Huang 			otp_print_conf_info(input);
25572d4b0742SJohnny Huang 		} else {
25582d4b0742SJohnny Huang 			otp_print_conf_info(-1);
25592d4b0742SJohnny Huang 		}
25602d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
25612d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2562a8bd6d8cSJohnny Huang 			view = 1;
2563a8bd6d8cSJohnny Huang 			/* Drop the view option */
2564a8bd6d8cSJohnny Huang 			argc--;
2565a8bd6d8cSJohnny Huang 			argv++;
2566a8bd6d8cSJohnny Huang 		}
2567b458cd62SJohnny Huang 		otp_print_strap_info(view);
25680dc9a440SJohnny Huang 	} else if (!strcmp(argv[1], "scu")) {
25690dc9a440SJohnny Huang 		otp_print_scu_info();
257088bd7d58SJohnny Huang 	} else if (!strcmp(argv[1], "key")) {
257188bd7d58SJohnny Huang 		otp_print_key_info();
257266f2f8e5SJohnny Huang 	} else {
257366f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
257466f2f8e5SJohnny Huang 	}
25752d4b0742SJohnny Huang 
257666f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
257766f2f8e5SJohnny Huang }
257866f2f8e5SJohnny Huang 
25790dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2580737ed20bSJohnny Huang {
25810dc9a440SJohnny Huang 	u32 input;
25820dc9a440SJohnny Huang 	u32 bit_offset;
2583e14b073cSJohnny Huang 	u32 prog_address;
2584030cb4a7SJohnny Huang 	char force;
258583655e91SJohnny Huang 	int ret;
2586a219f6deSJohnny Huang 
2587737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2588737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2589737ed20bSJohnny Huang 
2590e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2591737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2592030cb4a7SJohnny Huang 		force = 1;
2593737ed20bSJohnny Huang 	} else {
2594737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2595030cb4a7SJohnny Huang 		force = 0;
2596737ed20bSJohnny Huang 	}
2597737ed20bSJohnny Huang 
2598737ed20bSJohnny Huang 	if (input < 32) {
2599737ed20bSJohnny Huang 		bit_offset = input;
26000dc9a440SJohnny Huang 		prog_address = 0xe0c;
2601737ed20bSJohnny Huang 	} else if (input < 64) {
2602737ed20bSJohnny Huang 		bit_offset = input - 32;
26030dc9a440SJohnny Huang 		prog_address = 0xe0e;
2604737ed20bSJohnny Huang 	} else {
2605737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2606737ed20bSJohnny Huang 	}
2607737ed20bSJohnny Huang 
2608030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
2609030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
2610030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2611030cb4a7SJohnny Huang 	}
2612030cb4a7SJohnny Huang 
2613030cb4a7SJohnny Huang 	if (!force) {
2614b489486eSJohnny Huang 		printf("OTPSTRAP[0x%X] will be protected\n", input);
2615030cb4a7SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2616030cb4a7SJohnny Huang 		if (!confirm_yesno()) {
2617030cb4a7SJohnny Huang 			printf(" Aborting\n");
2618030cb4a7SJohnny Huang 			return CMD_RET_FAILURE;
2619030cb4a7SJohnny Huang 		}
2620030cb4a7SJohnny Huang 	}
2621030cb4a7SJohnny Huang 
2622e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2623b489486eSJohnny Huang 		printf("OTPSTRAP[0x%X] already protected\n", input);
2624e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2625e14b073cSJohnny Huang 	}
2626de6fbf1cSJohnny Huang 
2627f347c284SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
2628de6fbf1cSJohnny Huang 	otp_soak(0);
262983655e91SJohnny Huang 
263083655e91SJohnny Huang 	if (ret) {
2631b489486eSJohnny Huang 		printf("Protect OTPSTRAP[0x%X] fail\n", input);
2632737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2633737ed20bSJohnny Huang 	}
26349a4fe690SJohnny Huang 
2635b489486eSJohnny Huang 	printf("OTPSTRAP[0x%X] is protected\n", input);
2636794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2637794e27ecSJohnny Huang }
2638794e27ecSJohnny Huang 
26390dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2640e14b073cSJohnny Huang {
26410dc9a440SJohnny Huang 	u32 scu_offset;
26420dc9a440SJohnny Huang 	u32 bit_offset;
26430dc9a440SJohnny Huang 	u32 conf_offset;
26440dc9a440SJohnny Huang 	u32 prog_address;
26450dc9a440SJohnny Huang 	char force;
26460dc9a440SJohnny Huang 	int ret;
26470dc9a440SJohnny Huang 
26480dc9a440SJohnny Huang 	if (argc != 4 && argc != 3)
26490dc9a440SJohnny Huang 		return CMD_RET_USAGE;
26500dc9a440SJohnny Huang 
26510dc9a440SJohnny Huang 	if (!strcmp(argv[1], "o")) {
26520dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[2], NULL, 16);
26530dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[3], NULL, 16);
26540dc9a440SJohnny Huang 		force = 1;
26550dc9a440SJohnny Huang 	} else {
26560dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[1], NULL, 16);
26570dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[2], NULL, 16);
26580dc9a440SJohnny Huang 		force = 0;
26590dc9a440SJohnny Huang 	}
26600dc9a440SJohnny Huang 	if (scu_offset == 0x500) {
26610dc9a440SJohnny Huang 		prog_address = 0xe08;
26620dc9a440SJohnny Huang 		conf_offset = 28;
26630dc9a440SJohnny Huang 	} else if (scu_offset == 0x510) {
26640dc9a440SJohnny Huang 		prog_address = 0xe0a;
26650dc9a440SJohnny Huang 		conf_offset = 29;
26660dc9a440SJohnny Huang 	} else {
26670dc9a440SJohnny Huang 		return CMD_RET_USAGE;
26680dc9a440SJohnny Huang 	}
26690dc9a440SJohnny Huang 	if (bit_offset < 0 || bit_offset > 31)
26700dc9a440SJohnny Huang 		return CMD_RET_USAGE;
2671030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
2672030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
2673030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2674030cb4a7SJohnny Huang 	}
26750dc9a440SJohnny Huang 	if (!force) {
2676b489486eSJohnny Huang 		printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset);
2677b489486eSJohnny Huang 		printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset);
26780dc9a440SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
26790dc9a440SJohnny Huang 		if (!confirm_yesno()) {
26800dc9a440SJohnny Huang 			printf(" Aborting\n");
26810dc9a440SJohnny Huang 			return CMD_RET_FAILURE;
26820dc9a440SJohnny Huang 		}
2683e14b073cSJohnny Huang 	}
2684e14b073cSJohnny Huang 
26850dc9a440SJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2686b489486eSJohnny Huang 		printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset);
26870dc9a440SJohnny Huang 		return CMD_RET_SUCCESS;
26880dc9a440SJohnny Huang 	}
26890dc9a440SJohnny Huang 
26900dc9a440SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
26910dc9a440SJohnny Huang 	otp_soak(0);
26920dc9a440SJohnny Huang 
26930dc9a440SJohnny Huang 	if (ret) {
2694b489486eSJohnny Huang 		printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset);
26950dc9a440SJohnny Huang 		return CMD_RET_FAILURE;
26960dc9a440SJohnny Huang 	}
26970dc9a440SJohnny Huang 
2698b489486eSJohnny Huang 	printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset);
26990dc9a440SJohnny Huang 	return CMD_RET_SUCCESS;
2700e14b073cSJohnny Huang }
2701e14b073cSJohnny Huang 
2702f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2703f67375f7SJohnny Huang {
2704e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
2705f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2706f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2707f67375f7SJohnny Huang 
2708f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2709f67375f7SJohnny Huang }
2710f67375f7SJohnny Huang 
2711794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2712794e27ecSJohnny Huang {
2713794e27ecSJohnny Huang 	u32 update_num;
2714794e27ecSJohnny Huang 	int force = 0;
2715794e27ecSJohnny Huang 	int ret;
2716794e27ecSJohnny Huang 
2717794e27ecSJohnny Huang 	if (argc == 3) {
2718794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2719794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2720794e27ecSJohnny Huang 		force = 1;
2721794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2722794e27ecSJohnny Huang 	} else if (argc == 2) {
2723794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2724794e27ecSJohnny Huang 	} else {
2725794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2726794e27ecSJohnny Huang 	}
2727794e27ecSJohnny Huang 
2728794e27ecSJohnny Huang 	if (update_num > 64)
2729794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2730794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2731b8590031SJohnny Huang 
2732794e27ecSJohnny Huang 	if (ret)
2733794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2734794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2735794e27ecSJohnny Huang }
2736794e27ecSJohnny Huang 
2737794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2738794e27ecSJohnny Huang {
2739794e27ecSJohnny Huang 	u32 otp_rid[2];
2740a8789b47SJohnny Huang 	u32 sw_rid[2];
2741794e27ecSJohnny Huang 	int rid_num = 0;
2742a8789b47SJohnny Huang 	int sw_rid_num = 0;
2743794e27ecSJohnny Huang 	int ret;
2744794e27ecSJohnny Huang 
2745794e27ecSJohnny Huang 	if (argc != 1)
2746794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2747794e27ecSJohnny Huang 
2748f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2749f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2750794e27ecSJohnny Huang 
2751a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2752a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2753794e27ecSJohnny Huang 
2754a8789b47SJohnny Huang 	rid_num = get_rid_num(otp_rid);
2755a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2756a8789b47SJohnny Huang 
2757030cb4a7SJohnny Huang 	if (sw_rid_num < 0) {
2758030cb4a7SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
2759030cb4a7SJohnny Huang 		printf("SEC68:0x%x\n", sw_rid[0]);
2760030cb4a7SJohnny Huang 		printf("SEC6C:0x%x\n", sw_rid[1]);
2761030cb4a7SJohnny Huang 	} else {
2762a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
2763030cb4a7SJohnny Huang 	}
2764794e27ecSJohnny Huang 	if (rid_num >= 0) {
2765794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2766794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2767794e27ecSJohnny Huang 	} else {
2768b64ca396SJohnny Huang 		printf("Current OTP revision ID cannot handle by 'otp update',\n"
2769b64ca396SJohnny Huang 		       "please use 'otp pb' command to update it manually\n"
2770794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2771794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2772794e27ecSJohnny Huang 	}
2773794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2774794e27ecSJohnny Huang 
2775794e27ecSJohnny Huang 	return ret;
2776794e27ecSJohnny Huang }
2777794e27ecSJohnny Huang 
2778883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2779883625c5SJohnny Huang {
2780883625c5SJohnny Huang 	u32 retire_id;
2781883625c5SJohnny Huang 	int force = 0;
2782883625c5SJohnny Huang 	int ret;
2783883625c5SJohnny Huang 
2784883625c5SJohnny Huang 	if (argc == 3) {
2785883625c5SJohnny Huang 		if (strcmp(argv[1], "o"))
2786883625c5SJohnny Huang 			return CMD_RET_USAGE;
2787883625c5SJohnny Huang 		force = 1;
2788883625c5SJohnny Huang 		retire_id = simple_strtoul(argv[2], NULL, 16);
2789883625c5SJohnny Huang 	} else if (argc == 2) {
2790883625c5SJohnny Huang 		retire_id = simple_strtoul(argv[1], NULL, 16);
2791883625c5SJohnny Huang 	} else {
2792883625c5SJohnny Huang 		return CMD_RET_USAGE;
2793883625c5SJohnny Huang 	}
2794883625c5SJohnny Huang 
2795883625c5SJohnny Huang 	if (retire_id > 7)
2796883625c5SJohnny Huang 		return CMD_RET_USAGE;
2797883625c5SJohnny Huang 	ret = otp_retire_key(retire_id, force);
2798883625c5SJohnny Huang 
2799883625c5SJohnny Huang 	if (ret)
2800883625c5SJohnny Huang 		return CMD_RET_FAILURE;
2801883625c5SJohnny Huang 	return CMD_RET_SUCCESS;
2802883625c5SJohnny Huang }
2803883625c5SJohnny Huang 
28042a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2805f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
28062a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2807a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2808de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
28092a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2810737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
28110dc9a440SJohnny Huang 	U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""),
28122a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2813794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2814794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
2815883625c5SJohnny Huang 	U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""),
28162a856b9aSJohnny Huang };
28172a856b9aSJohnny Huang 
28182a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
28192a856b9aSJohnny Huang {
2820030cb4a7SJohnny Huang 	struct otp_pro_sts *pro_sts;
28212a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2822a219f6deSJohnny Huang 	u32 ver;
2823e14b073cSJohnny Huang 	int ret;
2824030cb4a7SJohnny Huang 	u32 otp_conf0;
28252a856b9aSJohnny Huang 
28262a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
28272a856b9aSJohnny Huang 
2828737ed20bSJohnny Huang 	/* Drop the otp command */
28292a856b9aSJohnny Huang 	argc--;
28302a856b9aSJohnny Huang 	argv++;
28312a856b9aSJohnny Huang 
2832a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
28332a856b9aSJohnny Huang 		return CMD_RET_USAGE;
28342a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
28352a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
28362a856b9aSJohnny Huang 
28370dae9d52SJohnny Huang 	ver = chip_version();
28380dae9d52SJohnny Huang 	switch (ver) {
2839e417205bSJohnny Huang 	case OTP_A0:
2840e417205bSJohnny Huang 		info_cb.version = OTP_A0;
28419a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
28429a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
28439a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
28449a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
28459a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
28469a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2847e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
28480dae9d52SJohnny Huang 		break;
2849e417205bSJohnny Huang 	case OTP_A1:
2850e417205bSJohnny Huang 		info_cb.version = OTP_A1;
28513cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
28523cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
28533cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
28543cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
28559a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
28569a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
28570dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
28580dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2859e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
28600dae9d52SJohnny Huang 		break;
2861e417205bSJohnny Huang 	case OTP_A2:
2862e417205bSJohnny Huang 		info_cb.version = OTP_A2;
28635fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
28645fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
2865fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2866fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
28675fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
28685fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
28690dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
28700dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2871e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
28720dae9d52SJohnny Huang 		break;
2873e417205bSJohnny Huang 	case OTP_A3:
2874e417205bSJohnny Huang 		info_cb.version = OTP_A3;
2875b63af886SJohnny Huang 		info_cb.conf_info = a3_conf_info;
2876b63af886SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
2877fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2878fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
2879181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2880181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
28810dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
28820dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2883e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
288464b66712SJohnny Huang 		break;
28850dae9d52SJohnny Huang 	default:
2886f1be5099SJohnny Huang 		printf("SOC is not supported\n");
28870dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
28889a4fe690SJohnny Huang 	}
28899a4fe690SJohnny Huang 
2890030cb4a7SJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2891030cb4a7SJohnny Huang 	otp_read_conf(0, &otp_conf0);
2892030cb4a7SJohnny Huang 	pro_sts = &info_cb.pro_sts;
2893030cb4a7SJohnny Huang 
2894030cb4a7SJohnny Huang 	pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1;
2895030cb4a7SJohnny Huang 	pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1;
2896030cb4a7SJohnny Huang 	pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1;
2897030cb4a7SJohnny Huang 	pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1;
2898030cb4a7SJohnny Huang 	pro_sts->pro_data = (otp_conf0 >> 23) & 0x1;
2899030cb4a7SJohnny Huang 	pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1;
2900030cb4a7SJohnny Huang 	pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5;
2901030cb4a7SJohnny Huang 
2902e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2903b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
2904e14b073cSJohnny Huang 
2905e14b073cSJohnny Huang 	return ret;
290669d5fd8fSJohnny Huang }
290769d5fd8fSJohnny Huang 
2908a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
290969d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2910f67375f7SJohnny Huang 	   "version\n"
2911f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
29122a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
29132d4b0742SJohnny Huang 	   "otp info strap [v]\n"
29142d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
29150dc9a440SJohnny Huang 	   "otp info scu\n"
291688bd7d58SJohnny Huang 	   "otp info key\n"
2917de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2918ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2919ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2920ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
29210dc9a440SJohnny Huang 	   "otp scuprotect [o] <scu_offset> <bit_offset>\n"
2922794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2923794e27ecSJohnny Huang 	   "otp rid\n"
2924883625c5SJohnny Huang 	   "otp retire [o] <key_id>\n"
292569d5fd8fSJohnny Huang 	  );
2926