xref: /openbmc/u-boot/cmd/otp.c (revision b85900318560ab0ff6acc89305065afca7222dc6)
1a219f6deSJohnny Huang // SPDX-License-Identifier: GPL-2.0+
269d5fd8fSJohnny Huang /*
3a219f6deSJohnny Huang  * Copyright 2021 Aspeed Technology Inc.
469d5fd8fSJohnny Huang  */
5e417205bSJohnny Huang 
64c1c9b35SJohnny Huang #include <stdlib.h>
769d5fd8fSJohnny Huang #include <common.h>
869d5fd8fSJohnny Huang #include <console.h>
969d5fd8fSJohnny Huang #include <bootretry.h>
1069d5fd8fSJohnny Huang #include <cli.h>
1169d5fd8fSJohnny Huang #include <command.h>
1269d5fd8fSJohnny Huang #include <console.h>
134c1c9b35SJohnny Huang #include <malloc.h>
1469d5fd8fSJohnny Huang #include <inttypes.h>
1569d5fd8fSJohnny Huang #include <mapmem.h>
1669d5fd8fSJohnny Huang #include <asm/io.h>
1769d5fd8fSJohnny Huang #include <linux/compiler.h>
18696656c6SJohnny Huang #include <u-boot/sha256.h>
190cee9a95SJohnny Huang #include "otp_info.h"
2069d5fd8fSJohnny Huang 
2169d5fd8fSJohnny Huang DECLARE_GLOBAL_DATA_PTR;
2269d5fd8fSJohnny Huang 
23f347c284SJohnny Huang #define OTP_VER				"1.1.0"
24f67375f7SJohnny Huang 
2569d5fd8fSJohnny Huang #define OTP_PASSWD			0x349fe38a
26dacbba92SJohnny Huang #define RETRY				20
277332532cSJohnny Huang #define OTP_REGION_STRAP		BIT(0)
287332532cSJohnny Huang #define OTP_REGION_CONF			BIT(1)
297332532cSJohnny Huang #define OTP_REGION_DATA			BIT(2)
3069d5fd8fSJohnny Huang 
312a856b9aSJohnny Huang #define OTP_USAGE			-1
322a856b9aSJohnny Huang #define OTP_FAILURE			-2
332a856b9aSJohnny Huang #define OTP_SUCCESS			0
342a856b9aSJohnny Huang 
35a6af4a17SJohnny Huang #define OTP_PROG_SKIP			1
36a6af4a17SJohnny Huang 
37181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PUB		1
38181f72d8SJohnny Huang #define OTP_KEY_TYPE_RSA_PRIV		2
39181f72d8SJohnny Huang #define OTP_KEY_TYPE_AES		3
40181f72d8SJohnny Huang #define OTP_KEY_TYPE_VAULT		4
41181f72d8SJohnny Huang #define OTP_KEY_TYPE_HMAC		5
429a4fe690SJohnny Huang 
434c1c9b35SJohnny Huang #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
444c1c9b35SJohnny Huang #define PBWIDTH 60
454c1c9b35SJohnny Huang 
463d3688adSJohnny Huang #define OTP_BASE		0x1e6f2000
473d3688adSJohnny Huang #define OTP_PROTECT_KEY		OTP_BASE
483d3688adSJohnny Huang #define OTP_COMMAND		OTP_BASE + 0x4
493d3688adSJohnny Huang #define OTP_TIMING		OTP_BASE + 0x8
503d3688adSJohnny Huang #define OTP_ADDR		OTP_BASE + 0x10
513d3688adSJohnny Huang #define OTP_STATUS		OTP_BASE + 0x14
523d3688adSJohnny Huang #define OTP_COMPARE_1		OTP_BASE + 0x20
533d3688adSJohnny Huang #define OTP_COMPARE_2		OTP_BASE + 0x24
543d3688adSJohnny Huang #define OTP_COMPARE_3		OTP_BASE + 0x28
553d3688adSJohnny Huang #define OTP_COMPARE_4		OTP_BASE + 0x2c
56a8789b47SJohnny Huang #define SW_REV_ID0		OTP_BASE + 0x68
57a8789b47SJohnny Huang #define SW_REV_ID1		OTP_BASE + 0x6c
583d3688adSJohnny Huang 
59696656c6SJohnny Huang #define OTP_MAGIC		"SOCOTP"
60696656c6SJohnny Huang #define CHECKSUM_LEN		32
61a219f6deSJohnny Huang #define OTP_INC_DATA		BIT(31)
62a219f6deSJohnny Huang #define OTP_INC_CONFIG		BIT(30)
63a219f6deSJohnny Huang #define OTP_INC_STRAP		BIT(29)
64a219f6deSJohnny Huang #define OTP_ECC_EN		BIT(28)
65696656c6SJohnny Huang #define OTP_REGION_SIZE(info)	((info >> 16) & 0xffff)
66696656c6SJohnny Huang #define OTP_REGION_OFFSET(info)	(info & 0xffff)
67696656c6SJohnny Huang #define OTP_IMAGE_SIZE(info)	(info & 0xffff)
68696656c6SJohnny Huang 
69e417205bSJohnny Huang #define OTP_A0		0
70e417205bSJohnny Huang #define OTP_A1		1
71e417205bSJohnny Huang #define OTP_A2		2
72e417205bSJohnny Huang #define OTP_A3		3
73e417205bSJohnny Huang 
74e417205bSJohnny Huang #define ID0_AST2600A0	0x05000303
75e417205bSJohnny Huang #define ID1_AST2600A0	0x05000303
76e417205bSJohnny Huang #define ID0_AST2600A1	0x05010303
7721a8cfceSJohnny Huang #define ID1_AST2600A1	0x05010303
78e417205bSJohnny Huang #define ID0_AST2600A2	0x05010303
79e417205bSJohnny Huang #define ID1_AST2600A2	0x05020303
80e417205bSJohnny Huang #define ID0_AST2600A3	0x05030303
81e417205bSJohnny Huang #define ID1_AST2600A3	0x05030303
82e417205bSJohnny Huang #define ID0_AST2620A1	0x05010203
83e417205bSJohnny Huang #define ID1_AST2620A1	0x05010203
84e417205bSJohnny Huang #define ID0_AST2620A2	0x05010203
85e417205bSJohnny Huang #define ID1_AST2620A2	0x05020203
86e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
87e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
88e417205bSJohnny Huang #define ID0_AST2620A3	0x05030203
89e417205bSJohnny Huang #define ID1_AST2620A3	0x05030203
90e417205bSJohnny Huang #define ID0_AST2605A2	0x05010103
91e417205bSJohnny Huang #define ID1_AST2605A2	0x05020103
92e417205bSJohnny Huang #define ID0_AST2605A3	0x05030103
93e417205bSJohnny Huang #define ID1_AST2605A3	0x05030103
94e417205bSJohnny Huang #define ID0_AST2625A3	0x05030403
95e417205bSJohnny Huang #define ID1_AST2625A3	0x05030403
96696656c6SJohnny Huang 
9761a6cda7SJohnny Huang #define SOC_AST2600A0	0
9861a6cda7SJohnny Huang #define SOC_AST2600A1	1
9961a6cda7SJohnny Huang #define SOC_AST2600A2	2
10061a6cda7SJohnny Huang #define SOC_AST2600A3	3
10161a6cda7SJohnny Huang 
10261a6cda7SJohnny Huang #define OTPTOOL_VERSION(a, b, c) (((a) << 24) + ((b) << 12) + (c))
10361a6cda7SJohnny Huang 
104696656c6SJohnny Huang struct otp_header {
105696656c6SJohnny Huang 	u8	otp_magic[8];
10661a6cda7SJohnny Huang 	u32	soc_ver;
10761a6cda7SJohnny Huang 	u32	otptool_ver;
108696656c6SJohnny Huang 	u32	image_info;
109696656c6SJohnny Huang 	u32	data_info;
110696656c6SJohnny Huang 	u32	config_info;
111696656c6SJohnny Huang 	u32	strap_info;
1127e523e3bSJohnny Huang 	u32	scu_protect_info;
113696656c6SJohnny Huang 	u32	checksum_offset;
114a219f6deSJohnny Huang } __packed;
115696656c6SJohnny Huang 
11666f2f8e5SJohnny Huang struct otpstrap_status {
11769d5fd8fSJohnny Huang 	int value;
11869d5fd8fSJohnny Huang 	int option_array[7];
11969d5fd8fSJohnny Huang 	int remain_times;
12069d5fd8fSJohnny Huang 	int writeable_option;
12169d5fd8fSJohnny Huang 	int protected;
12269d5fd8fSJohnny Huang };
12369d5fd8fSJohnny Huang 
1249a4fe690SJohnny Huang struct otpkey_type {
1259a4fe690SJohnny Huang 	int value;
1269a4fe690SJohnny Huang 	int key_type;
1279a4fe690SJohnny Huang 	int need_id;
1289a4fe690SJohnny Huang 	char information[110];
1299a4fe690SJohnny Huang };
1309a4fe690SJohnny Huang 
1319a4fe690SJohnny Huang struct otp_info_cb {
1329a4fe690SJohnny Huang 	int version;
133e417205bSJohnny Huang 	char ver_name[3];
13479e42a59SJoel Stanley 	const struct otpstrap_info *strap_info;
1359a4fe690SJohnny Huang 	int strap_info_len;
13679e42a59SJoel Stanley 	const struct otpconf_info *conf_info;
1379a4fe690SJohnny Huang 	int conf_info_len;
13879e42a59SJoel Stanley 	const struct otpkey_type *key_info;
1399a4fe690SJohnny Huang 	int key_info_len;
1400dc9a440SJohnny Huang 	const struct scu_info *scu_info;
1410dc9a440SJohnny Huang 	int scu_info_len;
1429a4fe690SJohnny Huang };
1439a4fe690SJohnny Huang 
144696656c6SJohnny Huang struct otp_image_layout {
1455010032bSJohnny Huang 	int data_length;
1465010032bSJohnny Huang 	int conf_length;
1475010032bSJohnny Huang 	int strap_length;
148a219f6deSJohnny Huang 	u8 *data;
149a219f6deSJohnny Huang 	u8 *data_ignore;
150a219f6deSJohnny Huang 	u8 *conf;
151a219f6deSJohnny Huang 	u8 *conf_ignore;
152a219f6deSJohnny Huang 	u8 *strap;
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
316377f8cd7SJohnny Huang 			otp_write(0x3000, 0x0); // Write MRA
317377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0); // Write MRB
318dacbba92SJohnny Huang 			otp_write(0x1000, 0x0); // Write MR
319dacbba92SJohnny Huang 			break;
320dacbba92SJohnny Huang 		case 1: //normal program
321377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
322377f8cd7SJohnny Huang 			otp_write(0x5000, 0x1008); // Write MRB
323377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0024); // Write MR
324feea3fdfSJohnny Huang 			writel(0x04191388, OTP_TIMING); // 200us
325dacbba92SJohnny Huang 			break;
326dacbba92SJohnny Huang 		case 2: //soak program
327377f8cd7SJohnny Huang 			otp_write(0x3000, 0x1320); // Write MRA
328377f8cd7SJohnny Huang 			otp_write(0x5000, 0x0007); // Write MRB
329377f8cd7SJohnny Huang 			otp_write(0x1000, 0x0100); // 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].protected = 0;
6385010032bSJohnny Huang 		}
6395010032bSJohnny Huang 		strap_end = 28;
6405010032bSJohnny Huang 	}
64176d13988SJohnny Huang 
642dacbba92SJohnny Huang 	otp_soak(0);
6435010032bSJohnny Huang 	for (i = 16; i < strap_end; i += 2) {
64476d13988SJohnny Huang 		int option = (i - 16) / 2;
645a219f6deSJohnny Huang 
646f347c284SJohnny Huang 		otp_read_conf(i, &OTPSTRAP_RAW[0]);
647f347c284SJohnny Huang 		otp_read_conf(i + 1, &OTPSTRAP_RAW[1]);
64876d13988SJohnny Huang 		for (j = 0; j < 32; j++) {
64976d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[0] >> j) & 0x1);
650a219f6deSJohnny Huang 
651a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
65276d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
65376d13988SJohnny Huang 			if (bit_value == 1)
65476d13988SJohnny Huang 				otpstrap[j].remain_times--;
65576d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
65676d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
65776d13988SJohnny Huang 		}
65876d13988SJohnny Huang 		for (j = 32; j < 64; j++) {
65976d13988SJohnny Huang 			char bit_value = ((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1);
660a219f6deSJohnny Huang 
661a219f6deSJohnny Huang 			if (bit_value == 0 && otpstrap[j].writeable_option == -1)
66276d13988SJohnny Huang 				otpstrap[j].writeable_option = option;
66376d13988SJohnny Huang 			if (bit_value == 1)
66476d13988SJohnny Huang 				otpstrap[j].remain_times--;
66576d13988SJohnny Huang 			otpstrap[j].value ^= bit_value;
66676d13988SJohnny Huang 			otpstrap[j].option_array[option] = bit_value;
66776d13988SJohnny Huang 		}
66876d13988SJohnny Huang 	}
6695010032bSJohnny Huang 
670f347c284SJohnny Huang 	otp_read_conf(30, &OTPSTRAP_RAW[0]);
671f347c284SJohnny Huang 	otp_read_conf(31, &OTPSTRAP_RAW[1]);
67276d13988SJohnny Huang 	for (j = 0; j < 32; j++) {
67376d13988SJohnny Huang 		if (((OTPSTRAP_RAW[0] >> j) & 0x1) == 1)
67476d13988SJohnny Huang 			otpstrap[j].protected = 1;
67576d13988SJohnny Huang 	}
67676d13988SJohnny Huang 	for (j = 32; j < 64; j++) {
67776d13988SJohnny Huang 		if (((OTPSTRAP_RAW[1] >> (j - 32)) & 0x1) == 1)
67876d13988SJohnny Huang 			otpstrap[j].protected = 1;
67976d13988SJohnny Huang 	}
68076d13988SJohnny Huang }
68176d13988SJohnny Huang 
6827e523e3bSJohnny Huang static int otp_strap_bit_confirm(struct otpstrap_status *otpstrap, int offset, int ibit, int bit, int pbit)
683f347c284SJohnny Huang {
684f347c284SJohnny Huang 	int prog_flag = 0;
685f347c284SJohnny Huang 
686f347c284SJohnny Huang 	// ignore this bit
687f347c284SJohnny Huang 	if (ibit == 1)
688f347c284SJohnny Huang 		return OTP_SUCCESS;
689f347c284SJohnny Huang 	printf("OTPSTRAP[%X]:\n", offset);
690f347c284SJohnny Huang 
691f347c284SJohnny Huang 	if (bit == otpstrap->value) {
6927e523e3bSJohnny Huang 		if (!pbit) {
693f347c284SJohnny Huang 			printf("    The value is same as before, skip it.\n");
694f347c284SJohnny Huang 			return OTP_PROG_SKIP;
695f347c284SJohnny Huang 		}
696f347c284SJohnny Huang 		printf("    The value is same as before.\n");
697f347c284SJohnny Huang 	} else {
698f347c284SJohnny Huang 		prog_flag = 1;
699f347c284SJohnny Huang 	}
700f347c284SJohnny Huang 	if (otpstrap->protected == 1 && prog_flag) {
701f347c284SJohnny Huang 		printf("    This bit is protected and is not writable\n");
702f347c284SJohnny Huang 		return OTP_FAILURE;
703f347c284SJohnny Huang 	}
704f347c284SJohnny Huang 	if (otpstrap->remain_times == 0 && prog_flag) {
705f347c284SJohnny Huang 		printf("    This bit is no remaining times to write.\n");
706f347c284SJohnny Huang 		return OTP_FAILURE;
707f347c284SJohnny Huang 	}
708f347c284SJohnny Huang 	if (pbit == 1)
709f347c284SJohnny Huang 		printf("    This bit will be protected and become non-writable.\n");
710f347c284SJohnny Huang 	if (prog_flag)
711f347c284SJohnny 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);
712f347c284SJohnny Huang 
713f347c284SJohnny Huang 	return OTP_SUCCESS;
714f347c284SJohnny Huang }
715f347c284SJohnny Huang 
716f347c284SJohnny Huang static int otp_prog_strap_b(int bit_offset, int value)
717f347c284SJohnny Huang {
718f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
719f347c284SJohnny Huang 	u32 prog_address;
720f347c284SJohnny Huang 	int offset;
721f347c284SJohnny Huang 	int ret;
722f347c284SJohnny Huang 
723f347c284SJohnny Huang 	otp_strap_status(otpstrap);
724f347c284SJohnny Huang 
7257e523e3bSJohnny Huang 	ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
726f347c284SJohnny Huang 
727f347c284SJohnny Huang 	if (ret != OTP_SUCCESS)
728f347c284SJohnny Huang 		return ret;
729f347c284SJohnny Huang 
730f347c284SJohnny Huang 	prog_address = 0x800;
731f347c284SJohnny Huang 	if (bit_offset < 32) {
732f347c284SJohnny Huang 		offset = bit_offset;
733f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) / 8) * 0x200;
734f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 16) % 8) * 0x2;
735f347c284SJohnny Huang 
736f347c284SJohnny Huang 	} else {
737f347c284SJohnny Huang 		offset = (bit_offset - 32);
738f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) / 8) * 0x200;
739f347c284SJohnny Huang 		prog_address |= ((otpstrap[bit_offset].writeable_option * 2 + 17) % 8) * 0x2;
740f347c284SJohnny Huang 	}
741f347c284SJohnny Huang 
742f347c284SJohnny Huang 	return otp_prog_dc_b(1, prog_address, offset);
743f347c284SJohnny Huang }
744f347c284SJohnny Huang 
745f347c284SJohnny Huang static int otp_print_conf(u32 offset, int dw_count)
746f347c284SJohnny Huang {
747f347c284SJohnny Huang 	int i;
748f347c284SJohnny Huang 	u32 ret[1];
749f347c284SJohnny Huang 
750f347c284SJohnny Huang 	if (offset + dw_count > 32)
751f347c284SJohnny Huang 		return OTP_USAGE;
752f347c284SJohnny Huang 	otp_soak(0);
753f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i++) {
754f347c284SJohnny Huang 		otp_read_conf(i, ret);
755f347c284SJohnny Huang 		printf("OTPCFG%X: %08X\n", i, ret[0]);
756f347c284SJohnny Huang 	}
757f347c284SJohnny Huang 	printf("\n");
758f347c284SJohnny Huang 	return OTP_SUCCESS;
759f347c284SJohnny Huang }
760f347c284SJohnny Huang 
761f347c284SJohnny Huang static int otp_print_data(u32 offset, int dw_count)
762f347c284SJohnny Huang {
763f347c284SJohnny Huang 	int i;
764f347c284SJohnny Huang 	u32 ret[2];
765f347c284SJohnny Huang 
766f347c284SJohnny Huang 	if (offset + dw_count > 2048 || offset % 4 != 0)
767f347c284SJohnny Huang 		return OTP_USAGE;
768f347c284SJohnny Huang 	otp_soak(0);
769f347c284SJohnny Huang 	for (i = offset; i < offset + dw_count; i += 2) {
770f347c284SJohnny Huang 		otp_read_data(i, ret);
771f347c284SJohnny Huang 		if (i % 4 == 0)
772f347c284SJohnny Huang 			printf("%03X: %08X %08X ", i * 4, ret[0], ret[1]);
773f347c284SJohnny Huang 		else
774f347c284SJohnny Huang 			printf("%08X %08X\n", ret[0], ret[1]);
775f347c284SJohnny Huang 	}
776f347c284SJohnny Huang 	printf("\n");
777f347c284SJohnny Huang 	return OTP_SUCCESS;
778f347c284SJohnny Huang }
779f347c284SJohnny Huang 
780f347c284SJohnny Huang static int otp_print_strap(int start, int count)
781f347c284SJohnny Huang {
782f347c284SJohnny Huang 	int i, j;
783f347c284SJohnny Huang 	int remains;
784f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
785f347c284SJohnny Huang 
786f347c284SJohnny Huang 	if (start < 0 || start > 64)
787f347c284SJohnny Huang 		return OTP_USAGE;
788f347c284SJohnny Huang 
789f347c284SJohnny Huang 	if ((start + count) < 0 || (start + count) > 64)
790f347c284SJohnny Huang 		return OTP_USAGE;
791f347c284SJohnny Huang 
792f347c284SJohnny Huang 	otp_strap_status(otpstrap);
793f347c284SJohnny Huang 
7947e523e3bSJohnny Huang 	if (info_cb.version == OTP_A0)
795f347c284SJohnny Huang 		remains = 7;
7967e523e3bSJohnny Huang 	else
797f347c284SJohnny Huang 		remains = 6;
7987e523e3bSJohnny Huang 	printf("BIT(hex)  Value  Option           Status\n");
799f347c284SJohnny Huang 	printf("______________________________________________________________________________\n");
800f347c284SJohnny Huang 
801f347c284SJohnny Huang 	for (i = start; i < start + count; i++) {
802f347c284SJohnny Huang 		printf("0x%-8X", i);
803f347c284SJohnny Huang 		printf("%-7d", otpstrap[i].value);
804f347c284SJohnny Huang 		for (j = 0; j < remains; j++)
805f347c284SJohnny Huang 			printf("%d ", otpstrap[i].option_array[j]);
806f347c284SJohnny Huang 		printf("   ");
807f347c284SJohnny Huang 		if (otpstrap[i].protected == 1) {
808f347c284SJohnny Huang 			printf("protected and not writable");
809f347c284SJohnny Huang 		} else {
810f347c284SJohnny Huang 			printf("not protected ");
811f347c284SJohnny Huang 			if (otpstrap[i].remain_times == 0)
812f347c284SJohnny Huang 				printf("and no remaining times to write.");
813f347c284SJohnny Huang 			else
814f347c284SJohnny Huang 				printf("and still can write %d times", otpstrap[i].remain_times);
815f347c284SJohnny Huang 		}
816f347c284SJohnny Huang 		printf("\n");
817f347c284SJohnny Huang 	}
818f347c284SJohnny Huang 
819f347c284SJohnny Huang 	return OTP_SUCCESS;
820f347c284SJohnny Huang }
821f347c284SJohnny Huang 
822794e27ecSJohnny Huang static void otp_print_revid(u32 *rid)
823794e27ecSJohnny Huang {
824794e27ecSJohnny Huang 	int bit_offset;
825794e27ecSJohnny Huang 	int i, j;
826794e27ecSJohnny Huang 
827794e27ecSJohnny Huang 	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
828794e27ecSJohnny Huang 	printf("___________________________________________________\n");
829794e27ecSJohnny Huang 	for (i = 0; i < 64; i++) {
830794e27ecSJohnny Huang 		if (i < 32) {
831794e27ecSJohnny Huang 			j = 0;
832794e27ecSJohnny Huang 			bit_offset = i;
833794e27ecSJohnny Huang 		} else {
834794e27ecSJohnny Huang 			j = 1;
835794e27ecSJohnny Huang 			bit_offset = i - 32;
836794e27ecSJohnny Huang 		}
837794e27ecSJohnny Huang 		if (i % 16 == 0)
838794e27ecSJohnny Huang 			printf("%2x | ", i);
839794e27ecSJohnny Huang 		printf("%d  ", (rid[j] >> bit_offset) & 0x1);
840794e27ecSJohnny Huang 		if ((i + 1) % 16 == 0)
841794e27ecSJohnny Huang 			printf("\n");
842794e27ecSJohnny Huang 	}
843794e27ecSJohnny Huang }
844794e27ecSJohnny Huang 
8450dc9a440SJohnny Huang static void otp_print_scu_info(void)
8460dc9a440SJohnny Huang {
8470dc9a440SJohnny Huang 	const struct scu_info *scu_info = info_cb.scu_info;
8480dc9a440SJohnny Huang 	u32 OTPCFG[2];
8490dc9a440SJohnny Huang 	u32 scu_offset;
8500dc9a440SJohnny Huang 	u32 bit_offset;
8510dc9a440SJohnny Huang 	u32 reg_p;
8520dc9a440SJohnny Huang 	u32 length;
8530dc9a440SJohnny Huang 	int i, j;
8540dc9a440SJohnny Huang 
8550dc9a440SJohnny Huang 	otp_soak(0);
8560dc9a440SJohnny Huang 	otp_read_conf(28, &OTPCFG[0]);
8570dc9a440SJohnny Huang 	otp_read_conf(29, &OTPCFG[1]);
8580dc9a440SJohnny Huang 	printf("SCU     BIT   reg_protect     Description\n");
8590dc9a440SJohnny Huang 	printf("____________________________________________________________________\n");
8600dc9a440SJohnny Huang 	for (i = 0; i < info_cb.scu_info_len; i++) {
8610dc9a440SJohnny Huang 		length = scu_info[i].length;
8620dc9a440SJohnny Huang 		for (j = 0; j < length; j++) {
8630dc9a440SJohnny Huang 			if (scu_info[i].bit_offset + j < 32) {
8640dc9a440SJohnny Huang 				scu_offset = 0x500;
8650dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j;
8660dc9a440SJohnny Huang 				reg_p = (OTPCFG[0] >> bit_offset) & 0x1;
8670dc9a440SJohnny Huang 			} else {
8680dc9a440SJohnny Huang 				scu_offset = 0x510;
8690dc9a440SJohnny Huang 				bit_offset = scu_info[i].bit_offset + j - 32;
8700dc9a440SJohnny Huang 				reg_p = (OTPCFG[1] >> bit_offset) & 0x1;
8710dc9a440SJohnny Huang 			}
8720dc9a440SJohnny Huang 			printf("0x%-6X", scu_offset);
8730dc9a440SJohnny Huang 			printf("0x%-4X", bit_offset);
8740dc9a440SJohnny Huang 			printf("0x%-13X", reg_p);
8750dc9a440SJohnny Huang 			if (length == 1) {
8760dc9a440SJohnny Huang 				printf(" %s\n", scu_info[i].information);
8770dc9a440SJohnny Huang 				continue;
8780dc9a440SJohnny Huang 			}
8790dc9a440SJohnny Huang 
8800dc9a440SJohnny Huang 			if (j == 0)
8810dc9a440SJohnny Huang 				printf("/%s\n", scu_info[i].information);
8820dc9a440SJohnny Huang 			else if (j == length - 1)
8830dc9a440SJohnny Huang 				printf("\\ \"\n");
8840dc9a440SJohnny Huang 			else
8850dc9a440SJohnny Huang 				printf("| \"\n");
8860dc9a440SJohnny Huang 		}
8870dc9a440SJohnny Huang 	}
8880dc9a440SJohnny Huang }
8890dc9a440SJohnny Huang 
890696656c6SJohnny Huang static int otp_print_conf_image(struct otp_image_layout *image_layout)
89169d5fd8fSJohnny Huang {
89279e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
893a219f6deSJohnny Huang 	u32 *OTPCFG = (u32 *)image_layout->conf;
894a219f6deSJohnny Huang 	u32 *OTPCFG_IGNORE = (u32 *)image_layout->conf_ignore;
895a219f6deSJohnny Huang 	u32 mask;
896a219f6deSJohnny Huang 	u32 dw_offset;
897a219f6deSJohnny Huang 	u32 bit_offset;
898a219f6deSJohnny Huang 	u32 otp_value;
899a219f6deSJohnny Huang 	u32 otp_ignore;
900b458cd62SJohnny Huang 	int fail = 0;
9017adec5f6SJohnny Huang 	int mask_err;
902794e27ecSJohnny Huang 	int rid_num = 0;
90373f11549SJohnny Huang 	char valid_bit[20];
904794e27ecSJohnny Huang 	int fz;
90566f2f8e5SJohnny Huang 	int i;
90673f11549SJohnny Huang 	int j;
90766f2f8e5SJohnny Huang 
908737ed20bSJohnny Huang 	printf("DW    BIT        Value       Description\n");
90966f2f8e5SJohnny Huang 	printf("__________________________________________________________________________\n");
9103cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
9117adec5f6SJohnny Huang 		mask_err = 0;
9123cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
9133cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
9143cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
915b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
916696656c6SJohnny Huang 		otp_ignore = (OTPCFG_IGNORE[dw_offset] >> bit_offset) & mask;
917b458cd62SJohnny Huang 
9187adec5f6SJohnny Huang 		if (conf_info[i].value == OTP_REG_VALID_BIT) {
9197adec5f6SJohnny Huang 			if (((otp_value + otp_ignore) & mask) != mask) {
920b458cd62SJohnny Huang 				fail = 1;
9217adec5f6SJohnny Huang 				mask_err = 1;
9227adec5f6SJohnny Huang 			}
9237adec5f6SJohnny Huang 		} else {
9247adec5f6SJohnny Huang 			if (otp_ignore == mask) {
9257adec5f6SJohnny Huang 				continue;
9267adec5f6SJohnny Huang 			} else if (otp_ignore != 0) {
9277adec5f6SJohnny Huang 				fail = 1;
9287adec5f6SJohnny Huang 				mask_err = 1;
9297adec5f6SJohnny Huang 			}
9307adec5f6SJohnny Huang 		}
931b458cd62SJohnny Huang 
932a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
9333cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
9343cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
9353cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
936b458cd62SJohnny Huang 			continue;
937b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
938b458cd62SJohnny Huang 
9393cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
9403cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
94166f2f8e5SJohnny Huang 		} else {
942b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
9433cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
9443cb28812SJohnny Huang 			       conf_info[i].bit_offset);
94566f2f8e5SJohnny Huang 		}
946b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
947b458cd62SJohnny Huang 
9487adec5f6SJohnny Huang 		if (mask_err) {
9497adec5f6SJohnny Huang 			printf("Ignore, mask error\n");
950a219f6deSJohnny Huang 			continue;
951a219f6deSJohnny Huang 		}
9523cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
953b458cd62SJohnny Huang 			printf("Reserved\n");
9543cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
9553cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
956b458cd62SJohnny Huang 			printf("\n");
9573cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
958b458cd62SJohnny Huang 			if (otp_value != 0) {
95973f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
960a219f6deSJohnny Huang 					if (otp_value == (1 << j))
96173f11549SJohnny Huang 						valid_bit[j * 2] = '1';
962a219f6deSJohnny Huang 					else
96373f11549SJohnny Huang 						valid_bit[j * 2] = '0';
96473f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
96573f11549SJohnny Huang 				}
96673f11549SJohnny Huang 				valid_bit[15] = 0;
96773f11549SJohnny Huang 			} else {
96873f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
969b458cd62SJohnny Huang 			}
9703cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
971b458cd62SJohnny Huang 			printf("\n");
972b458cd62SJohnny Huang 		} else {
9733cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
974b458cd62SJohnny Huang 		}
975b458cd62SJohnny Huang 	}
976b458cd62SJohnny Huang 
977794e27ecSJohnny Huang 	if (OTPCFG[0xa] != 0 || OTPCFG[0xb] != 0) {
978794e27ecSJohnny Huang 		if (OTPCFG_IGNORE[0xa] != 0 && OTPCFG_IGNORE[0xb] != 0) {
979794e27ecSJohnny Huang 			printf("OTP revision ID is invalid.\n");
980794e27ecSJohnny Huang 			fail = 1;
981794e27ecSJohnny Huang 		} else {
982794e27ecSJohnny Huang 			fz = 0;
983794e27ecSJohnny Huang 			for (i = 0; i < 64; i++) {
984794e27ecSJohnny Huang 				if (get_dw_bit(&OTPCFG[0xa], i) == 0) {
985794e27ecSJohnny Huang 					if (!fz)
986794e27ecSJohnny Huang 						fz = 1;
987794e27ecSJohnny Huang 				} else {
988794e27ecSJohnny Huang 					rid_num++;
989794e27ecSJohnny Huang 					if (fz) {
990794e27ecSJohnny Huang 						printf("OTP revision ID is invalid.\n");
991794e27ecSJohnny Huang 						fail = 1;
992794e27ecSJohnny Huang 						break;
993794e27ecSJohnny Huang 					}
994794e27ecSJohnny Huang 				}
995794e27ecSJohnny Huang 			}
996794e27ecSJohnny Huang 		}
997794e27ecSJohnny Huang 		if (fail)
998794e27ecSJohnny Huang 			printf("OTP revision ID\n");
999794e27ecSJohnny Huang 		else
1000794e27ecSJohnny Huang 			printf("OTP revision ID: 0x%x\n", rid_num);
1001794e27ecSJohnny Huang 		otp_print_revid(&OTPCFG[0xa]);
1002794e27ecSJohnny Huang 	}
1003794e27ecSJohnny Huang 
1004b458cd62SJohnny Huang 	if (fail)
1005b458cd62SJohnny Huang 		return OTP_FAILURE;
1006b458cd62SJohnny Huang 
100766f2f8e5SJohnny Huang 	return OTP_SUCCESS;
100866f2f8e5SJohnny Huang }
100966f2f8e5SJohnny Huang 
10102d4b0742SJohnny Huang static int otp_print_conf_info(int input_offset)
101166f2f8e5SJohnny Huang {
101279e42a59SJoel Stanley 	const struct otpconf_info *conf_info = info_cb.conf_info;
1013a219f6deSJohnny Huang 	u32 OTPCFG[16];
1014a219f6deSJohnny Huang 	u32 mask;
1015a219f6deSJohnny Huang 	u32 dw_offset;
1016a219f6deSJohnny Huang 	u32 bit_offset;
1017a219f6deSJohnny Huang 	u32 otp_value;
101873f11549SJohnny Huang 	char valid_bit[20];
101966f2f8e5SJohnny Huang 	int i;
102073f11549SJohnny Huang 	int j;
102166f2f8e5SJohnny Huang 
1022dacbba92SJohnny Huang 	otp_soak(0);
1023bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++)
1024f347c284SJohnny Huang 		otp_read_conf(i, &OTPCFG[i]);
102566f2f8e5SJohnny Huang 
1026b458cd62SJohnny Huang 	printf("DW    BIT        Value       Description\n");
1027b458cd62SJohnny Huang 	printf("__________________________________________________________________________\n");
10283cb28812SJohnny Huang 	for (i = 0; i < info_cb.conf_info_len; i++) {
10293cb28812SJohnny Huang 		if (input_offset != -1 && input_offset != conf_info[i].dw_offset)
10302d4b0742SJohnny Huang 			continue;
10313cb28812SJohnny Huang 		dw_offset = conf_info[i].dw_offset;
10323cb28812SJohnny Huang 		bit_offset = conf_info[i].bit_offset;
10333cb28812SJohnny Huang 		mask = BIT(conf_info[i].length) - 1;
1034b458cd62SJohnny Huang 		otp_value = (OTPCFG[dw_offset] >> bit_offset) & mask;
1035b458cd62SJohnny Huang 
1036a219f6deSJohnny Huang 		if (otp_value != conf_info[i].value &&
10373cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_RESERVED &&
10383cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALUE &&
10393cb28812SJohnny Huang 		    conf_info[i].value != OTP_REG_VALID_BIT)
1040b458cd62SJohnny Huang 			continue;
1041b458cd62SJohnny Huang 		printf("0x%-4X", dw_offset);
1042b458cd62SJohnny Huang 
10433cb28812SJohnny Huang 		if (conf_info[i].length == 1) {
10443cb28812SJohnny Huang 			printf("0x%-9X", conf_info[i].bit_offset);
1045b458cd62SJohnny Huang 		} else {
1046b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
10473cb28812SJohnny Huang 			       conf_info[i].bit_offset + conf_info[i].length - 1,
10483cb28812SJohnny Huang 			       conf_info[i].bit_offset);
1049b458cd62SJohnny Huang 		}
1050b458cd62SJohnny Huang 		printf("0x%-10x", otp_value);
1051b458cd62SJohnny Huang 
10523cb28812SJohnny Huang 		if (conf_info[i].value == OTP_REG_RESERVED) {
1053b458cd62SJohnny Huang 			printf("Reserved\n");
10543cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALUE) {
10553cb28812SJohnny Huang 			printf(conf_info[i].information, otp_value);
1056b458cd62SJohnny Huang 			printf("\n");
10573cb28812SJohnny Huang 		} else if (conf_info[i].value == OTP_REG_VALID_BIT) {
1058b458cd62SJohnny Huang 			if (otp_value != 0) {
105973f11549SJohnny Huang 				for (j = 0; j < 7; j++) {
1060a219f6deSJohnny Huang 					if (otp_value == (1 << j))
106173f11549SJohnny Huang 						valid_bit[j * 2] = '1';
1062a219f6deSJohnny Huang 					else
106373f11549SJohnny Huang 						valid_bit[j * 2] = '0';
106473f11549SJohnny Huang 					valid_bit[j * 2 + 1] = ' ';
106573f11549SJohnny Huang 				}
106673f11549SJohnny Huang 				valid_bit[15] = 0;
106773f11549SJohnny Huang 			} else {
106873f11549SJohnny Huang 				strcpy(valid_bit, "0 0 0 0 0 0 0 0\0");
1069b458cd62SJohnny Huang 			}
10703cb28812SJohnny Huang 			printf(conf_info[i].information, valid_bit);
1071b458cd62SJohnny Huang 			printf("\n");
1072b458cd62SJohnny Huang 		} else {
10733cb28812SJohnny Huang 			printf("%s\n", conf_info[i].information);
1074b458cd62SJohnny Huang 		}
1075b458cd62SJohnny Huang 	}
1076b458cd62SJohnny Huang 	return OTP_SUCCESS;
107766f2f8e5SJohnny Huang }
107866f2f8e5SJohnny Huang 
10795010032bSJohnny Huang static int otp_print_strap_image(struct otp_image_layout *image_layout)
108076d13988SJohnny Huang {
108179e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
1082a219f6deSJohnny Huang 	u32 *OTPSTRAP;
1083a219f6deSJohnny Huang 	u32 *OTPSTRAP_PRO;
1084a219f6deSJohnny Huang 	u32 *OTPSTRAP_IGNORE;
108576d13988SJohnny Huang 	int i;
1086a8bd6d8cSJohnny Huang 	int fail = 0;
1087a219f6deSJohnny Huang 	u32 bit_offset;
1088a219f6deSJohnny Huang 	u32 dw_offset;
1089a219f6deSJohnny Huang 	u32 mask;
1090a219f6deSJohnny Huang 	u32 otp_value;
1091a219f6deSJohnny Huang 	u32 otp_protect;
1092a219f6deSJohnny Huang 	u32 otp_ignore;
109376d13988SJohnny Huang 
1094a219f6deSJohnny Huang 	OTPSTRAP = (u32 *)image_layout->strap;
1095a219f6deSJohnny Huang 	OTPSTRAP_PRO = (u32 *)image_layout->strap_pro;
1096a219f6deSJohnny Huang 	OTPSTRAP_IGNORE = (u32 *)image_layout->strap_ignore;
10977e523e3bSJohnny Huang 
1098a8bd6d8cSJohnny Huang 	printf("BIT(hex)   Value       Protect     Description\n");
1099de6b0cc4SJohnny Huang 	printf("__________________________________________________________________________________________\n");
1100b458cd62SJohnny Huang 
11013cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
11027adec5f6SJohnny Huang 		fail = 0;
1103696656c6SJohnny Huang 		if (strap_info[i].bit_offset > 31) {
1104a8bd6d8cSJohnny Huang 			dw_offset = 1;
11053cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset - 32;
1106a8bd6d8cSJohnny Huang 		} else {
1107a8bd6d8cSJohnny Huang 			dw_offset = 0;
11083cb28812SJohnny Huang 			bit_offset = strap_info[i].bit_offset;
1109a8bd6d8cSJohnny Huang 		}
111076d13988SJohnny Huang 
11113cb28812SJohnny Huang 		mask = BIT(strap_info[i].length) - 1;
1112a8bd6d8cSJohnny Huang 		otp_value = (OTPSTRAP[dw_offset] >> bit_offset) & mask;
1113a8bd6d8cSJohnny Huang 		otp_protect = (OTPSTRAP_PRO[dw_offset] >> bit_offset) & mask;
1114696656c6SJohnny Huang 		otp_ignore = (OTPSTRAP_IGNORE[dw_offset] >> bit_offset) & mask;
1115a8bd6d8cSJohnny Huang 
1116a219f6deSJohnny Huang 		if (otp_ignore == mask)
1117a8bd6d8cSJohnny Huang 			continue;
1118a219f6deSJohnny Huang 		else if (otp_ignore != 0)
1119a8bd6d8cSJohnny Huang 			fail = 1;
1120a8bd6d8cSJohnny Huang 
1121a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
11223cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1123a8bd6d8cSJohnny Huang 			continue;
1124a8bd6d8cSJohnny Huang 
11253cb28812SJohnny Huang 		if (strap_info[i].length == 1) {
11263cb28812SJohnny Huang 			printf("0x%-9X", strap_info[i].bit_offset);
1127a8bd6d8cSJohnny Huang 		} else {
1128b458cd62SJohnny Huang 			printf("0x%-2X:0x%-4X",
11293cb28812SJohnny Huang 			       strap_info[i].bit_offset + strap_info[i].length - 1,
11303cb28812SJohnny Huang 			       strap_info[i].bit_offset);
1131a8bd6d8cSJohnny Huang 		}
1132a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_value);
1133a8bd6d8cSJohnny Huang 		printf("0x%-10x", otp_protect);
1134a8bd6d8cSJohnny Huang 
1135a8bd6d8cSJohnny Huang 		if (fail) {
1136696656c6SJohnny Huang 			printf("Ignore mask error\n");
1137a8bd6d8cSJohnny Huang 		} else {
11383cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
11393cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1140a8bd6d8cSJohnny Huang 			else
1141a8bd6d8cSJohnny Huang 				printf("Reserved\n");
1142a8bd6d8cSJohnny Huang 		}
1143a8bd6d8cSJohnny Huang 	}
1144a8bd6d8cSJohnny Huang 
1145a8bd6d8cSJohnny Huang 	if (fail)
114676d13988SJohnny Huang 		return OTP_FAILURE;
114776d13988SJohnny Huang 
114876d13988SJohnny Huang 	return OTP_SUCCESS;
114976d13988SJohnny Huang }
115076d13988SJohnny Huang 
1151b458cd62SJohnny Huang static int otp_print_strap_info(int view)
115276d13988SJohnny Huang {
115379e42a59SJoel Stanley 	const struct otpstrap_info *strap_info = info_cb.strap_info;
115476d13988SJohnny Huang 	struct otpstrap_status strap_status[64];
115507baa4e8SJohnny Huang 	int i, j;
1156b458cd62SJohnny Huang 	int fail = 0;
1157a219f6deSJohnny Huang 	u32 bit_offset;
1158a219f6deSJohnny Huang 	u32 length;
1159a219f6deSJohnny Huang 	u32 otp_value;
1160a219f6deSJohnny Huang 	u32 otp_protect;
116176d13988SJohnny Huang 
1162541eb887SJohnny Huang 	otp_strap_status(strap_status);
116376d13988SJohnny Huang 
1164b458cd62SJohnny Huang 	if (view) {
116507baa4e8SJohnny Huang 		printf("BIT(hex) Value  Remains  Protect   Description\n");
116607baa4e8SJohnny Huang 		printf("___________________________________________________________________________________________________\n");
1167b458cd62SJohnny Huang 	} else {
1168b458cd62SJohnny Huang 		printf("BIT(hex)   Value       Description\n");
1169b458cd62SJohnny Huang 		printf("________________________________________________________________________________\n");
117076d13988SJohnny Huang 	}
11713cb28812SJohnny Huang 	for (i = 0; i < info_cb.strap_info_len; i++) {
1172b458cd62SJohnny Huang 		otp_value = 0;
11733cb28812SJohnny Huang 		bit_offset = strap_info[i].bit_offset;
11743cb28812SJohnny Huang 		length = strap_info[i].length;
1175b458cd62SJohnny Huang 		for (j = 0; j < length; j++) {
1176c947ef08SJohnny Huang 			otp_value |= strap_status[bit_offset + j].value << j;
1177c947ef08SJohnny Huang 			otp_protect |= strap_status[bit_offset + j].protected << j;
1178b458cd62SJohnny Huang 		}
1179a219f6deSJohnny Huang 		if (otp_value != strap_info[i].value &&
11803cb28812SJohnny Huang 		    strap_info[i].value != OTP_REG_RESERVED)
1181b458cd62SJohnny Huang 			continue;
1182b458cd62SJohnny Huang 		if (view) {
1183b458cd62SJohnny Huang 			for (j = 0; j < length; j++) {
11843cb28812SJohnny Huang 				printf("0x%-7X", strap_info[i].bit_offset + j);
1185b458cd62SJohnny Huang 				printf("0x%-5X", strap_status[bit_offset + j].value);
118607baa4e8SJohnny Huang 				printf("%-9d", strap_status[bit_offset + j].remain_times);
1187e1a7245eSJohnny Huang 				printf("0x%-7X", strap_status[bit_offset + j].protected);
11883cb28812SJohnny Huang 				if (strap_info[i].value == OTP_REG_RESERVED) {
1189b458cd62SJohnny Huang 					printf(" Reserved\n");
1190b458cd62SJohnny Huang 					continue;
1191b458cd62SJohnny Huang 				}
1192b458cd62SJohnny Huang 				if (length == 1) {
11933cb28812SJohnny Huang 					printf(" %s\n", strap_info[i].information);
1194b458cd62SJohnny Huang 					continue;
119576d13988SJohnny Huang 				}
119676d13988SJohnny Huang 
1197b458cd62SJohnny Huang 				if (j == 0)
11983cb28812SJohnny Huang 					printf("/%s\n", strap_info[i].information);
1199b458cd62SJohnny Huang 				else if (j == length - 1)
1200b458cd62SJohnny Huang 					printf("\\ \"\n");
1201b458cd62SJohnny Huang 				else
1202b458cd62SJohnny Huang 					printf("| \"\n");
120376d13988SJohnny Huang 			}
1204b458cd62SJohnny Huang 		} else {
1205c947ef08SJohnny Huang 			if (length == 1) {
12063cb28812SJohnny Huang 				printf("0x%-9X", strap_info[i].bit_offset);
1207b458cd62SJohnny Huang 			} else {
1208b458cd62SJohnny Huang 				printf("0x%-2X:0x%-4X",
1209b458cd62SJohnny Huang 				       bit_offset + length - 1, bit_offset);
1210b458cd62SJohnny Huang 			}
1211b458cd62SJohnny Huang 
1212b458cd62SJohnny Huang 			printf("0x%-10X", otp_value);
1213b458cd62SJohnny Huang 
12143cb28812SJohnny Huang 			if (strap_info[i].value != OTP_REG_RESERVED)
12153cb28812SJohnny Huang 				printf("%s\n", strap_info[i].information);
1216b458cd62SJohnny Huang 			else
1217b458cd62SJohnny Huang 				printf("Reserved\n");
1218b458cd62SJohnny Huang 		}
1219b458cd62SJohnny Huang 	}
1220b458cd62SJohnny Huang 
1221b458cd62SJohnny Huang 	if (fail)
1222b458cd62SJohnny Huang 		return OTP_FAILURE;
1223b458cd62SJohnny Huang 
1224b458cd62SJohnny Huang 	return OTP_SUCCESS;
1225b458cd62SJohnny Huang }
1226b458cd62SJohnny Huang 
1227f347c284SJohnny Huang static int otp_print_data_image(struct otp_image_layout *image_layout)
122869d5fd8fSJohnny Huang {
122969d5fd8fSJohnny Huang 	int key_id, key_offset, last, key_type, key_length, exp_length;
123079e42a59SJoel Stanley 	const struct otpkey_type *key_info_array = info_cb.key_info;
12319a4fe690SJohnny Huang 	struct otpkey_type key_info;
1232a219f6deSJohnny Huang 	u32 *buf;
1233a219f6deSJohnny Huang 	u8 *byte_buf;
12349d998018SJohnny Huang 	char empty = 1;
123569d5fd8fSJohnny Huang 	int i = 0, len = 0;
12369a4fe690SJohnny Huang 	int j;
123754552c69SJohnny Huang 
1238696656c6SJohnny Huang 	byte_buf = image_layout->data;
1239a219f6deSJohnny Huang 	buf = (u32 *)byte_buf;
12409d998018SJohnny Huang 
12419d998018SJohnny Huang 	for (i = 0; i < 16; i++) {
1242a219f6deSJohnny Huang 		if (buf[i] != 0)
12439d998018SJohnny Huang 			empty = 0;
12449d998018SJohnny Huang 	}
12459d998018SJohnny Huang 	if (empty)
1246f347c284SJohnny Huang 		return OTP_SUCCESS;
12479d998018SJohnny Huang 
12489d998018SJohnny Huang 	i = 0;
124969d5fd8fSJohnny Huang 	while (1) {
125069d5fd8fSJohnny Huang 		key_id = buf[i] & 0x7;
125169d5fd8fSJohnny Huang 		key_offset = buf[i] & 0x1ff8;
125269d5fd8fSJohnny Huang 		last = (buf[i] >> 13) & 1;
125369d5fd8fSJohnny Huang 		key_type = (buf[i] >> 14) & 0xf;
125469d5fd8fSJohnny Huang 		key_length = (buf[i] >> 18) & 0x3;
125569d5fd8fSJohnny Huang 		exp_length = (buf[i] >> 20) & 0xfff;
12569a4fe690SJohnny Huang 
12579a4fe690SJohnny Huang 		for (j = 0; j < info_cb.key_info_len; j++) {
12589a4fe690SJohnny Huang 			if (key_type == key_info_array[j].value) {
12599a4fe690SJohnny Huang 				key_info = key_info_array[j];
12609a4fe690SJohnny Huang 				break;
12619a4fe690SJohnny Huang 			}
12629a4fe690SJohnny Huang 		}
12639a4fe690SJohnny Huang 
12647f795e57SJohnny Huang 		printf("\nKey[%d]:\n", i);
126569d5fd8fSJohnny Huang 		printf("Key Type: ");
12669a4fe690SJohnny Huang 		printf("%s\n", key_info.information);
12679a4fe690SJohnny Huang 
12689a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
126969d5fd8fSJohnny Huang 			printf("HMAC SHA Type: ");
127069d5fd8fSJohnny Huang 			switch (key_length) {
127169d5fd8fSJohnny Huang 			case 0:
127269d5fd8fSJohnny Huang 				printf("HMAC(SHA224)\n");
127369d5fd8fSJohnny Huang 				break;
127469d5fd8fSJohnny Huang 			case 1:
127569d5fd8fSJohnny Huang 				printf("HMAC(SHA256)\n");
127669d5fd8fSJohnny Huang 				break;
127769d5fd8fSJohnny Huang 			case 2:
127869d5fd8fSJohnny Huang 				printf("HMAC(SHA384)\n");
127969d5fd8fSJohnny Huang 				break;
128069d5fd8fSJohnny Huang 			case 3:
128169d5fd8fSJohnny Huang 				printf("HMAC(SHA512)\n");
128269d5fd8fSJohnny Huang 				break;
128369d5fd8fSJohnny Huang 			}
1284181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV ||
1285181f72d8SJohnny Huang 			   key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
128669d5fd8fSJohnny Huang 			printf("RSA SHA Type: ");
128769d5fd8fSJohnny Huang 			switch (key_length) {
128869d5fd8fSJohnny Huang 			case 0:
128969d5fd8fSJohnny Huang 				printf("RSA1024\n");
129069d5fd8fSJohnny Huang 				len = 0x100;
129169d5fd8fSJohnny Huang 				break;
129269d5fd8fSJohnny Huang 			case 1:
129369d5fd8fSJohnny Huang 				printf("RSA2048\n");
129469d5fd8fSJohnny Huang 				len = 0x200;
129569d5fd8fSJohnny Huang 				break;
129669d5fd8fSJohnny Huang 			case 2:
129769d5fd8fSJohnny Huang 				printf("RSA3072\n");
129869d5fd8fSJohnny Huang 				len = 0x300;
129969d5fd8fSJohnny Huang 				break;
130069d5fd8fSJohnny Huang 			case 3:
130169d5fd8fSJohnny Huang 				printf("RSA4096\n");
130269d5fd8fSJohnny Huang 				len = 0x400;
130369d5fd8fSJohnny Huang 				break;
130469d5fd8fSJohnny Huang 			}
130569d5fd8fSJohnny Huang 			printf("RSA exponent bit length: %d\n", exp_length);
130669d5fd8fSJohnny Huang 		}
13079a4fe690SJohnny Huang 		if (key_info.need_id)
130869d5fd8fSJohnny Huang 			printf("Key Number ID: %d\n", key_id);
130969d5fd8fSJohnny Huang 		printf("Key Value:\n");
13109a4fe690SJohnny Huang 		if (key_info.key_type == OTP_KEY_TYPE_HMAC) {
131169d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], 0x40);
13129a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_AES) {
13139a4fe690SJohnny Huang 			printf("AES Key:\n");
13149a4fe690SJohnny Huang 			buf_print(&byte_buf[key_offset], 0x20);
1315e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
13169a4fe690SJohnny Huang 				printf("AES IV:\n");
13179a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
13189a4fe690SJohnny Huang 			}
13199a4fe690SJohnny Huang 
13209a4fe690SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_VAULT) {
1321e417205bSJohnny Huang 			if (info_cb.version == OTP_A0) {
132269d5fd8fSJohnny Huang 				printf("AES Key:\n");
132369d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
132469d5fd8fSJohnny Huang 				printf("AES IV:\n");
132569d5fd8fSJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x10);
13265fdde29fSJohnny Huang 			} else {
13279a4fe690SJohnny Huang 				printf("AES Key 1:\n");
13289a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset], 0x20);
13299a4fe690SJohnny Huang 				printf("AES Key 2:\n");
13309a4fe690SJohnny Huang 				buf_print(&byte_buf[key_offset + 0x20], 0x20);
13319a4fe690SJohnny Huang 			}
1332181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PRIV) {
133369d5fd8fSJohnny Huang 			printf("RSA mod:\n");
133469d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
133569d5fd8fSJohnny Huang 			printf("RSA exp:\n");
133669d5fd8fSJohnny Huang 			buf_print(&byte_buf[key_offset + (len / 2)], len / 2);
1337181f72d8SJohnny Huang 		} else if (key_info.key_type == OTP_KEY_TYPE_RSA_PUB) {
1338181f72d8SJohnny Huang 			printf("RSA mod:\n");
1339181f72d8SJohnny Huang 			buf_print(&byte_buf[key_offset], len / 2);
1340181f72d8SJohnny Huang 			printf("RSA exp:\n");
1341a219f6deSJohnny Huang 			buf_print((u8 *)"\x01\x00\x01", 3);
134269d5fd8fSJohnny Huang 		}
134369d5fd8fSJohnny Huang 		if (last)
134469d5fd8fSJohnny Huang 			break;
134569d5fd8fSJohnny Huang 		i++;
134669d5fd8fSJohnny Huang 	}
1347f347c284SJohnny Huang 	return OTP_SUCCESS;
1348f347c284SJohnny Huang }
1349f347c284SJohnny Huang 
1350f347c284SJohnny Huang static int otp_strap_image_confirm(struct otp_image_layout *image_layout)
1351f347c284SJohnny Huang {
1352f347c284SJohnny Huang 	int i;
1353f347c284SJohnny Huang 	u32 *strap;
1354f347c284SJohnny Huang 	u32 *strap_ignore;
1355f347c284SJohnny Huang 	u32 *strap_pro;
13567e523e3bSJohnny Huang 	int bit, pbit, ibit;
1357f347c284SJohnny Huang 	int fail = 0;
1358f347c284SJohnny Huang 	int ret;
1359f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
1360f347c284SJohnny Huang 
1361f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1362f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1363f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1364f347c284SJohnny Huang 
1365f347c284SJohnny Huang 	otp_strap_status(otpstrap);
1366f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1367f347c284SJohnny Huang 		if (i < 32) {
1368f347c284SJohnny Huang 			bit = (strap[0] >> i) & 0x1;
1369f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> i) & 0x1;
1370f347c284SJohnny Huang 			pbit = (strap_pro[0] >> i) & 0x1;
1371f347c284SJohnny Huang 		} else {
1372f347c284SJohnny Huang 			bit = (strap[1] >> (i - 32)) & 0x1;
1373f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> (i - 32)) & 0x1;
1374f347c284SJohnny Huang 			pbit = (strap_pro[1] >> (i - 32)) & 0x1;
1375f347c284SJohnny Huang 		}
1376f347c284SJohnny Huang 
13777e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[i], i, ibit, bit, pbit);
1378f347c284SJohnny Huang 
1379f347c284SJohnny Huang 		if (ret == OTP_FAILURE)
1380f347c284SJohnny Huang 			fail = 1;
1381f347c284SJohnny Huang 	}
1382f347c284SJohnny Huang 	if (fail == 1)
1383f347c284SJohnny Huang 		return OTP_FAILURE;
1384f347c284SJohnny Huang 	else
1385f347c284SJohnny Huang 		return OTP_SUCCESS;
1386f347c284SJohnny Huang }
1387f347c284SJohnny Huang 
1388f347c284SJohnny Huang static int otp_prog_data(struct otp_image_layout *image_layout)
1389f347c284SJohnny Huang {
1390f347c284SJohnny Huang 	int i;
1391f347c284SJohnny Huang 	int ret;
1392f347c284SJohnny Huang 	int data_dw;
1393f347c284SJohnny Huang 	u32 data[2048];
1394f347c284SJohnny Huang 	u32 *buf;
1395f347c284SJohnny Huang 	u32 *buf_ignore;
1396f347c284SJohnny Huang 	u32 data_masked;
1397f347c284SJohnny Huang 	u32 buf_masked;
1398f347c284SJohnny Huang 
1399f347c284SJohnny Huang 	buf = (u32 *)image_layout->data;
1400f347c284SJohnny Huang 	buf_ignore = (u32 *)image_layout->data_ignore;
1401f347c284SJohnny Huang 
1402f347c284SJohnny Huang 	data_dw = image_layout->data_length / 4;
1403f347c284SJohnny Huang 
1404f347c284SJohnny Huang 	printf("Read OTP Data:\n");
1405f347c284SJohnny Huang 
1406f347c284SJohnny Huang 	for (i = 0; i < data_dw - 2 ; i += 2)
1407f347c284SJohnny Huang 		otp_read_data(i, &data[i]);
1408f347c284SJohnny Huang 
1409f347c284SJohnny Huang 	printf("Check writable...\n");
1410f347c284SJohnny Huang 	// ignore last two dw, the last two dw is used for slt otp write check.
1411f347c284SJohnny Huang 	for (i = 0; i < data_dw - 2; i++) {
1412f347c284SJohnny Huang 		data_masked = data[i]  & ~buf_ignore[i];
1413f347c284SJohnny Huang 		buf_masked  = buf[i] & ~buf_ignore[i];
1414f347c284SJohnny Huang 		if (data_masked == buf_masked)
1415f347c284SJohnny Huang 			continue;
1416f347c284SJohnny Huang 		if (i % 2 == 0) {
1417f347c284SJohnny Huang 			if ((data_masked | buf_masked) == buf_masked) {
1418f347c284SJohnny Huang 				continue;
1419f347c284SJohnny Huang 			} else {
1420f347c284SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1421f347c284SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1422f347c284SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1423f347c284SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
1424f347c284SJohnny Huang 				return OTP_FAILURE;
1425f347c284SJohnny Huang 			}
1426f347c284SJohnny Huang 		} else {
1427f347c284SJohnny Huang 			if ((data_masked & buf_masked) == buf_masked) {
1428f347c284SJohnny Huang 				continue;
1429f347c284SJohnny Huang 			} else {
1430f347c284SJohnny Huang 				printf("Input image can't program into OTP, please check.\n");
1431f347c284SJohnny Huang 				printf("OTP_ADDR[%x] = %x\n", i, data[i]);
1432f347c284SJohnny Huang 				printf("Input   [%x] = %x\n", i, buf[i]);
1433f347c284SJohnny Huang 				printf("Mask    [%x] = %x\n", i, ~buf_ignore[i]);
1434f347c284SJohnny Huang 				return OTP_FAILURE;
1435f347c284SJohnny Huang 			}
1436f347c284SJohnny Huang 		}
1437f347c284SJohnny Huang 	}
1438f347c284SJohnny Huang 
1439f347c284SJohnny Huang 	printf("Start Programing...\n");
1440f347c284SJohnny Huang 
1441f347c284SJohnny Huang 	// programing ecc region first
1442f347c284SJohnny Huang 	for (i = 1792; i < 2046; i += 2) {
1443f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1444f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1445f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1446f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1447f347c284SJohnny Huang 			return ret;
1448f347c284SJohnny Huang 		}
1449f347c284SJohnny Huang 	}
1450f347c284SJohnny Huang 
1451f347c284SJohnny Huang 	for (i = 0; i < 1792; i += 2) {
1452f347c284SJohnny Huang 		ret = otp_prog_verify_2dw(&data[i], &buf[i], &buf_ignore[i], i);
1453f347c284SJohnny Huang 		if (ret != OTP_SUCCESS) {
1454f347c284SJohnny Huang 			printf("address: %08x, data: %08x %08x, buffer: %08x %08x, mask: %08x %08x\n",
1455f347c284SJohnny Huang 			       i, data[i], data[i + 1], buf[i], buf[i + 1], buf_ignore[i], buf_ignore[i + 1]);
1456f347c284SJohnny Huang 			return ret;
1457f347c284SJohnny Huang 		}
1458f347c284SJohnny Huang 	}
1459f347c284SJohnny Huang 	otp_soak(0);
1460f347c284SJohnny Huang 	return OTP_SUCCESS;
1461f347c284SJohnny Huang }
1462f347c284SJohnny Huang 
1463f347c284SJohnny Huang static int otp_prog_strap(struct otp_image_layout *image_layout)
1464f347c284SJohnny Huang {
1465f347c284SJohnny Huang 	u32 *strap;
1466f347c284SJohnny Huang 	u32 *strap_ignore;
1467f347c284SJohnny Huang 	u32 *strap_pro;
1468f347c284SJohnny Huang 	u32 prog_address;
1469f347c284SJohnny Huang 	int i;
14707e523e3bSJohnny Huang 	int bit, pbit, ibit, offset;
1471f347c284SJohnny Huang 	int fail = 0;
1472f347c284SJohnny Huang 	int ret;
1473f347c284SJohnny Huang 	int prog_flag = 0;
1474f347c284SJohnny Huang 	struct otpstrap_status otpstrap[64];
1475f347c284SJohnny Huang 
1476f347c284SJohnny Huang 	strap = (u32 *)image_layout->strap;
1477f347c284SJohnny Huang 	strap_pro = (u32 *)image_layout->strap_pro;
1478f347c284SJohnny Huang 	strap_ignore = (u32 *)image_layout->strap_ignore;
1479f347c284SJohnny Huang 
1480f347c284SJohnny Huang 	printf("Read OTP Strap Region:\n");
1481f347c284SJohnny Huang 	otp_strap_status(otpstrap);
1482f347c284SJohnny Huang 
1483f347c284SJohnny Huang 	printf("Check writable...\n");
1484f347c284SJohnny Huang 	if (otp_strap_image_confirm(image_layout) == OTP_FAILURE) {
1485f347c284SJohnny Huang 		printf("Input image can't program into OTP, please check.\n");
1486f347c284SJohnny Huang 		return OTP_FAILURE;
1487f347c284SJohnny Huang 	}
1488f347c284SJohnny Huang 
1489f347c284SJohnny Huang 	for (i = 0; i < 64; i++) {
1490f347c284SJohnny Huang 		prog_address = 0x800;
1491f347c284SJohnny Huang 		if (i < 32) {
1492f347c284SJohnny Huang 			offset = i;
1493f347c284SJohnny Huang 			bit = (strap[0] >> offset) & 0x1;
1494f347c284SJohnny Huang 			ibit = (strap_ignore[0] >> offset) & 0x1;
1495f347c284SJohnny Huang 			pbit = (strap_pro[0] >> offset) & 0x1;
1496f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) / 8) * 0x200;
1497f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 16) % 8) * 0x2;
1498f347c284SJohnny Huang 
1499f347c284SJohnny Huang 		} else {
1500f347c284SJohnny Huang 			offset = (i - 32);
1501f347c284SJohnny Huang 			bit = (strap[1] >> offset) & 0x1;
1502f347c284SJohnny Huang 			ibit = (strap_ignore[1] >> offset) & 0x1;
1503f347c284SJohnny Huang 			pbit = (strap_pro[1] >> offset) & 0x1;
1504f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) / 8) * 0x200;
1505f347c284SJohnny Huang 			prog_address |= ((otpstrap[i].writeable_option * 2 + 17) % 8) * 0x2;
1506f347c284SJohnny Huang 		}
1507f347c284SJohnny Huang 
1508f347c284SJohnny Huang 		if (ibit == 1)
1509f347c284SJohnny Huang 			continue;
1510f347c284SJohnny Huang 		if (bit == otpstrap[i].value)
1511f347c284SJohnny Huang 			prog_flag = 0;
1512f347c284SJohnny Huang 		else
1513f347c284SJohnny Huang 			prog_flag = 1;
1514f347c284SJohnny Huang 
1515f347c284SJohnny Huang 		if (otpstrap[i].protected == 1 && prog_flag) {
1516f347c284SJohnny Huang 			fail = 1;
1517f347c284SJohnny Huang 			continue;
1518f347c284SJohnny Huang 		}
1519f347c284SJohnny Huang 		if (otpstrap[i].remain_times == 0 && prog_flag) {
1520f347c284SJohnny Huang 			fail = 1;
1521f347c284SJohnny Huang 			continue;
1522f347c284SJohnny Huang 		}
1523f347c284SJohnny Huang 
1524f347c284SJohnny Huang 		if (prog_flag) {
1525f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1526f347c284SJohnny Huang 			if (ret)
1527f347c284SJohnny Huang 				return OTP_FAILURE;
1528f347c284SJohnny Huang 		}
1529f347c284SJohnny Huang 
1530f347c284SJohnny Huang 		if (pbit != 0) {
1531f347c284SJohnny Huang 			prog_address = 0x800;
1532f347c284SJohnny Huang 			if (i < 32)
1533f347c284SJohnny Huang 				prog_address |= 0x60c;
1534f347c284SJohnny Huang 			else
1535f347c284SJohnny Huang 				prog_address |= 0x60e;
1536f347c284SJohnny Huang 
1537f347c284SJohnny Huang 			ret = otp_prog_dc_b(1, prog_address, offset);
1538f347c284SJohnny Huang 			if (ret)
1539f347c284SJohnny Huang 				return OTP_FAILURE;
1540f347c284SJohnny Huang 		}
1541f347c284SJohnny Huang 	}
1542f347c284SJohnny Huang 	otp_soak(0);
1543f347c284SJohnny Huang 	if (fail == 1)
1544f347c284SJohnny Huang 		return OTP_FAILURE;
1545f347c284SJohnny Huang 	return OTP_SUCCESS;
154669d5fd8fSJohnny Huang }
154769d5fd8fSJohnny Huang 
15485010032bSJohnny Huang static int otp_prog_conf(struct otp_image_layout *image_layout)
154969d5fd8fSJohnny Huang {
1550a6d0d645SJohnny Huang 	int i, k;
1551d90825e2SJohnny Huang 	int pass = 0;
1552a219f6deSJohnny Huang 	u32 prog_address;
1553a219f6deSJohnny Huang 	u32 data[16];
1554a219f6deSJohnny Huang 	u32 compare[2];
1555a219f6deSJohnny Huang 	u32 *conf = (u32 *)image_layout->conf;
1556a219f6deSJohnny Huang 	u32 *conf_ignore = (u32 *)image_layout->conf_ignore;
1557a219f6deSJohnny Huang 	u32 data_masked;
1558a219f6deSJohnny Huang 	u32 buf_masked;
155969d5fd8fSJohnny Huang 
1560a6d0d645SJohnny Huang 	printf("Read OTP Config Region:\n");
1561a6d0d645SJohnny Huang 
1562bb34a7bfSJohnny Huang 	for (i = 0; i < 16 ; i++) {
156369d5fd8fSJohnny Huang 		prog_address = 0x800;
1564a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1565a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1566a6d0d645SJohnny Huang 		otp_read_data(prog_address, &data[i]);
1567a6d0d645SJohnny Huang 	}
1568a6d0d645SJohnny Huang 
1569a6d0d645SJohnny Huang 	printf("Check writable...\n");
1570bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
15715010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
15725010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1573d90825e2SJohnny Huang 		if (data_masked == buf_masked)
157469d5fd8fSJohnny Huang 			continue;
1575d90825e2SJohnny Huang 		if ((data_masked | buf_masked) == buf_masked) {
1576a6d0d645SJohnny Huang 			continue;
1577a6d0d645SJohnny Huang 		} else {
1578a6d0d645SJohnny Huang 			printf("Input image can't program into OTP, please check.\n");
1579a6af4a17SJohnny Huang 			printf("OTPCFG[%X] = %x\n", i, data[i]);
15805010032bSJohnny Huang 			printf("Input [%X] = %x\n", i, conf[i]);
15815010032bSJohnny Huang 			printf("Mask  [%X] = %x\n", i, ~conf_ignore[i]);
15822a856b9aSJohnny Huang 			return OTP_FAILURE;
1583a6d0d645SJohnny Huang 		}
1584a6d0d645SJohnny Huang 	}
1585a6d0d645SJohnny Huang 
1586a6d0d645SJohnny Huang 	printf("Start Programing...\n");
1587d90825e2SJohnny Huang 	otp_soak(0);
1588bb34a7bfSJohnny Huang 	for (i = 0; i < 16; i++) {
15895010032bSJohnny Huang 		data_masked = data[i]  & ~conf_ignore[i];
15905010032bSJohnny Huang 		buf_masked  = conf[i] & ~conf_ignore[i];
1591a6d0d645SJohnny Huang 		prog_address = 0x800;
1592a6d0d645SJohnny Huang 		prog_address |= (i / 8) * 0x200;
1593a6d0d645SJohnny Huang 		prog_address |= (i % 8) * 0x2;
1594bb34a7bfSJohnny Huang 		if (data_masked == buf_masked) {
1595bb34a7bfSJohnny Huang 			pass = 1;
1596a6d0d645SJohnny Huang 			continue;
1597bb34a7bfSJohnny Huang 		}
1598de6fbf1cSJohnny Huang 
1599de6fbf1cSJohnny Huang 		otp_soak(1);
16005010032bSJohnny Huang 		otp_prog_dw(conf[i], conf_ignore[i], prog_address);
1601a6d0d645SJohnny Huang 
160269d5fd8fSJohnny Huang 		pass = 0;
160369d5fd8fSJohnny Huang 		for (k = 0; k < RETRY; k++) {
16045010032bSJohnny Huang 			if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1605de6fbf1cSJohnny Huang 				otp_soak(2);
1606feea3fdfSJohnny Huang 				otp_prog_dw(compare[0], conf_ignore[i], prog_address);
16075010032bSJohnny Huang 				if (verify_dw(prog_address, &conf[i], &conf_ignore[i], compare, 1) != 0) {
1608de6fbf1cSJohnny Huang 					otp_soak(1);
1609de6fbf1cSJohnny Huang 				} else {
1610de6fbf1cSJohnny Huang 					pass = 1;
1611de6fbf1cSJohnny Huang 					break;
1612de6fbf1cSJohnny Huang 				}
1613a6d0d645SJohnny Huang 			} else {
161469d5fd8fSJohnny Huang 				pass = 1;
161569d5fd8fSJohnny Huang 				break;
161669d5fd8fSJohnny Huang 			}
161769d5fd8fSJohnny Huang 		}
1618bb34a7bfSJohnny Huang 		if (pass == 0) {
1619bb34a7bfSJohnny Huang 			printf("address: %08x, data: %08x, buffer: %08x, mask: %08x\n",
16205010032bSJohnny Huang 			       i, data[i], conf[i], conf_ignore[i]);
1621bb34a7bfSJohnny Huang 			break;
1622bb34a7bfSJohnny Huang 		}
1623a6d0d645SJohnny Huang 	}
1624a6d0d645SJohnny Huang 
1625de6fbf1cSJohnny Huang 	otp_soak(0);
162669d5fd8fSJohnny Huang 	if (!pass)
16272a856b9aSJohnny Huang 		return OTP_FAILURE;
1628a6d0d645SJohnny Huang 
16292a856b9aSJohnny Huang 	return OTP_SUCCESS;
163069d5fd8fSJohnny Huang }
163169d5fd8fSJohnny Huang 
1632f347c284SJohnny Huang static int otp_verify_image(u8 *src_buf, u32 length, u8 *digest_buf)
1633696656c6SJohnny Huang {
1634696656c6SJohnny Huang 	sha256_context ctx;
1635696656c6SJohnny Huang 	u8 digest_ret[CHECKSUM_LEN];
1636696656c6SJohnny Huang 
1637696656c6SJohnny Huang 	sha256_starts(&ctx);
1638696656c6SJohnny Huang 	sha256_update(&ctx, src_buf, length);
1639696656c6SJohnny Huang 	sha256_finish(&ctx, digest_ret);
1640696656c6SJohnny Huang 
1641696656c6SJohnny Huang 	if (!memcmp(digest_buf, digest_ret, CHECKSUM_LEN))
1642f347c284SJohnny Huang 		return OTP_SUCCESS;
1643f347c284SJohnny Huang 	return OTP_FAILURE;
1644696656c6SJohnny Huang }
1645696656c6SJohnny Huang 
1646f347c284SJohnny Huang static int otp_prog_image(int addr, int nconfirm)
164769d5fd8fSJohnny Huang {
164869d5fd8fSJohnny Huang 	int ret;
164961a6cda7SJohnny Huang 	int image_soc_ver = 0;
1650696656c6SJohnny Huang 	struct otp_header *otp_header;
1651696656c6SJohnny Huang 	struct otp_image_layout image_layout;
1652696656c6SJohnny Huang 	int image_size;
1653a219f6deSJohnny Huang 	u8 *buf;
1654a219f6deSJohnny Huang 	u8 *checksum;
165569d5fd8fSJohnny Huang 
1656696656c6SJohnny Huang 	otp_header = map_physmem(addr, sizeof(struct otp_header), MAP_WRBACK);
1657696656c6SJohnny Huang 	if (!otp_header) {
165869d5fd8fSJohnny Huang 		puts("Failed to map physical memory\n");
16592a856b9aSJohnny Huang 		return OTP_FAILURE;
166069d5fd8fSJohnny Huang 	}
1661d90825e2SJohnny Huang 
1662696656c6SJohnny Huang 	image_size = OTP_IMAGE_SIZE(otp_header->image_info);
1663696656c6SJohnny Huang 	unmap_physmem(otp_header, MAP_WRBACK);
1664696656c6SJohnny Huang 
1665696656c6SJohnny Huang 	buf = map_physmem(addr, image_size + CHECKSUM_LEN, MAP_WRBACK);
1666696656c6SJohnny Huang 
1667696656c6SJohnny Huang 	if (!buf) {
1668696656c6SJohnny Huang 		puts("Failed to map physical memory\n");
1669696656c6SJohnny Huang 		return OTP_FAILURE;
1670696656c6SJohnny Huang 	}
1671696656c6SJohnny Huang 	otp_header = (struct otp_header *)buf;
1672696656c6SJohnny Huang 	checksum = buf + otp_header->checksum_offset;
1673696656c6SJohnny Huang 
1674696656c6SJohnny Huang 	if (strcmp(OTP_MAGIC, (char *)otp_header->otp_magic) != 0) {
1675696656c6SJohnny Huang 		puts("Image is invalid\n");
1676696656c6SJohnny Huang 		return OTP_FAILURE;
1677696656c6SJohnny Huang 	}
1678696656c6SJohnny Huang 
16795010032bSJohnny Huang 	image_layout.data_length = (int)(OTP_REGION_SIZE(otp_header->data_info) / 2);
16805010032bSJohnny Huang 	image_layout.data = buf + OTP_REGION_OFFSET(otp_header->data_info);
16815010032bSJohnny Huang 	image_layout.data_ignore = image_layout.data + image_layout.data_length;
16825010032bSJohnny Huang 
16835010032bSJohnny Huang 	image_layout.conf_length = (int)(OTP_REGION_SIZE(otp_header->config_info) / 2);
1684696656c6SJohnny Huang 	image_layout.conf = buf + OTP_REGION_OFFSET(otp_header->config_info);
16855010032bSJohnny Huang 	image_layout.conf_ignore = image_layout.conf + image_layout.conf_length;
1686696656c6SJohnny Huang 
1687696656c6SJohnny Huang 	image_layout.strap = buf + OTP_REGION_OFFSET(otp_header->strap_info);
16885010032bSJohnny Huang 	image_layout.strap_length = (int)(OTP_REGION_SIZE(otp_header->strap_info) / 3);
16895010032bSJohnny Huang 	image_layout.strap_pro = image_layout.strap + image_layout.strap_length;
16905010032bSJohnny Huang 	image_layout.strap_ignore = image_layout.strap + 2 * image_layout.strap_length;
16917e523e3bSJohnny Huang 
16927e523e3bSJohnny Huang 	if (otp_header->soc_ver == SOC_AST2600A0) {
16937e523e3bSJohnny Huang 		image_soc_ver = OTP_A0;
169461a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A1) {
169561a6cda7SJohnny Huang 		image_soc_ver = OTP_A1;
169661a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A2) {
169761a6cda7SJohnny Huang 		image_soc_ver = OTP_A2;
169861a6cda7SJohnny Huang 	} else if (otp_header->soc_ver == SOC_AST2600A3) {
169961a6cda7SJohnny Huang 		image_soc_ver = OTP_A3;
1700696656c6SJohnny Huang 	} else {
170161a6cda7SJohnny Huang 		puts("Image SOC Version is not supported\n");
1702696656c6SJohnny Huang 		return OTP_FAILURE;
1703696656c6SJohnny Huang 	}
1704696656c6SJohnny Huang 
170561a6cda7SJohnny Huang 	if (image_soc_ver != info_cb.version) {
17069a4fe690SJohnny Huang 		puts("Version is not match\n");
17079a4fe690SJohnny Huang 		return OTP_FAILURE;
17089a4fe690SJohnny Huang 	}
17099a4fe690SJohnny Huang 
171061a6cda7SJohnny Huang 	if (otp_header->otptool_ver != OTPTOOL_VERSION(1, 0, 0)) {
171161a6cda7SJohnny Huang 		puts("OTP image is not generated by otptool v1.0.0\n");
171261a6cda7SJohnny Huang 		return OTP_FAILURE;
171361a6cda7SJohnny Huang 	}
171461a6cda7SJohnny Huang 
1715f347c284SJohnny Huang 	if (otp_verify_image(buf, image_size, checksum)) {
1716696656c6SJohnny Huang 		puts("checksum is invalid\n");
1717696656c6SJohnny Huang 		return OTP_FAILURE;
1718d90825e2SJohnny Huang 	}
17197332532cSJohnny Huang 
172069d5fd8fSJohnny Huang 	if (!nconfirm) {
1721696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_DATA) {
17227f795e57SJohnny Huang 			printf("\nOTP data region :\n");
1723f347c284SJohnny Huang 			if (otp_print_data_image(&image_layout) < 0) {
172469d5fd8fSJohnny Huang 				printf("OTP data error, please check.\n");
17252a856b9aSJohnny Huang 				return OTP_FAILURE;
172669d5fd8fSJohnny Huang 			}
172769d5fd8fSJohnny Huang 		}
1728696656c6SJohnny Huang 		if (otp_header->image_info & OTP_INC_CONFIG) {
17297332532cSJohnny Huang 			printf("\nOTP configuration region :\n");
1730696656c6SJohnny Huang 			if (otp_print_conf_image(&image_layout) < 0) {
17317332532cSJohnny Huang 				printf("OTP config error, please check.\n");
17327332532cSJohnny Huang 				return OTP_FAILURE;
17337332532cSJohnny Huang 			}
17347332532cSJohnny Huang 		}
17357adec5f6SJohnny Huang 		if (otp_header->image_info & OTP_INC_STRAP) {
17367adec5f6SJohnny Huang 			printf("\nOTP strap region :\n");
17377adec5f6SJohnny Huang 			if (otp_print_strap_image(&image_layout) < 0) {
17387adec5f6SJohnny Huang 				printf("OTP strap error, please check.\n");
17397adec5f6SJohnny Huang 				return OTP_FAILURE;
17407adec5f6SJohnny Huang 			}
17417adec5f6SJohnny Huang 		}
17427332532cSJohnny Huang 
174369d5fd8fSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
174469d5fd8fSJohnny Huang 		if (!confirm_yesno()) {
174569d5fd8fSJohnny Huang 			printf(" Aborting\n");
17462a856b9aSJohnny Huang 			return OTP_FAILURE;
174769d5fd8fSJohnny Huang 		}
174869d5fd8fSJohnny Huang 	}
17497332532cSJohnny Huang 
17505010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_DATA) {
17515010032bSJohnny Huang 		printf("programing data region ...\n");
17525010032bSJohnny Huang 		ret = otp_prog_data(&image_layout);
17535010032bSJohnny Huang 		if (ret != 0) {
17545010032bSJohnny Huang 			printf("Error\n");
17555010032bSJohnny Huang 			return ret;
17565010032bSJohnny Huang 		}
1757a219f6deSJohnny Huang 		printf("Done\n");
17585010032bSJohnny Huang 	}
17595010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_STRAP) {
17605010032bSJohnny Huang 		printf("programing strap region ...\n");
17615010032bSJohnny Huang 		ret = otp_prog_strap(&image_layout);
17625010032bSJohnny Huang 		if (ret != 0) {
17635010032bSJohnny Huang 			printf("Error\n");
17645010032bSJohnny Huang 			return ret;
17655010032bSJohnny Huang 		}
1766a219f6deSJohnny Huang 		printf("Done\n");
17675010032bSJohnny Huang 	}
17685010032bSJohnny Huang 	if (otp_header->image_info & OTP_INC_CONFIG) {
17695010032bSJohnny Huang 		printf("programing configuration region ...\n");
17705010032bSJohnny Huang 		ret = otp_prog_conf(&image_layout);
17715010032bSJohnny Huang 		if (ret != 0) {
17725010032bSJohnny Huang 			printf("Error\n");
17735010032bSJohnny Huang 			return ret;
17745010032bSJohnny Huang 		}
17755010032bSJohnny Huang 		printf("Done\n");
17765010032bSJohnny Huang 	}
1777cd1610b4SJohnny Huang 
17787332532cSJohnny Huang 	return OTP_SUCCESS;
17792a856b9aSJohnny Huang }
17802a856b9aSJohnny Huang 
1781f347c284SJohnny Huang static int otp_prog_bit(int mode, int otp_dw_offset, int bit_offset, int value, int nconfirm)
1782cd1610b4SJohnny Huang {
1783a219f6deSJohnny Huang 	u32 read[2];
1784a219f6deSJohnny Huang 	u32 prog_address = 0;
178566f2f8e5SJohnny Huang 	struct otpstrap_status otpstrap[64];
1786cd1610b4SJohnny Huang 	int otp_bit;
178783655e91SJohnny Huang 	int ret = 0;
1788cd1610b4SJohnny Huang 
1789dacbba92SJohnny Huang 	otp_soak(0);
1790cd1610b4SJohnny Huang 	switch (mode) {
1791a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1792f347c284SJohnny Huang 		otp_read_conf(otp_dw_offset, read);
1793cd1610b4SJohnny Huang 		prog_address = 0x800;
1794cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset / 8) * 0x200;
1795cd1610b4SJohnny Huang 		prog_address |= (otp_dw_offset % 8) * 0x2;
1796a6af4a17SJohnny Huang 		otp_bit = (read[0] >> bit_offset) & 0x1;
1797cd1610b4SJohnny Huang 		if (otp_bit == value) {
1798a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1799cd1610b4SJohnny Huang 			printf("No need to program\n");
18002a856b9aSJohnny Huang 			return OTP_SUCCESS;
1801cd1610b4SJohnny Huang 		}
1802cd1610b4SJohnny Huang 		if (otp_bit == 1 && value == 0) {
1803a6af4a17SJohnny Huang 			printf("OTPCFG%X[%X] = 1\n", otp_dw_offset, bit_offset);
18040dc9a440SJohnny Huang 			printf("OTP is programmed, which can't be clean\n");
18052a856b9aSJohnny Huang 			return OTP_FAILURE;
1806cd1610b4SJohnny Huang 		}
1807a6af4a17SJohnny Huang 		printf("Program OTPCFG%X[%X] to 1\n", otp_dw_offset, bit_offset);
1808cd1610b4SJohnny Huang 		break;
1809a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1810cd1610b4SJohnny Huang 		prog_address = otp_dw_offset;
1811cd1610b4SJohnny Huang 
1812cd1610b4SJohnny Huang 		if (otp_dw_offset % 2 == 0) {
1813a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset, read);
1814a6af4a17SJohnny Huang 			otp_bit = (read[0] >> bit_offset) & 0x1;
1815643b9cfdSJohnny Huang 
1816643b9cfdSJohnny Huang 			if (otp_bit == 1 && value == 0) {
1817643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
18180dc9a440SJohnny Huang 				printf("OTP is programmed, which can't be cleaned\n");
1819643b9cfdSJohnny Huang 				return OTP_FAILURE;
1820643b9cfdSJohnny Huang 			}
1821cd1610b4SJohnny Huang 		} else {
1822a6af4a17SJohnny Huang 			otp_read_data(otp_dw_offset - 1, read);
1823a6af4a17SJohnny Huang 			otp_bit = (read[1] >> bit_offset) & 0x1;
1824643b9cfdSJohnny Huang 
1825643b9cfdSJohnny Huang 			if (otp_bit == 0 && value == 1) {
1826643b9cfdSJohnny Huang 				printf("OTPDATA%X[%X] = 1\n", otp_dw_offset, bit_offset);
18270dc9a440SJohnny Huang 				printf("OTP is programmed, which can't be writen\n");
1828643b9cfdSJohnny Huang 				return OTP_FAILURE;
1829643b9cfdSJohnny Huang 			}
1830cd1610b4SJohnny Huang 		}
1831cd1610b4SJohnny Huang 		if (otp_bit == value) {
1832a6af4a17SJohnny Huang 			printf("OTPDATA%X[%X] = %d\n", otp_dw_offset, bit_offset, value);
1833cd1610b4SJohnny Huang 			printf("No need to program\n");
18342a856b9aSJohnny Huang 			return OTP_SUCCESS;
1835cd1610b4SJohnny Huang 		}
1836643b9cfdSJohnny Huang 
1837a6af4a17SJohnny Huang 		printf("Program OTPDATA%X[%X] to 1\n", otp_dw_offset, bit_offset);
1838cd1610b4SJohnny Huang 		break;
1839a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
18408848d5dcSJohnny Huang 		otp_strap_status(otpstrap);
18418848d5dcSJohnny Huang 		otp_print_strap(bit_offset, 1);
18427e523e3bSJohnny Huang 		ret = otp_strap_bit_confirm(&otpstrap[bit_offset], bit_offset, 0, value, 0);
18438848d5dcSJohnny Huang 		if (ret == OTP_FAILURE)
18448848d5dcSJohnny Huang 			return OTP_FAILURE;
18458848d5dcSJohnny Huang 		else if (ret == OTP_PROG_SKIP)
18468848d5dcSJohnny Huang 			return OTP_SUCCESS;
1847a6af4a17SJohnny Huang 
1848cd1610b4SJohnny Huang 		break;
1849cd1610b4SJohnny Huang 	}
1850cd1610b4SJohnny Huang 
1851cd1610b4SJohnny Huang 	if (!nconfirm) {
1852cd1610b4SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1853cd1610b4SJohnny Huang 		if (!confirm_yesno()) {
1854cd1610b4SJohnny Huang 			printf(" Aborting\n");
18552a856b9aSJohnny Huang 			return OTP_FAILURE;
1856cd1610b4SJohnny Huang 		}
1857cd1610b4SJohnny Huang 	}
1858cd1610b4SJohnny Huang 
1859cd1610b4SJohnny Huang 	switch (mode) {
1860a6d0d645SJohnny Huang 	case OTP_REGION_STRAP:
1861f347c284SJohnny Huang 		ret =  otp_prog_strap_b(bit_offset, value);
186283655e91SJohnny Huang 		break;
1863a6d0d645SJohnny Huang 	case OTP_REGION_CONF:
1864a6d0d645SJohnny Huang 	case OTP_REGION_DATA:
1865f347c284SJohnny Huang 		ret = otp_prog_dc_b(value, prog_address, bit_offset);
1866de6fbf1cSJohnny Huang 		break;
1867de6fbf1cSJohnny Huang 	}
1868de6fbf1cSJohnny Huang 	otp_soak(0);
186983655e91SJohnny Huang 	if (ret) {
18700dc9a440SJohnny Huang 		printf("OTP cannot be programmed\n");
1871794e27ecSJohnny Huang 		printf("FAILURE\n");
1872794e27ecSJohnny Huang 		return OTP_FAILURE;
1873794e27ecSJohnny Huang 	}
1874794e27ecSJohnny Huang 
18759009c25dSJohnny Huang 	printf("SUCCESS\n");
18762a856b9aSJohnny Huang 	return OTP_SUCCESS;
1877a219f6deSJohnny Huang }
1878a219f6deSJohnny Huang 
1879794e27ecSJohnny Huang static int otp_update_rid(u32 update_num, int force)
1880794e27ecSJohnny Huang {
1881794e27ecSJohnny Huang 	u32 otp_rid[2];
1882a8789b47SJohnny Huang 	u32 sw_rid[2];
1883794e27ecSJohnny Huang 	int rid_num = 0;
1884a8789b47SJohnny Huang 	int sw_rid_num = 0;
1885794e27ecSJohnny Huang 	int bit_offset;
1886794e27ecSJohnny Huang 	int dw_offset;
1887794e27ecSJohnny Huang 	int i;
1888794e27ecSJohnny Huang 	int ret;
1889794e27ecSJohnny Huang 
1890f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
1891f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
1892794e27ecSJohnny Huang 
1893a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
1894a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
1895a8789b47SJohnny Huang 
1896794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1897a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
1898a8789b47SJohnny Huang 
1899a8789b47SJohnny Huang 	if (sw_rid_num < 0) {
1900a8789b47SJohnny Huang 		printf("SW revision id is invalid, please check.\n");
1901a8789b47SJohnny Huang 		return OTP_FAILURE;
1902a8789b47SJohnny Huang 	}
1903a8789b47SJohnny Huang 
1904a8789b47SJohnny Huang 	if (update_num > sw_rid_num) {
1905a8789b47SJohnny Huang 		printf("current SW revision ID: 0x%x\n", sw_rid_num);
1906a8789b47SJohnny Huang 		printf("update number could not bigger than current SW revision id\n");
1907a8789b47SJohnny Huang 		return OTP_FAILURE;
1908a8789b47SJohnny Huang 	}
1909794e27ecSJohnny Huang 
1910794e27ecSJohnny Huang 	if (rid_num < 0) {
1911794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by this command,\n"
1912794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n");
1913794e27ecSJohnny Huang 		otp_print_revid(otp_rid);
19149009c25dSJohnny Huang 		return OTP_FAILURE;
19159009c25dSJohnny Huang 	}
1916cd1610b4SJohnny Huang 
1917794e27ecSJohnny Huang 	printf("current OTP revision ID: 0x%x\n", rid_num);
1918794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1919794e27ecSJohnny Huang 	printf("input update number: 0x%x\n", update_num);
1920794e27ecSJohnny Huang 
1921a8789b47SJohnny Huang 	if (rid_num > update_num) {
1922a8789b47SJohnny Huang 		printf("OTP rev_id is bigger than 0x%X\n", update_num);
1923a8789b47SJohnny Huang 		printf("Skip\n");
1924a8789b47SJohnny Huang 		return OTP_FAILURE;
1925a8789b47SJohnny Huang 	} else if (rid_num == update_num) {
1926a8789b47SJohnny Huang 		printf("OTP rev_id is same as input\n");
1927794e27ecSJohnny Huang 		printf("Skip\n");
1928794e27ecSJohnny Huang 		return OTP_FAILURE;
1929794e27ecSJohnny Huang 	}
1930794e27ecSJohnny Huang 
1931794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1932794e27ecSJohnny Huang 		if (i < 32) {
1933794e27ecSJohnny Huang 			dw_offset = 0xa;
1934794e27ecSJohnny Huang 			bit_offset = i;
1935794e27ecSJohnny Huang 		} else {
1936794e27ecSJohnny Huang 			dw_offset = 0xb;
1937794e27ecSJohnny Huang 			bit_offset = i - 32;
1938794e27ecSJohnny Huang 		}
19390dc9a440SJohnny Huang 		printf("OTPCFG%X[%X]", dw_offset, bit_offset);
1940794e27ecSJohnny Huang 		if (i + 1 != update_num)
1941794e27ecSJohnny Huang 			printf(", ");
1942794e27ecSJohnny Huang 	}
1943794e27ecSJohnny Huang 
1944794e27ecSJohnny Huang 	printf(" will be programmed\n");
1945794e27ecSJohnny Huang 	if (force == 0) {
1946794e27ecSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
1947794e27ecSJohnny Huang 		if (!confirm_yesno()) {
1948794e27ecSJohnny Huang 			printf(" Aborting\n");
1949794e27ecSJohnny Huang 			return OTP_FAILURE;
1950794e27ecSJohnny Huang 		}
1951794e27ecSJohnny Huang 	}
1952794e27ecSJohnny Huang 
1953794e27ecSJohnny Huang 	ret = 0;
1954794e27ecSJohnny Huang 	for (i = rid_num; i < update_num; i++) {
1955794e27ecSJohnny Huang 		if (i < 32) {
1956794e27ecSJohnny Huang 			dw_offset = 0xa04;
1957794e27ecSJohnny Huang 			bit_offset = i;
1958794e27ecSJohnny Huang 		} else {
1959794e27ecSJohnny Huang 			dw_offset = 0xa06;
1960794e27ecSJohnny Huang 			bit_offset = i - 32;
1961794e27ecSJohnny Huang 		}
1962f347c284SJohnny Huang 		if (otp_prog_dc_b(1, dw_offset, bit_offset)) {
19630dc9a440SJohnny Huang 			printf("OTPCFG%X[%X] programming failed\n", dw_offset, bit_offset);
1964794e27ecSJohnny Huang 			ret = OTP_FAILURE;
1965794e27ecSJohnny Huang 			break;
1966794e27ecSJohnny Huang 		}
1967794e27ecSJohnny Huang 	}
1968794e27ecSJohnny Huang 
1969f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
1970f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
1971794e27ecSJohnny Huang 	rid_num = get_rid_num(otp_rid);
1972794e27ecSJohnny Huang 	if (rid_num >= 0)
1973794e27ecSJohnny Huang 		printf("OTP revision ID: 0x%x\n", rid_num);
1974794e27ecSJohnny Huang 	else
1975794e27ecSJohnny Huang 		printf("OTP revision ID\n");
1976794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
1977794e27ecSJohnny Huang 	if (!ret)
1978794e27ecSJohnny Huang 		printf("SUCCESS\n");
1979794e27ecSJohnny Huang 	else
1980794e27ecSJohnny Huang 		printf("FAILED\n");
1981794e27ecSJohnny Huang 	return ret;
1982794e27ecSJohnny Huang }
1983794e27ecSJohnny Huang 
19842a856b9aSJohnny Huang static int do_otpread(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
198569d5fd8fSJohnny Huang {
1986a219f6deSJohnny Huang 	u32 offset, count;
19872a856b9aSJohnny Huang 	int ret;
198869d5fd8fSJohnny Huang 
19892a856b9aSJohnny Huang 	if (argc == 4) {
19902a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
19912a856b9aSJohnny Huang 		count = simple_strtoul(argv[3], NULL, 16);
19922a856b9aSJohnny Huang 	} else if (argc == 3) {
19932a856b9aSJohnny Huang 		offset = simple_strtoul(argv[2], NULL, 16);
19942a856b9aSJohnny Huang 		count = 1;
19952a856b9aSJohnny Huang 	} else {
199669d5fd8fSJohnny Huang 		return CMD_RET_USAGE;
199769d5fd8fSJohnny Huang 	}
199869d5fd8fSJohnny Huang 
19992a856b9aSJohnny Huang 	if (!strcmp(argv[1], "conf")) {
20003d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2001f347c284SJohnny Huang 		ret = otp_print_conf(offset, count);
20022a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "data")) {
20033d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20042a856b9aSJohnny Huang 		ret = otp_print_data(offset, count);
20052a856b9aSJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
20063d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
20072a856b9aSJohnny Huang 		ret = otp_print_strap(offset, count);
20082a856b9aSJohnny Huang 	} else {
20092a856b9aSJohnny Huang 		return CMD_RET_USAGE;
201069d5fd8fSJohnny Huang 	}
2011*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
201269d5fd8fSJohnny Huang 
20132a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20142a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20152a856b9aSJohnny Huang 	return CMD_RET_USAGE;
20162a856b9aSJohnny Huang }
20172a856b9aSJohnny Huang 
20182a856b9aSJohnny Huang static int do_otpprog(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20192a856b9aSJohnny Huang {
20202a856b9aSJohnny Huang 	phys_addr_t addr;
20212a856b9aSJohnny Huang 	int ret;
20222a856b9aSJohnny Huang 
2023de6b0cc4SJohnny Huang 	if (argc == 3) {
2024ed071a2bSJohnny Huang 		if (strcmp(argv[1], "o"))
20252a856b9aSJohnny Huang 			return CMD_RET_USAGE;
20262a856b9aSJohnny Huang 		addr = simple_strtoul(argv[2], NULL, 16);
20273d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2028f347c284SJohnny Huang 		ret = otp_prog_image(addr, 1);
2029de6b0cc4SJohnny Huang 	} else if (argc == 2) {
20302a856b9aSJohnny Huang 		addr = simple_strtoul(argv[1], NULL, 16);
20313d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2032f347c284SJohnny Huang 		ret = otp_prog_image(addr, 0);
20332a856b9aSJohnny Huang 	} else {
20342a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20352a856b9aSJohnny Huang 	}
2036*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
20372a856b9aSJohnny Huang 
20382a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
20392a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
20402a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
20412a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
20422a856b9aSJohnny Huang 	else
20432a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20442a856b9aSJohnny Huang }
20452a856b9aSJohnny Huang 
20462a856b9aSJohnny Huang static int do_otppb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
20472a856b9aSJohnny Huang {
20482a856b9aSJohnny Huang 	int mode = 0;
20492a856b9aSJohnny Huang 	int nconfirm = 0;
20502a856b9aSJohnny Huang 	int otp_addr = 0;
20512a856b9aSJohnny Huang 	int bit_offset;
20522a856b9aSJohnny Huang 	int value;
20532a856b9aSJohnny Huang 	int ret;
20542a856b9aSJohnny Huang 
20552a856b9aSJohnny Huang 	if (argc != 4 && argc != 5 && argc != 6)
20562a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20572a856b9aSJohnny Huang 
20582a856b9aSJohnny Huang 	/* Drop the pb cmd */
20592a856b9aSJohnny Huang 	argc--;
20602a856b9aSJohnny Huang 	argv++;
20612a856b9aSJohnny Huang 
20622a856b9aSJohnny Huang 	if (!strcmp(argv[0], "conf"))
2063a6d0d645SJohnny Huang 		mode = OTP_REGION_CONF;
20642a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "strap"))
2065a6d0d645SJohnny Huang 		mode = OTP_REGION_STRAP;
20662a856b9aSJohnny Huang 	else if (!strcmp(argv[0], "data"))
2067a6d0d645SJohnny Huang 		mode = OTP_REGION_DATA;
2068cd1610b4SJohnny Huang 	else
20692a856b9aSJohnny Huang 		return CMD_RET_USAGE;
20702a856b9aSJohnny Huang 
20712a856b9aSJohnny Huang 	/* Drop the region cmd */
20722a856b9aSJohnny Huang 	argc--;
20732a856b9aSJohnny Huang 	argv++;
20742a856b9aSJohnny Huang 
2075ed071a2bSJohnny Huang 	if (!strcmp(argv[0], "o")) {
2076cd1610b4SJohnny Huang 		nconfirm = 1;
20772a856b9aSJohnny Huang 		/* Drop the force option */
20782a856b9aSJohnny Huang 		argc--;
20792a856b9aSJohnny Huang 		argv++;
20802a856b9aSJohnny Huang 	}
2081cd1610b4SJohnny Huang 
2082a6d0d645SJohnny Huang 	if (mode == OTP_REGION_STRAP) {
20832a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[0], NULL, 16);
20842a856b9aSJohnny Huang 		value = simple_strtoul(argv[1], NULL, 16);
20850808cc55SJohnny Huang 		if (bit_offset >= 64 || (value != 0 && value != 1))
20862a856b9aSJohnny Huang 			return CMD_RET_USAGE;
2087cd1610b4SJohnny Huang 	} else {
20882a856b9aSJohnny Huang 		otp_addr = simple_strtoul(argv[0], NULL, 16);
20892a856b9aSJohnny Huang 		bit_offset = simple_strtoul(argv[1], NULL, 16);
20902a856b9aSJohnny Huang 		value = simple_strtoul(argv[2], NULL, 16);
20910808cc55SJohnny Huang 		if (bit_offset >= 32 || (value != 0 && value != 1))
20922a856b9aSJohnny Huang 			return CMD_RET_USAGE;
20930808cc55SJohnny Huang 		if (mode == OTP_REGION_DATA) {
209478855207SJohnny Huang 			if (otp_addr >= 0x800)
20950808cc55SJohnny Huang 				return CMD_RET_USAGE;
20960808cc55SJohnny Huang 		} else {
209778855207SJohnny Huang 			if (otp_addr >= 0x20)
20980808cc55SJohnny Huang 				return CMD_RET_USAGE;
20990808cc55SJohnny Huang 		}
2100cd1610b4SJohnny Huang 	}
2101cd1610b4SJohnny Huang 	if (value != 0 && value != 1)
21022a856b9aSJohnny Huang 		return CMD_RET_USAGE;
2103cd1610b4SJohnny Huang 
21043d3688adSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2105f347c284SJohnny Huang 	ret = otp_prog_bit(mode, otp_addr, bit_offset, value, nconfirm);
2106*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
21072a856b9aSJohnny Huang 
21082a856b9aSJohnny Huang 	if (ret == OTP_SUCCESS)
21092a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
21102a856b9aSJohnny Huang 	else if (ret == OTP_FAILURE)
21112a856b9aSJohnny Huang 		return CMD_RET_FAILURE;
21122a856b9aSJohnny Huang 	else
21132a856b9aSJohnny Huang 		return CMD_RET_USAGE;
21142a856b9aSJohnny Huang }
21152a856b9aSJohnny Huang 
21162a856b9aSJohnny Huang static int do_otpcmp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
21172a856b9aSJohnny Huang {
21182a856b9aSJohnny Huang 	phys_addr_t addr;
21192a856b9aSJohnny Huang 	int otp_addr = 0;
2120*b8590031SJohnny Huang 	int ret;
21212a856b9aSJohnny Huang 
21222a856b9aSJohnny Huang 	if (argc != 3)
21232a856b9aSJohnny Huang 		return CMD_RET_USAGE;
21242a856b9aSJohnny Huang 
21252a856b9aSJohnny Huang 	addr = simple_strtoul(argv[1], NULL, 16);
21262a856b9aSJohnny Huang 	otp_addr = simple_strtoul(argv[2], NULL, 16);
2127*b8590031SJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2128*b8590031SJohnny Huang 	ret = otp_compare(otp_addr, addr);
2129*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
2130*b8590031SJohnny Huang 	if (ret == 0) {
213169d5fd8fSJohnny Huang 		printf("Compare pass\n");
21322a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
2133a219f6deSJohnny Huang 	}
213469d5fd8fSJohnny Huang 	printf("Compare fail\n");
21352a856b9aSJohnny Huang 	return CMD_RET_FAILURE;
213669d5fd8fSJohnny Huang }
213769d5fd8fSJohnny Huang 
213866f2f8e5SJohnny Huang static int do_otpinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
213966f2f8e5SJohnny Huang {
2140a8bd6d8cSJohnny Huang 	int view = 0;
21412d4b0742SJohnny Huang 	int input;
2142a8bd6d8cSJohnny Huang 
2143a8bd6d8cSJohnny Huang 	if (argc != 2 && argc != 3)
214466f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
214566f2f8e5SJohnny Huang 
21462d4b0742SJohnny Huang 	if (!strcmp(argv[1], "conf")) {
21473d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
21482d4b0742SJohnny Huang 		if (argc == 3) {
21492d4b0742SJohnny Huang 			input = simple_strtoul(argv[2], NULL, 16);
21502d4b0742SJohnny Huang 			otp_print_conf_info(input);
21512d4b0742SJohnny Huang 		} else {
21522d4b0742SJohnny Huang 			otp_print_conf_info(-1);
21532d4b0742SJohnny Huang 		}
21542d4b0742SJohnny Huang 	} else if (!strcmp(argv[1], "strap")) {
21552d4b0742SJohnny Huang 		if (!strcmp(argv[2], "v")) {
2156a8bd6d8cSJohnny Huang 			view = 1;
2157a8bd6d8cSJohnny Huang 			/* Drop the view option */
2158a8bd6d8cSJohnny Huang 			argc--;
2159a8bd6d8cSJohnny Huang 			argv++;
2160a8bd6d8cSJohnny Huang 		}
21613d3688adSJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2162b458cd62SJohnny Huang 		otp_print_strap_info(view);
21630dc9a440SJohnny Huang 	} else if (!strcmp(argv[1], "scu")) {
21640dc9a440SJohnny Huang 		writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
21650dc9a440SJohnny Huang 		otp_print_scu_info();
216666f2f8e5SJohnny Huang 	} else {
216766f2f8e5SJohnny Huang 		return CMD_RET_USAGE;
216866f2f8e5SJohnny Huang 	}
21692d4b0742SJohnny Huang 
2170*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
217166f2f8e5SJohnny Huang 	return CMD_RET_SUCCESS;
217266f2f8e5SJohnny Huang }
217366f2f8e5SJohnny Huang 
21740dc9a440SJohnny Huang static int do_otpprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2175737ed20bSJohnny Huang {
21760dc9a440SJohnny Huang 	u32 input;
21770dc9a440SJohnny Huang 	u32 bit_offset;
2178e14b073cSJohnny Huang 	u32 prog_address;
217983655e91SJohnny Huang 	int ret;
2180a219f6deSJohnny Huang 
2181737ed20bSJohnny Huang 	if (argc != 3 && argc != 2)
2182737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2183737ed20bSJohnny Huang 
2184e14b073cSJohnny Huang 	if (!strcmp(argv[1], "o")) {
2185737ed20bSJohnny Huang 		input = simple_strtoul(argv[2], NULL, 16);
2186737ed20bSJohnny Huang 	} else {
2187737ed20bSJohnny Huang 		input = simple_strtoul(argv[1], NULL, 16);
21880dc9a440SJohnny Huang 		printf("OTPSTRAP[%X] will be protected\n", input);
2189737ed20bSJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
2190737ed20bSJohnny Huang 		if (!confirm_yesno()) {
2191737ed20bSJohnny Huang 			printf(" Aborting\n");
2192737ed20bSJohnny Huang 			return CMD_RET_FAILURE;
2193737ed20bSJohnny Huang 		}
2194737ed20bSJohnny Huang 	}
2195737ed20bSJohnny Huang 
2196737ed20bSJohnny Huang 	if (input < 32) {
2197737ed20bSJohnny Huang 		bit_offset = input;
21980dc9a440SJohnny Huang 		prog_address = 0xe0c;
2199737ed20bSJohnny Huang 	} else if (input < 64) {
2200737ed20bSJohnny Huang 		bit_offset = input - 32;
22010dc9a440SJohnny Huang 		prog_address = 0xe0e;
2202737ed20bSJohnny Huang 	} else {
2203737ed20bSJohnny Huang 		return CMD_RET_USAGE;
2204737ed20bSJohnny Huang 	}
2205737ed20bSJohnny Huang 
2206e14b073cSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2207e14b073cSJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
22080dc9a440SJohnny Huang 		printf("OTPSTRAP[%X] already protected\n", input);
2209e14b073cSJohnny Huang 		return CMD_RET_SUCCESS;
2210e14b073cSJohnny Huang 	}
2211de6fbf1cSJohnny Huang 
2212f347c284SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
2213de6fbf1cSJohnny Huang 	otp_soak(0);
2214*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
221583655e91SJohnny Huang 
221683655e91SJohnny Huang 	if (ret) {
22170dc9a440SJohnny Huang 		printf("Protect OTPSTRAP[%X] fail\n", input);
2218737ed20bSJohnny Huang 		return CMD_RET_FAILURE;
2219737ed20bSJohnny Huang 	}
22209a4fe690SJohnny Huang 
22210dc9a440SJohnny Huang 	printf("OTPSTRAP[%X] is protected\n", input);
2222794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2223794e27ecSJohnny Huang }
2224794e27ecSJohnny Huang 
22250dc9a440SJohnny Huang static int do_otp_scuprotect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2226e14b073cSJohnny Huang {
22270dc9a440SJohnny Huang 	u32 scu_offset;
22280dc9a440SJohnny Huang 	u32 bit_offset;
22290dc9a440SJohnny Huang 	u32 conf_offset;
22300dc9a440SJohnny Huang 	u32 prog_address;
22310dc9a440SJohnny Huang 	char force;
22320dc9a440SJohnny Huang 	int ret;
22330dc9a440SJohnny Huang 
22340dc9a440SJohnny Huang 	if (argc != 4 && argc != 3)
22350dc9a440SJohnny Huang 		return CMD_RET_USAGE;
22360dc9a440SJohnny Huang 
22370dc9a440SJohnny Huang 	if (!strcmp(argv[1], "o")) {
22380dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[2], NULL, 16);
22390dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[3], NULL, 16);
22400dc9a440SJohnny Huang 		force = 1;
22410dc9a440SJohnny Huang 	} else {
22420dc9a440SJohnny Huang 		scu_offset = simple_strtoul(argv[1], NULL, 16);
22430dc9a440SJohnny Huang 		bit_offset = simple_strtoul(argv[2], NULL, 16);
22440dc9a440SJohnny Huang 		force = 0;
22450dc9a440SJohnny Huang 	}
22460dc9a440SJohnny Huang 	if (scu_offset == 0x500) {
22470dc9a440SJohnny Huang 		prog_address = 0xe08;
22480dc9a440SJohnny Huang 		conf_offset = 28;
22490dc9a440SJohnny Huang 	} else if (scu_offset == 0x510) {
22500dc9a440SJohnny Huang 		prog_address = 0xe0a;
22510dc9a440SJohnny Huang 		conf_offset = 29;
22520dc9a440SJohnny Huang 	} else {
22530dc9a440SJohnny Huang 		return CMD_RET_USAGE;
22540dc9a440SJohnny Huang 	}
22550dc9a440SJohnny Huang 	if (bit_offset < 0 || bit_offset > 31)
22560dc9a440SJohnny Huang 		return CMD_RET_USAGE;
22570dc9a440SJohnny Huang 
22580dc9a440SJohnny Huang 	if (!force) {
22590dc9a440SJohnny Huang 		printf("OTPCONF%X[%X] will be programmed\n", conf_offset, bit_offset);
22600dc9a440SJohnny Huang 		printf("SCU%X[%X] will be protected\n", scu_offset, bit_offset);
22610dc9a440SJohnny Huang 		printf("type \"YES\" (no quotes) to continue:\n");
22620dc9a440SJohnny Huang 		if (!confirm_yesno()) {
22630dc9a440SJohnny Huang 			printf(" Aborting\n");
22640dc9a440SJohnny Huang 			return CMD_RET_FAILURE;
22650dc9a440SJohnny Huang 		}
2266e14b073cSJohnny Huang 	}
2267e14b073cSJohnny Huang 
22680dc9a440SJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
22690dc9a440SJohnny Huang 	if (verify_bit(prog_address, bit_offset, 1) == 0) {
22700dc9a440SJohnny Huang 		printf("OTPCONF%X[%X] already programmed\n", conf_offset, bit_offset);
22710dc9a440SJohnny Huang 		return CMD_RET_SUCCESS;
22720dc9a440SJohnny Huang 	}
22730dc9a440SJohnny Huang 
22740dc9a440SJohnny Huang 	ret = otp_prog_dc_b(1, prog_address, bit_offset);
22750dc9a440SJohnny Huang 	otp_soak(0);
2276*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
22770dc9a440SJohnny Huang 
22780dc9a440SJohnny Huang 	if (ret) {
22790dc9a440SJohnny Huang 		printf("Program OTPCONF%X[%X] fail\n", conf_offset, bit_offset);
22800dc9a440SJohnny Huang 		return CMD_RET_FAILURE;
22810dc9a440SJohnny Huang 	}
22820dc9a440SJohnny Huang 
22830dc9a440SJohnny Huang 	printf("OTPCONF%X[%X] programmed success\n", conf_offset, bit_offset);
22840dc9a440SJohnny Huang 	return CMD_RET_SUCCESS;
2285e14b073cSJohnny Huang }
2286e14b073cSJohnny Huang 
2287f67375f7SJohnny Huang static int do_otpver(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2288f67375f7SJohnny Huang {
2289e417205bSJohnny Huang 	printf("SOC OTP version: %s\n", info_cb.ver_name);
2290f67375f7SJohnny Huang 	printf("OTP tool version: %s\n", OTP_VER);
2291f67375f7SJohnny Huang 	printf("OTP info version: %s\n", OTP_INFO_VER);
2292f67375f7SJohnny Huang 
2293f67375f7SJohnny Huang 	return CMD_RET_SUCCESS;
2294f67375f7SJohnny Huang }
2295f67375f7SJohnny Huang 
2296794e27ecSJohnny Huang static int do_otpupdate(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2297794e27ecSJohnny Huang {
2298794e27ecSJohnny Huang 	u32 update_num;
2299794e27ecSJohnny Huang 	int force = 0;
2300794e27ecSJohnny Huang 	int ret;
2301794e27ecSJohnny Huang 
2302794e27ecSJohnny Huang 	if (argc == 3) {
2303794e27ecSJohnny Huang 		if (strcmp(argv[1], "o"))
2304794e27ecSJohnny Huang 			return CMD_RET_USAGE;
2305794e27ecSJohnny Huang 		force = 1;
2306794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[2], NULL, 16);
2307794e27ecSJohnny Huang 	} else if (argc == 2) {
2308794e27ecSJohnny Huang 		update_num = simple_strtoul(argv[1], NULL, 16);
2309794e27ecSJohnny Huang 	} else {
2310794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2311794e27ecSJohnny Huang 	}
2312794e27ecSJohnny Huang 
2313794e27ecSJohnny Huang 	if (update_num > 64)
2314794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2315794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2316794e27ecSJohnny Huang 	ret = otp_update_rid(update_num, force);
2317*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
2318*b8590031SJohnny Huang 
2319794e27ecSJohnny Huang 	if (ret)
2320794e27ecSJohnny Huang 		return CMD_RET_FAILURE;
2321794e27ecSJohnny Huang 	return CMD_RET_SUCCESS;
2322794e27ecSJohnny Huang }
2323794e27ecSJohnny Huang 
2324794e27ecSJohnny Huang static int do_otprid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2325794e27ecSJohnny Huang {
2326794e27ecSJohnny Huang 	u32 otp_rid[2];
2327a8789b47SJohnny Huang 	u32 sw_rid[2];
2328794e27ecSJohnny Huang 	int rid_num = 0;
2329a8789b47SJohnny Huang 	int sw_rid_num = 0;
2330794e27ecSJohnny Huang 	int ret;
2331794e27ecSJohnny Huang 
2332794e27ecSJohnny Huang 	if (argc != 1)
2333794e27ecSJohnny Huang 		return CMD_RET_USAGE;
2334794e27ecSJohnny Huang 
2335794e27ecSJohnny Huang 	writel(OTP_PASSWD, OTP_PROTECT_KEY); //password
2336f347c284SJohnny Huang 	otp_read_conf(10, &otp_rid[0]);
2337f347c284SJohnny Huang 	otp_read_conf(11, &otp_rid[1]);
2338*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
2339794e27ecSJohnny Huang 
2340a8789b47SJohnny Huang 	sw_rid[0] = readl(SW_REV_ID0);
2341a8789b47SJohnny Huang 	sw_rid[1] = readl(SW_REV_ID1);
2342794e27ecSJohnny Huang 
2343a8789b47SJohnny Huang 	rid_num = get_rid_num(otp_rid);
2344a8789b47SJohnny Huang 	sw_rid_num = get_rid_num(sw_rid);
2345a8789b47SJohnny Huang 
2346a8789b47SJohnny Huang 	printf("current SW revision ID: 0x%x\n", sw_rid_num);
2347794e27ecSJohnny Huang 	if (rid_num >= 0) {
2348794e27ecSJohnny Huang 		printf("current OTP revision ID: 0x%x\n", rid_num);
2349794e27ecSJohnny Huang 		ret = CMD_RET_SUCCESS;
2350794e27ecSJohnny Huang 	} else {
2351794e27ecSJohnny Huang 		printf("Currennt OTP revision ID cannot handle by 'otp update',\n"
2352794e27ecSJohnny Huang 		       "plase use 'otp pb' command to update it manually\n"
2353794e27ecSJohnny Huang 		       "current OTP revision ID\n");
2354794e27ecSJohnny Huang 		ret = CMD_RET_FAILURE;
2355794e27ecSJohnny Huang 	}
2356794e27ecSJohnny Huang 	otp_print_revid(otp_rid);
2357794e27ecSJohnny Huang 
2358794e27ecSJohnny Huang 	return ret;
2359794e27ecSJohnny Huang }
2360794e27ecSJohnny Huang 
23612a856b9aSJohnny Huang static cmd_tbl_t cmd_otp[] = {
2362f67375f7SJohnny Huang 	U_BOOT_CMD_MKENT(version, 1, 0, do_otpver, "", ""),
23632a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(read, 4, 0, do_otpread, "", ""),
2364a8bd6d8cSJohnny Huang 	U_BOOT_CMD_MKENT(info, 3, 0, do_otpinfo, "", ""),
2365de6b0cc4SJohnny Huang 	U_BOOT_CMD_MKENT(prog, 3, 0, do_otpprog, "", ""),
23662a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(pb, 6, 0, do_otppb, "", ""),
2367737ed20bSJohnny Huang 	U_BOOT_CMD_MKENT(protect, 3, 0, do_otpprotect, "", ""),
23680dc9a440SJohnny Huang 	U_BOOT_CMD_MKENT(scuprotect, 4, 0, do_otp_scuprotect, "", ""),
23692a856b9aSJohnny Huang 	U_BOOT_CMD_MKENT(cmp, 3, 0, do_otpcmp, "", ""),
2370794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(update, 3, 0, do_otpupdate, "", ""),
2371794e27ecSJohnny Huang 	U_BOOT_CMD_MKENT(rid, 1, 0, do_otprid, "", ""),
23722a856b9aSJohnny Huang };
23732a856b9aSJohnny Huang 
23742a856b9aSJohnny Huang static int do_ast_otp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
23752a856b9aSJohnny Huang {
23762a856b9aSJohnny Huang 	cmd_tbl_t *cp;
2377a219f6deSJohnny Huang 	u32 ver;
2378e14b073cSJohnny Huang 	int ret;
23792a856b9aSJohnny Huang 
23802a856b9aSJohnny Huang 	cp = find_cmd_tbl(argv[1], cmd_otp, ARRAY_SIZE(cmd_otp));
23812a856b9aSJohnny Huang 
2382737ed20bSJohnny Huang 	/* Drop the otp command */
23832a856b9aSJohnny Huang 	argc--;
23842a856b9aSJohnny Huang 	argv++;
23852a856b9aSJohnny Huang 
2386a219f6deSJohnny Huang 	if (!cp || argc > cp->maxargs)
23872a856b9aSJohnny Huang 		return CMD_RET_USAGE;
23882a856b9aSJohnny Huang 	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
23892a856b9aSJohnny Huang 		return CMD_RET_SUCCESS;
23902a856b9aSJohnny Huang 
23910dae9d52SJohnny Huang 	ver = chip_version();
23920dae9d52SJohnny Huang 	switch (ver) {
2393e417205bSJohnny Huang 	case OTP_A0:
2394e417205bSJohnny Huang 		info_cb.version = OTP_A0;
23959a4fe690SJohnny Huang 		info_cb.conf_info = a0_conf_info;
23969a4fe690SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a0_conf_info);
23979a4fe690SJohnny Huang 		info_cb.strap_info = a0_strap_info;
23989a4fe690SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a0_strap_info);
23999a4fe690SJohnny Huang 		info_cb.key_info = a0_key_type;
24009a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a0_key_type);
2401e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A0");
24020dae9d52SJohnny Huang 		break;
2403e417205bSJohnny Huang 	case OTP_A1:
2404e417205bSJohnny Huang 		info_cb.version = OTP_A1;
24053cb28812SJohnny Huang 		info_cb.conf_info = a1_conf_info;
24063cb28812SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a1_conf_info);
24073cb28812SJohnny Huang 		info_cb.strap_info = a1_strap_info;
24083cb28812SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
24099a4fe690SJohnny Huang 		info_cb.key_info = a1_key_type;
24109a4fe690SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a1_key_type);
24110dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
24120dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2413e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A1");
24140dae9d52SJohnny Huang 		break;
2415e417205bSJohnny Huang 	case OTP_A2:
2416e417205bSJohnny Huang 		info_cb.version = OTP_A2;
24175fdde29fSJohnny Huang 		info_cb.conf_info = a2_conf_info;
24185fdde29fSJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a2_conf_info);
2419fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2420fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
24215fdde29fSJohnny Huang 		info_cb.key_info = a2_key_type;
24225fdde29fSJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a2_key_type);
24230dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
24240dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2425e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A2");
24260dae9d52SJohnny Huang 		break;
2427e417205bSJohnny Huang 	case OTP_A3:
2428e417205bSJohnny Huang 		info_cb.version = OTP_A3;
2429b63af886SJohnny Huang 		info_cb.conf_info = a3_conf_info;
2430b63af886SJohnny Huang 		info_cb.conf_info_len = ARRAY_SIZE(a3_conf_info);
2431fed30023SJohnny Huang 		info_cb.strap_info = a1_strap_info;
2432fed30023SJohnny Huang 		info_cb.strap_info_len = ARRAY_SIZE(a1_strap_info);
2433181f72d8SJohnny Huang 		info_cb.key_info = a3_key_type;
2434181f72d8SJohnny Huang 		info_cb.key_info_len = ARRAY_SIZE(a3_key_type);
24350dc9a440SJohnny Huang 		info_cb.scu_info = a1_scu_info;
24360dc9a440SJohnny Huang 		info_cb.scu_info_len = ARRAY_SIZE(a1_scu_info);
2437e417205bSJohnny Huang 		sprintf(info_cb.ver_name, "A3");
243864b66712SJohnny Huang 		break;
24390dae9d52SJohnny Huang 	default:
2440f1be5099SJohnny Huang 		printf("SOC is not supported\n");
24410dae9d52SJohnny Huang 		return CMD_RET_FAILURE;
24429a4fe690SJohnny Huang 	}
24439a4fe690SJohnny Huang 
2444e14b073cSJohnny Huang 	ret = cp->cmd(cmdtp, flag, argc, argv);
2445*b8590031SJohnny Huang 	writel(1, OTP_PROTECT_KEY); //protect otp controller
2446e14b073cSJohnny Huang 
2447e14b073cSJohnny Huang 	return ret;
244869d5fd8fSJohnny Huang }
244969d5fd8fSJohnny Huang 
2450a219f6deSJohnny Huang U_BOOT_CMD(otp, 7, 0,  do_ast_otp,
245169d5fd8fSJohnny Huang 	   "ASPEED One-Time-Programmable sub-system",
2452f67375f7SJohnny Huang 	   "version\n"
2453f67375f7SJohnny Huang 	   "otp read conf|data <otp_dw_offset> <dw_count>\n"
24542a856b9aSJohnny Huang 	   "otp read strap <strap_bit_offset> <bit_count>\n"
24552d4b0742SJohnny Huang 	   "otp info strap [v]\n"
24562d4b0742SJohnny Huang 	   "otp info conf [otp_dw_offset]\n"
24570dc9a440SJohnny Huang 	   "otp info scu\n"
2458de6b0cc4SJohnny Huang 	   "otp prog [o] <addr>\n"
2459ed071a2bSJohnny Huang 	   "otp pb conf|data [o] <otp_dw_offset> <bit_offset> <value>\n"
2460ed071a2bSJohnny Huang 	   "otp pb strap [o] <bit_offset> <value>\n"
2461ed071a2bSJohnny Huang 	   "otp protect [o] <bit_offset>\n"
24620dc9a440SJohnny Huang 	   "otp scuprotect [o] <scu_offset> <bit_offset>\n"
2463794e27ecSJohnny Huang 	   "otp update [o] <revision_id>\n"
2464794e27ecSJohnny Huang 	   "otp rid\n"
246569d5fd8fSJohnny Huang 	  );
2466