xref: /openbmc/u-boot/cmd/otp.c (revision e7e21c4455937427b95934f61c48824737c20816)
1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+
269d5fd8fSJohnny Huang /*
3a219f6deSJohnny Huang  * Copyright 2021 Aspeed Technology Inc.
469d5fd8fSJohnny Huang  */
5e417205bSJohnny Huang 
64c1c9b35SJohnny Huang #include <stdlib.h>
769d5fd8fSJohnny Huang #include <common.h>
869d5fd8fSJohnny Huang #include <console.h>
969d5fd8fSJohnny Huang #include <bootretry.h>
1069d5fd8fSJohnny Huang #include <cli.h>
1169d5fd8fSJohnny Huang #include <command.h>
1269d5fd8fSJohnny Huang #include <console.h>
134c1c9b35SJohnny Huang #include <malloc.h>
1469d5fd8fSJohnny Huang #include <inttypes.h>
1569d5fd8fSJohnny Huang #include <mapmem.h>
1669d5fd8fSJohnny Huang #include <asm/io.h>
1769d5fd8fSJohnny Huang #include <linux/compiler.h>
182031a123SJohnny Huang #include <linux/iopoll.h>
19*e7e21c44SJohnny Huang #include <u-boot/sha256.h>
20a3dcef30SJohnny Huang #include <u-boot/sha512.h>
21*e7e21c44SJohnny Huang #include <u-boot/rsa.h>
22*e7e21c44SJohnny Huang #include <u-boot/rsa-mod-exp.h>
23*e7e21c44SJohnny Huang #include <dm.h>
240cee9a95SJohnny Huang #include "otp_info.h"
2569d5fd8fSJohnny Huang 
2669d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2769d5fd8fSJohnny Huang 
28a3dcef30SJohnny Huang #define OTP_VER				"2.0.0"
29f67375f7SJohnny Huang 
3069d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
31dacbba92SJohnny Huang #define RETRY				20
327332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
337332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
347332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3569d5fd8fSJohnny Huang 
362a856b9aSJohnny Huang #define OTP_USAGE			-1
372a856b9aSJohnny Huang #define OTP_FAILURE			-2
382a856b9aSJohnny Huang #define OTP_SUCCESS			0
392a856b9aSJohnny Huang 
40a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
41a6af4a17SJohnny Huang 
42181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB		1
43181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV		2
44181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES		3
45181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT		4
46181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC		5
479a4fe690SJohnny Huang 
48*e7e21c44SJohnny Huang #define OTP_LIT_END			0
49*e7e21c44SJohnny Huang #define OTP_BIG_END			1
50*e7e21c44SJohnny Huang 
513d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
523d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
533d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
543d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
553d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
563d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
573d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
583d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
593d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
603d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
61a8789b47SJohnny Huang #define SW_REV_ID0		OTP_BASE + 0x68
62a8789b47SJohnny Huang #define SW_REV_ID1		OTP_BASE + 0x6c
63030cb4a7SJohnny Huang #define SEC_KEY_NUM		OTP_BASE + 0x78
643d3688adSJohnny Huang 
65696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
66*e7e21c44SJohnny Huang #define CHECKSUM_LEN		64
67a219f6deSJohnny Huang #define OTP_INC_DATA		BIT(31)
68a219f6deSJohnny Huang #define OTP_INC_CONFIG		BIT(30)
69a219f6deSJohnny Huang #define OTP_INC_STRAP		BIT(29)
70a219f6deSJohnny Huang #define OTP_ECC_EN		BIT(28)
71b25f02d2SJohnny Huang #define OTP_INC_SCU_PRO		BIT(25)
72696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
73696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
74696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
75696656c6SJohnny Huang 
76e417205bSJohnny Huang #define OTP_A0		0
77e417205bSJohnny Huang #define OTP_A1		1
78e417205bSJohnny Huang #define OTP_A2		2
79e417205bSJohnny Huang #define OTP_A3		3
80e417205bSJohnny Huang 
81e417205bSJohnny Huang #define ID0_AST2600A0	0x05000303
82e417205bSJohnny Huang #define ID1_AST2600A0	0x05000303
83e417205bSJohnny Huang #define ID0_AST2600A1	0x05010303
8421a8cfceSJohnny Huang #define ID1_AST2600A1	0x05010303
85e417205bSJohnny Huang #define ID0_AST2600A2	0x05010303
86e417205bSJohnny Huang #define ID1_AST2600A2	0x05020303
87e417205bSJohnny Huang #define ID0_AST2600A3	0x05030303
88e417205bSJohnny Huang #define ID1_AST2600A3	0x05030303
89e417205bSJohnny Huang #define ID0_AST2620A1	0x05010203
90e417205bSJohnny Huang #define ID1_AST2620A1	0x05010203
91e417205bSJohnny Huang #define ID0_AST2620A2	0x05010203
92e417205bSJohnny Huang #define ID1_AST2620A2	0x05020203
93e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
94e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
95e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
96e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
97e417205bSJohnny Huang #define ID0_AST2605A2	0x05010103
98e417205bSJohnny Huang #define ID1_AST2605A2	0x05020103
99e417205bSJohnny Huang #define ID0_AST2605A3	0x05030103
100e417205bSJohnny Huang #define ID1_AST2605A3	0x05030103
101e417205bSJohnny Huang #define ID0_AST2625A3	0x05030403
102e417205bSJohnny Huang #define ID1_AST2625A3	0x05030403
103696656c6SJohnny Huang 
10461a6cda7SJohnny Huang #define SOC_AST2600A0	0
10561a6cda7SJohnny Huang #define SOC_AST2600A1	1
10661a6cda7SJohnny Huang #define SOC_AST2600A2	2
10761a6cda7SJohnny Huang #define SOC_AST2600A3	3
10861a6cda7SJohnny Huang 
10961a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c))
1105e096f11SJohnny Huang #define OTPTOOL_VERSION_MAJOR(x) (((x) >> 24) & 0xff)
1115e096f11SJohnny Huang #define OTPTOOL_VERSION_PATCHLEVEL(x) (((x) >> 12) & 0xfff)
1125e096f11SJohnny Huang #define OTPTOOL_VERSION_SUBLEVEL(x) ((x) & 0xfff)
113a3dcef30SJohnny Huang #define OTPTOOL_COMPT_VERSION 2
11461a6cda7SJohnny Huang 
115696656c6SJohnny Huang struct otp_header {
116696656c6SJohnny Huang 	u8	otp_magic[8];
11761a6cda7SJohnny Huang 	u32	soc_ver;
11861a6cda7SJohnny Huang 	u32	otptool_ver;
119696656c6SJohnny Huang 	u32	image_info;
120696656c6SJohnny Huang 	u32	data_info;
121696656c6SJohnny Huang 	u32	config_info;
122696656c6SJohnny Huang 	u32	strap_info;
1237e523e3bSJohnny Huang 	u32	scu_protect_info;
124696656c6SJohnny Huang 	u32	checksum_offset;
125a219f6deSJohnny Huang } __packed;
126696656c6SJohnny Huang 
12766f2f8e5SJohnny Huang struct otpstrap_status {
12869d5fd8fSJohnny Huang 	int value;
12969d5fd8fSJohnny Huang 	int option_array[7];
13069d5fd8fSJohnny Huang 	int remain_times;
13169d5fd8fSJohnny Huang 	int writeable_option;
13269d5fd8fSJohnny Huang 	int protected;
13369d5fd8fSJohnny Huang };
13469d5fd8fSJohnny Huang 
1359a4fe690SJohnny Huang struct otpkey_type {
1369a4fe690SJohnny Huang 	int value;
1379a4fe690SJohnny Huang 	int key_type;
138*e7e21c44SJohnny Huang 	int order;
1399a4fe690SJohnny Huang 	int need_id;
1409a4fe690SJohnny Huang 	char information[110];
1419a4fe690SJohnny Huang };
1429a4fe690SJohnny Huang 
143030cb4a7SJohnny Huang struct otp_pro_sts {
144030cb4a7SJohnny Huang 	char mem_lock;
145030cb4a7SJohnny Huang 	char pro_key_ret;
146030cb4a7SJohnny Huang 	char pro_strap;
147030cb4a7SJohnny Huang 	char pro_conf;
148030cb4a7SJohnny Huang 	char pro_data;
149030cb4a7SJohnny Huang 	char pro_sec;
150030cb4a7SJohnny Huang 	u32 sec_size;
151030cb4a7SJohnny Huang };
152030cb4a7SJohnny Huang 
1539a4fe690SJohnny Huang struct otp_info_cb {
1549a4fe690SJohnny Huang 	int version;
155e417205bSJohnny Huang 	char ver_name[3];
15679e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1579a4fe690SJohnny Huang 	int strap_info_len;
15879e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1599a4fe690SJohnny Huang 	int conf_info_len;
16079e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1619a4fe690SJohnny Huang 	int key_info_len;
1620dc9a440SJohnny Huang 	const struct scu_info *scu_info;
1630dc9a440SJohnny Huang 	int scu_info_len;
164030cb4a7SJohnny Huang 	struct otp_pro_sts pro_sts;
1659a4fe690SJohnny Huang };
1669a4fe690SJohnny Huang 
167696656c6SJohnny Huang struct otp_image_layout {
1685010032bSJohnny Huang 	int data_length;
1695010032bSJohnny Huang 	int conf_length;
1705010032bSJohnny Huang 	int strap_length;
171b25f02d2SJohnny Huang 	int scu_pro_length;
172a219f6deSJohnny Huang 	u8 *data;
173a219f6deSJohnny Huang 	u8 *data_ignore;
174a219f6deSJohnny Huang 	u8 *conf;
175a219f6deSJohnny Huang 	u8 *conf_ignore;
176a219f6deSJohnny Huang 	u8 *strap;
177a219f6deSJohnny Huang 	u8 *strap_pro;
178a219f6deSJohnny Huang 	u8 *strap_ignore;
179b25f02d2SJohnny Huang 	u8 *scu_pro;
180b25f02d2SJohnny Huang 	u8 *scu_pro_ignore;
181696656c6SJohnny Huang };
182696656c6SJohnny Huang 
183*e7e21c44SJohnny Huang struct sb_info {
184*e7e21c44SJohnny Huang 	int header_offset;
185*e7e21c44SJohnny Huang 	int secure_region;
186*e7e21c44SJohnny Huang 	int rsa_algo;
187*e7e21c44SJohnny Huang 	int sha_algo;
188*e7e21c44SJohnny Huang 	int digest_len;
189*e7e21c44SJohnny Huang 	int retire_list[8];
190*e7e21c44SJohnny Huang 	int enc_flag;
191*e7e21c44SJohnny Huang };
192*e7e21c44SJohnny Huang 
193*e7e21c44SJohnny Huang struct key_list {
194*e7e21c44SJohnny Huang 	const struct otpkey_type *key_info;
195*e7e21c44SJohnny Huang 	int offset;
196*e7e21c44SJohnny Huang 	int id;
197*e7e21c44SJohnny Huang 	int retire;
198*e7e21c44SJohnny Huang };
199*e7e21c44SJohnny Huang 
200*e7e21c44SJohnny Huang struct sb_header {
201*e7e21c44SJohnny Huang 	u32 aes_data_offset;
202*e7e21c44SJohnny Huang 	u32 enc_offset;
203*e7e21c44SJohnny Huang 	u32 sign_image_size;
204*e7e21c44SJohnny Huang 	u32 signature_offset;
205*e7e21c44SJohnny Huang 	u32 revision_low;
206*e7e21c44SJohnny Huang 	u32 revision_high;
207*e7e21c44SJohnny Huang 	u32 reserved;
208*e7e21c44SJohnny Huang 	u32 bl1_header_checksum;
209*e7e21c44SJohnny Huang };
210*e7e21c44SJohnny Huang 
2119a4fe690SJohnny Huang static struct otp_info_cb info_cb;
2129a4fe690SJohnny Huang 
21379e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
214*e7e21c44SJohnny Huang 	{0, OTP_KEY_TYPE_AES,       OTP_LIT_END, 0, "AES-256 as OEM platform key for image encryption/decryption"},
215*e7e21c44SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT,     OTP_LIT_END, 0, "AES-256 as secret vault key"},
216*e7e21c44SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,      OTP_LIT_END, 1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
217*e7e21c44SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"},
218*e7e21c44SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   OTP_LIT_END, 0, "RSA-public as SOC public key"},
219*e7e21c44SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  OTP_LIT_END, 0, "RSA-public as AES key decryption key"},
220*e7e21c44SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as SOC private key"},
221*e7e21c44SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"},
2229a4fe690SJohnny Huang };
2239a4fe690SJohnny Huang 
22479e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
225*e7e21c44SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT,     OTP_LIT_END, 0, "AES-256 as secret vault key"},
226*e7e21c44SJohnny Huang 	{2, OTP_KEY_TYPE_AES,       OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
227*e7e21c44SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"},
228*e7e21c44SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  OTP_LIT_END, 0, "RSA-public as AES key decryption key"},
229*e7e21c44SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"},
2309a4fe690SJohnny Huang };
2319a4fe690SJohnny Huang 
2325fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
233*e7e21c44SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT,     OTP_LIT_END, 0, "AES-256 as secret vault key"},
234*e7e21c44SJohnny Huang 	{2, OTP_KEY_TYPE_AES,       OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
235*e7e21c44SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"},
236*e7e21c44SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  OTP_LIT_END, 0, "RSA-public as AES key decryption key"},
237*e7e21c44SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"},
238181f72d8SJohnny Huang };
239181f72d8SJohnny Huang 
240181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
241*e7e21c44SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT,     OTP_LIT_END, 0, "AES-256 as secret vault key"},
242*e7e21c44SJohnny Huang 	{2, OTP_KEY_TYPE_AES,       OTP_LIT_END, 1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
243*e7e21c44SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   OTP_LIT_END, 1, "RSA-public as OEM DSS public keys in Mode 2"},
244*e7e21c44SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   OTP_BIG_END, 1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
245*e7e21c44SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  OTP_LIT_END, 0, "RSA-public as AES key decryption key"},
246*e7e21c44SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  OTP_BIG_END, 0, "RSA-public as AES key decryption key(big endian)"},
247*e7e21c44SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV, OTP_LIT_END, 0, "RSA-private as AES key decryption key"},
248*e7e21c44SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV, OTP_BIG_END, 0, "RSA-private as AES key decryption key(big endian)"},
2495fdde29fSJohnny Huang };
2505fdde29fSJohnny Huang 
251f347c284SJohnny Huang static void buf_print(u8 *buf, int len)
252f347c284SJohnny Huang {
253f347c284SJohnny Huang 	int i;
254f347c284SJohnny Huang 
255f347c284SJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
256f347c284SJohnny Huang 	for (i = 0; i < len; i++) {
257f347c284SJohnny Huang 		if (i % 16 == 0)
258f347c284SJohnny Huang 			printf("%04X: ", i);
259f347c284SJohnny Huang 		printf("%02X ", buf[i]);
260f347c284SJohnny Huang 		if ((i + 1) % 16 == 0)
261f347c284SJohnny Huang 			printf("\n");
262f347c284SJohnny Huang 	}
26388bd7d58SJohnny Huang 	printf("\n");
264f347c284SJohnny Huang }
265f347c284SJohnny Huang 
266794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
267794e27ecSJohnny Huang {
268794e27ecSJohnny Huang 	int bit_offset;
269794e27ecSJohnny Huang 	int i;
270794e27ecSJohnny Huang 
271794e27ecSJohnny Huang 	if (offset < 32) {
272794e27ecSJohnny Huang 		i = 0;
273794e27ecSJohnny Huang 		bit_offset = offset;
274794e27ecSJohnny Huang 	} else {
275794e27ecSJohnny Huang 		i = 1;
276794e27ecSJohnny Huang 		bit_offset = offset - 32;
277794e27ecSJohnny Huang 	}
278794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
279794e27ecSJohnny Huang 		return 1;
280794e27ecSJohnny Huang 	else
281794e27ecSJohnny Huang 		return 0;
282794e27ecSJohnny Huang }
283794e27ecSJohnny Huang 
284794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
285794e27ecSJohnny Huang {
286794e27ecSJohnny Huang 	int i;
287794e27ecSJohnny Huang 	int fz = 0;
288794e27ecSJohnny Huang 	int rid_num = 0;
289794e27ecSJohnny Huang 	int ret = 0;
290794e27ecSJohnny Huang 
291794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
292794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
293794e27ecSJohnny Huang 			if (!fz)
294794e27ecSJohnny Huang 				fz = 1;
295794e27ecSJohnny Huang 
296794e27ecSJohnny Huang 		} else {
297794e27ecSJohnny Huang 			rid_num++;
298794e27ecSJohnny Huang 			if (fz)
299794e27ecSJohnny Huang 				ret = OTP_FAILURE;
300794e27ecSJohnny Huang 		}
301794e27ecSJohnny Huang 	}
302794e27ecSJohnny Huang 	if (ret)
303794e27ecSJohnny Huang 		return ret;
304794e27ecSJohnny Huang 
305794e27ecSJohnny Huang 	return rid_num;
306794e27ecSJohnny Huang }
307794e27ecSJohnny Huang 
308*e7e21c44SJohnny Huang static void sb_sha256(u8 *src, u32 len, u8 *digest_ret)
309*e7e21c44SJohnny Huang {
310*e7e21c44SJohnny Huang 	sha256_context ctx;
311*e7e21c44SJohnny Huang 
312*e7e21c44SJohnny Huang 	sha256_starts(&ctx);
313*e7e21c44SJohnny Huang 	sha256_update(&ctx, src, len);
314*e7e21c44SJohnny Huang 	sha256_finish(&ctx, digest_ret);
315*e7e21c44SJohnny Huang }
316*e7e21c44SJohnny Huang 
317*e7e21c44SJohnny Huang static void sb_sha384(u8 *src, u32 len, u8 *digest_ret)
318*e7e21c44SJohnny Huang {
319*e7e21c44SJohnny Huang 	sha512_context ctx;
320*e7e21c44SJohnny Huang 
321*e7e21c44SJohnny Huang 	sha384_starts(&ctx);
322*e7e21c44SJohnny Huang 	sha384_update(&ctx, src, len);
323*e7e21c44SJohnny Huang 	sha384_finish(&ctx, digest_ret);
324*e7e21c44SJohnny Huang }
325*e7e21c44SJohnny Huang 
326*e7e21c44SJohnny Huang static void sb_sha512(u8 *src, u32 len, u8 *digest_ret)
327*e7e21c44SJohnny Huang {
328*e7e21c44SJohnny Huang 	sha512_context ctx;
329*e7e21c44SJohnny Huang 
330*e7e21c44SJohnny Huang 	sha512_starts(&ctx);
331*e7e21c44SJohnny Huang 	sha512_update(&ctx, src, len);
332*e7e21c44SJohnny Huang 	sha512_finish(&ctx, digest_ret);
333*e7e21c44SJohnny Huang }
334*e7e21c44SJohnny Huang 
335a219f6deSJohnny Huang static u32 chip_version(void)
3369a4fe690SJohnny Huang {
337e417205bSJohnny Huang 	u32 revid0, revid1;
3389a4fe690SJohnny Huang 
339e417205bSJohnny Huang 	revid0 = readl(ASPEED_REVISION_ID0);
340e417205bSJohnny Huang 	revid1 = readl(ASPEED_REVISION_ID1);
3419a4fe690SJohnny Huang 
342e417205bSJohnny Huang 	if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
343badd21c2SJohnny Huang 		/* AST2600-A0 */
344e417205bSJohnny Huang 		return OTP_A0;
345e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
346badd21c2SJohnny Huang 		/* AST2600-A1 */
347e417205bSJohnny Huang 		return OTP_A1;
348e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
349badd21c2SJohnny Huang 		/* AST2600-A2 */
350e417205bSJohnny Huang 		return OTP_A2;
351e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
35264b66712SJohnny Huang 		/* AST2600-A3 */
353e417205bSJohnny Huang 		return OTP_A3;
354e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
355e417205bSJohnny Huang 		/* AST2620-A1 */
356e417205bSJohnny Huang 		return OTP_A1;
357e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
358e417205bSJohnny Huang 		/* AST2620-A2 */
359e417205bSJohnny Huang 		return OTP_A2;
360e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
36164b66712SJohnny Huang 		/* AST2620-A3 */
362e417205bSJohnny Huang 		return OTP_A3;
363e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
364e417205bSJohnny Huang 		/* AST2605-A2 */
365e417205bSJohnny Huang 		return OTP_A2;
366e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
367e417205bSJohnny Huang 		/* AST2605-A3 */
368e417205bSJohnny Huang 		return OTP_A3;
369e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
370e417205bSJohnny Huang 		/* AST2605-A3 */
371e417205bSJohnny Huang 		return OTP_A3;
3720dae9d52SJohnny Huang 	}
373f347c284SJohnny Huang 	return OTP_FAILURE;
3749a4fe690SJohnny Huang }
3759a4fe690SJohnny Huang 
3762031a123SJohnny Huang static int wait_complete(void)
3773d3688adSJohnny Huang {
3782031a123SJohnny Huang 	u32 val;
3792031a123SJohnny Huang 	int ret;
3803d3688adSJohnny Huang 
3812031a123SJohnny Huang 	udelay(1);
3822031a123SJohnny Huang 	ret = readl_poll_timeout(OTP_STATUS, val, (val & 0x6) == 0x6, 100000);
3832031a123SJohnny Huang 	if (ret)
3842031a123SJohnny Huang 		printf("%s: timeout, SEC14 = 0x%x\n", __func__, val);
3852031a123SJohnny Huang 
3862031a123SJohnny Huang 	return ret;
3873d3688adSJohnny Huang }
3883d3688adSJohnny Huang 
389a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
390dacbba92SJohnny Huang {
391dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
392dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
393dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
394dacbba92SJohnny Huang 	wait_complete();
395dacbba92SJohnny Huang }
396dacbba92SJohnny Huang 
397dacbba92SJohnny Huang static void otp_soak(int soak)
398dacbba92SJohnny Huang {
399e417205bSJohnny Huang 	if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
400dacbba92SJohnny Huang 		switch (soak) {
401dacbba92SJohnny Huang 		case 0: //default
402377f8cd7SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
403377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
404dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
405dacbba92SJohnny Huang 			break;
406dacbba92SJohnny Huang 		case 1: //normal program
407377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
408377f8cd7SJohnny Huang 			otp_write(0x5000, 0x1008); // Write MRB
409377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0024); // Write MR
410feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
411dacbba92SJohnny Huang 			break;
412dacbba92SJohnny Huang 		case 2: //soak program
413377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
414377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0007); // Write MRB
415377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0100); // Write MR
416feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
417dacbba92SJohnny Huang 			break;
418dacbba92SJohnny Huang 		}
419dacbba92SJohnny Huang 	} else {
420dacbba92SJohnny Huang 		switch (soak) {
421dacbba92SJohnny Huang 		case 0: //default
422dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
423dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
424dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
425dacbba92SJohnny Huang 			break;
426dacbba92SJohnny Huang 		case 1: //normal program
427dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
428dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
429dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
430feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
431dacbba92SJohnny Huang 			break;
432dacbba92SJohnny Huang 		case 2: //soak program
433dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
434dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
435dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
436feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
437dacbba92SJohnny Huang 			break;
438dacbba92SJohnny Huang 		}
439dacbba92SJohnny Huang 	}
440dacbba92SJohnny Huang 
441dacbba92SJohnny Huang 	wait_complete();
442dacbba92SJohnny Huang }
443dacbba92SJohnny Huang 
444a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
44569d5fd8fSJohnny Huang {
4463d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
4473d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4483d3688adSJohnny Huang 	wait_complete();
4493d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
4503d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
45169d5fd8fSJohnny Huang }
45269d5fd8fSJohnny Huang 
453f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data)
45469d5fd8fSJohnny Huang {
45569d5fd8fSJohnny Huang 	int config_offset;
45669d5fd8fSJohnny Huang 
45769d5fd8fSJohnny Huang 	config_offset = 0x800;
45869d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
45969d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
46069d5fd8fSJohnny Huang 
4613d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
4623d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4633d3688adSJohnny Huang 	wait_complete();
4643d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
46569d5fd8fSJohnny Huang }
46669d5fd8fSJohnny Huang 
467a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
46869d5fd8fSJohnny Huang {
469a219f6deSJohnny Huang 	u32 ret;
470a219f6deSJohnny Huang 	u32 *buf;
47169d5fd8fSJohnny Huang 
47269d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
47369d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
47469d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
47569d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
47669d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
4773d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
4783d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
4793d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
4803d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
4813d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
4823d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
4833d3688adSJohnny Huang 	wait_complete();
4843d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
48569d5fd8fSJohnny Huang 	if (ret & 0x1)
486f347c284SJohnny Huang 		return OTP_SUCCESS;
48769d5fd8fSJohnny Huang 	else
488f347c284SJohnny Huang 		return OTP_FAILURE;
48969d5fd8fSJohnny Huang }
49069d5fd8fSJohnny Huang 
491a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
49269d5fd8fSJohnny Huang {
493a219f6deSJohnny Huang 	u32 ret[2];
49469d5fd8fSJohnny Huang 
49530a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4963d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
49730a8c590SJohnny Huang 	else
4983d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
49930a8c590SJohnny Huang 
5003d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
5013d3688adSJohnny Huang 	wait_complete();
5023d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
5033d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
50483655e91SJohnny Huang 
50530a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
50630a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
507f347c284SJohnny Huang 			return OTP_SUCCESS;
50869d5fd8fSJohnny Huang 		else
509f347c284SJohnny Huang 			return OTP_FAILURE;
51030a8c590SJohnny Huang 	} else {
51130a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
512f347c284SJohnny Huang 			return OTP_SUCCESS;
51330a8c590SJohnny Huang 		else
514f347c284SJohnny Huang 			return OTP_FAILURE;
51530a8c590SJohnny Huang 	}
51669d5fd8fSJohnny Huang }
51769d5fd8fSJohnny Huang 
518a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
5194c1c9b35SJohnny Huang {
520a219f6deSJohnny Huang 	u32 ret[2];
5214c1c9b35SJohnny Huang 
5224c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
5234c1c9b35SJohnny Huang 
5244c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
5253d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
5264c1c9b35SJohnny Huang 	else
5273d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
5283d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
5293d3688adSJohnny Huang 	wait_complete();
5303d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
5313d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
5324c1c9b35SJohnny Huang 	if (size == 1) {
5334c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
5344c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
535696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
5364c1c9b35SJohnny Huang 				compare[0] = 0;
537f347c284SJohnny Huang 				return OTP_SUCCESS;
538a219f6deSJohnny Huang 			}
5394c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
540f347c284SJohnny Huang 			return OTP_FAILURE;
5414c1c9b35SJohnny Huang 
5424c1c9b35SJohnny Huang 		} else {
5434c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
544696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
5454c1c9b35SJohnny Huang 				compare[0] = ~0;
546f347c284SJohnny Huang 				return OTP_SUCCESS;
547a219f6deSJohnny Huang 			}
548d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
549f347c284SJohnny Huang 			return OTP_FAILURE;
5504c1c9b35SJohnny Huang 		}
5514c1c9b35SJohnny Huang 	} else if (size == 2) {
5524c1c9b35SJohnny Huang 		// otp_addr should be even
553696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
5544c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
5554c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
5564c1c9b35SJohnny Huang 			compare[0] = 0;
5574c1c9b35SJohnny Huang 			compare[1] = ~0;
558f347c284SJohnny Huang 			return OTP_SUCCESS;
559a219f6deSJohnny Huang 		}
5604c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
5614c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
5624c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
5634c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
564f347c284SJohnny Huang 		return OTP_FAILURE;
5654c1c9b35SJohnny Huang 	} else {
566f347c284SJohnny Huang 		return OTP_FAILURE;
5674c1c9b35SJohnny Huang 	}
5684c1c9b35SJohnny Huang }
5694c1c9b35SJohnny Huang 
5702031a123SJohnny Huang static int otp_prog(u32 otp_addr, u32 prog_bit)
57183655e91SJohnny Huang {
57290965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
57383655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
57483655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
57583655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
5762031a123SJohnny Huang 
5772031a123SJohnny Huang 	return wait_complete();
57883655e91SJohnny Huang }
57983655e91SJohnny Huang 
5802031a123SJohnny Huang static int _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
58183655e91SJohnny Huang {
58283655e91SJohnny Huang 	int prog_bit;
58383655e91SJohnny Huang 
58483655e91SJohnny Huang 	if (prog_address % 2 == 0) {
58583655e91SJohnny Huang 		if (value)
58683655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
58783655e91SJohnny Huang 		else
5882031a123SJohnny Huang 			return 0;
58983655e91SJohnny Huang 	} else {
590e417205bSJohnny Huang 		if (info_cb.version != OTP_A3)
59183655e91SJohnny Huang 			prog_address |= 1 << 15;
59283655e91SJohnny Huang 		if (!value)
59383655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
59483655e91SJohnny Huang 		else
5952031a123SJohnny Huang 			return 0;
59683655e91SJohnny Huang 	}
5972031a123SJohnny Huang 	return otp_prog(prog_address, prog_bit);
59883655e91SJohnny Huang }
59983655e91SJohnny Huang 
600f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset)
60183655e91SJohnny Huang {
60283655e91SJohnny Huang 	int pass;
60383655e91SJohnny Huang 	int i;
6042031a123SJohnny Huang 	int ret;
60583655e91SJohnny Huang 
60683655e91SJohnny Huang 	otp_soak(1);
6072031a123SJohnny Huang 	ret = _otp_prog_bit(value, prog_address, bit_offset);
6082031a123SJohnny Huang 	if (ret)
6092031a123SJohnny Huang 		return OTP_FAILURE;
61083655e91SJohnny Huang 	pass = 0;
61183655e91SJohnny Huang 
61283655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
61383655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
61483655e91SJohnny Huang 			otp_soak(2);
6152031a123SJohnny Huang 			ret = _otp_prog_bit(value, prog_address, bit_offset);
6162031a123SJohnny Huang 			if (ret)
6172031a123SJohnny Huang 				return OTP_FAILURE;
61883655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
61983655e91SJohnny Huang 				otp_soak(1);
62083655e91SJohnny Huang 			} else {
62183655e91SJohnny Huang 				pass = 1;
62283655e91SJohnny Huang 				break;
62383655e91SJohnny Huang 			}
62483655e91SJohnny Huang 		} else {
62583655e91SJohnny Huang 			pass = 1;
62683655e91SJohnny Huang 			break;
62783655e91SJohnny Huang 		}
62883655e91SJohnny Huang 	}
629794e27ecSJohnny Huang 	if (pass)
630794e27ecSJohnny Huang 		return OTP_SUCCESS;
63183655e91SJohnny Huang 
632794e27ecSJohnny Huang 	return OTP_FAILURE;
63383655e91SJohnny Huang }
63483655e91SJohnny Huang 
6352031a123SJohnny Huang static int otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
636d90825e2SJohnny Huang {
637d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
6382031a123SJohnny Huang 	int ret;
639d90825e2SJohnny Huang 
640d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
641696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
642d90825e2SJohnny Huang 			continue;
643d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
644d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
645d90825e2SJohnny Huang 			if (bit_value)
646d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
647d90825e2SJohnny Huang 			else
648d90825e2SJohnny Huang 				continue;
649d90825e2SJohnny Huang 		} else {
650e417205bSJohnny Huang 			if (info_cb.version != OTP_A3)
651d90825e2SJohnny Huang 				prog_address |= 1 << 15;
652d90825e2SJohnny Huang 			if (bit_value)
653d90825e2SJohnny Huang 				continue;
654d90825e2SJohnny Huang 			else
655d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
656d90825e2SJohnny Huang 		}
6572031a123SJohnny Huang 		ret = otp_prog(prog_address, prog_bit);
6582031a123SJohnny Huang 		if (ret)
6592031a123SJohnny Huang 			return ret;
660d90825e2SJohnny Huang 	}
6612031a123SJohnny Huang 	return 0;
662d90825e2SJohnny Huang }
663d90825e2SJohnny Huang 
664a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
66554552c69SJohnny Huang {
66654552c69SJohnny Huang 	int pass;
66754552c69SJohnny Huang 	int i;
668a219f6deSJohnny Huang 	u32 data0_masked;
669a219f6deSJohnny Huang 	u32 data1_masked;
670a219f6deSJohnny Huang 	u32 buf0_masked;
671a219f6deSJohnny Huang 	u32 buf1_masked;
672a219f6deSJohnny Huang 	u32 compare[2];
6732031a123SJohnny Huang 	int ret;
67454552c69SJohnny Huang 
67554552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
67654552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
67754552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
67854552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
679a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
680f347c284SJohnny Huang 		return OTP_SUCCESS;
68154552c69SJohnny Huang 
682b64ca396SJohnny Huang 	for (i = 0; i < 32; i++) {
683b64ca396SJohnny Huang 		if (((data0_masked >> i) & 0x1) == 1 && ((buf0_masked >> i) & 0x1) == 0)
684b64ca396SJohnny Huang 			return OTP_FAILURE;
685b64ca396SJohnny Huang 		if (((data1_masked >> i) & 0x1) == 0 && ((buf1_masked >> i) & 0x1) == 1)
686b64ca396SJohnny Huang 			return OTP_FAILURE;
687b64ca396SJohnny Huang 	}
688b64ca396SJohnny Huang 
68954552c69SJohnny Huang 	otp_soak(1);
6902031a123SJohnny Huang 	if (data0_masked != buf0_masked) {
6912031a123SJohnny Huang 		ret = otp_prog_dw(buf[0], ignore_mask[0], prog_address);
6922031a123SJohnny Huang 		if (ret)
6932031a123SJohnny Huang 			return OTP_FAILURE;
6942031a123SJohnny Huang 	}
6952031a123SJohnny Huang 
6962031a123SJohnny Huang 	if (data1_masked != buf1_masked) {
6972031a123SJohnny Huang 		ret = otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
6982031a123SJohnny Huang 		if (ret)
6992031a123SJohnny Huang 			return OTP_FAILURE;
7002031a123SJohnny Huang 	}
70154552c69SJohnny Huang 
70254552c69SJohnny Huang 	pass = 0;
70354552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
70454552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
70554552c69SJohnny Huang 			otp_soak(2);
7062031a123SJohnny Huang 			if (compare[0] != 0) {
7072031a123SJohnny Huang 				ret = otp_prog_dw(compare[0], ignore_mask[0], prog_address);
7082031a123SJohnny Huang 				if (ret)
7092031a123SJohnny Huang 					return OTP_FAILURE;
7102031a123SJohnny Huang 			}
7112031a123SJohnny Huang 			if (compare[1] != ~0) {
7122031a123SJohnny Huang 				ret = otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
7132031a123SJohnny Huang 				if (ret)
7142031a123SJohnny Huang 					return OTP_FAILURE;
7152031a123SJohnny Huang 			}
71654552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
71754552c69SJohnny Huang 				otp_soak(1);
71854552c69SJohnny Huang 			} else {
71954552c69SJohnny Huang 				pass = 1;
72054552c69SJohnny Huang 				break;
72154552c69SJohnny Huang 			}
72254552c69SJohnny Huang 		} else {
72354552c69SJohnny Huang 			pass = 1;
72454552c69SJohnny Huang 			break;
72554552c69SJohnny Huang 		}
72654552c69SJohnny Huang 	}
72754552c69SJohnny Huang 
72854552c69SJohnny Huang 	if (!pass) {
72954552c69SJohnny Huang 		otp_soak(0);
73054552c69SJohnny Huang 		return OTP_FAILURE;
73154552c69SJohnny Huang 	}
73254552c69SJohnny Huang 	return OTP_SUCCESS;
73354552c69SJohnny Huang }
73454552c69SJohnny Huang 
735541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
73676d13988SJohnny Huang {
737a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
7385010032bSJohnny Huang 	int strap_end;
73976d13988SJohnny Huang 	int i, j;
74076d13988SJohnny Huang 
741e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
74276d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
74376d13988SJohnny Huang 			otpstrap[j].value = 0;
74476d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
74576d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
74676d13988SJohnny Huang 			otpstrap[j].protected = 0;
74776d13988SJohnny Huang 		}
7485010032bSJohnny Huang 		strap_end = 30;
7495010032bSJohnny Huang 	} else {
7505010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
7515010032bSJohnny Huang 			otpstrap[j].value = 0;
7525010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
7535010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
7545010032bSJohnny Huang 			otpstrap[j].protected = 0;
7555010032bSJohnny Huang 		}
7565010032bSJohnny Huang 		strap_end = 28;
7575010032bSJohnny Huang 	}
75876d13988SJohnny Huang 
759dacbba92SJohnny Huang 	otp_soak(0);
7605010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
76176d13988SJohnny Huang 		int option = (i - 16) / 2;
762a219f6deSJohnny Huang 
763f347c284SJohnny Huang 		otp_read_conf(i, &OTPSTRAP_RAW[0]);
764f347c284SJohnny Huang 		otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
76576d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
76676d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
767a219f6deSJohnny Huang 
768a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
76976d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
77076d13988SJohnny Huang 			if (bit_value == 1)
77176d13988SJohnny Huang 				otpstrap[j].remain_times--;
77276d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
77376d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
77476d13988SJohnny Huang 		}
77576d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
77676d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
777a219f6deSJohnny Huang 
778a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
77976d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
78076d13988SJohnny Huang 			if (bit_value == 1)
78176d13988SJohnny Huang 				otpstrap[j].remain_times--;
78276d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
78376d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
78476d13988SJohnny Huang 		}
78576d13988SJohnny Huang 	}
7865010032bSJohnny Huang 
787f347c284SJohnny Huang 	otp_read_conf(30, &OTPSTRAP_RAW[0]);
788f347c284SJohnny Huang 	otp_read_conf(31, &OTPSTRAP_RAW[1]);
78976d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
79076d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
79176d13988SJohnny Huang 			otpstrap[j].protected = 1;
79276d13988SJohnny Huang 	}
79376d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
79476d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
79576d13988SJohnny Huang 			otpstrap[j].protected = 1;
79676d13988SJohnny Huang 	}
79776d13988SJohnny Huang }
79876d13988SJohnny Huang 
7997e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit)
800f347c284SJohnny Huang {
801f347c284SJohnny Huang 	int prog_flag = 0;
802f347c284SJohnny Huang 
803f347c284SJohnny Huang 	// ignore this bit
804f347c284SJohnny Huang 	if (ibit == 1)
805f347c284SJohnny Huang 		return OTP_SUCCESS;
806b489486eSJohnny Huang 	printf("OTPSTRAP[0x%X]:\n", offset);
807f347c284SJohnny Huang 
808f347c284SJohnny Huang 	if (bit == otpstrap->value) {
8097e523e3bSJohnny Huang 		if (!pbit) {
810f347c284SJohnny Huang 			printf("    The value is same as before, skip it.\n");
811f347c284SJohnny Huang 			return OTP_PROG_SKIP;
812f347c284SJohnny Huang 		}
813f347c284SJohnny Huang 		printf("    The value is same as before.\n");
814f347c284SJohnny Huang 	} else {
815f347c284SJohnny Huang 		prog_flag = 1;
816f347c284SJohnny Huang 	}
817f347c284SJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
818f347c284SJohnny Huang 		printf("    This bit is protected and is not writable\n");
819f347c284SJohnny Huang 		return OTP_FAILURE;
820f347c284SJohnny Huang 	}
821f347c284SJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
822b489486eSJohnny Huang 		printf("    This bit has no remaining chance to write.\n");
823f347c284SJohnny Huang 		return OTP_FAILURE;
824f347c284SJohnny Huang 	}
825f347c284SJohnny Huang 	if (pbit == 1)
826f347c284SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
827f347c284SJohnny Huang 	if (prog_flag)
828b489486eSJohnny 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);
829f347c284SJohnny Huang 
830f347c284SJohnny Huang 	return OTP_SUCCESS;
831f347c284SJohnny Huang }
832f347c284SJohnny Huang 
833f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
834f347c284SJohnny Huang {
835f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
836f347c284SJohnny Huang 	u32 prog_address;
837f347c284SJohnny Huang 	int offset;
838f347c284SJohnny Huang 	int ret;
839f347c284SJohnny Huang 
840f347c284SJohnny Huang 	otp_strap_status(otpstrap);
841f347c284SJohnny Huang 
8427e523e3bSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
843f347c284SJohnny Huang 
844f347c284SJohnny Huang 	if (ret != OTP_SUCCESS)
845f347c284SJohnny Huang 		return ret;
846f347c284SJohnny Huang 
847f347c284SJohnny Huang 	prog_address = 0x800;
848f347c284SJohnny Huang 	if (bit_offset < 32) {
849f347c284SJohnny Huang 		offset = bit_offset;
850f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
851f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
852f347c284SJohnny Huang 
853f347c284SJohnny Huang 	} else {
854f347c284SJohnny Huang 		offset = (bit_offset - 32);
855f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
856f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
857f347c284SJohnny Huang 	}
858f347c284SJohnny Huang 
859f347c284SJohnny Huang 	return otp_prog_dc_b(1, prog_address, offset);
860f347c284SJohnny Huang }
861f347c284SJohnny Huang 
862f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
863f347c284SJohnny Huang {
864f347c284SJohnny Huang 	int i;
865f347c284SJohnny Huang 	u32 ret[1];
866f347c284SJohnny Huang 
867f347c284SJohnny Huang 	if (offset + dw_count > 32)
868f347c284SJohnny Huang 		return OTP_USAGE;
869f347c284SJohnny Huang 	otp_soak(0);
870f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
871f347c284SJohnny Huang 		otp_read_conf(i, ret);
872b489486eSJohnny Huang 		printf("OTPCFG0x%X: 0x%08X\n", i, ret[0]);
873f347c284SJohnny Huang 	}
874f347c284SJohnny Huang 	printf("\n");
875f347c284SJohnny Huang 	return OTP_SUCCESS;
876f347c284SJohnny Huang }
877f347c284SJohnny Huang 
878f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
879f347c284SJohnny Huang {
880f347c284SJohnny Huang 	int i;
881f347c284SJohnny Huang 	u32 ret[2];
882f347c284SJohnny Huang 
883f347c284SJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
884f347c284SJohnny Huang 		return OTP_USAGE;
885f347c284SJohnny Huang 	otp_soak(0);
886f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
887f347c284SJohnny Huang 		otp_read_data(i, ret);
888f347c284SJohnny Huang 		if (i % 4 == 0)
889f347c284SJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
890f347c284SJohnny Huang 		else
891f347c284SJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
892f347c284SJohnny Huang 	}
893f347c284SJohnny Huang 	printf("\n");
894f347c284SJohnny Huang 	return OTP_SUCCESS;
895f347c284SJohnny Huang }
896f347c284SJohnny Huang 
897f347c284SJohnny Huang static int otp_print_strap(int start, int count)
898f347c284SJohnny Huang {
899f347c284SJohnny Huang 	int i, j;
900f347c284SJohnny Huang 	int remains;
901f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
902f347c284SJohnny Huang 
903f347c284SJohnny Huang 	if (start < 0 || start > 64)
904f347c284SJohnny Huang 		return OTP_USAGE;
905f347c284SJohnny Huang 
906f347c284SJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
907f347c284SJohnny Huang 		return OTP_USAGE;
908f347c284SJohnny Huang 
909f347c284SJohnny Huang 	otp_strap_status(otpstrap);
910f347c284SJohnny Huang 
9117e523e3bSJohnny Huang 	if (info_cb.version == OTP_A0)
912f347c284SJohnny Huang 		remains = 7;
9137e523e3bSJohnny Huang 	else
914f347c284SJohnny Huang 		remains = 6;
9157e523e3bSJohnny Huang 	printf("BIT(hex)  Value  Option           Status\n");
916f347c284SJohnny Huang 	printf("______________________________________________________________________________\n");
917f347c284SJohnny Huang 
918f347c284SJohnny Huang 	for (i = start; i < start + count; i++) {
919f347c284SJohnny Huang 		printf("0x%-8X", i);
920f347c284SJohnny Huang 		printf("%-7d", otpstrap[i].value);
921f347c284SJohnny Huang 		for (j = 0; j < remains; j++)
922f347c284SJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
923f347c284SJohnny Huang 		printf("   ");
924f347c284SJohnny Huang 		if (otpstrap[i].protected == 1) {
925f347c284SJohnny Huang 			printf("protected and not writable");
926f347c284SJohnny Huang 		} else {
927f347c284SJohnny Huang 			printf("not protected ");
928f347c284SJohnny Huang 			if (otpstrap[i].remain_times == 0)
929f347c284SJohnny Huang 				printf("and no remaining times to write.");
930f347c284SJohnny Huang 			else
931f347c284SJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
932f347c284SJohnny Huang 		}
933f347c284SJohnny Huang 		printf("\n");
934f347c284SJohnny Huang 	}
935f347c284SJohnny Huang 
936f347c284SJohnny Huang 	return OTP_SUCCESS;
937f347c284SJohnny Huang }
938f347c284SJohnny Huang 
939794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
940794e27ecSJohnny Huang {
941794e27ecSJohnny Huang 	int bit_offset;
942794e27ecSJohnny Huang 	int i, j;
943794e27ecSJohnny Huang 
944794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
945794e27ecSJohnny Huang 	printf("___________________________________________________\n");
946794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
947794e27ecSJohnny Huang 		if (i < 32) {
948794e27ecSJohnny Huang 			j = 0;
949794e27ecSJohnny Huang 			bit_offset = i;
950794e27ecSJohnny Huang 		} else {
951794e27ecSJohnny Huang 			j = 1;
952794e27ecSJohnny Huang 			bit_offset = i - 32;
953794e27ecSJohnny Huang 		}
954794e27ecSJohnny Huang 		if (i % 16 == 0)
955794e27ecSJohnny Huang 			printf("%2x | ", i);
956794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
957794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
958794e27ecSJohnny Huang 			printf("\n");
959794e27ecSJohnny Huang 	}
960794e27ecSJohnny Huang }
961794e27ecSJohnny Huang 
962b25f02d2SJohnny Huang static int otp_print_scu_image(struct otp_image_layout *image_layout)
963b25f02d2SJohnny Huang {
964b25f02d2SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
965b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
966b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
967b25f02d2SJohnny Huang 	int i;
968b25f02d2SJohnny Huang 	u32 scu_offset;
969b25f02d2SJohnny Huang 	u32 dw_offset;
970b25f02d2SJohnny Huang 	u32 bit_offset;
971b25f02d2SJohnny Huang 	u32 mask;
972b25f02d2SJohnny Huang 	u32 otp_value;
973b25f02d2SJohnny Huang 	u32 otp_ignore;
974b25f02d2SJohnny Huang 
975b25f02d2SJohnny Huang 	printf("SCU     BIT          reg_protect     Description\n");
976b25f02d2SJohnny Huang 	printf("____________________________________________________________________\n");
977b25f02d2SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
978b25f02d2SJohnny Huang 		mask = BIT(scu_info[i].length) - 1;
979b25f02d2SJohnny Huang 
980b25f02d2SJohnny Huang 		if (scu_info[i].bit_offset > 31) {
981b25f02d2SJohnny Huang 			scu_offset = 0x510;
982b25f02d2SJohnny Huang 			dw_offset = 1;
983b25f02d2SJohnny Huang 			bit_offset = scu_info[i].bit_offset - 32;
984b25f02d2SJohnny Huang 		} else {
985b25f02d2SJohnny Huang 			scu_offset = 0x500;
986b25f02d2SJohnny Huang 			dw_offset = 0;
987b25f02d2SJohnny Huang 			bit_offset = scu_info[i].bit_offset;
988b25f02d2SJohnny Huang 		}
989b25f02d2SJohnny Huang 
990b25f02d2SJohnny Huang 		otp_value = (OTPSCU[dw_offset] >> bit_offset) & mask;
991b25f02d2SJohnny Huang 		otp_ignore = (OTPSCU_IGNORE[dw_offset] >> bit_offset) & mask;
992b25f02d2SJohnny Huang 
993b25f02d2SJohnny Huang 		if (otp_ignore == mask)
994b25f02d2SJohnny Huang 			continue;
995b25f02d2SJohnny Huang 		else if (otp_ignore != 0)
996b25f02d2SJohnny Huang 			return OTP_FAILURE;
997b25f02d2SJohnny Huang 
998b25f02d2SJohnny Huang 		if (otp_value != 0 && otp_value != mask)
999b25f02d2SJohnny Huang 			return OTP_FAILURE;
1000b25f02d2SJohnny Huang 
1001b25f02d2SJohnny Huang 		printf("0x%-6X", scu_offset);
1002b25f02d2SJohnny Huang 		if (scu_info[i].length == 1)
1003b25f02d2SJohnny Huang 			printf("0x%-11X", bit_offset);
1004b25f02d2SJohnny Huang 		else
10052131c250SJohnny Huang 			printf("0x%-2X:0x%-6x", bit_offset, bit_offset + scu_info[i].length - 1);
1006b25f02d2SJohnny Huang 		printf("0x%-14X", otp_value);
1007b25f02d2SJohnny Huang 		printf("%s\n", scu_info[i].information);
1008b25f02d2SJohnny Huang 	}
1009b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1010b25f02d2SJohnny Huang }
1011b25f02d2SJohnny Huang 
10120dc9a440SJohnny Huang static void otp_print_scu_info(void)
10130dc9a440SJohnny Huang {
10140dc9a440SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
10150dc9a440SJohnny Huang 	u32 OTPCFG[2];
10160dc9a440SJohnny Huang 	u32 scu_offset;
10170dc9a440SJohnny Huang 	u32 bit_offset;
10180dc9a440SJohnny Huang 	u32 reg_p;
10190dc9a440SJohnny Huang 	u32 length;
10200dc9a440SJohnny Huang 	int i, j;
10210dc9a440SJohnny Huang 
10220dc9a440SJohnny Huang 	otp_soak(0);
10230dc9a440SJohnny Huang 	otp_read_conf(28, &OTPCFG[0]);
10240dc9a440SJohnny Huang 	otp_read_conf(29, &OTPCFG[1]);
10250dc9a440SJohnny Huang 	printf("SCU     BIT   reg_protect     Description\n");
10260dc9a440SJohnny Huang 	printf("____________________________________________________________________\n");
10270dc9a440SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
10280dc9a440SJohnny Huang 		length = scu_info[i].length;
10290dc9a440SJohnny Huang 		for (j = 0; j < length; j++) {
10300dc9a440SJohnny Huang 			if (scu_info[i].bit_offset + j < 32) {
10310dc9a440SJohnny Huang 				scu_offset = 0x500;
10320dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j;
10330dc9a440SJohnny Huang 				reg_p = (OTPCFG[0] >> bit_offset) & 0x1;
10340dc9a440SJohnny Huang 			} else {
10350dc9a440SJohnny Huang 				scu_offset = 0x510;
10360dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j - 32;
10370dc9a440SJohnny Huang 				reg_p = (OTPCFG[1] >> bit_offset) & 0x1;
10380dc9a440SJohnny Huang 			}
10390dc9a440SJohnny Huang 			printf("0x%-6X", scu_offset);
10400dc9a440SJohnny Huang 			printf("0x%-4X", bit_offset);
10410dc9a440SJohnny Huang 			printf("0x%-13X", reg_p);
10420dc9a440SJohnny Huang 			if (length == 1) {
10430dc9a440SJohnny Huang 				printf(" %s\n", scu_info[i].information);
10440dc9a440SJohnny Huang 				continue;
10450dc9a440SJohnny Huang 			}
10460dc9a440SJohnny Huang 
10470dc9a440SJohnny Huang 			if (j == 0)
10480dc9a440SJohnny Huang 				printf("/%s\n", scu_info[i].information);
10490dc9a440SJohnny Huang 			else if (j == length - 1)
10500dc9a440SJohnny Huang 				printf("\\ \"\n");
10510dc9a440SJohnny Huang 			else
10520dc9a440SJohnny Huang 				printf("| \"\n");
10530dc9a440SJohnny Huang 		}
10540dc9a440SJohnny Huang 	}
10550dc9a440SJohnny Huang }
10560dc9a440SJohnny Huang 
1057696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
105869d5fd8fSJohnny Huang {
105979e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
1060a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
1061a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
1062a219f6deSJohnny Huang 	u32 mask;
1063a219f6deSJohnny Huang 	u32 dw_offset;
1064a219f6deSJohnny Huang 	u32 bit_offset;
1065a219f6deSJohnny Huang 	u32 otp_value;
1066a219f6deSJohnny Huang 	u32 otp_ignore;
1067b458cd62SJohnny Huang 	int fail = 0;
10687adec5f6SJohnny Huang 	int mask_err;
1069794e27ecSJohnny Huang 	int rid_num = 0;
107073f11549SJohnny Huang 	char valid_bit[20];
1071794e27ecSJohnny Huang 	int fz;
107266f2f8e5SJohnny Huang 	int i;
107373f11549SJohnny Huang 	int j;
107466f2f8e5SJohnny Huang 
1075737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
107666f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
10773cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
10787adec5f6SJohnny Huang 		mask_err = 0;
10793cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
10803cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
10813cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
1082b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1083696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
1084b458cd62SJohnny Huang 
10857adec5f6SJohnny Huang 		if (conf_info[i].value == OTP_REG_VALID_BIT) {
10867adec5f6SJohnny Huang 			if (((otp_value + otp_ignore) & mask) != mask) {
1087b458cd62SJohnny Huang 				fail = 1;
10887adec5f6SJohnny Huang 				mask_err = 1;
10897adec5f6SJohnny Huang 			}
10907adec5f6SJohnny Huang 		} else {
10917adec5f6SJohnny Huang 			if (otp_ignore == mask) {
10927adec5f6SJohnny Huang 				continue;
10937adec5f6SJohnny Huang 			} else if (otp_ignore != 0) {
10947adec5f6SJohnny Huang 				fail = 1;
10957adec5f6SJohnny Huang 				mask_err = 1;
10967adec5f6SJohnny Huang 			}
10977adec5f6SJohnny Huang 		}
1098b458cd62SJohnny Huang 
1099a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
11003cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
11013cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
11023cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1103b458cd62SJohnny Huang 			continue;
1104b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1105b458cd62SJohnny Huang 
11063cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
11073cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
110866f2f8e5SJohnny Huang 		} else {
1109b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
11103cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
11113cb28812SJohnny Huang 			       conf_info[i].bit_offset);
111266f2f8e5SJohnny Huang 		}
1113b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1114b458cd62SJohnny Huang 
11157adec5f6SJohnny Huang 		if (mask_err) {
11167adec5f6SJohnny Huang 			printf("Ignore, mask error\n");
1117a219f6deSJohnny Huang 			continue;
1118a219f6deSJohnny Huang 		}
11193cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1120b458cd62SJohnny Huang 			printf("Reserved\n");
11213cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
11223cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1123b458cd62SJohnny Huang 			printf("\n");
11243cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1125b458cd62SJohnny Huang 			if (otp_value != 0) {
112673f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1127e2b82258SJohnny Huang 					if (otp_value & (1 << j))
112873f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1129a219f6deSJohnny Huang 					else
113073f11549SJohnny Huang 						valid_bit[j * 2] = '0';
113173f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
113273f11549SJohnny Huang 				}
113373f11549SJohnny Huang 				valid_bit[15] = 0;
113473f11549SJohnny Huang 			} else {
113573f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1136b458cd62SJohnny Huang 			}
11373cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1138b458cd62SJohnny Huang 			printf("\n");
1139b458cd62SJohnny Huang 		} else {
11403cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1141b458cd62SJohnny Huang 		}
1142b458cd62SJohnny Huang 	}
1143b458cd62SJohnny Huang 
1144794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
1145794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
1146794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
1147794e27ecSJohnny Huang 			fail = 1;
1148794e27ecSJohnny Huang 		} else {
1149794e27ecSJohnny Huang 			fz = 0;
1150794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
1151794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
1152794e27ecSJohnny Huang 					if (!fz)
1153794e27ecSJohnny Huang 						fz = 1;
1154794e27ecSJohnny Huang 				} else {
1155794e27ecSJohnny Huang 					rid_num++;
1156794e27ecSJohnny Huang 					if (fz) {
1157794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
1158794e27ecSJohnny Huang 						fail = 1;
1159794e27ecSJohnny Huang 						break;
1160794e27ecSJohnny Huang 					}
1161794e27ecSJohnny Huang 				}
1162794e27ecSJohnny Huang 			}
1163794e27ecSJohnny Huang 		}
1164794e27ecSJohnny Huang 		if (fail)
1165794e27ecSJohnny Huang 			printf("OTP revision ID\n");
1166794e27ecSJohnny Huang 		else
1167794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
1168794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
1169794e27ecSJohnny Huang 	}
1170794e27ecSJohnny Huang 
1171b458cd62SJohnny Huang 	if (fail)
1172b458cd62SJohnny Huang 		return OTP_FAILURE;
1173b458cd62SJohnny Huang 
117466f2f8e5SJohnny Huang 	return OTP_SUCCESS;
117566f2f8e5SJohnny Huang }
117666f2f8e5SJohnny Huang 
11772d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
117866f2f8e5SJohnny Huang {
117979e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
1180a219f6deSJohnny Huang 	u32 OTPCFG[16];
1181a219f6deSJohnny Huang 	u32 mask;
1182a219f6deSJohnny Huang 	u32 dw_offset;
1183a219f6deSJohnny Huang 	u32 bit_offset;
1184a219f6deSJohnny Huang 	u32 otp_value;
118573f11549SJohnny Huang 	char valid_bit[20];
118666f2f8e5SJohnny Huang 	int i;
118773f11549SJohnny Huang 	int j;
118866f2f8e5SJohnny Huang 
1189dacbba92SJohnny Huang 	otp_soak(0);
1190bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
1191f347c284SJohnny Huang 		otp_read_conf(i, &OTPCFG[i]);
119266f2f8e5SJohnny Huang 
1193b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
1194b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
11953cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
11963cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
11972d4b0742SJohnny Huang 			continue;
11983cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
11993cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
12003cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
1201b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1202b458cd62SJohnny Huang 
1203a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
12043cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
12053cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
12063cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1207b458cd62SJohnny Huang 			continue;
1208b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1209b458cd62SJohnny Huang 
12103cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
12113cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
1212b458cd62SJohnny Huang 		} else {
1213b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
12143cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
12153cb28812SJohnny Huang 			       conf_info[i].bit_offset);
1216b458cd62SJohnny Huang 		}
1217b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1218b458cd62SJohnny Huang 
12193cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1220b458cd62SJohnny Huang 			printf("Reserved\n");
12213cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
12223cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1223b458cd62SJohnny Huang 			printf("\n");
12243cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1225b458cd62SJohnny Huang 			if (otp_value != 0) {
122673f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1227030cb4a7SJohnny Huang 					if (otp_value & (1 << j))
122873f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1229a219f6deSJohnny Huang 					else
123073f11549SJohnny Huang 						valid_bit[j * 2] = '0';
123173f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
123273f11549SJohnny Huang 				}
123373f11549SJohnny Huang 				valid_bit[15] = 0;
123473f11549SJohnny Huang 			} else {
123573f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1236b458cd62SJohnny Huang 			}
12373cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1238b458cd62SJohnny Huang 			printf("\n");
1239b458cd62SJohnny Huang 		} else {
12403cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1241b458cd62SJohnny Huang 		}
1242b458cd62SJohnny Huang 	}
1243b458cd62SJohnny Huang 	return OTP_SUCCESS;
124466f2f8e5SJohnny Huang }
124566f2f8e5SJohnny Huang 
12465010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
124776d13988SJohnny Huang {
124879e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
1249a219f6deSJohnny Huang 	u32 *OTPSTRAP;
1250a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
1251a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
125276d13988SJohnny Huang 	int i;
1253a8bd6d8cSJohnny Huang 	int fail = 0;
1254a219f6deSJohnny Huang 	u32 bit_offset;
1255a219f6deSJohnny Huang 	u32 dw_offset;
1256a219f6deSJohnny Huang 	u32 mask;
1257a219f6deSJohnny Huang 	u32 otp_value;
1258a219f6deSJohnny Huang 	u32 otp_protect;
1259a219f6deSJohnny Huang 	u32 otp_ignore;
126076d13988SJohnny Huang 
1261a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
1262a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1263a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
12647e523e3bSJohnny Huang 
1265a8bd6d8cSJohnny Huang 	printf("BIT(hex)   Value       Protect     Description\n");
1266de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
1267b458cd62SJohnny Huang 
12683cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
12697adec5f6SJohnny Huang 		fail = 0;
1270696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
1271a8bd6d8cSJohnny Huang 			dw_offset = 1;
12723cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
1273a8bd6d8cSJohnny Huang 		} else {
1274a8bd6d8cSJohnny Huang 			dw_offset = 0;
12753cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
1276a8bd6d8cSJohnny Huang 		}
127776d13988SJohnny Huang 
12783cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
1279a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1280a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1281696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1282a8bd6d8cSJohnny Huang 
1283a219f6deSJohnny Huang 		if (otp_ignore == mask)
1284a8bd6d8cSJohnny Huang 			continue;
1285a219f6deSJohnny Huang 		else if (otp_ignore != 0)
1286a8bd6d8cSJohnny Huang 			fail = 1;
1287a8bd6d8cSJohnny Huang 
1288a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
12893cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1290a8bd6d8cSJohnny Huang 			continue;
1291a8bd6d8cSJohnny Huang 
12923cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
12933cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
1294a8bd6d8cSJohnny Huang 		} else {
1295b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
12963cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
12973cb28812SJohnny Huang 			       strap_info[i].bit_offset);
1298a8bd6d8cSJohnny Huang 		}
1299a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
1300a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
1301a8bd6d8cSJohnny Huang 
1302a8bd6d8cSJohnny Huang 		if (fail) {
1303696656c6SJohnny Huang 			printf("Ignore mask error\n");
1304a8bd6d8cSJohnny Huang 		} else {
13053cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
13063cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1307a8bd6d8cSJohnny Huang 			else
1308a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1309a8bd6d8cSJohnny Huang 		}
1310a8bd6d8cSJohnny Huang 	}
1311a8bd6d8cSJohnny Huang 
1312a8bd6d8cSJohnny Huang 	if (fail)
131376d13988SJohnny Huang 		return OTP_FAILURE;
131476d13988SJohnny Huang 
131576d13988SJohnny Huang 	return OTP_SUCCESS;
131676d13988SJohnny Huang }
131776d13988SJohnny Huang 
1318b458cd62SJohnny Huang static int otp_print_strap_info(int view)
131976d13988SJohnny Huang {
132079e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
132176d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
132207baa4e8SJohnny Huang 	int i, j;
1323b458cd62SJohnny Huang 	int fail = 0;
1324a219f6deSJohnny Huang 	u32 bit_offset;
1325a219f6deSJohnny Huang 	u32 length;
1326a219f6deSJohnny Huang 	u32 otp_value;
1327a219f6deSJohnny Huang 	u32 otp_protect;
132876d13988SJohnny Huang 
1329541eb887SJohnny Huang 	otp_strap_status(strap_status);
133076d13988SJohnny Huang 
1331b458cd62SJohnny Huang 	if (view) {
133207baa4e8SJohnny Huang 		printf("BIT(hex) Value  Remains  Protect   Description\n");
133307baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1334b458cd62SJohnny Huang 	} else {
1335b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1336b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
133776d13988SJohnny Huang 	}
13383cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1339b458cd62SJohnny Huang 		otp_value = 0;
13403cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
13413cb28812SJohnny Huang 		length = strap_info[i].length;
1342b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1343c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1344c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1345b458cd62SJohnny Huang 		}
1346a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
13473cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1348b458cd62SJohnny Huang 			continue;
1349b458cd62SJohnny Huang 		if (view) {
1350b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
13513cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1352b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
135307baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1354e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
13553cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1356b458cd62SJohnny Huang 					printf(" Reserved\n");
1357b458cd62SJohnny Huang 					continue;
1358b458cd62SJohnny Huang 				}
1359b458cd62SJohnny Huang 				if (length == 1) {
13603cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1361b458cd62SJohnny Huang 					continue;
136276d13988SJohnny Huang 				}
136376d13988SJohnny Huang 
1364b458cd62SJohnny Huang 				if (j == 0)
13653cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1366b458cd62SJohnny Huang 				else if (j == length - 1)
1367b458cd62SJohnny Huang 					printf("\\ \"\n");
1368b458cd62SJohnny Huang 				else
1369b458cd62SJohnny Huang 					printf("| \"\n");
137076d13988SJohnny Huang 			}
1371b458cd62SJohnny Huang 		} else {
1372c947ef08SJohnny Huang 			if (length == 1) {
13733cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1374b458cd62SJohnny Huang 			} else {
1375b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1376b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1377b458cd62SJohnny Huang 			}
1378b458cd62SJohnny Huang 
1379b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1380b458cd62SJohnny Huang 
13813cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
13823cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1383b458cd62SJohnny Huang 			else
1384b458cd62SJohnny Huang 				printf("Reserved\n");
1385b458cd62SJohnny Huang 		}
1386b458cd62SJohnny Huang 	}
1387b458cd62SJohnny Huang 
1388b458cd62SJohnny Huang 	if (fail)
1389b458cd62SJohnny Huang 		return OTP_FAILURE;
1390b458cd62SJohnny Huang 
1391b458cd62SJohnny Huang 	return OTP_SUCCESS;
1392b458cd62SJohnny Huang }
1393b458cd62SJohnny Huang 
139488bd7d58SJohnny Huang static void _otp_print_key(u32 *data)
139569d5fd8fSJohnny Huang {
139688bd7d58SJohnny Huang 	int i, j;
139769d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
13989a4fe690SJohnny Huang 	struct otpkey_type key_info;
139988bd7d58SJohnny Huang 	const struct otpkey_type *key_info_array = info_cb.key_info;
140088bd7d58SJohnny Huang 	int len = 0;
1401a219f6deSJohnny Huang 	u8 *byte_buf;
140288bd7d58SJohnny Huang 	int empty;
140354552c69SJohnny Huang 
140488bd7d58SJohnny Huang 	byte_buf = (u8 *)data;
14059d998018SJohnny Huang 
140688bd7d58SJohnny Huang 	empty = 1;
14079d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
140888bd7d58SJohnny Huang 		if (i % 2) {
140988bd7d58SJohnny Huang 			if (data[i] != 0xffffffff)
141088bd7d58SJohnny Huang 				empty = 0;
141188bd7d58SJohnny Huang 		} else {
141288bd7d58SJohnny Huang 			if (data[i] != 0)
14139d998018SJohnny Huang 				empty = 0;
14149d998018SJohnny Huang 		}
141588bd7d58SJohnny Huang 	}
141688bd7d58SJohnny Huang 	if (empty) {
141788bd7d58SJohnny Huang 		printf("OTP data header is empty\n");
141888bd7d58SJohnny Huang 		return;
141988bd7d58SJohnny Huang 	}
14209d998018SJohnny Huang 
142188bd7d58SJohnny Huang 	for (i = 0; i < 16; i++) {
142288bd7d58SJohnny Huang 		key_id = data[i] & 0x7;
142388bd7d58SJohnny Huang 		key_offset = data[i] & 0x1ff8;
142488bd7d58SJohnny Huang 		last = (data[i] >> 13) & 1;
142588bd7d58SJohnny Huang 		key_type = (data[i] >> 14) & 0xf;
142688bd7d58SJohnny Huang 		key_length = (data[i] >> 18) & 0x3;
142788bd7d58SJohnny Huang 		exp_length = (data[i] >> 20) & 0xfff;
14289a4fe690SJohnny Huang 
142988bd7d58SJohnny Huang 		key_info.value = -1;
14309a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
14319a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
14329a4fe690SJohnny Huang 				key_info = key_info_array[j];
14339a4fe690SJohnny Huang 				break;
14349a4fe690SJohnny Huang 			}
14359a4fe690SJohnny Huang 		}
143688bd7d58SJohnny Huang 		if (key_info.value == -1)
143788bd7d58SJohnny Huang 			break;
14389a4fe690SJohnny Huang 
14397f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
144069d5fd8fSJohnny Huang 		printf("Key Type: ");
14419a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
14429a4fe690SJohnny Huang 
14439a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
144469d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
144569d5fd8fSJohnny Huang 			switch (key_length) {
144669d5fd8fSJohnny Huang 			case 0:
144769d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
144869d5fd8fSJohnny Huang 				break;
144969d5fd8fSJohnny Huang 			case 1:
145069d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
145169d5fd8fSJohnny Huang 				break;
145269d5fd8fSJohnny Huang 			case 2:
145369d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
145469d5fd8fSJohnny Huang 				break;
145569d5fd8fSJohnny Huang 			case 3:
145669d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
145769d5fd8fSJohnny Huang 				break;
145869d5fd8fSJohnny Huang 			}
1459181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1460181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
146169d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
146269d5fd8fSJohnny Huang 			switch (key_length) {
146369d5fd8fSJohnny Huang 			case 0:
146469d5fd8fSJohnny Huang 				printf("RSA1024\n");
146569d5fd8fSJohnny Huang 				len = 0x100;
146669d5fd8fSJohnny Huang 				break;
146769d5fd8fSJohnny Huang 			case 1:
146869d5fd8fSJohnny Huang 				printf("RSA2048\n");
146969d5fd8fSJohnny Huang 				len = 0x200;
147069d5fd8fSJohnny Huang 				break;
147169d5fd8fSJohnny Huang 			case 2:
147269d5fd8fSJohnny Huang 				printf("RSA3072\n");
147369d5fd8fSJohnny Huang 				len = 0x300;
147469d5fd8fSJohnny Huang 				break;
147569d5fd8fSJohnny Huang 			case 3:
147669d5fd8fSJohnny Huang 				printf("RSA4096\n");
147769d5fd8fSJohnny Huang 				len = 0x400;
147869d5fd8fSJohnny Huang 				break;
147969d5fd8fSJohnny Huang 			}
148069d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
148169d5fd8fSJohnny Huang 		}
14829a4fe690SJohnny Huang 		if (key_info.need_id)
148369d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
148469d5fd8fSJohnny Huang 		printf("Key Value:\n");
14859a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
148669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
14879a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
14889a4fe690SJohnny Huang 			printf("AES Key:\n");
14899a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1490e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
14919a4fe690SJohnny Huang 				printf("AES IV:\n");
14929a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
14939a4fe690SJohnny Huang 			}
14949a4fe690SJohnny Huang 
14959a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1496e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
149769d5fd8fSJohnny Huang 				printf("AES Key:\n");
149869d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
149969d5fd8fSJohnny Huang 				printf("AES IV:\n");
150069d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
15015fdde29fSJohnny Huang 			} else {
15029a4fe690SJohnny Huang 				printf("AES Key 1:\n");
15039a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
15049a4fe690SJohnny Huang 				printf("AES Key 2:\n");
15059a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
15069a4fe690SJohnny Huang 			}
1507181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
150869d5fd8fSJohnny Huang 			printf("RSA mod:\n");
150969d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
151069d5fd8fSJohnny Huang 			printf("RSA exp:\n");
151169d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1512181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1513181f72d8SJohnny Huang 			printf("RSA mod:\n");
1514181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1515181f72d8SJohnny Huang 			printf("RSA exp:\n");
1516a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
151769d5fd8fSJohnny Huang 		}
151869d5fd8fSJohnny Huang 		if (last)
151969d5fd8fSJohnny Huang 			break;
152069d5fd8fSJohnny Huang 	}
152188bd7d58SJohnny Huang }
152288bd7d58SJohnny Huang 
152388bd7d58SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
152488bd7d58SJohnny Huang {
152588bd7d58SJohnny Huang 	u32 *buf;
152688bd7d58SJohnny Huang 
152788bd7d58SJohnny Huang 	buf = (u32 *)image_layout->data;
152888bd7d58SJohnny Huang 	_otp_print_key(buf);
152988bd7d58SJohnny Huang 
1530f347c284SJohnny Huang 	return OTP_SUCCESS;
1531f347c284SJohnny Huang }
1532f347c284SJohnny Huang 
153388bd7d58SJohnny Huang static void otp_print_key_info(void)
153488bd7d58SJohnny Huang {
153588bd7d58SJohnny Huang 	u32 data[2048];
153688bd7d58SJohnny Huang 	int i;
153788bd7d58SJohnny Huang 
153888bd7d58SJohnny Huang 	for (i = 0; i < 2048 ; i += 2)
153988bd7d58SJohnny Huang 		otp_read_data(i, &data[i]);
154088bd7d58SJohnny Huang 
154188bd7d58SJohnny Huang 	_otp_print_key(data);
154288bd7d58SJohnny Huang }
154388bd7d58SJohnny Huang 
1544b64ca396SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout, u32 *data)
1545f347c284SJohnny Huang {
1546f347c284SJohnny Huang 	int i;
1547f347c284SJohnny Huang 	int ret;
1548f347c284SJohnny Huang 	u32 *buf;
1549f347c284SJohnny Huang 	u32 *buf_ignore;
1550f347c284SJohnny Huang 
1551f347c284SJohnny Huang 	buf = (u32 *)image_layout->data;
1552f347c284SJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
1553f347c284SJohnny Huang 	printf("Start Programing...\n");
1554f347c284SJohnny Huang 
1555f347c284SJohnny Huang 	// programing ecc region first
1556f347c284SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1557f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1558f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1559f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1560f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1561f347c284SJohnny Huang 			return ret;
1562f347c284SJohnny Huang 		}
1563f347c284SJohnny Huang 	}
1564f347c284SJohnny Huang 
1565f347c284SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1566f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1567f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1568f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1569f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1570f347c284SJohnny Huang 			return ret;
1571f347c284SJohnny Huang 		}
1572f347c284SJohnny Huang 	}
1573f347c284SJohnny Huang 	otp_soak(0);
1574f347c284SJohnny Huang 	return OTP_SUCCESS;
1575f347c284SJohnny Huang }
1576f347c284SJohnny Huang 
1577b64ca396SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1578f347c284SJohnny Huang {
1579f347c284SJohnny Huang 	u32 *strap;
1580f347c284SJohnny Huang 	u32 *strap_ignore;
1581f347c284SJohnny Huang 	u32 *strap_pro;
1582f347c284SJohnny Huang 	u32 prog_address;
1583f347c284SJohnny Huang 	int i;
15847e523e3bSJohnny Huang 	int bit, pbit, ibit, offset;
1585f347c284SJohnny Huang 	int fail = 0;
1586f347c284SJohnny Huang 	int ret;
1587f347c284SJohnny Huang 	int prog_flag = 0;
1588f347c284SJohnny Huang 
1589f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1590f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1591f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1592f347c284SJohnny Huang 
1593f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1594f347c284SJohnny Huang 		prog_address = 0x800;
1595f347c284SJohnny Huang 		if (i < 32) {
1596f347c284SJohnny Huang 			offset = i;
1597f347c284SJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1598f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
1599f347c284SJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
1600f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1601f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1602f347c284SJohnny Huang 
1603f347c284SJohnny Huang 		} else {
1604f347c284SJohnny Huang 			offset = (i - 32);
1605f347c284SJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1606f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
1607f347c284SJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
1608f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1609f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1610f347c284SJohnny Huang 		}
1611f347c284SJohnny Huang 
1612f347c284SJohnny Huang 		if (ibit == 1)
1613f347c284SJohnny Huang 			continue;
1614f347c284SJohnny Huang 		if (bit == otpstrap[i].value)
1615f347c284SJohnny Huang 			prog_flag = 0;
1616f347c284SJohnny Huang 		else
1617f347c284SJohnny Huang 			prog_flag = 1;
1618f347c284SJohnny Huang 
1619f347c284SJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
1620f347c284SJohnny Huang 			fail = 1;
1621f347c284SJohnny Huang 			continue;
1622f347c284SJohnny Huang 		}
1623f347c284SJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
1624f347c284SJohnny Huang 			fail = 1;
1625f347c284SJohnny Huang 			continue;
1626f347c284SJohnny Huang 		}
1627f347c284SJohnny Huang 
1628f347c284SJohnny Huang 		if (prog_flag) {
1629f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1630f347c284SJohnny Huang 			if (ret)
1631f347c284SJohnny Huang 				return OTP_FAILURE;
1632f347c284SJohnny Huang 		}
1633f347c284SJohnny Huang 
1634f347c284SJohnny Huang 		if (pbit != 0) {
1635f347c284SJohnny Huang 			prog_address = 0x800;
1636f347c284SJohnny Huang 			if (i < 32)
1637f347c284SJohnny Huang 				prog_address |= 0x60c;
1638f347c284SJohnny Huang 			else
1639f347c284SJohnny Huang 				prog_address |= 0x60e;
1640f347c284SJohnny Huang 
1641f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1642f347c284SJohnny Huang 			if (ret)
1643f347c284SJohnny Huang 				return OTP_FAILURE;
1644f347c284SJohnny Huang 		}
1645f347c284SJohnny Huang 	}
1646f347c284SJohnny Huang 	otp_soak(0);
1647f347c284SJohnny Huang 	if (fail == 1)
1648f347c284SJohnny Huang 		return OTP_FAILURE;
1649f347c284SJohnny Huang 	return OTP_SUCCESS;
165069d5fd8fSJohnny Huang }
165169d5fd8fSJohnny Huang 
1652b64ca396SJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout, u32 *otp_conf)
165369d5fd8fSJohnny Huang {
1654a6d0d645SJohnny Huang 	int i, k;
1655d90825e2SJohnny Huang 	int pass = 0;
1656a219f6deSJohnny Huang 	u32 prog_address;
1657a219f6deSJohnny Huang 	u32 compare[2];
1658a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1659a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1660a219f6deSJohnny Huang 	u32 data_masked;
1661a219f6deSJohnny Huang 	u32 buf_masked;
16622031a123SJohnny Huang 	int ret;
166369d5fd8fSJohnny Huang 
1664a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1665d90825e2SJohnny Huang 	otp_soak(0);
1666bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
1667b64ca396SJohnny Huang 		data_masked = otp_conf[i]  & ~conf_ignore[i];
16685010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1669a6d0d645SJohnny Huang 		prog_address = 0x800;
1670a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1671a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1672bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1673bb34a7bfSJohnny Huang 			pass = 1;
1674a6d0d645SJohnny Huang 			continue;
1675bb34a7bfSJohnny Huang 		}
1676de6fbf1cSJohnny Huang 
1677de6fbf1cSJohnny Huang 		otp_soak(1);
16782031a123SJohnny Huang 		ret = otp_prog_dw(conf[i], conf_ignore[i], prog_address);
16792031a123SJohnny Huang 		if (ret)
16802031a123SJohnny Huang 			return OTP_FAILURE;
1681a6d0d645SJohnny Huang 
168269d5fd8fSJohnny Huang 		pass = 0;
168369d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
16845010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1685de6fbf1cSJohnny Huang 				otp_soak(2);
16862031a123SJohnny Huang 				ret = otp_prog_dw(compare[0], conf_ignore[i], prog_address);
16872031a123SJohnny Huang 				if (ret)
16882031a123SJohnny Huang 					return OTP_FAILURE;
16895010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1690de6fbf1cSJohnny Huang 					otp_soak(1);
1691de6fbf1cSJohnny Huang 				} else {
1692de6fbf1cSJohnny Huang 					pass = 1;
1693de6fbf1cSJohnny Huang 					break;
1694de6fbf1cSJohnny Huang 				}
1695a6d0d645SJohnny Huang 			} else {
169669d5fd8fSJohnny Huang 				pass = 1;
169769d5fd8fSJohnny Huang 				break;
169869d5fd8fSJohnny Huang 			}
169969d5fd8fSJohnny Huang 		}
1700bb34a7bfSJohnny Huang 		if (pass == 0) {
1701b64ca396SJohnny Huang 			printf("address: %08x, otp_conf: %08x, input_conf: %08x, mask: %08x\n",
1702b64ca396SJohnny Huang 			       i, otp_conf[i], conf[i], conf_ignore[i]);
1703bb34a7bfSJohnny Huang 			break;
1704bb34a7bfSJohnny Huang 		}
1705a6d0d645SJohnny Huang 	}
1706a6d0d645SJohnny Huang 
1707de6fbf1cSJohnny Huang 	otp_soak(0);
170869d5fd8fSJohnny Huang 	if (!pass)
17092a856b9aSJohnny Huang 		return OTP_FAILURE;
1710a6d0d645SJohnny Huang 
17112a856b9aSJohnny Huang 	return OTP_SUCCESS;
171269d5fd8fSJohnny Huang }
171369d5fd8fSJohnny Huang 
1714b25f02d2SJohnny Huang static int otp_prog_scu_protect(struct otp_image_layout *image_layout, u32 *scu_pro)
1715b25f02d2SJohnny Huang {
1716b25f02d2SJohnny Huang 	int i, k;
1717b25f02d2SJohnny Huang 	int pass = 0;
1718b25f02d2SJohnny Huang 	u32 prog_address;
1719b25f02d2SJohnny Huang 	u32 compare[2];
1720b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1721b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1722b25f02d2SJohnny Huang 	u32 data_masked;
1723b25f02d2SJohnny Huang 	u32 buf_masked;
17242031a123SJohnny Huang 	int ret;
1725b25f02d2SJohnny Huang 
1726b25f02d2SJohnny Huang 	printf("Start Programing...\n");
1727b25f02d2SJohnny Huang 	otp_soak(0);
1728b25f02d2SJohnny Huang 	for (i = 0; i < 2; i++) {
1729b25f02d2SJohnny Huang 		data_masked = scu_pro[i]  & ~OTPSCU_IGNORE[i];
1730b25f02d2SJohnny Huang 		buf_masked  = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1731b25f02d2SJohnny Huang 		prog_address = 0xe08 + i * 2;
1732b25f02d2SJohnny Huang 		if (data_masked == buf_masked) {
1733b25f02d2SJohnny Huang 			pass = 1;
1734b25f02d2SJohnny Huang 			continue;
1735b25f02d2SJohnny Huang 		}
1736b25f02d2SJohnny Huang 
1737b25f02d2SJohnny Huang 		otp_soak(1);
17382031a123SJohnny Huang 		ret = otp_prog_dw(OTPSCU[i], OTPSCU_IGNORE[i], prog_address);
17392031a123SJohnny Huang 		if (ret)
17402031a123SJohnny Huang 			return OTP_FAILURE;
1741b25f02d2SJohnny Huang 		pass = 0;
1742b25f02d2SJohnny Huang 		for (k = 0; k < RETRY; k++) {
1743b25f02d2SJohnny Huang 			if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1744b25f02d2SJohnny Huang 				otp_soak(2);
17452031a123SJohnny Huang 				ret = otp_prog_dw(compare[0], OTPSCU_IGNORE[i], prog_address);
17462031a123SJohnny Huang 				if (ret)
17472031a123SJohnny Huang 					return OTP_FAILURE;
1748b25f02d2SJohnny Huang 				if (verify_dw(prog_address, &OTPSCU[i], &OTPSCU_IGNORE[i], compare, 1) != 0) {
1749b25f02d2SJohnny Huang 					otp_soak(1);
1750b25f02d2SJohnny Huang 				} else {
1751b25f02d2SJohnny Huang 					pass = 1;
1752b25f02d2SJohnny Huang 					break;
1753b25f02d2SJohnny Huang 				}
1754b25f02d2SJohnny Huang 			} else {
1755b25f02d2SJohnny Huang 				pass = 1;
1756b25f02d2SJohnny Huang 				break;
1757b25f02d2SJohnny Huang 			}
1758b25f02d2SJohnny Huang 		}
1759b25f02d2SJohnny Huang 		if (pass == 0) {
1760b489486eSJohnny Huang 			printf("OTPCFG0x%x: 0x%08x, input: 0x%08x, mask: 0x%08x\n",
1761b25f02d2SJohnny Huang 			       i + 28, scu_pro[i], OTPSCU[i], OTPSCU_IGNORE[i]);
1762b25f02d2SJohnny Huang 			break;
1763b25f02d2SJohnny Huang 		}
1764b25f02d2SJohnny Huang 	}
1765b25f02d2SJohnny Huang 
1766b25f02d2SJohnny Huang 	otp_soak(0);
1767b25f02d2SJohnny Huang 	if (!pass)
1768b25f02d2SJohnny Huang 		return OTP_FAILURE;
1769b25f02d2SJohnny Huang 
1770b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1771b25f02d2SJohnny Huang }
1772b25f02d2SJohnny Huang 
1773b64ca396SJohnny Huang static int otp_check_data_image(struct otp_image_layout *image_layout, u32 *data)
1774b64ca396SJohnny Huang {
1775b64ca396SJohnny Huang 	int data_dw;
1776b64ca396SJohnny Huang 	u32 data_masked;
1777b64ca396SJohnny Huang 	u32 buf_masked;
1778b64ca396SJohnny Huang 	u32 *buf = (u32 *)image_layout->data;
1779b64ca396SJohnny Huang 	u32 *buf_ignore = (u32 *)image_layout->data_ignore;
1780b64ca396SJohnny Huang 	int i;
1781b64ca396SJohnny Huang 
1782b64ca396SJohnny Huang 	data_dw = image_layout->data_length / 4;
1783b64ca396SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
1784b64ca396SJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1785b64ca396SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1786b64ca396SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
1787b64ca396SJohnny Huang 		if (data_masked == buf_masked)
1788b64ca396SJohnny Huang 			continue;
1789b64ca396SJohnny Huang 		if (i % 2 == 0) {
1790b64ca396SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
1791b64ca396SJohnny Huang 				continue;
1792b64ca396SJohnny Huang 			} else {
1793b64ca396SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1794b489486eSJohnny Huang 				printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1795b489486eSJohnny Huang 				printf("Input   [0x%x] = 0x%x\n", i, buf[i]);
1796b489486eSJohnny Huang 				printf("Mask    [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1797b64ca396SJohnny Huang 				return OTP_FAILURE;
1798b64ca396SJohnny Huang 			}
1799b64ca396SJohnny Huang 		} else {
1800b64ca396SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1801b64ca396SJohnny Huang 				continue;
1802b64ca396SJohnny Huang 			} else {
1803b64ca396SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1804b489486eSJohnny Huang 				printf("OTP_ADDR[0x%x] = 0x%x\n", i, data[i]);
1805b489486eSJohnny Huang 				printf("Input   [0x%x] = 0x%x\n", i, buf[i]);
1806b489486eSJohnny Huang 				printf("Mask    [0x%x] = 0x%x\n", i, ~buf_ignore[i]);
1807b64ca396SJohnny Huang 				return OTP_FAILURE;
1808b64ca396SJohnny Huang 			}
1809b64ca396SJohnny Huang 		}
1810b64ca396SJohnny Huang 	}
1811b64ca396SJohnny Huang 	return OTP_SUCCESS;
1812b64ca396SJohnny Huang }
1813b64ca396SJohnny Huang 
1814b64ca396SJohnny Huang static int otp_check_strap_image(struct otp_image_layout *image_layout, struct otpstrap_status *otpstrap)
1815b64ca396SJohnny Huang {
1816b64ca396SJohnny Huang 	int i;
1817b64ca396SJohnny Huang 	u32 *strap;
1818b64ca396SJohnny Huang 	u32 *strap_ignore;
1819b64ca396SJohnny Huang 	u32 *strap_pro;
1820b64ca396SJohnny Huang 	int bit, pbit, ibit;
1821b64ca396SJohnny Huang 	int fail = 0;
1822b64ca396SJohnny Huang 	int ret;
1823b64ca396SJohnny Huang 
1824b64ca396SJohnny Huang 	strap = (u32 *)image_layout->strap;
1825b64ca396SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1826b64ca396SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1827b64ca396SJohnny Huang 
1828b64ca396SJohnny Huang 	for (i = 0; i < 64; i++) {
1829b64ca396SJohnny Huang 		if (i < 32) {
1830b64ca396SJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1831b64ca396SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
1832b64ca396SJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
1833b64ca396SJohnny Huang 		} else {
1834b64ca396SJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1835b64ca396SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1836b64ca396SJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1837b64ca396SJohnny Huang 		}
1838b64ca396SJohnny Huang 
1839b64ca396SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit);
1840b64ca396SJohnny Huang 
1841b64ca396SJohnny Huang 		if (ret == OTP_FAILURE)
1842b64ca396SJohnny Huang 			fail = 1;
1843b64ca396SJohnny Huang 	}
1844b64ca396SJohnny Huang 	if (fail == 1) {
1845b64ca396SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
1846b64ca396SJohnny Huang 		return OTP_FAILURE;
1847b64ca396SJohnny Huang 	}
1848b64ca396SJohnny Huang 	return OTP_SUCCESS;
1849b64ca396SJohnny Huang }
1850b64ca396SJohnny Huang 
1851b64ca396SJohnny Huang static int otp_check_conf_image(struct otp_image_layout *image_layout, u32 *otp_conf)
1852b64ca396SJohnny Huang {
1853b64ca396SJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1854b64ca396SJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1855b64ca396SJohnny Huang 	u32 data_masked;
1856b64ca396SJohnny Huang 	u32 buf_masked;
1857b64ca396SJohnny Huang 	int i;
1858b64ca396SJohnny Huang 
1859b64ca396SJohnny Huang 	for (i = 0; i < 16; i++) {
1860b64ca396SJohnny Huang 		data_masked = otp_conf[i]  & ~conf_ignore[i];
1861b64ca396SJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1862b64ca396SJohnny Huang 		if (data_masked == buf_masked)
1863b64ca396SJohnny Huang 			continue;
1864b64ca396SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1865b64ca396SJohnny Huang 			continue;
1866b64ca396SJohnny Huang 		} else {
1867b64ca396SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1868b64ca396SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, otp_conf[i]);
1869b64ca396SJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
1870b64ca396SJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
1871b64ca396SJohnny Huang 			return OTP_FAILURE;
1872b64ca396SJohnny Huang 		}
1873b64ca396SJohnny Huang 	}
1874b64ca396SJohnny Huang 	return OTP_SUCCESS;
1875b64ca396SJohnny Huang }
1876b64ca396SJohnny Huang 
1877b25f02d2SJohnny Huang static int otp_check_scu_image(struct otp_image_layout *image_layout, u32 *scu_pro)
1878b25f02d2SJohnny Huang {
1879b25f02d2SJohnny Huang 	u32 *OTPSCU = (u32 *)image_layout->scu_pro;
1880b25f02d2SJohnny Huang 	u32 *OTPSCU_IGNORE = (u32 *)image_layout->scu_pro_ignore;
1881b25f02d2SJohnny Huang 	u32 data_masked;
1882b25f02d2SJohnny Huang 	u32 buf_masked;
1883b25f02d2SJohnny Huang 	int i;
1884b25f02d2SJohnny Huang 
1885b25f02d2SJohnny Huang 	for (i = 0; i < 2; i++) {
1886b25f02d2SJohnny Huang 		data_masked = scu_pro[i]  & ~OTPSCU_IGNORE[i];
1887b25f02d2SJohnny Huang 		buf_masked  = OTPSCU[i] & ~OTPSCU_IGNORE[i];
1888b25f02d2SJohnny Huang 		if (data_masked == buf_masked)
1889b25f02d2SJohnny Huang 			continue;
1890b25f02d2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1891b25f02d2SJohnny Huang 			continue;
1892b25f02d2SJohnny Huang 		} else {
1893b25f02d2SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1894b489486eSJohnny Huang 			printf("OTPCFG[0x%X] = 0x%X\n", 28 + i, scu_pro[i]);
1895b489486eSJohnny Huang 			printf("Input [0x%X] = 0x%X\n", 28 + i, OTPSCU[i]);
1896b489486eSJohnny Huang 			printf("Mask  [0x%X] = 0x%X\n", 28 + i, ~OTPSCU_IGNORE[i]);
1897b25f02d2SJohnny Huang 			return OTP_FAILURE;
1898b25f02d2SJohnny Huang 		}
1899b25f02d2SJohnny Huang 	}
1900b25f02d2SJohnny Huang 	return OTP_SUCCESS;
1901b25f02d2SJohnny Huang }
1902b25f02d2SJohnny Huang 
1903*e7e21c44SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf, int version)
1904696656c6SJohnny Huang {
1905*e7e21c44SJohnny Huang 	u8 digest_ret[48];
1906*e7e21c44SJohnny Huang 	int digest_len;
1907696656c6SJohnny Huang 
1908*e7e21c44SJohnny Huang 	switch (version) {
1909*e7e21c44SJohnny Huang 	case 1:
1910*e7e21c44SJohnny Huang 		sb_sha256(src_buf, length, digest_ret);
1911*e7e21c44SJohnny Huang 		digest_len = 32;
1912*e7e21c44SJohnny Huang 		break;
1913*e7e21c44SJohnny Huang 	case 2:
1914*e7e21c44SJohnny Huang 		sb_sha384(src_buf, length, digest_ret);
1915*e7e21c44SJohnny Huang 		digest_len = 48;
1916*e7e21c44SJohnny Huang 		break;
1917*e7e21c44SJohnny Huang 	default:
1918*e7e21c44SJohnny Huang 		return OTP_FAILURE;
1919*e7e21c44SJohnny Huang 	}
1920696656c6SJohnny Huang 
1921*e7e21c44SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, digest_len))
1922f347c284SJohnny Huang 		return OTP_SUCCESS;
1923f347c284SJohnny Huang 	return OTP_FAILURE;
1924696656c6SJohnny Huang }
1925696656c6SJohnny Huang 
1926f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
192769d5fd8fSJohnny Huang {
192869d5fd8fSJohnny Huang 	int ret;
192961a6cda7SJohnny Huang 	int image_soc_ver = 0;
1930696656c6SJohnny Huang 	struct otp_header *otp_header;
1931696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1932696656c6SJohnny Huang 	int image_size;
1933a219f6deSJohnny Huang 	u8 *buf;
1934a219f6deSJohnny Huang 	u8 *checksum;
1935b64ca396SJohnny Huang 	int i;
1936b64ca396SJohnny Huang 	u32 data[2048];
1937b64ca396SJohnny Huang 	u32 conf[16];
1938b25f02d2SJohnny Huang 	u32 scu_pro[2];
1939b64ca396SJohnny Huang 	struct otpstrap_status otpstrap[64];
194069d5fd8fSJohnny Huang 
1941696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1942696656c6SJohnny Huang 	if (!otp_header) {
1943030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
19442a856b9aSJohnny Huang 		return OTP_FAILURE;
194569d5fd8fSJohnny Huang 	}
1946d90825e2SJohnny Huang 
1947696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1948696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1949696656c6SJohnny Huang 
1950696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1951696656c6SJohnny Huang 
1952696656c6SJohnny Huang 	if (!buf) {
1953030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
1954696656c6SJohnny Huang 		return OTP_FAILURE;
1955696656c6SJohnny Huang 	}
1956696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1957696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1958696656c6SJohnny Huang 
1959696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1960030cb4a7SJohnny Huang 		printf("Image is invalid\n");
1961696656c6SJohnny Huang 		return OTP_FAILURE;
1962696656c6SJohnny Huang 	}
1963696656c6SJohnny Huang 
19645010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
19655010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
19665010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
19675010032bSJohnny Huang 
19685010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1969696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
19705010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1971696656c6SJohnny Huang 
1972696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
19735010032bSJohnny Huang 	image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
19745010032bSJohnny Huang 	image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
19755010032bSJohnny Huang 	image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
19767e523e3bSJohnny Huang 
1977b25f02d2SJohnny Huang 	image_layout.scu_pro = buf + OTP_REGION_OFFSET(otp_header->scu_protect_info);
1978b25f02d2SJohnny Huang 	image_layout.scu_pro_length = (int)(OTP_REGION_SIZE(otp_header->scu_protect_info) / 2);
1979b25f02d2SJohnny Huang 	image_layout.scu_pro_ignore = image_layout.scu_pro + image_layout.scu_pro_length;
1980b25f02d2SJohnny Huang 
19817e523e3bSJohnny Huang 	if (otp_header->soc_ver == SOC_AST2600A0) {
19827e523e3bSJohnny Huang 		image_soc_ver = OTP_A0;
198361a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A1) {
198461a6cda7SJohnny Huang 		image_soc_ver = OTP_A1;
198561a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A2) {
198661a6cda7SJohnny Huang 		image_soc_ver = OTP_A2;
198761a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A3) {
198861a6cda7SJohnny Huang 		image_soc_ver = OTP_A3;
1989696656c6SJohnny Huang 	} else {
1990030cb4a7SJohnny Huang 		printf("Image SOC Version is not supported\n");
1991696656c6SJohnny Huang 		return OTP_FAILURE;
1992696656c6SJohnny Huang 	}
1993696656c6SJohnny Huang 
199461a6cda7SJohnny Huang 	if (image_soc_ver != info_cb.version) {
19955e096f11SJohnny Huang 		printf("Image SOC version is not match to HW SOC version\n");
19969a4fe690SJohnny Huang 		return OTP_FAILURE;
19979a4fe690SJohnny Huang 	}
19989a4fe690SJohnny Huang 
1999*e7e21c44SJohnny Huang 	switch (OTPTOOL_VERSION_MAJOR(otp_header->otptool_ver)) {
2000*e7e21c44SJohnny Huang 	case 1:
2001*e7e21c44SJohnny Huang 		printf("WARNING: OTP image is not generated by otptool v2.x.x\n");
2002*e7e21c44SJohnny Huang 		printf("Please use the latest version of otptool to generate OTP image\n");
2003*e7e21c44SJohnny Huang 		ret = otp_verify_image(buf, image_size, checksum, 1);
2004*e7e21c44SJohnny Huang 		break;
2005*e7e21c44SJohnny Huang 	case 2:
2006*e7e21c44SJohnny Huang 		ret = otp_verify_image(buf, image_size, checksum, 2);
2007*e7e21c44SJohnny Huang 		break;
2008*e7e21c44SJohnny Huang 	default:
2009*e7e21c44SJohnny Huang 		printf("OTP image version is not supported\n");
201061a6cda7SJohnny Huang 		return OTP_FAILURE;
201161a6cda7SJohnny Huang 	}
201261a6cda7SJohnny Huang 
2013*e7e21c44SJohnny Huang 	if (ret) {
2014030cb4a7SJohnny Huang 		printf("checksum is invalid\n");
2015696656c6SJohnny Huang 		return OTP_FAILURE;
2016d90825e2SJohnny Huang 	}
20177332532cSJohnny Huang 
2018030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
2019030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
2020030cb4a7SJohnny Huang 		return OTP_FAILURE;
2021030cb4a7SJohnny Huang 	}
2022b64ca396SJohnny Huang 	ret = 0;
2023030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
2024030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_data) {
2025030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
2026030cb4a7SJohnny Huang 			ret = -1;
2027030cb4a7SJohnny Huang 		}
2028030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_sec) {
2029030cb4a7SJohnny Huang 			printf("OTP secure region is protected\n");
2030030cb4a7SJohnny Huang 			ret = -1;
2031030cb4a7SJohnny Huang 		}
2032b64ca396SJohnny Huang 		printf("Read OTP Data Region:\n");
2033b64ca396SJohnny Huang 		for (i = 0; i < 2048 ; i += 2)
2034b64ca396SJohnny Huang 			otp_read_data(i, &data[i]);
2035b64ca396SJohnny Huang 
2036b64ca396SJohnny Huang 		printf("Check writable...\n");
2037b64ca396SJohnny Huang 		if (otp_check_data_image(&image_layout, data) == OTP_FAILURE)
2038b64ca396SJohnny Huang 			ret = -1;
2039030cb4a7SJohnny Huang 	}
2040030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
2041030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_conf) {
2042030cb4a7SJohnny Huang 			printf("OTP config region is protected\n");
2043030cb4a7SJohnny Huang 			ret = -1;
2044030cb4a7SJohnny Huang 		}
2045b64ca396SJohnny Huang 		printf("Read OTP Config Region:\n");
2046b64ca396SJohnny Huang 		for (i = 0; i < 16 ; i++)
2047b64ca396SJohnny Huang 			otp_read_conf(i, &conf[i]);
2048b64ca396SJohnny Huang 
2049b64ca396SJohnny Huang 		printf("Check writable...\n");
2050b64ca396SJohnny Huang 		if (otp_check_conf_image(&image_layout, conf) == OTP_FAILURE)
2051b64ca396SJohnny Huang 			ret = -1;
2052030cb4a7SJohnny Huang 	}
2053030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
2054030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
2055030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
2056030cb4a7SJohnny Huang 			ret = -1;
2057030cb4a7SJohnny Huang 		}
2058b64ca396SJohnny Huang 		printf("Read OTP Strap Region:\n");
2059b64ca396SJohnny Huang 		otp_strap_status(otpstrap);
2060b64ca396SJohnny Huang 
2061b64ca396SJohnny Huang 		printf("Check writable...\n");
2062b64ca396SJohnny Huang 		if (otp_check_strap_image(&image_layout, otpstrap) == OTP_FAILURE)
2063b64ca396SJohnny Huang 			ret = -1;
2064030cb4a7SJohnny Huang 	}
2065b25f02d2SJohnny Huang 	if (otp_header->image_info & OTP_INC_SCU_PRO) {
2066b25f02d2SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
2067b25f02d2SJohnny Huang 			printf("OTP strap region is protected\n");
2068b25f02d2SJohnny Huang 			ret = -1;
2069b25f02d2SJohnny Huang 		}
2070b25f02d2SJohnny Huang 		printf("Read SCU Protect Region:\n");
2071b25f02d2SJohnny Huang 		otp_read_conf(28, &scu_pro[0]);
2072b25f02d2SJohnny Huang 		otp_read_conf(29, &scu_pro[1]);
2073b25f02d2SJohnny Huang 
2074b25f02d2SJohnny Huang 		printf("Check writable...\n");
2075b25f02d2SJohnny Huang 		if (otp_check_scu_image(&image_layout, scu_pro) == OTP_FAILURE)
2076b25f02d2SJohnny Huang 			ret = -1;
2077b25f02d2SJohnny Huang 	}
2078030cb4a7SJohnny Huang 	if (ret == -1)
2079030cb4a7SJohnny Huang 		return OTP_FAILURE;
2080b64ca396SJohnny Huang 
208169d5fd8fSJohnny Huang 	if (!nconfirm) {
2082696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
20837f795e57SJohnny Huang 			printf("\nOTP data region :\n");
2084f347c284SJohnny Huang 			if (otp_print_data_image(&image_layout) < 0) {
208569d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
20862a856b9aSJohnny Huang 				return OTP_FAILURE;
208769d5fd8fSJohnny Huang 			}
208869d5fd8fSJohnny Huang 		}
2089696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
20907332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
2091696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
20927332532cSJohnny Huang 				printf("OTP config error, please check.\n");
20937332532cSJohnny Huang 				return OTP_FAILURE;
20947332532cSJohnny Huang 			}
20957332532cSJohnny Huang 		}
20967adec5f6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
20977adec5f6SJohnny Huang 			printf("\nOTP strap region :\n");
20987adec5f6SJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
20997adec5f6SJohnny Huang 				printf("OTP strap error, please check.\n");
21007adec5f6SJohnny Huang 				return OTP_FAILURE;
21017adec5f6SJohnny Huang 			}
21027adec5f6SJohnny Huang 		}
2103b25f02d2SJohnny Huang 		if (otp_header->image_info & OTP_INC_SCU_PRO) {
2104b25f02d2SJohnny Huang 			printf("\nOTP scu protect region :\n");
2105b25f02d2SJohnny Huang 			if (otp_print_scu_image(&image_layout) < 0) {
2106b25f02d2SJohnny Huang 				printf("OTP scu protect error, please check.\n");
2107b25f02d2SJohnny Huang 				return OTP_FAILURE;
2108b25f02d2SJohnny Huang 			}
2109b25f02d2SJohnny Huang 		}
21107332532cSJohnny Huang 
211169d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
211269d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
211369d5fd8fSJohnny Huang 			printf(" Aborting\n");
21142a856b9aSJohnny Huang 			return OTP_FAILURE;
211569d5fd8fSJohnny Huang 		}
211669d5fd8fSJohnny Huang 	}
21177332532cSJohnny Huang 
21185010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
21195010032bSJohnny Huang 		printf("programing data region ...\n");
2120b64ca396SJohnny Huang 		ret = otp_prog_data(&image_layout, data);
21215010032bSJohnny Huang 		if (ret != 0) {
21225010032bSJohnny Huang 			printf("Error\n");
21235010032bSJohnny Huang 			return ret;
21245010032bSJohnny Huang 		}
2125a219f6deSJohnny Huang 		printf("Done\n");
21265010032bSJohnny Huang 	}
21275010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
21285010032bSJohnny Huang 		printf("programing strap region ...\n");
2129b64ca396SJohnny Huang 		ret = otp_prog_strap(&image_layout, otpstrap);
21305010032bSJohnny Huang 		if (ret != 0) {
21315010032bSJohnny Huang 			printf("Error\n");
21325010032bSJohnny Huang 			return ret;
21335010032bSJohnny Huang 		}
2134a219f6deSJohnny Huang 		printf("Done\n");
21355010032bSJohnny Huang 	}
2136b25f02d2SJohnny Huang 	if (otp_header->image_info & OTP_INC_SCU_PRO) {
2137b25f02d2SJohnny Huang 		printf("programing scu protect region ...\n");
2138b25f02d2SJohnny Huang 		ret = otp_prog_scu_protect(&image_layout, scu_pro);
2139b25f02d2SJohnny Huang 		if (ret != 0) {
2140b25f02d2SJohnny Huang 			printf("Error\n");
2141b25f02d2SJohnny Huang 			return ret;
2142b25f02d2SJohnny Huang 		}
2143b25f02d2SJohnny Huang 		printf("Done\n");
2144b25f02d2SJohnny Huang 	}
21455010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
21465010032bSJohnny Huang 		printf("programing configuration region ...\n");
2147b64ca396SJohnny Huang 		ret = otp_prog_conf(&image_layout, conf);
21485010032bSJohnny Huang 		if (ret != 0) {
21495010032bSJohnny Huang 			printf("Error\n");
21505010032bSJohnny Huang 			return ret;
21515010032bSJohnny Huang 		}
21525010032bSJohnny Huang 		printf("Done\n");
21535010032bSJohnny Huang 	}
2154cd1610b4SJohnny Huang 
21557332532cSJohnny Huang 	return OTP_SUCCESS;
21562a856b9aSJohnny Huang }
21572a856b9aSJohnny Huang 
2158f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
2159cd1610b4SJohnny Huang {
2160a219f6deSJohnny Huang 	u32 read[2];
2161a219f6deSJohnny Huang 	u32 prog_address = 0;
216266f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
2163cd1610b4SJohnny Huang 	int otp_bit;
216483655e91SJohnny Huang 	int ret = 0;
2165cd1610b4SJohnny Huang 
2166dacbba92SJohnny Huang 	otp_soak(0);
2167cd1610b4SJohnny Huang 	switch (mode) {
2168a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
2169f347c284SJohnny Huang 		otp_read_conf(otp_dw_offset, read);
2170cd1610b4SJohnny Huang 		prog_address = 0x800;
2171cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
2172cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
2173a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
2174cd1610b4SJohnny Huang 		if (otp_bit == value) {
2175b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2176cd1610b4SJohnny Huang 			printf("No need to program\n");
21772a856b9aSJohnny Huang 			return OTP_SUCCESS;
2178cd1610b4SJohnny Huang 		}
2179cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
2180b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
21810dc9a440SJohnny Huang 			printf("OTP is programmed, which can't be clean\n");
21822a856b9aSJohnny Huang 			return OTP_FAILURE;
2183cd1610b4SJohnny Huang 		}
2184b489486eSJohnny Huang 		printf("Program OTPCFG0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2185cd1610b4SJohnny Huang 		break;
2186a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
2187cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
2188cd1610b4SJohnny Huang 
2189cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
2190a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
2191a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
2192643b9cfdSJohnny Huang 
2193643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
2194b489486eSJohnny Huang 				printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2195b64ca396SJohnny Huang 				printf("OTP is programmed, which can't be cleared\n");
2196643b9cfdSJohnny Huang 				return OTP_FAILURE;
2197643b9cfdSJohnny Huang 			}
2198cd1610b4SJohnny Huang 		} else {
2199a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
2200a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
2201643b9cfdSJohnny Huang 
2202643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
2203b489486eSJohnny Huang 				printf("OTPDATA0x%X[0x%X] = 1\n", otp_dw_offset, bit_offset);
2204b64ca396SJohnny Huang 				printf("OTP is programmed, which can't be written\n");
2205643b9cfdSJohnny Huang 				return OTP_FAILURE;
2206643b9cfdSJohnny Huang 			}
2207cd1610b4SJohnny Huang 		}
2208cd1610b4SJohnny Huang 		if (otp_bit == value) {
2209b489486eSJohnny Huang 			printf("OTPDATA0x%X[0x%X] = %d\n", otp_dw_offset, bit_offset, value);
2210cd1610b4SJohnny Huang 			printf("No need to program\n");
22112a856b9aSJohnny Huang 			return OTP_SUCCESS;
2212cd1610b4SJohnny Huang 		}
2213643b9cfdSJohnny Huang 
2214b489486eSJohnny Huang 		printf("Program OTPDATA0x%X[0x%X] to 1\n", otp_dw_offset, bit_offset);
2215cd1610b4SJohnny Huang 		break;
2216a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
22178848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
22188848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
22197e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
22208848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
22218848d5dcSJohnny Huang 			return OTP_FAILURE;
22228848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
22238848d5dcSJohnny Huang 			return OTP_SUCCESS;
2224a6af4a17SJohnny Huang 
2225cd1610b4SJohnny Huang 		break;
2226cd1610b4SJohnny Huang 	}
2227cd1610b4SJohnny Huang 
2228cd1610b4SJohnny Huang 	if (!nconfirm) {
2229cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2230cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
2231cd1610b4SJohnny Huang 			printf(" Aborting\n");
22322a856b9aSJohnny Huang 			return OTP_FAILURE;
2233cd1610b4SJohnny Huang 		}
2234cd1610b4SJohnny Huang 	}
2235cd1610b4SJohnny Huang 
2236cd1610b4SJohnny Huang 	switch (mode) {
2237a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
2238f347c284SJohnny Huang 		ret =  otp_prog_strap_b(bit_offset, value);
223983655e91SJohnny Huang 		break;
2240a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
2241a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
2242f347c284SJohnny Huang 		ret = otp_prog_dc_b(value, prog_address, bit_offset);
2243de6fbf1cSJohnny Huang 		break;
2244de6fbf1cSJohnny Huang 	}
2245de6fbf1cSJohnny Huang 	otp_soak(0);
224683655e91SJohnny Huang 	if (ret) {
22470dc9a440SJohnny Huang 		printf("OTP cannot be programmed\n");
2248794e27ecSJohnny Huang 		printf("FAILURE\n");
2249794e27ecSJohnny Huang 		return OTP_FAILURE;
2250794e27ecSJohnny Huang 	}
2251794e27ecSJohnny Huang 
22529009c25dSJohnny Huang 	printf("SUCCESS\n");
22532a856b9aSJohnny Huang 	return OTP_SUCCESS;
2254a219f6deSJohnny Huang }
2255a219f6deSJohnny Huang 
2256794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
2257794e27ecSJohnny Huang {
2258794e27ecSJohnny Huang 	u32 otp_rid[2];
2259a8789b47SJohnny Huang 	u32 sw_rid[2];
2260794e27ecSJohnny Huang 	int rid_num = 0;
2261a8789b47SJohnny Huang 	int sw_rid_num = 0;
2262794e27ecSJohnny Huang 	int bit_offset;
2263794e27ecSJohnny Huang 	int dw_offset;
2264794e27ecSJohnny Huang 	int i;
2265794e27ecSJohnny Huang 	int ret;
2266794e27ecSJohnny Huang 
2267f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2268f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2269794e27ecSJohnny Huang 
2270a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2271a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2272a8789b47SJohnny Huang 
2273794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2274a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2275a8789b47SJohnny Huang 
2276a8789b47SJohnny Huang 	if (sw_rid_num < 0) {
2277a8789b47SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
2278a8789b47SJohnny Huang 		return OTP_FAILURE;
2279a8789b47SJohnny Huang 	}
2280a8789b47SJohnny Huang 
2281a8789b47SJohnny Huang 	if (update_num > sw_rid_num) {
2282a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
2283a8789b47SJohnny Huang 		printf("update number could not bigger than current SW revision id\n");
2284a8789b47SJohnny Huang 		return OTP_FAILURE;
2285a8789b47SJohnny Huang 	}
2286794e27ecSJohnny Huang 
2287794e27ecSJohnny Huang 	if (rid_num < 0) {
2288b64ca396SJohnny Huang 		printf("Current OTP revision ID cannot handle by this command,\n"
2289b64ca396SJohnny Huang 		       "please use 'otp pb' command to update it manually\n");
2290794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
22919009c25dSJohnny Huang 		return OTP_FAILURE;
22929009c25dSJohnny Huang 	}
2293cd1610b4SJohnny Huang 
2294794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
2295794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2296794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
2297794e27ecSJohnny Huang 
2298a8789b47SJohnny Huang 	if (rid_num > update_num) {
2299a8789b47SJohnny Huang 		printf("OTP rev_id is bigger than 0x%X\n", update_num);
2300a8789b47SJohnny Huang 		printf("Skip\n");
2301a8789b47SJohnny Huang 		return OTP_FAILURE;
2302a8789b47SJohnny Huang 	} else if (rid_num == update_num) {
2303a8789b47SJohnny Huang 		printf("OTP rev_id is same as input\n");
2304794e27ecSJohnny Huang 		printf("Skip\n");
2305794e27ecSJohnny Huang 		return OTP_FAILURE;
2306794e27ecSJohnny Huang 	}
2307794e27ecSJohnny Huang 
2308794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
2309794e27ecSJohnny Huang 		if (i < 32) {
2310794e27ecSJohnny Huang 			dw_offset = 0xa;
2311794e27ecSJohnny Huang 			bit_offset = i;
2312794e27ecSJohnny Huang 		} else {
2313794e27ecSJohnny Huang 			dw_offset = 0xb;
2314794e27ecSJohnny Huang 			bit_offset = i - 32;
2315794e27ecSJohnny Huang 		}
2316b489486eSJohnny Huang 		printf("OTPCFG0x%X[0x%X]", dw_offset, bit_offset);
2317794e27ecSJohnny Huang 		if (i + 1 != update_num)
2318794e27ecSJohnny Huang 			printf(", ");
2319794e27ecSJohnny Huang 	}
2320794e27ecSJohnny Huang 
2321794e27ecSJohnny Huang 	printf(" will be programmed\n");
2322794e27ecSJohnny Huang 	if (force == 0) {
2323794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2324794e27ecSJohnny Huang 		if (!confirm_yesno()) {
2325794e27ecSJohnny Huang 			printf(" Aborting\n");
2326794e27ecSJohnny Huang 			return OTP_FAILURE;
2327794e27ecSJohnny Huang 		}
2328794e27ecSJohnny Huang 	}
2329794e27ecSJohnny Huang 
2330794e27ecSJohnny Huang 	ret = 0;
2331794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
2332794e27ecSJohnny Huang 		if (i < 32) {
2333794e27ecSJohnny Huang 			dw_offset = 0xa04;
2334794e27ecSJohnny Huang 			bit_offset = i;
2335794e27ecSJohnny Huang 		} else {
2336794e27ecSJohnny Huang 			dw_offset = 0xa06;
2337794e27ecSJohnny Huang 			bit_offset = i - 32;
2338794e27ecSJohnny Huang 		}
2339f347c284SJohnny Huang 		if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
2340b489486eSJohnny Huang 			printf("OTPCFG0x%X[0x%X] programming failed\n", dw_offset, bit_offset);
2341794e27ecSJohnny Huang 			ret = OTP_FAILURE;
2342794e27ecSJohnny Huang 			break;
2343794e27ecSJohnny Huang 		}
2344794e27ecSJohnny Huang 	}
2345061d3279SJohnny Huang 	otp_soak(0);
2346f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2347f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2348794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2349794e27ecSJohnny Huang 	if (rid_num >= 0)
2350794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
2351794e27ecSJohnny Huang 	else
2352794e27ecSJohnny Huang 		printf("OTP revision ID\n");
2353794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2354794e27ecSJohnny Huang 	if (!ret)
2355794e27ecSJohnny Huang 		printf("SUCCESS\n");
2356794e27ecSJohnny Huang 	else
2357794e27ecSJohnny Huang 		printf("FAILED\n");
2358794e27ecSJohnny Huang 	return ret;
2359794e27ecSJohnny Huang }
2360794e27ecSJohnny Huang 
2361883625c5SJohnny Huang static int otp_retire_key(u32 retire_id, int force)
2362883625c5SJohnny Huang {
2363883625c5SJohnny Huang 	u32 otpcfg4;
2364883625c5SJohnny Huang 	u32 krb;
2365883625c5SJohnny Huang 	u32 krb_b;
2366883625c5SJohnny Huang 	u32 krb_or;
2367883625c5SJohnny Huang 	u32 current_id;
2368883625c5SJohnny Huang 
2369883625c5SJohnny Huang 	otp_read_conf(4, &otpcfg4);
2370883625c5SJohnny Huang 	current_id = readl(SEC_KEY_NUM) & 7;
2371883625c5SJohnny Huang 	krb = otpcfg4 & 0xff;
2372883625c5SJohnny Huang 	krb_b = (otpcfg4 >> 16) & 0xff;
2373883625c5SJohnny Huang 	krb_or = krb | krb_b;
2374883625c5SJohnny Huang 
2375883625c5SJohnny Huang 	printf("current Key ID: 0x%x\n", current_id);
2376883625c5SJohnny Huang 	printf("input retire ID: 0x%x\n", retire_id);
2377883625c5SJohnny Huang 	printf("OTPCFG0x4 = 0x%X\n", otpcfg4);
2378883625c5SJohnny Huang 
2379883625c5SJohnny Huang 	if (info_cb.pro_sts.pro_key_ret) {
2380883625c5SJohnny Huang 		printf("OTPCFG4 is protected\n");
2381883625c5SJohnny Huang 		return OTP_FAILURE;
2382883625c5SJohnny Huang 	}
2383883625c5SJohnny Huang 
2384883625c5SJohnny Huang 	if (retire_id >= current_id) {
2385883625c5SJohnny Huang 		printf("Retire key id is equal or bigger than current boot key\n");
2386883625c5SJohnny Huang 		return OTP_FAILURE;
2387883625c5SJohnny Huang 	}
2388883625c5SJohnny Huang 
2389883625c5SJohnny Huang 	if (krb_or & (1 << retire_id)) {
2390883625c5SJohnny Huang 		printf("Key 0x%X already retired\n", retire_id);
2391883625c5SJohnny Huang 		return OTP_SUCCESS;
2392883625c5SJohnny Huang 	}
2393883625c5SJohnny Huang 
2394883625c5SJohnny Huang 	printf("OTPCFG0x4[0x%X] will be programmed\n", retire_id);
2395883625c5SJohnny Huang 	if (force == 0) {
2396883625c5SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2397883625c5SJohnny Huang 		if (!confirm_yesno()) {
2398883625c5SJohnny Huang 			printf(" Aborting\n");
2399883625c5SJohnny Huang 			return OTP_FAILURE;
2400883625c5SJohnny Huang 		}
2401883625c5SJohnny Huang 	}
2402883625c5SJohnny Huang 
2403883625c5SJohnny Huang 	if (otp_prog_dc_b(1, 0x808, retire_id) == OTP_FAILURE) {
2404883625c5SJohnny Huang 		printf("OTPCFG0x4[0x%X] programming failed\n", retire_id);
2405883625c5SJohnny Huang 		printf("try to program backup OTPCFG0x4[0x%X]\n", retire_id + 16);
2406883625c5SJohnny Huang 		if (otp_prog_dc_b(1, 0x808, retire_id + 16) == OTP_FAILURE)
2407883625c5SJohnny Huang 			printf("OTPCFG0x4[0x%X] programming failed", retire_id + 16);
2408883625c5SJohnny Huang 	}
2409883625c5SJohnny Huang 
2410883625c5SJohnny Huang 	otp_soak(0);
2411883625c5SJohnny Huang 	otp_read_conf(4, &otpcfg4);
2412883625c5SJohnny Huang 	krb = otpcfg4 & 0xff;
2413883625c5SJohnny Huang 	krb_b = (otpcfg4 >> 16) & 0xff;
2414883625c5SJohnny Huang 	krb_or = krb | krb_b;
2415883625c5SJohnny Huang 	if (krb_or & (1 << retire_id)) {
2416883625c5SJohnny Huang 		printf("SUCCESS\n");
2417883625c5SJohnny Huang 		return OTP_SUCCESS;
2418883625c5SJohnny Huang 	}
2419883625c5SJohnny Huang 	printf("FAILED\n");
2420883625c5SJohnny Huang 	return OTP_FAILURE;
2421883625c5SJohnny Huang }
2422883625c5SJohnny Huang 
2423*e7e21c44SJohnny Huang static int parse_config(struct sb_info *si)
2424*e7e21c44SJohnny Huang {
2425*e7e21c44SJohnny Huang 	int i;
2426*e7e21c44SJohnny Huang 	u32 cfg0, cfg3, cfg4;
2427*e7e21c44SJohnny Huang 	u32 sb_mode;
2428*e7e21c44SJohnny Huang 	u32 key_retire;
2429*e7e21c44SJohnny Huang 	u32 rsa_len;
2430*e7e21c44SJohnny Huang 	u32 sha_len;
2431*e7e21c44SJohnny Huang 
2432*e7e21c44SJohnny Huang 	otp_read_conf(0, &cfg0);
2433*e7e21c44SJohnny Huang 	otp_read_conf(3, &cfg3);
2434*e7e21c44SJohnny Huang 	otp_read_conf(4, &cfg4);
2435*e7e21c44SJohnny Huang 
2436*e7e21c44SJohnny Huang 	sb_mode = (cfg0 >> 7) & 0x1;
2437*e7e21c44SJohnny Huang 	si->enc_flag = (cfg0 >> 27) & 0x1;
2438*e7e21c44SJohnny Huang 	key_retire = (cfg4 & 0x7f) | ((cfg4 >> 16) & 0x7f);
2439*e7e21c44SJohnny Huang 
2440*e7e21c44SJohnny Huang 	if ((cfg0 >> 16) & 0x3f)
2441*e7e21c44SJohnny Huang 		si->secure_region = 1;
2442*e7e21c44SJohnny Huang 	else
2443*e7e21c44SJohnny Huang 		si->secure_region = 0;
2444*e7e21c44SJohnny Huang 
2445*e7e21c44SJohnny Huang 	si->header_offset = cfg3 & 0xffff;
2446*e7e21c44SJohnny Huang 	if (si->header_offset == 0)
2447*e7e21c44SJohnny Huang 		si->header_offset = 0x20;
2448*e7e21c44SJohnny Huang 
2449*e7e21c44SJohnny Huang 	for (i = 0; i < 8; i++) {
2450*e7e21c44SJohnny Huang 		if ((key_retire >> i) & 0x1)
2451*e7e21c44SJohnny Huang 			si->retire_list[i] = 1;
2452*e7e21c44SJohnny Huang 		else
2453*e7e21c44SJohnny Huang 			si->retire_list[i] = 0;
2454*e7e21c44SJohnny Huang 	}
2455*e7e21c44SJohnny Huang 
2456*e7e21c44SJohnny Huang 	if (sb_mode == 0) {
2457*e7e21c44SJohnny Huang 		printf("Mode GCM is not supported.\n");
2458*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2459*e7e21c44SJohnny Huang 	}
2460*e7e21c44SJohnny Huang 
2461*e7e21c44SJohnny Huang 	if (si->enc_flag)
2462*e7e21c44SJohnny Huang 		printf("Algorithm: AES_RSA_SHA\n");
2463*e7e21c44SJohnny Huang 	else
2464*e7e21c44SJohnny Huang 		printf("Algorithm: RSA_SHA\n");
2465*e7e21c44SJohnny Huang 
2466*e7e21c44SJohnny Huang 	rsa_len = (cfg0 >> 10) & 0x3;
2467*e7e21c44SJohnny Huang 	sha_len = (cfg0 >> 12) & 0x3;
2468*e7e21c44SJohnny Huang 
2469*e7e21c44SJohnny Huang 	if (rsa_len == 0) {
2470*e7e21c44SJohnny Huang 		si->rsa_algo = 1024;
2471*e7e21c44SJohnny Huang 		printf("RSA length: 1024\n");
2472*e7e21c44SJohnny Huang 	} else if (rsa_len == 1) {
2473*e7e21c44SJohnny Huang 		si->rsa_algo = 2048;
2474*e7e21c44SJohnny Huang 		printf("RSA length: 2048\n");
2475*e7e21c44SJohnny Huang 	} else if (rsa_len == 2) {
2476*e7e21c44SJohnny Huang 		si->rsa_algo = 3072;
2477*e7e21c44SJohnny Huang 		printf("RSA length: 3072\n");
2478*e7e21c44SJohnny Huang 	} else {
2479*e7e21c44SJohnny Huang 		si->rsa_algo = 4096;
2480*e7e21c44SJohnny Huang 		printf("RSA length: 4096\n");
2481*e7e21c44SJohnny Huang 	}
2482*e7e21c44SJohnny Huang 	if (sha_len == 0) {
2483*e7e21c44SJohnny Huang 		si->sha_algo = 224;
2484*e7e21c44SJohnny Huang 		si->digest_len = 28;
2485*e7e21c44SJohnny Huang 		printf("HASH length: 224\n");
2486*e7e21c44SJohnny Huang 	} else if (sha_len == 1) {
2487*e7e21c44SJohnny Huang 		si->sha_algo = 256;
2488*e7e21c44SJohnny Huang 		si->digest_len = 32;
2489*e7e21c44SJohnny Huang 		printf("HASH length: 256\n");
2490*e7e21c44SJohnny Huang 	} else if (sha_len == 2) {
2491*e7e21c44SJohnny Huang 		si->sha_algo = 384;
2492*e7e21c44SJohnny Huang 		si->digest_len = 48;
2493*e7e21c44SJohnny Huang 		printf("HASH length: 384\n");
2494*e7e21c44SJohnny Huang 	} else {
2495*e7e21c44SJohnny Huang 		si->sha_algo = 512;
2496*e7e21c44SJohnny Huang 		si->digest_len = 64;
2497*e7e21c44SJohnny Huang 		printf("HASH length: 512\n");
2498*e7e21c44SJohnny Huang 	}
2499*e7e21c44SJohnny Huang 	return OTP_SUCCESS;
2500*e7e21c44SJohnny Huang }
2501*e7e21c44SJohnny Huang 
2502*e7e21c44SJohnny Huang static void parse_data(struct key_list *kl, int *key_num, struct sb_info *si, u32 *data)
2503*e7e21c44SJohnny Huang {
2504*e7e21c44SJohnny Huang 	const struct otpkey_type *key_info_array = info_cb.key_info;
2505*e7e21c44SJohnny Huang 	int i, j;
2506*e7e21c44SJohnny Huang 	int id = 0;
2507*e7e21c44SJohnny Huang 	u32 h;
2508*e7e21c44SJohnny Huang 	u32 t;
2509*e7e21c44SJohnny Huang 
2510*e7e21c44SJohnny Huang 	*key_num = 0;
2511*e7e21c44SJohnny Huang 	for (i = 0; i < 16; i++) {
2512*e7e21c44SJohnny Huang 		h = data[i];
2513*e7e21c44SJohnny Huang 		t = (h >> 14) & 0xf;
2514*e7e21c44SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
2515*e7e21c44SJohnny Huang 			if (t == key_info_array[j].value) {
2516*e7e21c44SJohnny Huang 				kl[*key_num].key_info = &key_info_array[j];
2517*e7e21c44SJohnny Huang 				kl[*key_num].offset = h & 0x1ff8;
2518*e7e21c44SJohnny Huang 				id = h & 0x7;
2519*e7e21c44SJohnny Huang 				kl[*key_num].id = id;
2520*e7e21c44SJohnny Huang 				if (si->retire_list[id] == 1)
2521*e7e21c44SJohnny Huang 					kl[*key_num].retire = 1;
2522*e7e21c44SJohnny Huang 				else
2523*e7e21c44SJohnny Huang 					kl[*key_num].retire = 0;
2524*e7e21c44SJohnny Huang 				(*key_num)++;
2525*e7e21c44SJohnny Huang 				break;
2526*e7e21c44SJohnny Huang 			}
2527*e7e21c44SJohnny Huang 		}
2528*e7e21c44SJohnny Huang 		if ((data[i] >> 13) & 1)
2529*e7e21c44SJohnny Huang 			break;
2530*e7e21c44SJohnny Huang 	}
2531*e7e21c44SJohnny Huang }
2532*e7e21c44SJohnny Huang 
2533*e7e21c44SJohnny Huang static int sb_sha(struct sb_info *si, u8 *sec_image, u32 sign_image_size, u8 *digest_ret)
2534*e7e21c44SJohnny Huang {
2535*e7e21c44SJohnny Huang 	switch (si->sha_algo) {
2536*e7e21c44SJohnny Huang 	case 224:
2537*e7e21c44SJohnny Huang 		printf("otp verify does not support SHA224\n");
2538*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2539*e7e21c44SJohnny Huang 	case 256:
2540*e7e21c44SJohnny Huang 		sb_sha256(sec_image, sign_image_size, digest_ret);
2541*e7e21c44SJohnny Huang 		break;
2542*e7e21c44SJohnny Huang 	case 384:
2543*e7e21c44SJohnny Huang 		sb_sha384(sec_image, sign_image_size, digest_ret);
2544*e7e21c44SJohnny Huang 		break;
2545*e7e21c44SJohnny Huang 	case 512:
2546*e7e21c44SJohnny Huang 		sb_sha512(sec_image, sign_image_size, digest_ret);
2547*e7e21c44SJohnny Huang 		break;
2548*e7e21c44SJohnny Huang 	default:
2549*e7e21c44SJohnny Huang 		printf("SHA Algorithm is invalid\n");
2550*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2551*e7e21c44SJohnny Huang 	}
2552*e7e21c44SJohnny Huang 	return 0;
2553*e7e21c44SJohnny Huang }
2554*e7e21c44SJohnny Huang 
2555*e7e21c44SJohnny Huang static int mode2_verify(u8 *sec_image, u32 sign_image_size,
2556*e7e21c44SJohnny Huang 			u8 *signature, u8 *rsa_m,
2557*e7e21c44SJohnny Huang 			int order, u8 *digest,
2558*e7e21c44SJohnny Huang 			struct sb_info *si, struct udevice *mod_exp_dev)
2559*e7e21c44SJohnny Huang {
2560*e7e21c44SJohnny Huang 	struct key_prop prop;
2561*e7e21c44SJohnny Huang 	u8 rsa_e[3] = "\x01\x00\x01";
2562*e7e21c44SJohnny Huang 	u8 sign_ret[512];
2563*e7e21c44SJohnny Huang 	u8 rsa_m_rev[512];
2564*e7e21c44SJohnny Huang 	u8 signature_rev[512];
2565*e7e21c44SJohnny Huang 	u8 tmp;
2566*e7e21c44SJohnny Huang 	u32 rsa_len = si->rsa_algo / 8;
2567*e7e21c44SJohnny Huang 	int i;
2568*e7e21c44SJohnny Huang 	int ret;
2569*e7e21c44SJohnny Huang 
2570*e7e21c44SJohnny Huang 	memset(&prop, 0, sizeof(struct key_prop));
2571*e7e21c44SJohnny Huang 
2572*e7e21c44SJohnny Huang 	if (order == OTP_LIT_END) {
2573*e7e21c44SJohnny Huang 		memset(rsa_m_rev, 0, 512);
2574*e7e21c44SJohnny Huang 		memset(signature_rev, 0, 512);
2575*e7e21c44SJohnny Huang 		for (i = 0; i < rsa_len; i++) {
2576*e7e21c44SJohnny Huang 			rsa_m_rev[i] = rsa_m[rsa_len - 1 - i];
2577*e7e21c44SJohnny Huang 			signature_rev[i] = signature[rsa_len - 1 - i];
2578*e7e21c44SJohnny Huang 		}
2579*e7e21c44SJohnny Huang 		prop.modulus = rsa_m_rev;
2580*e7e21c44SJohnny Huang 		prop.num_bits = si->rsa_algo;
2581*e7e21c44SJohnny Huang 		prop.public_exponent = rsa_e;
2582*e7e21c44SJohnny Huang 		prop.exp_len = 3;
2583*e7e21c44SJohnny Huang 		ret = rsa_mod_exp(mod_exp_dev, signature_rev, rsa_len, &prop, sign_ret);
2584*e7e21c44SJohnny Huang 	} else {
2585*e7e21c44SJohnny Huang 		prop.modulus = rsa_m;
2586*e7e21c44SJohnny Huang 		prop.num_bits = si->rsa_algo;
2587*e7e21c44SJohnny Huang 		prop.public_exponent = rsa_e;
2588*e7e21c44SJohnny Huang 		prop.exp_len = 3;
2589*e7e21c44SJohnny Huang 		ret = rsa_mod_exp(mod_exp_dev, signature, rsa_len, &prop, sign_ret);
2590*e7e21c44SJohnny Huang 	}
2591*e7e21c44SJohnny Huang 
2592*e7e21c44SJohnny Huang 	if (ret) {
2593*e7e21c44SJohnny Huang 		printf("rsa_mod_exp error: %d\n", ret);
2594*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2595*e7e21c44SJohnny Huang 	}
2596*e7e21c44SJohnny Huang 
2597*e7e21c44SJohnny Huang 	if (order == OTP_LIT_END) {
2598*e7e21c44SJohnny Huang 		for (i = 0; i < rsa_len / 2; i++) {
2599*e7e21c44SJohnny Huang 			tmp = sign_ret[i];
2600*e7e21c44SJohnny Huang 			sign_ret[i] = sign_ret[rsa_len - 1 - i];
2601*e7e21c44SJohnny Huang 			sign_ret[rsa_len - 1 - i] = tmp;
2602*e7e21c44SJohnny Huang 		}
2603*e7e21c44SJohnny Huang 		ret = memcmp(digest, sign_ret, si->digest_len);
2604*e7e21c44SJohnny Huang 	} else {
2605*e7e21c44SJohnny Huang 		ret = memcmp(digest, sign_ret + (rsa_len - si->digest_len), si->digest_len);
2606*e7e21c44SJohnny Huang 	}
2607*e7e21c44SJohnny Huang 
2608*e7e21c44SJohnny Huang 	if (ret)
2609*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2610*e7e21c44SJohnny Huang 	return 0;
2611*e7e21c44SJohnny Huang }
2612*e7e21c44SJohnny Huang 
2613*e7e21c44SJohnny Huang static int otp_verify_boot_image(phys_addr_t addr)
2614*e7e21c44SJohnny Huang {
2615*e7e21c44SJohnny Huang 	struct udevice *mod_exp_dev;
2616*e7e21c44SJohnny Huang 	struct sb_info si;
2617*e7e21c44SJohnny Huang 	struct key_list kl[16];
2618*e7e21c44SJohnny Huang 	struct sb_header *sh;
2619*e7e21c44SJohnny Huang 	u32 data[2048];
2620*e7e21c44SJohnny Huang 	u8 digest[64];
2621*e7e21c44SJohnny Huang 	u8 *sec_image;
2622*e7e21c44SJohnny Huang 	u8 *signature;
2623*e7e21c44SJohnny Huang 	u8 *key;
2624*e7e21c44SJohnny Huang 	u32 otp_rid[2];
2625*e7e21c44SJohnny Huang 	u32 sw_rid[2];
2626*e7e21c44SJohnny Huang 	u64 *otp_rid64 = (u64 *)otp_rid;
2627*e7e21c44SJohnny Huang 	u64 *sw_rid64 = (u64 *)sw_rid;
2628*e7e21c44SJohnny Huang 	int key_num;
2629*e7e21c44SJohnny Huang 	int ret;
2630*e7e21c44SJohnny Huang 	int i;
2631*e7e21c44SJohnny Huang 	int pass = 0;
2632*e7e21c44SJohnny Huang 
2633*e7e21c44SJohnny Huang 	ret = uclass_get_device_by_driver(UCLASS_MOD_EXP, DM_GET_DRIVER(aspeed_acry), &mod_exp_dev);
2634*e7e21c44SJohnny Huang 	if (ret) {
2635*e7e21c44SJohnny Huang 		printf("RSA engine: Can't find aspeed_acry\n");
2636*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2637*e7e21c44SJohnny Huang 	}
2638*e7e21c44SJohnny Huang 
2639*e7e21c44SJohnny Huang 	for (i = 0; i < 2048 ; i += 2)
2640*e7e21c44SJohnny Huang 		otp_read_data(i, &data[i]);
2641*e7e21c44SJohnny Huang 	if (parse_config(&si))
2642*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2643*e7e21c44SJohnny Huang 	parse_data(kl, &key_num, &si, data);
2644*e7e21c44SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2645*e7e21c44SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2646*e7e21c44SJohnny Huang 
2647*e7e21c44SJohnny Huang 	sec_image = (u8 *)addr;
2648*e7e21c44SJohnny Huang 	sh = (struct sb_header *)(sec_image + si.header_offset);
2649*e7e21c44SJohnny Huang 	signature = sec_image + sh->signature_offset;
2650*e7e21c44SJohnny Huang 
2651*e7e21c44SJohnny Huang 	if (si.secure_region)
2652*e7e21c44SJohnny Huang 		printf("WARNING: Secure Region is enabled, the verification may not correct.\n");
2653*e7e21c44SJohnny Huang 
2654*e7e21c44SJohnny Huang 	if (sh->sign_image_size % 512) {
2655*e7e21c44SJohnny Huang 		printf("ERROR: The sign_image_size should be 512 bytes aligned\n");
2656*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2657*e7e21c44SJohnny Huang 	}
2658*e7e21c44SJohnny Huang 
2659*e7e21c44SJohnny Huang 	printf("Check revision ID: ");
2660*e7e21c44SJohnny Huang 
2661*e7e21c44SJohnny Huang 	sw_rid[0] = sh->revision_low;
2662*e7e21c44SJohnny Huang 	sw_rid[1] = sh->revision_high;
2663*e7e21c44SJohnny Huang 
2664*e7e21c44SJohnny Huang 	if (*otp_rid64 > *sw_rid64) {
2665*e7e21c44SJohnny Huang 		printf("FAIL\n");
2666*e7e21c44SJohnny Huang 		printf("Header revision_low:  %x\n", sh->revision_low);
2667*e7e21c44SJohnny Huang 		printf("Header revision_high: %x\n", sh->revision_high);
2668*e7e21c44SJohnny Huang 		printf("OTP revision_low:     %x\n", otp_rid[0]);
2669*e7e21c44SJohnny Huang 		printf("OTP revision_high:    %x\n", otp_rid[1]);
2670*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2671*e7e21c44SJohnny Huang 	}
2672*e7e21c44SJohnny Huang 	printf("PASS\n");
2673*e7e21c44SJohnny Huang 
2674*e7e21c44SJohnny Huang 	printf("Check secure image header: ");
2675*e7e21c44SJohnny Huang 	if (((sh->aes_data_offset + sh->enc_offset + sh->sign_image_size +
2676*e7e21c44SJohnny Huang 	      sh->signature_offset + sh->revision_high + sh->revision_low +
2677*e7e21c44SJohnny Huang 	      sh->reserved + sh->bl1_header_checksum) & 0xffffffff) != 0) {
2678*e7e21c44SJohnny Huang 		printf("FAIL\n");
2679*e7e21c44SJohnny Huang 		printf("aes_data_offset:     %x\n", sh->aes_data_offset);
2680*e7e21c44SJohnny Huang 		printf("enc_offset:          %x\n", sh->enc_offset);
2681*e7e21c44SJohnny Huang 		printf("sign_image_size:     %x\n", sh->sign_image_size);
2682*e7e21c44SJohnny Huang 		printf("signature_offset:    %x\n", sh->signature_offset);
2683*e7e21c44SJohnny Huang 		printf("revision_high:       %x\n", sh->revision_high);
2684*e7e21c44SJohnny Huang 		printf("revision_low:        %x\n", sh->revision_low);
2685*e7e21c44SJohnny Huang 		printf("reserved:            %x\n", sh->reserved);
2686*e7e21c44SJohnny Huang 		printf("bl1_header_checksum: %x\n", sh->bl1_header_checksum);
2687*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2688*e7e21c44SJohnny Huang 	}
2689*e7e21c44SJohnny Huang 	printf("PASS\n");
2690*e7e21c44SJohnny Huang 
2691*e7e21c44SJohnny Huang 	ret = sb_sha(&si, sec_image, sh->sign_image_size, digest);
2692*e7e21c44SJohnny Huang 	if (ret)
2693*e7e21c44SJohnny Huang 		return OTP_FAILURE;
2694*e7e21c44SJohnny Huang 
2695*e7e21c44SJohnny Huang 	printf("Verifying secure image\n");
2696*e7e21c44SJohnny Huang 	for (i = 0; i < key_num; i++) {
2697*e7e21c44SJohnny Huang 		if (kl[i].key_info->key_type != OTP_KEY_TYPE_RSA_PUB)
2698*e7e21c44SJohnny Huang 			continue;
2699*e7e21c44SJohnny Huang 		printf(" Key %d\n", kl[i].id);
2700*e7e21c44SJohnny Huang 		if (kl[i].retire) {
2701*e7e21c44SJohnny Huang 			printf(" Key %d is retired.\n", kl[i].id);
2702*e7e21c44SJohnny Huang 			continue;
2703*e7e21c44SJohnny Huang 		}
2704*e7e21c44SJohnny Huang 		key = (u8 *)data + kl[i].offset;
2705*e7e21c44SJohnny Huang 		if (!mode2_verify(sec_image, sh->sign_image_size,
2706*e7e21c44SJohnny Huang 				  signature, key, kl[i].key_info->order, digest,
2707*e7e21c44SJohnny Huang 				  &si, mod_exp_dev)) {
2708*e7e21c44SJohnny Huang 			pass = 1;
2709*e7e21c44SJohnny Huang 			break;
2710*e7e21c44SJohnny Huang 		}
2711*e7e21c44SJohnny Huang 	}
2712*e7e21c44SJohnny Huang 	if (pass) {
2713*e7e21c44SJohnny Huang 		printf("  OEM DSS RSA public keys\n");
2714*e7e21c44SJohnny Huang 		printf("  ID: %d\n", kl[i].id);
2715*e7e21c44SJohnny Huang 		if (kl[i].key_info->order == OTP_BIG_END)
2716*e7e21c44SJohnny Huang 			printf("  Big endian\n");
2717*e7e21c44SJohnny Huang 		else
2718*e7e21c44SJohnny Huang 			printf("  Little endian\n");
2719*e7e21c44SJohnny Huang 		printf("Verify secure image: PASS\n");
2720*e7e21c44SJohnny Huang 		return OTP_SUCCESS;
2721*e7e21c44SJohnny Huang 	}
2722*e7e21c44SJohnny Huang 	printf("Verify secure image: FAIL\n");
2723*e7e21c44SJohnny Huang 	return OTP_FAILURE;
2724*e7e21c44SJohnny Huang }
2725*e7e21c44SJohnny Huang 
27262a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
272769d5fd8fSJohnny Huang {
2728a219f6deSJohnny Huang 	u32 offset, count;
27292a856b9aSJohnny Huang 	int ret;
273069d5fd8fSJohnny Huang 
27312a856b9aSJohnny Huang 	if (argc == 4) {
27322a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
27332a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
27342a856b9aSJohnny Huang 	} else if (argc == 3) {
27352a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
27362a856b9aSJohnny Huang 		count = 1;
27372a856b9aSJohnny Huang 	} else {
273869d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
273969d5fd8fSJohnny Huang 	}
274069d5fd8fSJohnny Huang 
2741030cb4a7SJohnny Huang 	if (!strcmp(argv[1], "conf"))
2742f347c284SJohnny Huang 		ret = otp_print_conf(offset, count);
2743030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "data"))
27442a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
2745030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "strap"))
27462a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
2747030cb4a7SJohnny Huang 	else
27482a856b9aSJohnny Huang 		return CMD_RET_USAGE;
274969d5fd8fSJohnny Huang 
27502a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
27512a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
27522a856b9aSJohnny Huang 	return CMD_RET_USAGE;
27532a856b9aSJohnny Huang }
27542a856b9aSJohnny Huang 
27552a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
27562a856b9aSJohnny Huang {
27572a856b9aSJohnny Huang 	phys_addr_t addr;
27582a856b9aSJohnny Huang 	int ret;
27592a856b9aSJohnny Huang 
2760de6b0cc4SJohnny Huang 	if (argc == 3) {
2761ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
27622a856b9aSJohnny Huang 			return CMD_RET_USAGE;
27632a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
2764f347c284SJohnny Huang 		ret = otp_prog_image(addr, 1);
2765de6b0cc4SJohnny Huang 	} else if (argc == 2) {
27662a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
2767f347c284SJohnny Huang 		ret = otp_prog_image(addr, 0);
27682a856b9aSJohnny Huang 	} else {
27692a856b9aSJohnny Huang 		return CMD_RET_USAGE;
27702a856b9aSJohnny Huang 	}
27712a856b9aSJohnny Huang 
27722a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
27732a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
27742a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
27752a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
27762a856b9aSJohnny Huang 	else
27772a856b9aSJohnny Huang 		return CMD_RET_USAGE;
27782a856b9aSJohnny Huang }
27792a856b9aSJohnny Huang 
27802a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
27812a856b9aSJohnny Huang {
27822a856b9aSJohnny Huang 	int mode = 0;
27832a856b9aSJohnny Huang 	int nconfirm = 0;
27842a856b9aSJohnny Huang 	int otp_addr = 0;
27852a856b9aSJohnny Huang 	int bit_offset;
27862a856b9aSJohnny Huang 	int value;
27872a856b9aSJohnny Huang 	int ret;
2788030cb4a7SJohnny Huang 	u32 otp_strap_pro;
27892a856b9aSJohnny Huang 
27902a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
27912a856b9aSJohnny Huang 		return CMD_RET_USAGE;
27922a856b9aSJohnny Huang 
27932a856b9aSJohnny Huang 	/* Drop the pb cmd */
27942a856b9aSJohnny Huang 	argc--;
27952a856b9aSJohnny Huang 	argv++;
27962a856b9aSJohnny Huang 
27972a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2798a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
27992a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2800a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
28012a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2802a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2803cd1610b4SJohnny Huang 	else
28042a856b9aSJohnny Huang 		return CMD_RET_USAGE;
28052a856b9aSJohnny Huang 
28062a856b9aSJohnny Huang 	/* Drop the region cmd */
28072a856b9aSJohnny Huang 	argc--;
28082a856b9aSJohnny Huang 	argv++;
28092a856b9aSJohnny Huang 
2810ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2811cd1610b4SJohnny Huang 		nconfirm = 1;
28122a856b9aSJohnny Huang 		/* Drop the force option */
28132a856b9aSJohnny Huang 		argc--;
28142a856b9aSJohnny Huang 		argv++;
28152a856b9aSJohnny Huang 	}
2816cd1610b4SJohnny Huang 
2817a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
28182a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
28192a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
28200808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
28212a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2822cd1610b4SJohnny Huang 	} else {
28232a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
28242a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
28252a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
28260808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
28272a856b9aSJohnny Huang 			return CMD_RET_USAGE;
28280808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
282978855207SJohnny Huang 			if (otp_addr >= 0x800)
28300808cc55SJohnny Huang 				return CMD_RET_USAGE;
28310808cc55SJohnny Huang 		} else {
283278855207SJohnny Huang 			if (otp_addr >= 0x20)
28330808cc55SJohnny Huang 				return CMD_RET_USAGE;
28340808cc55SJohnny Huang 		}
2835cd1610b4SJohnny Huang 	}
2836cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
28372a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2838cd1610b4SJohnny Huang 
2839030cb4a7SJohnny Huang 	ret = 0;
2840030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
2841030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
2842030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2843030cb4a7SJohnny Huang 	}
2844030cb4a7SJohnny Huang 	if (mode == OTP_REGION_DATA) {
2845030cb4a7SJohnny Huang 		if (info_cb.pro_sts.sec_size == 0) {
2846030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_data) {
2847030cb4a7SJohnny Huang 				printf("OTP data region is protected\n");
2848030cb4a7SJohnny Huang 				ret = -1;
2849030cb4a7SJohnny Huang 			}
2850030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) {
2851030cb4a7SJohnny Huang 			printf("OTP secure region is not readable, skip it to prevent unpredictable result\n");
2852030cb4a7SJohnny Huang 			ret = -1;
2853030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size) {
2854030cb4a7SJohnny Huang 			// header region(0x0~0x40) is still readable even secure region is set.
2855030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_sec) {
2856030cb4a7SJohnny Huang 				printf("OTP secure region is protected\n");
2857030cb4a7SJohnny Huang 				ret = -1;
2858030cb4a7SJohnny Huang 			}
2859030cb4a7SJohnny Huang 		} else if (info_cb.pro_sts.pro_data) {
2860030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
2861030cb4a7SJohnny Huang 			ret = -1;
2862030cb4a7SJohnny Huang 		}
2863030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_CONF) {
2864030cb4a7SJohnny Huang 		if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) {
2865030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_conf) {
2866030cb4a7SJohnny Huang 				printf("OTP config region is protected\n");
2867030cb4a7SJohnny Huang 				ret = -1;
2868030cb4a7SJohnny Huang 			}
2869030cb4a7SJohnny Huang 		} else if (otp_addr == 10 || otp_addr == 11) {
2870030cb4a7SJohnny Huang 			u32 otp_rid[2];
2871030cb4a7SJohnny Huang 			u32 sw_rid[2];
2872030cb4a7SJohnny Huang 			u64 *otp_rid64 = (u64 *)otp_rid;
2873030cb4a7SJohnny Huang 			u64 *sw_rid64 = (u64 *)sw_rid;
2874030cb4a7SJohnny Huang 
2875030cb4a7SJohnny Huang 			otp_read_conf(10, &otp_rid[0]);
2876030cb4a7SJohnny Huang 			otp_read_conf(11, &otp_rid[1]);
2877030cb4a7SJohnny Huang 			sw_rid[0] = readl(SW_REV_ID0);
2878030cb4a7SJohnny Huang 			sw_rid[1] = readl(SW_REV_ID1);
2879030cb4a7SJohnny Huang 
2880030cb4a7SJohnny Huang 			if (otp_addr == 10)
2881030cb4a7SJohnny Huang 				otp_rid[0] |= 1 << bit_offset;
2882030cb4a7SJohnny Huang 			else
2883030cb4a7SJohnny Huang 				otp_rid[1] |= 1 << bit_offset;
2884030cb4a7SJohnny Huang 
2885030cb4a7SJohnny Huang 			if (*otp_rid64 > *sw_rid64) {
2886030cb4a7SJohnny Huang 				printf("update number could not bigger than current SW revision id\n");
2887030cb4a7SJohnny Huang 				ret = -1;
2888030cb4a7SJohnny Huang 			}
2889030cb4a7SJohnny Huang 		} else if (otp_addr == 4) {
2890030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_key_ret) {
2891030cb4a7SJohnny Huang 				printf("OTPCFG4 is protected\n");
2892030cb4a7SJohnny Huang 				ret = -1;
2893030cb4a7SJohnny Huang 			} else {
2894030cb4a7SJohnny Huang 				if ((bit_offset >= 0 && bit_offset <= 7) ||
2895030cb4a7SJohnny Huang 				    (bit_offset >= 16 && bit_offset <= 23)) {
2896030cb4a7SJohnny Huang 					u32 key_num;
2897030cb4a7SJohnny Huang 					u32 retire;
2898030cb4a7SJohnny Huang 
2899030cb4a7SJohnny Huang 					key_num = readl(SEC_KEY_NUM) & 3;
2900030cb4a7SJohnny Huang 					if (bit_offset >= 16)
2901030cb4a7SJohnny Huang 						retire = bit_offset - 16;
2902030cb4a7SJohnny Huang 					else
2903030cb4a7SJohnny Huang 						retire = bit_offset;
2904030cb4a7SJohnny Huang 					if (retire >= key_num) {
2905030cb4a7SJohnny Huang 						printf("Retire key id is equal or bigger than current boot key\n");
2906030cb4a7SJohnny Huang 						ret = -1;
2907030cb4a7SJohnny Huang 					}
2908030cb4a7SJohnny Huang 				}
2909030cb4a7SJohnny Huang 			}
2910030cb4a7SJohnny Huang 		} else if (otp_addr >= 16 && otp_addr <= 31) {
2911030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_strap) {
2912030cb4a7SJohnny Huang 				printf("OTP strap region is protected\n");
2913030cb4a7SJohnny Huang 				ret = -1;
2914030cb4a7SJohnny Huang 			} else if ((otp_addr < 30 && info_cb.version == OTP_A0) ||
2915030cb4a7SJohnny Huang 				   (otp_addr < 28 && info_cb.version != OTP_A0)) {
2916030cb4a7SJohnny Huang 				if (otp_addr % 2 == 0)
2917030cb4a7SJohnny Huang 					otp_read_conf(30, &otp_strap_pro);
2918030cb4a7SJohnny Huang 				else
2919030cb4a7SJohnny Huang 					otp_read_conf(31, &otp_strap_pro);
2920030cb4a7SJohnny Huang 				if (otp_strap_pro >> bit_offset & 0x1) {
2921b489486eSJohnny Huang 					printf("OTPCFG0x%X[0x%X] is protected\n", otp_addr, bit_offset);
2922030cb4a7SJohnny Huang 					ret = -1;
2923030cb4a7SJohnny Huang 				}
2924030cb4a7SJohnny Huang 			}
2925030cb4a7SJohnny Huang 		}
2926030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_STRAP) {
2927030cb4a7SJohnny Huang 		// per bit protection will check in otp_strap_bit_confirm
2928030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
2929030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
2930030cb4a7SJohnny Huang 			ret = -1;
2931030cb4a7SJohnny Huang 		}
2932030cb4a7SJohnny Huang 	}
2933030cb4a7SJohnny Huang 
2934030cb4a7SJohnny Huang 	if (ret == -1)
2935030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2936030cb4a7SJohnny Huang 
2937f347c284SJohnny Huang 	ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
29382a856b9aSJohnny Huang 
29392a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
29402a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
29412a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
29422a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
29432a856b9aSJohnny Huang 	else
29442a856b9aSJohnny Huang 		return CMD_RET_USAGE;
29452a856b9aSJohnny Huang }
29462a856b9aSJohnny Huang 
29472a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
29482a856b9aSJohnny Huang {
29492a856b9aSJohnny Huang 	phys_addr_t addr;
29502a856b9aSJohnny Huang 	int otp_addr = 0;
2951b8590031SJohnny Huang 	int ret;
29522a856b9aSJohnny Huang 
29532a856b9aSJohnny Huang 	if (argc != 3)
29542a856b9aSJohnny Huang 		return CMD_RET_USAGE;
29552a856b9aSJohnny Huang 
29562a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
29572a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
2958b8590031SJohnny Huang 	ret = otp_compare(otp_addr, addr);
2959b8590031SJohnny Huang 	if (ret == 0) {
296069d5fd8fSJohnny Huang 		printf("Compare pass\n");
29612a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2962a219f6deSJohnny Huang 	}
296369d5fd8fSJohnny Huang 	printf("Compare fail\n");
29642a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
296569d5fd8fSJohnny Huang }
296669d5fd8fSJohnny Huang 
296766f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
296866f2f8e5SJohnny Huang {
2969a8bd6d8cSJohnny Huang 	int view = 0;
29702d4b0742SJohnny Huang 	int input;
2971a8bd6d8cSJohnny Huang 
2972a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
297366f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
297466f2f8e5SJohnny Huang 
29752d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
29762d4b0742SJohnny Huang 		if (argc == 3) {
29772d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
29782d4b0742SJohnny Huang 			otp_print_conf_info(input);
29792d4b0742SJohnny Huang 		} else {
29802d4b0742SJohnny Huang 			otp_print_conf_info(-1);
29812d4b0742SJohnny Huang 		}
29822d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
29832d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2984a8bd6d8cSJohnny Huang 			view = 1;
2985a8bd6d8cSJohnny Huang 			/* Drop the view option */
2986a8bd6d8cSJohnny Huang 			argc--;
2987a8bd6d8cSJohnny Huang 			argv++;
2988a8bd6d8cSJohnny Huang 		}
2989b458cd62SJohnny Huang 		otp_print_strap_info(view);
29900dc9a440SJohnny Huang 	} else if (!strcmp(argv[1], "scu")) {
29910dc9a440SJohnny Huang 		otp_print_scu_info();
299288bd7d58SJohnny Huang 	} else if (!strcmp(argv[1], "key")) {
299388bd7d58SJohnny Huang 		otp_print_key_info();
299466f2f8e5SJohnny Huang 	} else {
299566f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
299666f2f8e5SJohnny Huang 	}
29972d4b0742SJohnny Huang 
299866f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
299966f2f8e5SJohnny Huang }
300066f2f8e5SJohnny Huang 
30010dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3002737ed20bSJohnny Huang {
30030dc9a440SJohnny Huang 	u32 input;
30040dc9a440SJohnny Huang 	u32 bit_offset;
3005e14b073cSJohnny Huang 	u32 prog_address;
3006030cb4a7SJohnny Huang 	char force;
300783655e91SJohnny Huang 	int ret;
3008a219f6deSJohnny Huang 
3009737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
3010737ed20bSJohnny Huang 		return CMD_RET_USAGE;
3011737ed20bSJohnny Huang 
3012e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
3013737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
3014030cb4a7SJohnny Huang 		force = 1;
3015737ed20bSJohnny Huang 	} else {
3016737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
3017030cb4a7SJohnny Huang 		force = 0;
3018737ed20bSJohnny Huang 	}
3019737ed20bSJohnny Huang 
3020737ed20bSJohnny Huang 	if (input < 32) {
3021737ed20bSJohnny Huang 		bit_offset = input;
30220dc9a440SJohnny Huang 		prog_address = 0xe0c;
3023737ed20bSJohnny Huang 	} else if (input < 64) {
3024737ed20bSJohnny Huang 		bit_offset = input - 32;
30250dc9a440SJohnny Huang 		prog_address = 0xe0e;
3026737ed20bSJohnny Huang 	} else {
3027737ed20bSJohnny Huang 		return CMD_RET_USAGE;
3028737ed20bSJohnny Huang 	}
3029737ed20bSJohnny Huang 
3030030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
3031030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
3032030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
3033030cb4a7SJohnny Huang 	}
3034030cb4a7SJohnny Huang 
3035030cb4a7SJohnny Huang 	if (!force) {
3036b489486eSJohnny Huang 		printf("OTPSTRAP[0x%X] will be protected\n", input);
3037030cb4a7SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
3038030cb4a7SJohnny Huang 		if (!confirm_yesno()) {
3039030cb4a7SJohnny Huang 			printf(" Aborting\n");
3040030cb4a7SJohnny Huang 			return CMD_RET_FAILURE;
3041030cb4a7SJohnny Huang 		}
3042030cb4a7SJohnny Huang 	}
3043030cb4a7SJohnny Huang 
3044e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
3045b489486eSJohnny Huang 		printf("OTPSTRAP[0x%X] already protected\n", input);
3046e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
3047e14b073cSJohnny Huang 	}
3048de6fbf1cSJohnny Huang 
3049f347c284SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
3050de6fbf1cSJohnny Huang 	otp_soak(0);
305183655e91SJohnny Huang 
305283655e91SJohnny Huang 	if (ret) {
3053b489486eSJohnny Huang 		printf("Protect OTPSTRAP[0x%X] fail\n", input);
3054737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
3055737ed20bSJohnny Huang 	}
30569a4fe690SJohnny Huang 
3057b489486eSJohnny Huang 	printf("OTPSTRAP[0x%X] is protected\n", input);
3058794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
3059794e27ecSJohnny Huang }
3060794e27ecSJohnny Huang 
30610dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3062e14b073cSJohnny Huang {
30630dc9a440SJohnny Huang 	u32 scu_offset;
30640dc9a440SJohnny Huang 	u32 bit_offset;
30650dc9a440SJohnny Huang 	u32 conf_offset;
30660dc9a440SJohnny Huang 	u32 prog_address;
30670dc9a440SJohnny Huang 	char force;
30680dc9a440SJohnny Huang 	int ret;
30690dc9a440SJohnny Huang 
30700dc9a440SJohnny Huang 	if (argc != 4 && argc != 3)
30710dc9a440SJohnny Huang 		return CMD_RET_USAGE;
30720dc9a440SJohnny Huang 
30730dc9a440SJohnny Huang 	if (!strcmp(argv[1], "o")) {
30740dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[2], NULL, 16);
30750dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[3], NULL, 16);
30760dc9a440SJohnny Huang 		force = 1;
30770dc9a440SJohnny Huang 	} else {
30780dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[1], NULL, 16);
30790dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[2], NULL, 16);
30800dc9a440SJohnny Huang 		force = 0;
30810dc9a440SJohnny Huang 	}
30820dc9a440SJohnny Huang 	if (scu_offset == 0x500) {
30830dc9a440SJohnny Huang 		prog_address = 0xe08;
30840dc9a440SJohnny Huang 		conf_offset = 28;
30850dc9a440SJohnny Huang 	} else if (scu_offset == 0x510) {
30860dc9a440SJohnny Huang 		prog_address = 0xe0a;
30870dc9a440SJohnny Huang 		conf_offset = 29;
30880dc9a440SJohnny Huang 	} else {
30890dc9a440SJohnny Huang 		return CMD_RET_USAGE;
30900dc9a440SJohnny Huang 	}
30910dc9a440SJohnny Huang 	if (bit_offset < 0 || bit_offset > 31)
30920dc9a440SJohnny Huang 		return CMD_RET_USAGE;
3093030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
3094030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
3095030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
3096030cb4a7SJohnny Huang 	}
30970dc9a440SJohnny Huang 	if (!force) {
3098b489486eSJohnny Huang 		printf("OTPCONF0x%X[0x%X] will be programmed\n", conf_offset, bit_offset);
3099b489486eSJohnny Huang 		printf("SCU0x%X[0x%X] will be protected\n", scu_offset, bit_offset);
31000dc9a440SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
31010dc9a440SJohnny Huang 		if (!confirm_yesno()) {
31020dc9a440SJohnny Huang 			printf(" Aborting\n");
31030dc9a440SJohnny Huang 			return CMD_RET_FAILURE;
31040dc9a440SJohnny Huang 		}
3105e14b073cSJohnny Huang 	}
3106e14b073cSJohnny Huang 
31070dc9a440SJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
3108b489486eSJohnny Huang 		printf("OTPCONF0x%X[0x%X] already programmed\n", conf_offset, bit_offset);
31090dc9a440SJohnny Huang 		return CMD_RET_SUCCESS;
31100dc9a440SJohnny Huang 	}
31110dc9a440SJohnny Huang 
31120dc9a440SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
31130dc9a440SJohnny Huang 	otp_soak(0);
31140dc9a440SJohnny Huang 
31150dc9a440SJohnny Huang 	if (ret) {
3116b489486eSJohnny Huang 		printf("Program OTPCONF0x%X[0x%X] fail\n", conf_offset, bit_offset);
31170dc9a440SJohnny Huang 		return CMD_RET_FAILURE;
31180dc9a440SJohnny Huang 	}
31190dc9a440SJohnny Huang 
3120b489486eSJohnny Huang 	printf("OTPCONF0x%X[0x%X] programmed success\n", conf_offset, bit_offset);
31210dc9a440SJohnny Huang 	return CMD_RET_SUCCESS;
3122e14b073cSJohnny Huang }
3123e14b073cSJohnny Huang 
3124f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3125f67375f7SJohnny Huang {
3126e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
3127f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
3128f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
3129f67375f7SJohnny Huang 
3130f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
3131f67375f7SJohnny Huang }
3132f67375f7SJohnny Huang 
3133794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3134794e27ecSJohnny Huang {
3135794e27ecSJohnny Huang 	u32 update_num;
3136794e27ecSJohnny Huang 	int force = 0;
3137794e27ecSJohnny Huang 	int ret;
3138794e27ecSJohnny Huang 
3139794e27ecSJohnny Huang 	if (argc == 3) {
3140794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
3141794e27ecSJohnny Huang 			return CMD_RET_USAGE;
3142794e27ecSJohnny Huang 		force = 1;
3143794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
3144794e27ecSJohnny Huang 	} else if (argc == 2) {
3145794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
3146794e27ecSJohnny Huang 	} else {
3147794e27ecSJohnny Huang 		return CMD_RET_USAGE;
3148794e27ecSJohnny Huang 	}
3149794e27ecSJohnny Huang 
3150794e27ecSJohnny Huang 	if (update_num > 64)
3151794e27ecSJohnny Huang 		return CMD_RET_USAGE;
3152794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
3153b8590031SJohnny Huang 
3154794e27ecSJohnny Huang 	if (ret)
3155794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
3156794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
3157794e27ecSJohnny Huang }
3158794e27ecSJohnny Huang 
3159794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3160794e27ecSJohnny Huang {
3161794e27ecSJohnny Huang 	u32 otp_rid[2];
3162a8789b47SJohnny Huang 	u32 sw_rid[2];
3163794e27ecSJohnny Huang 	int rid_num = 0;
3164a8789b47SJohnny Huang 	int sw_rid_num = 0;
3165794e27ecSJohnny Huang 	int ret;
3166794e27ecSJohnny Huang 
3167794e27ecSJohnny Huang 	if (argc != 1)
3168794e27ecSJohnny Huang 		return CMD_RET_USAGE;
3169794e27ecSJohnny Huang 
3170f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
3171f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
3172794e27ecSJohnny Huang 
3173a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
3174a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
3175794e27ecSJohnny Huang 
3176a8789b47SJohnny Huang 	rid_num = get_rid_num(otp_rid);
3177a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
3178a8789b47SJohnny Huang 
3179030cb4a7SJohnny Huang 	if (sw_rid_num < 0) {
3180030cb4a7SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
3181030cb4a7SJohnny Huang 		printf("SEC68:0x%x\n", sw_rid[0]);
3182030cb4a7SJohnny Huang 		printf("SEC6C:0x%x\n", sw_rid[1]);
3183030cb4a7SJohnny Huang 	} else {
3184a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
3185030cb4a7SJohnny Huang 	}
3186794e27ecSJohnny Huang 	if (rid_num >= 0) {
3187794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
3188794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
3189794e27ecSJohnny Huang 	} else {
3190b64ca396SJohnny Huang 		printf("Current OTP revision ID cannot handle by 'otp update',\n"
3191b64ca396SJohnny Huang 		       "please use 'otp pb' command to update it manually\n"
3192794e27ecSJohnny Huang 		       "current OTP revision ID\n");
3193794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
3194794e27ecSJohnny Huang 	}
3195794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
3196794e27ecSJohnny Huang 
3197794e27ecSJohnny Huang 	return ret;
3198794e27ecSJohnny Huang }
3199794e27ecSJohnny Huang 
3200883625c5SJohnny Huang static int do_otpretire(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3201883625c5SJohnny Huang {
3202883625c5SJohnny Huang 	u32 retire_id;
3203883625c5SJohnny Huang 	int force = 0;
3204883625c5SJohnny Huang 	int ret;
3205883625c5SJohnny Huang 
3206883625c5SJohnny Huang 	if (argc == 3) {
3207883625c5SJohnny Huang 		if (strcmp(argv[1], "o"))
3208883625c5SJohnny Huang 			return CMD_RET_USAGE;
3209883625c5SJohnny Huang 		force = 1;
3210883625c5SJohnny Huang 		retire_id = simple_strtoul(argv[2], NULL, 16);
3211883625c5SJohnny Huang 	} else if (argc == 2) {
3212883625c5SJohnny Huang 		retire_id = simple_strtoul(argv[1], NULL, 16);
3213883625c5SJohnny Huang 	} else {
3214883625c5SJohnny Huang 		return CMD_RET_USAGE;
3215883625c5SJohnny Huang 	}
3216883625c5SJohnny Huang 
3217883625c5SJohnny Huang 	if (retire_id > 7)
3218883625c5SJohnny Huang 		return CMD_RET_USAGE;
3219883625c5SJohnny Huang 	ret = otp_retire_key(retire_id, force);
3220883625c5SJohnny Huang 
3221883625c5SJohnny Huang 	if (ret)
3222883625c5SJohnny Huang 		return CMD_RET_FAILURE;
3223883625c5SJohnny Huang 	return CMD_RET_SUCCESS;
3224883625c5SJohnny Huang }
3225883625c5SJohnny Huang 
3226*e7e21c44SJohnny Huang static int do_otpverify(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
3227*e7e21c44SJohnny Huang {
3228*e7e21c44SJohnny Huang 	phys_addr_t addr;
3229*e7e21c44SJohnny Huang 	int ret;
3230*e7e21c44SJohnny Huang 
3231*e7e21c44SJohnny Huang 	if (argc == 2) {
3232*e7e21c44SJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
3233*e7e21c44SJohnny Huang 		ret = otp_verify_boot_image(addr);
3234*e7e21c44SJohnny Huang 	} else {
3235*e7e21c44SJohnny Huang 		return CMD_RET_USAGE;
3236*e7e21c44SJohnny Huang 	}
3237*e7e21c44SJohnny Huang 
3238*e7e21c44SJohnny Huang 	if (ret == OTP_SUCCESS)
3239*e7e21c44SJohnny Huang 		return CMD_RET_SUCCESS;
3240*e7e21c44SJohnny Huang 	else if (ret == OTP_FAILURE)
3241*e7e21c44SJohnny Huang 		return CMD_RET_FAILURE;
3242*e7e21c44SJohnny Huang 	else
3243*e7e21c44SJohnny Huang 		return CMD_RET_USAGE;
3244*e7e21c44SJohnny Huang }
3245*e7e21c44SJohnny Huang 
32462a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
3247f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
32482a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
3249a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
3250de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
32512a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
3252737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
32530dc9a440SJohnny Huang 	U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""),
32542a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
3255794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
3256794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
3257883625c5SJohnny Huang 	U_BOOT_CMD_MKENT(retire, 3, 0, do_otpretire, "", ""),
3258*e7e21c44SJohnny Huang 	U_BOOT_CMD_MKENT(verify, 2, 0, do_otpverify, "", ""),
32592a856b9aSJohnny Huang };
32602a856b9aSJohnny Huang 
32612a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
32622a856b9aSJohnny Huang {
3263030cb4a7SJohnny Huang 	struct otp_pro_sts *pro_sts;
32642a856b9aSJohnny Huang 	cmd_tbl_t *cp;
3265a219f6deSJohnny Huang 	u32 ver;
3266e14b073cSJohnny Huang 	int ret;
3267030cb4a7SJohnny Huang 	u32 otp_conf0;
32682a856b9aSJohnny Huang 
32692a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
32702a856b9aSJohnny Huang 
3271737ed20bSJohnny Huang 	/* Drop the otp command */
32722a856b9aSJohnny Huang 	argc--;
32732a856b9aSJohnny Huang 	argv++;
32742a856b9aSJohnny Huang 
3275a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
32762a856b9aSJohnny Huang 		return CMD_RET_USAGE;
32772a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
32782a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
32792a856b9aSJohnny Huang 
32800dae9d52SJohnny Huang 	ver = chip_version();
32810dae9d52SJohnny Huang 	switch (ver) {
3282e417205bSJohnny Huang 	case OTP_A0:
3283e417205bSJohnny Huang 		info_cb.version = OTP_A0;
32849a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
32859a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
32869a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
32879a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
32889a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
32899a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
3290e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
32910dae9d52SJohnny Huang 		break;
3292e417205bSJohnny Huang 	case OTP_A1:
3293e417205bSJohnny Huang 		info_cb.version = OTP_A1;
32943cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
32953cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
32963cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
32973cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
32989a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
32999a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
33000dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
33010dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
3302e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
33030dae9d52SJohnny Huang 		break;
3304e417205bSJohnny Huang 	case OTP_A2:
3305e417205bSJohnny Huang 		info_cb.version = OTP_A2;
33065fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
33075fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
3308fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
3309fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
33105fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
33115fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
33120dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
33130dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
3314e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
33150dae9d52SJohnny Huang 		break;
3316e417205bSJohnny Huang 	case OTP_A3:
3317e417205bSJohnny Huang 		info_cb.version = OTP_A3;
3318b63af886SJohnny Huang 		info_cb.conf_info = a3_conf_info;
3319b63af886SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
3320fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
3321fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
3322181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
3323181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
33240dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
33250dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
3326e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
332764b66712SJohnny Huang 		break;
33280dae9d52SJohnny Huang 	default:
3329f1be5099SJohnny Huang 		printf("SOC is not supported\n");
33300dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
33319a4fe690SJohnny Huang 	}
33329a4fe690SJohnny Huang 
3333030cb4a7SJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
3334030cb4a7SJohnny Huang 	otp_read_conf(0, &otp_conf0);
3335030cb4a7SJohnny Huang 	pro_sts = &info_cb.pro_sts;
3336030cb4a7SJohnny Huang 
3337030cb4a7SJohnny Huang 	pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1;
3338030cb4a7SJohnny Huang 	pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1;
3339030cb4a7SJohnny Huang 	pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1;
3340030cb4a7SJohnny Huang 	pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1;
3341030cb4a7SJohnny Huang 	pro_sts->pro_data = (otp_conf0 >> 23) & 0x1;
3342030cb4a7SJohnny Huang 	pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1;
3343030cb4a7SJohnny Huang 	pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5;
3344030cb4a7SJohnny Huang 
3345e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
3346b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
3347e14b073cSJohnny Huang 
3348e14b073cSJohnny Huang 	return ret;
334969d5fd8fSJohnny Huang }
335069d5fd8fSJohnny Huang 
3351a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
335269d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
3353f67375f7SJohnny Huang 	   "version\n"
3354f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
33552a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
33562d4b0742SJohnny Huang 	   "otp info strap [v]\n"
33572d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
33580dc9a440SJohnny Huang 	   "otp info scu\n"
335988bd7d58SJohnny Huang 	   "otp info key\n"
3360de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
3361ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
3362ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
3363ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
33640dc9a440SJohnny Huang 	   "otp scuprotect [o] <scu_offset> <bit_offset>\n"
3365794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
3366794e27ecSJohnny Huang 	   "otp rid\n"
3367883625c5SJohnny Huang 	   "otp retire [o] <key_id>\n"
3368*e7e21c44SJohnny Huang 	   "otp verify <addr>\n"
336969d5fd8fSJohnny Huang 	  );
3370