xref: /openbmc/u-boot/cmd/otp.c (revision e417205b4aa6dbc9f264e9cd2341f0002de4d76a)
1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+
269d5fd8fSJohnny Huang /*
3a219f6deSJohnny Huang  * Copyright 2021 Aspeed Technology Inc.
469d5fd8fSJohnny Huang  */
5*e417205bSJohnny 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 
2364b66712SJohnny Huang #define OTP_VER				"1.0.3"
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
563d3688adSJohnny Huang 
57696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
58696656c6SJohnny Huang #define CHECKSUM_LEN		32
59a219f6deSJohnny Huang #define OTP_INC_DATA		BIT(31)
60a219f6deSJohnny Huang #define OTP_INC_CONFIG		BIT(30)
61a219f6deSJohnny Huang #define OTP_INC_STRAP		BIT(29)
62a219f6deSJohnny Huang #define OTP_ECC_EN		BIT(28)
63696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
64696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
65696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
66696656c6SJohnny Huang 
67*e417205bSJohnny Huang #define OTP_A0		0
68*e417205bSJohnny Huang #define OTP_A1		1
69*e417205bSJohnny Huang #define OTP_A2		2
70*e417205bSJohnny Huang #define OTP_A3		3
71*e417205bSJohnny Huang 
72*e417205bSJohnny Huang #define ID0_AST2600A0	0x05000303
73*e417205bSJohnny Huang #define ID1_AST2600A0	0x05000303
74*e417205bSJohnny Huang #define ID0_AST2600A1	0x05010303
75*e417205bSJohnny Huang #define ID1_AST2600A1	0x05010203
76*e417205bSJohnny Huang #define ID0_AST2600A2	0x05010303
77*e417205bSJohnny Huang #define ID1_AST2600A2	0x05020303
78*e417205bSJohnny Huang #define ID0_AST2600A3	0x05030303
79*e417205bSJohnny Huang #define ID1_AST2600A3	0x05030303
80*e417205bSJohnny Huang #define ID0_AST2620A1	0x05010203
81*e417205bSJohnny Huang #define ID1_AST2620A1	0x05010203
82*e417205bSJohnny Huang #define ID0_AST2620A2	0x05010203
83*e417205bSJohnny Huang #define ID1_AST2620A2	0x05020203
84*e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
85*e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
86*e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
87*e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
88*e417205bSJohnny Huang #define ID0_AST2605A2	0x05010103
89*e417205bSJohnny Huang #define ID1_AST2605A2	0x05020103
90*e417205bSJohnny Huang #define ID0_AST2605A3	0x05030103
91*e417205bSJohnny Huang #define ID1_AST2605A3	0x05030103
92*e417205bSJohnny Huang #define ID0_AST2625A3	0x05030403
93*e417205bSJohnny Huang #define ID1_AST2625A3	0x05030403
94696656c6SJohnny Huang 
95696656c6SJohnny Huang struct otp_header {
96696656c6SJohnny Huang 	u8	otp_magic[8];
97696656c6SJohnny Huang 	u8	otp_version[8];
98696656c6SJohnny Huang 	u32	image_info;
99696656c6SJohnny Huang 	u32	data_info;
100696656c6SJohnny Huang 	u32	config_info;
101696656c6SJohnny Huang 	u32	strap_info;
102696656c6SJohnny Huang 	u32	checksum_offset;
103a219f6deSJohnny Huang } __packed;
104696656c6SJohnny Huang 
10566f2f8e5SJohnny Huang struct otpstrap_status {
10669d5fd8fSJohnny Huang 	int value;
10769d5fd8fSJohnny Huang 	int option_array[7];
10869d5fd8fSJohnny Huang 	int remain_times;
10969d5fd8fSJohnny Huang 	int writeable_option;
1105010032bSJohnny Huang 	int reg_protected;
11169d5fd8fSJohnny Huang 	int protected;
11269d5fd8fSJohnny Huang };
11369d5fd8fSJohnny Huang 
11466f2f8e5SJohnny Huang struct otpconf_parse {
11566f2f8e5SJohnny Huang 	int dw_offset;
11666f2f8e5SJohnny Huang 	int bit;
11766f2f8e5SJohnny Huang 	int length;
11866f2f8e5SJohnny Huang 	int value;
119696656c6SJohnny Huang 	int ignore;
12066f2f8e5SJohnny Huang 	char status[80];
12166f2f8e5SJohnny Huang };
12266f2f8e5SJohnny Huang 
1239a4fe690SJohnny Huang struct otpkey_type {
1249a4fe690SJohnny Huang 	int value;
1259a4fe690SJohnny Huang 	int key_type;
1269a4fe690SJohnny Huang 	int need_id;
1279a4fe690SJohnny Huang 	char information[110];
1289a4fe690SJohnny Huang };
1299a4fe690SJohnny Huang 
1309a4fe690SJohnny Huang struct otp_info_cb {
1319a4fe690SJohnny Huang 	int version;
132*e417205bSJohnny Huang 	char ver_name[3];
13379e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1349a4fe690SJohnny Huang 	int strap_info_len;
13579e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1369a4fe690SJohnny Huang 	int conf_info_len;
13779e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1389a4fe690SJohnny Huang 	int key_info_len;
1399a4fe690SJohnny Huang };
1409a4fe690SJohnny Huang 
141696656c6SJohnny Huang struct otp_image_layout {
1425010032bSJohnny Huang 	int data_length;
1435010032bSJohnny Huang 	int conf_length;
1445010032bSJohnny Huang 	int strap_length;
145a219f6deSJohnny Huang 	u8 *data;
146a219f6deSJohnny Huang 	u8 *data_ignore;
147a219f6deSJohnny Huang 	u8 *conf;
148a219f6deSJohnny Huang 	u8 *conf_ignore;
149a219f6deSJohnny Huang 	u8 *strap;
150a219f6deSJohnny Huang 	u8 *strap_reg_pro;
151a219f6deSJohnny Huang 	u8 *strap_pro;
152a219f6deSJohnny Huang 	u8 *strap_ignore;
153696656c6SJohnny Huang };
154696656c6SJohnny Huang 
1559a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1569a4fe690SJohnny Huang 
15779e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1589a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1599a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1609a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
161181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
162181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   0, "RSA-public as SOC public key"},
163181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
164181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as SOC private key"},
165181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1669a4fe690SJohnny Huang };
1679a4fe690SJohnny Huang 
16879e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1699a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1709a4fe690SJohnny 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"},
171181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
172181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
173181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1749a4fe690SJohnny Huang };
1759a4fe690SJohnny Huang 
1765fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1775fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1785fdde29fSJohnny 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"},
179181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
180181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
181181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
182181f72d8SJohnny Huang };
183181f72d8SJohnny Huang 
184181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
185181f72d8SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
186181f72d8SJohnny 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"},
187181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
188181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
189181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
190181f72d8SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key(big endian)"},
191181f72d8SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
192181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key(big endian)"},
1935fdde29fSJohnny Huang };
1945fdde29fSJohnny Huang 
195794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
196794e27ecSJohnny Huang {
197794e27ecSJohnny Huang 	int bit_offset;
198794e27ecSJohnny Huang 	int i;
199794e27ecSJohnny Huang 
200794e27ecSJohnny Huang 	if (offset < 32) {
201794e27ecSJohnny Huang 		i = 0;
202794e27ecSJohnny Huang 		bit_offset = offset;
203794e27ecSJohnny Huang 	} else {
204794e27ecSJohnny Huang 		i = 1;
205794e27ecSJohnny Huang 		bit_offset = offset - 32;
206794e27ecSJohnny Huang 	}
207794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
208794e27ecSJohnny Huang 		return 1;
209794e27ecSJohnny Huang 	else
210794e27ecSJohnny Huang 		return 0;
211794e27ecSJohnny Huang }
212794e27ecSJohnny Huang 
213794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
214794e27ecSJohnny Huang {
215794e27ecSJohnny Huang 	int i;
216794e27ecSJohnny Huang 	int fz = 0;
217794e27ecSJohnny Huang 	int rid_num = 0;
218794e27ecSJohnny Huang 	int ret = 0;
219794e27ecSJohnny Huang 
220794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
221794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
222794e27ecSJohnny Huang 			if (!fz)
223794e27ecSJohnny Huang 				fz = 1;
224794e27ecSJohnny Huang 
225794e27ecSJohnny Huang 		} else {
226794e27ecSJohnny Huang 			rid_num++;
227794e27ecSJohnny Huang 			if (fz)
228794e27ecSJohnny Huang 				ret = OTP_FAILURE;
229794e27ecSJohnny Huang 		}
230794e27ecSJohnny Huang 	}
231794e27ecSJohnny Huang 	if (ret)
232794e27ecSJohnny Huang 		return ret;
233794e27ecSJohnny Huang 
234794e27ecSJohnny Huang 	return rid_num;
235794e27ecSJohnny Huang }
236794e27ecSJohnny Huang 
237794e27ecSJohnny Huang static void buf_print(u8 *buf, int len)
238794e27ecSJohnny Huang {
239794e27ecSJohnny Huang 	int i;
240794e27ecSJohnny Huang 
241794e27ecSJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
242794e27ecSJohnny Huang 	for (i = 0; i < len; i++) {
243794e27ecSJohnny Huang 		if (i % 16 == 0)
244794e27ecSJohnny Huang 			printf("%04X: ", i);
245794e27ecSJohnny Huang 		printf("%02X ", buf[i]);
246794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
247794e27ecSJohnny Huang 			printf("\n");
248794e27ecSJohnny Huang 	}
249794e27ecSJohnny Huang }
250794e27ecSJohnny Huang 
251a219f6deSJohnny Huang static u32 chip_version(void)
2529a4fe690SJohnny Huang {
253*e417205bSJohnny Huang 	u32 revid0, revid1;
2549a4fe690SJohnny Huang 
255*e417205bSJohnny Huang 	revid0 = readl(ASPEED_REVISION_ID0);
256*e417205bSJohnny Huang 	revid1 = readl(ASPEED_REVISION_ID1);
2579a4fe690SJohnny Huang 
258*e417205bSJohnny Huang 	if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
259badd21c2SJohnny Huang 		/* AST2600-A0 */
260*e417205bSJohnny Huang 		return OTP_A0;
261*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
262badd21c2SJohnny Huang 		/* AST2600-A1 */
263*e417205bSJohnny Huang 		return OTP_A1;
264*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
265badd21c2SJohnny Huang 		/* AST2600-A2 */
266*e417205bSJohnny Huang 		return OTP_A2;
267*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
26864b66712SJohnny Huang 		/* AST2600-A3 */
269*e417205bSJohnny Huang 		return OTP_A3;
270*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
271*e417205bSJohnny Huang 		/* AST2620-A1 */
272*e417205bSJohnny Huang 		return OTP_A1;
273*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
274*e417205bSJohnny Huang 		/* AST2620-A2 */
275*e417205bSJohnny Huang 		return OTP_A2;
276*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
27764b66712SJohnny Huang 		/* AST2620-A3 */
278*e417205bSJohnny Huang 		return OTP_A3;
279*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
280*e417205bSJohnny Huang 		/* AST2605-A2 */
281*e417205bSJohnny Huang 		return OTP_A2;
282*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
283*e417205bSJohnny Huang 		/* AST2605-A3 */
284*e417205bSJohnny Huang 		return OTP_A3;
285*e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
286*e417205bSJohnny Huang 		/* AST2605-A3 */
287*e417205bSJohnny Huang 		return OTP_A3;
2880dae9d52SJohnny Huang 	}
2895fdde29fSJohnny Huang 	return -1;
2909a4fe690SJohnny Huang }
2919a4fe690SJohnny Huang 
2923d3688adSJohnny Huang static void wait_complete(void)
2933d3688adSJohnny Huang {
2943d3688adSJohnny Huang 	int reg;
2953d3688adSJohnny Huang 
2963d3688adSJohnny Huang 	do {
2973d3688adSJohnny Huang 		reg = readl(OTP_STATUS);
2983d3688adSJohnny Huang 	} while ((reg & 0x6) != 0x6);
2993d3688adSJohnny Huang }
3003d3688adSJohnny Huang 
301a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
302dacbba92SJohnny Huang {
303dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
304dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
305dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
306dacbba92SJohnny Huang 	wait_complete();
307dacbba92SJohnny Huang }
308dacbba92SJohnny Huang 
309dacbba92SJohnny Huang static void otp_soak(int soak)
310dacbba92SJohnny Huang {
311*e417205bSJohnny Huang 	if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
312dacbba92SJohnny Huang 		switch (soak) {
313dacbba92SJohnny Huang 		case 0: //default
314dacbba92SJohnny Huang 			otp_write(0x3000, 0x0210); // Write MRA
315dacbba92SJohnny Huang 			otp_write(0x5000, 0x2000); // Write MRB
316dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
317dacbba92SJohnny Huang 			break;
318dacbba92SJohnny Huang 		case 1: //normal program
319dacbba92SJohnny Huang 			otp_write(0x3000, 0x1200); // Write MRA
320feea3fdfSJohnny Huang 			otp_write(0x5000, 0x107F); // Write MRB
321dacbba92SJohnny Huang 			otp_write(0x1000, 0x1024); // Write MR
322feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
323dacbba92SJohnny Huang 			break;
324dacbba92SJohnny Huang 		case 2: //soak program
325dacbba92SJohnny Huang 			otp_write(0x3000, 0x1220); // Write MRA
326feea3fdfSJohnny Huang 			otp_write(0x5000, 0x2074); // Write MRB
327dacbba92SJohnny Huang 			otp_write(0x1000, 0x08a4); // Write MR
328feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
329dacbba92SJohnny Huang 			break;
330dacbba92SJohnny Huang 		}
331dacbba92SJohnny Huang 	} else {
332dacbba92SJohnny Huang 		switch (soak) {
333dacbba92SJohnny Huang 		case 0: //default
334dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
335dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
336dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
337dacbba92SJohnny Huang 			break;
338dacbba92SJohnny Huang 		case 1: //normal program
339dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
340dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
341dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
342feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
343dacbba92SJohnny Huang 			break;
344dacbba92SJohnny Huang 		case 2: //soak program
345dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
346dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
347dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
348feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
349dacbba92SJohnny Huang 			break;
350dacbba92SJohnny Huang 		}
351dacbba92SJohnny Huang 	}
352dacbba92SJohnny Huang 
353dacbba92SJohnny Huang 	wait_complete();
354dacbba92SJohnny Huang }
355dacbba92SJohnny Huang 
356a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
35769d5fd8fSJohnny Huang {
3583d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
3593d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3603d3688adSJohnny Huang 	wait_complete();
3613d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
3623d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
36369d5fd8fSJohnny Huang }
36469d5fd8fSJohnny Huang 
365a219f6deSJohnny Huang static void otp_read_config(u32 offset, u32 *data)
36669d5fd8fSJohnny Huang {
36769d5fd8fSJohnny Huang 	int config_offset;
36869d5fd8fSJohnny Huang 
36969d5fd8fSJohnny Huang 	config_offset = 0x800;
37069d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
37169d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
37269d5fd8fSJohnny Huang 
3733d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
3743d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3753d3688adSJohnny Huang 	wait_complete();
3763d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
37769d5fd8fSJohnny Huang }
37869d5fd8fSJohnny Huang 
379a219f6deSJohnny Huang static int otp_print_config(u32 offset, int dw_count)
38069d5fd8fSJohnny Huang {
38169d5fd8fSJohnny Huang 	int i;
382a219f6deSJohnny Huang 	u32 ret[1];
38369d5fd8fSJohnny Huang 
38469d5fd8fSJohnny Huang 	if (offset + dw_count > 32)
3852a856b9aSJohnny Huang 		return OTP_USAGE;
386dacbba92SJohnny Huang 	otp_soak(0);
38769d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
38869d5fd8fSJohnny Huang 		otp_read_config(i, ret);
389a6af4a17SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
39069d5fd8fSJohnny Huang 	}
39169d5fd8fSJohnny Huang 	printf("\n");
3922a856b9aSJohnny Huang 	return OTP_SUCCESS;
39369d5fd8fSJohnny Huang }
39469d5fd8fSJohnny Huang 
395a219f6deSJohnny Huang static int otp_print_data(u32 offset, int dw_count)
39669d5fd8fSJohnny Huang {
39769d5fd8fSJohnny Huang 	int i;
398a219f6deSJohnny Huang 	u32 ret[2];
39969d5fd8fSJohnny Huang 
40069d5fd8fSJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
4012a856b9aSJohnny Huang 		return OTP_USAGE;
402dacbba92SJohnny Huang 	otp_soak(0);
40369d5fd8fSJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
40469d5fd8fSJohnny Huang 		otp_read_data(i, ret);
40569d5fd8fSJohnny Huang 		if (i % 4 == 0)
40669d5fd8fSJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
40769d5fd8fSJohnny Huang 		else
40869d5fd8fSJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
40969d5fd8fSJohnny Huang 	}
41069d5fd8fSJohnny Huang 	printf("\n");
4112a856b9aSJohnny Huang 	return OTP_SUCCESS;
41269d5fd8fSJohnny Huang }
41369d5fd8fSJohnny Huang 
414a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
41569d5fd8fSJohnny Huang {
416a219f6deSJohnny Huang 	u32 ret;
417a219f6deSJohnny Huang 	u32 *buf;
41869d5fd8fSJohnny Huang 
41969d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
42069d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
42169d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
42269d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
42369d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
4243d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
4253d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
4263d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
4273d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
4283d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
4293d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
4303d3688adSJohnny Huang 	wait_complete();
4313d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
43269d5fd8fSJohnny Huang 	if (ret & 0x1)
43369d5fd8fSJohnny Huang 		return 0;
43469d5fd8fSJohnny Huang 	else
43569d5fd8fSJohnny Huang 		return -1;
43669d5fd8fSJohnny Huang }
43769d5fd8fSJohnny Huang 
438a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
43969d5fd8fSJohnny Huang {
440a219f6deSJohnny Huang 	u32 ret[2];
44169d5fd8fSJohnny Huang 
44230a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4433d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
44430a8c590SJohnny Huang 	else
4453d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
44630a8c590SJohnny Huang 
4473d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4483d3688adSJohnny Huang 	wait_complete();
4493d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4503d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
45183655e91SJohnny Huang 
45230a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
45330a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
45469d5fd8fSJohnny Huang 			return 0;
45569d5fd8fSJohnny Huang 		else
45669d5fd8fSJohnny Huang 			return -1;
45730a8c590SJohnny Huang 	} else {
45830a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
45930a8c590SJohnny Huang 			return 0;
46030a8c590SJohnny Huang 		else
46130a8c590SJohnny Huang 			return -1;
46230a8c590SJohnny Huang 	}
46369d5fd8fSJohnny Huang }
46469d5fd8fSJohnny Huang 
465a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4664c1c9b35SJohnny Huang {
467a219f6deSJohnny Huang 	u32 ret[2];
4684c1c9b35SJohnny Huang 
4694c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4704c1c9b35SJohnny Huang 
4714c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4723d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
4734c1c9b35SJohnny Huang 	else
4743d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
4753d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4763d3688adSJohnny Huang 	wait_complete();
4773d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4783d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4794c1c9b35SJohnny Huang 	if (size == 1) {
4804c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4814c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
482696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4834c1c9b35SJohnny Huang 				compare[0] = 0;
4844c1c9b35SJohnny Huang 				return 0;
485a219f6deSJohnny Huang 			}
4864c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
4874c1c9b35SJohnny Huang 			return -1;
4884c1c9b35SJohnny Huang 
4894c1c9b35SJohnny Huang 		} else {
4904c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
491696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4924c1c9b35SJohnny Huang 				compare[0] = ~0;
4934c1c9b35SJohnny Huang 				return 0;
494a219f6deSJohnny Huang 			}
495d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
4964c1c9b35SJohnny Huang 			return -1;
4974c1c9b35SJohnny Huang 		}
4984c1c9b35SJohnny Huang 	} else if (size == 2) {
4994c1c9b35SJohnny Huang 		// otp_addr should be even
500696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
5014c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
5024c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
5034c1c9b35SJohnny Huang 			compare[0] = 0;
5044c1c9b35SJohnny Huang 			compare[1] = ~0;
5054c1c9b35SJohnny Huang 			return 0;
506a219f6deSJohnny Huang 		}
5074c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
5084c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
5094c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
5104c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
5114c1c9b35SJohnny Huang 		return -1;
5124c1c9b35SJohnny Huang 	} else {
5134c1c9b35SJohnny Huang 		return -1;
5144c1c9b35SJohnny Huang 	}
5154c1c9b35SJohnny Huang }
5164c1c9b35SJohnny Huang 
517a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit)
51883655e91SJohnny Huang {
51990965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
52083655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
52183655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
52283655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
52383655e91SJohnny Huang 	wait_complete();
52483655e91SJohnny Huang }
52583655e91SJohnny Huang 
526a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
52783655e91SJohnny Huang {
52883655e91SJohnny Huang 	int prog_bit;
52983655e91SJohnny Huang 
53083655e91SJohnny Huang 	if (prog_address % 2 == 0) {
53183655e91SJohnny Huang 		if (value)
53283655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
53383655e91SJohnny Huang 		else
53483655e91SJohnny Huang 			return;
53583655e91SJohnny Huang 	} else {
536*e417205bSJohnny Huang 		if (info_cb.version != OTP_A3)
53783655e91SJohnny Huang 			prog_address |= 1 << 15;
53883655e91SJohnny Huang 		if (!value)
53983655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
54083655e91SJohnny Huang 		else
54183655e91SJohnny Huang 			return;
54283655e91SJohnny Huang 	}
54383655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
54483655e91SJohnny Huang }
54583655e91SJohnny Huang 
546a219f6deSJohnny Huang static int otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
54783655e91SJohnny Huang {
54883655e91SJohnny Huang 	int pass;
54983655e91SJohnny Huang 	int i;
55083655e91SJohnny Huang 
55183655e91SJohnny Huang 	otp_soak(1);
55283655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
55383655e91SJohnny Huang 	pass = 0;
55483655e91SJohnny Huang 
55583655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
55683655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
55783655e91SJohnny Huang 			otp_soak(2);
55883655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
55983655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
56083655e91SJohnny Huang 				otp_soak(1);
56183655e91SJohnny Huang 			} else {
56283655e91SJohnny Huang 				pass = 1;
56383655e91SJohnny Huang 				break;
56483655e91SJohnny Huang 			}
56583655e91SJohnny Huang 		} else {
56683655e91SJohnny Huang 			pass = 1;
56783655e91SJohnny Huang 			break;
56883655e91SJohnny Huang 		}
56983655e91SJohnny Huang 	}
570794e27ecSJohnny Huang 	if (pass)
571794e27ecSJohnny Huang 		return OTP_SUCCESS;
57283655e91SJohnny Huang 
573794e27ecSJohnny Huang 	return OTP_FAILURE;
57483655e91SJohnny Huang }
57583655e91SJohnny Huang 
576a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
577d90825e2SJohnny Huang {
578d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
579d90825e2SJohnny Huang 
580d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
581696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
582d90825e2SJohnny Huang 			continue;
583d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
584d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
585d90825e2SJohnny Huang 			if (bit_value)
586d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
587d90825e2SJohnny Huang 			else
588d90825e2SJohnny Huang 				continue;
589d90825e2SJohnny Huang 		} else {
590*e417205bSJohnny Huang 			if (info_cb.version != OTP_A3)
591d90825e2SJohnny Huang 				prog_address |= 1 << 15;
592d90825e2SJohnny Huang 			if (bit_value)
593d90825e2SJohnny Huang 				continue;
594d90825e2SJohnny Huang 			else
595d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
596d90825e2SJohnny Huang 		}
597d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
598d90825e2SJohnny Huang 	}
599d90825e2SJohnny Huang }
600d90825e2SJohnny Huang 
601a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
60254552c69SJohnny Huang {
60354552c69SJohnny Huang 	int pass;
60454552c69SJohnny Huang 	int i;
605a219f6deSJohnny Huang 	u32 data0_masked;
606a219f6deSJohnny Huang 	u32 data1_masked;
607a219f6deSJohnny Huang 	u32 buf0_masked;
608a219f6deSJohnny Huang 	u32 buf1_masked;
609a219f6deSJohnny Huang 	u32 compare[2];
61054552c69SJohnny Huang 
61154552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
61254552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
61354552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
61454552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
615a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
61654552c69SJohnny Huang 		return 0;
61754552c69SJohnny Huang 
61854552c69SJohnny Huang 	otp_soak(1);
61954552c69SJohnny Huang 	if (data0_masked != buf0_masked)
62054552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
62154552c69SJohnny Huang 	if (data1_masked != buf1_masked)
62254552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
62354552c69SJohnny Huang 
62454552c69SJohnny Huang 	pass = 0;
62554552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
62654552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
62754552c69SJohnny Huang 			otp_soak(2);
628a219f6deSJohnny Huang 			if (compare[0] != 0)
62954552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
630a219f6deSJohnny Huang 			if (compare[1] != ~0)
6315537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
63254552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
63354552c69SJohnny Huang 				otp_soak(1);
63454552c69SJohnny Huang 			} else {
63554552c69SJohnny Huang 				pass = 1;
63654552c69SJohnny Huang 				break;
63754552c69SJohnny Huang 			}
63854552c69SJohnny Huang 		} else {
63954552c69SJohnny Huang 			pass = 1;
64054552c69SJohnny Huang 			break;
64154552c69SJohnny Huang 		}
64254552c69SJohnny Huang 	}
64354552c69SJohnny Huang 
64454552c69SJohnny Huang 	if (!pass) {
64554552c69SJohnny Huang 		otp_soak(0);
64654552c69SJohnny Huang 		return OTP_FAILURE;
64754552c69SJohnny Huang 	}
64854552c69SJohnny Huang 	return OTP_SUCCESS;
64954552c69SJohnny Huang }
65054552c69SJohnny Huang 
651541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
65276d13988SJohnny Huang {
653a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
6545010032bSJohnny Huang 	int strap_end;
65576d13988SJohnny Huang 	int i, j;
65676d13988SJohnny Huang 
657*e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
65876d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
65976d13988SJohnny Huang 			otpstrap[j].value = 0;
66076d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
66176d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
66276d13988SJohnny Huang 			otpstrap[j].protected = 0;
66376d13988SJohnny Huang 		}
6645010032bSJohnny Huang 		strap_end = 30;
6655010032bSJohnny Huang 	} else {
6665010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
6675010032bSJohnny Huang 			otpstrap[j].value = 0;
6685010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
6695010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
6705010032bSJohnny Huang 			otpstrap[j].reg_protected = 0;
6715010032bSJohnny Huang 			otpstrap[j].protected = 0;
6725010032bSJohnny Huang 		}
6735010032bSJohnny Huang 		strap_end = 28;
6745010032bSJohnny Huang 	}
67576d13988SJohnny Huang 
676dacbba92SJohnny Huang 	otp_soak(0);
6775010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
67876d13988SJohnny Huang 		int option = (i - 16) / 2;
679a219f6deSJohnny Huang 
68076d13988SJohnny Huang 		otp_read_config(i, &OTPSTRAP_RAW[0]);
68176d13988SJohnny Huang 		otp_read_config(i + 1, &OTPSTRAP_RAW[1]);
68276d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
68376d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
684a219f6deSJohnny Huang 
685a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
68676d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
68776d13988SJohnny Huang 			if (bit_value == 1)
68876d13988SJohnny Huang 				otpstrap[j].remain_times--;
68976d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
69076d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
69176d13988SJohnny Huang 		}
69276d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
69376d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
694a219f6deSJohnny Huang 
695a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
69676d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
69776d13988SJohnny Huang 			if (bit_value == 1)
69876d13988SJohnny Huang 				otpstrap[j].remain_times--;
69976d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
70076d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
70176d13988SJohnny Huang 		}
70276d13988SJohnny Huang 	}
7035010032bSJohnny Huang 
704*e417205bSJohnny Huang 	if (info_cb.version != OTP_A0) {
7055010032bSJohnny Huang 		otp_read_config(28, &OTPSTRAP_RAW[0]);
7065010032bSJohnny Huang 		otp_read_config(29, &OTPSTRAP_RAW[1]);
7075010032bSJohnny Huang 		for (j = 0; j < 32; j++) {
7085010032bSJohnny Huang 			if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
7095010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
7105010032bSJohnny Huang 		}
7115010032bSJohnny Huang 		for (j = 32; j < 64; j++) {
7125010032bSJohnny Huang 			if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
7135010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
7145010032bSJohnny Huang 		}
7155010032bSJohnny Huang 	}
7165010032bSJohnny Huang 
71776d13988SJohnny Huang 	otp_read_config(30, &OTPSTRAP_RAW[0]);
71876d13988SJohnny Huang 	otp_read_config(31, &OTPSTRAP_RAW[1]);
71976d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
72076d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
72176d13988SJohnny Huang 			otpstrap[j].protected = 1;
72276d13988SJohnny Huang 	}
72376d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
72476d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
72576d13988SJohnny Huang 			otpstrap[j].protected = 1;
72676d13988SJohnny Huang 	}
72776d13988SJohnny Huang }
72876d13988SJohnny Huang 
729794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
730794e27ecSJohnny Huang {
731794e27ecSJohnny Huang 	int bit_offset;
732794e27ecSJohnny Huang 	int i, j;
733794e27ecSJohnny Huang 
734794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
735794e27ecSJohnny Huang 	printf("___________________________________________________\n");
736794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
737794e27ecSJohnny Huang 		if (i < 32) {
738794e27ecSJohnny Huang 			j = 0;
739794e27ecSJohnny Huang 			bit_offset = i;
740794e27ecSJohnny Huang 		} else {
741794e27ecSJohnny Huang 			j = 1;
742794e27ecSJohnny Huang 			bit_offset = i - 32;
743794e27ecSJohnny Huang 		}
744794e27ecSJohnny Huang 		if (i % 16 == 0)
745794e27ecSJohnny Huang 			printf("%2x | ", i);
746794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
747794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
748794e27ecSJohnny Huang 			printf("\n");
749794e27ecSJohnny Huang 	}
750794e27ecSJohnny Huang }
751794e27ecSJohnny Huang 
752696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
75369d5fd8fSJohnny Huang {
75479e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
755a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
756a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
757a219f6deSJohnny Huang 	u32 mask;
758a219f6deSJohnny Huang 	u32 dw_offset;
759a219f6deSJohnny Huang 	u32 bit_offset;
760a219f6deSJohnny Huang 	u32 otp_value;
761a219f6deSJohnny Huang 	u32 otp_ignore;
762b458cd62SJohnny Huang 	int fail = 0;
763794e27ecSJohnny Huang 	int rid_num = 0;
76473f11549SJohnny Huang 	char valid_bit[20];
765794e27ecSJohnny Huang 	int fz;
76666f2f8e5SJohnny Huang 	int i;
76773f11549SJohnny Huang 	int j;
76866f2f8e5SJohnny Huang 
769737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
77066f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
7713cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
7723cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
7733cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
7743cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
775b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
776696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
777b458cd62SJohnny Huang 
778a219f6deSJohnny Huang 		if (otp_ignore == mask)
779b458cd62SJohnny Huang 			continue;
780a219f6deSJohnny Huang 		else if (otp_ignore != 0)
781b458cd62SJohnny Huang 			fail = 1;
782b458cd62SJohnny Huang 
783a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
7843cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
7853cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
7863cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
787b458cd62SJohnny Huang 			continue;
788b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
789b458cd62SJohnny Huang 
7903cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
7913cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
79266f2f8e5SJohnny Huang 		} else {
793b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
7943cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
7953cb28812SJohnny Huang 			       conf_info[i].bit_offset);
79666f2f8e5SJohnny Huang 		}
797b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
798b458cd62SJohnny Huang 
799b458cd62SJohnny Huang 		if (fail) {
800696656c6SJohnny Huang 			printf("Ignore mask error\n");
801a219f6deSJohnny Huang 			continue;
802a219f6deSJohnny Huang 		}
8033cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
804b458cd62SJohnny Huang 			printf("Reserved\n");
8053cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
8063cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
807b458cd62SJohnny Huang 			printf("\n");
8083cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
809b458cd62SJohnny Huang 			if (otp_value != 0) {
81073f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
811a219f6deSJohnny Huang 					if (otp_value == (1 << j))
81273f11549SJohnny Huang 						valid_bit[j * 2] = '1';
813a219f6deSJohnny Huang 					else
81473f11549SJohnny Huang 						valid_bit[j * 2] = '0';
81573f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
81673f11549SJohnny Huang 				}
81773f11549SJohnny Huang 				valid_bit[15] = 0;
81873f11549SJohnny Huang 			} else {
81973f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
820b458cd62SJohnny Huang 			}
8213cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
822b458cd62SJohnny Huang 			printf("\n");
823b458cd62SJohnny Huang 		} else {
8243cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
825b458cd62SJohnny Huang 		}
826b458cd62SJohnny Huang 	}
827b458cd62SJohnny Huang 
828794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
829794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
830794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
831794e27ecSJohnny Huang 			fail = 1;
832794e27ecSJohnny Huang 		} else {
833794e27ecSJohnny Huang 			fz = 0;
834794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
835794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
836794e27ecSJohnny Huang 					if (!fz)
837794e27ecSJohnny Huang 						fz = 1;
838794e27ecSJohnny Huang 				} else {
839794e27ecSJohnny Huang 					rid_num++;
840794e27ecSJohnny Huang 					if (fz) {
841794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
842794e27ecSJohnny Huang 						fail = 1;
843794e27ecSJohnny Huang 						break;
844794e27ecSJohnny Huang 					}
845794e27ecSJohnny Huang 				}
846794e27ecSJohnny Huang 			}
847794e27ecSJohnny Huang 		}
848794e27ecSJohnny Huang 		if (fail)
849794e27ecSJohnny Huang 			printf("OTP revision ID\n");
850794e27ecSJohnny Huang 		else
851794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
852794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
853794e27ecSJohnny Huang 	}
854794e27ecSJohnny Huang 
855b458cd62SJohnny Huang 	if (fail)
856b458cd62SJohnny Huang 		return OTP_FAILURE;
857b458cd62SJohnny Huang 
85866f2f8e5SJohnny Huang 	return OTP_SUCCESS;
85966f2f8e5SJohnny Huang }
86066f2f8e5SJohnny Huang 
8612d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
86266f2f8e5SJohnny Huang {
86379e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
864a219f6deSJohnny Huang 	u32 OTPCFG[16];
865a219f6deSJohnny Huang 	u32 mask;
866a219f6deSJohnny Huang 	u32 dw_offset;
867a219f6deSJohnny Huang 	u32 bit_offset;
868a219f6deSJohnny Huang 	u32 otp_value;
86973f11549SJohnny Huang 	char valid_bit[20];
87066f2f8e5SJohnny Huang 	int i;
87173f11549SJohnny Huang 	int j;
87266f2f8e5SJohnny Huang 
873dacbba92SJohnny Huang 	otp_soak(0);
874bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
87566f2f8e5SJohnny Huang 		otp_read_config(i, &OTPCFG[i]);
87666f2f8e5SJohnny Huang 
877b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
878b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
8793cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
8803cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
8812d4b0742SJohnny Huang 			continue;
8823cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
8833cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
8843cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
885b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
886b458cd62SJohnny Huang 
887a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
8883cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
8893cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
8903cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
891b458cd62SJohnny Huang 			continue;
892b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
893b458cd62SJohnny Huang 
8943cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
8953cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
896b458cd62SJohnny Huang 		} else {
897b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
8983cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
8993cb28812SJohnny Huang 			       conf_info[i].bit_offset);
900b458cd62SJohnny Huang 		}
901b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
902b458cd62SJohnny Huang 
9033cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
904b458cd62SJohnny Huang 			printf("Reserved\n");
9053cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
9063cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
907b458cd62SJohnny Huang 			printf("\n");
9083cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
909b458cd62SJohnny Huang 			if (otp_value != 0) {
91073f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
911a219f6deSJohnny Huang 					if (otp_value == (1 << j))
91273f11549SJohnny Huang 						valid_bit[j * 2] = '1';
913a219f6deSJohnny Huang 					else
91473f11549SJohnny Huang 						valid_bit[j * 2] = '0';
91573f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
91673f11549SJohnny Huang 				}
91773f11549SJohnny Huang 				valid_bit[15] = 0;
91873f11549SJohnny Huang 			} else {
91973f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
920b458cd62SJohnny Huang 			}
9213cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
922b458cd62SJohnny Huang 			printf("\n");
923b458cd62SJohnny Huang 		} else {
9243cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
925b458cd62SJohnny Huang 		}
926b458cd62SJohnny Huang 	}
927b458cd62SJohnny Huang 	return OTP_SUCCESS;
92866f2f8e5SJohnny Huang }
92966f2f8e5SJohnny Huang 
9305010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
93176d13988SJohnny Huang {
93279e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
933a219f6deSJohnny Huang 	u32 *OTPSTRAP;
934a219f6deSJohnny Huang 	u32 *OTPSTRAP_REG_PRO;
935a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
936a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
93776d13988SJohnny Huang 	int i;
938a8bd6d8cSJohnny Huang 	int fail = 0;
939a219f6deSJohnny Huang 	u32 bit_offset;
940a219f6deSJohnny Huang 	u32 dw_offset;
941a219f6deSJohnny Huang 	u32 mask;
942a219f6deSJohnny Huang 	u32 otp_value;
943a219f6deSJohnny Huang 	u32 otp_reg_protect;
944a219f6deSJohnny Huang 	u32 otp_protect;
945a219f6deSJohnny Huang 	u32 otp_ignore;
94676d13988SJohnny Huang 
947a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
948a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
949a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
950*e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
951696656c6SJohnny Huang 		OTPSTRAP_REG_PRO = NULL;
952a8bd6d8cSJohnny Huang 		printf("BIT(hex)   Value       Protect     Description\n");
953696656c6SJohnny Huang 	} else {
954a219f6deSJohnny Huang 		OTPSTRAP_REG_PRO = (u32 *)image_layout->strap_reg_pro;
955de6b0cc4SJohnny Huang 		printf("BIT(hex)   Value       Reg_Protect Protect     Description\n");
956696656c6SJohnny Huang 	}
957de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
958b458cd62SJohnny Huang 
9593cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
960696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
961a8bd6d8cSJohnny Huang 			dw_offset = 1;
9623cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
963a8bd6d8cSJohnny Huang 		} else {
964a8bd6d8cSJohnny Huang 			dw_offset = 0;
9653cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
966a8bd6d8cSJohnny Huang 		}
96776d13988SJohnny Huang 
9683cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
969a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
970a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
971696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
972a8bd6d8cSJohnny Huang 
973*e417205bSJohnny Huang 		if (info_cb.version != OTP_A0)
974696656c6SJohnny Huang 			otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask;
9755010032bSJohnny Huang 		else
9765010032bSJohnny Huang 			otp_reg_protect = 0;
977696656c6SJohnny Huang 
978a219f6deSJohnny Huang 		if (otp_ignore == mask)
979a8bd6d8cSJohnny Huang 			continue;
980a219f6deSJohnny Huang 		else if (otp_ignore != 0)
981a8bd6d8cSJohnny Huang 			fail = 1;
982a8bd6d8cSJohnny Huang 
983a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
9843cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
985a8bd6d8cSJohnny Huang 			continue;
986a8bd6d8cSJohnny Huang 
9873cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
9883cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
989a8bd6d8cSJohnny Huang 		} else {
990b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
9913cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
9923cb28812SJohnny Huang 			       strap_info[i].bit_offset);
993a8bd6d8cSJohnny Huang 		}
994a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
995*e417205bSJohnny Huang 		if (info_cb.version != OTP_A0)
996696656c6SJohnny Huang 			printf("0x%-10x", otp_reg_protect);
997a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
998a8bd6d8cSJohnny Huang 
999a8bd6d8cSJohnny Huang 		if (fail) {
1000696656c6SJohnny Huang 			printf("Ignore mask error\n");
1001a8bd6d8cSJohnny Huang 		} else {
10023cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
10033cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1004a8bd6d8cSJohnny Huang 			else
1005a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1006a8bd6d8cSJohnny Huang 		}
1007a8bd6d8cSJohnny Huang 	}
1008a8bd6d8cSJohnny Huang 
1009a8bd6d8cSJohnny Huang 	if (fail)
101076d13988SJohnny Huang 		return OTP_FAILURE;
101176d13988SJohnny Huang 
101276d13988SJohnny Huang 	return OTP_SUCCESS;
101376d13988SJohnny Huang }
101476d13988SJohnny Huang 
1015b458cd62SJohnny Huang static int otp_print_strap_info(int view)
101676d13988SJohnny Huang {
101779e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
101876d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
101907baa4e8SJohnny Huang 	int i, j;
1020b458cd62SJohnny Huang 	int fail = 0;
1021a219f6deSJohnny Huang 	u32 bit_offset;
1022a219f6deSJohnny Huang 	u32 length;
1023a219f6deSJohnny Huang 	u32 otp_value;
1024a219f6deSJohnny Huang 	u32 otp_protect;
102576d13988SJohnny Huang 
1026541eb887SJohnny Huang 	otp_strap_status(strap_status);
102776d13988SJohnny Huang 
1028b458cd62SJohnny Huang 	if (view) {
1029*e417205bSJohnny Huang 		if (info_cb.version == OTP_A0)
103007baa4e8SJohnny Huang 			printf("BIT(hex) Value  Remains  Protect   Description\n");
103183655e91SJohnny Huang 		else
103283655e91SJohnny Huang 			printf("BIT(hex) Value  Remains  Reg_Protect Protect   Description\n");
103307baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1034b458cd62SJohnny Huang 	} else {
1035b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1036b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
103776d13988SJohnny Huang 	}
10383cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1039b458cd62SJohnny Huang 		otp_value = 0;
10403cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
10413cb28812SJohnny Huang 		length = strap_info[i].length;
1042b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1043c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1044c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1045b458cd62SJohnny Huang 		}
1046a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
10473cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1048b458cd62SJohnny Huang 			continue;
1049b458cd62SJohnny Huang 		if (view) {
1050b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
10513cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1052b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
105307baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1054*e417205bSJohnny Huang 				if (info_cb.version != OTP_A0)
1055e1a7245eSJohnny Huang 					printf("0x%-10X", strap_status[bit_offset + j].reg_protected);
1056e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
10573cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1058b458cd62SJohnny Huang 					printf(" Reserved\n");
1059b458cd62SJohnny Huang 					continue;
1060b458cd62SJohnny Huang 				}
1061b458cd62SJohnny Huang 				if (length == 1) {
10623cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1063b458cd62SJohnny Huang 					continue;
106476d13988SJohnny Huang 				}
106576d13988SJohnny Huang 
1066b458cd62SJohnny Huang 				if (j == 0)
10673cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1068b458cd62SJohnny Huang 				else if (j == length - 1)
1069b458cd62SJohnny Huang 					printf("\\ \"\n");
1070b458cd62SJohnny Huang 				else
1071b458cd62SJohnny Huang 					printf("| \"\n");
107276d13988SJohnny Huang 			}
1073b458cd62SJohnny Huang 		} else {
1074c947ef08SJohnny Huang 			if (length == 1) {
10753cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1076b458cd62SJohnny Huang 			} else {
1077b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1078b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1079b458cd62SJohnny Huang 			}
1080b458cd62SJohnny Huang 
1081b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1082b458cd62SJohnny Huang 
10833cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
10843cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1085b458cd62SJohnny Huang 			else
1086b458cd62SJohnny Huang 				printf("Reserved\n");
1087b458cd62SJohnny Huang 		}
1088b458cd62SJohnny Huang 	}
1089b458cd62SJohnny Huang 
1090b458cd62SJohnny Huang 	if (fail)
1091b458cd62SJohnny Huang 		return OTP_FAILURE;
1092b458cd62SJohnny Huang 
1093b458cd62SJohnny Huang 	return OTP_SUCCESS;
1094b458cd62SJohnny Huang }
1095b458cd62SJohnny Huang 
1096696656c6SJohnny Huang static int otp_print_data_info(struct otp_image_layout *image_layout)
109769d5fd8fSJohnny Huang {
109869d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
109979e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
11009a4fe690SJohnny Huang 	struct otpkey_type key_info;
1101a219f6deSJohnny Huang 	u32 *buf;
1102a219f6deSJohnny Huang 	u8 *byte_buf;
11039d998018SJohnny Huang 	char empty = 1;
110469d5fd8fSJohnny Huang 	int i = 0, len = 0;
11059a4fe690SJohnny Huang 	int j;
110654552c69SJohnny Huang 
1107696656c6SJohnny Huang 	byte_buf = image_layout->data;
1108a219f6deSJohnny Huang 	buf = (u32 *)byte_buf;
11099d998018SJohnny Huang 
11109d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
1111a219f6deSJohnny Huang 		if (buf[i] != 0)
11129d998018SJohnny Huang 			empty = 0;
11139d998018SJohnny Huang 	}
11149d998018SJohnny Huang 	if (empty)
11159d998018SJohnny Huang 		return 0;
11169d998018SJohnny Huang 
11179d998018SJohnny Huang 	i = 0;
111869d5fd8fSJohnny Huang 	while (1) {
111969d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
112069d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
112169d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
112269d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
112369d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
112469d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
11259a4fe690SJohnny Huang 
11269a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
11279a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
11289a4fe690SJohnny Huang 				key_info = key_info_array[j];
11299a4fe690SJohnny Huang 				break;
11309a4fe690SJohnny Huang 			}
11319a4fe690SJohnny Huang 		}
11329a4fe690SJohnny Huang 
11337f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
113469d5fd8fSJohnny Huang 		printf("Key Type: ");
11359a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
11369a4fe690SJohnny Huang 
11379a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
113869d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
113969d5fd8fSJohnny Huang 			switch (key_length) {
114069d5fd8fSJohnny Huang 			case 0:
114169d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
114269d5fd8fSJohnny Huang 				break;
114369d5fd8fSJohnny Huang 			case 1:
114469d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
114569d5fd8fSJohnny Huang 				break;
114669d5fd8fSJohnny Huang 			case 2:
114769d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
114869d5fd8fSJohnny Huang 				break;
114969d5fd8fSJohnny Huang 			case 3:
115069d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
115169d5fd8fSJohnny Huang 				break;
115269d5fd8fSJohnny Huang 			}
1153181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1154181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
115569d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
115669d5fd8fSJohnny Huang 			switch (key_length) {
115769d5fd8fSJohnny Huang 			case 0:
115869d5fd8fSJohnny Huang 				printf("RSA1024\n");
115969d5fd8fSJohnny Huang 				len = 0x100;
116069d5fd8fSJohnny Huang 				break;
116169d5fd8fSJohnny Huang 			case 1:
116269d5fd8fSJohnny Huang 				printf("RSA2048\n");
116369d5fd8fSJohnny Huang 				len = 0x200;
116469d5fd8fSJohnny Huang 				break;
116569d5fd8fSJohnny Huang 			case 2:
116669d5fd8fSJohnny Huang 				printf("RSA3072\n");
116769d5fd8fSJohnny Huang 				len = 0x300;
116869d5fd8fSJohnny Huang 				break;
116969d5fd8fSJohnny Huang 			case 3:
117069d5fd8fSJohnny Huang 				printf("RSA4096\n");
117169d5fd8fSJohnny Huang 				len = 0x400;
117269d5fd8fSJohnny Huang 				break;
117369d5fd8fSJohnny Huang 			}
117469d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
117569d5fd8fSJohnny Huang 		}
11769a4fe690SJohnny Huang 		if (key_info.need_id)
117769d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
117869d5fd8fSJohnny Huang 		printf("Key Value:\n");
11799a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
118069d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
11819a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
11829a4fe690SJohnny Huang 			printf("AES Key:\n");
11839a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1184*e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
11859a4fe690SJohnny Huang 				printf("AES IV:\n");
11869a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
11879a4fe690SJohnny Huang 			}
11889a4fe690SJohnny Huang 
11899a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1190*e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
119169d5fd8fSJohnny Huang 				printf("AES Key:\n");
119269d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
119369d5fd8fSJohnny Huang 				printf("AES IV:\n");
119469d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
11955fdde29fSJohnny Huang 			} else {
11969a4fe690SJohnny Huang 				printf("AES Key 1:\n");
11979a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
11989a4fe690SJohnny Huang 				printf("AES Key 2:\n");
11999a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
12009a4fe690SJohnny Huang 			}
1201181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
120269d5fd8fSJohnny Huang 			printf("RSA mod:\n");
120369d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
120469d5fd8fSJohnny Huang 			printf("RSA exp:\n");
120569d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1206181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1207181f72d8SJohnny Huang 			printf("RSA mod:\n");
1208181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1209181f72d8SJohnny Huang 			printf("RSA exp:\n");
1210a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
121169d5fd8fSJohnny Huang 		}
121269d5fd8fSJohnny Huang 		if (last)
121369d5fd8fSJohnny Huang 			break;
121469d5fd8fSJohnny Huang 		i++;
121569d5fd8fSJohnny Huang 	}
121669d5fd8fSJohnny Huang 	return 0;
121769d5fd8fSJohnny Huang }
121869d5fd8fSJohnny Huang 
12195010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout)
122069d5fd8fSJohnny Huang {
1221a6d0d645SJohnny Huang 	int i, k;
1222d90825e2SJohnny Huang 	int pass = 0;
1223a219f6deSJohnny Huang 	u32 prog_address;
1224a219f6deSJohnny Huang 	u32 data[16];
1225a219f6deSJohnny Huang 	u32 compare[2];
1226a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1227a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1228a219f6deSJohnny Huang 	u32 data_masked;
1229a219f6deSJohnny Huang 	u32 buf_masked;
123069d5fd8fSJohnny Huang 
1231a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1232a6d0d645SJohnny Huang 
1233bb34a7bfSJohnny Huang 	for (i = 0; i < 16 ; i++) {
123469d5fd8fSJohnny Huang 		prog_address = 0x800;
1235a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1236a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1237a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1238a6d0d645SJohnny Huang 	}
1239a6d0d645SJohnny Huang 
1240a6d0d645SJohnny Huang 	printf("Check writable...\n");
1241bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
12425010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
12435010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1244d90825e2SJohnny Huang 		if (data_masked == buf_masked)
124569d5fd8fSJohnny Huang 			continue;
1246d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1247a6d0d645SJohnny Huang 			continue;
1248a6d0d645SJohnny Huang 		} else {
1249a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1250a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
12515010032bSJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
12525010032bSJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
12532a856b9aSJohnny Huang 			return OTP_FAILURE;
1254a6d0d645SJohnny Huang 		}
1255a6d0d645SJohnny Huang 	}
1256a6d0d645SJohnny Huang 
1257a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1258d90825e2SJohnny Huang 	otp_soak(0);
1259bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
12605010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
12615010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1262a6d0d645SJohnny Huang 		prog_address = 0x800;
1263a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1264a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1265bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1266bb34a7bfSJohnny Huang 			pass = 1;
1267a6d0d645SJohnny Huang 			continue;
1268bb34a7bfSJohnny Huang 		}
1269de6fbf1cSJohnny Huang 
1270de6fbf1cSJohnny Huang 		otp_soak(1);
12715010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1272a6d0d645SJohnny Huang 
127369d5fd8fSJohnny Huang 		pass = 0;
127469d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
12755010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1276de6fbf1cSJohnny Huang 				otp_soak(2);
1277feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
12785010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1279de6fbf1cSJohnny Huang 					otp_soak(1);
1280de6fbf1cSJohnny Huang 				} else {
1281de6fbf1cSJohnny Huang 					pass = 1;
1282de6fbf1cSJohnny Huang 					break;
1283de6fbf1cSJohnny Huang 				}
1284a6d0d645SJohnny Huang 			} else {
128569d5fd8fSJohnny Huang 				pass = 1;
128669d5fd8fSJohnny Huang 				break;
128769d5fd8fSJohnny Huang 			}
128869d5fd8fSJohnny Huang 		}
1289bb34a7bfSJohnny Huang 		if (pass == 0) {
1290bb34a7bfSJohnny Huang 			printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
12915010032bSJohnny Huang 			       i, data[i], conf[i], conf_ignore[i]);
1292bb34a7bfSJohnny Huang 			break;
1293bb34a7bfSJohnny Huang 		}
1294a6d0d645SJohnny Huang 	}
1295a6d0d645SJohnny Huang 
1296de6fbf1cSJohnny Huang 	otp_soak(0);
129769d5fd8fSJohnny Huang 	if (!pass)
12982a856b9aSJohnny Huang 		return OTP_FAILURE;
1299a6d0d645SJohnny Huang 
13002a856b9aSJohnny Huang 	return OTP_SUCCESS;
130169d5fd8fSJohnny Huang }
130269d5fd8fSJohnny Huang 
1303eda10d61SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit)
1304eda10d61SJohnny Huang {
13059901d43aSJohnny Huang 	int prog_flag = 0;
13069901d43aSJohnny Huang 
13079901d43aSJohnny Huang 	// ignore this bit
13089901d43aSJohnny Huang 	if (ibit == 1)
1309eda10d61SJohnny Huang 		return OTP_SUCCESS;
1310eda10d61SJohnny Huang 	printf("OTPSTRAP[%X]:\n", offset);
13119901d43aSJohnny Huang 
1312eda10d61SJohnny Huang 	if (bit == otpstrap->value) {
13139901d43aSJohnny Huang 		if (!pbit && !rpbit) {
1314eda10d61SJohnny Huang 			printf("    The value is same as before, skip it.\n");
1315eda10d61SJohnny Huang 			return OTP_PROG_SKIP;
1316eda10d61SJohnny Huang 		}
13179901d43aSJohnny Huang 		printf("    The value is same as before.\n");
13189901d43aSJohnny Huang 	} else {
13199901d43aSJohnny Huang 		prog_flag = 1;
13209901d43aSJohnny Huang 	}
13219901d43aSJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
1322eda10d61SJohnny Huang 		printf("    This bit is protected and is not writable\n");
1323eda10d61SJohnny Huang 		return OTP_FAILURE;
1324eda10d61SJohnny Huang 	}
13259901d43aSJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
1326eda10d61SJohnny Huang 		printf("    This bit is no remaining times to write.\n");
1327eda10d61SJohnny Huang 		return OTP_FAILURE;
1328eda10d61SJohnny Huang 	}
13299901d43aSJohnny Huang 	if (pbit == 1)
1330eda10d61SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
1331*e417205bSJohnny Huang 	if (rpbit == 1 && info_cb.version != OTP_A0)
1332eda10d61SJohnny Huang 		printf("    The relative register will be protected.\n");
13339901d43aSJohnny Huang 	if (prog_flag)
1334eda10d61SJohnny 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);
13359901d43aSJohnny Huang 
1336eda10d61SJohnny Huang 	return OTP_SUCCESS;
1337eda10d61SJohnny Huang }
1338eda10d61SJohnny Huang 
13395010032bSJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
134069d5fd8fSJohnny Huang {
134169d5fd8fSJohnny Huang 	int i;
1342a219f6deSJohnny Huang 	u32 *strap;
1343a219f6deSJohnny Huang 	u32 *strap_ignore;
1344a219f6deSJohnny Huang 	u32 *strap_reg_protect;
1345a219f6deSJohnny Huang 	u32 *strap_pro;
1346eda10d61SJohnny Huang 	int bit, pbit, ibit, rpbit;
134769d5fd8fSJohnny Huang 	int fail = 0;
1348eda10d61SJohnny Huang 	int ret;
134966f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
135069d5fd8fSJohnny Huang 
1351a219f6deSJohnny Huang 	strap = (u32 *)image_layout->strap;
1352a219f6deSJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1353a219f6deSJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1354a219f6deSJohnny Huang 	strap_reg_protect = (u32 *)image_layout->strap_reg_pro;
13555010032bSJohnny Huang 
1356541eb887SJohnny Huang 	otp_strap_status(otpstrap);
135769d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
135869d5fd8fSJohnny Huang 		if (i < 32) {
13595010032bSJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1360eda10d61SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
13615010032bSJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
136269d5fd8fSJohnny Huang 		} else {
13635010032bSJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1364eda10d61SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
13655010032bSJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
13665010032bSJohnny Huang 		}
13675010032bSJohnny Huang 
1368*e417205bSJohnny Huang 		if (info_cb.version != OTP_A0) {
1369a219f6deSJohnny Huang 			if (i < 32)
13705010032bSJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
1371a219f6deSJohnny Huang 			else
13725010032bSJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
13735010032bSJohnny Huang 		} else {
13745010032bSJohnny Huang 			rpbit = 0;
137569d5fd8fSJohnny Huang 		}
1376eda10d61SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit);
1377eda10d61SJohnny Huang 
1378eda10d61SJohnny Huang 		if (ret == OTP_FAILURE)
137969d5fd8fSJohnny Huang 			fail = 1;
138069d5fd8fSJohnny Huang 	}
138169d5fd8fSJohnny Huang 	if (fail == 1)
1382a6af4a17SJohnny Huang 		return OTP_FAILURE;
13839901d43aSJohnny Huang 	else
1384eda10d61SJohnny Huang 		return OTP_SUCCESS;
138569d5fd8fSJohnny Huang }
138669d5fd8fSJohnny Huang 
13872a856b9aSJohnny Huang static int otp_print_strap(int start, int count)
138869d5fd8fSJohnny Huang {
138969d5fd8fSJohnny Huang 	int i, j;
1390de6b0cc4SJohnny Huang 	int remains;
139166f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
139269d5fd8fSJohnny Huang 
13932a856b9aSJohnny Huang 	if (start < 0 || start > 64)
13942a856b9aSJohnny Huang 		return OTP_USAGE;
13952a856b9aSJohnny Huang 
13962a856b9aSJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
13972a856b9aSJohnny Huang 		return OTP_USAGE;
13982a856b9aSJohnny Huang 
1399541eb887SJohnny Huang 	otp_strap_status(otpstrap);
140069d5fd8fSJohnny Huang 
1401*e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
1402de6b0cc4SJohnny Huang 		remains = 7;
140307baa4e8SJohnny Huang 		printf("BIT(hex)  Value  Option           Status\n");
1404de6b0cc4SJohnny Huang 	} else {
1405de6b0cc4SJohnny Huang 		remains = 6;
1406de6b0cc4SJohnny Huang 		printf("BIT(hex)  Value  Option         Reg_Protect Status\n");
1407de6b0cc4SJohnny Huang 	}
1408de6b0cc4SJohnny Huang 	printf("______________________________________________________________________________\n");
1409737ed20bSJohnny Huang 
1410cd1610b4SJohnny Huang 	for (i = start; i < start + count; i++) {
141107baa4e8SJohnny Huang 		printf("0x%-8X", i);
1412737ed20bSJohnny Huang 		printf("%-7d", otpstrap[i].value);
1413de6b0cc4SJohnny Huang 		for (j = 0; j < remains; j++)
1414737ed20bSJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
1415737ed20bSJohnny Huang 		printf("   ");
1416*e417205bSJohnny Huang 		if (info_cb.version != OTP_A0)
1417de6b0cc4SJohnny Huang 			printf("%d           ", otpstrap[i].reg_protected);
141869d5fd8fSJohnny Huang 		if (otpstrap[i].protected == 1) {
1419737ed20bSJohnny Huang 			printf("protected and not writable");
142069d5fd8fSJohnny Huang 		} else {
1421737ed20bSJohnny Huang 			printf("not protected ");
1422a219f6deSJohnny Huang 			if (otpstrap[i].remain_times == 0)
1423737ed20bSJohnny Huang 				printf("and no remaining times to write.");
1424a219f6deSJohnny Huang 			else
1425737ed20bSJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
142669d5fd8fSJohnny Huang 		}
1427737ed20bSJohnny Huang 		printf("\n");
142869d5fd8fSJohnny Huang 	}
14292a856b9aSJohnny Huang 
14302a856b9aSJohnny Huang 	return OTP_SUCCESS;
143169d5fd8fSJohnny Huang }
143269d5fd8fSJohnny Huang 
14338848d5dcSJohnny Huang static int otp_prog_strap_bit(int bit_offset, int value)
14348848d5dcSJohnny Huang {
14358848d5dcSJohnny Huang 	struct otpstrap_status otpstrap[64];
1436a219f6deSJohnny Huang 	u32 prog_address;
14378848d5dcSJohnny Huang 	int offset;
14388848d5dcSJohnny Huang 	int ret;
14398848d5dcSJohnny Huang 
14408848d5dcSJohnny Huang 	otp_strap_status(otpstrap);
14418848d5dcSJohnny Huang 
14428848d5dcSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
14438848d5dcSJohnny Huang 
1444a219f6deSJohnny Huang 	if (ret != OTP_SUCCESS)
14458848d5dcSJohnny Huang 		return ret;
14468848d5dcSJohnny Huang 
14478848d5dcSJohnny Huang 	prog_address = 0x800;
14488848d5dcSJohnny Huang 	if (bit_offset < 32) {
14498848d5dcSJohnny Huang 		offset = bit_offset;
14508848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
14518848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
14528848d5dcSJohnny Huang 
14538848d5dcSJohnny Huang 	} else {
14548848d5dcSJohnny Huang 		offset = (bit_offset - 32);
14558848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
14568848d5dcSJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
14578848d5dcSJohnny Huang 	}
14588848d5dcSJohnny Huang 
145983655e91SJohnny Huang 	return otp_prog_bit(1, prog_address, offset);
14608848d5dcSJohnny Huang }
14618848d5dcSJohnny Huang 
14625010032bSJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout)
146369d5fd8fSJohnny Huang {
1464a219f6deSJohnny Huang 	u32 *strap;
1465a219f6deSJohnny Huang 	u32 *strap_ignore;
1466a219f6deSJohnny Huang 	u32 *strap_pro;
1467a219f6deSJohnny Huang 	u32 *strap_reg_protect;
1468a219f6deSJohnny Huang 	u32 prog_address;
146983655e91SJohnny Huang 	int i;
1470eda10d61SJohnny Huang 	int bit, pbit, ibit, offset, rpbit;
147169d5fd8fSJohnny Huang 	int fail = 0;
147283655e91SJohnny Huang 	int ret;
14739901d43aSJohnny Huang 	int prog_flag = 0;
147466f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
147569d5fd8fSJohnny Huang 
1476a219f6deSJohnny Huang 	strap = (u32 *)image_layout->strap;
1477a219f6deSJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1478a219f6deSJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1479a219f6deSJohnny Huang 	strap_reg_protect = (u32 *)image_layout->strap_reg_pro;
14805010032bSJohnny Huang 
14817f795e57SJohnny Huang 	printf("Read OTP Strap Region:\n");
1482541eb887SJohnny Huang 	otp_strap_status(otpstrap);
148369d5fd8fSJohnny Huang 
14847f795e57SJohnny Huang 	printf("Check writable...\n");
14855010032bSJohnny Huang 	if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
14867f795e57SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
14877f795e57SJohnny Huang 		return OTP_FAILURE;
14887f795e57SJohnny Huang 	}
14897e22f42dSJohnny Huang 
149069d5fd8fSJohnny Huang 	for (i = 0; i < 64; i++) {
149169d5fd8fSJohnny Huang 		prog_address = 0x800;
149269d5fd8fSJohnny Huang 		if (i < 32) {
149369d5fd8fSJohnny Huang 			offset = i;
14945010032bSJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1495eda10d61SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
14965010032bSJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
149769d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
149869d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
149969d5fd8fSJohnny Huang 
150069d5fd8fSJohnny Huang 		} else {
150169d5fd8fSJohnny Huang 			offset = (i - 32);
15025010032bSJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1503eda10d61SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
15045010032bSJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
150569d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
150669d5fd8fSJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
150769d5fd8fSJohnny Huang 		}
1508*e417205bSJohnny Huang 		if (info_cb.version != OTP_A0) {
1509a219f6deSJohnny Huang 			if (i < 32)
15105010032bSJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
1511a219f6deSJohnny Huang 			else
15125010032bSJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
15135010032bSJohnny Huang 		} else {
15145010032bSJohnny Huang 			rpbit = 0;
15155010032bSJohnny Huang 		}
151669d5fd8fSJohnny Huang 
1517a219f6deSJohnny Huang 		if (ibit == 1)
151869d5fd8fSJohnny Huang 			continue;
15199901d43aSJohnny Huang 		if (bit == otpstrap[i].value)
15209901d43aSJohnny Huang 			prog_flag = 0;
15219901d43aSJohnny Huang 		else
15229901d43aSJohnny Huang 			prog_flag = 1;
15239901d43aSJohnny Huang 
15249901d43aSJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
152569d5fd8fSJohnny Huang 			fail = 1;
152669d5fd8fSJohnny Huang 			continue;
152769d5fd8fSJohnny Huang 		}
15289901d43aSJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
152969d5fd8fSJohnny Huang 			fail = 1;
153069d5fd8fSJohnny Huang 			continue;
153169d5fd8fSJohnny Huang 		}
15327e22f42dSJohnny Huang 
15339901d43aSJohnny Huang 		if (prog_flag) {
153483655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
1535794e27ecSJohnny Huang 			if (ret)
15362a856b9aSJohnny Huang 				return OTP_FAILURE;
15379901d43aSJohnny Huang 		}
153869d5fd8fSJohnny Huang 
1539*e417205bSJohnny Huang 		if (rpbit == 1 && info_cb.version != OTP_A0) {
154069d5fd8fSJohnny Huang 			prog_address = 0x800;
154169d5fd8fSJohnny Huang 			if (i < 32)
15425010032bSJohnny Huang 				prog_address |= 0x608;
154369d5fd8fSJohnny Huang 			else
15445010032bSJohnny Huang 				prog_address |= 0x60a;
15457e22f42dSJohnny Huang 
154683655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
1547794e27ecSJohnny Huang 			if (ret)
15482a856b9aSJohnny Huang 				return OTP_FAILURE;
15495010032bSJohnny Huang 		}
15505010032bSJohnny Huang 
15515010032bSJohnny Huang 		if (pbit != 0) {
15525010032bSJohnny Huang 			prog_address = 0x800;
15535010032bSJohnny Huang 			if (i < 32)
15545010032bSJohnny Huang 				prog_address |= 0x60c;
15555010032bSJohnny Huang 			else
15565010032bSJohnny Huang 				prog_address |= 0x60e;
15575010032bSJohnny Huang 
155883655e91SJohnny Huang 			ret = otp_prog_bit(1, prog_address, offset);
1559794e27ecSJohnny Huang 			if (ret)
15605010032bSJohnny Huang 				return OTP_FAILURE;
15615010032bSJohnny Huang 		}
156269d5fd8fSJohnny Huang 	}
1563de6fbf1cSJohnny Huang 	otp_soak(0);
156469d5fd8fSJohnny Huang 	if (fail == 1)
15652a856b9aSJohnny Huang 		return OTP_FAILURE;
15662a856b9aSJohnny Huang 	return OTP_SUCCESS;
156769d5fd8fSJohnny Huang }
156869d5fd8fSJohnny Huang 
15695010032bSJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout)
15704c1c9b35SJohnny Huang {
157154552c69SJohnny Huang 	int i;
157254552c69SJohnny Huang 	int ret;
15735010032bSJohnny Huang 	int data_dw;
1574a219f6deSJohnny Huang 	u32 data[2048];
1575a219f6deSJohnny Huang 	u32 *buf;
1576a219f6deSJohnny Huang 	u32 *buf_ignore;
1577a219f6deSJohnny Huang 	u32 data_masked;
1578a219f6deSJohnny Huang 	u32 buf_masked;
15794c1c9b35SJohnny Huang 
1580a219f6deSJohnny Huang 	buf = (u32 *)image_layout->data;
1581a219f6deSJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
15825010032bSJohnny Huang 
15835010032bSJohnny Huang 	data_dw = image_layout->data_length / 4;
15845010032bSJohnny Huang 
15854c1c9b35SJohnny Huang 	printf("Read OTP Data:\n");
15864c1c9b35SJohnny Huang 
1587a219f6deSJohnny Huang 	for (i = 0; i < data_dw - 2 ; i += 2)
1588d90825e2SJohnny Huang 		otp_read_data(i, &data[i]);
1589d90825e2SJohnny Huang 
15904c1c9b35SJohnny Huang 	printf("Check writable...\n");
159154552c69SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
15925010032bSJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1593696656c6SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1594696656c6SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
159554552c69SJohnny Huang 		if (data_masked == buf_masked)
15964c1c9b35SJohnny Huang 			continue;
1597d90825e2SJohnny Huang 		if (i % 2 == 0) {
159854552c69SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
15994c1c9b35SJohnny Huang 				continue;
16004c1c9b35SJohnny Huang 			} else {
16014c1c9b35SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1602d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
16034c1c9b35SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1604696656c6SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
16052a856b9aSJohnny Huang 				return OTP_FAILURE;
160669d5fd8fSJohnny Huang 			}
1607d90825e2SJohnny Huang 		} else {
160854552c69SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1609d90825e2SJohnny Huang 				continue;
1610d90825e2SJohnny Huang 			} else {
1611d90825e2SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1612d90825e2SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1613d90825e2SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1614696656c6SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
16152a856b9aSJohnny Huang 				return OTP_FAILURE;
1616d90825e2SJohnny Huang 			}
1617d90825e2SJohnny Huang 		}
1618d90825e2SJohnny Huang 	}
161969d5fd8fSJohnny Huang 
1620d90825e2SJohnny Huang 	printf("Start Programing...\n");
1621d90825e2SJohnny Huang 
162254552c69SJohnny Huang 	// programing ecc region first
162354552c69SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1624696656c6SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
162554552c69SJohnny Huang 		if (ret != OTP_SUCCESS) {
162654552c69SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1627696656c6SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
162854552c69SJohnny Huang 			return ret;
1629d90825e2SJohnny Huang 		}
1630d90825e2SJohnny Huang 	}
1631d90825e2SJohnny Huang 
163254552c69SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1633696656c6SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
163454552c69SJohnny Huang 		if (ret != OTP_SUCCESS) {
163554552c69SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1636696656c6SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
163754552c69SJohnny Huang 			return ret;
1638d90825e2SJohnny Huang 		}
1639de6fbf1cSJohnny Huang 	}
1640de6fbf1cSJohnny Huang 	otp_soak(0);
16412a856b9aSJohnny Huang 	return OTP_SUCCESS;
1642d90825e2SJohnny Huang }
1643d90825e2SJohnny Huang 
1644a219f6deSJohnny Huang static int otp_image_verify(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))
1654696656c6SJohnny Huang 		return 0;
1655696656c6SJohnny Huang 	return -1;
1656696656c6SJohnny Huang }
1657696656c6SJohnny Huang 
1658de6b0cc4SJohnny Huang static int do_otp_prog(int addr, int nconfirm)
165969d5fd8fSJohnny Huang {
166069d5fd8fSJohnny Huang 	int ret;
16619a4fe690SJohnny Huang 	int image_version = 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) {
167069d5fd8fSJohnny Huang 		puts("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) {
1680696656c6SJohnny Huang 		puts("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) {
1687696656c6SJohnny Huang 		puts("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);
1700696656c6SJohnny Huang 
1701696656c6SJohnny Huang 	if (!strcmp("A0", (char *)otp_header->otp_version)) {
1702*e417205bSJohnny Huang 		image_version = OTP_A0;
17035010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
17045010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
17055010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
1706696656c6SJohnny Huang 	} else if (!strcmp("A1", (char *)otp_header->otp_version)) {
1707*e417205bSJohnny Huang 		image_version = OTP_A1;
17085010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
17095010032bSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
17105010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
17115010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
17125fdde29fSJohnny Huang 	} else if (!strcmp("A2", (char *)otp_header->otp_version)) {
1713*e417205bSJohnny Huang 		image_version = OTP_A2;
17145fdde29fSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
17155fdde29fSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
17165fdde29fSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
17175fdde29fSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
171864b66712SJohnny Huang 	} else if (!strcmp("A3", (char *)otp_header->otp_version)) {
1719*e417205bSJohnny Huang 		image_version = OTP_A3;
172064b66712SJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
172164b66712SJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
172264b66712SJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
172364b66712SJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
1724696656c6SJohnny Huang 	} else {
1725696656c6SJohnny Huang 		puts("Version is not supported\n");
1726696656c6SJohnny Huang 		return OTP_FAILURE;
1727696656c6SJohnny Huang 	}
1728696656c6SJohnny Huang 
17299a4fe690SJohnny Huang 	if (image_version != info_cb.version) {
17309a4fe690SJohnny Huang 		puts("Version is not match\n");
17319a4fe690SJohnny Huang 		return OTP_FAILURE;
17329a4fe690SJohnny Huang 	}
17339a4fe690SJohnny Huang 
1734696656c6SJohnny Huang 	if (otp_image_verify(buf, image_size, checksum)) {
1735696656c6SJohnny Huang 		puts("checksum is invalid\n");
1736696656c6SJohnny Huang 		return OTP_FAILURE;
1737d90825e2SJohnny Huang 	}
17387332532cSJohnny Huang 
173969d5fd8fSJohnny Huang 	if (!nconfirm) {
1740696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
17417f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1742696656c6SJohnny Huang 			if (otp_print_data_info(&image_layout) < 0) {
174369d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
17442a856b9aSJohnny Huang 				return OTP_FAILURE;
174569d5fd8fSJohnny Huang 			}
174669d5fd8fSJohnny Huang 		}
1747696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
17487332532cSJohnny Huang 			printf("\nOTP strap region :\n");
17495010032bSJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
17507332532cSJohnny Huang 				printf("OTP strap error, please check.\n");
17517332532cSJohnny Huang 				return OTP_FAILURE;
17527332532cSJohnny Huang 			}
17537332532cSJohnny Huang 		}
1754696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
17557332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1756696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
17577332532cSJohnny Huang 				printf("OTP config error, please check.\n");
17587332532cSJohnny Huang 				return OTP_FAILURE;
17597332532cSJohnny Huang 			}
17607332532cSJohnny Huang 		}
17617332532cSJohnny Huang 
176269d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
176369d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
176469d5fd8fSJohnny Huang 			printf(" Aborting\n");
17652a856b9aSJohnny Huang 			return OTP_FAILURE;
176669d5fd8fSJohnny Huang 		}
176769d5fd8fSJohnny Huang 	}
17687332532cSJohnny Huang 
17695010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
17705010032bSJohnny Huang 		printf("programing data region ...\n");
17715010032bSJohnny Huang 		ret = otp_prog_data(&image_layout);
17725010032bSJohnny Huang 		if (ret != 0) {
17735010032bSJohnny Huang 			printf("Error\n");
17745010032bSJohnny Huang 			return ret;
17755010032bSJohnny Huang 		}
1776a219f6deSJohnny Huang 		printf("Done\n");
17775010032bSJohnny Huang 	}
17785010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
17795010032bSJohnny Huang 		printf("programing strap region ...\n");
17805010032bSJohnny Huang 		ret = otp_prog_strap(&image_layout);
17815010032bSJohnny Huang 		if (ret != 0) {
17825010032bSJohnny Huang 			printf("Error\n");
17835010032bSJohnny Huang 			return ret;
17845010032bSJohnny Huang 		}
1785a219f6deSJohnny Huang 		printf("Done\n");
17865010032bSJohnny Huang 	}
17875010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
17885010032bSJohnny Huang 		printf("programing configuration region ...\n");
17895010032bSJohnny Huang 		ret = otp_prog_conf(&image_layout);
17905010032bSJohnny Huang 		if (ret != 0) {
17915010032bSJohnny Huang 			printf("Error\n");
17925010032bSJohnny Huang 			return ret;
17935010032bSJohnny Huang 		}
17945010032bSJohnny Huang 		printf("Done\n");
17955010032bSJohnny Huang 	}
1796cd1610b4SJohnny Huang 
17977332532cSJohnny Huang 	return OTP_SUCCESS;
17982a856b9aSJohnny Huang }
17992a856b9aSJohnny Huang 
18002a856b9aSJohnny Huang static int do_otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1801cd1610b4SJohnny Huang {
1802a219f6deSJohnny Huang 	u32 read[2];
1803a219f6deSJohnny Huang 	u32 prog_address = 0;
180466f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1805cd1610b4SJohnny Huang 	int otp_bit;
180683655e91SJohnny Huang 	int ret = 0;
1807cd1610b4SJohnny Huang 
1808dacbba92SJohnny Huang 	otp_soak(0);
1809cd1610b4SJohnny Huang 	switch (mode) {
1810a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1811a6af4a17SJohnny Huang 		otp_read_config(otp_dw_offset, read);
1812cd1610b4SJohnny Huang 		prog_address = 0x800;
1813cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1814cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1815a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1816cd1610b4SJohnny Huang 		if (otp_bit == value) {
1817a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1818cd1610b4SJohnny Huang 			printf("No need to program\n");
18192a856b9aSJohnny Huang 			return OTP_SUCCESS;
1820cd1610b4SJohnny Huang 		}
1821cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1822a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
1823cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
18242a856b9aSJohnny Huang 			return OTP_FAILURE;
1825cd1610b4SJohnny Huang 		}
1826a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1827cd1610b4SJohnny Huang 		break;
1828a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1829cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1830cd1610b4SJohnny Huang 
1831cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1832a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1833a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1834643b9cfdSJohnny Huang 
1835643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
1836643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1837643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be cleaned\n");
1838643b9cfdSJohnny Huang 				return OTP_FAILURE;
1839643b9cfdSJohnny Huang 			}
1840cd1610b4SJohnny Huang 		} else {
1841a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1842a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1843643b9cfdSJohnny Huang 
1844643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
1845643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1846643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be writen\n");
1847643b9cfdSJohnny Huang 				return OTP_FAILURE;
1848643b9cfdSJohnny Huang 			}
1849cd1610b4SJohnny Huang 		}
1850cd1610b4SJohnny Huang 		if (otp_bit == value) {
1851a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1852cd1610b4SJohnny Huang 			printf("No need to program\n");
18532a856b9aSJohnny Huang 			return OTP_SUCCESS;
1854cd1610b4SJohnny Huang 		}
1855643b9cfdSJohnny Huang 
1856a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1857cd1610b4SJohnny Huang 		break;
1858a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
18598848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
18608848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
18618848d5dcSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
18628848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
18638848d5dcSJohnny Huang 			return OTP_FAILURE;
18648848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
18658848d5dcSJohnny Huang 			return OTP_SUCCESS;
1866a6af4a17SJohnny Huang 
1867cd1610b4SJohnny Huang 		break;
1868cd1610b4SJohnny Huang 	}
1869cd1610b4SJohnny Huang 
1870cd1610b4SJohnny Huang 	if (!nconfirm) {
1871cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1872cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1873cd1610b4SJohnny Huang 			printf(" Aborting\n");
18742a856b9aSJohnny Huang 			return OTP_FAILURE;
1875cd1610b4SJohnny Huang 		}
1876cd1610b4SJohnny Huang 	}
1877cd1610b4SJohnny Huang 
1878cd1610b4SJohnny Huang 	switch (mode) {
1879a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
188083655e91SJohnny Huang 		ret =  otp_prog_strap_bit(bit_offset, value);
188183655e91SJohnny Huang 		break;
1882a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1883a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
188483655e91SJohnny Huang 		ret = otp_prog_bit(value, prog_address, bit_offset);
1885de6fbf1cSJohnny Huang 		break;
1886de6fbf1cSJohnny Huang 	}
1887de6fbf1cSJohnny Huang 	otp_soak(0);
188883655e91SJohnny Huang 	if (ret) {
1889794e27ecSJohnny Huang 		printf("OTP cannot be programed\n");
1890794e27ecSJohnny Huang 		printf("FAILURE\n");
1891794e27ecSJohnny Huang 		return OTP_FAILURE;
1892794e27ecSJohnny Huang 	}
1893794e27ecSJohnny Huang 
18949009c25dSJohnny Huang 	printf("SUCCESS\n");
18952a856b9aSJohnny Huang 	return OTP_SUCCESS;
1896a219f6deSJohnny Huang }
1897a219f6deSJohnny Huang 
1898794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
1899794e27ecSJohnny Huang {
1900794e27ecSJohnny Huang 	u32 otp_rid[2];
1901794e27ecSJohnny Huang 	int rid_num = 0;
1902794e27ecSJohnny Huang 	int bit_offset;
1903794e27ecSJohnny Huang 	int dw_offset;
1904794e27ecSJohnny Huang 	int i;
1905794e27ecSJohnny Huang 	int ret;
1906794e27ecSJohnny Huang 
1907794e27ecSJohnny Huang 	otp_read_config(10, &otp_rid[0]);
1908794e27ecSJohnny Huang 	otp_read_config(11, &otp_rid[1]);
1909794e27ecSJohnny Huang 
1910794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1911794e27ecSJohnny Huang 
1912794e27ecSJohnny Huang 	if (rid_num < 0) {
1913794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by this command,\n"
1914794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n");
1915794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
19169009c25dSJohnny Huang 		return OTP_FAILURE;
19179009c25dSJohnny Huang 	}
1918cd1610b4SJohnny Huang 
1919794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
1920794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1921794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
1922794e27ecSJohnny Huang 
1923794e27ecSJohnny Huang 	if (rid_num >= update_num) {
1924794e27ecSJohnny Huang 		printf("OTP rev_id is bigger than 0x%x\n", update_num);
1925794e27ecSJohnny Huang 		printf("Skip\n");
1926794e27ecSJohnny Huang 		return OTP_FAILURE;
1927794e27ecSJohnny Huang 	}
1928794e27ecSJohnny Huang 
1929794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1930794e27ecSJohnny Huang 		if (i < 32) {
1931794e27ecSJohnny Huang 			dw_offset = 0xa;
1932794e27ecSJohnny Huang 			bit_offset = i;
1933794e27ecSJohnny Huang 		} else {
1934794e27ecSJohnny Huang 			dw_offset = 0xb;
1935794e27ecSJohnny Huang 			bit_offset = i - 32;
1936794e27ecSJohnny Huang 		}
1937794e27ecSJohnny Huang 		printf("OTPCFG%X[%d]", dw_offset, bit_offset);
1938794e27ecSJohnny Huang 		if (i + 1 != update_num)
1939794e27ecSJohnny Huang 			printf(", ");
1940794e27ecSJohnny Huang 	}
1941794e27ecSJohnny Huang 
1942794e27ecSJohnny Huang 	printf(" will be programmed\n");
1943794e27ecSJohnny Huang 	if (force == 0) {
1944794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1945794e27ecSJohnny Huang 		if (!confirm_yesno()) {
1946794e27ecSJohnny Huang 			printf(" Aborting\n");
1947794e27ecSJohnny Huang 			return OTP_FAILURE;
1948794e27ecSJohnny Huang 		}
1949794e27ecSJohnny Huang 	}
1950794e27ecSJohnny Huang 
1951794e27ecSJohnny Huang 	ret = 0;
1952794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1953794e27ecSJohnny Huang 		if (i < 32) {
1954794e27ecSJohnny Huang 			dw_offset = 0xa04;
1955794e27ecSJohnny Huang 			bit_offset = i;
1956794e27ecSJohnny Huang 		} else {
1957794e27ecSJohnny Huang 			dw_offset = 0xa06;
1958794e27ecSJohnny Huang 			bit_offset = i - 32;
1959794e27ecSJohnny Huang 		}
1960794e27ecSJohnny Huang 		if (otp_prog_bit(1, dw_offset, bit_offset)) {
1961794e27ecSJohnny Huang 			printf("OTPCFG%X[%d] programming failed\n", dw_offset, bit_offset);
1962794e27ecSJohnny Huang 			ret = OTP_FAILURE;
1963794e27ecSJohnny Huang 			break;
1964794e27ecSJohnny Huang 		}
1965794e27ecSJohnny Huang 	}
1966794e27ecSJohnny Huang 
1967794e27ecSJohnny Huang 	otp_read_config(10, &otp_rid[0]);
1968794e27ecSJohnny Huang 	otp_read_config(11, &otp_rid[1]);
1969794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1970794e27ecSJohnny Huang 	if (rid_num >= 0)
1971794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
1972794e27ecSJohnny Huang 	else
1973794e27ecSJohnny Huang 		printf("OTP revision ID\n");
1974794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1975794e27ecSJohnny Huang 	if (!ret)
1976794e27ecSJohnny Huang 		printf("SUCCESS\n");
1977794e27ecSJohnny Huang 	else
1978794e27ecSJohnny Huang 		printf("FAILED\n");
1979794e27ecSJohnny Huang 	return ret;
1980794e27ecSJohnny Huang }
1981794e27ecSJohnny Huang 
19822a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
198369d5fd8fSJohnny Huang {
1984a219f6deSJohnny Huang 	u32 offset, count;
19852a856b9aSJohnny Huang 	int ret;
198669d5fd8fSJohnny Huang 
19872a856b9aSJohnny Huang 	if (argc == 4) {
19882a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
19892a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
19902a856b9aSJohnny Huang 	} else if (argc == 3) {
19912a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
19922a856b9aSJohnny Huang 		count = 1;
19932a856b9aSJohnny Huang 	} else {
199469d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
199569d5fd8fSJohnny Huang 	}
199669d5fd8fSJohnny Huang 
19972a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
19983d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19992a856b9aSJohnny Huang 		ret = otp_print_config(offset, count);
20002a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
20013d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20022a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
20032a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
20043d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20052a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
20062a856b9aSJohnny Huang 	} else {
20072a856b9aSJohnny Huang 		return CMD_RET_USAGE;
200869d5fd8fSJohnny Huang 	}
200969d5fd8fSJohnny Huang 
20102a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20112a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20122a856b9aSJohnny Huang 	return CMD_RET_USAGE;
20132a856b9aSJohnny Huang }
20142a856b9aSJohnny Huang 
20152a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20162a856b9aSJohnny Huang {
20172a856b9aSJohnny Huang 	phys_addr_t addr;
20182a856b9aSJohnny Huang 	int ret;
20192a856b9aSJohnny Huang 
2020de6b0cc4SJohnny Huang 	if (argc == 3) {
2021ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
20222a856b9aSJohnny Huang 			return CMD_RET_USAGE;
20232a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
20243d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2025de6b0cc4SJohnny Huang 		ret = do_otp_prog(addr, 1);
2026de6b0cc4SJohnny Huang 	} else if (argc == 2) {
20272a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
20283d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2029de6b0cc4SJohnny Huang 		ret = do_otp_prog(addr, 0);
20302a856b9aSJohnny Huang 	} else {
20312a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20322a856b9aSJohnny Huang 	}
20332a856b9aSJohnny Huang 
20342a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20352a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20362a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
20372a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
20382a856b9aSJohnny Huang 	else
20392a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20402a856b9aSJohnny Huang }
20412a856b9aSJohnny Huang 
20422a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20432a856b9aSJohnny Huang {
20442a856b9aSJohnny Huang 	int mode = 0;
20452a856b9aSJohnny Huang 	int nconfirm = 0;
20462a856b9aSJohnny Huang 	int otp_addr = 0;
20472a856b9aSJohnny Huang 	int bit_offset;
20482a856b9aSJohnny Huang 	int value;
20492a856b9aSJohnny Huang 	int ret;
20502a856b9aSJohnny Huang 
20512a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
20522a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20532a856b9aSJohnny Huang 
20542a856b9aSJohnny Huang 	/* Drop the pb cmd */
20552a856b9aSJohnny Huang 	argc--;
20562a856b9aSJohnny Huang 	argv++;
20572a856b9aSJohnny Huang 
20582a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2059a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
20602a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2061a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
20622a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2063a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2064cd1610b4SJohnny Huang 	else
20652a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20662a856b9aSJohnny Huang 
20672a856b9aSJohnny Huang 	/* Drop the region cmd */
20682a856b9aSJohnny Huang 	argc--;
20692a856b9aSJohnny Huang 	argv++;
20702a856b9aSJohnny Huang 
2071ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2072cd1610b4SJohnny Huang 		nconfirm = 1;
20732a856b9aSJohnny Huang 		/* Drop the force option */
20742a856b9aSJohnny Huang 		argc--;
20752a856b9aSJohnny Huang 		argv++;
20762a856b9aSJohnny Huang 	}
2077cd1610b4SJohnny Huang 
2078a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
20792a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
20802a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
20810808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
20822a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2083cd1610b4SJohnny Huang 	} else {
20842a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
20852a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
20862a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
20870808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
20882a856b9aSJohnny Huang 			return CMD_RET_USAGE;
20890808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
209078855207SJohnny Huang 			if (otp_addr >= 0x800)
20910808cc55SJohnny Huang 				return CMD_RET_USAGE;
20920808cc55SJohnny Huang 		} else {
209378855207SJohnny Huang 			if (otp_addr >= 0x20)
20940808cc55SJohnny Huang 				return CMD_RET_USAGE;
20950808cc55SJohnny Huang 		}
2096cd1610b4SJohnny Huang 	}
2097cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
20982a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2099cd1610b4SJohnny Huang 
21003d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
21012a856b9aSJohnny Huang 	ret = do_otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
21022a856b9aSJohnny Huang 
21032a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
21042a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
21052a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
21062a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
21072a856b9aSJohnny Huang 	else
21082a856b9aSJohnny Huang 		return CMD_RET_USAGE;
21092a856b9aSJohnny Huang }
21102a856b9aSJohnny Huang 
21112a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
21122a856b9aSJohnny Huang {
21132a856b9aSJohnny Huang 	phys_addr_t addr;
21142a856b9aSJohnny Huang 	int otp_addr = 0;
21152a856b9aSJohnny Huang 
21162a856b9aSJohnny Huang 	if (argc != 3)
21172a856b9aSJohnny Huang 		return CMD_RET_USAGE;
21182a856b9aSJohnny Huang 
21193d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
21202a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
21212a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
21222a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
212369d5fd8fSJohnny Huang 		printf("Compare pass\n");
21242a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2125a219f6deSJohnny Huang 	}
212669d5fd8fSJohnny Huang 	printf("Compare fail\n");
21272a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
212869d5fd8fSJohnny Huang }
212969d5fd8fSJohnny Huang 
213066f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
213166f2f8e5SJohnny Huang {
2132a8bd6d8cSJohnny Huang 	int view = 0;
21332d4b0742SJohnny Huang 	int input;
2134a8bd6d8cSJohnny Huang 
2135a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
213666f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
213766f2f8e5SJohnny Huang 
21382d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
21393d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
21402d4b0742SJohnny Huang 		if (argc == 3) {
21412d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
21422d4b0742SJohnny Huang 			otp_print_conf_info(input);
21432d4b0742SJohnny Huang 		} else {
21442d4b0742SJohnny Huang 			otp_print_conf_info(-1);
21452d4b0742SJohnny Huang 		}
21462d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
21472d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2148a8bd6d8cSJohnny Huang 			view = 1;
2149a8bd6d8cSJohnny Huang 			/* Drop the view option */
2150a8bd6d8cSJohnny Huang 			argc--;
2151a8bd6d8cSJohnny Huang 			argv++;
2152a8bd6d8cSJohnny Huang 		}
21533d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2154b458cd62SJohnny Huang 		otp_print_strap_info(view);
215566f2f8e5SJohnny Huang 	} else {
215666f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
215766f2f8e5SJohnny Huang 	}
21582d4b0742SJohnny Huang 
215966f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
216066f2f8e5SJohnny Huang }
216166f2f8e5SJohnny Huang 
2162e14b073cSJohnny Huang static int _do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[], int preg)
2163737ed20bSJohnny Huang {
2164737ed20bSJohnny Huang 	int input;
2165737ed20bSJohnny Huang 	int bit_offset;
2166e14b073cSJohnny Huang 	u32 prog_address;
216783655e91SJohnny Huang 	int ret;
2168e14b073cSJohnny Huang 	char info[10];
2169e14b073cSJohnny Huang 
2170e14b073cSJohnny Huang 	if (preg) {
2171e14b073cSJohnny Huang 		sprintf(info, "register ");
2172e14b073cSJohnny Huang 		prog_address = 0xe08;
2173e14b073cSJohnny Huang 	} else {
2174e14b073cSJohnny Huang 		info[0] = 0;
2175e14b073cSJohnny Huang 		prog_address = 0xe0c;
2176e14b073cSJohnny Huang 	}
2177a219f6deSJohnny Huang 
2178737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2179737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2180737ed20bSJohnny Huang 
2181e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2182737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2183737ed20bSJohnny Huang 	} else {
2184737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2185e14b073cSJohnny Huang 		printf("OTPSTRAP[%d] %swill be protected\n", input, info);
2186737ed20bSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2187737ed20bSJohnny Huang 		if (!confirm_yesno()) {
2188737ed20bSJohnny Huang 			printf(" Aborting\n");
2189737ed20bSJohnny Huang 			return CMD_RET_FAILURE;
2190737ed20bSJohnny Huang 		}
2191737ed20bSJohnny Huang 	}
2192737ed20bSJohnny Huang 
2193737ed20bSJohnny Huang 	if (input < 32) {
2194737ed20bSJohnny Huang 		bit_offset = input;
2195737ed20bSJohnny Huang 	} else if (input < 64) {
2196737ed20bSJohnny Huang 		bit_offset = input - 32;
2197e14b073cSJohnny Huang 		prog_address += 2;
2198737ed20bSJohnny Huang 	} else {
2199737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2200737ed20bSJohnny Huang 	}
2201737ed20bSJohnny Huang 
2202e14b073cSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2203e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2204e14b073cSJohnny Huang 		printf("OTPSTRAP[%d] %salready protected\n", input, info);
2205e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2206e14b073cSJohnny Huang 	}
2207de6fbf1cSJohnny Huang 
220883655e91SJohnny Huang 	ret = otp_prog_bit(1, prog_address, bit_offset);
2209de6fbf1cSJohnny Huang 	otp_soak(0);
221083655e91SJohnny Huang 
221183655e91SJohnny Huang 	if (ret) {
2212e14b073cSJohnny Huang 		printf("Protect OTPSTRAP[%d] %sfail\n", input, info);
2213737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2214737ed20bSJohnny Huang 	}
22159a4fe690SJohnny Huang 
2216794e27ecSJohnny Huang 	printf("OTPSTRAP[%d] %sis protected\n", input, info);
2217794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2218794e27ecSJohnny Huang }
2219794e27ecSJohnny Huang 
2220e14b073cSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2221e14b073cSJohnny Huang {
2222e14b073cSJohnny Huang 	return _do_otpprotect(cmdtp, flag, argc, argv, 0);
2223e14b073cSJohnny Huang }
2224e14b073cSJohnny Huang 
2225e14b073cSJohnny Huang static int do_otprprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2226e14b073cSJohnny Huang {
2227e14b073cSJohnny Huang 	return _do_otpprotect(cmdtp, flag, argc, argv, 1);
2228e14b073cSJohnny Huang }
2229e14b073cSJohnny Huang 
2230f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2231f67375f7SJohnny Huang {
2232*e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
2233f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2234f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2235f67375f7SJohnny Huang 
2236f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2237f67375f7SJohnny Huang }
2238f67375f7SJohnny Huang 
2239794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2240794e27ecSJohnny Huang {
2241794e27ecSJohnny Huang 	u32 update_num;
2242794e27ecSJohnny Huang 	int force = 0;
2243794e27ecSJohnny Huang 	int ret;
2244794e27ecSJohnny Huang 
2245794e27ecSJohnny Huang 	if (argc == 3) {
2246794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2247794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2248794e27ecSJohnny Huang 		force = 1;
2249794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2250794e27ecSJohnny Huang 	} else if (argc == 2) {
2251794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2252794e27ecSJohnny Huang 	} else {
2253794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2254794e27ecSJohnny Huang 	}
2255794e27ecSJohnny Huang 
2256794e27ecSJohnny Huang 	if (update_num > 64)
2257794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2258794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2259794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2260794e27ecSJohnny Huang 	if (ret)
2261794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2262794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2263794e27ecSJohnny Huang }
2264794e27ecSJohnny Huang 
2265794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2266794e27ecSJohnny Huang {
2267794e27ecSJohnny Huang 	u32 otp_rid[2];
2268794e27ecSJohnny Huang 	int rid_num = 0;
2269794e27ecSJohnny Huang 	int ret;
2270794e27ecSJohnny Huang 
2271794e27ecSJohnny Huang 	if (argc != 1)
2272794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2273794e27ecSJohnny Huang 
2274794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2275794e27ecSJohnny Huang 	otp_read_config(10, &otp_rid[0]);
2276794e27ecSJohnny Huang 	otp_read_config(11, &otp_rid[1]);
2277794e27ecSJohnny Huang 
2278794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
2279794e27ecSJohnny Huang 
2280794e27ecSJohnny Huang 	if (rid_num >= 0) {
2281794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2282794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2283794e27ecSJohnny Huang 	} else {
2284794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by 'otp update',\n"
2285794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n"
2286794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2287794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2288794e27ecSJohnny Huang 	}
2289794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2290794e27ecSJohnny Huang 
2291794e27ecSJohnny Huang 	return ret;
2292794e27ecSJohnny Huang }
2293794e27ecSJohnny Huang 
22942a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2295f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
22962a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2297a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2298de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
22992a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2300737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
2301e14b073cSJohnny Huang 	U_BOOT_CMD_MKENT(rprotect, 3, 0, do_otprprotect, "", ""),
23022a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2303794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2304794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
23052a856b9aSJohnny Huang };
23062a856b9aSJohnny Huang 
23072a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
23082a856b9aSJohnny Huang {
23092a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2310a219f6deSJohnny Huang 	u32 ver;
2311e14b073cSJohnny Huang 	int ret;
23122a856b9aSJohnny Huang 
23132a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
23142a856b9aSJohnny Huang 
2315737ed20bSJohnny Huang 	/* Drop the otp command */
23162a856b9aSJohnny Huang 	argc--;
23172a856b9aSJohnny Huang 	argv++;
23182a856b9aSJohnny Huang 
2319a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
23202a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23212a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
23222a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
23232a856b9aSJohnny Huang 
23240dae9d52SJohnny Huang 	ver = chip_version();
23250dae9d52SJohnny Huang 	switch (ver) {
2326*e417205bSJohnny Huang 	case OTP_A0:
2327*e417205bSJohnny Huang 		info_cb.version = OTP_A0;
23289a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
23299a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
23309a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
23319a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
23329a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
23339a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2334*e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
23350dae9d52SJohnny Huang 		break;
2336*e417205bSJohnny Huang 	case OTP_A1:
2337*e417205bSJohnny Huang 		info_cb.version = OTP_A1;
23383cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
23393cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
23403cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
23413cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
23429a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
23439a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
2344*e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
23450dae9d52SJohnny Huang 		break;
2346*e417205bSJohnny Huang 	case OTP_A2:
2347*e417205bSJohnny Huang 		info_cb.version = OTP_A2;
23485fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
23495fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
23505fdde29fSJohnny Huang 		info_cb.strap_info = a2_strap_info;
23515fdde29fSJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
23525fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
23535fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
2354*e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
23550dae9d52SJohnny Huang 		break;
2356*e417205bSJohnny Huang 	case OTP_A3:
2357*e417205bSJohnny Huang 		info_cb.version = OTP_A3;
235864b66712SJohnny Huang 		info_cb.conf_info = a2_conf_info;
235964b66712SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
236064b66712SJohnny Huang 		info_cb.strap_info = a2_strap_info;
236164b66712SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
2362181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2363181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
2364*e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
236564b66712SJohnny Huang 		break;
23660dae9d52SJohnny Huang 	default:
2367f1be5099SJohnny Huang 		printf("SOC is not supported\n");
23680dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
23699a4fe690SJohnny Huang 	}
23709a4fe690SJohnny Huang 
2371e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2372e14b073cSJohnny Huang 	writel(1, OTP_PROTECT_KEY); //password
2373e14b073cSJohnny Huang 
2374e14b073cSJohnny Huang 	return ret;
237569d5fd8fSJohnny Huang }
237669d5fd8fSJohnny Huang 
2377a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
237869d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2379f67375f7SJohnny Huang 	   "version\n"
2380f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
23812a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
23822d4b0742SJohnny Huang 	   "otp info strap [v]\n"
23832d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
2384de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2385ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2386ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2387ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
2388e14b073cSJohnny Huang 	   "otp rprotect [o] <bit_offset>\n"
2389794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2390794e27ecSJohnny Huang 	   "otp rid\n"
239169d5fd8fSJohnny Huang 	  );
2392