xref: /openbmc/u-boot/cmd/otp.c (revision 7e523e3bd5cb83f8fdcdf0b598159c668eabcf5a)
1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+
269d5fd8fSJohnny Huang /*
3a219f6deSJohnny Huang  * Copyright 2021 Aspeed Technology Inc.
469d5fd8fSJohnny Huang  */
5e417205bSJohnny Huang 
64c1c9b35SJohnny Huang #include <stdlib.h>
769d5fd8fSJohnny Huang #include <common.h>
869d5fd8fSJohnny Huang #include <console.h>
969d5fd8fSJohnny Huang #include <bootretry.h>
1069d5fd8fSJohnny Huang #include <cli.h>
1169d5fd8fSJohnny Huang #include <command.h>
1269d5fd8fSJohnny Huang #include <console.h>
134c1c9b35SJohnny Huang #include <malloc.h>
1469d5fd8fSJohnny Huang #include <inttypes.h>
1569d5fd8fSJohnny Huang #include <mapmem.h>
1669d5fd8fSJohnny Huang #include <asm/io.h>
1769d5fd8fSJohnny Huang #include <linux/compiler.h>
18696656c6SJohnny Huang #include <u-boot/sha256.h>
190cee9a95SJohnny Huang #include "otp_info.h"
2069d5fd8fSJohnny Huang 
2169d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2269d5fd8fSJohnny Huang 
23f347c284SJohnny Huang #define OTP_VER				"1.1.0"
24f67375f7SJohnny Huang 
2569d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
26dacbba92SJohnny Huang #define RETRY				20
277332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
287332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
297332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3069d5fd8fSJohnny Huang 
312a856b9aSJohnny Huang #define OTP_USAGE			-1
322a856b9aSJohnny Huang #define OTP_FAILURE			-2
332a856b9aSJohnny Huang #define OTP_SUCCESS			0
342a856b9aSJohnny Huang 
35a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
36a6af4a17SJohnny Huang 
37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB		1
38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV		2
39181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES		3
40181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT		4
41181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC		5
429a4fe690SJohnny Huang 
434c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
444c1c9b35SJohnny Huang #define PBWIDTH 60
454c1c9b35SJohnny Huang 
463d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
473d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
483d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
493d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
503d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
513d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
523d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
533d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
543d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
553d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
56a8789b47SJohnny Huang #define SW_REV_ID0		OTP_BASE + 0x68
57a8789b47SJohnny Huang #define SW_REV_ID1		OTP_BASE + 0x6c
583d3688adSJohnny Huang 
59696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
60696656c6SJohnny Huang #define CHECKSUM_LEN		32
61a219f6deSJohnny Huang #define OTP_INC_DATA		BIT(31)
62a219f6deSJohnny Huang #define OTP_INC_CONFIG		BIT(30)
63a219f6deSJohnny Huang #define OTP_INC_STRAP		BIT(29)
64a219f6deSJohnny Huang #define OTP_ECC_EN		BIT(28)
65696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
66696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
67696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
68696656c6SJohnny Huang 
69e417205bSJohnny Huang #define OTP_A0		0
70e417205bSJohnny Huang #define OTP_A1		1
71e417205bSJohnny Huang #define OTP_A2		2
72e417205bSJohnny Huang #define OTP_A3		3
73e417205bSJohnny Huang 
74e417205bSJohnny Huang #define ID0_AST2600A0	0x05000303
75e417205bSJohnny Huang #define ID1_AST2600A0	0x05000303
76e417205bSJohnny Huang #define ID0_AST2600A1	0x05010303
7721a8cfceSJohnny Huang #define ID1_AST2600A1	0x05010303
78e417205bSJohnny Huang #define ID0_AST2600A2	0x05010303
79e417205bSJohnny Huang #define ID1_AST2600A2	0x05020303
80e417205bSJohnny Huang #define ID0_AST2600A3	0x05030303
81e417205bSJohnny Huang #define ID1_AST2600A3	0x05030303
82e417205bSJohnny Huang #define ID0_AST2620A1	0x05010203
83e417205bSJohnny Huang #define ID1_AST2620A1	0x05010203
84e417205bSJohnny Huang #define ID0_AST2620A2	0x05010203
85e417205bSJohnny Huang #define ID1_AST2620A2	0x05020203
86e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
87e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
88e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
89e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
90e417205bSJohnny Huang #define ID0_AST2605A2	0x05010103
91e417205bSJohnny Huang #define ID1_AST2605A2	0x05020103
92e417205bSJohnny Huang #define ID0_AST2605A3	0x05030103
93e417205bSJohnny Huang #define ID1_AST2605A3	0x05030103
94e417205bSJohnny Huang #define ID0_AST2625A3	0x05030403
95e417205bSJohnny Huang #define ID1_AST2625A3	0x05030403
96696656c6SJohnny Huang 
9761a6cda7SJohnny Huang #define SOC_AST2600A0	0
9861a6cda7SJohnny Huang #define SOC_AST2600A1	1
9961a6cda7SJohnny Huang #define SOC_AST2600A2	2
10061a6cda7SJohnny Huang #define SOC_AST2600A3	3
10161a6cda7SJohnny Huang 
10261a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c))
10361a6cda7SJohnny Huang 
104696656c6SJohnny Huang struct otp_header {
105696656c6SJohnny Huang 	u8	otp_magic[8];
10661a6cda7SJohnny Huang 	u32	soc_ver;
10761a6cda7SJohnny Huang 	u32	otptool_ver;
108696656c6SJohnny Huang 	u32	image_info;
109696656c6SJohnny Huang 	u32	data_info;
110696656c6SJohnny Huang 	u32	config_info;
111696656c6SJohnny Huang 	u32	strap_info;
112*7e523e3bSJohnny Huang 	u32	scu_protect_info;
113696656c6SJohnny Huang 	u32	checksum_offset;
114a219f6deSJohnny Huang } __packed;
115696656c6SJohnny Huang 
11666f2f8e5SJohnny Huang struct otpstrap_status {
11769d5fd8fSJohnny Huang 	int value;
11869d5fd8fSJohnny Huang 	int option_array[7];
11969d5fd8fSJohnny Huang 	int remain_times;
12069d5fd8fSJohnny Huang 	int writeable_option;
12169d5fd8fSJohnny Huang 	int protected;
12269d5fd8fSJohnny Huang };
12369d5fd8fSJohnny Huang 
1249a4fe690SJohnny Huang struct otpkey_type {
1259a4fe690SJohnny Huang 	int value;
1269a4fe690SJohnny Huang 	int key_type;
1279a4fe690SJohnny Huang 	int need_id;
1289a4fe690SJohnny Huang 	char information[110];
1299a4fe690SJohnny Huang };
1309a4fe690SJohnny Huang 
1319a4fe690SJohnny Huang struct otp_info_cb {
1329a4fe690SJohnny Huang 	int version;
133e417205bSJohnny Huang 	char ver_name[3];
13479e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1359a4fe690SJohnny Huang 	int strap_info_len;
13679e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1379a4fe690SJohnny Huang 	int conf_info_len;
13879e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1399a4fe690SJohnny Huang 	int key_info_len;
1409a4fe690SJohnny Huang };
1419a4fe690SJohnny Huang 
142696656c6SJohnny Huang struct otp_image_layout {
1435010032bSJohnny Huang 	int data_length;
1445010032bSJohnny Huang 	int conf_length;
1455010032bSJohnny Huang 	int strap_length;
146a219f6deSJohnny Huang 	u8 *data;
147a219f6deSJohnny Huang 	u8 *data_ignore;
148a219f6deSJohnny Huang 	u8 *conf;
149a219f6deSJohnny Huang 	u8 *conf_ignore;
150a219f6deSJohnny Huang 	u8 *strap;
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 
195f347c284SJohnny Huang static void buf_print(u8 *buf, int len)
196f347c284SJohnny Huang {
197f347c284SJohnny Huang 	int i;
198f347c284SJohnny Huang 
199f347c284SJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
200f347c284SJohnny Huang 	for (i = 0; i < len; i++) {
201f347c284SJohnny Huang 		if (i % 16 == 0)
202f347c284SJohnny Huang 			printf("%04X: ", i);
203f347c284SJohnny Huang 		printf("%02X ", buf[i]);
204f347c284SJohnny Huang 		if ((i + 1) % 16 == 0)
205f347c284SJohnny Huang 			printf("\n");
206f347c284SJohnny Huang 	}
207f347c284SJohnny Huang }
208f347c284SJohnny Huang 
209794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
210794e27ecSJohnny Huang {
211794e27ecSJohnny Huang 	int bit_offset;
212794e27ecSJohnny Huang 	int i;
213794e27ecSJohnny Huang 
214794e27ecSJohnny Huang 	if (offset < 32) {
215794e27ecSJohnny Huang 		i = 0;
216794e27ecSJohnny Huang 		bit_offset = offset;
217794e27ecSJohnny Huang 	} else {
218794e27ecSJohnny Huang 		i = 1;
219794e27ecSJohnny Huang 		bit_offset = offset - 32;
220794e27ecSJohnny Huang 	}
221794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
222794e27ecSJohnny Huang 		return 1;
223794e27ecSJohnny Huang 	else
224794e27ecSJohnny Huang 		return 0;
225794e27ecSJohnny Huang }
226794e27ecSJohnny Huang 
227794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
228794e27ecSJohnny Huang {
229794e27ecSJohnny Huang 	int i;
230794e27ecSJohnny Huang 	int fz = 0;
231794e27ecSJohnny Huang 	int rid_num = 0;
232794e27ecSJohnny Huang 	int ret = 0;
233794e27ecSJohnny Huang 
234794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
235794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
236794e27ecSJohnny Huang 			if (!fz)
237794e27ecSJohnny Huang 				fz = 1;
238794e27ecSJohnny Huang 
239794e27ecSJohnny Huang 		} else {
240794e27ecSJohnny Huang 			rid_num++;
241794e27ecSJohnny Huang 			if (fz)
242794e27ecSJohnny Huang 				ret = OTP_FAILURE;
243794e27ecSJohnny Huang 		}
244794e27ecSJohnny Huang 	}
245794e27ecSJohnny Huang 	if (ret)
246794e27ecSJohnny Huang 		return ret;
247794e27ecSJohnny Huang 
248794e27ecSJohnny Huang 	return rid_num;
249794e27ecSJohnny Huang }
250794e27ecSJohnny Huang 
251a219f6deSJohnny Huang static u32 chip_version(void)
2529a4fe690SJohnny Huang {
253e417205bSJohnny Huang 	u32 revid0, revid1;
2549a4fe690SJohnny Huang 
255e417205bSJohnny Huang 	revid0 = readl(ASPEED_REVISION_ID0);
256e417205bSJohnny Huang 	revid1 = readl(ASPEED_REVISION_ID1);
2579a4fe690SJohnny Huang 
258e417205bSJohnny Huang 	if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
259badd21c2SJohnny Huang 		/* AST2600-A0 */
260e417205bSJohnny Huang 		return OTP_A0;
261e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
262badd21c2SJohnny Huang 		/* AST2600-A1 */
263e417205bSJohnny Huang 		return OTP_A1;
264e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
265badd21c2SJohnny Huang 		/* AST2600-A2 */
266e417205bSJohnny Huang 		return OTP_A2;
267e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
26864b66712SJohnny Huang 		/* AST2600-A3 */
269e417205bSJohnny Huang 		return OTP_A3;
270e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
271e417205bSJohnny Huang 		/* AST2620-A1 */
272e417205bSJohnny Huang 		return OTP_A1;
273e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
274e417205bSJohnny Huang 		/* AST2620-A2 */
275e417205bSJohnny Huang 		return OTP_A2;
276e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
27764b66712SJohnny Huang 		/* AST2620-A3 */
278e417205bSJohnny Huang 		return OTP_A3;
279e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
280e417205bSJohnny Huang 		/* AST2605-A2 */
281e417205bSJohnny Huang 		return OTP_A2;
282e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
283e417205bSJohnny Huang 		/* AST2605-A3 */
284e417205bSJohnny Huang 		return OTP_A3;
285e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
286e417205bSJohnny Huang 		/* AST2605-A3 */
287e417205bSJohnny Huang 		return OTP_A3;
2880dae9d52SJohnny Huang 	}
289f347c284SJohnny Huang 	return OTP_FAILURE;
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 {
311e417205bSJohnny Huang 	if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
312dacbba92SJohnny Huang 		switch (soak) {
313dacbba92SJohnny Huang 		case 0: //default
314377f8cd7SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
315377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
316dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
317dacbba92SJohnny Huang 			break;
318dacbba92SJohnny Huang 		case 1: //normal program
319377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
320377f8cd7SJohnny Huang 			otp_write(0x5000, 0x1008); // Write MRB
321377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0024); // Write MR
322feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
323dacbba92SJohnny Huang 			break;
324dacbba92SJohnny Huang 		case 2: //soak program
325377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
326377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0007); // Write MRB
327377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0100); // 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 
365f347c284SJohnny Huang static void otp_read_conf(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_compare(u32 otp_addr, u32 addr)
38069d5fd8fSJohnny Huang {
381a219f6deSJohnny Huang 	u32 ret;
382a219f6deSJohnny Huang 	u32 *buf;
38369d5fd8fSJohnny Huang 
38469d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
38569d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
38669d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
38769d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
38869d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
3893d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
3903d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
3913d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
3923d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
3933d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
3943d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
3953d3688adSJohnny Huang 	wait_complete();
3963d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
39769d5fd8fSJohnny Huang 	if (ret & 0x1)
398f347c284SJohnny Huang 		return OTP_SUCCESS;
39969d5fd8fSJohnny Huang 	else
400f347c284SJohnny Huang 		return OTP_FAILURE;
40169d5fd8fSJohnny Huang }
40269d5fd8fSJohnny Huang 
403a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
40469d5fd8fSJohnny Huang {
405a219f6deSJohnny Huang 	u32 ret[2];
40669d5fd8fSJohnny Huang 
40730a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4083d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
40930a8c590SJohnny Huang 	else
4103d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
41130a8c590SJohnny Huang 
4123d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4133d3688adSJohnny Huang 	wait_complete();
4143d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4153d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
41683655e91SJohnny Huang 
41730a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
41830a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
419f347c284SJohnny Huang 			return OTP_SUCCESS;
42069d5fd8fSJohnny Huang 		else
421f347c284SJohnny Huang 			return OTP_FAILURE;
42230a8c590SJohnny Huang 	} else {
42330a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
424f347c284SJohnny Huang 			return OTP_SUCCESS;
42530a8c590SJohnny Huang 		else
426f347c284SJohnny Huang 			return OTP_FAILURE;
42730a8c590SJohnny Huang 	}
42869d5fd8fSJohnny Huang }
42969d5fd8fSJohnny Huang 
430a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4314c1c9b35SJohnny Huang {
432a219f6deSJohnny Huang 	u32 ret[2];
4334c1c9b35SJohnny Huang 
4344c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4354c1c9b35SJohnny Huang 
4364c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4373d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
4384c1c9b35SJohnny Huang 	else
4393d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
4403d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4413d3688adSJohnny Huang 	wait_complete();
4423d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4433d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4444c1c9b35SJohnny Huang 	if (size == 1) {
4454c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4464c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
447696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4484c1c9b35SJohnny Huang 				compare[0] = 0;
449f347c284SJohnny Huang 				return OTP_SUCCESS;
450a219f6deSJohnny Huang 			}
4514c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
452f347c284SJohnny Huang 			return OTP_FAILURE;
4534c1c9b35SJohnny Huang 
4544c1c9b35SJohnny Huang 		} else {
4554c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
456696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4574c1c9b35SJohnny Huang 				compare[0] = ~0;
458f347c284SJohnny Huang 				return OTP_SUCCESS;
459a219f6deSJohnny Huang 			}
460d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
461f347c284SJohnny Huang 			return OTP_FAILURE;
4624c1c9b35SJohnny Huang 		}
4634c1c9b35SJohnny Huang 	} else if (size == 2) {
4644c1c9b35SJohnny Huang 		// otp_addr should be even
465696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
4664c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4674c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4684c1c9b35SJohnny Huang 			compare[0] = 0;
4694c1c9b35SJohnny Huang 			compare[1] = ~0;
470f347c284SJohnny Huang 			return OTP_SUCCESS;
471a219f6deSJohnny Huang 		}
4724c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4734c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4744c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
4754c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
476f347c284SJohnny Huang 		return OTP_FAILURE;
4774c1c9b35SJohnny Huang 	} else {
478f347c284SJohnny Huang 		return OTP_FAILURE;
4794c1c9b35SJohnny Huang 	}
4804c1c9b35SJohnny Huang }
4814c1c9b35SJohnny Huang 
482a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit)
48383655e91SJohnny Huang {
48490965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
48583655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
48683655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
48783655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
48883655e91SJohnny Huang 	wait_complete();
48983655e91SJohnny Huang }
49083655e91SJohnny Huang 
491a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
49283655e91SJohnny Huang {
49383655e91SJohnny Huang 	int prog_bit;
49483655e91SJohnny Huang 
49583655e91SJohnny Huang 	if (prog_address % 2 == 0) {
49683655e91SJohnny Huang 		if (value)
49783655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
49883655e91SJohnny Huang 		else
49983655e91SJohnny Huang 			return;
50083655e91SJohnny Huang 	} else {
501e417205bSJohnny Huang 		if (info_cb.version != OTP_A3)
50283655e91SJohnny Huang 			prog_address |= 1 << 15;
50383655e91SJohnny Huang 		if (!value)
50483655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
50583655e91SJohnny Huang 		else
50683655e91SJohnny Huang 			return;
50783655e91SJohnny Huang 	}
50883655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
50983655e91SJohnny Huang }
51083655e91SJohnny Huang 
511f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset)
51283655e91SJohnny Huang {
51383655e91SJohnny Huang 	int pass;
51483655e91SJohnny Huang 	int i;
51583655e91SJohnny Huang 
51683655e91SJohnny Huang 	otp_soak(1);
51783655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
51883655e91SJohnny Huang 	pass = 0;
51983655e91SJohnny Huang 
52083655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
52183655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
52283655e91SJohnny Huang 			otp_soak(2);
52383655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
52483655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
52583655e91SJohnny Huang 				otp_soak(1);
52683655e91SJohnny Huang 			} else {
52783655e91SJohnny Huang 				pass = 1;
52883655e91SJohnny Huang 				break;
52983655e91SJohnny Huang 			}
53083655e91SJohnny Huang 		} else {
53183655e91SJohnny Huang 			pass = 1;
53283655e91SJohnny Huang 			break;
53383655e91SJohnny Huang 		}
53483655e91SJohnny Huang 	}
535794e27ecSJohnny Huang 	if (pass)
536794e27ecSJohnny Huang 		return OTP_SUCCESS;
53783655e91SJohnny Huang 
538794e27ecSJohnny Huang 	return OTP_FAILURE;
53983655e91SJohnny Huang }
54083655e91SJohnny Huang 
541a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
542d90825e2SJohnny Huang {
543d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
544d90825e2SJohnny Huang 
545d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
546696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
547d90825e2SJohnny Huang 			continue;
548d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
549d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
550d90825e2SJohnny Huang 			if (bit_value)
551d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
552d90825e2SJohnny Huang 			else
553d90825e2SJohnny Huang 				continue;
554d90825e2SJohnny Huang 		} else {
555e417205bSJohnny Huang 			if (info_cb.version != OTP_A3)
556d90825e2SJohnny Huang 				prog_address |= 1 << 15;
557d90825e2SJohnny Huang 			if (bit_value)
558d90825e2SJohnny Huang 				continue;
559d90825e2SJohnny Huang 			else
560d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
561d90825e2SJohnny Huang 		}
562d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
563d90825e2SJohnny Huang 	}
564d90825e2SJohnny Huang }
565d90825e2SJohnny Huang 
566a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
56754552c69SJohnny Huang {
56854552c69SJohnny Huang 	int pass;
56954552c69SJohnny Huang 	int i;
570a219f6deSJohnny Huang 	u32 data0_masked;
571a219f6deSJohnny Huang 	u32 data1_masked;
572a219f6deSJohnny Huang 	u32 buf0_masked;
573a219f6deSJohnny Huang 	u32 buf1_masked;
574a219f6deSJohnny Huang 	u32 compare[2];
57554552c69SJohnny Huang 
57654552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
57754552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
57854552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
57954552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
580a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
581f347c284SJohnny Huang 		return OTP_SUCCESS;
58254552c69SJohnny Huang 
58354552c69SJohnny Huang 	otp_soak(1);
58454552c69SJohnny Huang 	if (data0_masked != buf0_masked)
58554552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
58654552c69SJohnny Huang 	if (data1_masked != buf1_masked)
58754552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
58854552c69SJohnny Huang 
58954552c69SJohnny Huang 	pass = 0;
59054552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
59154552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
59254552c69SJohnny Huang 			otp_soak(2);
593a219f6deSJohnny Huang 			if (compare[0] != 0)
59454552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
595a219f6deSJohnny Huang 			if (compare[1] != ~0)
5965537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
59754552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
59854552c69SJohnny Huang 				otp_soak(1);
59954552c69SJohnny Huang 			} else {
60054552c69SJohnny Huang 				pass = 1;
60154552c69SJohnny Huang 				break;
60254552c69SJohnny Huang 			}
60354552c69SJohnny Huang 		} else {
60454552c69SJohnny Huang 			pass = 1;
60554552c69SJohnny Huang 			break;
60654552c69SJohnny Huang 		}
60754552c69SJohnny Huang 	}
60854552c69SJohnny Huang 
60954552c69SJohnny Huang 	if (!pass) {
61054552c69SJohnny Huang 		otp_soak(0);
61154552c69SJohnny Huang 		return OTP_FAILURE;
61254552c69SJohnny Huang 	}
61354552c69SJohnny Huang 	return OTP_SUCCESS;
61454552c69SJohnny Huang }
61554552c69SJohnny Huang 
616541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
61776d13988SJohnny Huang {
618a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
6195010032bSJohnny Huang 	int strap_end;
62076d13988SJohnny Huang 	int i, j;
62176d13988SJohnny Huang 
622e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
62376d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
62476d13988SJohnny Huang 			otpstrap[j].value = 0;
62576d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
62676d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
62776d13988SJohnny Huang 			otpstrap[j].protected = 0;
62876d13988SJohnny Huang 		}
6295010032bSJohnny Huang 		strap_end = 30;
6305010032bSJohnny Huang 	} else {
6315010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
6325010032bSJohnny Huang 			otpstrap[j].value = 0;
6335010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
6345010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
6355010032bSJohnny Huang 			otpstrap[j].protected = 0;
6365010032bSJohnny Huang 		}
6375010032bSJohnny Huang 		strap_end = 28;
6385010032bSJohnny Huang 	}
63976d13988SJohnny Huang 
640dacbba92SJohnny Huang 	otp_soak(0);
6415010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
64276d13988SJohnny Huang 		int option = (i - 16) / 2;
643a219f6deSJohnny Huang 
644f347c284SJohnny Huang 		otp_read_conf(i, &OTPSTRAP_RAW[0]);
645f347c284SJohnny Huang 		otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
64676d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
64776d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
648a219f6deSJohnny Huang 
649a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
65076d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
65176d13988SJohnny Huang 			if (bit_value == 1)
65276d13988SJohnny Huang 				otpstrap[j].remain_times--;
65376d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
65476d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
65576d13988SJohnny Huang 		}
65676d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
65776d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
658a219f6deSJohnny Huang 
659a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
66076d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
66176d13988SJohnny Huang 			if (bit_value == 1)
66276d13988SJohnny Huang 				otpstrap[j].remain_times--;
66376d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
66476d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
66576d13988SJohnny Huang 		}
66676d13988SJohnny Huang 	}
6675010032bSJohnny Huang 
668f347c284SJohnny Huang 	otp_read_conf(30, &OTPSTRAP_RAW[0]);
669f347c284SJohnny Huang 	otp_read_conf(31, &OTPSTRAP_RAW[1]);
67076d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
67176d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
67276d13988SJohnny Huang 			otpstrap[j].protected = 1;
67376d13988SJohnny Huang 	}
67476d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
67576d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
67676d13988SJohnny Huang 			otpstrap[j].protected = 1;
67776d13988SJohnny Huang 	}
67876d13988SJohnny Huang }
67976d13988SJohnny Huang 
680*7e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit)
681f347c284SJohnny Huang {
682f347c284SJohnny Huang 	int prog_flag = 0;
683f347c284SJohnny Huang 
684f347c284SJohnny Huang 	// ignore this bit
685f347c284SJohnny Huang 	if (ibit == 1)
686f347c284SJohnny Huang 		return OTP_SUCCESS;
687f347c284SJohnny Huang 	printf("OTPSTRAP[%X]:\n", offset);
688f347c284SJohnny Huang 
689f347c284SJohnny Huang 	if (bit == otpstrap->value) {
690*7e523e3bSJohnny Huang 		if (!pbit) {
691f347c284SJohnny Huang 			printf("    The value is same as before, skip it.\n");
692f347c284SJohnny Huang 			return OTP_PROG_SKIP;
693f347c284SJohnny Huang 		}
694f347c284SJohnny Huang 		printf("    The value is same as before.\n");
695f347c284SJohnny Huang 	} else {
696f347c284SJohnny Huang 		prog_flag = 1;
697f347c284SJohnny Huang 	}
698f347c284SJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
699f347c284SJohnny Huang 		printf("    This bit is protected and is not writable\n");
700f347c284SJohnny Huang 		return OTP_FAILURE;
701f347c284SJohnny Huang 	}
702f347c284SJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
703f347c284SJohnny Huang 		printf("    This bit is no remaining times to write.\n");
704f347c284SJohnny Huang 		return OTP_FAILURE;
705f347c284SJohnny Huang 	}
706f347c284SJohnny Huang 	if (pbit == 1)
707f347c284SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
708f347c284SJohnny Huang 	if (prog_flag)
709f347c284SJohnny 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);
710f347c284SJohnny Huang 
711f347c284SJohnny Huang 	return OTP_SUCCESS;
712f347c284SJohnny Huang }
713f347c284SJohnny Huang 
714f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
715f347c284SJohnny Huang {
716f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
717f347c284SJohnny Huang 	u32 prog_address;
718f347c284SJohnny Huang 	int offset;
719f347c284SJohnny Huang 	int ret;
720f347c284SJohnny Huang 
721f347c284SJohnny Huang 	otp_strap_status(otpstrap);
722f347c284SJohnny Huang 
723*7e523e3bSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
724f347c284SJohnny Huang 
725f347c284SJohnny Huang 	if (ret != OTP_SUCCESS)
726f347c284SJohnny Huang 		return ret;
727f347c284SJohnny Huang 
728f347c284SJohnny Huang 	prog_address = 0x800;
729f347c284SJohnny Huang 	if (bit_offset < 32) {
730f347c284SJohnny Huang 		offset = bit_offset;
731f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
732f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
733f347c284SJohnny Huang 
734f347c284SJohnny Huang 	} else {
735f347c284SJohnny Huang 		offset = (bit_offset - 32);
736f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
737f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
738f347c284SJohnny Huang 	}
739f347c284SJohnny Huang 
740f347c284SJohnny Huang 	return otp_prog_dc_b(1, prog_address, offset);
741f347c284SJohnny Huang }
742f347c284SJohnny Huang 
743f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
744f347c284SJohnny Huang {
745f347c284SJohnny Huang 	int i;
746f347c284SJohnny Huang 	u32 ret[1];
747f347c284SJohnny Huang 
748f347c284SJohnny Huang 	if (offset + dw_count > 32)
749f347c284SJohnny Huang 		return OTP_USAGE;
750f347c284SJohnny Huang 	otp_soak(0);
751f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
752f347c284SJohnny Huang 		otp_read_conf(i, ret);
753f347c284SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
754f347c284SJohnny Huang 	}
755f347c284SJohnny Huang 	printf("\n");
756f347c284SJohnny Huang 	return OTP_SUCCESS;
757f347c284SJohnny Huang }
758f347c284SJohnny Huang 
759f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
760f347c284SJohnny Huang {
761f347c284SJohnny Huang 	int i;
762f347c284SJohnny Huang 	u32 ret[2];
763f347c284SJohnny Huang 
764f347c284SJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
765f347c284SJohnny Huang 		return OTP_USAGE;
766f347c284SJohnny Huang 	otp_soak(0);
767f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
768f347c284SJohnny Huang 		otp_read_data(i, ret);
769f347c284SJohnny Huang 		if (i % 4 == 0)
770f347c284SJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
771f347c284SJohnny Huang 		else
772f347c284SJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
773f347c284SJohnny Huang 	}
774f347c284SJohnny Huang 	printf("\n");
775f347c284SJohnny Huang 	return OTP_SUCCESS;
776f347c284SJohnny Huang }
777f347c284SJohnny Huang 
778f347c284SJohnny Huang static int otp_print_strap(int start, int count)
779f347c284SJohnny Huang {
780f347c284SJohnny Huang 	int i, j;
781f347c284SJohnny Huang 	int remains;
782f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
783f347c284SJohnny Huang 
784f347c284SJohnny Huang 	if (start < 0 || start > 64)
785f347c284SJohnny Huang 		return OTP_USAGE;
786f347c284SJohnny Huang 
787f347c284SJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
788f347c284SJohnny Huang 		return OTP_USAGE;
789f347c284SJohnny Huang 
790f347c284SJohnny Huang 	otp_strap_status(otpstrap);
791f347c284SJohnny Huang 
792*7e523e3bSJohnny Huang 	if (info_cb.version == OTP_A0)
793f347c284SJohnny Huang 		remains = 7;
794*7e523e3bSJohnny Huang 	else
795f347c284SJohnny Huang 		remains = 6;
796*7e523e3bSJohnny Huang 	printf("BIT(hex)  Value  Option           Status\n");
797f347c284SJohnny Huang 	printf("______________________________________________________________________________\n");
798f347c284SJohnny Huang 
799f347c284SJohnny Huang 	for (i = start; i < start + count; i++) {
800f347c284SJohnny Huang 		printf("0x%-8X", i);
801f347c284SJohnny Huang 		printf("%-7d", otpstrap[i].value);
802f347c284SJohnny Huang 		for (j = 0; j < remains; j++)
803f347c284SJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
804f347c284SJohnny Huang 		printf("   ");
805f347c284SJohnny Huang 		if (otpstrap[i].protected == 1) {
806f347c284SJohnny Huang 			printf("protected and not writable");
807f347c284SJohnny Huang 		} else {
808f347c284SJohnny Huang 			printf("not protected ");
809f347c284SJohnny Huang 			if (otpstrap[i].remain_times == 0)
810f347c284SJohnny Huang 				printf("and no remaining times to write.");
811f347c284SJohnny Huang 			else
812f347c284SJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
813f347c284SJohnny Huang 		}
814f347c284SJohnny Huang 		printf("\n");
815f347c284SJohnny Huang 	}
816f347c284SJohnny Huang 
817f347c284SJohnny Huang 	return OTP_SUCCESS;
818f347c284SJohnny Huang }
819f347c284SJohnny Huang 
820794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
821794e27ecSJohnny Huang {
822794e27ecSJohnny Huang 	int bit_offset;
823794e27ecSJohnny Huang 	int i, j;
824794e27ecSJohnny Huang 
825794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
826794e27ecSJohnny Huang 	printf("___________________________________________________\n");
827794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
828794e27ecSJohnny Huang 		if (i < 32) {
829794e27ecSJohnny Huang 			j = 0;
830794e27ecSJohnny Huang 			bit_offset = i;
831794e27ecSJohnny Huang 		} else {
832794e27ecSJohnny Huang 			j = 1;
833794e27ecSJohnny Huang 			bit_offset = i - 32;
834794e27ecSJohnny Huang 		}
835794e27ecSJohnny Huang 		if (i % 16 == 0)
836794e27ecSJohnny Huang 			printf("%2x | ", i);
837794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
838794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
839794e27ecSJohnny Huang 			printf("\n");
840794e27ecSJohnny Huang 	}
841794e27ecSJohnny Huang }
842794e27ecSJohnny Huang 
843696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
84469d5fd8fSJohnny Huang {
84579e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
846a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
847a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
848a219f6deSJohnny Huang 	u32 mask;
849a219f6deSJohnny Huang 	u32 dw_offset;
850a219f6deSJohnny Huang 	u32 bit_offset;
851a219f6deSJohnny Huang 	u32 otp_value;
852a219f6deSJohnny Huang 	u32 otp_ignore;
853b458cd62SJohnny Huang 	int fail = 0;
8547adec5f6SJohnny Huang 	int mask_err;
855794e27ecSJohnny Huang 	int rid_num = 0;
85673f11549SJohnny Huang 	char valid_bit[20];
857794e27ecSJohnny Huang 	int fz;
85866f2f8e5SJohnny Huang 	int i;
85973f11549SJohnny Huang 	int j;
86066f2f8e5SJohnny Huang 
861737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
86266f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
8633cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
8647adec5f6SJohnny Huang 		mask_err = 0;
8653cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
8663cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
8673cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
868b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
869696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
870b458cd62SJohnny Huang 
8717adec5f6SJohnny Huang 		if (conf_info[i].value == OTP_REG_VALID_BIT) {
8727adec5f6SJohnny Huang 			if (((otp_value + otp_ignore) & mask) != mask) {
873b458cd62SJohnny Huang 				fail = 1;
8747adec5f6SJohnny Huang 				mask_err = 1;
8757adec5f6SJohnny Huang 			}
8767adec5f6SJohnny Huang 		} else {
8777adec5f6SJohnny Huang 			if (otp_ignore == mask) {
8787adec5f6SJohnny Huang 				continue;
8797adec5f6SJohnny Huang 			} else if (otp_ignore != 0) {
8807adec5f6SJohnny Huang 				fail = 1;
8817adec5f6SJohnny Huang 				mask_err = 1;
8827adec5f6SJohnny Huang 			}
8837adec5f6SJohnny Huang 		}
884b458cd62SJohnny Huang 
885a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
8863cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
8873cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
8883cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
889b458cd62SJohnny Huang 			continue;
890b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
891b458cd62SJohnny Huang 
8923cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
8933cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
89466f2f8e5SJohnny Huang 		} else {
895b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
8963cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
8973cb28812SJohnny Huang 			       conf_info[i].bit_offset);
89866f2f8e5SJohnny Huang 		}
899b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
900b458cd62SJohnny Huang 
9017adec5f6SJohnny Huang 		if (mask_err) {
9027adec5f6SJohnny Huang 			printf("Ignore, mask error\n");
903a219f6deSJohnny Huang 			continue;
904a219f6deSJohnny Huang 		}
9053cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
906b458cd62SJohnny Huang 			printf("Reserved\n");
9073cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
9083cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
909b458cd62SJohnny Huang 			printf("\n");
9103cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
911b458cd62SJohnny Huang 			if (otp_value != 0) {
91273f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
913a219f6deSJohnny Huang 					if (otp_value == (1 << j))
91473f11549SJohnny Huang 						valid_bit[j * 2] = '1';
915a219f6deSJohnny Huang 					else
91673f11549SJohnny Huang 						valid_bit[j * 2] = '0';
91773f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
91873f11549SJohnny Huang 				}
91973f11549SJohnny Huang 				valid_bit[15] = 0;
92073f11549SJohnny Huang 			} else {
92173f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
922b458cd62SJohnny Huang 			}
9233cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
924b458cd62SJohnny Huang 			printf("\n");
925b458cd62SJohnny Huang 		} else {
9263cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
927b458cd62SJohnny Huang 		}
928b458cd62SJohnny Huang 	}
929b458cd62SJohnny Huang 
930794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
931794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
932794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
933794e27ecSJohnny Huang 			fail = 1;
934794e27ecSJohnny Huang 		} else {
935794e27ecSJohnny Huang 			fz = 0;
936794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
937794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
938794e27ecSJohnny Huang 					if (!fz)
939794e27ecSJohnny Huang 						fz = 1;
940794e27ecSJohnny Huang 				} else {
941794e27ecSJohnny Huang 					rid_num++;
942794e27ecSJohnny Huang 					if (fz) {
943794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
944794e27ecSJohnny Huang 						fail = 1;
945794e27ecSJohnny Huang 						break;
946794e27ecSJohnny Huang 					}
947794e27ecSJohnny Huang 				}
948794e27ecSJohnny Huang 			}
949794e27ecSJohnny Huang 		}
950794e27ecSJohnny Huang 		if (fail)
951794e27ecSJohnny Huang 			printf("OTP revision ID\n");
952794e27ecSJohnny Huang 		else
953794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
954794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
955794e27ecSJohnny Huang 	}
956794e27ecSJohnny Huang 
957b458cd62SJohnny Huang 	if (fail)
958b458cd62SJohnny Huang 		return OTP_FAILURE;
959b458cd62SJohnny Huang 
96066f2f8e5SJohnny Huang 	return OTP_SUCCESS;
96166f2f8e5SJohnny Huang }
96266f2f8e5SJohnny Huang 
9632d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
96466f2f8e5SJohnny Huang {
96579e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
966a219f6deSJohnny Huang 	u32 OTPCFG[16];
967a219f6deSJohnny Huang 	u32 mask;
968a219f6deSJohnny Huang 	u32 dw_offset;
969a219f6deSJohnny Huang 	u32 bit_offset;
970a219f6deSJohnny Huang 	u32 otp_value;
97173f11549SJohnny Huang 	char valid_bit[20];
97266f2f8e5SJohnny Huang 	int i;
97373f11549SJohnny Huang 	int j;
97466f2f8e5SJohnny Huang 
975dacbba92SJohnny Huang 	otp_soak(0);
976bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
977f347c284SJohnny Huang 		otp_read_conf(i, &OTPCFG[i]);
97866f2f8e5SJohnny Huang 
979b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
980b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
9813cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
9823cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
9832d4b0742SJohnny Huang 			continue;
9843cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
9853cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
9863cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
987b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
988b458cd62SJohnny Huang 
989a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
9903cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
9913cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
9923cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
993b458cd62SJohnny Huang 			continue;
994b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
995b458cd62SJohnny Huang 
9963cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
9973cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
998b458cd62SJohnny Huang 		} else {
999b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
10003cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
10013cb28812SJohnny Huang 			       conf_info[i].bit_offset);
1002b458cd62SJohnny Huang 		}
1003b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1004b458cd62SJohnny Huang 
10053cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1006b458cd62SJohnny Huang 			printf("Reserved\n");
10073cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
10083cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1009b458cd62SJohnny Huang 			printf("\n");
10103cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1011b458cd62SJohnny Huang 			if (otp_value != 0) {
101273f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1013a219f6deSJohnny Huang 					if (otp_value == (1 << j))
101473f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1015a219f6deSJohnny Huang 					else
101673f11549SJohnny Huang 						valid_bit[j * 2] = '0';
101773f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
101873f11549SJohnny Huang 				}
101973f11549SJohnny Huang 				valid_bit[15] = 0;
102073f11549SJohnny Huang 			} else {
102173f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1022b458cd62SJohnny Huang 			}
10233cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1024b458cd62SJohnny Huang 			printf("\n");
1025b458cd62SJohnny Huang 		} else {
10263cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1027b458cd62SJohnny Huang 		}
1028b458cd62SJohnny Huang 	}
1029b458cd62SJohnny Huang 	return OTP_SUCCESS;
103066f2f8e5SJohnny Huang }
103166f2f8e5SJohnny Huang 
10325010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
103376d13988SJohnny Huang {
103479e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
1035a219f6deSJohnny Huang 	u32 *OTPSTRAP;
1036a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
1037a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
103876d13988SJohnny Huang 	int i;
1039a8bd6d8cSJohnny Huang 	int fail = 0;
1040a219f6deSJohnny Huang 	u32 bit_offset;
1041a219f6deSJohnny Huang 	u32 dw_offset;
1042a219f6deSJohnny Huang 	u32 mask;
1043a219f6deSJohnny Huang 	u32 otp_value;
1044a219f6deSJohnny Huang 	u32 otp_protect;
1045a219f6deSJohnny Huang 	u32 otp_ignore;
104676d13988SJohnny Huang 
1047a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
1048a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1049a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
1050*7e523e3bSJohnny Huang 
1051a8bd6d8cSJohnny Huang 	printf("BIT(hex)   Value       Protect     Description\n");
1052de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
1053b458cd62SJohnny Huang 
10543cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
10557adec5f6SJohnny Huang 		fail = 0;
1056696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
1057a8bd6d8cSJohnny Huang 			dw_offset = 1;
10583cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
1059a8bd6d8cSJohnny Huang 		} else {
1060a8bd6d8cSJohnny Huang 			dw_offset = 0;
10613cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
1062a8bd6d8cSJohnny Huang 		}
106376d13988SJohnny Huang 
10643cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
1065a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1066a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1067696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1068a8bd6d8cSJohnny Huang 
1069a219f6deSJohnny Huang 		if (otp_ignore == mask)
1070a8bd6d8cSJohnny Huang 			continue;
1071a219f6deSJohnny Huang 		else if (otp_ignore != 0)
1072a8bd6d8cSJohnny Huang 			fail = 1;
1073a8bd6d8cSJohnny Huang 
1074a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
10753cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1076a8bd6d8cSJohnny Huang 			continue;
1077a8bd6d8cSJohnny Huang 
10783cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
10793cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
1080a8bd6d8cSJohnny Huang 		} else {
1081b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
10823cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
10833cb28812SJohnny Huang 			       strap_info[i].bit_offset);
1084a8bd6d8cSJohnny Huang 		}
1085a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
1086a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
1087a8bd6d8cSJohnny Huang 
1088a8bd6d8cSJohnny Huang 		if (fail) {
1089696656c6SJohnny Huang 			printf("Ignore mask error\n");
1090a8bd6d8cSJohnny Huang 		} else {
10913cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
10923cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1093a8bd6d8cSJohnny Huang 			else
1094a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1095a8bd6d8cSJohnny Huang 		}
1096a8bd6d8cSJohnny Huang 	}
1097a8bd6d8cSJohnny Huang 
1098a8bd6d8cSJohnny Huang 	if (fail)
109976d13988SJohnny Huang 		return OTP_FAILURE;
110076d13988SJohnny Huang 
110176d13988SJohnny Huang 	return OTP_SUCCESS;
110276d13988SJohnny Huang }
110376d13988SJohnny Huang 
1104b458cd62SJohnny Huang static int otp_print_strap_info(int view)
110576d13988SJohnny Huang {
110679e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
110776d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
110807baa4e8SJohnny Huang 	int i, j;
1109b458cd62SJohnny Huang 	int fail = 0;
1110a219f6deSJohnny Huang 	u32 bit_offset;
1111a219f6deSJohnny Huang 	u32 length;
1112a219f6deSJohnny Huang 	u32 otp_value;
1113a219f6deSJohnny Huang 	u32 otp_protect;
111476d13988SJohnny Huang 
1115541eb887SJohnny Huang 	otp_strap_status(strap_status);
111676d13988SJohnny Huang 
1117b458cd62SJohnny Huang 	if (view) {
111807baa4e8SJohnny Huang 		printf("BIT(hex) Value  Remains  Protect   Description\n");
111907baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1120b458cd62SJohnny Huang 	} else {
1121b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1122b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
112376d13988SJohnny Huang 	}
11243cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1125b458cd62SJohnny Huang 		otp_value = 0;
11263cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
11273cb28812SJohnny Huang 		length = strap_info[i].length;
1128b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1129c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1130c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1131b458cd62SJohnny Huang 		}
1132a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
11333cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1134b458cd62SJohnny Huang 			continue;
1135b458cd62SJohnny Huang 		if (view) {
1136b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
11373cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1138b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
113907baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1140e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
11413cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1142b458cd62SJohnny Huang 					printf(" Reserved\n");
1143b458cd62SJohnny Huang 					continue;
1144b458cd62SJohnny Huang 				}
1145b458cd62SJohnny Huang 				if (length == 1) {
11463cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1147b458cd62SJohnny Huang 					continue;
114876d13988SJohnny Huang 				}
114976d13988SJohnny Huang 
1150b458cd62SJohnny Huang 				if (j == 0)
11513cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1152b458cd62SJohnny Huang 				else if (j == length - 1)
1153b458cd62SJohnny Huang 					printf("\\ \"\n");
1154b458cd62SJohnny Huang 				else
1155b458cd62SJohnny Huang 					printf("| \"\n");
115676d13988SJohnny Huang 			}
1157b458cd62SJohnny Huang 		} else {
1158c947ef08SJohnny Huang 			if (length == 1) {
11593cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1160b458cd62SJohnny Huang 			} else {
1161b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1162b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1163b458cd62SJohnny Huang 			}
1164b458cd62SJohnny Huang 
1165b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1166b458cd62SJohnny Huang 
11673cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
11683cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1169b458cd62SJohnny Huang 			else
1170b458cd62SJohnny Huang 				printf("Reserved\n");
1171b458cd62SJohnny Huang 		}
1172b458cd62SJohnny Huang 	}
1173b458cd62SJohnny Huang 
1174b458cd62SJohnny Huang 	if (fail)
1175b458cd62SJohnny Huang 		return OTP_FAILURE;
1176b458cd62SJohnny Huang 
1177b458cd62SJohnny Huang 	return OTP_SUCCESS;
1178b458cd62SJohnny Huang }
1179b458cd62SJohnny Huang 
1180f347c284SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
118169d5fd8fSJohnny Huang {
118269d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
118379e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
11849a4fe690SJohnny Huang 	struct otpkey_type key_info;
1185a219f6deSJohnny Huang 	u32 *buf;
1186a219f6deSJohnny Huang 	u8 *byte_buf;
11879d998018SJohnny Huang 	char empty = 1;
118869d5fd8fSJohnny Huang 	int i = 0, len = 0;
11899a4fe690SJohnny Huang 	int j;
119054552c69SJohnny Huang 
1191696656c6SJohnny Huang 	byte_buf = image_layout->data;
1192a219f6deSJohnny Huang 	buf = (u32 *)byte_buf;
11939d998018SJohnny Huang 
11949d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
1195a219f6deSJohnny Huang 		if (buf[i] != 0)
11969d998018SJohnny Huang 			empty = 0;
11979d998018SJohnny Huang 	}
11989d998018SJohnny Huang 	if (empty)
1199f347c284SJohnny Huang 		return OTP_SUCCESS;
12009d998018SJohnny Huang 
12019d998018SJohnny Huang 	i = 0;
120269d5fd8fSJohnny Huang 	while (1) {
120369d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
120469d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
120569d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
120669d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
120769d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
120869d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
12099a4fe690SJohnny Huang 
12109a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
12119a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
12129a4fe690SJohnny Huang 				key_info = key_info_array[j];
12139a4fe690SJohnny Huang 				break;
12149a4fe690SJohnny Huang 			}
12159a4fe690SJohnny Huang 		}
12169a4fe690SJohnny Huang 
12177f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
121869d5fd8fSJohnny Huang 		printf("Key Type: ");
12199a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
12209a4fe690SJohnny Huang 
12219a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
122269d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
122369d5fd8fSJohnny Huang 			switch (key_length) {
122469d5fd8fSJohnny Huang 			case 0:
122569d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
122669d5fd8fSJohnny Huang 				break;
122769d5fd8fSJohnny Huang 			case 1:
122869d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
122969d5fd8fSJohnny Huang 				break;
123069d5fd8fSJohnny Huang 			case 2:
123169d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
123269d5fd8fSJohnny Huang 				break;
123369d5fd8fSJohnny Huang 			case 3:
123469d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
123569d5fd8fSJohnny Huang 				break;
123669d5fd8fSJohnny Huang 			}
1237181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1238181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
123969d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
124069d5fd8fSJohnny Huang 			switch (key_length) {
124169d5fd8fSJohnny Huang 			case 0:
124269d5fd8fSJohnny Huang 				printf("RSA1024\n");
124369d5fd8fSJohnny Huang 				len = 0x100;
124469d5fd8fSJohnny Huang 				break;
124569d5fd8fSJohnny Huang 			case 1:
124669d5fd8fSJohnny Huang 				printf("RSA2048\n");
124769d5fd8fSJohnny Huang 				len = 0x200;
124869d5fd8fSJohnny Huang 				break;
124969d5fd8fSJohnny Huang 			case 2:
125069d5fd8fSJohnny Huang 				printf("RSA3072\n");
125169d5fd8fSJohnny Huang 				len = 0x300;
125269d5fd8fSJohnny Huang 				break;
125369d5fd8fSJohnny Huang 			case 3:
125469d5fd8fSJohnny Huang 				printf("RSA4096\n");
125569d5fd8fSJohnny Huang 				len = 0x400;
125669d5fd8fSJohnny Huang 				break;
125769d5fd8fSJohnny Huang 			}
125869d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
125969d5fd8fSJohnny Huang 		}
12609a4fe690SJohnny Huang 		if (key_info.need_id)
126169d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
126269d5fd8fSJohnny Huang 		printf("Key Value:\n");
12639a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
126469d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
12659a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
12669a4fe690SJohnny Huang 			printf("AES Key:\n");
12679a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1268e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
12699a4fe690SJohnny Huang 				printf("AES IV:\n");
12709a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
12719a4fe690SJohnny Huang 			}
12729a4fe690SJohnny Huang 
12739a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1274e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
127569d5fd8fSJohnny Huang 				printf("AES Key:\n");
127669d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
127769d5fd8fSJohnny Huang 				printf("AES IV:\n");
127869d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
12795fdde29fSJohnny Huang 			} else {
12809a4fe690SJohnny Huang 				printf("AES Key 1:\n");
12819a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
12829a4fe690SJohnny Huang 				printf("AES Key 2:\n");
12839a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
12849a4fe690SJohnny Huang 			}
1285181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
128669d5fd8fSJohnny Huang 			printf("RSA mod:\n");
128769d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
128869d5fd8fSJohnny Huang 			printf("RSA exp:\n");
128969d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1290181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1291181f72d8SJohnny Huang 			printf("RSA mod:\n");
1292181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1293181f72d8SJohnny Huang 			printf("RSA exp:\n");
1294a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
129569d5fd8fSJohnny Huang 		}
129669d5fd8fSJohnny Huang 		if (last)
129769d5fd8fSJohnny Huang 			break;
129869d5fd8fSJohnny Huang 		i++;
129969d5fd8fSJohnny Huang 	}
1300f347c284SJohnny Huang 	return OTP_SUCCESS;
1301f347c284SJohnny Huang }
1302f347c284SJohnny Huang 
1303f347c284SJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
1304f347c284SJohnny Huang {
1305f347c284SJohnny Huang 	int i;
1306f347c284SJohnny Huang 	u32 *strap;
1307f347c284SJohnny Huang 	u32 *strap_ignore;
1308f347c284SJohnny Huang 	u32 *strap_pro;
1309*7e523e3bSJohnny Huang 	int bit, pbit, ibit;
1310f347c284SJohnny Huang 	int fail = 0;
1311f347c284SJohnny Huang 	int ret;
1312f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
1313f347c284SJohnny Huang 
1314f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1315f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1316f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1317f347c284SJohnny Huang 
1318f347c284SJohnny Huang 	otp_strap_status(otpstrap);
1319f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1320f347c284SJohnny Huang 		if (i < 32) {
1321f347c284SJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1322f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
1323f347c284SJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
1324f347c284SJohnny Huang 		} else {
1325f347c284SJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1326f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1327f347c284SJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1328f347c284SJohnny Huang 		}
1329f347c284SJohnny Huang 
1330*7e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit);
1331f347c284SJohnny Huang 
1332f347c284SJohnny Huang 		if (ret == OTP_FAILURE)
1333f347c284SJohnny Huang 			fail = 1;
1334f347c284SJohnny Huang 	}
1335f347c284SJohnny Huang 	if (fail == 1)
1336f347c284SJohnny Huang 		return OTP_FAILURE;
1337f347c284SJohnny Huang 	else
1338f347c284SJohnny Huang 		return OTP_SUCCESS;
1339f347c284SJohnny Huang }
1340f347c284SJohnny Huang 
1341f347c284SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout)
1342f347c284SJohnny Huang {
1343f347c284SJohnny Huang 	int i;
1344f347c284SJohnny Huang 	int ret;
1345f347c284SJohnny Huang 	int data_dw;
1346f347c284SJohnny Huang 	u32 data[2048];
1347f347c284SJohnny Huang 	u32 *buf;
1348f347c284SJohnny Huang 	u32 *buf_ignore;
1349f347c284SJohnny Huang 	u32 data_masked;
1350f347c284SJohnny Huang 	u32 buf_masked;
1351f347c284SJohnny Huang 
1352f347c284SJohnny Huang 	buf = (u32 *)image_layout->data;
1353f347c284SJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
1354f347c284SJohnny Huang 
1355f347c284SJohnny Huang 	data_dw = image_layout->data_length / 4;
1356f347c284SJohnny Huang 
1357f347c284SJohnny Huang 	printf("Read OTP Data:\n");
1358f347c284SJohnny Huang 
1359f347c284SJohnny Huang 	for (i = 0; i < data_dw - 2 ; i += 2)
1360f347c284SJohnny Huang 		otp_read_data(i, &data[i]);
1361f347c284SJohnny Huang 
1362f347c284SJohnny Huang 	printf("Check writable...\n");
1363f347c284SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
1364f347c284SJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1365f347c284SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1366f347c284SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
1367f347c284SJohnny Huang 		if (data_masked == buf_masked)
1368f347c284SJohnny Huang 			continue;
1369f347c284SJohnny Huang 		if (i % 2 == 0) {
1370f347c284SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
1371f347c284SJohnny Huang 				continue;
1372f347c284SJohnny Huang 			} else {
1373f347c284SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1374f347c284SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1375f347c284SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1376f347c284SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
1377f347c284SJohnny Huang 				return OTP_FAILURE;
1378f347c284SJohnny Huang 			}
1379f347c284SJohnny Huang 		} else {
1380f347c284SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1381f347c284SJohnny Huang 				continue;
1382f347c284SJohnny Huang 			} else {
1383f347c284SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1384f347c284SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1385f347c284SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1386f347c284SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
1387f347c284SJohnny Huang 				return OTP_FAILURE;
1388f347c284SJohnny Huang 			}
1389f347c284SJohnny Huang 		}
1390f347c284SJohnny Huang 	}
1391f347c284SJohnny Huang 
1392f347c284SJohnny Huang 	printf("Start Programing...\n");
1393f347c284SJohnny Huang 
1394f347c284SJohnny Huang 	// programing ecc region first
1395f347c284SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1396f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1397f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1398f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1399f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1400f347c284SJohnny Huang 			return ret;
1401f347c284SJohnny Huang 		}
1402f347c284SJohnny Huang 	}
1403f347c284SJohnny Huang 
1404f347c284SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1405f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1406f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1407f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1408f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1409f347c284SJohnny Huang 			return ret;
1410f347c284SJohnny Huang 		}
1411f347c284SJohnny Huang 	}
1412f347c284SJohnny Huang 	otp_soak(0);
1413f347c284SJohnny Huang 	return OTP_SUCCESS;
1414f347c284SJohnny Huang }
1415f347c284SJohnny Huang 
1416f347c284SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout)
1417f347c284SJohnny Huang {
1418f347c284SJohnny Huang 	u32 *strap;
1419f347c284SJohnny Huang 	u32 *strap_ignore;
1420f347c284SJohnny Huang 	u32 *strap_pro;
1421f347c284SJohnny Huang 	u32 prog_address;
1422f347c284SJohnny Huang 	int i;
1423*7e523e3bSJohnny Huang 	int bit, pbit, ibit, offset;
1424f347c284SJohnny Huang 	int fail = 0;
1425f347c284SJohnny Huang 	int ret;
1426f347c284SJohnny Huang 	int prog_flag = 0;
1427f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
1428f347c284SJohnny Huang 
1429f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1430f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1431f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1432f347c284SJohnny Huang 
1433f347c284SJohnny Huang 	printf("Read OTP Strap Region:\n");
1434f347c284SJohnny Huang 	otp_strap_status(otpstrap);
1435f347c284SJohnny Huang 
1436f347c284SJohnny Huang 	printf("Check writable...\n");
1437f347c284SJohnny Huang 	if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
1438f347c284SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
1439f347c284SJohnny Huang 		return OTP_FAILURE;
1440f347c284SJohnny Huang 	}
1441f347c284SJohnny Huang 
1442f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1443f347c284SJohnny Huang 		prog_address = 0x800;
1444f347c284SJohnny Huang 		if (i < 32) {
1445f347c284SJohnny Huang 			offset = i;
1446f347c284SJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1447f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
1448f347c284SJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
1449f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1450f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1451f347c284SJohnny Huang 
1452f347c284SJohnny Huang 		} else {
1453f347c284SJohnny Huang 			offset = (i - 32);
1454f347c284SJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1455f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
1456f347c284SJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
1457f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1458f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1459f347c284SJohnny Huang 		}
1460f347c284SJohnny Huang 
1461f347c284SJohnny Huang 		if (ibit == 1)
1462f347c284SJohnny Huang 			continue;
1463f347c284SJohnny Huang 		if (bit == otpstrap[i].value)
1464f347c284SJohnny Huang 			prog_flag = 0;
1465f347c284SJohnny Huang 		else
1466f347c284SJohnny Huang 			prog_flag = 1;
1467f347c284SJohnny Huang 
1468f347c284SJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
1469f347c284SJohnny Huang 			fail = 1;
1470f347c284SJohnny Huang 			continue;
1471f347c284SJohnny Huang 		}
1472f347c284SJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
1473f347c284SJohnny Huang 			fail = 1;
1474f347c284SJohnny Huang 			continue;
1475f347c284SJohnny Huang 		}
1476f347c284SJohnny Huang 
1477f347c284SJohnny Huang 		if (prog_flag) {
1478f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1479f347c284SJohnny Huang 			if (ret)
1480f347c284SJohnny Huang 				return OTP_FAILURE;
1481f347c284SJohnny Huang 		}
1482f347c284SJohnny Huang 
1483f347c284SJohnny Huang 		if (pbit != 0) {
1484f347c284SJohnny Huang 			prog_address = 0x800;
1485f347c284SJohnny Huang 			if (i < 32)
1486f347c284SJohnny Huang 				prog_address |= 0x60c;
1487f347c284SJohnny Huang 			else
1488f347c284SJohnny Huang 				prog_address |= 0x60e;
1489f347c284SJohnny Huang 
1490f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1491f347c284SJohnny Huang 			if (ret)
1492f347c284SJohnny Huang 				return OTP_FAILURE;
1493f347c284SJohnny Huang 		}
1494f347c284SJohnny Huang 	}
1495f347c284SJohnny Huang 	otp_soak(0);
1496f347c284SJohnny Huang 	if (fail == 1)
1497f347c284SJohnny Huang 		return OTP_FAILURE;
1498f347c284SJohnny Huang 	return OTP_SUCCESS;
149969d5fd8fSJohnny Huang }
150069d5fd8fSJohnny Huang 
15015010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout)
150269d5fd8fSJohnny Huang {
1503a6d0d645SJohnny Huang 	int i, k;
1504d90825e2SJohnny Huang 	int pass = 0;
1505a219f6deSJohnny Huang 	u32 prog_address;
1506a219f6deSJohnny Huang 	u32 data[16];
1507a219f6deSJohnny Huang 	u32 compare[2];
1508a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1509a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1510a219f6deSJohnny Huang 	u32 data_masked;
1511a219f6deSJohnny Huang 	u32 buf_masked;
151269d5fd8fSJohnny Huang 
1513a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1514a6d0d645SJohnny Huang 
1515bb34a7bfSJohnny Huang 	for (i = 0; i < 16 ; i++) {
151669d5fd8fSJohnny Huang 		prog_address = 0x800;
1517a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1518a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1519a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1520a6d0d645SJohnny Huang 	}
1521a6d0d645SJohnny Huang 
1522a6d0d645SJohnny Huang 	printf("Check writable...\n");
1523bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
15245010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
15255010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1526d90825e2SJohnny Huang 		if (data_masked == buf_masked)
152769d5fd8fSJohnny Huang 			continue;
1528d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1529a6d0d645SJohnny Huang 			continue;
1530a6d0d645SJohnny Huang 		} else {
1531a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1532a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
15335010032bSJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
15345010032bSJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
15352a856b9aSJohnny Huang 			return OTP_FAILURE;
1536a6d0d645SJohnny Huang 		}
1537a6d0d645SJohnny Huang 	}
1538a6d0d645SJohnny Huang 
1539a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1540d90825e2SJohnny Huang 	otp_soak(0);
1541bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
15425010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
15435010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1544a6d0d645SJohnny Huang 		prog_address = 0x800;
1545a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1546a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1547bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1548bb34a7bfSJohnny Huang 			pass = 1;
1549a6d0d645SJohnny Huang 			continue;
1550bb34a7bfSJohnny Huang 		}
1551de6fbf1cSJohnny Huang 
1552de6fbf1cSJohnny Huang 		otp_soak(1);
15535010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1554a6d0d645SJohnny Huang 
155569d5fd8fSJohnny Huang 		pass = 0;
155669d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
15575010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1558de6fbf1cSJohnny Huang 				otp_soak(2);
1559feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
15605010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1561de6fbf1cSJohnny Huang 					otp_soak(1);
1562de6fbf1cSJohnny Huang 				} else {
1563de6fbf1cSJohnny Huang 					pass = 1;
1564de6fbf1cSJohnny Huang 					break;
1565de6fbf1cSJohnny Huang 				}
1566a6d0d645SJohnny Huang 			} else {
156769d5fd8fSJohnny Huang 				pass = 1;
156869d5fd8fSJohnny Huang 				break;
156969d5fd8fSJohnny Huang 			}
157069d5fd8fSJohnny Huang 		}
1571bb34a7bfSJohnny Huang 		if (pass == 0) {
1572bb34a7bfSJohnny Huang 			printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
15735010032bSJohnny Huang 			       i, data[i], conf[i], conf_ignore[i]);
1574bb34a7bfSJohnny Huang 			break;
1575bb34a7bfSJohnny Huang 		}
1576a6d0d645SJohnny Huang 	}
1577a6d0d645SJohnny Huang 
1578de6fbf1cSJohnny Huang 	otp_soak(0);
157969d5fd8fSJohnny Huang 	if (!pass)
15802a856b9aSJohnny Huang 		return OTP_FAILURE;
1581a6d0d645SJohnny Huang 
15822a856b9aSJohnny Huang 	return OTP_SUCCESS;
158369d5fd8fSJohnny Huang }
158469d5fd8fSJohnny Huang 
1585f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf)
1586696656c6SJohnny Huang {
1587696656c6SJohnny Huang 	sha256_context ctx;
1588696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1589696656c6SJohnny Huang 
1590696656c6SJohnny Huang 	sha256_starts(&ctx);
1591696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1592696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1593696656c6SJohnny Huang 
1594696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1595f347c284SJohnny Huang 		return OTP_SUCCESS;
1596f347c284SJohnny Huang 	return OTP_FAILURE;
1597696656c6SJohnny Huang }
1598696656c6SJohnny Huang 
1599f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
160069d5fd8fSJohnny Huang {
160169d5fd8fSJohnny Huang 	int ret;
160261a6cda7SJohnny Huang 	int image_soc_ver = 0;
1603696656c6SJohnny Huang 	struct otp_header *otp_header;
1604696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1605696656c6SJohnny Huang 	int image_size;
1606a219f6deSJohnny Huang 	u8 *buf;
1607a219f6deSJohnny Huang 	u8 *checksum;
160869d5fd8fSJohnny Huang 
1609696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1610696656c6SJohnny Huang 	if (!otp_header) {
161169d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
16122a856b9aSJohnny Huang 		return OTP_FAILURE;
161369d5fd8fSJohnny Huang 	}
1614d90825e2SJohnny Huang 
1615696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1616696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1617696656c6SJohnny Huang 
1618696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1619696656c6SJohnny Huang 
1620696656c6SJohnny Huang 	if (!buf) {
1621696656c6SJohnny Huang 		puts("Failed to map physical memory\n");
1622696656c6SJohnny Huang 		return OTP_FAILURE;
1623696656c6SJohnny Huang 	}
1624696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1625696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1626696656c6SJohnny Huang 
1627696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1628696656c6SJohnny Huang 		puts("Image is invalid\n");
1629696656c6SJohnny Huang 		return OTP_FAILURE;
1630696656c6SJohnny Huang 	}
1631696656c6SJohnny Huang 
16325010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
16335010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
16345010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
16355010032bSJohnny Huang 
16365010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1637696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
16385010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1639696656c6SJohnny Huang 
1640696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
16415010032bSJohnny Huang 	image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
16425010032bSJohnny Huang 	image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
16435010032bSJohnny Huang 	image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
1644*7e523e3bSJohnny Huang 
1645*7e523e3bSJohnny Huang 	if (otp_header->soc_ver == SOC_AST2600A0) {
1646*7e523e3bSJohnny Huang 		image_soc_ver = OTP_A0;
164761a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A1) {
164861a6cda7SJohnny Huang 		image_soc_ver = OTP_A1;
164961a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A2) {
165061a6cda7SJohnny Huang 		image_soc_ver = OTP_A2;
165161a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A3) {
165261a6cda7SJohnny Huang 		image_soc_ver = OTP_A3;
1653696656c6SJohnny Huang 	} else {
165461a6cda7SJohnny Huang 		puts("Image SOC Version is not supported\n");
1655696656c6SJohnny Huang 		return OTP_FAILURE;
1656696656c6SJohnny Huang 	}
1657696656c6SJohnny Huang 
165861a6cda7SJohnny Huang 	if (image_soc_ver != info_cb.version) {
16599a4fe690SJohnny Huang 		puts("Version is not match\n");
16609a4fe690SJohnny Huang 		return OTP_FAILURE;
16619a4fe690SJohnny Huang 	}
16629a4fe690SJohnny Huang 
166361a6cda7SJohnny Huang 	if (otp_header->otptool_ver != OTPTOOL_VERSION(1, 0, 0)) {
166461a6cda7SJohnny Huang 		puts("OTP image is not generated by otptool v1.0.0\n");
166561a6cda7SJohnny Huang 		return OTP_FAILURE;
166661a6cda7SJohnny Huang 	}
166761a6cda7SJohnny Huang 
1668f347c284SJohnny Huang 	if (otp_verify_image(buf, image_size, checksum)) {
1669696656c6SJohnny Huang 		puts("checksum is invalid\n");
1670696656c6SJohnny Huang 		return OTP_FAILURE;
1671d90825e2SJohnny Huang 	}
16727332532cSJohnny Huang 
167369d5fd8fSJohnny Huang 	if (!nconfirm) {
1674696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
16757f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1676f347c284SJohnny Huang 			if (otp_print_data_image(&image_layout) < 0) {
167769d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
16782a856b9aSJohnny Huang 				return OTP_FAILURE;
167969d5fd8fSJohnny Huang 			}
168069d5fd8fSJohnny Huang 		}
1681696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
16827332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1683696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
16847332532cSJohnny Huang 				printf("OTP config error, please check.\n");
16857332532cSJohnny Huang 				return OTP_FAILURE;
16867332532cSJohnny Huang 			}
16877332532cSJohnny Huang 		}
16887adec5f6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
16897adec5f6SJohnny Huang 			printf("\nOTP strap region :\n");
16907adec5f6SJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
16917adec5f6SJohnny Huang 				printf("OTP strap error, please check.\n");
16927adec5f6SJohnny Huang 				return OTP_FAILURE;
16937adec5f6SJohnny Huang 			}
16947adec5f6SJohnny Huang 		}
16957332532cSJohnny Huang 
169669d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
169769d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
169869d5fd8fSJohnny Huang 			printf(" Aborting\n");
16992a856b9aSJohnny Huang 			return OTP_FAILURE;
170069d5fd8fSJohnny Huang 		}
170169d5fd8fSJohnny Huang 	}
17027332532cSJohnny Huang 
17035010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
17045010032bSJohnny Huang 		printf("programing data region ...\n");
17055010032bSJohnny Huang 		ret = otp_prog_data(&image_layout);
17065010032bSJohnny Huang 		if (ret != 0) {
17075010032bSJohnny Huang 			printf("Error\n");
17085010032bSJohnny Huang 			return ret;
17095010032bSJohnny Huang 		}
1710a219f6deSJohnny Huang 		printf("Done\n");
17115010032bSJohnny Huang 	}
17125010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
17135010032bSJohnny Huang 		printf("programing strap region ...\n");
17145010032bSJohnny Huang 		ret = otp_prog_strap(&image_layout);
17155010032bSJohnny Huang 		if (ret != 0) {
17165010032bSJohnny Huang 			printf("Error\n");
17175010032bSJohnny Huang 			return ret;
17185010032bSJohnny Huang 		}
1719a219f6deSJohnny Huang 		printf("Done\n");
17205010032bSJohnny Huang 	}
17215010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
17225010032bSJohnny Huang 		printf("programing configuration region ...\n");
17235010032bSJohnny Huang 		ret = otp_prog_conf(&image_layout);
17245010032bSJohnny Huang 		if (ret != 0) {
17255010032bSJohnny Huang 			printf("Error\n");
17265010032bSJohnny Huang 			return ret;
17275010032bSJohnny Huang 		}
17285010032bSJohnny Huang 		printf("Done\n");
17295010032bSJohnny Huang 	}
1730cd1610b4SJohnny Huang 
17317332532cSJohnny Huang 	return OTP_SUCCESS;
17322a856b9aSJohnny Huang }
17332a856b9aSJohnny Huang 
1734f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1735cd1610b4SJohnny Huang {
1736a219f6deSJohnny Huang 	u32 read[2];
1737a219f6deSJohnny Huang 	u32 prog_address = 0;
173866f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1739cd1610b4SJohnny Huang 	int otp_bit;
174083655e91SJohnny Huang 	int ret = 0;
1741cd1610b4SJohnny Huang 
1742dacbba92SJohnny Huang 	otp_soak(0);
1743cd1610b4SJohnny Huang 	switch (mode) {
1744a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1745f347c284SJohnny Huang 		otp_read_conf(otp_dw_offset, read);
1746cd1610b4SJohnny Huang 		prog_address = 0x800;
1747cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1748cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1749a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1750cd1610b4SJohnny Huang 		if (otp_bit == value) {
1751a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1752cd1610b4SJohnny Huang 			printf("No need to program\n");
17532a856b9aSJohnny Huang 			return OTP_SUCCESS;
1754cd1610b4SJohnny Huang 		}
1755cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1756a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
1757cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
17582a856b9aSJohnny Huang 			return OTP_FAILURE;
1759cd1610b4SJohnny Huang 		}
1760a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1761cd1610b4SJohnny Huang 		break;
1762a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1763cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1764cd1610b4SJohnny Huang 
1765cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1766a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1767a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1768643b9cfdSJohnny Huang 
1769643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
1770643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1771643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be cleaned\n");
1772643b9cfdSJohnny Huang 				return OTP_FAILURE;
1773643b9cfdSJohnny Huang 			}
1774cd1610b4SJohnny Huang 		} else {
1775a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1776a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1777643b9cfdSJohnny Huang 
1778643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
1779643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1780643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be writen\n");
1781643b9cfdSJohnny Huang 				return OTP_FAILURE;
1782643b9cfdSJohnny Huang 			}
1783cd1610b4SJohnny Huang 		}
1784cd1610b4SJohnny Huang 		if (otp_bit == value) {
1785a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1786cd1610b4SJohnny Huang 			printf("No need to program\n");
17872a856b9aSJohnny Huang 			return OTP_SUCCESS;
1788cd1610b4SJohnny Huang 		}
1789643b9cfdSJohnny Huang 
1790a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1791cd1610b4SJohnny Huang 		break;
1792a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
17938848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
17948848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
1795*7e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
17968848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
17978848d5dcSJohnny Huang 			return OTP_FAILURE;
17988848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
17998848d5dcSJohnny Huang 			return OTP_SUCCESS;
1800a6af4a17SJohnny Huang 
1801cd1610b4SJohnny Huang 		break;
1802cd1610b4SJohnny Huang 	}
1803cd1610b4SJohnny Huang 
1804cd1610b4SJohnny Huang 	if (!nconfirm) {
1805cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1806cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1807cd1610b4SJohnny Huang 			printf(" Aborting\n");
18082a856b9aSJohnny Huang 			return OTP_FAILURE;
1809cd1610b4SJohnny Huang 		}
1810cd1610b4SJohnny Huang 	}
1811cd1610b4SJohnny Huang 
1812cd1610b4SJohnny Huang 	switch (mode) {
1813a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1814f347c284SJohnny Huang 		ret =  otp_prog_strap_b(bit_offset, value);
181583655e91SJohnny Huang 		break;
1816a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1817a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1818f347c284SJohnny Huang 		ret = otp_prog_dc_b(value, prog_address, bit_offset);
1819de6fbf1cSJohnny Huang 		break;
1820de6fbf1cSJohnny Huang 	}
1821de6fbf1cSJohnny Huang 	otp_soak(0);
182283655e91SJohnny Huang 	if (ret) {
1823794e27ecSJohnny Huang 		printf("OTP cannot be programed\n");
1824794e27ecSJohnny Huang 		printf("FAILURE\n");
1825794e27ecSJohnny Huang 		return OTP_FAILURE;
1826794e27ecSJohnny Huang 	}
1827794e27ecSJohnny Huang 
18289009c25dSJohnny Huang 	printf("SUCCESS\n");
18292a856b9aSJohnny Huang 	return OTP_SUCCESS;
1830a219f6deSJohnny Huang }
1831a219f6deSJohnny Huang 
1832794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
1833794e27ecSJohnny Huang {
1834794e27ecSJohnny Huang 	u32 otp_rid[2];
1835a8789b47SJohnny Huang 	u32 sw_rid[2];
1836794e27ecSJohnny Huang 	int rid_num = 0;
1837a8789b47SJohnny Huang 	int sw_rid_num = 0;
1838794e27ecSJohnny Huang 	int bit_offset;
1839794e27ecSJohnny Huang 	int dw_offset;
1840794e27ecSJohnny Huang 	int i;
1841794e27ecSJohnny Huang 	int ret;
1842794e27ecSJohnny Huang 
1843f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
1844f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
1845794e27ecSJohnny Huang 
1846a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
1847a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
1848a8789b47SJohnny Huang 
1849794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1850a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
1851a8789b47SJohnny Huang 
1852a8789b47SJohnny Huang 	if (sw_rid_num < 0) {
1853a8789b47SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
1854a8789b47SJohnny Huang 		return OTP_FAILURE;
1855a8789b47SJohnny Huang 	}
1856a8789b47SJohnny Huang 
1857a8789b47SJohnny Huang 	if (update_num > sw_rid_num) {
1858a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
1859a8789b47SJohnny Huang 		printf("update number could not bigger than current SW revision id\n");
1860a8789b47SJohnny Huang 		return OTP_FAILURE;
1861a8789b47SJohnny Huang 	}
1862794e27ecSJohnny Huang 
1863794e27ecSJohnny Huang 	if (rid_num < 0) {
1864794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by this command,\n"
1865794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n");
1866794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
18679009c25dSJohnny Huang 		return OTP_FAILURE;
18689009c25dSJohnny Huang 	}
1869cd1610b4SJohnny Huang 
1870794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
1871794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1872794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
1873794e27ecSJohnny Huang 
1874a8789b47SJohnny Huang 	if (rid_num > update_num) {
1875a8789b47SJohnny Huang 		printf("OTP rev_id is bigger than 0x%X\n", update_num);
1876a8789b47SJohnny Huang 		printf("Skip\n");
1877a8789b47SJohnny Huang 		return OTP_FAILURE;
1878a8789b47SJohnny Huang 	} else if (rid_num == update_num) {
1879a8789b47SJohnny Huang 		printf("OTP rev_id is same as input\n");
1880794e27ecSJohnny Huang 		printf("Skip\n");
1881794e27ecSJohnny Huang 		return OTP_FAILURE;
1882794e27ecSJohnny Huang 	}
1883794e27ecSJohnny Huang 
1884794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1885794e27ecSJohnny Huang 		if (i < 32) {
1886794e27ecSJohnny Huang 			dw_offset = 0xa;
1887794e27ecSJohnny Huang 			bit_offset = i;
1888794e27ecSJohnny Huang 		} else {
1889794e27ecSJohnny Huang 			dw_offset = 0xb;
1890794e27ecSJohnny Huang 			bit_offset = i - 32;
1891794e27ecSJohnny Huang 		}
1892794e27ecSJohnny Huang 		printf("OTPCFG%X[%d]", dw_offset, bit_offset);
1893794e27ecSJohnny Huang 		if (i + 1 != update_num)
1894794e27ecSJohnny Huang 			printf(", ");
1895794e27ecSJohnny Huang 	}
1896794e27ecSJohnny Huang 
1897794e27ecSJohnny Huang 	printf(" will be programmed\n");
1898794e27ecSJohnny Huang 	if (force == 0) {
1899794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1900794e27ecSJohnny Huang 		if (!confirm_yesno()) {
1901794e27ecSJohnny Huang 			printf(" Aborting\n");
1902794e27ecSJohnny Huang 			return OTP_FAILURE;
1903794e27ecSJohnny Huang 		}
1904794e27ecSJohnny Huang 	}
1905794e27ecSJohnny Huang 
1906794e27ecSJohnny Huang 	ret = 0;
1907794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1908794e27ecSJohnny Huang 		if (i < 32) {
1909794e27ecSJohnny Huang 			dw_offset = 0xa04;
1910794e27ecSJohnny Huang 			bit_offset = i;
1911794e27ecSJohnny Huang 		} else {
1912794e27ecSJohnny Huang 			dw_offset = 0xa06;
1913794e27ecSJohnny Huang 			bit_offset = i - 32;
1914794e27ecSJohnny Huang 		}
1915f347c284SJohnny Huang 		if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
1916794e27ecSJohnny Huang 			printf("OTPCFG%X[%d] programming failed\n", dw_offset, bit_offset);
1917794e27ecSJohnny Huang 			ret = OTP_FAILURE;
1918794e27ecSJohnny Huang 			break;
1919794e27ecSJohnny Huang 		}
1920794e27ecSJohnny Huang 	}
1921794e27ecSJohnny Huang 
1922f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
1923f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
1924794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1925794e27ecSJohnny Huang 	if (rid_num >= 0)
1926794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
1927794e27ecSJohnny Huang 	else
1928794e27ecSJohnny Huang 		printf("OTP revision ID\n");
1929794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1930794e27ecSJohnny Huang 	if (!ret)
1931794e27ecSJohnny Huang 		printf("SUCCESS\n");
1932794e27ecSJohnny Huang 	else
1933794e27ecSJohnny Huang 		printf("FAILED\n");
1934794e27ecSJohnny Huang 	return ret;
1935794e27ecSJohnny Huang }
1936794e27ecSJohnny Huang 
19372a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
193869d5fd8fSJohnny Huang {
1939a219f6deSJohnny Huang 	u32 offset, count;
19402a856b9aSJohnny Huang 	int ret;
194169d5fd8fSJohnny Huang 
19422a856b9aSJohnny Huang 	if (argc == 4) {
19432a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
19442a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
19452a856b9aSJohnny Huang 	} else if (argc == 3) {
19462a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
19472a856b9aSJohnny Huang 		count = 1;
19482a856b9aSJohnny Huang 	} else {
194969d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
195069d5fd8fSJohnny Huang 	}
195169d5fd8fSJohnny Huang 
19522a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
19533d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1954f347c284SJohnny Huang 		ret = otp_print_conf(offset, count);
19552a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
19563d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19572a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
19582a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
19593d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
19602a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
19612a856b9aSJohnny Huang 	} else {
19622a856b9aSJohnny Huang 		return CMD_RET_USAGE;
196369d5fd8fSJohnny Huang 	}
196469d5fd8fSJohnny Huang 
19652a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
19662a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
19672a856b9aSJohnny Huang 	return CMD_RET_USAGE;
19682a856b9aSJohnny Huang }
19692a856b9aSJohnny Huang 
19702a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
19712a856b9aSJohnny Huang {
19722a856b9aSJohnny Huang 	phys_addr_t addr;
19732a856b9aSJohnny Huang 	int ret;
19742a856b9aSJohnny Huang 
1975de6b0cc4SJohnny Huang 	if (argc == 3) {
1976ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
19772a856b9aSJohnny Huang 			return CMD_RET_USAGE;
19782a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
19793d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1980f347c284SJohnny Huang 		ret = otp_prog_image(addr, 1);
1981de6b0cc4SJohnny Huang 	} else if (argc == 2) {
19822a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
19833d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
1984f347c284SJohnny Huang 		ret = otp_prog_image(addr, 0);
19852a856b9aSJohnny Huang 	} else {
19862a856b9aSJohnny Huang 		return CMD_RET_USAGE;
19872a856b9aSJohnny Huang 	}
19882a856b9aSJohnny Huang 
19892a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
19902a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
19912a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
19922a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
19932a856b9aSJohnny Huang 	else
19942a856b9aSJohnny Huang 		return CMD_RET_USAGE;
19952a856b9aSJohnny Huang }
19962a856b9aSJohnny Huang 
19972a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
19982a856b9aSJohnny Huang {
19992a856b9aSJohnny Huang 	int mode = 0;
20002a856b9aSJohnny Huang 	int nconfirm = 0;
20012a856b9aSJohnny Huang 	int otp_addr = 0;
20022a856b9aSJohnny Huang 	int bit_offset;
20032a856b9aSJohnny Huang 	int value;
20042a856b9aSJohnny Huang 	int ret;
20052a856b9aSJohnny Huang 
20062a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
20072a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20082a856b9aSJohnny Huang 
20092a856b9aSJohnny Huang 	/* Drop the pb cmd */
20102a856b9aSJohnny Huang 	argc--;
20112a856b9aSJohnny Huang 	argv++;
20122a856b9aSJohnny Huang 
20132a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2014a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
20152a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2016a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
20172a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2018a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2019cd1610b4SJohnny Huang 	else
20202a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20212a856b9aSJohnny Huang 
20222a856b9aSJohnny Huang 	/* Drop the region cmd */
20232a856b9aSJohnny Huang 	argc--;
20242a856b9aSJohnny Huang 	argv++;
20252a856b9aSJohnny Huang 
2026ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2027cd1610b4SJohnny Huang 		nconfirm = 1;
20282a856b9aSJohnny Huang 		/* Drop the force option */
20292a856b9aSJohnny Huang 		argc--;
20302a856b9aSJohnny Huang 		argv++;
20312a856b9aSJohnny Huang 	}
2032cd1610b4SJohnny Huang 
2033a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
20342a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
20352a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
20360808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
20372a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2038cd1610b4SJohnny Huang 	} else {
20392a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
20402a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
20412a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
20420808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
20432a856b9aSJohnny Huang 			return CMD_RET_USAGE;
20440808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
204578855207SJohnny Huang 			if (otp_addr >= 0x800)
20460808cc55SJohnny Huang 				return CMD_RET_USAGE;
20470808cc55SJohnny Huang 		} else {
204878855207SJohnny Huang 			if (otp_addr >= 0x20)
20490808cc55SJohnny Huang 				return CMD_RET_USAGE;
20500808cc55SJohnny Huang 		}
2051cd1610b4SJohnny Huang 	}
2052cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
20532a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2054cd1610b4SJohnny Huang 
20553d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2056f347c284SJohnny Huang 	ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
20572a856b9aSJohnny Huang 
20582a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20592a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20602a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
20612a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
20622a856b9aSJohnny Huang 	else
20632a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20642a856b9aSJohnny Huang }
20652a856b9aSJohnny Huang 
20662a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20672a856b9aSJohnny Huang {
20682a856b9aSJohnny Huang 	phys_addr_t addr;
20692a856b9aSJohnny Huang 	int otp_addr = 0;
20702a856b9aSJohnny Huang 
20712a856b9aSJohnny Huang 	if (argc != 3)
20722a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20732a856b9aSJohnny Huang 
20743d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20752a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
20762a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
20772a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
207869d5fd8fSJohnny Huang 		printf("Compare pass\n");
20792a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2080a219f6deSJohnny Huang 	}
208169d5fd8fSJohnny Huang 	printf("Compare fail\n");
20822a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
208369d5fd8fSJohnny Huang }
208469d5fd8fSJohnny Huang 
208566f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
208666f2f8e5SJohnny Huang {
2087a8bd6d8cSJohnny Huang 	int view = 0;
20882d4b0742SJohnny Huang 	int input;
2089a8bd6d8cSJohnny Huang 
2090a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
209166f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
209266f2f8e5SJohnny Huang 
20932d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
20943d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20952d4b0742SJohnny Huang 		if (argc == 3) {
20962d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
20972d4b0742SJohnny Huang 			otp_print_conf_info(input);
20982d4b0742SJohnny Huang 		} else {
20992d4b0742SJohnny Huang 			otp_print_conf_info(-1);
21002d4b0742SJohnny Huang 		}
21012d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
21022d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2103a8bd6d8cSJohnny Huang 			view = 1;
2104a8bd6d8cSJohnny Huang 			/* Drop the view option */
2105a8bd6d8cSJohnny Huang 			argc--;
2106a8bd6d8cSJohnny Huang 			argv++;
2107a8bd6d8cSJohnny Huang 		}
21083d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2109b458cd62SJohnny Huang 		otp_print_strap_info(view);
211066f2f8e5SJohnny Huang 	} else {
211166f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
211266f2f8e5SJohnny Huang 	}
21132d4b0742SJohnny Huang 
211466f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
211566f2f8e5SJohnny Huang }
211666f2f8e5SJohnny Huang 
2117e14b073cSJohnny Huang static int _do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[], int preg)
2118737ed20bSJohnny Huang {
2119737ed20bSJohnny Huang 	int input;
2120737ed20bSJohnny Huang 	int bit_offset;
2121e14b073cSJohnny Huang 	u32 prog_address;
212283655e91SJohnny Huang 	int ret;
2123e14b073cSJohnny Huang 	char info[10];
2124e14b073cSJohnny Huang 
2125e14b073cSJohnny Huang 	if (preg) {
2126e14b073cSJohnny Huang 		sprintf(info, "register ");
2127e14b073cSJohnny Huang 		prog_address = 0xe08;
2128e14b073cSJohnny Huang 	} else {
2129e14b073cSJohnny Huang 		info[0] = 0;
2130e14b073cSJohnny Huang 		prog_address = 0xe0c;
2131e14b073cSJohnny Huang 	}
2132a219f6deSJohnny Huang 
2133737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2134737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2135737ed20bSJohnny Huang 
2136e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2137737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2138737ed20bSJohnny Huang 	} else {
2139737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2140e14b073cSJohnny Huang 		printf("OTPSTRAP[%d] %swill be protected\n", input, info);
2141737ed20bSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2142737ed20bSJohnny Huang 		if (!confirm_yesno()) {
2143737ed20bSJohnny Huang 			printf(" Aborting\n");
2144737ed20bSJohnny Huang 			return CMD_RET_FAILURE;
2145737ed20bSJohnny Huang 		}
2146737ed20bSJohnny Huang 	}
2147737ed20bSJohnny Huang 
2148737ed20bSJohnny Huang 	if (input < 32) {
2149737ed20bSJohnny Huang 		bit_offset = input;
2150737ed20bSJohnny Huang 	} else if (input < 64) {
2151737ed20bSJohnny Huang 		bit_offset = input - 32;
2152e14b073cSJohnny Huang 		prog_address += 2;
2153737ed20bSJohnny Huang 	} else {
2154737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2155737ed20bSJohnny Huang 	}
2156737ed20bSJohnny Huang 
2157e14b073cSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2158e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2159e14b073cSJohnny Huang 		printf("OTPSTRAP[%d] %salready protected\n", input, info);
2160e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2161e14b073cSJohnny Huang 	}
2162de6fbf1cSJohnny Huang 
2163f347c284SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
2164de6fbf1cSJohnny Huang 	otp_soak(0);
216583655e91SJohnny Huang 
216683655e91SJohnny Huang 	if (ret) {
2167e14b073cSJohnny Huang 		printf("Protect OTPSTRAP[%d] %sfail\n", input, info);
2168737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2169737ed20bSJohnny Huang 	}
21709a4fe690SJohnny Huang 
2171794e27ecSJohnny Huang 	printf("OTPSTRAP[%d] %sis protected\n", input, info);
2172794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2173794e27ecSJohnny Huang }
2174794e27ecSJohnny Huang 
2175e14b073cSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2176e14b073cSJohnny Huang {
2177e14b073cSJohnny Huang 	return _do_otpprotect(cmdtp, flag, argc, argv, 0);
2178e14b073cSJohnny Huang }
2179e14b073cSJohnny Huang 
2180e14b073cSJohnny Huang static int do_otprprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2181e14b073cSJohnny Huang {
2182e14b073cSJohnny Huang 	return _do_otpprotect(cmdtp, flag, argc, argv, 1);
2183e14b073cSJohnny Huang }
2184e14b073cSJohnny Huang 
2185f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2186f67375f7SJohnny Huang {
2187e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
2188f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2189f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2190f67375f7SJohnny Huang 
2191f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2192f67375f7SJohnny Huang }
2193f67375f7SJohnny Huang 
2194794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2195794e27ecSJohnny Huang {
2196794e27ecSJohnny Huang 	u32 update_num;
2197794e27ecSJohnny Huang 	int force = 0;
2198794e27ecSJohnny Huang 	int ret;
2199794e27ecSJohnny Huang 
2200794e27ecSJohnny Huang 	if (argc == 3) {
2201794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2202794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2203794e27ecSJohnny Huang 		force = 1;
2204794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2205794e27ecSJohnny Huang 	} else if (argc == 2) {
2206794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2207794e27ecSJohnny Huang 	} else {
2208794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2209794e27ecSJohnny Huang 	}
2210794e27ecSJohnny Huang 
2211794e27ecSJohnny Huang 	if (update_num > 64)
2212794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2213794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2214794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2215794e27ecSJohnny Huang 	if (ret)
2216794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2217794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2218794e27ecSJohnny Huang }
2219794e27ecSJohnny Huang 
2220794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2221794e27ecSJohnny Huang {
2222794e27ecSJohnny Huang 	u32 otp_rid[2];
2223a8789b47SJohnny Huang 	u32 sw_rid[2];
2224794e27ecSJohnny Huang 	int rid_num = 0;
2225a8789b47SJohnny Huang 	int sw_rid_num = 0;
2226794e27ecSJohnny Huang 	int ret;
2227794e27ecSJohnny Huang 
2228794e27ecSJohnny Huang 	if (argc != 1)
2229794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2230794e27ecSJohnny Huang 
2231794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2232f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2233f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2234794e27ecSJohnny Huang 
2235a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2236a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2237794e27ecSJohnny Huang 
2238a8789b47SJohnny Huang 	rid_num = get_rid_num(otp_rid);
2239a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2240a8789b47SJohnny Huang 
2241a8789b47SJohnny Huang 	printf("current SW revision ID: 0x%x\n", sw_rid_num);
2242794e27ecSJohnny Huang 	if (rid_num >= 0) {
2243794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2244794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2245794e27ecSJohnny Huang 	} else {
2246794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by 'otp update',\n"
2247794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n"
2248794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2249794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2250794e27ecSJohnny Huang 	}
2251794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2252794e27ecSJohnny Huang 
2253794e27ecSJohnny Huang 	return ret;
2254794e27ecSJohnny Huang }
2255794e27ecSJohnny Huang 
22562a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2257f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
22582a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2259a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2260de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
22612a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2262737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
2263e14b073cSJohnny Huang 	U_BOOT_CMD_MKENT(rprotect, 3, 0, do_otprprotect, "", ""),
22642a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2265794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2266794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
22672a856b9aSJohnny Huang };
22682a856b9aSJohnny Huang 
22692a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
22702a856b9aSJohnny Huang {
22712a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2272a219f6deSJohnny Huang 	u32 ver;
2273e14b073cSJohnny Huang 	int ret;
22742a856b9aSJohnny Huang 
22752a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
22762a856b9aSJohnny Huang 
2277737ed20bSJohnny Huang 	/* Drop the otp command */
22782a856b9aSJohnny Huang 	argc--;
22792a856b9aSJohnny Huang 	argv++;
22802a856b9aSJohnny Huang 
2281a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
22822a856b9aSJohnny Huang 		return CMD_RET_USAGE;
22832a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
22842a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
22852a856b9aSJohnny Huang 
22860dae9d52SJohnny Huang 	ver = chip_version();
22870dae9d52SJohnny Huang 	switch (ver) {
2288e417205bSJohnny Huang 	case OTP_A0:
2289e417205bSJohnny Huang 		info_cb.version = OTP_A0;
22909a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
22919a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
22929a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
22939a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
22949a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
22959a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2296e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
22970dae9d52SJohnny Huang 		break;
2298e417205bSJohnny Huang 	case OTP_A1:
2299e417205bSJohnny Huang 		info_cb.version = OTP_A1;
23003cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
23013cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
23023cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
23033cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
23049a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
23059a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
2306e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
23070dae9d52SJohnny Huang 		break;
2308e417205bSJohnny Huang 	case OTP_A2:
2309e417205bSJohnny Huang 		info_cb.version = OTP_A2;
23105fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
23115fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
2312fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2313fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
23145fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
23155fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
2316e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
23170dae9d52SJohnny Huang 		break;
2318e417205bSJohnny Huang 	case OTP_A3:
2319e417205bSJohnny Huang 		info_cb.version = OTP_A3;
2320b63af886SJohnny Huang 		info_cb.conf_info = a3_conf_info;
2321b63af886SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
2322fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2323fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
2324181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2325181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
2326e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
232764b66712SJohnny Huang 		break;
23280dae9d52SJohnny Huang 	default:
2329f1be5099SJohnny Huang 		printf("SOC is not supported\n");
23300dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
23319a4fe690SJohnny Huang 	}
23329a4fe690SJohnny Huang 
2333e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2334e14b073cSJohnny Huang 	writel(1, OTP_PROTECT_KEY); //password
2335e14b073cSJohnny Huang 
2336e14b073cSJohnny Huang 	return ret;
233769d5fd8fSJohnny Huang }
233869d5fd8fSJohnny Huang 
2339a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
234069d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2341f67375f7SJohnny Huang 	   "version\n"
2342f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
23432a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
23442d4b0742SJohnny Huang 	   "otp info strap [v]\n"
23452d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
2346de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2347ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2348ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2349ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
2350e14b073cSJohnny Huang 	   "otp rprotect [o] <bit_offset>\n"
2351794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2352794e27ecSJohnny Huang 	   "otp rid\n"
235369d5fd8fSJohnny Huang 	  );
2354