xref: /openbmc/u-boot/cmd/otp.c (revision b489486ed361e28230236e08027a1a8a20456113)
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 
23f347c284SJohnny Huang #define OTP_VER				"1.1.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))
10261a6cda7SJohnny Huang 
103696656c6SJohnny Huang struct otp_header {
104696656c6SJohnny Huang 	u8	otp_magic[8];
10561a6cda7SJohnny Huang 	u32	soc_ver;
10661a6cda7SJohnny Huang 	u32	otptool_ver;
107696656c6SJohnny Huang 	u32	image_info;
108696656c6SJohnny Huang 	u32	data_info;
109696656c6SJohnny Huang 	u32	config_info;
110696656c6SJohnny Huang 	u32	strap_info;
1117e523e3bSJohnny Huang 	u32	scu_protect_info;
112696656c6SJohnny Huang 	u32	checksum_offset;
113a219f6deSJohnny Huang } __packed;
114696656c6SJohnny Huang 
11566f2f8e5SJohnny Huang struct otpstrap_status {
11669d5fd8fSJohnny Huang 	int value;
11769d5fd8fSJohnny Huang 	int option_array[7];
11869d5fd8fSJohnny Huang 	int remain_times;
11969d5fd8fSJohnny Huang 	int writeable_option;
12069d5fd8fSJohnny Huang 	int protected;
12169d5fd8fSJohnny Huang };
12269d5fd8fSJohnny Huang 
1239a4fe690SJohnny Huang struct otpkey_type {
1249a4fe690SJohnny Huang 	int value;
1259a4fe690SJohnny Huang 	int key_type;
1269a4fe690SJohnny Huang 	int need_id;
1279a4fe690SJohnny Huang 	char information[110];
1289a4fe690SJohnny Huang };
1299a4fe690SJohnny Huang 
130030cb4a7SJohnny Huang struct otp_pro_sts {
131030cb4a7SJohnny Huang 	char mem_lock;
132030cb4a7SJohnny Huang 	char pro_key_ret;
133030cb4a7SJohnny Huang 	char pro_strap;
134030cb4a7SJohnny Huang 	char pro_conf;
135030cb4a7SJohnny Huang 	char pro_data;
136030cb4a7SJohnny Huang 	char pro_sec;
137030cb4a7SJohnny Huang 	u32 sec_size;
138030cb4a7SJohnny Huang };
139030cb4a7SJohnny Huang 
1409a4fe690SJohnny Huang struct otp_info_cb {
1419a4fe690SJohnny Huang 	int version;
142e417205bSJohnny Huang 	char ver_name[3];
14379e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1449a4fe690SJohnny Huang 	int strap_info_len;
14579e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1469a4fe690SJohnny Huang 	int conf_info_len;
14779e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1489a4fe690SJohnny Huang 	int key_info_len;
1490dc9a440SJohnny Huang 	const struct scu_info *scu_info;
1500dc9a440SJohnny Huang 	int scu_info_len;
151030cb4a7SJohnny Huang 	struct otp_pro_sts pro_sts;
1529a4fe690SJohnny Huang };
1539a4fe690SJohnny Huang 
154696656c6SJohnny Huang struct otp_image_layout {
1555010032bSJohnny Huang 	int data_length;
1565010032bSJohnny Huang 	int conf_length;
1575010032bSJohnny Huang 	int strap_length;
158b25f02d2SJohnny Huang 	int scu_pro_length;
159a219f6deSJohnny Huang 	u8 *data;
160a219f6deSJohnny Huang 	u8 *data_ignore;
161a219f6deSJohnny Huang 	u8 *conf;
162a219f6deSJohnny Huang 	u8 *conf_ignore;
163a219f6deSJohnny Huang 	u8 *strap;
164a219f6deSJohnny Huang 	u8 *strap_pro;
165a219f6deSJohnny Huang 	u8 *strap_ignore;
166b25f02d2SJohnny Huang 	u8 *scu_pro;
167b25f02d2SJohnny Huang 	u8 *scu_pro_ignore;
168696656c6SJohnny Huang };
169696656c6SJohnny Huang 
1709a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1719a4fe690SJohnny Huang 
17279e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1739a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1749a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1759a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
176181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
177181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   0, "RSA-public as SOC public key"},
178181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
179181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as SOC private key"},
180181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1819a4fe690SJohnny Huang };
1829a4fe690SJohnny Huang 
18379e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1849a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1859a4fe690SJohnny 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"},
186181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
187181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
188181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1899a4fe690SJohnny Huang };
1909a4fe690SJohnny Huang 
1915fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1925fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1935fdde29fSJohnny 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"},
194181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
195181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
196181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
197181f72d8SJohnny Huang };
198181f72d8SJohnny Huang 
199181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
200181f72d8SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
201181f72d8SJohnny 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"},
202181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
203181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
204181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
205181f72d8SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key(big endian)"},
206181f72d8SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
207181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key(big endian)"},
2085fdde29fSJohnny Huang };
2095fdde29fSJohnny Huang 
210f347c284SJohnny Huang static void buf_print(u8 *buf, int len)
211f347c284SJohnny Huang {
212f347c284SJohnny Huang 	int i;
213f347c284SJohnny Huang 
214f347c284SJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
215f347c284SJohnny Huang 	for (i = 0; i < len; i++) {
216f347c284SJohnny Huang 		if (i % 16 == 0)
217f347c284SJohnny Huang 			printf("%04X: ", i);
218f347c284SJohnny Huang 		printf("%02X ", buf[i]);
219f347c284SJohnny Huang 		if ((i + 1) % 16 == 0)
220f347c284SJohnny Huang 			printf("\n");
221f347c284SJohnny Huang 	}
222f347c284SJohnny Huang }
223f347c284SJohnny Huang 
224794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
225794e27ecSJohnny Huang {
226794e27ecSJohnny Huang 	int bit_offset;
227794e27ecSJohnny Huang 	int i;
228794e27ecSJohnny Huang 
229794e27ecSJohnny Huang 	if (offset < 32) {
230794e27ecSJohnny Huang 		i = 0;
231794e27ecSJohnny Huang 		bit_offset = offset;
232794e27ecSJohnny Huang 	} else {
233794e27ecSJohnny Huang 		i = 1;
234794e27ecSJohnny Huang 		bit_offset = offset - 32;
235794e27ecSJohnny Huang 	}
236794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
237794e27ecSJohnny Huang 		return 1;
238794e27ecSJohnny Huang 	else
239794e27ecSJohnny Huang 		return 0;
240794e27ecSJohnny Huang }
241794e27ecSJohnny Huang 
242794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
243794e27ecSJohnny Huang {
244794e27ecSJohnny Huang 	int i;
245794e27ecSJohnny Huang 	int fz = 0;
246794e27ecSJohnny Huang 	int rid_num = 0;
247794e27ecSJohnny Huang 	int ret = 0;
248794e27ecSJohnny Huang 
249794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
250794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
251794e27ecSJohnny Huang 			if (!fz)
252794e27ecSJohnny Huang 				fz = 1;
253794e27ecSJohnny Huang 
254794e27ecSJohnny Huang 		} else {
255794e27ecSJohnny Huang 			rid_num++;
256794e27ecSJohnny Huang 			if (fz)
257794e27ecSJohnny Huang 				ret = OTP_FAILURE;
258794e27ecSJohnny Huang 		}
259794e27ecSJohnny Huang 	}
260794e27ecSJohnny Huang 	if (ret)
261794e27ecSJohnny Huang 		return ret;
262794e27ecSJohnny Huang 
263794e27ecSJohnny Huang 	return rid_num;
264794e27ecSJohnny Huang }
265794e27ecSJohnny Huang 
266a219f6deSJohnny Huang static u32 chip_version(void)
2679a4fe690SJohnny Huang {
268e417205bSJohnny Huang 	u32 revid0, revid1;
2699a4fe690SJohnny Huang 
270e417205bSJohnny Huang 	revid0 = readl(ASPEED_REVISION_ID0);
271e417205bSJohnny Huang 	revid1 = readl(ASPEED_REVISION_ID1);
2729a4fe690SJohnny Huang 
273e417205bSJohnny Huang 	if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
274badd21c2SJohnny Huang 		/* AST2600-A0 */
275e417205bSJohnny Huang 		return OTP_A0;
276e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
277badd21c2SJohnny Huang 		/* AST2600-A1 */
278e417205bSJohnny Huang 		return OTP_A1;
279e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
280badd21c2SJohnny Huang 		/* AST2600-A2 */
281e417205bSJohnny Huang 		return OTP_A2;
282e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
28364b66712SJohnny Huang 		/* AST2600-A3 */
284e417205bSJohnny Huang 		return OTP_A3;
285e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
286e417205bSJohnny Huang 		/* AST2620-A1 */
287e417205bSJohnny Huang 		return OTP_A1;
288e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
289e417205bSJohnny Huang 		/* AST2620-A2 */
290e417205bSJohnny Huang 		return OTP_A2;
291e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
29264b66712SJohnny Huang 		/* AST2620-A3 */
293e417205bSJohnny Huang 		return OTP_A3;
294e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
295e417205bSJohnny Huang 		/* AST2605-A2 */
296e417205bSJohnny Huang 		return OTP_A2;
297e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
298e417205bSJohnny Huang 		/* AST2605-A3 */
299e417205bSJohnny Huang 		return OTP_A3;
300e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
301e417205bSJohnny Huang 		/* AST2605-A3 */
302e417205bSJohnny Huang 		return OTP_A3;
3030dae9d52SJohnny Huang 	}
304f347c284SJohnny Huang 	return OTP_FAILURE;
3059a4fe690SJohnny Huang }
3069a4fe690SJohnny Huang 
3073d3688adSJohnny Huang static void wait_complete(void)
3083d3688adSJohnny Huang {
3093d3688adSJohnny Huang 	int reg;
3103d3688adSJohnny Huang 
3113d3688adSJohnny Huang 	do {
3123d3688adSJohnny Huang 		reg = readl(OTP_STATUS);
3133d3688adSJohnny Huang 	} while ((reg & 0x6) != 0x6);
3143d3688adSJohnny Huang }
3153d3688adSJohnny Huang 
316a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
317dacbba92SJohnny Huang {
318dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
319dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
320dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
321dacbba92SJohnny Huang 	wait_complete();
322dacbba92SJohnny Huang }
323dacbba92SJohnny Huang 
324dacbba92SJohnny Huang static void otp_soak(int soak)
325dacbba92SJohnny Huang {
326e417205bSJohnny Huang 	if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
327dacbba92SJohnny Huang 		switch (soak) {
328dacbba92SJohnny Huang 		case 0: //default
329377f8cd7SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
330377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
331dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
332dacbba92SJohnny Huang 			break;
333dacbba92SJohnny Huang 		case 1: //normal program
334377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
335377f8cd7SJohnny Huang 			otp_write(0x5000, 0x1008); // Write MRB
336377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0024); // Write MR
337feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
338dacbba92SJohnny Huang 			break;
339dacbba92SJohnny Huang 		case 2: //soak program
340377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
341377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0007); // Write MRB
342377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0100); // Write MR
343feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
344dacbba92SJohnny Huang 			break;
345dacbba92SJohnny Huang 		}
346dacbba92SJohnny Huang 	} else {
347dacbba92SJohnny Huang 		switch (soak) {
348dacbba92SJohnny Huang 		case 0: //default
349dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
350dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
351dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
352dacbba92SJohnny Huang 			break;
353dacbba92SJohnny Huang 		case 1: //normal program
354dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
355dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
356dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
357feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
358dacbba92SJohnny Huang 			break;
359dacbba92SJohnny Huang 		case 2: //soak program
360dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
361dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
362dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
363feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
364dacbba92SJohnny Huang 			break;
365dacbba92SJohnny Huang 		}
366dacbba92SJohnny Huang 	}
367dacbba92SJohnny Huang 
368dacbba92SJohnny Huang 	wait_complete();
369dacbba92SJohnny Huang }
370dacbba92SJohnny Huang 
371a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
37269d5fd8fSJohnny Huang {
3733d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
3743d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3753d3688adSJohnny Huang 	wait_complete();
3763d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
3773d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
37869d5fd8fSJohnny Huang }
37969d5fd8fSJohnny Huang 
380f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data)
38169d5fd8fSJohnny Huang {
38269d5fd8fSJohnny Huang 	int config_offset;
38369d5fd8fSJohnny Huang 
38469d5fd8fSJohnny Huang 	config_offset = 0x800;
38569d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
38669d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
38769d5fd8fSJohnny Huang 
3883d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
3893d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3903d3688adSJohnny Huang 	wait_complete();
3913d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
39269d5fd8fSJohnny Huang }
39369d5fd8fSJohnny Huang 
394a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
39569d5fd8fSJohnny Huang {
396a219f6deSJohnny Huang 	u32 ret;
397a219f6deSJohnny Huang 	u32 *buf;
39869d5fd8fSJohnny Huang 
39969d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
40069d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
40169d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
40269d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
40369d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
4043d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
4053d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
4063d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
4073d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
4083d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
4093d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
4103d3688adSJohnny Huang 	wait_complete();
4113d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
41269d5fd8fSJohnny Huang 	if (ret & 0x1)
413f347c284SJohnny Huang 		return OTP_SUCCESS;
41469d5fd8fSJohnny Huang 	else
415f347c284SJohnny Huang 		return OTP_FAILURE;
41669d5fd8fSJohnny Huang }
41769d5fd8fSJohnny Huang 
418a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
41969d5fd8fSJohnny Huang {
420a219f6deSJohnny Huang 	u32 ret[2];
42169d5fd8fSJohnny Huang 
42230a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4233d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
42430a8c590SJohnny Huang 	else
4253d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
42630a8c590SJohnny Huang 
4273d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4283d3688adSJohnny Huang 	wait_complete();
4293d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4303d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
43183655e91SJohnny Huang 
43230a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
43330a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
434f347c284SJohnny Huang 			return OTP_SUCCESS;
43569d5fd8fSJohnny Huang 		else
436f347c284SJohnny Huang 			return OTP_FAILURE;
43730a8c590SJohnny Huang 	} else {
43830a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
439f347c284SJohnny Huang 			return OTP_SUCCESS;
44030a8c590SJohnny Huang 		else
441f347c284SJohnny Huang 			return OTP_FAILURE;
44230a8c590SJohnny Huang 	}
44369d5fd8fSJohnny Huang }
44469d5fd8fSJohnny Huang 
445a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4464c1c9b35SJohnny Huang {
447a219f6deSJohnny Huang 	u32 ret[2];
4484c1c9b35SJohnny Huang 
4494c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4504c1c9b35SJohnny Huang 
4514c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4523d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
4534c1c9b35SJohnny Huang 	else
4543d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
4553d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4563d3688adSJohnny Huang 	wait_complete();
4573d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4583d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4594c1c9b35SJohnny Huang 	if (size == 1) {
4604c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4614c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
462696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4634c1c9b35SJohnny Huang 				compare[0] = 0;
464f347c284SJohnny Huang 				return OTP_SUCCESS;
465a219f6deSJohnny Huang 			}
4664c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
467f347c284SJohnny Huang 			return OTP_FAILURE;
4684c1c9b35SJohnny Huang 
4694c1c9b35SJohnny Huang 		} else {
4704c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
471696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4724c1c9b35SJohnny Huang 				compare[0] = ~0;
473f347c284SJohnny Huang 				return OTP_SUCCESS;
474a219f6deSJohnny Huang 			}
475d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
476f347c284SJohnny Huang 			return OTP_FAILURE;
4774c1c9b35SJohnny Huang 		}
4784c1c9b35SJohnny Huang 	} else if (size == 2) {
4794c1c9b35SJohnny Huang 		// otp_addr should be even
480696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
4814c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4824c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4834c1c9b35SJohnny Huang 			compare[0] = 0;
4844c1c9b35SJohnny Huang 			compare[1] = ~0;
485f347c284SJohnny Huang 			return OTP_SUCCESS;
486a219f6deSJohnny Huang 		}
4874c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4884c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4894c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
4904c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
491f347c284SJohnny Huang 		return OTP_FAILURE;
4924c1c9b35SJohnny Huang 	} else {
493f347c284SJohnny Huang 		return OTP_FAILURE;
4944c1c9b35SJohnny Huang 	}
4954c1c9b35SJohnny Huang }
4964c1c9b35SJohnny Huang 
497a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit)
49883655e91SJohnny Huang {
49990965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
50083655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
50183655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
50283655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
50383655e91SJohnny Huang 	wait_complete();
50483655e91SJohnny Huang }
50583655e91SJohnny Huang 
506a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
50783655e91SJohnny Huang {
50883655e91SJohnny Huang 	int prog_bit;
50983655e91SJohnny Huang 
51083655e91SJohnny Huang 	if (prog_address % 2 == 0) {
51183655e91SJohnny Huang 		if (value)
51283655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
51383655e91SJohnny Huang 		else
51483655e91SJohnny Huang 			return;
51583655e91SJohnny Huang 	} else {
516e417205bSJohnny Huang 		if (info_cb.version != OTP_A3)
51783655e91SJohnny Huang 			prog_address |= 1 << 15;
51883655e91SJohnny Huang 		if (!value)
51983655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
52083655e91SJohnny Huang 		else
52183655e91SJohnny Huang 			return;
52283655e91SJohnny Huang 	}
52383655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
52483655e91SJohnny Huang }
52583655e91SJohnny Huang 
526f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset)
52783655e91SJohnny Huang {
52883655e91SJohnny Huang 	int pass;
52983655e91SJohnny Huang 	int i;
53083655e91SJohnny Huang 
53183655e91SJohnny Huang 	otp_soak(1);
53283655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
53383655e91SJohnny Huang 	pass = 0;
53483655e91SJohnny Huang 
53583655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
53683655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
53783655e91SJohnny Huang 			otp_soak(2);
53883655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
53983655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
54083655e91SJohnny Huang 				otp_soak(1);
54183655e91SJohnny Huang 			} else {
54283655e91SJohnny Huang 				pass = 1;
54383655e91SJohnny Huang 				break;
54483655e91SJohnny Huang 			}
54583655e91SJohnny Huang 		} else {
54683655e91SJohnny Huang 			pass = 1;
54783655e91SJohnny Huang 			break;
54883655e91SJohnny Huang 		}
54983655e91SJohnny Huang 	}
550794e27ecSJohnny Huang 	if (pass)
551794e27ecSJohnny Huang 		return OTP_SUCCESS;
55283655e91SJohnny Huang 
553794e27ecSJohnny Huang 	return OTP_FAILURE;
55483655e91SJohnny Huang }
55583655e91SJohnny Huang 
556a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
557d90825e2SJohnny Huang {
558d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
559d90825e2SJohnny Huang 
560d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
561696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
562d90825e2SJohnny Huang 			continue;
563d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
564d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
565d90825e2SJohnny Huang 			if (bit_value)
566d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
567d90825e2SJohnny Huang 			else
568d90825e2SJohnny Huang 				continue;
569d90825e2SJohnny Huang 		} else {
570e417205bSJohnny Huang 			if (info_cb.version != OTP_A3)
571d90825e2SJohnny Huang 				prog_address |= 1 << 15;
572d90825e2SJohnny Huang 			if (bit_value)
573d90825e2SJohnny Huang 				continue;
574d90825e2SJohnny Huang 			else
575d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
576d90825e2SJohnny Huang 		}
577d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
578d90825e2SJohnny Huang 	}
579d90825e2SJohnny Huang }
580d90825e2SJohnny Huang 
581a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
58254552c69SJohnny Huang {
58354552c69SJohnny Huang 	int pass;
58454552c69SJohnny Huang 	int i;
585a219f6deSJohnny Huang 	u32 data0_masked;
586a219f6deSJohnny Huang 	u32 data1_masked;
587a219f6deSJohnny Huang 	u32 buf0_masked;
588a219f6deSJohnny Huang 	u32 buf1_masked;
589a219f6deSJohnny Huang 	u32 compare[2];
59054552c69SJohnny Huang 
59154552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
59254552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
59354552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
59454552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
595a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
596f347c284SJohnny Huang 		return OTP_SUCCESS;
59754552c69SJohnny Huang 
598b64ca396SJohnny Huang 	for (i = 0; i < 32; i++) {
599b64ca396SJohnny Huang 		if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0)
600b64ca396SJohnny Huang 			return OTP_FAILURE;
601b64ca396SJohnny Huang 		if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1)
602b64ca396SJohnny Huang 			return OTP_FAILURE;
603b64ca396SJohnny Huang 	}
604b64ca396SJohnny Huang 
60554552c69SJohnny Huang 	otp_soak(1);
60654552c69SJohnny Huang 	if (data0_masked != buf0_masked)
60754552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
60854552c69SJohnny Huang 	if (data1_masked != buf1_masked)
60954552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
61054552c69SJohnny Huang 
61154552c69SJohnny Huang 	pass = 0;
61254552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
61354552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
61454552c69SJohnny Huang 			otp_soak(2);
615a219f6deSJohnny Huang 			if (compare[0] != 0)
61654552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
617a219f6deSJohnny Huang 			if (compare[1] != ~0)
6185537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
61954552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
62054552c69SJohnny Huang 				otp_soak(1);
62154552c69SJohnny Huang 			} else {
62254552c69SJohnny Huang 				pass = 1;
62354552c69SJohnny Huang 				break;
62454552c69SJohnny Huang 			}
62554552c69SJohnny Huang 		} else {
62654552c69SJohnny Huang 			pass = 1;
62754552c69SJohnny Huang 			break;
62854552c69SJohnny Huang 		}
62954552c69SJohnny Huang 	}
63054552c69SJohnny Huang 
63154552c69SJohnny Huang 	if (!pass) {
63254552c69SJohnny Huang 		otp_soak(0);
63354552c69SJohnny Huang 		return OTP_FAILURE;
63454552c69SJohnny Huang 	}
63554552c69SJohnny Huang 	return OTP_SUCCESS;
63654552c69SJohnny Huang }
63754552c69SJohnny Huang 
638541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
63976d13988SJohnny Huang {
640a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
6415010032bSJohnny Huang 	int strap_end;
64276d13988SJohnny Huang 	int i, j;
64376d13988SJohnny Huang 
644e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
64576d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
64676d13988SJohnny Huang 			otpstrap[j].value = 0;
64776d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
64876d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
64976d13988SJohnny Huang 			otpstrap[j].protected = 0;
65076d13988SJohnny Huang 		}
6515010032bSJohnny Huang 		strap_end = 30;
6525010032bSJohnny Huang 	} else {
6535010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
6545010032bSJohnny Huang 			otpstrap[j].value = 0;
6555010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
6565010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
6575010032bSJohnny Huang 			otpstrap[j].protected = 0;
6585010032bSJohnny Huang 		}
6595010032bSJohnny Huang 		strap_end = 28;
6605010032bSJohnny Huang 	}
66176d13988SJohnny Huang 
662dacbba92SJohnny Huang 	otp_soak(0);
6635010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
66476d13988SJohnny Huang 		int option = (i - 16) / 2;
665a219f6deSJohnny Huang 
666f347c284SJohnny Huang 		otp_read_conf(i, &OTPSTRAP_RAW[0]);
667f347c284SJohnny Huang 		otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
66876d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
66976d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
670a219f6deSJohnny Huang 
671a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
67276d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
67376d13988SJohnny Huang 			if (bit_value == 1)
67476d13988SJohnny Huang 				otpstrap[j].remain_times--;
67576d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
67676d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
67776d13988SJohnny Huang 		}
67876d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
67976d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
680a219f6deSJohnny Huang 
681a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
68276d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
68376d13988SJohnny Huang 			if (bit_value == 1)
68476d13988SJohnny Huang 				otpstrap[j].remain_times--;
68576d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
68676d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
68776d13988SJohnny Huang 		}
68876d13988SJohnny Huang 	}
6895010032bSJohnny Huang 
690f347c284SJohnny Huang 	otp_read_conf(30, &OTPSTRAP_RAW[0]);
691f347c284SJohnny Huang 	otp_read_conf(31, &OTPSTRAP_RAW[1]);
69276d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
69376d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
69476d13988SJohnny Huang 			otpstrap[j].protected = 1;
69576d13988SJohnny Huang 	}
69676d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
69776d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
69876d13988SJohnny Huang 			otpstrap[j].protected = 1;
69976d13988SJohnny Huang 	}
70076d13988SJohnny Huang }
70176d13988SJohnny Huang 
7027e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit)
703f347c284SJohnny Huang {
704f347c284SJohnny Huang 	int prog_flag = 0;
705f347c284SJohnny Huang 
706f347c284SJohnny Huang 	// ignore this bit
707f347c284SJohnny Huang 	if (ibit == 1)
708f347c284SJohnny Huang 		return OTP_SUCCESS;
709*b489486eSJohnny Huang 	printf("OTPSTRAP[0x%X]:\n", offset);
710f347c284SJohnny Huang 
711f347c284SJohnny Huang 	if (bit == otpstrap->value) {
7127e523e3bSJohnny Huang 		if (!pbit) {
713f347c284SJohnny Huang 			printf("    The value is same as before, skip it.\n");
714f347c284SJohnny Huang 			return OTP_PROG_SKIP;
715f347c284SJohnny Huang 		}
716f347c284SJohnny Huang 		printf("    The value is same as before.\n");
717f347c284SJohnny Huang 	} else {
718f347c284SJohnny Huang 		prog_flag = 1;
719f347c284SJohnny Huang 	}
720f347c284SJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
721f347c284SJohnny Huang 		printf("    This bit is protected and is not writable\n");
722f347c284SJohnny Huang 		return OTP_FAILURE;
723f347c284SJohnny Huang 	}
724f347c284SJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
725*b489486eSJohnny Huang 		printf("    This bit has no remaining chance to write.\n");
726f347c284SJohnny Huang 		return OTP_FAILURE;
727f347c284SJohnny Huang 	}
728f347c284SJohnny Huang 	if (pbit == 1)
729f347c284SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
730f347c284SJohnny Huang 	if (prog_flag)
731*b489486eSJohnny 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);
732f347c284SJohnny Huang 
733f347c284SJohnny Huang 	return OTP_SUCCESS;
734f347c284SJohnny Huang }
735f347c284SJohnny Huang 
736f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
737f347c284SJohnny Huang {
738f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
739f347c284SJohnny Huang 	u32 prog_address;
740f347c284SJohnny Huang 	int offset;
741f347c284SJohnny Huang 	int ret;
742f347c284SJohnny Huang 
743f347c284SJohnny Huang 	otp_strap_status(otpstrap);
744f347c284SJohnny Huang 
7457e523e3bSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
746f347c284SJohnny Huang 
747f347c284SJohnny Huang 	if (ret != OTP_SUCCESS)
748f347c284SJohnny Huang 		return ret;
749f347c284SJohnny Huang 
750f347c284SJohnny Huang 	prog_address = 0x800;
751f347c284SJohnny Huang 	if (bit_offset < 32) {
752f347c284SJohnny Huang 		offset = bit_offset;
753f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
754f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
755f347c284SJohnny Huang 
756f347c284SJohnny Huang 	} else {
757f347c284SJohnny Huang 		offset = (bit_offset - 32);
758f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
759f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
760f347c284SJohnny Huang 	}
761f347c284SJohnny Huang 
762f347c284SJohnny Huang 	return otp_prog_dc_b(1, prog_address, offset);
763f347c284SJohnny Huang }
764f347c284SJohnny Huang 
765f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
766f347c284SJohnny Huang {
767f347c284SJohnny Huang 	int i;
768f347c284SJohnny Huang 	u32 ret[1];
769f347c284SJohnny Huang 
770f347c284SJohnny Huang 	if (offset + dw_count > 32)
771f347c284SJohnny Huang 		return OTP_USAGE;
772f347c284SJohnny Huang 	otp_soak(0);
773f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
774f347c284SJohnny Huang 		otp_read_conf(i, ret);
775*b489486eSJohnny Huang 		printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]);
776f347c284SJohnny Huang 	}
777f347c284SJohnny Huang 	printf("\n");
778f347c284SJohnny Huang 	return OTP_SUCCESS;
779f347c284SJohnny Huang }
780f347c284SJohnny Huang 
781f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
782f347c284SJohnny Huang {
783f347c284SJohnny Huang 	int i;
784f347c284SJohnny Huang 	u32 ret[2];
785f347c284SJohnny Huang 
786f347c284SJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
787f347c284SJohnny Huang 		return OTP_USAGE;
788f347c284SJohnny Huang 	otp_soak(0);
789f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
790f347c284SJohnny Huang 		otp_read_data(i, ret);
791f347c284SJohnny Huang 		if (i % 4 == 0)
792f347c284SJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
793f347c284SJohnny Huang 		else
794f347c284SJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
795f347c284SJohnny Huang 	}
796f347c284SJohnny Huang 	printf("\n");
797f347c284SJohnny Huang 	return OTP_SUCCESS;
798f347c284SJohnny Huang }
799f347c284SJohnny Huang 
800f347c284SJohnny Huang static int otp_print_strap(int start, int count)
801f347c284SJohnny Huang {
802f347c284SJohnny Huang 	int i, j;
803f347c284SJohnny Huang 	int remains;
804f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
805f347c284SJohnny Huang 
806f347c284SJohnny Huang 	if (start < 0 || start > 64)
807f347c284SJohnny Huang 		return OTP_USAGE;
808f347c284SJohnny Huang 
809f347c284SJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
810f347c284SJohnny Huang 		return OTP_USAGE;
811f347c284SJohnny Huang 
812f347c284SJohnny Huang 	otp_strap_status(otpstrap);
813f347c284SJohnny Huang 
8147e523e3bSJohnny Huang 	if (info_cb.version == OTP_A0)
815f347c284SJohnny Huang 		remains = 7;
8167e523e3bSJohnny Huang 	else
817f347c284SJohnny Huang 		remains = 6;
8187e523e3bSJohnny Huang 	printf("BIT(hex)  Value  Option           Status\n");
819f347c284SJohnny Huang 	printf("______________________________________________________________________________\n");
820f347c284SJohnny Huang 
821f347c284SJohnny Huang 	for (i = start; i < start + count; i++) {
822f347c284SJohnny Huang 		printf("0x%-8X", i);
823f347c284SJohnny Huang 		printf("%-7d", otpstrap[i].value);
824f347c284SJohnny Huang 		for (j = 0; j < remains; j++)
825f347c284SJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
826f347c284SJohnny Huang 		printf("   ");
827f347c284SJohnny Huang 		if (otpstrap[i].protected == 1) {
828f347c284SJohnny Huang 			printf("protected and not writable");
829f347c284SJohnny Huang 		} else {
830f347c284SJohnny Huang 			printf("not protected ");
831f347c284SJohnny Huang 			if (otpstrap[i].remain_times == 0)
832f347c284SJohnny Huang 				printf("and no remaining times to write.");
833f347c284SJohnny Huang 			else
834f347c284SJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
835f347c284SJohnny Huang 		}
836f347c284SJohnny Huang 		printf("\n");
837f347c284SJohnny Huang 	}
838f347c284SJohnny Huang 
839f347c284SJohnny Huang 	return OTP_SUCCESS;
840f347c284SJohnny Huang }
841f347c284SJohnny Huang 
842794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
843794e27ecSJohnny Huang {
844794e27ecSJohnny Huang 	int bit_offset;
845794e27ecSJohnny Huang 	int i, j;
846794e27ecSJohnny Huang 
847794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
848794e27ecSJohnny Huang 	printf("___________________________________________________\n");
849794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
850794e27ecSJohnny Huang 		if (i < 32) {
851794e27ecSJohnny Huang 			j = 0;
852794e27ecSJohnny Huang 			bit_offset = i;
853794e27ecSJohnny Huang 		} else {
854794e27ecSJohnny Huang 			j = 1;
855794e27ecSJohnny Huang 			bit_offset = i - 32;
856794e27ecSJohnny Huang 		}
857794e27ecSJohnny Huang 		if (i % 16 == 0)
858794e27ecSJohnny Huang 			printf("%2x | ", i);
859794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
860794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
861794e27ecSJohnny Huang 			printf("\n");
862794e27ecSJohnny Huang 	}
863794e27ecSJohnny Huang }
864794e27ecSJohnny Huang 
865b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout)
866b25f02d2SJohnny Huang {
867b25f02d2SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
868b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
869b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
870b25f02d2SJohnny Huang 	int i;
871b25f02d2SJohnny Huang 	u32 scu_offset;
872b25f02d2SJohnny Huang 	u32 dw_offset;
873b25f02d2SJohnny Huang 	u32 bit_offset;
874b25f02d2SJohnny Huang 	u32 mask;
875b25f02d2SJohnny Huang 	u32 otp_value;
876b25f02d2SJohnny Huang 	u32 otp_ignore;
877b25f02d2SJohnny Huang 
878b25f02d2SJohnny Huang 	printf("SCU     BIT          reg_protect     Description\n");
879b25f02d2SJohnny Huang 	printf("____________________________________________________________________\n");
880b25f02d2SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
881b25f02d2SJohnny Huang 		mask = BIT(scu_info[i].length) - 1;
882b25f02d2SJohnny Huang 
883b25f02d2SJohnny Huang 		if (scu_info[i].bit_offset > 31) {
884b25f02d2SJohnny Huang 			scu_offset = 0x510;
885b25f02d2SJohnny Huang 			dw_offset = 1;
886b25f02d2SJohnny Huang 			bit_offset = scu_info[i].bit_offset - 32;
887b25f02d2SJohnny Huang 		} else {
888b25f02d2SJohnny Huang 			scu_offset = 0x500;
889b25f02d2SJohnny Huang 			dw_offset = 0;
890b25f02d2SJohnny Huang 			bit_offset = scu_info[i].bit_offset;
891b25f02d2SJohnny Huang 		}
892b25f02d2SJohnny Huang 
893b25f02d2SJohnny Huang 		otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask;
894b25f02d2SJohnny Huang 		otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask;
895b25f02d2SJohnny Huang 
896b25f02d2SJohnny Huang 		if (otp_ignore == mask)
897b25f02d2SJohnny Huang 			continue;
898b25f02d2SJohnny Huang 		else if (otp_ignore != 0)
899b25f02d2SJohnny Huang 			return OTP_FAILURE;
900b25f02d2SJohnny Huang 
901b25f02d2SJohnny Huang 		if (otp_value != 0 && otp_value != mask)
902b25f02d2SJohnny Huang 			return OTP_FAILURE;
903b25f02d2SJohnny Huang 
904b25f02d2SJohnny Huang 		printf("0x%-6X", scu_offset);
905b25f02d2SJohnny Huang 		if (scu_info[i].length == 1)
906b25f02d2SJohnny Huang 			printf("0x%-11X", bit_offset);
907b25f02d2SJohnny Huang 		else
908b25f02d2SJohnny Huang 			printf("0x%-2X:0x%-4x", bit_offset, bit_offset + scu_info[i].length - 1);
909b25f02d2SJohnny Huang 		printf("0x%-14X", otp_value);
910b25f02d2SJohnny Huang 		printf("%s\n", scu_info[i].information);
911b25f02d2SJohnny Huang 	}
912b25f02d2SJohnny Huang 	return OTP_SUCCESS;
913b25f02d2SJohnny Huang }
914b25f02d2SJohnny Huang 
9150dc9a440SJohnny Huang static void otp_print_scu_info(void)
9160dc9a440SJohnny Huang {
9170dc9a440SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
9180dc9a440SJohnny Huang 	u32 OTPCFG[2];
9190dc9a440SJohnny Huang 	u32 scu_offset;
9200dc9a440SJohnny Huang 	u32 bit_offset;
9210dc9a440SJohnny Huang 	u32 reg_p;
9220dc9a440SJohnny Huang 	u32 length;
9230dc9a440SJohnny Huang 	int i, j;
9240dc9a440SJohnny Huang 
9250dc9a440SJohnny Huang 	otp_soak(0);
9260dc9a440SJohnny Huang 	otp_read_conf(28, &OTPCFG[0]);
9270dc9a440SJohnny Huang 	otp_read_conf(29, &OTPCFG[1]);
9280dc9a440SJohnny Huang 	printf("SCU     BIT   reg_protect     Description\n");
9290dc9a440SJohnny Huang 	printf("____________________________________________________________________\n");
9300dc9a440SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
9310dc9a440SJohnny Huang 		length = scu_info[i].length;
9320dc9a440SJohnny Huang 		for (j = 0; j < length; j++) {
9330dc9a440SJohnny Huang 			if (scu_info[i].bit_offset + j < 32) {
9340dc9a440SJohnny Huang 				scu_offset = 0x500;
9350dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j;
9360dc9a440SJohnny Huang 				reg_p = (OTPCFG[0] >> bit_offset) & 0x1;
9370dc9a440SJohnny Huang 			} else {
9380dc9a440SJohnny Huang 				scu_offset = 0x510;
9390dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j - 32;
9400dc9a440SJohnny Huang 				reg_p = (OTPCFG[1] >> bit_offset) & 0x1;
9410dc9a440SJohnny Huang 			}
9420dc9a440SJohnny Huang 			printf("0x%-6X", scu_offset);
9430dc9a440SJohnny Huang 			printf("0x%-4X", bit_offset);
9440dc9a440SJohnny Huang 			printf("0x%-13X", reg_p);
9450dc9a440SJohnny Huang 			if (length == 1) {
9460dc9a440SJohnny Huang 				printf(" %s\n", scu_info[i].information);
9470dc9a440SJohnny Huang 				continue;
9480dc9a440SJohnny Huang 			}
9490dc9a440SJohnny Huang 
9500dc9a440SJohnny Huang 			if (j == 0)
9510dc9a440SJohnny Huang 				printf("/%s\n", scu_info[i].information);
9520dc9a440SJohnny Huang 			else if (j == length - 1)
9530dc9a440SJohnny Huang 				printf("\\ \"\n");
9540dc9a440SJohnny Huang 			else
9550dc9a440SJohnny Huang 				printf("| \"\n");
9560dc9a440SJohnny Huang 		}
9570dc9a440SJohnny Huang 	}
9580dc9a440SJohnny Huang }
9590dc9a440SJohnny Huang 
960696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
96169d5fd8fSJohnny Huang {
96279e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
963a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
964a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
965a219f6deSJohnny Huang 	u32 mask;
966a219f6deSJohnny Huang 	u32 dw_offset;
967a219f6deSJohnny Huang 	u32 bit_offset;
968a219f6deSJohnny Huang 	u32 otp_value;
969a219f6deSJohnny Huang 	u32 otp_ignore;
970b458cd62SJohnny Huang 	int fail = 0;
9717adec5f6SJohnny Huang 	int mask_err;
972794e27ecSJohnny Huang 	int rid_num = 0;
97373f11549SJohnny Huang 	char valid_bit[20];
974794e27ecSJohnny Huang 	int fz;
97566f2f8e5SJohnny Huang 	int i;
97673f11549SJohnny Huang 	int j;
97766f2f8e5SJohnny Huang 
978737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
97966f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
9803cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
9817adec5f6SJohnny Huang 		mask_err = 0;
9823cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
9833cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
9843cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
985b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
986696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
987b458cd62SJohnny Huang 
9887adec5f6SJohnny Huang 		if (conf_info[i].value == OTP_REG_VALID_BIT) {
9897adec5f6SJohnny Huang 			if (((otp_value + otp_ignore) & mask) != mask) {
990b458cd62SJohnny Huang 				fail = 1;
9917adec5f6SJohnny Huang 				mask_err = 1;
9927adec5f6SJohnny Huang 			}
9937adec5f6SJohnny Huang 		} else {
9947adec5f6SJohnny Huang 			if (otp_ignore == mask) {
9957adec5f6SJohnny Huang 				continue;
9967adec5f6SJohnny Huang 			} else if (otp_ignore != 0) {
9977adec5f6SJohnny Huang 				fail = 1;
9987adec5f6SJohnny Huang 				mask_err = 1;
9997adec5f6SJohnny Huang 			}
10007adec5f6SJohnny Huang 		}
1001b458cd62SJohnny Huang 
1002a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
10033cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
10043cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
10053cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1006b458cd62SJohnny Huang 			continue;
1007b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1008b458cd62SJohnny Huang 
10093cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
10103cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
101166f2f8e5SJohnny Huang 		} else {
1012b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
10133cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
10143cb28812SJohnny Huang 			       conf_info[i].bit_offset);
101566f2f8e5SJohnny Huang 		}
1016b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1017b458cd62SJohnny Huang 
10187adec5f6SJohnny Huang 		if (mask_err) {
10197adec5f6SJohnny Huang 			printf("Ignore, mask error\n");
1020a219f6deSJohnny Huang 			continue;
1021a219f6deSJohnny Huang 		}
10223cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1023b458cd62SJohnny Huang 			printf("Reserved\n");
10243cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
10253cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1026b458cd62SJohnny Huang 			printf("\n");
10273cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1028b458cd62SJohnny Huang 			if (otp_value != 0) {
102973f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1030a219f6deSJohnny Huang 					if (otp_value == (1 << j))
103173f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1032a219f6deSJohnny Huang 					else
103373f11549SJohnny Huang 						valid_bit[j * 2] = '0';
103473f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
103573f11549SJohnny Huang 				}
103673f11549SJohnny Huang 				valid_bit[15] = 0;
103773f11549SJohnny Huang 			} else {
103873f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1039b458cd62SJohnny Huang 			}
10403cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1041b458cd62SJohnny Huang 			printf("\n");
1042b458cd62SJohnny Huang 		} else {
10433cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1044b458cd62SJohnny Huang 		}
1045b458cd62SJohnny Huang 	}
1046b458cd62SJohnny Huang 
1047794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
1048794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
1049794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
1050794e27ecSJohnny Huang 			fail = 1;
1051794e27ecSJohnny Huang 		} else {
1052794e27ecSJohnny Huang 			fz = 0;
1053794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
1054794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
1055794e27ecSJohnny Huang 					if (!fz)
1056794e27ecSJohnny Huang 						fz = 1;
1057794e27ecSJohnny Huang 				} else {
1058794e27ecSJohnny Huang 					rid_num++;
1059794e27ecSJohnny Huang 					if (fz) {
1060794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
1061794e27ecSJohnny Huang 						fail = 1;
1062794e27ecSJohnny Huang 						break;
1063794e27ecSJohnny Huang 					}
1064794e27ecSJohnny Huang 				}
1065794e27ecSJohnny Huang 			}
1066794e27ecSJohnny Huang 		}
1067794e27ecSJohnny Huang 		if (fail)
1068794e27ecSJohnny Huang 			printf("OTP revision ID\n");
1069794e27ecSJohnny Huang 		else
1070794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
1071794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
1072794e27ecSJohnny Huang 	}
1073794e27ecSJohnny Huang 
1074b458cd62SJohnny Huang 	if (fail)
1075b458cd62SJohnny Huang 		return OTP_FAILURE;
1076b458cd62SJohnny Huang 
107766f2f8e5SJohnny Huang 	return OTP_SUCCESS;
107866f2f8e5SJohnny Huang }
107966f2f8e5SJohnny Huang 
10802d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
108166f2f8e5SJohnny Huang {
108279e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
1083a219f6deSJohnny Huang 	u32 OTPCFG[16];
1084a219f6deSJohnny Huang 	u32 mask;
1085a219f6deSJohnny Huang 	u32 dw_offset;
1086a219f6deSJohnny Huang 	u32 bit_offset;
1087a219f6deSJohnny Huang 	u32 otp_value;
108873f11549SJohnny Huang 	char valid_bit[20];
108966f2f8e5SJohnny Huang 	int i;
109073f11549SJohnny Huang 	int j;
109166f2f8e5SJohnny Huang 
1092dacbba92SJohnny Huang 	otp_soak(0);
1093bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
1094f347c284SJohnny Huang 		otp_read_conf(i, &OTPCFG[i]);
109566f2f8e5SJohnny Huang 
1096b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
1097b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
10983cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
10993cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
11002d4b0742SJohnny Huang 			continue;
11013cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
11023cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
11033cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
1104b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1105b458cd62SJohnny Huang 
1106a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
11073cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
11083cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
11093cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1110b458cd62SJohnny Huang 			continue;
1111b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1112b458cd62SJohnny Huang 
11133cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
11143cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
1115b458cd62SJohnny Huang 		} else {
1116b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
11173cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
11183cb28812SJohnny Huang 			       conf_info[i].bit_offset);
1119b458cd62SJohnny Huang 		}
1120b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1121b458cd62SJohnny Huang 
11223cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1123b458cd62SJohnny Huang 			printf("Reserved\n");
11243cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
11253cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1126b458cd62SJohnny Huang 			printf("\n");
11273cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1128b458cd62SJohnny Huang 			if (otp_value != 0) {
112973f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1130030cb4a7SJohnny Huang 					if (otp_value & (1 << j))
113173f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1132a219f6deSJohnny Huang 					else
113373f11549SJohnny Huang 						valid_bit[j * 2] = '0';
113473f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
113573f11549SJohnny Huang 				}
113673f11549SJohnny Huang 				valid_bit[15] = 0;
113773f11549SJohnny Huang 			} else {
113873f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1139b458cd62SJohnny Huang 			}
11403cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1141b458cd62SJohnny Huang 			printf("\n");
1142b458cd62SJohnny Huang 		} else {
11433cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1144b458cd62SJohnny Huang 		}
1145b458cd62SJohnny Huang 	}
1146b458cd62SJohnny Huang 	return OTP_SUCCESS;
114766f2f8e5SJohnny Huang }
114866f2f8e5SJohnny Huang 
11495010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
115076d13988SJohnny Huang {
115179e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
1152a219f6deSJohnny Huang 	u32 *OTPSTRAP;
1153a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
1154a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
115576d13988SJohnny Huang 	int i;
1156a8bd6d8cSJohnny Huang 	int fail = 0;
1157a219f6deSJohnny Huang 	u32 bit_offset;
1158a219f6deSJohnny Huang 	u32 dw_offset;
1159a219f6deSJohnny Huang 	u32 mask;
1160a219f6deSJohnny Huang 	u32 otp_value;
1161a219f6deSJohnny Huang 	u32 otp_protect;
1162a219f6deSJohnny Huang 	u32 otp_ignore;
116376d13988SJohnny Huang 
1164a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
1165a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1166a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
11677e523e3bSJohnny Huang 
1168a8bd6d8cSJohnny Huang 	printf("BIT(hex)   Value       Protect     Description\n");
1169de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
1170b458cd62SJohnny Huang 
11713cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
11727adec5f6SJohnny Huang 		fail = 0;
1173696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
1174a8bd6d8cSJohnny Huang 			dw_offset = 1;
11753cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
1176a8bd6d8cSJohnny Huang 		} else {
1177a8bd6d8cSJohnny Huang 			dw_offset = 0;
11783cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
1179a8bd6d8cSJohnny Huang 		}
118076d13988SJohnny Huang 
11813cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
1182a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1183a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1184696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1185a8bd6d8cSJohnny Huang 
1186a219f6deSJohnny Huang 		if (otp_ignore == mask)
1187a8bd6d8cSJohnny Huang 			continue;
1188a219f6deSJohnny Huang 		else if (otp_ignore != 0)
1189a8bd6d8cSJohnny Huang 			fail = 1;
1190a8bd6d8cSJohnny Huang 
1191a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
11923cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1193a8bd6d8cSJohnny Huang 			continue;
1194a8bd6d8cSJohnny Huang 
11953cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
11963cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
1197a8bd6d8cSJohnny Huang 		} else {
1198b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
11993cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
12003cb28812SJohnny Huang 			       strap_info[i].bit_offset);
1201a8bd6d8cSJohnny Huang 		}
1202a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
1203a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
1204a8bd6d8cSJohnny Huang 
1205a8bd6d8cSJohnny Huang 		if (fail) {
1206696656c6SJohnny Huang 			printf("Ignore mask error\n");
1207a8bd6d8cSJohnny Huang 		} else {
12083cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
12093cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1210a8bd6d8cSJohnny Huang 			else
1211a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1212a8bd6d8cSJohnny Huang 		}
1213a8bd6d8cSJohnny Huang 	}
1214a8bd6d8cSJohnny Huang 
1215a8bd6d8cSJohnny Huang 	if (fail)
121676d13988SJohnny Huang 		return OTP_FAILURE;
121776d13988SJohnny Huang 
121876d13988SJohnny Huang 	return OTP_SUCCESS;
121976d13988SJohnny Huang }
122076d13988SJohnny Huang 
1221b458cd62SJohnny Huang static int otp_print_strap_info(int view)
122276d13988SJohnny Huang {
122379e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
122476d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
122507baa4e8SJohnny Huang 	int i, j;
1226b458cd62SJohnny Huang 	int fail = 0;
1227a219f6deSJohnny Huang 	u32 bit_offset;
1228a219f6deSJohnny Huang 	u32 length;
1229a219f6deSJohnny Huang 	u32 otp_value;
1230a219f6deSJohnny Huang 	u32 otp_protect;
123176d13988SJohnny Huang 
1232541eb887SJohnny Huang 	otp_strap_status(strap_status);
123376d13988SJohnny Huang 
1234b458cd62SJohnny Huang 	if (view) {
123507baa4e8SJohnny Huang 		printf("BIT(hex) Value  Remains  Protect   Description\n");
123607baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1237b458cd62SJohnny Huang 	} else {
1238b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1239b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
124076d13988SJohnny Huang 	}
12413cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1242b458cd62SJohnny Huang 		otp_value = 0;
12433cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
12443cb28812SJohnny Huang 		length = strap_info[i].length;
1245b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1246c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1247c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1248b458cd62SJohnny Huang 		}
1249a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
12503cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1251b458cd62SJohnny Huang 			continue;
1252b458cd62SJohnny Huang 		if (view) {
1253b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
12543cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1255b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
125607baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1257e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
12583cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1259b458cd62SJohnny Huang 					printf(" Reserved\n");
1260b458cd62SJohnny Huang 					continue;
1261b458cd62SJohnny Huang 				}
1262b458cd62SJohnny Huang 				if (length == 1) {
12633cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1264b458cd62SJohnny Huang 					continue;
126576d13988SJohnny Huang 				}
126676d13988SJohnny Huang 
1267b458cd62SJohnny Huang 				if (j == 0)
12683cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1269b458cd62SJohnny Huang 				else if (j == length - 1)
1270b458cd62SJohnny Huang 					printf("\\ \"\n");
1271b458cd62SJohnny Huang 				else
1272b458cd62SJohnny Huang 					printf("| \"\n");
127376d13988SJohnny Huang 			}
1274b458cd62SJohnny Huang 		} else {
1275c947ef08SJohnny Huang 			if (length == 1) {
12763cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1277b458cd62SJohnny Huang 			} else {
1278b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1279b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1280b458cd62SJohnny Huang 			}
1281b458cd62SJohnny Huang 
1282b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1283b458cd62SJohnny Huang 
12843cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
12853cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1286b458cd62SJohnny Huang 			else
1287b458cd62SJohnny Huang 				printf("Reserved\n");
1288b458cd62SJohnny Huang 		}
1289b458cd62SJohnny Huang 	}
1290b458cd62SJohnny Huang 
1291b458cd62SJohnny Huang 	if (fail)
1292b458cd62SJohnny Huang 		return OTP_FAILURE;
1293b458cd62SJohnny Huang 
1294b458cd62SJohnny Huang 	return OTP_SUCCESS;
1295b458cd62SJohnny Huang }
1296b458cd62SJohnny Huang 
1297f347c284SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
129869d5fd8fSJohnny Huang {
129969d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
130079e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
13019a4fe690SJohnny Huang 	struct otpkey_type key_info;
1302a219f6deSJohnny Huang 	u32 *buf;
1303a219f6deSJohnny Huang 	u8 *byte_buf;
13049d998018SJohnny Huang 	char empty = 1;
130569d5fd8fSJohnny Huang 	int i = 0, len = 0;
13069a4fe690SJohnny Huang 	int j;
130754552c69SJohnny Huang 
1308696656c6SJohnny Huang 	byte_buf = image_layout->data;
1309a219f6deSJohnny Huang 	buf = (u32 *)byte_buf;
13109d998018SJohnny Huang 
13119d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
1312a219f6deSJohnny Huang 		if (buf[i] != 0)
13139d998018SJohnny Huang 			empty = 0;
13149d998018SJohnny Huang 	}
13159d998018SJohnny Huang 	if (empty)
1316f347c284SJohnny Huang 		return OTP_SUCCESS;
13179d998018SJohnny Huang 
13189d998018SJohnny Huang 	i = 0;
131969d5fd8fSJohnny Huang 	while (1) {
132069d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
132169d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
132269d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
132369d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
132469d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
132569d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
13269a4fe690SJohnny Huang 
13279a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
13289a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
13299a4fe690SJohnny Huang 				key_info = key_info_array[j];
13309a4fe690SJohnny Huang 				break;
13319a4fe690SJohnny Huang 			}
13329a4fe690SJohnny Huang 		}
13339a4fe690SJohnny Huang 
13347f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
133569d5fd8fSJohnny Huang 		printf("Key Type: ");
13369a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
13379a4fe690SJohnny Huang 
13389a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
133969d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
134069d5fd8fSJohnny Huang 			switch (key_length) {
134169d5fd8fSJohnny Huang 			case 0:
134269d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
134369d5fd8fSJohnny Huang 				break;
134469d5fd8fSJohnny Huang 			case 1:
134569d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
134669d5fd8fSJohnny Huang 				break;
134769d5fd8fSJohnny Huang 			case 2:
134869d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
134969d5fd8fSJohnny Huang 				break;
135069d5fd8fSJohnny Huang 			case 3:
135169d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
135269d5fd8fSJohnny Huang 				break;
135369d5fd8fSJohnny Huang 			}
1354181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1355181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
135669d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
135769d5fd8fSJohnny Huang 			switch (key_length) {
135869d5fd8fSJohnny Huang 			case 0:
135969d5fd8fSJohnny Huang 				printf("RSA1024\n");
136069d5fd8fSJohnny Huang 				len = 0x100;
136169d5fd8fSJohnny Huang 				break;
136269d5fd8fSJohnny Huang 			case 1:
136369d5fd8fSJohnny Huang 				printf("RSA2048\n");
136469d5fd8fSJohnny Huang 				len = 0x200;
136569d5fd8fSJohnny Huang 				break;
136669d5fd8fSJohnny Huang 			case 2:
136769d5fd8fSJohnny Huang 				printf("RSA3072\n");
136869d5fd8fSJohnny Huang 				len = 0x300;
136969d5fd8fSJohnny Huang 				break;
137069d5fd8fSJohnny Huang 			case 3:
137169d5fd8fSJohnny Huang 				printf("RSA4096\n");
137269d5fd8fSJohnny Huang 				len = 0x400;
137369d5fd8fSJohnny Huang 				break;
137469d5fd8fSJohnny Huang 			}
137569d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
137669d5fd8fSJohnny Huang 		}
13779a4fe690SJohnny Huang 		if (key_info.need_id)
137869d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
137969d5fd8fSJohnny Huang 		printf("Key Value:\n");
13809a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
138169d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
13829a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
13839a4fe690SJohnny Huang 			printf("AES Key:\n");
13849a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1385e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
13869a4fe690SJohnny Huang 				printf("AES IV:\n");
13879a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
13889a4fe690SJohnny Huang 			}
13899a4fe690SJohnny Huang 
13909a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1391e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
139269d5fd8fSJohnny Huang 				printf("AES Key:\n");
139369d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
139469d5fd8fSJohnny Huang 				printf("AES IV:\n");
139569d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
13965fdde29fSJohnny Huang 			} else {
13979a4fe690SJohnny Huang 				printf("AES Key 1:\n");
13989a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
13999a4fe690SJohnny Huang 				printf("AES Key 2:\n");
14009a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
14019a4fe690SJohnny Huang 			}
1402181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
140369d5fd8fSJohnny Huang 			printf("RSA mod:\n");
140469d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
140569d5fd8fSJohnny Huang 			printf("RSA exp:\n");
140669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1407181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1408181f72d8SJohnny Huang 			printf("RSA mod:\n");
1409181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1410181f72d8SJohnny Huang 			printf("RSA exp:\n");
1411a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
141269d5fd8fSJohnny Huang 		}
141369d5fd8fSJohnny Huang 		if (last)
141469d5fd8fSJohnny Huang 			break;
141569d5fd8fSJohnny Huang 		i++;
141669d5fd8fSJohnny Huang 	}
1417f347c284SJohnny Huang 	return OTP_SUCCESS;
1418f347c284SJohnny Huang }
1419f347c284SJohnny Huang 
1420b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data)
1421f347c284SJohnny Huang {
1422f347c284SJohnny Huang 	int i;
1423f347c284SJohnny Huang 	int ret;
1424f347c284SJohnny Huang 	u32 *buf;
1425f347c284SJohnny Huang 	u32 *buf_ignore;
1426f347c284SJohnny Huang 
1427f347c284SJohnny Huang 	buf = (u32 *)image_layout->data;
1428f347c284SJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
1429f347c284SJohnny Huang 	printf("Start Programing...\n");
1430f347c284SJohnny Huang 
1431f347c284SJohnny Huang 	// programing ecc region first
1432f347c284SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1433f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1434f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1435f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1436f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1437f347c284SJohnny Huang 			return ret;
1438f347c284SJohnny Huang 		}
1439f347c284SJohnny Huang 	}
1440f347c284SJohnny Huang 
1441f347c284SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1442f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1443f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1444f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1445f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1446f347c284SJohnny Huang 			return ret;
1447f347c284SJohnny Huang 		}
1448f347c284SJohnny Huang 	}
1449f347c284SJohnny Huang 	otp_soak(0);
1450f347c284SJohnny Huang 	return OTP_SUCCESS;
1451f347c284SJohnny Huang }
1452f347c284SJohnny Huang 
1453b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1454f347c284SJohnny Huang {
1455f347c284SJohnny Huang 	u32 *strap;
1456f347c284SJohnny Huang 	u32 *strap_ignore;
1457f347c284SJohnny Huang 	u32 *strap_pro;
1458f347c284SJohnny Huang 	u32 prog_address;
1459f347c284SJohnny Huang 	int i;
14607e523e3bSJohnny Huang 	int bit, pbit, ibit, offset;
1461f347c284SJohnny Huang 	int fail = 0;
1462f347c284SJohnny Huang 	int ret;
1463f347c284SJohnny Huang 	int prog_flag = 0;
1464f347c284SJohnny Huang 
1465f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1466f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1467f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1468f347c284SJohnny Huang 
1469f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1470f347c284SJohnny Huang 		prog_address = 0x800;
1471f347c284SJohnny Huang 		if (i < 32) {
1472f347c284SJohnny Huang 			offset = i;
1473f347c284SJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1474f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
1475f347c284SJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
1476f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1477f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1478f347c284SJohnny Huang 
1479f347c284SJohnny Huang 		} else {
1480f347c284SJohnny Huang 			offset = (i - 32);
1481f347c284SJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1482f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
1483f347c284SJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
1484f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1485f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1486f347c284SJohnny Huang 		}
1487f347c284SJohnny Huang 
1488f347c284SJohnny Huang 		if (ibit == 1)
1489f347c284SJohnny Huang 			continue;
1490f347c284SJohnny Huang 		if (bit == otpstrap[i].value)
1491f347c284SJohnny Huang 			prog_flag = 0;
1492f347c284SJohnny Huang 		else
1493f347c284SJohnny Huang 			prog_flag = 1;
1494f347c284SJohnny Huang 
1495f347c284SJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
1496f347c284SJohnny Huang 			fail = 1;
1497f347c284SJohnny Huang 			continue;
1498f347c284SJohnny Huang 		}
1499f347c284SJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
1500f347c284SJohnny Huang 			fail = 1;
1501f347c284SJohnny Huang 			continue;
1502f347c284SJohnny Huang 		}
1503f347c284SJohnny Huang 
1504f347c284SJohnny Huang 		if (prog_flag) {
1505f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1506f347c284SJohnny Huang 			if (ret)
1507f347c284SJohnny Huang 				return OTP_FAILURE;
1508f347c284SJohnny Huang 		}
1509f347c284SJohnny Huang 
1510f347c284SJohnny Huang 		if (pbit != 0) {
1511f347c284SJohnny Huang 			prog_address = 0x800;
1512f347c284SJohnny Huang 			if (i < 32)
1513f347c284SJohnny Huang 				prog_address |= 0x60c;
1514f347c284SJohnny Huang 			else
1515f347c284SJohnny Huang 				prog_address |= 0x60e;
1516f347c284SJohnny Huang 
1517f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1518f347c284SJohnny Huang 			if (ret)
1519f347c284SJohnny Huang 				return OTP_FAILURE;
1520f347c284SJohnny Huang 		}
1521f347c284SJohnny Huang 	}
1522f347c284SJohnny Huang 	otp_soak(0);
1523f347c284SJohnny Huang 	if (fail == 1)
1524f347c284SJohnny Huang 		return OTP_FAILURE;
1525f347c284SJohnny Huang 	return OTP_SUCCESS;
152669d5fd8fSJohnny Huang }
152769d5fd8fSJohnny Huang 
1528b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf)
152969d5fd8fSJohnny Huang {
1530a6d0d645SJohnny Huang 	int i, k;
1531d90825e2SJohnny Huang 	int pass = 0;
1532a219f6deSJohnny Huang 	u32 prog_address;
1533a219f6deSJohnny Huang 	u32 compare[2];
1534a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1535a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1536a219f6deSJohnny Huang 	u32 data_masked;
1537a219f6deSJohnny Huang 	u32 buf_masked;
153869d5fd8fSJohnny Huang 
1539a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1540d90825e2SJohnny Huang 	otp_soak(0);
1541bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
1542b64ca396SJohnny Huang 		data_masked = otp_conf[i]  & ~conf_ignore[i];
15435010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1544a6d0d645SJohnny Huang 		prog_address = 0x800;
1545a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1546a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1547bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1548bb34a7bfSJohnny Huang 			pass = 1;
1549a6d0d645SJohnny Huang 			continue;
1550bb34a7bfSJohnny Huang 		}
1551de6fbf1cSJohnny Huang 
1552de6fbf1cSJohnny Huang 		otp_soak(1);
15535010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1554a6d0d645SJohnny Huang 
155569d5fd8fSJohnny Huang 		pass = 0;
155669d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
15575010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1558de6fbf1cSJohnny Huang 				otp_soak(2);
1559feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
15605010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1561de6fbf1cSJohnny Huang 					otp_soak(1);
1562de6fbf1cSJohnny Huang 				} else {
1563de6fbf1cSJohnny Huang 					pass = 1;
1564de6fbf1cSJohnny Huang 					break;
1565de6fbf1cSJohnny Huang 				}
1566a6d0d645SJohnny Huang 			} else {
156769d5fd8fSJohnny Huang 				pass = 1;
156869d5fd8fSJohnny Huang 				break;
156969d5fd8fSJohnny Huang 			}
157069d5fd8fSJohnny Huang 		}
1571bb34a7bfSJohnny Huang 		if (pass == 0) {
1572b64ca396SJohnny Huang 			printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n",
1573b64ca396SJohnny Huang 			       i, otp_conf[i], conf[i], conf_ignore[i]);
1574bb34a7bfSJohnny Huang 			break;
1575bb34a7bfSJohnny Huang 		}
1576a6d0d645SJohnny Huang 	}
1577a6d0d645SJohnny Huang 
1578de6fbf1cSJohnny Huang 	otp_soak(0);
157969d5fd8fSJohnny Huang 	if (!pass)
15802a856b9aSJohnny Huang 		return OTP_FAILURE;
1581a6d0d645SJohnny Huang 
15822a856b9aSJohnny Huang 	return OTP_SUCCESS;
158369d5fd8fSJohnny Huang }
158469d5fd8fSJohnny Huang 
1585b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro)
1586b25f02d2SJohnny Huang {
1587b25f02d2SJohnny Huang 	int i, k;
1588b25f02d2SJohnny Huang 	int pass = 0;
1589b25f02d2SJohnny Huang 	u32 prog_address;
1590b25f02d2SJohnny Huang 	u32 compare[2];
1591b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1592b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1593b25f02d2SJohnny Huang 	u32 data_masked;
1594b25f02d2SJohnny Huang 	u32 buf_masked;
1595b25f02d2SJohnny Huang 
1596b25f02d2SJohnny Huang 	printf("Start Programing...\n");
1597b25f02d2SJohnny Huang 	otp_soak(0);
1598b25f02d2SJohnny Huang 	for (i = 0; i < 2; i++) {
1599b25f02d2SJohnny Huang 		data_masked = scu_pro[i]  & ~OTPSCU_IGNORE[i];
1600b25f02d2SJohnny Huang 		buf_masked  = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1601b25f02d2SJohnny Huang 		prog_address = 0xe08 + i * 2;
1602b25f02d2SJohnny Huang 		if (data_masked == buf_masked) {
1603b25f02d2SJohnny Huang 			pass = 1;
1604b25f02d2SJohnny Huang 			continue;
1605b25f02d2SJohnny Huang 		}
1606b25f02d2SJohnny Huang 
1607b25f02d2SJohnny Huang 		otp_soak(1);
1608b25f02d2SJohnny Huang 		otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address);
1609b25f02d2SJohnny Huang 
1610b25f02d2SJohnny Huang 		pass = 0;
1611b25f02d2SJohnny Huang 		for (k = 0; k < RETRY; k++) {
1612b25f02d2SJohnny Huang 			if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1613b25f02d2SJohnny Huang 				otp_soak(2);
1614b25f02d2SJohnny Huang 				otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address);
1615b25f02d2SJohnny Huang 				if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1616b25f02d2SJohnny Huang 					otp_soak(1);
1617b25f02d2SJohnny Huang 				} else {
1618b25f02d2SJohnny Huang 					pass = 1;
1619b25f02d2SJohnny Huang 					break;
1620b25f02d2SJohnny Huang 				}
1621b25f02d2SJohnny Huang 			} else {
1622b25f02d2SJohnny Huang 				pass = 1;
1623b25f02d2SJohnny Huang 				break;
1624b25f02d2SJohnny Huang 			}
1625b25f02d2SJohnny Huang 		}
1626b25f02d2SJohnny Huang 		if (pass == 0) {
1627*b489486eSJohnny Huang 			printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n",
1628b25f02d2SJohnny Huang 			       i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]);
1629b25f02d2SJohnny Huang 			break;
1630b25f02d2SJohnny Huang 		}
1631b25f02d2SJohnny Huang 	}
1632b25f02d2SJohnny Huang 
1633b25f02d2SJohnny Huang 	otp_soak(0);
1634b25f02d2SJohnny Huang 	if (!pass)
1635b25f02d2SJohnny Huang 		return OTP_FAILURE;
1636b25f02d2SJohnny Huang 
1637b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1638b25f02d2SJohnny Huang }
1639b25f02d2SJohnny Huang 
1640b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data)
1641b64ca396SJohnny Huang {
1642b64ca396SJohnny Huang 	int data_dw;
1643b64ca396SJohnny Huang 	u32 data_masked;
1644b64ca396SJohnny Huang 	u32 buf_masked;
1645b64ca396SJohnny Huang 	u32 *buf = (u32 *)image_layout->data;
1646b64ca396SJohnny Huang 	u32 *buf_ignore = (u32 *)image_layout->data_ignore;
1647b64ca396SJohnny Huang 	int i;
1648b64ca396SJohnny Huang 
1649b64ca396SJohnny Huang 	data_dw = image_layout->data_length / 4;
1650b64ca396SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
1651b64ca396SJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1652b64ca396SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1653b64ca396SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
1654b64ca396SJohnny Huang 		if (data_masked == buf_masked)
1655b64ca396SJohnny Huang 			continue;
1656b64ca396SJohnny Huang 		if (i % 2 == 0) {
1657b64ca396SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
1658b64ca396SJohnny Huang 				continue;
1659b64ca396SJohnny Huang 			} else {
1660b64ca396SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1661*b489486eSJohnny Huang 				printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1662*b489486eSJohnny Huang 				printf("Input   [0x%x] = 0x%x\n", i, buf[i]);
1663*b489486eSJohnny Huang 				printf("Mask    [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1664b64ca396SJohnny Huang 				return OTP_FAILURE;
1665b64ca396SJohnny Huang 			}
1666b64ca396SJohnny Huang 		} else {
1667b64ca396SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1668b64ca396SJohnny Huang 				continue;
1669b64ca396SJohnny Huang 			} else {
1670b64ca396SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1671*b489486eSJohnny Huang 				printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1672*b489486eSJohnny Huang 				printf("Input   [0x%x] = 0x%x\n", i, buf[i]);
1673*b489486eSJohnny Huang 				printf("Mask    [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1674b64ca396SJohnny Huang 				return OTP_FAILURE;
1675b64ca396SJohnny Huang 			}
1676b64ca396SJohnny Huang 		}
1677b64ca396SJohnny Huang 	}
1678b64ca396SJohnny Huang 	return OTP_SUCCESS;
1679b64ca396SJohnny Huang }
1680b64ca396SJohnny Huang 
1681b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1682b64ca396SJohnny Huang {
1683b64ca396SJohnny Huang 	int i;
1684b64ca396SJohnny Huang 	u32 *strap;
1685b64ca396SJohnny Huang 	u32 *strap_ignore;
1686b64ca396SJohnny Huang 	u32 *strap_pro;
1687b64ca396SJohnny Huang 	int bit, pbit, ibit;
1688b64ca396SJohnny Huang 	int fail = 0;
1689b64ca396SJohnny Huang 	int ret;
1690b64ca396SJohnny Huang 
1691b64ca396SJohnny Huang 	strap = (u32 *)image_layout->strap;
1692b64ca396SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1693b64ca396SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1694b64ca396SJohnny Huang 
1695b64ca396SJohnny Huang 	for (i = 0; i < 64; i++) {
1696b64ca396SJohnny Huang 		if (i < 32) {
1697b64ca396SJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1698b64ca396SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
1699b64ca396SJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
1700b64ca396SJohnny Huang 		} else {
1701b64ca396SJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1702b64ca396SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1703b64ca396SJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1704b64ca396SJohnny Huang 		}
1705b64ca396SJohnny Huang 
1706b64ca396SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit);
1707b64ca396SJohnny Huang 
1708b64ca396SJohnny Huang 		if (ret == OTP_FAILURE)
1709b64ca396SJohnny Huang 			fail = 1;
1710b64ca396SJohnny Huang 	}
1711b64ca396SJohnny Huang 	if (fail == 1) {
1712b64ca396SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
1713b64ca396SJohnny Huang 		return OTP_FAILURE;
1714b64ca396SJohnny Huang 	}
1715b64ca396SJohnny Huang 	return OTP_SUCCESS;
1716b64ca396SJohnny Huang }
1717b64ca396SJohnny Huang 
1718b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf)
1719b64ca396SJohnny Huang {
1720b64ca396SJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1721b64ca396SJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1722b64ca396SJohnny Huang 	u32 data_masked;
1723b64ca396SJohnny Huang 	u32 buf_masked;
1724b64ca396SJohnny Huang 	int i;
1725b64ca396SJohnny Huang 
1726b64ca396SJohnny Huang 	for (i = 0; i < 16; i++) {
1727b64ca396SJohnny Huang 		data_masked = otp_conf[i]  & ~conf_ignore[i];
1728b64ca396SJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1729b64ca396SJohnny Huang 		if (data_masked == buf_masked)
1730b64ca396SJohnny Huang 			continue;
1731b64ca396SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1732b64ca396SJohnny Huang 			continue;
1733b64ca396SJohnny Huang 		} else {
1734b64ca396SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1735b64ca396SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, otp_conf[i]);
1736b64ca396SJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
1737b64ca396SJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
1738b64ca396SJohnny Huang 			return OTP_FAILURE;
1739b64ca396SJohnny Huang 		}
1740b64ca396SJohnny Huang 	}
1741b64ca396SJohnny Huang 	return OTP_SUCCESS;
1742b64ca396SJohnny Huang }
1743b64ca396SJohnny Huang 
1744b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro)
1745b25f02d2SJohnny Huang {
1746b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1747b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1748b25f02d2SJohnny Huang 	u32 data_masked;
1749b25f02d2SJohnny Huang 	u32 buf_masked;
1750b25f02d2SJohnny Huang 	int i;
1751b25f02d2SJohnny Huang 
1752b25f02d2SJohnny Huang 	for (i = 0; i < 2; i++) {
1753b25f02d2SJohnny Huang 		data_masked = scu_pro[i]  & ~OTPSCU_IGNORE[i];
1754b25f02d2SJohnny Huang 		buf_masked  = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1755b25f02d2SJohnny Huang 		if (data_masked == buf_masked)
1756b25f02d2SJohnny Huang 			continue;
1757b25f02d2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1758b25f02d2SJohnny Huang 			continue;
1759b25f02d2SJohnny Huang 		} else {
1760b25f02d2SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1761*b489486eSJohnny Huang 			printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]);
1762*b489486eSJohnny Huang 			printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]);
1763*b489486eSJohnny Huang 			printf("Mask  [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]);
1764b25f02d2SJohnny Huang 			return OTP_FAILURE;
1765b25f02d2SJohnny Huang 		}
1766b25f02d2SJohnny Huang 	}
1767b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1768b25f02d2SJohnny Huang }
1769b25f02d2SJohnny Huang 
1770f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf)
1771696656c6SJohnny Huang {
1772696656c6SJohnny Huang 	sha256_context ctx;
1773696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1774696656c6SJohnny Huang 
1775696656c6SJohnny Huang 	sha256_starts(&ctx);
1776696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1777696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1778696656c6SJohnny Huang 
1779696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1780f347c284SJohnny Huang 		return OTP_SUCCESS;
1781f347c284SJohnny Huang 	return OTP_FAILURE;
1782696656c6SJohnny Huang }
1783696656c6SJohnny Huang 
1784f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
178569d5fd8fSJohnny Huang {
178669d5fd8fSJohnny Huang 	int ret;
178761a6cda7SJohnny Huang 	int image_soc_ver = 0;
1788696656c6SJohnny Huang 	struct otp_header *otp_header;
1789696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1790696656c6SJohnny Huang 	int image_size;
1791a219f6deSJohnny Huang 	u8 *buf;
1792a219f6deSJohnny Huang 	u8 *checksum;
1793b64ca396SJohnny Huang 	int i;
1794b64ca396SJohnny Huang 	u32 data[2048];
1795b64ca396SJohnny Huang 	u32 conf[16];
1796b25f02d2SJohnny Huang 	u32 scu_pro[2];
1797b64ca396SJohnny Huang 	struct otpstrap_status otpstrap[64];
179869d5fd8fSJohnny Huang 
1799696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1800696656c6SJohnny Huang 	if (!otp_header) {
1801030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
18022a856b9aSJohnny Huang 		return OTP_FAILURE;
180369d5fd8fSJohnny Huang 	}
1804d90825e2SJohnny Huang 
1805696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1806696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1807696656c6SJohnny Huang 
1808696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1809696656c6SJohnny Huang 
1810696656c6SJohnny Huang 	if (!buf) {
1811030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
1812696656c6SJohnny Huang 		return OTP_FAILURE;
1813696656c6SJohnny Huang 	}
1814696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1815696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1816696656c6SJohnny Huang 
1817696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1818030cb4a7SJohnny Huang 		printf("Image is invalid\n");
1819696656c6SJohnny Huang 		return OTP_FAILURE;
1820696656c6SJohnny Huang 	}
1821696656c6SJohnny Huang 
18225010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
18235010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
18245010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
18255010032bSJohnny Huang 
18265010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1827696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
18285010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1829696656c6SJohnny Huang 
1830696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
18315010032bSJohnny Huang 	image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
18325010032bSJohnny Huang 	image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
18335010032bSJohnny Huang 	image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
18347e523e3bSJohnny Huang 
1835b25f02d2SJohnny Huang 	image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info);
1836b25f02d2SJohnny Huang 	image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2);
1837b25f02d2SJohnny Huang 	image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length;
1838b25f02d2SJohnny Huang 
18397e523e3bSJohnny Huang 	if (otp_header->soc_ver == SOC_AST2600A0) {
18407e523e3bSJohnny Huang 		image_soc_ver = OTP_A0;
184161a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A1) {
184261a6cda7SJohnny Huang 		image_soc_ver = OTP_A1;
184361a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A2) {
184461a6cda7SJohnny Huang 		image_soc_ver = OTP_A2;
184561a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A3) {
184661a6cda7SJohnny Huang 		image_soc_ver = OTP_A3;
1847696656c6SJohnny Huang 	} else {
1848030cb4a7SJohnny Huang 		printf("Image SOC Version is not supported\n");
1849696656c6SJohnny Huang 		return OTP_FAILURE;
1850696656c6SJohnny Huang 	}
1851696656c6SJohnny Huang 
185261a6cda7SJohnny Huang 	if (image_soc_ver != info_cb.version) {
1853030cb4a7SJohnny Huang 		printf("Version is not match\n");
18549a4fe690SJohnny Huang 		return OTP_FAILURE;
18559a4fe690SJohnny Huang 	}
18569a4fe690SJohnny Huang 
185761a6cda7SJohnny Huang 	if (otp_header->otptool_ver != OTPTOOL_VERSION(1, 0, 0)) {
1858030cb4a7SJohnny Huang 		printf("OTP image is not generated by otptool v1.0.0\n");
185961a6cda7SJohnny Huang 		return OTP_FAILURE;
186061a6cda7SJohnny Huang 	}
186161a6cda7SJohnny Huang 
1862f347c284SJohnny Huang 	if (otp_verify_image(buf, image_size, checksum)) {
1863030cb4a7SJohnny Huang 		printf("checksum is invalid\n");
1864696656c6SJohnny Huang 		return OTP_FAILURE;
1865d90825e2SJohnny Huang 	}
18667332532cSJohnny Huang 
1867030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
1868030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
1869030cb4a7SJohnny Huang 		return OTP_FAILURE;
1870030cb4a7SJohnny Huang 	}
1871b64ca396SJohnny Huang 	ret = 0;
1872030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
1873030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_data) {
1874030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
1875030cb4a7SJohnny Huang 			ret = -1;
1876030cb4a7SJohnny Huang 		}
1877030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_sec) {
1878030cb4a7SJohnny Huang 			printf("OTP secure region is protected\n");
1879030cb4a7SJohnny Huang 			ret = -1;
1880030cb4a7SJohnny Huang 		}
1881b64ca396SJohnny Huang 		printf("Read OTP Data Region:\n");
1882b64ca396SJohnny Huang 		for (i = 0; i < 2048 ; i += 2)
1883b64ca396SJohnny Huang 			otp_read_data(i, &data[i]);
1884b64ca396SJohnny Huang 
1885b64ca396SJohnny Huang 		printf("Check writable...\n");
1886b64ca396SJohnny Huang 		if (otp_check_data_image(&image_layout, data) == OTP_FAILURE)
1887b64ca396SJohnny Huang 			ret = -1;
1888030cb4a7SJohnny Huang 	}
1889030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
1890030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_conf) {
1891030cb4a7SJohnny Huang 			printf("OTP config region is protected\n");
1892030cb4a7SJohnny Huang 			ret = -1;
1893030cb4a7SJohnny Huang 		}
1894b64ca396SJohnny Huang 		printf("Read OTP Config Region:\n");
1895b64ca396SJohnny Huang 		for (i = 0; i < 16 ; i++)
1896b64ca396SJohnny Huang 			otp_read_conf(i, &conf[i]);
1897b64ca396SJohnny Huang 
1898b64ca396SJohnny Huang 		printf("Check writable...\n");
1899b64ca396SJohnny Huang 		if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE)
1900b64ca396SJohnny Huang 			ret = -1;
1901030cb4a7SJohnny Huang 	}
1902030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
1903030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
1904030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
1905030cb4a7SJohnny Huang 			ret = -1;
1906030cb4a7SJohnny Huang 		}
1907b64ca396SJohnny Huang 		printf("Read OTP Strap Region:\n");
1908b64ca396SJohnny Huang 		otp_strap_status(otpstrap);
1909b64ca396SJohnny Huang 
1910b64ca396SJohnny Huang 		printf("Check writable...\n");
1911b64ca396SJohnny Huang 		if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE)
1912b64ca396SJohnny Huang 			ret = -1;
1913030cb4a7SJohnny Huang 	}
1914b25f02d2SJohnny Huang 	if (otp_header->image_info & OTP_INC_SCU_PRO) {
1915b25f02d2SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
1916b25f02d2SJohnny Huang 			printf("OTP strap region is protected\n");
1917b25f02d2SJohnny Huang 			ret = -1;
1918b25f02d2SJohnny Huang 		}
1919b25f02d2SJohnny Huang 		printf("Read SCU Protect Region:\n");
1920b25f02d2SJohnny Huang 		otp_read_conf(28, &scu_pro[0]);
1921b25f02d2SJohnny Huang 		otp_read_conf(29, &scu_pro[1]);
1922b25f02d2SJohnny Huang 
1923b25f02d2SJohnny Huang 		printf("Check writable...\n");
1924b25f02d2SJohnny Huang 		if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE)
1925b25f02d2SJohnny Huang 			ret = -1;
1926b25f02d2SJohnny Huang 	}
1927030cb4a7SJohnny Huang 	if (ret == -1)
1928030cb4a7SJohnny Huang 		return OTP_FAILURE;
1929b64ca396SJohnny Huang 
193069d5fd8fSJohnny Huang 	if (!nconfirm) {
1931696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
19327f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1933f347c284SJohnny Huang 			if (otp_print_data_image(&image_layout) < 0) {
193469d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
19352a856b9aSJohnny Huang 				return OTP_FAILURE;
193669d5fd8fSJohnny Huang 			}
193769d5fd8fSJohnny Huang 		}
1938696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
19397332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1940696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
19417332532cSJohnny Huang 				printf("OTP config error, please check.\n");
19427332532cSJohnny Huang 				return OTP_FAILURE;
19437332532cSJohnny Huang 			}
19447332532cSJohnny Huang 		}
19457adec5f6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
19467adec5f6SJohnny Huang 			printf("\nOTP strap region :\n");
19477adec5f6SJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
19487adec5f6SJohnny Huang 				printf("OTP strap error, please check.\n");
19497adec5f6SJohnny Huang 				return OTP_FAILURE;
19507adec5f6SJohnny Huang 			}
19517adec5f6SJohnny Huang 		}
1952b25f02d2SJohnny Huang 		if (otp_header->image_info & OTP_INC_SCU_PRO) {
1953b25f02d2SJohnny Huang 			printf("\nOTP scu protect region :\n");
1954b25f02d2SJohnny Huang 			if (otp_print_scu_image(&image_layout) < 0) {
1955b25f02d2SJohnny Huang 				printf("OTP scu protect error, please check.\n");
1956b25f02d2SJohnny Huang 				return OTP_FAILURE;
1957b25f02d2SJohnny Huang 			}
1958b25f02d2SJohnny Huang 		}
19597332532cSJohnny Huang 
196069d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
196169d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
196269d5fd8fSJohnny Huang 			printf(" Aborting\n");
19632a856b9aSJohnny Huang 			return OTP_FAILURE;
196469d5fd8fSJohnny Huang 		}
196569d5fd8fSJohnny Huang 	}
19667332532cSJohnny Huang 
19675010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
19685010032bSJohnny Huang 		printf("programing data region ...\n");
1969b64ca396SJohnny Huang 		ret = otp_prog_data(&image_layout, data);
19705010032bSJohnny Huang 		if (ret != 0) {
19715010032bSJohnny Huang 			printf("Error\n");
19725010032bSJohnny Huang 			return ret;
19735010032bSJohnny Huang 		}
1974a219f6deSJohnny Huang 		printf("Done\n");
19755010032bSJohnny Huang 	}
19765010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
19775010032bSJohnny Huang 		printf("programing strap region ...\n");
1978b64ca396SJohnny Huang 		ret = otp_prog_strap(&image_layout, otpstrap);
19795010032bSJohnny Huang 		if (ret != 0) {
19805010032bSJohnny Huang 			printf("Error\n");
19815010032bSJohnny Huang 			return ret;
19825010032bSJohnny Huang 		}
1983a219f6deSJohnny Huang 		printf("Done\n");
19845010032bSJohnny Huang 	}
1985b25f02d2SJohnny Huang 	if (otp_header->image_info & OTP_INC_SCU_PRO) {
1986b25f02d2SJohnny Huang 		printf("programing scu protect region ...\n");
1987b25f02d2SJohnny Huang 		ret = otp_prog_scu_protect(&image_layout, scu_pro);
1988b25f02d2SJohnny Huang 		if (ret != 0) {
1989b25f02d2SJohnny Huang 			printf("Error\n");
1990b25f02d2SJohnny Huang 			return ret;
1991b25f02d2SJohnny Huang 		}
1992b25f02d2SJohnny Huang 		printf("Done\n");
1993b25f02d2SJohnny Huang 	}
19945010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
19955010032bSJohnny Huang 		printf("programing configuration region ...\n");
1996b64ca396SJohnny Huang 		ret = otp_prog_conf(&image_layout, conf);
19975010032bSJohnny Huang 		if (ret != 0) {
19985010032bSJohnny Huang 			printf("Error\n");
19995010032bSJohnny Huang 			return ret;
20005010032bSJohnny Huang 		}
20015010032bSJohnny Huang 		printf("Done\n");
20025010032bSJohnny Huang 	}
2003cd1610b4SJohnny Huang 
20047332532cSJohnny Huang 	return OTP_SUCCESS;
20052a856b9aSJohnny Huang }
20062a856b9aSJohnny Huang 
2007f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
2008cd1610b4SJohnny Huang {
2009a219f6deSJohnny Huang 	u32 read[2];
2010a219f6deSJohnny Huang 	u32 prog_address = 0;
201166f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
2012cd1610b4SJohnny Huang 	int otp_bit;
201383655e91SJohnny Huang 	int ret = 0;
2014cd1610b4SJohnny Huang 
2015dacbba92SJohnny Huang 	otp_soak(0);
2016cd1610b4SJohnny Huang 	switch (mode) {
2017a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
2018f347c284SJohnny Huang 		otp_read_conf(otp_dw_offset, read);
2019cd1610b4SJohnny Huang 		prog_address = 0x800;
2020cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
2021cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
2022a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
2023cd1610b4SJohnny Huang 		if (otp_bit == value) {
2024*b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2025cd1610b4SJohnny Huang 			printf("No need to program\n");
20262a856b9aSJohnny Huang 			return OTP_SUCCESS;
2027cd1610b4SJohnny Huang 		}
2028cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
2029*b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
20300dc9a440SJohnny Huang 			printf("OTP is programmed, which can't be clean\n");
20312a856b9aSJohnny Huang 			return OTP_FAILURE;
2032cd1610b4SJohnny Huang 		}
2033*b489486eSJohnny Huang 		printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2034cd1610b4SJohnny Huang 		break;
2035a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
2036cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
2037cd1610b4SJohnny Huang 
2038cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
2039a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
2040a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
2041643b9cfdSJohnny Huang 
2042643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
2043*b489486eSJohnny Huang 				printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2044b64ca396SJohnny Huang 				printf("OTP is programmed, which can't be cleared\n");
2045643b9cfdSJohnny Huang 				return OTP_FAILURE;
2046643b9cfdSJohnny Huang 			}
2047cd1610b4SJohnny Huang 		} else {
2048a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
2049a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
2050643b9cfdSJohnny Huang 
2051643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
2052*b489486eSJohnny Huang 				printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2053b64ca396SJohnny Huang 				printf("OTP is programmed, which can't be written\n");
2054643b9cfdSJohnny Huang 				return OTP_FAILURE;
2055643b9cfdSJohnny Huang 			}
2056cd1610b4SJohnny Huang 		}
2057cd1610b4SJohnny Huang 		if (otp_bit == value) {
2058*b489486eSJohnny Huang 			printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2059cd1610b4SJohnny Huang 			printf("No need to program\n");
20602a856b9aSJohnny Huang 			return OTP_SUCCESS;
2061cd1610b4SJohnny Huang 		}
2062643b9cfdSJohnny Huang 
2063*b489486eSJohnny Huang 		printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2064cd1610b4SJohnny Huang 		break;
2065a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
20668848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
20678848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
20687e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
20698848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
20708848d5dcSJohnny Huang 			return OTP_FAILURE;
20718848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
20728848d5dcSJohnny Huang 			return OTP_SUCCESS;
2073a6af4a17SJohnny Huang 
2074cd1610b4SJohnny Huang 		break;
2075cd1610b4SJohnny Huang 	}
2076cd1610b4SJohnny Huang 
2077cd1610b4SJohnny Huang 	if (!nconfirm) {
2078cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2079cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
2080cd1610b4SJohnny Huang 			printf(" Aborting\n");
20812a856b9aSJohnny Huang 			return OTP_FAILURE;
2082cd1610b4SJohnny Huang 		}
2083cd1610b4SJohnny Huang 	}
2084cd1610b4SJohnny Huang 
2085cd1610b4SJohnny Huang 	switch (mode) {
2086a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
2087f347c284SJohnny Huang 		ret =  otp_prog_strap_b(bit_offset, value);
208883655e91SJohnny Huang 		break;
2089a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
2090a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
2091f347c284SJohnny Huang 		ret = otp_prog_dc_b(value, prog_address, bit_offset);
2092de6fbf1cSJohnny Huang 		break;
2093de6fbf1cSJohnny Huang 	}
2094de6fbf1cSJohnny Huang 	otp_soak(0);
209583655e91SJohnny Huang 	if (ret) {
20960dc9a440SJohnny Huang 		printf("OTP cannot be programmed\n");
2097794e27ecSJohnny Huang 		printf("FAILURE\n");
2098794e27ecSJohnny Huang 		return OTP_FAILURE;
2099794e27ecSJohnny Huang 	}
2100794e27ecSJohnny Huang 
21019009c25dSJohnny Huang 	printf("SUCCESS\n");
21022a856b9aSJohnny Huang 	return OTP_SUCCESS;
2103a219f6deSJohnny Huang }
2104a219f6deSJohnny Huang 
2105794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
2106794e27ecSJohnny Huang {
2107794e27ecSJohnny Huang 	u32 otp_rid[2];
2108a8789b47SJohnny Huang 	u32 sw_rid[2];
2109794e27ecSJohnny Huang 	int rid_num = 0;
2110a8789b47SJohnny Huang 	int sw_rid_num = 0;
2111794e27ecSJohnny Huang 	int bit_offset;
2112794e27ecSJohnny Huang 	int dw_offset;
2113794e27ecSJohnny Huang 	int i;
2114794e27ecSJohnny Huang 	int ret;
2115794e27ecSJohnny Huang 
2116f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2117f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2118794e27ecSJohnny Huang 
2119a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2120a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2121a8789b47SJohnny Huang 
2122794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2123a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2124a8789b47SJohnny Huang 
2125a8789b47SJohnny Huang 	if (sw_rid_num < 0) {
2126a8789b47SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
2127a8789b47SJohnny Huang 		return OTP_FAILURE;
2128a8789b47SJohnny Huang 	}
2129a8789b47SJohnny Huang 
2130a8789b47SJohnny Huang 	if (update_num > sw_rid_num) {
2131a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
2132a8789b47SJohnny Huang 		printf("update number could not bigger than current SW revision id\n");
2133a8789b47SJohnny Huang 		return OTP_FAILURE;
2134a8789b47SJohnny Huang 	}
2135794e27ecSJohnny Huang 
2136794e27ecSJohnny Huang 	if (rid_num < 0) {
2137b64ca396SJohnny Huang 		printf("Current OTP revision ID cannot handle by this command,\n"
2138b64ca396SJohnny Huang 		       "please use 'otp pb' command to update it manually\n");
2139794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
21409009c25dSJohnny Huang 		return OTP_FAILURE;
21419009c25dSJohnny Huang 	}
2142cd1610b4SJohnny Huang 
2143794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
2144794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2145794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
2146794e27ecSJohnny Huang 
2147a8789b47SJohnny Huang 	if (rid_num > update_num) {
2148a8789b47SJohnny Huang 		printf("OTP rev_id is bigger than 0x%X\n", update_num);
2149a8789b47SJohnny Huang 		printf("Skip\n");
2150a8789b47SJohnny Huang 		return OTP_FAILURE;
2151a8789b47SJohnny Huang 	} else if (rid_num == update_num) {
2152a8789b47SJohnny Huang 		printf("OTP rev_id is same as input\n");
2153794e27ecSJohnny Huang 		printf("Skip\n");
2154794e27ecSJohnny Huang 		return OTP_FAILURE;
2155794e27ecSJohnny Huang 	}
2156794e27ecSJohnny Huang 
2157794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
2158794e27ecSJohnny Huang 		if (i < 32) {
2159794e27ecSJohnny Huang 			dw_offset = 0xa;
2160794e27ecSJohnny Huang 			bit_offset = i;
2161794e27ecSJohnny Huang 		} else {
2162794e27ecSJohnny Huang 			dw_offset = 0xb;
2163794e27ecSJohnny Huang 			bit_offset = i - 32;
2164794e27ecSJohnny Huang 		}
2165*b489486eSJohnny Huang 		printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset);
2166794e27ecSJohnny Huang 		if (i + 1 != update_num)
2167794e27ecSJohnny Huang 			printf(", ");
2168794e27ecSJohnny Huang 	}
2169794e27ecSJohnny Huang 
2170794e27ecSJohnny Huang 	printf(" will be programmed\n");
2171794e27ecSJohnny Huang 	if (force == 0) {
2172794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2173794e27ecSJohnny Huang 		if (!confirm_yesno()) {
2174794e27ecSJohnny Huang 			printf(" Aborting\n");
2175794e27ecSJohnny Huang 			return OTP_FAILURE;
2176794e27ecSJohnny Huang 		}
2177794e27ecSJohnny Huang 	}
2178794e27ecSJohnny Huang 
2179794e27ecSJohnny Huang 	ret = 0;
2180794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
2181794e27ecSJohnny Huang 		if (i < 32) {
2182794e27ecSJohnny Huang 			dw_offset = 0xa04;
2183794e27ecSJohnny Huang 			bit_offset = i;
2184794e27ecSJohnny Huang 		} else {
2185794e27ecSJohnny Huang 			dw_offset = 0xa06;
2186794e27ecSJohnny Huang 			bit_offset = i - 32;
2187794e27ecSJohnny Huang 		}
2188f347c284SJohnny Huang 		if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
2189*b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset);
2190794e27ecSJohnny Huang 			ret = OTP_FAILURE;
2191794e27ecSJohnny Huang 			break;
2192794e27ecSJohnny Huang 		}
2193794e27ecSJohnny Huang 	}
2194061d3279SJohnny Huang 	otp_soak(0);
2195f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2196f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2197794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2198794e27ecSJohnny Huang 	if (rid_num >= 0)
2199794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
2200794e27ecSJohnny Huang 	else
2201794e27ecSJohnny Huang 		printf("OTP revision ID\n");
2202794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2203794e27ecSJohnny Huang 	if (!ret)
2204794e27ecSJohnny Huang 		printf("SUCCESS\n");
2205794e27ecSJohnny Huang 	else
2206794e27ecSJohnny Huang 		printf("FAILED\n");
2207794e27ecSJohnny Huang 	return ret;
2208794e27ecSJohnny Huang }
2209794e27ecSJohnny Huang 
22102a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
221169d5fd8fSJohnny Huang {
2212a219f6deSJohnny Huang 	u32 offset, count;
22132a856b9aSJohnny Huang 	int ret;
221469d5fd8fSJohnny Huang 
22152a856b9aSJohnny Huang 	if (argc == 4) {
22162a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
22172a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
22182a856b9aSJohnny Huang 	} else if (argc == 3) {
22192a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
22202a856b9aSJohnny Huang 		count = 1;
22212a856b9aSJohnny Huang 	} else {
222269d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
222369d5fd8fSJohnny Huang 	}
222469d5fd8fSJohnny Huang 
2225030cb4a7SJohnny Huang 	if (!strcmp(argv[1], "conf"))
2226f347c284SJohnny Huang 		ret = otp_print_conf(offset, count);
2227030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "data"))
22282a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
2229030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "strap"))
22302a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
2231030cb4a7SJohnny Huang 	else
22322a856b9aSJohnny Huang 		return CMD_RET_USAGE;
223369d5fd8fSJohnny Huang 
22342a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
22352a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
22362a856b9aSJohnny Huang 	return CMD_RET_USAGE;
22372a856b9aSJohnny Huang }
22382a856b9aSJohnny Huang 
22392a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
22402a856b9aSJohnny Huang {
22412a856b9aSJohnny Huang 	phys_addr_t addr;
22422a856b9aSJohnny Huang 	int ret;
22432a856b9aSJohnny Huang 
2244de6b0cc4SJohnny Huang 	if (argc == 3) {
2245ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
22462a856b9aSJohnny Huang 			return CMD_RET_USAGE;
22472a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
2248f347c284SJohnny Huang 		ret = otp_prog_image(addr, 1);
2249de6b0cc4SJohnny Huang 	} else if (argc == 2) {
22502a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
2251f347c284SJohnny Huang 		ret = otp_prog_image(addr, 0);
22522a856b9aSJohnny Huang 	} else {
22532a856b9aSJohnny Huang 		return CMD_RET_USAGE;
22542a856b9aSJohnny Huang 	}
22552a856b9aSJohnny Huang 
22562a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
22572a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
22582a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
22592a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
22602a856b9aSJohnny Huang 	else
22612a856b9aSJohnny Huang 		return CMD_RET_USAGE;
22622a856b9aSJohnny Huang }
22632a856b9aSJohnny Huang 
22642a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
22652a856b9aSJohnny Huang {
22662a856b9aSJohnny Huang 	int mode = 0;
22672a856b9aSJohnny Huang 	int nconfirm = 0;
22682a856b9aSJohnny Huang 	int otp_addr = 0;
22692a856b9aSJohnny Huang 	int bit_offset;
22702a856b9aSJohnny Huang 	int value;
22712a856b9aSJohnny Huang 	int ret;
2272030cb4a7SJohnny Huang 	u32 otp_strap_pro;
22732a856b9aSJohnny Huang 
22742a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
22752a856b9aSJohnny Huang 		return CMD_RET_USAGE;
22762a856b9aSJohnny Huang 
22772a856b9aSJohnny Huang 	/* Drop the pb cmd */
22782a856b9aSJohnny Huang 	argc--;
22792a856b9aSJohnny Huang 	argv++;
22802a856b9aSJohnny Huang 
22812a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2282a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
22832a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2284a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
22852a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2286a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2287cd1610b4SJohnny Huang 	else
22882a856b9aSJohnny Huang 		return CMD_RET_USAGE;
22892a856b9aSJohnny Huang 
22902a856b9aSJohnny Huang 	/* Drop the region cmd */
22912a856b9aSJohnny Huang 	argc--;
22922a856b9aSJohnny Huang 	argv++;
22932a856b9aSJohnny Huang 
2294ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2295cd1610b4SJohnny Huang 		nconfirm = 1;
22962a856b9aSJohnny Huang 		/* Drop the force option */
22972a856b9aSJohnny Huang 		argc--;
22982a856b9aSJohnny Huang 		argv++;
22992a856b9aSJohnny Huang 	}
2300cd1610b4SJohnny Huang 
2301a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
23022a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
23032a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
23040808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
23052a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2306cd1610b4SJohnny Huang 	} else {
23072a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
23082a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
23092a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
23100808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
23112a856b9aSJohnny Huang 			return CMD_RET_USAGE;
23120808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
231378855207SJohnny Huang 			if (otp_addr >= 0x800)
23140808cc55SJohnny Huang 				return CMD_RET_USAGE;
23150808cc55SJohnny Huang 		} else {
231678855207SJohnny Huang 			if (otp_addr >= 0x20)
23170808cc55SJohnny Huang 				return CMD_RET_USAGE;
23180808cc55SJohnny Huang 		}
2319cd1610b4SJohnny Huang 	}
2320cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
23212a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2322cd1610b4SJohnny Huang 
2323030cb4a7SJohnny Huang 	ret = 0;
2324030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
2325030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
2326030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2327030cb4a7SJohnny Huang 	}
2328030cb4a7SJohnny Huang 	if (mode == OTP_REGION_DATA) {
2329030cb4a7SJohnny Huang 		if (info_cb.pro_sts.sec_size == 0) {
2330030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_data) {
2331030cb4a7SJohnny Huang 				printf("OTP data region is protected\n");
2332030cb4a7SJohnny Huang 				ret = -1;
2333030cb4a7SJohnny Huang 			}
2334030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) {
2335030cb4a7SJohnny Huang 			printf("OTP secure region is not readable, skip it to prevent unpredictable result\n");
2336030cb4a7SJohnny Huang 			ret = -1;
2337030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size) {
2338030cb4a7SJohnny Huang 			// header region(0x0~0x40) is still readable even secure region is set.
2339030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_sec) {
2340030cb4a7SJohnny Huang 				printf("OTP secure region is protected\n");
2341030cb4a7SJohnny Huang 				ret = -1;
2342030cb4a7SJohnny Huang 			}
2343030cb4a7SJohnny Huang 		} else if (info_cb.pro_sts.pro_data) {
2344030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
2345030cb4a7SJohnny Huang 			ret = -1;
2346030cb4a7SJohnny Huang 		}
2347030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_CONF) {
2348030cb4a7SJohnny Huang 		if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) {
2349030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_conf) {
2350030cb4a7SJohnny Huang 				printf("OTP config region is protected\n");
2351030cb4a7SJohnny Huang 				ret = -1;
2352030cb4a7SJohnny Huang 			}
2353030cb4a7SJohnny Huang 		} else if (otp_addr == 10 || otp_addr == 11) {
2354030cb4a7SJohnny Huang 			u32 otp_rid[2];
2355030cb4a7SJohnny Huang 			u32 sw_rid[2];
2356030cb4a7SJohnny Huang 			u64 *otp_rid64 = (u64 *)otp_rid;
2357030cb4a7SJohnny Huang 			u64 *sw_rid64 = (u64 *)sw_rid;
2358030cb4a7SJohnny Huang 
2359030cb4a7SJohnny Huang 			otp_read_conf(10, &otp_rid[0]);
2360030cb4a7SJohnny Huang 			otp_read_conf(11, &otp_rid[1]);
2361030cb4a7SJohnny Huang 			sw_rid[0] = readl(SW_REV_ID0);
2362030cb4a7SJohnny Huang 			sw_rid[1] = readl(SW_REV_ID1);
2363030cb4a7SJohnny Huang 
2364030cb4a7SJohnny Huang 			if (otp_addr == 10)
2365030cb4a7SJohnny Huang 				otp_rid[0] |= 1 << bit_offset;
2366030cb4a7SJohnny Huang 			else
2367030cb4a7SJohnny Huang 				otp_rid[1] |= 1 << bit_offset;
2368030cb4a7SJohnny Huang 
2369030cb4a7SJohnny Huang 			if (*otp_rid64 > *sw_rid64) {
2370030cb4a7SJohnny Huang 				printf("update number could not bigger than current SW revision id\n");
2371030cb4a7SJohnny Huang 				ret = -1;
2372030cb4a7SJohnny Huang 			}
2373030cb4a7SJohnny Huang 		} else if (otp_addr == 4) {
2374030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_key_ret) {
2375030cb4a7SJohnny Huang 				printf("OTPCFG4 is protected\n");
2376030cb4a7SJohnny Huang 				ret = -1;
2377030cb4a7SJohnny Huang 			} else {
2378030cb4a7SJohnny Huang 				if ((bit_offset >= 0 && bit_offset <= 7) ||
2379030cb4a7SJohnny Huang 				    (bit_offset >= 16 && bit_offset <= 23)) {
2380030cb4a7SJohnny Huang 					u32 key_num;
2381030cb4a7SJohnny Huang 					u32 retire;
2382030cb4a7SJohnny Huang 
2383030cb4a7SJohnny Huang 					key_num = readl(SEC_KEY_NUM) & 3;
2384030cb4a7SJohnny Huang 					if (bit_offset >= 16)
2385030cb4a7SJohnny Huang 						retire = bit_offset - 16;
2386030cb4a7SJohnny Huang 					else
2387030cb4a7SJohnny Huang 						retire = bit_offset;
2388030cb4a7SJohnny Huang 					if (retire >= key_num) {
2389030cb4a7SJohnny Huang 						printf("Retire key id is equal or bigger than current boot key\n");
2390030cb4a7SJohnny Huang 						ret = -1;
2391030cb4a7SJohnny Huang 					}
2392030cb4a7SJohnny Huang 				}
2393030cb4a7SJohnny Huang 			}
2394030cb4a7SJohnny Huang 		} else if (otp_addr >= 16 && otp_addr <= 31) {
2395030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_strap) {
2396030cb4a7SJohnny Huang 				printf("OTP strap region is protected\n");
2397030cb4a7SJohnny Huang 				ret = -1;
2398030cb4a7SJohnny Huang 			} else if ((otp_addr < 30 && info_cb.version == OTP_A0) ||
2399030cb4a7SJohnny Huang 				   (otp_addr < 28 && info_cb.version != OTP_A0)) {
2400030cb4a7SJohnny Huang 				if (otp_addr % 2 == 0)
2401030cb4a7SJohnny Huang 					otp_read_conf(30, &otp_strap_pro);
2402030cb4a7SJohnny Huang 				else
2403030cb4a7SJohnny Huang 					otp_read_conf(31, &otp_strap_pro);
2404030cb4a7SJohnny Huang 				if (otp_strap_pro >> bit_offset & 0x1) {
2405*b489486eSJohnny Huang 					printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset);
2406030cb4a7SJohnny Huang 					ret = -1;
2407030cb4a7SJohnny Huang 				}
2408030cb4a7SJohnny Huang 			}
2409030cb4a7SJohnny Huang 		}
2410030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_STRAP) {
2411030cb4a7SJohnny Huang 		// per bit protection will check in otp_strap_bit_confirm
2412030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
2413030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
2414030cb4a7SJohnny Huang 			ret = -1;
2415030cb4a7SJohnny Huang 		}
2416030cb4a7SJohnny Huang 	}
2417030cb4a7SJohnny Huang 
2418030cb4a7SJohnny Huang 	if (ret == -1)
2419030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2420030cb4a7SJohnny Huang 
2421f347c284SJohnny Huang 	ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
24222a856b9aSJohnny Huang 
24232a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
24242a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
24252a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
24262a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
24272a856b9aSJohnny Huang 	else
24282a856b9aSJohnny Huang 		return CMD_RET_USAGE;
24292a856b9aSJohnny Huang }
24302a856b9aSJohnny Huang 
24312a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
24322a856b9aSJohnny Huang {
24332a856b9aSJohnny Huang 	phys_addr_t addr;
24342a856b9aSJohnny Huang 	int otp_addr = 0;
2435b8590031SJohnny Huang 	int ret;
24362a856b9aSJohnny Huang 
24372a856b9aSJohnny Huang 	if (argc != 3)
24382a856b9aSJohnny Huang 		return CMD_RET_USAGE;
24392a856b9aSJohnny Huang 
24402a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
24412a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
2442b8590031SJohnny Huang 	ret = otp_compare(otp_addr, addr);
2443b8590031SJohnny Huang 	if (ret == 0) {
244469d5fd8fSJohnny Huang 		printf("Compare pass\n");
24452a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2446a219f6deSJohnny Huang 	}
244769d5fd8fSJohnny Huang 	printf("Compare fail\n");
24482a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
244969d5fd8fSJohnny Huang }
245069d5fd8fSJohnny Huang 
245166f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
245266f2f8e5SJohnny Huang {
2453a8bd6d8cSJohnny Huang 	int view = 0;
24542d4b0742SJohnny Huang 	int input;
2455a8bd6d8cSJohnny Huang 
2456a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
245766f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
245866f2f8e5SJohnny Huang 
24592d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
24602d4b0742SJohnny Huang 		if (argc == 3) {
24612d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
24622d4b0742SJohnny Huang 			otp_print_conf_info(input);
24632d4b0742SJohnny Huang 		} else {
24642d4b0742SJohnny Huang 			otp_print_conf_info(-1);
24652d4b0742SJohnny Huang 		}
24662d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
24672d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2468a8bd6d8cSJohnny Huang 			view = 1;
2469a8bd6d8cSJohnny Huang 			/* Drop the view option */
2470a8bd6d8cSJohnny Huang 			argc--;
2471a8bd6d8cSJohnny Huang 			argv++;
2472a8bd6d8cSJohnny Huang 		}
2473b458cd62SJohnny Huang 		otp_print_strap_info(view);
24740dc9a440SJohnny Huang 	} else if (!strcmp(argv[1], "scu")) {
24750dc9a440SJohnny Huang 		otp_print_scu_info();
247666f2f8e5SJohnny Huang 	} else {
247766f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
247866f2f8e5SJohnny Huang 	}
24792d4b0742SJohnny Huang 
248066f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
248166f2f8e5SJohnny Huang }
248266f2f8e5SJohnny Huang 
24830dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2484737ed20bSJohnny Huang {
24850dc9a440SJohnny Huang 	u32 input;
24860dc9a440SJohnny Huang 	u32 bit_offset;
2487e14b073cSJohnny Huang 	u32 prog_address;
2488030cb4a7SJohnny Huang 	char force;
248983655e91SJohnny Huang 	int ret;
2490a219f6deSJohnny Huang 
2491737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2492737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2493737ed20bSJohnny Huang 
2494e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2495737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2496030cb4a7SJohnny Huang 		force = 1;
2497737ed20bSJohnny Huang 	} else {
2498737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2499030cb4a7SJohnny Huang 		force = 0;
2500737ed20bSJohnny Huang 	}
2501737ed20bSJohnny Huang 
2502737ed20bSJohnny Huang 	if (input < 32) {
2503737ed20bSJohnny Huang 		bit_offset = input;
25040dc9a440SJohnny Huang 		prog_address = 0xe0c;
2505737ed20bSJohnny Huang 	} else if (input < 64) {
2506737ed20bSJohnny Huang 		bit_offset = input - 32;
25070dc9a440SJohnny Huang 		prog_address = 0xe0e;
2508737ed20bSJohnny Huang 	} else {
2509737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2510737ed20bSJohnny Huang 	}
2511737ed20bSJohnny Huang 
2512030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
2513030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
2514030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2515030cb4a7SJohnny Huang 	}
2516030cb4a7SJohnny Huang 
2517030cb4a7SJohnny Huang 	if (!force) {
2518*b489486eSJohnny Huang 		printf("OTPSTRAP[0x%X] will be protected\n", input);
2519030cb4a7SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2520030cb4a7SJohnny Huang 		if (!confirm_yesno()) {
2521030cb4a7SJohnny Huang 			printf(" Aborting\n");
2522030cb4a7SJohnny Huang 			return CMD_RET_FAILURE;
2523030cb4a7SJohnny Huang 		}
2524030cb4a7SJohnny Huang 	}
2525030cb4a7SJohnny Huang 
2526e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2527*b489486eSJohnny Huang 		printf("OTPSTRAP[0x%X] already protected\n", input);
2528e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2529e14b073cSJohnny Huang 	}
2530de6fbf1cSJohnny Huang 
2531f347c284SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
2532de6fbf1cSJohnny Huang 	otp_soak(0);
253383655e91SJohnny Huang 
253483655e91SJohnny Huang 	if (ret) {
2535*b489486eSJohnny Huang 		printf("Protect OTPSTRAP[0x%X] fail\n", input);
2536737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2537737ed20bSJohnny Huang 	}
25389a4fe690SJohnny Huang 
2539*b489486eSJohnny Huang 	printf("OTPSTRAP[0x%X] is protected\n", input);
2540794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2541794e27ecSJohnny Huang }
2542794e27ecSJohnny Huang 
25430dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2544e14b073cSJohnny Huang {
25450dc9a440SJohnny Huang 	u32 scu_offset;
25460dc9a440SJohnny Huang 	u32 bit_offset;
25470dc9a440SJohnny Huang 	u32 conf_offset;
25480dc9a440SJohnny Huang 	u32 prog_address;
25490dc9a440SJohnny Huang 	char force;
25500dc9a440SJohnny Huang 	int ret;
25510dc9a440SJohnny Huang 
25520dc9a440SJohnny Huang 	if (argc != 4 && argc != 3)
25530dc9a440SJohnny Huang 		return CMD_RET_USAGE;
25540dc9a440SJohnny Huang 
25550dc9a440SJohnny Huang 	if (!strcmp(argv[1], "o")) {
25560dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[2], NULL, 16);
25570dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[3], NULL, 16);
25580dc9a440SJohnny Huang 		force = 1;
25590dc9a440SJohnny Huang 	} else {
25600dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[1], NULL, 16);
25610dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[2], NULL, 16);
25620dc9a440SJohnny Huang 		force = 0;
25630dc9a440SJohnny Huang 	}
25640dc9a440SJohnny Huang 	if (scu_offset == 0x500) {
25650dc9a440SJohnny Huang 		prog_address = 0xe08;
25660dc9a440SJohnny Huang 		conf_offset = 28;
25670dc9a440SJohnny Huang 	} else if (scu_offset == 0x510) {
25680dc9a440SJohnny Huang 		prog_address = 0xe0a;
25690dc9a440SJohnny Huang 		conf_offset = 29;
25700dc9a440SJohnny Huang 	} else {
25710dc9a440SJohnny Huang 		return CMD_RET_USAGE;
25720dc9a440SJohnny Huang 	}
25730dc9a440SJohnny Huang 	if (bit_offset < 0 || bit_offset > 31)
25740dc9a440SJohnny Huang 		return CMD_RET_USAGE;
2575030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
2576030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
2577030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2578030cb4a7SJohnny Huang 	}
25790dc9a440SJohnny Huang 	if (!force) {
2580*b489486eSJohnny Huang 		printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset);
2581*b489486eSJohnny Huang 		printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset);
25820dc9a440SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
25830dc9a440SJohnny Huang 		if (!confirm_yesno()) {
25840dc9a440SJohnny Huang 			printf(" Aborting\n");
25850dc9a440SJohnny Huang 			return CMD_RET_FAILURE;
25860dc9a440SJohnny Huang 		}
2587e14b073cSJohnny Huang 	}
2588e14b073cSJohnny Huang 
25890dc9a440SJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2590*b489486eSJohnny Huang 		printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset);
25910dc9a440SJohnny Huang 		return CMD_RET_SUCCESS;
25920dc9a440SJohnny Huang 	}
25930dc9a440SJohnny Huang 
25940dc9a440SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
25950dc9a440SJohnny Huang 	otp_soak(0);
25960dc9a440SJohnny Huang 
25970dc9a440SJohnny Huang 	if (ret) {
2598*b489486eSJohnny Huang 		printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset);
25990dc9a440SJohnny Huang 		return CMD_RET_FAILURE;
26000dc9a440SJohnny Huang 	}
26010dc9a440SJohnny Huang 
2602*b489486eSJohnny Huang 	printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset);
26030dc9a440SJohnny Huang 	return CMD_RET_SUCCESS;
2604e14b073cSJohnny Huang }
2605e14b073cSJohnny Huang 
2606f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2607f67375f7SJohnny Huang {
2608e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
2609f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2610f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2611f67375f7SJohnny Huang 
2612f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2613f67375f7SJohnny Huang }
2614f67375f7SJohnny Huang 
2615794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2616794e27ecSJohnny Huang {
2617794e27ecSJohnny Huang 	u32 update_num;
2618794e27ecSJohnny Huang 	int force = 0;
2619794e27ecSJohnny Huang 	int ret;
2620794e27ecSJohnny Huang 
2621794e27ecSJohnny Huang 	if (argc == 3) {
2622794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2623794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2624794e27ecSJohnny Huang 		force = 1;
2625794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2626794e27ecSJohnny Huang 	} else if (argc == 2) {
2627794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2628794e27ecSJohnny Huang 	} else {
2629794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2630794e27ecSJohnny Huang 	}
2631794e27ecSJohnny Huang 
2632794e27ecSJohnny Huang 	if (update_num > 64)
2633794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2634794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2635b8590031SJohnny Huang 
2636794e27ecSJohnny Huang 	if (ret)
2637794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2638794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2639794e27ecSJohnny Huang }
2640794e27ecSJohnny Huang 
2641794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2642794e27ecSJohnny Huang {
2643794e27ecSJohnny Huang 	u32 otp_rid[2];
2644a8789b47SJohnny Huang 	u32 sw_rid[2];
2645794e27ecSJohnny Huang 	int rid_num = 0;
2646a8789b47SJohnny Huang 	int sw_rid_num = 0;
2647794e27ecSJohnny Huang 	int ret;
2648794e27ecSJohnny Huang 
2649794e27ecSJohnny Huang 	if (argc != 1)
2650794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2651794e27ecSJohnny Huang 
2652f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2653f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2654794e27ecSJohnny Huang 
2655a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2656a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2657794e27ecSJohnny Huang 
2658a8789b47SJohnny Huang 	rid_num = get_rid_num(otp_rid);
2659a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2660a8789b47SJohnny Huang 
2661030cb4a7SJohnny Huang 	if (sw_rid_num < 0) {
2662030cb4a7SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
2663030cb4a7SJohnny Huang 		printf("SEC68:0x%x\n", sw_rid[0]);
2664030cb4a7SJohnny Huang 		printf("SEC6C:0x%x\n", sw_rid[1]);
2665030cb4a7SJohnny Huang 	} else {
2666a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
2667030cb4a7SJohnny Huang 	}
2668794e27ecSJohnny Huang 	if (rid_num >= 0) {
2669794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2670794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2671794e27ecSJohnny Huang 	} else {
2672b64ca396SJohnny Huang 		printf("Current OTP revision ID cannot handle by 'otp update',\n"
2673b64ca396SJohnny Huang 		       "please use 'otp pb' command to update it manually\n"
2674794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2675794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2676794e27ecSJohnny Huang 	}
2677794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2678794e27ecSJohnny Huang 
2679794e27ecSJohnny Huang 	return ret;
2680794e27ecSJohnny Huang }
2681794e27ecSJohnny Huang 
26822a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2683f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
26842a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2685a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2686de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
26872a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2688737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
26890dc9a440SJohnny Huang 	U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""),
26902a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2691794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2692794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
26932a856b9aSJohnny Huang };
26942a856b9aSJohnny Huang 
26952a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
26962a856b9aSJohnny Huang {
2697030cb4a7SJohnny Huang 	struct otp_pro_sts *pro_sts;
26982a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2699a219f6deSJohnny Huang 	u32 ver;
2700e14b073cSJohnny Huang 	int ret;
2701030cb4a7SJohnny Huang 	u32 otp_conf0;
27022a856b9aSJohnny Huang 
27032a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
27042a856b9aSJohnny Huang 
2705737ed20bSJohnny Huang 	/* Drop the otp command */
27062a856b9aSJohnny Huang 	argc--;
27072a856b9aSJohnny Huang 	argv++;
27082a856b9aSJohnny Huang 
2709a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
27102a856b9aSJohnny Huang 		return CMD_RET_USAGE;
27112a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
27122a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
27132a856b9aSJohnny Huang 
27140dae9d52SJohnny Huang 	ver = chip_version();
27150dae9d52SJohnny Huang 	switch (ver) {
2716e417205bSJohnny Huang 	case OTP_A0:
2717e417205bSJohnny Huang 		info_cb.version = OTP_A0;
27189a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
27199a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
27209a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
27219a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
27229a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
27239a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2724e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
27250dae9d52SJohnny Huang 		break;
2726e417205bSJohnny Huang 	case OTP_A1:
2727e417205bSJohnny Huang 		info_cb.version = OTP_A1;
27283cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
27293cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
27303cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
27313cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
27329a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
27339a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
27340dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
27350dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2736e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
27370dae9d52SJohnny Huang 		break;
2738e417205bSJohnny Huang 	case OTP_A2:
2739e417205bSJohnny Huang 		info_cb.version = OTP_A2;
27405fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
27415fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
2742fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2743fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
27445fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
27455fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
27460dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
27470dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2748e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
27490dae9d52SJohnny Huang 		break;
2750e417205bSJohnny Huang 	case OTP_A3:
2751e417205bSJohnny Huang 		info_cb.version = OTP_A3;
2752b63af886SJohnny Huang 		info_cb.conf_info = a3_conf_info;
2753b63af886SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
2754fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2755fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
2756181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2757181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
27580dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
27590dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2760e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
276164b66712SJohnny Huang 		break;
27620dae9d52SJohnny Huang 	default:
2763f1be5099SJohnny Huang 		printf("SOC is not supported\n");
27640dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
27659a4fe690SJohnny Huang 	}
27669a4fe690SJohnny Huang 
2767030cb4a7SJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2768030cb4a7SJohnny Huang 	otp_read_conf(0, &otp_conf0);
2769030cb4a7SJohnny Huang 	pro_sts = &info_cb.pro_sts;
2770030cb4a7SJohnny Huang 
2771030cb4a7SJohnny Huang 	pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1;
2772030cb4a7SJohnny Huang 	pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1;
2773030cb4a7SJohnny Huang 	pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1;
2774030cb4a7SJohnny Huang 	pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1;
2775030cb4a7SJohnny Huang 	pro_sts->pro_data = (otp_conf0 >> 23) & 0x1;
2776030cb4a7SJohnny Huang 	pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1;
2777030cb4a7SJohnny Huang 	pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5;
2778030cb4a7SJohnny Huang 
2779e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2780b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
2781e14b073cSJohnny Huang 
2782e14b073cSJohnny Huang 	return ret;
278369d5fd8fSJohnny Huang }
278469d5fd8fSJohnny Huang 
2785a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
278669d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2787f67375f7SJohnny Huang 	   "version\n"
2788f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
27892a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
27902d4b0742SJohnny Huang 	   "otp info strap [v]\n"
27912d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
27920dc9a440SJohnny Huang 	   "otp info scu\n"
2793de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2794ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2795ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2796ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
27970dc9a440SJohnny Huang 	   "otp scuprotect [o] <scu_offset> <bit_offset>\n"
2798794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2799794e27ecSJohnny Huang 	   "otp rid\n"
280069d5fd8fSJohnny Huang 	  );
2801