xref: /openbmc/u-boot/cmd/otp.c (revision 030cb4a7e031736a93a4a7e7f672aa1515f722ef)
1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+
269d5fd8fSJohnny Huang /*
3a219f6deSJohnny Huang  * Copyright 2021 Aspeed Technology Inc.
469d5fd8fSJohnny Huang  */
5e417205bSJohnny Huang 
64c1c9b35SJohnny Huang #include <stdlib.h>
769d5fd8fSJohnny Huang #include <common.h>
869d5fd8fSJohnny Huang #include <console.h>
969d5fd8fSJohnny Huang #include <bootretry.h>
1069d5fd8fSJohnny Huang #include <cli.h>
1169d5fd8fSJohnny Huang #include <command.h>
1269d5fd8fSJohnny Huang #include <console.h>
134c1c9b35SJohnny Huang #include <malloc.h>
1469d5fd8fSJohnny Huang #include <inttypes.h>
1569d5fd8fSJohnny Huang #include <mapmem.h>
1669d5fd8fSJohnny Huang #include <asm/io.h>
1769d5fd8fSJohnny Huang #include <linux/compiler.h>
18696656c6SJohnny Huang #include <u-boot/sha256.h>
190cee9a95SJohnny Huang #include "otp_info.h"
2069d5fd8fSJohnny Huang 
2169d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2269d5fd8fSJohnny Huang 
23f347c284SJohnny Huang #define OTP_VER				"1.1.0"
24f67375f7SJohnny Huang 
2569d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
26dacbba92SJohnny Huang #define RETRY				20
277332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
287332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
297332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3069d5fd8fSJohnny Huang 
312a856b9aSJohnny Huang #define OTP_USAGE			-1
322a856b9aSJohnny Huang #define OTP_FAILURE			-2
332a856b9aSJohnny Huang #define OTP_SUCCESS			0
342a856b9aSJohnny Huang 
35a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
36a6af4a17SJohnny Huang 
37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB		1
38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV		2
39181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES		3
40181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT		4
41181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC		5
429a4fe690SJohnny Huang 
434c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
444c1c9b35SJohnny Huang #define PBWIDTH 60
454c1c9b35SJohnny Huang 
463d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
473d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
483d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
493d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
503d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
513d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
523d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
533d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
543d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
553d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
56a8789b47SJohnny Huang #define SW_REV_ID0		OTP_BASE + 0x68
57a8789b47SJohnny Huang #define SW_REV_ID1		OTP_BASE + 0x6c
58*030cb4a7SJohnny Huang #define SEC_KEY_NUM		OTP_BASE + 0x78
593d3688adSJohnny Huang 
60696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
61696656c6SJohnny Huang #define CHECKSUM_LEN		32
62a219f6deSJohnny Huang #define OTP_INC_DATA		BIT(31)
63a219f6deSJohnny Huang #define OTP_INC_CONFIG		BIT(30)
64a219f6deSJohnny Huang #define OTP_INC_STRAP		BIT(29)
65a219f6deSJohnny Huang #define OTP_ECC_EN		BIT(28)
66696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
67696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
68696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
69696656c6SJohnny Huang 
70e417205bSJohnny Huang #define OTP_A0		0
71e417205bSJohnny Huang #define OTP_A1		1
72e417205bSJohnny Huang #define OTP_A2		2
73e417205bSJohnny Huang #define OTP_A3		3
74e417205bSJohnny Huang 
75e417205bSJohnny Huang #define ID0_AST2600A0	0x05000303
76e417205bSJohnny Huang #define ID1_AST2600A0	0x05000303
77e417205bSJohnny Huang #define ID0_AST2600A1	0x05010303
7821a8cfceSJohnny Huang #define ID1_AST2600A1	0x05010303
79e417205bSJohnny Huang #define ID0_AST2600A2	0x05010303
80e417205bSJohnny Huang #define ID1_AST2600A2	0x05020303
81e417205bSJohnny Huang #define ID0_AST2600A3	0x05030303
82e417205bSJohnny Huang #define ID1_AST2600A3	0x05030303
83e417205bSJohnny Huang #define ID0_AST2620A1	0x05010203
84e417205bSJohnny Huang #define ID1_AST2620A1	0x05010203
85e417205bSJohnny Huang #define ID0_AST2620A2	0x05010203
86e417205bSJohnny Huang #define ID1_AST2620A2	0x05020203
87e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
88e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
89e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
90e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
91e417205bSJohnny Huang #define ID0_AST2605A2	0x05010103
92e417205bSJohnny Huang #define ID1_AST2605A2	0x05020103
93e417205bSJohnny Huang #define ID0_AST2605A3	0x05030103
94e417205bSJohnny Huang #define ID1_AST2605A3	0x05030103
95e417205bSJohnny Huang #define ID0_AST2625A3	0x05030403
96e417205bSJohnny Huang #define ID1_AST2625A3	0x05030403
97696656c6SJohnny Huang 
9861a6cda7SJohnny Huang #define SOC_AST2600A0	0
9961a6cda7SJohnny Huang #define SOC_AST2600A1	1
10061a6cda7SJohnny Huang #define SOC_AST2600A2	2
10161a6cda7SJohnny Huang #define SOC_AST2600A3	3
10261a6cda7SJohnny Huang 
10361a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c))
10461a6cda7SJohnny Huang 
105696656c6SJohnny Huang struct otp_header {
106696656c6SJohnny Huang 	u8	otp_magic[8];
10761a6cda7SJohnny Huang 	u32	soc_ver;
10861a6cda7SJohnny Huang 	u32	otptool_ver;
109696656c6SJohnny Huang 	u32	image_info;
110696656c6SJohnny Huang 	u32	data_info;
111696656c6SJohnny Huang 	u32	config_info;
112696656c6SJohnny Huang 	u32	strap_info;
1137e523e3bSJohnny Huang 	u32	scu_protect_info;
114696656c6SJohnny Huang 	u32	checksum_offset;
115a219f6deSJohnny Huang } __packed;
116696656c6SJohnny Huang 
11766f2f8e5SJohnny Huang struct otpstrap_status {
11869d5fd8fSJohnny Huang 	int value;
11969d5fd8fSJohnny Huang 	int option_array[7];
12069d5fd8fSJohnny Huang 	int remain_times;
12169d5fd8fSJohnny Huang 	int writeable_option;
12269d5fd8fSJohnny Huang 	int protected;
12369d5fd8fSJohnny Huang };
12469d5fd8fSJohnny Huang 
1259a4fe690SJohnny Huang struct otpkey_type {
1269a4fe690SJohnny Huang 	int value;
1279a4fe690SJohnny Huang 	int key_type;
1289a4fe690SJohnny Huang 	int need_id;
1299a4fe690SJohnny Huang 	char information[110];
1309a4fe690SJohnny Huang };
1319a4fe690SJohnny Huang 
132*030cb4a7SJohnny Huang struct otp_pro_sts {
133*030cb4a7SJohnny Huang 	char mem_lock;
134*030cb4a7SJohnny Huang 	char pro_key_ret;
135*030cb4a7SJohnny Huang 	char pro_strap;
136*030cb4a7SJohnny Huang 	char pro_conf;
137*030cb4a7SJohnny Huang 	char pro_data;
138*030cb4a7SJohnny Huang 	char pro_sec;
139*030cb4a7SJohnny Huang 	u32 sec_size;
140*030cb4a7SJohnny Huang };
141*030cb4a7SJohnny Huang 
1429a4fe690SJohnny Huang struct otp_info_cb {
1439a4fe690SJohnny Huang 	int version;
144e417205bSJohnny Huang 	char ver_name[3];
14579e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1469a4fe690SJohnny Huang 	int strap_info_len;
14779e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1489a4fe690SJohnny Huang 	int conf_info_len;
14979e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1509a4fe690SJohnny Huang 	int key_info_len;
1510dc9a440SJohnny Huang 	const struct scu_info *scu_info;
1520dc9a440SJohnny Huang 	int scu_info_len;
153*030cb4a7SJohnny Huang 	struct otp_pro_sts pro_sts;
1549a4fe690SJohnny Huang };
1559a4fe690SJohnny Huang 
156696656c6SJohnny Huang struct otp_image_layout {
1575010032bSJohnny Huang 	int data_length;
1585010032bSJohnny Huang 	int conf_length;
1595010032bSJohnny Huang 	int strap_length;
160a219f6deSJohnny Huang 	u8 *data;
161a219f6deSJohnny Huang 	u8 *data_ignore;
162a219f6deSJohnny Huang 	u8 *conf;
163a219f6deSJohnny Huang 	u8 *conf_ignore;
164a219f6deSJohnny Huang 	u8 *strap;
165a219f6deSJohnny Huang 	u8 *strap_pro;
166a219f6deSJohnny Huang 	u8 *strap_ignore;
167696656c6SJohnny Huang };
168696656c6SJohnny Huang 
1699a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1709a4fe690SJohnny Huang 
17179e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1729a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1739a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1749a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
175181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
176181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   0, "RSA-public as SOC public key"},
177181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
178181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as SOC private key"},
179181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1809a4fe690SJohnny Huang };
1819a4fe690SJohnny Huang 
18279e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1839a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1849a4fe690SJohnny Huang 	{2, OTP_KEY_TYPE_AES,   1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
185181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
186181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
187181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1889a4fe690SJohnny Huang };
1899a4fe690SJohnny Huang 
1905fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1915fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1925fdde29fSJohnny Huang 	{2, OTP_KEY_TYPE_AES,   1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
193181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
194181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
195181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
196181f72d8SJohnny Huang };
197181f72d8SJohnny Huang 
198181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
199181f72d8SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
200181f72d8SJohnny Huang 	{2, OTP_KEY_TYPE_AES,   1, "AES-256 as OEM platform key for image encryption/decryption in Mode 2 or AES-256 as OEM DSS keys for Mode GCM"},
201181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
202181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
203181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
204181f72d8SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key(big endian)"},
205181f72d8SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
206181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key(big endian)"},
2075fdde29fSJohnny Huang };
2085fdde29fSJohnny Huang 
209f347c284SJohnny Huang static void buf_print(u8 *buf, int len)
210f347c284SJohnny Huang {
211f347c284SJohnny Huang 	int i;
212f347c284SJohnny Huang 
213f347c284SJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
214f347c284SJohnny Huang 	for (i = 0; i < len; i++) {
215f347c284SJohnny Huang 		if (i % 16 == 0)
216f347c284SJohnny Huang 			printf("%04X: ", i);
217f347c284SJohnny Huang 		printf("%02X ", buf[i]);
218f347c284SJohnny Huang 		if ((i + 1) % 16 == 0)
219f347c284SJohnny Huang 			printf("\n");
220f347c284SJohnny Huang 	}
221f347c284SJohnny Huang }
222f347c284SJohnny Huang 
223794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
224794e27ecSJohnny Huang {
225794e27ecSJohnny Huang 	int bit_offset;
226794e27ecSJohnny Huang 	int i;
227794e27ecSJohnny Huang 
228794e27ecSJohnny Huang 	if (offset < 32) {
229794e27ecSJohnny Huang 		i = 0;
230794e27ecSJohnny Huang 		bit_offset = offset;
231794e27ecSJohnny Huang 	} else {
232794e27ecSJohnny Huang 		i = 1;
233794e27ecSJohnny Huang 		bit_offset = offset - 32;
234794e27ecSJohnny Huang 	}
235794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
236794e27ecSJohnny Huang 		return 1;
237794e27ecSJohnny Huang 	else
238794e27ecSJohnny Huang 		return 0;
239794e27ecSJohnny Huang }
240794e27ecSJohnny Huang 
241794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
242794e27ecSJohnny Huang {
243794e27ecSJohnny Huang 	int i;
244794e27ecSJohnny Huang 	int fz = 0;
245794e27ecSJohnny Huang 	int rid_num = 0;
246794e27ecSJohnny Huang 	int ret = 0;
247794e27ecSJohnny Huang 
248794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
249794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
250794e27ecSJohnny Huang 			if (!fz)
251794e27ecSJohnny Huang 				fz = 1;
252794e27ecSJohnny Huang 
253794e27ecSJohnny Huang 		} else {
254794e27ecSJohnny Huang 			rid_num++;
255794e27ecSJohnny Huang 			if (fz)
256794e27ecSJohnny Huang 				ret = OTP_FAILURE;
257794e27ecSJohnny Huang 		}
258794e27ecSJohnny Huang 	}
259794e27ecSJohnny Huang 	if (ret)
260794e27ecSJohnny Huang 		return ret;
261794e27ecSJohnny Huang 
262794e27ecSJohnny Huang 	return rid_num;
263794e27ecSJohnny Huang }
264794e27ecSJohnny Huang 
265a219f6deSJohnny Huang static u32 chip_version(void)
2669a4fe690SJohnny Huang {
267e417205bSJohnny Huang 	u32 revid0, revid1;
2689a4fe690SJohnny Huang 
269e417205bSJohnny Huang 	revid0 = readl(ASPEED_REVISION_ID0);
270e417205bSJohnny Huang 	revid1 = readl(ASPEED_REVISION_ID1);
2719a4fe690SJohnny Huang 
272e417205bSJohnny Huang 	if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
273badd21c2SJohnny Huang 		/* AST2600-A0 */
274e417205bSJohnny Huang 		return OTP_A0;
275e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
276badd21c2SJohnny Huang 		/* AST2600-A1 */
277e417205bSJohnny Huang 		return OTP_A1;
278e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
279badd21c2SJohnny Huang 		/* AST2600-A2 */
280e417205bSJohnny Huang 		return OTP_A2;
281e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
28264b66712SJohnny Huang 		/* AST2600-A3 */
283e417205bSJohnny Huang 		return OTP_A3;
284e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
285e417205bSJohnny Huang 		/* AST2620-A1 */
286e417205bSJohnny Huang 		return OTP_A1;
287e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
288e417205bSJohnny Huang 		/* AST2620-A2 */
289e417205bSJohnny Huang 		return OTP_A2;
290e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
29164b66712SJohnny Huang 		/* AST2620-A3 */
292e417205bSJohnny Huang 		return OTP_A3;
293e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
294e417205bSJohnny Huang 		/* AST2605-A2 */
295e417205bSJohnny Huang 		return OTP_A2;
296e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
297e417205bSJohnny Huang 		/* AST2605-A3 */
298e417205bSJohnny Huang 		return OTP_A3;
299e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
300e417205bSJohnny Huang 		/* AST2605-A3 */
301e417205bSJohnny Huang 		return OTP_A3;
3020dae9d52SJohnny Huang 	}
303f347c284SJohnny Huang 	return OTP_FAILURE;
3049a4fe690SJohnny Huang }
3059a4fe690SJohnny Huang 
3063d3688adSJohnny Huang static void wait_complete(void)
3073d3688adSJohnny Huang {
3083d3688adSJohnny Huang 	int reg;
3093d3688adSJohnny Huang 
3103d3688adSJohnny Huang 	do {
3113d3688adSJohnny Huang 		reg = readl(OTP_STATUS);
3123d3688adSJohnny Huang 	} while ((reg & 0x6) != 0x6);
3133d3688adSJohnny Huang }
3143d3688adSJohnny Huang 
315a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
316dacbba92SJohnny Huang {
317dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
318dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
319dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
320dacbba92SJohnny Huang 	wait_complete();
321dacbba92SJohnny Huang }
322dacbba92SJohnny Huang 
323dacbba92SJohnny Huang static void otp_soak(int soak)
324dacbba92SJohnny Huang {
325e417205bSJohnny Huang 	if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
326dacbba92SJohnny Huang 		switch (soak) {
327dacbba92SJohnny Huang 		case 0: //default
328377f8cd7SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
329377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
330dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
331dacbba92SJohnny Huang 			break;
332dacbba92SJohnny Huang 		case 1: //normal program
333377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
334377f8cd7SJohnny Huang 			otp_write(0x5000, 0x1008); // Write MRB
335377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0024); // Write MR
336feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
337dacbba92SJohnny Huang 			break;
338dacbba92SJohnny Huang 		case 2: //soak program
339377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
340377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0007); // Write MRB
341377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0100); // Write MR
342feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
343dacbba92SJohnny Huang 			break;
344dacbba92SJohnny Huang 		}
345dacbba92SJohnny Huang 	} else {
346dacbba92SJohnny Huang 		switch (soak) {
347dacbba92SJohnny Huang 		case 0: //default
348dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
349dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
350dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
351dacbba92SJohnny Huang 			break;
352dacbba92SJohnny Huang 		case 1: //normal program
353dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
354dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
355dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
356feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
357dacbba92SJohnny Huang 			break;
358dacbba92SJohnny Huang 		case 2: //soak program
359dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
360dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
361dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
362feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
363dacbba92SJohnny Huang 			break;
364dacbba92SJohnny Huang 		}
365dacbba92SJohnny Huang 	}
366dacbba92SJohnny Huang 
367dacbba92SJohnny Huang 	wait_complete();
368dacbba92SJohnny Huang }
369dacbba92SJohnny Huang 
370a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
37169d5fd8fSJohnny Huang {
3723d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
3733d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3743d3688adSJohnny Huang 	wait_complete();
3753d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
3763d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
37769d5fd8fSJohnny Huang }
37869d5fd8fSJohnny Huang 
379f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data)
38069d5fd8fSJohnny Huang {
38169d5fd8fSJohnny Huang 	int config_offset;
38269d5fd8fSJohnny Huang 
38369d5fd8fSJohnny Huang 	config_offset = 0x800;
38469d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
38569d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
38669d5fd8fSJohnny Huang 
3873d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
3883d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3893d3688adSJohnny Huang 	wait_complete();
3903d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
39169d5fd8fSJohnny Huang }
39269d5fd8fSJohnny Huang 
393a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
39469d5fd8fSJohnny Huang {
395a219f6deSJohnny Huang 	u32 ret;
396a219f6deSJohnny Huang 	u32 *buf;
39769d5fd8fSJohnny Huang 
39869d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
39969d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
40069d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
40169d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
40269d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
4033d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
4043d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
4053d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
4063d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
4073d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
4083d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
4093d3688adSJohnny Huang 	wait_complete();
4103d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
41169d5fd8fSJohnny Huang 	if (ret & 0x1)
412f347c284SJohnny Huang 		return OTP_SUCCESS;
41369d5fd8fSJohnny Huang 	else
414f347c284SJohnny Huang 		return OTP_FAILURE;
41569d5fd8fSJohnny Huang }
41669d5fd8fSJohnny Huang 
417a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
41869d5fd8fSJohnny Huang {
419a219f6deSJohnny Huang 	u32 ret[2];
42069d5fd8fSJohnny Huang 
42130a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4223d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
42330a8c590SJohnny Huang 	else
4243d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
42530a8c590SJohnny Huang 
4263d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4273d3688adSJohnny Huang 	wait_complete();
4283d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4293d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
43083655e91SJohnny Huang 
43130a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
43230a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
433f347c284SJohnny Huang 			return OTP_SUCCESS;
43469d5fd8fSJohnny Huang 		else
435f347c284SJohnny Huang 			return OTP_FAILURE;
43630a8c590SJohnny Huang 	} else {
43730a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
438f347c284SJohnny Huang 			return OTP_SUCCESS;
43930a8c590SJohnny Huang 		else
440f347c284SJohnny Huang 			return OTP_FAILURE;
44130a8c590SJohnny Huang 	}
44269d5fd8fSJohnny Huang }
44369d5fd8fSJohnny Huang 
444a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4454c1c9b35SJohnny Huang {
446a219f6deSJohnny Huang 	u32 ret[2];
4474c1c9b35SJohnny Huang 
4484c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4494c1c9b35SJohnny Huang 
4504c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4513d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
4524c1c9b35SJohnny Huang 	else
4533d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
4543d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4553d3688adSJohnny Huang 	wait_complete();
4563d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4573d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4584c1c9b35SJohnny Huang 	if (size == 1) {
4594c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4604c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
461696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4624c1c9b35SJohnny Huang 				compare[0] = 0;
463f347c284SJohnny Huang 				return OTP_SUCCESS;
464a219f6deSJohnny Huang 			}
4654c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
466f347c284SJohnny Huang 			return OTP_FAILURE;
4674c1c9b35SJohnny Huang 
4684c1c9b35SJohnny Huang 		} else {
4694c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
470696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4714c1c9b35SJohnny Huang 				compare[0] = ~0;
472f347c284SJohnny Huang 				return OTP_SUCCESS;
473a219f6deSJohnny Huang 			}
474d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
475f347c284SJohnny Huang 			return OTP_FAILURE;
4764c1c9b35SJohnny Huang 		}
4774c1c9b35SJohnny Huang 	} else if (size == 2) {
4784c1c9b35SJohnny Huang 		// otp_addr should be even
479696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
4804c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4814c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4824c1c9b35SJohnny Huang 			compare[0] = 0;
4834c1c9b35SJohnny Huang 			compare[1] = ~0;
484f347c284SJohnny Huang 			return OTP_SUCCESS;
485a219f6deSJohnny Huang 		}
4864c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4874c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4884c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
4894c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
490f347c284SJohnny Huang 		return OTP_FAILURE;
4914c1c9b35SJohnny Huang 	} else {
492f347c284SJohnny Huang 		return OTP_FAILURE;
4934c1c9b35SJohnny Huang 	}
4944c1c9b35SJohnny Huang }
4954c1c9b35SJohnny Huang 
496a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit)
49783655e91SJohnny Huang {
49890965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
49983655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
50083655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
50183655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
50283655e91SJohnny Huang 	wait_complete();
50383655e91SJohnny Huang }
50483655e91SJohnny Huang 
505a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
50683655e91SJohnny Huang {
50783655e91SJohnny Huang 	int prog_bit;
50883655e91SJohnny Huang 
50983655e91SJohnny Huang 	if (prog_address % 2 == 0) {
51083655e91SJohnny Huang 		if (value)
51183655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
51283655e91SJohnny Huang 		else
51383655e91SJohnny Huang 			return;
51483655e91SJohnny Huang 	} else {
515e417205bSJohnny Huang 		if (info_cb.version != OTP_A3)
51683655e91SJohnny Huang 			prog_address |= 1 << 15;
51783655e91SJohnny Huang 		if (!value)
51883655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
51983655e91SJohnny Huang 		else
52083655e91SJohnny Huang 			return;
52183655e91SJohnny Huang 	}
52283655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
52383655e91SJohnny Huang }
52483655e91SJohnny Huang 
525f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset)
52683655e91SJohnny Huang {
52783655e91SJohnny Huang 	int pass;
52883655e91SJohnny Huang 	int i;
52983655e91SJohnny Huang 
53083655e91SJohnny Huang 	otp_soak(1);
53183655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
53283655e91SJohnny Huang 	pass = 0;
53383655e91SJohnny Huang 
53483655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
53583655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
53683655e91SJohnny Huang 			otp_soak(2);
53783655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
53883655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
53983655e91SJohnny Huang 				otp_soak(1);
54083655e91SJohnny Huang 			} else {
54183655e91SJohnny Huang 				pass = 1;
54283655e91SJohnny Huang 				break;
54383655e91SJohnny Huang 			}
54483655e91SJohnny Huang 		} else {
54583655e91SJohnny Huang 			pass = 1;
54683655e91SJohnny Huang 			break;
54783655e91SJohnny Huang 		}
54883655e91SJohnny Huang 	}
549794e27ecSJohnny Huang 	if (pass)
550794e27ecSJohnny Huang 		return OTP_SUCCESS;
55183655e91SJohnny Huang 
552794e27ecSJohnny Huang 	return OTP_FAILURE;
55383655e91SJohnny Huang }
55483655e91SJohnny Huang 
555a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
556d90825e2SJohnny Huang {
557d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
558d90825e2SJohnny Huang 
559d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
560696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
561d90825e2SJohnny Huang 			continue;
562d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
563d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
564d90825e2SJohnny Huang 			if (bit_value)
565d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
566d90825e2SJohnny Huang 			else
567d90825e2SJohnny Huang 				continue;
568d90825e2SJohnny Huang 		} else {
569e417205bSJohnny Huang 			if (info_cb.version != OTP_A3)
570d90825e2SJohnny Huang 				prog_address |= 1 << 15;
571d90825e2SJohnny Huang 			if (bit_value)
572d90825e2SJohnny Huang 				continue;
573d90825e2SJohnny Huang 			else
574d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
575d90825e2SJohnny Huang 		}
576d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
577d90825e2SJohnny Huang 	}
578d90825e2SJohnny Huang }
579d90825e2SJohnny Huang 
580a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
58154552c69SJohnny Huang {
58254552c69SJohnny Huang 	int pass;
58354552c69SJohnny Huang 	int i;
584a219f6deSJohnny Huang 	u32 data0_masked;
585a219f6deSJohnny Huang 	u32 data1_masked;
586a219f6deSJohnny Huang 	u32 buf0_masked;
587a219f6deSJohnny Huang 	u32 buf1_masked;
588a219f6deSJohnny Huang 	u32 compare[2];
58954552c69SJohnny Huang 
59054552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
59154552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
59254552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
59354552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
594a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
595f347c284SJohnny Huang 		return OTP_SUCCESS;
59654552c69SJohnny Huang 
59754552c69SJohnny Huang 	otp_soak(1);
59854552c69SJohnny Huang 	if (data0_masked != buf0_masked)
59954552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
60054552c69SJohnny Huang 	if (data1_masked != buf1_masked)
60154552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
60254552c69SJohnny Huang 
60354552c69SJohnny Huang 	pass = 0;
60454552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
60554552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
60654552c69SJohnny Huang 			otp_soak(2);
607a219f6deSJohnny Huang 			if (compare[0] != 0)
60854552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
609a219f6deSJohnny Huang 			if (compare[1] != ~0)
6105537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
61154552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
61254552c69SJohnny Huang 				otp_soak(1);
61354552c69SJohnny Huang 			} else {
61454552c69SJohnny Huang 				pass = 1;
61554552c69SJohnny Huang 				break;
61654552c69SJohnny Huang 			}
61754552c69SJohnny Huang 		} else {
61854552c69SJohnny Huang 			pass = 1;
61954552c69SJohnny Huang 			break;
62054552c69SJohnny Huang 		}
62154552c69SJohnny Huang 	}
62254552c69SJohnny Huang 
62354552c69SJohnny Huang 	if (!pass) {
62454552c69SJohnny Huang 		otp_soak(0);
62554552c69SJohnny Huang 		return OTP_FAILURE;
62654552c69SJohnny Huang 	}
62754552c69SJohnny Huang 	return OTP_SUCCESS;
62854552c69SJohnny Huang }
62954552c69SJohnny Huang 
630541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
63176d13988SJohnny Huang {
632a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
6335010032bSJohnny Huang 	int strap_end;
63476d13988SJohnny Huang 	int i, j;
63576d13988SJohnny Huang 
636e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
63776d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
63876d13988SJohnny Huang 			otpstrap[j].value = 0;
63976d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
64076d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
64176d13988SJohnny Huang 			otpstrap[j].protected = 0;
64276d13988SJohnny Huang 		}
6435010032bSJohnny Huang 		strap_end = 30;
6445010032bSJohnny Huang 	} else {
6455010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
6465010032bSJohnny Huang 			otpstrap[j].value = 0;
6475010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
6485010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
6495010032bSJohnny Huang 			otpstrap[j].protected = 0;
6505010032bSJohnny Huang 		}
6515010032bSJohnny Huang 		strap_end = 28;
6525010032bSJohnny Huang 	}
65376d13988SJohnny Huang 
654dacbba92SJohnny Huang 	otp_soak(0);
6555010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
65676d13988SJohnny Huang 		int option = (i - 16) / 2;
657a219f6deSJohnny Huang 
658f347c284SJohnny Huang 		otp_read_conf(i, &OTPSTRAP_RAW[0]);
659f347c284SJohnny Huang 		otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
66076d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
66176d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
662a219f6deSJohnny Huang 
663a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
66476d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
66576d13988SJohnny Huang 			if (bit_value == 1)
66676d13988SJohnny Huang 				otpstrap[j].remain_times--;
66776d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
66876d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
66976d13988SJohnny Huang 		}
67076d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
67176d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
672a219f6deSJohnny Huang 
673a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
67476d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
67576d13988SJohnny Huang 			if (bit_value == 1)
67676d13988SJohnny Huang 				otpstrap[j].remain_times--;
67776d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
67876d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
67976d13988SJohnny Huang 		}
68076d13988SJohnny Huang 	}
6815010032bSJohnny Huang 
682f347c284SJohnny Huang 	otp_read_conf(30, &OTPSTRAP_RAW[0]);
683f347c284SJohnny Huang 	otp_read_conf(31, &OTPSTRAP_RAW[1]);
68476d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
68576d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
68676d13988SJohnny Huang 			otpstrap[j].protected = 1;
68776d13988SJohnny Huang 	}
68876d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
68976d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
69076d13988SJohnny Huang 			otpstrap[j].protected = 1;
69176d13988SJohnny Huang 	}
69276d13988SJohnny Huang }
69376d13988SJohnny Huang 
6947e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit)
695f347c284SJohnny Huang {
696f347c284SJohnny Huang 	int prog_flag = 0;
697f347c284SJohnny Huang 
698f347c284SJohnny Huang 	// ignore this bit
699f347c284SJohnny Huang 	if (ibit == 1)
700f347c284SJohnny Huang 		return OTP_SUCCESS;
701f347c284SJohnny Huang 	printf("OTPSTRAP[%X]:\n", offset);
702f347c284SJohnny Huang 
703f347c284SJohnny Huang 	if (bit == otpstrap->value) {
7047e523e3bSJohnny Huang 		if (!pbit) {
705f347c284SJohnny Huang 			printf("    The value is same as before, skip it.\n");
706f347c284SJohnny Huang 			return OTP_PROG_SKIP;
707f347c284SJohnny Huang 		}
708f347c284SJohnny Huang 		printf("    The value is same as before.\n");
709f347c284SJohnny Huang 	} else {
710f347c284SJohnny Huang 		prog_flag = 1;
711f347c284SJohnny Huang 	}
712f347c284SJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
713f347c284SJohnny Huang 		printf("    This bit is protected and is not writable\n");
714f347c284SJohnny Huang 		return OTP_FAILURE;
715f347c284SJohnny Huang 	}
716f347c284SJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
717f347c284SJohnny Huang 		printf("    This bit is no remaining times to write.\n");
718f347c284SJohnny Huang 		return OTP_FAILURE;
719f347c284SJohnny Huang 	}
720f347c284SJohnny Huang 	if (pbit == 1)
721f347c284SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
722f347c284SJohnny Huang 	if (prog_flag)
723f347c284SJohnny Huang 		printf("    Write 1 to OTPSTRAP[%X] OPTION[%X], that value becomes from %d to %d.\n", offset, otpstrap->writeable_option + 1, otpstrap->value, otpstrap->value ^ 1);
724f347c284SJohnny Huang 
725f347c284SJohnny Huang 	return OTP_SUCCESS;
726f347c284SJohnny Huang }
727f347c284SJohnny Huang 
728f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
729f347c284SJohnny Huang {
730f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
731f347c284SJohnny Huang 	u32 prog_address;
732f347c284SJohnny Huang 	int offset;
733f347c284SJohnny Huang 	int ret;
734f347c284SJohnny Huang 
735f347c284SJohnny Huang 	otp_strap_status(otpstrap);
736f347c284SJohnny Huang 
7377e523e3bSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
738f347c284SJohnny Huang 
739f347c284SJohnny Huang 	if (ret != OTP_SUCCESS)
740f347c284SJohnny Huang 		return ret;
741f347c284SJohnny Huang 
742f347c284SJohnny Huang 	prog_address = 0x800;
743f347c284SJohnny Huang 	if (bit_offset < 32) {
744f347c284SJohnny Huang 		offset = bit_offset;
745f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
746f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
747f347c284SJohnny Huang 
748f347c284SJohnny Huang 	} else {
749f347c284SJohnny Huang 		offset = (bit_offset - 32);
750f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
751f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
752f347c284SJohnny Huang 	}
753f347c284SJohnny Huang 
754f347c284SJohnny Huang 	return otp_prog_dc_b(1, prog_address, offset);
755f347c284SJohnny Huang }
756f347c284SJohnny Huang 
757f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
758f347c284SJohnny Huang {
759f347c284SJohnny Huang 	int i;
760f347c284SJohnny Huang 	u32 ret[1];
761f347c284SJohnny Huang 
762f347c284SJohnny Huang 	if (offset + dw_count > 32)
763f347c284SJohnny Huang 		return OTP_USAGE;
764f347c284SJohnny Huang 	otp_soak(0);
765f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
766f347c284SJohnny Huang 		otp_read_conf(i, ret);
767f347c284SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
768f347c284SJohnny Huang 	}
769f347c284SJohnny Huang 	printf("\n");
770f347c284SJohnny Huang 	return OTP_SUCCESS;
771f347c284SJohnny Huang }
772f347c284SJohnny Huang 
773f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
774f347c284SJohnny Huang {
775f347c284SJohnny Huang 	int i;
776f347c284SJohnny Huang 	u32 ret[2];
777f347c284SJohnny Huang 
778f347c284SJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
779f347c284SJohnny Huang 		return OTP_USAGE;
780f347c284SJohnny Huang 	otp_soak(0);
781f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
782f347c284SJohnny Huang 		otp_read_data(i, ret);
783f347c284SJohnny Huang 		if (i % 4 == 0)
784f347c284SJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
785f347c284SJohnny Huang 		else
786f347c284SJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
787f347c284SJohnny Huang 	}
788f347c284SJohnny Huang 	printf("\n");
789f347c284SJohnny Huang 	return OTP_SUCCESS;
790f347c284SJohnny Huang }
791f347c284SJohnny Huang 
792f347c284SJohnny Huang static int otp_print_strap(int start, int count)
793f347c284SJohnny Huang {
794f347c284SJohnny Huang 	int i, j;
795f347c284SJohnny Huang 	int remains;
796f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
797f347c284SJohnny Huang 
798f347c284SJohnny Huang 	if (start < 0 || start > 64)
799f347c284SJohnny Huang 		return OTP_USAGE;
800f347c284SJohnny Huang 
801f347c284SJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
802f347c284SJohnny Huang 		return OTP_USAGE;
803f347c284SJohnny Huang 
804f347c284SJohnny Huang 	otp_strap_status(otpstrap);
805f347c284SJohnny Huang 
8067e523e3bSJohnny Huang 	if (info_cb.version == OTP_A0)
807f347c284SJohnny Huang 		remains = 7;
8087e523e3bSJohnny Huang 	else
809f347c284SJohnny Huang 		remains = 6;
8107e523e3bSJohnny Huang 	printf("BIT(hex)  Value  Option           Status\n");
811f347c284SJohnny Huang 	printf("______________________________________________________________________________\n");
812f347c284SJohnny Huang 
813f347c284SJohnny Huang 	for (i = start; i < start + count; i++) {
814f347c284SJohnny Huang 		printf("0x%-8X", i);
815f347c284SJohnny Huang 		printf("%-7d", otpstrap[i].value);
816f347c284SJohnny Huang 		for (j = 0; j < remains; j++)
817f347c284SJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
818f347c284SJohnny Huang 		printf("   ");
819f347c284SJohnny Huang 		if (otpstrap[i].protected == 1) {
820f347c284SJohnny Huang 			printf("protected and not writable");
821f347c284SJohnny Huang 		} else {
822f347c284SJohnny Huang 			printf("not protected ");
823f347c284SJohnny Huang 			if (otpstrap[i].remain_times == 0)
824f347c284SJohnny Huang 				printf("and no remaining times to write.");
825f347c284SJohnny Huang 			else
826f347c284SJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
827f347c284SJohnny Huang 		}
828f347c284SJohnny Huang 		printf("\n");
829f347c284SJohnny Huang 	}
830f347c284SJohnny Huang 
831f347c284SJohnny Huang 	return OTP_SUCCESS;
832f347c284SJohnny Huang }
833f347c284SJohnny Huang 
834794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
835794e27ecSJohnny Huang {
836794e27ecSJohnny Huang 	int bit_offset;
837794e27ecSJohnny Huang 	int i, j;
838794e27ecSJohnny Huang 
839794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
840794e27ecSJohnny Huang 	printf("___________________________________________________\n");
841794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
842794e27ecSJohnny Huang 		if (i < 32) {
843794e27ecSJohnny Huang 			j = 0;
844794e27ecSJohnny Huang 			bit_offset = i;
845794e27ecSJohnny Huang 		} else {
846794e27ecSJohnny Huang 			j = 1;
847794e27ecSJohnny Huang 			bit_offset = i - 32;
848794e27ecSJohnny Huang 		}
849794e27ecSJohnny Huang 		if (i % 16 == 0)
850794e27ecSJohnny Huang 			printf("%2x | ", i);
851794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
852794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
853794e27ecSJohnny Huang 			printf("\n");
854794e27ecSJohnny Huang 	}
855794e27ecSJohnny Huang }
856794e27ecSJohnny Huang 
8570dc9a440SJohnny Huang static void otp_print_scu_info(void)
8580dc9a440SJohnny Huang {
8590dc9a440SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
8600dc9a440SJohnny Huang 	u32 OTPCFG[2];
8610dc9a440SJohnny Huang 	u32 scu_offset;
8620dc9a440SJohnny Huang 	u32 bit_offset;
8630dc9a440SJohnny Huang 	u32 reg_p;
8640dc9a440SJohnny Huang 	u32 length;
8650dc9a440SJohnny Huang 	int i, j;
8660dc9a440SJohnny Huang 
8670dc9a440SJohnny Huang 	otp_soak(0);
8680dc9a440SJohnny Huang 	otp_read_conf(28, &OTPCFG[0]);
8690dc9a440SJohnny Huang 	otp_read_conf(29, &OTPCFG[1]);
8700dc9a440SJohnny Huang 	printf("SCU     BIT   reg_protect     Description\n");
8710dc9a440SJohnny Huang 	printf("____________________________________________________________________\n");
8720dc9a440SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
8730dc9a440SJohnny Huang 		length = scu_info[i].length;
8740dc9a440SJohnny Huang 		for (j = 0; j < length; j++) {
8750dc9a440SJohnny Huang 			if (scu_info[i].bit_offset + j < 32) {
8760dc9a440SJohnny Huang 				scu_offset = 0x500;
8770dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j;
8780dc9a440SJohnny Huang 				reg_p = (OTPCFG[0] >> bit_offset) & 0x1;
8790dc9a440SJohnny Huang 			} else {
8800dc9a440SJohnny Huang 				scu_offset = 0x510;
8810dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j - 32;
8820dc9a440SJohnny Huang 				reg_p = (OTPCFG[1] >> bit_offset) & 0x1;
8830dc9a440SJohnny Huang 			}
8840dc9a440SJohnny Huang 			printf("0x%-6X", scu_offset);
8850dc9a440SJohnny Huang 			printf("0x%-4X", bit_offset);
8860dc9a440SJohnny Huang 			printf("0x%-13X", reg_p);
8870dc9a440SJohnny Huang 			if (length == 1) {
8880dc9a440SJohnny Huang 				printf(" %s\n", scu_info[i].information);
8890dc9a440SJohnny Huang 				continue;
8900dc9a440SJohnny Huang 			}
8910dc9a440SJohnny Huang 
8920dc9a440SJohnny Huang 			if (j == 0)
8930dc9a440SJohnny Huang 				printf("/%s\n", scu_info[i].information);
8940dc9a440SJohnny Huang 			else if (j == length - 1)
8950dc9a440SJohnny Huang 				printf("\\ \"\n");
8960dc9a440SJohnny Huang 			else
8970dc9a440SJohnny Huang 				printf("| \"\n");
8980dc9a440SJohnny Huang 		}
8990dc9a440SJohnny Huang 	}
9000dc9a440SJohnny Huang }
9010dc9a440SJohnny Huang 
902696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
90369d5fd8fSJohnny Huang {
90479e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
905a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
906a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
907a219f6deSJohnny Huang 	u32 mask;
908a219f6deSJohnny Huang 	u32 dw_offset;
909a219f6deSJohnny Huang 	u32 bit_offset;
910a219f6deSJohnny Huang 	u32 otp_value;
911a219f6deSJohnny Huang 	u32 otp_ignore;
912b458cd62SJohnny Huang 	int fail = 0;
9137adec5f6SJohnny Huang 	int mask_err;
914794e27ecSJohnny Huang 	int rid_num = 0;
91573f11549SJohnny Huang 	char valid_bit[20];
916794e27ecSJohnny Huang 	int fz;
91766f2f8e5SJohnny Huang 	int i;
91873f11549SJohnny Huang 	int j;
91966f2f8e5SJohnny Huang 
920737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
92166f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
9223cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
9237adec5f6SJohnny Huang 		mask_err = 0;
9243cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
9253cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
9263cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
927b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
928696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
929b458cd62SJohnny Huang 
9307adec5f6SJohnny Huang 		if (conf_info[i].value == OTP_REG_VALID_BIT) {
9317adec5f6SJohnny Huang 			if (((otp_value + otp_ignore) & mask) != mask) {
932b458cd62SJohnny Huang 				fail = 1;
9337adec5f6SJohnny Huang 				mask_err = 1;
9347adec5f6SJohnny Huang 			}
9357adec5f6SJohnny Huang 		} else {
9367adec5f6SJohnny Huang 			if (otp_ignore == mask) {
9377adec5f6SJohnny Huang 				continue;
9387adec5f6SJohnny Huang 			} else if (otp_ignore != 0) {
9397adec5f6SJohnny Huang 				fail = 1;
9407adec5f6SJohnny Huang 				mask_err = 1;
9417adec5f6SJohnny Huang 			}
9427adec5f6SJohnny Huang 		}
943b458cd62SJohnny Huang 
944a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
9453cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
9463cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
9473cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
948b458cd62SJohnny Huang 			continue;
949b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
950b458cd62SJohnny Huang 
9513cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
9523cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
95366f2f8e5SJohnny Huang 		} else {
954b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
9553cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
9563cb28812SJohnny Huang 			       conf_info[i].bit_offset);
95766f2f8e5SJohnny Huang 		}
958b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
959b458cd62SJohnny Huang 
9607adec5f6SJohnny Huang 		if (mask_err) {
9617adec5f6SJohnny Huang 			printf("Ignore, mask error\n");
962a219f6deSJohnny Huang 			continue;
963a219f6deSJohnny Huang 		}
9643cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
965b458cd62SJohnny Huang 			printf("Reserved\n");
9663cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
9673cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
968b458cd62SJohnny Huang 			printf("\n");
9693cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
970b458cd62SJohnny Huang 			if (otp_value != 0) {
97173f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
972a219f6deSJohnny Huang 					if (otp_value == (1 << j))
97373f11549SJohnny Huang 						valid_bit[j * 2] = '1';
974a219f6deSJohnny Huang 					else
97573f11549SJohnny Huang 						valid_bit[j * 2] = '0';
97673f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
97773f11549SJohnny Huang 				}
97873f11549SJohnny Huang 				valid_bit[15] = 0;
97973f11549SJohnny Huang 			} else {
98073f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
981b458cd62SJohnny Huang 			}
9823cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
983b458cd62SJohnny Huang 			printf("\n");
984b458cd62SJohnny Huang 		} else {
9853cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
986b458cd62SJohnny Huang 		}
987b458cd62SJohnny Huang 	}
988b458cd62SJohnny Huang 
989794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
990794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
991794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
992794e27ecSJohnny Huang 			fail = 1;
993794e27ecSJohnny Huang 		} else {
994794e27ecSJohnny Huang 			fz = 0;
995794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
996794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
997794e27ecSJohnny Huang 					if (!fz)
998794e27ecSJohnny Huang 						fz = 1;
999794e27ecSJohnny Huang 				} else {
1000794e27ecSJohnny Huang 					rid_num++;
1001794e27ecSJohnny Huang 					if (fz) {
1002794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
1003794e27ecSJohnny Huang 						fail = 1;
1004794e27ecSJohnny Huang 						break;
1005794e27ecSJohnny Huang 					}
1006794e27ecSJohnny Huang 				}
1007794e27ecSJohnny Huang 			}
1008794e27ecSJohnny Huang 		}
1009794e27ecSJohnny Huang 		if (fail)
1010794e27ecSJohnny Huang 			printf("OTP revision ID\n");
1011794e27ecSJohnny Huang 		else
1012794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
1013794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
1014794e27ecSJohnny Huang 	}
1015794e27ecSJohnny Huang 
1016b458cd62SJohnny Huang 	if (fail)
1017b458cd62SJohnny Huang 		return OTP_FAILURE;
1018b458cd62SJohnny Huang 
101966f2f8e5SJohnny Huang 	return OTP_SUCCESS;
102066f2f8e5SJohnny Huang }
102166f2f8e5SJohnny Huang 
10222d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
102366f2f8e5SJohnny Huang {
102479e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
1025a219f6deSJohnny Huang 	u32 OTPCFG[16];
1026a219f6deSJohnny Huang 	u32 mask;
1027a219f6deSJohnny Huang 	u32 dw_offset;
1028a219f6deSJohnny Huang 	u32 bit_offset;
1029a219f6deSJohnny Huang 	u32 otp_value;
103073f11549SJohnny Huang 	char valid_bit[20];
103166f2f8e5SJohnny Huang 	int i;
103273f11549SJohnny Huang 	int j;
103366f2f8e5SJohnny Huang 
1034dacbba92SJohnny Huang 	otp_soak(0);
1035bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
1036f347c284SJohnny Huang 		otp_read_conf(i, &OTPCFG[i]);
103766f2f8e5SJohnny Huang 
1038b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
1039b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
10403cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
10413cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
10422d4b0742SJohnny Huang 			continue;
10433cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
10443cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
10453cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
1046b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1047b458cd62SJohnny Huang 
1048a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
10493cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
10503cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
10513cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1052b458cd62SJohnny Huang 			continue;
1053b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1054b458cd62SJohnny Huang 
10553cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
10563cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
1057b458cd62SJohnny Huang 		} else {
1058b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
10593cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
10603cb28812SJohnny Huang 			       conf_info[i].bit_offset);
1061b458cd62SJohnny Huang 		}
1062b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1063b458cd62SJohnny Huang 
10643cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1065b458cd62SJohnny Huang 			printf("Reserved\n");
10663cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
10673cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1068b458cd62SJohnny Huang 			printf("\n");
10693cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1070b458cd62SJohnny Huang 			if (otp_value != 0) {
107173f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1072*030cb4a7SJohnny Huang 					if (otp_value & (1 << j))
107373f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1074a219f6deSJohnny Huang 					else
107573f11549SJohnny Huang 						valid_bit[j * 2] = '0';
107673f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
107773f11549SJohnny Huang 				}
107873f11549SJohnny Huang 				valid_bit[15] = 0;
107973f11549SJohnny Huang 			} else {
108073f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1081b458cd62SJohnny Huang 			}
10823cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1083b458cd62SJohnny Huang 			printf("\n");
1084b458cd62SJohnny Huang 		} else {
10853cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1086b458cd62SJohnny Huang 		}
1087b458cd62SJohnny Huang 	}
1088b458cd62SJohnny Huang 	return OTP_SUCCESS;
108966f2f8e5SJohnny Huang }
109066f2f8e5SJohnny Huang 
10915010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
109276d13988SJohnny Huang {
109379e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
1094a219f6deSJohnny Huang 	u32 *OTPSTRAP;
1095a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
1096a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
109776d13988SJohnny Huang 	int i;
1098a8bd6d8cSJohnny Huang 	int fail = 0;
1099a219f6deSJohnny Huang 	u32 bit_offset;
1100a219f6deSJohnny Huang 	u32 dw_offset;
1101a219f6deSJohnny Huang 	u32 mask;
1102a219f6deSJohnny Huang 	u32 otp_value;
1103a219f6deSJohnny Huang 	u32 otp_protect;
1104a219f6deSJohnny Huang 	u32 otp_ignore;
110576d13988SJohnny Huang 
1106a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
1107a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1108a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
11097e523e3bSJohnny Huang 
1110a8bd6d8cSJohnny Huang 	printf("BIT(hex)   Value       Protect     Description\n");
1111de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
1112b458cd62SJohnny Huang 
11133cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
11147adec5f6SJohnny Huang 		fail = 0;
1115696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
1116a8bd6d8cSJohnny Huang 			dw_offset = 1;
11173cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
1118a8bd6d8cSJohnny Huang 		} else {
1119a8bd6d8cSJohnny Huang 			dw_offset = 0;
11203cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
1121a8bd6d8cSJohnny Huang 		}
112276d13988SJohnny Huang 
11233cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
1124a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1125a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1126696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1127a8bd6d8cSJohnny Huang 
1128a219f6deSJohnny Huang 		if (otp_ignore == mask)
1129a8bd6d8cSJohnny Huang 			continue;
1130a219f6deSJohnny Huang 		else if (otp_ignore != 0)
1131a8bd6d8cSJohnny Huang 			fail = 1;
1132a8bd6d8cSJohnny Huang 
1133a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
11343cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1135a8bd6d8cSJohnny Huang 			continue;
1136a8bd6d8cSJohnny Huang 
11373cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
11383cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
1139a8bd6d8cSJohnny Huang 		} else {
1140b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
11413cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
11423cb28812SJohnny Huang 			       strap_info[i].bit_offset);
1143a8bd6d8cSJohnny Huang 		}
1144a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
1145a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
1146a8bd6d8cSJohnny Huang 
1147a8bd6d8cSJohnny Huang 		if (fail) {
1148696656c6SJohnny Huang 			printf("Ignore mask error\n");
1149a8bd6d8cSJohnny Huang 		} else {
11503cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
11513cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1152a8bd6d8cSJohnny Huang 			else
1153a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1154a8bd6d8cSJohnny Huang 		}
1155a8bd6d8cSJohnny Huang 	}
1156a8bd6d8cSJohnny Huang 
1157a8bd6d8cSJohnny Huang 	if (fail)
115876d13988SJohnny Huang 		return OTP_FAILURE;
115976d13988SJohnny Huang 
116076d13988SJohnny Huang 	return OTP_SUCCESS;
116176d13988SJohnny Huang }
116276d13988SJohnny Huang 
1163b458cd62SJohnny Huang static int otp_print_strap_info(int view)
116476d13988SJohnny Huang {
116579e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
116676d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
116707baa4e8SJohnny Huang 	int i, j;
1168b458cd62SJohnny Huang 	int fail = 0;
1169a219f6deSJohnny Huang 	u32 bit_offset;
1170a219f6deSJohnny Huang 	u32 length;
1171a219f6deSJohnny Huang 	u32 otp_value;
1172a219f6deSJohnny Huang 	u32 otp_protect;
117376d13988SJohnny Huang 
1174541eb887SJohnny Huang 	otp_strap_status(strap_status);
117576d13988SJohnny Huang 
1176b458cd62SJohnny Huang 	if (view) {
117707baa4e8SJohnny Huang 		printf("BIT(hex) Value  Remains  Protect   Description\n");
117807baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1179b458cd62SJohnny Huang 	} else {
1180b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1181b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
118276d13988SJohnny Huang 	}
11833cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1184b458cd62SJohnny Huang 		otp_value = 0;
11853cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
11863cb28812SJohnny Huang 		length = strap_info[i].length;
1187b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1188c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1189c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1190b458cd62SJohnny Huang 		}
1191a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
11923cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1193b458cd62SJohnny Huang 			continue;
1194b458cd62SJohnny Huang 		if (view) {
1195b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
11963cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1197b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
119807baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1199e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
12003cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1201b458cd62SJohnny Huang 					printf(" Reserved\n");
1202b458cd62SJohnny Huang 					continue;
1203b458cd62SJohnny Huang 				}
1204b458cd62SJohnny Huang 				if (length == 1) {
12053cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1206b458cd62SJohnny Huang 					continue;
120776d13988SJohnny Huang 				}
120876d13988SJohnny Huang 
1209b458cd62SJohnny Huang 				if (j == 0)
12103cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1211b458cd62SJohnny Huang 				else if (j == length - 1)
1212b458cd62SJohnny Huang 					printf("\\ \"\n");
1213b458cd62SJohnny Huang 				else
1214b458cd62SJohnny Huang 					printf("| \"\n");
121576d13988SJohnny Huang 			}
1216b458cd62SJohnny Huang 		} else {
1217c947ef08SJohnny Huang 			if (length == 1) {
12183cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1219b458cd62SJohnny Huang 			} else {
1220b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1221b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1222b458cd62SJohnny Huang 			}
1223b458cd62SJohnny Huang 
1224b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1225b458cd62SJohnny Huang 
12263cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
12273cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1228b458cd62SJohnny Huang 			else
1229b458cd62SJohnny Huang 				printf("Reserved\n");
1230b458cd62SJohnny Huang 		}
1231b458cd62SJohnny Huang 	}
1232b458cd62SJohnny Huang 
1233b458cd62SJohnny Huang 	if (fail)
1234b458cd62SJohnny Huang 		return OTP_FAILURE;
1235b458cd62SJohnny Huang 
1236b458cd62SJohnny Huang 	return OTP_SUCCESS;
1237b458cd62SJohnny Huang }
1238b458cd62SJohnny Huang 
1239f347c284SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
124069d5fd8fSJohnny Huang {
124169d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
124279e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
12439a4fe690SJohnny Huang 	struct otpkey_type key_info;
1244a219f6deSJohnny Huang 	u32 *buf;
1245a219f6deSJohnny Huang 	u8 *byte_buf;
12469d998018SJohnny Huang 	char empty = 1;
124769d5fd8fSJohnny Huang 	int i = 0, len = 0;
12489a4fe690SJohnny Huang 	int j;
124954552c69SJohnny Huang 
1250696656c6SJohnny Huang 	byte_buf = image_layout->data;
1251a219f6deSJohnny Huang 	buf = (u32 *)byte_buf;
12529d998018SJohnny Huang 
12539d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
1254a219f6deSJohnny Huang 		if (buf[i] != 0)
12559d998018SJohnny Huang 			empty = 0;
12569d998018SJohnny Huang 	}
12579d998018SJohnny Huang 	if (empty)
1258f347c284SJohnny Huang 		return OTP_SUCCESS;
12599d998018SJohnny Huang 
12609d998018SJohnny Huang 	i = 0;
126169d5fd8fSJohnny Huang 	while (1) {
126269d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
126369d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
126469d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
126569d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
126669d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
126769d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
12689a4fe690SJohnny Huang 
12699a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
12709a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
12719a4fe690SJohnny Huang 				key_info = key_info_array[j];
12729a4fe690SJohnny Huang 				break;
12739a4fe690SJohnny Huang 			}
12749a4fe690SJohnny Huang 		}
12759a4fe690SJohnny Huang 
12767f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
127769d5fd8fSJohnny Huang 		printf("Key Type: ");
12789a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
12799a4fe690SJohnny Huang 
12809a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
128169d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
128269d5fd8fSJohnny Huang 			switch (key_length) {
128369d5fd8fSJohnny Huang 			case 0:
128469d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
128569d5fd8fSJohnny Huang 				break;
128669d5fd8fSJohnny Huang 			case 1:
128769d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
128869d5fd8fSJohnny Huang 				break;
128969d5fd8fSJohnny Huang 			case 2:
129069d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
129169d5fd8fSJohnny Huang 				break;
129269d5fd8fSJohnny Huang 			case 3:
129369d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
129469d5fd8fSJohnny Huang 				break;
129569d5fd8fSJohnny Huang 			}
1296181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1297181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
129869d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
129969d5fd8fSJohnny Huang 			switch (key_length) {
130069d5fd8fSJohnny Huang 			case 0:
130169d5fd8fSJohnny Huang 				printf("RSA1024\n");
130269d5fd8fSJohnny Huang 				len = 0x100;
130369d5fd8fSJohnny Huang 				break;
130469d5fd8fSJohnny Huang 			case 1:
130569d5fd8fSJohnny Huang 				printf("RSA2048\n");
130669d5fd8fSJohnny Huang 				len = 0x200;
130769d5fd8fSJohnny Huang 				break;
130869d5fd8fSJohnny Huang 			case 2:
130969d5fd8fSJohnny Huang 				printf("RSA3072\n");
131069d5fd8fSJohnny Huang 				len = 0x300;
131169d5fd8fSJohnny Huang 				break;
131269d5fd8fSJohnny Huang 			case 3:
131369d5fd8fSJohnny Huang 				printf("RSA4096\n");
131469d5fd8fSJohnny Huang 				len = 0x400;
131569d5fd8fSJohnny Huang 				break;
131669d5fd8fSJohnny Huang 			}
131769d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
131869d5fd8fSJohnny Huang 		}
13199a4fe690SJohnny Huang 		if (key_info.need_id)
132069d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
132169d5fd8fSJohnny Huang 		printf("Key Value:\n");
13229a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
132369d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
13249a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
13259a4fe690SJohnny Huang 			printf("AES Key:\n");
13269a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1327e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
13289a4fe690SJohnny Huang 				printf("AES IV:\n");
13299a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
13309a4fe690SJohnny Huang 			}
13319a4fe690SJohnny Huang 
13329a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1333e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
133469d5fd8fSJohnny Huang 				printf("AES Key:\n");
133569d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
133669d5fd8fSJohnny Huang 				printf("AES IV:\n");
133769d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
13385fdde29fSJohnny Huang 			} else {
13399a4fe690SJohnny Huang 				printf("AES Key 1:\n");
13409a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
13419a4fe690SJohnny Huang 				printf("AES Key 2:\n");
13429a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
13439a4fe690SJohnny Huang 			}
1344181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
134569d5fd8fSJohnny Huang 			printf("RSA mod:\n");
134669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
134769d5fd8fSJohnny Huang 			printf("RSA exp:\n");
134869d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1349181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1350181f72d8SJohnny Huang 			printf("RSA mod:\n");
1351181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1352181f72d8SJohnny Huang 			printf("RSA exp:\n");
1353a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
135469d5fd8fSJohnny Huang 		}
135569d5fd8fSJohnny Huang 		if (last)
135669d5fd8fSJohnny Huang 			break;
135769d5fd8fSJohnny Huang 		i++;
135869d5fd8fSJohnny Huang 	}
1359f347c284SJohnny Huang 	return OTP_SUCCESS;
1360f347c284SJohnny Huang }
1361f347c284SJohnny Huang 
1362f347c284SJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
1363f347c284SJohnny Huang {
1364f347c284SJohnny Huang 	int i;
1365f347c284SJohnny Huang 	u32 *strap;
1366f347c284SJohnny Huang 	u32 *strap_ignore;
1367f347c284SJohnny Huang 	u32 *strap_pro;
13687e523e3bSJohnny Huang 	int bit, pbit, ibit;
1369f347c284SJohnny Huang 	int fail = 0;
1370f347c284SJohnny Huang 	int ret;
1371f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
1372f347c284SJohnny Huang 
1373f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1374f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1375f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1376f347c284SJohnny Huang 
1377f347c284SJohnny Huang 	otp_strap_status(otpstrap);
1378f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1379f347c284SJohnny Huang 		if (i < 32) {
1380f347c284SJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1381f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
1382f347c284SJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
1383f347c284SJohnny Huang 		} else {
1384f347c284SJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1385f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1386f347c284SJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1387f347c284SJohnny Huang 		}
1388f347c284SJohnny Huang 
13897e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit);
1390f347c284SJohnny Huang 
1391f347c284SJohnny Huang 		if (ret == OTP_FAILURE)
1392f347c284SJohnny Huang 			fail = 1;
1393f347c284SJohnny Huang 	}
1394f347c284SJohnny Huang 	if (fail == 1)
1395f347c284SJohnny Huang 		return OTP_FAILURE;
1396f347c284SJohnny Huang 	else
1397f347c284SJohnny Huang 		return OTP_SUCCESS;
1398f347c284SJohnny Huang }
1399f347c284SJohnny Huang 
1400f347c284SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout)
1401f347c284SJohnny Huang {
1402f347c284SJohnny Huang 	int i;
1403f347c284SJohnny Huang 	int ret;
1404f347c284SJohnny Huang 	int data_dw;
1405f347c284SJohnny Huang 	u32 data[2048];
1406f347c284SJohnny Huang 	u32 *buf;
1407f347c284SJohnny Huang 	u32 *buf_ignore;
1408f347c284SJohnny Huang 	u32 data_masked;
1409f347c284SJohnny Huang 	u32 buf_masked;
1410f347c284SJohnny Huang 
1411f347c284SJohnny Huang 	buf = (u32 *)image_layout->data;
1412f347c284SJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
1413f347c284SJohnny Huang 
1414f347c284SJohnny Huang 	data_dw = image_layout->data_length / 4;
1415f347c284SJohnny Huang 
1416f347c284SJohnny Huang 	printf("Read OTP Data:\n");
1417f347c284SJohnny Huang 
1418f347c284SJohnny Huang 	for (i = 0; i < data_dw - 2 ; i += 2)
1419f347c284SJohnny Huang 		otp_read_data(i, &data[i]);
1420f347c284SJohnny Huang 
1421f347c284SJohnny Huang 	printf("Check writable...\n");
1422f347c284SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
1423f347c284SJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1424f347c284SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1425f347c284SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
1426f347c284SJohnny Huang 		if (data_masked == buf_masked)
1427f347c284SJohnny Huang 			continue;
1428f347c284SJohnny Huang 		if (i % 2 == 0) {
1429f347c284SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
1430f347c284SJohnny Huang 				continue;
1431f347c284SJohnny Huang 			} else {
1432f347c284SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1433f347c284SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1434f347c284SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1435f347c284SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
1436f347c284SJohnny Huang 				return OTP_FAILURE;
1437f347c284SJohnny Huang 			}
1438f347c284SJohnny Huang 		} else {
1439f347c284SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1440f347c284SJohnny Huang 				continue;
1441f347c284SJohnny Huang 			} else {
1442f347c284SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1443f347c284SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1444f347c284SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1445f347c284SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
1446f347c284SJohnny Huang 				return OTP_FAILURE;
1447f347c284SJohnny Huang 			}
1448f347c284SJohnny Huang 		}
1449f347c284SJohnny Huang 	}
1450f347c284SJohnny Huang 
1451f347c284SJohnny Huang 	printf("Start Programing...\n");
1452f347c284SJohnny Huang 
1453f347c284SJohnny Huang 	// programing ecc region first
1454f347c284SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1455f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1456f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1457f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1458f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1459f347c284SJohnny Huang 			return ret;
1460f347c284SJohnny Huang 		}
1461f347c284SJohnny Huang 	}
1462f347c284SJohnny Huang 
1463f347c284SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1464f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1465f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1466f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1467f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1468f347c284SJohnny Huang 			return ret;
1469f347c284SJohnny Huang 		}
1470f347c284SJohnny Huang 	}
1471f347c284SJohnny Huang 	otp_soak(0);
1472f347c284SJohnny Huang 	return OTP_SUCCESS;
1473f347c284SJohnny Huang }
1474f347c284SJohnny Huang 
1475f347c284SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout)
1476f347c284SJohnny Huang {
1477f347c284SJohnny Huang 	u32 *strap;
1478f347c284SJohnny Huang 	u32 *strap_ignore;
1479f347c284SJohnny Huang 	u32 *strap_pro;
1480f347c284SJohnny Huang 	u32 prog_address;
1481f347c284SJohnny Huang 	int i;
14827e523e3bSJohnny Huang 	int bit, pbit, ibit, offset;
1483f347c284SJohnny Huang 	int fail = 0;
1484f347c284SJohnny Huang 	int ret;
1485f347c284SJohnny Huang 	int prog_flag = 0;
1486f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
1487f347c284SJohnny Huang 
1488f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1489f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1490f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1491f347c284SJohnny Huang 
1492f347c284SJohnny Huang 	printf("Read OTP Strap Region:\n");
1493f347c284SJohnny Huang 	otp_strap_status(otpstrap);
1494f347c284SJohnny Huang 
1495f347c284SJohnny Huang 	printf("Check writable...\n");
1496f347c284SJohnny Huang 	if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
1497f347c284SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
1498f347c284SJohnny Huang 		return OTP_FAILURE;
1499f347c284SJohnny Huang 	}
1500f347c284SJohnny Huang 
1501f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1502f347c284SJohnny Huang 		prog_address = 0x800;
1503f347c284SJohnny Huang 		if (i < 32) {
1504f347c284SJohnny Huang 			offset = i;
1505f347c284SJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1506f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
1507f347c284SJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
1508f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1509f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1510f347c284SJohnny Huang 
1511f347c284SJohnny Huang 		} else {
1512f347c284SJohnny Huang 			offset = (i - 32);
1513f347c284SJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1514f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
1515f347c284SJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
1516f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1517f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1518f347c284SJohnny Huang 		}
1519f347c284SJohnny Huang 
1520f347c284SJohnny Huang 		if (ibit == 1)
1521f347c284SJohnny Huang 			continue;
1522f347c284SJohnny Huang 		if (bit == otpstrap[i].value)
1523f347c284SJohnny Huang 			prog_flag = 0;
1524f347c284SJohnny Huang 		else
1525f347c284SJohnny Huang 			prog_flag = 1;
1526f347c284SJohnny Huang 
1527f347c284SJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
1528f347c284SJohnny Huang 			fail = 1;
1529f347c284SJohnny Huang 			continue;
1530f347c284SJohnny Huang 		}
1531f347c284SJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
1532f347c284SJohnny Huang 			fail = 1;
1533f347c284SJohnny Huang 			continue;
1534f347c284SJohnny Huang 		}
1535f347c284SJohnny Huang 
1536f347c284SJohnny Huang 		if (prog_flag) {
1537f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1538f347c284SJohnny Huang 			if (ret)
1539f347c284SJohnny Huang 				return OTP_FAILURE;
1540f347c284SJohnny Huang 		}
1541f347c284SJohnny Huang 
1542f347c284SJohnny Huang 		if (pbit != 0) {
1543f347c284SJohnny Huang 			prog_address = 0x800;
1544f347c284SJohnny Huang 			if (i < 32)
1545f347c284SJohnny Huang 				prog_address |= 0x60c;
1546f347c284SJohnny Huang 			else
1547f347c284SJohnny Huang 				prog_address |= 0x60e;
1548f347c284SJohnny Huang 
1549f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1550f347c284SJohnny Huang 			if (ret)
1551f347c284SJohnny Huang 				return OTP_FAILURE;
1552f347c284SJohnny Huang 		}
1553f347c284SJohnny Huang 	}
1554f347c284SJohnny Huang 	otp_soak(0);
1555f347c284SJohnny Huang 	if (fail == 1)
1556f347c284SJohnny Huang 		return OTP_FAILURE;
1557f347c284SJohnny Huang 	return OTP_SUCCESS;
155869d5fd8fSJohnny Huang }
155969d5fd8fSJohnny Huang 
15605010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout)
156169d5fd8fSJohnny Huang {
1562a6d0d645SJohnny Huang 	int i, k;
1563d90825e2SJohnny Huang 	int pass = 0;
1564a219f6deSJohnny Huang 	u32 prog_address;
1565a219f6deSJohnny Huang 	u32 data[16];
1566a219f6deSJohnny Huang 	u32 compare[2];
1567a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1568a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1569a219f6deSJohnny Huang 	u32 data_masked;
1570a219f6deSJohnny Huang 	u32 buf_masked;
157169d5fd8fSJohnny Huang 
1572a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1573a6d0d645SJohnny Huang 
1574bb34a7bfSJohnny Huang 	for (i = 0; i < 16 ; i++) {
157569d5fd8fSJohnny Huang 		prog_address = 0x800;
1576a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1577a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1578a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1579a6d0d645SJohnny Huang 	}
1580a6d0d645SJohnny Huang 
1581a6d0d645SJohnny Huang 	printf("Check writable...\n");
1582bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
15835010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
15845010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1585d90825e2SJohnny Huang 		if (data_masked == buf_masked)
158669d5fd8fSJohnny Huang 			continue;
1587d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1588a6d0d645SJohnny Huang 			continue;
1589a6d0d645SJohnny Huang 		} else {
1590a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1591a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
15925010032bSJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
15935010032bSJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
15942a856b9aSJohnny Huang 			return OTP_FAILURE;
1595a6d0d645SJohnny Huang 		}
1596a6d0d645SJohnny Huang 	}
1597a6d0d645SJohnny Huang 
1598a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1599d90825e2SJohnny Huang 	otp_soak(0);
1600bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
16015010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
16025010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1603a6d0d645SJohnny Huang 		prog_address = 0x800;
1604a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1605a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1606bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1607bb34a7bfSJohnny Huang 			pass = 1;
1608a6d0d645SJohnny Huang 			continue;
1609bb34a7bfSJohnny Huang 		}
1610de6fbf1cSJohnny Huang 
1611de6fbf1cSJohnny Huang 		otp_soak(1);
16125010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1613a6d0d645SJohnny Huang 
161469d5fd8fSJohnny Huang 		pass = 0;
161569d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
16165010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1617de6fbf1cSJohnny Huang 				otp_soak(2);
1618feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
16195010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1620de6fbf1cSJohnny Huang 					otp_soak(1);
1621de6fbf1cSJohnny Huang 				} else {
1622de6fbf1cSJohnny Huang 					pass = 1;
1623de6fbf1cSJohnny Huang 					break;
1624de6fbf1cSJohnny Huang 				}
1625a6d0d645SJohnny Huang 			} else {
162669d5fd8fSJohnny Huang 				pass = 1;
162769d5fd8fSJohnny Huang 				break;
162869d5fd8fSJohnny Huang 			}
162969d5fd8fSJohnny Huang 		}
1630bb34a7bfSJohnny Huang 		if (pass == 0) {
1631bb34a7bfSJohnny Huang 			printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
16325010032bSJohnny Huang 			       i, data[i], conf[i], conf_ignore[i]);
1633bb34a7bfSJohnny Huang 			break;
1634bb34a7bfSJohnny Huang 		}
1635a6d0d645SJohnny Huang 	}
1636a6d0d645SJohnny Huang 
1637de6fbf1cSJohnny Huang 	otp_soak(0);
163869d5fd8fSJohnny Huang 	if (!pass)
16392a856b9aSJohnny Huang 		return OTP_FAILURE;
1640a6d0d645SJohnny Huang 
16412a856b9aSJohnny Huang 	return OTP_SUCCESS;
164269d5fd8fSJohnny Huang }
164369d5fd8fSJohnny Huang 
1644f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf)
1645696656c6SJohnny Huang {
1646696656c6SJohnny Huang 	sha256_context ctx;
1647696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1648696656c6SJohnny Huang 
1649696656c6SJohnny Huang 	sha256_starts(&ctx);
1650696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1651696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1652696656c6SJohnny Huang 
1653696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1654f347c284SJohnny Huang 		return OTP_SUCCESS;
1655f347c284SJohnny Huang 	return OTP_FAILURE;
1656696656c6SJohnny Huang }
1657696656c6SJohnny Huang 
1658f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
165969d5fd8fSJohnny Huang {
166069d5fd8fSJohnny Huang 	int ret;
166161a6cda7SJohnny Huang 	int image_soc_ver = 0;
1662696656c6SJohnny Huang 	struct otp_header *otp_header;
1663696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1664696656c6SJohnny Huang 	int image_size;
1665a219f6deSJohnny Huang 	u8 *buf;
1666a219f6deSJohnny Huang 	u8 *checksum;
166769d5fd8fSJohnny Huang 
1668696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1669696656c6SJohnny Huang 	if (!otp_header) {
1670*030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
16712a856b9aSJohnny Huang 		return OTP_FAILURE;
167269d5fd8fSJohnny Huang 	}
1673d90825e2SJohnny Huang 
1674696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1675696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1676696656c6SJohnny Huang 
1677696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1678696656c6SJohnny Huang 
1679696656c6SJohnny Huang 	if (!buf) {
1680*030cb4a7SJohnny Huang 		printf("Failed to map physical memory\n");
1681696656c6SJohnny Huang 		return OTP_FAILURE;
1682696656c6SJohnny Huang 	}
1683696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1684696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1685696656c6SJohnny Huang 
1686696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1687*030cb4a7SJohnny Huang 		printf("Image is invalid\n");
1688696656c6SJohnny Huang 		return OTP_FAILURE;
1689696656c6SJohnny Huang 	}
1690696656c6SJohnny Huang 
16915010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
16925010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
16935010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
16945010032bSJohnny Huang 
16955010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1696696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
16975010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1698696656c6SJohnny Huang 
1699696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
17005010032bSJohnny Huang 	image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
17015010032bSJohnny Huang 	image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
17025010032bSJohnny Huang 	image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
17037e523e3bSJohnny Huang 
17047e523e3bSJohnny Huang 	if (otp_header->soc_ver == SOC_AST2600A0) {
17057e523e3bSJohnny Huang 		image_soc_ver = OTP_A0;
170661a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A1) {
170761a6cda7SJohnny Huang 		image_soc_ver = OTP_A1;
170861a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A2) {
170961a6cda7SJohnny Huang 		image_soc_ver = OTP_A2;
171061a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A3) {
171161a6cda7SJohnny Huang 		image_soc_ver = OTP_A3;
1712696656c6SJohnny Huang 	} else {
1713*030cb4a7SJohnny Huang 		printf("Image SOC Version is not supported\n");
1714696656c6SJohnny Huang 		return OTP_FAILURE;
1715696656c6SJohnny Huang 	}
1716696656c6SJohnny Huang 
171761a6cda7SJohnny Huang 	if (image_soc_ver != info_cb.version) {
1718*030cb4a7SJohnny Huang 		printf("Version is not match\n");
17199a4fe690SJohnny Huang 		return OTP_FAILURE;
17209a4fe690SJohnny Huang 	}
17219a4fe690SJohnny Huang 
172261a6cda7SJohnny Huang 	if (otp_header->otptool_ver != OTPTOOL_VERSION(1, 0, 0)) {
1723*030cb4a7SJohnny Huang 		printf("OTP image is not generated by otptool v1.0.0\n");
172461a6cda7SJohnny Huang 		return OTP_FAILURE;
172561a6cda7SJohnny Huang 	}
172661a6cda7SJohnny Huang 
1727f347c284SJohnny Huang 	if (otp_verify_image(buf, image_size, checksum)) {
1728*030cb4a7SJohnny Huang 		printf("checksum is invalid\n");
1729696656c6SJohnny Huang 		return OTP_FAILURE;
1730d90825e2SJohnny Huang 	}
17317332532cSJohnny Huang 
1732*030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
1733*030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
1734*030cb4a7SJohnny Huang 		return OTP_FAILURE;
1735*030cb4a7SJohnny Huang 	}
1736*030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
1737*030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_data) {
1738*030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
1739*030cb4a7SJohnny Huang 			ret = -1;
1740*030cb4a7SJohnny Huang 		}
1741*030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_sec) {
1742*030cb4a7SJohnny Huang 			printf("OTP secure region is protected\n");
1743*030cb4a7SJohnny Huang 			ret = -1;
1744*030cb4a7SJohnny Huang 		}
1745*030cb4a7SJohnny Huang 	}
1746*030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
1747*030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_conf) {
1748*030cb4a7SJohnny Huang 			printf("OTP config region is protected\n");
1749*030cb4a7SJohnny Huang 			ret = -1;
1750*030cb4a7SJohnny Huang 		}
1751*030cb4a7SJohnny Huang 	}
1752*030cb4a7SJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
1753*030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
1754*030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
1755*030cb4a7SJohnny Huang 			ret = -1;
1756*030cb4a7SJohnny Huang 		}
1757*030cb4a7SJohnny Huang 	}
1758*030cb4a7SJohnny Huang 	if (ret == -1)
1759*030cb4a7SJohnny Huang 		return OTP_FAILURE;
176069d5fd8fSJohnny Huang 	if (!nconfirm) {
1761696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
17627f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1763f347c284SJohnny Huang 			if (otp_print_data_image(&image_layout) < 0) {
176469d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
17652a856b9aSJohnny Huang 				return OTP_FAILURE;
176669d5fd8fSJohnny Huang 			}
176769d5fd8fSJohnny Huang 		}
1768696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
17697332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1770696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
17717332532cSJohnny Huang 				printf("OTP config error, please check.\n");
17727332532cSJohnny Huang 				return OTP_FAILURE;
17737332532cSJohnny Huang 			}
17747332532cSJohnny Huang 		}
17757adec5f6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
17767adec5f6SJohnny Huang 			printf("\nOTP strap region :\n");
17777adec5f6SJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
17787adec5f6SJohnny Huang 				printf("OTP strap error, please check.\n");
17797adec5f6SJohnny Huang 				return OTP_FAILURE;
17807adec5f6SJohnny Huang 			}
17817adec5f6SJohnny Huang 		}
17827332532cSJohnny Huang 
178369d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
178469d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
178569d5fd8fSJohnny Huang 			printf(" Aborting\n");
17862a856b9aSJohnny Huang 			return OTP_FAILURE;
178769d5fd8fSJohnny Huang 		}
178869d5fd8fSJohnny Huang 	}
17897332532cSJohnny Huang 
17905010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
17915010032bSJohnny Huang 		printf("programing data region ...\n");
17925010032bSJohnny Huang 		ret = otp_prog_data(&image_layout);
17935010032bSJohnny Huang 		if (ret != 0) {
17945010032bSJohnny Huang 			printf("Error\n");
17955010032bSJohnny Huang 			return ret;
17965010032bSJohnny Huang 		}
1797a219f6deSJohnny Huang 		printf("Done\n");
17985010032bSJohnny Huang 	}
17995010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
18005010032bSJohnny Huang 		printf("programing strap region ...\n");
18015010032bSJohnny Huang 		ret = otp_prog_strap(&image_layout);
18025010032bSJohnny Huang 		if (ret != 0) {
18035010032bSJohnny Huang 			printf("Error\n");
18045010032bSJohnny Huang 			return ret;
18055010032bSJohnny Huang 		}
1806a219f6deSJohnny Huang 		printf("Done\n");
18075010032bSJohnny Huang 	}
18085010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
18095010032bSJohnny Huang 		printf("programing configuration region ...\n");
18105010032bSJohnny Huang 		ret = otp_prog_conf(&image_layout);
18115010032bSJohnny Huang 		if (ret != 0) {
18125010032bSJohnny Huang 			printf("Error\n");
18135010032bSJohnny Huang 			return ret;
18145010032bSJohnny Huang 		}
18155010032bSJohnny Huang 		printf("Done\n");
18165010032bSJohnny Huang 	}
1817cd1610b4SJohnny Huang 
18187332532cSJohnny Huang 	return OTP_SUCCESS;
18192a856b9aSJohnny Huang }
18202a856b9aSJohnny Huang 
1821f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1822cd1610b4SJohnny Huang {
1823a219f6deSJohnny Huang 	u32 read[2];
1824a219f6deSJohnny Huang 	u32 prog_address = 0;
182566f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1826cd1610b4SJohnny Huang 	int otp_bit;
182783655e91SJohnny Huang 	int ret = 0;
1828cd1610b4SJohnny Huang 
1829dacbba92SJohnny Huang 	otp_soak(0);
1830cd1610b4SJohnny Huang 	switch (mode) {
1831a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1832f347c284SJohnny Huang 		otp_read_conf(otp_dw_offset, read);
1833cd1610b4SJohnny Huang 		prog_address = 0x800;
1834cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1835cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1836a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1837cd1610b4SJohnny Huang 		if (otp_bit == value) {
1838a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1839cd1610b4SJohnny Huang 			printf("No need to program\n");
18402a856b9aSJohnny Huang 			return OTP_SUCCESS;
1841cd1610b4SJohnny Huang 		}
1842cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1843a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
18440dc9a440SJohnny Huang 			printf("OTP is programmed, which can't be clean\n");
18452a856b9aSJohnny Huang 			return OTP_FAILURE;
1846cd1610b4SJohnny Huang 		}
1847a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1848cd1610b4SJohnny Huang 		break;
1849a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1850cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1851cd1610b4SJohnny Huang 
1852cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1853a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1854a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1855643b9cfdSJohnny Huang 
1856643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
1857643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
18580dc9a440SJohnny Huang 				printf("OTP is programmed, which can't be cleaned\n");
1859643b9cfdSJohnny Huang 				return OTP_FAILURE;
1860643b9cfdSJohnny Huang 			}
1861cd1610b4SJohnny Huang 		} else {
1862a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1863a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1864643b9cfdSJohnny Huang 
1865643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
1866643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
18670dc9a440SJohnny Huang 				printf("OTP is programmed, which can't be writen\n");
1868643b9cfdSJohnny Huang 				return OTP_FAILURE;
1869643b9cfdSJohnny Huang 			}
1870cd1610b4SJohnny Huang 		}
1871cd1610b4SJohnny Huang 		if (otp_bit == value) {
1872a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1873cd1610b4SJohnny Huang 			printf("No need to program\n");
18742a856b9aSJohnny Huang 			return OTP_SUCCESS;
1875cd1610b4SJohnny Huang 		}
1876643b9cfdSJohnny Huang 
1877a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1878cd1610b4SJohnny Huang 		break;
1879a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
18808848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
18818848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
18827e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
18838848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
18848848d5dcSJohnny Huang 			return OTP_FAILURE;
18858848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
18868848d5dcSJohnny Huang 			return OTP_SUCCESS;
1887a6af4a17SJohnny Huang 
1888cd1610b4SJohnny Huang 		break;
1889cd1610b4SJohnny Huang 	}
1890cd1610b4SJohnny Huang 
1891cd1610b4SJohnny Huang 	if (!nconfirm) {
1892cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1893cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1894cd1610b4SJohnny Huang 			printf(" Aborting\n");
18952a856b9aSJohnny Huang 			return OTP_FAILURE;
1896cd1610b4SJohnny Huang 		}
1897cd1610b4SJohnny Huang 	}
1898cd1610b4SJohnny Huang 
1899cd1610b4SJohnny Huang 	switch (mode) {
1900a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1901f347c284SJohnny Huang 		ret =  otp_prog_strap_b(bit_offset, value);
190283655e91SJohnny Huang 		break;
1903a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1904a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1905f347c284SJohnny Huang 		ret = otp_prog_dc_b(value, prog_address, bit_offset);
1906de6fbf1cSJohnny Huang 		break;
1907de6fbf1cSJohnny Huang 	}
1908de6fbf1cSJohnny Huang 	otp_soak(0);
190983655e91SJohnny Huang 	if (ret) {
19100dc9a440SJohnny Huang 		printf("OTP cannot be programmed\n");
1911794e27ecSJohnny Huang 		printf("FAILURE\n");
1912794e27ecSJohnny Huang 		return OTP_FAILURE;
1913794e27ecSJohnny Huang 	}
1914794e27ecSJohnny Huang 
19159009c25dSJohnny Huang 	printf("SUCCESS\n");
19162a856b9aSJohnny Huang 	return OTP_SUCCESS;
1917a219f6deSJohnny Huang }
1918a219f6deSJohnny Huang 
1919794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
1920794e27ecSJohnny Huang {
1921794e27ecSJohnny Huang 	u32 otp_rid[2];
1922a8789b47SJohnny Huang 	u32 sw_rid[2];
1923794e27ecSJohnny Huang 	int rid_num = 0;
1924a8789b47SJohnny Huang 	int sw_rid_num = 0;
1925794e27ecSJohnny Huang 	int bit_offset;
1926794e27ecSJohnny Huang 	int dw_offset;
1927794e27ecSJohnny Huang 	int i;
1928794e27ecSJohnny Huang 	int ret;
1929794e27ecSJohnny Huang 
1930f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
1931f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
1932794e27ecSJohnny Huang 
1933a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
1934a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
1935a8789b47SJohnny Huang 
1936794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1937a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
1938a8789b47SJohnny Huang 
1939a8789b47SJohnny Huang 	if (sw_rid_num < 0) {
1940a8789b47SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
1941a8789b47SJohnny Huang 		return OTP_FAILURE;
1942a8789b47SJohnny Huang 	}
1943a8789b47SJohnny Huang 
1944a8789b47SJohnny Huang 	if (update_num > sw_rid_num) {
1945a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
1946a8789b47SJohnny Huang 		printf("update number could not bigger than current SW revision id\n");
1947a8789b47SJohnny Huang 		return OTP_FAILURE;
1948a8789b47SJohnny Huang 	}
1949794e27ecSJohnny Huang 
1950794e27ecSJohnny Huang 	if (rid_num < 0) {
1951794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by this command,\n"
1952794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n");
1953794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
19549009c25dSJohnny Huang 		return OTP_FAILURE;
19559009c25dSJohnny Huang 	}
1956cd1610b4SJohnny Huang 
1957794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
1958794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1959794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
1960794e27ecSJohnny Huang 
1961a8789b47SJohnny Huang 	if (rid_num > update_num) {
1962a8789b47SJohnny Huang 		printf("OTP rev_id is bigger than 0x%X\n", update_num);
1963a8789b47SJohnny Huang 		printf("Skip\n");
1964a8789b47SJohnny Huang 		return OTP_FAILURE;
1965a8789b47SJohnny Huang 	} else if (rid_num == update_num) {
1966a8789b47SJohnny Huang 		printf("OTP rev_id is same as input\n");
1967794e27ecSJohnny Huang 		printf("Skip\n");
1968794e27ecSJohnny Huang 		return OTP_FAILURE;
1969794e27ecSJohnny Huang 	}
1970794e27ecSJohnny Huang 
1971794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1972794e27ecSJohnny Huang 		if (i < 32) {
1973794e27ecSJohnny Huang 			dw_offset = 0xa;
1974794e27ecSJohnny Huang 			bit_offset = i;
1975794e27ecSJohnny Huang 		} else {
1976794e27ecSJohnny Huang 			dw_offset = 0xb;
1977794e27ecSJohnny Huang 			bit_offset = i - 32;
1978794e27ecSJohnny Huang 		}
19790dc9a440SJohnny Huang 		printf("OTPCFG%X[%X]", dw_offset, bit_offset);
1980794e27ecSJohnny Huang 		if (i + 1 != update_num)
1981794e27ecSJohnny Huang 			printf(", ");
1982794e27ecSJohnny Huang 	}
1983794e27ecSJohnny Huang 
1984794e27ecSJohnny Huang 	printf(" will be programmed\n");
1985794e27ecSJohnny Huang 	if (force == 0) {
1986794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1987794e27ecSJohnny Huang 		if (!confirm_yesno()) {
1988794e27ecSJohnny Huang 			printf(" Aborting\n");
1989794e27ecSJohnny Huang 			return OTP_FAILURE;
1990794e27ecSJohnny Huang 		}
1991794e27ecSJohnny Huang 	}
1992794e27ecSJohnny Huang 
1993794e27ecSJohnny Huang 	ret = 0;
1994794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1995794e27ecSJohnny Huang 		if (i < 32) {
1996794e27ecSJohnny Huang 			dw_offset = 0xa04;
1997794e27ecSJohnny Huang 			bit_offset = i;
1998794e27ecSJohnny Huang 		} else {
1999794e27ecSJohnny Huang 			dw_offset = 0xa06;
2000794e27ecSJohnny Huang 			bit_offset = i - 32;
2001794e27ecSJohnny Huang 		}
2002f347c284SJohnny Huang 		if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
20030dc9a440SJohnny Huang 			printf("OTPCFG%X[%X] programming failed\n", dw_offset, bit_offset);
2004794e27ecSJohnny Huang 			ret = OTP_FAILURE;
2005794e27ecSJohnny Huang 			break;
2006794e27ecSJohnny Huang 		}
2007794e27ecSJohnny Huang 	}
2008061d3279SJohnny Huang 	otp_soak(0);
2009f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2010f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2011794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2012794e27ecSJohnny Huang 	if (rid_num >= 0)
2013794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
2014794e27ecSJohnny Huang 	else
2015794e27ecSJohnny Huang 		printf("OTP revision ID\n");
2016794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2017794e27ecSJohnny Huang 	if (!ret)
2018794e27ecSJohnny Huang 		printf("SUCCESS\n");
2019794e27ecSJohnny Huang 	else
2020794e27ecSJohnny Huang 		printf("FAILED\n");
2021794e27ecSJohnny Huang 	return ret;
2022794e27ecSJohnny Huang }
2023794e27ecSJohnny Huang 
20242a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
202569d5fd8fSJohnny Huang {
2026a219f6deSJohnny Huang 	u32 offset, count;
20272a856b9aSJohnny Huang 	int ret;
202869d5fd8fSJohnny Huang 
20292a856b9aSJohnny Huang 	if (argc == 4) {
20302a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
20312a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
20322a856b9aSJohnny Huang 	} else if (argc == 3) {
20332a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
20342a856b9aSJohnny Huang 		count = 1;
20352a856b9aSJohnny Huang 	} else {
203669d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
203769d5fd8fSJohnny Huang 	}
203869d5fd8fSJohnny Huang 
2039*030cb4a7SJohnny Huang 	if (!strcmp(argv[1], "conf"))
2040f347c284SJohnny Huang 		ret = otp_print_conf(offset, count);
2041*030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "data"))
20422a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
2043*030cb4a7SJohnny Huang 	else if (!strcmp(argv[1], "strap"))
20442a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
2045*030cb4a7SJohnny Huang 	else
20462a856b9aSJohnny Huang 		return CMD_RET_USAGE;
204769d5fd8fSJohnny Huang 
20482a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20492a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20502a856b9aSJohnny Huang 	return CMD_RET_USAGE;
20512a856b9aSJohnny Huang }
20522a856b9aSJohnny Huang 
20532a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20542a856b9aSJohnny Huang {
20552a856b9aSJohnny Huang 	phys_addr_t addr;
20562a856b9aSJohnny Huang 	int ret;
20572a856b9aSJohnny Huang 
2058de6b0cc4SJohnny Huang 	if (argc == 3) {
2059ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
20602a856b9aSJohnny Huang 			return CMD_RET_USAGE;
20612a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
2062f347c284SJohnny Huang 		ret = otp_prog_image(addr, 1);
2063de6b0cc4SJohnny Huang 	} else if (argc == 2) {
20642a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
2065f347c284SJohnny Huang 		ret = otp_prog_image(addr, 0);
20662a856b9aSJohnny Huang 	} else {
20672a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20682a856b9aSJohnny Huang 	}
20692a856b9aSJohnny Huang 
20702a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20712a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20722a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
20732a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
20742a856b9aSJohnny Huang 	else
20752a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20762a856b9aSJohnny Huang }
20772a856b9aSJohnny Huang 
20782a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20792a856b9aSJohnny Huang {
20802a856b9aSJohnny Huang 	int mode = 0;
20812a856b9aSJohnny Huang 	int nconfirm = 0;
20822a856b9aSJohnny Huang 	int otp_addr = 0;
20832a856b9aSJohnny Huang 	int bit_offset;
20842a856b9aSJohnny Huang 	int value;
20852a856b9aSJohnny Huang 	int ret;
2086*030cb4a7SJohnny Huang 	u32 otp_strap_pro;
20872a856b9aSJohnny Huang 
20882a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
20892a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20902a856b9aSJohnny Huang 
20912a856b9aSJohnny Huang 	/* Drop the pb cmd */
20922a856b9aSJohnny Huang 	argc--;
20932a856b9aSJohnny Huang 	argv++;
20942a856b9aSJohnny Huang 
20952a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2096a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
20972a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2098a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
20992a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2100a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2101cd1610b4SJohnny Huang 	else
21022a856b9aSJohnny Huang 		return CMD_RET_USAGE;
21032a856b9aSJohnny Huang 
21042a856b9aSJohnny Huang 	/* Drop the region cmd */
21052a856b9aSJohnny Huang 	argc--;
21062a856b9aSJohnny Huang 	argv++;
21072a856b9aSJohnny Huang 
2108ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2109cd1610b4SJohnny Huang 		nconfirm = 1;
21102a856b9aSJohnny Huang 		/* Drop the force option */
21112a856b9aSJohnny Huang 		argc--;
21122a856b9aSJohnny Huang 		argv++;
21132a856b9aSJohnny Huang 	}
2114cd1610b4SJohnny Huang 
2115a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
21162a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
21172a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
21180808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
21192a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2120cd1610b4SJohnny Huang 	} else {
21212a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
21222a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
21232a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
21240808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
21252a856b9aSJohnny Huang 			return CMD_RET_USAGE;
21260808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
212778855207SJohnny Huang 			if (otp_addr >= 0x800)
21280808cc55SJohnny Huang 				return CMD_RET_USAGE;
21290808cc55SJohnny Huang 		} else {
213078855207SJohnny Huang 			if (otp_addr >= 0x20)
21310808cc55SJohnny Huang 				return CMD_RET_USAGE;
21320808cc55SJohnny Huang 		}
2133cd1610b4SJohnny Huang 	}
2134cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
21352a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2136cd1610b4SJohnny Huang 
2137*030cb4a7SJohnny Huang 	ret = 0;
2138*030cb4a7SJohnny Huang 	if (info_cb.pro_sts.mem_lock) {
2139*030cb4a7SJohnny Huang 		printf("OTP memory is locked\n");
2140*030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2141*030cb4a7SJohnny Huang 	}
2142*030cb4a7SJohnny Huang 	if (mode == OTP_REGION_DATA) {
2143*030cb4a7SJohnny Huang 		if (info_cb.pro_sts.sec_size == 0) {
2144*030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_data) {
2145*030cb4a7SJohnny Huang 				printf("OTP data region is protected\n");
2146*030cb4a7SJohnny Huang 				ret = -1;
2147*030cb4a7SJohnny Huang 			}
2148*030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size && otp_addr >= 16) {
2149*030cb4a7SJohnny Huang 			printf("OTP secure region is not readable, skip it to prevent unpredictable result\n");
2150*030cb4a7SJohnny Huang 			ret = -1;
2151*030cb4a7SJohnny Huang 		} else if (otp_addr < info_cb.pro_sts.sec_size) {
2152*030cb4a7SJohnny Huang 			// header region(0x0~0x40) is still readable even secure region is set.
2153*030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_sec) {
2154*030cb4a7SJohnny Huang 				printf("OTP secure region is protected\n");
2155*030cb4a7SJohnny Huang 				ret = -1;
2156*030cb4a7SJohnny Huang 			}
2157*030cb4a7SJohnny Huang 		} else if (info_cb.pro_sts.pro_data) {
2158*030cb4a7SJohnny Huang 			printf("OTP data region is protected\n");
2159*030cb4a7SJohnny Huang 			ret = -1;
2160*030cb4a7SJohnny Huang 		}
2161*030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_CONF) {
2162*030cb4a7SJohnny Huang 		if (otp_addr != 4 && otp_addr != 10 && otp_addr != 11 && otp_addr < 16) {
2163*030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_conf) {
2164*030cb4a7SJohnny Huang 				printf("OTP config region is protected\n");
2165*030cb4a7SJohnny Huang 				ret = -1;
2166*030cb4a7SJohnny Huang 			}
2167*030cb4a7SJohnny Huang 		} else if (otp_addr == 10 || otp_addr == 11) {
2168*030cb4a7SJohnny Huang 			u32 otp_rid[2];
2169*030cb4a7SJohnny Huang 			u32 sw_rid[2];
2170*030cb4a7SJohnny Huang 			u64 *otp_rid64 = (u64 *)otp_rid;
2171*030cb4a7SJohnny Huang 			u64 *sw_rid64 = (u64 *)sw_rid;
2172*030cb4a7SJohnny Huang 
2173*030cb4a7SJohnny Huang 			otp_read_conf(10, &otp_rid[0]);
2174*030cb4a7SJohnny Huang 			otp_read_conf(11, &otp_rid[1]);
2175*030cb4a7SJohnny Huang 			sw_rid[0] = readl(SW_REV_ID0);
2176*030cb4a7SJohnny Huang 			sw_rid[1] = readl(SW_REV_ID1);
2177*030cb4a7SJohnny Huang 
2178*030cb4a7SJohnny Huang 			if (otp_addr == 10)
2179*030cb4a7SJohnny Huang 				otp_rid[0] |= 1 << bit_offset;
2180*030cb4a7SJohnny Huang 			else
2181*030cb4a7SJohnny Huang 				otp_rid[1] |= 1 << bit_offset;
2182*030cb4a7SJohnny Huang 
2183*030cb4a7SJohnny Huang 			if (*otp_rid64 > *sw_rid64) {
2184*030cb4a7SJohnny Huang 				printf("update number could not bigger than current SW revision id\n");
2185*030cb4a7SJohnny Huang 				ret = -1;
2186*030cb4a7SJohnny Huang 			}
2187*030cb4a7SJohnny Huang 		} else if (otp_addr == 4) {
2188*030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_key_ret) {
2189*030cb4a7SJohnny Huang 				printf("OTPCFG4 is protected\n");
2190*030cb4a7SJohnny Huang 				ret = -1;
2191*030cb4a7SJohnny Huang 			} else {
2192*030cb4a7SJohnny Huang 				if ((bit_offset >= 0 && bit_offset <= 7) ||
2193*030cb4a7SJohnny Huang 				    (bit_offset >= 16 && bit_offset <= 23)) {
2194*030cb4a7SJohnny Huang 					u32 key_num;
2195*030cb4a7SJohnny Huang 					u32 retire;
2196*030cb4a7SJohnny Huang 
2197*030cb4a7SJohnny Huang 					key_num = readl(SEC_KEY_NUM) & 3;
2198*030cb4a7SJohnny Huang 					if (bit_offset >= 16)
2199*030cb4a7SJohnny Huang 						retire = bit_offset - 16;
2200*030cb4a7SJohnny Huang 					else
2201*030cb4a7SJohnny Huang 						retire = bit_offset;
2202*030cb4a7SJohnny Huang 					if (retire >= key_num) {
2203*030cb4a7SJohnny Huang 						printf("Retire key id is equal or bigger than current boot key\n");
2204*030cb4a7SJohnny Huang 						ret = -1;
2205*030cb4a7SJohnny Huang 					}
2206*030cb4a7SJohnny Huang 				}
2207*030cb4a7SJohnny Huang 			}
2208*030cb4a7SJohnny Huang 		} else if (otp_addr >= 16 && otp_addr <= 31) {
2209*030cb4a7SJohnny Huang 			if (info_cb.pro_sts.pro_strap) {
2210*030cb4a7SJohnny Huang 				printf("OTP strap region is protected\n");
2211*030cb4a7SJohnny Huang 				ret = -1;
2212*030cb4a7SJohnny Huang 			} else if ((otp_addr < 30 && info_cb.version == OTP_A0) ||
2213*030cb4a7SJohnny Huang 				   (otp_addr < 28 && info_cb.version != OTP_A0)) {
2214*030cb4a7SJohnny Huang 				if (otp_addr % 2 == 0)
2215*030cb4a7SJohnny Huang 					otp_read_conf(30, &otp_strap_pro);
2216*030cb4a7SJohnny Huang 				else
2217*030cb4a7SJohnny Huang 					otp_read_conf(31, &otp_strap_pro);
2218*030cb4a7SJohnny Huang 				if (otp_strap_pro >> bit_offset & 0x1) {
2219*030cb4a7SJohnny Huang 					printf("OTPCFG%X[%X] is protected\n", otp_addr, bit_offset);
2220*030cb4a7SJohnny Huang 					ret = -1;
2221*030cb4a7SJohnny Huang 				}
2222*030cb4a7SJohnny Huang 			}
2223*030cb4a7SJohnny Huang 		}
2224*030cb4a7SJohnny Huang 	} else if (mode == OTP_REGION_STRAP) {
2225*030cb4a7SJohnny Huang 		// per bit protection will check in otp_strap_bit_confirm
2226*030cb4a7SJohnny Huang 		if (info_cb.pro_sts.pro_strap) {
2227*030cb4a7SJohnny Huang 			printf("OTP strap region is protected\n");
2228*030cb4a7SJohnny Huang 			ret = -1;
2229*030cb4a7SJohnny Huang 		}
2230*030cb4a7SJohnny Huang 	}
2231*030cb4a7SJohnny Huang 
2232*030cb4a7SJohnny Huang 	if (ret == -1)
2233*030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2234*030cb4a7SJohnny Huang 
2235f347c284SJohnny Huang 	ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
22362a856b9aSJohnny Huang 
22372a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
22382a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
22392a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
22402a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
22412a856b9aSJohnny Huang 	else
22422a856b9aSJohnny Huang 		return CMD_RET_USAGE;
22432a856b9aSJohnny Huang }
22442a856b9aSJohnny Huang 
22452a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
22462a856b9aSJohnny Huang {
22472a856b9aSJohnny Huang 	phys_addr_t addr;
22482a856b9aSJohnny Huang 	int otp_addr = 0;
2249b8590031SJohnny Huang 	int ret;
22502a856b9aSJohnny Huang 
22512a856b9aSJohnny Huang 	if (argc != 3)
22522a856b9aSJohnny Huang 		return CMD_RET_USAGE;
22532a856b9aSJohnny Huang 
22542a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
22552a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
2256b8590031SJohnny Huang 	ret = otp_compare(otp_addr, addr);
2257b8590031SJohnny Huang 	if (ret == 0) {
225869d5fd8fSJohnny Huang 		printf("Compare pass\n");
22592a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2260a219f6deSJohnny Huang 	}
226169d5fd8fSJohnny Huang 	printf("Compare fail\n");
22622a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
226369d5fd8fSJohnny Huang }
226469d5fd8fSJohnny Huang 
226566f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
226666f2f8e5SJohnny Huang {
2267a8bd6d8cSJohnny Huang 	int view = 0;
22682d4b0742SJohnny Huang 	int input;
2269a8bd6d8cSJohnny Huang 
2270a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
227166f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
227266f2f8e5SJohnny Huang 
22732d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
22742d4b0742SJohnny Huang 		if (argc == 3) {
22752d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
22762d4b0742SJohnny Huang 			otp_print_conf_info(input);
22772d4b0742SJohnny Huang 		} else {
22782d4b0742SJohnny Huang 			otp_print_conf_info(-1);
22792d4b0742SJohnny Huang 		}
22802d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
22812d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2282a8bd6d8cSJohnny Huang 			view = 1;
2283a8bd6d8cSJohnny Huang 			/* Drop the view option */
2284a8bd6d8cSJohnny Huang 			argc--;
2285a8bd6d8cSJohnny Huang 			argv++;
2286a8bd6d8cSJohnny Huang 		}
2287b458cd62SJohnny Huang 		otp_print_strap_info(view);
22880dc9a440SJohnny Huang 	} else if (!strcmp(argv[1], "scu")) {
22890dc9a440SJohnny Huang 		otp_print_scu_info();
229066f2f8e5SJohnny Huang 	} else {
229166f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
229266f2f8e5SJohnny Huang 	}
22932d4b0742SJohnny Huang 
229466f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
229566f2f8e5SJohnny Huang }
229666f2f8e5SJohnny Huang 
22970dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2298737ed20bSJohnny Huang {
22990dc9a440SJohnny Huang 	u32 input;
23000dc9a440SJohnny Huang 	u32 bit_offset;
2301e14b073cSJohnny Huang 	u32 prog_address;
2302*030cb4a7SJohnny Huang 	char force;
230383655e91SJohnny Huang 	int ret;
2304a219f6deSJohnny Huang 
2305737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2306737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2307737ed20bSJohnny Huang 
2308e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2309737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2310*030cb4a7SJohnny Huang 		force = 1;
2311737ed20bSJohnny Huang 	} else {
2312737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2313*030cb4a7SJohnny Huang 		force = 0;
2314737ed20bSJohnny Huang 	}
2315737ed20bSJohnny Huang 
2316737ed20bSJohnny Huang 	if (input < 32) {
2317737ed20bSJohnny Huang 		bit_offset = input;
23180dc9a440SJohnny Huang 		prog_address = 0xe0c;
2319737ed20bSJohnny Huang 	} else if (input < 64) {
2320737ed20bSJohnny Huang 		bit_offset = input - 32;
23210dc9a440SJohnny Huang 		prog_address = 0xe0e;
2322737ed20bSJohnny Huang 	} else {
2323737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2324737ed20bSJohnny Huang 	}
2325737ed20bSJohnny Huang 
2326*030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
2327*030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
2328*030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2329*030cb4a7SJohnny Huang 	}
2330*030cb4a7SJohnny Huang 
2331*030cb4a7SJohnny Huang 	if (!force) {
2332*030cb4a7SJohnny Huang 		printf("OTPSTRAP[%X] will be protected\n", input);
2333*030cb4a7SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2334*030cb4a7SJohnny Huang 		if (!confirm_yesno()) {
2335*030cb4a7SJohnny Huang 			printf(" Aborting\n");
2336*030cb4a7SJohnny Huang 			return CMD_RET_FAILURE;
2337*030cb4a7SJohnny Huang 		}
2338*030cb4a7SJohnny Huang 	}
2339*030cb4a7SJohnny Huang 
2340e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
23410dc9a440SJohnny Huang 		printf("OTPSTRAP[%X] already protected\n", input);
2342e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2343e14b073cSJohnny Huang 	}
2344de6fbf1cSJohnny Huang 
2345f347c284SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
2346de6fbf1cSJohnny Huang 	otp_soak(0);
234783655e91SJohnny Huang 
234883655e91SJohnny Huang 	if (ret) {
23490dc9a440SJohnny Huang 		printf("Protect OTPSTRAP[%X] fail\n", input);
2350737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2351737ed20bSJohnny Huang 	}
23529a4fe690SJohnny Huang 
23530dc9a440SJohnny Huang 	printf("OTPSTRAP[%X] is protected\n", input);
2354794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2355794e27ecSJohnny Huang }
2356794e27ecSJohnny Huang 
23570dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2358e14b073cSJohnny Huang {
23590dc9a440SJohnny Huang 	u32 scu_offset;
23600dc9a440SJohnny Huang 	u32 bit_offset;
23610dc9a440SJohnny Huang 	u32 conf_offset;
23620dc9a440SJohnny Huang 	u32 prog_address;
23630dc9a440SJohnny Huang 	char force;
23640dc9a440SJohnny Huang 	int ret;
23650dc9a440SJohnny Huang 
23660dc9a440SJohnny Huang 	if (argc != 4 && argc != 3)
23670dc9a440SJohnny Huang 		return CMD_RET_USAGE;
23680dc9a440SJohnny Huang 
23690dc9a440SJohnny Huang 	if (!strcmp(argv[1], "o")) {
23700dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[2], NULL, 16);
23710dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[3], NULL, 16);
23720dc9a440SJohnny Huang 		force = 1;
23730dc9a440SJohnny Huang 	} else {
23740dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[1], NULL, 16);
23750dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[2], NULL, 16);
23760dc9a440SJohnny Huang 		force = 0;
23770dc9a440SJohnny Huang 	}
23780dc9a440SJohnny Huang 	if (scu_offset == 0x500) {
23790dc9a440SJohnny Huang 		prog_address = 0xe08;
23800dc9a440SJohnny Huang 		conf_offset = 28;
23810dc9a440SJohnny Huang 	} else if (scu_offset == 0x510) {
23820dc9a440SJohnny Huang 		prog_address = 0xe0a;
23830dc9a440SJohnny Huang 		conf_offset = 29;
23840dc9a440SJohnny Huang 	} else {
23850dc9a440SJohnny Huang 		return CMD_RET_USAGE;
23860dc9a440SJohnny Huang 	}
23870dc9a440SJohnny Huang 	if (bit_offset < 0 || bit_offset > 31)
23880dc9a440SJohnny Huang 		return CMD_RET_USAGE;
2389*030cb4a7SJohnny Huang 	if (info_cb.pro_sts.pro_strap) {
2390*030cb4a7SJohnny Huang 		printf("OTP strap region is protected\n");
2391*030cb4a7SJohnny Huang 		return CMD_RET_FAILURE;
2392*030cb4a7SJohnny Huang 	}
23930dc9a440SJohnny Huang 	if (!force) {
23940dc9a440SJohnny Huang 		printf("OTPCONF%X[%X] will be programmed\n", conf_offset, bit_offset);
23950dc9a440SJohnny Huang 		printf("SCU%X[%X] will be protected\n", scu_offset, bit_offset);
23960dc9a440SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
23970dc9a440SJohnny Huang 		if (!confirm_yesno()) {
23980dc9a440SJohnny Huang 			printf(" Aborting\n");
23990dc9a440SJohnny Huang 			return CMD_RET_FAILURE;
24000dc9a440SJohnny Huang 		}
2401e14b073cSJohnny Huang 	}
2402e14b073cSJohnny Huang 
24030dc9a440SJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
24040dc9a440SJohnny Huang 		printf("OTPCONF%X[%X] already programmed\n", conf_offset, bit_offset);
24050dc9a440SJohnny Huang 		return CMD_RET_SUCCESS;
24060dc9a440SJohnny Huang 	}
24070dc9a440SJohnny Huang 
24080dc9a440SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
24090dc9a440SJohnny Huang 	otp_soak(0);
24100dc9a440SJohnny Huang 
24110dc9a440SJohnny Huang 	if (ret) {
24120dc9a440SJohnny Huang 		printf("Program OTPCONF%X[%X] fail\n", conf_offset, bit_offset);
24130dc9a440SJohnny Huang 		return CMD_RET_FAILURE;
24140dc9a440SJohnny Huang 	}
24150dc9a440SJohnny Huang 
24160dc9a440SJohnny Huang 	printf("OTPCONF%X[%X] programmed success\n", conf_offset, bit_offset);
24170dc9a440SJohnny Huang 	return CMD_RET_SUCCESS;
2418e14b073cSJohnny Huang }
2419e14b073cSJohnny Huang 
2420f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2421f67375f7SJohnny Huang {
2422e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
2423f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2424f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2425f67375f7SJohnny Huang 
2426f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2427f67375f7SJohnny Huang }
2428f67375f7SJohnny Huang 
2429794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2430794e27ecSJohnny Huang {
2431794e27ecSJohnny Huang 	u32 update_num;
2432794e27ecSJohnny Huang 	int force = 0;
2433794e27ecSJohnny Huang 	int ret;
2434794e27ecSJohnny Huang 
2435794e27ecSJohnny Huang 	if (argc == 3) {
2436794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2437794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2438794e27ecSJohnny Huang 		force = 1;
2439794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2440794e27ecSJohnny Huang 	} else if (argc == 2) {
2441794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2442794e27ecSJohnny Huang 	} else {
2443794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2444794e27ecSJohnny Huang 	}
2445794e27ecSJohnny Huang 
2446794e27ecSJohnny Huang 	if (update_num > 64)
2447794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2448794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2449b8590031SJohnny Huang 
2450794e27ecSJohnny Huang 	if (ret)
2451794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2452794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2453794e27ecSJohnny Huang }
2454794e27ecSJohnny Huang 
2455794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2456794e27ecSJohnny Huang {
2457794e27ecSJohnny Huang 	u32 otp_rid[2];
2458a8789b47SJohnny Huang 	u32 sw_rid[2];
2459794e27ecSJohnny Huang 	int rid_num = 0;
2460a8789b47SJohnny Huang 	int sw_rid_num = 0;
2461794e27ecSJohnny Huang 	int ret;
2462794e27ecSJohnny Huang 
2463794e27ecSJohnny Huang 	if (argc != 1)
2464794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2465794e27ecSJohnny Huang 
2466f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2467f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2468794e27ecSJohnny Huang 
2469a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2470a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2471794e27ecSJohnny Huang 
2472a8789b47SJohnny Huang 	rid_num = get_rid_num(otp_rid);
2473a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2474a8789b47SJohnny Huang 
2475*030cb4a7SJohnny Huang 	if (sw_rid_num < 0) {
2476*030cb4a7SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
2477*030cb4a7SJohnny Huang 		printf("SEC68:0x%x\n", sw_rid[0]);
2478*030cb4a7SJohnny Huang 		printf("SEC6C:0x%x\n", sw_rid[1]);
2479*030cb4a7SJohnny Huang 	} else {
2480a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
2481*030cb4a7SJohnny Huang 	}
2482794e27ecSJohnny Huang 	if (rid_num >= 0) {
2483794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2484794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2485794e27ecSJohnny Huang 	} else {
2486794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by 'otp update',\n"
2487794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n"
2488794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2489794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2490794e27ecSJohnny Huang 	}
2491794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2492794e27ecSJohnny Huang 
2493794e27ecSJohnny Huang 	return ret;
2494794e27ecSJohnny Huang }
2495794e27ecSJohnny Huang 
24962a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2497f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
24982a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2499a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2500de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
25012a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2502737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
25030dc9a440SJohnny Huang 	U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""),
25042a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2505794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2506794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
25072a856b9aSJohnny Huang };
25082a856b9aSJohnny Huang 
25092a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
25102a856b9aSJohnny Huang {
2511*030cb4a7SJohnny Huang 	struct otp_pro_sts *pro_sts;
25122a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2513a219f6deSJohnny Huang 	u32 ver;
2514e14b073cSJohnny Huang 	int ret;
2515*030cb4a7SJohnny Huang 	u32 otp_conf0;
25162a856b9aSJohnny Huang 
25172a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
25182a856b9aSJohnny Huang 
2519737ed20bSJohnny Huang 	/* Drop the otp command */
25202a856b9aSJohnny Huang 	argc--;
25212a856b9aSJohnny Huang 	argv++;
25222a856b9aSJohnny Huang 
2523a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
25242a856b9aSJohnny Huang 		return CMD_RET_USAGE;
25252a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
25262a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
25272a856b9aSJohnny Huang 
25280dae9d52SJohnny Huang 	ver = chip_version();
25290dae9d52SJohnny Huang 	switch (ver) {
2530e417205bSJohnny Huang 	case OTP_A0:
2531e417205bSJohnny Huang 		info_cb.version = OTP_A0;
25329a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
25339a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
25349a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
25359a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
25369a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
25379a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2538e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
25390dae9d52SJohnny Huang 		break;
2540e417205bSJohnny Huang 	case OTP_A1:
2541e417205bSJohnny Huang 		info_cb.version = OTP_A1;
25423cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
25433cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
25443cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
25453cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
25469a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
25479a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
25480dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
25490dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2550e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
25510dae9d52SJohnny Huang 		break;
2552e417205bSJohnny Huang 	case OTP_A2:
2553e417205bSJohnny Huang 		info_cb.version = OTP_A2;
25545fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
25555fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
2556fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2557fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
25585fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
25595fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
25600dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
25610dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2562e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
25630dae9d52SJohnny Huang 		break;
2564e417205bSJohnny Huang 	case OTP_A3:
2565e417205bSJohnny Huang 		info_cb.version = OTP_A3;
2566b63af886SJohnny Huang 		info_cb.conf_info = a3_conf_info;
2567b63af886SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
2568fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2569fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
2570181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2571181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
25720dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
25730dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2574e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
257564b66712SJohnny Huang 		break;
25760dae9d52SJohnny Huang 	default:
2577f1be5099SJohnny Huang 		printf("SOC is not supported\n");
25780dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
25799a4fe690SJohnny Huang 	}
25809a4fe690SJohnny Huang 
2581*030cb4a7SJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2582*030cb4a7SJohnny Huang 	otp_read_conf(0, &otp_conf0);
2583*030cb4a7SJohnny Huang 	pro_sts = &info_cb.pro_sts;
2584*030cb4a7SJohnny Huang 
2585*030cb4a7SJohnny Huang 	pro_sts->mem_lock = (otp_conf0 >> 31) & 0x1;
2586*030cb4a7SJohnny Huang 	pro_sts->pro_key_ret = (otp_conf0 >> 29) & 0x1;
2587*030cb4a7SJohnny Huang 	pro_sts->pro_strap = (otp_conf0 >> 25) & 0x1;
2588*030cb4a7SJohnny Huang 	pro_sts->pro_conf = (otp_conf0 >> 24) & 0x1;
2589*030cb4a7SJohnny Huang 	pro_sts->pro_data = (otp_conf0 >> 23) & 0x1;
2590*030cb4a7SJohnny Huang 	pro_sts->pro_sec = (otp_conf0 >> 22) & 0x1;
2591*030cb4a7SJohnny Huang 	pro_sts->sec_size = ((otp_conf0 >> 16) & 0x3f) << 5;
2592*030cb4a7SJohnny Huang 
2593e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2594b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
2595e14b073cSJohnny Huang 
2596e14b073cSJohnny Huang 	return ret;
259769d5fd8fSJohnny Huang }
259869d5fd8fSJohnny Huang 
2599a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
260069d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2601f67375f7SJohnny Huang 	   "version\n"
2602f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
26032a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
26042d4b0742SJohnny Huang 	   "otp info strap [v]\n"
26052d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
26060dc9a440SJohnny Huang 	   "otp info scu\n"
2607de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2608ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2609ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2610ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
26110dc9a440SJohnny Huang 	   "otp scuprotect [o] <scu_offset> <bit_offset>\n"
2612794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2613794e27ecSJohnny Huang 	   "otp rid\n"
261469d5fd8fSJohnny Huang 	  );
2615