xref: /openbmc/u-boot/cmd/otp.c (revision a8789b471f84d9bd97366c48eb075cb286685388)
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
56*a8789b47SJohnny Huang #define SW_REV_ID0		OTP_BASE + 0x68
57*a8789b47SJohnny 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
77e417205bSJohnny Huang #define ID1_AST2600A1	0x05010203
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 
97696656c6SJohnny Huang struct otp_header {
98696656c6SJohnny Huang 	u8	otp_magic[8];
99696656c6SJohnny Huang 	u8	otp_version[8];
100696656c6SJohnny Huang 	u32	image_info;
101696656c6SJohnny Huang 	u32	data_info;
102696656c6SJohnny Huang 	u32	config_info;
103696656c6SJohnny Huang 	u32	strap_info;
104696656c6SJohnny Huang 	u32	checksum_offset;
105a219f6deSJohnny Huang } __packed;
106696656c6SJohnny Huang 
10766f2f8e5SJohnny Huang struct otpstrap_status {
10869d5fd8fSJohnny Huang 	int value;
10969d5fd8fSJohnny Huang 	int option_array[7];
11069d5fd8fSJohnny Huang 	int remain_times;
11169d5fd8fSJohnny Huang 	int writeable_option;
1125010032bSJohnny Huang 	int reg_protected;
11369d5fd8fSJohnny Huang 	int protected;
11469d5fd8fSJohnny Huang };
11569d5fd8fSJohnny Huang 
11666f2f8e5SJohnny Huang struct otpconf_parse {
11766f2f8e5SJohnny Huang 	int dw_offset;
11866f2f8e5SJohnny Huang 	int bit;
11966f2f8e5SJohnny Huang 	int length;
12066f2f8e5SJohnny Huang 	int value;
121696656c6SJohnny Huang 	int ignore;
12266f2f8e5SJohnny Huang 	char status[80];
12366f2f8e5SJohnny Huang };
12466f2f8e5SJohnny Huang 
1259a4fe690SJohnny Huang struct otpkey_type {
1269a4fe690SJohnny Huang 	int value;
1279a4fe690SJohnny Huang 	int key_type;
1289a4fe690SJohnny Huang 	int need_id;
1299a4fe690SJohnny Huang 	char information[110];
1309a4fe690SJohnny Huang };
1319a4fe690SJohnny Huang 
1329a4fe690SJohnny Huang struct otp_info_cb {
1339a4fe690SJohnny Huang 	int version;
134e417205bSJohnny Huang 	char ver_name[3];
13579e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1369a4fe690SJohnny Huang 	int strap_info_len;
13779e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1389a4fe690SJohnny Huang 	int conf_info_len;
13979e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1409a4fe690SJohnny Huang 	int key_info_len;
1419a4fe690SJohnny Huang };
1429a4fe690SJohnny Huang 
143696656c6SJohnny Huang struct otp_image_layout {
1445010032bSJohnny Huang 	int data_length;
1455010032bSJohnny Huang 	int conf_length;
1465010032bSJohnny Huang 	int strap_length;
147a219f6deSJohnny Huang 	u8 *data;
148a219f6deSJohnny Huang 	u8 *data_ignore;
149a219f6deSJohnny Huang 	u8 *conf;
150a219f6deSJohnny Huang 	u8 *conf_ignore;
151a219f6deSJohnny Huang 	u8 *strap;
152a219f6deSJohnny Huang 	u8 *strap_reg_pro;
153a219f6deSJohnny Huang 	u8 *strap_pro;
154a219f6deSJohnny Huang 	u8 *strap_ignore;
155696656c6SJohnny Huang };
156696656c6SJohnny Huang 
1579a4fe690SJohnny Huang static struct otp_info_cb info_cb;
1589a4fe690SJohnny Huang 
15979e42a59SJoel Stanley static const struct otpkey_type a0_key_type[] = {
1609a4fe690SJohnny Huang 	{0, OTP_KEY_TYPE_AES,   0, "AES-256 as OEM platform key for image encryption/decryption"},
1619a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1629a4fe690SJohnny Huang 	{4, OTP_KEY_TYPE_HMAC,  1, "HMAC as encrypted OEM HMAC keys in Mode 1"},
163181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
164181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   0, "RSA-public as SOC public key"},
165181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
166181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as SOC private key"},
167181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1689a4fe690SJohnny Huang };
1699a4fe690SJohnny Huang 
17079e42a59SJoel Stanley static const struct otpkey_type a1_key_type[] = {
1719a4fe690SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1729a4fe690SJohnny 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"},
173181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
174181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
175181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
1769a4fe690SJohnny Huang };
1779a4fe690SJohnny Huang 
1785fdde29fSJohnny Huang static const struct otpkey_type a2_key_type[] = {
1795fdde29fSJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
1805fdde29fSJohnny 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"},
181181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
182181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
183181f72d8SJohnny Huang 	{14, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
184181f72d8SJohnny Huang };
185181f72d8SJohnny Huang 
186181f72d8SJohnny Huang static const struct otpkey_type a3_key_type[] = {
187181f72d8SJohnny Huang 	{1, OTP_KEY_TYPE_VAULT, 0, "AES-256 as secret vault key"},
188181f72d8SJohnny 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"},
189181f72d8SJohnny Huang 	{8, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2"},
190181f72d8SJohnny Huang 	{9, OTP_KEY_TYPE_RSA_PUB,   1, "RSA-public as OEM DSS public keys in Mode 2(big endian)"},
191181f72d8SJohnny Huang 	{10, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key"},
192181f72d8SJohnny Huang 	{11, OTP_KEY_TYPE_RSA_PUB,  0, "RSA-public as AES key decryption key(big endian)"},
193181f72d8SJohnny Huang 	{12, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key"},
194181f72d8SJohnny Huang 	{13, OTP_KEY_TYPE_RSA_PRIV,  0, "RSA-private as AES key decryption key(big endian)"},
1955fdde29fSJohnny Huang };
1965fdde29fSJohnny Huang 
197f347c284SJohnny Huang static void buf_print(u8 *buf, int len)
198f347c284SJohnny Huang {
199f347c284SJohnny Huang 	int i;
200f347c284SJohnny Huang 
201f347c284SJohnny Huang 	printf("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
202f347c284SJohnny Huang 	for (i = 0; i < len; i++) {
203f347c284SJohnny Huang 		if (i % 16 == 0)
204f347c284SJohnny Huang 			printf("%04X: ", i);
205f347c284SJohnny Huang 		printf("%02X ", buf[i]);
206f347c284SJohnny Huang 		if ((i + 1) % 16 == 0)
207f347c284SJohnny Huang 			printf("\n");
208f347c284SJohnny Huang 	}
209f347c284SJohnny Huang }
210f347c284SJohnny Huang 
211794e27ecSJohnny Huang static int get_dw_bit(u32 *rid, int offset)
212794e27ecSJohnny Huang {
213794e27ecSJohnny Huang 	int bit_offset;
214794e27ecSJohnny Huang 	int i;
215794e27ecSJohnny Huang 
216794e27ecSJohnny Huang 	if (offset < 32) {
217794e27ecSJohnny Huang 		i = 0;
218794e27ecSJohnny Huang 		bit_offset = offset;
219794e27ecSJohnny Huang 	} else {
220794e27ecSJohnny Huang 		i = 1;
221794e27ecSJohnny Huang 		bit_offset = offset - 32;
222794e27ecSJohnny Huang 	}
223794e27ecSJohnny Huang 	if ((rid[i] >> bit_offset) & 0x1)
224794e27ecSJohnny Huang 		return 1;
225794e27ecSJohnny Huang 	else
226794e27ecSJohnny Huang 		return 0;
227794e27ecSJohnny Huang }
228794e27ecSJohnny Huang 
229794e27ecSJohnny Huang static int get_rid_num(u32 *rid)
230794e27ecSJohnny Huang {
231794e27ecSJohnny Huang 	int i;
232794e27ecSJohnny Huang 	int fz = 0;
233794e27ecSJohnny Huang 	int rid_num = 0;
234794e27ecSJohnny Huang 	int ret = 0;
235794e27ecSJohnny Huang 
236794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
237794e27ecSJohnny Huang 		if (get_dw_bit(rid, i) == 0) {
238794e27ecSJohnny Huang 			if (!fz)
239794e27ecSJohnny Huang 				fz = 1;
240794e27ecSJohnny Huang 
241794e27ecSJohnny Huang 		} else {
242794e27ecSJohnny Huang 			rid_num++;
243794e27ecSJohnny Huang 			if (fz)
244794e27ecSJohnny Huang 				ret = OTP_FAILURE;
245794e27ecSJohnny Huang 		}
246794e27ecSJohnny Huang 	}
247794e27ecSJohnny Huang 	if (ret)
248794e27ecSJohnny Huang 		return ret;
249794e27ecSJohnny Huang 
250794e27ecSJohnny Huang 	return rid_num;
251794e27ecSJohnny Huang }
252794e27ecSJohnny Huang 
253a219f6deSJohnny Huang static u32 chip_version(void)
2549a4fe690SJohnny Huang {
255e417205bSJohnny Huang 	u32 revid0, revid1;
2569a4fe690SJohnny Huang 
257e417205bSJohnny Huang 	revid0 = readl(ASPEED_REVISION_ID0);
258e417205bSJohnny Huang 	revid1 = readl(ASPEED_REVISION_ID1);
2599a4fe690SJohnny Huang 
260e417205bSJohnny Huang 	if (revid0 == ID0_AST2600A0 && revid1 == ID1_AST2600A0) {
261badd21c2SJohnny Huang 		/* AST2600-A0 */
262e417205bSJohnny Huang 		return OTP_A0;
263e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A1 && revid1 == ID1_AST2600A1) {
264badd21c2SJohnny Huang 		/* AST2600-A1 */
265e417205bSJohnny Huang 		return OTP_A1;
266e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A2 && revid1 == ID1_AST2600A2) {
267badd21c2SJohnny Huang 		/* AST2600-A2 */
268e417205bSJohnny Huang 		return OTP_A2;
269e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2600A3 && revid1 == ID1_AST2600A3) {
27064b66712SJohnny Huang 		/* AST2600-A3 */
271e417205bSJohnny Huang 		return OTP_A3;
272e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A1 && revid1 == ID1_AST2620A1) {
273e417205bSJohnny Huang 		/* AST2620-A1 */
274e417205bSJohnny Huang 		return OTP_A1;
275e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A2 && revid1 == ID1_AST2620A2) {
276e417205bSJohnny Huang 		/* AST2620-A2 */
277e417205bSJohnny Huang 		return OTP_A2;
278e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2620A3 && revid1 == ID1_AST2620A3) {
27964b66712SJohnny Huang 		/* AST2620-A3 */
280e417205bSJohnny Huang 		return OTP_A3;
281e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A2 && revid1 == ID1_AST2605A2) {
282e417205bSJohnny Huang 		/* AST2605-A2 */
283e417205bSJohnny Huang 		return OTP_A2;
284e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2605A3 && revid1 == ID1_AST2605A3) {
285e417205bSJohnny Huang 		/* AST2605-A3 */
286e417205bSJohnny Huang 		return OTP_A3;
287e417205bSJohnny Huang 	} else if (revid0 == ID0_AST2625A3 && revid1 == ID1_AST2625A3) {
288e417205bSJohnny Huang 		/* AST2605-A3 */
289e417205bSJohnny Huang 		return OTP_A3;
2900dae9d52SJohnny Huang 	}
291f347c284SJohnny Huang 	return OTP_FAILURE;
2929a4fe690SJohnny Huang }
2939a4fe690SJohnny Huang 
2943d3688adSJohnny Huang static void wait_complete(void)
2953d3688adSJohnny Huang {
2963d3688adSJohnny Huang 	int reg;
2973d3688adSJohnny Huang 
2983d3688adSJohnny Huang 	do {
2993d3688adSJohnny Huang 		reg = readl(OTP_STATUS);
3003d3688adSJohnny Huang 	} while ((reg & 0x6) != 0x6);
3013d3688adSJohnny Huang }
3023d3688adSJohnny Huang 
303a219f6deSJohnny Huang static void otp_write(u32 otp_addr, u32 data)
304dacbba92SJohnny Huang {
305dacbba92SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
306dacbba92SJohnny Huang 	writel(data, OTP_COMPARE_1); //write data
307dacbba92SJohnny Huang 	writel(0x23b1e362, OTP_COMMAND); //write command
308dacbba92SJohnny Huang 	wait_complete();
309dacbba92SJohnny Huang }
310dacbba92SJohnny Huang 
311dacbba92SJohnny Huang static void otp_soak(int soak)
312dacbba92SJohnny Huang {
313e417205bSJohnny Huang 	if (info_cb.version == OTP_A2 || info_cb.version == OTP_A3) {
314dacbba92SJohnny Huang 		switch (soak) {
315dacbba92SJohnny Huang 		case 0: //default
316dacbba92SJohnny Huang 			otp_write(0x3000, 0x0210); // Write MRA
317dacbba92SJohnny Huang 			otp_write(0x5000, 0x2000); // Write MRB
318dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
319dacbba92SJohnny Huang 			break;
320dacbba92SJohnny Huang 		case 1: //normal program
321dacbba92SJohnny Huang 			otp_write(0x3000, 0x1200); // Write MRA
322feea3fdfSJohnny Huang 			otp_write(0x5000, 0x107F); // Write MRB
323dacbba92SJohnny Huang 			otp_write(0x1000, 0x1024); // Write MR
324feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
325dacbba92SJohnny Huang 			break;
326dacbba92SJohnny Huang 		case 2: //soak program
327dacbba92SJohnny Huang 			otp_write(0x3000, 0x1220); // Write MRA
328feea3fdfSJohnny Huang 			otp_write(0x5000, 0x2074); // Write MRB
329dacbba92SJohnny Huang 			otp_write(0x1000, 0x08a4); // Write MR
330feea3fdfSJohnny Huang 			writel(0x04193a98, OTP_TIMING); // 600us
331dacbba92SJohnny Huang 			break;
332dacbba92SJohnny Huang 		}
333dacbba92SJohnny Huang 	} else {
334dacbba92SJohnny Huang 		switch (soak) {
335dacbba92SJohnny Huang 		case 0: //default
336dacbba92SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
337dacbba92SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
338dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
339dacbba92SJohnny Huang 			break;
340dacbba92SJohnny Huang 		case 1: //normal program
341dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
342dacbba92SJohnny Huang 			otp_write(0x5000, 0x302f); // Write MRB
343dacbba92SJohnny Huang 			otp_write(0x1000, 0x4020); // Write MR
344feea3fdfSJohnny Huang 			writel(0x04190760, OTP_TIMING); // 75us
345dacbba92SJohnny Huang 			break;
346dacbba92SJohnny Huang 		case 2: //soak program
347dacbba92SJohnny Huang 			otp_write(0x3000, 0x4021); // Write MRA
348dacbba92SJohnny Huang 			otp_write(0x5000, 0x1027); // Write MRB
349dacbba92SJohnny Huang 			otp_write(0x1000, 0x4820); // Write MR
350feea3fdfSJohnny Huang 			writel(0x041930d4, OTP_TIMING); // 500us
351dacbba92SJohnny Huang 			break;
352dacbba92SJohnny Huang 		}
353dacbba92SJohnny Huang 	}
354dacbba92SJohnny Huang 
355dacbba92SJohnny Huang 	wait_complete();
356dacbba92SJohnny Huang }
357dacbba92SJohnny Huang 
358a219f6deSJohnny Huang static void otp_read_data(u32 offset, u32 *data)
35969d5fd8fSJohnny Huang {
3603d3688adSJohnny Huang 	writel(offset, OTP_ADDR); //Read address
3613d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3623d3688adSJohnny Huang 	wait_complete();
3633d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
3643d3688adSJohnny Huang 	data[1] = readl(OTP_COMPARE_2);
36569d5fd8fSJohnny Huang }
36669d5fd8fSJohnny Huang 
367f347c284SJohnny Huang static void otp_read_conf(u32 offset, u32 *data)
36869d5fd8fSJohnny Huang {
36969d5fd8fSJohnny Huang 	int config_offset;
37069d5fd8fSJohnny Huang 
37169d5fd8fSJohnny Huang 	config_offset = 0x800;
37269d5fd8fSJohnny Huang 	config_offset |= (offset / 8) * 0x200;
37369d5fd8fSJohnny Huang 	config_offset |= (offset % 8) * 0x2;
37469d5fd8fSJohnny Huang 
3753d3688adSJohnny Huang 	writel(config_offset, OTP_ADDR);  //Read address
3763d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
3773d3688adSJohnny Huang 	wait_complete();
3783d3688adSJohnny Huang 	data[0] = readl(OTP_COMPARE_1);
37969d5fd8fSJohnny Huang }
38069d5fd8fSJohnny Huang 
381a219f6deSJohnny Huang static int otp_compare(u32 otp_addr, u32 addr)
38269d5fd8fSJohnny Huang {
383a219f6deSJohnny Huang 	u32 ret;
384a219f6deSJohnny Huang 	u32 *buf;
38569d5fd8fSJohnny Huang 
38669d5fd8fSJohnny Huang 	buf = map_physmem(addr, 16, MAP_WRBACK);
38769d5fd8fSJohnny Huang 	printf("%08X\n", buf[0]);
38869d5fd8fSJohnny Huang 	printf("%08X\n", buf[1]);
38969d5fd8fSJohnny Huang 	printf("%08X\n", buf[2]);
39069d5fd8fSJohnny Huang 	printf("%08X\n", buf[3]);
3913d3688adSJohnny Huang 	writel(otp_addr, OTP_ADDR); //Compare address
3923d3688adSJohnny Huang 	writel(buf[0], OTP_COMPARE_1); //Compare data 1
3933d3688adSJohnny Huang 	writel(buf[1], OTP_COMPARE_2); //Compare data 2
3943d3688adSJohnny Huang 	writel(buf[2], OTP_COMPARE_3); //Compare data 3
3953d3688adSJohnny Huang 	writel(buf[3], OTP_COMPARE_4); //Compare data 4
3963d3688adSJohnny Huang 	writel(0x23b1e363, OTP_COMMAND); //Compare command
3973d3688adSJohnny Huang 	wait_complete();
3983d3688adSJohnny Huang 	ret = readl(OTP_STATUS); //Compare command
39969d5fd8fSJohnny Huang 	if (ret & 0x1)
400f347c284SJohnny Huang 		return OTP_SUCCESS;
40169d5fd8fSJohnny Huang 	else
402f347c284SJohnny Huang 		return OTP_FAILURE;
40369d5fd8fSJohnny Huang }
40469d5fd8fSJohnny Huang 
405a219f6deSJohnny Huang static int verify_bit(u32 otp_addr, int bit_offset, int value)
40669d5fd8fSJohnny Huang {
407a219f6deSJohnny Huang 	u32 ret[2];
40869d5fd8fSJohnny Huang 
40930a8c590SJohnny Huang 	if (otp_addr % 2 == 0)
4103d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
41130a8c590SJohnny Huang 	else
4123d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
41330a8c590SJohnny Huang 
4143d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4153d3688adSJohnny Huang 	wait_complete();
4163d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4173d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
41883655e91SJohnny Huang 
41930a8c590SJohnny Huang 	if (otp_addr % 2 == 0) {
42030a8c590SJohnny Huang 		if (((ret[0] >> bit_offset) & 1) == value)
421f347c284SJohnny Huang 			return OTP_SUCCESS;
42269d5fd8fSJohnny Huang 		else
423f347c284SJohnny Huang 			return OTP_FAILURE;
42430a8c590SJohnny Huang 	} else {
42530a8c590SJohnny Huang 		if (((ret[1] >> bit_offset) & 1) == value)
426f347c284SJohnny Huang 			return OTP_SUCCESS;
42730a8c590SJohnny Huang 		else
428f347c284SJohnny Huang 			return OTP_FAILURE;
42930a8c590SJohnny Huang 	}
43069d5fd8fSJohnny Huang }
43169d5fd8fSJohnny Huang 
432a219f6deSJohnny Huang static u32 verify_dw(u32 otp_addr, u32 *value, u32 *ignore, u32 *compare, int size)
4334c1c9b35SJohnny Huang {
434a219f6deSJohnny Huang 	u32 ret[2];
4354c1c9b35SJohnny Huang 
4364c1c9b35SJohnny Huang 	otp_addr &= ~(1 << 15);
4374c1c9b35SJohnny Huang 
4384c1c9b35SJohnny Huang 	if (otp_addr % 2 == 0)
4393d3688adSJohnny Huang 		writel(otp_addr, OTP_ADDR); //Read address
4404c1c9b35SJohnny Huang 	else
4413d3688adSJohnny Huang 		writel(otp_addr - 1, OTP_ADDR); //Read address
4423d3688adSJohnny Huang 	writel(0x23b1e361, OTP_COMMAND); //trigger read
4433d3688adSJohnny Huang 	wait_complete();
4443d3688adSJohnny Huang 	ret[0] = readl(OTP_COMPARE_1);
4453d3688adSJohnny Huang 	ret[1] = readl(OTP_COMPARE_2);
4464c1c9b35SJohnny Huang 	if (size == 1) {
4474c1c9b35SJohnny Huang 		if (otp_addr % 2 == 0) {
4484c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[0], value[0]);
449696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0])) {
4504c1c9b35SJohnny Huang 				compare[0] = 0;
451f347c284SJohnny Huang 				return OTP_SUCCESS;
452a219f6deSJohnny Huang 			}
4534c1c9b35SJohnny Huang 			compare[0] = value[0] ^ ret[0];
454f347c284SJohnny Huang 			return OTP_FAILURE;
4554c1c9b35SJohnny Huang 
4564c1c9b35SJohnny Huang 		} else {
4574c1c9b35SJohnny Huang 			// printf("check %x : %x = %x\n", otp_addr, ret[1], value[0]);
458696656c6SJohnny Huang 			if ((value[0] & ~ignore[0]) == (ret[1] & ~ignore[0])) {
4594c1c9b35SJohnny Huang 				compare[0] = ~0;
460f347c284SJohnny Huang 				return OTP_SUCCESS;
461a219f6deSJohnny Huang 			}
462d90825e2SJohnny Huang 			compare[0] = ~(value[0] ^ ret[1]);
463f347c284SJohnny Huang 			return OTP_FAILURE;
4644c1c9b35SJohnny Huang 		}
4654c1c9b35SJohnny Huang 	} else if (size == 2) {
4664c1c9b35SJohnny Huang 		// otp_addr should be even
467696656c6SJohnny Huang 		if ((value[0] & ~ignore[0]) == (ret[0] & ~ignore[0]) && (value[1] & ~ignore[1]) == (ret[1] & ~ignore[1])) {
4684c1c9b35SJohnny Huang 			// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4694c1c9b35SJohnny Huang 			// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4704c1c9b35SJohnny Huang 			compare[0] = 0;
4714c1c9b35SJohnny Huang 			compare[1] = ~0;
472f347c284SJohnny Huang 			return OTP_SUCCESS;
473a219f6deSJohnny Huang 		}
4744c1c9b35SJohnny Huang 		// printf("check[0] %x : %x = %x\n", otp_addr, ret[0], value[0]);
4754c1c9b35SJohnny Huang 		// printf("check[1] %x : %x = %x\n", otp_addr, ret[1], value[1]);
4764c1c9b35SJohnny Huang 		compare[0] = value[0] ^ ret[0];
4774c1c9b35SJohnny Huang 		compare[1] = ~(value[1] ^ ret[1]);
478f347c284SJohnny Huang 		return OTP_FAILURE;
4794c1c9b35SJohnny Huang 	} else {
480f347c284SJohnny Huang 		return OTP_FAILURE;
4814c1c9b35SJohnny Huang 	}
4824c1c9b35SJohnny Huang }
4834c1c9b35SJohnny Huang 
484a219f6deSJohnny Huang static void otp_prog(u32 otp_addr, u32 prog_bit)
48583655e91SJohnny Huang {
48690965bb3SJohnny Huang 	otp_write(0x0, prog_bit);
48783655e91SJohnny Huang 	writel(otp_addr, OTP_ADDR); //write address
48883655e91SJohnny Huang 	writel(prog_bit, OTP_COMPARE_1); //write data
48983655e91SJohnny Huang 	writel(0x23b1e364, OTP_COMMAND); //write command
49083655e91SJohnny Huang 	wait_complete();
49183655e91SJohnny Huang }
49283655e91SJohnny Huang 
493a219f6deSJohnny Huang static void _otp_prog_bit(u32 value, u32 prog_address, u32 bit_offset)
49483655e91SJohnny Huang {
49583655e91SJohnny Huang 	int prog_bit;
49683655e91SJohnny Huang 
49783655e91SJohnny Huang 	if (prog_address % 2 == 0) {
49883655e91SJohnny Huang 		if (value)
49983655e91SJohnny Huang 			prog_bit = ~(0x1 << bit_offset);
50083655e91SJohnny Huang 		else
50183655e91SJohnny Huang 			return;
50283655e91SJohnny Huang 	} else {
503e417205bSJohnny Huang 		if (info_cb.version != OTP_A3)
50483655e91SJohnny Huang 			prog_address |= 1 << 15;
50583655e91SJohnny Huang 		if (!value)
50683655e91SJohnny Huang 			prog_bit = 0x1 << bit_offset;
50783655e91SJohnny Huang 		else
50883655e91SJohnny Huang 			return;
50983655e91SJohnny Huang 	}
51083655e91SJohnny Huang 	otp_prog(prog_address, prog_bit);
51183655e91SJohnny Huang }
51283655e91SJohnny Huang 
513f347c284SJohnny Huang static int otp_prog_dc_b(u32 value, u32 prog_address, u32 bit_offset)
51483655e91SJohnny Huang {
51583655e91SJohnny Huang 	int pass;
51683655e91SJohnny Huang 	int i;
51783655e91SJohnny Huang 
51883655e91SJohnny Huang 	otp_soak(1);
51983655e91SJohnny Huang 	_otp_prog_bit(value, prog_address, bit_offset);
52083655e91SJohnny Huang 	pass = 0;
52183655e91SJohnny Huang 
52283655e91SJohnny Huang 	for (i = 0; i < RETRY; i++) {
52383655e91SJohnny Huang 		if (verify_bit(prog_address, bit_offset, value) != 0) {
52483655e91SJohnny Huang 			otp_soak(2);
52583655e91SJohnny Huang 			_otp_prog_bit(value, prog_address, bit_offset);
52683655e91SJohnny Huang 			if (verify_bit(prog_address, bit_offset, value) != 0) {
52783655e91SJohnny Huang 				otp_soak(1);
52883655e91SJohnny Huang 			} else {
52983655e91SJohnny Huang 				pass = 1;
53083655e91SJohnny Huang 				break;
53183655e91SJohnny Huang 			}
53283655e91SJohnny Huang 		} else {
53383655e91SJohnny Huang 			pass = 1;
53483655e91SJohnny Huang 			break;
53583655e91SJohnny Huang 		}
53683655e91SJohnny Huang 	}
537794e27ecSJohnny Huang 	if (pass)
538794e27ecSJohnny Huang 		return OTP_SUCCESS;
53983655e91SJohnny Huang 
540794e27ecSJohnny Huang 	return OTP_FAILURE;
54183655e91SJohnny Huang }
54283655e91SJohnny Huang 
543a219f6deSJohnny Huang static void otp_prog_dw(u32 value, u32 ignore, u32 prog_address)
544d90825e2SJohnny Huang {
545d90825e2SJohnny Huang 	int j, bit_value, prog_bit;
546d90825e2SJohnny Huang 
547d90825e2SJohnny Huang 	for (j = 0; j < 32; j++) {
548696656c6SJohnny Huang 		if ((ignore >> j) & 0x1)
549d90825e2SJohnny Huang 			continue;
550d90825e2SJohnny Huang 		bit_value = (value >> j) & 0x1;
551d90825e2SJohnny Huang 		if (prog_address % 2 == 0) {
552d90825e2SJohnny Huang 			if (bit_value)
553d90825e2SJohnny Huang 				prog_bit = ~(0x1 << j);
554d90825e2SJohnny Huang 			else
555d90825e2SJohnny Huang 				continue;
556d90825e2SJohnny Huang 		} else {
557e417205bSJohnny Huang 			if (info_cb.version != OTP_A3)
558d90825e2SJohnny Huang 				prog_address |= 1 << 15;
559d90825e2SJohnny Huang 			if (bit_value)
560d90825e2SJohnny Huang 				continue;
561d90825e2SJohnny Huang 			else
562d90825e2SJohnny Huang 				prog_bit = 0x1 << j;
563d90825e2SJohnny Huang 		}
564d90825e2SJohnny Huang 		otp_prog(prog_address, prog_bit);
565d90825e2SJohnny Huang 	}
566d90825e2SJohnny Huang }
567d90825e2SJohnny Huang 
568a219f6deSJohnny Huang static int otp_prog_verify_2dw(u32 *data, u32 *buf, u32 *ignore_mask, u32 prog_address)
56954552c69SJohnny Huang {
57054552c69SJohnny Huang 	int pass;
57154552c69SJohnny Huang 	int i;
572a219f6deSJohnny Huang 	u32 data0_masked;
573a219f6deSJohnny Huang 	u32 data1_masked;
574a219f6deSJohnny Huang 	u32 buf0_masked;
575a219f6deSJohnny Huang 	u32 buf1_masked;
576a219f6deSJohnny Huang 	u32 compare[2];
57754552c69SJohnny Huang 
57854552c69SJohnny Huang 	data0_masked = data[0]  & ~ignore_mask[0];
57954552c69SJohnny Huang 	buf0_masked  = buf[0] & ~ignore_mask[0];
58054552c69SJohnny Huang 	data1_masked = data[1]  & ~ignore_mask[1];
58154552c69SJohnny Huang 	buf1_masked  = buf[1] & ~ignore_mask[1];
582a219f6deSJohnny Huang 	if (data0_masked == buf0_masked && data1_masked == buf1_masked)
583f347c284SJohnny Huang 		return OTP_SUCCESS;
58454552c69SJohnny Huang 
58554552c69SJohnny Huang 	otp_soak(1);
58654552c69SJohnny Huang 	if (data0_masked != buf0_masked)
58754552c69SJohnny Huang 		otp_prog_dw(buf[0], ignore_mask[0], prog_address);
58854552c69SJohnny Huang 	if (data1_masked != buf1_masked)
58954552c69SJohnny Huang 		otp_prog_dw(buf[1], ignore_mask[1], prog_address + 1);
59054552c69SJohnny Huang 
59154552c69SJohnny Huang 	pass = 0;
59254552c69SJohnny Huang 	for (i = 0; i < RETRY; i++) {
59354552c69SJohnny Huang 		if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
59454552c69SJohnny Huang 			otp_soak(2);
595a219f6deSJohnny Huang 			if (compare[0] != 0)
59654552c69SJohnny Huang 				otp_prog_dw(compare[0], ignore_mask[0], prog_address);
597a219f6deSJohnny Huang 			if (compare[1] != ~0)
5985537bc72SJohnny Huang 				otp_prog_dw(compare[1], ignore_mask[1], prog_address + 1);
59954552c69SJohnny Huang 			if (verify_dw(prog_address, buf, ignore_mask, compare, 2) != 0) {
60054552c69SJohnny Huang 				otp_soak(1);
60154552c69SJohnny Huang 			} else {
60254552c69SJohnny Huang 				pass = 1;
60354552c69SJohnny Huang 				break;
60454552c69SJohnny Huang 			}
60554552c69SJohnny Huang 		} else {
60654552c69SJohnny Huang 			pass = 1;
60754552c69SJohnny Huang 			break;
60854552c69SJohnny Huang 		}
60954552c69SJohnny Huang 	}
61054552c69SJohnny Huang 
61154552c69SJohnny Huang 	if (!pass) {
61254552c69SJohnny Huang 		otp_soak(0);
61354552c69SJohnny Huang 		return OTP_FAILURE;
61454552c69SJohnny Huang 	}
61554552c69SJohnny Huang 	return OTP_SUCCESS;
61654552c69SJohnny Huang }
61754552c69SJohnny Huang 
618541eb887SJohnny Huang static void otp_strap_status(struct otpstrap_status *otpstrap)
61976d13988SJohnny Huang {
620a219f6deSJohnny Huang 	u32 OTPSTRAP_RAW[2];
6215010032bSJohnny Huang 	int strap_end;
62276d13988SJohnny Huang 	int i, j;
62376d13988SJohnny Huang 
624e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
62576d13988SJohnny Huang 		for (j = 0; j < 64; j++) {
62676d13988SJohnny Huang 			otpstrap[j].value = 0;
62776d13988SJohnny Huang 			otpstrap[j].remain_times = 7;
62876d13988SJohnny Huang 			otpstrap[j].writeable_option = -1;
62976d13988SJohnny Huang 			otpstrap[j].protected = 0;
63076d13988SJohnny Huang 		}
6315010032bSJohnny Huang 		strap_end = 30;
6325010032bSJohnny Huang 	} else {
6335010032bSJohnny Huang 		for (j = 0; j < 64; j++) {
6345010032bSJohnny Huang 			otpstrap[j].value = 0;
6355010032bSJohnny Huang 			otpstrap[j].remain_times = 6;
6365010032bSJohnny Huang 			otpstrap[j].writeable_option = -1;
6375010032bSJohnny Huang 			otpstrap[j].reg_protected = 0;
6385010032bSJohnny Huang 			otpstrap[j].protected = 0;
6395010032bSJohnny Huang 		}
6405010032bSJohnny Huang 		strap_end = 28;
6415010032bSJohnny Huang 	}
64276d13988SJohnny Huang 
643dacbba92SJohnny Huang 	otp_soak(0);
6445010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
64576d13988SJohnny Huang 		int option = (i - 16) / 2;
646a219f6deSJohnny Huang 
647f347c284SJohnny Huang 		otp_read_conf(i, &OTPSTRAP_RAW[0]);
648f347c284SJohnny Huang 		otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
64976d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
65076d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
651a219f6deSJohnny Huang 
652a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
65376d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
65476d13988SJohnny Huang 			if (bit_value == 1)
65576d13988SJohnny Huang 				otpstrap[j].remain_times--;
65676d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
65776d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
65876d13988SJohnny Huang 		}
65976d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
66076d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
661a219f6deSJohnny Huang 
662a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
66376d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
66476d13988SJohnny Huang 			if (bit_value == 1)
66576d13988SJohnny Huang 				otpstrap[j].remain_times--;
66676d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
66776d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
66876d13988SJohnny Huang 		}
66976d13988SJohnny Huang 	}
6705010032bSJohnny Huang 
671e417205bSJohnny Huang 	if (info_cb.version != OTP_A0) {
672f347c284SJohnny Huang 		otp_read_conf(28, &OTPSTRAP_RAW[0]);
673f347c284SJohnny Huang 		otp_read_conf(29, &OTPSTRAP_RAW[1]);
6745010032bSJohnny Huang 		for (j = 0; j < 32; j++) {
6755010032bSJohnny Huang 			if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
6765010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
6775010032bSJohnny Huang 		}
6785010032bSJohnny Huang 		for (j = 32; j < 64; j++) {
6795010032bSJohnny Huang 			if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
6805010032bSJohnny Huang 				otpstrap[j].reg_protected = 1;
6815010032bSJohnny Huang 		}
6825010032bSJohnny Huang 	}
6835010032bSJohnny Huang 
684f347c284SJohnny Huang 	otp_read_conf(30, &OTPSTRAP_RAW[0]);
685f347c284SJohnny Huang 	otp_read_conf(31, &OTPSTRAP_RAW[1]);
68676d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
68776d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
68876d13988SJohnny Huang 			otpstrap[j].protected = 1;
68976d13988SJohnny Huang 	}
69076d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
69176d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
69276d13988SJohnny Huang 			otpstrap[j].protected = 1;
69376d13988SJohnny Huang 	}
69476d13988SJohnny Huang }
69576d13988SJohnny Huang 
696f347c284SJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit, int rpbit)
697f347c284SJohnny Huang {
698f347c284SJohnny Huang 	int prog_flag = 0;
699f347c284SJohnny Huang 
700f347c284SJohnny Huang 	// ignore this bit
701f347c284SJohnny Huang 	if (ibit == 1)
702f347c284SJohnny Huang 		return OTP_SUCCESS;
703f347c284SJohnny Huang 	printf("OTPSTRAP[%X]:\n", offset);
704f347c284SJohnny Huang 
705f347c284SJohnny Huang 	if (bit == otpstrap->value) {
706f347c284SJohnny Huang 		if (!pbit && !rpbit) {
707f347c284SJohnny Huang 			printf("    The value is same as before, skip it.\n");
708f347c284SJohnny Huang 			return OTP_PROG_SKIP;
709f347c284SJohnny Huang 		}
710f347c284SJohnny Huang 		printf("    The value is same as before.\n");
711f347c284SJohnny Huang 	} else {
712f347c284SJohnny Huang 		prog_flag = 1;
713f347c284SJohnny Huang 	}
714f347c284SJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
715f347c284SJohnny Huang 		printf("    This bit is protected and is not writable\n");
716f347c284SJohnny Huang 		return OTP_FAILURE;
717f347c284SJohnny Huang 	}
718f347c284SJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
719f347c284SJohnny Huang 		printf("    This bit is no remaining times to write.\n");
720f347c284SJohnny Huang 		return OTP_FAILURE;
721f347c284SJohnny Huang 	}
722f347c284SJohnny Huang 	if (pbit == 1)
723f347c284SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
724f347c284SJohnny Huang 	if (rpbit == 1 && info_cb.version != OTP_A0)
725f347c284SJohnny Huang 		printf("    The relative register will be protected.\n");
726f347c284SJohnny Huang 	if (prog_flag)
727f347c284SJohnny 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);
728f347c284SJohnny Huang 
729f347c284SJohnny Huang 	return OTP_SUCCESS;
730f347c284SJohnny Huang }
731f347c284SJohnny Huang 
732f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
733f347c284SJohnny Huang {
734f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
735f347c284SJohnny Huang 	u32 prog_address;
736f347c284SJohnny Huang 	int offset;
737f347c284SJohnny Huang 	int ret;
738f347c284SJohnny Huang 
739f347c284SJohnny Huang 	otp_strap_status(otpstrap);
740f347c284SJohnny Huang 
741f347c284SJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
742f347c284SJohnny Huang 
743f347c284SJohnny Huang 	if (ret != OTP_SUCCESS)
744f347c284SJohnny Huang 		return ret;
745f347c284SJohnny Huang 
746f347c284SJohnny Huang 	prog_address = 0x800;
747f347c284SJohnny Huang 	if (bit_offset < 32) {
748f347c284SJohnny Huang 		offset = bit_offset;
749f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
750f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
751f347c284SJohnny Huang 
752f347c284SJohnny Huang 	} else {
753f347c284SJohnny Huang 		offset = (bit_offset - 32);
754f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
755f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
756f347c284SJohnny Huang 	}
757f347c284SJohnny Huang 
758f347c284SJohnny Huang 	return otp_prog_dc_b(1, prog_address, offset);
759f347c284SJohnny Huang }
760f347c284SJohnny Huang 
761f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
762f347c284SJohnny Huang {
763f347c284SJohnny Huang 	int i;
764f347c284SJohnny Huang 	u32 ret[1];
765f347c284SJohnny Huang 
766f347c284SJohnny Huang 	if (offset + dw_count > 32)
767f347c284SJohnny Huang 		return OTP_USAGE;
768f347c284SJohnny Huang 	otp_soak(0);
769f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
770f347c284SJohnny Huang 		otp_read_conf(i, ret);
771f347c284SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
772f347c284SJohnny Huang 	}
773f347c284SJohnny Huang 	printf("\n");
774f347c284SJohnny Huang 	return OTP_SUCCESS;
775f347c284SJohnny Huang }
776f347c284SJohnny Huang 
777f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
778f347c284SJohnny Huang {
779f347c284SJohnny Huang 	int i;
780f347c284SJohnny Huang 	u32 ret[2];
781f347c284SJohnny Huang 
782f347c284SJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
783f347c284SJohnny Huang 		return OTP_USAGE;
784f347c284SJohnny Huang 	otp_soak(0);
785f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
786f347c284SJohnny Huang 		otp_read_data(i, ret);
787f347c284SJohnny Huang 		if (i % 4 == 0)
788f347c284SJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
789f347c284SJohnny Huang 		else
790f347c284SJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
791f347c284SJohnny Huang 	}
792f347c284SJohnny Huang 	printf("\n");
793f347c284SJohnny Huang 	return OTP_SUCCESS;
794f347c284SJohnny Huang }
795f347c284SJohnny Huang 
796f347c284SJohnny Huang static int otp_print_strap(int start, int count)
797f347c284SJohnny Huang {
798f347c284SJohnny Huang 	int i, j;
799f347c284SJohnny Huang 	int remains;
800f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
801f347c284SJohnny Huang 
802f347c284SJohnny Huang 	if (start < 0 || start > 64)
803f347c284SJohnny Huang 		return OTP_USAGE;
804f347c284SJohnny Huang 
805f347c284SJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
806f347c284SJohnny Huang 		return OTP_USAGE;
807f347c284SJohnny Huang 
808f347c284SJohnny Huang 	otp_strap_status(otpstrap);
809f347c284SJohnny Huang 
810f347c284SJohnny Huang 	if (info_cb.version == OTP_A0) {
811f347c284SJohnny Huang 		remains = 7;
812f347c284SJohnny Huang 		printf("BIT(hex)  Value  Option           Status\n");
813f347c284SJohnny Huang 	} else {
814f347c284SJohnny Huang 		remains = 6;
815f347c284SJohnny Huang 		printf("BIT(hex)  Value  Option         Reg_Protect Status\n");
816f347c284SJohnny Huang 	}
817f347c284SJohnny Huang 	printf("______________________________________________________________________________\n");
818f347c284SJohnny Huang 
819f347c284SJohnny Huang 	for (i = start; i < start + count; i++) {
820f347c284SJohnny Huang 		printf("0x%-8X", i);
821f347c284SJohnny Huang 		printf("%-7d", otpstrap[i].value);
822f347c284SJohnny Huang 		for (j = 0; j < remains; j++)
823f347c284SJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
824f347c284SJohnny Huang 		printf("   ");
825f347c284SJohnny Huang 		if (info_cb.version != OTP_A0)
826f347c284SJohnny Huang 			printf("%d           ", otpstrap[i].reg_protected);
827f347c284SJohnny Huang 		if (otpstrap[i].protected == 1) {
828f347c284SJohnny Huang 			printf("protected and not writable");
829f347c284SJohnny Huang 		} else {
830f347c284SJohnny Huang 			printf("not protected ");
831f347c284SJohnny Huang 			if (otpstrap[i].remain_times == 0)
832f347c284SJohnny Huang 				printf("and no remaining times to write.");
833f347c284SJohnny Huang 			else
834f347c284SJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
835f347c284SJohnny Huang 		}
836f347c284SJohnny Huang 		printf("\n");
837f347c284SJohnny Huang 	}
838f347c284SJohnny Huang 
839f347c284SJohnny Huang 	return OTP_SUCCESS;
840f347c284SJohnny Huang }
841f347c284SJohnny Huang 
842794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
843794e27ecSJohnny Huang {
844794e27ecSJohnny Huang 	int bit_offset;
845794e27ecSJohnny Huang 	int i, j;
846794e27ecSJohnny Huang 
847794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
848794e27ecSJohnny Huang 	printf("___________________________________________________\n");
849794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
850794e27ecSJohnny Huang 		if (i < 32) {
851794e27ecSJohnny Huang 			j = 0;
852794e27ecSJohnny Huang 			bit_offset = i;
853794e27ecSJohnny Huang 		} else {
854794e27ecSJohnny Huang 			j = 1;
855794e27ecSJohnny Huang 			bit_offset = i - 32;
856794e27ecSJohnny Huang 		}
857794e27ecSJohnny Huang 		if (i % 16 == 0)
858794e27ecSJohnny Huang 			printf("%2x | ", i);
859794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
860794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
861794e27ecSJohnny Huang 			printf("\n");
862794e27ecSJohnny Huang 	}
863794e27ecSJohnny Huang }
864794e27ecSJohnny Huang 
865696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
86669d5fd8fSJohnny Huang {
86779e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
868a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
869a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
870a219f6deSJohnny Huang 	u32 mask;
871a219f6deSJohnny Huang 	u32 dw_offset;
872a219f6deSJohnny Huang 	u32 bit_offset;
873a219f6deSJohnny Huang 	u32 otp_value;
874a219f6deSJohnny Huang 	u32 otp_ignore;
875b458cd62SJohnny Huang 	int fail = 0;
876794e27ecSJohnny Huang 	int rid_num = 0;
87773f11549SJohnny Huang 	char valid_bit[20];
878794e27ecSJohnny Huang 	int fz;
87966f2f8e5SJohnny Huang 	int i;
88073f11549SJohnny Huang 	int j;
88166f2f8e5SJohnny Huang 
882737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
88366f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
8843cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
8853cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
8863cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
8873cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
888b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
889696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
890b458cd62SJohnny Huang 
891a219f6deSJohnny Huang 		if (otp_ignore == mask)
892b458cd62SJohnny Huang 			continue;
893a219f6deSJohnny Huang 		else if (otp_ignore != 0)
894b458cd62SJohnny Huang 			fail = 1;
895b458cd62SJohnny Huang 
896a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
8973cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
8983cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
8993cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
900b458cd62SJohnny Huang 			continue;
901b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
902b458cd62SJohnny Huang 
9033cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
9043cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
90566f2f8e5SJohnny Huang 		} else {
906b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
9073cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
9083cb28812SJohnny Huang 			       conf_info[i].bit_offset);
90966f2f8e5SJohnny Huang 		}
910b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
911b458cd62SJohnny Huang 
912b458cd62SJohnny Huang 		if (fail) {
913696656c6SJohnny Huang 			printf("Ignore mask error\n");
914a219f6deSJohnny Huang 			continue;
915a219f6deSJohnny Huang 		}
9163cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
917b458cd62SJohnny Huang 			printf("Reserved\n");
9183cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
9193cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
920b458cd62SJohnny Huang 			printf("\n");
9213cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
922b458cd62SJohnny Huang 			if (otp_value != 0) {
92373f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
924a219f6deSJohnny Huang 					if (otp_value == (1 << j))
92573f11549SJohnny Huang 						valid_bit[j * 2] = '1';
926a219f6deSJohnny Huang 					else
92773f11549SJohnny Huang 						valid_bit[j * 2] = '0';
92873f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
92973f11549SJohnny Huang 				}
93073f11549SJohnny Huang 				valid_bit[15] = 0;
93173f11549SJohnny Huang 			} else {
93273f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
933b458cd62SJohnny Huang 			}
9343cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
935b458cd62SJohnny Huang 			printf("\n");
936b458cd62SJohnny Huang 		} else {
9373cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
938b458cd62SJohnny Huang 		}
939b458cd62SJohnny Huang 	}
940b458cd62SJohnny Huang 
941794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
942794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
943794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
944794e27ecSJohnny Huang 			fail = 1;
945794e27ecSJohnny Huang 		} else {
946794e27ecSJohnny Huang 			fz = 0;
947794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
948794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
949794e27ecSJohnny Huang 					if (!fz)
950794e27ecSJohnny Huang 						fz = 1;
951794e27ecSJohnny Huang 				} else {
952794e27ecSJohnny Huang 					rid_num++;
953794e27ecSJohnny Huang 					if (fz) {
954794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
955794e27ecSJohnny Huang 						fail = 1;
956794e27ecSJohnny Huang 						break;
957794e27ecSJohnny Huang 					}
958794e27ecSJohnny Huang 				}
959794e27ecSJohnny Huang 			}
960794e27ecSJohnny Huang 		}
961794e27ecSJohnny Huang 		if (fail)
962794e27ecSJohnny Huang 			printf("OTP revision ID\n");
963794e27ecSJohnny Huang 		else
964794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
965794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
966794e27ecSJohnny Huang 	}
967794e27ecSJohnny Huang 
968b458cd62SJohnny Huang 	if (fail)
969b458cd62SJohnny Huang 		return OTP_FAILURE;
970b458cd62SJohnny Huang 
97166f2f8e5SJohnny Huang 	return OTP_SUCCESS;
97266f2f8e5SJohnny Huang }
97366f2f8e5SJohnny Huang 
9742d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
97566f2f8e5SJohnny Huang {
97679e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
977a219f6deSJohnny Huang 	u32 OTPCFG[16];
978a219f6deSJohnny Huang 	u32 mask;
979a219f6deSJohnny Huang 	u32 dw_offset;
980a219f6deSJohnny Huang 	u32 bit_offset;
981a219f6deSJohnny Huang 	u32 otp_value;
98273f11549SJohnny Huang 	char valid_bit[20];
98366f2f8e5SJohnny Huang 	int i;
98473f11549SJohnny Huang 	int j;
98566f2f8e5SJohnny Huang 
986dacbba92SJohnny Huang 	otp_soak(0);
987bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
988f347c284SJohnny Huang 		otp_read_conf(i, &OTPCFG[i]);
98966f2f8e5SJohnny Huang 
990b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
991b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
9923cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
9933cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
9942d4b0742SJohnny Huang 			continue;
9953cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
9963cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
9973cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
998b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
999b458cd62SJohnny Huang 
1000a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
10013cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
10023cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
10033cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1004b458cd62SJohnny Huang 			continue;
1005b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1006b458cd62SJohnny Huang 
10073cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
10083cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
1009b458cd62SJohnny Huang 		} else {
1010b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
10113cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
10123cb28812SJohnny Huang 			       conf_info[i].bit_offset);
1013b458cd62SJohnny Huang 		}
1014b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1015b458cd62SJohnny Huang 
10163cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1017b458cd62SJohnny Huang 			printf("Reserved\n");
10183cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
10193cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1020b458cd62SJohnny Huang 			printf("\n");
10213cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1022b458cd62SJohnny Huang 			if (otp_value != 0) {
102373f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1024a219f6deSJohnny Huang 					if (otp_value == (1 << j))
102573f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1026a219f6deSJohnny Huang 					else
102773f11549SJohnny Huang 						valid_bit[j * 2] = '0';
102873f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
102973f11549SJohnny Huang 				}
103073f11549SJohnny Huang 				valid_bit[15] = 0;
103173f11549SJohnny Huang 			} else {
103273f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1033b458cd62SJohnny Huang 			}
10343cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1035b458cd62SJohnny Huang 			printf("\n");
1036b458cd62SJohnny Huang 		} else {
10373cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1038b458cd62SJohnny Huang 		}
1039b458cd62SJohnny Huang 	}
1040b458cd62SJohnny Huang 	return OTP_SUCCESS;
104166f2f8e5SJohnny Huang }
104266f2f8e5SJohnny Huang 
10435010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
104476d13988SJohnny Huang {
104579e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
1046a219f6deSJohnny Huang 	u32 *OTPSTRAP;
1047a219f6deSJohnny Huang 	u32 *OTPSTRAP_REG_PRO;
1048a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
1049a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
105076d13988SJohnny Huang 	int i;
1051a8bd6d8cSJohnny Huang 	int fail = 0;
1052a219f6deSJohnny Huang 	u32 bit_offset;
1053a219f6deSJohnny Huang 	u32 dw_offset;
1054a219f6deSJohnny Huang 	u32 mask;
1055a219f6deSJohnny Huang 	u32 otp_value;
1056a219f6deSJohnny Huang 	u32 otp_reg_protect;
1057a219f6deSJohnny Huang 	u32 otp_protect;
1058a219f6deSJohnny Huang 	u32 otp_ignore;
105976d13988SJohnny Huang 
1060a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
1061a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1062a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
1063e417205bSJohnny Huang 	if (info_cb.version == OTP_A0) {
1064696656c6SJohnny Huang 		OTPSTRAP_REG_PRO = NULL;
1065a8bd6d8cSJohnny Huang 		printf("BIT(hex)   Value       Protect     Description\n");
1066696656c6SJohnny Huang 	} else {
1067a219f6deSJohnny Huang 		OTPSTRAP_REG_PRO = (u32 *)image_layout->strap_reg_pro;
1068de6b0cc4SJohnny Huang 		printf("BIT(hex)   Value       Reg_Protect Protect     Description\n");
1069696656c6SJohnny Huang 	}
1070de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
1071b458cd62SJohnny Huang 
10723cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1073696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
1074a8bd6d8cSJohnny Huang 			dw_offset = 1;
10753cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
1076a8bd6d8cSJohnny Huang 		} else {
1077a8bd6d8cSJohnny Huang 			dw_offset = 0;
10783cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
1079a8bd6d8cSJohnny Huang 		}
108076d13988SJohnny Huang 
10813cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
1082a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1083a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1084696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1085a8bd6d8cSJohnny Huang 
1086e417205bSJohnny Huang 		if (info_cb.version != OTP_A0)
1087696656c6SJohnny Huang 			otp_reg_protect = (OTPSTRAP_REG_PRO[dw_offset] >> bit_offset) & mask;
10885010032bSJohnny Huang 		else
10895010032bSJohnny Huang 			otp_reg_protect = 0;
1090696656c6SJohnny Huang 
1091a219f6deSJohnny Huang 		if (otp_ignore == mask)
1092a8bd6d8cSJohnny Huang 			continue;
1093a219f6deSJohnny Huang 		else if (otp_ignore != 0)
1094a8bd6d8cSJohnny Huang 			fail = 1;
1095a8bd6d8cSJohnny Huang 
1096a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
10973cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1098a8bd6d8cSJohnny Huang 			continue;
1099a8bd6d8cSJohnny Huang 
11003cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
11013cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
1102a8bd6d8cSJohnny Huang 		} else {
1103b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
11043cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
11053cb28812SJohnny Huang 			       strap_info[i].bit_offset);
1106a8bd6d8cSJohnny Huang 		}
1107a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
1108e417205bSJohnny Huang 		if (info_cb.version != OTP_A0)
1109696656c6SJohnny Huang 			printf("0x%-10x", otp_reg_protect);
1110a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
1111a8bd6d8cSJohnny Huang 
1112a8bd6d8cSJohnny Huang 		if (fail) {
1113696656c6SJohnny Huang 			printf("Ignore mask error\n");
1114a8bd6d8cSJohnny Huang 		} else {
11153cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
11163cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1117a8bd6d8cSJohnny Huang 			else
1118a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1119a8bd6d8cSJohnny Huang 		}
1120a8bd6d8cSJohnny Huang 	}
1121a8bd6d8cSJohnny Huang 
1122a8bd6d8cSJohnny Huang 	if (fail)
112376d13988SJohnny Huang 		return OTP_FAILURE;
112476d13988SJohnny Huang 
112576d13988SJohnny Huang 	return OTP_SUCCESS;
112676d13988SJohnny Huang }
112776d13988SJohnny Huang 
1128b458cd62SJohnny Huang static int otp_print_strap_info(int view)
112976d13988SJohnny Huang {
113079e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
113176d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
113207baa4e8SJohnny Huang 	int i, j;
1133b458cd62SJohnny Huang 	int fail = 0;
1134a219f6deSJohnny Huang 	u32 bit_offset;
1135a219f6deSJohnny Huang 	u32 length;
1136a219f6deSJohnny Huang 	u32 otp_value;
1137a219f6deSJohnny Huang 	u32 otp_protect;
113876d13988SJohnny Huang 
1139541eb887SJohnny Huang 	otp_strap_status(strap_status);
114076d13988SJohnny Huang 
1141b458cd62SJohnny Huang 	if (view) {
1142e417205bSJohnny Huang 		if (info_cb.version == OTP_A0)
114307baa4e8SJohnny Huang 			printf("BIT(hex) Value  Remains  Protect   Description\n");
114483655e91SJohnny Huang 		else
114583655e91SJohnny Huang 			printf("BIT(hex) Value  Remains  Reg_Protect Protect   Description\n");
114607baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1147b458cd62SJohnny Huang 	} else {
1148b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1149b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
115076d13988SJohnny Huang 	}
11513cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1152b458cd62SJohnny Huang 		otp_value = 0;
11533cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
11543cb28812SJohnny Huang 		length = strap_info[i].length;
1155b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1156c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1157c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1158b458cd62SJohnny Huang 		}
1159a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
11603cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1161b458cd62SJohnny Huang 			continue;
1162b458cd62SJohnny Huang 		if (view) {
1163b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
11643cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1165b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
116607baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1167e417205bSJohnny Huang 				if (info_cb.version != OTP_A0)
1168e1a7245eSJohnny Huang 					printf("0x%-10X", strap_status[bit_offset + j].reg_protected);
1169e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
11703cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1171b458cd62SJohnny Huang 					printf(" Reserved\n");
1172b458cd62SJohnny Huang 					continue;
1173b458cd62SJohnny Huang 				}
1174b458cd62SJohnny Huang 				if (length == 1) {
11753cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1176b458cd62SJohnny Huang 					continue;
117776d13988SJohnny Huang 				}
117876d13988SJohnny Huang 
1179b458cd62SJohnny Huang 				if (j == 0)
11803cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1181b458cd62SJohnny Huang 				else if (j == length - 1)
1182b458cd62SJohnny Huang 					printf("\\ \"\n");
1183b458cd62SJohnny Huang 				else
1184b458cd62SJohnny Huang 					printf("| \"\n");
118576d13988SJohnny Huang 			}
1186b458cd62SJohnny Huang 		} else {
1187c947ef08SJohnny Huang 			if (length == 1) {
11883cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1189b458cd62SJohnny Huang 			} else {
1190b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1191b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1192b458cd62SJohnny Huang 			}
1193b458cd62SJohnny Huang 
1194b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1195b458cd62SJohnny Huang 
11963cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
11973cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1198b458cd62SJohnny Huang 			else
1199b458cd62SJohnny Huang 				printf("Reserved\n");
1200b458cd62SJohnny Huang 		}
1201b458cd62SJohnny Huang 	}
1202b458cd62SJohnny Huang 
1203b458cd62SJohnny Huang 	if (fail)
1204b458cd62SJohnny Huang 		return OTP_FAILURE;
1205b458cd62SJohnny Huang 
1206b458cd62SJohnny Huang 	return OTP_SUCCESS;
1207b458cd62SJohnny Huang }
1208b458cd62SJohnny Huang 
1209f347c284SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
121069d5fd8fSJohnny Huang {
121169d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
121279e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
12139a4fe690SJohnny Huang 	struct otpkey_type key_info;
1214a219f6deSJohnny Huang 	u32 *buf;
1215a219f6deSJohnny Huang 	u8 *byte_buf;
12169d998018SJohnny Huang 	char empty = 1;
121769d5fd8fSJohnny Huang 	int i = 0, len = 0;
12189a4fe690SJohnny Huang 	int j;
121954552c69SJohnny Huang 
1220696656c6SJohnny Huang 	byte_buf = image_layout->data;
1221a219f6deSJohnny Huang 	buf = (u32 *)byte_buf;
12229d998018SJohnny Huang 
12239d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
1224a219f6deSJohnny Huang 		if (buf[i] != 0)
12259d998018SJohnny Huang 			empty = 0;
12269d998018SJohnny Huang 	}
12279d998018SJohnny Huang 	if (empty)
1228f347c284SJohnny Huang 		return OTP_SUCCESS;
12299d998018SJohnny Huang 
12309d998018SJohnny Huang 	i = 0;
123169d5fd8fSJohnny Huang 	while (1) {
123269d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
123369d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
123469d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
123569d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
123669d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
123769d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
12389a4fe690SJohnny Huang 
12399a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
12409a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
12419a4fe690SJohnny Huang 				key_info = key_info_array[j];
12429a4fe690SJohnny Huang 				break;
12439a4fe690SJohnny Huang 			}
12449a4fe690SJohnny Huang 		}
12459a4fe690SJohnny Huang 
12467f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
124769d5fd8fSJohnny Huang 		printf("Key Type: ");
12489a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
12499a4fe690SJohnny Huang 
12509a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
125169d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
125269d5fd8fSJohnny Huang 			switch (key_length) {
125369d5fd8fSJohnny Huang 			case 0:
125469d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
125569d5fd8fSJohnny Huang 				break;
125669d5fd8fSJohnny Huang 			case 1:
125769d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
125869d5fd8fSJohnny Huang 				break;
125969d5fd8fSJohnny Huang 			case 2:
126069d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
126169d5fd8fSJohnny Huang 				break;
126269d5fd8fSJohnny Huang 			case 3:
126369d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
126469d5fd8fSJohnny Huang 				break;
126569d5fd8fSJohnny Huang 			}
1266181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1267181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
126869d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
126969d5fd8fSJohnny Huang 			switch (key_length) {
127069d5fd8fSJohnny Huang 			case 0:
127169d5fd8fSJohnny Huang 				printf("RSA1024\n");
127269d5fd8fSJohnny Huang 				len = 0x100;
127369d5fd8fSJohnny Huang 				break;
127469d5fd8fSJohnny Huang 			case 1:
127569d5fd8fSJohnny Huang 				printf("RSA2048\n");
127669d5fd8fSJohnny Huang 				len = 0x200;
127769d5fd8fSJohnny Huang 				break;
127869d5fd8fSJohnny Huang 			case 2:
127969d5fd8fSJohnny Huang 				printf("RSA3072\n");
128069d5fd8fSJohnny Huang 				len = 0x300;
128169d5fd8fSJohnny Huang 				break;
128269d5fd8fSJohnny Huang 			case 3:
128369d5fd8fSJohnny Huang 				printf("RSA4096\n");
128469d5fd8fSJohnny Huang 				len = 0x400;
128569d5fd8fSJohnny Huang 				break;
128669d5fd8fSJohnny Huang 			}
128769d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
128869d5fd8fSJohnny Huang 		}
12899a4fe690SJohnny Huang 		if (key_info.need_id)
129069d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
129169d5fd8fSJohnny Huang 		printf("Key Value:\n");
12929a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
129369d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
12949a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
12959a4fe690SJohnny Huang 			printf("AES Key:\n");
12969a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1297e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
12989a4fe690SJohnny Huang 				printf("AES IV:\n");
12999a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
13009a4fe690SJohnny Huang 			}
13019a4fe690SJohnny Huang 
13029a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1303e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
130469d5fd8fSJohnny Huang 				printf("AES Key:\n");
130569d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
130669d5fd8fSJohnny Huang 				printf("AES IV:\n");
130769d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
13085fdde29fSJohnny Huang 			} else {
13099a4fe690SJohnny Huang 				printf("AES Key 1:\n");
13109a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
13119a4fe690SJohnny Huang 				printf("AES Key 2:\n");
13129a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
13139a4fe690SJohnny Huang 			}
1314181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
131569d5fd8fSJohnny Huang 			printf("RSA mod:\n");
131669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
131769d5fd8fSJohnny Huang 			printf("RSA exp:\n");
131869d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1319181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1320181f72d8SJohnny Huang 			printf("RSA mod:\n");
1321181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1322181f72d8SJohnny Huang 			printf("RSA exp:\n");
1323a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
132469d5fd8fSJohnny Huang 		}
132569d5fd8fSJohnny Huang 		if (last)
132669d5fd8fSJohnny Huang 			break;
132769d5fd8fSJohnny Huang 		i++;
132869d5fd8fSJohnny Huang 	}
1329f347c284SJohnny Huang 	return OTP_SUCCESS;
1330f347c284SJohnny Huang }
1331f347c284SJohnny Huang 
1332f347c284SJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
1333f347c284SJohnny Huang {
1334f347c284SJohnny Huang 	int i;
1335f347c284SJohnny Huang 	u32 *strap;
1336f347c284SJohnny Huang 	u32 *strap_ignore;
1337f347c284SJohnny Huang 	u32 *strap_reg_protect;
1338f347c284SJohnny Huang 	u32 *strap_pro;
1339f347c284SJohnny Huang 	int bit, pbit, ibit, rpbit;
1340f347c284SJohnny Huang 	int fail = 0;
1341f347c284SJohnny Huang 	int ret;
1342f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
1343f347c284SJohnny Huang 
1344f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1345f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1346f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1347f347c284SJohnny Huang 	strap_reg_protect = (u32 *)image_layout->strap_reg_pro;
1348f347c284SJohnny Huang 
1349f347c284SJohnny Huang 	otp_strap_status(otpstrap);
1350f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1351f347c284SJohnny Huang 		if (i < 32) {
1352f347c284SJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1353f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
1354f347c284SJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
1355f347c284SJohnny Huang 		} else {
1356f347c284SJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1357f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1358f347c284SJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1359f347c284SJohnny Huang 		}
1360f347c284SJohnny Huang 
1361f347c284SJohnny Huang 		if (info_cb.version != OTP_A0) {
1362f347c284SJohnny Huang 			if (i < 32)
1363f347c284SJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
1364f347c284SJohnny Huang 			else
1365f347c284SJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
1366f347c284SJohnny Huang 		} else {
1367f347c284SJohnny Huang 			rpbit = 0;
1368f347c284SJohnny Huang 		}
1369f347c284SJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit, rpbit);
1370f347c284SJohnny Huang 
1371f347c284SJohnny Huang 		if (ret == OTP_FAILURE)
1372f347c284SJohnny Huang 			fail = 1;
1373f347c284SJohnny Huang 	}
1374f347c284SJohnny Huang 	if (fail == 1)
1375f347c284SJohnny Huang 		return OTP_FAILURE;
1376f347c284SJohnny Huang 	else
1377f347c284SJohnny Huang 		return OTP_SUCCESS;
1378f347c284SJohnny Huang }
1379f347c284SJohnny Huang 
1380f347c284SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout)
1381f347c284SJohnny Huang {
1382f347c284SJohnny Huang 	int i;
1383f347c284SJohnny Huang 	int ret;
1384f347c284SJohnny Huang 	int data_dw;
1385f347c284SJohnny Huang 	u32 data[2048];
1386f347c284SJohnny Huang 	u32 *buf;
1387f347c284SJohnny Huang 	u32 *buf_ignore;
1388f347c284SJohnny Huang 	u32 data_masked;
1389f347c284SJohnny Huang 	u32 buf_masked;
1390f347c284SJohnny Huang 
1391f347c284SJohnny Huang 	buf = (u32 *)image_layout->data;
1392f347c284SJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
1393f347c284SJohnny Huang 
1394f347c284SJohnny Huang 	data_dw = image_layout->data_length / 4;
1395f347c284SJohnny Huang 
1396f347c284SJohnny Huang 	printf("Read OTP Data:\n");
1397f347c284SJohnny Huang 
1398f347c284SJohnny Huang 	for (i = 0; i < data_dw - 2 ; i += 2)
1399f347c284SJohnny Huang 		otp_read_data(i, &data[i]);
1400f347c284SJohnny Huang 
1401f347c284SJohnny Huang 	printf("Check writable...\n");
1402f347c284SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
1403f347c284SJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1404f347c284SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1405f347c284SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
1406f347c284SJohnny Huang 		if (data_masked == buf_masked)
1407f347c284SJohnny Huang 			continue;
1408f347c284SJohnny Huang 		if (i % 2 == 0) {
1409f347c284SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
1410f347c284SJohnny Huang 				continue;
1411f347c284SJohnny Huang 			} else {
1412f347c284SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1413f347c284SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1414f347c284SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1415f347c284SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
1416f347c284SJohnny Huang 				return OTP_FAILURE;
1417f347c284SJohnny Huang 			}
1418f347c284SJohnny Huang 		} else {
1419f347c284SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1420f347c284SJohnny Huang 				continue;
1421f347c284SJohnny Huang 			} else {
1422f347c284SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1423f347c284SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1424f347c284SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1425f347c284SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
1426f347c284SJohnny Huang 				return OTP_FAILURE;
1427f347c284SJohnny Huang 			}
1428f347c284SJohnny Huang 		}
1429f347c284SJohnny Huang 	}
1430f347c284SJohnny Huang 
1431f347c284SJohnny Huang 	printf("Start Programing...\n");
1432f347c284SJohnny Huang 
1433f347c284SJohnny Huang 	// programing ecc region first
1434f347c284SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1435f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1436f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1437f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1438f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1439f347c284SJohnny Huang 			return ret;
1440f347c284SJohnny Huang 		}
1441f347c284SJohnny Huang 	}
1442f347c284SJohnny Huang 
1443f347c284SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1444f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1445f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1446f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1447f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1448f347c284SJohnny Huang 			return ret;
1449f347c284SJohnny Huang 		}
1450f347c284SJohnny Huang 	}
1451f347c284SJohnny Huang 	otp_soak(0);
1452f347c284SJohnny Huang 	return OTP_SUCCESS;
1453f347c284SJohnny Huang }
1454f347c284SJohnny Huang 
1455f347c284SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout)
1456f347c284SJohnny Huang {
1457f347c284SJohnny Huang 	u32 *strap;
1458f347c284SJohnny Huang 	u32 *strap_ignore;
1459f347c284SJohnny Huang 	u32 *strap_pro;
1460f347c284SJohnny Huang 	u32 *strap_reg_protect;
1461f347c284SJohnny Huang 	u32 prog_address;
1462f347c284SJohnny Huang 	int i;
1463f347c284SJohnny Huang 	int bit, pbit, ibit, offset, rpbit;
1464f347c284SJohnny Huang 	int fail = 0;
1465f347c284SJohnny Huang 	int ret;
1466f347c284SJohnny Huang 	int prog_flag = 0;
1467f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
1468f347c284SJohnny Huang 
1469f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1470f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1471f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1472f347c284SJohnny Huang 	strap_reg_protect = (u32 *)image_layout->strap_reg_pro;
1473f347c284SJohnny Huang 
1474f347c284SJohnny Huang 	printf("Read OTP Strap Region:\n");
1475f347c284SJohnny Huang 	otp_strap_status(otpstrap);
1476f347c284SJohnny Huang 
1477f347c284SJohnny Huang 	printf("Check writable...\n");
1478f347c284SJohnny Huang 	if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
1479f347c284SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
1480f347c284SJohnny Huang 		return OTP_FAILURE;
1481f347c284SJohnny Huang 	}
1482f347c284SJohnny Huang 
1483f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1484f347c284SJohnny Huang 		prog_address = 0x800;
1485f347c284SJohnny Huang 		if (i < 32) {
1486f347c284SJohnny Huang 			offset = i;
1487f347c284SJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1488f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
1489f347c284SJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
1490f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1491f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1492f347c284SJohnny Huang 
1493f347c284SJohnny Huang 		} else {
1494f347c284SJohnny Huang 			offset = (i - 32);
1495f347c284SJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1496f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
1497f347c284SJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
1498f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1499f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1500f347c284SJohnny Huang 		}
1501f347c284SJohnny Huang 		if (info_cb.version != OTP_A0) {
1502f347c284SJohnny Huang 			if (i < 32)
1503f347c284SJohnny Huang 				rpbit = (strap_reg_protect[0] >> i) & 0x1;
1504f347c284SJohnny Huang 			else
1505f347c284SJohnny Huang 				rpbit = (strap_reg_protect[1] >> (i - 32)) & 0x1;
1506f347c284SJohnny Huang 		} else {
1507f347c284SJohnny Huang 			rpbit = 0;
1508f347c284SJohnny Huang 		}
1509f347c284SJohnny Huang 
1510f347c284SJohnny Huang 		if (ibit == 1)
1511f347c284SJohnny Huang 			continue;
1512f347c284SJohnny Huang 		if (bit == otpstrap[i].value)
1513f347c284SJohnny Huang 			prog_flag = 0;
1514f347c284SJohnny Huang 		else
1515f347c284SJohnny Huang 			prog_flag = 1;
1516f347c284SJohnny Huang 
1517f347c284SJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
1518f347c284SJohnny Huang 			fail = 1;
1519f347c284SJohnny Huang 			continue;
1520f347c284SJohnny Huang 		}
1521f347c284SJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
1522f347c284SJohnny Huang 			fail = 1;
1523f347c284SJohnny Huang 			continue;
1524f347c284SJohnny Huang 		}
1525f347c284SJohnny Huang 
1526f347c284SJohnny Huang 		if (prog_flag) {
1527f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1528f347c284SJohnny Huang 			if (ret)
1529f347c284SJohnny Huang 				return OTP_FAILURE;
1530f347c284SJohnny Huang 		}
1531f347c284SJohnny Huang 
1532f347c284SJohnny Huang 		if (rpbit == 1 && info_cb.version != OTP_A0) {
1533f347c284SJohnny Huang 			prog_address = 0x800;
1534f347c284SJohnny Huang 			if (i < 32)
1535f347c284SJohnny Huang 				prog_address |= 0x608;
1536f347c284SJohnny Huang 			else
1537f347c284SJohnny Huang 				prog_address |= 0x60a;
1538f347c284SJohnny Huang 
1539f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1540f347c284SJohnny Huang 			if (ret)
1541f347c284SJohnny Huang 				return OTP_FAILURE;
1542f347c284SJohnny Huang 		}
1543f347c284SJohnny Huang 
1544f347c284SJohnny Huang 		if (pbit != 0) {
1545f347c284SJohnny Huang 			prog_address = 0x800;
1546f347c284SJohnny Huang 			if (i < 32)
1547f347c284SJohnny Huang 				prog_address |= 0x60c;
1548f347c284SJohnny Huang 			else
1549f347c284SJohnny Huang 				prog_address |= 0x60e;
1550f347c284SJohnny Huang 
1551f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1552f347c284SJohnny Huang 			if (ret)
1553f347c284SJohnny Huang 				return OTP_FAILURE;
1554f347c284SJohnny Huang 		}
1555f347c284SJohnny Huang 	}
1556f347c284SJohnny Huang 	otp_soak(0);
1557f347c284SJohnny Huang 	if (fail == 1)
1558f347c284SJohnny Huang 		return OTP_FAILURE;
1559f347c284SJohnny Huang 	return OTP_SUCCESS;
156069d5fd8fSJohnny Huang }
156169d5fd8fSJohnny Huang 
15625010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout)
156369d5fd8fSJohnny Huang {
1564a6d0d645SJohnny Huang 	int i, k;
1565d90825e2SJohnny Huang 	int pass = 0;
1566a219f6deSJohnny Huang 	u32 prog_address;
1567a219f6deSJohnny Huang 	u32 data[16];
1568a219f6deSJohnny Huang 	u32 compare[2];
1569a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1570a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1571a219f6deSJohnny Huang 	u32 data_masked;
1572a219f6deSJohnny Huang 	u32 buf_masked;
157369d5fd8fSJohnny Huang 
1574a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1575a6d0d645SJohnny Huang 
1576bb34a7bfSJohnny Huang 	for (i = 0; i < 16 ; i++) {
157769d5fd8fSJohnny Huang 		prog_address = 0x800;
1578a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1579a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1580a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1581a6d0d645SJohnny Huang 	}
1582a6d0d645SJohnny Huang 
1583a6d0d645SJohnny Huang 	printf("Check writable...\n");
1584bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
15855010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
15865010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1587d90825e2SJohnny Huang 		if (data_masked == buf_masked)
158869d5fd8fSJohnny Huang 			continue;
1589d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1590a6d0d645SJohnny Huang 			continue;
1591a6d0d645SJohnny Huang 		} else {
1592a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1593a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
15945010032bSJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
15955010032bSJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
15962a856b9aSJohnny Huang 			return OTP_FAILURE;
1597a6d0d645SJohnny Huang 		}
1598a6d0d645SJohnny Huang 	}
1599a6d0d645SJohnny Huang 
1600a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1601d90825e2SJohnny Huang 	otp_soak(0);
1602bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
16035010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
16045010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1605a6d0d645SJohnny Huang 		prog_address = 0x800;
1606a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1607a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1608bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1609bb34a7bfSJohnny Huang 			pass = 1;
1610a6d0d645SJohnny Huang 			continue;
1611bb34a7bfSJohnny Huang 		}
1612de6fbf1cSJohnny Huang 
1613de6fbf1cSJohnny Huang 		otp_soak(1);
16145010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1615a6d0d645SJohnny Huang 
161669d5fd8fSJohnny Huang 		pass = 0;
161769d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
16185010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1619de6fbf1cSJohnny Huang 				otp_soak(2);
1620feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
16215010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1622de6fbf1cSJohnny Huang 					otp_soak(1);
1623de6fbf1cSJohnny Huang 				} else {
1624de6fbf1cSJohnny Huang 					pass = 1;
1625de6fbf1cSJohnny Huang 					break;
1626de6fbf1cSJohnny Huang 				}
1627a6d0d645SJohnny Huang 			} else {
162869d5fd8fSJohnny Huang 				pass = 1;
162969d5fd8fSJohnny Huang 				break;
163069d5fd8fSJohnny Huang 			}
163169d5fd8fSJohnny Huang 		}
1632bb34a7bfSJohnny Huang 		if (pass == 0) {
1633bb34a7bfSJohnny Huang 			printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
16345010032bSJohnny Huang 			       i, data[i], conf[i], conf_ignore[i]);
1635bb34a7bfSJohnny Huang 			break;
1636bb34a7bfSJohnny Huang 		}
1637a6d0d645SJohnny Huang 	}
1638a6d0d645SJohnny Huang 
1639de6fbf1cSJohnny Huang 	otp_soak(0);
164069d5fd8fSJohnny Huang 	if (!pass)
16412a856b9aSJohnny Huang 		return OTP_FAILURE;
1642a6d0d645SJohnny Huang 
16432a856b9aSJohnny Huang 	return OTP_SUCCESS;
164469d5fd8fSJohnny Huang }
164569d5fd8fSJohnny Huang 
1646f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf)
1647696656c6SJohnny Huang {
1648696656c6SJohnny Huang 	sha256_context ctx;
1649696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1650696656c6SJohnny Huang 
1651696656c6SJohnny Huang 	sha256_starts(&ctx);
1652696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1653696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1654696656c6SJohnny Huang 
1655696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1656f347c284SJohnny Huang 		return OTP_SUCCESS;
1657f347c284SJohnny Huang 	return OTP_FAILURE;
1658696656c6SJohnny Huang }
1659696656c6SJohnny Huang 
1660f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
166169d5fd8fSJohnny Huang {
166269d5fd8fSJohnny Huang 	int ret;
16639a4fe690SJohnny Huang 	int image_version = 0;
1664696656c6SJohnny Huang 	struct otp_header *otp_header;
1665696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1666696656c6SJohnny Huang 	int image_size;
1667a219f6deSJohnny Huang 	u8 *buf;
1668a219f6deSJohnny Huang 	u8 *checksum;
166969d5fd8fSJohnny Huang 
1670696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1671696656c6SJohnny Huang 	if (!otp_header) {
167269d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
16732a856b9aSJohnny Huang 		return OTP_FAILURE;
167469d5fd8fSJohnny Huang 	}
1675d90825e2SJohnny Huang 
1676696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1677696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1678696656c6SJohnny Huang 
1679696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1680696656c6SJohnny Huang 
1681696656c6SJohnny Huang 	if (!buf) {
1682696656c6SJohnny Huang 		puts("Failed to map physical memory\n");
1683696656c6SJohnny Huang 		return OTP_FAILURE;
1684696656c6SJohnny Huang 	}
1685696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1686696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1687696656c6SJohnny Huang 
1688696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1689696656c6SJohnny Huang 		puts("Image is invalid\n");
1690696656c6SJohnny Huang 		return OTP_FAILURE;
1691696656c6SJohnny Huang 	}
1692696656c6SJohnny Huang 
16935010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
16945010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
16955010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
16965010032bSJohnny Huang 
16975010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1698696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
16995010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1700696656c6SJohnny Huang 
1701696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
1702696656c6SJohnny Huang 
1703696656c6SJohnny Huang 	if (!strcmp("A0", (char *)otp_header->otp_version)) {
1704e417205bSJohnny Huang 		image_version = OTP_A0;
17055010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
17065010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
17075010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
1708696656c6SJohnny Huang 	} else if (!strcmp("A1", (char *)otp_header->otp_version)) {
1709e417205bSJohnny Huang 		image_version = OTP_A1;
17105010032bSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
17115010032bSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
17125010032bSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
17135010032bSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
17145fdde29fSJohnny Huang 	} else if (!strcmp("A2", (char *)otp_header->otp_version)) {
1715e417205bSJohnny Huang 		image_version = OTP_A2;
17165fdde29fSJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
17175fdde29fSJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
17185fdde29fSJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
17195fdde29fSJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
172064b66712SJohnny Huang 	} else if (!strcmp("A3", (char *)otp_header->otp_version)) {
1721e417205bSJohnny Huang 		image_version = OTP_A3;
172264b66712SJohnny Huang 		image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 4);
172364b66712SJohnny Huang 		image_layout.strap_reg_pro = image_layout.strap + image_layout.strap_length;
172464b66712SJohnny Huang 		image_layout.strap_pro = image_layout.strap + 2 * image_layout.strap_length;
172564b66712SJohnny Huang 		image_layout.strap_ignore = image_layout.strap + 3 * image_layout.strap_length;
1726696656c6SJohnny Huang 	} else {
1727696656c6SJohnny Huang 		puts("Version is not supported\n");
1728696656c6SJohnny Huang 		return OTP_FAILURE;
1729696656c6SJohnny Huang 	}
1730696656c6SJohnny Huang 
17319a4fe690SJohnny Huang 	if (image_version != info_cb.version) {
17329a4fe690SJohnny Huang 		puts("Version is not match\n");
17339a4fe690SJohnny Huang 		return OTP_FAILURE;
17349a4fe690SJohnny Huang 	}
17359a4fe690SJohnny Huang 
1736f347c284SJohnny Huang 	if (otp_verify_image(buf, image_size, checksum)) {
1737696656c6SJohnny Huang 		puts("checksum is invalid\n");
1738696656c6SJohnny Huang 		return OTP_FAILURE;
1739d90825e2SJohnny Huang 	}
17407332532cSJohnny Huang 
174169d5fd8fSJohnny Huang 	if (!nconfirm) {
1742696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
17437f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1744f347c284SJohnny Huang 			if (otp_print_data_image(&image_layout) < 0) {
174569d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
17462a856b9aSJohnny Huang 				return OTP_FAILURE;
174769d5fd8fSJohnny Huang 			}
174869d5fd8fSJohnny Huang 		}
1749696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
17507332532cSJohnny Huang 			printf("\nOTP strap region :\n");
17515010032bSJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
17527332532cSJohnny Huang 				printf("OTP strap error, please check.\n");
17537332532cSJohnny Huang 				return OTP_FAILURE;
17547332532cSJohnny Huang 			}
17557332532cSJohnny Huang 		}
1756696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
17577332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1758696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
17597332532cSJohnny Huang 				printf("OTP config error, please check.\n");
17607332532cSJohnny Huang 				return OTP_FAILURE;
17617332532cSJohnny Huang 			}
17627332532cSJohnny Huang 		}
17637332532cSJohnny Huang 
176469d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
176569d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
176669d5fd8fSJohnny Huang 			printf(" Aborting\n");
17672a856b9aSJohnny Huang 			return OTP_FAILURE;
176869d5fd8fSJohnny Huang 		}
176969d5fd8fSJohnny Huang 	}
17707332532cSJohnny Huang 
17715010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
17725010032bSJohnny Huang 		printf("programing data region ...\n");
17735010032bSJohnny Huang 		ret = otp_prog_data(&image_layout);
17745010032bSJohnny Huang 		if (ret != 0) {
17755010032bSJohnny Huang 			printf("Error\n");
17765010032bSJohnny Huang 			return ret;
17775010032bSJohnny Huang 		}
1778a219f6deSJohnny Huang 		printf("Done\n");
17795010032bSJohnny Huang 	}
17805010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
17815010032bSJohnny Huang 		printf("programing strap region ...\n");
17825010032bSJohnny Huang 		ret = otp_prog_strap(&image_layout);
17835010032bSJohnny Huang 		if (ret != 0) {
17845010032bSJohnny Huang 			printf("Error\n");
17855010032bSJohnny Huang 			return ret;
17865010032bSJohnny Huang 		}
1787a219f6deSJohnny Huang 		printf("Done\n");
17885010032bSJohnny Huang 	}
17895010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
17905010032bSJohnny Huang 		printf("programing configuration region ...\n");
17915010032bSJohnny Huang 		ret = otp_prog_conf(&image_layout);
17925010032bSJohnny Huang 		if (ret != 0) {
17935010032bSJohnny Huang 			printf("Error\n");
17945010032bSJohnny Huang 			return ret;
17955010032bSJohnny Huang 		}
17965010032bSJohnny Huang 		printf("Done\n");
17975010032bSJohnny Huang 	}
1798cd1610b4SJohnny Huang 
17997332532cSJohnny Huang 	return OTP_SUCCESS;
18002a856b9aSJohnny Huang }
18012a856b9aSJohnny Huang 
1802f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1803cd1610b4SJohnny Huang {
1804a219f6deSJohnny Huang 	u32 read[2];
1805a219f6deSJohnny Huang 	u32 prog_address = 0;
180666f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1807cd1610b4SJohnny Huang 	int otp_bit;
180883655e91SJohnny Huang 	int ret = 0;
1809cd1610b4SJohnny Huang 
1810dacbba92SJohnny Huang 	otp_soak(0);
1811cd1610b4SJohnny Huang 	switch (mode) {
1812a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1813f347c284SJohnny Huang 		otp_read_conf(otp_dw_offset, read);
1814cd1610b4SJohnny Huang 		prog_address = 0x800;
1815cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1816cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1817a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1818cd1610b4SJohnny Huang 		if (otp_bit == value) {
1819a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1820cd1610b4SJohnny Huang 			printf("No need to program\n");
18212a856b9aSJohnny Huang 			return OTP_SUCCESS;
1822cd1610b4SJohnny Huang 		}
1823cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1824a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
1825cd1610b4SJohnny Huang 			printf("OTP is programed, which can't be clean\n");
18262a856b9aSJohnny Huang 			return OTP_FAILURE;
1827cd1610b4SJohnny Huang 		}
1828a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1829cd1610b4SJohnny Huang 		break;
1830a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1831cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1832cd1610b4SJohnny Huang 
1833cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1834a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1835a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1836643b9cfdSJohnny Huang 
1837643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
1838643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1839643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be cleaned\n");
1840643b9cfdSJohnny Huang 				return OTP_FAILURE;
1841643b9cfdSJohnny Huang 			}
1842cd1610b4SJohnny Huang 		} else {
1843a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1844a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1845643b9cfdSJohnny Huang 
1846643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
1847643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
1848643b9cfdSJohnny Huang 				printf("OTP is programed, which can't be writen\n");
1849643b9cfdSJohnny Huang 				return OTP_FAILURE;
1850643b9cfdSJohnny Huang 			}
1851cd1610b4SJohnny Huang 		}
1852cd1610b4SJohnny Huang 		if (otp_bit == value) {
1853a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1854cd1610b4SJohnny Huang 			printf("No need to program\n");
18552a856b9aSJohnny Huang 			return OTP_SUCCESS;
1856cd1610b4SJohnny Huang 		}
1857643b9cfdSJohnny Huang 
1858a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1859cd1610b4SJohnny Huang 		break;
1860a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
18618848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
18628848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
18638848d5dcSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0, 0);
18648848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
18658848d5dcSJohnny Huang 			return OTP_FAILURE;
18668848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
18678848d5dcSJohnny Huang 			return OTP_SUCCESS;
1868a6af4a17SJohnny Huang 
1869cd1610b4SJohnny Huang 		break;
1870cd1610b4SJohnny Huang 	}
1871cd1610b4SJohnny Huang 
1872cd1610b4SJohnny Huang 	if (!nconfirm) {
1873cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1874cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1875cd1610b4SJohnny Huang 			printf(" Aborting\n");
18762a856b9aSJohnny Huang 			return OTP_FAILURE;
1877cd1610b4SJohnny Huang 		}
1878cd1610b4SJohnny Huang 	}
1879cd1610b4SJohnny Huang 
1880cd1610b4SJohnny Huang 	switch (mode) {
1881a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1882f347c284SJohnny Huang 		ret =  otp_prog_strap_b(bit_offset, value);
188383655e91SJohnny Huang 		break;
1884a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1885a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1886f347c284SJohnny Huang 		ret = otp_prog_dc_b(value, prog_address, bit_offset);
1887de6fbf1cSJohnny Huang 		break;
1888de6fbf1cSJohnny Huang 	}
1889de6fbf1cSJohnny Huang 	otp_soak(0);
189083655e91SJohnny Huang 	if (ret) {
1891794e27ecSJohnny Huang 		printf("OTP cannot be programed\n");
1892794e27ecSJohnny Huang 		printf("FAILURE\n");
1893794e27ecSJohnny Huang 		return OTP_FAILURE;
1894794e27ecSJohnny Huang 	}
1895794e27ecSJohnny Huang 
18969009c25dSJohnny Huang 	printf("SUCCESS\n");
18972a856b9aSJohnny Huang 	return OTP_SUCCESS;
1898a219f6deSJohnny Huang }
1899a219f6deSJohnny Huang 
1900794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
1901794e27ecSJohnny Huang {
1902794e27ecSJohnny Huang 	u32 otp_rid[2];
1903*a8789b47SJohnny Huang 	u32 sw_rid[2];
1904794e27ecSJohnny Huang 	int rid_num = 0;
1905*a8789b47SJohnny Huang 	int sw_rid_num = 0;
1906794e27ecSJohnny Huang 	int bit_offset;
1907794e27ecSJohnny Huang 	int dw_offset;
1908794e27ecSJohnny Huang 	int i;
1909794e27ecSJohnny Huang 	int ret;
1910794e27ecSJohnny Huang 
1911f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
1912f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
1913794e27ecSJohnny Huang 
1914*a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
1915*a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
1916*a8789b47SJohnny Huang 
1917794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1918*a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
1919*a8789b47SJohnny Huang 
1920*a8789b47SJohnny Huang 	if (sw_rid_num < 0) {
1921*a8789b47SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
1922*a8789b47SJohnny Huang 		return OTP_FAILURE;
1923*a8789b47SJohnny Huang 	}
1924*a8789b47SJohnny Huang 
1925*a8789b47SJohnny Huang 	if (update_num > sw_rid_num) {
1926*a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
1927*a8789b47SJohnny Huang 		printf("update number could not bigger than current SW revision id\n");
1928*a8789b47SJohnny Huang 		return OTP_FAILURE;
1929*a8789b47SJohnny Huang 	}
1930794e27ecSJohnny Huang 
1931794e27ecSJohnny Huang 	if (rid_num < 0) {
1932794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by this command,\n"
1933794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n");
1934794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
19359009c25dSJohnny Huang 		return OTP_FAILURE;
19369009c25dSJohnny Huang 	}
1937cd1610b4SJohnny Huang 
1938794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
1939794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1940794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
1941794e27ecSJohnny Huang 
1942*a8789b47SJohnny Huang 	if (rid_num > update_num) {
1943*a8789b47SJohnny Huang 		printf("OTP rev_id is bigger than 0x%X\n", update_num);
1944*a8789b47SJohnny Huang 		printf("Skip\n");
1945*a8789b47SJohnny Huang 		return OTP_FAILURE;
1946*a8789b47SJohnny Huang 	} else if (rid_num == update_num) {
1947*a8789b47SJohnny Huang 		printf("OTP rev_id is same as input\n");
1948794e27ecSJohnny Huang 		printf("Skip\n");
1949794e27ecSJohnny Huang 		return OTP_FAILURE;
1950794e27ecSJohnny Huang 	}
1951794e27ecSJohnny Huang 
1952794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1953794e27ecSJohnny Huang 		if (i < 32) {
1954794e27ecSJohnny Huang 			dw_offset = 0xa;
1955794e27ecSJohnny Huang 			bit_offset = i;
1956794e27ecSJohnny Huang 		} else {
1957794e27ecSJohnny Huang 			dw_offset = 0xb;
1958794e27ecSJohnny Huang 			bit_offset = i - 32;
1959794e27ecSJohnny Huang 		}
1960794e27ecSJohnny Huang 		printf("OTPCFG%X[%d]", dw_offset, bit_offset);
1961794e27ecSJohnny Huang 		if (i + 1 != update_num)
1962794e27ecSJohnny Huang 			printf(", ");
1963794e27ecSJohnny Huang 	}
1964794e27ecSJohnny Huang 
1965794e27ecSJohnny Huang 	printf(" will be programmed\n");
1966794e27ecSJohnny Huang 	if (force == 0) {
1967794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1968794e27ecSJohnny Huang 		if (!confirm_yesno()) {
1969794e27ecSJohnny Huang 			printf(" Aborting\n");
1970794e27ecSJohnny Huang 			return OTP_FAILURE;
1971794e27ecSJohnny Huang 		}
1972794e27ecSJohnny Huang 	}
1973794e27ecSJohnny Huang 
1974794e27ecSJohnny Huang 	ret = 0;
1975794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1976794e27ecSJohnny Huang 		if (i < 32) {
1977794e27ecSJohnny Huang 			dw_offset = 0xa04;
1978794e27ecSJohnny Huang 			bit_offset = i;
1979794e27ecSJohnny Huang 		} else {
1980794e27ecSJohnny Huang 			dw_offset = 0xa06;
1981794e27ecSJohnny Huang 			bit_offset = i - 32;
1982794e27ecSJohnny Huang 		}
1983f347c284SJohnny Huang 		if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
1984794e27ecSJohnny Huang 			printf("OTPCFG%X[%d] programming failed\n", dw_offset, bit_offset);
1985794e27ecSJohnny Huang 			ret = OTP_FAILURE;
1986794e27ecSJohnny Huang 			break;
1987794e27ecSJohnny Huang 		}
1988794e27ecSJohnny Huang 	}
1989794e27ecSJohnny Huang 
1990f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
1991f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
1992794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1993794e27ecSJohnny Huang 	if (rid_num >= 0)
1994794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
1995794e27ecSJohnny Huang 	else
1996794e27ecSJohnny Huang 		printf("OTP revision ID\n");
1997794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1998794e27ecSJohnny Huang 	if (!ret)
1999794e27ecSJohnny Huang 		printf("SUCCESS\n");
2000794e27ecSJohnny Huang 	else
2001794e27ecSJohnny Huang 		printf("FAILED\n");
2002794e27ecSJohnny Huang 	return ret;
2003794e27ecSJohnny Huang }
2004794e27ecSJohnny Huang 
20052a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
200669d5fd8fSJohnny Huang {
2007a219f6deSJohnny Huang 	u32 offset, count;
20082a856b9aSJohnny Huang 	int ret;
200969d5fd8fSJohnny Huang 
20102a856b9aSJohnny Huang 	if (argc == 4) {
20112a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
20122a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
20132a856b9aSJohnny Huang 	} else if (argc == 3) {
20142a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
20152a856b9aSJohnny Huang 		count = 1;
20162a856b9aSJohnny Huang 	} else {
201769d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
201869d5fd8fSJohnny Huang 	}
201969d5fd8fSJohnny Huang 
20202a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
20213d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2022f347c284SJohnny Huang 		ret = otp_print_conf(offset, count);
20232a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
20243d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20252a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
20262a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
20273d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20282a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
20292a856b9aSJohnny Huang 	} else {
20302a856b9aSJohnny Huang 		return CMD_RET_USAGE;
203169d5fd8fSJohnny Huang 	}
203269d5fd8fSJohnny Huang 
20332a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20342a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20352a856b9aSJohnny Huang 	return CMD_RET_USAGE;
20362a856b9aSJohnny Huang }
20372a856b9aSJohnny Huang 
20382a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20392a856b9aSJohnny Huang {
20402a856b9aSJohnny Huang 	phys_addr_t addr;
20412a856b9aSJohnny Huang 	int ret;
20422a856b9aSJohnny Huang 
2043de6b0cc4SJohnny Huang 	if (argc == 3) {
2044ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
20452a856b9aSJohnny Huang 			return CMD_RET_USAGE;
20462a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
20473d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2048f347c284SJohnny Huang 		ret = otp_prog_image(addr, 1);
2049de6b0cc4SJohnny Huang 	} else if (argc == 2) {
20502a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
20513d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2052f347c284SJohnny Huang 		ret = otp_prog_image(addr, 0);
20532a856b9aSJohnny Huang 	} else {
20542a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20552a856b9aSJohnny Huang 	}
20562a856b9aSJohnny Huang 
20572a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20582a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20592a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
20602a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
20612a856b9aSJohnny Huang 	else
20622a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20632a856b9aSJohnny Huang }
20642a856b9aSJohnny Huang 
20652a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20662a856b9aSJohnny Huang {
20672a856b9aSJohnny Huang 	int mode = 0;
20682a856b9aSJohnny Huang 	int nconfirm = 0;
20692a856b9aSJohnny Huang 	int otp_addr = 0;
20702a856b9aSJohnny Huang 	int bit_offset;
20712a856b9aSJohnny Huang 	int value;
20722a856b9aSJohnny Huang 	int ret;
20732a856b9aSJohnny Huang 
20742a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
20752a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20762a856b9aSJohnny Huang 
20772a856b9aSJohnny Huang 	/* Drop the pb cmd */
20782a856b9aSJohnny Huang 	argc--;
20792a856b9aSJohnny Huang 	argv++;
20802a856b9aSJohnny Huang 
20812a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2082a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
20832a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2084a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
20852a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2086a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2087cd1610b4SJohnny Huang 	else
20882a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20892a856b9aSJohnny Huang 
20902a856b9aSJohnny Huang 	/* Drop the region cmd */
20912a856b9aSJohnny Huang 	argc--;
20922a856b9aSJohnny Huang 	argv++;
20932a856b9aSJohnny Huang 
2094ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2095cd1610b4SJohnny Huang 		nconfirm = 1;
20962a856b9aSJohnny Huang 		/* Drop the force option */
20972a856b9aSJohnny Huang 		argc--;
20982a856b9aSJohnny Huang 		argv++;
20992a856b9aSJohnny Huang 	}
2100cd1610b4SJohnny Huang 
2101a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
21022a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
21032a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
21040808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
21052a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2106cd1610b4SJohnny Huang 	} else {
21072a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
21082a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
21092a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
21100808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
21112a856b9aSJohnny Huang 			return CMD_RET_USAGE;
21120808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
211378855207SJohnny Huang 			if (otp_addr >= 0x800)
21140808cc55SJohnny Huang 				return CMD_RET_USAGE;
21150808cc55SJohnny Huang 		} else {
211678855207SJohnny Huang 			if (otp_addr >= 0x20)
21170808cc55SJohnny Huang 				return CMD_RET_USAGE;
21180808cc55SJohnny Huang 		}
2119cd1610b4SJohnny Huang 	}
2120cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
21212a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2122cd1610b4SJohnny Huang 
21233d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2124f347c284SJohnny Huang 	ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
21252a856b9aSJohnny Huang 
21262a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
21272a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
21282a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
21292a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
21302a856b9aSJohnny Huang 	else
21312a856b9aSJohnny Huang 		return CMD_RET_USAGE;
21322a856b9aSJohnny Huang }
21332a856b9aSJohnny Huang 
21342a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
21352a856b9aSJohnny Huang {
21362a856b9aSJohnny Huang 	phys_addr_t addr;
21372a856b9aSJohnny Huang 	int otp_addr = 0;
21382a856b9aSJohnny Huang 
21392a856b9aSJohnny Huang 	if (argc != 3)
21402a856b9aSJohnny Huang 		return CMD_RET_USAGE;
21412a856b9aSJohnny Huang 
21423d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
21432a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
21442a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
21452a856b9aSJohnny Huang 	if (otp_compare(otp_addr, addr) == 0) {
214669d5fd8fSJohnny Huang 		printf("Compare pass\n");
21472a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2148a219f6deSJohnny Huang 	}
214969d5fd8fSJohnny Huang 	printf("Compare fail\n");
21502a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
215169d5fd8fSJohnny Huang }
215269d5fd8fSJohnny Huang 
215366f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
215466f2f8e5SJohnny Huang {
2155a8bd6d8cSJohnny Huang 	int view = 0;
21562d4b0742SJohnny Huang 	int input;
2157a8bd6d8cSJohnny Huang 
2158a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
215966f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
216066f2f8e5SJohnny Huang 
21612d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
21623d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
21632d4b0742SJohnny Huang 		if (argc == 3) {
21642d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
21652d4b0742SJohnny Huang 			otp_print_conf_info(input);
21662d4b0742SJohnny Huang 		} else {
21672d4b0742SJohnny Huang 			otp_print_conf_info(-1);
21682d4b0742SJohnny Huang 		}
21692d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
21702d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2171a8bd6d8cSJohnny Huang 			view = 1;
2172a8bd6d8cSJohnny Huang 			/* Drop the view option */
2173a8bd6d8cSJohnny Huang 			argc--;
2174a8bd6d8cSJohnny Huang 			argv++;
2175a8bd6d8cSJohnny Huang 		}
21763d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2177b458cd62SJohnny Huang 		otp_print_strap_info(view);
217866f2f8e5SJohnny Huang 	} else {
217966f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
218066f2f8e5SJohnny Huang 	}
21812d4b0742SJohnny Huang 
218266f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
218366f2f8e5SJohnny Huang }
218466f2f8e5SJohnny Huang 
2185e14b073cSJohnny Huang static int _do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[], int preg)
2186737ed20bSJohnny Huang {
2187737ed20bSJohnny Huang 	int input;
2188737ed20bSJohnny Huang 	int bit_offset;
2189e14b073cSJohnny Huang 	u32 prog_address;
219083655e91SJohnny Huang 	int ret;
2191e14b073cSJohnny Huang 	char info[10];
2192e14b073cSJohnny Huang 
2193e14b073cSJohnny Huang 	if (preg) {
2194e14b073cSJohnny Huang 		sprintf(info, "register ");
2195e14b073cSJohnny Huang 		prog_address = 0xe08;
2196e14b073cSJohnny Huang 	} else {
2197e14b073cSJohnny Huang 		info[0] = 0;
2198e14b073cSJohnny Huang 		prog_address = 0xe0c;
2199e14b073cSJohnny Huang 	}
2200a219f6deSJohnny Huang 
2201737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2202737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2203737ed20bSJohnny Huang 
2204e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2205737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2206737ed20bSJohnny Huang 	} else {
2207737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
2208e14b073cSJohnny Huang 		printf("OTPSTRAP[%d] %swill be protected\n", input, info);
2209737ed20bSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2210737ed20bSJohnny Huang 		if (!confirm_yesno()) {
2211737ed20bSJohnny Huang 			printf(" Aborting\n");
2212737ed20bSJohnny Huang 			return CMD_RET_FAILURE;
2213737ed20bSJohnny Huang 		}
2214737ed20bSJohnny Huang 	}
2215737ed20bSJohnny Huang 
2216737ed20bSJohnny Huang 	if (input < 32) {
2217737ed20bSJohnny Huang 		bit_offset = input;
2218737ed20bSJohnny Huang 	} else if (input < 64) {
2219737ed20bSJohnny Huang 		bit_offset = input - 32;
2220e14b073cSJohnny Huang 		prog_address += 2;
2221737ed20bSJohnny Huang 	} else {
2222737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2223737ed20bSJohnny Huang 	}
2224737ed20bSJohnny Huang 
2225e14b073cSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2226e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
2227e14b073cSJohnny Huang 		printf("OTPSTRAP[%d] %salready protected\n", input, info);
2228e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2229e14b073cSJohnny Huang 	}
2230de6fbf1cSJohnny Huang 
2231f347c284SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
2232de6fbf1cSJohnny Huang 	otp_soak(0);
223383655e91SJohnny Huang 
223483655e91SJohnny Huang 	if (ret) {
2235e14b073cSJohnny Huang 		printf("Protect OTPSTRAP[%d] %sfail\n", input, info);
2236737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2237737ed20bSJohnny Huang 	}
22389a4fe690SJohnny Huang 
2239794e27ecSJohnny Huang 	printf("OTPSTRAP[%d] %sis protected\n", input, info);
2240794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2241794e27ecSJohnny Huang }
2242794e27ecSJohnny Huang 
2243e14b073cSJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2244e14b073cSJohnny Huang {
2245e14b073cSJohnny Huang 	return _do_otpprotect(cmdtp, flag, argc, argv, 0);
2246e14b073cSJohnny Huang }
2247e14b073cSJohnny Huang 
2248e14b073cSJohnny Huang static int do_otprprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2249e14b073cSJohnny Huang {
2250e14b073cSJohnny Huang 	return _do_otpprotect(cmdtp, flag, argc, argv, 1);
2251e14b073cSJohnny Huang }
2252e14b073cSJohnny Huang 
2253f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2254f67375f7SJohnny Huang {
2255e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
2256f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2257f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2258f67375f7SJohnny Huang 
2259f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2260f67375f7SJohnny Huang }
2261f67375f7SJohnny Huang 
2262794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2263794e27ecSJohnny Huang {
2264794e27ecSJohnny Huang 	u32 update_num;
2265794e27ecSJohnny Huang 	int force = 0;
2266794e27ecSJohnny Huang 	int ret;
2267794e27ecSJohnny Huang 
2268794e27ecSJohnny Huang 	if (argc == 3) {
2269794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2270794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2271794e27ecSJohnny Huang 		force = 1;
2272794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2273794e27ecSJohnny Huang 	} else if (argc == 2) {
2274794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2275794e27ecSJohnny Huang 	} else {
2276794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2277794e27ecSJohnny Huang 	}
2278794e27ecSJohnny Huang 
2279794e27ecSJohnny Huang 	if (update_num > 64)
2280794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2281794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2282794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2283794e27ecSJohnny Huang 	if (ret)
2284794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2285794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2286794e27ecSJohnny Huang }
2287794e27ecSJohnny Huang 
2288794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2289794e27ecSJohnny Huang {
2290794e27ecSJohnny Huang 	u32 otp_rid[2];
2291*a8789b47SJohnny Huang 	u32 sw_rid[2];
2292794e27ecSJohnny Huang 	int rid_num = 0;
2293*a8789b47SJohnny Huang 	int sw_rid_num = 0;
2294794e27ecSJohnny Huang 	int ret;
2295794e27ecSJohnny Huang 
2296794e27ecSJohnny Huang 	if (argc != 1)
2297794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2298794e27ecSJohnny Huang 
2299794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2300f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2301f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2302794e27ecSJohnny Huang 
2303*a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2304*a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2305794e27ecSJohnny Huang 
2306*a8789b47SJohnny Huang 	rid_num = get_rid_num(otp_rid);
2307*a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2308*a8789b47SJohnny Huang 
2309*a8789b47SJohnny Huang 	printf("current SW revision ID: 0x%x\n", sw_rid_num);
2310794e27ecSJohnny Huang 	if (rid_num >= 0) {
2311794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2312794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2313794e27ecSJohnny Huang 	} else {
2314794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by 'otp update',\n"
2315794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n"
2316794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2317794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2318794e27ecSJohnny Huang 	}
2319794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2320794e27ecSJohnny Huang 
2321794e27ecSJohnny Huang 	return ret;
2322794e27ecSJohnny Huang }
2323794e27ecSJohnny Huang 
23242a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2325f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
23262a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2327a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2328de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
23292a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2330737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
2331e14b073cSJohnny Huang 	U_BOOT_CMD_MKENT(rprotect, 3, 0, do_otprprotect, "", ""),
23322a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2333794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2334794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
23352a856b9aSJohnny Huang };
23362a856b9aSJohnny Huang 
23372a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
23382a856b9aSJohnny Huang {
23392a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2340a219f6deSJohnny Huang 	u32 ver;
2341e14b073cSJohnny Huang 	int ret;
23422a856b9aSJohnny Huang 
23432a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
23442a856b9aSJohnny Huang 
2345737ed20bSJohnny Huang 	/* Drop the otp command */
23462a856b9aSJohnny Huang 	argc--;
23472a856b9aSJohnny Huang 	argv++;
23482a856b9aSJohnny Huang 
2349a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
23502a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23512a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
23522a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
23532a856b9aSJohnny Huang 
23540dae9d52SJohnny Huang 	ver = chip_version();
23550dae9d52SJohnny Huang 	switch (ver) {
2356e417205bSJohnny Huang 	case OTP_A0:
2357e417205bSJohnny Huang 		info_cb.version = OTP_A0;
23589a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
23599a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
23609a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
23619a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
23629a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
23639a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2364e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
23650dae9d52SJohnny Huang 		break;
2366e417205bSJohnny Huang 	case OTP_A1:
2367e417205bSJohnny Huang 		info_cb.version = OTP_A1;
23683cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
23693cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
23703cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
23713cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
23729a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
23739a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
2374e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
23750dae9d52SJohnny Huang 		break;
2376e417205bSJohnny Huang 	case OTP_A2:
2377e417205bSJohnny Huang 		info_cb.version = OTP_A2;
23785fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
23795fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
23805fdde29fSJohnny Huang 		info_cb.strap_info = a2_strap_info;
23815fdde29fSJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
23825fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
23835fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
2384e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
23850dae9d52SJohnny Huang 		break;
2386e417205bSJohnny Huang 	case OTP_A3:
2387e417205bSJohnny Huang 		info_cb.version = OTP_A3;
238864b66712SJohnny Huang 		info_cb.conf_info = a2_conf_info;
238964b66712SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
239064b66712SJohnny Huang 		info_cb.strap_info = a2_strap_info;
239164b66712SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a2_strap_info);
2392181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2393181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
2394e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
239564b66712SJohnny Huang 		break;
23960dae9d52SJohnny Huang 	default:
2397f1be5099SJohnny Huang 		printf("SOC is not supported\n");
23980dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
23999a4fe690SJohnny Huang 	}
24009a4fe690SJohnny Huang 
2401e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2402e14b073cSJohnny Huang 	writel(1, OTP_PROTECT_KEY); //password
2403e14b073cSJohnny Huang 
2404e14b073cSJohnny Huang 	return ret;
240569d5fd8fSJohnny Huang }
240669d5fd8fSJohnny Huang 
2407a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
240869d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2409f67375f7SJohnny Huang 	   "version\n"
2410f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
24112a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
24122d4b0742SJohnny Huang 	   "otp info strap [v]\n"
24132d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
2414de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2415ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2416ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2417ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
2418e14b073cSJohnny Huang 	   "otp rprotect [o] <bit_offset>\n"
2419794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2420794e27ecSJohnny Huang 	   "otp rid\n"
242169d5fd8fSJohnny Huang 	  );
2422